Android跨進(jìn)程通信IPC整體內(nèi)容如下
- 1、Android跨進(jìn)程通信IPC之1——Linux基礎(chǔ)
- 2、Android跨進(jìn)程通信IPC之2——Bionic
- 3昏翰、Android跨進(jìn)程通信IPC之3——關(guān)于"JNI"的那些事
- 4、Android跨進(jìn)程通信IPC之4——AndroidIPC基礎(chǔ)1
- 4、Android跨進(jìn)程通信IPC之4——AndroidIPC基礎(chǔ)2
- 5太抓、Android跨進(jìn)程通信IPC之5——Binder的三大接口
- 6、Android跨進(jìn)程通信IPC之6——Binder框架
- 7令杈、Android跨進(jìn)程通信IPC之7——Binder相關(guān)結(jié)構(gòu)體簡(jiǎn)介
- 8走敌、Android跨進(jìn)程通信IPC之8——Binder驅(qū)動(dòng)
- 9、Android跨進(jìn)程通信IPC之9——Binder之Framework層C++篇1
- 9逗噩、Android跨進(jìn)程通信IPC之9——Binder之Framework層C++篇2
- 10掉丽、Android跨進(jìn)程通信IPC之10——Binder之Framework層Java篇
- 11、Android跨進(jìn)程通信IPC之11——AIDL
- 12异雁、Android跨進(jìn)程通信IPC之12——Binder補(bǔ)充
- 13捶障、Android跨進(jìn)程通信IPC之13——Binder總結(jié)
- 14、Android跨進(jìn)程通信IPC之14——其他IPC方式
- 15纲刀、Android跨進(jìn)程通信IPC之15——感謝
本篇文章的主要內(nèi)容如下:
- 1 Android為什么選用Binder作為最重要的IPC機(jī)制
- 2 Binder中相關(guān)的類簡(jiǎn)述
- 3 Binder機(jī)制概述
- 4 Binder通信概述
- 5 Binder協(xié)議
- 6 Binder架構(gòu)
一 项炼、 Android為什么選用Binder作為最重要的IPC機(jī)制
我們知道在Linux系統(tǒng)中,進(jìn)程間的通信方式有socket示绊,named pipe锭部,message queue, signal面褐,sharememory等拌禾。這幾種通信方式的優(yōu)缺點(diǎn)如下:
- name pipe:任何進(jìn)程都能通訊,但速度慢
- message queue:容量受到系統(tǒng)限制展哭,且要注意第一次讀的時(shí)候蹋砚,要考慮上一次沒有讀完數(shù)據(jù)的問題扼菠。
- signal:不能傳遞復(fù)雜消息,只能用來同步
- shared memory:能夠容易控制容量坝咐,速度快循榆,但要保持同步,比如寫一個(gè)進(jìn)程的時(shí)候墨坚,另一個(gè)進(jìn)程要注意讀寫的問題秧饮,相當(dāng)于線程中的線程安全。當(dāng)然泽篮,共享內(nèi)存同樣可以作為線程通訊盗尸,不過沒有這個(gè)必要,線程間本來就已經(jīng)共享了同一個(gè)進(jìn)程內(nèi)的一塊內(nèi)存帽撑。
- socket:本機(jī)進(jìn)程之間可以利用socket通信泼各,跨進(jìn)程之間也可利用socket通信,通常RPC的實(shí)現(xiàn)最底層都是通過socket通信亏拉。socket通信是一種比較復(fù)雜的通信方式扣蜻,通常客戶端需要開啟單獨(dú)的監(jiān)聽線程來接受從服務(wù)端發(fā)過來的數(shù)據(jù)及塘,客戶端線程發(fā)送數(shù)據(jù)給服務(wù)端莽使,如果需要等待服務(wù)端的響應(yīng),并通過監(jiān)聽線程接受數(shù)據(jù)笙僚,需要進(jìn)行同步芳肌,是一件很麻煩的事情。socket通信速度也不快肋层。
Android中屬性服務(wù)的實(shí)現(xiàn)和vold服務(wù)的實(shí)現(xiàn)采用了socket亿笤,getprop和setprop等命令都是通過socket和init進(jìn)程通信來獲的屬性或者設(shè)置屬性,vdc命令和mount service也是通過socket和vold服務(wù)通信來操作外接設(shè)備栋猖,比如SD卡
Message queue允許任意進(jìn)程共享消息隊(duì)列實(shí)現(xiàn)進(jìn)程間通信责嚷,并由內(nèi)核負(fù)責(zé)消息發(fā)送和接受之間的同步,從而使得用戶在使用消息隊(duì)列進(jìn)行通信時(shí)不再需要考慮同步問題掂铐。這樣使用方便罕拂,但是信息的復(fù)制需要額外消耗CPU時(shí)間,不適合信息量大或者操作頻繁的場(chǎng)合全陨。共享內(nèi)存針對(duì)消息緩存的缺點(diǎn)改而利用內(nèi)存緩沖區(qū)直接交換信息爆班,無須復(fù)制,快遞辱姨,信息量大是其優(yōu)點(diǎn)柿菩。
共享內(nèi)存塊提供了在任意數(shù)量的進(jìn)程之間進(jìn)行高效的雙向通信機(jī)制,每個(gè)使用者都可以讀寫數(shù)據(jù)雨涛,但是所有程序之間必須達(dá)成并遵守一定的協(xié)議枢舶,以防止諸如在讀取信息之前覆蓋內(nèi)存空間等競(jìng)爭(zhēng)狀態(tài)的實(shí)現(xiàn)懦胞。不幸的是,Linux無法嚴(yán)格保證對(duì)內(nèi)存塊的獨(dú)占訪問凉泄,甚至是你通過使用IPC_PRIVATE創(chuàng)建新的共享內(nèi)存塊的時(shí)候躏尉,也不能保證訪問的的獨(dú)占性。同時(shí)后众,多個(gè)使用共享內(nèi)存塊的進(jìn)程之間必須協(xié)調(diào)使用同一個(gè)鍵值胀糜。
Android應(yīng)用程序開發(fā)者開發(fā)應(yīng)用程序時(shí),對(duì)系統(tǒng)框架的進(jìn)程和線程運(yùn)行機(jī)制不必了解蒂誉,只需要利用四大組件開發(fā)教藻,Android應(yīng)用開發(fā)時(shí)可以輕易調(diào)用別的軟件提供的功能,甚至可以調(diào)用系統(tǒng)App右锨,在Android的世界里括堤,所有應(yīng)用都是平等的,但實(shí)質(zhì)上應(yīng)用進(jìn)程被隔離在不同的沙盒里绍移。
Android平臺(tái)的進(jìn)程之間需要頻繁的通信悄窃,比如打開一個(gè)應(yīng)用便需要在Home應(yīng)用程序進(jìn)程和運(yùn)行在system_server進(jìn)程里的ActivityManagerService通信才能打開。正式由于Android平臺(tái)的進(jìn)程需要非常頻繁的通信登夫,故此對(duì)進(jìn)程間通信機(jī)制要求比較高广匙,速度要快允趟,還要能進(jìn)行復(fù)雜的數(shù)據(jù)的交換恼策,應(yīng)用開發(fā)時(shí)盡可能簡(jiǎn)單,并能提供同步調(diào)用潮剪。雖然共享內(nèi)存的效率高涣楷,但是它需要復(fù)雜的同步機(jī)制,使用時(shí)很麻煩抗碰,故此不能采用狮斗。Binder能滿足這些要求,所以Android選擇了Binder作為最核心的進(jìn)程間通信方式弧蝇。Binder主要提供一下功能:
- 1碳褒、用驅(qū)動(dòng)程序來推進(jìn)進(jìn)程間的通信方式
- 2、通過共享內(nèi)存來提高性能
- 3看疗、為進(jìn)程請(qǐng)求分配的每個(gè)進(jìn)程的線程池沙峻,每個(gè)進(jìn)程默認(rèn)啟動(dòng)的兩個(gè)Binder服務(wù)線程
- 4、針對(duì)系統(tǒng)中的對(duì)象引入技術(shù)和跨進(jìn)程對(duì)象的引用映射
- 5两芳、進(jìn)程間同步調(diào)用摔寨。
二、Binder中相關(guān)的類簡(jiǎn)述
為了讓大家更好的理解Binder機(jī)制怖辆,我這里把每個(gè)類都簡(jiǎn)單說下是复,設(shè)計(jì)到C層就是結(jié)構(gòu)體删顶。每個(gè)類/結(jié)構(gòu)體都有一個(gè)基本的作用,還是按照之前的分類淑廊,如下圖
關(guān)于其中的關(guān)系逗余,比如繼承,實(shí)現(xiàn)如下圖:
(一)蒋纬、Java層相關(guān)類
1猎荠、IInterface
類型:接口
作用:供Java層服務(wù)接口繼承的接口,所有的服務(wù)提供者蜀备,必須繼承這個(gè)接口
比如我們知道的ActivityManagerService繼承自ActivityManagerNative关摇,而ActivityManagerNative實(shí)現(xiàn)了IActivityManager,而IActivityManager繼承自IInterface
2碾阁、IBinder
類型:接口
作用:Java層的IBinder類输虱,定義了Java層Binder通信的一些規(guī)則;提供了transact方法來調(diào)用遠(yuǎn)程服務(wù)
比如我們知道的Binder類就是實(shí)現(xiàn)了IBinder
3脂凶、Binder
類型:類
作用:實(shí)現(xiàn)了IBinder接口宪睹,封裝了JNI的實(shí)現(xiàn)。Java層Binder服務(wù)的基類蚕钦。存在服務(wù)端的Binder對(duì)象
比如我們知道的ActivityManagerService繼承自ActivityManagerNative亭病,而ActivityManagerNative繼承自Binder
4、BinderProxy
類型:類
作用:實(shí)現(xiàn)了IBinder接口嘶居,封裝了JNI的實(shí)現(xiàn)罪帖,提供了transaction()方法提供進(jìn)行遠(yuǎn)程調(diào)用
存在客戶端的進(jìn)程的服務(wù)端Binder的代理
5、Parcel
類型:類
作用:Java層的數(shù)據(jù)包裝器邮屁,跨進(jìn)程通信傳遞的數(shù)據(jù)的載體就是Parcel
我們經(jīng)常的Parcelable其實(shí)就是將數(shù)據(jù)寫入Parcel整袁。具體可以看C++層的Parcel類
(二)、JNI層相關(guān)類
1佑吝、JavaBBinderHolder
類型:類
作用:內(nèi)部存儲(chǔ)了JavaBBinder
2坐昙、JavaBBinder
類型:類
作用:將C++端的onTransact調(diào)用傳遞到Java端
JavaBBinder和JavaBBinderHolder相關(guān)的類類圖如下所示(若看不清,請(qǐng)點(diǎn)擊看大圖)芋忿,JavaBBinder繼承自本地框架的BBinder炸客,代表Binder Service服務(wù)端的實(shí)體,而JavaBBinderHolder保存了JavaBBinder指針戈钢,Java層的Binder的mObject保存的JavaBBinderHolder指針的值痹仙,故此這里用聚合關(guān)系表示。BinderProxy的mObject保存的是BpBinder對(duì)象的指針的值逆趣,故此這里用聚合關(guān)系表示
3蝶溶、Java層Binder對(duì)象和NativeBinder對(duì)象相互轉(zhuǎn)化的方法
這里涉及兩個(gè)重要的函數(shù)
- 1、javaObjectForBinder(JNIEnv* env, const sp<IBinder>& val)——>將Native層的IBinder對(duì)象轉(zhuǎn)化為Java層的IBinder對(duì)象。
- 2抖所、ibinderForJavaObject(JNIEnv* env, jobject obj)——> 將Java層的IBinder對(duì)象轉(zhuǎn)化為Native層的IBinder對(duì)象
這樣就實(shí)現(xiàn)了兩層對(duì)象的轉(zhuǎn)化
(三)梨州、Native層相關(guān)類
1、BpRefBase
類型:基類
作用:RefBase子類田轧,提供remote方法獲取遠(yuǎn)程Binder暴匠,Client端在查詢ServiceManager獲取所需的BpBinder后,BpRefBase負(fù)責(zé)管理當(dāng)前獲取的BpBinder實(shí)例傻粘。
2每窖、IInterface
類型:基類
作用:Binder服務(wù)接口的基類,Binder服務(wù)通常需要同時(shí)提供本地接口和遠(yuǎn)程接口弦悉。它的子類分別聲明了Client/Server能夠?qū)崿F(xiàn)所有的方法窒典。
3、BpInterface
類型: 接口
作用:遠(yuǎn)程接口的積累稽莉,遠(yuǎn)程接口是供客戶端調(diào)用的接口集
如通client端想要使用 Binder IPC與Service通信瀑志,那么首先會(huì)從SerrviceManager處查詢并獲得server端service的BpBinder,在client端污秆,這個(gè)對(duì)象被認(rèn)為是server端的遠(yuǎn)程代理劈猪。為了使Client能能夠像本地一樣調(diào)用一個(gè)遠(yuǎn)程server,server需要向client提供一個(gè)接口良拼,client在這個(gè)接口的基礎(chǔ)上創(chuàng)建一個(gè)BpInterface战得,使用這個(gè)對(duì)象,client的應(yīng)用能夠像本地一樣直接調(diào)用server端的方法庸推。而不是用去關(guān)心具體的Binder IPC實(shí)現(xiàn)
BpInterface的原型:
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
BpInterface是一個(gè)模板類常侦,當(dāng)server提供了INTERFACE接口(例如IXXXService),通常會(huì)繼承BpInterface模板實(shí)現(xiàn)了一個(gè)BpXXXService
class BpXXXService: public BpInterface<IXXXService>
實(shí)際上BpXXXService實(shí)現(xiàn)了雙繼承IXXXService和BpRefBase,這樣既實(shí)現(xiàn)了Service中各方法的本地操作予弧,將每個(gè)方法的參數(shù)以Parcel的形式發(fā)給Binder Driver刮吧;同時(shí)又將BpBinder作為自己的成員來管理湖饱,將BpBinder存儲(chǔ)在mRemote中掖蛤,通過調(diào)用BpRefBase的remote()函數(shù)來獲取BpBinder的指針。
4井厌、BnInterface
類型 :接口
作用:本地接口的基類蚓庭,本地接口是需要服務(wù)中真正實(shí)現(xiàn)的接口集合
BnInterface也是一個(gè)模板類。在定義Native端的Service時(shí)仅仆,基于server提供的INTERFACE接口(IXXXService)器赞,通常會(huì)繼承BnInterface模板類實(shí)現(xiàn)一個(gè)BnXXXService,而Native端的Service繼承自BnXXXService墓拜。BnXXXService定義了一個(gè)onTransact函數(shù)港柜,這個(gè)函數(shù)負(fù)責(zé)解包收到的Parcel并執(zhí)行client端的請(qǐng)求方法。BnInterface的原型是:
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
BnXXXService 例如:
class BnXXXService: public BnInterface<IXXXService>
IXXXService為client端的代理接口BpXXXService和Server端的BnXXXServer的共同接口類,這個(gè)共同接口類的目的就是保證Service方法在C/S兩端的一致性夏醉。
每個(gè)Service都可視為一個(gè)binder爽锥,而真正的Service端的Binder操作及狀態(tài)的維護(hù)就是通過繼承自BBinder來實(shí)現(xiàn)的。BBinder是Service作為BBinder的本質(zhì)所在
那么畔柔,BBinder與BpBinder的區(qū)別是什么氯夷?BpBinder是Client端創(chuàng)建的用于向Server發(fā)送消息的代理,而BBinder是Server端用于接受消息的通道靶擦。他們代碼中雖然均有transact方法腮考,但兩者的作用不同,BpBinder的transact方法時(shí)向IPCThreadStata實(shí)例發(fā)送消息玄捕,通知其有消息要發(fā)送給Binder Driver踩蔚;而BBinder則當(dāng)IPCThreadState實(shí)例收到Binder Driver消息時(shí),通過BBinder的transact方法將其傳遞給它的子類BnXXXService的onTransact函數(shù)執(zhí)行Server端的操作
5枚粘、IBiner
類型 接口
作用 Binder對(duì)象的基類寂纪,BBinder和BpBinder都是這個(gè)的類的子類
這個(gè)類比較重要,說一下他的幾個(gè)方法
方法名 | 說明 |
---|---|
localBinder | 獲取本地Binder對(duì)象 |
remoteBinder | 獲取遠(yuǎn)程Binder對(duì)象 |
transact | 進(jìn)行一次Binder操作 |
queryLocalInterface | 獲取本地Binder赌结,如果沒有則返回NULL |
getInterfaceDescriptor | 獲取Binder的服務(wù)接口描述捞蛋,其實(shí)就是Binder服務(wù)的唯一標(biāo)識(shí) |
isBinderAlive | 查詢Binder服務(wù)是否還活著 |
pingBinder | 發(fā)送PING_TRANSACTION給Binder服務(wù) |
6、BpBinder
類型 類
作用 遠(yuǎn)程Binder對(duì)象柬姚,這個(gè)類提供transact方法來發(fā)送請(qǐng)求拟杉,BpXXX中會(huì)用到。
BpBinder的實(shí)例代表了遠(yuǎn)程Binder量承,這個(gè)類的對(duì)象將被客戶端調(diào)用搬设。其中handle()函數(shù)將返回指向Binder服務(wù)實(shí)現(xiàn)者的句柄,這個(gè)類最重要的就是提供了transact()函數(shù)撕捍,這個(gè)函數(shù)將遠(yuǎn)程調(diào)用的參數(shù)封裝好發(fā)送給Binder驅(qū)動(dòng)拿穴。
7、BBinder
類型 基類
作用 本地Binder忧风,服務(wù)實(shí)現(xiàn)方的基類默色,提供了onTransact接口來接收請(qǐng)求。
BBinder的實(shí)例代表了本地的Binder狮腿,它描述了服務(wù)的提供方腿宰,所有Binder服務(wù)的實(shí)現(xiàn)者都繼承這個(gè)類(的子類),在繼承類中缘厢,最重要的就是實(shí)現(xiàn)onTransact()函數(shù)吃度,因?yàn)檫@個(gè)方法是所有請(qǐng)求的入口。因此贴硫,這個(gè)方法是和BpBinder中的transact()函數(shù)對(duì)應(yīng)的椿每。
由于BBinder與BpBinder都是IBinder的子類,具體區(qū)別如下:
8、ProcessState
類型 類
作用 代表Binder的進(jìn)程
ProcessState是以單例模式設(shè)計(jì)的间护,每個(gè)進(jìn)程在使用Binder機(jī)制進(jìn)行通信時(shí)删壮,均需要維護(hù)一個(gè)ProcessState實(shí)例來描述當(dāng)前進(jìn)程在Binder通信時(shí)Binder狀態(tài)。
ProcessState有兩個(gè)主要功能:
- 1兑牡、創(chuàng)建一個(gè)thread央碟,該線程負(fù)責(zé)與內(nèi)核中的Binder模塊進(jìn)行通信,該線程稱為Poolthread均函;
- 2亿虽、為指定的handle創(chuàng)建一個(gè)BpBinder對(duì)象,并管理該進(jìn)程中所有的BpBinder對(duì)象苞也。
在Binder IPC中洛勉,所有進(jìn)程均會(huì)啟動(dòng)一個(gè)thread來負(fù)責(zé)與Binder Drive來通信,也就是不停的讀寫B(tài)inder Drive如迟。Poolthread的啟動(dòng)方式為
ProcessState::self()->startThreadPool();
BpBinder的主要功能是負(fù)責(zé)Client向Binder Driver發(fā)送調(diào)用請(qǐng)求的數(shù)據(jù)收毫,它是Client端Binder通信的核心對(duì)象,通過調(diào)用transact函數(shù)向Binder Driver發(fā)送調(diào)用請(qǐng)求數(shù)據(jù)殷勘。BpBinder的構(gòu)造函數(shù)為
BpBinder(int32_t handle);
該構(gòu)造函數(shù)可見此再,BpBinder會(huì)將通信中的Server的handle記錄下來,當(dāng)有數(shù)據(jù)發(fā)送時(shí)玲销,會(huì)通知Binder Driver數(shù)據(jù)的發(fā)送目標(biāo)输拇。
ProcessState通過下下述方式來獲取BpBinder對(duì)象。
ProcessState::self()->getContextObject(handle);
ProcessState創(chuàng)建的BpBinder實(shí)例贤斜,一般情況下會(huì)作為參數(shù)創(chuàng)建一個(gè)Client端的Service代理接口策吠,例如BpXXX,在和ServiceManager通信時(shí)瘩绒,Client會(huì)創(chuàng)建一個(gè)代理接口BpServieManager猴抹。
9、IPCThreadState
類型 類
作用 代表了使用Binder的線程锁荔,這個(gè)類中封裝了與Binder驅(qū)動(dòng)通信的邏輯蟀给,說白了就是負(fù)責(zé)與Binder Driver的驅(qū)動(dòng)
IPCThreadState是以單例模式設(shè)計(jì)的。因?yàn)槊總€(gè)進(jìn)程只維護(hù)了一個(gè)ProcessState實(shí)例堕战,同時(shí)Process state只啟動(dòng)了一個(gè)Poolthread坤溃,因此每個(gè)進(jìn)程只需要一個(gè)IPCThreadState即可拍霜。
Poolthread實(shí)際內(nèi)容為:
IPCThreadState::self()->joinThreadPool();
ProcessState中有兩個(gè)Parcel對(duì)象嘱丢,mIn和mOut。Poolthread會(huì)不停的查詢Binder Driver中是否有數(shù)據(jù)可讀祠饺,如果有越驻,將其讀出并保存到mIn;同時(shí)不聽的查詢mOut是否有數(shù)據(jù)要想Binder Driver發(fā)送,如果有,則將其內(nèi)容寫入Binder Driver中缀旁〖桥總而言之,從Binder Driver讀出的數(shù)據(jù)保存在mIn并巍,待寫入到Binder Driver中的數(shù)據(jù)保存在mOut中目木。
ProcessState中生成了BpBinder實(shí)例通過調(diào)用IPCThreadState的transact函數(shù)來向mOut中寫入數(shù)據(jù)。
IPCThreadState有兩個(gè)重要的函數(shù)懊渡,talkWithDriver函數(shù)負(fù)責(zé)從Binder Driver續(xù)寫數(shù)據(jù)刽射,executeCommand函數(shù)負(fù)責(zé)解析并執(zhí)行mIn中的數(shù)據(jù)
10、Parcel
類型 類
作用 在Binder上傳遞數(shù)據(jù)的包裝器剃执。
Parcel是Binder IPC中最基本的通信單元誓禁,它存儲(chǔ)C/S間函數(shù)調(diào)用的參數(shù)。Parccel只能存儲(chǔ)基本的數(shù)據(jù)類型肾档,如果是復(fù)雜的數(shù)據(jù)類型的話摹恰,在存儲(chǔ)時(shí),需要將其拆分為基本的數(shù)據(jù)類型來存儲(chǔ)怒见。
Binder通信的雙方即可以作為Client俗慈,也可以作為Server,此時(shí)Binder通信是一個(gè)半雙工的通信遣耍,操作的過程會(huì)比單工的情況復(fù)雜姜盈,但是基本原理是一樣的。
11配阵、補(bǔ)充
這里補(bǔ)充一下 這里的IInterface馏颂、IBinder和C++層的兩個(gè)類是同名的。這個(gè)同名并不是巧合:它們不僅僅同名棋傍,它們所起的作用救拉,以及其中包含的接口都是幾乎一樣的,區(qū)別僅僅是一個(gè)在C++層瘫拣,一個(gè)是在Java層
12亿絮、類關(guān)系
下圖描述了這些類之間的關(guān)系:
PS:Binder的服務(wù)實(shí)現(xiàn)類(圖中紫色部分)通常都會(huì)遵守下面的命名規(guī)則:
- 服務(wù)的接口使用I字母作為前綴
- 遠(yuǎn)程接口使用Bp作為前綴
- 本地接口使用Bn作為前綴
12、Native流程
那我們來看下在Native層中的Binder流程麸拄,以MediaPlayer為例
總結(jié)一下:
- 1派昧、在已知服務(wù)名的情況下,App通過getService()從ServiceManager獲取服務(wù)的信息拢切,該信息封裝在Parcel里蒂萎。
- 2、應(yīng)用程序收到返回的這個(gè)Parcel對(duì)象(通過Binder Drive)淮椰,從中讀取出flat_binder_object對(duì)象五慈,最終從對(duì)象中得到服務(wù)對(duì)應(yīng)的服務(wù)號(hào)纳寂,mHandle。
- 3泻拦、以該號(hào)碼作為參數(shù)輸入生成一個(gè)IBinder對(duì)象(實(shí)際上是BpBinder)毙芜。
- 4、應(yīng)用獲取該對(duì)象后争拐,通過asInterface(IBinder*)生成服務(wù)對(duì)應(yīng)的Proxy對(duì)象(BpXXX)腋粥,并將其強(qiáng)轉(zhuǎn)為接口對(duì)象(IXXX),然后直接調(diào)用接口函數(shù)架曹。
- 5灯抛、所有接口對(duì)象調(diào)用最終會(huì)走到BpBinder->transact()函數(shù),這個(gè)函數(shù)調(diào)用IPCThreadState->transact()并以Service號(hào)作為參數(shù)之一音瓷。
- 6对嚼、最終通過系統(tǒng)調(diào)用ioctl()進(jìn)入內(nèi)核空間,Binder驅(qū)動(dòng)根據(jù)傳進(jìn)來的Service號(hào)尋找該Service正處于等待狀態(tài)的Binder Thread绳慎,喚醒它并在該線程內(nèi)執(zhí)行相應(yīng)的函數(shù)纵竖,并返回結(jié)果給App。
強(qiáng)調(diào)一下:
1杏愤、從應(yīng)用程序的角度來看靡砌,他只認(rèn)識(shí)IBinder和IMediaPlayer這兩個(gè)類,但真正的實(shí)現(xiàn)在BpBinder和BpMediaPlayer珊楼,這正式是設(shè)計(jì)模式中所推崇的“Programs to interface通殃,not implementations”,可以說Android是一個(gè)嚴(yán)格遵循設(shè)計(jì)模式思想精心設(shè)計(jì)的系統(tǒng)厕宗。
2画舌、客戶端應(yīng)該層層的封裝,最終目的就是獲取和傳遞這個(gè)mHandle值已慢,從圖中曲聂,我們看到,這個(gè)mHandle值來自與IServiceManager佑惠,他是一個(gè)管理其他服務(wù)的服務(wù)朋腋,通過服務(wù)的名字我們可以拿到這個(gè)服務(wù)對(duì)應(yīng)的Handle號(hào),類似網(wǎng)絡(luò)域名服務(wù)系統(tǒng)膜楷。但是我們說了旭咽,IServiceManager也是服務(wù),要訪問他我們也需要一個(gè)Handle號(hào)赌厅,對(duì)了穷绵,就如同你必須為你的機(jī)器設(shè)置DNS服務(wù)器地址,你才能獲得DNS服務(wù)察蹲。在Android系統(tǒng)里请垛,默認(rèn)的將ServiceManager的Handler號(hào)設(shè)為0催训,0就是DNS服務(wù)器的地址洽议,這樣宗收,我們通過調(diào)用getStrongProxyForHandle(0)就可以拿到ServiceManager的IBinder對(duì)象,當(dāng)然系統(tǒng)提供一個(gè)getService(char*)函數(shù)來完成這個(gè)過程亚兄。
3 Android Binder設(shè)計(jì)目的就是讓訪問遠(yuǎn)端服務(wù)就像調(diào)用本地函數(shù)一樣簡(jiǎn)單混稽,但是遠(yuǎn)端對(duì)象不再本地控制之內(nèi),我們必須保證調(diào)用過程中遠(yuǎn)端的對(duì)象不能被析構(gòu)审胚,否則本地應(yīng)用程序?qū)⒑芸赡鼙罎⒒癫纭M瑫r(shí)鲁僚,萬一遠(yuǎn)端服務(wù)異常退出,如Crash,本地對(duì)象必須知曉從而避免后續(xù)的錯(cuò)誤吊履。Android通過智能指針和DeathNotifacation來支持這兩個(gè)請(qǐng)求。
Binder的Native層設(shè)計(jì)邏輯簡(jiǎn)單介紹完畢迄委。我們接下來看看Binder的底層設(shè)計(jì)蚌吸。
(四)、Linux內(nèi)核層的結(jié)構(gòu)體
Binder驅(qū)動(dòng)中有很多結(jié)構(gòu)體龄坪,驅(qū)動(dòng)中的結(jié)構(gòu)體可以分為兩類:
1健田、與用戶控件共用的結(jié)構(gòu)體
結(jié)構(gòu)體名稱 | 說明 |
---|---|
flat_binder_object | 描述在Binder在IPC中傳遞的對(duì)象 |
binder_write_read | 存儲(chǔ)一次讀寫操作的數(shù)據(jù) |
binder_version | 存儲(chǔ)Binder的版本號(hào) |
transaction_flags | 描述事務(wù)的flag烛卧,例如是否是異步請(qǐng)求,是否支持fd |
binder_transaction_data | 存儲(chǔ)一次事務(wù)的數(shù)據(jù) |
binder_ptr_cookie | 包含了一個(gè)指針和一個(gè)cookie |
binder_handle_cookie | 包含了一個(gè)句柄和一個(gè)cookie |
這里面binder_write_read和binder_transaction_data這兩個(gè)結(jié)構(gòu)體最為重要妓局,它們存儲(chǔ)了IPC調(diào)用過程中的數(shù)據(jù)
2总放、僅在Binder驅(qū)動(dòng)中使用
結(jié)構(gòu)體名稱 | 說明 |
---|---|
binder_node | 描述了Binder實(shí)體節(jié)點(diǎn),即對(duì)應(yīng)一個(gè)Server |
binder_ref | 描述對(duì)于Binder實(shí)體的引用 |
binder_buffer | 描述Binder通信過程中存儲(chǔ)數(shù)據(jù)的Buffer |
binder_proc | 描述使用Binder的進(jìn)程 |
binder_thread | 描述Binder的線程 |
binder_work | 描述通信的一項(xiàng)任務(wù) |
binder_transaction | 描述一次事務(wù)的相關(guān)信息 |
binder_deferred_state | 描述延遲任務(wù) |
binder_ref_death | 描述Binder實(shí)體死亡的信息 |
binder_transaction_log | debugfs日志 |
binder_transaction_log_entry | debugfs日志條目 |
3好爬、總結(jié)
- 1 當(dāng)一個(gè)service向Binder Driver注冊(cè)時(shí)(通過flat_binder_object)间聊,Binder Driver會(huì)創(chuàng)建一個(gè)binder_node,并掛載到service所在進(jìn)程的nodes紅黑樹中抵拘。
- 2 這個(gè)service的binder線程在proc->wait隊(duì)列上進(jìn)入睡眠等待哎榴。等待一個(gè)binder_work的到來。
- 3 客戶端的BpBinder創(chuàng)建的時(shí)候僵蛛,它在Binder Driver內(nèi)部也產(chǎn)生了一個(gè)binder_ref對(duì)象尚蝌,并指向某個(gè)binder_node,在Binder Driver內(nèi)部充尉,將client和server關(guān)聯(lián)起來飘言。如果它需要或者Service的死亡狀態(tài),則會(huì)生成相應(yīng)的binder_ref_death驼侠。
- 4 客戶端通過transact() (對(duì)應(yīng)內(nèi)核命令BC_TRANSACTION)請(qǐng)求遠(yuǎn)端服務(wù)姿鸿,Driver 通過ref->node的映射谆吴,找到service所在進(jìn)程,生產(chǎn)一個(gè)binder_buffer苛预,binder_transaction和binder_work并插入proc->todo對(duì)下列句狼,接著喚醒某個(gè)睡在proc->wait隊(duì)列上的Binder_thread,與此同時(shí)热某,該客戶端線程在其線程的wait隊(duì)列上進(jìn)入睡眠腻菇,等待返回值。
- 5 這個(gè)binder thread 從proc->todo隊(duì)列中讀出一個(gè)binder_transaction昔馋,封裝成transaction_data(命令為BR_TRANSACTION)并送到用戶控件筹吐。Binder用戶線程喚醒并最終執(zhí)行對(duì)應(yīng)的on_transact()函數(shù)
- 6 Binder用戶線程通過transact()向內(nèi)核發(fā)送BC_REPLY命令,Driver收到后從其thread->transaction_stack中找到對(duì)應(yīng)的binder_trannsaction秘遏,從而知道是哪個(gè)客戶端線程正在等待這個(gè)返回
- 7 Driver 生產(chǎn)新的binder_transaction(命令 BR_REPLY)丘薛,binder_buffer,binder_work邦危,將其插入應(yīng)用線程的todo隊(duì)列洋侨,并將該線程喚醒。
- 8 客戶端的用戶線程收到回復(fù)數(shù)據(jù)铡俐,該Transaction完成凰兑。
- 9 當(dāng)service所在進(jìn)程發(fā)生異常,Driver的release函數(shù)被調(diào)用到审丘,在某位內(nèi)核work_queue線程里完成該service在內(nèi)核態(tài)的清理工作(thread,buffer,node,work...)吏够,并找到所有引用它的binder_ref,如果某個(gè)binder_ref有不在空的binder_ref_death滩报,生成新的binder_work锅知,送入其線程的todo隊(duì)列,喚醒它來執(zhí)行剩余工作脓钾,用戶端的
DeathRecipient會(huì)最終調(diào)用來完成client端的清理工作售睹。
西面這張時(shí)序圖描述了上述一個(gè)transaction完成的過程。不同顏色代表不同的線程可训。注意的是昌妹,雖然Kernel和User space線程顏色是不一樣的,但所有的系統(tǒng)調(diào)用都發(fā)生在用戶進(jìn)程的上下文李(所謂上下文握截,就是Kernel能通過某種方式找到關(guān)聯(lián)的進(jìn)程飞崖,并完成進(jìn)程的相關(guān)操作,比如喚醒某個(gè)睡眠線程谨胞,或跟用戶控件交換數(shù)據(jù)固歪,copy_from,copy_to胯努,與之相對(duì)應(yīng)的是中斷上下文牢裳,其完全異步出發(fā)逢防, 因此無法做任何與進(jìn)程相關(guān)的操作,比如睡眠蒲讯,鎖等).
(五)忘朝、Binder整個(gè)通信個(gè)過程
三、Binder機(jī)制概述
前面幾篇文章分別從驅(qū)動(dòng)伶椿,Native辜伟,F(xiàn)ramework層介紹了Binder氓侧,那我們就來總結(jié)一下:
- 1脊另、從IPC角度來說:Binder是Android中的一種跨進(jìn)程通信方式,該方式在linux中沒有约巷,是Android獨(dú)有的偎痛。
- 2、從Android Driver層:Binder還可以理解為一種虛擬物理設(shè)備独郎,它的設(shè)備驅(qū)動(dòng)是/dev/binder踩麦。
- 3、從Android Native層:Binder創(chuàng)建Service Manager以及BpBinder/BBinder模型氓癌,大推薦與binder驅(qū)動(dòng)的橋梁
- 4谓谦、從Android Framework層:Binder是各種Manager(ActivityManager,WindowManager等)和相應(yīng)的xxManagerService的橋梁
- 5、從Android App層:Binder是客戶端和服務(wù)端進(jìn)行通信的媒介贪婉,當(dāng)binderService時(shí)候反粥,服務(wù)端會(huì)返回一個(gè)包含了服務(wù)端業(yè)務(wù)調(diào)用的Binder對(duì)象,通過這個(gè)Binder對(duì)象疲迂,客戶端就可以獲取服務(wù)端提供的服務(wù)或者數(shù)據(jù)才顿,這里的服務(wù)包括普通服務(wù)和基于AIDL的服務(wù)。
四尤蒿、Binder通信概述
Binder通信是一種C/S結(jié)構(gòu)的通信結(jié)構(gòu)郑气。
- 從表面上來看,是client通過獲得一個(gè)server的代理接口腰池,對(duì)server進(jìn)行直接調(diào)用尾组。
- 實(shí)際上,代理接口中定義的方法與server中定義的方法是一一對(duì)應(yīng)的示弓。
- Client端調(diào)用某這個(gè)代理接口中的方法時(shí)讳侨,代理接口的方法會(huì)將client傳遞的參數(shù)打包成Parcel對(duì)象。
- 代理接口將該P(yáng)arcel發(fā)送給內(nèi)核中的Binder Driver避乏。
- Server端會(huì)讀取Binder Driver中的請(qǐng)求的數(shù)據(jù)爷耀,如果是發(fā)送給自己的,解包Parcel對(duì)象拍皮,處理并將結(jié)果返回歹叮。
- 整個(gè)的調(diào)用過程是一個(gè)同步過程跑杭,在server處理的時(shí)候,client會(huì)block住咆耿。
整體流程如下:
五德谅、Binder協(xié)議
Binder協(xié)議可以分為控制協(xié)議和驅(qū)動(dòng)協(xié)議兩類
(一) Binder控制協(xié)議
Binder控制協(xié)議是 進(jìn)程通過 ioctl("/dev/binder") 與Binder設(shè)備進(jìn)行通訊的協(xié)議,該協(xié)議包含以下幾種命令:
命令 | 說明 | 參數(shù)類型 |
---|---|---|
BINDER_WRITE_READ | 讀寫操作萨螺,最常用的命令窄做。IPC過程就是通過這個(gè)命令進(jìn)行數(shù)據(jù)傳遞 | binder_write_read |
BINDER_SET_MAX_THREADS | 設(shè)置進(jìn)程支持的最大線程數(shù)量 | size_t |
BINDER_SET_CONTEXT_MGR | 設(shè)置自身為ServiceManager | 無 |
BINDER_THREAD_EXIT | 通知驅(qū)動(dòng)Binder線程退出 | 無 |
BINDER_VERSION | 獲取Binder驅(qū)動(dòng)的版本號(hào) | binder_version |
(二) Binder驅(qū)動(dòng)協(xié)議
Binder驅(qū)動(dòng)協(xié)議描述了對(duì)Binder驅(qū)動(dòng)的具體使用過程。驅(qū)動(dòng)協(xié)議又可以分為兩類:
- binder_driver_command_protocol:描述了進(jìn)程發(fā)送給Binder驅(qū)動(dòng)的命令
- binder_driver_return_protocol:描述了Binder驅(qū)動(dòng)發(fā)送給進(jìn)程的命令
1慰技、binder_driver_command_protocol 共包含17條命令椭盏,分別如下:
命令 | 說明 | 參數(shù)類型 |
---|---|---|
BC_TRANSACTION | Binder事務(wù),即:Client對(duì)于Server的請(qǐng)求 | binder_transaction_data |
BC_REPLAY | 事務(wù)的應(yīng)答吻商,即Server對(duì)于Client的回復(fù) | binder_transaction_data |
BC_FREE_BUFFER | 通知驅(qū)動(dòng)釋放Buffer | binder_uintptr_t |
BC_ACQUIRE | 強(qiáng)引用技術(shù)+1 | _u32 |
BC_RELEASE | 強(qiáng)引用技術(shù)-1 | _u32 |
BC_INCREFS | 弱引用+1 | _u32 |
BC_DECREFS | 弱引用 -1 | _u32 |
BC_ACQUIRE_DONE | BR_ACQUIRE的回復(fù) | binder_ptr_cookie |
BC_INCREFS_DONE | BR_INCREFS的回復(fù) | binder_ptr_cookie |
BC_ENTER_LOOPER | 通知驅(qū)動(dòng)主線程ready | void |
BC_REGISTER_LOOPER | 通知驅(qū)動(dòng)子線程ready | void |
BC_EXIT_LOOPER | 通知驅(qū)動(dòng)線程已經(jīng)退出 | void |
BC_REQUEST_DEATH_NOTIFICATION | 請(qǐng)求接受死亡通知 | binder_ptr_cookie |
BC_CLEAR_DEATH_NOTIFICATION | 去除接收死亡通知 | binder_ptr_cookie |
BC_DEAD_BINDER_DONE | 已經(jīng)處理完死亡通知 | binder_uintptr_t |
BC_ATTEMPT_ACQUIRE 和 BC_ACQUIRE_RESULT 暫未實(shí)現(xiàn)掏颊。
2、binder_driver_return_protocol 共包含18條命令艾帐,分別如下:
返回類型 | 說明 | 參數(shù)類型 |
---|---|---|
BR_OK | 操作完成 | void |
BR_NOOP | 操作完成 | void |
BR_ERROR | 發(fā)生錯(cuò)誤 | _s32 |
BR_TRANSACTION | 通知進(jìn)程收到一次Binder請(qǐng)求(Server端) | binder_transaction_data |
BR_REPLAY | 通知進(jìn)程收到Binder請(qǐng)求的回復(fù)(Client端) | binder_transaction_data |
BR_TRANSACTION_COMPLETE | 驅(qū)動(dòng)對(duì)于接受請(qǐng)求的確認(rèn)稅負(fù) | void |
BR_FAILED_REPLAY | 告知發(fā)送發(fā)通信目標(biāo)不存在 | void |
BR_SPWAN_LOOPER | 通知Binder進(jìn)程創(chuàng)建一個(gè)新的線程 | void |
BR_ACQUIRE | 強(qiáng)引用計(jì)數(shù)+1 | binder_ptr_cookie |
BR_RELEASE | 強(qiáng)引用計(jì)數(shù)-1 | binder_ptr_cookie |
BR_INCREFS | 弱引用計(jì)數(shù)+1 | binder_ptr_cookie |
BR_DECREFS | 弱引用計(jì)數(shù)-1 | binder_ptr_cookie |
BR_DEAD_BINDER | 發(fā)送死亡通知 | binder_uintptr_t |
BR_CELAR_DEATH_NOTIFACATION_DONE | 清理死亡通知完成 | binder_uintptr_t |
BR_DEAD_REPLY | 告知發(fā)送方對(duì)方已經(jīng)死亡 | void |
BR_ACQUIRE_RESULT 乌叶、BR_FINISHED 和 BR_ATTEMPT_ACQUIRE 暫未實(shí)現(xiàn)。
單獨(dú)看上面的協(xié)議可能很難理解柒爸,這里我們可以將一次Binder請(qǐng)求過程來看一下Binder協(xié)議是如何通信的准浴,就比較好理解了,如下圖:
圖說明:
- Binder是C/S機(jī)構(gòu)捎稚,通信從過程涉及到Client乐横、Service以及Binder驅(qū)動(dòng)三個(gè)角色
- Client對(duì)于Server的請(qǐng)求以及Server對(duì)于Client回復(fù)都需要通過Binder驅(qū)動(dòng)來中轉(zhuǎn)數(shù)據(jù)
- BC_XXX 命令是進(jìn)城發(fā)送給驅(qū)動(dòng)的命令
- BR_XXX 命令是驅(qū)動(dòng)發(fā)送給進(jìn)程的命令
- 整個(gè)通信過程有Binder驅(qū)動(dòng)控制
補(bǔ)充說明,通過上面的Binder協(xié)議阳藻,我們知道晰奖,Binder協(xié)議的通信過程中,不僅僅是發(fā)送請(qǐng)求和接收數(shù)據(jù)這些命令腥泥。同時(shí)包括了對(duì)于引用計(jì)數(shù)的管理和對(duì)于死亡通知管理的功能(告知一方匾南,通信的另外一方已經(jīng)死亡)。這些功能的通信過程和上面這幅圖類似:
一方發(fā)送BC_XXX蛔外,然后由驅(qū)動(dòng)控制通信過程蛆楞,接著發(fā)送對(duì)應(yīng)BR_XXX命令給通信的另外一方。因?yàn)檫@種相似性夹厌,我就不多說了豹爹。
上面提到了Binder的架構(gòu),那我們下面就來研究下Binder的結(jié)構(gòu)
六矛纹、Binder架構(gòu)
(一)臂聋、Binder架構(gòu)的思考
在說到Binder架構(gòu)之前,先簡(jiǎn)單說說大家熟悉的TCP/IP五層通信系統(tǒng)結(jié)構(gòu)
- 應(yīng)用層:直接為用戶提供服務(wù)
- 傳輸層:傳輸?shù)氖菆?bào)文(TCP數(shù)據(jù))或者用戶數(shù)據(jù)報(bào)(UDP數(shù)據(jù))
- 網(wǎng)絡(luò)層:傳輸?shù)氖前?Paceket),例如路由器
- 數(shù)據(jù)鏈路層:傳輸?shù)氖菐?Frame)孩等,例如以太網(wǎng)交互機(jī)
- 物理層:相鄰節(jié)點(diǎn)間傳輸bit艾君,例如集線器,雙絞線等
這是經(jīng)典的五層TCP/IP協(xié)議體系肄方,這樣分層設(shè)計(jì)的思想冰垄,讓每一個(gè)子問題都設(shè)計(jì)成一個(gè)獨(dú)立的協(xié)議,這協(xié)議的設(shè)計(jì)/分析/實(shí)現(xiàn)/測(cè)試都變得更加簡(jiǎn)單:
- 層與層具有獨(dú)立性权她,例如應(yīng)用層可以使用傳輸層提供的功能而無需知曉其原理原理虹茶。
- 設(shè)計(jì)靈活,層與層之間都定義好接口隅要,即便層內(nèi)方法發(fā)生變化蝴罪,只有接口不變,對(duì)這個(gè)系統(tǒng)便毫無影響拾徙。
- 結(jié)構(gòu)的解耦合洲炊,讓每一層可以用更適合的技術(shù)方案感局,更適合的語(yǔ)言
- 方便維護(hù)尼啡,可分層調(diào)試和定位問題
Binder架構(gòu)也是采用分層架構(gòu)設(shè)計(jì),每一層都有其不同的功能询微,以大家平時(shí)用的startService為例子崖瞭,AMP為ActivityManagerProxy,AMS為ActivityManagerSerivce 如下圖:
- Java應(yīng)用層:對(duì)于上層通過調(diào)用AMP.startService撑毛,完全可以不用去關(guān)心底層书聚,經(jīng)過層層調(diào)用,最終必然會(huì)調(diào)用到AMS.startService藻雌。
- Java IPC層:Binder采用的是C/S腳骨雌续,Android系統(tǒng)的基礎(chǔ)架構(gòu)便已經(jīng)設(shè)計(jì)好的Binder在Java Framework層的Binder 客戶端BinderProxy和服務(wù)端Binder。
- Native IPC層: 對(duì)于Native層胯杭,如果需要使用Binder驯杜,則可以直接使用BpBinder和BBinder(也包括JavaBBindder)即可,對(duì)于上一層Java IPC通信也是基于這個(gè)層面做个。
- Kernel物理層:這里是Binder Driver鸽心,前面三層都跑在用戶控件,對(duì)于用戶控件內(nèi)存資源是不共享的居暖,每個(gè)Android的進(jìn)程只能運(yùn)行在自己基礎(chǔ)訥航所擁有的虛擬地址空間顽频,而內(nèi)核空間卻是可共享的。真正通信的核心環(huán)節(jié)還是Binder Driver太闺。
(二) 糯景、Binder結(jié)構(gòu)
Binder在整個(gè)Android系統(tǒng)中有著舉足輕重的地位,在Native層有一套完成的Binder通信的C/S架構(gòu)(圖中的藍(lán)色),BpBinder作為客戶端蟀淮,BBinder作為服務(wù)端丑孩。基于native層的Binder框架灭贷,Java也有一套鏡像功能的Binder C/S架構(gòu)温学,通過JNI技術(shù),與Native層的Binder對(duì)應(yīng)甚疟,Java層的Binder功能最終都是交給native的Binder來完成仗岖。從kernel到native,jni览妖,framwork層的架構(gòu)所涉及的所有有關(guān)類和方法見下圖:
(三) 轧拄、startService的流程
如下圖:
(四)、SeviceManager自身的注冊(cè)和其他service的注冊(cè)
這里放一張圖說明整個(gè)過程
詳細(xì)經(jīng)過這么多篇文章的講解讽膏,大家對(duì)Binder有一點(diǎn)的了解檩电,為了讓大家加深對(duì)Binder的理解,推薦下面幾篇文章
聽說你Binder機(jī)制學(xué)的不錯(cuò)府树,來面試下這幾個(gè)問題(一)
聽說你Binder機(jī)制學(xué)的不錯(cuò)俐末,來面試下這幾個(gè)問題(二)
聽說你Binder機(jī)制學(xué)的不錯(cuò),來面試下這幾個(gè)問題(三)