Android跨進程通信IPC整體內容如下
- 1、Android跨進程通信IPC之1——Linux基礎
- 2、Android跨進程通信IPC之2——Bionic
- 3、Android跨進程通信IPC之3——關于"JNI"的那些事
- 4、Android跨進程通信IPC之4——AndroidIPC基礎1
- 4、Android跨進程通信IPC之4——AndroidIPC基礎2
- 5、Android跨進程通信IPC之5——Binder的三大接口
- 6、Android跨進程通信IPC之6——Binder框架
- 7、Android跨進程通信IPC之7——Binder相關結構體簡介
- 8、Android跨進程通信IPC之8——Binder驅動
- 9、Android跨進程通信IPC之9——Binder之Framework層C++篇1
- 9、Android跨進程通信IPC之9——Binder之Framework層C++篇2
- 10、Android跨進程通信IPC之10——Binder之Framework層Java篇
- 11、Android跨進程通信IPC之11——AIDL
- 12、Android跨進程通信IPC之12——Binder補充
- 13、Android跨進程通信IPC之13——Binder總結
- 14、Android跨進程通信IPC之14——其他IPC方式
- 15、Android跨進程通信IPC之15——感謝
本篇文章的主要內容如下:
- 1 Android為什么選用Binder作為最重要的IPC機制
- 2 Binder中相關的類簡述
- 3 Binder機制概述
- 4 Binder通信概述
- 5 Binder協議
- 6 Binder架構
一 、 Android為什么選用Binder作為最重要的IPC機制
我們知道在Linux系統中,進程間的通信方式有socket,named pipe,message queue, signal,sharememory等。這幾種通信方式的優缺點如下:
- name pipe:任何進程都能通訊,但速度慢
- message queue:容量受到系統限制,且要注意第一次讀的時候,要考慮上一次沒有讀完數據的問題。
- signal:不能傳遞復雜消息,只能用來同步
- shared memory:能夠容易控制容量,速度快,但要保持同步,比如寫一個進程的時候,另一個進程要注意讀寫的問題,相當于線程中的線程安全。當然,共享內存同樣可以作為線程通訊,不過沒有這個必要,線程間本來就已經共享了同一個進程內的一塊內存。
- socket:本機進程之間可以利用socket通信,跨進程之間也可利用socket通信,通常RPC的實現最底層都是通過socket通信。socket通信是一種比較復雜的通信方式,通常客戶端需要開啟單獨的監聽線程來接受從服務端發過來的數據,客戶端線程發送數據給服務端,如果需要等待服務端的響應,并通過監聽線程接受數據,需要進行同步,是一件很麻煩的事情。socket通信速度也不快。
Android中屬性服務的實現和vold服務的實現采用了socket,getprop和setprop等命令都是通過socket和init進程通信來獲的屬性或者設置屬性,vdc命令和mount service也是通過socket和vold服務通信來操作外接設備,比如SD卡
Message queue允許任意進程共享消息隊列實現進程間通信,并由內核負責消息發送和接受之間的同步,從而使得用戶在使用消息隊列進行通信時不再需要考慮同步問題。這樣使用方便,但是信息的復制需要額外消耗CPU時間,不適合信息量大或者操作頻繁的場合。共享內存針對消息緩存的缺點改而利用內存緩沖區直接交換信息,無須復制,快遞,信息量大是其優點。
共享內存塊提供了在任意數量的進程之間進行高效的雙向通信機制,每個使用者都可以讀寫數據,但是所有程序之間必須達成并遵守一定的協議,以防止諸如在讀取信息之前覆蓋內存空間等競爭狀態的實現。不幸的是,Linux無法嚴格保證對內存塊的獨占訪問,甚至是你通過使用IPC_PRIVATE創建新的共享內存塊的時候,也不能保證訪問的的獨占性。同時,多個使用共享內存塊的進程之間必須協調使用同一個鍵值。
Android應用程序開發者開發應用程序時,對系統框架的進程和線程運行機制不必了解,只需要利用四大組件開發,Android應用開發時可以輕易調用別的軟件提供的功能,甚至可以調用系統App,在Android的世界里,所有應用都是平等的,但實質上應用進程被隔離在不同的沙盒里。
Android平臺的進程之間需要頻繁的通信,比如打開一個應用便需要在Home應用程序進程和運行在system_server進程里的ActivityManagerService通信才能打開。正式由于Android平臺的進程需要非常頻繁的通信,故此對進程間通信機制要求比較高,速度要快,還要能進行復雜的數據的交換,應用開發時盡可能簡單,并能提供同步調用。雖然共享內存的效率高,但是它需要復雜的同步機制,使用時很麻煩,故此不能采用。Binder能滿足這些要求,所以Android選擇了Binder作為最核心的進程間通信方式。Binder主要提供一下功能:
- 1、用驅動程序來推進進程間的通信方式
- 2、通過共享內存來提高性能
- 3、為進程請求分配的每個進程的線程池,每個進程默認啟動的兩個Binder服務線程
- 4、針對系統中的對象引入技術和跨進程對象的引用映射
- 5、進程間同步調用。
二、Binder中相關的類簡述
為了讓大家更好的理解Binder機制,我這里把每個類都簡單說下,設計到C層就是結構體。每個類/結構體都有一個基本的作用,還是按照之前的分類,如下圖
關于其中的關系,比如繼承,實現如下圖:
(一)、Java層相關類
1、IInterface
類型:接口
作用:供Java層服務接口繼承的接口,所有的服務提供者,必須繼承這個接口
比如我們知道的ActivityManagerService繼承自ActivityManagerNative,而ActivityManagerNative實現了IActivityManager,而IActivityManager繼承自IInterface
2、IBinder
類型:接口
作用:Java層的IBinder類,定義了Java層Binder通信的一些規則;提供了transact方法來調用遠程服務
比如我們知道的Binder類就是實現了IBinder
3、Binder
類型:類
作用:實現了IBinder接口,封裝了JNI的實現。Java層Binder服務的基類。存在服務端的Binder對象
比如我們知道的ActivityManagerService繼承自ActivityManagerNative,而ActivityManagerNative繼承自Binder
4、BinderProxy
類型:類
作用:實現了IBinder接口,封裝了JNI的實現,提供了transaction()方法提供進行遠程調用
存在客戶端的進程的服務端Binder的代理
5、Parcel
類型:類
作用:Java層的數據包裝器,跨進程通信傳遞的數據的載體就是Parcel
我們經常的Parcelable其實就是將數據寫入Parcel。具體可以看C++層的Parcel類
(二)、JNI層相關類
1、JavaBBinderHolder
類型:類
作用:內部存儲了JavaBBinder
2、JavaBBinder
類型:類
作用:將C++端的onTransact調用傳遞到Java端
JavaBBinder和JavaBBinderHolder相關的類類圖如下所示(若看不清,請點擊看大圖),JavaBBinder繼承自本地框架的BBinder,代表Binder Service服務端的實體,而JavaBBinderHolder保存了JavaBBinder指針,Java層的Binder的mObject保存的JavaBBinderHolder指針的值,故此這里用聚合關系表示。BinderProxy的mObject保存的是BpBinder對象的指針的值,故此這里用聚合關系表示
3、Java層Binder對象和NativeBinder對象相互轉化的方法
這里涉及兩個重要的函數
- 1、javaObjectForBinder(JNIEnv* env, const sp<IBinder>& val)——>將Native層的IBinder對象轉化為Java層的IBinder對象。
- 2、ibinderForJavaObject(JNIEnv* env, jobject obj)——> 將Java層的IBinder對象轉化為Native層的IBinder對象
這樣就實現了兩層對象的轉化
(三)、Native層相關類
1、BpRefBase
類型:基類
作用:RefBase子類,提供remote方法獲取遠程Binder,Client端在查詢ServiceManager獲取所需的BpBinder后,BpRefBase負責管理當前獲取的BpBinder實例。
2、IInterface
類型:基類
作用:Binder服務接口的基類,Binder服務通常需要同時提供本地接口和遠程接口。它的子類分別聲明了Client/Server能夠實現所有的方法。
3、BpInterface
類型: 接口
作用:遠程接口的積累,遠程接口是供客戶端調用的接口集
如通client端想要使用 Binder IPC與Service通信,那么首先會從SerrviceManager處查詢并獲得server端service的BpBinder,在client端,這個對象被認為是server端的遠程代理。為了使Client能能夠像本地一樣調用一個遠程server,server需要向client提供一個接口,client在這個接口的基礎上創建一個BpInterface,使用這個對象,client的應用能夠像本地一樣直接調用server端的方法。而不是用去關心具體的Binder IPC實現
BpInterface的原型:
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
BpInterface是一個模板類,當server提供了INTERFACE接口(例如IXXXService),通常會繼承BpInterface模板實現了一個BpXXXService
class BpXXXService: public BpInterface<IXXXService>
實際上BpXXXService實現了雙繼承IXXXService和BpRefBase,這樣既實現了Service中各方法的本地操作,將每個方法的參數以Parcel的形式發給Binder Driver;同時又將BpBinder作為自己的成員來管理,將BpBinder存儲在mRemote中,通過調用BpRefBase的remote()函數來獲取BpBinder的指針。
4、BnInterface
類型 :接口
作用:本地接口的基類,本地接口是需要服務中真正實現的接口集合
BnInterface也是一個模板類。在定義Native端的Service時,基于server提供的INTERFACE接口(IXXXService),通常會繼承BnInterface模板類實現一個BnXXXService,而Native端的Service繼承自BnXXXService。BnXXXService定義了一個onTransact函數,這個函數負責解包收到的Parcel并執行client端的請求方法。BnInterface的原型是:
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
BnXXXService 例如:
class BnXXXService: public BnInterface<IXXXService>
IXXXService為client端的代理接口BpXXXService和Server端的BnXXXServer的共同接口類,這個共同接口類的目的就是保證Service方法在C/S兩端的一致性。
每個Service都可視為一個binder,而真正的Service端的Binder操作及狀態的維護就是通過繼承自BBinder來實現的。BBinder是Service作為BBinder的本質所在
那么,BBinder與BpBinder的區別是什么?BpBinder是Client端創建的用于向Server發送消息的代理,而BBinder是Server端用于接受消息的通道。他們代碼中雖然均有transact方法,但兩者的作用不同,BpBinder的transact方法時向IPCThreadStata實例發送消息,通知其有消息要發送給Binder Driver;而BBinder則當IPCThreadState實例收到Binder Driver消息時,通過BBinder的transact方法將其傳遞給它的子類BnXXXService的onTransact函數執行Server端的操作
5、IBiner
類型 接口
作用 Binder對象的基類,BBinder和BpBinder都是這個的類的子類
這個類比較重要,說一下他的幾個方法
方法名 | 說明 |
---|---|
localBinder | 獲取本地Binder對象 |
remoteBinder | 獲取遠程Binder對象 |
transact | 進行一次Binder操作 |
queryLocalInterface | 獲取本地Binder,如果沒有則返回NULL |
getInterfaceDescriptor | 獲取Binder的服務接口描述,其實就是Binder服務的唯一標識 |
isBinderAlive | 查詢Binder服務是否還活著 |
pingBinder | 發送PING_TRANSACTION給Binder服務 |
6、BpBinder
類型 類
作用 遠程Binder對象,這個類提供transact方法來發送請求,BpXXX中會用到。
BpBinder的實例代表了遠程Binder,這個類的對象將被客戶端調用。其中handle()函數將返回指向Binder服務實現者的句柄,這個類最重要的就是提供了transact()函數,這個函數將遠程調用的參數封裝好發送給Binder驅動。
7、BBinder
類型 基類
作用 本地Binder,服務實現方的基類,提供了onTransact接口來接收請求。
BBinder的實例代表了本地的Binder,它描述了服務的提供方,所有Binder服務的實現者都繼承這個類(的子類),在繼承類中,最重要的就是實現onTransact()函數,因為這個方法是所有請求的入口。因此,這個方法是和BpBinder中的transact()函數對應的。
由于BBinder與BpBinder都是IBinder的子類,具體區別如下:
8、ProcessState
類型 類
作用 代表Binder的進程
ProcessState是以單例模式設計的,每個進程在使用Binder機制進行通信時,均需要維護一個ProcessState實例來描述當前進程在Binder通信時Binder狀態。
ProcessState有兩個主要功能:
- 1、創建一個thread,該線程負責與內核中的Binder模塊進行通信,該線程稱為Poolthread;
- 2、為指定的handle創建一個BpBinder對象,并管理該進程中所有的BpBinder對象。
在Binder IPC中,所有進程均會啟動一個thread來負責與Binder Drive來通信,也就是不停的讀寫Binder Drive。Poolthread的啟動方式為
ProcessState::self()->startThreadPool();
BpBinder的主要功能是負責Client向Binder Driver發送調用請求的數據,它是Client端Binder通信的核心對象,通過調用transact函數向Binder Driver發送調用請求數據。BpBinder的構造函數為
BpBinder(int32_t handle);
該構造函數可見,BpBinder會將通信中的Server的handle記錄下來,當有數據發送時,會通知Binder Driver數據的發送目標。
ProcessState通過下下述方式來獲取BpBinder對象。
ProcessState::self()->getContextObject(handle);
ProcessState創建的BpBinder實例,一般情況下會作為參數創建一個Client端的Service代理接口,例如BpXXX,在和ServiceManager通信時,Client會創建一個代理接口BpServieManager。
9、IPCThreadState
類型 類
作用 代表了使用Binder的線程,這個類中封裝了與Binder驅動通信的邏輯,說白了就是負責與Binder Driver的驅動
IPCThreadState是以單例模式設計的。因為每個進程只維護了一個ProcessState實例,同時Process state只啟動了一個Poolthread,因此每個進程只需要一個IPCThreadState即可。
Poolthread實際內容為:
IPCThreadState::self()->joinThreadPool();
ProcessState中有兩個Parcel對象,mIn和mOut。Poolthread會不停的查詢Binder Driver中是否有數據可讀,如果有,將其讀出并保存到mIn;同時不聽的查詢mOut是否有數據要想Binder Driver發送,如果有,則將其內容寫入Binder Driver中。總而言之,從Binder Driver讀出的數據保存在mIn,待寫入到Binder Driver中的數據保存在mOut中。
ProcessState中生成了BpBinder實例通過調用IPCThreadState的transact函數來向mOut中寫入數據。
IPCThreadState有兩個重要的函數,talkWithDriver函數負責從Binder Driver續寫數據,executeCommand函數負責解析并執行mIn中的數據
10、Parcel
類型 類
作用 在Binder上傳遞數據的包裝器。
Parcel是Binder IPC中最基本的通信單元,它存儲C/S間函數調用的參數。Parccel只能存儲基本的數據類型,如果是復雜的數據類型的話,在存儲時,需要將其拆分為基本的數據類型來存儲。
Binder通信的雙方即可以作為Client,也可以作為Server,此時Binder通信是一個半雙工的通信,操作的過程會比單工的情況復雜,但是基本原理是一樣的。
11、補充
這里補充一下 這里的IInterface、IBinder和C++層的兩個類是同名的。這個同名并不是巧合:它們不僅僅同名,它們所起的作用,以及其中包含的接口都是幾乎一樣的,區別僅僅是一個在C++層,一個是在Java層
12、類關系
下圖描述了這些類之間的關系:
PS:Binder的服務實現類(圖中紫色部分)通常都會遵守下面的命名規則:
- 服務的接口使用I字母作為前綴
- 遠程接口使用Bp作為前綴
- 本地接口使用Bn作為前綴
12、Native流程
那我們來看下在Native層中的Binder流程,以MediaPlayer為例
總結一下:
- 1、在已知服務名的情況下,App通過getService()從ServiceManager獲取服務的信息,該信息封裝在Parcel里。
- 2、應用程序收到返回的這個Parcel對象(通過Binder Drive),從中讀取出flat_binder_object對象,最終從對象中得到服務對應的服務號,mHandle。
- 3、以該號碼作為參數輸入生成一個IBinder對象(實際上是BpBinder)。
- 4、應用獲取該對象后,通過asInterface(IBinder*)生成服務對應的Proxy對象(BpXXX),并將其強轉為接口對象(IXXX),然后直接調用接口函數。
- 5、所有接口對象調用最終會走到BpBinder->transact()函數,這個函數調用IPCThreadState->transact()并以Service號作為參數之一。
- 6、最終通過系統調用ioctl()進入內核空間,Binder驅動根據傳進來的Service號尋找該Service正處于等待狀態的Binder Thread,喚醒它并在該線程內執行相應的函數,并返回結果給App。
強調一下:
1、從應用程序的角度來看,他只認識IBinder和IMediaPlayer這兩個類,但真正的實現在BpBinder和BpMediaPlayer,這正式是設計模式中所推崇的“Programs to interface,not implementations”,可以說Android是一個嚴格遵循設計模式思想精心設計的系統。
2、客戶端應該層層的封裝,最終目的就是獲取和傳遞這個mHandle值,從圖中,我們看到,這個mHandle值來自與IServiceManager,他是一個管理其他服務的服務,通過服務的名字我們可以拿到這個服務對應的Handle號,類似網絡域名服務系統。但是我們說了,IServiceManager也是服務,要訪問他我們也需要一個Handle號,對了,就如同你必須為你的機器設置DNS服務器地址,你才能獲得DNS服務。在Android系統里,默認的將ServiceManager的Handler號設為0,0就是DNS服務器的地址,這樣,我們通過調用getStrongProxyForHandle(0)就可以拿到ServiceManager的IBinder對象,當然系統提供一個getService(char*)函數來完成這個過程。
3 Android Binder設計目的就是讓訪問遠端服務就像調用本地函數一樣簡單,但是遠端對象不再本地控制之內,我們必須保證調用過程中遠端的對象不能被析構,否則本地應用程序將很可能崩潰。同時,萬一遠端服務異常退出,如Crash,本地對象必須知曉從而避免后續的錯誤。Android通過智能指針和DeathNotifacation來支持這兩個請求。
Binder的Native層設計邏輯簡單介紹完畢。我們接下來看看Binder的底層設計。
(四)、Linux內核層的結構體
Binder驅動中有很多結構體,驅動中的結構體可以分為兩類:
1、與用戶控件共用的結構體
結構體名稱 | 說明 |
---|---|
flat_binder_object | 描述在Binder在IPC中傳遞的對象 |
binder_write_read | 存儲一次讀寫操作的數據 |
binder_version | 存儲Binder的版本號 |
transaction_flags | 描述事務的flag,例如是否是異步請求,是否支持fd |
binder_transaction_data | 存儲一次事務的數據 |
binder_ptr_cookie | 包含了一個指針和一個cookie |
binder_handle_cookie | 包含了一個句柄和一個cookie |
這里面binder_write_read和binder_transaction_data這兩個結構體最為重要,它們存儲了IPC調用過程中的數據
2、僅在Binder驅動中使用
結構體名稱 | 說明 |
---|---|
binder_node | 描述了Binder實體節點,即對應一個Server |
binder_ref | 描述對于Binder實體的引用 |
binder_buffer | 描述Binder通信過程中存儲數據的Buffer |
binder_proc | 描述使用Binder的進程 |
binder_thread | 描述Binder的線程 |
binder_work | 描述通信的一項任務 |
binder_transaction | 描述一次事務的相關信息 |
binder_deferred_state | 描述延遲任務 |
binder_ref_death | 描述Binder實體死亡的信息 |
binder_transaction_log | debugfs日志 |
binder_transaction_log_entry | debugfs日志條目 |
3、總結
- 1 當一個service向Binder Driver注冊時(通過flat_binder_object),Binder Driver會創建一個binder_node,并掛載到service所在進程的nodes紅黑樹中。
- 2 這個service的binder線程在proc->wait隊列上進入睡眠等待。等待一個binder_work的到來。
- 3 客戶端的BpBinder創建的時候,它在Binder Driver內部也產生了一個binder_ref對象,并指向某個binder_node,在Binder Driver內部,將client和server關聯起來。如果它需要或者Service的死亡狀態,則會生成相應的binder_ref_death。
- 4 客戶端通過transact() (對應內核命令BC_TRANSACTION)請求遠端服務,Driver 通過ref->node的映射,找到service所在進程,生產一個binder_buffer,binder_transaction和binder_work并插入proc->todo對下列,接著喚醒某個睡在proc->wait隊列上的Binder_thread,與此同時,該客戶端線程在其線程的wait隊列上進入睡眠,等待返回值。
- 5 這個binder thread 從proc->todo隊列中讀出一個binder_transaction,封裝成transaction_data(命令為BR_TRANSACTION)并送到用戶控件。Binder用戶線程喚醒并最終執行對應的on_transact()函數
- 6 Binder用戶線程通過transact()向內核發送BC_REPLY命令,Driver收到后從其thread->transaction_stack中找到對應的binder_trannsaction,從而知道是哪個客戶端線程正在等待這個返回
- 7 Driver 生產新的binder_transaction(命令 BR_REPLY),binder_buffer,binder_work,將其插入應用線程的todo隊列,并將該線程喚醒。
- 8 客戶端的用戶線程收到回復數據,該Transaction完成。
- 9 當service所在進程發生異常,Driver的release函數被調用到,在某位內核work_queue線程里完成該service在內核態的清理工作(thread,buffer,node,work...),并找到所有引用它的binder_ref,如果某個binder_ref有不在空的binder_ref_death,生成新的binder_work,送入其線程的todo隊列,喚醒它來執行剩余工作,用戶端的
DeathRecipient會最終調用來完成client端的清理工作。
西面這張時序圖描述了上述一個transaction完成的過程。不同顏色代表不同的線程。注意的是,雖然Kernel和User space線程顏色是不一樣的,但所有的系統調用都發生在用戶進程的上下文李(所謂上下文,就是Kernel能通過某種方式找到關聯的進程,并完成進程的相關操作,比如喚醒某個睡眠線程,或跟用戶控件交換數據,copy_from,copy_to,與之相對應的是中斷上下文,其完全異步出發, 因此無法做任何與進程相關的操作,比如睡眠,鎖等).
(五)、Binder整個通信個過程
三、Binder機制概述
前面幾篇文章分別從驅動,Native,Framework層介紹了Binder,那我們就來總結一下:
- 1、從IPC角度來說:Binder是Android中的一種跨進程通信方式,該方式在linux中沒有,是Android獨有的。
- 2、從Android Driver層:Binder還可以理解為一種虛擬物理設備,它的設備驅動是/dev/binder。
- 3、從Android Native層:Binder創建Service Manager以及BpBinder/BBinder模型,大推薦與binder驅動的橋梁
- 4、從Android Framework層:Binder是各種Manager(ActivityManager,WindowManager等)和相應的xxManagerService的橋梁
- 5、從Android App層:Binder是客戶端和服務端進行通信的媒介,當binderService時候,服務端會返回一個包含了服務端業務調用的Binder對象,通過這個Binder對象,客戶端就可以獲取服務端提供的服務或者數據,這里的服務包括普通服務和基于AIDL的服務。
四、Binder通信概述
Binder通信是一種C/S結構的通信結構。
- 從表面上來看,是client通過獲得一個server的代理接口,對server進行直接調用。
- 實際上,代理接口中定義的方法與server中定義的方法是一一對應的。
- Client端調用某這個代理接口中的方法時,代理接口的方法會將client傳遞的參數打包成Parcel對象。
- 代理接口將該Parcel發送給內核中的Binder Driver。
- Server端會讀取Binder Driver中的請求的數據,如果是發送給自己的,解包Parcel對象,處理并將結果返回。
- 整個的調用過程是一個同步過程,在server處理的時候,client會block住。
整體流程如下:
五、Binder協議
Binder協議可以分為控制協議和驅動協議兩類
(一) Binder控制協議
Binder控制協議是 進程通過 ioctl("/dev/binder") 與Binder設備進行通訊的協議,該協議包含以下幾種命令:
命令 | 說明 | 參數類型 |
---|---|---|
BINDER_WRITE_READ | 讀寫操作,最常用的命令。IPC過程就是通過這個命令進行數據傳遞 | binder_write_read |
BINDER_SET_MAX_THREADS | 設置進程支持的最大線程數量 | size_t |
BINDER_SET_CONTEXT_MGR | 設置自身為ServiceManager | 無 |
BINDER_THREAD_EXIT | 通知驅動Binder線程退出 | 無 |
BINDER_VERSION | 獲取Binder驅動的版本號 | binder_version |
(二) Binder驅動協議
Binder驅動協議描述了對Binder驅動的具體使用過程。驅動協議又可以分為兩類:
- binder_driver_command_protocol:描述了進程發送給Binder驅動的命令
- binder_driver_return_protocol:描述了Binder驅動發送給進程的命令
1、binder_driver_command_protocol 共包含17條命令,分別如下:
命令 | 說明 | 參數類型 |
---|---|---|
BC_TRANSACTION | Binder事務,即:Client對于Server的請求 | binder_transaction_data |
BC_REPLAY | 事務的應答,即Server對于Client的回復 | binder_transaction_data |
BC_FREE_BUFFER | 通知驅動釋放Buffer | binder_uintptr_t |
BC_ACQUIRE | 強引用技術+1 | _u32 |
BC_RELEASE | 強引用技術-1 | _u32 |
BC_INCREFS | 弱引用+1 | _u32 |
BC_DECREFS | 弱引用 -1 | _u32 |
BC_ACQUIRE_DONE | BR_ACQUIRE的回復 | binder_ptr_cookie |
BC_INCREFS_DONE | BR_INCREFS的回復 | binder_ptr_cookie |
BC_ENTER_LOOPER | 通知驅動主線程ready | void |
BC_REGISTER_LOOPER | 通知驅動子線程ready | void |
BC_EXIT_LOOPER | 通知驅動線程已經退出 | void |
BC_REQUEST_DEATH_NOTIFICATION | 請求接受死亡通知 | binder_ptr_cookie |
BC_CLEAR_DEATH_NOTIFICATION | 去除接收死亡通知 | binder_ptr_cookie |
BC_DEAD_BINDER_DONE | 已經處理完死亡通知 | binder_uintptr_t |
BC_ATTEMPT_ACQUIRE 和 BC_ACQUIRE_RESULT 暫未實現。
2、binder_driver_return_protocol 共包含18條命令,分別如下:
返回類型 | 說明 | 參數類型 |
---|---|---|
BR_OK | 操作完成 | void |
BR_NOOP | 操作完成 | void |
BR_ERROR | 發生錯誤 | _s32 |
BR_TRANSACTION | 通知進程收到一次Binder請求(Server端) | binder_transaction_data |
BR_REPLAY | 通知進程收到Binder請求的回復(Client端) | binder_transaction_data |
BR_TRANSACTION_COMPLETE | 驅動對于接受請求的確認稅負 | void |
BR_FAILED_REPLAY | 告知發送發通信目標不存在 | void |
BR_SPWAN_LOOPER | 通知Binder進程創建一個新的線程 | void |
BR_ACQUIRE | 強引用計數+1 | binder_ptr_cookie |
BR_RELEASE | 強引用計數-1 | binder_ptr_cookie |
BR_INCREFS | 弱引用計數+1 | binder_ptr_cookie |
BR_DECREFS | 弱引用計數-1 | binder_ptr_cookie |
BR_DEAD_BINDER | 發送死亡通知 | binder_uintptr_t |
BR_CELAR_DEATH_NOTIFACATION_DONE | 清理死亡通知完成 | binder_uintptr_t |
BR_DEAD_REPLY | 告知發送方對方已經死亡 | void |
BR_ACQUIRE_RESULT 、BR_FINISHED 和 BR_ATTEMPT_ACQUIRE 暫未實現。
單獨看上面的協議可能很難理解,這里我們可以將一次Binder請求過程來看一下Binder協議是如何通信的,就比較好理解了,如下圖:
圖說明:
- Binder是C/S機構,通信從過程涉及到Client、Service以及Binder驅動三個角色
- Client對于Server的請求以及Server對于Client回復都需要通過Binder驅動來中轉數據
- BC_XXX 命令是進城發送給驅動的命令
- BR_XXX 命令是驅動發送給進程的命令
- 整個通信過程有Binder驅動控制
補充說明,通過上面的Binder協議,我們知道,Binder協議的通信過程中,不僅僅是發送請求和接收數據這些命令。同時包括了對于引用計數的管理和對于死亡通知管理的功能(告知一方,通信的另外一方已經死亡)。這些功能的通信過程和上面這幅圖類似:
一方發送BC_XXX,然后由驅動控制通信過程,接著發送對應BR_XXX命令給通信的另外一方。因為這種相似性,我就不多說了。
上面提到了Binder的架構,那我們下面就來研究下Binder的結構
六、Binder架構
(一)、Binder架構的思考
在說到Binder架構之前,先簡單說說大家熟悉的TCP/IP五層通信系統結構
- 應用層:直接為用戶提供服務
- 傳輸層:傳輸的是報文(TCP數據)或者用戶數據報(UDP數據)
- 網絡層:傳輸的是包(Paceket),例如路由器
- 數據鏈路層:傳輸的是幀(Frame),例如以太網交互機
- 物理層:相鄰節點間傳輸bit,例如集線器,雙絞線等
這是經典的五層TCP/IP協議體系,這樣分層設計的思想,讓每一個子問題都設計成一個獨立的協議,這協議的設計/分析/實現/測試都變得更加簡單:
- 層與層具有獨立性,例如應用層可以使用傳輸層提供的功能而無需知曉其原理原理。
- 設計靈活,層與層之間都定義好接口,即便層內方法發生變化,只有接口不變,對這個系統便毫無影響。
- 結構的解耦合,讓每一層可以用更適合的技術方案,更適合的語言
- 方便維護,可分層調試和定位問題
Binder架構也是采用分層架構設計,每一層都有其不同的功能,以大家平時用的startService為例子,AMP為ActivityManagerProxy,AMS為ActivityManagerSerivce 如下圖:
- Java應用層:對于上層通過調用AMP.startService,完全可以不用去關心底層,經過層層調用,最終必然會調用到AMS.startService。
- Java IPC層:Binder采用的是C/S腳骨,Android系統的基礎架構便已經設計好的Binder在Java Framework層的Binder 客戶端BinderProxy和服務端Binder。
- Native IPC層: 對于Native層,如果需要使用Binder,則可以直接使用BpBinder和BBinder(也包括JavaBBindder)即可,對于上一層Java IPC通信也是基于這個層面。
- Kernel物理層:這里是Binder Driver,前面三層都跑在用戶控件,對于用戶控件內存資源是不共享的,每個Android的進程只能運行在自己基礎訥航所擁有的虛擬地址空間,而內核空間卻是可共享的。真正通信的核心環節還是Binder Driver。
(二) 、Binder結構
Binder在整個Android系統中有著舉足輕重的地位,在Native層有一套完成的Binder通信的C/S架構(圖中的藍色),BpBinder作為客戶端,BBinder作為服務端。基于native層的Binder框架,Java也有一套鏡像功能的Binder C/S架構,通過JNI技術,與Native層的Binder對應,Java層的Binder功能最終都是交給native的Binder來完成。從kernel到native,jni,framwork層的架構所涉及的所有有關類和方法見下圖:
(三) 、startService的流程
如下圖:
(四)、SeviceManager自身的注冊和其他service的注冊
這里放一張圖說明整個過程
詳細經過這么多篇文章的講解,大家對Binder有一點的了解,為了讓大家加深對Binder的理解,推薦下面幾篇文章
聽說你Binder機制學的不錯,來面試下這幾個問題(一)
聽說你Binder機制學的不錯,來面試下這幾個問題(二)
聽說你Binder機制學的不錯,來面試下這幾個問題(三)