圖說Android Binder機制

背景


  Binder機制阵翎,是Android系統(tǒng)跨進程協(xié)作的核心怜俐。我們知道器紧,每個應用獨立地運行在自己的進程虛擬地址空間中伞租,就像是獨自占有CPU、內存等資源十性,相互之間不可見叛溢。Android系統(tǒng)中的一個個應用,亦如一個個信息孤島烁试。正是Binder這樣的跨進程訪問機制雇初,提供了孤島之間溝通的橋梁。

Binder是應用之間溝通的橋梁

  如上圖所示减响,鑒于安全和效率的考慮,Android系統(tǒng)服務提供是一種典型的C/S架構郭怪,如果希望獲取系統(tǒng)服務支示,就必須進程IPC請求,而Binder正是數(shù)據(jù)交互的核心鄙才。
  平時做應用開發(fā)颂鸿,其實很少會操心這種底層機制,但是設計思想?yún)s是通用的攒庵,為了學習它的這種思想嘴纺,同時弄懂Binder機制,更好地進行應用開發(fā)浓冒,這幾天找了很多資料≡钥剩現(xiàn)在開始,才有那么點繞出來的感覺稳懒。這里闲擦,不談源碼實現(xiàn),通過對各種資料的匯集,更多的以圖的形式通俗展現(xiàn)Binder的內部機制墅冷。

Binder通信基礎


  就整個通信過程纯路,將圍繞著數(shù)據(jù)傳遞的前提,數(shù)據(jù)如何傳遞寞忿,以及傳遞背后的協(xié)議來展開驰唬。

用戶空間和內核空間---誰來中轉數(shù)據(jù)

  我們知道,進程運行在虛擬地址空間腔彰,鑒于安全考慮定嗓,這塊空間被分為用戶空間和內核空間。其中萍桌,用戶空間的執(zhí)行權限較低宵溅,凡是需要訪問物理設備、IO等上炎,都需要通過系統(tǒng)調用的方式恃逻,由內核代碼在內核空間運行。如下圖所示:

用戶空間和內核空間的關系

  由上圖可知藕施,每個進程通過系統(tǒng)調用進入內核寇损,Linux內核空間由系統(tǒng)內的所有進程共享。從進程的角度看裳食,每個進程擁有4G的虛擬空間矛市。每個進程有各自的私有用戶空間(0-3G),這個空間對系統(tǒng)的其他進程是不可見的诲祸。最高的1G內核空間則為所有進程以及內核所共享浊吏。這段共享的內核空間,就構成了傳統(tǒng)Linux系統(tǒng)中數(shù)據(jù)不同進程之間數(shù)據(jù)交換的基礎救氯。更進一步找田,是依賴兩個函數(shù):

進程空間、內核空間與物理地址之間的轉換關系

數(shù)據(jù)通過 copy_from_user 來到內核空間着憨,通過copy_to_user 返回給用戶空間墩衙。
由上可知,數(shù)據(jù)的傳輸過程至少需要對數(shù)據(jù)進行兩次拷貝甲抖,但是在 Android 中又有不同漆改,為了數(shù)據(jù)的高效傳輸,它對數(shù)據(jù)的拷貝僅需要一次准谚,原因在于:Server 進程在通過 open 打開 Binder 驅動(在此處傳入了進程信息挫剑,即 binder_proc),使用 mmap 進行內存映射的時候氛魁,映射出的物理內存同時存在于內核空間和 Server 所運行的 Binder 進程的用戶空間暮顺。而內核空間和用戶空間都是虛擬邏輯空間厅篓。這樣,當數(shù)據(jù) copy_from_user 之后存在內核空間捶码,這頁內存空間所在的實際物理空間實際上也對應于用戶空間羽氮。這樣,就無需在執(zhí)行 copy_to_user的操作惫恼。

Android 數(shù)據(jù)跨進程傳輸過程
序列化與反序列化---什么樣的數(shù)據(jù)完成進程穿透

  那么档押,什么樣的數(shù)據(jù),能夠方便祈纯、安全地穿透進程間壁壘令宿,完成進程間通信呢?
  序列化數(shù)據(jù)腕窥。在應用層粒没,就是一個Parcel對象。
  關于序列化和反序列化簇爆,下面的這張圖癞松,描述的很清楚。

數(shù)據(jù)的轉換過程

  如上圖所示入蛆,我們都做過將一張紙裁剪成正方體的游戲∠烊兀現(xiàn)在將正方體拆開,還原成平面的紙哨毁,然后通過傳真機發(fā)送到遠端枫甲,在遠端接收后,安裝紙面上的軌跡扼褪,還原這個正方體想幻。
  實際上,這給了我們啟示迎捺,在面向對象的世界里举畸,一個復雜的對象該如何在不同進程中傳遞的思路,這是說我們需要把一個復雜的對象的簡化了凳枝,變得平滑,轉換成基礎數(shù)據(jù)結構(int ,float,long等)跋核,發(fā)送到遠端后岖瑰,再從遠端復原成復雜對象。

 public class MyParcelable implements Parcelable {
     private int mData;

     public int describeContents() {
         return 0;
     }
     //轉換成Parcel對象砂代,完成序列化
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mData);
     }
     //從Parcel轉換成原對象蹋订,完成反序列化
     public static final Parcelable.Creator<MyParcelable> CREATOR
             = new Parcelable.Creator<MyParcelable>() {
         public MyParcelable createFromParcel(Parcel in) {
             return new MyParcelable(in);
         }

         public MyParcelable[] newArray(int size) {
             return new MyParcelable[size];
         }
     };
     
     private MyParcelable(Parcel in) {
         mData = in.readInt();
     }
 }
來一發(fā)服務請求---協(xié)議保證

  什么是協(xié)議?協(xié)議就是雙方的約定刻伊,就是規(guī)矩露戒,就是格式椒功。下面,我們來看看一個實際遠程調用過程的數(shù)據(jù)穿透協(xié)議智什。

跨進程調用

  上圖實際執(zhí)行了系統(tǒng)服務MediaPlayer的setVolume(float,float)函數(shù)調用過程动漾,而執(zhí)行的實體實際上是遠端的服務進程。
  數(shù)據(jù)write_buffer實際上是通過copy_from_user傳遞到內核空間荠锭。傳遞的內容旱眯,在上圖中一目了然,主要包括類(android.media.IMediaPlayer)证九,方法(通過數(shù)字26映射)删豺,參數(shù)(1.0,1.0)。以上愧怜,就是函數(shù)調用從用戶空間被傳遞到內核空間呀页,通過Binder驅動發(fā)送到實際執(zhí)行的遠程服務進程完成執(zhí)行操作。

Binder通信機制


  上面拥坛,我們該對整個通信過程有了一個大概的印象蓬蝶,應該已經(jīng)清楚,數(shù)據(jù)從哪里來渴逻,如何穿透進程壁壘以及穿透的基礎疾党。接下來,我們先來通過下圖澄清幾個概念惨奕。

Binder通信的粗略過程
  • Binder驅動:一個內核層級的驅動雪位,促成了進程間通信。有人把它比作網(wǎng)絡通信中的路由器梨撞,而路由器的作用雹洗,就是從原地址存儲轉發(fā)數(shù)據(jù)目的地址,很貼切卧波。
  • Binder對象:是IBinder接口的實現(xiàn)时肿。實際上就是遠程服務動作的實際執(zhí)行者。
  • BinderToken:也有叫 handler 的港粱。實際上就是一個32位的整型值螃成,唯一的代表了一個遠端Binder對象。
  • Binder Service:實際持有Binder對象查坪,處理業(yè)務邏輯寸宏。
  • Binder Client:請求Binder服務者。
  • Proxy:實現(xiàn)了AIDL接口偿曙,能夠序列化/反序列化數(shù)據(jù)結構氮凝,同時能夠通過Binder引用進程遠程調用。
  • Stub:能夠序列化和反序列化數(shù)據(jù)望忆,并把轉換過程映射到實際的服務端的方法調用罩阵。
  • Context Manager:一個注冊 handler(句柄)為0的特殊Binder對象竿秆。通過name到handler的映射關系,注冊和查找別的Binder對象稿壁。也有人把它對應為DNS服務器幽钢。DNS服務器的作用,就是通過IP地質到域名的映射常摧,提供查找和注冊搅吁。即我們向DNS服務器注冊自己的IP,并把它映射到一個域名落午;這樣谎懦,別人就可以通過域名來訪問我們的主機,因為DNS服務器將把這個域名轉換為IP溃斋。

把上圖再細致一點界拦,放大,如下圖所示:


Binder通信詳細過程

