Android之vold进程启动源码分析

1.Vold (Volume Daemon)介绍

vold进程接收来自内核的外部设备消息,用于管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化等;当外部设备发生变化时,内核通过Netlink发送uEvent格式的消息给用户空间程序,Netlink 是一种基于异步通信机制,在内核与用户应用间进行双向数据传输的特殊 socket,用户态应用使用标准的socket API 就可以使用 netlink 提供的强大功能;

2.Vold 框架设计




Vold是native程序,用于管理和控制Android平台外部存储设备的管控中心,是一个后台运行的进程。它与Java层的MountService交互,Vold接收来自kernel的uevent消息,然后向上层转发,MountService接收来自vold的消息,同时也可以向vold发送控制命令。从以上Vold设计框架图中可以看到,Vold有三个模块,分别为NetlinkManager,VolumeManager,CommandListener。
NetlinkManager模块专门接收来自Linux内核uevent消息,并将消息转发给VolumeManager处理,VolumeManager模块接着又把相关信息通过CommandListener发送给MountService,MountService根据收到的消息会发送相应的处理命令给VolumeManager,VolumeManager接收到命令后直接对外部存储设备进行操作。
CommandListener模块内部封装良一个Socket用于跨进程通信,Java层的客户端MountService就是通过该Socket和服务端Vold进行通信的。


1.Netlink介绍

Netlink是Linux系统中用户空间进程和Kernel进行通信的一种机制,用户空间进程可以接收来自Kernel的消息,同时也可以向Kernel发送一些控制命令。 LINUX netlink机制一文中详细介绍了Netlink的用法。

2.Uevent介绍

uevent和Linux的设备文件系统及设备模型有关,是sysfs向用户空间发送的消息。消息格式实际上是一串字符串。当外部设备发生变化时,会引起Kernel发送Uevent消息;一般设备在/sys对应的目录下有个叫uevent的文件,往该文件里写入指定数据,也会触发Kernel发送和该设备相关的uevent消息,内核通过uevent告知外部存储系统发生的变化。

3.Vold 源码分析

 \system\vold\main.cpp
  1. int main()   
  2. {  
  3.         VolumeManager *vm;  
  4.         CommandListener *cl;  
  5.         NetlinkManager *nm;  
  6.         //创建vold设备文件夹  
  7.         mkdir("/dev/block/vold", 0755);  
  8.           
  9.         //初始化Vold相关的类实例 single  
  10.         vm = VolumeManager::Instance();  
  11.         nm = NetlinkManager::Instance();  
  12.           
  13.         //CommandListener 创建vold socket监听上层消息  
  14.         cl = new CommandListener();  
  15.         vm->setBroadcaster((SocketListener *) cl);  
  16.         nm->setBroadcaster((SocketListener *) cl);  
  17.           
  18.         //启动VolumeManager   
  19.         vm->start();  
  20.           
  21.         //根据配置文件/etc/vold.fstab 初始化VolumeManager   
  22.         process_config(vm);  
  23.           
  24.         //启动NetlinkManager socket监听内核发送uevent  
  25.         nm->start();  
  26.           
  27.         //向/sys/block/目录下所有设备uevent文件写入“add\n”,  
  28.         //触发内核sysfs发送uevent消息  
  29.         coldboot("/sys/block");  
  30.           
  31.         //启动CommandListener监听vold socket  
  32.         cl->startListener();  
  33.           
  34.         // Eventually we'll become the monitoring thread  
  35.         while(1) {  
  36.             sleep(1000);  
  37.         }  
  38.           
  39.         exit(0);  
  40. }  
/etc/vold.fstab的内容如下:
[plain] view plain copy
  1. <span style="font-family:Verdana, Arial, Helvetica, sans-serif;font-size:18px;"><span style="line-height: 24px; background-color: rgb(254, 254, 242);">#######################  
  2. ## Regular device mount  
  3. ##  
  4. ## Format: dev_mount <label> <mount_point> <part> <sysfs_path1...>  
  5. ## label        - Label for the volume  
  6. ## mount_point  - Where the volume will be mounted  
  7. ## part         - Partition # (1 based), or 'auto' for first usable partition.  
  8. ## <sysfs_path> - List of sysfs paths to source devices  
  9. ######################  
  10.   
  11. # Mounts the first usable partition of the specified device  
  12. #dev_mount sdcard /mnt/sdcard auto /block/mmcblk0  
  13. dev_mount internal /mnt/sdcard 19 /devices/platform/sprd-sdhci.3/mmc_host/mmc3  
  14. dev_mount sdcard /mnt/sdcard/external auto /devices/platform/sprd-sdhci.0/mmc_host/mmc0</span></span>  

