Vold工作机制

来源:互联网 发布:李杰灵的淘宝店 编辑:程序博客网 时间:2024/05/16 09:46

一、Vold工作机制

Vold是Volume Daemon的缩写,它是Android平台中外部存储系统的管控中心,是管理和控制Android平台外部存储设备的后台进程。其功能主要包括:SD卡的插拔事件检测、SD卡挂载、卸载、格式化等。

如上图所示,Vold中的NetlinkManager模块接收来自Linux Kernel的uevent消息。 
NetlinkManager将这些消息转发给VolumeManager模块。VolumeManager会对应做一些操作,然后把相关信息通过CommandListener发送给MountService。 
MountService根据收到的消息后,根据情况会利用CommandListener发送相关的处理命令给VolumeManager做进一步处理。 
CommandListener模块内部封装了一个Socket用于跨进程通信。它一方面接收来自MountService的控制命令,另一方面VolumeManager通过它将消息发送给MountService。

Tips: 
Netlink是Linux系统中用户空间进程和Kernel进行通信的一种机制,是基于Socket的异步通信机制。 
通过这种机制,位于用户空间的进程可以接收来自Kernel的一些信息,同时用户空间进程也可以利用Netlink向Kernel发送一些控制命令。

二、Vold进程启动过程 
Vold进程启动文件定义于system/vold/vold.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    writepid /dev/cpuset/foreground/tasks
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

被init进程启动后,将调用system/vold/main.cpp中的main函数:

