2018年5月8日 星期二

VolD (Volume Daemon) 介紹

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中

[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->開始();  
  20.           
  21.         //根據配置文件/etc/vold.fstab 初始化VolumeManager   
  22.         process_config(VM);  
  23.           
  24.         //啟動NetlinkManager socket監聽內核發送uevent  
  25.         NM->開始();  
  26.           
  27.         //向/sys/block/目錄下所有設備uevent文件寫入“add\n”,  
  28.         //觸發內核sysfs發送uevent消息  
  29.         冷啟動(“/ sys / block” );  
  30.           
  31.         //啟動CommandListener監聽vold socket  
  32.         CL-> startListener();  
  33.           
  34.         //最終我們將成為監控線程  
  35.         (1){  
  36.             睡眠(1000);  
  37.         }  
  38.           
  39.         出口(0);  
  40. }  
/etc/vold.fstab的內容如下:
[純] 查看純文本 
  1. # ######################  
  2. ##常規設備安裝  
  3. ##  
  4. ##格式:dev_mount
  5. ## label - 卷的標籤  
  6. ## mount_point - 卷的安裝位置  
  7. ## part - Partition#(1 based),或'auto'表示第一個可用的分區。  
  8. ## - 源設備的sysfs路徑列表  
  9. ######################  
  10.   
  11. #安裝指定設備的第一個可用分區  
  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>  


process_config解析vold.fstab文件:

[cpp] 查看純文本 
  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.         如果 (!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.     返回 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實例

[cpp] 查看純文本 
  1. NetlinkManager * NetlinkManager :: Instance(){  
  2.     if  (!sInstance)  //採用單例模式創建NetlinkManager實例  
  3.         sInstance =  new  NetlinkManager();  
  4.     返回 sInstance;  
  5. }  

啟動NetlinkManager

[cpp] 查看純文本 
  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 =  新的 NetlinkHandler(mSock);  
  20.     mHandler->開始();  
  21.     返回 0;  
  22. }  
在啟動NetlinkManager時,初始化socket用於創建NetlinkManager的屬性變量mHandle實例,並啟動NetlinkHandler,NetlinkHandler繼承於NetlinkListener,NetlinkListener又繼承於SocketListener,因此在構造NetlinkHandler實例時首先構造SocketListener及NetlinkListener,構造NetlinkListener對象的父類對象SocketListener:
[cpp] 查看純文本 
  1. SocketListener :: SocketListener(int  socketFd,  bool  listen){  
  2.     init(NULL,socketFd,listen,  false );  
  3. }  
[cpp] 查看純文本 
  1. void  SocketListener :: init(const char  * socketName,  int  socketFd,  bool  listen,  bool  useCmdNum){   
  2.     mListen = list;  
  3.     mSocketName = socketName;  
  4.     mSock = socketFd;  
  5.     mUseCmdNum = useCmdNum;  
  6.     pthread_mutex_init(&mClientsLock,NULL);  
  7.     mClients =  new  SocketClientCollection();  
  8. }  
NetlinkListener構造函數:
[cpp] 查看純文本 
  1. NetlinkListener :: NetlinkListener(int  socket):  
  2.                             SocketListener(socket,  false ){  
  3.     mFormat = NETLINK_FORMAT_ASCII;  
  4. }  
NetlinkHandler構造函數:
[cpp] 查看純文本 
  1. NetlinkHandler :: NetlinkHandler(int  listenerSocket):  
  2.                 NetlinkListener(listenerSocket){  
  3. }  
因此構造NetlinkHandler實例過程僅僅創建良一個socket客戶端連接。
NetlinkHandler開始:
[cpp] 查看純文本 
  1. int  NetlinkHandler :: start(){  
  2.     //父類startListener  
  3.     返回這個- > startListener();   
  4. }  
