Android系列-Binder機(jī)制

Binder 通信架構(gòu)簡介

Binder 采用 C/S 架構(gòu),是 Android 提供的一種通信機(jī)制,通過 ServiceManager 集中管理系統(tǒng)中的有名服務(wù)。

使用服務(wù)的大致過程:

  1. Server 端首先向 ServiceManager 注冊服務(wù)以便 Client 可以使用(此時(shí) ServerClient 端, ServiceManager 是服務(wù)端)
  2. ClientServiceManager 請求它要使用的服務(wù)(此時(shí) ClientClient 端, ServiceManager 是服務(wù)端)。
  3. Client 根據(jù)得到的 Service 信息,和 Server 進(jìn)行通信(此時(shí) ClientClient 端, Server 是服務(wù)端)。

以上三步均通過 Binder 通信機(jī)制實(shí)現(xiàn),只是封裝的層次可能有所不同,理解其中任意即可知道其它。

如圖:

binder_arch.png

通信過程

這里先以 MediaServerServiceManager 注冊 MediaPlayerService 服務(wù)為例,進(jìn)行其流程的大致描述,每步后面都會(huì)對其中一些難以理解的地方進(jìn)一步說明。

注: MediaPlayerService 只是 MediaServerserviceManager 注冊的眾多服務(wù)之一。

serviceManager 啟動(dòng)

注冊服務(wù)前首先要啟動(dòng)好 serviceManager 服務(wù)程序,該程序是掌管服務(wù)的服總控管理服務(wù)程序,比較特殊,它的啟動(dòng)沒有使用 Android 的封裝機(jī)制而是直接和 binder 交互。

大致過程就是:

  1. 設(shè)置自己的 handle ,該 handle 為宏值 BINDER_SERVICE_MANAGER ,用來標(biāo)示 serviceManager 服務(wù)程序,也就是其它程序請求服務(wù)時(shí)的目的端。
  2. 打開 binder 設(shè)備映射 binder 所需緩存
  3. 通過 binderioctl 命令設(shè)置自身為 serviceManager ,整個(gè)系統(tǒng)中只有一個(gè) serviceManager 。
  4. 進(jìn)入消息循環(huán),根據(jù) handle 判斷消息目標(biāo),如果是自身的 handle ,則處理接收到的消息。

注:其它服務(wù)程序的啟動(dòng)一般使用 android 的封裝機(jī)制,后面講述服務(wù)啟動(dòng)的時(shí)候會(huì)講述利用 android 封裝機(jī)制如何啟動(dòng)一個(gè)普通的服務(wù)。

MediaServerserviceManager 注冊 MediaPlayerService 服務(wù)

1、業(yè)務(wù)層實(shí)現(xiàn)

打包數(shù)據(jù),即將標(biāo)示“注冊服務(wù)”的 AddService 關(guān)鍵字打包,至此業(yè)務(wù)層內(nèi)容完畢,余下的交由通信層處理。

注: Android 將通信和處理過程通過其封裝機(jī)制,劃分為“業(yè)務(wù)層”和“通信層”兩個(gè)部分(這點(diǎn)至關(guān)重要?。?。

  • “業(yè)務(wù)層”專注對業(yè)務(wù)流程的處理,依據(jù)不同的應(yīng)用功能而不同;
  • “通信層”專注對消息通信的處理,采用 Binder 機(jī)制實(shí)現(xiàn),這也意味著也可用其它的通信機(jī)制實(shí)現(xiàn)此部分的功能例如“socket”、“管道”等。

2、通信層實(shí)現(xiàn)層次1- BpBinder 代理類的處理

通信層可借助 BpBinder 這個(gè)工具類來實(shí)現(xiàn),通過 BpBinderTransact 函數(shù)最終傳遞數(shù)據(jù)給 ServerManager 處理。 BpBinder 通過“人手一份”的 IPCThreadState ,以線程局部變量的方式,將 BpBinder 自身、 BBinder 對應(yīng)的 handler 與數(shù)據(jù)等信息交由其 transact 函數(shù)處理。

注: BpBinderBBinder 都是 Android 中與 binder 通信的代表,它們都繼承自 IBinder 類。 BpBinder 是客戶端和服務(wù)端交互的代理類, pproxy 的意思; BBinder 則是與 BpBinder 相對的一端,是 proxy 的目的端。兩者一個(gè)是客戶端,一個(gè)是服務(wù)端,并且一一對應(yīng),和 BpBinder 對應(yīng)的 BBbinder 用一個(gè) Bpbinderhandler 成員( mHandler )來索引到。

3、通信層實(shí)現(xiàn)層次2- 和驅(qū)動(dòng)的交互

IPCThreadState 對象包含:

  • mIn ,包含用于接收數(shù)據(jù)的緩存和操作。
  • mOut ,包含用于發(fā)送數(shù)據(jù)的緩存和操作。
  • mProcess ,包含 binder 通信所需的具體文件描述符內(nèi)存

IPCThreadStatetransact 函數(shù)首先將數(shù)據(jù)發(fā)送至其 mOut 成員中,然后通過 talkWithDriver 函數(shù)與 binder 驅(qū)動(dòng)交互(即發(fā)送請求到 binder 設(shè)備并接收回復(fù)到 mIn 中)后,從 mIn 中取出相應(yīng)的回復(fù)信息,并調(diào)用 executeCommand 函數(shù)進(jìn)行進(jìn)一步的處理。

注: talkWithDriver 中,通過 ioctl 的方式與驅(qū)動(dòng)交互。這里使用 BINDER_WRITE_READ 命令將 mOut 的數(shù)據(jù)發(fā)送給 driver ,然后接收消息到 mIn 中。(這里,我們需要注意,一般在處理不同命令的分支中,發(fā)送給設(shè)備驅(qū)動(dòng)的分支命令碼是 BC_XXX ,設(shè)備回復(fù)的命令碼是 BR_XXX

4、通信層實(shí)現(xiàn)層次3- BBinder 的處理

executeCommand 函數(shù)中,借助回復(fù)得到的 BBinder 這個(gè)工具類對象,調(diào)用其 transact 函數(shù)進(jìn)行處理(若 server 死掉,則由 BpBinder 處理)。

注:此時(shí)客戶端接收回復(fù),相當(dāng)于服務(wù)器的“服務(wù)端”,這個(gè) BBinder 也是客戶端做為服務(wù)服務(wù)端的代表,具體這個(gè) BBinder 的處理情況,可參考后面服務(wù)端的處理過程。

5、通信層實(shí)現(xiàn)層次4- 服務(wù)端的工作

客戶端程序發(fā)送信息后,服務(wù)端在接收消息循環(huán)中接收到消息并開始處理。這里因?yàn)槭窍?ServerManager 發(fā)送注冊服務(wù)請求,而 ServerManager 這個(gè)服務(wù)程序比較特殊,沒有使用 BBinderBnXXX 之類的封裝工具接口,它是直接使用操作 binder 提供的相關(guān)接口完成這個(gè)過程的。

至此,我們分兩種方式講解此處內(nèi)容:

5.1、在 ServerManager 中實(shí)際的處理

直接在其循環(huán)中調(diào)用 binderioctl 接口接收到消息,然后再進(jìn)行相關(guān)處理,再通過 binderioctl 接口回復(fù)消息給請求方。

5.2、正常 Server 程序的處理

一般 Server 都至少有一個(gè)線程處于接收消息的循環(huán)中,假設(shè)其中一個(gè)線程接收到客戶端發(fā)送來的消息,最終會(huì)調(diào)用到 executeCommand 函數(shù)進(jìn)一步處理。
處理過程如前所述:

  1. 從接收到的消息中,取得代表自己的 BBinder 對象,
  2. 進(jìn)入 BBinder::transact 函數(shù),
  3. 再調(diào)用 onTransact 處理通信的內(nèi)容,
  4. onTransact 中調(diào)用業(yè)務(wù)函數(shù)處理業(yè)務(wù)邏輯的內(nèi)容。

注:這里調(diào)用的 BBinder::onTransact ,其實(shí)指向的是其子類對象的函數(shù),即 BnXXX ;而其中調(diào)用的業(yè)務(wù)函數(shù),也是其子類對象自己實(shí)現(xiàn)的函數(shù),即 XXXService 。具體是什么子類,依據(jù)服務(wù)有所不同,以剛剛注冊的 MediaPlayerService 為例,其它類似,涉及的相關(guān)類如下圖:

mediaplayerservice.png

我們實(shí)現(xiàn) MediaPlayerService 的業(yè)務(wù)功能(如 createMediaRecorder )時(shí),就實(shí)現(xiàn) MediaPlayerService 子類的函數(shù)。處理通信信息時(shí)(如根據(jù)不同類型的信息,調(diào)用不同的業(yè)務(wù)函數(shù)),實(shí)現(xiàn) BnMediaPlayerService 子類的函數(shù)。

服務(wù)端啟動(dòng)

前面講述的服務(wù)注冊過程只是服務(wù)程序啟動(dòng)的一個(gè)階段,這個(gè)階段服務(wù)程序做為 serviceManager 的客戶端,向 serviceManager 程序請求注冊服務(wù)。當(dāng)注冊完服務(wù)后,服務(wù)程序本身便可做為服務(wù)端,進(jìn)入自己的消息循環(huán),接收客戶端的請求,和 serviceManager 不同的是, serviceManager 啟動(dòng)時(shí)直接與 binder 交互,而一般服務(wù)端通過 android 封裝的機(jī)制來啟動(dòng)。

這里還是以 MediaServer 的啟動(dòng)為例,介紹啟動(dòng)的大致過程:

1、獲得 ProcessState 單實(shí)例對象

每個(gè)進(jìn)程啟動(dòng)時(shí),都通過單實(shí)例方式創(chuàng)建一個(gè)唯一的 ProcessState ,它主要打開 binder 設(shè)備文件,以及通過 mmap 映射好通信所需的內(nèi)存地址,相關(guān)信息在其成員中保存。后面使用 binder 通信時(shí),最終會(huì)用到這里的內(nèi)容。

2、獲得 IServiceManager 單實(shí)例對象以便和 serviceManager 進(jìn)程交互

這里通過 defaultServiceManager 函數(shù),以單實(shí)例方式進(jìn)行。

  1. 首先創(chuàng)建 BpBinder 對象,該對象由 serviceManager 對應(yīng)的 handle 初始化,完成通信層功能;
  2. 然后通過該 BpBinder ,轉(zhuǎn)換生成 IServiceManager 對象(其實(shí)是子類 BpServerManager 對象),完成業(yè)務(wù)層功能;
  3. BpBinder 對象做為 IServiceManager 對象的成員存在,以這種方式將業(yè)務(wù)層和通信層相關(guān)聯(lián)。

交互實(shí)現(xiàn)的關(guān)鍵

  1. 通信層、業(yè)務(wù)層、通信業(yè)務(wù)關(guān)聯(lián)

    • 通信層相關(guān)內(nèi)容

      根據(jù)前面, serviceManagerhandleBINDER_SERVICE_MANAGER ,一般就是0,這個(gè)為系統(tǒng)所周知。借助該 handle 做為成員構(gòu)成的 BpBinder 代理對象,來向 serviceManager 發(fā)送消息協(xié)助完成通信層的功能。服務(wù)端會(huì)通過接受到消息中的 handle 比對,判斷出是否為發(fā)送給自己的消息。

    • 業(yè)務(wù)層相關(guān)內(nèi)容

      生成的 BpBinder 對象,會(huì)最終通過 interface_cast ,轉(zhuǎn)換成 IServiceManager 對象,完成 serviceManager 應(yīng)用程序?qū)?yīng)的業(yè)務(wù)功能(如: getService 、 addService 等)。

    • 通信層和業(yè)務(wù)層的關(guān)聯(lián)

      是利用 BpBinder 創(chuàng)建 BpServiceManager 對象,使用 BpBinder 是通過 BpServiceManager 對象的 mRemote 成員來做到的。

    期間所涉及的類關(guān)系如下:

iservice_manager.png
  1. 實(shí)現(xiàn)通信層、業(yè)務(wù)層類的關(guān)系

    對于前面的類圖,我們還是從“業(yè)務(wù)層”和“通信層”兩個(gè)方面來看。

    • 業(yè)務(wù)層

      BpServiceManager 、 BnServiceManager 都繼承自 IServiceManager ,通過 IServiceManager 完成業(yè)務(wù)邏輯功能,通過其子類實(shí)現(xiàn)業(yè)務(wù)邏輯,其中 BnServiceManager 的功能需要又由子類 MyServiceManager 來實(shí)現(xiàn)。

    • 通信層

      通過 IBinder 完成通信相關(guān)邏輯,具體實(shí)現(xiàn)由其子類: BpBinder 完成客戶代理功能, BBinder 完成服務(wù)端功能。而實(shí)現(xiàn)又是借助于封裝的 BpServiceManagerBnServiceManager 完成的。 BnServiceManager 繼承自 BBinder ;而 BpServiceManager 通過父類 BpInterface 的父類 BpRefBasemRemote 成員,與 BpBinder 對象關(guān)聯(lián)。

    1. 總結(jié)

      結(jié)合前面描述“正常 server 程序的處理”中的“ MediaPlayerService 家譜”圖,我們可大致理清 Android 封裝機(jī)制對“業(yè)務(wù)層”和“通信層”的封裝機(jī)制。而兩者間的關(guān)聯(lián),正是 BnServerXXXBpServiceXXX 即能涉及業(yè)務(wù)相關(guān)的內(nèi)容,也能涉及通信相關(guān)內(nèi)容的原因。

