Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android: Binder

Android: Binder

編輯:關於Android編程

Binder概述

Binder是一種Android實現的IPC,用於進程間通信。

通常Linux系統提供好幾種進程間通信的方式,比如
1) Message Queue :把進程之間通信用的message保存到內核中或者從內核中讀取的方式。

2) Shared Memory:進程間指定共享的內存,把需要傳輸的內容保存到相應的內存的方式

3) Socket:

Android中選擇Binder為主要的IPC方式,因為Binder比其他的IPC方式有更加簡潔快速,消耗內存更小等優點。

下面來看一下Framework層Java空間都是怎麼用Binder實現進程間通信的。

Framework層Binder

Binder實際是一種C/S模式的工作方式,客戶端通過Binde向服務端發出請求,服務端再通過Binder返回相應的內容給服務端。Binder的工作流程如下:
1)客戶首先獲得服務端的代理對象。所謂代理對象就是客戶端建立一個服務端的”引用”,該代理對象具有服務端的功能,使其在客戶端訪問服務端的方法就像訪問本地方法一樣。
2)客戶端通過調用服務器代理對象的方法,向服務器端發送請求
3)代理對象通過Binder驅動將用戶請求發送給服務器端
4)服務器端處理客戶端請求,並通過Binder驅動將處理結果返回給客戶端
5)客戶端收到服務器端的返回結果

這裡說的服務端為:BBinder 服務端代理對象為:BpBinder
還需要說一下IBinder接口。這個接口是對跨進程對象的抽象,在C/C++和Java都有定義。IBinder定義了一套使用Binder機制來實現客戶程序與服務器的通信協議。
一個對象只能在當前進程中被訪問,如果希望它能被其他進程訪問,就必須實現IBinder接口。IBinder接口可以指向本地對象,也可以指向遠程對象。關鍵在與IBinder接口中的transact函數。如果IBinder指向服務端代理,那transact負責把請求發送給服務器;如果IBinder指向的是一個服務端,那麼transact只負責提供服務。因此不管是服務端還是服務端代理對象,都必須實現該接口,這樣才能進行Binder通信。
C/C++中BBinder和BpBinder都是繼承了IBinder接口的類。

所以實現Binder就很簡單,服務器端繼承BBinder並實現onTransact函數,客戶端繼承BpBinder實現transact函數即可。
以MediaPlayerService為例,在Stagefright.cpp文件的main函數中有如下代碼

        sp sm = defaultServiceManager();
        sp binder = sm->getService(String16("media.player"));
        sp service =
            interface_cast(binder);

        sp omx = service->getOMX();

這裡getOMX函數是BpMediaPlayerService類中的函數,這個很容易看的出來。
定義如下:

    virtual sp getOMX() {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
        remote()->transact(GET_OMX, data, &reply); //調用tranact函數發送Binder請求
        return interface_cast(reply.readStrongBinder());
    }

上述的Binder請求會最終發給服務器端,也就是BnMediaPlayerService類的onTransact函數中

status_t BnMediaPlayerService::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch (code) {
        ...
        case GET_OMX: {
            CHECK_INTERFACE(IMediaPlayerService, data, reply);
            sp omx = getOMX();
            reply->writeStrongBinder(omx->asBinder());
            return NO_ERROR;
        } break;
        ...
    }
}

最終getOMX函數就是調用繼承了BnMediaPlayerService類的MediaPlayerService類中的getOMX函數

sp MediaPlayerService::getOMX() {
    Mutex::Autolock autoLock(mLock);

    if (mOMX.get() == NULL) {
        mOMX = new OMX;
    }

    return mOMX;
}

下面來看一下上述的過程是怎麼通過Binder驅動來傳遞的,因為上面說的內容都沒有涉及到打開,讀寫Binder驅動(/dev/binder)的內容。

要看service是怎麼打開Binder驅動並實現,必須要從其初始化過程以及service的注冊過程看起。
在系統開機的時候,init.rc裡邊有如下配置,負責啟動mediaserver。

service media /system/bin/mediaserver
    class main
    user media
    group system audio camera inet net_bt net_bt_admin net_bw_acct drmrpc sdcard_r shell mediadrm media_rw qcom_diag radio
    ioprio rt 4

可以從Android.mk配置中找到,上面的service啟動,入口函數是main_mediaserver.cpp文件中的main函數。

int main(int argc __unused, char** argv)
{
    signal(SIGPIPE, SIG_IGN);
    char value[PROPERTY_VALUE_MAX];
    bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
    pid_t childPid;

    if (doLog && (childPid = fork()) != 0) {
        //如果doLog為true,其父進程就會跑到這裡,處理幾個子進程的消息。這個不是重點,跳過!!
    } else {
        ...
        sp proc(ProcessState::self());
        sp sm = defaultServiceManager();
        ...
        waitBeforeAdding(String16("media.player"));
        MediaPlayerService::instantiate();
        ALOGI("Add MediaPlayerService on mediaserver");  // SEC_PRODUCT_FEATURE_AUDIO_COMMON
        ...
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
    }
}

來看一下上面幾行代碼的說明

1.  sp proc(ProcessState::self()) 
    ProcessState沒有初始化就初始化,已經初始化的話就把ProcessState的對象加一個sp。這裡加sp的作用,
    可以看Android中sp/wp的說明,這裡就不再贅述。那ProcessState初始化都在干什麼呢?
    ProcessState::ProcessState()
        : mDriverFD(open_driver()) //這裡打開Binder驅動設備
        , mVMStart(MAP_FAILED)
        , mManagesContexts(false)
        , mBinderContextCheckFunc(NULL)
        , mBinderContextUserData(NULL)
        , mThreadPoolStarted(false)
        , mThreadPoolSeq(1)
    {
        if (mDriverFD >= 0) {
            //驅動設備的mmap!!!
            mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);

        }

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

2.  sp sm = defaultServiceManager()

    sp defaultServiceManager()
    {
        if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
        {
            AutoMutex _l(gDefaultServiceManagerLock);
            while (gDefaultServiceManager == NULL) {
                gDefaultServiceManager = interface_cast(
                    ProcessState::self()->getContextObject(NULL));
                if (gDefaultServiceManager == NULL)
                    sleep(1);
            }
        }

        return gDefaultServiceManager;
    }

    sp ProcessState::getStrongProxyForHandle(int32_t handle)
    {
        ...
        b = new BpBinder(handle); 
        //BpBinder為一個服務器代理客戶端,handle(也就是mHandle)標識一個service。
        //一個客戶端在通過transact發送Binder消息給ServiceManager的時候會發送自己的handle。
        //ServiceManager會根據這個handle來分發Binder消息給相應的服務端。
        //handle為0是ServiceManager本身

        //當然getService()找到相應的service不是通過handle,而是通過service名字
        ...
        result = b;
    }

    BpBinder強制轉換成IServiceManager??

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

    BpServiceManager::addService(){
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeStrongBinder(service);
        data.writeInt32(allowIsolated ? 1 : 0);
        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
        //按理說應該是BnServiceManager::onTransact()函數接收!!!但其實是
        //service_manager.c文件的函數接收處理
        return err == NO_ERROR ? reply.readExceptionCode() : err;
    }
    這裡的remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply)按理說應該是傳到
    BnServiceManager::onTransact()函數來處理。但ServiceManager比較特殊。其實這個是傳到
    service_manager.c文件中去實現了
    添加service的操作!!BnServiceManager為什麼沒有用呢??

4.ProcessState::self()->startThreadPool(), IPCThreadState::self()->joinThreadPool()

把相關的Server加到ServiceManger之後,Service會使用ProcessState::self()->startThreadPool()
啟動一個線程(使用IPCThreadState::self()->joinThreadPool()),負責打開Binder驅動等待客戶端發來消
息。下面的IPCThreadState::self()->joinThreadPool()本身也會打開一個Binder設備等待客戶端消息。

看一下客戶端發送Binder消息給對應的Service的流程以及Service接收到Binder消息之後的處理

1.在需要使用到Service完成功能的時候,需要按如下流程發送Binder消息

    1) 需要從ServiceManager根據Service的名字,獲取相應的Service(當然如果Service沒有注冊的話是獲取不到
    的)。

    sp sm = defaultServiceManager();
    sp binder = sm->getService(String16("media.player"));
    mOMX = service->getOMX();

    2)打包數據只會通過remote()->transact發送數據
    virtual sp getOMX() {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
        remote()->transact(GET_OMX, data, &reply);
        return interface_cast(reply.readStrongBinder());
    }