SocketListener開始:
[cpp] 查看純文本 
  1. int  SocketListener :: startListener(){  
  2.    // NetlinkHandler mListen為false   
  3.     if  (mListen && listen(mSock,4)<0 font="" nbsp="">
  4.         返回 -1;  
  5.     }  else if  (!mListen){   
  6.         //mListen為false 用於netlink消息監聽  
  7.         //創建SocketClient作為SocketListener 的客戶端   
  8.         mClients-> push_back(新的 SocketClient(mSock,  false ,mUseCmdNum));  
  9.     }  
  10.   
  11.     //創建匿名管道  
  12.     管(mCtrlPipe);  
  13.     //創建線程執行函數threadStart 參this  
  14.     pthread_create(&mThread,NULL,SocketListener :: threadStart,  this );  
  15. }  

uevent消息監聽線程

啟動NetlinkHandler過程通過創建一個SocketListener工作線程來監聽Kernel netlink發送的UEvent消息,該線程完成的工作:

[cpp] 查看純文本 
  1. void  * SocketListener :: threadStart(void  * obj){  
  2.   
  3.     //參數轉換  
  4.     SocketListener * me =  reinterpret_cast (obj);  
  5.   
  6.     我 - > runListener();  
  7.   
  8.     了pthread_exit(NULL);  
  9.   
  10.     返回 NULL;  
  11.   
  12. }  
SocketListener 線程消息循環:

[cpp] 查看純文本 
  1. void  SocketListener :: runListener(){  
  2.         // SocketClient列表  
  3.     SocketClientCollection * pendingList =  new  SocketClientCollection();  
  4.   
  5.     (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.             如果 (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.         如果 (FD_ISSET(mCtrlPipe [0],&read_fds))  
  27.             休息;  
  28.         // mListen為false  
  29.         if  (mListen && FD_ISSET(mSock,&read_fds)){  
  30.                 //mListen 為ture 表示正常監聽socket  
  31.             struct  sockaddr addr;  
  32.              {  
  33.                 //接收客戶端連接  
  34.                 c = accept(mSock,&addr,&alen);  
  35.             }  while  (c <0 amp="" eintr="" errno="=" font="" nbsp="">
  36.               
  37.             //此處創建一個客戶端SocketClient加入mClients列表中,異步延遲處理  
  38.             的pthread_mutex_lock(&mClientsLock);  
  39.             mClients-> push_back(新的 SocketClient(c,  true ,mUseCmdNum));  
  40.             調用pthread_mutex_unlock(&mClientsLock);  
  41.         }  
  42.   
  43.         / *先將所有活動客戶端添加到待處理列表中* /  
  44.         pendingList->清晰();  
  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(*它);  
  51.             }  
  52.         }  
  53.         調用pthread_mutex_unlock(&mClientsLock);  
  54.   
  55.         //處理所有消息  
  56.         while  (!pendingList-> empty()){  
  57.             it = pendingList-> begin();  
  58.             SocketClient * c = * it;  
  59.             pendingList->擦除(它);  
  60.                //處理有數據發送的socket 虛函數  
  61.             if  (!onDataAvailable(c)&& mListen){  
  62.                // mListen為假  
  63.             }  
  64.         }  
  65.     }  
  66. }  
在消息循環中調用onDataAvailable處理消息,onDataAvailable是個虛函數,NetlinkListener重寫了此函數。

[cpp] 查看純文本 
  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->解碼(mBuffer,count,mFormat);  
  11.       
  12.     //處理NetlinkEvent onEvent虛函數  
  13.     onEvent(evt);  
  14. }  
將接收的Uevent數據轉化成NetlinkEvent數據,調用onEvent處理,NetlinkListener子類NetlinkHandler重寫了此函數。