bp_bn_layer.png
    服務(wù)端啟動(dòng)后,與客戶端的交互過程,與服務(wù)程序本身做為客戶端向 `serviceManager` 注冊服務(wù)的過程類似,參見后面講述“客戶端和服務(wù)端交互”時(shí)的內(nèi)容。這里著重講述 `Android` 系統(tǒng)中,大部分服務(wù)程序是如何利用 `Android` 的封裝機(jī)制實(shí)現(xiàn)啟動(dòng),以便后續(xù)的客戶端能向注冊服務(wù)一般向該服務(wù)程序請求服務(wù)的。

3、向 serviceManager 注冊各類服務(wù)

前面注冊的 MediaPlayerService ,只是 MediaServer 的眾服務(wù)之一,它使用 MediaPlayerService::instantiate 函數(shù),調(diào)用通過 defaultServiceManager 函數(shù)返回的 IServiceManageraddService 業(yè)務(wù)接口實(shí)現(xiàn)。

注冊期間 MediaServer 做為 serviceManager 的客戶端,向 serviceManager 程序請求注冊服務(wù);其它服務(wù)的注冊類似,其詳細(xì)過程參考前面講述的 “ MediaServerserviceManager 注冊 MediaPlayerService 服務(wù)” 相關(guān)內(nèi)容。

4、服務(wù)端進(jìn)入自己的消息循環(huán)

通過 StartThreadPoolJoinThreadPool 實(shí)現(xiàn)。

啟動(dòng)的這些線程,進(jìn)入消息循環(huán)統(tǒng)一為前面各類服務(wù)工作。如果任務(wù)不繁重,可以不用 StartThreadPool ,使用主線程即可。

客戶端和服務(wù)端交互

這里,以客戶端與MediaPlayerService服務(wù)的交互為例

1、客戶端向 ServiceManager 查詢 MediaPlayerService 服務(wù)

  1. 首先客戶端通過 defaultServiceManage 函數(shù)獲取到代表 serviceManageIServiceManager 接口;
  2. 然后通過 IServerManagergetService 業(yè)務(wù)接口,獲取到 MediaPlayerServiceBpBinder ;
  3. 最后將獲取的 BpBinder 通過 interface_cast 轉(zhuǎn)換成 IMediaPlayerService 接口,做為獲取的結(jié)果。

2、客戶端向服務(wù)端發(fā)送服務(wù)請求

ImediaPlayerService 接口包含了 MediaPlayerService 可提供的各種業(yè)務(wù)接口函數(shù)供客戶端使用,大致過程是:

  1. 客戶端的業(yè)務(wù)層( BpMediaPlayerService 相關(guān))打包數(shù)據(jù)遞交給通信層;
  2. 客戶端通信層( BpBinder 相關(guān))將數(shù)據(jù)發(fā)送給 Binder 驅(qū)動(dòng)。

這里客戶端發(fā)送數(shù)據(jù)時(shí)涉及到從業(yè)務(wù)層到通信層的過程(類似數(shù)據(jù)打包),之后我們可以看到,通過 Binder 驅(qū)動(dòng),在服務(wù)端接收數(shù)據(jù)時(shí)會(huì)經(jīng)歷從通信層到業(yè)務(wù)層的過程(類似數(shù)據(jù)解包)。

注:這些業(yè)務(wù)接口目前還是在客戶端被調(diào)用,實(shí)際調(diào)用的是子類 BpMediaPlayerService ,這是一個(gè)代理接口,客戶端通過繼承自 IMediaPlayerServiceBpMediaPlayerService 代理接口來調(diào)用各種業(yè)務(wù)接口請求服務(wù)端的服務(wù),在代理接口的業(yè)務(wù)函數(shù)中將封裝好的信息借助其通信層的代理 BpBinder 類發(fā)送給內(nèi)核 Binder 設(shè)備的驅(qū)動(dòng),之后的過程在服務(wù)端的處理中可以看到。

3、服務(wù)端處理收到的客戶端請求

這里的內(nèi)容在前面講述注冊服務(wù)過程時(shí)的 “正常 Server 程序的處理” 中已經(jīng)詳細(xì)講述,可參考相關(guān)內(nèi)容。

大致過程是:

  1. 服務(wù)端的通信層接收到請求( BBinder 相關(guān));
  2. 遞交給服務(wù)端的業(yè)務(wù)層處理( BnMediaPlayerService 相關(guān))。

這里,服務(wù)端通過調(diào)用同樣繼承自 IMediaPlayerServiceBnMediaplayerService 業(yè)務(wù)接口,來實(shí)現(xiàn)客戶端用 BpMediaPlayerService 業(yè)務(wù)接口中的對應(yīng)的各種業(yè)務(wù)接口,客戶端調(diào)用時(shí)采用的是代理接口的業(yè)務(wù)函數(shù),和服務(wù)端服務(wù)時(shí)對應(yīng)的真正實(shí)現(xiàn)的業(yè)務(wù)函數(shù),因?yàn)閬碜酝桓割?,一般都是相同的函?shù)簽名。

注:
Binder 驅(qū)動(dòng)通過客戶端通過 BpBinder 發(fā)送來的 handle 找到在驅(qū)動(dòng)中對應(yīng)的 Server 端通信層的 BBinder ,將數(shù)據(jù)傳送到服務(wù)端的業(yè)務(wù)層,在服務(wù)端有一個(gè)和 BpMediaPlayerService 繼承自同一個(gè)父類的 BnMediaPlayerservice 接口,其中的業(yè)務(wù)函數(shù)才是真正的業(yè)務(wù)實(shí)現(xiàn),該業(yè)務(wù)接口的業(yè)務(wù)函數(shù)收到 BBinder 通信端傳上來的信息后,調(diào)用相應(yīng)的真正實(shí)現(xiàn)了的業(yè)務(wù)函數(shù)進(jìn)行業(yè)務(wù)處理。

其他

參考資料:

  • 《深入理解Android 卷I》
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容