Binder native層源碼分析(七):BBinder

Binder驅動部分的主要內容已經基本分析完了,現在回到native層,把之前源碼分析三中未分析的部分拿出來分析一遍,注意目的是說明BBinder的作用。我把這一部分內容放在這裏分析其實是有原因的,因爲如果不理解Binder驅動部分的內容,那麼肯定很難理解waitForResponse後面對接收到協議的處理

源碼分析三我們分析了waitForResponse中發送數據的部分,我們接着看waitForResponse的後半部分。分析後半部分時,我們不能用前面服務向sm註冊或客戶向sm請求爲例進行分析,我們必須設想另一個場景才能講清楚BBinder的作用。

設想一下這種情形,客戶端已經取得了服務端,並且向服務端發送了請求,請求的協議爲BR_TRANSACTION。現在服務端準備接收這個請求,並作出處理。

waitForResponse分段2

while(1){
	//...talkWithDriver將請求讀取到mIn,這部分代碼略過。
	cmd = (uint32_t)mIn.readInt32();
	switch (cmd) {
		//...對case的處理,略去
		default:
		    err = executeCommand(cmd);
		    if (err != NO_ERROR) goto finish;
		    break;
	}
}

調用完talkWithDriver之後,當檢查到mIn中有值時,從mIn中讀取協議cmd。下面的switch case和executeCommand的作用根據協議進行相應的處理。而對BR_TRANSACTION的處理在executeCommand中。

executeCommand對BR_TRANSACTION的處理

status_t IPCThreadState::executeCommand(int32_t cmd)
{
    BBinder* obj;
    RefBase::weakref_type* refs;
    status_t result = NO_ERROR;
    
    switch ((uint32_t)cmd) {
    //...
    case BR_TRANSACTION:
        {
            binder_transaction_data tr;
            result = mIn.read(&tr, sizeof(tr));//從mIn中讀出binder_transaction_data
            ALOG_ASSERT(result == NO_ERROR,
                "Not enough command data for brTRANSACTION");
            if (result != NO_ERROR) break;
            
            Parcel buffer;
            //將tr恢復成Parcel
            buffer.ipcSetDataReference(
                reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                tr.data_size,
                reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
            
            const pid_t origPid = mCallingPid;
            const uid_t origUid = mCallingUid;
            const int32_t origStrictModePolicy = mStrictModePolicy;
            const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;

            mCallingPid = tr.sender_pid;
            mCallingUid = tr.sender_euid;
            mLastTransactionBinderFlags = tr.flags;

            int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
            if (gDisableBackgroundScheduling) {
                if (curPrio > ANDROID_PRIORITY_NORMAL) {
                    setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
                }
            } else {
                if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
                    set_sched_policy(mMyThreadId, SP_BACKGROUND);
                }
            }
            Parcel reply;
            status_t error;
            if (tr.target.ptr) {
                if (reinterpret_cast<RefBase::weakref_type*>(
                        tr.target.ptr)->attemptIncStrong(this)) {
                     //注意這個調用
                    error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
                            &reply, tr.flags);
                    reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
                } else {
                    error = UNKNOWN_TRANSACTION;
                }

            } else {
                error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
            }
            if ((tr.flags & TF_ONE_WAY) == 0) {
                LOG_ONEWAY("Sending reply to %d!", mCallingPid);
                if (error < NO_ERROR) reply.setError(error);
                sendReply(reply, 0);
            } else {
                LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
            }
            
            mCallingPid = origPid;
            mCallingUid = origUid;
            mStrictModePolicy = origStrictModePolicy;
            mLastTransactionBinderFlags = origTransactionBinderFlags;
            
        }
        break;

忽略具體實現的細節,我們大致可以知道在對BR_TRANSACTION的處理中,首先是從mIn中讀取數據恢復binder_transaction_data tr,然後再構造出Parcel Buffer,其實就是前面數據發送的逆過程,同樣用一張圖總結如下:
在這裏插入圖片描述
executeCommand中最重要的是下面這條語句。

error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
                            &reply, tr.flags);

這個cookie值是什麼?答案就在源碼分析五中對binder_thread_read的分析中。截取部分代碼如下:

		if (t->buffer->target_node) {
		//得到sm對應的binder_node
			struct binder_node *target_node = t->buffer->target_node;
			struct binder_priority node_prio;
		//根據上篇博文的分析我們知道,ptr和cookie指向服務類
			tr.target.ptr = target_node->ptr;
			tr.cookie =  target_node->cookie;//注意這裏對cookie進行賦值

當target_node不爲空時,cookie值等於target_node的cookie。在源碼分析四中我們知道,binder_node的cookie等於obj的cookie,而在源碼分析二中我們知道,obj的cookie等於服務類例如MediaPlayerService的指針。

所以傳遞的數據包Parcel就交給了服務類的transact函數。而服務類是BBinder的派生類,也就相當於交給了BBinder的transact處理。

BBinder

//\frameworks\native\libs\binder\Binder.cpp
status_t BBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    data.setDataPosition(0);

    status_t err = NO_ERROR;
    switch (code) {
        case PING_TRANSACTION:
            reply->writeInt32(pingBinder());
            break;
        default:
            err = onTransact(code, data, reply, flags);
            break;
    }

    if (reply != NULL) {
        reply->setDataPosition(0);
    }

    return err;
}

又將數據交給了onTransact函數,onTransact都是虛函數,所以實際上處理數據的是BBinder繼承者的onTransact()。比如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;
    //...

onTransact()就是根據code的值調用不同的函數。正如前面在分析BpBinder的transact函數時所提到的,code的值決定BBinder受到數據後會做什麼樣的處理。從這裏就可以看出Binder通信其實就是遠程過程調用的過程。

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