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