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

来源:http://www.cnblogs.com/pepsimaxin/archive/2016/02/17/5194319.html
-Advertisement-
Play Games

Android的存儲系統(二) 回顧:前貼主要分析了Android存儲系統的架構和原理圖,簡要的介紹了整個從Kernel-->Vold-->上層MountService之間的數據傳輸流程,在這樣的基礎上,我們開始今天的源碼分析! 【源碼分析】 1. Vold的main函數 Vold也是通過init進


Android的存儲系統(二)

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

【源碼分析】

1. Vold的main函數

  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對象中。

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

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

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在Android版YouTube播放器API使您可以將視頻播放功能到你的Android應用程式。該API允許您載入和播放YouTube視頻(和播放列表),並自定義和控制視頻播放體驗。 您可以載入或暗示的視頻嵌入到你的應用程式的用戶界面的球員視圖。然後,您可以通過編程式控制制播放。例如播放,暫停,或尋求在
  • 本篇寫的是實現環形進度條,並帶動畫效果,要實現這些,僅能通過自己畫一個 方法直接看代碼 為了方便多次調用,用繼承UIView的方式 .m文件 1 #import <UIKit/UIKit.h> 2 3 @interface LoopProgressView : UIView 4 5 @propert
  • 游戲開發賺錢如此輕鬆? 手游席卷大中小學,你還在等什麼呢?
  • [_loadImageViewsetShowActivityIndicatorView:YES]; [_loadImageViewsetIndicatorStyle:UIActivityIndicatorViewStyleGray]; _loadImageView.contentMode = UIV
  • Android系統四層架構 個人網站:http://www.51pansou.com Android視頻下載:Android視頻 Android源碼下載:Android源碼 如果把Android系統看做一層一層的,那麼基本可以理解成以下結構(這是其中一種簡單的分層方式):1、最上層是應用層(Appl
  • 項目中的需求~~~~ 商城中物品的一個本身價格,還有一個就是優惠價格。。。需要用到一個刪除線。 public class TestActivity extends Activity { private TextView tv; @Override public void onCreate(Bundl
  • Android開發必看-快速提高 Android 開發效率的 Web 工具 本文摘自同行說用戶“Alex”分享的文章,原文鏈接:http://droidyue.com/blog/2014/08/03/great-web-tools-for-android-development/?comefrom=
  • 平常開發中對於啟動頁可能會有一些特別的要求,比如在啟動頁加動畫或加一些按鍵可以響應事件等,最近項目中要在啟動頁增加版本號,因為版本號是不斷的改變,所以要動態實現把它加到啟動頁上;在XCode上面配置的Launch Images Source或Launch Screen FIle(IOS8以上會優先調
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...