Android進(jìn)程間通信之7——Binder框架

本文的主要內(nèi)容如下:

  • 1 Android整體架構(gòu)
  • 2 IPC原理
  • 3 Binder簡介
  • 4 Binder通信機(jī)制
  • 5 Binder協(xié)議

一、Android整體架構(gòu)

(一) Android的整體架構(gòu)

為了讓大家更好的理解Binder機(jī)制,我們先來看下Android的整體架構(gòu)。因?yàn)檫@樣大家就知道在Android架構(gòu)中Binder出于什么地位。
用一下官網(wǎng)上的圖片


Android架構(gòu)

從下往上依次為:

  • 內(nèi)核層:Linux內(nèi)核和各類硬件設(shè)備的驅(qū)動(dòng),這里需要注意的是,Binder IPC驅(qū)動(dòng)也是這一層的實(shí)現(xiàn),比較特殊。
  • 硬件抽象層:封裝"內(nèi)核層"硬件驅(qū)動(dòng),提供可供"系統(tǒng)服務(wù)層"調(diào)用的統(tǒng)一硬件接口
  • 系統(tǒng)服務(wù)層:提供核心服務(wù),并且提供可供"應(yīng)用程序框架層"調(diào)用的接口
  • Binder IPC 層:作為"系統(tǒng)服務(wù)層"與"應(yīng)用程序框架層"的IPC橋梁,相互傳遞接口調(diào)用的數(shù)據(jù),實(shí)現(xiàn)跨進(jìn)程的通信。
  • 應(yīng)用程序框架層:這一層可以理解為Android SDK,提供四大組件,View繪制等平時(shí)開發(fā)中用到的基礎(chǔ)部件

(二) Android的架構(gòu)解析

在一個(gè)大的項(xiàng)目里面,分層是非常重要的,處于最底層的接口最具有"通用性",接口顆粒度最細(xì),越往上層通用性降低。理論上來說上面每一層都可以"開放"給開發(fā)者調(diào)用,例如開發(fā)者可以直接調(diào)用硬件抽象層的接口去操作硬件,或者直接調(diào)用系統(tǒng)服務(wù)層中的接口去直接操作系統(tǒng)服務(wù),甚至像Windows開發(fā)一樣,開發(fā)者可以在內(nèi)核層寫程序,運(yùn)行在內(nèi)核中。不過開放帶來的問題就是開發(fā)者權(quán)利太大,對(duì)于系統(tǒng)的穩(wěn)定性是沒有任何好處的,一個(gè)病毒制作者搞一個(gè)內(nèi)核層的病毒出來,系統(tǒng)可能就永遠(yuǎn)起不來。所以谷歌的做法是將開發(fā)者的權(quán)利收攏到"應(yīng)用程序框架層",開發(fā)者只能調(diào)用這一層的接口。
在上面的層次中,內(nèi)核層與硬件抽象層均用C/C++實(shí)現(xiàn),系統(tǒng)服務(wù)層是以Java實(shí)現(xiàn),硬件抽象層編譯為so文件,以JNI的形式供系統(tǒng)服務(wù)層使用。系統(tǒng)服務(wù)層中的服務(wù)隨著系統(tǒng)啟動(dòng)而啟動(dòng),只要不關(guān)機(jī),就會(huì)一直運(yùn)行。這些服務(wù)干什么事情?其實(shí)很簡單,就是完成一個(gè)手機(jī)有的核心功能如短信的收發(fā)管、電話的接聽、掛斷以及應(yīng)用程序的包管理、Activity的管理等等。每一個(gè)服務(wù)均運(yùn)行在一個(gè)獨(dú)立的進(jìn)程中,因此是以Java實(shí)現(xiàn),所以本質(zhì)上來說是運(yùn)行在一個(gè)獨(dú)立進(jìn)程的Dalvik虛擬機(jī)中。那么問題來了,開發(fā)者的App也運(yùn)行在一個(gè)獨(dú)立的進(jìn)程空間中,如果調(diào)用到系統(tǒng)的服務(wù)層中的接口?答案是IPC(Inter-Process Communication),進(jìn)程間通訊是和RPC(Remote Procedure Call)不一樣的,實(shí)現(xiàn)原理也不一樣。每一個(gè)系統(tǒng)服務(wù)在應(yīng)用框架層都有一個(gè)Manager與之對(duì)應(yīng),方便開發(fā)者調(diào)用其相關(guān)功能,具體關(guān)系如下:

調(diào)用關(guān)系

(三)、總結(jié)一下:

  • Android 從下而上分了內(nèi)核層、硬件抽象層、系統(tǒng)服務(wù)層、Binder IPC 層、應(yīng)用程序框架層
  • Android 中"應(yīng)用程序框架層"以 SDK 的形式開放給開發(fā)者使用,"系統(tǒng)服務(wù)層" 中的核心服務(wù)隨系統(tǒng)啟動(dòng)而運(yùn)行,通過應(yīng)用層序框架層提供的 Manager 實(shí)時(shí)為應(yīng)用程序提供服務(wù)調(diào)用。系統(tǒng)服務(wù)層中每一個(gè)服務(wù)運(yùn)行在自己獨(dú)立的進(jìn)程空間中,應(yīng)用程序框架層中的 Manager 通過 Binder IPC 的方式調(diào)用系統(tǒng)服務(wù)層中的服務(wù)。

二、IPC原理

從進(jìn)程的角度來看IPC機(jī)制



每個(gè)Android進(jìn)程,只能運(yùn)行在自己的進(jìn)程所擁有的虛擬地址空間,如果是32位的系統(tǒng),對(duì)應(yīng)一個(gè)4GB的虛擬地址空間,其中3GB是用戶空,1GB是內(nèi)核空間,而內(nèi)核空間的大小是可以通過參數(shù)配置的。對(duì)于用戶空間,不同進(jìn)程之間彼此是不能共享的,而內(nèi)核空間確實(shí)可以共享的。Client進(jìn)程與Server進(jìn)程通信,恰恰是利用進(jìn)程間可共享的內(nèi)核內(nèi)空間來完成底層通信工作的,Client端與Server端進(jìn)程往往采用ioctl等方法跟內(nèi)核空間的驅(qū)動(dòng)進(jìn)行。

三、Binder綜述

(一) Binder簡介

1、Binder的由來

簡單的說,Binder是Android平臺(tái)上的一種跨進(jìn)程通信技術(shù)。該技術(shù)最早并不是谷歌公司提出的,它前身是Be Inc公司開發(fā)的OpenBinder,而且在Palm中也有應(yīng)用。后來OpenBinder的作者Dianne Hackborn加入了谷歌公司,并負(fù)責(zé)Android平臺(tái)開發(fā)的工作,所以把這項(xiàng)技術(shù)也帶進(jìn)了Android。

我們知道,在Android的應(yīng)用層次上,基本上已經(jīng)沒有了進(jìn)程的概念了,然后在具體的實(shí)現(xiàn)層次上,它畢竟還是要構(gòu)建一個(gè)個(gè)進(jìn)程之上的。實(shí)際上,在Android內(nèi)部,哪些支持應(yīng)用的組件往往會(huì)身處不同的繼承,那么應(yīng)用的底層必然會(huì)涉及大批的跨進(jìn)程通信,為了保證了通信的高效性,Android提供了Binder機(jī)制。

2、什么是Binder

讓我們從四個(gè)維度來看Binder,這樣會(huì)讓大家對(duì)理解Binder機(jī)制更有幫助

  • 1 從來類的角度來說,Binder就是Android的一個(gè)類,它繼承了IBinder接口
  • 2 從IPC的角度來說,Binder是Android中的一種跨進(jìn)程通信方式,Binder還可以理解為一種虛擬的物理設(shè)備,它的設(shè)備驅(qū)動(dòng)是/dev/binder,該通信方式在Linux中沒有(由于耦合性太強(qiáng),Linux沒有接納)
  • 3 從Android Framework角度來說,Binder是ServiceManager連接各種Manager(ActivityManager、WindowManager等)和相應(yīng)的ManagerService的橋梁
  • 4 從Android應(yīng)用層的角度來說,Binder是客戶端和服務(wù)端進(jìn)行通信的媒介,當(dāng)你bindService的時(shí)候,服務(wù)端會(huì)返回一個(gè)包含了服務(wù)端業(yè)務(wù)調(diào)用的Binder對(duì)象,通過這個(gè)Binder對(duì)象,客戶端就可以獲取服務(wù)端提供的服務(wù)或者數(shù)據(jù),這里的服務(wù)包括普通服務(wù)和基于AIDL的服務(wù)。

3、Binder機(jī)制的意義

Binder機(jī)制具有兩層含義:

  • 1 是一種跨進(jìn)程通信的方式(IPC)
  • 2 是一種遠(yuǎn)程過程調(diào)用方式(PRC)

而從實(shí)現(xiàn)的角度來說,Binder核心被實(shí)現(xiàn)成一個(gè)Linux驅(qū)動(dòng)程序,并運(yùn)行于內(nèi)核態(tài)。這樣它才能具有強(qiáng)大的跨進(jìn)程訪問能力。

4、和傳統(tǒng)IPC機(jī)制相比,谷歌為什么采用Binder

我們先看下Linux中的IPC通信機(jī)制:

  • 1、傳統(tǒng)IPC:匿名管道(PIPE)、信號(hào)(signal)、有名管道(FIFO)
  • 2、AT&T Unix:共享內(nèi)存,信號(hào)量,消息隊(duì)列
  • 3、BSD Unix:Socket

關(guān)于這塊如果大家不了解,請(qǐng)看前面的文章。
雖然Android繼承Linux內(nèi)核,但是Linux與Android通信機(jī)制是不同的。Android中有大量的C/S(Client/Server)應(yīng)用方式,這就要求Android內(nèi)部提供IPC方法,而如果采用Linux所支持的進(jìn)程通信方式有兩個(gè)問題:性能安全性

  • 性能:目前Linux支持的IPC包括傳統(tǒng)的管道,System V IPC(包括消息隊(duì)列/共享內(nèi)存/信號(hào)量)以及socket,但是只有socket支持Client/Server的通信方式,由于socket是一套通用當(dāng)初網(wǎng)絡(luò)通信方式,其效率低下,且消耗比較大(socket建立連接過程和中斷連接過程都有一定的開銷),明顯在手機(jī)上不適合大面積使用socket。而消息隊(duì)列和管道采用"存儲(chǔ)-轉(zhuǎn)發(fā)" 方式,即數(shù)據(jù)先從發(fā)送方緩存區(qū)拷貝到內(nèi)核開辟的緩存區(qū)中,然后再從內(nèi)核緩存中拷貝到接收方緩存中,至少有兩次拷貝過程。共享內(nèi)存雖然無需拷貝,但控制復(fù)雜,難以使用。
  • 安全性:在安全性方面,Android作為一個(gè)開放式,擁有眾多開發(fā)者的平臺(tái),應(yīng)用程序的來源廣泛,確保智能終端的安全是非常重要的。終端用戶不希望從網(wǎng)上下載的程序在不知情的情況下偷窺隱私數(shù)據(jù),連接無線網(wǎng)絡(luò),長期操作底層設(shè)備導(dǎo)致電池很快耗盡的情況。傳統(tǒng)IPC沒有任何安全措施,完全依賴上層協(xié)議來去報(bào)。首先傳統(tǒng)IPC的接受方無法獲取對(duì)方進(jìn)程可靠的UID/PID(用戶ID/進(jìn)程ID),從而無法鑒別對(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訪問接入點(diǎn)是開放的,無法建立私有通道。比如命名管道、system V的鍵值,socket的ip地址或者文件名都是開放的,只要知道這些接入點(diǎn)的程序都可以對(duì)端建立連接,不管怎樣都無法阻止惡意程序通過接收方地址獲得連接。

基于以上原因,Android需要建立一套新的IPC機(jī)制來滿足系統(tǒng)對(duì)通信方式,傳輸性能和安全性的要求,所以就有了Binder。Binder基于Client/Server通信模式,傳輸過程只需要一次拷貝,為發(fā)送方添加UID/PID身份,支持實(shí)名Binder也支持匿名Binder,安全性高。下圖為Binder通信過程示例:


Binder通信過程
  • 相比于傳統(tǒng)的跨進(jìn)程通信手段,通信雙方必須要處理線程同步,內(nèi)存管理等問題,工作量大,而且問題多,就像我們前面介紹的傳統(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)程中、組件的生命周期等問題。隨時(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)程了(前面文章說了,一般IPC都需要兩步,第一步用戶進(jìn)程復(fù)制到內(nèi)核,第二步再從內(nèi)核復(fù)制到服務(wù)進(jìn)程。)

PS: 整個(gè)Androdi系統(tǒng)架構(gòu)中,雖然大量采用了Binder機(jī)制作為IPC(進(jìn)程間通信)方式,但是也存在部分其他的IPC方式,比如Zygote通信就是采用socket。

5、Binder在Service服務(wù)中的作用

在Android中,有很多Service都是通過Binder來通信的,比如MediaService名下的眾多Service:

  • AudioFlinger音頻核心服務(wù)
  • AudioPolicyService:音頻策略相關(guān)的重要服務(wù)
  • MediaPlayerService:多媒體系統(tǒng)中的重要服務(wù)
  • CarmeraService:有關(guān)攝像/照相的重要服務(wù)

那具體是怎么應(yīng)用或者通信機(jī)制是什么那?那就讓我們來詳細(xì)了解下

(二)、總結(jié)

Android Binder 是在OpenBinder上定制實(shí)現(xiàn)的。原先的OpenBinder 框架現(xiàn)在已經(jīng)不再繼續(xù)開發(fā),所以也可以說Android讓原先的OpenBinder得到了重生。Binder是Android上大量使用的IPC(Inter-process communication,進(jìn)程間通訊)機(jī)制。無論是應(yīng)用程序?qū)ο到y(tǒng)服務(wù)的請(qǐng)求,還是應(yīng)用程序自身提供對(duì)外服務(wù),都需要使用Binder。

