1 Android整體架構(gòu)
Android系統(tǒng)架構(gòu)及系統(tǒng)源碼目錄
- Android系統(tǒng)架構(gòu)分為五層曼月,從上到下依次是應(yīng)用層惠奸、應(yīng)用框架層、系統(tǒng)運(yùn)行庫(kù)層蝗茁、硬件抽象層和Linux內(nèi)核層。
- 應(yīng)用層:系統(tǒng)內(nèi)置的應(yīng)用程序以及非系統(tǒng)級(jí)的應(yīng)用程序都是屬于應(yīng)用層。
- 應(yīng)用框架層(Java Framework):應(yīng)用框架層為開(kāi)發(fā)人員提供了可以開(kāi)發(fā)應(yīng)用程序所需要的API都弹,各種Manager(Activity Manager(活動(dòng)管理器),Package Manager(包管理器)匙姜,Telephony Manager(電話管理器)畅厢,View System(視圖系統(tǒng),構(gòu)建應(yīng)用程序的基本組件)氮昧,Content Providers(內(nèi)容提供器))
- 系統(tǒng)運(yùn)行庫(kù)層(Native):系統(tǒng)運(yùn)行庫(kù)層分為兩部分框杜,分別是C/C++程序庫(kù)和Android運(yùn)行時(shí)庫(kù)浦楣。C/C++程序庫(kù):SQLite數(shù)據(jù)庫(kù),SSL咪辱,OpenGL ES(3D繪圖函數(shù)庫(kù))...振劳。Android運(yùn)行時(shí)庫(kù):ART(5.0系統(tǒng)之后,Dalvik虛擬機(jī)被ART取代)油狂,核心庫(kù)(Java語(yǔ)言核心庫(kù))
- 硬件抽象層(HAL):其目的在于將硬件抽象化历恐,提供可供"系統(tǒng)服務(wù)層"調(diào)用的統(tǒng)一硬件接口。相機(jī)专筷,藍(lán)牙弱贼,Audio
- Linux內(nèi)核層:Linux內(nèi)核和各類硬件設(shè)備的驅(qū)動(dòng),這里需要注意的是磷蛹,Binder IPC驅(qū)動(dòng)也是這一層的實(shí)現(xiàn)
每一個(gè)系統(tǒng)服務(wù)在應(yīng)用框架層都有一個(gè)Manager與之對(duì)應(yīng)
2 IPC原理
從進(jìn)程的角度來(lái)看IPC機(jī)制
- 每個(gè)Android進(jìn)程哮洽,只能運(yùn)行在自己的進(jìn)程所擁有的虛擬地址空間,如果是32位的系統(tǒng)弦聂,對(duì)應(yīng)一個(gè)4GB的虛擬地址空間鸟辅,其中3GB是用戶空,1GB是內(nèi)核空間莺葫,而內(nèi)核空間的大小是可以通過(guò)參數(shù)配置的匪凉。
- 對(duì)于用戶空間,不同進(jìn)程之間彼此是不能共享的捺檬,而內(nèi)核空間確實(shí)可以共享的再层。
- Client進(jìn)程與Server進(jìn)程通信,恰恰是利用進(jìn)程間可共享的內(nèi)核內(nèi)空間來(lái)完成底層通信工作的堡纬,Client端與Server端進(jìn)程往往采用ioctl等方法跟內(nèi)核空間的驅(qū)動(dòng)進(jìn)行聂受。
3 Binder綜述
3.1 Binder簡(jiǎn)介
3.1.1 Binder的由來(lái)
- Binder是Android平臺(tái)上的一種跨進(jìn)程通信技術(shù)。
- 最早并不是谷歌公司提出的烤镐,它前身是Be Inc公司開(kāi)發(fā)的OpenBinder蛋济,而且在Palm中也有應(yīng)用
- 后來(lái)OpenBinder的作者Dianne Hackborn加入了谷歌公司,并負(fù)責(zé)Android平臺(tái)開(kāi)發(fā)的工作炮叶,所以把這項(xiàng)技術(shù)也帶進(jìn)了Android碗旅。
3.1.2 什么是Binder
- 從來(lái)類的角度來(lái)說(shuō),Binder就是Android的一個(gè)類镜悉,它繼承了IBinder接口
- 從IPC的角度來(lái)說(shuō)祟辟,Binder是Android中的一個(gè)中的一種跨進(jìn)程通信方式,Binder還可以理解為一種虛擬的物理設(shè)備侣肄,它的設(shè)備驅(qū)動(dòng)是/dev/binder旧困,該通信方式在Linux中沒(méi)有(由于耦合性太強(qiáng),而Linux沒(méi)有接納)
- 從Android Framework角度來(lái)說(shuō),Binder是ServiceManager連接各種Manager(ActivityManager吼具、WindowManager等)和相應(yīng)的ManagerService的橋梁
- 4 從Android應(yīng)用層的角度來(lái)說(shuō)被芳,Binder是客戶端和服務(wù)端進(jìn)行通信的媒介,當(dāng)你bindService的時(shí)候馍悟,服務(wù)端會(huì)返回一個(gè)包含了服務(wù)端業(yè)務(wù)調(diào)用的Binder對(duì)象畔濒,通過(guò)這個(gè)Binder對(duì)象,客戶端就可以獲取服務(wù)端提供的服務(wù)或者數(shù)據(jù)锣咒,這里的服務(wù)包括普通服務(wù)和基于AIDL的服務(wù)侵状。
3.1.3 Binder機(jī)制的意義
- Binder機(jī)制具有兩層含義:
- 1 是一種跨進(jìn)程通信的方式(IPC)
- 2 是一種遠(yuǎn)程過(guò)程調(diào)用方式(PRC)
而從實(shí)現(xiàn)的角度來(lái)說(shuō),Binder核心被實(shí)現(xiàn)成一個(gè)Linux驅(qū)動(dòng)程序毅整,并運(yùn)行于內(nèi)核態(tài)趣兄。這樣它才能具有強(qiáng)大的跨進(jìn)程訪問(wèn)能力。
3.1.4 和傳統(tǒng)IPC機(jī)制相比悼嫉,谷歌為什么采用Binder
- 雖然Android繼承Linux內(nèi)核艇潭,但是Linux與Android通信機(jī)制是不同的。
- Android中有大量的C/S(Client/Server)應(yīng)用方式戏蔑,這就要求Android內(nèi)部提供IPC方法蹋凝,而如果采用Linux所支持的進(jìn)程通信方式有兩個(gè)問(wèn)題:性能和安全性。
Android跨進(jìn)程通信IPC系列
- 性能:目前Linux支持的IPC包括傳統(tǒng)的管道总棵,System V IPC(包括消息隊(duì)列/共享內(nèi)存/信號(hào)量)以及socket鳍寂,但是只有socket支持Client/Server的通信方式,由于socket是一套通用當(dāng)初網(wǎng)絡(luò)通信方式情龄,其效率低下迄汛,且消耗比較大(socket建立連接過(guò)程和中斷連接過(guò)程都有一定的開(kāi)銷(xiāo)),明顯在手機(jī)上不適合大面積使用socket骤视。而消息隊(duì)列和管道采用"存儲(chǔ)-轉(zhuǎn)發(fā)" 方式鞍爱,即數(shù)據(jù)先從發(fā)送方緩存區(qū)拷貝到內(nèi)核開(kāi)辟的緩存區(qū)中,然后再?gòu)膬?nèi)核緩存中拷貝到接收方緩存中专酗,至少有兩次拷貝過(guò)程睹逃。共享內(nèi)存雖然無(wú)需拷貝,但控制復(fù)雜笼裳,難以使用唯卖。
- 安全性:在安全性方面粱玲,Android作為一個(gè)開(kāi)放式躬柬,擁有眾多開(kāi)發(fā)者的平臺(tái),應(yīng)用程序的來(lái)源廣泛抽减,確保智能終端的安全是非常重要的允青。終端用戶不希望從網(wǎng)上下載的程序在不知情的情況下偷窺隱私數(shù)據(jù),連接無(wú)線網(wǎng)絡(luò)卵沉,長(zhǎng)期操作底層設(shè)備導(dǎo)致電池很快耗盡的情況颠锉。傳統(tǒng)IPC沒(méi)有任何安全措施法牲,完全依賴上層協(xié)議來(lái)去報(bào)。首先傳統(tǒng)IPC的接受方無(wú)法獲取對(duì)方進(jìn)程可靠的UID/PID(用戶ID/進(jìn)程ID)琼掠,從而無(wú)法鑒別對(duì)方身份拒垃。Android為每個(gè)安裝好的應(yīng)用程序分配了自己的UID,故進(jìn)程的UID是鑒別進(jìn)程的身份的重要標(biāo)志瓷蛙。使用傳統(tǒng)IPC只能由用戶在數(shù)據(jù)包里填入U(xiǎn)ID/PID悼瓮,但這樣不可靠,容易被惡意程序利用艰猬『岜ぃ可靠的身份標(biāo)記只由IPC機(jī)制本身在內(nèi)核中添加。其次傳統(tǒng)IPC訪問(wèn)接入點(diǎn)是開(kāi)放的冠桃,無(wú)法建立私有通道命贴。比如命名管道、system V的鍵值食听,socket的ip地址或者文件名都是開(kāi)放的胸蛛,只要知道這些接入點(diǎn)的程序都可以對(duì)端建立連接,不管怎樣都無(wú)法阻止惡意程序通過(guò)接收方地址獲得連接樱报。
基于以上原因胚泌,Android需要建立一套新的IPC機(jī)制來(lái)滿足系統(tǒng)對(duì)通信方式,傳輸性能和安全性的要求肃弟,所以就有了Binder玷室。
Binder基于Client/Server通信模式,傳輸過(guò)程只需要一次拷貝笤受,為發(fā)送發(fā)添加UID/PID身份穷缤,即支持實(shí)名Binder也支持匿名Binder,安全性高箩兽。
-
Binder通信過(guò)程示例
5713484-235dbffbd3b4e3fa.png 通信雙方必須要處理線程同步津肛,內(nèi)存管理等問(wèn)題,工作量大汗贫,而且問(wèn)題多身坐,
介紹的傳統(tǒng)IPC 命名管道(FIFO) 信號(hào)量(semaphore) 消息隊(duì)列已經(jīng)從Android中去掉了,同其他IPC相比落包,Socket是一種比較成熟的通信手段了部蛇,同步控制也很容易實(shí)現(xiàn)。Socket用于網(wǎng)絡(luò)通信非常合適咐蝇,但是用于進(jìn)程間通信就效率很低涯鲁。
Android在架構(gòu)上一直希望模糊進(jìn)程的概念,取而代之以組件的概念。應(yīng)用也不需要關(guān)心組件存放的位置抹腿、組件運(yùn)行在那個(gè)進(jìn)程中岛请、組件的生命周期等問(wèn)題。隨時(shí)隨地的警绩,只要擁有Binder對(duì)象崇败,就能使用組件的功能。Binder就像一張網(wǎng)肩祥,將整個(gè)系統(tǒng)的組件僚匆,跨進(jìn)程和線程的組織在一起。
Binder是整個(gè)系統(tǒng)的運(yùn)行的中樞搭幻。Android在進(jìn)程間傳遞數(shù)據(jù)使用共享內(nèi)存的方式咧擂,這樣數(shù)據(jù)只需要復(fù)制一次就能從一個(gè)進(jìn)程到達(dá)另一個(gè)進(jìn)程了(前面文章說(shuō)了,一般IPC都需要兩步檀蹋,第一步用戶進(jìn)程復(fù)制到內(nèi)核松申,第二步再?gòu)膬?nèi)核復(fù)制到服務(wù)進(jìn)程。)
- PS: 整個(gè)Androdi系統(tǒng)架構(gòu)中俯逾,雖然大量采用了Binder機(jī)制作為IPC(進(jìn)程間通信)方式贸桶,但是也存在部分其他的IPC方式,比如Zygote通信就是采用socket桌肴。
3.1.5 Binder在Service服務(wù)中的作用
在Android中皇筛,有很多Service都是通過(guò)Binder來(lái)通信的,比如MediaService名下的眾多Service:
- AudioFlinger音頻核心服務(wù)
- AudioPolicyService:音頻策略相關(guān)的重要服務(wù)
- MediaPlayerService:多媒體系統(tǒng)中的重要服務(wù)
- CarmeraService:有關(guān)攝像/照相的重要服務(wù)
3.2 總結(jié)
- Android Binder 是在OpenBinder上定制實(shí)現(xiàn)的坠七。原先的OpenBinder 框架現(xiàn)在已經(jīng)不再繼續(xù)開(kāi)發(fā)水醋,所以也可以說(shuō)Android讓原先的OpenBinder得到了重生。Binder是Android上大量使用的IPC(Inter-process communication彪置,進(jìn)程間通訊)機(jī)制拄踪。
- 無(wú)論是應(yīng)用程序?qū)ο到y(tǒng)服務(wù)的請(qǐng)求,還是應(yīng)用程序自身提供對(duì)外服務(wù)拳魁,都需要使用Binder惶桐。
整體架構(gòu)
從圖中可以看出,Binder的實(shí)現(xiàn)分為這幾層潘懊,按照大的框架理解是
- framewor層
--- ---java 層
--- ---jni 層
--- ---native/ C++層- linux驅(qū)動(dòng)層 c語(yǔ)言
其中Linux驅(qū)動(dòng)層位于Linux內(nèi)核中姚糊,它提供了最底層的數(shù)據(jù)傳遞,對(duì)象標(biāo)示授舟,線程管理救恨,通過(guò)調(diào)用過(guò)程控制等功能。驅(qū)動(dòng)層其實(shí)是Binder機(jī)制的核心岂却。
Framework層以Linux驅(qū)動(dòng)層為基礎(chǔ)忿薇,提供了應(yīng)用開(kāi)發(fā)的基礎(chǔ)設(shè)施裙椭。Framework層既包含了C++部分的實(shí)現(xiàn)躏哩,也包含了Java基礎(chǔ)部分的實(shí)現(xiàn)署浩。為了能將C++ 的實(shí)現(xiàn)復(fù)用到Java端,中間通過(guò)JNI進(jìn)行銜接扫尺。
Binder框架是典型的C/S架構(gòu)筋栋。
我們把服務(wù)的請(qǐng)求方稱為Client,服務(wù)的實(shí)現(xiàn)方稱之Server正驻。Clinet對(duì)于Server的請(qǐng)求會(huì)經(jīng)由Binder驅(qū)動(dòng)框架由上至下傳遞到內(nèi)核的Binder驅(qū)動(dòng)中弊攘,請(qǐng)求中包含了Client將要調(diào)用的命令和參數(shù)。
請(qǐng)求到了Binder驅(qū)動(dòng)以后姑曙,在確定了服務(wù)的提供方之后襟交,再講從下至上將請(qǐng)求傳遞給具體的服務(wù)。
4 Binder通信機(jī)制
Android內(nèi)部采用C/S架構(gòu)伤靠。而B(niǎo)inder通信也是采用C/S架構(gòu)捣域。那我們來(lái)看下Binder在C/S的中的流程。
4.1 Binder在C/S中的流程
具體流程如下:
- 相應(yīng)的Service需要注冊(cè)服務(wù)宴合。Service作為很多Service的擁有者焕梅,當(dāng)它想向Client提供服務(wù)時(shí),得先去Service Manager(以后縮寫(xiě)成SM)那兒注冊(cè)自己的服務(wù)卦洽。Server可以向SM注冊(cè)一個(gè)或者多個(gè)服務(wù)贞言。
- Client申請(qǐng)服務(wù)。Client作為Service的使用者阀蒂,當(dāng)他想使用服務(wù)時(shí)该窗,得向SM申請(qǐng)自己所需要的服務(wù)。Client可以申請(qǐng)一個(gè)或者多個(gè)服務(wù)蚤霞。
- 當(dāng)Client申請(qǐng)服務(wù)成功后挪捕,Client就可以使用服務(wù)了。
- SM一方面管理Server所提供的服務(wù)争便,同時(shí)又響應(yīng)Client的請(qǐng)求并為之分配響應(yīng)的服務(wù)级零。
- 通信方式的好處是:
- 一方面,service和Client請(qǐng)求便于管理
- 另一方面在應(yīng)用程序開(kāi)發(fā)時(shí)滞乙,只需要為Client建立到Server的連接即可奏纪,這樣只需要花很少的時(shí)間成本去實(shí)現(xiàn)Server的相應(yīng)功能。
- 那么Binder與這個(gè)通信有什么關(guān)系斩启?其實(shí)三者的通信方式就是Binder機(jī)制(比如Server向SM注冊(cè)服務(wù)序调,使用Binder通信;Client申請(qǐng)請(qǐng)求也是Binder通信兔簇。)
PS:注意這里的ServiceManager是指Nativie層的ServiceManager(C++)发绢,并非是framework層的ServiceManager(Java)硬耍。ServiceManager是整個(gè)Binder通信機(jī)制的大管家,是Android進(jìn)程間通信機(jī)制的守護(hù)進(jìn)程边酒。
4.2 Binder通信整體框架
后面我們會(huì)不斷的提及兩個(gè)概念经柴,一個(gè)是Server,還有一個(gè)是Service墩朦,我這里先強(qiáng)調(diào)下坯认,Server是Server,Service是Service氓涣,大家不要混淆牛哺,一個(gè)Server下面可能有很多Service,但是一個(gè)Servcie也只能隸屬于一個(gè)Server劳吠。
4.2.1 從內(nèi)核和用戶空間的角度來(lái)看
Binder通信模型如下:
我們可以發(fā)現(xiàn):
- Client和Server是存在于用戶空間
- Client和Server通信實(shí)現(xiàn)是由Binder驅(qū)動(dòng)在內(nèi)核的實(shí)現(xiàn)
- SM作為守護(hù)進(jìn)程引润,處理客戶端請(qǐng)求,管理所有服務(wù)
我們可以把SM理解成為DNS服務(wù)器痒玩,那么Binder Driver就相當(dāng)于路由的功能淳附。
4.2.2 從Android的層級(jí)的角度
如下圖:(注意圖片的右邊)
- Client/Server/ServiceManager之間的相互通信都是基于Binder機(jī)制。
- Clinet/Server/ServiceManager之間交互都是虛線表示凰荚,是由于他們彼此之間不直接交互燃观,都是通過(guò)Binder驅(qū)動(dòng)進(jìn)行交互,從而實(shí)現(xiàn)IPC通信方式便瑟。
- 其中Binder驅(qū)動(dòng)位于內(nèi)核空間缆毁,Client/Server/ServiceManager可以看做是Android平臺(tái)的基礎(chǔ)架構(gòu)。
- Client和Server是Android的應(yīng)用層到涂,開(kāi)發(fā)人員只需要自定義實(shí)現(xiàn)client脊框、Server端,借助Android的基本平臺(tái)架構(gòu)就可以直接進(jìn)行IPC通信践啄。
4.2.3 從Binder的架構(gòu)角度來(lái)看
- Binder IPC 屬于 C/S 結(jié)構(gòu)浇雹,Client 部分是用戶代碼,用戶代碼最終會(huì)調(diào)用 Binder Driver 的 transact 接口屿讽,Binder Driver 會(huì)調(diào)用 Server昭灵,這里的 Server 與 service 不同,可以理解為 Service 中 onBind 返回的 Binder 對(duì)象伐谈,請(qǐng)注意區(qū)分下烂完。
- Client端:用戶需要實(shí)現(xiàn)的代碼,如 AIDL 自動(dòng)生成的接口類
- Binder Driver:在內(nèi)核層實(shí)現(xiàn)的 Driver
- Server端:這個(gè) Server 就是 Service 中 onBind 返回的 IBinder 對(duì)象
- 上面綠色的色塊部分都是屬于用戶需要實(shí)現(xiàn)的部分诵棵,而藍(lán)色部分是系統(tǒng)去實(shí)現(xiàn)了抠蚣。
- Binder Driver 這塊并不需要知道,Server 中會(huì)開(kāi)啟一個(gè)線程池去處理客戶端調(diào)用履澳。
- 為什么要用線程池而不是一個(gè)單線程隊(duì)列呢嘶窄?試想一下怀跛,如果用單線程隊(duì)列,則會(huì)有任務(wù)積壓柄冲,多個(gè)客戶端同時(shí)調(diào)用一個(gè)服務(wù)的時(shí)候就會(huì)有來(lái)不及響應(yīng)的情況發(fā)生吻谋,這是絕對(duì)不允許的。
- 對(duì)于調(diào)用 Binder Driver 中的 transact 接口羊初,客戶端可以手動(dòng)調(diào)用滨溉,也可以通過(guò) AIDL 的方式生成的代理類來(lái)調(diào)用
- 服務(wù)端可以繼承 Binder 對(duì)象什湘,也可以繼承 AIDL 生成的接口類的** Stub 對(duì)象**长赞。
切記,這里 Server 的實(shí)現(xiàn)是線程池的方式闽撤,而不是單線程隊(duì)列的方式得哆,區(qū)別在于,單線程隊(duì)列的話哟旗,Server 的代碼是線程安全的贩据,線程池的話,Server 的代碼則不是線程安全的闸餐,需要開(kāi)發(fā)者自己做好多線程同步饱亮。
4.3 Binder流程
4.3.1 Server向SM注冊(cè)服務(wù)
- 首先 XXServer(XXX代表某個(gè))在自己的進(jìn)程中向Binder驅(qū)動(dòng)申請(qǐng)創(chuàng)建一個(gè)XXXService的Binder實(shí)體。
- Binder驅(qū)動(dòng)為這個(gè)XXXService創(chuàng)建位于內(nèi)核中的Binder實(shí)體節(jié)點(diǎn)以及Binder的引用包颁,注意饵隙,是將名字和新建的引用打包傳遞給SM(實(shí)體沒(méi)有傳給SM)阀捅,通知SM注冊(cè)一個(gè)名叫XXX的Service。
- SM收到數(shù)據(jù)包后壹无,從中取出XXXService名字和引用,填入一張查找表中
- 4感帅、此時(shí)斗锭,如果有Client向SM發(fā)送申請(qǐng)服務(wù)XXXService的請(qǐng)求,那么SM就可以查找表中該Service的Binder引用失球,并把BInder引用(XXXBpBinder返回給Client)
在進(jìn)一步了解Binder通信機(jī)制之前岖是,我們先弄清楚幾個(gè)概念。
- 引用和實(shí)體实苞。這里豺撑,對(duì)于一個(gè)用于通信的實(shí)體(可以理解為真實(shí)空間的Object),可以額有多個(gè)該實(shí)體的引用(沒(méi)有真實(shí)空間硬梁,可以理解成實(shí)體的一個(gè)鏈接前硫,操作引用就可以操作對(duì)應(yīng)鏈接上的實(shí)體)。如果一個(gè)進(jìn)程持有某個(gè)實(shí)體荧止,其他進(jìn)程也想操作該實(shí)體屹电,最高效的做法是去獲取該實(shí)體的引用阶剑,再去操作這個(gè)引用。
為了大家在后面更好的理解危号,這里補(bǔ)充幾個(gè)概念
- Binder實(shí)體對(duì)象 :Binder實(shí)體對(duì)象就是Binder服務(wù)的提供者牧愁。一個(gè)提供Binder服務(wù)的類必須繼承BBinder類,因此外莲,有時(shí)為了強(qiáng)調(diào)對(duì)象類型猪半,也用"BBinder對(duì)象"來(lái)代替"Binder實(shí)體對(duì)象"。
- Binder引用對(duì)象 :Binder引用對(duì)象是Binder實(shí)體對(duì)象在客戶進(jìn)程的代表偷线,每個(gè)引用對(duì)象的類型都是BpBiner類磨确,同樣可以用名稱"BpBinder對(duì)象"來(lái)代替"Binder引用對(duì)象"。
- Binder代理對(duì)象 :代理對(duì)象也成為接口對(duì)象声邦,它主要是為了客戶端的上層應(yīng)用提供接口服務(wù)乏奥,從IInterface類派生。它實(shí)現(xiàn)了Binder服務(wù)的函數(shù)接口亥曹,當(dāng)然只是一個(gè)轉(zhuǎn)調(diào)的空殼邓了。通過(guò)代理對(duì)象,應(yīng)用能像使用本地對(duì)象一樣使用遠(yuǎn)端實(shí)體對(duì)象提供服務(wù)媳瞪,將Binder代理對(duì)象和Binder引用對(duì)應(yīng)(BpBinder對(duì)象)分開(kāi)的好處是代理對(duì)象可以有很多實(shí)例骗炉,但是它們包含的是同一個(gè)引用對(duì)象,這樣方便了應(yīng)用層的使用蛇受。句葵。
- IBiner對(duì)象 :BBinder和BpBinder類是從IBinder類中繼承來(lái)。在很多場(chǎng)合龙巨,不需要刻意地去區(qū)分實(shí)體對(duì)象和引用對(duì)象笼呆,這時(shí)候也可以統(tǒng)一使用"IBinder對(duì)象"來(lái)統(tǒng)一稱呼他們。
- 這樣應(yīng)用層可以直接拋開(kāi)接口對(duì)象直接使用Binder的引用對(duì)象旨别,但是這樣開(kāi)發(fā)的程序兼容性不好诗赌。也正是客戶端將引用對(duì)象和代理對(duì)象分離,Android才能用一套架構(gòu)來(lái)同時(shí)為Java和native層提供Binder服務(wù)秸弛。隔離后铭若,Binder底層不需要關(guān)系上層的實(shí)現(xiàn)細(xì)節(jié),只需要和Binder實(shí)體對(duì)象和引用對(duì)象進(jìn)行交互递览。
PS:BpBinder(Binder引用對(duì)象,在客戶端)和BBinder(Binder實(shí)體,在服務(wù)端)都是Android中Binder通信相關(guān)的代表叼屠,它們都是從IBiner類中派生而來(lái)(BpBinder和BBinder在Native層,不在framework層)绞铃,
client端:BpBinder通過(guò)調(diào)用transact()來(lái)發(fā)送事物請(qǐng)求
server端:BBinder通過(guò)onTransact()會(huì)接受到相應(yīng)的事物
這時(shí)候再來(lái)看下這個(gè)圖镜雨,然后大家思考一下,就會(huì)明白很多事情儿捧。
4.3.2 如何獲得一個(gè)SM的遠(yuǎn)程接口
如果你足夠細(xì)心荚坞,你會(huì)發(fā)現(xiàn)這里有一個(gè)問(wèn)題:
SM和Server都是進(jìn)程挑宠,Server向SM注冊(cè)Binder需要進(jìn)程間通信,當(dāng)前實(shí)現(xiàn)的是進(jìn)程間通信颓影,卻又用到進(jìn)程間通信各淀。有點(diǎn)暈是不,就好像先有雞還是先有蛋這個(gè)問(wèn)題诡挂。
其實(shí)Binder是這么解決這個(gè)問(wèn)題的:
- 針對(duì)Binder的通信機(jī)制碎浇,Server端擁有的是Binder的實(shí)體(BBinder);Client擁有的是Binder的引用(BpBinder)璃俗。
- 如果把SM看做Server端奴璃,讓它在Binder驅(qū)動(dòng)一起運(yùn)行起來(lái)時(shí)就有自己的實(shí)體(BBinder)(代碼中設(shè)置ServiceManager的Binder其handle的值恒為0)。這個(gè)Binder實(shí)體沒(méi)有名字也不需要注冊(cè)旧找,所有的Client都認(rèn)為handle值為0的binder引用(BpBinder)是用來(lái)與SM通信的溺健。那么這個(gè)問(wèn)題就解決了麦牺。
- Client和Server中handle的值為0(值為0的引用是專門(mén)與SM通信用的)钮蛛,還不行,還需要讓SM的handle值為0的實(shí)體(BBinder)為0才算大功告成剖膳。怎么實(shí)現(xiàn)的? 當(dāng)一個(gè)進(jìn)程調(diào)用Binder驅(qū)動(dòng)時(shí)魏颓,使用** "BINDER_SET_CONTEXXT_MGR" ** 命名(在binder_ioctl中)將自己注冊(cè)成SM時(shí),Binder驅(qū)動(dòng)會(huì)自動(dòng)為她創(chuàng)建Binder實(shí)體吱晒。這個(gè)Binder的引用對(duì)所有Client都為0甸饱。
4.3.3 Client從SM中獲得Service的遠(yuǎn)程接口
- Server向SM注冊(cè)了Binder實(shí)體及其名字后,Client就可以Service的名字在SM在查找表中獲得了該Binder的引用(BpBinder)了
- Client也利用了保留的handle值為0的引用向SM請(qǐng)求訪問(wèn)某個(gè)Service:當(dāng)申請(qǐng)?jiān)L問(wèn)XXXService的引用仑濒。
- SM就會(huì)從請(qǐng)求數(shù)據(jù)包中獲得XXXService的名字叹话,在查找表中找到名字對(duì)應(yīng)的條目,取出Binder的引用打包回復(fù)給Client墩瞳。
- Client就可以利用XXXService的引用使用XXXService的服務(wù)了驼壶。如果有更多的Client請(qǐng)求該Service,系統(tǒng)中就會(huì)有更多的Client獲得這個(gè)引用喉酌。
如下圖
4.3.4 建立C/S連接后
首先要明白一個(gè)事情:
Client要擁有自己的自己的Binder實(shí)體热凹,以及Server的Binder的應(yīng)用;Server有用自己的Binder的實(shí)體泪电,以及Client的Binder引用般妙。
我們也可以按照網(wǎng)絡(luò)請(qǐng)求的方式來(lái)分析:
- 從Client向Server發(fā)送數(shù)據(jù):Client為發(fā)送方,擁有Binder實(shí)體相速;Server為接收方碟渺,擁有Binder引用。
- 從Server向Client發(fā)送數(shù)據(jù):Server為發(fā)送方突诬,擁有Binder實(shí)體:Client為接收方苫拍,擁有Binder引用烹棉。
其實(shí),在我們建立C/S連接后怯疤,無(wú)需考慮誰(shuí)是Client浆洗,誰(shuí)是Server。只要理清誰(shuí)是發(fā)送方集峦,誰(shuí)是接收方伏社,就能知道Binder的實(shí)體和應(yīng)用在那邊。
那我們看下建立C/S連接后的塔淤,具體流程,如下圖:
那我們說(shuō)下具體的流程:
- 第一步摘昌,發(fā)送方通過(guò)Binder實(shí)體請(qǐng)求發(fā)送操作
- 第二步,Binder驅(qū)動(dòng)會(huì)處理這個(gè)操作請(qǐng)求高蜂,把發(fā)送方的數(shù)據(jù)放入寫(xiě)緩存(binder_write_read.write_buffer)(對(duì)于接受方來(lái)說(shuō)為讀緩存區(qū))聪黎,并把read_size(接收方讀數(shù)據(jù))置為數(shù)據(jù)大小。
- 第三步备恤,接收方之前一直在阻塞狀態(tài)中稿饰,當(dāng)寫(xiě)緩存有數(shù)據(jù),則會(huì)讀取數(shù)據(jù)露泊,執(zhí)行命令操作
- 第四步喉镰,接收方執(zhí)行完后,會(huì)把返回結(jié)果同樣采用binder_transaction_data結(jié)構(gòu)體封裝惭笑,寫(xiě)入緩沖區(qū)(對(duì)于發(fā)送方侣姆,為讀緩沖區(qū))
4.3.4 匿名Binder
- 在Android中Binder還可以建立點(diǎn)對(duì)點(diǎn)的私有通道,匿名Binder就是這種方式沉噩。
- 在Binder通信中捺宗,并不是所有通信的Binder實(shí)體都需要注冊(cè)給SM的,Server可以通過(guò)已建立的實(shí)體Binder連接將創(chuàng)建的Binder實(shí)體傳給Client川蒙。
- 這個(gè)Binder沒(méi)有向SM注冊(cè)名字蚜厉。這樣Server和Client通信就有很高的隱私性和安全性。
如下圖:
5 Binder的層次
從代碼上看派歌,Binder設(shè)計(jì)的類可以分成4個(gè)層級(jí)弯囊,如下圖所示
- 最上層的是位于Framewok中的各種Binder服務(wù)類和它們的接口類。這一層的類非常多胶果,比如常見(jiàn)的ActivityManagerService(縮寫(xiě)叫AMS)匾嘱、WindowManagerService(縮寫(xiě)叫WMS)、PackageManagerService(縮寫(xiě)是PMS)等早抠,它們?yōu)閼?yīng)用程序提供了各種各樣的服務(wù)霎烙。
- 中間則分為為兩層,上面是用于服務(wù)類和接口開(kāi)發(fā)的基礎(chǔ),比如IBinder悬垃、BBinder游昼、BpBinder等。下層是和驅(qū)動(dòng)交互的IPCThreadState和ProcessState類尝蠕。
- 這里刻意把中間的libbinder中的類劃分為兩個(gè)層次的原因烘豌,是在這4層中,第一層的和第二層聯(lián)系很緊密看彼,第二層中的 各種Binder類用來(lái)支撐服務(wù)類和代理類的開(kāi)發(fā)廊佩。但是第三層的IPCThread和第四層之間耦合得很厲害,單獨(dú)理解IPCThread或者是驅(qū)動(dòng)都是一件很難的事靖榕,必須把它們結(jié)合起來(lái)理解标锄,這一點(diǎn)正是Binder架構(gòu)被人詬病的地方,驅(qū)動(dòng)和應(yīng)用層之間過(guò)于耦合茁计,違反了Linux驅(qū)動(dòng)設(shè)計(jì)的原則料皇,因此,主流的Linux并不愿意接納Binder
6 Binder協(xié)議
Biner協(xié)議格式基本是"命令+數(shù)據(jù)"星压,使用ioctl(fd,cmd,arg)函數(shù)實(shí)現(xiàn)交互践剂。命令由參數(shù)cmd承載,數(shù)據(jù)由參數(shù)arg租幕,隨著cmd不同而不動(dòng)舷手。
命令 | 含義 | 參數(shù)(arg) |
---|---|---|
BINDER_WRITE_READ | 該命令向Binder寫(xiě)入或讀取數(shù)據(jù)。參數(shù)分為兩段:寫(xiě)部分和讀部分劲绪。如果write_size不為0,就將write_buffer里的數(shù)據(jù)寫(xiě)入Binder盆赤;如果read_ size不為0再?gòu)腂inder中讀取數(shù)據(jù)存入read_buffer中贾富。write_consumered和read_consumered表示操作完成時(shí)Binder驅(qū)動(dòng)實(shí)際寫(xiě)入或者讀出數(shù)據(jù)的個(gè)數(shù) | struct binder_write_read{ singed long write_size;singed long write_consumed; unsigned long write_buffer; signed long read_size; signed long read_consumed; unsigned long read_buffer; } ; |
BINDER_SET_MAX_THREADS | 該命令告知Binder驅(qū)動(dòng)接收方(通常是Server端)線程池中最大的線程數(shù)。由于Client是并發(fā)向Server端發(fā)送請(qǐng)求的牺六,Server端必須開(kāi)辟線程池為這些并發(fā)請(qǐng)求提供服務(wù) 颤枪。告知驅(qū)動(dòng)線程池的最大值是為了讓驅(qū)動(dòng)發(fā)現(xiàn)線程數(shù)達(dá)到該線程池的最大值是為了讓驅(qū)動(dòng)發(fā)現(xiàn)線程數(shù)達(dá)到該值時(shí),不要再命令接收端啟動(dòng)先的線程淑际。 | int max_threads; |
BINDER_SET_CONTEXT_MGR | 當(dāng)前進(jìn)程注冊(cè)為SM畏纲。系統(tǒng)中只能存在一個(gè)SM,只要當(dāng)前的SM沒(méi)有調(diào)用close()關(guān)閉春缕,Binder驅(qū)動(dòng)就不能有別的進(jìn)程變成SM | 無(wú) |
BINDER_TREAD_EXIT | 通知Binder驅(qū)動(dòng)當(dāng)前線程退出了盗胀。Binder會(huì)為所有參與的通信線程(包括Server線程池中的線程和Client發(fā)出的請(qǐng)求的線程) 建立相應(yīng)的數(shù)據(jù)結(jié)構(gòu)。這些線程在退出時(shí)必須通知驅(qū)動(dòng)釋放相應(yīng)的數(shù)據(jù)結(jié)構(gòu) | 無(wú) |
BINDER_VERSION | 獲取Binder驅(qū)動(dòng)的版本號(hào) | 無(wú) |
這其中最常用的命令是 BINDER_WRITE_READ锄贼。該命令的參數(shù)包括兩個(gè)部分:
- 是向Binder寫(xiě)入數(shù)據(jù)
- 是向Binder讀出數(shù)據(jù)
驅(qū)動(dòng)程序先處理寫(xiě)部分再處理讀部分票灰。這樣安排的好處是應(yīng)用程序可以很靈活的地處理命令的同步或者異步。
例如若要發(fā)送異步命令可以只填入寫(xiě)部分而將read_size設(shè)置為0,若要只從Binder獲得的數(shù)據(jù)可以將寫(xiě)部分置空屑迂,即write_size置0浸策。如果想要發(fā)送請(qǐng)求并同步等待返回?cái)?shù)據(jù)可以將兩部分都置上。
6.1 BINDER_WRITE_READ 之寫(xiě)操作
- Binder寫(xiě)操作的數(shù)據(jù)時(shí)格式同樣也是(命令+數(shù)據(jù))惹盼。這時(shí)候命令和數(shù)據(jù)都存放在binder_write_read結(jié)構(gòu)中的write_buffer域指向的內(nèi)存空間里庸汗,多條命令可以連續(xù)存放。
- 數(shù)據(jù)緊接著存放在命令后面手报,格式根據(jù)命令不同而不同夫晌。下表列舉了Binder寫(xiě)操作支持的命令:
-
我提供兩套,一套是圖片昧诱,方便手機(jī)用戶晓淀,一部分是文字,方便PC用戶
5713484-ffb7c05eaa6f6eaa.png
上面圖片盏档,下面是文字
命令 | 含義 | 參數(shù)(arg) |
---|---|---|
BC_TRANSACTION BC_REPLY | BC_TRANSACTION用于Client向Server發(fā)送請(qǐng)求數(shù)據(jù)凶掰;BC_REPLY用于Server向Client發(fā)送回復(fù)(應(yīng)答)數(shù)據(jù)。其后面緊接著一個(gè)binder_transaction_data結(jié)構(gòu)體表明要寫(xiě)入的數(shù)據(jù)蜈亩。 | struct binder_transaction_data |
BC_ACQUIRE_RESULT | 暫未實(shí)現(xiàn) | |
BC_FREE_BUFFER | 釋放一塊映射內(nèi)存懦窘。Binder接受方通過(guò)mmap()映射一塊較大的內(nèi)存空間,Binder驅(qū)動(dòng)基于這片內(nèi)存采用最佳匹配算法實(shí)現(xiàn)接受數(shù)據(jù)緩存的動(dòng)態(tài)分配和釋放稚配,滿足并發(fā)請(qǐng)求對(duì)接受緩存區(qū)的需求畅涂。應(yīng)用程序處理完這篇數(shù)據(jù)后必須盡快使用費(fèi)改命令釋放緩存區(qū),否則會(huì)因?yàn)榫彺鎱^(qū)耗盡而無(wú)法接受新數(shù)據(jù) | 指向需要釋放的緩存區(qū)的指針道川;該指針位于收到的Binder數(shù)據(jù)包中 |
BC_INCREFS BC_ACQUIRE BC_RELEASE BC_DECREFS | 這組命令增加或減少Binder的引用計(jì)數(shù)午衰,用以實(shí)現(xiàn)強(qiáng)指針或弱指針的功能 | 32位Binder引用號(hào) |
BC_REGISTER_LOOPER BC_ENTER_LOOPER BC_EXIT_LOOPER | 這組命令同BINDER_SET_MAX_THREADS 一并實(shí)現(xiàn)Binder驅(qū)動(dòng)對(duì)接收方線程池的管理。BC_REGISTER_LOOPER通知驅(qū)動(dòng)線程池中的一個(gè)線程已經(jīng)創(chuàng)建了冒萄;BC_ENTER_LOOPER通知該驅(qū)動(dòng)線程已經(jīng)進(jìn)入主循環(huán)臊岸,可以接受數(shù)據(jù);BC_EXIT_LOOPER通知驅(qū)動(dòng)該線程退出主循環(huán)尊流,不在接受數(shù)據(jù)帅戒。 | ----- |
BC_REQUEST_DEATH_NOTIFICATION | 獲得Binder引用的進(jìn)程通過(guò)該命令要求驅(qū)動(dòng)在Binder實(shí)體銷(xiāo)毀得到通知。雖說(shuō)強(qiáng)指針可以確保只要有引用就不會(huì)銷(xiāo)毀實(shí)體崖技,但這畢竟是個(gè)跨進(jìn)程的引用逻住,誰(shuí)也無(wú)法保證實(shí)體由于所在的Server關(guān)閉Binder驅(qū)動(dòng)或異常退出而消失,引用者能做的就是要求Server在此刻給出通知 | uint32 *ptr;需要得到死亡的通知Binder引用 |
BC_DEAD_BINDER | 收到實(shí)體死亡通知書(shū)的進(jìn)程在刪除引用后用本命令告知驅(qū)動(dòng) | void * cookie |
- 在這些命令中迎献,最常用的h是BC_TRANSACTION/BC_REPLY命令對(duì)瞎访,Binder請(qǐng)求和應(yīng)答數(shù)據(jù)就是通過(guò)這對(duì)命令發(fā)送給接受方。
- 這對(duì)命令所承載的數(shù)據(jù)包由結(jié)構(gòu)體struct binder_transaction_data定義忿晕。Binder交互有同步和異步之分装诡。
- 利用binder_transcation_data中的flag區(qū)域劃分银受。如果flag區(qū)域的TF_ONE_WAY位為1,則為異步交互鸦采,即client發(fā)送完請(qǐng)求交互即結(jié)束宾巍,Server端不再返回BC_REPLY數(shù)據(jù)包;否則Server會(huì)返回BC_REPLY數(shù)據(jù)包渔伯,Client端必須等待接受完數(shù)據(jù)包后才能完成一次交互顶霞。
6.2 BINDER_WRITE_READ:從Binder讀出數(shù)據(jù)
在Binder里讀出數(shù)據(jù)格式和向Binder中寫(xiě)入數(shù)據(jù)格式一樣,采用(消息ID+數(shù)據(jù))形式锣吼,并且多條消息可以連續(xù)存放选浑。
Binder讀操作消息ID
消息 | 含義 | 參數(shù)(arg) |
---|---|---|
BR_ERROR | 發(fā)生內(nèi)部錯(cuò)誤(如內(nèi)存分配失敗) | ---- |
BR_OK BR_NOOP | 操作完成 | ---- |
BR_SPAWN_LOOPER | 消息用于接受方線程池管理。當(dāng)驅(qū)動(dòng)發(fā)現(xiàn)接收方所有線程都處于忙碌狀態(tài)且線程池中的線程總數(shù)沒(méi)有超過(guò)BINDER_SET_MAX_THREADS設(shè)置的最大線程時(shí)玄叠,向接收方發(fā)送該命令要求創(chuàng)建更多的線程以備接受數(shù)據(jù) | ---- |
BR_TRANSCATION BR_REPLY | 這兩條消息分別對(duì)應(yīng)發(fā)送方的 BC_TRANSACTION 和BC_REPLY古徒,表示當(dāng)前接受的數(shù)據(jù)是請(qǐng)求還是回復(fù) | binder_transaction_data |
BR_ACQUIRE_RESULT BR_ATTEMPT_ACQUIRE BR_FINISHED | 尚未實(shí)現(xiàn) | ---- |
BR_DEAD_REPLY | 交互過(guò)程中如果發(fā)現(xiàn)對(duì)方進(jìn)程或線程已經(jīng)死亡則返回該消息 | ---- |
BR_TRANSACTION_COMPLETE | 發(fā)送方通過(guò)BC_TRRANSACTION或BC_REPLY發(fā)送完一個(gè)數(shù)據(jù)包后,都能收到該消息作為成功發(fā)送的反饋读恃。這和BR_REPLY不一樣隧膘,是驅(qū)動(dòng)告知發(fā)送方已經(jīng)發(fā)送成功,而不是Server端返回?cái)?shù)據(jù)寺惫。所以不管同步還是異步交互接收方都能獲得本消息疹吃。 | ---- |
BR_INCREFS BR_ACQUIRE BR_RFLEASE BR_DECREFS | 這組消息用于管理強(qiáng)/弱指針的引用計(jì)數(shù)。只有提供Binder實(shí)體的進(jìn)程才能收到這組消息 | void *ptr : Binder實(shí)體在用戶空間中的指針 void **cookie:與該實(shí)體相關(guān)的附加數(shù)據(jù) |
BR_DEAD_BINDER BR_CLEAR_DEATH_NOTIFICATION_DONE | 向獲得Binder引用的進(jìn)程發(fā)送Binder實(shí)體死亡通知書(shū):收到死亡通知書(shū)的進(jìn)程接下來(lái)會(huì)返回 BC_DEAD_BINDER_DONE 確認(rèn) | void *cookie 在使用BC_REQUEST_DEATH_NOTIFICATION注冊(cè)死亡通知時(shí)的附加參數(shù) |
BR_FAILED_REPLY | 如果發(fā)送非法引用號(hào)則返回該消息 | ---- |
和寫(xiě)數(shù)據(jù)一樣西雀,其中最重要的消息是BR_TRANSACTION或BR_REPLY萨驶,表明收到一個(gè)格式為binder_transaction_data的請(qǐng)求數(shù)據(jù)包(BR_TRANSACTION或返回?cái)?shù)據(jù)包(BR_REPLY))
6.3 struct binder_transaction_data :收發(fā)數(shù)據(jù)包結(jié)構(gòu)
該結(jié)構(gòu)是Binder接收/發(fā)送數(shù)據(jù)包的標(biāo)準(zhǔn)格式,每個(gè)成員定義如下:
成員 | 含義 |
---|---|
union{ size_t handle; void *ptr;} target艇肴; | 對(duì)于發(fā)送數(shù)據(jù)包的一方腔呜,該成員指明發(fā)送目的地。由于目的地是遠(yuǎn)端豆挽,所以在這里填入的是對(duì)Binder實(shí)體的引用育谬,存放在target.handle中。如前述帮哈,Binder的引用在代碼中也叫句柄(handle)。 當(dāng)數(shù)據(jù)包到達(dá)接收方時(shí)锰镀,驅(qū)動(dòng)已將該成員修改成Binder實(shí)體娘侍,即指向 Binder對(duì)象內(nèi)存的指針,使用target.ptr來(lái)獲取泳炉。該指針是接受方在將Binder實(shí)體傳輸給其他進(jìn)程時(shí)提交給驅(qū)動(dòng)的憾筏,驅(qū)動(dòng)程序能夠自動(dòng)將發(fā)送方填入的引用轉(zhuǎn)換成接收方的Binder對(duì)象的指針,故接收方可以直接將其當(dāng)對(duì)象指針來(lái)使用(通常是將其reinpterpret_cast相應(yīng)類) |
void *cookie花鹅; | 發(fā)送方忽略該成員氧腰;接收方收到數(shù)據(jù)包時(shí),該成員存放的是創(chuàng)建Binder實(shí)體時(shí)由該接收方自定義的任意數(shù)值,做為與Binder指針相關(guān)的額外信息存放在驅(qū)動(dòng)中古拴。驅(qū)動(dòng)基本上不關(guān)心該成員 |
unsigned int code ; | 該成員存放收發(fā)雙方約定的命令碼箩帚,驅(qū)動(dòng)完全不關(guān)心該成員的內(nèi)容。通常是Server端的定義的公共接口函數(shù)的編號(hào) |
unsigned int code; | 與交互相關(guān)的標(biāo)志位黄痪,其中最重要的是TF_ONE_WAY位紧帕。如果該位置上表明這次交互是異步的,Server端不會(huì)返回任何數(shù)據(jù)桅打。驅(qū)動(dòng)利用該位決定是否構(gòu)建與返回有關(guān)的數(shù)據(jù)結(jié)構(gòu)是嗜。另外一位TF_ACCEPT_FDS是處于安全考慮,如果發(fā)起請(qǐng)求的一方不希望在收到回復(fù)中接收文件的Binder可以將位置上挺尾。因?yàn)槭盏揭粋€(gè)文件形式的Binder會(huì)自動(dòng)為接收方打開(kāi)一個(gè)文件鹅搪,使用該位可以防止打開(kāi)文件過(guò)多 |
pid_t send_pid uid_t sender_euid | 該成員存放發(fā)送方的進(jìn)程ID和用戶ID,由驅(qū)動(dòng)負(fù)責(zé)填入遭铺,接收方可以讀取該成員獲取發(fā)送方的身份丽柿。 |
size_t data_size | 驅(qū)動(dòng)一般情況下不關(guān)心data.buffer里存放了什么數(shù)據(jù)。但如果有Binder在其中傳輸則需要將其對(duì)應(yīng)data.buffer的偏移位置指出來(lái)讓驅(qū)動(dòng)知道掂僵。有可能存在多個(gè)Binder同時(shí)在數(shù)據(jù)中傳遞航厚,所以須用數(shù)組表示所有偏移位置。本成員表示該數(shù)組的大小锰蓬。 |
union{ struct{ const void *buffer; const void * offset; } ptr; uint8_t buf[8];} data; | data.buffer存放要發(fā)送或接收到的數(shù)據(jù)幔睬;data.offsets指向Binder偏移位置數(shù)組,該數(shù)組可以位于data.buffer中芹扭,也可以在另外的內(nèi)存空間中麻顶,并無(wú)限制。buf[8]是為了無(wú)論保證32位還是64位平臺(tái)舱卡,成員data的大小都是8字節(jié)辅肾。 |
- offsets_size和data.offsets兩個(gè)成員,這是Binder通信有別于其他IPC的地方轮锥。
- Binder采用面向?qū)ο?/strong>的設(shè)計(jì)思想矫钓,一個(gè)Binder實(shí)體可以發(fā)送給其他進(jìn)程從而建立許多跨進(jìn)程的引用;另外這些引用也可以在進(jìn)程之間傳遞舍杜,就像java將一個(gè)引用賦值給另外一個(gè)引用一樣新娜。為Binder在不同進(jìn)程中創(chuàng)建引用必須有驅(qū)動(dòng)參與,由驅(qū)動(dòng)在內(nèi)核創(chuàng)建并注冊(cè)相關(guān)的數(shù)據(jù)結(jié)構(gòu)后接收方才能使用該引用既绩。而且這些引用可以是強(qiáng)類型的概龄,需要驅(qū)動(dòng)為其維護(hù)引用計(jì)數(shù)。
- 然后這些跨進(jìn)程傳遞的Binder混雜在應(yīng)用程序發(fā)送的數(shù)據(jù)包里饲握,數(shù)據(jù)格式由用戶定義私杜,如果不把他們一一標(biāo)記出來(lái)告知驅(qū)動(dòng)蚕键,驅(qū)動(dòng)將無(wú)法從數(shù)據(jù)中將他們提取出來(lái)。
- 使用數(shù)組data.offsets存放用戶數(shù)據(jù)中每個(gè)Binder相對(duì)于data.buffer的偏移量衰粹,用offersets_size表示這個(gè)數(shù)組的大小锣光。驅(qū)動(dòng)在發(fā)送數(shù)據(jù)包時(shí)會(huì)根據(jù)data.offsets和offset_size將散落于data.buffer中的Binder找出來(lái)并一一為它們創(chuàng)建相關(guān)的數(shù)據(jù)結(jié)構(gòu)。