[cpp] 查看純文本 
  1. void  NetlinkHandler :: onEvent(NetlinkEvent * evt){  
  2.   
  3.     //獲取VolumeManager實例  
  4.     VolumeManager * vm = VolumeManager :: Instance();  
  5.   
  6.     //設備類型  
  7.     const char  * subsys = possible-> getSubsystem();   
  8.                    
  9.     //將消息傳遞給VolumeManager處理  
  10.     如果 (!strcmp(subsys,  “block” )){  
  11.         VM>作用塊事件(如果有的話);  
  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對象


[cpp] 查看純文本 
  1. VolumeManager * VolumeManager :: Instance(){  
  2.     如果 (!sInstance)  
  3.         sInstance =  new  VolumeManager();  
  4.     返回 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.     //當UMS處於活動狀態時,將臟比率設置為20  
  15.     mUmsDirtyRatio = 20;  
  16.     mVolManagerDisabled = 0;  
  17. }  

2.啟動VolumeManager


[cpp] 查看純文本 
  1. int  VolumeManager :: start(){  
  2.     返回 0;  
  3. }  
VolumeManager啟動過程什麼都沒有做。

3.uevent事件處理

前面NetlinkManager模塊中介紹到,NetlinkHandler在onEvent函數中,將NetlinkEvent事件轉交給VolumeManager處理:

[cpp] 查看純文本 
  1. void  NetlinkHandler :: onEvent(NetlinkEvent * evt){  
  2.         ……  
  3.             //將消息傳遞給VolumeManager處理  
  4.         如果 (!strcmp(subsys,  “block” )){  
  5.             VM>作用塊事件(如果有的話);  
  6.         }  
  7. }  

[cpp] 查看純文本 
  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.           休息;  
  10.       }  
  11. }  
VolumeManager將消息交給各個DirectVolume對象處理:

[cpp] 查看純文本 
  1. int  DirectVolume :: handleBlockEvent(NetlinkEvent * possible){  
  2.     //從NetlinkEvent消息中取出有狀態變化設備路徑  
  3.     const char  * dp = evt-> findParam(“DEVPATH” );   
  4.   
  5.     PathCollection :: iterator它;  
  6.     //遍歷所有的存儲設備  
  7.     for  (it = mPaths-> begin(); it!= mPaths-> end(); ++ it){  
  8.         //根據存儲設備路徑進行匹配  
  9.         如果 (!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的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(“錯誤使設備節點'%s'(%s)” ,nodepath,strerror(errno));  
  24.                 }  
  25.                 //新增磁盤  
  26.                 如果 (!strcmp(devtype,  “disk” )){  
  27.                     handleDiskAdded(dp,如果有的話);  
  28.                 //新增分區  
  29.                 }  else  {  
  30.                     handlePartitionAdded(dp,如果有的話);  
  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.                 如果 (!strcmp(devtype,  “disk” )){  
  37.                     handleDiskRemoved(dp,如果有的話);  
  38.                 //刪除分區  
  39.                 }  else  {  
  40.                     handlePartitionRemoved(dp,如果有的話);  
  41.                 }  
  42.             //設備改變  
  43.             }  else if  (action == NetlinkEvent :: NlActionChange){   
  44.                 //磁盤變化  
  45.                 如果 (!strcmp(devtype,  “disk” )){  
  46.                     handleDiskChanged(dp,如果有的話);  
  47.                 //分區變化  
  48.                 }  else  {  
  49.                     handlePartitionChanged(dp,如果有的話);  
  50.                 }  
  51.             }  else  {  
  52.                     SLOGW(“忽略不添加/刪除/更改事件” );  
  53.             }  
  54.   
  55.             返回 0;  
  56.         }  
  57.     }  
  58.     errno = ENODEV;  
  59.     返回 -1;  
  60. }  
每一個Volume可能對應多個Path;即一個掛載點對應多個物理設備,因此VolumeManager中的每一個Volume對像都需要處理SD狀態變換消息,當新增一個disk時:
[cpp] 查看純文本 
  1. void  DirectVolume :: handleDiskAdded(const char  * devpath,NetlinkEvent *可選){   
  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(音量:: State_Idle);  
  13.     }  else  {  
  14.         //有分區未加載,設置Volume狀態Pending  
  15.         的setState(音量:: 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通知上層的消息流程圖:

[cpp] 查看純文本 
  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對象

[cpp] 查看純文本 
  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構造:
[cpp] 查看純文本 
  1. FrameworkListener :: FrameworkListener(const char  * socketName,  bool  withSeq):   
  2.                             SocketListener(socketName,  true ,withSeq){  
  3.     init(socketName,withSeq);  
  4. }  
直接調用init函數;
[cpp] 查看純文本 
  1. void  FrameworkListener :: init(const char  * socketName,  bool  withSeq){   
  2.     mCommands =  new  FrameworkCommandCollection();  
  3.     errorRate = 0;  
  4.     mCommandCount = 0;  
  5.     mWithSeq = withSeq;  
  6. }  
SocketListener的構造函數:
[cpp] 查看純文本 
  1. SocketListener :: SocketListener(const char  * socketName,  bool  listen,  bool  useCmdNum){   
  2.     init(socketName,-1,listen,useCmdNum);  
  3. }  
同樣調用init函數進行初始化:
[cpp] 查看純文本 
  1. void  SocketListener :: init(const char  * socketName,  int  socketFd,  bool  listen,  bool  useCmdNum){   
  2.     mListen = list;  
  3.     mSocketName = socketName;  
  4.     mSock = socketFd;  
  5.     mUseCmdNum = useCmdNum;  
  6.     pthread_mutex_init(&mClientsLock,NULL);  
  7.     mClients =  new  SocketClientCollection();  
  8. }  
構造CommandListener對象過程中,首先註冊了各種命令,並創建良一個socket客戶端連接。命令註冊過程:
[cpp] 查看純文本 
  1. void  FrameworkListener :: registerCmd(FrameworkCommand * cmd){  
  2.     mCommands->的push_back(CMD);  
  3. }  
將各種命令存放到mCommand列表中。

2.啟動CommandListener監聽

[cpp] 查看純文本 
  1. int  SocketListener :: startListener(){  
  2.     // mSocketName =“暴力”  
  3.     mSock = android_get_control_socket(mSocketName);  
  4.           
  5.     //NetlinkHandler mListen為true 監聽socket  
  6.     if  (mListen && <0 font="" nbsp="">
  7.         返回 -1;  
  8.     }  else if  (!mListen){   
  9.         mClients-> push_back(新的 SocketClient(mSock,  false ,mUseCmdNum));  
  10.     }  
  11.           
  12.     //創建匿名管道  
  13.     管(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 (obj);  
  20.     我 - > runListener();  
  21. }  
  22.   
  23. void  SocketListener :: runListener(){  
  24.     // SocketClient列表  
  25.     SocketClientCollection * pendingList =  new  SocketClientCollection();  
  26.   
  27.     (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.             如果 (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.         如果 (FD_ISSET(mCtrlPipe [0],&read_fds))  
  49.             休息;  
  50.   
  51.         //mListen 為true  
  52.         if  (mListen && FD_ISSET(mSock,&read_fds)){  
  53.             //mListen 為ture 表示正常監聽socket  
  54.             struct  sockaddr addr;  
  55.              {  
  56.                 c = accept(mSock,&addr,&alen);  
  57.             }  while  (c <0 amp="" eintr="" errno="=" font="" nbsp="">
  58.               
  59.             //創建一個客戶端SocketClient,加入mClients列表中 到異步延遲處理  
  60.             的pthread_mutex_lock(&mClientsLock);  
  61.             mClients-> push_back(新的 SocketClient(c,  true ,mUseCmdNum));  
  62.             調用pthread_mutex_unlock(&mClientsLock);  
  63.         }  
  64.   
  65.         / *先將所有活動客戶端添加到待處理列表中* /  
  66.         pendingList->清晰();  
  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(*它);  
  73.             }  
  74.         }  
  75.         調用pthread_mutex_unlock(&mClientsLock);  
  76.   
  77.         / *處理待處理列表,因為它由線程擁有,* /  
  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發過來的命令。


沒有留言: