Android Binder機制
備注:
文章大部分內(nèi)容路源于:
https://blog.csdn.net/crs0313/article/details/81737323?spm=1001.2014.3001.5501
https://blog.csdn.net/crs0313/article/details/81737408?spm=1001.2014.3001.5501
主要記錄學(xué)習(xí)的過程,可能會有錯誤的地方
IPC
所謂IPC,IPC(Inter-Process Communication)進程間通信,就是跨進程通信。線程是CPU調(diào)度的基本單位,而進程則是向系統(tǒng)申請資源的基本單位。同一個進程中的各個線程是可以相互訪問內(nèi)存的,因為這些線程中的變量都是在堆棧中的。
Linux C編程中有幾種方法
(1) 半雙工Unix管道
(2) FIFOs(命名管道)
(3) 消息隊列
(4) 信號量
(5) 共享內(nèi)存
(6) Socket
為什么選擇Binder
Android是基于Linux內(nèi)核的,Binder是Android基于Linux的一種獨特的IPC機制
一者性能方面,傳輸效率問題,傳統(tǒng)的管道隊列模式采用內(nèi)存緩沖區(qū)的方式,數(shù)據(jù)先從發(fā)送方緩存區(qū)拷貝到內(nèi)核開辟的緩存區(qū)中,然后再從內(nèi)核緩存區(qū)拷貝到接收方緩存區(qū),至少有兩次拷貝過程,而socket都知道傳輸效率低,開銷大,用于跨網(wǎng)絡(luò)進程交互比較多,共享內(nèi)存雖然無需拷貝。
二者這是安全問題,Android作為一個開放式,擁有眾多開發(fā)者的的平臺,應(yīng)用程序的來源廣泛,確保終端安全是非常重要的,傳統(tǒng)的IPC通信方式?jīng)]有任何措施,基本依靠上層協(xié)議,其一無法確認對方可靠的身份,Android為每個安裝好的應(yīng)用程序分配了自己的UID,故進程的UID是鑒別進程身份的重要標志,傳統(tǒng)的IPC要發(fā)送類似的UID也只能放在數(shù)據(jù)包里,但也容易被攔截,惡意進攻,socket則需要暴露自己的ip和端口,知道這些惡意程序則可以進行任意接入。
三者是Binder本身是C/S架構(gòu)的,易用性高。
Binder只需要一次拷貝,性能僅次于共享內(nèi)存,而且采用的傳統(tǒng)的C/S結(jié)構(gòu),穩(wěn)定性也是沒得說,發(fā)送添加UID/PID,安全性高。

整體架構(gòu)

圖片來源:https://blog.csdn.net/dfvbrtdhy/article/details/113571419?spm=1001.2014.3001.5501
Binder的實現(xiàn)分為這么幾層
Java應(yīng)用層部分:定義了Binder FrameWork層通信的接口
Framework層:定義了和Binder驅(qū)動的通信的規(guī)則,C/S架構(gòu)
驅(qū)動層:數(shù)據(jù)傳遞,對象標識,線程管理,調(diào)用過程控制等功能
Binder模型的4類角色:Binder驅(qū)動,ServiceManager,Server和Client
驅(qū)動層
源碼路徑
/kernel/drivers/android/binder.c
/kernel/drivers/android/binder_internal.h
/kernel/include/uapi/linux/android/binder.h
binder.c 的主要工作


圖片來源:https://blog.csdn.net/dfvbrtdhy/article/details/113571419?spm=1001.2014.3001.5501
mmap
mmap的作用是進行內(nèi)存映射。當(dāng)應(yīng)用調(diào)用mmap()映射內(nèi)存到進程虛擬地址時,該函數(shù)會進行兩個操作:第一,將指定大小的”物理內(nèi)存” 映射到 “用戶空間”(即,進程的虛擬地址中)。 第二,將該”物理內(nèi)存” 也映射到 “內(nèi)核空間(即,內(nèi)核的虛擬地址中)”。
簡單來說,就是”將進程虛擬地址空間和內(nèi)核虛擬地址空間映射同一個物理頁面”。
在Binder通信機制中,mmap()會將Server進程的虛擬地址和內(nèi)核虛擬地址映射到同一個物理頁面。那么當(dāng)Client進程向Server進程發(fā)送請求時,只需要將Client的數(shù)據(jù)拷貝到內(nèi)核空間即可!由于Server進程的地址和內(nèi)核空間映射到同一個物理頁面,因此,Client中的數(shù)據(jù)拷貝到內(nèi)核空間時,也就相當(dāng)于拷貝到了Server進程中。因此,Binder通信機制中,數(shù)據(jù)傳輸時,只需要1次內(nèi)存拷貝!
Binder中的數(shù)據(jù)結(jié)構(gòu)
內(nèi)核空間的Binder數(shù)據(jù)結(jié)構(gòu)
詳細信息請參考:Android Binder機制(二) Binder中的數(shù)據(jù)結(jié)構(gòu)
binder_proc:是描述進程上下文信息的,每一個用戶空間的進程都對應(yīng)一個binder_proc結(jié)構(gòu)體Binder驅(qū)動的文件節(jié)點是"/dev/binder",每當(dāng)一個程序打開該文件節(jié)點時;Binder驅(qū)動中都會新建一個binder_proc對象來保存該進程的上下文信息。
binder_node:是Binder實體對應(yīng)的結(jié)構(gòu)體,它是Server在Binder驅(qū)動中的體現(xiàn)
binder_ref:是Binder引用對應(yīng)的結(jié)構(gòu)體,它是Client在Binder驅(qū)動中的體現(xiàn)
binder_buffer:binder_buffer是描述Binder進程所管理的每段內(nèi)存的結(jié)構(gòu)體。
binder_thread:描述Binder線程的結(jié)構(gòu)體
flat_binder_object:描述Binder對象信息的結(jié)構(gòu)體
binder_write_read:描述Binder讀寫信息的結(jié)構(gòu)體。
binder_transaction_data:描述Binder事務(wù)交互的數(shù)據(jù)格式的結(jié)構(gòu)體
用戶空間的Binder數(shù)據(jù)結(jié)構(gòu)
ServiceManager守護進程中的數(shù)據(jù)結(jié)構(gòu)
binder_state:定義在frameworks/native/cmds/servicemanager/binder.c中,它是ServiceManager用來描述打開的"/dev/binder"的信息結(jié)構(gòu)體
binder_object:定義在frameworks/native/cmds/servicemanager/binder.h中,ServiceManager中與flat_binder_object對應(yīng)的結(jié)構(gòu)體
binder_txn:定義在frameworks/native/cmds/servicemanager/binder.h中,ServiceManager中與binder_transaction_data對應(yīng)的結(jié)構(gòu)體
svcinfo:定義在frameworks/native/cmds/servicemanager/service_manager.c中,它是ServiceManager守護進程的私有結(jié)構(gòu)體,svcinfo是保存"注冊到ServiceManager中的服務(wù)"的相關(guān)信息的結(jié)構(gòu)體。它是一個單鏈表,在ServiceManager守護進程中的svclist是保存注冊到ServiceManager中的服務(wù)的鏈表,它就是struct info類型。svcinfo中的next是指向下一個服務(wù)的節(jié)點,而ptr是該服務(wù)在Binder驅(qū)動中Binder引用的描述。name則是服務(wù)的名稱。
C++層的數(shù)據(jù)結(jié)構(gòu)
Parcel:Parcel是描述Binder通信信息的結(jié)構(gòu)體
ServiceManager
ServiceManager是用戶空間的一個守護進程,它一直運行在后臺。它的職責(zé)是管理Binder機制中的各個Server。當(dāng)Server啟動時,Server會將”Server對象的名字”連同”Server對象的信息”一起注冊到ServiceManager中;而當(dāng)Client需要獲取Server接入點時,則通過”Server的名字”來從ServiceManager中找到對應(yīng)的Server。
ServiceManager是整個Binder機制能夠運作的的橋梁和管家,ServiceManager管理了Android的系統(tǒng)服務(wù)和用戶的服務(wù)。

圖片來源:https://blog.csdn.net/dfvbrtdhy/article/details/113571419?spm=1001.2014.3001.5501
Android系統(tǒng)啟動時會開啟init進程,init進程會先去創(chuàng)建servicemanager進程,其所對應(yīng)的可執(zhí)行程序servicemanager,所對應(yīng)的源文件是service_manager.c,進程名為servicemanager。
啟動ServiceManager的入口函數(shù)是 service_manager.c 中的main()方法,主要做了以下操作
binder_open
ServiceManager進程:打開/dev/binder,同時映射物理內(nèi)存到進程空間。
Binder驅(qū)動:新建并初始化該進程對應(yīng)的binder_proc結(jié)構(gòu)體,同時將內(nèi)核虛擬地址和該進程的虛擬地址映射到同一物理內(nèi)存中。
binder_become_context_manager
ServiceManager進程:告訴Kernel驅(qū)動,當(dāng)前進程(即ServiceManager進程)是Binder上下文管理者。
Binder驅(qū)動:新建當(dāng)前線程對應(yīng)的binder_thread對象,并將其添加到進程上下文信息binder_proc的threads紅黑樹中;新建ServiceManager對應(yīng)的binder實體,并將該binder實體保存到全局變量binder_context_mgr_node中。
binder_loop
ServiceManager進程:binder_loop()通過BC_ENTER_LOOPER告訴Kernel,ServiceManager進入了消息循環(huán)狀態(tài)。接著,ServiceManager就進入等待狀態(tài),等待Client請求。
Binder驅(qū)動:已知ServiceManager進入了消息循環(huán)狀態(tài);在收到ServiceManager的BINDER_WRITE_READ消息之后,就去ServiceManager的從進程上下文binder_proc對象中讀取是否有待處理事務(wù),由于沒有事務(wù)處理,則將ServiceManager線程設(shè)為中斷等待狀態(tài)。
ServiceManager的main()進程完成了以下工作
對于ServiceManager進程而言
它打開了Binder設(shè)備文件,并且將內(nèi)存映射到ServiceManager的進程空間。然后,它告訴Binder驅(qū)動自己是Binder上下文的管理者。最后,進入消息循環(huán),等待Client請求。
對于Binder驅(qū)動而言
初始化了ServiceManager對應(yīng)的進程上下文環(huán)境(即binder_proc變量),并將內(nèi)核虛擬地址和進程虛擬地址映射到同一物理內(nèi)存中。然后,新建當(dāng)前線程對應(yīng)的binder_thread對象,并將其添加到進程上下文信息binder_proc->threads紅黑樹中。在得知ServiceManager是Binder上下文管理者后,建立ServiceManager對應(yīng)的Binder實體,并將該Binder實體保存到全局變量中。最后,得知ServiceManager進入消息循環(huán)后,由于當(dāng)前線程中沒有事務(wù)可處理,則進入中斷等待狀態(tài),等待其他進程將其喚醒。
Service Manager的獲取
獲取Service Manager是通過defaultServiceManager()方法來完成。
frameworks/native/libs/binder/IServiceManager.cpp
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;
}
ProcessState::self()->getContextObject(NULL)
會先通過open_driver()打開”/dev/binder”,設(shè)置線程最大數(shù)目:15, 設(shè)置共享內(nèi)存大小 (1M-8K),接著調(diào)用mmap()映射內(nèi)存到當(dāng)前進程中。此時,ProcessState就初始化完畢,它將”/dev/binder”的文件句柄以及映射內(nèi)存都保存在自己的私有成員中。
getContextObject()
獲取ServiceManager對應(yīng)的BpBinder代理對象。 在新建BpBinder時,會通過IPCThreadState::self()獲取IPCThreadState對象;因為,需要通過IPCThreadState對象來與Binder驅(qū)動進行交互。
interface_cast
前面已經(jīng)成功獲取到了ServiceManager的BpBinder代理,而defaultServiceManager()返回的是IServiceManager對象。這里,使用了一個技巧,通過宏interface_cast而調(diào)用asInterface()函數(shù),從而返回IServiceManager的代理BpServiceManager。這樣,defaultServiceManager()就執(zhí)行完畢了。
主要類
RefBase
它定義在system/core/include/utils/RefBase.h中。RefBase是一個公共父類,它聲明了許多常用的接口。包括增加引用計數(shù),獲取引用計數(shù),新增對象的弱引用等接口。
IInterface
它定義在frameworks/native/include/binder/IInterface.h中。和RefBase類似,它也是一個公共父類,IInterface中聲明了asBinder()方法,用于獲取對象的IBinder對象。
IBinder
它定義在frameworks/native/include/binder/IBinder.h中。IBinder也是一個抽象出來的類,它包括了localBinder(), remoteBinder()和transact()等非常重要的接口。IBinder有兩個直接子類類:BpBinder和BBinder。
BpBinder
BpBinder是Binder代理類。通過remoteBinder()可以獲取BpBinder對象;而且,對于C++層而言,它相當(dāng)于一個遠程Binder。BpBinder的事務(wù)接口transact()會調(diào)用IPCThreadState的transact(),進而實現(xiàn)與Binder驅(qū)動的事務(wù)交互。此外,BpBinder中有一個mHandle句柄成員,它用來保存Server位于Binder驅(qū)動中的”Binder引用的描述”。句柄0是ServiceManager的句柄。
BBinder
BBinder是本地Binder。通過localBinder()可以獲取BBinder對象。當(dāng)Server收到請求之后,會調(diào)用BBinder的onTransact()函數(shù)進行處理。而不同的Server會重載onTransact()函數(shù),從而可以根據(jù)各自的情況對事務(wù)進行處理。
BpInterface
它定義在frameworks/native/include/binder/IInterface.h中。實際上,BpInterface是一個模板類,同時繼承了BpRefBase和INTERFACE,這里的INTERFACE是模板。像IServiceManager,IMediaPlayerService等Server都是通過繼承模板類是實現(xiàn)的。
BnInterface
它定義在frameworks/native/include/binder/IInterface.h中。和BpInterface類似,BnInterface也是一個模板類,它同時繼承了BBinder和INTERFACE。像BnServiceManager,BnMediaPlayerService等本地Server都是通過繼承模板類是實現(xiàn)的。
BpRefBase
它定義在frameworks/native/include/binder/Binder.h中。BpRefBase繼承于RefBase,它有一個IBinder*類型的成員mRemote,同時提供了獲取該mRemote的方法。實際上,該mRemote就是BpBinder對象。
ProcessState
它定義在frameworks/native/libs/binder/ProcessState.cpp中中。ProcessState的實例是采用單例模式實現(xiàn)的,它擁有兩個非常重要的成員:mDriverFD和mHandleToObject。
mDriverFD是文件”/dev/binder”的句柄,而mHandleToObject是一個Vector矢量數(shù)組,矢量數(shù)組中的每個元素都保存了兩個變量:Server的句柄,以及Server對應(yīng)的BpBinder對象。實際上,Server的句柄是”Server在Binder驅(qū)動中的Binder引用的描述”;句柄0是ServiceManager的句柄。
IPCThreadState
它定義在frameworks/native/libs/binder/IPCThreadState.cpp中中。IPCThreadState的實例也是采用單例模式實現(xiàn)的,它是正在與Binder驅(qū)動進行交互的類。
對于一個Server而言,它都會存在一個”遠程BpBinder對象”和”本地BBinder對象”。
- 遠程BpBinder對象的作用是和Binder驅(qū)動進行交互。具體的方式是,當(dāng)Server要向Binder發(fā)起事務(wù)請求時,會調(diào)用BpBinder的transact()接口,而該接口會調(diào)用到IPCThreadState::transact()接口,通過IPCThreadState類來和Binder驅(qū)動交互。此外,該BpBinder在Binder驅(qū)動中的Binder引用的描述會被保存到ProcessState的mHandleToObject矢量緩沖數(shù)組中。
- 本地BBinder對象的作用,是Server響應(yīng)Client請求的類。當(dāng)Client有請求發(fā)送給Server時,都會調(diào)用到BBinder的onTransact()函數(shù),而每個Server都會覆蓋onTransact()函數(shù)。這樣,每個Server就可以在onTransact()中根據(jù)自己的情況對請求進行處理。
gDefaultServiceManager實際返回的是一個BpServiceManager對象,該對象包含IBinder的代理BpBinder,和Binder驅(qū)動進行交互。
注冊Server到ServiceManager中
客戶端:
getIServiceManager().addService(name, service, false)
ServiceManagerNative.asInterface(BinderInternal.getContextObject())
- BinderInternal.getContextObject(): new ServiceManagerProxy(new BinderProxy()),創(chuàng)建一個BpBinder并且和BinderProxy 綁定,并返回BinderProxy 對象
- ServiceManagerNative.asInterface:返回 ServiceManagerProxy,此時ServiceManagerProxy持有BinderProxy
addService
- 將服務(wù)service 放入 data中
- mRemote.transact 相當(dāng)于BinderProxy的transact ,調(diào)用writeTransactionData給驅(qū)動寫入BC_TRANSACTION
- waitForResponse:數(shù)據(jù)拷貝數(shù)據(jù)到驅(qū)動,就也是映射到了一個物理空間,然后記錄客戶端的寫入命令BR_TRANSACTION_COMPLETE,客戶端掛起,發(fā)送BINDER_WORK_TRANSACTION給ServiceManager,調(diào)用wake_up_interruptible 喚醒ServiceManager
ServiceManager
- 處理客戶端的BINDER_WORK_TRANSACTION ,然后給服務(wù)端寫入BR_TRANSACTION命令
- 用 svclist 保存所有服務(wù)的。接著記錄服務(wù)端的命令為BC_REPLAY,記錄任務(wù),然后寫入ServiceManager的命令為BINDER_WORK_TRANSACTION_COMPLETE,ServiceManager掛起,調(diào)用wake_up_interruptible(target_wait)喚醒客戶端
客戶端被喚醒
- 處理BINDER_WORK_TRANSACTION 命令,然后寫入BR_REPLY給驅(qū)動
Aidl工作過程
AIDL文件會在開發(fā)工具在編譯的時候生成一個文件,那么這個文件就是Binder通信在應(yīng)用層的實現(xiàn)。我們具體梳理流程如下:
生成的文件類解析:
Sub抽象類繼承Binder,空實現(xiàn)通信接口,并持有服務(wù)的Token,重載onTransact方法處理客戶端傳入的數(shù)據(jù),并且給reply賦值
通信接口的實現(xiàn)類也就是代理類Proxy,在構(gòu)造中接受一個IBInder對象即remote,在方法實現(xiàn)中打包通信的數(shù)據(jù),使用remote的transact方法提交數(shù)據(jù)
transact之后,一般都是同步將會掛起
通信過程:
服務(wù)端定義一個Server,在服務(wù)綁定成功后,onBind回調(diào)中返回一個繼承自Binder的Sub實例
客戶端綁定服務(wù)成功的時候創(chuàng)建Proxy實例,并將服務(wù)下發(fā)的IBinder實例給了Proxy,客戶端使用Proxy調(diào)用接口,進入對應(yīng)的方法,實現(xiàn)數(shù)據(jù)的封裝打包,然后使用IBinder實例調(diào)用transact
之后進入native和kernel進行內(nèi)存映射
之后ServiceManager會調(diào)用Server服務(wù)端的onTransact方法,就是繼承Binder的Sub類中,在onTransact中接受到客戶端傳入的數(shù)據(jù),然后將數(shù)據(jù)下發(fā)到具體的實現(xiàn)類,也就是Server中的Sub的實現(xiàn)類中
參考文章:
https://segmentfault.com/a/1190000018317841?utm_source=tag-newest
https://blog.csdn.net/crs0313/article/details/81737242?spm=1001.2014.3001.5501
https://blog.csdn.net/crs0313/article/details/81737323?spm=1001.2014.3001.5501
https://blog.csdn.net/crs0313/article/details/81737408?spm=1001.2014.3001.5501
https://blog.csdn.net/crs0313/article/details/81737478?spm=1001.2014.3001.5501