process_config解析vold.fstab文件:
  1. static int process_config(VolumeManager *vm) {  
  2.         //打开vold.fstab的配置文件  
  3.         fp = fopen("/etc/vold.fstab""r")  
  4.         //解析vold.fstab 配置存储设备的挂载点  
  5.     while(fgets(line, sizeof(line), fp)) {  
  6.         const char *delim = " \t";  
  7.         char *type, *label, *mount_point, *part, *mount_flags, *sysfs_path;  
  8.   
  9.         type = strtok_r(line, delim, &save_ptr)  
  10.         label = strtok_r(NULL, delim, &save_ptr)  
  11.         mount_point = strtok_r(NULL, delim, &save_ptr)  
  12.               //判断分区 auto没有分区  
  13.         part = strtok_r(NULL, delim, &save_ptr)  
  14.         if (!strcmp(part, "auto")) {  
  15.              //创建DirectVolume对象 相关的挂载点设备的操作  
  16.            dv = new DirectVolume(vm, label, mount_point, -1);  
  17.         } else {  
  18.            dv = new DirectVolume(vm, label, mount_point, atoi(part));  
  19.         }  
  20.                 //添加挂载点设备路径  
  21.         while ((sysfs_path = strtok_r(NULL, delim, &save_ptr))) {  
  22.             dv->addPath(sysfs_path)  
  23.         }  
  24.               //将DirectVolume 添加到VolumeManager管理  
  25.               vm->addVolume(dv);  
  26.     }  
  27.   
  28.     fclose(fp);  
  29.     return 0;  
  30. }  

4.Vold各模块分析

前面介绍了Vold包含NetlinkManager,VolumeManager,CommandListener三大模块,他们之间的关系如下:

接下来就分别针对每个模块进行详细分析。

1.NetlinkManager模块

NetlinkManager模块接收从Kernel发送的Uevent消息,解析转换成NetlinkEvent对象;再将此NetlinkEvent对象传递给VolumeManager处理。
启动流程
1)构造NetlinkManager实例:nm = NetlinkManager::Instance()
2)设置事件广播监听:nm->setBroadcaster((SocketListener *) cl)
3)启动NetlinkManager:nm->start()

构造NetlinkManager实例

  1. NetlinkManager *NetlinkManager::Instance() {  
  2.     if (!sInstance) //采用单例模式创建NetlinkManager实例  
  3.         sInstance = new NetlinkManager();  
  4.     return sInstance;  
  5. }  
 

启动NetlinkManager

  1. int NetlinkManager::start() {  
  2.     //netlink使用的socket结构  
  3.     struct sockaddr_nl nladdr;  
  4.           
  5.     //初始化socket数据结构  
  6.     memset(&nladdr, 0, sizeof(nladdr));  
  7.     nladdr.nl_family = AF_NETLINK;  
  8.     nladdr.nl_pid = getpid();  
  9.     nladdr.nl_groups = 0xffffffff;  
  10.     //创建socket PF_NETLINK类型  
  11.     mSock = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT);  
  12.     //配置socket 大小  
  13.     setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz);  
  14.     setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on);  
  15.     //bindsocket地址  
  16.     bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr);  
  17.           
  18.     //创建NetlinkHandler 传递socket标识,并启动  
  19.     mHandler = new NetlinkHandler(mSock);  
  20.     mHandler->start();  
  21.     return 0;  
  22. }  
在启动NetlinkManager时,初始化socket用于创建NetlinkManager的属性变量mHandle实例,并启动NetlinkHandler,NetlinkHandler继承于NetlinkListener,NetlinkListener又继承于SocketListener,因此在构造NetlinkHandler实例时首先构造SocketListener及NetlinkListener,构造NetlinkListener对象的父类对象SocketListener:
  1. SocketListener::SocketListener(int socketFd, bool listen) {  
  2.     init(NULL, socketFd, listen, false);  
  3. }  
  1. void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {  
  2.     mListen = listen;  
  3.     mSocketName = socketName;  
  4.     mSock = socketFd;  
  5.     mUseCmdNum = useCmdNum;  
  6.     pthread_mutex_init(&mClientsLock, NULL);  
  7.     mClients = new SocketClientCollection();  
  8. }  
NetlinkListener构造函数:
  1. NetlinkListener::NetlinkListener(int socket) :  
  2.                             SocketListener(socket, false) {  
  3.     mFormat = NETLINK_FORMAT_ASCII;  
  4. }  
NetlinkHandler构造函数:
  1. NetlinkHandler::NetlinkHandler(int listenerSocket) :  
  2.                 NetlinkListener(listenerSocket) {  
  3. }  
因此构造NetlinkHandler实例过程仅仅创建良一个socket客户端连接。
NetlinkHandler start:
  1. int NetlinkHandler::start() {  
  2.     //父类startListener  
  3.     return this->startListener();  
  4. }  
SocketListener  start:
  1. int SocketListener::startListener() {  
  2.    //NetlinkHandler mListen为false   
  3.     if (mListen && listen(mSock, 4) < 0) {  
  4.         return -1;  
  5.     } else if (!mListen){  
  6.         //mListen为false 用于netlink消息监听  
  7.         //创建SocketClient作为SocketListener 的客户端   
  8.         mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));  
  9.     }  
  10.   
  11.     //创建匿名管道  
  12.     pipe(mCtrlPipe);  
  13.     //创建线程执行函数threadStart    参this  
  14.     pthread_create(&mThread, NULL, SocketListener::threadStart, this);  
  15. }  

uevent消息监听线程

启动NetlinkHandler过程通过创建一个SocketListener工作线程来 监听Kernel netlink发送的UEvent消息,该线程完成的工作:
  1. void *SocketListener::threadStart(void *obj) {  
  2.   
  3.     //参数转换  
  4.     SocketListener *me = reinterpret_cast<SocketListener *>(obj);  
  5.   
  6.     me->runListener();  
  7.   
  8.     pthread_exit(NULL);  
  9.   
  10.     return NULL;  
  11.   
  12. }  
SocketListener 线程消息循环:
  1. void SocketListener::runListener() {  
  2.         //SocketClient List  
  3.     SocketClientCollection *pendingList = new SocketClientCollection();  
  4.   
  5.     while(1) {  
  6.         fd_set read_fds;  
  7.         //mListen 为false  
  8.         if (mListen) {  
  9.             max = mSock;  
  10.             FD_SET(mSock, &read_fds);  
  11.         }  
  12.         //加入一组文件描述符集合 选择fd最大的max  
  13.         FD_SET(mCtrlPipe[0], &read_fds);  
  14.         pthread_mutex_lock(&mClientsLock);  
  15.         for (it = mClients->begin(); it != mClients->end(); ++it) {  
  16.             int fd = (*it)->getSocket();  
  17.             FD_SET(fd, &read_fds);  
  18.             if (fd > max)  
  19.                 max = fd;  
  20.         }  
  21.         pthread_mutex_unlock(&mClientsLock);  
  22.           
  23.         //监听文件描述符是否变化  
  24.         rc = select(max + 1, &read_fds, NULL, NULL, NULL);  
  25.         //匿名管道被写,退出线程  
  26.         if (FD_ISSET(mCtrlPipe[0], &read_fds))  
  27.             break;  
  28.         //mListen 为false  
  29.         if (mListen && FD_ISSET(mSock, &read_fds)) {  
  30.                 //mListen 为ture 表示正常监听socket  
  31.             struct sockaddr addr;  
  32.             do {  
  33.                 //接收客户端连接  
  34.                 c = accept(mSock, &addr, &alen);  
  35.             } while (c < 0 && errno == EINTR);  
  36.               
  37.             //此处创建一个客户端SocketClient加入mClients列表中,异步延迟处理  
  38.             pthread_mutex_lock(&mClientsLock);  
  39.             mClients->push_back(new SocketClient(c, true, mUseCmdNum));  
  40.             pthread_mutex_unlock(&mClientsLock);  
  41.         }  
  42.   
  43.         /* Add all active clients to the pending list first */  
  44.         pendingList->clear();  
  45.         //将所有有消息的Client加入到pendingList中  
  46.         pthread_mutex_lock(&mClientsLock);  
  47.         for (it = mClients->begin(); it != mClients->end(); ++it) {  
  48.             int fd = (*it)->getSocket();  
  49.             if (FD_ISSET(fd, &read_fds)) {  
  50.                 pendingList->push_back(*it);  
  51.             }  
  52.         }  
  53.         pthread_mutex_unlock(&mClientsLock);  
  54.   
  55.         //处理所有消息  
  56.         while (!pendingList->empty()) {  
  57.             it = pendingList->begin();  
  58.             SocketClient* c = *it;  
  59.             pendingList->erase(it);  
  60.                //处理有数据发送的socket 虚函数  
  61.             if (!onDataAvailable(c) && mListen) {  
  62.                //mListen为false  
  63.             }  
  64.         }  
  65.     }  
  66. }  
在消息循环中调用onDataAvailable处理消息,onDataAvailable是个虚函数,NetlinkListener重写了此函数。
  1. bool NetlinkListener::onDataAvailable(SocketClient *cli)  
  2. {  
  3.     //获取socket id  
  4.     int socket = cli->getSocket();  
  5.     //接收netlink uevent消息  
  6.     count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv(  
  7.                                  socket, mBuffer, sizeof(mBuffer), &uid));  
  8.     //解析uevent消息为NetlinkEvent消息  
  9.     NetlinkEvent *evt = new NetlinkEvent();  
  10.     evt->decode(mBuffer, count, mFormat);  
  11.       
  12.     //处理NetlinkEvent onEvent虚函数  
  13.     onEvent(evt);  
  14. }  
将接收的Uevent数据转化成NetlinkEvent数据,调用onEvent处理,NetlinkListener子类NetlinkHandler重写了此函数。
  1. void NetlinkHandler::onEvent(NetlinkEvent *evt) {  
  2.   
  3.     //获取VolumeManager实例  
  4.     VolumeManager *vm = VolumeManager::Instance();  
  5.   
  6.     //设备类型  
  7.     const char *subsys = evt->getSubsystem();  
  8.                    
  9.     //将消息传递给VolumeManager处理  
  10.     if (!strcmp(subsys, "block")) {  
  11.         vm->handleBlockEvent(evt);  
  12.   
  13.     }  
  14. }  

NetlinkManager通过NetlinkHandler将接收到Kernel内核发送的Uenvet消息,转化成了NetlinkEvent结构数据传递给VolumeManager处理,uevent消息的上传流程:


2.VolumeManager模块

启动流程
1)构造VolumeManager对象实例
2)设置事件广播监听
3)启动VolumeManager
4)配置VolumeManager

VolumeManager类关系图:


DirectVolume是一个实体存储设备的抽象,通过系统调用直接操作存储设备。VolumeManager的SocketListenner与NetlinkManager的SocketListenner有所不同的:

NetlinkManager构造的SocketListenner:Kernel与Vold通信;

VolumeManager构造的SocketListenner:Native Vold与Framework MountService 通信;

NetlinkManager与VolumeManager交互流程图:



1.构造VolumeManager对象

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

2.启动VolumeManager

  1. int VolumeManager::start() {  
  2.     return 0;  
  3. }  
VolumeManager启动过程什么都没有做。

3.uevent事件处理

前面NetlinkManager模块中介绍到,NetlinkHandler在onEvent函数中,将NetlinkEvent事件转交给VolumeManager处理:
  1. void NetlinkHandler::onEvent(NetlinkEvent *evt) {  
  2.         ……  
  3.             //将消息传递给VolumeManager处理  
  4.         if (!strcmp(subsys, "block")) {  
  5.             vm->handleBlockEvent(evt);  
  6.         }  
  7. }  

  1. void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {  
  2.     //有状态变化设备路径  
  3.   const char *devpath = evt->findParam("DEVPATH");  
  4.   
  5.   //遍历VolumeManager中所管理Volume对象(各存储设备代码抽象)  
  6.   for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {  
  7.       if (!(*it)->handleBlockEvent(evt)) {  
  8.           hit = true;  
  9.           break;  
  10.       }  
  11. }  
VolumeManager将消息交给各个DirectVolume对象处理:
  1. int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {  
  2.     //从NetlinkEvent消息中取出有状态变化设备路径  
  3.     const char *dp = evt->findParam("DEVPATH");  
  4.   
  5.     PathCollection::iterator  it;  
  6.     //遍历所有的存储设备  
  7.     for (it = mPaths->begin(); it != mPaths->end(); ++it) {  
  8.         //根据存储设备路径进行匹配  
  9.         if (!strncmp(dp, *it, strlen(*it))) {  
  10.             /* 从NetlinkEvent消息中取出设备变化的动作 */  
  11.             int action = evt->getAction();  
  12.             /* 从NetlinkEvent消息中取出设备类型 */  
  13.             const char *devtype = evt->findParam("DEVTYPE");  
  14.             SLOGE("DirectVolume::handleBlockEvent() evt's DEVPATH= %s DEVTYPE= %s action= %d",dp, devtype, action);    //设备插入  
  15.             if (action == NetlinkEvent::NlActionAdd) {  
  16.                 int major = atoi(evt->findParam("MAJOR"));  
  17.                 int minor = atoi(evt->findParam("MINOR"));  
  18.                 char nodepath[255];  
  19.   
  20.                 snprintf(nodepath,sizeof(nodepath), "/dev/block/vold/%d:%d",major, minor);  
  21.                 SLOGE("DirectVolume::handleBlockEvent() NlActionAdd - /dev/block/vold/%d:%d\n", major, minor);  
  22.                 if (createDeviceNode(nodepath, major, minor)) {  
  23.                     SLOGE("Error making device node '%s' (%s)", nodepath,strerror(errno));  
  24.                 }  
  25.                 //新增磁盘  
  26.                 if (!strcmp(devtype, "disk")) {  
  27.                     handleDiskAdded(dp, evt);  
  28.                 //新增分区  
  29.                 } else {  
  30.                     handlePartitionAdded(dp, evt);  
  31.                 }  
  32.             //设备移除  
  33.             } else if (action == NetlinkEvent::NlActionRemove) {  
  34.                 SLOGE("Volume  partition %d:%d removed",  atoi(evt->findParam("MAJOR")), atoi(evt->findParam("MINOR")));  
  35.                 //删除磁盘  
  36.                 if (!strcmp(devtype, "disk")) {  
  37.                     handleDiskRemoved(dp, evt);  
  38.                 //删除分区  
  39.                 } else {  
  40.                     handlePartitionRemoved(dp, evt);  
  41.                 }  
  42.             //设备改变  
  43.             } else if (action == NetlinkEvent::NlActionChange) {  
  44.                 //磁盘变化  
  45.                 if (!strcmp(devtype, "disk")) {  
  46.                     handleDiskChanged(dp, evt);  
  47.                 //分区变化  
  48.                 } else {  
  49.                     handlePartitionChanged(dp, evt);  
  50.                 }  
  51.             } else {  
  52.                     SLOGW("Ignoring non add/remove/change event");  
  53.             }  
  54.   
  55.             return 0;  
  56.         }  
  57.     }  
  58.     errno = ENODEV;  
  59.     return -1;  
  60. }  

每一个Volume可能对应多个Path;即一个挂载点对应多个物理设备,因此VolumeManager中的每一个Volume对象都需要处理SD状态变换消息,当新增一个disk时:

  1. void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) {  
  2.     //主次设备号  
  3.     mDiskMajor = atoi(evt->findParam("MAJOR"));  
  4.     mDiskMinor = atoi(evt->findParam("MINOR"));  
  5.           
  6.     //设备分区情况  
  7.     const char *tmp = evt->findParam("NPARTS");  
  8.   mDiskNumParts = atoi(tmp);  
  9.       
  10.     if (mDiskNumParts == 0) {  
  11.         //没有分区,Volume状态为Idle  
  12.         setState(Volume::State_Idle);  
  13.     } else {  
  14.         //有分区未加载,设置Volume状态Pending  
  15.         setState(Volume::State_Pending);  
  16.     }  
  17.     //格式化通知msg:"Volume sdcard /mnt/sdcard disk inserted (179:0)"  
  18.     char msg[255];  
  19.     snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);  
  20.     //调用VolumeManager中的Broadcaster——>CommandListener 发送此msg  
  21.     mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,msg, false);  
  22. }  
将新增一个disk以消息的方式通过CommandListener向MountService发送,由于CommandListener继承于FrameworkListener,而FrameworkListener又继承于SocketListener,CommandListener和FrameworkListener都没用重写父类的sendBroadcast方法,因此消息是通过 SocketListener的sendBroadcast函数向上层发送的,VolumeManager通知上层的消息流程图:

  1. void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno)   
  2. {  
  3.     pthread_mutex_lock(&mClientsLock);  
  4.     //遍历所有的消息接收时创建的Client SocketClient  
  5.     // SocketClient将消息通过socket(“vold”)通信  
  6.     for (i = mClients->begin(); i != mClients->end(); ++i) {  
  7.         (*i)->sendMsg(code, msg, addErrno, false);  
  8.     }  
  9.     pthread_mutex_unlock(&mClientsLock);  
  10. }  

3.CommandListener模块

1)构造CommandListener对象实例
2)调用startListener函数启动监听

1.构造CommandListener对象

  1. CommandListener::CommandListener() :  
  2.                 FrameworkListener("vold"true) {  
  3.   
  4.     //注册Framework发送的相关命令 Command模式  
  5.   
  6.     registerCmd(new DumpCmd());  
  7.   
  8.     registerCmd(new VolumeCmd());  
  9.   
  10.     registerCmd(new AsecCmd());  
  11.   
  12.     registerCmd(new ObbCmd());  
  13.   
  14.     registerCmd(new StorageCmd());  
  15.   
  16.     registerCmd(new XwarpCmd());  
  17.   
  18.     registerCmd(new CryptfsCmd());  
  19.   
  20. }  
父类FrameworkListener构造:
  1. FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :  
  2.                             SocketListener(socketName, true, withSeq) {  
  3.     init(socketName, withSeq);  
  4. }  
直接调用init函数;
  1. void FrameworkListener::init(const char *socketName, bool withSeq) {  
  2.     mCommands = new FrameworkCommandCollection();  
  3.     errorRate = 0;  
  4.     mCommandCount = 0;  
  5.     mWithSeq = withSeq;  
  6. }  
SocketListener的构造函数:
  1. SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {  
  2.     init(socketName, -1, listen, useCmdNum);  
  3. }  
同样调用init函数进行初始化:
  1. void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {  
  2.     mListen = listen;  
  3.     mSocketName = socketName;  
  4.     mSock = socketFd;  
  5.     mUseCmdNum = useCmdNum;  
  6.     pthread_mutex_init(&mClientsLock, NULL);  
  7.     mClients = new SocketClientCollection();  
  8. }  
构造CommandListener对象过程中,首先注册了各种命令,并创建良一个socket客户端连接。命令注册过程:
  1. void FrameworkListener::registerCmd(FrameworkCommand *cmd) {  
  2.     mCommands->push_back(cmd);  
  3. }  
将各种命令存放到mCommand列表中。

2.启动CommandListener监听

  1. int SocketListener::startListener() {  
  2.     //mSocketName = “Vold”  
  3.     mSock = android_get_control_socket(mSocketName);  
  4.           
  5.     //NetlinkHandler mListen为true 监听socket  
  6.     if (mListen && < 0) {  
  7.         return -1;  
  8.     } else if (!mListen){  
  9.         mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));  
  10.     }  
  11.           
  12.     //创建匿名管道  
  13.     pipe(mCtrlPipe);  
  14.     //创建线程执行函数threadStart 参数this  
  15.     pthread_create(&mThread, NULL, SocketListener::threadStart, this);  
  16. }  
  17.   
  18. void *SocketListener::threadStart(void *obj) {  
  19.     SocketListener *me = reinterpret_cast<SocketListener *>(obj);  
  20.     me->runListener();  
  21. }  
  22.   
  23. void SocketListener::runListener() {  
  24.     //SocketClient List  
  25.     SocketClientCollection *pendingList = new SocketClientCollection();  
  26.   
  27.     while(1) {  
  28.         fd_set read_fds;  
  29.                 //mListen 为true  
  30.         if (mListen) {  
  31.             max = mSock;  
  32.             FD_SET(mSock, &read_fds);  
  33.         }  
  34.                 //加入一组文件描述符集合 选择fd最大的max select有关  
  35.         FD_SET(mCtrlPipe[0], &read_fds);  
  36.         pthread_mutex_lock(&mClientsLock);  
  37.         for (it = mClients->begin(); it != mClients->end(); ++it) {  
  38.             int fd = (*it)->getSocket();  
  39.             FD_SET(fd, &read_fds);  
  40.             if (fd > max)  
  41.                 max = fd;  
  42.         }  
  43.         pthread_mutex_unlock(&mClientsLock);  
  44.           
  45.         //监听文件描述符是否变化  
  46.         rc = select(max + 1, &read_fds, NULL, NULL, NULL);  
  47.         //匿名管道被写,退出线程  
  48.         if (FD_ISSET(mCtrlPipe[0], &read_fds))  
  49.             break;  
  50.   
  51.         //mListen 为true  
  52.         if (mListen && FD_ISSET(mSock, &read_fds)) {  
  53.             //mListen 为ture 表示正常监听socket  
  54.             struct sockaddr addr;  
  55.             do {  
  56.                 c = accept(mSock, &addr, &alen);  
  57.             } while (c < 0 && errno == EINTR);  
  58.               
  59.             //创建一个客户端SocketClient,加入mClients列表中 到异步延迟处理  
  60.             pthread_mutex_lock(&mClientsLock);  
  61.             mClients->push_back(new SocketClient(c, true, mUseCmdNum));  
  62.             pthread_mutex_unlock(&mClientsLock);  
  63.         }  
  64.   
  65.         /* Add all active clients to the pending list first */  
  66.         pendingList->clear();  
  67.         //将所有有消息的Client加入到pendingList中  
  68.         pthread_mutex_lock(&mClientsLock);  
  69.         for (it = mClients->begin(); it != mClients->end(); ++it) {  
  70.             int fd = (*it)->getSocket();  
  71.             if (FD_ISSET(fd, &read_fds)) {  
  72.                 pendingList->push_back(*it);  
  73.             }  
  74.         }  
  75.         pthread_mutex_unlock(&mClientsLock);  
  76.   
  77.         /* Process the pending list, since it is owned by the thread,*/  
  78.         while (!pendingList->empty()) {  
  79.             it = pendingList->begin();  
  80.             SocketClient* c = *it;  
  81.                //处理有数据发送的socket   
  82.             if (!onDataAvailable(c) && mListen) {  
  83.                //mListen为true  
  84.                ……  
  85.             }  
  86.         }  
  87.     }  
  88. }  

启动CommandListener监听过程其实就是创建一个监听的工作线程,用于监听客户端即MountService发过来的命令。

3.消息处理

当接收到MountService发送的消息时,将回调onDataAvailable函数进行处理。CommandListener父类FrameworkCommand重写了消息处理onDataAvailable函数。

  1. bool FrameworkListener::onDataAvailable(SocketClient *c) {  
  2.     char buffer[255];  
  3.     //读取socket消息  
  4.     len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));  
  5.     for (i = 0; i < len; i++) {  
  6.         if (buffer[i] == '\0') {  
  7.             //根据消息内容 派发命令  
  8.             dispatchCommand(c, buffer + offset);  
  9.             offset = i + 1;  
  10.         }  
  11.     }  
  12.     return true;  
  13. }  
  14.   
  15. void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {  
  16.    char *argv[FrameworkListener::CMD_ARGS_MAX];  
  17.     //解析消息内容 命令 参数  
  18.     ……  
  19.       
  20.     //执行对应的消息  
  21.     for (i = mCommands->begin(); i != mCommands->end(); ++i) {  
  22.         FrameworkCommand *c = *i;  
  23.         //匹配命令  
  24.         if (!strcmp(argv[0], c->getCommand())) {  
  25.             //执行命令  
  26.             c->runCommand(cli, argc, argv);  
  27.             goto out;  
  28.         }  
  29.     }  
  30. out:  
  31.         return;  
  32. }  


对于 VolumeCommand,其runCommand函数为:

  1. int CommandListener::VolumeCmd::runCommand(SocketClient *cli,int argc, char **argv) {  
  2.     dumpArgs(argc, argv, -1);  
  3.     if (argc < 2) {  
  4.         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument"false);  
  5.         return 0;  
  6.     }  
  7.     VolumeManager *vm = VolumeManager::Instance();  
  8.     int rc = 0;  
  9.     //查看存储设备  
  10.     if (!strcmp(argv[1], "list")) {  
  11.         return vm->listVolumes(cli);  
  12.     } else if (!strcmp(argv[1], "debug")) {  
  13.         if (argc != 3 || (argc == 3 && (strcmp(argv[2], "off") && strcmp(argv[2], "on")))) {  
  14.             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume debug <off/on>"false);  
  15.             return 0;  
  16.         }  
  17.         vm->setDebug(!strcmp(argv[2], "on") ? true : false);  
  18.     //挂载存储设备  
  19.     } else if (!strcmp(argv[1], "mount")) {  
  20.         if (argc != 3) {  
  21.             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>"false);  
  22.             return 0;  
  23.         }  
  24.         rc = vm->mountVolume(argv[2]);  
  25.     //卸载存储设备  
  26.     } else if (!strcmp(argv[1], "unmount")) {  
  27.         if (argc < 3 || argc > 4 ||  
  28.            ((argc == 4 && strcmp(argv[3], "force")) &&  
  29.             (argc == 4 && strcmp(argv[3], "force_and_revert")))) {  
  30.             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount <path> [force|force_and_revert]"false);  
  31.             return 0;  
  32.         }  
  33.   
  34.         bool force = false;  
  35.         bool revert = false;  
  36.         if (argc >= 4 && !strcmp(argv[3], "force")) {  
  37.             force = true;  
  38.         } else if (argc >= 4 && !strcmp(argv[3], "force_and_revert")) {  
  39.             force = true;  
  40.             revert = true;  
  41.         }  
  42.         rc = vm->unmountVolume(argv[2], force, revert);  
  43.     //格式化存储设备  
  44.     } else if (!strcmp(argv[1], "format")) {  
  45.         if (argc != 3) {  
  46.             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume format <path>"false);  
  47.             return 0;  
  48.         }  
  49.         rc = vm->formatVolume(argv[2]);  
  50.     //共享存储设备  
  51.     } else if (!strcmp(argv[1], "share")) {  
  52.         if (argc != 4) {  
  53.             cli->sendMsg(ResponseCode::CommandSyntaxError,  
  54.                     "Usage: volume share <path> <method>"false);  
  55.             return 0;  
  56.         }  
  57.         rc = vm->shareVolume(argv[2], argv[3]);  
  58.     } else if (!strcmp(argv[1], "unshare")) {  
  59.         if (argc != 4) {  
  60.             cli->sendMsg(ResponseCode::CommandSyntaxError,  
  61.                     "Usage: volume unshare <path> <method>"false);  
  62.             return 0;  
  63.         }  
  64.         rc = vm->unshareVolume(argv[2], argv[3]);  
  65.     } else if (!strcmp(argv[1], "shared")) {  
  66.         bool enabled = false;  
  67.         if (argc != 4) {  
  68.             cli->sendMsg(ResponseCode::CommandSyntaxError,  
  69.                     "Usage: volume shared <path> <method>"false);  
  70.             return 0;  
  71.         }  
  72.   
  73.         if (vm->shareEnabled(argv[2], argv[3], &enabled)) {  
  74.             cli->sendMsg(  
  75.                     ResponseCode::OperationFailed, "Failed to determine share enable state"true);  
  76.         } else {  
  77.             cli->sendMsg(ResponseCode::ShareEnabledResult,  
  78.                     (enabled ? "Share enabled" : "Share disabled"), false);  
  79.         }  
  80.         return 0;  
  81.     } else {  
  82.         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd"false);  
  83.     }  
  84.   
  85.     if (!rc) {  
  86.         cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded"false);  
  87.     } else {  
  88.         int erno = errno;  
  89.         rc = ResponseCode::convertFromErrno();  
  90.         cli->sendMsg(rc, "volume operation failed"true);  
  91.     }  
  92.     return 0;  
  93. }  
针对不同的命令,调用VolumeManager的不同函数对存储设备进行操作,如挂载磁盘命令,则调用mountVolume函数:

  1. int VolumeManager::mountVolume(const char *label) {  
  2.     //根据卷标查找Volume  
  3.     Volume *v = lookupVolume(label);  
  4.     if (!v) {  
  5.         errno = ENOENT;  
  6.         return -1;  
  7.     }  
  8.     return v->mountVol();  
  9. }  
调用Volume的mountVol函数来挂载设备。MountServcie发送命令的流程图:




整个Vold处理过程框架图如下:


更多

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值