Client:

  1. 首先梗劫,客戶端從ContextManager中通過服務名享甸,拿到遠程服務的handler(句柄),也就是binder token梳侨。
  2. 調用遠程服務的 foo 方法蛉威,然后序列化參數(shù);
  3. 通過 transact 把調用相關的資料提交給 libbinder處理走哺;
  4. 由 libbinder 通過ioctl進程系統(tǒng)調用蚯嫌,將foo調用請求提交給binder驅動;
  5. binder驅動通過handler找到真正的遠端服務進程丙躏,然后通過ioctl函數(shù)將foo調用傳遞給遠端服務進程的 libbinder择示;
  6. 遠端libbinder將調用交給Stub;
  7. 在Stub中晒旅,反序列化調用信息栅盲,還原;
  8. Stub找到實際服務提供者废恋,執(zhí)行客戶端的請求谈秫;
  9. 將結果序列化
    ......
    再通過Binder驅動,返回給客戶端鱼鼓。

Server:
主要是在ContextManager中完成注冊(name -> handler)孝常;等待接收Binder驅動發(fā)來的請求。

Binder限制


在使用Binder進程跨進程調用的時候蚓哩,有兩個重要的限制需要注意:

  • 一個服務進程中最多同時支持15個binder線程處理請求;
  • 一個進程中用戶交互穿透數(shù)據(jù)的緩存大小最多為1M上渴,這就意味著岸梨,在傳遞的數(shù)據(jù)是有限的喜颁,如果資源耗盡,會拋出異常曹阔。

最后


作為一個應用開發(fā)者半开,對本質對底層的C實現(xiàn)機制,有些技癢赃份,但是久未使用過C寂拆,想從源碼的角度深入分析,需要花費更多精力抓韩,目前似乎又沒有這個必要纠永,那么,就先淺嘗輒止谒拴,不求甚解尝江。如有不對的地方,還請指出英上。
收獲炭序,就在于對序列化、反序列化的認識苍日;對數(shù)據(jù)結構化的認識惭聂;從Binder框架的認識;以后再讀源碼的時候相恃,不會被各種服務調用搞的暈頭轉向辜纲;再有就是對AIDL的使用上,不用再死記硬背如何通過AIDL進程跨進程調用了豆茫。
后面侨歉,會寫一下AIDL跨進程調用過程。
本文參考鏈接:
https://blog.checkpoint.com/wp-content/uploads/2015/02/Man-In-The-Binder-He-Who-Controls-IPC-Controls-The-Droid-wp.pdf
https://events.linuxfoundation.org/images/stories/slides/abs2013_gargentas.pdf
https://www.dre.vanderbilt.edu/~schmidt/cs282/PDFs/android-binder-ipc.pdf
想要深入源碼和數(shù)據(jù)結構的同學揩魂,可以參考以下鏈接:
http://gityuan.com/2015/11/01/binder-driver/
http://www.cloudchou.com/android/post-507.html
http://www.reibang.com/p/1050ce12bc1e
http://blog.csdn.net/universus/article/details/6211589#comments
https://github.com/xdtianyu/SourceAnalysis/blob/master/Binder%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90.md
或者幽邓,自己去找binder.c 和 binder.h 這兩個文件來看吧。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末火脉,一起剝皮案震驚了整個濱河市牵舵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌倦挂,老刑警劉巖畸颅,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異方援,居然都是意外死亡没炒,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門犯戏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來送火,“玉大人拳话,你說我怎么就攤上這事≈治” “怎么了弃衍?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長坚俗。 經(jīng)常有香客問我镜盯,道長,這世上最難降的妖魔是什么猖败? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任速缆,我火速辦了婚禮,結果婚禮上辙浑,老公的妹妹穿的比我還像新娘激涤。我一直安慰自己,他們只是感情好判呕,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布倦踢。 她就那樣靜靜地躺著,像睡著了一般侠草。 火紅的嫁衣襯著肌膚如雪辱挥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天边涕,我揣著相機與錄音晤碘,去河邊找鬼。 笑死功蜓,一個胖子當著我的面吹牛园爷,可吹牛的內容都是我干的。 我是一名探鬼主播式撼,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼童社,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了著隆?” 一聲冷哼從身側響起扰楼,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎美浦,沒想到半個月后弦赖,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡浦辨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年蹬竖,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡案腺,死狀恐怖庆冕,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情劈榨,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布晦嵌,位于F島的核電站同辣,受9級特大地震影響,放射性物質發(fā)生泄漏惭载。R本人自食惡果不足惜旱函,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望描滔。 院中可真熱鬧棒妨,春花似錦、人聲如沸含长。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拘泞。三九已至纷纫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間陪腌,已是汗流浹背辱魁。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留诗鸭,地道東北人染簇。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像强岸,于是被迫代替她去往敵國和親锻弓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內容