整體架構(gòu)

整體架構(gòu)

從圖中可以看出,Binder的實(shí)現(xiàn)分為這幾層,按照大的框架理解是

  • framewor層
    java 層
    jni 層
    native/ C++層
  • linux驅(qū)動(dòng)層 c語言

讓我們來仔細(xì)研究下。

  • 其中Linux驅(qū)動(dòng)層位于Linux內(nèi)核中,它提供了最底層的數(shù)據(jù)傳遞,對(duì)象標(biāo)示,線程管理,通過調(diào)用過程控制等功能。驅(qū)動(dòng)層其實(shí)是Binder機(jī)制的核心。
  • Framework層以Linux驅(qū)動(dòng)層為基礎(chǔ),提供了應(yīng)用開發(fā)的基礎(chǔ)設(shè)施。Framework層既包含了C++部分的實(shí)現(xiàn),也包含了Java基礎(chǔ)部分的實(shí)現(xiàn)。為了能將C++ 的實(shí)現(xiàn)復(fù)用到Java端,中間通過JNI進(jìn)行銜接。

開發(fā)者可以在Framework之上利用Binder提供的機(jī)制來進(jìn)行具體的業(yè)務(wù)邏輯開發(fā)。其實(shí)不僅僅是第三方開發(fā)者,Android系統(tǒng)中本身也包含很多系統(tǒng)服務(wù)都是基于Binder框架開發(fā)的。其中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ù)。如下圖所示:

Binder調(diào)用.png

如果大家對(duì)網(wǎng)絡(luò)協(xié)議有所了解的話,其實(shí)會(huì)發(fā)現(xiàn)整個(gè)數(shù)據(jù)的傳遞過程和網(wǎng)絡(luò)協(xié)議如此的相似。

四、Binder通信機(jī)制

Android內(nèi)部采用C/S架構(gòu)。而Binder通信也是采用C/S架構(gòu)。那我們來看下Binder在C/S的中的流程。

(一) Binder在C/S中的流程

如下圖


Binder流程.png

具體流程如下:

  • 1、相應(yīng)的Service需要注冊(cè)服務(wù)。Service作為很多Service的擁有者,當(dāng)它想向Client提供服務(wù)時(shí),得先去Service Manager(以后縮寫成SM)那兒注冊(cè)自己的服務(wù)。Server可以向SM注冊(cè)一個(gè)或者多個(gè)服務(wù)。
  • 2、Client申請(qǐng)服務(wù)。Client作為Service的使用者,當(dāng)他想使用服務(wù)時(shí),得向SM申請(qǐng)自己所需要的服務(wù)。Client可以申請(qǐng)一個(gè)或者多個(gè)服務(wù)。
  • 3、當(dāng)Client申請(qǐng)服務(wù)成功后,Client就可以使用服務(wù)了。

SM一方面管理Server所提供的服務(wù),同時(shí)又響應(yīng)Client的請(qǐng)求并為之分配響應(yīng)的服務(wù)。扮演角色相當(dāng)于月老,兩邊牽線。這種通信方式的好處是:一方面,service和Client請(qǐng)求便于管理,另一方面在應(yīng)用程序開發(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)程。

(二)Binder通信整體框架

這里先提前和大家說下,后面我們會(huì)不斷的提及兩個(gè)概念,一個(gè)是Server,還有一個(gè)是Service,我這里先強(qiáng)調(diào)下,Server是Server,Service是Service,大家不要混淆,一個(gè)Server下面可能有很多Service,但是一個(gè)Servcie也只能隸屬于一個(gè)Server。下面我們將從三個(gè)角度來看Binder框架,這樣

1、從內(nèi)核和用戶空間的角度來看

Binder通信模型如下:

Binder通信整體框架.png
  • 1、Client和Server是存在于用戶空間
  • 2、Client和Server通信實(shí)現(xiàn)是由Binder驅(qū)動(dòng)在內(nèi)核的實(shí)現(xiàn)
  • 3、SM作為守護(hù)進(jìn)程,處理客戶端請(qǐng)求,管理所有服務(wù)

如果大家不好理解上面的意思,我們可以把SM理解成為DNS服務(wù)器,那么Binder Driver就相當(dāng)于路由的功能。這里就涉及到Client和Server是如何通信的問題。

2、從Android的層級(jí)的角度

如下圖:(注意圖片的右邊)


Binder原理.png

圖中Client/Server/ServiceManager之間的相互通信都是基于Binder機(jī)制。圖中Clinet/Server/ServiceManager之間交互都是虛線表示,是由于他們彼此之間不直接交互,都是通過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)用層,開發(fā)人員只需要自定義實(shí)現(xiàn)client、Server端,借助Android的基本平臺(tái)架構(gòu)就可以直接進(jìn)行IPC通信。

3、從Binder的架構(gòu)角度來看

Binder架構(gòu).png

同樣

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ì)開啟一個(gè)線程池去處理客戶端調(diào)用。為什么要用線程池而不是一個(gè)單線程隊(duì)列呢?試想一下,如果用單線程隊(duì)列,則會(huì)有任務(wù)積壓,多個(gè)客戶端同時(shí)調(diào)用一個(gè)服務(wù)的時(shí)候就會(huì)有來不及響應(yīng)的情況發(fā)生,這是絕對(duì)不允許的。

對(duì)于調(diào)用 Binder Driver 中的 transact 接口,客戶端可以手動(dòng)調(diào)用,也可以通過 AIDL 的方式生成的代理類來調(diào)用,服務(wù)端可以繼承 Binder 對(duì)象,也可以繼承 AIDL 生成的接口類的 Stub 對(duì)象。這些細(xì)節(jié)下面繼續(xù)接著說,這里暫時(shí)不展開。

切記,這里 Server 的實(shí)現(xiàn)是線程池的方式,而不是單線程隊(duì)列的方式,區(qū)別在于,單線程隊(duì)列的話,Server 的代碼是線程安全的,線程池的話,Server 的代碼則不是線程安全的,需要開發(fā)者自己做好多線程同步。

(三)、Binder流程

1、Server向SM注冊(cè)服務(wù)

注冊(cè).png
  • 1、首先 XXServer(XXX代表某個(gè))在自己的進(jìn)程中向Binder驅(qū)動(dòng)申請(qǐng)創(chuàng)建一個(gè)XXXService的Binder實(shí)體。
  • 2、Binder驅(qū)動(dòng)為這個(gè)XXXService創(chuàng)建位于內(nèi)核中的Binder實(shí)體節(jié)點(diǎn)以及Binder的引用,注意,是將名字和新建的引用打包傳遞給SM(實(shí)體沒有傳給SM),通知SM注冊(cè)一個(gè)名叫XXX的Service。
  • 3、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í)體的引用(沒有真實(shí)空間,可以理解成實(shí)體的一個(gè)鏈接,操作引用就可以操作對(duì)應(yīng)鏈接上的實(shí)體)。如果一個(gè)進(jìn)程持有某個(gè)實(shí)體,其他進(jìn)程也想操作該實(shí)體,最高效的做法是去獲取該實(shí)體的引用,再去操作這個(gè)引用。
  • 有些資源也把實(shí)體成本本地對(duì)象,應(yīng)用稱為遠(yuǎn)程對(duì)象。所以也可以這么理解:應(yīng)用是從本地進(jìn)程發(fā)送給其他進(jìn)程操作實(shí)體之用,所以有本地和遠(yuǎn)程對(duì)象之名。

為了大家在后面更好的理解,這里補(bǔ)充幾個(gè)概念

  • Binder實(shí)體對(duì) :Binder實(shí)體對(duì)象就是Binder實(shí)體對(duì)象就是Binder服務(wù)的提供者。一個(gè)提供Binder服務(wù)的類必須繼承BBinder類,因此,有時(shí)為了強(qiáng)調(diào)對(duì)象類型,也用"BBinder對(duì)象"來代替"Binder實(shí)體對(duì)象"。
  • Binder引用對(duì)象 :Binder引用對(duì)象是Binder實(shí)體對(duì)象在客戶進(jìn)程的代表,每個(gè)引用對(duì)象的類型都是BpBiner類,同樣可以用名稱"BpBinder對(duì)象"來代替"Binder引用對(duì)象"。
  • Binder代理對(duì)象 :代理對(duì)象也成為接口對(duì)象,它主要是為了客戶端的上層應(yīng)用提供接口服務(wù),從IInterface類派生。它實(shí)現(xiàn)了Binder服務(wù)的函數(shù)接口,當(dāng)然只是一個(gè)轉(zhuǎn)調(diào)的空殼。通過代理對(duì)象,應(yīng)用能像使用本地對(duì)象一樣使用遠(yuǎn)端實(shí)體對(duì)象提供服務(wù)。
  • IBiner對(duì)象 :BBinder和BpBinder類是從IBinder類中繼承來。在很多場合,不需要刻意地去區(qū)分實(shí)體對(duì)象和引用對(duì)象,這時(shí)候也可以統(tǒng)一使用"IBinder對(duì)象"來統(tǒng)一稱呼他們。
  • Binder代理對(duì)象 主要是和應(yīng)用程序打交道,將Binder代理對(duì)象和Binder引用對(duì)應(yīng)(BpBinder對(duì)象)分開的好處是代理對(duì)象可以有很多實(shí)例,但是它們包含的是同一個(gè)引用對(duì)象,這樣方便了應(yīng)用層的使用。如下圖所示:

