Android 2.1 Vold 分析

Android VoldVolume Daemon 

負責大容量存儲設備掛載和刪除的守護進程。

服務在init.rc中被開啓:

 

  1. service vold /system/bin/vold  
  2.     socket vold stream 0660 root mount  
 

 

本文主要分爲兩個部分:

 

·Vold 的架構分析

·Vold的功能總結

 

1.Vold的架構分析

 

Android Vold ,一方面負責接受內核發送的關於外部存儲設備加載和刪除的信息,然後將信息發送給framework層的MountService;另一方面負責執行MountService發送的命令。

這些cmdmes的傳遞主要是通過Socket通信來實現(Socket的通信的具體細節這裏不再贅述)。

下面從代碼的角度簡要分析這一過程的實現:

1.1在vold.c中,首先建立和framework層的通信:

  1. if ((door_sock = android_get_control_socket(VOLD_SOCKET)) < 0) {  
  2.     LOGE("Obtaining file descriptor socket '%s' failed: %s",  
  3.          VOLD_SOCKET, strerror(errno));  
  4.     exit(1);  
  5. }  
  6. if (listen(door_sock, 4) < 0) {  
  7.     LOGE("Unable to listen on fd '%d' for socket '%s': %s",   
  8.          door_sock, VOLD_SOCKET, strerror(errno));  
  9.     exit(1);  
  10. }  
 

其中,VOLD_SOCKETinit進程中創建,android_get_control_socket()主要是獲取VOLD_SOCKET的文件描述符。

Listern()主要用於監聽來自其他framework層的Socket連接請求。

 

framewok層,MountService開啓之後,會創建一個新的線程。在class MountService 的構造方法中:

 

  1. if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {  
  2.                 Thread thread = new Thread(mListener, MountListener.class.getName());  
  3.                 thread.start();  
  4.             }  
 

 

class MountListener 實現了Runnable接口,在它繼承的run()方法中創建了一個無限循環:

  1. while (true) {  
  2.                 listenToSocket();  
  3.             }  
 

 

listenToSocket()方法中:

 

  1.   socket = new LocalSocket();  
  2.   LocalSocketAddress address = new LocalSocketAddress(VOLD_SOCKET,   
  3.           LocalSocketAddress.Namespace.RESERVED);  
  4.   socket.connect(address);  
  5.   InputStream inputStream = socket.getInputStream();  
  6.   mOutputStream = socket.getOutputStream();  
  7. ····································  
  8.   while (true) {  
  9.       int count = inputStream.read(buffer);  
  10.       if (count < 0) break;  
  11.       int start = 0;  
  12.       for (int i = 0; i < count; i++) {  
  13.           if (buffer[i] == 0) {  
  14.               String event = new String(buffer, start, i - start);  
  15.               handleEvent(event);  
  16.               start = i + 1;  
  17.           }                     
  18.       }  
  19.   }    
  

首先,實例化一個本地的LocalSocket 用於與Vold的通信,其次建立與VOLD_SOCKET的連接。然後再建立一個文件輸入流,用於保存Vold傳來的mesbuff中。最後,在一個無線循環中讀取buff的內容,並執行handleEvent()

