Android之vold進程啓動源碼分析

轉自http://blog.csdn.net/yangwen123/article/details/8919503

 2529人閱讀 評論(0) 收藏 舉報

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 plaincopy
  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處理過程框架圖如下:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章