1. Binder概述
- 從IPC角度來說:Binder是Android中的一種跨進程通信方式,該通信方式在linux中沒有,是Android獨有;
- 從Android Driver層:Binder還可以理解為一種虛擬的物理設備,它的設備驅動是/dev/binder;
- 從Android Native層:Binder是創建Service Manager以及BpBinder/BBinder模型,搭建與binder驅動的橋梁;
- 從Android Framework層:Binder是各種Manager(ActivityManager、WindowManager等)和相應xxxManagerService的橋梁;
- 從Android APP層:Binder是客戶端和服務端進行通信的媒介,當bindService的時候,服務端會返回一個包含了服務端業務調用的 Binder對象,通過這個Binder對象,客戶端就可以獲取服務端提供的服務或者數據,這里的服務包括普通服務和基於AIDL的服務。
2. Binder架構
Binder在整個Android系統中有這舉足輕重的地位,在Native層有一套完整的binder通信的C/S架構(圖中的藍色),Bpinder作為客戶端,BBinder作為服務端。基於naive層的Binder框架,Java也有一套鏡像功能的binder C/S架構,通過JNI技術,與native層的binder對應,Java層的binder功能最終都是交給native的binder來完成。從kernel到native,jni,framework層的架構所涉及的所有有關類和方法見 Binder類圖。
3. Binder進程與線程
對於底層Binder驅動,通過binder_procs
鏈表記錄所有創建的binder_proc結構體,binder驅動層的每一個binder_proc結構體都與用戶空間的一個用於binder通信的進程一一對應,且每個進程有且只有一個ProcessState
對象,這是通過單例模式來保證的。在每個進程中可以有很多個線程,每個線程對應一個IPCThreadState對象,IPCThreadState對象也是單例模式,即一個線程對應一個IPCThreadState對象,在Binder驅動層也有與之相對應的結構,那就是Binder_thread結構體。在binder_proc結構體中通過成員變量 rb_root threads
,來記錄當前進程內所有的binder_thread。
Binder線程池:每個Server進程在啟動時會創建一個binder線程池,並向其中注冊一個Binder線程;之后Server進程也可以向binder線程池注冊新的線程,或者Binder驅動在探測到沒有空閑binder線程時會主動向Server進程注冊新的的binder線程。對於一個Server進程有一個最大Binder線程數限制,默認為16個binder線程,例如Android的system_server進程就存在16個線程。對於所有Client端進程的binder請求都是交由Server端進程的binder線程來處理的。
4. Binder傳輸過程
Binder IPC機制,就是指在進程間傳輸數據(binder_transaction_data),一次數據的傳輸,稱為事務(binder_transaction)。對於多個不同進程向同一個進程發送事務時,這個同一個進程或線程的事務需要串行執行,在Binder驅動中為binder_proc和binder_thread都有todo隊列。
也就是說對於進程間的通信,就是發送端把binder_transaction節點,插入到目標進程或其子線程的todo隊列中,等目標進程或線程不斷循環地從todo隊列中取出數據並進行相應的操作。
在Binder驅動層,每個接收端進程都有一個todo隊列,用於保存發送端進程發送過來的binder請求,這類請求可以由接收端進程的任意一個空閑的binder線程處理;接收端進程存在一個或多個binder線程,在每個binder線程里都有一個todo隊列,也是用於保存發送端進程發送過來的binder請求,這類請求只能由當前binder線程來處理。binder線程在空閑時進入可中斷的休眠狀態,當自己的todo隊列或所屬進程的todo隊列有新的請求到來時便會喚醒,如果是由所需進程喚醒的,那么進程會讓其中一個線程處理響應的請求,其他線程再次進入休眠狀態。
5. Binder路由
先來看看Native Binder IPC的兩個重量級對象:BpBinder(客戶端)和BBinder(服務端)都是Android中Binder通信相關的代表,它們都從IBinder類中派生而來,關系圖如下:
- IBinder有一個重要方法queryLocalInterface, 默認返回值為NULL;
- BBinder/BpBinder都沒有實現,默認返回NULL;BnInterface重寫該方法;
- BinderProxy(Java)默認返回NULL;Binder(Java)重寫該方法;
- IInterface有一個重要方法asBinder;
- IInterface子類(服務端)會有一個方法asInterface;
Native層通過宏IMPLEMENT_META_INTERFACE來完成asInterface實現和descriptor的賦值過程;
對於Java層跟Native一樣,也有完全對應的一套對象和方法:
- 例如ActivityManagerNative, 通過實現asInterface方法,以及其通過其構造函數 調用attachInterface(),完成descriptor的賦值過程。
- 再如AIDL全自動生成asInterface和descriptor賦值過程。
同一個進程,請求binder服務,不需要創建binder_ref,BpBinder等這些對象,但是是否需要經過binder call,取決於descriptor是否設置。 這就涉及到Java服務Native使用,或許Native服務在Java層使用,需要格外注意。
binder的路由原理:BpBinder發送端,根據handler,在當前binder_proc中,找到相應的binder_ref,由binder_ref再找到目標binder_node實體,由目標binder_node再找到目標進程binder_proc。簡單地方式是直接把binder_transaction節點插入到binder_proc的todo隊列中,完成傳輸過程。
對於binder驅動來說應盡可能地把binder_transaction節點插入到目標進程的某個線程的todo隊列,效率更高。當binder驅動可以找到合適的線程,就會把binder_transaction節點插入到相應線程的todo隊列中,如果找不到合適的線程,就把節點之間插入binder_proc的todo隊列。