一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Android Binder機制(超級詳盡)

 昵稱14797374 2014-10-20

1.binder通信概述

    binder通信是一種client-server的通信結(jié)構(gòu),
    1.從表面上來看,是client通過獲得一個server的代理接口,對server進行直接調(diào)用;
    2.實際上,代理接口中定義的方法與server中定義的方法是一一對應(yīng)的;
    3.client調(diào)用某個代理接口中的方法時,代理接口的方法會將client傳遞的參數(shù)打包成為Parcel對象;
    4.代理接口將該Parcel發(fā)送給內(nèi)核中的binder driver.
    5.server會讀取binder driver中的請求數(shù)據(jù),如果是發(fā)送給自己的,解包Parcel對象,處理并將結(jié)果返回;
    6.整個的調(diào)用過程是一個同步過程,在server處理的時候,client會block住。

 

 

 

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時,應(yīng)該首先向SM查詢是否存在該服務(wù)。如果SM存在這個service,那么會將該service的handle返回給client,handle是每個service的唯一標(biāo)識符。
   
    SM的入口函數(shù)在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設(shè)備;在內(nèi)存中為binder映射128K字節(jié)空間;
    2.指定SM對應(yīng)的代理binder的handle為0,當(dāng)client嘗試與SM通信時,需要創(chuàng)建一個handle為0的代理binder,這里的代理binder其實就是第一節(jié)中描述的那個代理接口;

3.通知binder driver(BD)使SM成為BD的context manager;
4.維護一個死循環(huán),在這個死循環(huán)中,不停地去讀內(nèi)核中binder driver,查看是否有可讀的內(nèi)容;即是否有對service的操作要求, 如果有,則調(diào)用svcmgr_handler回調(diào)來處理請求的操作。

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

 



這里需要聲明一下,當(dāng)service在向SM注冊時,該service就是一個client,而SM則作為了server。而某個進程需要與service通信時,此時這個進程為client,service才作為server。因此service不一定為server,有時它也是作為client存在的。

 

由于下面幾節(jié)會介紹一些與binder通信相關(guān)的幾個概念,所以將SM的功能介紹放在了后面的部分來講。

應(yīng)用和service之間的通信會涉及到2次binder通信。

1.應(yīng)用向SM查詢service是否存在,如果存在獲得該service的代理binder,此為一次binder通信;
2.應(yīng)用通過代理binder調(diào)用service的方法,此為第二次binder通信。

3.ProcessState

ProcessState是以單例模式設(shè)計的。每個進程在使用binder機制通信時,均需要維護一個ProcessState實例來描述當(dāng)前進程在binder通信時的binder狀態(tài)。
    ProcessState有如下2個主要功能:
    1.創(chuàng)建一個thread,該線程負責(zé)與內(nèi)核中的binder模塊進行通信,稱該線程為Pool thread;
    2.為指定的handle創(chuàng)建一個BpBinder對象,并管理該進程中所有的BpBinder對象。

 

3.1 Pool thread

            在Binder IPC中,所有進程均會啟動一個thread來負責(zé)與BD來直接通信,也就是不停的讀寫B(tài)D,這個線程的實現(xiàn)主體是一個IPCThreadState對象,下面會介紹這個類型。

            下面是 Pool thread的啟動方式:

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

3.2 BpBinder獲取

BpBinder主要功能是負責(zé)client向BD發(fā)送調(diào)用請求的數(shù)據(jù)。它是client端binder通信的核心對象,通過調(diào)用transact函數(shù)向BD發(fā)送調(diào)用請求的數(shù)據(jù),它的構(gòu)造函數(shù)如下:

BpBinder(int32_t handle);
    通過BpBinder的構(gòu)造函數(shù)發(fā)現(xiàn),BpBinder會將當(dāng)前通信中server的handle記錄下來,當(dāng)有數(shù)據(jù)發(fā)送時,會通知BD數(shù)據(jù)的發(fā)送目標(biāo)。

ProcessState通過如下方式來獲取BpBinder對象:

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

在這個過程中,ProcessState會維護一個BpBinder的vector mHandleToObject,每當(dāng)ProcessState創(chuàng)建一個BpBinder的實例時,回去查詢mHandleToObject,如果對應(yīng)的handle已經(jīng)有binder指針,那么不再創(chuàng)建,否則創(chuàng)建binder并插入到mHandleToObject中。
    ProcessState創(chuàng)建的BpBinder實例,一般情況下會作為參數(shù)構(gòu)建一個client端的代理接口,這個代理接口的形式為BpINTERFACE,例如在與SM通信時,client會創(chuàng)建一個代理接口BpServiceManager.
    
   

