BpBinder和BBinder在Binder通信機制中屬於通信層,也就是說這兩個類是真正幹實事的,Binder通信需要通過這兩個類來進行。
BpBinder是客戶端用來與服務交互的代理類,也就意味着BpBinder本身不實現通信功能,通信功能由其它類和函數實現,但由於這些類和函數被BpBinder代理,所以客戶端需要通過BpBinder來發送Binder通信數據。
BBinder代表服務端,當服務端從Binder驅動中讀取到數據後,由BBinder類進行處理。
BpBinder和BBbinder都繼承自IBinder,但它們的transact()函數實現了完全不同的功能。BpBinder和BBinder的關係如下圖:
上圖省略了很多中間函數,接下來,我們根據通信數據的流向,一一分析其中的函數做了什麼。
使用BpBinder發送Binder通信數據
源碼位於\frameworks\native\libs\binder\BpBinder.cpp
BpBinder::BpBinder(int32_t handle)
: mHandle(handle)
, mAlive(1)
, mObitsSent(0)
, mObituaries(NULL)
{
//...
}
構造BpBinder時需要一個參數handle用於初始化成員變量mHandle。每個BpBinder都有唯一一個和他對應的BBinder對象,BpBinder就是通過這個mHandle來標識它對應的BBinder。可以看到在後面的transact()中,這個mHandle會作爲一個參數傳入,代表本次通信的目的端。
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
客戶端通過BpBinder的transact()函數來發送數據,該函數需要如上幾個參數。code控制服務端進入不同的分支,具體來說,在BBinder的transact()或onTransact()函數中會根據接收到的code的值進入不同的分支。data即傳輸的數據,reply用於接收回復,flags表示本次通信的類型。
BpBinder的transact()函數只是將參數原封不動的交給IPCThreadState的transact()處理,並且還額外傳入了mHandle表示通信的目的端。
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
每個進程都有一個IPCThreadState。這個類有兩個Parcel結構成員mIn和mOut,用於向Binder驅動接收或寫入數據。
IPCThreadState的transact()將傳進來的所有參數又傳給了writeTransactionData(),額外傳入了BC_TRANSACTION表示通信協議,然後waitForResponse()。當flag是TF_ONE_WAY的時候,傳給waitForResponse()的參數爲NULL,意思是不需要接收返回數據;不然則會將reply傳進去,用於接收通信返回的Parcel。
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
這個函數中首先構造了一個binder_transaction_data對象tr,它的內容來源於傳入的Parcel data和其它參數。其中,tr.data.ptr.buffer等於data.mData,即爲傳輸的數據。
函數的最後把cmd和tr寫進mOut。所以傳進來的Parcel data並不直接用於通信,而是用於填充binder_transaction_data,而mOut纔是用於通信的Parcel。
接下來看waitForResponse(),看它是怎麼處理接收到的通信數據的。
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
在waitForResponse()的實現中,首先是調用talkWithDriver()向Binder驅動發送數據,然後等待迴應。當檢查到mIn中有值時,表明收到了迴應,然後從mIn中讀4個字節作爲協議並根據協議進行相應的處理。
服務端同樣是通過waitForResponse()等待數據,由於我們在writeTransactionData()中傳入的協議是BC_TRANSACTION,所以在這裏我們只關心waitForResponse()對BR_TRANSACTION協議的處理,主要乾了三件事:
- 從mIn中讀出binder_transaction_data存在tr中。從上面的writeTransactionData()中我們知道,存放在協議後面的就是binder_transaction_data
- 用tr的數據恢復出Parcel buffer,這裏恢復出來的buffer就是writeTransactionData()中的Parcel data。
- 轉發給BBinder處理,關鍵代碼如下:
//如果tr.target.ptr存在
reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags);
//否則
the_context_object->transact(tr.code, buffer, &reply, tr.flags);
這裏的tr.cookie應該就是Parcel中的cookie,在調用Parcel.writeObject()的時候會把一個IBinder儲存到cookie中。詳情可見Parcel分析。這個IBinder對象是本進程的一個BBinder,所以這裏就是將數據交給了BBinder處理。
接下來分析talkWithDriver(),這個函數實現了與Binder驅動的通信。
status_t IPCThreadState::talkWithDriver(bool doReceive)
這個函數統一處理對Binder驅動的讀寫。當doReceive爲true或mIn.dataPosition() < mIn.dataSize()時,執行讀操作,否則執行寫操作。
這裏通過將binder_write_read結構體bwr傳入ioctl()來與Binder驅動通信。在調用ioctl()前,會對bwr作如下賦值操作。
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
bwr.read_size = mIn.dataCapacity();//不需要讀的時候設爲0
bwr.read_buffer = (uintptr_t)mIn.data();//不需要讀的時候設爲0
bwr.write_consumed = 0;
bwr.read_consumed = 0;
調用完ioctl後,會檢查bwr的write_consumed和read_consumed。如果write_consumed等於0,則將mOut的mDataSize清0,釋放mData(setDataSize(0))。如果read_consumed大於0,設置mIn的mDataSize爲read_consumed,設置mDataPos爲0,這樣在waitForResponse()中可以從0開始讀取mIn的數據。
BBinder處理接收數據
從前面的分析可以看到,waitForResponse()把收到的Parcel傳給BBinder處理。
BBinder相關代碼在\frameworks\native\libs\binder\Binder.cpp中。
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
調用了onTransact()函數處理。
status_t BBinder::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/)
根據code的值作出不同的處理。
BBinder的transact和onTransact都是虛函數,所以實際上處理數據的是BBinder繼承者的transact()和onTransact()。它們大抵都是根據code的值作出相應處理。比如BnMediaPlayerService的onTransact():
// \frameworks\av\media\libmedia\IMediaPlayerService.cpp
status_t BnMediaPlayerService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch (code) {
case CREATE: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
sp<IMediaPlayerClient> client =
interface_cast<IMediaPlayerClient>(data.readStrongBinder());
audio_session_t audioSessionId = (audio_session_t) data.readInt32();
sp<IMediaPlayer> player = create(client, audioSessionId);
reply->writeStrongBinder(IInterface::asBinder(player));
return NO_ERROR;
} break;
//...