論Android Binder驅動在Framework中的重要性

這篇博文其實就是想簡單的來記錄下Binder驅動在Android中的重要性,早在2012年的時候就按著2.3的源碼深入學習過Binder驅動的底層實現(Android之binder驅動個人學習小結),Binder驅動主要是android為瞭構建C/S的通信模型而量身定做的,沒有過多復雜的協議,一個Parcl基本包含瞭所要傳遞的所有信息,本文就對FrameWork從運用到的Binder機制做一個模型的總結。

還是先把Android的Binder驅動架構提煉出來先,如下圖所示是典型的CS架構,和Binder驅動密切相關的結構體包括BBinder、BpBinder、BpRefBase:

一個基於Binder的驅動架構,一般的實現過程分為如下幾部:

先來看下Binder架構下涉及的一般類圖佈局會如下所示

基於以上Android的類,我們構建的Ixxx定義整個通信的接口函數,主要由Bpxxx來實現但主要是進行命令字與數據的打包傳輸,然後遠程鏈接到本地的Bnxxx進行業務的解析與處理。一般需要構建2個文件:Ixxx.h,Ixxx.cpp.

在Ixxx.h內部申請Ixxx接口類,以及類Bnxxx的申明,一般該類隻對應一個成員函數即OnTransact;在Ixxx.cpp中主要實現類Bpxxx的申明以及對Ixxx的接口函數進行實現,其核心是調用BpBinder來實現的。

理解Binder最好的方式是ServiceManager,一般以BnxxxService命名服務,都會向其進行服務的註冊,而BpxxxClient是直接通過和SM在客戶端的代理來獲取BnxxxService在本地的代理。

其實按照我個人的理解,Bpxxx和Bnxxx更好的理解是2個進程間的通信,當然作為Service和Client是最好的使用方式。比如先前通過一個客戶端的BpxxxClient發出一個請求建立一個Client處的Bpxxx接口,相應的在服務端也就存在著Bnxxx的實現函數,故而這兩者之間就可以實現正常的通訊,當然Bnxxx不在是以服務的形象存在與SM中,隻是簡單的實現進程、線程間的通信而已。

下面將從一個SurfaceFlinger進程的啟動到Binder驅動的操作,以及Bnxxx和Bpxxx的通信來簡單介紹。

step1: Binder驅動的open和mmap過程

int main(int argc, char** argv) {
    SurfaceFlinger::publishAndJoinThreadPool(true);
    // When SF is launched in its own process, limit the number of
    // binder threads to 4.
    ProcessState::self()->setThreadPoolMaxThreadCount(4);
    return 0;
}
sp ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }
    gProcess = new ProcessState;
    return gProcess;
}

ProcessState作為一個進程中唯一的變量(所謂的單列模式),他是真正和Binder驅動打交道的地方所在

ProcessState::ProcessState()
    : mDriverFD(open_driver())
    , mVMStart(MAP_FAILED)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{
    if (mDriverFD >= 0) {
        // XXX Ideally, there should be a specific define for whether we
        // have mmap (or whether we could possibly have the kernel module
        // availabla).
#if !defined(HAVE_WIN32_IPC)
        // mmap the binder, providing a chunk of virtual address space to receive transactions.
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
        if (mVMStart == MAP_FAILED) {
            // *sigh*
            ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
            close(mDriverFD);
            mDriverFD = -1;
        }
#else
        mDriverFD = -1;
#endif
    }

    LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened.  Terminating.");
}

上述的構造函數主要完成Binder驅動的打開已經mmap的操作。

step2:Binder驅動的交互主要是接收其他的客戶端請求

void ProcessState::startThreadPool()
{
    AutoMutex _l(mLock);
    if (!mThreadPoolStarted) {
        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }
}
void IPCThreadState::joinThreadPool(bool isMain)
{
talkWithDriver();
executeCommand();
}

在這裡是通過獲取和binder驅動的交互,得到待處理的信息後進行executeCommand的執行,該函數其實內部就是找到對應的本地的BBinder來執行他的transact,而通過上圖的繼承關系可知,一般就直接有Bnxxx的Ontransact來解析完成,如下所示;

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;
}

step3: 作為客戶端是如何發送相關消息的

當你在Client有瞭對應的proxy後,直接操作的就是BpBinder的相關內容,我們常常見到的remote->(xxx)其實內部的實現是這樣的:

status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    // Once a binder has died, it will never come back to life.
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

可以看到是一個IPCThreadState在和幫助者你,再看他的transaction:

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)//數據的發送
{
   if (reply) {
            err = waitForResponse(reply);//等待服務端的回復
}
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
status_t IPCThreadState::talkWithDriver(bool doReceive)//和底層走的最近的地方

}

其實無論是Binder的服務端還是客戶端,真正的Binder在內核驅動中度會為當前的進程維護一個binder的node樹,隻有有新的節點產生經過內核驅動後都會記錄下來,使得一旦遠程的客戶通過代理訪問時,都是能找到對應的Binder實體,並找個該實體所示的loop服務線程,進行必要的喚醒與處理。最終反饋處理後的數據到客戶端,客戶端益是從線程的等待到喚醒這個過程來響應相關的處理結果,進行保存。

Binder驅動在下面要介紹的camera和SurfaceFlinger架構中會普遍的用到,所以先在這裡總一個最簡單的應用方式總結,以便更好的閱讀代碼。

發佈留言