Binder理解


native takepicture -> camera -> ICamera: class bpbinder: transact -> BpBinder: transact -> IPCThread: transact->IPCThread:writeTransactionData 寫到mout中,之后會waitForResponse()

IPCThread : joinThreadPool 為一個無限循環線程,循環中不斷調用 getandExecuteCommand(),

getandExecuteCommand() ->talkWithDriver():會從mIn中讀取數據,並將mOut中的數據通過ioctl寫入共享內存。

getandExecuteCommand() -> executeCommand():從mIn中讀取命令及數據,若為transact:reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer, &reply, tr.flags);

調用BBinder的transact()->BnCamera:BnInterface -> onTransact()

再調用到hal層的實現

 

從AMP.startService是如何通過Binder一步步調用進入到system_server進程的AMS.startService. 整個過程涉及Java framework, native, kernel driver各個層面知識:

 

從通信流程角度來看整個過程:binder_ipc_process

 

圖解:

 

  1. 發起端線程向Binder Driver發起binder ioctl請求后, 便采用環不斷talkWithDriver,此時該線程處於阻塞狀態, 直到收到如下BR_XXX命令才會結束該過程.
    • BR_TRANSACTION_COMPLETE: oneway模式下,收到該命令則退出
    • BR_REPLY: 非oneway模式下,收到該命令才退出;
    • BR_DEAD_REPLY: 目標進程/線程/binder實體為空, 以及釋放正在等待reply的binder thread或者binder buffer;
    • BR_FAILED_REPLY: 情況較多,比如非法handle, 錯誤事務棧, security, 內存不足, buffer不足, 數據拷貝失敗, 節點創建失敗, 各種不匹配等問題
    • BR_ACQUIRE_RESULT: 目前未使用的協議;
  2. 左圖中waitForResponse收到BR_TRANSACTION_COMPLETE,則直接退出循環, 則沒有機會執行executeCommand()方法, 故將其顏色畫為灰色. 除以上5種BR_XXX命令, 當收到其他BR命令,則都會執行executeCommand過程.
  3. 目標Binder線程創建后, 便進入joinThreadPool()方法, 采用循環不斷地循環執行getAndExecuteCommand()方法, 當bwr的讀寫buffer都沒有數據時,則阻塞在binder_thread_read的wait_event過程. 另外,正常情況下binder線程一旦創建則不會退出.

 

6.2 通信協議

 

從通信協議的角度來看這個過程:

 

binder_transaction

 

  • Binder客戶端或者服務端向Binder Driver發送的命令都是以BC_開頭,例如本文的BC_TRANSACTIONBC_REPLY, 所有Binder Driver向Binder客戶端或者服務端發送的命令則都是以BR_開頭, 例如本文中的BR_TRANSACTIONBR_REPLY.
  • 只有當BC_TRANSACTION或者BC_REPLY時, 才調用binder_transaction()來處理事務. 並且都會回應調用者一個BINDER_WORK_TRANSACTION_COMPLETE事務, 經過binder_thread_read()會轉變成BR_TRANSACTION_COMPLETE.
  • startService過程便是一個非oneway的過程, 那么oneway的通信過程如下所述.

 

6.3 說一說oneway

 

上圖是非oneway通信過程的協議圖, 下圖則是對於oneway場景下的通信協議圖:

 

binder_transaction_oneway

 

當收到BR_TRANSACTION_COMPLETE則程序返回,有人可能覺得好奇,為何oneway怎么還要等待回應消息? 我舉個例子,你就明白了.

 

你(app進程)要給遠方的家人(system_server進程)郵寄一封信(transaction), 你需要通過郵寄員(Binder Driver)來完成.整個過程如下:

 

  1. 你把信交給郵寄員(BC_TRANSACTION);
  2. 郵寄員收到信后, 填一張單子給你作為一份回執(BR_TRANSACTION_COMPLETE). 這樣你才放心知道郵遞員已確定接收信, 否則就這樣走了,信到底有沒有交到郵遞員手里都不知道,這樣的通信實在太讓人不省心, 長時間收不到遠方家人的回信, 無法得知是在路的中途信件丟失呢,還是壓根就沒有交到郵遞員的手里. 所以說oneway也得知道信是投遞狀態是否成功.
  3. 郵遞員利用交通工具(Binder Driver),將信交給了你的家人(BR_TRANSACTION);

 

當你收到回執(BR_TRANSACTION_COMPLETE)時心里也不期待家人回信, 那么這便是一次oneway的通信過程.

 

如果你希望家人回信, 那便是非oneway的過程,在上述步驟2后並不是直接返回,而是繼續等待着收到家人的回信, 經歷前3個步驟之后繼續執行:

 

  1. 家人收到信后, 立馬寫了個回信交給郵遞員BC_REPLY;
  2. 同樣,郵遞員要寫一個回執(BR_TRANSACTION_COMPLETE)給你家人;
  3. 郵遞員再次利用交通工具(Binder Driver), 將回信成功交到你的手上(BR_REPLY)

 

這便是一次完成的非oneway通信過程.

 

oneway與非oneway: 都是需要等待Binder Driver的回應消息BR_TRANSACTION_COMPLETE. 主要區別在於oneway的通信收到BR_TRANSACTION_COMPLETE則返回,而不會再等待BR_REPLY消息的到來. 另外,oneway的binder IPC則接收端無法獲取對方的pid.

 

總結

