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

Android的存儲系統(二)html

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

【源碼分析】異步

1. Vold的main函數socket

  Vold也是經過init進程啓動,它在init.rc中的定義以下:函數

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(),代碼以下:學習

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

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

  從前貼的架構圖中能夠發現,CommandListener對象用於和Java層的NativeDaemonConnector對象進行socket通訊,所以,不管是VolumeManager對象仍是NetlinkManager對象都須要擁有CommandListener對象的引用。spa

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

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

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

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

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

1 NetlinkManager::NetlinkManager() {
2       mBroadcaster = NULL;
3

  NetlinkManager的構造函數只是對mBroadcaster進行了初始化。咱們能夠發現main()函數中經過調用NetlinkManager的setBroadcaster()函數來給變量mBroadcaster從新賦值。

nm->setBroadcaster((SocketListener *) cl);

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

 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的家族關係,以下圖:

  上面的虛線爲啓動時的調用流程:

  (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()方法深刻分析,繼續源碼的學習,很快會與你們見面,歡迎你們批評指正,咱們互相學習。
相關文章
相關標籤/搜索