Android Binder框架不談代碼

下面是本身分析 Android 的Binder代碼時,總結出的框架,有什麼不妥,敬請諒解,請以斧正!編程

咱們講解的思路是:讓本身開發一個Binder框架,應該如何實現?數組

在文章中,沒有談論任何的代碼,都是思路!例如,下面提到Client進程給Server進程發送 CMD_FUNC命令碼的時候,在Binder驅動中,須要特別定義該命令碼,例如:框架

#define CMD_FUNC IBinder::FIRST_CALL_TRANSACTION 1編程語言

還有BnXXX, BpXXX等 binder 類都不會討論!函數

咱們只是討論 Binder 框架的設計思路,那麼,有了這個思路,任何編程語言均可以實現一個Binder框架!設計

1 從Binder框架的思路出發3d

       假設要咱們開發一個Binder框架,咱們應該怎麼樣實現?首先,要明確Binder框架,要實現什麼功能,明確功能的定義,而後,再設計該Binder框架!調試

       那麼,如今,咱們就定Binder的功能:server

1 進程間通訊;對象

2遠程調用其餘服務;

       那麼,要實現這樣的功能,咱們要怎麼樣設計本身的 Binder框架?

下面是本身分析Android的Binder框架,給出的框架圖!

       設計框架的時候,咱們應該從最頂層概況,明確:

1 該框架服務哪些對象?

2 服務的對象是什麼職能? 它們要完成怎麼樣的工做?

3 對象之間是怎麼樣聯繫?
1 總體框架圖

 

       那麼,根據這些疑問,本身總結了Android的Binder框架,給出以下的框架圖:


其中,能夠看到,涉及到以下的對象:

1 Client進程,做爲客戶端,請求service服務組件;

2 service服務組件,提供服務;

3 service_manager進程,管理service服務組件;

4 Binder驅動,負責對象之間的通訊;

5 binder對象列表,是Binder驅動中,維護的一個列表,存放全部使用當前驅動進行通訊的對象;

6 service註冊列表,是service_manager進程中,維護的一個列表,存放系統中,全部service組件的註冊信息;

       那麼,咱們在這個Binder框架中,就須要涉及這樣的 6個對象;那麼,每一個對象之間是怎麼樣工做的?下面,咱們以註冊一個service和請求一個service服務爲例子,分析每一個對象之間的工做狀態。
2 註冊一個service

       如今,咱們註冊一個service組件,看看Binder框架中,每一個對象之間是如何卸載。假設有一個service組件,咱們給它起一個名字:abc,而後,註冊到Android系統中。

       有以下的框架圖:


執行的流程以下:

1 server進程,建立service服務組件,把這個service服務組件的地址addr和名稱「abc」發送給Binder驅動;

2 Binder驅動收到service服務組件的地址addr,封裝成一個binder對象,存放在binder對象列表中。

       其中,該binder對象存放在binder對象列表中,是一個數組,它所在的位置是「下標 = 1」;

因此,設置 int handle = 1; 那麼,根據這個 handle = 1 的數值,做爲 binder對象列表數組的下標,就能夠找到 service 服務組件對應的 binder 對象;

3 Binder驅動把service服務組件存放在binder對象列表中的位置:handle = 1 和 它的名稱 abc 發送給service_manager進程;

4 service_manager進程接收到 handle = 1和name = abc 這樣的數據,而後,存放到service註冊列表中;

5 這樣,service組件的註冊就完成了,有:

(1) 在 Binder驅動中,存放service組件對象的地址,構造的 binder 對象;

(2) 在service_manager進程中,存放了service組件對象在Binder驅動中存放的位置handle值和它的名稱abc。

       此時,咱們隱約地感受到,service_manager就是存放一個handle和name的鍵值對。當client想請求一個service組件的時候,須要在 service_manager中找到name對應的handle值,而後,Binder驅動根據handle值,在binder對象列表中找到service組件對應的binder對象。最終,就找到了該service組件。
3 獲取一個service

       通過上面的分析,咱們在系統在註冊了一個service組件,名稱是abc;那麼,如今咱們就在一個Client進程中,獲取該 abc 服務組件。

       有以下的框架圖:

有以下的執行流程:

1 Client向Binder請求一個service組件,該組件的名稱是 abc;

因此,Client進程把組件名稱 abc 發送給Binder驅動,而後,Binder把Client進程掛起等待;