4.IPCThreadState

IPCThreadState也是以單例模式設(shè)計的。由于每個進程只維護了一個ProcessState實例,同時ProcessState只啟動一個Pool thread,也就是說每一個進程只會啟動一個Pool thread,因此每個進程則只需要一個IPCThreadState即可。
    Pool thread的實際內(nèi)容則為:
    IPCThreadState::self()->joinThreadPool();

 

ProcessState中有2個Parcel成員,mIn和mOut,Pool thread會不停的查詢BD中是否有數(shù)據(jù)可讀,如果有將其讀出并保存到mIn,同時不停的檢查mOut是否有數(shù)據(jù)需要向BD發(fā)送,如果有,則將其內(nèi)容寫入到BD中,總而言之,從BD中讀出的數(shù)據(jù)保存到mIn,待寫入到BD中的數(shù)據(jù)保存在了mOut中。

ProcessState中生成的BpBinder實例通過調(diào)用IPCThreadState的transact函數(shù)來向mOut中寫入數(shù)據(jù),這樣的話這個binder IPC過程的client端的調(diào)用請求的發(fā)送過程就明了了。

 

IPCThreadState有兩個重要的函數(shù),talkWithDriver函數(shù)負責(zé)從BD讀寫數(shù)據(jù),executeCommand函數(shù)負責(zé)解析并執(zhí)行mIn中的數(shù)據(jù)。

5.主要基類

5.1基類IInterface

為server端提供接口,它的子類聲明了service能夠?qū)崿F(xiàn)的所有的方法;


5.2基類IBinder
    BBinder與BpBinder均為IBinder的子類,因此可以看出IBinder定義了binder IPC的通信協(xié)議,BBinder與BpBinder在這個協(xié)議框架內(nèi)進行的收和發(fā)操作,構(gòu)建了基本的binder IPC機制。
5.3基類BpRefBase
    client端在查詢SM獲得所需的的BpBinder后,BpRefBase負責(zé)管理當(dāng)前獲得的BpBinder實例。

 

 

6.兩個接口類

6.1 BpINTERFACE

如果client想要使用binder IPC來通信,那么首先會從SM出查詢并獲得server端service的BpBinder,在client端,這個對象被認為是server端的遠程代理。為了能夠使client能夠想本地調(diào)用一樣調(diào)用一個遠程server,server端需要向client提供一個接口,client在在這個接口的基礎(chǔ)上創(chuàng)建一個BpINTERFACE,使用這個對象,client的應(yīng)用能夠想本地調(diào)用一樣直接調(diào)用server端的方法。而不用去關(guān)心具體的binder IPC實現(xiàn)。
下面看一下BpINTERFACE的原型:
    class BpINTERFACE : public BpInterface<IINTERFACE>

    順著繼承關(guān)系再往上看
    template<typename INTERFACE>
    class BpInterface : public INTERFACE, public BpRefBase

    BpINTERFACE分別繼承自INTERFACE,和BpRefBase;
● BpINTERFACE既實現(xiàn)了service中各方法的本地操作,將每個方法的參數(shù)以Parcel的形式發(fā)送給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通過調(diào)用BpRefBase的remote()來獲得BpBinder指針。

 

6.2 BnINTERFACE

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

    順著BnINTERFACE的繼承關(guān)系再往上看,
        class BnINTERFACE: public BnInterface<IINTERFACE>

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

    再往上看
        class BnInterface : public INTERFACE, public BBinder

    同時我們發(fā)現(xiàn)了BBinder類型,這個類型又是干什么用的呢?既然每個service均可視為一個binder,那么真正的server端的binder的操作及狀態(tài)的維護就是通過繼承自BBinder來實現(xiàn)的。可見BBinder是service作為binder的本質(zhì)所在。

    那么BBinder與BpBinder的區(qū)別又是什么呢?

    其實它們的區(qū)別很簡單,BpBinder是client端創(chuàng)建的用于消息發(fā)送的代理,而BBinder是server端用于接收消息的通道。查看各自的代碼就會發(fā)現(xiàn),雖然兩個類型均有transact的方法,但是兩者的作用不同,BpBinder的transact方法是向IPCThreadState實例發(fā)送消息,通知其有消息要發(fā)送給BD;而BBinder則是當(dāng)IPCThreadState實例收到BD消息時,通過BBinder的transact的方法將其傳遞給它的子類BnSERVICE的onTransact函數(shù)執(zhí)行server端的操作。

 

7. Parcel

