Binder 原理剖析

1 Binder 概述

Binder 是一種進(jìn)程間通信機(jī)制,基于開源的 OpenBinder 實(shí)現(xiàn);
OpenBinder 起初由 Be Inc. 開發(fā),后由 Plam Inc. 接手。

1.1 為什么必須理解 Binder ?

  • 作為 Android 工程師的你,是不是常常會有這樣的疑問:
  • 為什么 Activity 間傳遞對象需要序列化?
  • Activity 的啟動流程是什么樣的?
  • 四大組件底層的通信機(jī)制是怎樣的?
  • AIDL 內(nèi)部的實(shí)現(xiàn)原理是什么?
  • 插件化編程技術(shù)應(yīng)該從何學(xué)起?等等...
  • 這些問題的背后都與 Binder 有莫大的關(guān)系,要弄懂上面這些問題理解 Bidner 通信機(jī)制是必須的。

1.2 為什么是 Binder ?

IPC種類.png

Android 系統(tǒng)是基于 Linux 內(nèi)核的,Linux 已經(jīng)提供了管道消息隊列共享內(nèi)存Socket 等 IPC 機(jī)制。
那為什么 Android 還要提供 Binder 來實(shí)現(xiàn) IPC 呢?主要是基于性能穩(wěn)定性安全性幾方面的原因。

1.2.1 性能

Socket 作為一款通用接口,其傳輸效率低,開銷大,主要用在跨網(wǎng)絡(luò)的進(jìn)程間通信和本機(jī)上進(jìn)程間的低速通信。
消息隊列管道采用存儲-轉(zhuǎn)發(fā)方式,即數(shù)據(jù)先從發(fā)送方緩存區(qū)拷貝到內(nèi)核開辟的緩存區(qū)中,然后再從內(nèi)核緩存區(qū)拷貝到接收方緩存區(qū),至少有兩次拷貝過程。
共享內(nèi)存雖然無需拷貝,但控制復(fù)雜,難以使用。
**Binder **只需要一次數(shù)據(jù)拷貝,性能上僅次于共享內(nèi)存。

IPC方式 數(shù)據(jù)拷貝次數(shù)
共享內(nèi)存 0
Binder 1
Socket/管道/消息隊列 2

1.2.2 穩(wěn)定性

  • Binder 基于 C/S 架構(gòu),客戶端(Client)有什么需求就丟給服務(wù)端(Server)去完成,架構(gòu)清晰、職責(zé)明確又相互獨(dú)立,自然穩(wěn)定性更好。
  • 共享內(nèi)存雖然無需拷貝,但是控制負(fù)責(zé),難以使用。
  • 從穩(wěn)定性的角度講,Binder 機(jī)制是優(yōu)于內(nèi)存共享的。

1.2.3 安全性

  • 傳統(tǒng)的 IPC 沒有任何安全措施,完全依賴上層協(xié)議來確保。
  • 首先傳統(tǒng)的 IPC 接收方無法獲得對方可靠的進(jìn)程用戶ID/進(jìn)程ID(UID/PID),從而無法鑒別對方身份。
  • Android 為每個安裝好的 APP 分配了自己的 UID,故而進(jìn)程的 UID 是鑒別進(jìn)程身份的重要標(biāo)志。
  • 傳統(tǒng)的 IPC 只能由用戶在數(shù)據(jù)包中填入 UID/PID,但這樣不可靠,容易被惡意程序利用。
  • 可靠的身份標(biāo)識只有由 IPC 機(jī)制在內(nèi)核中添加。
  • 其次傳統(tǒng)的 IPC 訪問接入點(diǎn)是開放的,只要知道這些接入點(diǎn)的程序都可以和對端建立連接,不管怎樣都無法阻止惡意程序通過猜測接收方地址獲得連接。
    同時 Binder 既支持實(shí)名 Binder,又支持匿名 Binder,安全性高。

1.2.4 Binder 的優(yōu)勢:

優(yōu)勢 描述
性能 只需要一次數(shù)據(jù)拷貝,性能上僅次于共享內(nèi)存
穩(wěn)定性 基于 C/S 架構(gòu),職責(zé)明確、架構(gòu)清晰,因此穩(wěn)定性好
安全性 為每個 APP 分配 UID,進(jìn)程的 UID 是鑒別進(jìn)程身份的重要標(biāo)志

基于上述原因,Android 需要建立一套新的 IPC 機(jī)制來滿足系統(tǒng)對穩(wěn)定性、傳輸性能和安全性方面的要求,這就是 Binder。

2 Binder 跨進(jìn)程通信原理

2.1 動態(tài)內(nèi)核可加載模塊

  • 跨進(jìn)程通信是需要內(nèi)核空間做支持的。
  • 傳統(tǒng)的 IPC 機(jī)制如管道、Socket 都是內(nèi)核的一部分,因此通過內(nèi)核支持來實(shí)現(xiàn)進(jìn)程間通信自然是沒問題的。
  • Binder 并不是 Linux 系統(tǒng)內(nèi)核的一部分,能夠通信得益于Linux 的動態(tài)內(nèi)核可加載模塊(Loadable Kernel Module,LKM)的機(jī)制;
  • 模塊是具有獨(dú)立功能的程序,它可以被單獨(dú)編譯,但是不能獨(dú)立運(yùn)行。它在運(yùn)行時被鏈接到內(nèi)核作為內(nèi)核的一部分運(yùn)行。
  • Android 系統(tǒng)就可以通過動態(tài)添加一個內(nèi)核模塊運(yùn)行在內(nèi)核空間,用戶進(jìn)程之間通過這個內(nèi)核模塊作為橋梁來實(shí)現(xiàn)通信。
  • 在 Android 系統(tǒng)中,這個運(yùn)行在內(nèi)核空間,負(fù)責(zé)各個用戶進(jìn)程通過 Binder 實(shí)現(xiàn)通信的內(nèi)核模塊就叫 Binder 驅(qū)動(Binder Dirver)

2.2 內(nèi)存映射

  • Binder IPC 機(jī)制中涉及到的內(nèi)存映射通過 mmap() 來實(shí)現(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ù),實(shí)現(xiàn)用戶空間和內(nèi)核空間的高效互動。
  • 兩個空間各自的修改能直接反映在映射的內(nèi)存區(qū)域,從而被對方空間及時感知。也正因?yàn)槿绱耍?strong>內(nèi)存映射能夠提供對進(jìn)程間通信的支持。

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

  • Binder IPC 正是基于內(nèi)存映射(mmap)來實(shí)現(xiàn)的,但是 mmap() 通常是用在有物理介質(zhì)的文件系統(tǒng)上的。
  • 進(jìn)程中的用戶區(qū)域是不能直接和物理設(shè)備打交道的,如果想要把磁盤上的數(shù)據(jù)讀取到進(jìn)程的用戶區(qū)域,需要兩次拷貝(磁盤-->內(nèi)核空間-->用戶空間);通常在這種場景下 mmap() 就能發(fā)揮作用,通過在物理介質(zhì)和用戶空間之間建立映射,減少數(shù)據(jù)的拷貝次數(shù),用內(nèi)存讀寫取代I/O讀寫,提高文件讀取效率。
  • Binder 并不存在物理介質(zhì),因此 Binder 驅(qū)動使用 mmap() 并不是為了在物理介質(zhì)和用戶空間之間建立映射,而是用來在內(nèi)核空間創(chuàng)建數(shù)據(jù)接收的緩存空間

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

  • 1.首先 Binder 驅(qū)動在內(nèi)核空間創(chuàng)建一個數(shù)據(jù)接收緩存區(qū);
  • 2.接著在內(nèi)核空間開辟一塊內(nèi)核緩存區(qū),建立內(nèi)核緩存區(qū)和內(nèi)核中數(shù)據(jù)接收緩存區(qū)之間的映射關(guān)系,以及內(nèi)核中數(shù)據(jù)接收緩存區(qū)和接收進(jìn)程用戶空間地址的映射關(guān)系
  • 3.發(fā)送方進(jìn)程通過系統(tǒng)調(diào)用 copy_from_user() 將數(shù)據(jù) copy 到內(nèi)核中的內(nèi)核緩存區(qū),由于內(nèi)核緩存區(qū)和接收進(jìn)程的用戶空間存在內(nèi)存映射,因此也就相當(dāng)于把數(shù)據(jù)發(fā)送到了接收進(jìn)程的用戶空間,這樣便完成了一次進(jìn)程間的通信。
162b00a9557158d0.png

3 Binder的工作機(jī)制

3.1 binder的工作流程

binder的工作流程.png
  • 通過上圖,我們可以看出binder的工作流程是這樣實(shí)現(xiàn)的:
  • (1)Client發(fā)送請求給Server,在Server未返回結(jié)果前,Client處于阻塞狀態(tài)。請求的數(shù)據(jù)和相應(yīng)操作交給Client的Proxy處理。
  • (2)Proxy代理將數(shù)據(jù)封裝后,交給Binder驅(qū)動程序進(jìn)行數(shù)據(jù)的傳輸調(diào)度。(transact()
  • (3)Binder驅(qū)動程序?qū)?shù)據(jù)發(fā)送個Server,Server對數(shù)據(jù)進(jìn)行解析,并根據(jù)相應(yīng)的操作標(biāo)識進(jìn)行相應(yīng)的操作處理。
  • (4)Server操作完成之后,將執(zhí)行之后結(jié)果數(shù)據(jù)封裝。然后將數(shù)據(jù)交給Binder驅(qū)動程序調(diào)度。(onTransact()
  • (5)Binder驅(qū)動程序?qū)⒔Y(jié)果數(shù)據(jù)交給Client的Proxy代理,Proxy代理將數(shù)據(jù)解析后將最終結(jié)果返回給Client。
  • (6)Client接收到數(shù)據(jù)之后,結(jié)束阻塞狀態(tài)。

3.2 Server向ServiceManager注冊服務(wù)

  • 在Binder的工作機(jī)制中,我們是依賴binder驅(qū)動程序去執(zhí)行數(shù)據(jù)的調(diào)度,發(fā)送方依賴binder打包數(shù)據(jù),接收方依賴binder回傳數(shù)據(jù)
Server向ServiceManager注冊服務(wù).png
  • 注冊流程是這樣的:
  • (1)Server在自己的進(jìn)程中向Binder驅(qū)動程序申請創(chuàng)建一個作為自己Service的Binder實(shí)體。
  • (2)Binder驅(qū)動程序為這個Service創(chuàng)建位于內(nèi)核中binder實(shí)體節(jié)點(diǎn)binder引用,然后將Service的名稱和binder的引用傳給ServiceManager,通知ServiceManager注冊相應(yīng)的Service服務(wù)。
  • (3)ServiceManager接收到數(shù)據(jù)之后,根據(jù)Service的名稱和binder引用填寫入一張表中。

3.3 Client從SericeManager獲取Service的遠(yuǎn)程接口

Client從SericeManager獲取Service的遠(yuǎn)程接口.png
  • 如果這時Client向Server發(fā)送申請該Service服務(wù)請求時,ServiceManager就會通過該服務(wù)的名稱,查找表獲取相應(yīng)服務(wù)的binder引用,返回給Client。

3.4 總結(jié)

總結(jié):作為數(shù)據(jù)發(fā)送方,它持有Binder的實(shí)體;作為數(shù)據(jù)接收方,它持有Binder的引用。

4 Binder 通信模型

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

4.1Client/Server/ServiceManager/BinderDriver驅(qū)動

  • Binder 是基于 C/S 架構(gòu)的。由一系列的組件組成,包括Client、Server、ServiceManager、Binder 驅(qū)動
  • Client、Server、Service Manager 運(yùn)行在用戶空間,Binder 驅(qū)動運(yùn)行在內(nèi)核空間
  • 其中 Service Manager 和 Binder 驅(qū)動由系統(tǒng)提供,而 Client、Server 由應(yīng)用程序來實(shí)現(xiàn)。
  • Client、Server 和 ServiceManager 均是通過系統(tǒng)調(diào)用 open、mmap 和 ioctl 來訪問設(shè)備文件 /dev/binder,從而實(shí)現(xiàn)與 Binder 驅(qū)動的交互來間接的實(shí)現(xiàn)跨進(jìn)程通信。