2 Binder驅動把須要請求的 service名稱 abc 發送給service_manager進程;

3 service_manager進程收到一個查詢請求,須要查詢service的名稱是 abc,因此,到service註冊表中查找,找到名稱 abc 的元素,其 handle = 1;而後,把 handle = 1 返回給Binder驅動;

4 Binder驅動根據service_manager返回的 handle = 1 數值,做爲binder對象列表數組的下標,找到對應的binder對象;而後,返回給Client進程;喚醒Client進程;

5 Client進程獲得Binder驅動發送過來的binder對象引用,就是service組件的引用;那麼,能夠「間接」地操做service組件;
4 Client請求service服務

       通過上面分析,咱們讓Client進程獲得了一個service組件的引用,那麼,假設service組件提供一個 func() 函數,實現:

int func(int x,int y)

{

       return (x + y);

}

那麼,Client進程怎麼樣引用service服務提供的 func() 函數?

       那麼,能夠有以下的框架圖:

       如今,Client想引用service提供的 func() 接口服務,就能夠有以下的邏輯:

1 在client與service通訊的過程當中,咱們爲 func() 函數的調用,定義一個命令碼,假設爲:

#define CMD_FUNC 1

       那麼,client就能夠把 CMD_FUNC 命令碼發送給service組件,當service組件接收到CMD_FUNC命令的時候,就知道是調用 func() 函數。

       那麼,再解出須要處理的函數x, y值,就能夠丟給 func()函數處理;最後,service組件處理完 func() 函數以後以後,再把返回值傳遞給Client進程。

2 其實,Client和service之間進行通訊,傳遞的數據須要按照必定的「協議格式」來存放;這樣,傳遞的數據語義才明確。每一個對象才能夠按照協議格式,解出正確的數據。

       因此,咱們能夠總結以下的流程:

1 Client把CMD_FUNC這命令碼和x, y參數,封裝到一個數據包中,稱爲 pkg 數據包;

2 Client把 pkg 數據包發送給Binder驅動;

3 Binder驅動再把 pkg 數據包發送給 service 所在的server進程;

4 server進程接收到 pkg 數據包,解析數據,獲得 CMD_FUNC 命令碼,就指定是要調用 func() 函數;

因此,server進程再解析 x, y 參數,而後,調用 server 組件的 func() 函數來處理;

最終,獲得 (x + y) 這樣的結果值;

5 server 進程把 (x + y) 結果返回給Binder驅動;

6 Binder驅動再把 (x + y) 結果返回給 Client 進程;

       最終,Client 進程就可以獲得了server進程中,調用service組件的func()函數來處理的數據。

       在開發的過程當中,Client引用service組件的func()接口服務,如同直接調用 service組件對象。其實,這是一個「遠程調用」的思路。

       其實,Client並無直接調用service組件,而是把須要處理的x,y 參數,傳遞給Binder驅動,而後,Binder驅動再轉發給server進程;

       最終,由server進程來處理Client進程發送過來的x, y參數。


       因此,實際上,對x, y參數處理的過程,是在server進程中完成,不是在Client進程中完成。

       Client進程只是把參數發送給Binder驅動,而後,Binder驅動就把Client進程掛起等待,再把數據轉發給server進程處理。

       當server進程處理完以後,Binder再把返回結果告訴Client進程,而後,再喚醒Client進程。
5 總結

對於Android的Binder框架來講,它提供了一套完善的「進程通訊」機制,與普通的管道,消息隊列,共享內存不同;它還提供了「遠程調用」的功能。

例如,Client進程能夠調用Server進程提供的service服務組件。Client使用service組件提供的接口服務時,實際上,是由Server進程使用service組件來處理數據,處理完以後,再把處理結果返回給Client進程,因此,實現一個「遠程調用」的功能。

在該文件,只是提供一個大概的思路,不少細節仍是未提到!例如,Binder驅動在接收Client進程的請求時,應該阻塞掛起當前的進程,而後,把數據丟給Server進程,其中,會涉及到一個「todo」隊列,而後 Binder 驅動喚醒掛載在 todo 隊列上的進程,就是執行 Server 進程,處理 service 服務接口。

本身調試的一個 service, client 通訊的例子,是 C++ 版本,能夠手動調試,加深理解! ---------------------    

相關文章
相關標籤/搜索