int main(int argc, char** argv) {    .............    VolumeManager *vm;    CommandListener *cl;    .............    NetlinkManager *nm;    //解析vold.rc中定义的blkid和fsck相关的参数    parse_args(argc, argv);    ..............    // Quickly throw a CLOEXEC on the socket we just inherited from init    //这里的含义不是很明白    //对于fcntl(fd, F_SETFD, FD_CLOEXEC)函数    //FD_CLOEXEC表示当程序执行exec函数时, fd将被系统自动关闭, 不传递给exec创建的新进程,以免fd在子进程中仍然有效    //但在init进程中,是先fork出子进程,然后在进程中创建出socket,才执行exec函数,有必要使用fcntl函数么?    fcntl(android_get_control_socket("vold"), F_SETFD, FD_CLOEXEC);    fcntl(android_get_control_socket("cryptd"), F_SETFD, FD_CLOEXEC);    //创建文件夹/dev/block/vold    mkdir("/dev/block/vold", 0755);    .........    //创建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);    }    ...................    //创建CommandListener    cl = new CommandListener();    ............    vm->setBroadcaster((SocketListener *) cl);    nm->setBroadcaster((SocketListener *) cl);    //启动VolumeManager    if (vm->start()) {        PLOG(ERROR) << "Unable to start VolumeManager";        exit(1);    }    //根据配置文件初始化VolumeManager    if (process_config(vm)) {        PLOG(ERROR) << "Error reading configuration... continuing anyways";    }    //启动NetlinkManager    if (nm->start()) {        PLOG(ERROR) << "Unable to start NetlinkManager";        exit(1);    }    //与ueventd进程进行冷启动类似,此处通过往/sys/block目录下对应的uevent文件写"add\n"来触发内核发送uevent消息    coldboot("/sys/block");    //启动CommandListener    if (cl->startListener()) {        PLOG(ERROR) << "Unable to start CommandListener";        exit(1);    }    .......    // Eventually we'll become the monitoring thread    while(1) {        sleep(1000);    }    LOG(ERROR) << "Vold exiting";    exit(0);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

从上面的代码不难看出,Vold进程的main函数中,创建并启动其子模块VolumeManager、NetlinkManager和CommandListener后,就不再执行实际的工作了。 
以后Vold进程具体的工作就会交付给子模块进行处理。

三、Vold进程中各模块分析 
为了进一步了解整个Vold进程的主要工作流程,接下来我们分析一下其主要模块的工作流程。

1、NetlinkManager模块

1.1 NetlinkManager的创建和启动 
在Vold的main函数中,调用NetlinkManager::Instance创建出NetlinkManager:

NetlinkManager *NetlinkManager::Instance() {    if (!sInstance)        sInstance = new NetlinkManager();    return sInstance;}//mBroadcaster的类型为SocketListenerNetlinkManager::NetlinkManager() {    mBroadcaster = NULL;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

从上面的代码可以看到,NetlinkManager的创建比较简单。

在创建出NetlinkManager后,Vold调用了NetlinkManager的setBroadcaster函数:

void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
  • 1

依然言简意赅。 
这里唯一需要说明的是,Android这里的设计看起来比较很奇怪,虽然NetlinkManager设置了CommandListener对象,但它并没有通过CommandListener发送消息和接收命令。

配置好NetlinkManager后,Vold就调用了NetlinkManger的start函数:

int NetlinkManager::start() {    //以下定义并初始化socket的地址结构    struct sockaddr_nl nladdr;    int sz = 64 * 1024;    int on = 1;    memset(&nladdr, 0, sizeof(nladdr));    nladdr.nl_family = AF_NETLINK;    nladdr.nl_pid = getpid();    nladdr.nl_groups = 0xffffffff;    //创建PF_NETLINK地址簇的socket,NETLINK_KOBJECT_UEVENT表示该socket将接收内核的Uevent事件    if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,            NETLINK_KOBJECT_UEVENT)) < 0) {        SLOGE("Unable to create uevent socket: %s", strerror(errno));        return -1;    }    //setsockopt设置socket的选项,此处设置socket的接收缓冲区大小为64 * 1024    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;    }    //此处设置允许接收凭证相关的信息    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;    }    //将创建出的socket绑定到之前的地址上,此时socket可以收到Kernel的数据了    if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {        SLOGE("Unable to bind uevent socket: %s", strerror(errno));        goto out;    }    //创建并启动一个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;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

通过上面的代码不难看出,其实NetlinkManager启动后就是创建一个可以接收Kernel消息的socket,并以此socket构建并启动NetlinkHandler。 
可以预见NetlinkHandler将用来处理socket收到的信息。

1.2 NetlinkHandler

NetlinkHandler::NetlinkHandler(int listenerSocket) :                NetlinkListener(listenerSocket) {}
  • 1
  • 2
  • 3

NetlinkHandler初始化时,将与Kernel通信的socket描述符传入到父类NetlinkListener中。

NetlinkListener::NetlinkListener(int socket) :                          SocketListener(socket, false) {    mFormat = NETLINK_FORMAT_ASCII;}
  • 1
  • 2
  • 3
  • 4

NetlinkListener又进一步调用其父类SocketListener:

SocketListener::SocketListener(int socketFd, bool listen) {    init(NULL, socketFd, listen, false);}//socektName为null, listen和useCmdNum的值均为falsevoid SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {    mListen = listen;    mSocketName = socketName;    mSock = socketFd;    mUseCmdNum = useCmdNum;    //初始化一个mutex    pthread_mutex_init(&mClientsLock, NULL);    //SocketClientCollection用于存储与Socket服务端通信的客户端    mClients = new SocketClientCollection();}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

从上面的代码可以看出,NetlinkHandler对应的继承体系如下图所示:

创建完NetlinkHandler后,NetlinkManager调用了NetlinkHandler的start方法:

int NetlinkHandler::start() {    //根据继承体系,实际上调用了SocketListener的startListenr函数    return this->startListener();}int SocketListener::startListener() {    return startListener(4);}int SocketListener::startListener(int backlog) {    //前面代码已经提及,构造NetlinkHandler时,mSocketName为null,略去部分代码    ................    //mListen的参数也为false,表明mSocket并不是一个服务器端    if (mListen && listen(mSock, backlog) < 0) {        ..............    } else if (!mListen)        //利用mSocket构造SocketClient加入到mClients中        //这个SocketClient并不是真实客户端的代表,此处只是为了代码和操作的统一        mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));    //pipe系统调用将创建一个匿名管道,mCtrlPipe是一个int类型的二元数组    //其中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;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

至此,我们知道了NetlinkHandler启动后,创建了一个工作线程,用于接收和处理数据。现在进一步看看threadStart函数:

void *SocketListener::threadStart(void *obj) {    SocketListener *me = reinterpret_cast<SocketListener *>(obj);    //调用SocketListener的runListener函数    me->runListener();    pthread_exit(NULL);    return NULL;}void SocketListener::runListener() {    SocketClientCollection pendingList;    //无线循环,接收socket收到的数据    while(1) {        SocketClientCollection::iterator it;        fd_set read_fds;        int rc = 0;        int max = -1;        //将指定的文件描述符集清空,系统分配时默认是不清空的        FD_ZERO(&read_fds);        ..........        //在文件描述符集中增加一个新的描述符        FD_SET(mCtrlPipe[0], &read_fds);        //max将与select函数        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);        ...............        //监听是否有数据到来        if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {            ............        } else if (!rc)             continue;        //FD_ISSET用于测试指定的文件描述符是否在该集合中,前面已经加入了        if (FD_ISSET(mCtrlPipe[0], &read_fds)) {            char c = CtrlPipe_Shutdown;            TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));            //如果从管道中读出CtrlPipe_Shutdown,则退出工作线程            if (c == CtrlPipe_Shutdown) {                break;            }            continue;        }        //如果mSock是服务器端,进入这个分支,NetlinkHandler中的mSock并不是服务器端,此处仅作了解        if (mListen && FD_ISSET(mSock, &read_fds)) {            sockaddr_storage ss;            sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);            socklen_t alen;            int c;            do {                alen = sizeof(ss);                //服务器端接收客户端请求                c = accept(mSock, addrp, &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中            mClients->push_back(new SocketClient(c, true, mUseCmdNum));            pthread_mutex_unlock(&mClientsLock);        }        /* Add all active clients to the pending list first */        //这里引入了pendingList,主要是针对服务端提出的        //当mSocket是服务端的时候,上面的代码将会增加新的mClient,但在下一次循环之前,这些mClient还未被加入到read_fds中        pendingList.clear();        pthread_mutex_lock(&mClientsLock);        //由于NetlinkHandler中的mSocket不是服务端,因此mClients中实际上只有mSocket自己(前面startListener中加入的)        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)) {                //待处理的SocketClient加入到pendingList中                pendingList.push_back(c);                c->incRef();            }        }        pthread_mutex_unlock(&mClientsLock);        while (!pendingList.empty()) {            it = pendingList.begin();            SocketClient* c = *it;            pendingList.erase(it);            //调用子类的onDataAvailable函数处理收到的数据            if (!onDataAvailable(c)) {                //返回false时,需要关闭该SocketClient                //关闭SocketClient将直接操作mClients对象                release(c, false);            }            c->decRef();        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115

上面的代码看起来比较复杂,主要是因为考虑到了Socket作为服务端的情况。 
在NetlinkHandler中Socket仅作为客户端接收数据,因此在上面的代码中,其实就是利用子类的onDataAvailable函数处理收到的数据而已。

bool NetlinkListener::onDataAvailable(SocketClient *cli){    int socket = cli->getSocket();    ssize_t count;    uid_t uid = -1;    .................    //这里用uevent_kernel_recv函数,从socket中取出Uevent数据    count = TEMP_FAILURE_RETRY(uevent_kernel_recv(socket,            mBuffer, sizeof(mBuffer), require_group, &uid));    if (count < 0) {        ........        return false;    }    NetlinkEvent *evt = new NetlinkEvent();    //mFormat初始化时指定为NETLINK_FORMAT_ASCII    //此处将Uevent数据解码成NetlinkEvent,然后调用子类的onEvent进行处理    if (evt->decode(mBuffer, count, mFormat)) {        onEvent(evt);    } else if (mFormat != NETLINK_FORMAT_BINARY) {        ..........    }    delete evt;    return true;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

上面的代码比较简单,其实就是从socket中的字节流中取出Uevent事件,然后将这些事件解码成NetlinkEvent,然后利用子类的onEvent做进一步处理。

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")) {        //将NetlinkEvent递交给VolumeManager处理        vm->handleBlockEvent(evt);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

最后总结一下NetlinkManager模块的工作,如上图所示: 
1、NetlinkManager启动后,将创建出与Kernel通信的socket,并用此socket创建出NetlinkHandler。 
2、NetlinkHandler启动后,将创建出工作线程(其父类函数完成)。 
3、工作线程启动后,将负责监听socket是否有数据到来。 
4、当工作线程监听到数据到来后,负责将数据递交给NetlinkHandler。 
5、NetlinkHandler负责从socket中的数据中解析出Uevent,并进一步解码成NetlinkEvent,以递交给VolumeManager。

2、VolumeManager模块

2.1 VolumeManager的创建和启动 
在Vold的main函数中,调用VolumeManager的instance函数创建VolumeManager:

VolumeManager *VolumeManager::Instance() {    if (!sInstance)        sInstance = new VolumeManager();    return sInstance;}VolumeManager::VolumeManager() {    mDebug = false;    mActiveContainers = new AsecIdCollection();    mBroadcaster = NULL;    mUmsSharingCount = 0;    mSavedDirtyRatio = -1;    // set dirty ratio to 0 when UMS is active    mUmsDirtyRatio = 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

容易看出VolumeManager也是单例模式创建的。 
接着,Vold进程利用VolumeManager的setBroadcaster函数,将Commandlistener对象赋予VolumeManager。

void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
  • 1

完成VolumeManager的创建后,Vold进程调用start函数,启动VolumeManager:

int VolumeManager::start() {    // Always start from a clean state 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);    mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>(            new android::vold::EmulatedVolume("/data/media"));    mInternalEmulated->create();    return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

从上面的代码可以看出,VolumeManager启动后就干了两件事: 
1、清楚所有已挂载的设备。正如注释所说的,通过这种方式可以让VolumeManager每次都从一个确定的“干净”的状态启动,避免之前出现Vold进程出现过crash。 
看看unmountAll函数:

int VolumeManager::unmountAll() {    std::lock_guard<std::mutex> lock(mLock);    // First, try gracefully unmounting all known devices    if (mInternalEmulated != nullptr) {        mInternalEmulated->unmount();    }    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;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

unmountAll的内容比较简单,同时注释清晰,此处不再赘述。

2、创建一个内部的挂载设备。 
mInternalEmulated是一个VolumeBase类型的对象,我们看看其create函数:

status_t VolumeBase::create() {    CHECK(!mCreated);    mCreated = true;    //doCreate进行实际的创建    status_t res = doCreate();    //通过CommandListener通知框架中的MountService    notifyEvent(ResponseCode::VolumeCreated,            StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str()));    setState(State::kUnmounted);    return res;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2.2 配置VolumeManager 
当Vold创建并启动完VolumeManager后,就调用process_config函数对VolumeManager进行配置:

static int process_config(VolumeManager *vm) {    //读取默认的fstab文件    std::string path(android::vold::DefaultFstabPath());    fstab = fs_mgr_read_fstab(path.c_str());    ...........    /* Loop through entries looking for ones that vold manages */    ........    for (int i = 0; i < fstab->num_entries; i++) {        //是否能被被vold管理        if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {            //根据fstab文件中设备的信息构造sysPattern、nickname和flags            ...........            //            vm->addDiskSource(std::shared_ptr<VolumeManager::DiskSource>(                    new VolumeManager::DiskSource(sysPattern, nickname, flags)));        }    }    ................}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

结合代码,我们知道process_config其实就是解析fstab文件,然后设置一些存储设备的挂载点。

2.3 NetlinkManager与VolumeManager之间的交互 
在前面介绍NetlinkManager时,我们知道当NetlinkManager收到Kernel的事件后,将利用NetlinkHandler通知VolumeManager:

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")) {        vm->handleBlockEvent(evt);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

我们看看VolumeManager的handleBlockeEvent:

void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {    ..............    //取出主设备号和次设备号    int major = atoi(evt->findParam("MAJOR"));    int minor = atoi(evt->findParam("MINOR"));    dev_t device = makedev(major, minor);    switch (evt->getAction()) {    case NetlinkEvent::Action::kAdd: {        //创建新的disk        .........        auto disk = new android::vold::Disk(eventPath, device,                source->getNickname(), flags);        disk->create();        mDisks.push_back(std::shared_ptr<android::vold::Disk>(disk));        break;    }    case NetlinkEvent::Action::kChange: {        ..........        //改变对应的disk信息        for (auto disk : mDisks) {            if (disk->getDevice() == device) {                disk->readMetadata();                disk->readPartitions();            }        }        break;    }    case NetlinkEvent::Action::kRemove: {        //移除对应的disk        auto i = mDisks.begin();        while (i != mDisks.end()) {            if ((*i)->getDevice() == device) {                (*i)->destroy();                i = mDisks.erase(i);            } else {                ++i;            }        }        break;    }    default: {        LOG(WARNING) << "Unexpected block event action " << (int) evt->getAction();        break;    }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

至此VolumeManager的主要工作介绍完毕,从上面的代码可以看出VolumeManager使用Disk对象来抽象实际的存储设备。 
 
我们现在可以结合上图总结一下VolumeManager的工作流程: 
1、存储设备发生变化(如热插拔等),将导致Linux Kernel发出Uevent消息给NetlinkManager。 
2、NetlinkManager将事件通知给VolumeManager。 
3、VolumeManager根据事件的内容,判断是设备的变化情况,然后操作对应的Disk对象。例如新增存储设备,就利用事件中的内容创建出新的Disk(创建Disk时,就会进一步读取分区信息,创建出Volume对象,此处不再细分);设备被移除了,VolumeManager就负责移除对应的Disk。

到目前为止,我们分析的流程都停留在Vold进程中,并没有与Android框架发生实际的交互。为了引出交互的实际流程,我们需要先分析一下Vold进程与框架交互的桥梁,即CommandListener。

3、CommandListener

3.1 CommandListener的创建 
Vold进程在main函数中创建出了CommandListener,然后调用了CommandListener的startListener函数。 
我们先看看CommandListener的构造函数:

class CommandListener : public FrameworkListener {........}
  • 1
  • 2
  • 3

从定义来看CommandListener继承于FrameworkListener。

CommandListener::CommandListener() :                 FrameworkListener("vold", true) {    //注册CommandListener支持的命令    registerCmd(new DumpCmd());    registerCmd(new VolumeCmd());    registerCmd(new AsecCmd());    registerCmd(new ObbCmd());    registerCmd(new StorageCmd());    registerCmd(new FstrimCmd());    registerCmd(new AppFuseCmd());}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在CommandListener的构造函数中,调用了父类的构造函数,同时利用其父类的registerCmd函数创建并注册了一些Cmd对象。

我们看看FrameworkListener:

FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :                            SocketListener(socketName, true, withSeq) {    init(socketName, withSeq);}void FrameworkListener::init(const char *socketName UNUSED, bool withSeq) {    mCommands = new FrameworkCommandCollection();    errorRate = 0;    mCommandCount = 0;    mWithSeq = withSeq;}void FrameworkListener::registerCmd(FrameworkCommand *cmd) {    //将注册的Command保存到列表中    mCommands->push_back(cmd);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

根据前面的代码,我们可以得到上图的继承关系。 
可以看到与之前分析NetlinkManager一样,CommandListener最终继承自SocketListener。不过与NetlinkManager不同的是,CommandListener传入到SocketListener的mListen参数为true,这意味着CommandListener中的socket将作为服务端存在。 
从FrameworkListener的registerCmd函数来看,FrameworkListener仅仅是保存了新创建的Cmd对象。这里采用了设计模式中的Command模式,每个命令的处理函数都是runCommand。

3.2 CommandListener启动 
当Vold进程创建出CommandListener后,同样调用了CommandListener的startListener函数。 
根据继承关系,我们知道最终将会调用到SocketListener的startListener函数。

在分析NetlinkManager时,我们已经分析过SocketListener的startListener函数。在startListener函数中将启动一个工作线程,以监听对应socket的数据。 
此处CommandListener监听的是init进程创建出Vold进程后,Vold进程创建的名为”vold”的socket,并且该socket是作为服务端存在的。当服务端收到注册请求后,将生成对应的SocketClient对象。然后,工作线程就可以监听SocketClient是否有数据到来。

“vold”的客户端是MountService。与之前分析的一样,当工作线程收到客户端数据时,将调用子类的onDataAvailable函数进行处理。 
此时SocketListener的子类是FrameworkListener:

bool FrameworkListener::onDataAvailable(SocketClient *c) {    char buffer[CMD_BUF_SIZE];    int len;    //将socket的数据读入到buffer中    len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));    ............    for (i = 0; i < len; i++) {        if (buffer[i] == '\0') {            /* IMPORTANT: dispatchCommand() expects a zero-terminated string */            dispatchCommand(c, buffer + offset);            offset = i + 1;        }    }    return true;}//解析并分发Commandvoid FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {    //从data中解析出Command的参数    ............    for (i = mCommands->begin(); i != mCommands->end(); ++i) {        FrameworkCommand *c = *i;        //根据参数判断是否能被CommandListener中注册的命令处理        if (!strcmp(argv[0], c->getCommand())) {            //调用对应Command的runCommand函数            if (c->runCommand(cli, argc, argv)) {                SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));            }            goto out;        }    }    ............}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

以DumpCommand举例,看看runCommand函数:

int CommandListener::DumpCmd::runCommand(SocketClient *cli,                                         int /*argc*/, char ** /*argv*/) {    cli->sendMsg(0, "Dumping loop status", false);    if (Loop::dumpState(cli)) {        cli->sendMsg(ResponseCode::CommandOkay, "Loop dump failed", true);    }    cli->sendMsg(0, "Dumping DM status", false);    if (Devmapper::dumpState(cli)) {        cli->sendMsg(ResponseCode::CommandOkay, "Devmapper dump failed", true);    }    cli->sendMsg(0, "Dumping mounted filesystems", false);    FILE *fp = fopen("/proc/mounts", "r");    if (fp) {        char line[1024];        while (fgets(line, sizeof(line), fp)) {            line[strlen(line)-1] = '\0';            cli->sendMsg(0, line, false);;        }        fclose(fp);    }    cli->sendMsg(ResponseCode::CommandOkay, "dump complete", false);    return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

从上面的代码容易看出,DumpCmd执行相应的操作后,都是通过SocketClient的sendMsg发送结果。在SocketClient的底层,就是靠”vold” socket将数据返回给MountService。

现在我们总结一下CommandListener涉及的工作流程: 

如上图所示: 
1、init进程启动Vold进程时,根据vold.rc创建了”vold” socket,”vold” socket作为server端存在于Vold进程中。 
2、在Vold进程的main函数中,创建出了CommandListener(部分工作尤其父类完成);CommandListener创建一些Cmd。 
3、调用CommandListener的startListener函数,尤其父类SocketListener中创建出实际的工作线程,监听”vold” socket是否有请求到来。 
4、框架中的MountService启动后,间接利用socket与”vold”通信(通过NativeDaemonConnector封装)。初始时,将向”vold”发送connect请求。 
5、当工作线程监听到”vold”有请求到来后,利用accept函数创建出与MountService端通信的server端,即上图的s。接下来,工作线程开始监听s上是否有数据到来。 
6、当工作线程监听到s有数据到来后,将数据递交给CommandListener(实际是FrameworkListener处理)。 
7、CommandListener根据数据的类型,调用对应的Command进行处理。 
8、实际的Cmd根据参数进行实际的操作,然后将运行结果递交给s,s再将数据通过c递交给MountService。

接下来,我们看看运行在框架层中的MountService。

4 MountService 
有些应用程序需要检测外部存储卡的插入/拔出事件,这些事件由MountService通过Intent广播发送。例如外部存储卡插入后,MountService就会发送Intent.ACTION_MEDIA_MOUNTED消息。 
MountService由SystemServer启动,我们简单看看它的构造函数:

class MountService extends IMountService.Stub        implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {    public MountService(Context context) {        .........        //与NetworkManagementService一样,MountService也是靠NativeDaemonConnector与底层守护进程通信        //第一个参数传入回调接口,第二参数指明通信的server端        mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25, null);        .........        //创建一个线程与server socket通信        mConnectorThread = new Thread(mConnector, VOLD_TAG);        ..........    }    private void start() {        //NativeDaemonConnector是一个runnable对象,线程启动后将调用其run方法        //在介绍Android7.0 数据业务长连接拨号过程时,我们提到过NetworkManagementService中NativeDaemonConnector连接netd的过程        //MountService中的过程是一致的,只是这次连接的是vold        mConnectorThread.start();        .........    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

从MountService的启动情况来看,对于Vold进程而言,我们需要关注的就是MountService利用NativeDaemonConnector建立与”vold”的连接,使得Vold进程能够与Android框架进行沟通了。

Android中的Service启动后,基本上都是靠事件驱动的,因此无法按一个有序的流程进行全面的介绍,比较好的方式还是了解整体架构后,分析一个具体的示例。 
因此接下来我们以设备插入为例,分析一下MountService的主要工作。 
根据上文的分析,我们知道当设备插入后,Kernel发送消息是的NetlinkManager能够收到Uevent。然后,NetlinkManager将会构造出NetlinkEvent,并通知VolumeManager进行处理。 
在VolumeManager中,利用handleBlockEvent根据事件的类型进行相应的处理,我们截取设备添加时的处理代码:

void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {    ........    switch (evt->getAction()) {    case NetlinkEvent::Action::kAdd: {        //前文已述,DiskSource是配置VolumeManager时,读取fstab文件得到的        for (auto source : mDiskSources) {            if (source->matches(eventPath)) {                .......                //创建设备对象                auto disk = new android::vold::Disk(eventPath, device,                        source->getNickname(), flags);                disk->create();                mDisks.push_back(std::shared_ptr<android::vold::Disk>(disk));                break;            }        }        break;    }    ........}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

我们看看Disk的代码:

Disk::Disk(const std::string& eventPath, dev_t device,        const std::string& nickname, int flags) :        mDevice(device), mSize(-1), mNickname(nickname), mFlags(flags), mCreated(                false), mJustPartitioned(false) {    mId = StringPrintf("disk:%u,%u", major(device), minor(device));    mEventPath = eventPath;    mSysPath = StringPrintf("/sys/%s", eventPath.c_str());    mDevPath = StringPrintf("/dev/block/vold/%s", mId.c_str());    //在CreateDeviceNode中,利用mknod创建设备节点    CreateDeviceNode(mDevPath, mDevice);}status_t Disk::create() {    CHECK(!mCreated);    mCreated = true;    //注意这里的notifyEvent    notifyEvent(ResponseCode::DiskCreated, StringPrintf("%d", mFlags));    readMetadata();    readPartitions();    return OK;}status_t Disk::readMetadata() {    //读取设备信息    ...........    notifyEvent(ResponseCode::DiskSizeChanged, StringPrintf("%" PRIu64, mSize));    notifyEvent(ResponseCode::DiskLabelChanged, mLabel);    notifyEvent(ResponseCode::DiskSysPathChanged, mSysPath);    return OK;}status_t Disk::readPartitions() {    //读取分取信息    .............    Table table = Table::kUnknown;    bool foundParts = false;    for (auto line : output) {        ..........        if (!strcmp(token, "DISK")) {            const char* type = strtok(nullptr, kSgdiskToken);            if (!strcmp(type, "mbr")) {                table = Table::kMbr;            } else if (!strcmp(type, "gpt")) {                    table = Table::kGpt;            }        } else if (!strcmp(token, "PART")) {            .........            dev_t partDevice = makedev(major(mDevice), minor(mDevice) + i);            if (table == Table::kMbr) {                ........                createPublicVolume(partDevice);                ........            } else if (table == Table::kGpt) {                const char* typeGuid = strtok(nullptr, kSgdiskToken);                const char* partGuid = strtok(nullptr, kSgdiskToken);                if (!strcasecmp(typeGuid, kGptBasicData)) {                    //关注一下这个                    createPublicVolume(partDevice);                } else if (!strcasecmp(typeGuid, kGptAndroidExpand)) {                    createPrivateVolume(partDevice, partGuid);                }            }        }    }    ...............}void Disk::createPublicVolume(dev_t device) {    auto vol = std::shared_ptr<VolumeBase>(new PublicVolume(device));    if (mJustPartitioned) {        LOG(DEBUG) << "Device just partitioned; silently formatting";        vol->setSilent(true);        vol->create();        vol->format("auto");        vol->destroy();        vol->setSilent(false);    }    mVolumes.push_back(vol);    vol->setDiskId(getId());    vol->create();}status_t VolumeBase::create() {    CHECK(!mCreated);    mCreated = true;    //子类实现    status_t res = doCreate();    notifyEvent(ResponseCode::VolumeCreated,            StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str()));    setState(State::kUnmounted);    return res;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95

上面列举了创建Disk和Volume的代码,注意到进行实际工作后,均会调用notifyEvent函数。

我们接下来就看看notifyEvent函数的用途:

void Disk::notifyEvent(int event, const std::string& value) {    //还记得么?VolumeManager初始时指定其Broadcaster为CommandListener    VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,            StringPrintf("%s %s", getId().c_str(), value.c_str()).c_str(), false);}
  • 1
  • 2
  • 3
  • 4
  • 5

现在我们看看CommandListener的sendBroadcast函数(实际定义于父类的父类SocketListener中):

void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {    SocketClientCollection safeList;    /* Add all active clients to the safe list first */    //这应该算一种好习惯吧    safeList.clear();    pthread_mutex_lock(&mClientsLock);    SocketClientCollection::iterator i;    //注意将SocketListener当前所有的SocketClient均加入到safeList,所以函数名才叫sendBroadcast    //当然,对于Vold进程而言,它的client只有MountService对应的socket    for (i = mClients->begin(); i != mClients->end(); ++i) {        SocketClient* c = *i;        c->incRef();        safeList.push_back(c);    }    pthread_mutex_unlock(&mClientsLock);    while (!safeList.empty()) {        /* Pop the first item from the list */        i = safeList.begin();        SocketClient* c = *i;        safeList.erase(i);        // broadcasts are unsolicited and should not include a cmd number        //前面提到过SocketClient的sendMsg底层就是靠socket通信方式        if (c->sendMsg(code, msg, addErrno, false)) {            SLOGW("Error sending broadcast (%s)", strerror(errno));        }        c->decRef();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

从上面的代码,我们知道将由MountService来处理socket中的数据。 
前面我们已经知道,MountService创建NativeDaemonConnector来封装socket相关的操作,在创建NativeDaemonConnector时需要传入回调接口。当NativeDaemonConnector收到数据后,通过回调接口进行通知。

MountService继承了INativeDaemonConnectorCallbacks,我们看看它的onEvent函数:

@Overridepublic boolean onEvent(int code, String raw, String[] cooked) {    synchronized (mLock) {        return onEventLocked(code, raw, cooked);    }}private boolean onEventLocked(int code, String raw, String[] cooked) {    switch (code) {        case VoldResponseCode.DISK_CREATED: {            if (cooked.length != 3) break;            final String id = cooked[1];            int flags = Integer.parseInt(cooked[2]);            if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)                    || mForceAdoptable) {                flags |= DiskInfo.FLAG_ADOPTABLE;            }            mDisks.put(id, new DiskInfo(id, flags));            break;        }        ...........        case VoldResponseCode.VOLUME_CREATED: {            final String id = cooked[1];            final int type = Integer.parseInt(cooked[2]);            final String diskId = TextUtils.nullIfEmpty(cooked[3]);            final String partGuid = TextUtils.nullIfEmpty(cooked[4]);            final DiskInfo disk = mDisks.get(diskId);            final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid);            mVolumes.put(id, vol);            onVolumeCreatedLocked(vol);            break;        }        ...........    }    return true;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

从上面的代码可以看出,MountService收到DISK_CREATED消息后,仅会记录DiskInfo;收到VOLUME_CREATED消息后,还需要调用onVolumeCreatedLocked函数作进一步地处理。

private void onVolumeCreatedLocked(VolumeInfo vol) {    .........    if (vol.type == VolumeInfo.TYPE_EMULATED) {        .......    } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {        //以public type为例        mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();    } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {        ........    } else {        .......    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
class MountServiceHandler extends Handler {    public MountServiceHandler(Looper looper) {        super(looper);    }    @Override    public void handleMessage(Message msg) {        switch (msg.what) {            ........            final VolumeInfo vol = (VolumeInfo) msg.obj;            if (isMountDisallowed(vol)) {                Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");                break;            }            try {                //利用NativeDaemonConnector中socket将消息发送给CommandListenr                mConnector.execute("volume", "mount", vol.id, vol.mountFlags,                        vol.mountUserId);            } catch (NativeDaemonConnectorException ignored) {            }            break;            ........        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

注意消息重新发回到了CommandListener,根据前面的代码的分析我们知道,在FrameworkListener中将利用dispatchCommand根据类型,调用不同Command的runCommand方法,此处将调用volumeCommand的运行方法:

int CommandListener::VolumeCmd::runCommand(SocketClient *cli,                                      int argc, char **argv) {    //解析参数    .........    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);        //调用volumebase的mount方法,实际调用其子类的doMount        int res = vol->mount();        if (mountFlags & android::vold::VolumeBase::MountFlags::kPrimary) {            vm->setPrimary(vol);        }        //执行成功后,将返回消息给MountService        return sendGenericOkFail(cli, res);    }    .........}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

我们跟进一下VolumeBase的mount函数:

void VolumeBase::setState(State state) {    mState = state;    //再次通知到MountService    notifyEvent(ResponseCode::VolumeStateChanged, StringPrintf("%d", mState));}
  • 1
  • 2
  • 3
  • 4
  • 5

在MountService的onEvent函数中,将再次处理VolumeStateChanged事件,实际上就是发送ACTION_MEDIA_MOUNTED广播。

上述的整个过程略去了大量的细节,但看起来仍很琐碎。不过,若是理解了前面介绍CommandListener时,分析的整个通信架构,那么这些流程的大致方向是比较好理解的。

结束语 
Vold进程的主要内容基本上就是这些,在实际的工作中大多数人应该不会接触到这个进程。但是它整个架构是非常具有参考意义的,很清晰地阐释了Android中的框架层、Native层以及Kernel是如何交互的。Android中还有许多重要部分也采用了类似的架构,比较明显的就是netd。因此,以Vold入手进行分析,重在理解这种通信架构。

原创粉丝点击