這樣應(yīng)用層可以直接拋開接口對(duì)象直接使用Binder的引用對(duì)象,但是這樣開發(fā)的程序兼容性不好。也正是客戶端將引用對(duì)象和代理對(duì)象分離,Android才能用一套架構(gòu)來同時(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類中派生而來(BpBinder和BBinder在Native層,不在framework層),關(guān)系圖如下:


  • client端:BpBinder通過調(diào)用transact()來發(fā)送事物請(qǐng)求
  • server端:BBinder通過onTransact()會(huì)接受到相應(yīng)的事物

這時(shí)候再來看下這個(gè)圖,然后大家思考一下,就會(huì)明白很多事情。


Binder原理.png

2、如何獲得一個(gè)SM的遠(yuǎn)程接口


如果你足夠細(xì)心,你會(huì)發(fā)現(xiàn)這里有一個(gè)問題:

SM和Server都是進(jìn)程,Server向SM注冊(cè)Binder需要進(jìn)程間通信,當(dāng)前實(shí)現(xiàn)的是進(jìn)程間通信,卻又用到進(jìn)程間通信。有點(diǎn)暈是不,就好像先有雞還是先有蛋這個(gè)問題。

其實(shí)Binder是這么解決這個(gè)問題的:

  • 針對(duì)Binder的通信機(jī)制,Server端擁有的是Binder的實(shí)體(BBinder);Client擁有的是Binder的引用(BpBinder)。
  • 如果把SM看做Server端,讓它在Binder驅(qū)動(dòng)一起運(yùn)行起來時(shí)就有自己的實(shí)體(BBinder)(代碼中設(shè)置ServiceManager的Binder其handle的值恒為0)。這個(gè)Binder實(shí)體沒有名字也不需要注冊(cè),所有的Client都認(rèn)為handle值為0的binder引用(BpBinder)是用來與SM通信的。那么這個(gè)問題就解決了。
  • 但是問題又來了,Client和Server中handle的值為0(值為0的引用是專門與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。

3、Client從SM中獲得Service的遠(yuǎn)程接口

Server向SM注冊(cè)了Binder實(shí)體及其名字后,Client就可以Service的名字在SM在查找表中獲得了該Binder的引用(BpBinder)了。Client也利用了保留的handle值為0的引用向SM請(qǐng)求訪問某個(gè)Service:當(dāng)申請(qǐng)?jiān)L問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è)引用。

如下圖


獲取遠(yuǎn)程接口.png

4、建立C/S連接后

首先要明白一個(gè)事情:

Client要擁有自己的Binder實(shí)體,以及Server的Binder的引用;Server有用自己的Binder的實(shí)體,以及Client的Binder引用。

我們也可以按照網(wǎng)絡(luò)請(qǐng)求的方式來分析:

  • 從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連接后,無需考慮誰是Client,誰是Server。只要理清誰是發(fā)送方,誰是接收方,就能知道Binder的實(shí)體和應(yīng)用在哪邊。

那我們看下建立C/S連接后的,具體流程,如下圖:


建立C/S連接后的流程.png

那我們說下具體的流程:

  • 第一步,發(fā)送方通過Binder實(shí)體請(qǐng)求發(fā)送操作
  • 第二步,Binder驅(qū)動(dòng)會(huì)處理這個(gè)操作請(qǐng)求,把發(fā)送方的數(shù)據(jù)放入寫緩存(binder_write_read.write_buffer)(對(duì)于接受方來說為讀緩存區(qū)),并把read_size(接收方讀數(shù)據(jù))置為數(shù)據(jù)大小。
  • 第三步,接收方之前一直在阻塞狀態(tài)中,當(dāng)寫緩存有數(shù)據(jù),則會(huì)讀取數(shù)據(jù),執(zhí)行命令操作
  • 第四步,接收方執(zhí)行完后,會(huì)把返回結(jié)果同樣采用binder_transaction_data結(jié)構(gòu)體封裝,寫入緩沖區(qū)(對(duì)于發(fā)送方,為讀緩沖區(qū))

(四) 匿名Binder

在Android中Binder還可以建立點(diǎn)對(duì)點(diǎn)的私有通道,匿名Binder就是這種方式。在Binder通信中,并不是所有通信的Binder實(shí)體都需要注冊(cè)給SM的,Server可以通過已建立的實(shí)體Binder連接將創(chuàng)建的Binder實(shí)體傳給Client。而這個(gè)Binder沒有向SM注冊(cè)名字。這樣Server和Client通信就有很高的隱私性和安全性。

如下圖:


匿名Binder.png

五、 Binder的層次

從代碼上看,Binder設(shè)計(jì)的類可以分成4個(gè)層級(jí),如下圖所示


  • 最上層的是位于Framewok中的各種Binder服務(wù)類和它們的接口類。這一層的類非常多,比如常見的ActivityManagerService(縮寫叫AMS)、WindowManagerService(縮寫叫WMS)、PackageManagerService(縮寫是PMS)等,它們?yōu)閼?yīng)用程序提供了各種各樣的服務(wù)。
  • 中間則分為為兩層,上面是用于服務(wù)類和接口開發(fā)的基礎(chǔ),比如IBinder、BBinder、BpBinder等。下層是和驅(qū)動(dòng)交互的IPCThreadState和ProcessState類
  • 最上層的是位于Framewok中的各種Binder服務(wù)類和它們的接口類。這一層的類非常多,比如常見的ActivityManagerService(縮寫叫AMS)、WindowManagerService(縮寫叫WMS)、PackageManagerService(縮寫是PMS)等,它們?yōu)閼?yīng)用程序提供了各種各樣的服務(wù)。
    中間則分為為兩層,上面是用于服務(wù)類和接口開發(fā)的基礎(chǔ),比如IBinder、BBinder、BpBinder等。下層是和驅(qū)動(dòng)交互的IPCThreadState和ProcessState類。
    這里刻意把中間的libbinder中的類劃分為兩個(gè)層次的原因,是在這4層中,第一層的和第二層聯(lián)系很緊密,第二層中的 各種Binder類用來支撐服務(wù)類和代理類的開發(fā)。但是第三層的IPCThread和第四層之間耦合得很厲害,單獨(dú)理解IPCThread或者是驅(qū)動(dòng)都是一件很難的事,必須把它們結(jié)合起來理解,這一點(diǎn)正是Binder架構(gòu)被人詬病的地方,驅(qū)動(dòng)和應(yīng)用層之間過于耦合,違反了Linux驅(qū)動(dòng)設(shè)計(jì)的原則,因此,主流的Linux并不愿意接納Binder。

下面我們就來詳細(xì)的看來Binder

六、Binder協(xié)議

Biner協(xié)議格式基本是"命令+數(shù)據(jù)",使用ioctl(fd,cmd,arg)函數(shù)實(shí)現(xiàn)交互。命令由參數(shù)cmd承載,數(shù)據(jù)由參數(shù)arg,隨著cmd不同而不同。下表列了所有命令及其對(duì)應(yīng)的數(shù)據(jù):

命令 含義 參數(shù)(arg)
BINDER_WRITE_READ 該命令向Binder寫入或讀取數(shù)據(jù)。參數(shù)分為兩段:寫部分和讀部分。如果write_size不為0,就將write_buffer里的數(shù)據(jù)寫入Binder;如果read_ size不為0再從Binder中讀取數(shù)據(jù)存入read_buffer中。write_consumered和read_consumered表示操作完成時(shí)Binder驅(qū)動(dòng)實(shí)際寫入或者讀出數(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端必須開辟線程池為這些并發(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沒有調(diào)用close()關(guān)閉,Binder驅(qū)動(dòng)就不能有別的進(jìn)程變成SM
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)
BINDER_VERSION 獲取Binder驅(qū)動(dòng)的版本號(hào)

這其中最常用的命令是 BINDER_WRITE_READ。該命令的參數(shù)包括兩個(gè)部分:

  • 1、是向Binder寫入數(shù)據(jù)
  • 2、是向Binder讀出數(shù)據(jù)

驅(qū)動(dòng)程序先處理寫部分再處理讀部分。這樣安排的好處是應(yīng)用程序可以很靈活的地處理命令的同步或者異步。例如若要發(fā)送異步命令可以只填入寫部分而將read_size設(shè)置為0,若要只從Binder獲得的數(shù)據(jù)可以將寫部分置空,即write_size置0。如果想要發(fā)送請(qǐng)求并同步等待返回?cái)?shù)據(jù)可以將兩部分都置上。

(一)、BINDER_WRITE_READ 之寫操作

Binder寫操作的數(shù)據(jù)時(shí)格式同樣也是(命令+數(shù)據(jù))。這時(shí)候命令和數(shù)據(jù)都存放在binder_write_read結(jié)構(gòu)中的write_buffer域指向的內(nèi)存空間里,多條命令可以連續(xù)存放。數(shù)據(jù)緊接著存放在命令后面,格式根據(jù)命令不同而不同。下表列舉了Binder寫操作支持的命令:
我提供兩套,一套是圖片,方便手機(jī)用戶,一部分是文字,方便PC用戶


