Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Android存儲系統—Vold與MountService分析(二)

Android存儲系統—Vold與MountService分析(二)

編輯:關於android開發

  回顧:前貼主要分析了Android存儲系統的架構和原理圖,簡要的介紹了整個從Kernel-->Vold-->上層MountService之間的數據傳輸流程,在這樣的基礎上,我們開始今天的源碼分析!

  【源碼分析】

  1. Vold的main函數

  Vold也是通過init進程啟動,它在init.rc中的定義如下:

XML/HTML代碼
  1. service vold /system/bin/vold  
  2. class core  
  3. socket vold stream 0660 root mount  
  4. ioprio be 2  

  Vold服務放到了core分組,這就意味著系統啟動時,它就會被init進程啟動。這裡定義的一個socket,主要用語Vold和Java層的MountService通信。

  Vold模塊的源代碼位於system/vold,我們看看入口函數main(),代碼如下:

C++代碼
  1. int main() {  
  2.     VolumeManager *vm;  
  3.     CommandListener *cl;  
  4.     NetlinkManager *nm;  
  5.     SLOGI("Vold 2.1 (the revenge) firing up");  
  6.       
  7.     mkdir("/dev/block/vold", 0755);                 // 創建vold目錄  
  8.     klog_set_level(6);  
  9.     if (!(vm = VolumeManager::Instance())) {        // 創建VolumeManager對象  
  10.        exit(1);  
  11.    };  
  12.       
  13.    if (!(nm = NetlinkManager::Instance())) {       // 創建NetlinkManager對象  
  14.        exit(1);  
  15.    };  
  16.     cl = new CommandListener();                     // 創建CommandListener對象  
  17.    vm->setBroadcaster((SocketListener *) cl);      // 建立vm和cl的聯系  
  18.    nm->setBroadcaster((SocketListener *) cl);      // 建立nm和cl的聯系  
  19.     if (vm->start()) {                              // 啟動VolumeManager  
  20.        exit(1);  
  21.    }  
  22.     if (process_config(vm)) {                       // 創建文件/fstab.xxx中定義的Volume對象  
  23.        SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno));  
  24.    }  
  25.     cryptfs_pfe_boot();  
  26.     if (nm->start()) {                              // 啟動NetlinkManager,會調用NetlinkManager的start()方法,它創建PF_NETLINK socket,並開啟線程從此socket中讀取數據  
  27.        exit(1);  
  28.    }  
  29.     coldboot("/sys/block");                         // 冷啟動,創建/sys/block下的節點文件  
  30.     if (cl->startListener()) {                      // 開始監聽Framework的socket  
  31.        exit(1);  
  32.    }  
  33.      
  34.    while(1) {                                      // 進入循環  
  35.        sleep(1000);                                // 主線程進入休眠  
  36.    }  
  37.     SLOGI("Vold exiting");  
  38.    exit(0);  
  39. }  

  main函數的主要工作是創建3個對象:VolumeManager、NetlinkManager和CommandListener,同時將CommandListener對象分別設置到了VolumeManager對象和NetlinkManager對象中。

  從前貼的架構圖中可以發現,CommandListener對象用於和Java層的NativeDaemonConnector對象進行socket通信,因此,無論是VolumeManager對象還是NetlinkManager對象都需要擁有CommandListener對象的引用。

  2. 監聽驅動發出的消息—Vold的NetlinkManager對象

  NetlinkManager對象的主要工作是監聽驅動發出的uevent消息。

  main()函數中調用NetlinkManager類的靜態函數Instance()來創建NetlinkManager對象,代碼如下:

C++代碼
  1. NetlinkManager *NetlinkManager::Instance() {  
  2.       if (!sInstance)  
  3.           sInstance = new NetlinkManager();      // NetlinkManager對象通過靜態變量sInstance來引用,這意味著vold進程中只有一個NetlinkManager對象。  
  4.       return sInstance;  
  5. }  

  看下NetlinkManager的構造函數,代碼如下:

C++代碼
  1. NetlinkManager::NetlinkManager() {  
  2.       mBroadcaster = NULL;  
  3. }  

  NetlinkManager的構造函數只是對mBroadcaster進行了初始化。我們可以發現main()函數中通過調用NetlinkManager的setBroadcaster()函數來給變量mBroadcaster重新賦值。

C++代碼
  1. nm->setBroadcaster((SocketListener *) cl);  

  main()函數還調用了NetlinkManager的start()函數,我們觀察一下NetlinkManager中的start()方法,代碼如下:

C++代碼
  1. int NetlinkManager::start() {  
  2.      struct sockaddr_nl nladdr;  
  3.      int sz = 64 * 1024;  
  4.      int on = 1;  
  5.   
  6.      memset(&nladdr, 0, sizeof(nladdr));  
  7.      nladdr.nl_family = AF_NETLINK;  
  8.      nladdr.nl_pid = getpid();  
  9.      nladdr.nl_groups = 0xffffffff;  
  10.      /*創建一個socket用於內核空間和用戶空間的異步通信,監控系統的hotplug事件*/  
  11.      if ((mSock = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {  
  12.          SLOGE("Unable to create uevent socket: %s", strerror(errno));  
  13.          return -1;  
  14.      }  
  15.      /*設置緩沖區大小為64KB*/  
  16.      if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {  
  17.          SLOGE("Unable to set uevent socket SO_RCVBUFFORCE option: %s", strerror(errno));  
  18.          goto out;  
  19.      }  
  20.      /*設置允許 SCM_CREDENTIALS 控制消息的接收*/  
  21.      if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {  
  22.          SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));  
  23.          goto out;  
  24.      }  
  25.      /*綁定 socket 地址*/  
  26.      if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {  
  27.          SLOGE("Unable to bind uevent socket: %s", strerror(errno));  
  28.          goto out;  
  29.      }  
  30.      /*利用新創建的socket實例化一個NetlinkHandler類對象用於監聽socket,NetlinkHandler繼承了類NetlinkListener,NetlinkListener又繼承了類SocketListener*/  
  31.      mHandler = new NetlinkHandler(mSock);  
  32.       if (mHandler->start()) {                                               // 啟動NetlinkHandler,調用NetlinkHandler的start()函數  
  33.           SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));  
  34.           goto out;  
  35.      }  
  36.   
  37.      return 0;  
  38.   
  39. out:  
  40.      close(mSock);  
  41.      return -1;  
  42. }  

  我們看一下NetlinkManager的家族關系,如下圖:

Android存儲系統—Vold與MountService分析(二)

  上面的虛線為啟動時的調用流程:

  (1) class NetlinkManager(在其start函數中創建了NetlinkHandler對象,並把創建的socket作為參數)

  (2)class NetlinkHandler: public NetlinkListener(實現了onEvent)

  (3) class NetlinkListener : public SocketListener(實現了onDataAvailable)

  (4) class SocketListener(實現了runListener,在一個線程中通過select查看哪些socket有數據,通過調用onDataAvailable來讀取數據)。

  總結:此貼主要分析了Vold的main()函數和NetlinkManager對象的源碼,通過源碼了解對象的創建時機和函數調用流程,下一貼會繼續從NetlinkHandler的start()方法深入分析,繼續源碼的學習,很快會與大家見面,歡迎大家批評指正,我們互相學習。

  1. 上一頁:
  2. No
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved