Android Binder 機(jī)制學(xué)習(xí)3 - Binder IPC 基本原理

了解了 Linux IPC 相關(guān)的概念和通信原理, 下面正式介紹下 Binder IPC 的原理.
(如有侵權(quán), 請(qǐng)聯(lián)系刪除)

1. 動(dòng)態(tài)內(nèi)核可加載模塊 && 內(nèi)存映射

正如上一章所說(shuō), 跨進(jìn)程通信是需要內(nèi)核空間做支持的. 傳統(tǒng)的 IPC 機(jī)制如 管道, Socket, 都是內(nèi)核的一部分, 因此通過(guò)內(nèi)核支持來(lái)實(shí)現(xiàn)進(jìn)程間通信自然是沒(méi)問(wèn)題的.

但是 Binder 并不是 Linux 系統(tǒng)內(nèi)核的一部分, 那怎么辦呢, 這得益于 Linux 的動(dòng)態(tài)內(nèi)核可加載模塊 (Loadable Kernel Module, LKM)的機(jī)制

1.1 動(dòng)態(tài)內(nèi)核可加載模塊 (Loadable Kernel Module, LKM)

動(dòng)態(tài)內(nèi)核可加載模塊 (Loadable Kernel Module, LKM)
?
模塊是具有獨(dú)立功能的程序, 它可以被單獨(dú)編譯, 但是不能獨(dú)立運(yùn)行. 它在運(yùn)行時(shí)被鏈接到內(nèi)核作為內(nèi)核的一部分運(yùn)行.

這樣 Android 系統(tǒng)就可以通過(guò)動(dòng)態(tài)添加一個(gè)內(nèi)核模塊運(yùn)行在內(nèi)核空間, 用戶(hù)進(jìn)程進(jìn)程之間通過(guò)這個(gè)內(nèi)核模塊作為橋梁來(lái)實(shí)現(xiàn)通信.

在 Android 中, 這個(gè)運(yùn)行在內(nèi)核空間, 負(fù)責(zé)各個(gè)用戶(hù)進(jìn)程通過(guò) Binder 實(shí)現(xiàn)通信的內(nèi)核模塊就叫做 Binder 驅(qū)動(dòng) (Binder Driver)

那么在 Android 系統(tǒng)中用戶(hù)進(jìn)程之間是如何通過(guò)這個(gè)內(nèi)核模塊 (Binder Driver)來(lái)實(shí)現(xiàn)通信的呢? 顯然不是和上一章的傳統(tǒng) IPC 通信一樣,進(jìn)行兩次 copy 了, 不然Binder 也不有在性能方面的優(yōu)勢(shì)了.

1.2 內(nèi)存映射

Binder IPC 機(jī)制中設(shè)計(jì)到的內(nèi)存映射通過(guò) mmap() 來(lái)實(shí)現(xiàn), mmap() 是操作系統(tǒng)中一種內(nèi)存映射的方法.

內(nèi)存映射
?
簡(jiǎn)單的說(shuō)就是將用戶(hù)空間的一塊內(nèi)存區(qū)域映射到內(nèi)核空間.
映射關(guān)系建立后, 用戶(hù)對(duì)這塊內(nèi)存區(qū)域的修改可以直接反應(yīng)到內(nèi)核空間.
反之,內(nèi)核空間對(duì)這段區(qū)域的修改也能直接反應(yīng)到用戶(hù)空間.

內(nèi)存映射能減少數(shù)據(jù) copy 的次數(shù), 實(shí)現(xiàn)用戶(hù)空間和內(nèi)核空間的高效互動(dòng). 兩個(gè)空間各自的修改也能直接反應(yīng)在映射的內(nèi)存區(qū)域, 從而被對(duì)方空間及時(shí)感知. 也正因?yàn)槿绱? 內(nèi)存映射能夠提供對(duì)進(jìn)程間通信的支持.


2. Binder IPC 實(shí)現(xiàn)原理

Binder IPC 正是基于內(nèi)存映射(mmap()) 來(lái)實(shí)現(xiàn)的, 但是mmap() 通常是用在有物理介質(zhì)的文件系統(tǒng)上的.

比如進(jìn)程中的用戶(hù)區(qū)域是不能直接和物理設(shè)備打交道的, 如果想要把磁盤(pán)上的數(shù)據(jù)讀取到進(jìn)程的用戶(hù)區(qū)域, 需要兩次 copy (磁盤(pán) -> 內(nèi)核空間 -> 用戶(hù)空間). 通常在這種場(chǎng)景下 mmap() 就能發(fā)揮作用, 通過(guò)在物理介質(zhì)和用戶(hù)空間之間建立映射, 減少數(shù)據(jù)的 copy 次數(shù), 用內(nèi)存讀寫(xiě)代替 I/O 讀寫(xiě), 提高文件讀取效率.

而 Binder 并不存在物理介質(zhì), 因此 Binder 驅(qū)動(dòng)使用 mmap() 并不是為了在物理介質(zhì)和用戶(hù)空間之間映射, 而是用來(lái)在內(nèi)核空間創(chuàng)建數(shù)據(jù)接收的緩存空間.

一次完整的 Binder IPC 通信過(guò)程通常是這樣:

  1. 首先 Binder 驅(qū)動(dòng)在內(nèi)核空間創(chuàng)建一個(gè)數(shù)據(jù)接收緩存區(qū)
  2. 接著在內(nèi)核空間開(kāi)辟一塊內(nèi)核緩存區(qū).
  3. 建立內(nèi)核緩存區(qū) 和 內(nèi)核中數(shù)據(jù)接收緩存區(qū) 之間的映射關(guān)系.
  4. 建立內(nèi)核中數(shù)據(jù)接收緩存區(qū) 與 數(shù)據(jù)接收進(jìn)程用戶(hù)空間 的地址的映射關(guān)系
  5. 發(fā)送方進(jìn)程通過(guò)系統(tǒng)調(diào)用 copy_from_user() 將數(shù)據(jù) copy 到內(nèi)核中的內(nèi)核緩存區(qū), 由于內(nèi)核緩存區(qū) 與 內(nèi)核數(shù)據(jù)接收緩存區(qū) 存在映射關(guān)系, 而內(nèi)核數(shù)據(jù)接收緩存區(qū) 又與 數(shù)據(jù)接收進(jìn)程用戶(hù)空間 存在映射關(guān)系, 所以相當(dāng)于 內(nèi)核緩存區(qū) 與 數(shù)據(jù)接收進(jìn)程用戶(hù)空間存在映射關(guān)系. 因此也就相當(dāng)于把數(shù)據(jù)發(fā)送到了數(shù)據(jù)接收進(jìn)程的用戶(hù)空間.

這樣就完成了一次進(jìn)程間通信
如下圖:


Binder IPC 進(jìn)程間通信基本流程

3. Binder 通信模型

介紹完 Binder IPC 的底層通信原理, 接下來(lái)我們看看實(shí)現(xiàn)層面是如何設(shè)計(jì)的

一次完成的進(jìn)程間通信必然至少包含兩個(gè)進(jìn)程, 通常我們稱(chēng)通信的雙方分別為客戶(hù)端進(jìn)程(Client) 和服務(wù)端進(jìn)程(Server), 由于進(jìn)程隔離機(jī)制的存在, 通信雙方必然需要借助 Binder 來(lái)實(shí)現(xiàn).

3.1 Client/Server/ServiceManager/Binder驅(qū)動(dòng)

BInder 是基于 C/S 架構(gòu). 是由一些列組件組成. 包括 Client, Server, ServiceManager, Binder 驅(qū)動(dòng).

  • Client, Server, ServiceManager 運(yùn)行在用戶(hù)空間
  • Binder 驅(qū)動(dòng)運(yùn)行在內(nèi)核空間.
  • ServiceManager, Binder 驅(qū)動(dòng)由系統(tǒng)提供.
  • Client, Service 由應(yīng)用程序來(lái)實(shí)現(xiàn)

Client, Server, ServiceManager 都是通過(guò)系統(tǒng)調(diào)用 open, mmap,ioctl 來(lái)訪問(wèn)設(shè)備文件 /dev/binder, 從而實(shí)現(xiàn)與 Binder 驅(qū)動(dòng)的交互來(lái)間接的實(shí)現(xiàn)跨進(jìn)程通信.

3.1.1 Binder 驅(qū)動(dòng)

Binder 驅(qū)動(dòng)就如如同路由器一樣, 是整個(gè)通信的核心. 驅(qū)動(dòng)負(fù)責(zé)進(jìn)程之間 Binder 通信的建立 / 傳遞, Binder 引用計(jì)數(shù)管理, 數(shù)據(jù)包在進(jìn)程之間的傳遞和交互等一系列底層支持.

3.1.2 ServiceManager 與 實(shí)名 Binder

ServiceManager 作用是將字符形式的 Binder 名字轉(zhuǎn)化成 Client 中對(duì)該 Binder 的引用, 使得 Client 能夠通過(guò) Binder 的名字獲得對(duì) Binder 實(shí)體的引用.

注冊(cè)了名字的 Binder 叫實(shí)名 Binder, 就像網(wǎng)站一樣除了 IP 地址以外還有自己的網(wǎng)址.
Server 創(chuàng)建了 Binder, 并為它起一個(gè)字符形式, 可讀易記的名字, 將這個(gè) BInder 實(shí)體連同名字一起以數(shù)據(jù)包的形式通過(guò) Binder 驅(qū)動(dòng) 發(fā)送給 ServiceManager, 通知 ServiceManager 注冊(cè)一個(gè)名字為 "張三"的 Binder, 它位于某個(gè) Server 中, 驅(qū)動(dòng)為這個(gè)穿越進(jìn)程邊界的 BInder 創(chuàng)建位于內(nèi)核中的實(shí)體節(jié)點(diǎn)以及 ServiceManager 對(duì)實(shí)體的引用, 將名字以及新建的引用打包傳給 ServiceManager, ServiceManager 收到數(shù)據(jù)后從中取出名字和引用填入查找表.

ServiceManager 是一個(gè)進(jìn)程, Server 又是一個(gè)另外的進(jìn)程, Server 向 ServiceManager 中注冊(cè) BInder 必然涉及到進(jìn)程間通信. 當(dāng)實(shí)現(xiàn)進(jìn)程間通信又要用到進(jìn)程間通信, 這就好像蛋可以孵出雞的前提確實(shí)要先找只雞下蛋! Binder 的實(shí)現(xiàn)比較巧妙, 就是預(yù)先創(chuàng)造一只雞來(lái)下蛋. ServiceManager 和其他進(jìn)程同樣采用 Binder 通信, ServiceManager 是 Server 端, 有自己的 Binder 實(shí)體, 其他進(jìn)程都是 Client, 需要通過(guò)這個(gè) Binder 的引用來(lái)實(shí)現(xiàn) Binder 的注冊(cè), 查詢(xún)和獲取. ServiceManager 提供的 Binder 比較特殊, 它沒(méi)有名字也不需要注冊(cè). 當(dāng)一個(gè)進(jìn)程使用 BINDERSETCONTEXT_MGR 命令將自己注冊(cè)成 ServiceManager 時(shí) Binder 驅(qū)動(dòng)會(huì)自動(dòng)為它創(chuàng)建 Binder 實(shí)體(這就是那只預(yù)先造好的那只雞). 其實(shí)這個(gè) Binder 實(shí)體的引用在所有 Client 中都固定為 0 , 而無(wú)需通過(guò)其他手段獲得. 也就是說(shuō), 一個(gè) Server 想要向 ServiceManager 注冊(cè)自己的 Binder 就必須通過(guò)這個(gè) 0 號(hào)引用和 ServiceManager 的 Binder 通信. 這里說(shuō)的 Client 是相對(duì)于 ServiceManager 而言的, 一個(gè)進(jìn)程或者應(yīng)用程序可能是提供服務(wù)的 Server, 但是對(duì)于 ServiceManager 來(lái)說(shuō)它仍然是個(gè) Client.

Server 向 ServiceManager 中注冊(cè)了 Binder 以后, Client 就能通過(guò)名字獲得 Binder 的引用. Client 也利用保留的 0 號(hào)引用向 ServiceManager 請(qǐng)求訪問(wèn)某個(gè) Binder. 比如,Client 申請(qǐng)?jiān)L問(wèn)名字叫"張三"的 Binder 引用. ServiceManager 收到這個(gè)請(qǐng)求后從請(qǐng)求數(shù)據(jù)包中取出 Binder 名稱(chēng), 在查找表里找到對(duì)應(yīng)的條目, 取出對(duì)應(yīng)的 Binder 引用, 作為回復(fù)發(fā)送給發(fā)起請(qǐng)求的 Client. 從面相對(duì)象的角度看, Server 中的 Binder 實(shí)體現(xiàn)在有兩個(gè)引用: 一個(gè)位于 ServiceManager 中, 一個(gè)位于發(fā)起請(qǐng)求的 Client 中. 如果后面會(huì)有更多的 Client 請(qǐng)求該 Binder, 系統(tǒng)中就會(huì)有更多的引用指向這個(gè) Binder, 就像 Java 中一個(gè)對(duì)象有多個(gè)引用一樣.


4. Binder 通信中的代理模式

我們已經(jīng)解釋清楚 Client, Server 借助 Binder 驅(qū)動(dòng)完成跨進(jìn)程通信的實(shí)現(xiàn)機(jī)制了, 但是還有個(gè)問(wèn)題需要弄清楚, 比如 A 進(jìn)程想要 B 進(jìn)程中的某個(gè)對(duì)象(object) 是如何實(shí)現(xiàn)的呢, 畢竟它們屬于不同的進(jìn)程, A 進(jìn)程沒(méi)辦法直接使用 B 進(jìn)程中的 object.

前面我們說(shuō)過(guò)跨進(jìn)程通信的過(guò)程都有 Binder 驅(qū)動(dòng)的參與, 因此在數(shù)據(jù)流經(jīng) Binder 驅(qū)動(dòng)的時(shí)候 Binder 驅(qū)動(dòng)會(huì)對(duì)數(shù)據(jù)做一層轉(zhuǎn)換.

我們?cè)?Client端掏击,向 ServiceManager 獲取具體的 Server 端的 Binder 引用的時(shí)候突琳,會(huì)首先進(jìn)過(guò) Binder 驅(qū)動(dòng)索守,Binder 驅(qū)動(dòng)它并不會(huì)把真正的 Server 的 Binder 引用返回給 Client 端桌硫,而是返回一個(gè)代理的 java 對(duì)象,該對(duì)象具有跟 Server 端的 Binder 引用相同的方法簽名饵逐,這個(gè)對(duì)象為 ProxyObject另玖,他具有跟 Server 的 Binder 實(shí)例一樣的方法袱贮,只是這些方法并沒(méi)有 Server 端的能力,這些方法只需要把請(qǐng)求參數(shù)交給 Binder 驅(qū)動(dòng)即可. 對(duì)于 Client 端來(lái)說(shuō)和直接調(diào)用 Server 中的方法是一樣的.


5. Binder 通信過(guò)程

了解了上面之后, 我們大致可以推算出 Binder 的通信過(guò)程

1. 注冊(cè) ServiceManager

一個(gè)進(jìn)程使用 BINDERSETCONTEXT_MGR 命令通過(guò) Binder 驅(qū)動(dòng)將自己注冊(cè)成為 ServiceManager.

2. 注冊(cè) Server

Server 通過(guò) Binder 驅(qū)動(dòng)向 ServiceManager 中注冊(cè) Binder (Server 中 Binder 實(shí)體), 表明可以對(duì)外提供服務(wù).
Binder 驅(qū)動(dòng)為這個(gè) Binder 創(chuàng)建位于內(nèi)核中的實(shí)體節(jié)點(diǎn)以及 ServiceManager 對(duì)實(shí)體的引用, 然后將名字及新建的引用打包傳給 ServiceManager, 最后 ServiceManager 將其填入到查找表.

3. Client 獲取 Server 的 Binder 引用

Client 請(qǐng)求獲得 Server 的 Binder 引用, Binder 驅(qū)動(dòng)在接收到 Client 的請(qǐng)求的時(shí)候, 就去 ServiceManager 中查詢(xún), 查詢(xún)到后會(huì)創(chuàng)建一個(gè) Server 端 Binder 對(duì)象的 ProxyObject (Binder 的代理對(duì)象), 并將該 ProxyObject 返回給 Client.

4. Client 與 Server 通信

Client 收到 Binder 驅(qū)動(dòng)返回的 ProxyObject 后, 通過(guò) ProxyObject 調(diào)用其中的方法. ProxyObject 的方法再去調(diào)用 Binder 驅(qū)動(dòng), Binder 驅(qū)動(dòng)會(huì)去查詢(xún)自己維護(hù)的表單, 發(fā)現(xiàn)這是某個(gè) Server 端 Binder 的代理對(duì)象, 就會(huì)通知 Server 端調(diào)用具體的方法,(會(huì)把 Client 端調(diào)用 ProxyObject 中方法的參數(shù)傳過(guò)去. ), 并要求 Server 把結(jié)果返回給自己. 當(dāng) Binder 驅(qū)動(dòng)拿到結(jié)果后, 就會(huì)轉(zhuǎn)發(fā)給 Client 端.

image.png

6. Binder 的完整定義

  • 從進(jìn)程間通信的角度看, Binder 是一種進(jìn)程間通信的機(jī)制
  • 從 Server 進(jìn)程的角度看, Binder 指的是 Server 中的 Binder 實(shí)體對(duì)象.
  • 從 Client 進(jìn)程的角度看, Binder 指的是對(duì) Binder 代理對(duì)象, 是 Binder 實(shí)體對(duì)象的一個(gè)遠(yuǎn)程代理.
  • 從傳輸過(guò)程的角度看, Binder 是一個(gè)可以跨進(jìn)程通信的對(duì)象. Binder 驅(qū)動(dòng)會(huì)對(duì)這個(gè)跨越進(jìn)程邊界的對(duì)象
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末迄沫,一起剝皮案震驚了整個(gè)濱河市稻扬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌羊瘩,老刑警劉巖泰佳,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盼砍,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡逝她,警方通過(guò)查閱死者的電腦和手機(jī)浇坐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)黔宛,“玉大人近刘,你說(shuō)我怎么就攤上這事⊥位危” “怎么了觉渴?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)徽惋。 經(jīng)常有香客問(wèn)我案淋,道長(zhǎng),這世上最難降的妖魔是什么寂曹? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任哎迄,我火速辦了婚禮,結(jié)果婚禮上隆圆,老公的妹妹穿的比我還像新娘漱挚。我一直安慰自己,他們只是感情好渺氧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布旨涝。 她就那樣靜靜地躺著,像睡著了一般侣背。 火紅的嫁衣襯著肌膚如雪白华。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,679評(píng)論 1 305
  • 那天贩耐,我揣著相機(jī)與錄音弧腥,去河邊找鬼。 笑死潮太,一個(gè)胖子當(dāng)著我的面吹牛管搪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播铡买,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼更鲁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了奇钞?” 一聲冷哼從身側(cè)響起澡为,我...
    開(kāi)封第一講書(shū)人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎景埃,沒(méi)想到半個(gè)月后媒至,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體顶别,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年塘慕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了筋夏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡图呢,死狀恐怖条篷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蛤织,我是刑警寧澤赴叹,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站指蚜,受9級(jí)特大地震影響乞巧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜摊鸡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一绽媒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧免猾,春花似錦是辕、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至锨苏,卻和暖如春疙教,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伞租。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工贞谓, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人葵诈。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓经宏,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親驯击。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

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