vold流程分析

前言

vold作为管理和控制Android 存储设备的后台进程,已经被无数人分析过了,比较好的有这个:
http://blog.csdn.net/fe421504975/article/details/8240190
http://wiki.jikexueyuan.com/project/deep-android-v1/vold-rild.html
写下今天这篇,主要是为了记录一些自己的感悟

框架

vold流程分析_第1张图片
VOLD分析.png

代码分析

init进程启动vold

Android起来后会解析init.rc,init.rc中启动了vold,代码如下

service vold /system/bin/vold
    class core
    socket vold stream 0660 root mount  //①

    ioprio be 2

① 表示系统会创建一个“ /dev/socket/vold”的socket文件,用来和上层通信

main函数

一切都是从main函数开始的,直接看main函数,简略如下:

int main() {
    VolumeManager *vm;
    CommandListener *cl;
    NetlinkManager *nm;

    //1. 创建VolumeManager的实例,作为大总管管理上下层的消息传递
    if (!(vm = VolumeManager::Instance())) {
        SLOGE("Unable to create VolumeManager");
        exit(1);
    };

    //2. NetlinkManager用来处理下层的消息
    if (!(nm = NetlinkManager::Instance())) {
        SLOGE("Unable to create NetlinkManager");
        exit(1);
    };
    //3. 创建CommandListener来监听上层消息
    cl = new CommandListener();
    vm->setBroadcaster((SocketListener *) cl);
    nm->setBroadcaster((SocketListener *) cl);

    //4. 根据flash类型解析根目录下的fstab.*文件
    //并将文件中的每一个有效行都新建一个DirectVolume来管理
    if (process_config(vm)) {
        SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno));
    }

    //5. 建立用于底层通信的socket并处理底层netlink消息
    if (nm->start()) {
        SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));
        exit(1);
    }

    //6. 向/sys/block的uevent文件写入“add”触发内核上报uevent消息
    coldboot("/sys/block");
    
    //7. 一切都准备完毕,可以通过/dev/socket/vold与上层通信了
    if (cl->startListener()) {
        SLOGE("Unable to start CommandListener (%s)", strerror(errno));
        exit(1);
    }

    //8. 主循环不退出
    while(1) {
        sleep(1000);
    }

    SLOGI("Vold exiting");
    exit(0);
}

可以看到vold启动很简洁,没有什么难点,接下来分析NetlinkManager、CommandListener和VolumeManager

NetlinkManager

NetlinkManager主要是在start上:

int NetlinkManager::start() {
    //1. 创建socket,可以在/proc/net/socket
   if ((mSock = socket(PF_NETLINK,
    SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {
        SLOGE("Unable to create uevent socket: %s", strerror(errno));
        return -1;
    }
    //设置socket相关参数
    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一样用就好了
    if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
        SLOGE("Unable to bind uevent socket: %s", strerror(errno));
        goto out;
    }
    //这个用来监听socket上报的消息,并处理消息
    mHandler = new NetlinkHandler(mSock);
    if (mHandler->start()) {
        SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
        goto out;
    } 
   return 0;
out:
    close(mSock);
    return -1;
}

NetlinkHandler的继承关系如下(来自深入理解Android 卷I):

vold流程分析_第2张图片
图片.png

主要知道,socketlistener已经实现了socket的监控方法,最后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;
    }
    // 这里会比对上传的事件是“block”还是“usb”,然后调用VolumeManager的handle函数
    if (!strcmp(subsys, "block")) {
        vm->handleBlockEvent(evt);
#ifdef USE_USB_MODE_SWITCH
    }else if(!strcmp(subsys, "usb") || !strcmp(subsys, "scsi_device")) {
     SLOGW("subsystem found in netlink event"); 
     MiscManager *mm = MiscManager::Instance();
      mm->handleEvent(evt);
#endif
    }
}

VolumeManager

其实VM的handle函数就是遍历所有之前解析好的DirectVolume,并调用它们的handle函数

void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
    const char *devpath = evt->findParam("DEVPATH");
    /* Lookup a volume to handle this device */
    VolumeCollection::iterator it;    bool hit = false;
    //这个就是之前解析好的DirectVolume
    for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
        // 调用DirectVolume的处理函数
        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    }}

DirectVolume

代码比较长,挑重点看

int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {
    const char *dp = evt->findParam("DEVPATH");

    //遍历路径
    for (it = mPaths->begin(); it != mPaths->end(); ++it) {
        if (!strncmp(dp, *it, strlen(*it))) {
            int action = evt->getAction();
            const char *devtype = evt->findParam("DEVTYPE");

            //通过action判断是插入还是拔出还是有变更
            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);
                //创建dev节点
                if (createDeviceNode(nodepath, major, minor)) {
                    SLOGE("Error making device node '%s' (%s)", nodepath,
                                                               strerror(errno));
                }
                //判断是什么类型,物理分区还是逻辑分区;
                //如果sd卡只有一个分区,那么上报disk消息
                //如果SD卡有多个分区,先上报disk消息,再上报多个partition消息
                if (!strcmp(devtype, "disk")) {
                    handleDiskAdded(dp, evt);
                } else {
                    handlePartitionAdded(dp, evt);
                }
                /* Send notification iff disk is ready (ie all partitions found) */
                if (getState() == Volume::State_Idle) {
                    char msg[255];

                    snprintf(msg, sizeof(msg),
                             "Volume %s %s disk inserted (%d:%d)", getLabel(),
                             getFuseMountpoint(), mDiskMajor, mDiskMinor);
                    //通过广播发送消息,还记得之前提供的commandListener嘛?
                    //这个广播发送者就是它
                    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,
                                                         msg, false);
                }
            } else if (action == NetlinkEvent::NlActionRemove) {
                if (!strcmp(devtype, "disk")) {
#ifdef SUPPORTED_MULTI_USB_PARTITIONS
                    if (!strcmp(getLabel(),USB_DISK_LABEL))
                        handlePartitionRemoved(dp, evt);
#endif
                    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;
}

看看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");
    //分区个数,这里应该是0
    if (tmp) {
        mDiskNumParts = atoi(tmp);
    } else {
        SLOGW("Kernel block uevent missing 'NPARTS'");
        mDiskNumParts = 1;
    }

    if (mDiskNumParts == 0) {
        setState(Volume::State_Idle);
            //通过socket发送消息到JAVA层
     snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",
              getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);
     mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,msg, false);

    } else {
        setState(Volume::State_Pending);
    }
}

CommandListener

可以看到,CL向上层发送有设备插入的广播。上层接受到广播后,会进行处理,然后再向CL发送挂载或者卸载命令等。与上层所有的交互都通过socket进行。
先看下CommandListener的继承关系(来自深入理解Android 卷I):

vold流程分析_第3张图片
图片.png

可以看到,它也是由socketListener继承而来,我们来看看CommandListener的初始化

CommandListener::CommandListener() : 
      FrameworkListener("vold") {
    //CL模块支持的命令
    registerCmd(new DumpCmd());
    registerCmd(new VolumeCmd());
    registerCmd(new AsecCmd());
    registerCmd(new ShareCmd());
    registerCmd(new StorageCmd());
    registerCmd(new XwarpCmd());}

都是registerCmd,所以说这些CMD一定都有共同的特征,他们都实现了一个runCommand的函数。
registerCmd是在FrameworkListener实现的,他的作用就是把Command保存到一个mCommands的列表中。
在上层来消息的时候,遍历这些Command的runCommand方法。
那CL是怎么发送消息给上层的呢?通过SocketClient的sendMsg方法,就可以跟上层通信了

总结

总得来说vold的代码并不困难,稍加分析就可以理清他的逻辑和思路,这篇文章也是编分析编写,如果有不对的地方,请各位大佬指出

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