騷年!用Binder原理去徹底征服Android大廠面試官吧

前言

在學習ServiceManager中的Binder機制過程中,有一個問題由於篇幅問題沒有講完,那就是MediaPlayerService是如何註冊的。通過了解MediaPlayerService是如何註冊的,可以得知系統服務的註冊過程。

1.從調用鏈角度說明MediaPlayerService是如何註冊的

我們先來看MediaServer的入口函數,代碼如下所示。
frameworks/av/media/mediaserver/main_mediaserver.cpp

int main(int argc __unused, char **argv __unused)
{
    signal(SIGPIPE, SIG_IGN);
    //獲取ProcessState實例
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm(defaultServiceManager());
    ALOGI("ServiceManager: %p", sm.get());
    InitializeIcuOrDie();
    //註冊MediaPlayerService
    MediaPlayerService::instantiate();//1
    ResourceManagerService::instantiate();
    registerExtensions();
    //啓動Binder線程池
    ProcessState::self()->startThreadPool();
    //當前線程加入到線程池
    IPCThreadState::self()->joinThreadPool();
}

這段代碼中的很多內容都在上一篇文章介紹過了,接着分析註釋1處的代碼。

frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

void MediaPlayerService::instantiate() {
    defaultServiceManager()->addService(
            String16("media.player"), new MediaPlayerService,());
}

defaultServiceManager返回的是BpServiceManager,參數是一個字符串和MediaPlayerService,看起來像是Key/Value的形式來完成註冊,接着看addService函數。

frameworks/native/libs/binder/IServiceManager.cpp

 virtual status_t addService(const String16& name, const sp<IBinder>& service,
                                bool allowIsolated, int dumpsysPriority) {
        Parcel data, reply;//數據包
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name); //name值爲"media.player"
        data.writeStrongBinder(service); //service值爲MediaPlayerService
        data.writeInt32(allowIsolated ? 1 : 0);
        data.writeInt32(dumpsysPriority);
        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);//1
        return err == NO_ERROR ? reply.readExceptionCode() : err;
    }

data是一個數據包,後面會不斷的將數據寫入到data中, 註釋1處的remote()指的是mRemote,也就是BpBinder。addService函數的作用就是將請求數據打包成data,然後傳給BpBinder的transact函數,代碼如下所示。

frameworks/native/libs/binder/BpBinder.cpp

status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

BpBinder將邏輯處理交給IPCThreadState,先來看IPCThreadState::self()幹了什麼?
frameworks/native/libs/binder/IPCThreadState.cpp

IPCThreadState* IPCThreadState::self()
{   
    //首次進來gHaveTLS的值爲false
    if (gHaveTLS) {
restart:
        const pthread_key_t k = gTLS;//1
        IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);//2
        if (st) return st;
        return new IPCThreadState;//3
    }
    ...
    pthread_mutex_unlock(&gTLSMutex);
    goto restart;
}

註釋1處的TLS的全稱爲Thread local storage,指的是線程本地存儲空間,在每個線程中都有TLS,並且線程間不共享。註釋2處用於獲取TLS中的內容並賦值給IPCThreadState*指針。註釋3處會新建一個IPCThreadState,這裏可以得知IPCThreadState::self()實際上是爲了創建IPCThreadState,它的構造函數如下所示。

frameworks/native/libs/binder/IPCThreadState.cpp

IPCThreadState::IPCThreadState()
    : mProcess(ProcessState::self()),
      mStrictModePolicy(0),
      mLastTransactionBinderFlags(0)
{
    pthread_setspecific(gTLS, this);//1
    clearCaller();
    mIn.setDataCapacity(256);
    mOut.setDataCapacity(256);
}

註釋1處的pthread_setspecific函數用於設置TLS,將IPCThreadState::self()獲得的TLS和自身傳進去。

IPCThreadState中還包含mIn、一個mOut,其中mIn用來接收來自Binder驅動的數據,mOut用來存儲發往Binder驅動的數據,它們默認大小都爲256字節。

知道了IPCThreadState的構造函數,再回來查看IPCThreadState的transact函數。

frameworks/native/libs/binder/IPCThreadState.cpp

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err;

    flags |= TF_ACCEPT_FDS;
    ...
    err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);//1

    if (err != NO_ERROR) {
        if (reply) reply->setError(err);
        return (mLastError = err);
    }

    if ((flags & TF_ONE_WAY) == 0) {
       ...
        if (reply) {
            err = waitForResponse(reply);//2
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
       ...
    } else {
       //不需要等待reply的分支
        err = waitForResponse(NULL, NULL);
    }

    return err;
}

調用BpBinder的transact函數實際上就是調用IPCThreadState的transact函數。註釋1處的writeTransactionData函數用於傳輸數據,其中第一個參數BC_TRANSACTION代表向Binder驅動發送命令協議,向Binder設備發送的命令協議都以BC_開頭,而Binder驅動返回的命令協議以BR_開頭。這個命令協議我們先記住,後面會再次提到他。

現在分別來分析註釋1的writeTransactionData函數和註釋2處的waitForResponse函數。

1.1 writeTransactionData函數分析

frameworks/native/libs/binder/IPCThreadState.cpp

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;//1

    tr.target.ptr = 0; 
    tr.target.handle = handle;//2 
    tr.code = code;  //code=ADD_SERVICE_TRANSACTION
    tr.flags = binderFlags;
    tr.cookie = 0;
    tr.sender_pid = 0;
    tr.sender_euid = 0;

    const status_t err = data.errorCheck();//3
    if (err == NO_ERROR) {
        tr.data_size = data.ipcDataSize();
        tr.data.ptr.buffer = data.ipcData();
        tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
        tr.data.ptr.offsets = data.ipcObjects();
    } else if (statusBuffer) {
        tr.flags |= TF_STATUS_CODE;
        *statusBuffer = err;
        tr.data_size = sizeof(status_t);
        tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
        tr.offsets_size = 0;
        tr.data.ptr.offsets = 0;
    } else {
        return (mLastError = err);
    }

    mOut.writeInt32(cmd);  //cmd=BC_TRANSACTION
    mOut.write(&tr, sizeof(tr));

    return NO_ERROR;
}

註釋1處的binder_transaction_data結構體(tr結構體)是向Binder驅動通信的數據結構,註釋2處將handle傳遞給target的handle,用於標識目標,這裏的handle的值爲0,代表了ServiceManager。
註釋3處對數據data進行錯誤檢查,如果沒有錯誤就將數據賦值給對應的tr結構體。最後會將BC_TRANSACTION和tr結構體寫入到mOut中。

上面代碼調用鏈的時序圖如下所示。

1.2 waitForResponse函數分析

接着回過頭來查看waitForResponse函數做了什麼,waitForResponse函數中的case語句很多,這裏截取部分代碼。
frameworks/native/libs/binder/IPCThreadState.cpp

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    uint32_t cmd;
    int32_t err;
    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;//1
        err = mIn.errorCheck();
        if (err < NO_ERROR) break;
        if (mIn.dataAvail() == 0) continue;
        cmd = (uint32_t)mIn.readInt32();
        IF_LOG_COMMANDS() {
            alog << "Processing waitForResponse Command: "
                << getReturnString(cmd) << endl;
        }
        switch (cmd) {
        case BR_TRANSACTION_COMPLETE:
            if (!reply && !acquireResult) goto finish;
            break;

        case BR_DEAD_REPLY:
            err = DEAD_OBJECT;
            goto finish;
       ...
        default:
            //處理各種命令協議
            err = executeCommand(cmd);
            if (err != NO_ERROR) goto finish;
            break;
        }
}
finish:
    ...
    return err;
}

註釋1處的talkWithDriver函數的內部通過ioctl與Binder驅動進行通信,代碼如下所示。
frameworks/native/libs/binder/IPCThreadState.cpp

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    if (mProcess->mDriverFD <= 0) {
        return -EBADF;
    }
    //和Binder驅動通信的結構體
    binder_write_read bwr; //1
    //mIn是否有可讀的數據,接收的數據存儲在mIn
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
    bwr.write_size = outAvail;
    bwr.write_buffer = (uintptr_t)mOut.data();//2
    //這時doReceive的值爲true
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();//3
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }
   ...
    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
    bwr.write_consumed = 0;
    bwr.read_consumed = 0;
    status_t err;
    do {
        IF_LOG_COMMANDS() {
            alog << "About to read/write, write size = " << mOut.dataSize() << endl;
        }
#if defined(__ANDROID__)
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)//4
            err = NO_ERROR;
        else
            err = -errno;
