android vold流程分析

本来自己转载的两篇vold的文章已经分析的很详细了,有图有文字,但还是想把自己分析的见解写下来,毕竟自己的思路才是最清晰的,所以写了笔记供以后参考。

先把整体路程图画出来,再参考分析:

android vold流程分析_第1张图片

从vold的main函数说起:

nm->setBroadcaster((SocketListener *) cl) -> 
 void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
简单赋值,后续再分析该过程。


接着main中nm->start()的调用过程:

NetlinkManager::start() -> mHandler = new NetlinkHandler(mSock); mHandler->start() ->

     37 int NetlinkHandler::start() {
     38     return this->startListener();
     39 }

NetlinkHandler类:
    class NetlinkHandler: public NetlinkListener {

    public:
        NetlinkHandler(int listenerSocket);
        virtual ~NetlinkHandler();

        int start(void);
        int stop(void);

    protected:
        virtual void onEvent(NetlinkEvent *evt);
    };


NetlinkHandler继承了NetlinkListener,而NetlinkListener又继承了SocketListener,所以调用的是基类的startListener,在system/core/libsysutils/src/SocketListener.cpp中:
    int SocketListener::startListener() {

        if (!mSocketName && mSock == -1) {                                                                
        SLOGE("Failed to start unbound listener");
        errno = EINVAL;
        return -1;
        } else if (mSocketName) {
        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);
        }   

        if (mListen && listen(mSock, 4) < 0) {
        SLOGE("Unable to listen on socket (%s)", strerror(errno));
        return -1;
        } else if (!mListen)
        mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));

        if (pipe(mCtrlPipe)) {
        SLOGE("pipe failed (%s)", strerror(errno));
        return -1;
        }   

        if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
        SLOGE("pthread_create (%s)", strerror(errno));
        return -1;
        }   

        return 0;
    }


这里会pthread_create创建线程来监听事件,在线程中:
    void SocketListener::runListener() {
        while(1) {
            ...................

            if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {

            .....................

            if (!onDataAvailable(c) && mListen) {

        
            .........................

    }


这是一个死循环,监听到数据后调用onDataAvailable,这样会调用其派生类的onDataAvailable来处理数据。实际上SocketListener会监听底层内核事件和上层framework的事件,反正系统中的socket通讯都会经过它,比如在init.rc中socket创建的通讯等。在这里vold的分析中,我们关注的是SocketListener监听的UMS和SD卡的底层uevent事件和framework层MountService事件。
底层事件处理会被NetlinkListener.cpp中的onDataAvailable继承,framework事件处理会被FrameworkListener.cpp的onDataAvailable继承。所以先从插入SD卡后底层事件上报开始,看NetlinkListener.cpp中的onDataAvailable:
    bool NetlinkListener::onDataAvailable(SocketClient *cli)
    {
        int socket = cli->getSocket();
        ssize_t count;
        uid_t uid = -1;

        count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv(
                                       socket, mBuffer, sizeof(mBuffer), &uid));
        if (count < 0) {
        if (uid > 0)
            LOG_EVENT_INT(65537, uid);
        SLOGE("recvmsg failed (%s)", strerror(errno));
        return false;
        }   

        NetlinkEvent *evt = new NetlinkEvent();                                                                               
        if (!evt->decode(mBuffer, count, mFormat)) {
        SLOGE("Error decoding NetlinkEvent");
        } else {
        onEvent(evt);
        }   

        delete evt;
        return true;
    }


这里当插入SD卡时候mBuffer中的数据格式如下:
E/NetlinkEvent( 1282): sclu add@/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa
E/NetlinkEvent( 1281): sclu add@/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa
E/NetlinkEvent( 1281): sclu ACTION=add
E/NetlinkEvent( 1281): sclu DEVPATH=/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa
E/NetlinkEvent( 1281): sclu SUBSYSTEM=mmc
E/NetlinkEvent( 1281): sclu MMC_TYPE=SD
E/NetlinkEvent( 1281): sclu MMC_NAME=SU08G
E/NetlinkEvent( 1281): sclu MODALIAS=mmc:block
E/NetlinkEvent( 1281): sclu SEQNUM=1244
E/NetlinkEvent( 1282): sclu ACTION=add
E/NetlinkEvent( 1282): sclu DEVPATH=/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa
E/NetlinkEvent( 1282): sclu SUBSYSTEM=mmc
E/NetlinkEvent( 1282): sclu MMC_TYPE=SD
E/NetlinkEvent( 1282): sclu MMC_NAME=SU08G
E/NetlinkEvent( 1282): sclu MODALIAS=mmc:block
E/NetlinkEvent( 1282): sclu SEQNUM=1244
E/NetlinkEvent( 1282): sclu add@/devices/virtual/bdi/179:0
E/NetlinkEvent( 1282): sclu ACTION=add
E/NetlinkEvent( 1281): sclu add@/devices/virtual/bdi/179:0
E/NetlinkEvent( 1282): sclu DEVPATH=/devices/virtual/bdi/179:0
E/NetlinkEvent( 1281): sclu ACTION=add
E/NetlinkEvent( 1282): sclu SUBSYSTEM=bdi
E/NetlinkEvent( 1281): sclu DEVPATH=/devices/virtual/bdi/179:0
E/NetlinkEvent( 1282): sclu SEQNUM=1245
E/NetlinkEvent( 1281): sclu SUBSYSTEM=bdi
E/NetlinkEvent( 1281): sclu SEQNUM=1245
E/NetlinkEvent( 1282): sclu add@/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0
E/NetlinkEvent( 1282): sclu ACTION=add
E/NetlinkEvent( 1282): sclu DEVPATH=/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0
E/NetlinkEvent( 1282): sclu SUBSYSTEM=block
E/NetlinkEvent( 1282): sclu MAJOR=179
E/NetlinkEvent( 1282): sclu MINOR=0
E/NetlinkEvent( 1282): sclu DEVNAME=mmcblk0
E/NetlinkEvent( 1282): sclu DEVTYPE=disk
E/NetlinkEvent( 1282): sclu NPARTS=1
E/NetlinkEvent( 1282): sclu SEQNUM=1246
E/NetlinkEvent( 1281): sclu add@/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0
E/NetlinkEvent( 1281): sclu ACTION=add
E/NetlinkEvent( 1281): sclu DEVPATH=/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0
E/NetlinkEvent( 1281): sclu SUBSYSTEM=block
E/NetlinkEvent( 1281): sclu MAJOR=179
E/NetlinkEvent( 1281): sclu MINOR=0
E/NetlinkEvent( 1281): sclu DEVNAME=mmcblk0
E/NetlinkEvent( 1282): sclu add@/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0/mmcblk0p1
E/NetlinkEvent( 1281): sclu DEVTYPE=disk
E/NetlinkEvent( 1281): sclu NPARTS=1
E/NetlinkEvent( 1281): sclu SEQNUM=1246
D/Vold    ( 1281): Volume SDCARD state changing 0 (No-Media) -> 2 (Pending)
E/NetlinkEvent( 1282): sclu ACTION=add
E/NetlinkEvent( 1282): sclu DEVPATH=/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0/mmcblk0p1
E/NetlinkEvent( 1282): sclu SUBSYSTEM=block
E/NetlinkEvent( 1282): sclu MAJOR=179
E/NetlinkEvent( 1282): sclu MINOR=1
E/NetlinkEvent( 1282): sclu DEVNAME=mmcblk0p1
E/NetlinkEvent( 1282): sclu DEVTYPE=partition
E/NetlinkEvent( 1282): sclu PARTN=1
E/NetlinkEvent( 1282): sclu SEQNUM=1247
E/NetlinkEvent( 1281): sclu add@/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0/mmcblk0p1
E/NetlinkEvent( 1281): sclu ACTION=add
E/NetlinkEvent( 1281): sclu DEVPATH=/devices/platform/imap-mmc.1/mmc_host/mmc0/mmc0:aaaa/block/mmcblk0/mmcblk0p1
E/NetlinkEvent( 1281): sclu SUBSYSTEM=block
E/NetlinkEvent( 1281): sclu MAJOR=179
E/NetlinkEvent( 1281): sclu MINOR=1
E/NetlinkEvent( 1281): sclu DEVNAME=mmcblk0p1
E/NetlinkEvent( 1281): sclu DEVTYPE=partition
E/NetlinkEvent( 1281): sclu PARTN=1
E/NetlinkEvent( 1281): sclu SEQNUM=1247





decode完数据后调用派生类NetlinkHandler的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")) {
        vm->handleBlockEvent(evt);
        }   
    }


