借助 AIDL 理解 Android Binder 機制——Binder 來龍去脈

AIDL 是 Android Interface Definition Language(Android 接口定義語言)的縮寫碘举,它是 Android 進程間通信的接口語言。由于 Android 系統(tǒng)的內(nèi)核是 Linux鼻听,它采用了進程隔離機制,使得不同的應(yīng)用程序運行在不同的進程當中联四,有時候兩個應(yīng)用之間需要傳遞或者共享某些數(shù)據(jù)撑碴,就需要進行進程間的通信訊。

Android 進程間通信的方式有很多種朝墩,比如 Messenger醉拓、文件(SharePreference)、AIDL、Socket 和 Content Provider 等亿卤,它們當中 Messenge愤兵、AIDL 和 Content Provider 的底層都是依賴于 Binder 機制去實現(xiàn)的。除此之外排吴,Android 四大組件的啟動和通信的核心過程也是通過 Binder 機制去實現(xiàn)的秆乳,這里,我們借助 AIDL 來了解 Binder 的實現(xiàn)機制钻哩。

在了解 AIDL 機制和用法之前屹堰,首先要了解幾個概念,這對后續(xù)的深入理解有較大的幫助街氢。

進程隔離

以下內(nèi)容來自維基百科

進程隔離是為保護操作系統(tǒng)中進程互不干擾而設(shè)計的一組不同硬件和軟件的技術(shù)扯键。這個技術(shù)是為了避免進程 A 寫入進程 B 的情況發(fā)生。 進程的隔離實現(xiàn)阳仔,使用了虛擬地址空間忧陪。進程 A 的虛擬地址和進程B的虛擬地址不同,這樣就防止進程 A 將數(shù)據(jù)信息寫入進程 B近范。

Linux IPC 原理

由于 Linux 采用了虛擬地址空間技術(shù)嘶摊,操作系統(tǒng)在邏輯上將虛擬內(nèi)存分為用戶空間(User Space)內(nèi)核空間(Kernel Space),普通應(yīng)用程序運行在用戶空間评矩,系統(tǒng)內(nèi)核運行在內(nèi)核空間叶堆,為了控制應(yīng)用程序的訪問范圍、保證系統(tǒng)安全斥杜,用戶空間只能通過系統(tǒng)調(diào)用的方式去訪問內(nèi)核空間虱颗。當進程執(zhí)行系統(tǒng)調(diào)用而陷入內(nèi)核代碼的時候,該進程則進入了內(nèi)核態(tài)蔗喂,相比之下忘渔,進程在用戶空間執(zhí)行自己的代碼的時候,則是處于用戶態(tài)缰儿。

由于進程 A 和進程 B 的虛擬地址不同畦粮,因此它們之間是相互透明的,都以為自己獨享了系統(tǒng)的資源乖阵,當然也不能直接跟對方交互宣赔。但是,有些情況下有些進程難免會需要跟其他進程進行交互瞪浸,這個交互過程就叫 IPC(Inter-Process Communication儒将,進程間通信)。IPC 的實質(zhì)就是數(shù)據(jù)的交互对蒲,因此我們這里將進行 IPC 過程中的通信調(diào)用方和被調(diào)用放分別稱為數(shù)據(jù)發(fā)送方和數(shù)據(jù)接收方钩蚊,IPC 通信的過程如下:

  1. 數(shù)據(jù)發(fā)送方進程將數(shù)據(jù)放在內(nèi)存緩存區(qū)贡翘,通過系統(tǒng)調(diào)用陷入內(nèi)核態(tài)
  2. 內(nèi)核程序在內(nèi)核空間開辟一塊內(nèi)核緩存區(qū),通過 copy_from_user 函數(shù)將數(shù)據(jù)從數(shù)據(jù)發(fā)送方用戶空間的內(nèi)存緩存區(qū)拷貝到內(nèi)核空間的內(nèi)核緩存區(qū)中
  3. 數(shù)據(jù)接收方進程在自己的用戶空間開辟一塊內(nèi)存緩存區(qū)
  4. 內(nèi)核程序?qū)?nèi)核緩存區(qū)中通過 copy_to_user 函數(shù)將數(shù)據(jù)拷貝到數(shù)據(jù)接收方進程的內(nèi)存緩存區(qū)
Linux IPC

通過以上過程两疚,一次 IPC 就完成了床估,但是這種傳統(tǒng)的 IPC 機制有兩個問題:

  • 性能比較低:整個過程數(shù)據(jù)的傳遞需要經(jīng)歷發(fā)送方內(nèi)存緩存區(qū)——內(nèi)核緩存區(qū)——接收方內(nèi)存緩存區(qū)的過程
  • 接收方進程事先不知道需要開辟多大的內(nèi)存用于存放數(shù)據(jù),因此需要開辟盡可能大的空間或者事先調(diào)用 API 來解決這個問題诱渤,這兩種方式不是浪費空間就是浪費時間丐巫。

Binder IPC 原理

為了克服 Linux 傳統(tǒng)的 IPC 機制中的不足之處,Android 系統(tǒng)引入了 Binder 機制勺美,從字面上看 Binder 是膠水的意思递胧,在這里,Binder 的職責是在不同的進程之間扮演一個橋梁的角色赡茸,讓它們之間能夠相互通信缎脾。從上一小節(jié)內(nèi)容可以了解到,進程間的通訊少不了 Linux 內(nèi)核的支持占卧,而 Binder 并不屬于內(nèi)核的一部分遗菠,但是,得益于 Linux 的 LKM(Loadable Kernel Module) 機制:

模塊是具有獨立功能的程序华蜒,它可以被單獨編譯辙纬,但不能獨立運行。它在運行時被鏈接到內(nèi)核作為內(nèi)核的一部分在內(nèi)核空間運行

因此叭喜,Binder 作為這種模塊存在于內(nèi)核之中贺拣,也稱為 Binder 驅(qū)動∥嬖蹋回顧上一小節(jié)的內(nèi)容譬涡,傳統(tǒng) Linux IPC 的過程需要經(jīng)歷兩次數(shù)據(jù)拷貝,Binder 借助 Linux 的另一個特性啥辨,只用一次數(shù)據(jù)拷貝涡匀,就能實現(xiàn) IPC 過程,這就是內(nèi)存映射

Binder IPC 機制中涉及到的內(nèi)存映射通過 mmap() 來實現(xiàn)溉知,mmap() 是操作系統(tǒng)中一種內(nèi)存映射的方法渊跋。內(nèi)存映射簡單的講就是將用戶空間的一塊內(nèi)存區(qū)域映射到內(nèi)核空間,映射關(guān)系建立后着倾,用戶對這塊內(nèi)存區(qū)域的修改可以直接反應(yīng)到內(nèi)核空間;反之內(nèi)核空間對這段區(qū)域的修改也能直接反應(yīng)到用戶空間燕少。

內(nèi)存映射能減少數(shù)據(jù)拷貝次數(shù)卡者,實現(xiàn)用戶空間和內(nèi)核空間的高效互動。兩個空間各自的修改能直接反映在映射的內(nèi)存區(qū)域客们,從而被對方空間及時感知崇决。也正因為如此材诽,內(nèi)存映射能夠提供對進程間通信的支持。

Binder IPC 通信過程如下:

  1. Binder 驅(qū)動在內(nèi)核空間創(chuàng)建一個數(shù)據(jù)接收緩存區(qū)
  2. 然后在內(nèi)核空間開辟一塊內(nèi)存緩存區(qū)并與數(shù)據(jù)接收緩存區(qū)建立映射關(guān)系恒傻,同時脸侥,建立數(shù)據(jù)接收緩存區(qū)數(shù)據(jù)接收方的內(nèi)存緩存區(qū)的映射關(guān)系
  3. 數(shù)據(jù)發(fā)送方通過系統(tǒng)調(diào)用 copy_from_user 函數(shù)將數(shù)據(jù)從內(nèi)存緩存區(qū)拷貝到內(nèi)核緩存區(qū),由于內(nèi)核緩存區(qū)通過數(shù)據(jù)接收緩存區(qū)跟數(shù)據(jù)接收方的內(nèi)存緩存區(qū)存在間接的映射關(guān)系盈厘,相當于將數(shù)據(jù)直接拷貝到了接收方的用戶空間睁枕,這樣便完成了一次 IPC 的過程。
Android IPC

Binder 通信模型和通信過程

在進行 Binder IPC 的時候沸手,實際情況比上面介紹的要復(fù)雜外遇,Binder 通訊模型是基于 C/S 架構(gòu)的,通信調(diào)用方進程稱為 Client 進程契吉,被調(diào)用方稱為 Server 進程跳仿,除此之外還需要 ServiceManager 和 Binder 驅(qū)動的參與,它們都是通過 open/mmap/iotl 等系統(tǒng)調(diào)用來訪問設(shè)備文件 dev/binder 來實現(xiàn) IPC 過程的捐晶。

Binder IPC module

其中菲语,Client、Server 和 ServiceManager 運行在用戶空間惑灵,Binder Driver 運行在內(nèi)核空間山上,Client 和 Server 需由用戶自己實現(xiàn),ServiceManager 和 Binder Driver 則由系統(tǒng)提供泣棋。

Android Binder 設(shè)計與實現(xiàn) 文章中對 Client 和 Server 等角色有詳細的描述:

Binder 驅(qū)動:
Binder 驅(qū)動就如同路由器一樣胶哲,是整個通信的核心;驅(qū)動負責進程之間 Binder 通信的建立潭辈,Binder 在進程之間的傳遞鸯屿,Binder 引用計數(shù)管理,數(shù)據(jù)包在進程之間的傳遞和交互等一系列底層支持把敢。

ServiceManager 與實名 Binder:
ServiceManager 和 DNS 類似寄摆,作用是將字符形式的 Binder 名字轉(zhuǎn)化成 Client 中對該 Binder 的引用,使得 Client 能夠通過 Binder 的名字獲得對 Binder 實體的引用修赞。注冊了名字的 Binder 叫實名 Binder婶恼,就像網(wǎng)站一樣除了除了有 IP 地址意外還有自己的網(wǎng)址。Server 創(chuàng)建了 Binder柏副,并為它起一個字符形式勾邦,可讀易記得名字,將這個 Binder 實體連同名字一起以數(shù)據(jù)包的形式通過 Binder 驅(qū)動發(fā)送給 ServiceManager 割择,通知 ServiceManager 注冊一個名為“張三”的 Binder眷篇,它位于某個 Server 中。驅(qū)動為這個穿越進程邊界的 Binder 創(chuàng)建位于內(nèi)核中的實體節(jié)點以及 ServiceManager 對實體的引用荔泳,將名字以及新建的引用打包傳給 ServiceManager蕉饼。ServiceManger 收到數(shù)據(jù)后從中取出名字和引用填入查找表虐杯。

細心的讀者可能會發(fā)現(xiàn),ServierManager 是一個進程昧港,Server 是另一個進程擎椰,Server 向 ServiceManager 中注冊 Binder 必然涉及到進程間通信。當前實現(xiàn)進程間通信又要用到進程間通信创肥,這就好像蛋可以孵出雞的前提卻是要先找只雞下蛋达舒!Binder 的實現(xiàn)比較巧妙,就是預(yù)先創(chuàng)造一只雞來下蛋瓤的。ServiceManager 和其他進程同樣采用 Bidner 通信休弃,ServiceManager 是 Server 端,有自己的 Binder 實體圈膏,其他進程都是 Client塔猾,需要通過這個 Binder 的引用來實現(xiàn) Binder 的注冊,查詢和獲取稽坤。ServiceManager 提供的 Binder 比較特殊丈甸,它沒有名字也不需要注冊。當一個進程使用 BINDERSETCONTEXT_MGR 命令將自己注冊成 ServiceManager 時 Binder 驅(qū)動會自動為它創(chuàng)建 Binder 實體(這就是那只預(yù)先造好的那只雞)尿褪。其次這個 Binder 實體的引用在所有 Client 中都固定為 0 而無需通過其它手段獲得睦擂。也就是說,一個 Server 想要向 ServiceManager 注冊自己的 Binder 就必須通過這個 0 號引用和 ServiceManager 的 Binder 通信杖玲。類比互聯(lián)網(wǎng)顿仇,0 號引用就好比是域名服務(wù)器的地址,你必須預(yù)先動態(tài)或者手工配置好摆马。要注意的是臼闻,這里說的 Client 是相對于 ServiceManager 而言的,一個進程或者應(yīng)用程序可能是提供服務(wù)的 Server囤采,但對于 ServiceManager 來說它仍然是個 Client述呐。

Client 獲得實名 Binder 的引用:
Server 向 ServiceManager 中注冊了 Binder 以后, Client 就能通過名字獲得 Binder 的引用了蕉毯。Client 也利用保留的 0 號引用向 ServiceManager 請求訪問某個 Binder: 我申請訪問名字叫張三的 Binder 引用乓搬。ServiceManager 收到這個請求后從請求數(shù)據(jù)包中取出 Binder 名稱,在查找表里找到對應(yīng)的條目代虾,取出對應(yīng)的 Binder 引用作為回復(fù)發(fā)送給發(fā)起請求的 Client进肯。從面向?qū)ο蟮慕嵌瓤矗琒erver 中的 Binder 實體現(xiàn)在有兩個引用:一個位于 ServiceManager 中棉磨,一個位于發(fā)起請求的 Client 中坷澡。如果接下來有更多的 Client 請求該 Binder,系統(tǒng)中就會有更多的引用指向該 Binder ,就像 Java 中一個對象有多個引用一樣频敛。

因此 Binder IPC 過程可以總結(jié)成以下步驟:

  1. 某個進程使用 BINDER_SET_CONTEXT_MGR 命令通過 Binder 驅(qū)動將自己注冊成 ServiceManager,負責管理所有的 Service
  2. 各個 Server 通過 Binder 驅(qū)動向 ServiceManager 注冊 Binder 實體馅扣,表明自己可以對外提供服務(wù)斟赚,這時 Binder 驅(qū)動會為這個 Binder 創(chuàng)建位于內(nèi)核中的實體節(jié)點以及 ServiceManager 對該節(jié)點的引用,并將名字和該引用打包給 ServiceManager差油,ServiceManager 接收到數(shù)據(jù)包后將數(shù)據(jù)包中的名字和引用填入查找表中
  3. Client 通過上面 Server 的名字在 Binder 驅(qū)動的幫助下從 ServiceManager 中獲取到該 Server 對應(yīng)的 Binder 引用對象拗军,由于該引用對象同樣具有 Server 的能力,因此 Client 可以通過這個引用與真實的 Server 進行交互

還是universus 老師的圖:

Binder Role

總結(jié)

進程隔離雖然使操作系統(tǒng)的安全性和應(yīng)用程序的穩(wěn)定性得到了提升蓄喇,但同時也給 IPC 帶來了一定的難度发侵,Android 系統(tǒng)巧妙地應(yīng)用了 Binder 機制,使得系統(tǒng)得于在存儲空間和硬件性能等有限的移動設(shè)備上能夠流暢地運行妆偏。關(guān)于 Binder 在應(yīng)用層的使用和分析刃鳄,請看下一篇文章內(nèi)容:借助 AIDL 理解 Android Binder 機制——AIDL 的使用和原理分析

參考文章

寫給 Android 應(yīng)用工程師的 Binder 原理剖析

Binder學習指南

如果你對文章內(nèi)容有疑問或者有不同意見,歡迎留言钱骂,我們一同探討叔锐。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市见秽,隨后出現(xiàn)的幾起案子愉烙,更是在濱河造成了極大的恐慌,老刑警劉巖解取,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件步责,死亡現(xiàn)場離奇詭異,居然都是意外死亡禀苦,警方通過查閱死者的電腦和手機蔓肯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來伦忠,“玉大人省核,你說我怎么就攤上這事±ヂ耄” “怎么了气忠?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長赋咽。 經(jīng)常有香客問我旧噪,道長,這世上最難降的妖魔是什么脓匿? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任淘钟,我火速辦了婚禮,結(jié)果婚禮上陪毡,老公的妹妹穿的比我還像新娘米母。我一直安慰自己勾扭,他們只是感情好,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布铁瞒。 她就那樣靜靜地躺著妙色,像睡著了一般。 火紅的嫁衣襯著肌膚如雪慧耍。 梳的紋絲不亂的頭發(fā)上身辨,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音芍碧,去河邊找鬼煌珊。 笑死,一個胖子當著我的面吹牛泌豆,可吹牛的內(nèi)容都是我干的定庵。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼践美,長吁一口氣:“原來是場噩夢啊……” “哼洗贰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起陨倡,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤敛滋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后兴革,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绎晃,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年杂曲,在試婚紗的時候發(fā)現(xiàn)自己被綠了庶艾。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡擎勘,死狀恐怖咱揍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情棚饵,我是刑警寧澤煤裙,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站噪漾,受9級特大地震影響硼砰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜欣硼,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一题翰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦豹障、人聲如沸冯事。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽桅咆。三九已至,卻和暖如春坞笙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背荚虚。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工薛夜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人版述。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓梯澜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親渴析。 傳聞我的和親對象是個殘疾皇子晚伙,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容