Android10.0 Binder通信原理(十一)-Binder總結

摘要:本節主要來講解Android10.0 Binder的通信原理總結

閱讀本文大約需要花費17分鐘。

文章首發微信公衆號:IngresGe

專注於Android系統級源碼分析,Android的平臺設計,歡迎關注我,謝謝!

[Android取經之路] 的源碼都基於Android-Q(10.0) 進行分析

[Android取經之路] 系列文章:

《系統啓動篇》

  1. Android系統架構
  2. Android是怎麼啓動的
  3. Android 10.0系統啓動之init進程
  4. Android10.0系統啓動之Zygote進程
  5. Android 10.0 系統啓動之SystemServer進程
  6. Android 10.0 系統服務之ActivityMnagerService
  7. Android10.0系統啓動之Launcher(桌面)啓動流程
  8. Android10.0應用進程創建過程以及Zygote的fork流程
  9. Android 10.0 PackageManagerService(一)工作原理及啓動流程
  10. Android 10.0 PackageManagerService(二)權限掃描
  11. Android 10.0 PackageManagerService(三)APK掃描
  12. Android 10.0 PackageManagerService(四)APK安裝流程

《日誌系統篇》

  1. Android10.0 日誌系統分析(一)-logd、logcat 指令說明、分類和屬性
  2. Android10.0 日誌系統分析(二)-logd、logcat架構分析及日誌系統初始化
  3. Android10.0 日誌系統分析(三)-logd、logcat讀寫日誌源碼分析
  4. Android10.0 日誌系統分析(四)-selinux、kernel日誌在logd中的實現​

《Binder通信原理》

  1. Android10.0 Binder通信原理(一)Binder、HwBinder、VndBinder概要
  2. Android10.0 Binder通信原理(二)-Binder入門篇
  3. Android10.0 Binder通信原理(三)-ServiceManager篇
  4. Android10.0 Binder通信原理(四)-Native-C\C++實例分析
  5. Android10.0 Binder通信原理(五)-Binder驅動分析
  6. Android10.0 Binder通信原理(六)-Binder數據如何完成定向打擊
  7. Android10.0 Binder通信原理(七)-Framework binder示例
  8. Android10.0 Binder通信原理(八)-Framework層分析
  9. Android10.0 Binder通信原理(九)-AIDL Binder示例
  10. Android10.0 Binder通信原理(十)-AIDL原理分析-Proxy-Stub設計模式
  11. Android10.0 Binder通信原理(十一)-Binder總結

1.概述

 Binder的通信原理基本上都已經說完,這一節我們做一個簡單的概要總結。

 

 

2.Binder通信模型

下圖中涉及到Binder模型的4類角色:Binder驅動,ServiceManager,Server和Client。Binder機制的目的是實現IPC(Inter-Process Communication),即Client和Server之間的通信。

其中Server,Client,ServiceManager運行於用戶空間,Binder驅動運行於內核空間。這四個角色的關係和互聯網類似:Server是服務器,Client是客戶終端,ServiceManager是域名服務器(DNS),驅動是路由器。

 

3.Binder的架構

 

4.Binder的通信原理

Binder 通信採用 C/S 架構,從組件視角來說,包含 Client、 Server、 ServiceManager 以及 Binder 驅動,其中 ServiceManager 用於管理系統中的各種服務。

Binder 在 framework 層進行了封裝,通過 JNI 技術調用 Native(C/C++)層的 Binder 架構。

Binder 在 Native 層以 ioctl 的方式與 Binder 驅動通訊。

       

Binder通信流程如下

  1. 首先服務端需要向ServiceManager進行服務註冊,ServiceManager有一個全局的service列表svcinfo,用來緩存所有服務的handler和name。
  2. 客戶端與服務端通信,需要拿到服務端的對象,由於進程隔離,客戶端拿到的其實是服務端的代理,也可以理解爲引用。客戶端通過ServiceManager從svcinfo中查找服務,ServiceManager返回服務的代理。
  3. 拿到服務對象後,我們需要向服務發送請求,實現我們需要的功能。通過 BinderProxy 將我們的請求參數發送給 內核,通過共享內存的方式使用內核方法 copy_from_user() 將我們的參數先拷貝到內核空間,這時我們的客戶端進入等待狀態。然後 Binder 驅動向服務端的 todo 隊列裏面插入一條事務,執行完之後把執行結果通過 copy_to_user() 將內核的結果拷貝到用戶空間(這裏只是執行了拷貝命令,並沒有拷貝數據,binder只進行一次拷貝),喚醒等待的客戶端並把結果響應回來,這樣就完成了一次通訊。

在這裏其實會存在一個問題,Client和Server之間通信是稱爲進程間通信,使用了Binder機制,那麼Server和ServiceManager之間通信也叫進程間通信,Client和Server之間還會用到ServiceManager,也就是說Binder進程間通信通過Binder進程間通信來完成,這就好比是 孵出雞前提卻是要找只雞來孵蛋,這是怎麼實現的呢?

Binder的實現比較巧妙:預先創造一隻雞來孵蛋:ServiceManager和其它進程同樣採用Binder通信,ServiceManager是Server端,有自己的Binder對象(實體),其它進程都是Client,需要通過這個Binder的引用來實現Binder的註冊,查詢和獲取。

ServiceManager提供的Binder比較特殊,它沒有名字也不需要註冊,當一個進程使用BINDER_SET_CONTEXT_MGR_EXT命令將自己註冊成ServiceManager時Binder驅動會自動爲它創建Binder實體(這就是那隻預先造好的雞)。

其次這個Binder的引用在所有Client中都固定爲0(handle=0)而無須通過其它手段獲得。也就是說,一個Server若要向ServiceManager註冊自己Binder就必須通過0這個引用號和ServiceManager的Binder通信。

類比網絡通信,0號引用就好比域名服務器的地址,你必須預先手工或動態配置好。要注意這裏說的Client是相對ServiceManager而言的,一個應用程序可能是個提供服務的Server,但對ServiceManager來說它仍然是個Client。

 

圖片來源csdn-jeanboydev

5 Binder傳輸過程

Binder-IPC機制,就是指在進程間傳輸數據(binder_transaction_data),一次數據的傳輸,稱爲事務(binder_transaction)。

對於多個不同進程向同一個進程發送事務時,這個同一個進程或線程的事務需要串行執行,在Binder驅動中爲binder_proc和binder_thread都有todo隊列。

也就是說對於進程間的通信,就是發送端把binder_transaction節點,插入到目標進程或其子線程的todo隊列中,等目標進程或線程不斷循環地從todo隊列中取出數據並進行相應的操作。

在Binder驅動層,每個接收端進程都有一個todo隊列,用於保存發送端進程發送過來的binder請求,這類請求可以由接收端進程的任意一個空閒的binder線程處理。

接收端進程存在一個或多個binder線程,在每個binder線程裏都有一個todo隊列,也是用於保存發送端進程發送過來的binder請求,這類請求只能由當前binder線程來處理。

binder線程在空閒時進入可中斷的休眠狀態,當自己的todo隊列或所屬進程的todo隊列有新的請求到來時便會喚醒,如果是由所需進程喚醒的,那麼進程會讓其中一個線程處理響應的請求,其他線程再次進入休眠狀態。

 

6 Binder協議的演變

下面展示了Binder協議碼的演變過程,在Android9.0之前,當client向Binder驅動發送BC_TRANSACTION,Binder驅動喚醒Server進程時,會向client進程發送BR_TRANSACTION_COMPLETE,現在這一步被移到了 喚醒Client之後再做,減少了數據延遲。

Android9.0之前的協議碼流程:

Android9.0及之後的協議碼流程:

上面第5步的 BR_TRANSACTION_COMPLETE 被延遲到 第 10步 ,Android做了deferred_thread_work,延遲 TRANSACTION_COMPLETE,因此不會立即返回到用戶空間;這允許目標進程立即開始處理此事務,從而減少延遲。然後,當目標回覆(或出現錯誤)時,我們將返回TRANSACTION_COMPLETE。

7.AIDL的Proxy-Stub設計模式

AIDL的設計採用了Proxy-Stub(代理-存根) 的設計模式,Client拿到的是Proxy的Binder代理對象,Server拿到的是Stub的Binder服務實體,兩者之間的數據傳入通過Parcel進行扁平化傳輸。

Proxy將特殊性接口轉換成通用性接口,Stub將通用性接口轉換成特殊性接口,二者之間的數據轉換通過Parcel(打包)進行的,Proxy常作爲數據發送代理,通過Parcel將數據打包發送,Stub常作爲數據接收樁,解包並解析Parcel Data package。

 

Client和Server交互的簡單示意流程:

 

Binder通信的數據流轉如下圖所示:

AIDL的具體流程如下:

  1. Client和Server都使用同一個AIDL文件,包名相同,編譯後,兩邊都會生成IMyService.java,其中有Stub實體和Proxy代理兩個對象
  2. Server端通過AndroidManifest.xml 註冊Service
  3. Client通過bindService()獲得服務的代理Stub.Proxy()
  4. Client 調用AIDL的方法add(),其實調用的是IMyService.java中的Stub.Proxy.add(),最終通過BinderProxy.java的transact()向服務端發送
  5. 通過Binder驅動的流程,進入到服務端的onTransact(),根據Client發送的TRANSACTION code,解析進入相應的流程處理,進入add()
  6. MyService在被綁定時,有了實體IMyService.Stub,最終進入MyService.java的add()處理,完成接口調用,調用完成後把數據寫入Parcel,通過reply發送給Client

我的微信公衆號:IngresGe

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章