#else
        err = INVALID_OPERATION;
#endif
     ...
    } while (err == -EINTR);
    ...
    return err;
}

註釋1處的 binder_write_read是和Binder驅動通信的結構體,在註釋2和3處將mOut、mIn賦值給binder_write_read的相應字段,最終通過註釋4處的ioctl函數和Binder驅動進行通信,這一部分涉及到Driver Binder的內容
了,就不再詳細介紹了。

1.3 小節

從調用鏈的角度來看,MediaPlayerService是如何註冊的貌似並不複雜,因爲這裏只是簡單的介紹了一個調用鏈分支,可以簡單的總結爲以下幾個步驟:

  1. addService函數將數據打包發送給BpBinder來進行處理。

  2. BpBinder新建一個IPCThreadState對象,並將通信的任務交給IPCThreadState。

  3. IPCThreadState的writeTransactionData函數用於將命令協議和數據寫入到mOut中。

  4. IPCThreadState的waitForResponse函數主要做了兩件事,一件事是通過ioctl函數操作mOut和mIn來與Binder驅動進行數據交互,另一件事是處理各種命令協議。

2.從進程角度說明MediaPlayerService是如何註冊的

實際上MediaPlayerService的註冊還涉及到了進程,如下圖所示。

從圖中看出是以C/S架構爲基礎,addService是在MediaPlayerService進行的,它是Client端,用於請求添加系統服務。而Server端則是指的是ServiceManager,用於完成系統服務的添加。

Client端和Server端分別運行在兩個進程中,通過向Binder來進行通信。更詳細點描述,就是兩端通過向Binder驅動發送命令協議來完成系統服務的添加。這其中命令協議非常多,過程也比較複雜,這裏對命令協議進行了簡化,只涉及到了四個命令協議,其中
BC_TRANSACTION和BR_TRANSACTION過程是一個完整的事務,BC_REPLY和BR_REPLY是一個完整的事務。

Client端和Server端向Binder驅動發送命令協議以BC開頭,而Binder驅動向Client端和Server端返回的命令協議以BR_開頭。

步驟如下所示:

1.Client端向Binder驅動發送BC_TRANSACTION命令。
2.Binder驅動接收到請求後生成BR_TRANSACTION命令,喚醒Server端後將BR_TRANSACTION命令發送給ServiceManager。
3.Server端中的服務註冊完成後,生成BC_REPLY命令發送給Binder驅動。
4.Binder驅動生成BR_REPLY命令,喚醒Client端後將BR_REPLY命令發送個Client端。

通過這些協議命令來驅動並完成系統服務的註冊。

3.總結

本文分別從調用鏈角度和進程角度來講解MediaPlayerService是如何註冊的,間接的得出了服務是如何註冊的。這兩個角度都比較複雜,因此這裏分別對這兩個角度做了簡化,作爲應用開發,我們不需要注重太多的過程和細節,只需要瞭解大概的步驟即可。

最後有些東西你不僅要懂,而且要能夠很好地表達出來,能夠讓面試官認可你的理解,例如Handler機制,這個是面試必問之題。有些晦澀的點,或許它只活在面試當中,實際工作當中你壓根不會用到它,但是你要知道它是什麼東西。

馬上就要到金三銀四得面試旺季,大家都希望趁着這個機會找到一個心儀的工作,但是不管怎麼樣,不論是什麼樣的大小面試,要想不被面試官虐的不要不要的,只有刷爆面試題題做好全面的準備,當然除了這個還需要在平時把自己的基礎打紮實,這樣不論面試官怎麼樣一個知識點裏往死裏鑿,你也能應付如流啊~

面試:如果不準備充分的面試,完全是浪費時間,更是對自己的不負責!

最後這裏是關於我自己的Android 學習,面試文檔,視頻收集大整理,有興趣的夥伴們可以看看~

發佈了208 篇原創文章 · 獲贊 780 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章