Parcel是binder IPC中的最基本的通信單元,它存儲C-S間函數(shù)調(diào)用的參數(shù).但是Parcel只能存儲基本的數(shù)據(jù)類型,如果是復(fù)雜的數(shù)據(jù)類型的話,在存儲時,需要將其拆分為基本的數(shù)據(jù)類型來存儲。

    簡單的Parcel讀寫不再介紹,下面著重介紹一下2個函數(shù)

 

7.1 writeStrongBinder

當(dāng)client需要將一個binder向server發(fā)送時,可以調(diào)用此函數(shù)。例如
        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為例,它的參數(shù)為一個BnINTERFACE類型指針,BnINTERFACE又繼承自BBinder,
    BBinder* BBinder::localBinder()
    {
        return this;
    }
    所以寫入到Parcel的binder類型為BINDER_TYPE_BINDER,同時你在閱讀SM的代碼時會發(fā)現(xiàn)如果SM收到的service的binder類型不為BINDER_TYPE_HANDLE時,SM將不會將此service添加到svclist,但是很顯然每個service的添加都是成功的,addService在開始傳遞的binder類型為BINDER_TYPE_BINDER,SM收到的binder類型為BINDER_TYPE_HANDLE,那么這個過程當(dāng)中究竟發(fā)生了什么?
    為了搞明白這個問題,花費我很多的事件,最終發(fā)現(xiàn)了問題的所在,原來在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的代碼,你會發(fā)現(xiàn)SM只是保存了service binder的handle和service的name,那么當(dāng)client需要和某個service通信了,如何獲得service的binder呢?看下一個函數(shù)

7.2 readStrongBinder

當(dāng)server端收到client的調(diào)用請求之后,如果需要返回一個binder時,可以向BD發(fā)送這個binder,當(dāng)IPCThreadState實例收到這個返回的Parcel時,client可以通過這個函數(shù)將這個被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;
}


發(fā)現(xiàn)如果server返回的binder類型為BINDER_TYPE_BINDER的話,也就是返回一個binder引用的話,直接獲取這個binder;如果server返回的binder類型為BINDER_TYPE_HANDLE時,也就是server返回的僅僅是binder的handle,那么需要重新創(chuàng)建一個BpBinder返回給client。


    有上面的代碼可以看出,SM保存的service的binder僅僅是一個handle,而client則是通過向SM獲得這個handle,從而重新構(gòu)建代理binder與server通信。


    這里順帶提一下一種特殊的情況,binder通信的雙方即可作為client,也可以作為server.也就是說此時的binder通信是一個半雙工的通信。那么在這種情況下,操作的過程會比單工的情況復(fù)雜,但是基本的原理是一樣的,有興趣可以分析一下MediaPlayer和MediaPlayerService的例子。

 

8. 經(jīng)典橋段分析

main_ mediaserver.cpp
int main(int argc, char** argv)
{

//創(chuàng)建進程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();

//這一步有重復(fù)之嫌,加不加無關(guān)緊要。
    IPCThreadState::self()->joinThreadPool();
}

 

9. Java 層的binder機制

了解了native通信機制后,再去分析JAVA層的binder機制,就會很好理解了。它只是對native的binder做了一個封裝。這一部分基本上沒有太復(fù)雜的過程,這里不再贅述了。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    日韩成人动画在线观看| 99日韩在线视频精品免费| 日本人妻精品有码字幕| 国内外免费在线激情视频| 日本福利写真在线观看| 免费大片黄在线观看国语| 国产不卡免费高清视频| 国产成人一区二区三区久久| 日韩精品视频免费观看| 亚洲高清中文字幕一区二区三区| 五月情婷婷综合激情综合狠狠| 国产丝袜极品黑色高跟鞋| 亚洲精品成人综合色在线| 最新国产欧美精品91| 亚洲午夜精品视频在线| 中文字幕一区久久综合| 日韩国产精品激情一区| 国产精品国产亚洲区久久| 麻豆精品在线一区二区三区| 日韩aa一区二区三区| 国产黄色高清内射熟女视频| 亚洲一区二区三区三区| 欧美中文字幕日韩精品| 伊人久久青草地综合婷婷| 亚洲欧美国产精品一区二区| 色综合久久中文综合网| 国内外免费在线激情视频| 久久精品国产亚洲av久按摩| 99久久国产精品成人观看| 成人日韩在线播放视频| 欧美国产日产在线观看| 人妻一区二区三区多毛女| 国产老熟女乱子人伦视频| 亚洲性生活一区二区三区| 中文字幕高清不卡一区| 亚洲男人的天堂就去爱| 高清在线精品一区二区| 中文字幕区自拍偷拍区| 国产又爽又猛又粗又色对黄| 九九热九九热九九热九九热| 国产麻豆一线二线三线|