1. Binder概述

  1. 從IPC角度來說:Binder是Android中的一種跨進程通信方式,該通信方式在linux中沒有,是Android獨有;
  2. 從Android Driver層:Binder還可以理解為一種虛擬的物理設備,它的設備驅動是/dev/binder;
  3. 從Android Native層:Binder是創建Service Manager以及BpBinder/BBinder模型,搭建與binder驅動的橋梁;
  4. 從Android Framework層:Binder是各種Manager(ActivityManager、WindowManager等)和相應xxxManagerService的橋梁;
  5. 從Android APP層:Binder是客戶端和服務端進行通信的媒介,當bindService的時候,服務端會返回一個包含了服務端業務調用的 Binder對象,通過這個Binder對象,客戶端就可以獲取服務端提供的服務或者數據,這里的服務包括普通服務和基於AIDL的服務。

2. Binder架構

binder_arch

Binder在整個Android系統中有這舉足輕重的地位,在Native層有一套完整的binder通信的C/S架構(圖中的藍色),Bpinder作為客戶端,BBinder作為服務端。基於naive層的Binder框架,Java也有一套鏡像功能的binder C/S架構,通過JNI技術,與native層的binder對應,Java層的binder功能最終都是交給native的binder來完成。從kernel到native,jni,framework層的架構所涉及的所有有關類和方法見Binder類圖

3. Binder進程與線程

binder_proc_relation

對於底層Binder驅動,通過binder_procs鏈表記錄所有創建的binder_proc結構體,binder驅動層的每一個binder_proc結構體都與用戶空間的一個用於binder通信的進程一一對應,且每個進程有且只有一個ProcessState對象,這是通過單例模式來保證的。在每個進程中可以有很多個線程,每個線程對應一個IPCThreadState對象,IPCThreadState對象也是單例模式,即一個線程對應一個IPCThreadState對象,在Binder驅動層也有與之相對應的結構,那就是Binder_thread結構體。在binder_proc結構體中通過成員變量rb_root threads,來記錄當前進程內所有的binder_thread。

Binder線程池:每個Server進程在啟動時會創建一個binder線程池,並向其中注冊一個Binder線程;之后Server進程也可以向binder線程池注冊新的線程,或者Binder驅動在探測到沒有空閑binder線程時會主動向Server進程注冊新的的binder線程。對於一個Server進程有一個最大Binder線程數限制,默認為16個binder線程,例如Android的system_server進程就存在16個線程。對於所有Client端進程的binder請求都是交由Server端進程的binder線程來處理的。

4. Binder傳輸過程

Binder IPC機制,就是指在進程間傳輸數據(binder_transaction_data),一次數據的傳輸,稱為事務(binder_transaction)。對於多個不同進程向同一個進程發送事務時,這個同一個進程或線程的事務需要串行執行,在Binder驅動中為binder_proc和binder_thread都有todo隊列。

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

binder_transaction

在Binder驅動層,每個接收端進程都有一個todo隊列,用於保存發送端進程發送過來的binder請求,這類請求可以由接收端進程的任意一個空閑的binder線程處理;接收端進程存在一個或多個binder線程,在每個binder線程里都有一個todo隊列,也是用於保存發送端進程發送過來的binder請求,這類請求只能由當前binder線程來處理。binder線程在空閑時進入可中斷的休眠狀態,當自己的todo隊列或所屬進程的todo隊列有新的請求到來時便會喚醒,如果是由所需進程喚醒的,那么進程會讓其中一個線程處理響應的請求,其他線程再次進入休眠狀態。

5. Binder路由

先來看看Native Binder IPC的兩個重量級對象:BpBinder(客戶端)和BBinder(服務端)都是Android中Binder通信相關的代表,它們都從IBinder類中派生而來,關系圖如下:

Binder關系圖

  • IBinder有一個重要方法queryLocalInterface, 默認返回值為NULL;
    • BBinder/BpBinder都沒有實現,默認返回NULL;BnInterface重寫該方法;
    • BinderProxy(Java)默認返回NULL;Binder(Java)重寫該方法;
  • IInterface有一個重要方法asBinder;
  • IInterface子類(服務端)會有一個方法asInterface;

Native層通過宏IMPLEMENT_META_INTERFACE來完成asInterface實現和descriptor的賦值過程;

對於Java層跟Native一樣,也有完全對應的一套對象和方法:

  • 例如ActivityManagerNative, 通過實現asInterface方法,以及其通過其構造函數 調用attachInterface(),完成descriptor的賦值過程。
  • 再如AIDL全自動生成asInterface和descriptor賦值過程。

同一個進程,請求binder服務,不需要創建binder_ref,BpBinder等這些對象,但是是否需要經過binder call,取決於descriptor是否設置。 這就涉及到Java服務Native使用,或許Native服務在Java層使用,需要格外注意。

binder的路由原理:BpBinder發送端,根據handler,在當前binder_proc中,找到相應的binder_ref,由binder_ref再找到目標binder_node實體,由目標binder_node再找到目標進程binder_proc。簡單地方式是直接把binder_transaction節點插入到binder_proc的todo隊列中,完成傳輸過程。

對於binder驅動來說應盡可能地把binder_transaction節點插入到目標進程的某個線程的todo隊列,效率更高。當binder驅動可以找到合適的線程,就會把binder_transaction節點插入到相應線程的todo隊列中,如果找不到合適的線程,就把節點之間插入binder_proc的todo隊列。

 

 

轉自:http://gityuan.com/2016/09/04/binder-start-service/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM