android Binder設計與實現二

4 Binder 協議

Binder協議基本格式是(命令+數據),使用ioctl(fd, cmd, arg)函數實現交互。命令由參數cmd承載,數據由參數arg承載,隨cmd不同而不同。下表列舉瞭所有命令及其所對應的數據:

表 2 Binder通信命令字

  

命令 含義 arg
BINDER_WRITE_READ 該命令向Binder寫入或讀取數據。參數分為兩段:寫部分和讀部分。如果write_size不為0就先將write_buffer裡的數據寫入Binder;如果read_size不為0再從Binder中讀取數據存入read_buffer中。write_consumed和read_consumed表示操作完成時Binder驅動實際寫入或讀出的數據個數。 struct binder_write_read {
signed long write_size;
signed long write_consumed;
unsigned long write_buffer;
signed long read_size;
signed long read_consumed;
unsigned long read_buffer;
};
BINDER_SET_MAX_THREADS 該命令告知Binder驅動接收方(通常是Server端)線程池中最大的線程數。由於Client是並發向Server端發送請求的,Server端必須開辟線程池為這些並發請求提供服務。告知驅動線程池的最大值是為瞭讓驅動在線程達到該值時不要再命令接收端啟動新的線程。 int max_threads;
BINDER_SET_CONTEXT_MGR 將當前進程註冊為SMgr。系統中同時隻能存在一個SMgr。隻要當前的SMgr沒有調用close()關閉Binder驅動就不能有別的進程可以成為SMgr。
BINDER_THREAD_EXIT 通知Binder驅動當前線程退出瞭。Binder會為所有參與Binder通信的線程(包括Server線程池中的線程和Client發出請求的線程)建立相應的數據結構。這些線程在退出時必須通知驅動釋放相應的數據結構。
BINDER_VERSION 獲得Binder驅動的版本號。

 

這其中最常用的命令是BINDER_WRITE_READ。該命令的參數包括兩部分數據:一部分是向Binder寫入的數據,一部分是要從 Binder讀出的數據,驅動程序先處理寫部分再處理讀部分。這樣安排的好處是應用程序可以很靈活地處理命令的同步或異步。例如若要發送異步命令可以隻填入寫部分而將read_size置成0;若要隻從Binder獲得數據可以將寫部分置空即write_size置成0;若要發送請求並同步等待返回數據可以將兩部分都置上。

4.1 BINDER_WRITE_READ 之寫操作

Binder寫操作的數據時格式同樣也是(命令+數據)。這時候命令和數據都存放在binder_write_read 結構write_buffer域指向的內存空間裡,多條命令可以連續存放。數據緊接著存放在命令後面,格式根據命令不同而不同。下表列舉瞭Binder寫 操作支持的命令:

表 3 Binder寫操作命令字

  

cmd 含義 arg
BC_TRANSACTION
BC_REPLY
BC_TRANSACTION用於寫入請求數據;BC_REPLY用於寫入回復數據。其後面緊接著一個binder_transaction_data結構體表明要寫入的數據。 struct binder_transaction_data
BC_ACQUIRE_RESULT
BC_ATTEMPT_ACQUIRE
暫未實現
BC_FREE_BUFFER 釋放一塊映射的內存。Binder接收方通過mmap()映射一塊較大的內存空間,Binder驅動基於這片內存采用最佳匹配算法實現接收數據緩存的動態分配和釋放,滿足並發請求對接收緩存區的需求。應用程序處理完這片數據後必須盡快使用該命令釋放緩存區,否則會因為緩存區耗盡而無法接收新數據。 指向需要釋放的緩存區的指針;該指針位於收到的Binder數據包中
BC_INCREFS
BC_ACQUIRE
BC_RELEASE
BC_DECREFS
這組命令增加或減少Binder的引用計數,用以實現強指針或弱指針的功能。 32位Binder引用號
BC_INCREFS_DONE
BC_ACQUIRE_DONE
第一次增加Binder實體引用計數時,驅動向Binder實體所在的進程發送BR_INCREFS,BR_ACQUIRE消息;Binder實體所在的進程處理完畢回饋BC_INCREFS_DONE,BC_ACQUIRE_DONE void *ptr:Binder實體在用戶空間中的指針
void *cookie:與該實體相關的附加數據
BC_REGISTER_LOOPER
BC_ENTER_LOOPER
BC_EXIT_LOOPER
這組命令同BINDER_SET_MAX_THREADS一道實現Binder驅動對接收方線程池管理。BC_REGISTER_LOOPER通知驅動線程池中一個線程已經創建瞭;BC_ENTER_LOOPER通知驅動該線程已經進入主循環,可以接收數據;BC_EXIT_LOOPER通知驅動該線程退出主循環,不再接收數據。
BC_REQUEST_DEATH_NOTIFICATION 獲得Binder引用的進程通過該命令要求驅動在Binder實體銷毀得到通知。雖說強指針可以確保隻要有引用就不會銷毀實體,但這畢竟是個跨進程的引用,誰也無法保證實體由於所在的Server關閉Binder驅動或異常退出而消失,引用者能做的是要求Server在此刻給出通知。 uint32 *ptr; 需要得到死亡通知的Binder引用
void **cookie: 與死亡通知相關的信息,驅動會在發出死亡通知時返回給發出請求的進程。
BC_DEAD_BINDER_DONE 收到實體死亡通知書的進程在刪除引用後用本命令告知驅動。 void **cookie

 

在這些命令中,最常用的是BC_TRANSACTION/BC_REPLY命令對,Binder數據通過這對命令發送給接收方。這對命令所承載的數據包由結構體struct binder_transaction_data定義。Binder交互有同步和異步之分,利用binder_transaction_data中 flag域區分。如果flag域的TF_ONE_WAY位為1則為異步交互,即Client端發送完請求交互即結束, Server端不再返回BC_REPLY數據包;否則Server會返回BC_REPLY數據包,Client端必須等待接收完該數據包方才完成一次交 互。

4.2 BINDER_WRITE_READ :從Binder讀出數據

從Binder裡讀出的數據格式和向Binder中寫入的數據格式一樣,采用(消息ID+數據)形式,並且多條消息可以連續存放。下表列舉瞭從 Binder讀出的命令字及其相應的參數:

表 4 Binder讀操作消息ID

  

消息 含義 參數
BR_ERROR 發生內部錯誤(如內存分配失敗)
BR_OK
BR_NOOP
操作完成
BR_SPAWN_LOOPER 該消息用於接收方線程池管理。當驅動發現接收方所有線程都處於忙碌狀態且線程池裡的線程總數沒有超過BINDER_SET_MAX_THREADS 設置的最大線程數時,向接收方發送該命令要求創建更多線程以備接收數據。
BR_TRANSACTION
BR_REPLY
這兩條消息分別對應發送方的BC_TRANSACTION和BC_REPLY,表示當前接收的數據是請求或是回復。 binder_transaction_data
BR_ACQUIRE_RESULT
BR_ATTEMPT_ACQUIRE
BR_FINISHED
尚未實現
BR_DEAD_REPLY 交互過程中如果發現對方進程或線程已經死亡則返回該消息
BR_TRANSACTION_COMPLETE 發送方通過BC_TRANSACTION或BC_REPLY發送完一個數據包後,都能收到該消息做為成功發送的反饋。這和BR_REPLY不一樣,是驅動告知發送方已經發送成功,而不是接收方返回請求數據。所以不管同步還是異步交互接收方都能獲得本消息。
BR_INCREFS
BR_ACQUIRE
BR_RELEASE
BR_DECREFS
這一組消息用於管理強/弱指針的引用計數。隻有提供Binder實體的進程才能收到這組消息。 void *ptr:Binder實體在用戶空間中的指針
void *cookie:與該實體相關的附加數據
BR_DEAD_BINDER
BR_CLEAR_DEATH_NOTIFICATION_DONE
向獲得Binder引用的進程發送Binder實體死亡通知書;收到死亡通知書的進程接下來會返回BC_DEAD_BINDER_DONE做確認。 void **cookie:在使用BC_REQUEST_DEATH_NOTIFICATION註冊死亡通知時的附加參數。
BR_FAILED_REPLY 如果發送非法引用號則返回該消息

 
和寫數據一樣,其中最重要的消息是BR_TRANSACTION 或BR_REPLY,表明收到瞭一個格式為binder_transaction_data的請求數據包(BR_TRANSACTION)或返回數據包(BR_REPLY)。

摘自 LuoXianXiong,您的夥伴

發佈留言