2.具體看一下用來發送的am->transact()函數都在干什麼

    //am->transact()最終會調用到其父類的BpBinder::transact()函數
    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::transact() {
        IPCThreadState::writeTransactionData();
        //負責數據的打包 
        /*   //這裡的cookie和handle負責找到指定的Service並調用相應的onTransact函數
             //怎麼通過cookie或者handle找到相應的onTranact函數呢????
        tr.target.ptr = 0; 
        tr.target.handle = handle;
        tr.code = code;
        tr.flags = binderFlags;
        tr.cookie = 0;
        tr.sender_pid = 0;
        tr.sender_euid = 0;
        */
        IPCThreadState::waitForResponse();//talkWithDriver()發送Binder消息
    }

3.以main_mediaserver.cpp文件為例,main函數最後會通過ProcessState::self()->startThreadPool(), IPCThreadState::self()->joinThreadPool()函數開啟線程和打開Binder設備等待客戶端發來消息

//來看一下調用流程
IPCThreadState::joinThreadPool()->IPCThreadState::getAndExecuteCommand() {
     talkWithDriver();
     executeCommand(cmd);
}

executeCommand()//這個函數如果發現是有Binder Transact會跑到下面部分
{
    if (tr.target.ptr) {
        sp b((BBinder*)tr.cookie);
        error = b->transact(tr.code, buffer, &reply, tr.flags);
    }
}
//這裡tr.target.pr其實就是tr.target.handle。這裡b->transact()會調用到
//BBinder::transact()->onTransact()然後怎麼調用到子類的onTransact()函數的?????
/*if(tr.target.ptr)為真的分支部分是最重要的。它從binder內核驅動中獲取到一個地址並轉換為BBinder類型的指針(該指針在執行IServiceManager::addService()函數時放入binder內核驅動)。記住,MediaPlayerService繼承自BnMediaPlayerService,BnMediaPlayerService又繼承自BBinder。該指針實際上與BnMediaPlayerService實例是同一個指針。於是接下來的transact()函數將調用到BnMediaPlayerService::onTransact()/

Service的注冊以及獲取Servcie,然後客戶端發送請求給服務端的流程如下:
1) Service啟動的時候通過IServiceManager的addService()把自己加到ServiceManager中
2) addService的service參數會在Binder Driver中變成handle變量
3) Binder Driver會根據名字來管理所有的service
4) IServiceManager可以通過getService()找到已經注冊的Service的Interface handle
5) android.os.IBinder.INTERFACE_TRANSACTION code來找到Interface handle的實際名字

這裡寫圖片描述

到此上面解釋完了Framework層是怎麼通過Binder實現IPC了!!

http://egloos.zum.com/windom/v/1865390

Java Binder

Binder in java layer

Java層的binder機制主要涉及到以下類:
 服務層:IFooService;FooService; FooManager
其中,IFooService 接口定義服務所提供的方法,由.aidl文件實現;
FooService具體實現各個功能函數,提供具體服務;
FooManager用於注冊和查找該服務;


中間層:IFooService.Stub;IFooService.Stub.Proxy
中間代碼,用於實現框架封裝,實際工作中由.aidl接口文件自動生成;

IPC層:Binder;BinderProxy;Parcel
BinderProxy為Binder對象在本地的代理,接收客戶端傳過來的數據,對其進行封裝,調用JNI函數將數據發送至底層框架;
Binder接收從底層框架傳過來的數據,解包,並傳送至遠程服務。
Parcel類對數據進行包封裝。

Java 層 Binder 框架數據傳遞的實現

int register_android_os_Binder(JNIEnv* env)
{
    if (int_register_android_os_Binder(env) < 0)
        return -1;
    if (int_register_android_os_BinderInternal(env) < 0)
        return -1;
    if (int_register_android_os_BinderProxy(env) < 0)
        return -1;
    if (int_register_android_os_Parcel(env) < 0)
        return -1;
    return 0;
}

Linux Binder驅動

待續。。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved