Android Binder機制(超級詳盡)

1.binder通訊概述linux

 

    binder通訊是一種client-server的通訊結構,android

    1.從表面上來看,是client經過得到一個server的代理接口,對server進行直接調用;cookie

    2.實際上,代理接口中定義的方法與server中定義的方法是一一對應的;框架

    3.client調用某個代理接口中的方法時,代理接口的方法會將client傳遞的參數打包成爲Parcel對象;函數

    4.代理接口將該Parcel發送給內核中的binder driver.oop

    5.server會讀取binder driver中的請求數據,若是是發送給本身的,解包Parcel對象,處理並將結果返回;this

    6.整個的調用過程是一個同步過程,在server處理的時候,client會block住。.net

 

 

 

2.service manager線程

Service Manager是一個linux級的進程,顧名思義,就是service的管理器。這裏的service是什麼概念呢?這裏的service的概念和init過程當中init.rc中的service是不一樣,init.rc中的service是都是linux進程,可是這裏的service它並不必定是一個進程,也就是說可能一個或多個service屬於同一個linux進程。在這篇文章中不加特殊說明均指Android native端的service。設計

任何service在被使用以前,均要向SM(Service Manager)註冊,同時客戶端須要訪問某個service時,應該首先向SM查詢是否存在該服務。若是SM存在這個service,那麼會將該service的handle返回給client,handle是每一個service的惟一標識符。

    

    SM的入口函數在service_manager.c中,下面是SM的代碼部分

int main(int argc, char **argv)

{

    struct binder_state *bs;

    void *svcmgr = BINDER_SERVICE_MANAGER;

 

    bs = binder_open(128*1024);

 

    if (binder_become_context_manager(bs)) {

        LOGE("cannot become context manager (%s)/n", strerror(errno));

        return -1;

    }

 

    svcmgr_handle = svcmgr;

    binder_loop(bs, svcmgr_handler);

    return 0;

}

這個進程的主要工做以下:

    1.初始化binder,打開/dev/binder設備;在內存中爲binder映射128K字節空間;

    2.指定SM對應的代理binder的handle爲0,當client嘗試與SM通訊時,須要建立一個handle爲0的代理binder,這裏的代理binder其實就是第一節中描述的那個代理接口;

3.通知binder driver(BD)使SM成爲BD的context manager;

4.維護一個死循環,在這個死循環中,不停地去讀內核中binder driver,查看是否有可讀的內容;便是否有對service的操做要求, 若是有,則調用svcmgr_handler回調來處理請求的操做。

5.SM維護了一個svclist列表來存儲service的信息。

 

 

這裏須要聲明一下,當service在向SM註冊時,該service就是一個client,而SM則做爲了server。而某個進程須要與service通訊時,此時這個進程爲client,service才做爲server。所以service不必定爲server,有時它也是做爲client存在的。

 

因爲下面幾節會介紹一些與binder通訊相關的幾個概念,因此將SM的功能介紹放在了後面的部分來說。

 

應用和service之間的通訊會涉及到2次binder通訊。

 

1.應用向SM查詢service是否存在,若是存在得到該service的代理binder,此爲一次binder通訊;

2.應用經過代理binder調用service的方法,此爲第二次binder通訊。

 

3.ProcessState

ProcessState是以單例模式設計的。每一個進程在使用binder機制通訊時,均須要維護一個ProcessState實例來描述當前進程在binder通訊時的binder狀態。

    ProcessState有以下2個主要功能:

    1.建立一個thread,該線程負責與內核中的binder模塊進行通訊,稱該線程爲Pool thread;

    2.爲指定的handle建立一個BpBinder對象,並管理該進程中全部的BpBinder對象。

 

3.1 Pool thread

            在Binder IPC中,全部進程均會啓動一個thread來負責與BD來直接通訊,也就是不停的讀寫BD,這個線程的實現主體是一個IPCThreadState對象,下面會介紹這個類型。

            下面是 Pool thread的啓動方式:

ProcessState::self()->startThreadPool();

3.2 BpBinder獲取

BpBinder主要功能是負責client向BD發送調用請求的數據。它是client端binder通訊的核心對象,經過調用transact函數向BD發送調用請求的數據,它的構造函數以下:

BpBinder(int32_t handle);

    經過BpBinder的構造函數發現,BpBinder會將當前通訊中server的handle記錄下來,當有數據發送時,會通知BD數據的發送目標。

ProcessState經過以下方式來獲取BpBinder對象:

ProcessState::self()->getContextObject(handle);

在這個過程當中,ProcessState會維護一個BpBinder的vector mHandleToObject,每當ProcessState建立一個BpBinder的實例時,回去查詢mHandleToObject,若是對應的handle已經有binder指針,那麼再也不建立,不然建立binder並插入到mHandleToObject中。

    ProcessState建立的BpBinder實例,通常狀況下會做爲參數構建一個client端的代理接口,這個代理接口的形式爲BpINTERFACE,例如在與SM通訊時,client會建立一個代理接口BpServiceManager.

    

   

4.IPCThreadState

IPCThreadState也是以單例模式設計的。因爲每一個進程只維護了一個ProcessState實例,同時ProcessState只啓動一個Pool thread,也就是說每個進程只會啓動一個Pool thread,所以每一個進程則只須要一個IPCThreadState便可。

    Pool thread的實際內容則爲:

    IPCThreadState::self()->joinThreadPool();

 

ProcessState中有2個Parcel成員,mIn和mOut,Pool thread會不停的查詢BD中是否有數據可讀,若是有將其讀出並保存到mIn,同時不停的檢查mOut是否有數據須要向BD發送,若是有,則將其內容寫入到BD中,總而言之,從BD中讀出的數據保存到mIn,待寫入到BD中的數據保存在了mOut中。

ProcessState中生成的BpBinder實例經過調用IPCThreadState的transact函數來向mOut中寫入數據,這樣的話這個binder IPC過程的client端的調用請求的發送過程就明瞭了。

 

IPCThreadState有兩個重要的函數,talkWithDriver函數負責從BD讀寫數據,executeCommand函數負責解析並執行mIn中的數據。

5.主要基類

5.1基類IInterface

爲server端提供接口,它的子類聲明瞭service可以實現的全部的方法;

 

5.2基類IBinder

    BBinder與BpBinder均爲IBinder的子類,所以能夠看出IBinder定義了binder IPC的通訊協議,BBinder與BpBinder在這個協議框架內進行的收和發操做,構建了基本的binder IPC機制。

5.3基類BpRefBase

    client端在查詢SM得到所需的的BpBinder後,BpRefBase負責管理當前得到的BpBinder實例。

 

 

6.兩個接口類

6.1 BpINTERFACE

若是client想要使用binder IPC來通訊,那麼首先會從SM出查詢並得到server端service的BpBinder,在client端,這個對象被認爲是server端的遠程代理。爲了可以使client可以想本地調用同樣調用一個遠程server,server端須要向client提供一個接口,client在在這個接口的基礎上建立一個BpINTERFACE,使用這個對象,client的應用可以想本地調用同樣直接調用server端的方法。而不用去關心具體的binder IPC實現。

下面看一下BpINTERFACE的原型:

    class BpINTERFACE : public BpInterface<IINTERFACE>

 

    順着繼承關係再往上看

    template<typename INTERFACE>

    class BpInterface : public INTERFACE, public BpRefBase

 

    BpINTERFACE分別繼承自INTERFACE,和BpRefBase;

● BpINTERFACE既實現了service中各方法的本地操做,將每一個方法的參數以Parcel的形式發送給BD。

例如BpServiceManager的

    virtual status_t addService(const String16& name, const sp<IBinder>& service)

    {

        Parcel data, reply;

        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());

        data.writeString16(name);

        data.writeStrongBinder(service);

        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);

        return err == NO_ERROR ? reply.readExceptionCode() : err;

    }

● 同時又將BpBinder做爲了本身的成員來管理,將BpBinder存儲在mRemote中,BpServiceManager經過調用BpRefBase的remote()來得到BpBinder指針。

 

6.2 BnINTERFACE

在定義android native端的service時,每一個service均繼承自BnINTERFACE(INTERFACE爲service name)。BnINTERFACE類型定義了一個onTransact函數,這個函數負責解包收到的Parcel並執行client端的請求的方法。

 

    順着BnINTERFACE的繼承關係再往上看,

        class BnINTERFACE: public BnInterface<IINTERFACE>

 

    IINTERFACE爲client端的代理接口BpINTERFACE和server端的BnINTERFACE的共同接口類,這個共同接口類的目的就是保證service方法在C-S兩端的一致性。

 

    再往上看

        class BnInterface : public INTERFACE, public BBinder

 

    同時咱們發現了BBinder類型,這個類型又是幹什麼用的呢?既然每一個service都可視爲一個binder,那麼真正的server端的binder的操做及狀態的維護就是經過繼承自BBinder來實現的。可見BBinder是service做爲binder的本質所在。

 

    那麼BBinder與BpBinder的區別又是什麼呢?

 

    其實它們的區別很簡單,BpBinder是client端建立的用於消息發送的代理,而BBinder是server端用於接收消息的通道。查看各自的代碼就會發現,雖然兩個類型均有transact的方法,可是二者的做用不一樣,BpBinder的transact方法是向IPCThreadState實例發送消息,通知其有消息要發送給BD;而BBinder則是當IPCThreadState實例收到BD消息時,經過BBinder的transact的方法將其傳遞給它的子類BnSERVICE的onTransact函數執行server端的操做。

 

7. Parcel

Parcel是binder IPC中的最基本的通訊單元,它存儲C-S間函數調用的參數.可是Parcel只能存儲基本的數據類型,若是是複雜的數據類型的話,在存儲時,須要將其拆分爲基本的數據類型來存儲。

 

    簡單的Parcel讀寫再也不介紹,下面着重介紹一下2個函數

 

7.1 writeStrongBinder

當client須要將一個binder向server發送時,能夠調用此函數。例如

        virtual status_t addService(const String16& name, const sp<IBinder>& service)

        {

            Parcel data, reply;

            data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());

            data.writeString16(name);

            data.writeStrongBinder(service);

            status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);

            return err == NO_ERROR ? reply.readExceptionCode() : err;

        }

 

 

看一下writeStrongBinder的實體

status_t Parcel::writeStrongBinder(const sp<IBinder>& val)

{

    return flatten_binder(ProcessState::self(), val, this);

}

 

接着往裏看flatten_binder

status_t flatten_binder(const sp<ProcessState>& proc,

    const sp<IBinder>& binder, Parcel* out)

{

    flat_binder_object obj;

    

    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;

    if (binder != NULL) {

        IBinder *local = binder->localBinder();

        if (!local) {

            BpBinder *proxy = binder->remoteBinder();

            if (proxy == NULL) {

                LOGE("null proxy");

            }

            const int32_t handle = proxy ? proxy->handle() : 0;

            obj.type = BINDER_TYPE_HANDLE;

            obj.handle = handle;

            obj.cookie = NULL;

        } else {

            obj.type = BINDER_TYPE_BINDER;

            obj.binder = local->getWeakRefs();

            obj.cookie = local;

        }

    } else {

        obj.type = BINDER_TYPE_BINDER;

        obj.binder = NULL;

        obj.cookie = NULL;

    }

    

    return finish_flatten_binder(binder, obj, out);

}

 

    仍是拿addService爲例,它的參數爲一個BnINTERFACE類型指針,BnINTERFACE又繼承自BBinder,

    BBinder* BBinder::localBinder()

    {

        return this;

    }

    因此寫入到Parcel的binder類型爲BINDER_TYPE_BINDER,同時你在閱讀SM的代碼時會發現若是SM收到的service的binder類型不爲BINDER_TYPE_HANDLE時,SM將不會將此service添加到svclist,可是很顯然每一個service的添加都是成功的,addService在開始傳遞的binder類型爲BINDER_TYPE_BINDER,SM收到的binder類型爲BINDER_TYPE_HANDLE,那麼這個過程中究竟發生了什麼?

    爲了搞明白這個問題,花費我不少的事件,最終發現了問題的所在,原來在BD中作了以下操做(drivers/staging/android/Binder.c):

 

static void binder_transaction(struct binder_proc *proc,

                   struct binder_thread *thread,

                   struct binder_transaction_data *tr, int reply)

{

..........................................

 

    if (fp->type == BINDER_TYPE_BINDER)

        fp->type = BINDER_TYPE_HANDLE;

    else

        fp->type = BINDER_TYPE_WEAK_HANDLE;

    fp->handle = ref->desc;

..........................................

}

 

 

 

閱讀完addService的代碼,你會發現SM只是保存了service binder的handle和service的name,那麼當client須要和某個service通訊了,如何得到service的binder呢?看下一個函數

7.2 readStrongBinder

當server端收到client的調用請求以後,若是須要返回一個binder時,能夠向BD發送這個binder,當IPCThreadState實例收到這個返回的Parcel時,client能夠經過這個函數將這個被server返回的binder讀出。

 

sp<IBinder> Parcel::readStrongBinder() const

{

    sp<IBinder> val;

    unflatten_binder(ProcessState::self(), *this, &val);

    return val;

}

 

往裏查看unflatten_binder

 

status_t unflatten_binder(const sp<ProcessState>& proc,

    const Parcel& in, sp<IBinder>* out)

{

    const flat_binder_object* flat = in.readObject(false);

    

    if (flat) {

        switch (flat->type) {

            case BINDER_TYPE_BINDER:

                *out = static_cast<IBinder*>(flat->cookie);

                return finish_unflatten_binder(NULL, *flat, in);

            case BINDER_TYPE_HANDLE:

                *out = proc->getStrongProxyForHandle(flat->handle);

                return finish_unflatten_binder(

                    static_cast<BpBinder*>(out->get()), *flat, in);

        }        

    }

    return BAD_TYPE;

}

 

發現若是server返回的binder類型爲BINDER_TYPE_BINDER的話,也就是返回一個binder引用的話,直接獲取這個binder;若是server返回的binder類型爲BINDER_TYPE_HANDLE時,也就是server返回的僅僅是binder的handle,那麼須要從新建立一個BpBinder返回給client。

 

 

    有上面的代碼能夠看出,SM保存的service的binder僅僅是一個handle,而client則是經過向SM得到這個handle,從而從新構建代理binder與server通訊。

 

 

    這裏順帶提一下一種特殊的狀況,binder通訊的雙方便可做爲client,也能夠做爲server.也就是說此時的binder通訊是一個半雙工的通訊。那麼在這種狀況下,操做的過程會比單工的狀況複雜,可是基本的原理是同樣的,有興趣能夠分析一下MediaPlayer和MediaPlayerService的例子。

 

8. 經典橋段分析

main_ mediaserver.cpp

int main(int argc, char** argv)

{

//建立進程mediaserver的ProcessState實例

    sp<ProcessState> proc(ProcessState::self());

//得到SM的BpServiceManager

    sp<IServiceManager> sm = defaultServiceManager();

    LOGI("ServiceManager: %p", sm.get());

//添加mediaserver中支持的service。

    AudioFlinger::instantiate();

    MediaPlayerService::instantiate();

    CameraService::instantiate();

    AudioPolicyService::instantiate();

//啓動ProcessState的pool thread

    ProcessState::self()->startThreadPool();

//這一步有重複之嫌,加不加可有可無。

    IPCThreadState::self()->joinThreadPool();

}

 

9. Java 層的binder機制

瞭解了native通訊機制後,再去分析Java層的binder機制,就會很好理解了。它只是對native的binder作了一個封裝。這一部分基本上沒有太複雜的過程,這裏再也不贅述了。

相關文章
相關標籤/搜索