handleEvent()中通過if else語句對傳來的事件做相應處理

 

  1. if (event.equals(VOLD_EVT_UMS_ENABLED)) {  
  2.             ................  
  3.         } else if (event.equals(VOLD_EVT_UMS_DISABLED)) {  
  4.             ................  
  5.         } else if (event.equals(VOLD_EVT_EXTERNAL_UMS_CONNECTED)) {  
  6.             ...............            
  7.             mService.notifyUmsConnected(path);                   
  8.             .....................  
  9.         } else if (event.equals(VOLD_EVT_UMS_CONNECTED)) {  
  10.             ...........................  
  11.             mService.notifyUmsConnected(path);               
  12.         } else if (event.equals(VOLD_EVT_EXTERNAL_UMS_DISCONNECTED)) {  
  13.              .........................  
 

對於其中一個事件的處理,例如.notifyUmsConnected():

 

最後,將處理之後需要執行的命令發送給vold

 

到現在爲止,我們就建立了vold MountService之間的通信。

 

1.2建立與內核的socket通信

  1. ....................  
  2. Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED);  
  3.         mContext.sendBroadcast(intent);     
  4. ....................     
  
  1. if ((uevent_sock = socket(PF_NETLINK,  
  2.                              SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {  
  3. ........  
  4.     }  
  5.     if (setsockopt(uevent_sock, SOL_SOCKET, SO_RCVBUFFORCE, &uevent_sz,  
  6.                    sizeof(uevent_sz)) < 0) {  
  7. .......  
  8.     }  
  9.     if (bind(uevent_sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {  
  10.      ......  
  11.     }  
 

創建一個uevent_sock,建立與內核的通信。setsockopt()函數主要用於設置uevent_sock的選項,bind()用於將內核的socketuevent_sock進行地址的綁定。

 

1.3掛載現有存儲設備

 

volmgr_bootstrap()函數首先解析配置文件vold.conf

最後會將需要掛載的設備信息放在一個全局變量的鏈表中val_root

static volume_t *vol_root = NULL;

1.4掛載mmc/sdcard

  1. volmgr_bootstrap();  
  2. simulate_uevent()確定uevent的action是'add','remove'還是'change';  
  3. if ((rc = volmgr_readconfig("/system/etc/vold.conf")) < 0) {  
  4.         LOGE("Unable to process config");  
  5.         return rc;  
  6.     }  
 

mmc_bootstrap()

 

dipatch_uevent():根據uevent->subsystem確定uevent處理的句柄。

 

 

  1. struct uevent {  
  2.     const char *action;  
  3.     const char *path;  
  4.     const char *subsystem;  
  5.     const char *firmware;  
  6.     int major;  
  7.     int minor;  
  8. };  
 

 

最終的掛載操作在MountService開啓之後實現

1.5 usb大容量存儲的處理ums_bootstrap()

 

1.6 switch_bootstrap()

 

1.7主服務(死循環)

 

  1. struct uevent_dispatch {  
  2.     char *subsystem;  
  3.     int (* dispatch) (struct uevent *);  
  4. };  
 
  1. while(1) {  
  2.        ········  
  3.         FD_ZERO(&read_fds);//初始化文件描述集合  
  4.         FD_SET(door_sock, &read_fds);//將door_sock加入文件描述集  
  5.         if (door_sock > max)  
  6.             max = door_sock;  
  7.         FD_SET(uevent_sock, &read_fds);//將event_sock加入文件描述集  
  8.         if (uevent_sock > max)  
  9.             max = uevent_sock;  
  10.         if (fw_sock != -1) {  
  11.             FD_SET(fw_sock, &read_fds);//將fw_sock加入文件描述集  
  12.             if (fw_sock > max)  
  13.                 max = fw_sock;  
  14.         }  
  15.        //當所有的文件描述符都沒改變時,阻塞線程  
  16.         if ((rc = select(max + 1, &read_fds, NULL, NULL, &to)) < 0) {  
  17.             LOGE("select() failed (%s)", strerror(errno));  
  18.             sleep(1);  
  19.             continue;  
  20.         }  
  21.         if (!rc) {  
  22.             continue;  
  23.         }  
  24.         //檢測如果是door_sock,檢測與framework的連接,併發送msg  
  25.         if (FD_ISSET(door_sock, &read_fds)) {  
  26.             struct sockaddr addr;  
  27.             socklen_t alen;  
  28.             alen = sizeof(addr);  
  29.             if (fw_sock != -1) {  
  30.                 LOGE("Dropping duplicate framework connection");  
  31.                 int tmp = accept(door_sock, &addr, &alen);  
  32.                 close(tmp);  
  33.                 continue;  
  34.             }  
  35.             if ((fw_sock = accept(door_sock, &addr, &alen)) < 0) {  
  36.                 LOGE("Unable to accept framework connection (%s)",  
  37.                      strerror(errno));  
  38.             }  
  39.             LOG_VOL("Accepted connection from framework");  
  40. /* for iNand */  
  41. volmgr_usb_bootstrap();  
  42.             if ((rc = volmgr_send_states()) < 0) {  
  43.                 LOGE("Unable to send volmgr status to framework (%d)", rc);  
  44.             }  
  45.         }  
  46.         //如果是fw_sock,執行framework傳來的命令  
  47.         if (FD_ISSET(fw_sock, &read_fds)) {  
  48.             if ((rc = process_framework_command(fw_sock)) < 0) {  
  49.                 if (rc == -ECONNRESET) {  
  50.                     LOGE("Framework disconnected");  
  51.                     close(fw_sock);  
  52.                     fw_sock = -1;  
  53.                 } else {  
  54.                     LOGE("Error processing framework command (%s)",  
  55.                          strerror(errno));  
  56.                 }  
  57.             }  
  58.         }  
  59.       //如果是uevent_sock,產生一個uevent事件  
  60.         if (FD_ISSET(uevent_sock, &read_fds)) {  
  61.             if ((rc = process_uevent_message(uevent_sock)) < 0) {  
  62.                 LOGE("Error processing uevent msg (%s)", strerror(errno));  
  63.             }  
  64.         }  
  65.     } // while  
 

 

2.Vold的功能總結

1)創建連接:
     在vold作爲一個守護進程,一方面接受驅動的信息,並把信息傳給應用層;另一方面接受上層的命令並完成相應操作。
     所以這裏的連接一共有兩條:
       ·vold socket: 負責vold與應用層的信息傳遞;
       ·訪問udevsocket: 負責vold與底層的信息傳遞;
     這兩個連接都是在進程的一開始完成創建的。

 

     2)引導
     這裏主要是在vold啓動時,對現有外設存儲設備的處理。

·首先,要加載並解析vold.conf,並檢查掛載點是否已經被掛載;

·其次,執行MMC卡掛載; 

·最後,處理USB大容量存儲。

 

     3)事件處理:
     這裏通過對兩個連接的監聽,完成對動態事件的處理,以及對上層應用操作的響應。

補充:

Telechips比較google原生Android 針對Vold的移植主要在以下兩方面:

1.Telchips支持多種存儲設備,例如nand,sata,scsi,mmc/sd;從代碼角度而言,主要增加了對這些設備事件的處理句柄;

2.Telchips加入了對ntfs的支持,主要增加了三個處理函數:ntfs_check(),ntfs_identify()和ntfs_mount();

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