寫操作.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)體表明要寫入的數(shù)據(jù)。 struct binder_transaction_data
BC_ACQUIRE_RESULT 暫未實(shí)現(xiàn)
BC_FREE_BUFFER 釋放 一塊映射內(nèi)存。Binder接受方通過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ū)耗盡而無法接受新數(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)程通過該命令要求驅(qū)動(dòng)在Binder實(shí)體銷毀得到通知。雖說強(qiáng)指針可以確保只要有引用就不會(huì)銷毀實(shí)體,但這畢竟是個(gè)跨進(jìn)程的引用,誰也無法保證實(shí)體由于所在的Server關(guān)閉Binder驅(qū)動(dòng)或異常退出而消失,引用者能做的就是要求Server在此刻給出通知 uint32 *ptr;需要得到死亡的通知Binder引用 void **cookie:與死亡通知相關(guān)的信息,驅(qū)動(dòng)會(huì)在發(fā)出死亡通知時(shí)返回給發(fā)出請(qǐng)求的進(jìn)程。
BC_DEAD_BINDER 收到實(shí)體死亡通知書的進(jìn)程在刪除引用后用本命令告知驅(qū)動(dòng) void * cookie

在這些命令中,最常用的h是BC_TRANSACTION/BC_REPLY命令對(duì),Binder請(qǐng)求和應(yīng)答數(shù)據(jù)就是通過這對(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ù)包后才能完成一次交互。

(二)、BINDER_WRITE_READ:從Binder讀出數(shù)據(jù)

在Binder里讀出數(shù)據(jù)格式和向Binder中寫入數(shù)據(jù)格式一樣,采用(消息ID+數(shù)據(jù))形式,并且多條消息可以連續(xù)存放。下面列舉從Binder讀出命令及相應(yīng)的參數(shù)。
為了照顧手機(jī)端的朋友,先發(fā)圖片


Binder讀出數(shù)據(jù).png
消息 含義 參數(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ù)沒有超過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 交互過程中如果發(fā)現(xiàn)對(duì)方進(jìn)程或線程已經(jīng)死亡則返回該消息 -----
BR_TRANSACTION_COMPLETE 發(fā)送方通過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í)體死亡通知書:收到死亡通知書的進(jìn)程接下來會(huì)返回 BC_DEAD_BINDER_DONE 確認(rèn) void *cookie 在使用BC_REQUEST_DEATH_NOTIFICATION注冊(cè)死亡通知時(shí)的附加參數(shù)
BR_FAILED_REPLY 如果發(fā)送非法引用號(hào)則返回該消息 -----

和寫數(shù)據(jù)一樣,其中最重要的消息是BR_TRANSACTION或BR_REPLY,表明收到一個(gè)格式為binder_transaction_data的請(qǐng)求數(shù)據(jù)包(BR_TRANSACTION或返回?cái)?shù)據(jù)包(BR_REPLY))

(三)、struct binder_transaction_data :收發(fā)數(shù)據(jù)包結(jié)構(gòu)

該結(jié)構(gòu)是Binder接收/發(fā)送數(shù)據(jù)包的標(biāo)準(zhǔn)格式,每個(gè)成員定義如下:
下圖是Binder


Binder數(shù)據(jù)包.png
成員 含義
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來獲取。該指針是接受方在將Binder實(shí)體傳輸給其他進(jìn)程時(shí)提交給驅(qū)動(dòng)的,驅(qū)動(dòng)程序能夠自動(dòng)將發(fā)送方填入的引用轉(zhuǎn)換成接收方的Binder對(duì)象的指針,故接收方可以直接將其當(dāng)對(duì)象指針來使用(通常是將其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)為接收方打開一個(gè)文件,使用該位可以防止打開文件過多
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的偏移位置指出來讓驅(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)存空間中,并無限制。buf[8]是為了無論保證32位還是64位平臺(tái),成員data的大小都是8字節(jié)。

PS:這里有必要強(qiáng)調(diào)一下offsets_size和data.offsets兩個(gè)成員,這是Binder通信有別于其他IPC的地方。就像前面說說的,Binder采用面向?qū)ο蟮脑O(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)記出來告知驅(qū)動(dòng),驅(qū)動(dòng)將無法從數(shù)據(jù)中將他們提取出來。于是就是使用數(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找出來并一一為它們創(chuàng)建相關(guān)的數(shù)據(jù)結(jié)構(gòu)。

七、Binder的整體架構(gòu)

Binder的整體架構(gòu).png

參考文獻(xiàn)

Android跨進(jìn)程通信IPC之6——Binder框架

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容