BpBinder和BBinder

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協議的處理,主要乾了三件事:

  1. 從mIn中讀出binder_transaction_data存在tr中。從上面的writeTransactionData()中我們知道,存放在協議後面的就是binder_transaction_data
  2. 用tr的數據恢復出Parcel buffer,這裏恢復出來的buffer就是writeTransactionData()中的Parcel data。
  3. 轉發給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;
    //...

 

 

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