162b00a955f25e1c.png

4.2 網(wǎng)頁請求模型

  • Client、Server、ServiceManager、Binder 驅(qū)動這幾個組件在通信過程中扮演的角色就如同互聯(lián)網(wǎng)中服務(wù)器(Server)、客戶端(Client)、DNS域名服務(wù)器(ServiceManager)以及路由器(Binder 驅(qū)動)之前的關(guān)系。
  • 通常我們訪問一個網(wǎng)頁的步驟是這樣的:首先在瀏覽器輸入一個地址,如 www.google.com 然后按下回車鍵。但是并沒有辦法通過域名地址直接找到我們要訪問的服務(wù)器,因此需要首先訪問 DNS 域名服務(wù)器,域名服務(wù)器中保存了 www.google.com 對應(yīng)的 ip 地址 10.249.23.13,然后通過這個 ip 地址才能放到到 www.google.com 對應(yīng)的服務(wù)器。
162b00a979646aee.png

4.3 流程

  • Binder Driver位于內(nèi)核空間中,其以字符設(shè)備中的misc類型注冊
  • 用戶可以從/dev/binder設(shè)備文件節(jié)點(diǎn)上,通過open和ioctl文件操作函數(shù)與Binder Driver進(jìn)行通信,其主要負(fù)責(zé)Binder通信的建立,以及其在進(jìn)程間的傳遞和Binder引用計數(shù)管理/數(shù)據(jù)包的傳輸?shù)取?/li>
  • 1.當(dāng)手機(jī)啟動后,ServiceManager會先向Binder Driver進(jìn)行注冊,它在Binder Driver中是最先被注冊的,其注冊ID為0
  • 2.當(dāng)其他的服務(wù)想要注冊到Binder Driver時,會先通過這個0號ID獲取到ServiceManager所對應(yīng)的IBinder接口,該接口實(shí)質(zhì)上的實(shí)現(xiàn)邏輯是由BpBinder實(shí)現(xiàn)的。
  • 3.獲取到對應(yīng)的接口后就回調(diào)用其中的transact方法,此后就會在Binder Driver中新注冊一個ID 1來對應(yīng)這個服務(wù)。
  • 4.如果有客戶端想要使用這個服務(wù),那么,它先會像 Binder Driver 一樣獲取到ID為0的接口,也就是ServiceManager所對應(yīng)的接口,并調(diào)用其transact方法要求連接到剛才的服務(wù),這時候Binder Driver就會將ID為1的服務(wù)回傳給客戶端并將相關(guān)消息反饋給 ServiceManager 完成。

5 Binder架構(gòu)

Binder架構(gòu).png
  • Java應(yīng)用層: 對于上層應(yīng)用通過調(diào)用AMP.startService, 完全可以不用關(guān)心底層,經(jīng)過層層調(diào)用,最終必然會調(diào)用到AMS.startService.
  • Java IPC層: Binder通信是采用C/S架構(gòu), Android系統(tǒng)的基礎(chǔ)架構(gòu)便已設(shè)計好Binder在Java framework層的Binder客戶類BinderProxy和服務(wù)類Binder;
  • Native IPC層: 對于Native層,如果需要直接使用Binder(比如media相關(guān)), 則可以直接使用BpBinder和BBinder(當(dāng)然這里還有JavaBBinder)即可, 對于上一層Java IPC的通信也是基于這個層面.
  • Kernel物理層: 這里是Binder Driver, 前面3層都跑在用戶空間,對于用戶空間的內(nèi)存資源是不共享的,每個Android的進(jìn)程只能運(yùn)行在自己進(jìn)程所擁有的虛擬地址空間, 而內(nèi)核空間卻是可共享的. 真正通信的核心環(huán)節(jié)還是在Binder Driver.

參考

https://blog.csdn.net/universus/article/details/6211589
https://juejin.im/post/5acccf845188255c3201100f?utm_medium=an&utm_source=weixinqun
http://www.lxweimin.com/p/82cdb9d53ca3
https://juejin.im/post/5a181ed151882512a86100e5

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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