Binder學習(二)Binder機制解析

wustor發表於2017-11-25

概述

由於Android是基於Linux核心的作業系統,所以在瞭解Binder級之前需要先了解一些關於Linux的知識,程式隔離以及虛擬地址:

程式隔離

程式隔離是為保護作業系統中程式互不干擾而設計的一組不同硬體和軟體的技術。這個技術是為了避免程式A寫入程式B的情況發生。 程式的隔離實現,使用了虛擬地址空間。

虛擬地址

虛擬地址是對整個記憶體的抽像描述。它是相對於實體記憶體來講的,可以直接理解成“不真實的”,“假的”記憶體,例如,一個0x08000000記憶體地址,它並不對就實體地址上那個大陣列中0x08000000 - 1那個地址元素;之所以是這樣,是因為現代作業系統都提供了一種記憶體管理的抽像,即虛擬記憶體(virtual memory)。程式使用虛擬記憶體中的地址,由作業系統協助相關硬體,把它“轉換”成真正的實體地址。

正文

由於Linux的程式隔離,所以導致了程式間不能直接進行通訊,那麼Linux有沒有其它的通訊方式呢,如果有的話,為什麼要使用Binder作為IPC的通訊方式?帶著這些疑問,來對Binder機制進行一步一步的分析。

IPC原理

IPC機制
IPC機制

Client程式向Server程式通訊,是利用程式間可共享的核心記憶體空間來完成底層通訊工作的,Client端與Server端程式往往採用ioctl等方法跟核心空間的驅動進行互動。

IPC種類

IPC種類
IPC種類

  • 1.管道(Pipe):管道可用於具有親緣關係程式間的通訊,有名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關係程式間的通訊;
  • 2.訊號(Signal):訊號是比較複雜的通訊方式,用於通知接受程式有某種事件發生,除了用於程式間通訊外,程式還可以傳送訊號給程式本身
  • 3.(Message)佇列(訊息佇列):訊息佇列是訊息的連結表,包括Posix訊息隊- 列system V訊息佇列。有足夠許可權的程式可以向佇列中新增訊息,被賦予讀許可權的程式則可以讀走佇列中的訊息。訊息佇列克服了訊號承載資訊量少,管道只能承載無格式位元組流以及緩衝區大小受限等缺點。
  • 4.共享記憶體:使得多個程式可以訪問同一塊記憶體空間,是最快的可用IPC形式。是針對其他通訊機制執行效率較低而設計的。往往與其它通訊機制,如訊號量結合使用,來達到程式間的同步及互斥。
  • 5.套接字(Socket):更為一般的程式間通訊機制,可用於不同機器之間的程式間通訊。

Binder原理

雖然,Linux程式間通訊有很多種方式,但是Android並沒有採用以上幾種,而是使用了Binder機制,在分析原因前,還是先看看什麼是Binder機制以及Binder機制的特點:

  • 1.直觀來說,Binder是Android中的一個類,它繼承了IBinder介面
  • 2.從IPC角度來說,Binder是Android中的一種跨程式通訊方式,Binder還可以理解為一種虛擬的物理裝置,它的裝置驅動是/dev/binder,該通訊方式在linux中沒有
  • 3.從Android Framework角度來說,Binder是ServiceManager連線各種Manager(ActivityManager、WindowManager,etc)和相應ManagerService的橋樑
  • 4.從Android應用層來說,Binder是客戶端和服務端進行通訊的媒介,當你bindService的時候,服務端會返回一個包含了服務端業務呼叫的Binder物件,通過這個Binder物件,客戶端就可以獲取服務端提供的服務或者資料,這裡的服務包括普通服務和基於AIDL的服務

Binder原理
Binder原理

Binder從字面意思來看是黏合劑,黏結劑的意思,那麼它的作用必然是把什麼東西連線在一起呢,在Android系統的Binder機制中,由一系統元件組成,分別是Client、Server、Service Manager和Binder驅動程式,其中Client、Server和Service Manager執行在使用者空間,Binder驅動程式執行核心空間。Binder就是一種把這四個元件粘合在一起的粘結劑了,其中,核心元件便是Binder驅動程式了,Service Manager提供了輔助管理的功能,Client和Server正是在Binder驅動和Service Manager提供的基礎設施上,進行Client-Server之間的通訊。Service Manager和Binder驅動已經在Android平臺中實現好,開發者只要按照規範實現自己的Client和Server元件就可以了。

Binder架構

Binder架構
Binder架構

  • Java應用層: 對於上層應用通過呼叫AMP.startService, 完全可以不用關心底層,經過層層呼叫,最終必然會呼叫到AMS.startService.
  • Java IPC層: Binder通訊是採用C/S架構, Android系統的基礎架構便已設計好Binder在Java framework層的Binder客戶類BinderProxy和服務類Binder;
  • Native IPC層: 對於Native層,如果需要直接使用Binder(比如media相關), 則可以直接使用BpBinder和BBinder(當然這裡還有JavaBBinder)即可, 對於上一層Java IPC的通訊也是基於這個層面.
  • Kernel物理層: 這裡是Binder Driver, 前面3層都跑在使用者空間,對於使用者空間的記憶體資源是不共享的,每個Android的程式只能執行在自己程式所擁有的虛擬地址空間, 而核心空間卻是可共享的. 真正通訊的核心環節還是在Binder Driver.

Binder通訊流程

Binder通訊流程
Binder通訊流程

  • Server在ServiceManager中註冊。
    -Client想要呼叫Server的getName方法,就需要先獲取Server物件, 但是SM不會把真正的Server物件返回給Client,而是把Server的一個代理物件返回給Client,也就是Proxy。
  • 然後,Client呼叫Proxy的getName方法,SM會幫他去呼叫Server的getName方法,並把結果返回給Client。

IPC方式對比

雖然Android已經有很多的IPC方式了,但是Android依然採用Binder來進行執行緒間通訊,主要是從效能和安全性以及穩定性的角度來考慮的。

  1. 管道:在建立時分配一個page大小的記憶體,快取區大小比較有限;
  2. 訊息佇列:資訊複製兩次,額外的CPU消耗;不合適頻繁或資訊量大的通訊;
  3. 共享記憶體:無須複製,共享緩衝區直接付附加到程式虛擬地址空間,速度快;但程式間的同步問題作業系統無法實現,必須各程式利用同步工具解決;
  4. 套接字:作為更通用的介面,傳輸效率低,主要用於不通機器或跨網路的通訊;
  5. 訊號量:常作為一種鎖機制,防止某程式正在訪問共享資源時,其他程式也訪問該資源。因此,主要作為程式間以及同一程式內不同執行緒之間的同步手段。
  6. 訊號: 不適用於資訊交換,更適用於程式中斷控制,比如非法記憶體訪問,殺死某個程式等;

Android之所以採用Binder機制來進行通訊,主要是基於效能,安全以及穩定性來考慮,Binder基於 Client-Server通訊模式,傳輸過程只需一次拷貝,為傳送發新增UID/PID身份,既支援實名Binder也支援匿名Binder,安全性高;

參考資料

gityuan.com/2015/10/31/…
segmentfault.com/a/119000000…

相關文章