Android的存储系统相对来讲还是比较复杂,其中主要包括了native层的Vold以及Java层的MountService。其中Vold在init进程中通过init脚本进行启动,而MountService则是在Java的服务总站SystemServer中配置启动的。它们之间的通信采用的Socket进行,而不是Binder机制,其主要的原因就是架构上比较简单,代码量也少。本文就从启动流程上分析安卓系统中的存储模块是如何加载起来的,下面就让我们直接进入正题。
Vold启动流程
native层的Vlod进程启动在init.rc脚本中进行配置的,其定义于 /system/core/rootdir/init.rc 中,我们看一下脚本文件内容。
init脚本相关配置
init.rc 脚本配置如下:
service vold /system/bin/vold \
--blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:blkid_untrusted:s0 \
--fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0
class core
socket vold stream 0660 root mount
socket cryptd stream 0660 root mount
ioprio be 2
脚本文件声明服务 service 为 vold,对应的程序文件路径 /system/bin/vold,系统级 core 核心服务。
Vold.main
init进程通过解析上述脚本文件内容,启动对应的Vold进程,进入到vold的main函数中。其函数文件位于 system/vold/main.cpp 中
// vold 启动时都创建了若干对象
int main(int argc, char** argv) {
setenv("ANDROID_LOG_TAGS", "*:v", 1);
android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
...
VolumeManager *vm;
CommandListener *cl;
CryptCommandListener *ccl;
NetlinkManager *nm;
//解析参数
parse_args(argc, argv);
...
// Quickly throw a CLOEXEC on the socket we just inherited from init
fcntl(android_get_control_socket("vold"), F_SETFD, FD_CLOEXEC);
fcntl(android_get_control_socket("cryptd"), F_SETFD, FD_CLOEXEC);
mkdir("/dev/block/vold", 0755);
// 用于cryptfs检查,并mount加密的文件系统
klog_set_level(6);
//创建单例对象 VolumeManager
if (!(vm = VolumeManager::Instance())) {
LOG(ERROR) << "Unable to create VolumeManager";
exit(1);
}
//创建单例对象 NetlinkManager
if (!(nm = NetlinkManager::Instance())) {
LOG(ERROR) << "Unable to create NetlinkManager";
exit(1);
}
if (property_get_bool("vold.debug", false)) {
vm->setDebug(true);
}
// 创建 CommandListener 对象
cl = new CommandListener();
// 创建 CryptCommandListener 对象
ccl = new CryptCommandListener();
// 将新创建的 CommandListener 对象 sl 赋值给 vm 对象的成员变量 mBroadcaster
vm->setBroadcaster((SocketListener *) cl);
nm->setBroadcaster((SocketListener *) cl);
if (vm->start()) {
PLOG(ERROR) << "Unable to start VolumeManager";
exit(1);
}
if (process_config(vm)) {
PLOG(ERROR) << "Error reading configuration... continuing anyways";
}
if (nm->start()) {
PLOG(ERROR) << "Unable to start NetlinkManager";
exit(1);
}
coldboot("/sys/block");
// coldboot("/sys/class/switch");
//启动响应命令的监听器
if (cl->startListener()) {
PLOG(ERROR) << "Unable to start CommandListener";
exit(1);
}
if (ccl->startListener()) {
PLOG(ERROR) << "Unable to start CryptCommandListener";
exit(1);
}
//Vold成为监听线程
while(1) {
sleep(1000);
}
LOG(ERROR) << "Vold exiting";
exit(0);
}
上述代码可以看出,Vold.main函数中主要做了以下几件事:
- 解析传入参数
- 创建 VolumeManager,设置监听并启动
- 创建 NetlinkManager,设置监听并启动
- 创建 CommandListener
- 创建 CryptCommandListener
- 循环成为监听线程
VM流程分析
VM初始化
VolumeManager是Vold进程中最重要的几个类之一,其简而言之就是Vold的统筹管理类,代码位于 /system/vold/VolumeBase.cpp 下,我们看一下其初始化流程。
// 单例模式
VolumeManager *VolumeManager::Instance() {
if (!sInstance)
sInstance = new VolumeManager();
return sInstance;
}
VolumeManager::VolumeManager() {
mDebug = false;
mActiveContainers = new AsecIdCollection();
mBroadcaster = NULL;
mUmsSharingCount = 0;
mSavedDirtyRatio = -1;
// 当UMS获取时,则设置 dirty ratio 为 0
mUmsDirtyRatio = 0;
}
VolumeManager类内部通过单例模式进行创建,创建同时创建AsecIdCollection负责aesc文件的收集,从析构函数中可以看出其被手动删除释放。下面便是设置监听。
VM->setBroadcaster
VolumeManager设置监听后,VM才可以开启,并且监听线程才能启动。其代码位于头文件中。
void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
代码中,将CommandListener 对象sl赋值给 mBroadcaster。
VM->start
VolumeManager设置监听后,便开启工作。
int VolumeManager::start() {
// Always start from a clean slate by unmounting everything in
// directories that we own, in case we crashed.
// 卸载所有设备,已提供最干净的环境
unmountAll();
// Assume that we always have an emulated volume on internal
// storage; the framework will decide if it should be mounted.
CHECK(mInternalEmulated == nullptr);
// 创建Emulated内部存储
// 其类型为 EmulatedVolume,设备路径为/data/media
// id和label为“emulated”,mMountFlags=0
// EmulatedVolume 继承于 VolumeBase
mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>(
new android::vold::EmulatedVolume("/data/media"));
// EmulatedVolume继承VolumeBase
mInternalEmulated->create();
return 0;
}
VolumeManager开启时候,会线卸载所有设备,保证干净的环境,之后在重新建立存储化境。
unmountAll卸载设备
int VolumeManager::unmountAll() {
std::lock_guard<std::mutex> lock(mLock);
// First, try gracefully unmounting all known devices
// 1.卸载内部存储
if (mInternalEmulated != nullptr) {
mInternalEmulated->unmount();
}
// 2.卸载外部存储
for (auto disk : mDisks) {
disk->unmountAll();
}
// Worst case we might have some stale mounts lurking around, so
// force unmount those just to be safe.
// 有可能存在严重的潜在的旧的挂载设备存在,强力卸载以保证安全
FILE* fp = setmntent("/proc/mounts", "r");
if (fp == NULL) {
SLOGE("Error opening /proc/mounts: %s", strerror(errno));
return -errno;
}
// Some volumes can be stacked on each other, so force unmount in
// reverse order to give us the best chance of success.
std::list<std::string> toUnmount;
mntent* mentry;
while ((mentry = getmntent(fp)) != NULL) {
if (strncmp(mentry->mnt_dir, "/mnt/", 5) == 0
|| strncmp(mentry->mnt_dir, "/storage/", 9) == 0) {
toUnmount.push_front(std::string(mentry->mnt_dir));
}
}
endmntent(fp);
for (auto path : toUnmount) {
SLOGW("Tearing down stale mount %s", path.c_str());
android::vold::ForceUnmount(path);
}
return 0;
}
unmountAll中主要卸载系统内部和外部设备,以提供最干净的设备环境。先卸载内部设备,在遍历外部设备,遍历卸载,之后再针对其他情况卸载而外干扰设备。
其中mInternalEmulated设备为EmulatedVolume类型,其继承了父类VolumeBase,其子类调用unmount方法,优先走父类VolumeBase的方法,其内容如下:
status_t VolumeBase::unmount() {
if (mState != State::kMounted) {
LOG(WARNING) << getId() << " unmount requires state mounted";
return -EBUSY;
}
// 设置状态,651,5
setState(State::kEjecting);
for (auto vol : mVolumes) {
if (vol->destroy()) {
LOG(WARNING) << getId() << " failed to destroy " << vol->getId()
<< " stacked above";
}
}
mVolumes.clear();
status_t res = doUnmount();
// 设置状态,发送 651,0
setState(State::kUnmounted);
return res;
}
父类的上述方法中,首先设置状态,其最终通过VM的方法,向Socket发送命令。其具体代码如下:
void VolumeBase::setState(State state) {
mState = state;
notifyEvent(ResponseCode::VolumeStateChanged, StringPrintf("%d", mState));
}
void VolumeBase::notifyEvent(int event) {
if (mSilent) return;
// 通过socket向MountService发送创建volume的命令(650)
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
getId().c_str(), false);
}
其次是调用子类的doUnmount方法,其对应到实现的子类自己的方法,这里的子类为EmulatedVolume,其对应的实现方法如下:
status_t EmulatedVolume::doUnmount() {
if (mFusePid > 0) {
kill(mFusePid, SIGTERM);
TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));
mFusePid = 0;
}
// 强制卸载fuse路径
ForceUnmount(mFuseDefault);
ForceUnmount(mFuseRead);
ForceUnmount(mFuseWrite);
rmdir(mFuseDefault.c_str());
rmdir(mFuseRead.c_str());
rmdir(mFuseWrite.c_str());
mFuseDefault.clear();
mFuseRead.clear();
mFuseWrite.clear();
return OK;
}
其内部具体的卸载方法就不一一细看了。最终,在再一次设置状态。到此内部设备就完成卸载,下面是外部设备的卸载过程。
status_t Disk::unmountAll() {
for (auto vol : mVolumes) {
vol->unmount();
}
return OK;
}
其通过遍历,调用所有Disk的unmount实现卸载操作,这里就不一一分析了。其具体内容可以参考GitYuan博客内容。
EmulatedVolume->create
EmulatedVolume设备的create方法,首先走父类的VolumeBase的create方法,如下:
status_t VolumeBase::create() {
CHECK(!mCreated);
mCreated = true;
status_t res = doCreate();
// 通知VolumeCreated事件,发送650
notifyEvent(ResponseCode::VolumeCreated,
StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str()));
// 设置为非挂载状态,发送651,0
setState(State::kUnmounted);
return res;
}
status_t VolumeBase::doCreate() {
return OK;
}
父类中检查状态后,直接调用doCreate方法,之后通过VM的Socket发送消息到MountService中。至此,VolumeManager便启动完成。
NM流程分析
NM初始化
Vold.main中初始化VM后,便初始化NM,如下:
// 同样是单利模式获取
NetlinkManager *NetlinkManager::Instance() {
if (!sInstance)
sInstance = new NetlinkManager();
return sInstance;
}
NetlinkManager::NetlinkManager() {
mBroadcaster = NULL;
}
同样是单例模式进行实例化对象,之后便启动start函数,如下:
int NetlinkManager::start() {
struct sockaddr_nl nladdr;
int sz = 64 * 1024;
int on = 1;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
// 记录当前进程的pid
nladdr.nl_pid = getpid();
nladdr.nl_groups = 0xffffffff;
// 创建 event socket
if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,
NETLINK_KOBJECT_UEVENT)) < 0) {
SLOGE("Unable to create uevent socket: %s", strerror(errno));
return -1;
}
// 设置 uevent 的 SO_RCVBUFFORCE 选项
if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
SLOGE("Unable to set uevent socket SO_RCVBUFFORCE option: %s", strerror(errno));
goto out;
}
// 设置 uevent 的 SO_PASSCRED 选项
if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
goto out;
}
// 绑定 uevent socket
if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
SLOGE("Unable to bind uevent socket: %s", strerror(errno));
goto out;
}
// 在 NetlinkManager 启动中创建 NetlinkHandler
mHandler = new NetlinkHandler(mSock);
if (mHandler->start()) {
SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
goto out;
}
return 0;
out:
close(mSock);
return -1;
}
其中内容比较多,最后我们发现其start时候,新建了一个NetlinkHandler负责通信。下面我们具体看看内部流程。
NH流程分析
NH初始化
NetlinkHandler为NetlinkManager内部的handler,负责通信操作,具体如下:
// NetlinkHandler继承于 NetlinkListener,NetlinkListener 继承于 SocketListener
// new NetlinkHandler(mSock) 中参数 mSock 是用于与 Kernel 进行通信的 socket 对象
// 由于这个继承关系,当 NetlinkHandler 初始化时会调用基类的初始化
NetlinkHandler::NetlinkHandler(int listenerSocket) :
NetlinkListener(listenerSocket) {
}
int NetlinkHandler::start() {
return this->startListener();
}
其中如注释所写,NetlinkHandler继承于 NetlinkListener,NetlinkListener 继承于 SocketListener,我们看一下其父类和爷爷类:
NetlinkListener::NetlinkListener(int socket) :
SocketListener(socket, false) {
mFormat = NETLINK_FORMAT_ASCII;
}
SocketListener::SocketListener(const char *socketName, bool listen) {
init(socketName, -1, listen, false);
}
// 通过层层继承调用至此(SocketListener <- NetlinkListener <- NetlinkHandler <- NetlinkManager)
void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {
mListen = listen;
mSocketName = socketName;
// 用于监听 Kernel 发送过程的 uevent 事件
mSock = socketFd;
mUseCmdNum = useCmdNum;
// 初始化同步锁
pthread_mutex_init(&mClientsLock, NULL);
// 创建 socket 通信的 client 端
mClients = new SocketClientCollection();
}
由此最终走到了SocketListener,其最终实现监听kernel发送过来的uevent事件,当然最终上层调用的开始监听也是在这里最终实现,后下面分析到这里会具体分析。
NH->start
NH初始化完成后,便进入start状态。代码跟踪如下:
int NetlinkHandler::start() {
return this->startListener();
}
然后调用父类的方法,这里只在爷爷类SocketListener发现其实现代码,如下:
int SocketListener::startListener(int backlog) {
if (!mSocketName && mSock == -1) {
SLOGE("Failed to start unbound listener");
errno = EINVAL;
return -1;
} else if (mSocketName) {
// 获取所对应的 socket 的句柄
if ((mSock = android_get_control_socket(mSocketName)) < 0) {
SLOGE("Obtaining file descriptor socket '%s' failed: %s",
mSocketName, strerror(errno));
return -1;
}
SLOGV("got mSock = %d for %s", mSock, mSocketName);
fcntl(mSock, F_SETFD, FD_CLOEXEC);
}
// 开始监听
if (mListen && listen(mSock, backlog) < 0) {
SLOGE("Unable to listen on socket (%s)", strerror(errno));
return -1;
} else if (!mListen)
// 创建 SocketClient 对象,并加入到 mClients 队列
mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
// 创建匿名管道
// 这是一个二元数组,mCtrlPipe[0]从管道读数据,mCtrlPipe[1]从管道写数据
if (pipe(mCtrlPipe)) {
SLOGE("pipe failed (%s)", strerror(errno));
return -1;
}
// 创建工作线程,线程运行函数threadStart
if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
SLOGE("pthread_create (%s)", strerror(errno));
return -1;
}
return 0;
}
在SocketListener开始监听中,其创建SocketClient对象,加入到mClients队列中,然后对二元数组管道进行读写,最终通过pthread_create另外开启一个线程进行监听。线程代码开启如下:
void *SocketListener::threadStart(void *obj) {
SocketListener *me = reinterpret_cast<SocketListener *>(obj);
//开始监听
me->runListener();
// 线程退出
pthread_exit(NULL);
return NULL;
}
void SocketListener::runListener() {
SocketClientCollection pendingList;
while(1) {
SocketClientCollection::iterator it;
fd_set read_fds;
int rc = 0;
int max = -1;
FD_ZERO(&read_fds);
if (mListen) {
max = mSock;
FD_SET(mSock, &read_fds);
}
FD_SET(mCtrlPipe[0], &read_fds);
if (mCtrlPipe[0] > max)
max = mCtrlPipe[0];
pthread_mutex_lock(&mClientsLock);
for (it = mClients->begin(); it != mClients->end(); ++it) {
// NB: calling out to an other object with mClientsLock held (safe)
int fd = (*it)->getSocket();
FD_SET(fd, &read_fds);
if (fd > max) {
max = fd;
}
}
pthread_mutex_unlock(&mClientsLock);
SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
if (errno == EINTR)
continue;
SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
sleep(1);
continue;
} else if (!rc)
continue;
if (FD_ISSET(mCtrlPipe[0], &read_fds)) {
char c = CtrlPipe_Shutdown;
TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
if (c == CtrlPipe_Shutdown) {
break;
}
continue;
}
if (mListen && FD_ISSET(mSock, &read_fds)) {
struct sockaddr addr;
socklen_t alen;
int c;
do {
alen = sizeof(addr);
c = accept(mSock, &addr, &alen);
SLOGV("%s got %d from accept", mSocketName, c);
} while (c < 0 && errno == EINTR);
if (c < 0) {
SLOGE("accept failed (%s)", strerror(errno));
sleep(1);
continue;
}
fcntl(c, F_SETFD, FD_CLOEXEC);
pthread_mutex_lock(&mClientsLock);
mClients->push_back(new SocketClient(c, true, mUseCmdNum));
pthread_mutex_unlock(&mClientsLock);
}
/* Add all active clients to the pending list first */
pendingList.clear();
pthread_mutex_lock(&mClientsLock);
for (it = mClients->begin(); it != mClients->end(); ++it) {
SocketClient* c = *it;
// NB: calling out to an other object with mClientsLock held (safe)
int fd = c->getSocket();
if (FD_ISSET(fd, &read_fds)) {
pendingList.push_back(c);
c->incRef();
}
}
pthread_mutex_unlock(&mClientsLock);
/* Process the pending list, since it is owned by the thread,
* there is no need to lock it */
while (!pendingList.empty()) {
/* Pop the first item from the list */
it = pendingList.begin();
SocketClient* c = *it;
pendingList.erase(it);
/* Process it, if false is returned, remove from list */
if (!onDataAvailable(c)) {
release(c, false);
}
c->decRef();
}
}
}
runListener中,通过死循环和加锁机制,不断读取上述二元数组内的数据,最终将读写到的数据通过方法onDataAvailable实现回调。
SL->onDataAvailable
这里我们不妨多看看其回调过程,其SocketListener本身没有实现这个方法,其直接子类NetlinkListener实现了,如下:
// 父类 SocketListener 回调此方法
bool NetlinkListener::onDataAvailable(SocketClient *cli)
{
int socket = cli->getSocket();
ssize_t count;
uid_t uid = -1;
bool require_group = true;
if (mFormat == NETLINK_FORMAT_BINARY_UNICAST) {
require_group = false;
}
// 多次尝试获取socket数据
count = TEMP_FAILURE_RETRY(uevent_kernel_recv(socket,
mBuffer, sizeof(mBuffer), require_group, &uid));
if (count < 0) {
if (uid > 0)
LOG_EVENT_INT(65537, uid);
SLOGE("recvmsg failed (%s)", strerror(errno));
return false;
}
NetlinkEvent *evt = new NetlinkEvent();
// 解析消息并封装成 NetlinkEvent
if (evt->decode(mBuffer, count, mFormat)) {
//事件处理
onEvent(evt);
} else if (mFormat != NETLINK_FORMAT_BINARY) {
// Don't complain if parseBinaryNetlinkMessage returns false. That can
// just mean that the buffer contained no messages we're interested in.
SLOGE("Error decoding NetlinkEvent");
}
delete evt;
return true;
}
NetlinkListener在得到父类传来的数据后,将数据进行封装NetlinkEvent。最终实现onEvent方法回调。这里的onEvent接口是在哪声明的呢?根据头文件我们发现,其是一个虚函数,需要子类进行实现,其声明如下:
-> /system/vold/NetlinkHandler.h
protected:
virtual void onEvent(NetlinkEvent *evt);
};
由于NetlinkHandler为NetlinkListener的子类,我们查看发现其具体实现如下:
// NetlinkListener 在 onDataAvailable 回调到此方法
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
VolumeManager *vm = VolumeManager::Instance();
const char *subsys = evt->getSubsystem();
if (!subsys) {
SLOGW("No subsystem found in netlink event");
return;
}
if (!strcmp(subsys, "block")) {
// 调用 VolumeManager 处理块设备
vm->handleBlockEvent(evt);
}
}
到这里,最终调用VolumeManager的handleBlockEvent实现处理。至此我们先告一段落,在后面存储系统工作流程中进行具体分析。
CommandListener流程分析
CL初始化
分析完程VM和NM的流程,下面便是CommandListener的实例化过程,如下:
CommandListener::CommandListener() :
FrameworkListener("vold", true) {
// 加入到 mCommands 队列
registerCmd(new DumpCmd());
registerCmd(new VolumeCmd());
registerCmd(new AsecCmd());
registerCmd(new ObbCmd());
registerCmd(new StorageCmd());
registerCmd(new FstrimCmd());
// MStar Android Patch Begin
registerCmd(new ISOCmd());
registerCmd(new SambaCmd());
// MStar Android Patch End
}
void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
// 加入到mCommands队列
mCommands->push_back(cmd);
}
CommandListener在实例化中,注册了各种设备的操作命令,例如DumpCmd,VolumCmd等,其父类FrameworkListener做了啥,我们查看一下:
FrameworkListener::FrameworkListener(const char *socketName) :
SocketListener(socketName, true, false) {
init(socketName, false);
}
void FrameworkListener::init(const char *socketName UNUSED, bool withSeq) {
mCommands = new FrameworkCommandCollection();
errorRate = 0;
mCommandCount = 0;
mWithSeq = withSeq;
mSkipToNextNullByte = false;
}
父类FrameworkListener初始化又新建了FrameworkCommandCollection,这是干嘛的呀?其通过typedef重声明定义如下:
typedef android::sysutils::List<FrameworkCommand *> FrameworkCommandCollection;
FrameworkCommand::FrameworkCommand(const char *cmd) {
mCommand = cmd;
}
关于DumpCmd,VolumCmd等几种cmd的介绍
在这里有必要介绍这几种DumpCmd,VolumCmd之间的关系,例如VolumCmd继承自VoldCommand继承自FrameworkCommand,FrameworkCommand有一个重要的方法runCommand实现如下:
int FrameworkCommand::runCommand(SocketClient *c UNUSED, int argc UNUSED,
char **argv UNUSED) {
SLOGW("Command %s has no run handler!", getCommand());
errno = ENOSYS;
return -1;
}
其中其没有必要的实现代码,我们继续通过继承关系向上追溯,发现其在CommandListener类中实现了具体代码,如下:
int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
dumpArgs(argc, argv, -1);
if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
return 0;
}
VolumeManager *vm = VolumeManager::Instance();
std::lock_guard<std::mutex> lock(vm->getLock());
std::string cmd(argv[1]);
if (cmd == "reset") {
return sendGenericOkFail(cli, vm->reset());
}
...
} else if (cmd == "mount" && argc > 2) {
// mount [volId] [flags] [user]
std::string id(argv[2]);
auto vol = vm->findVolume(id);
if (vol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
int mountFlags = (argc > 3) ? atoi(argv[3]) : 0;
userid_t mountUserId = (argc > 4) ? atoi(argv[4]) : -1;
vol->setMountFlags(mountFlags);
vol->setMountUserId(mountUserId);
// Mstar Android Patch Begin
CommandListener::VolumeCmd::finished = false;
CommandListener::VolumeCmd::res = 1;
std::thread mThread(&CommandListener::VolumeCmd::doMount,this,vol);
mThread.detach();
int i = 0;
// if mount time > 3S ,return fail
while(i<6 && CommandListener::VolumeCmd::finished == false) {
SLOGD("sleep 0.5s");
usleep(500000); //sleep 0.5s
i++;
}
if (mountFlags & android::vold::VolumeBase::MountFlags::kPrimary) {
vm->setPrimary(vol);
}
return sendGenericOkFail(cli, CommandListener::VolumeCmd::res);
// Mstar Android Patch End
} else if (cmd == "unmount" && argc > 2) {
// unmount [volId]
std::string id(argv[2]);
auto vol = vm->findVolume(id);
if (vol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
return sendGenericOkFail(cli, vol->unmount());
} else if (cmd == "format" && argc > 3) {
// format [volId] [fsType|auto]
std::string id(argv[2]);
std::string fsType(argv[3]);
auto vol = vm->findVolume(id);
if (vol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
return sendGenericOkFail(cli, vol->format(fsType));
}
...
return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
}
其中代码比较长,实现了各种针对Volume设备的各种操作,比如 挂载mount,格式化format等等。。。
CL->startListener
下面我们查看一下CommandListener的startListener方法,CommandListener没有实现此方法,但是其继承自FrameworkListener,FrameworkListener也没有实现,其又继承自SocketListener,最终由SocketListener实现,如下:
int SocketListener::startListener() {
return startListener(4);
}
int SocketListener::startListener(int backlog) {
if (!mSocketName && mSock == -1) {
SLOGE("Failed to start unbound listener");
errno = EINVAL;
return -1;
} else if (mSocketName) {
// 获取所对应的 socket 的句柄
if ((mSock = android_get_control_socket(mSocketName)) < 0) {
SLOGE("Obtaining file descriptor socket '%s' failed: %s",
mSocketName, strerror(errno));
return -1;
}
SLOGV("got mSock = %d for %s", mSock, mSocketName);
fcntl(mSock, F_SETFD, FD_CLOEXEC);
}
// 开始监听
if (mListen && listen(mSock, backlog) < 0) {
SLOGE("Unable to listen on socket (%s)", strerror(errno));
return -1;
} else if (!mListen)
// 创建 SocketClient 对象,并加入到 mClients 队列
mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
// 创建匿名管道
// 这是一个二元数组,mCtrlPipe[0]从管道读数据,mCtrlPipe[1]从管道写数据
if (pipe(mCtrlPipe)) {
SLOGE("pipe failed (%s)", strerror(errno));
return -1;
}
// 创建工作线程,线程运行函数threadStart
if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
SLOGE("pthread_create (%s)", strerror(errno));
return -1;
}
return 0;
}
至此,CommandListener的startListener就分析完毕。
CryptCommandListener流程分析
CLL初始化
CryptCommandListener的初始化流程和上述的CommandListener基本相似,这了我们粗略的看一下,有兴趣的读者自行查看:
CryptCommandListener::CryptCommandListener() :
FrameworkListener("cryptd", true) {
registerCmd(new CryptfsCmd());
}
CryptCommandListener::CryptfsCmd::CryptfsCmd() :
VoldCommand("cryptfs") {
}
通过额外的registerCmd注册CryptfsCmd命令,其具体的runCommand实现对应的操作,这里就不贴代码了。
CLL->startListener
当然CryptCommandListener也没有实现方法startListener,其最终还是通过SocketListener来实现的。具体参考上述流程。
相关类图
相信到此,如果你认真的看完第一遍并且是第一次看完的话,肯定是一头雾水,什么跟什么啊,这么多类,各种跳真的是烦。不急不急,这里我们引用一张类图还是有必要的,根据这张类图,在回过去看代码流程,你就能轻松的知道各个类之间的关系是如何的。
VM相关类图

VolumeManager作为Vold模块最重要的一个类,其承载了很多重要的工作流程,其中涉及到很多类,类中各种继承关系也很复杂,对着上述的类图就很容易理清各个类之间的关系了。
NM相关类图

NetLinkManager负责直接接收Kernel发来的uevent事件,其类之间的关系更是复杂,相信有这张类图后,在回溯到代码流程中就很清晰了。SocketListener为最重要的父类,其直接和Socket打交道,之后在分发到子类中处理,其大概可以分为两个部分,如下:
命令流程如下:
SocketListener发现Socket中有数据后,对数据进行封装(NetlinkEvent),通过dispatchCommand方法,将命令分别分发到指定的Cmd进行处理,各种Cmd的声明和处理流程在CommandListener中都有声明。其中各种Cmd相似的方法处理都由父类FrameworkCommand进行统一的抽象管理。
命令分发如下:
当然SocketListener得到数据后,还会通过onDataAvaiable进行回传,到Netlinkhandler中通过onEventh回传到VolumeManager进行处理。
其他
内容说明
本想一篇章写完Android存储系统中启动流程,其主要包括native层的Vold和Java层MountService。介于篇幅太长,下面会在独立篇章介绍MountService启动流程以及两者之间的通信过程,希望三篇博客可以结束这段痛苦的代码阅读之旅。
引用说明
此博客内容为作者实战编辑,并非随便的拷贝,内容参考学习GitYuan博客中内容,这里郑重说明一下。其链接见下面。