调用了VolumeManager的handleBlockEvent:
    void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {                                                           
        const char *devpath = evt->findParam("DEVPATH");

        /* Lookup a volume to handle this device */
        VolumeCollection::iterator it;
        bool hit = false;
        for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
        if (!(*it)->handleBlockEvent(evt)) {
    #ifdef NETLINK_DEBUG
            SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
    #endif
            hit = true;
            break;
        }    
        }    

        if (!hit) {
    #ifdef NETLINK_DEBUG
        SLOGW("No volumes handled block event for '%s'", devpath);
    #endif
        }    
    }


这里会遍历mVolumes容器,mVolumes的成员是在前面解析/etc/vold.fstab配置文件时候调用addVolume函数加进来的:
process_config -> dv = new DirectVolume(vm, label, mount_point, -1) -> vm->addVolume(dv)
int VolumeManager::addVolume(Volume *v) {                                                                                    
    mVolumes->push_back(v);
    return 0;
}


实际是DirectVolume类型,所以调用的是DirectVolume类的handleBlockEvent:
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {
    const char *dp = evt->findParam("DEVPATH");

    PathCollection::iterator  it;
    char *usbneedle = strstr(dp,"usb");

    if( (evt->getAction() != NetlinkEvent::NlActionRemove)
            && !strncmp(getMountpoint(),"/mnt/udisk",10)
            && (getState() == Volume::State_NoMedia || getState() == Volume::State_Idle)
            && usbneedle != 0)
    {   
        it = mPaths->begin();
        while(it != mPaths->end())
        {   
            if (strncmp(dp, *it, strlen(*it)))
            {   
                free(*it);
                it = mPaths->erase(it);
            } else {
                break;
                //++it;
            }   
        }   
        if(mPaths->size() < 1)
        {   
            SLOGE("mPaths donot have the path,so add it\n");
            addPath(dp);
        }   
    }  
    for (it = mPaths->begin(); it != mPaths->end(); ++it) {
        if (!strncmp(dp, *it, strlen(*it))) {
            /* We can handle this disk */
            int action = evt->getAction();                                                                                   
            const char *devtype = evt->findParam("DEVTYPE");

            if (action == NetlinkEvent::NlActionAdd) {
                int major = atoi(evt->findParam("MAJOR"));
                int minor = atoi(evt->findParam("MINOR"));
                char nodepath[255];

                snprintf(nodepath,
                         sizeof(nodepath), "/dev/block/vold/%d:%d",
                         major, minor);
                if (createDeviceNode(nodepath, major, minor)) {
                    SLOGE("Error making device node '%s' (%s)", nodepath,
                                                               strerror(errno));
                }
                if (!strcmp(devtype, "disk")) {
                    handleDiskAdded(dp, evt);
                } else {
                    handlePartitionAdded(dp, evt);
                }
            } else if (action == NetlinkEvent::NlActionRemove) {
                if (!strcmp(devtype, "disk")) {
                    handleDiskRemoved(dp, evt);
                } else {
                    handlePartitionRemoved(dp, evt);
                }
            } else if (action == NetlinkEvent::NlActionChange) {
                if (!strcmp(devtype, "disk")) {
                    handleDiskChanged(dp, evt);
                } else {
                    handlePartitionChanged(dp, evt);
                }
            } else {
                    SLOGW("Ignoring non add/remove/change event");
            }

            return 0;
        }
    }
    errno = ENODEV;
    return -1;
}


这个函数确实很长,它处理了所有的插入,挂载,移除等事件
首先根据主从设备号创建了/dev/block/vold/%d:%d节点名称,根据前面的LOG做参考,应该很容易理解主从设备号是怎么来的了
如果是只有一个分区,并且DEVTYPE=disk(LOG信息可以看到),那么调用handleDiskAdded函数:
    void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) {
        mDiskMajor = atoi(evt->findParam("MAJOR"));
        mDiskMinor = atoi(evt->findParam("MINOR"));

        const char *tmp = evt->findParam("NPARTS");

        .......................

        setState(Volume::State_Pending);
        }

        snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",
             getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);
        mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,
                                             msg, false);
    }


最后一行发送广播给framework,表示有事件要处理了。到这里SD卡还没有挂载的,因为挂载的决定权在mountservice,所以vold还要等待mountservice的决定
mVm->getBroadcaster()返回的就是SocketListener,在main函数中我们有看到这一句:
     cl = new CommandListener();
    vm->setBroadcaster((SocketListener *) cl);
所以返回的其实就是cl,调用了cl的sendBroadcast,来看看CommandListener的继承关系:
    class CommandListener : public FrameworkListener;
    class FrameworkListener : public SocketListener;
继承关系和前面分析的NetlinkListener是差不多的:
    void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
        pthread_mutex_lock(&mClientsLock);
        SocketClientCollection::iterator i;

        for (i = mClients->begin(); i != mClients->end(); ++i) {
        // broadcasts are unsolicited and should not include a cmd number
        if ((*i)->sendMsg(code, msg, addErrno, false)) {
            SLOGW("Error sending broadcast (%s)", strerror(errno));
        }   
        }   
        pthread_mutex_unlock(&mClientsLock);
    }

 
这里,遍历mClients,调用的是SocketClient.cpp的sendMsg函数。会在系统中发送消息,感兴趣的接收者就可以捕获消息了。
至于最底层的socket通讯,就不必深究了,只要了解过程即可,在init.rc中启动vold服务:
service vold /system/bin/vold                                                                                                       
    class core
    socket vold stream 0660 root mount
    ioprio be 2
这里就创建好了socket通讯,会在/dev/socket下生成vold节点
想要监听vold的接收者,只要创建一个socket,名字也为vold即可监听消息了
所以进入接收端看看如何处理消息的,在MountService.java中:
    mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);
创建了NativeDaemonConnector类,可以看到这里的名字为vold,在该类中:
            socket = new LocalSocket();
            LocalSocketAddress address = new LocalSocketAddress(mSocket,                                                  
                    LocalSocketAddress.Namespace.RESERVED);

            socket.connect(address);
这样就可以监听vold发送的消息了,最终会取出事件,回调在MountService的onEvent函数来处理:
public boolean onEvent(int code, String raw, String[] cooked) {

    ......................

    if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {

    ..................
}


在doMountVolume中会调用mConnector.execute("volume", "mount", path)函数,通过NativeDaemonConnector的socket发送命令回vold,执行挂载操作。

vold是如何监听framework发送过来的数据呢?
回到void的main.c中:
  
 cl = new CommandListener();
    cl->startListener();

CommandListener的构造函数:
CommandListener::CommandListener() :                                                                                            
    FrameworkListener("vold", true) {
    registerCmd(new DumpCmd());
    registerCmd(new VolumeCmd());
    registerCmd(new AsecCmd());
    registerCmd(new ObbCmd());
    registerCmd(new StorageCmd());
    registerCmd(new XwarpCmd());
    registerCmd(new CryptfsCmd());
}


CommandListener的继承关系:
    class CommandListener : public FrameworkListener;
    class FrameworkListener : public SocketListener;
其实继承关系和前面分析的一样,也是在线程的onDataAvailable中接收数据,然后派发给派生类FrameworkListener处理:
    bool FrameworkListener::onDataAvailable(SocketClient *c) {                                                           
        char buffer[255];
        int len;

        len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
        if (len < 0) {
        SLOGE("read() failed (%s)", strerror(errno));
        return false;
        } else if (!len)
        return false;

        int offset = 0;
        int i;

        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;
    }

dispatchCommand的实现:

    void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
        FrameworkCommandCollection::iterator i;

        .....................

            for (i = mCommands->begin(); i != mCommands->end(); ++i) {
            FrameworkCommand *c = *i;

            if (!strcmp(argv[0], c->getCommand())) {
                if (c->runCommand(cli, argc, argv)) {
                SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
                }
                goto out;
            }
            }

        ........................

    }


遍历了mCommands容器,mCommands就是前面CommandListener中registerCmd注册进来的,根据名字调用各自的runCommand方法,在这个情景中:

    registerCmd(new VolumeCmd()) -> CommandListener::VolumeCmd::VolumeCmd() :VoldCommand("volume") {}
而从framework命令可以看到argv[0]也为"volume",所以调用了VolumeCmd的runCommand方法:
    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();

        ........................

        } else if (!strcmp(argv[1], "mount")) {
        if (argc != 3) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);
            return 0;
        }   
        rc = vm->mountVolume(argv[2]);
        } else if (!strcmp(argv[1], "unmount")) {

        .....................

    }


调用VolumeManager的mountVolume方法:
    int VolumeManager::mountVolume(const char *label) {                                                              
        Volume *v = lookupVolume(label);

        if (!v) {
        errno = ENOENT;
        return -1;
        }    

        return v->mountVol();
    }


V是Volume容器,Volume是父类,其实V存放的是DirectVolume类成员,DirectVolume并没有实现mountVol方法,所以调用父类Volume的:
到这里就是最终的挂载函数了。
整体流程就这样,其中还涉及到很多socket通讯,但是流程还是和上述差不多了。






























你可能感兴趣的:(android vold流程分析)