Binder c++試驗、分析與理解

Binder c++試驗、分析與理解

本文的文章結構和內容依賴於韋東山老師講解的Binder系統(免費課程),歡迎前往韋東山老師主站http://www.100ask.org瞭解詳情。


1. Binder系統_c++實現

1.1 程序結構

在這裏插入圖片描述

1.2 程序結構

  1. 抽象共同的部分爲接口,BnHelloService實現native方法,實現提供具體的服務。BpHelloservice實現服務的代理,服務使用的實現。
    在這裏插入圖片描述
  2. server端和client端,server端添加服務,進入循環體等待client端調用。client端得到服務,通過得到的服務,調用服務中的函數。
    在這裏插入圖片描述

1.3 具體代碼

  1. IHelloService.h
    定義IHelloservice接口,聲明BnHelloservice。
#define HELLO_SVR_CMD_SAYHELLO 0
#define HELLO_SVR_CMD_SAYHELLO_TO 1

namespace android{

class IHelloService: public IInterface
{
public:
    DECLARE_META_INTERFACE(HelloService);
    virtual void sayhello(viod) = 0;
    virtual int sayhello_to(const char *name) = 0;
};

//繼承IHelloService接口
class BnHelloService:public BnInterface<IHelloService>
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
    virtual void sayhello(void);
    virtual int sayhello_to(const char *name);
};
  1. BnHelloService.cpp
namespace android{
//收到binder調用,來解析傳過來的數據
status_t    onTransact( uint32_t code,
                                const Parcel& data,
                                Parcel* reply,
                                uint32_t flags = 0)
{
    /* 解析數據,調用sayhello/sayhello_to*/
    switch (code) {
        case HELLO_SVR_CMD_SAYHELLO: {
            sayhello();
            return NO_ERROR;
        } break;
        case HELLO_SVR_CMD_SAYHELLO_TO: {
            /*取出傳入的數據*/
            int32_t policy = data.readInt32();
            String16 name16 = data.readString16();
            String8 name8(name16);

            /*調用執行函數*/
            int ret = sayhello_to(name8);
            /*把返回值返回回去*/
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        default:
            return BBinder::onTransact( code, data, reply, flags);
    }
}
void sayhello(void)
{
    static int cnt = 0;
    ALOGD("say hello : %d", cnt++);
}
int sayhello_to(const char *name)
{
    static int cnt = 0;
    ALOGD("say hello to %s : %d", name, cnt++);
}

Binder native實現,收到Binder的Bp端調用後,進入onTransact函數,解析數據並調用native方法。

  1. BpHelloService.cpp
namespace android{

class BpHelloService: public BpInterface<IHelloService>
{
public:
    BpHelloService(const sp<IBinder>& impl)
        : BpInterface<IHelloService>(impl)
    {
    }
    void sayhello(void)
    {
        Parcel data, reply;
        data.writeInt32(0);
        remote()->transact(HELLO_SVR_CMD_SAYHELLO, data, &reply);
    }
    int sayhello_to(const char *name)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
        data.writeStrongBinder(IInterface::asBinder(client));
        data.writeInt32(audioSessionId);

        remote()->transact(CREATE, data, &reply);
        return interface_cast<IMediaPlayer>(reply.readStrongBinder());
    }
}
IMPLEMENT_META_INTERFACE(HelloService, "android.media.IHelloService");
}

Binder 代理端,實現了數據構造和消息發送。

  1. test_server.cpp
using namespace android;

void main(void)
{
    /*addService*/

    /*while(1){讀取數據,解析數據,根據數據調用服務函數}*/

    /*打開binder驅動,mmap*/
    sp<ProcessState> proc(ProcessState::self());

    /*獲取BpServiceManager*/
    sp<IServiceManager> sm = defaultServiceManager();
    ALOGI("ServiceManager: %p", sm.get());
    /*添加服務*/
    sm->addService(String16("hello"), new BnHelloService());
    /*開啓循環,線程池使用場景*/
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}

獲取ServiceManager的binder代理Bp,然後調用服務中的方法添加服務,爲本服務進程創建線程池。進入循環體,等待客戶端使用。

  1. test_client.cpp
int main(int argc, char **argv)
{
    if(argc < 2){
        ALOGD("Help:");
        ALOGD("%s <hello>", argv[0]);
        ALOGD("%s <hello> <name>",argv[0]);
        return -1;
    }
    /*獲得service*/
    /*打開binder驅動,mmap*/
    sp<ProcessState> proc(ProcessState::self());
    /*獲取BpServiceManager*/
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService(String16("hello"));
    if(binder == 0){
        ALOGD("error: can't get hello service");
        return -1;
    }
    //interface_cast<Interface>(binder句柄),通過句柄轉化爲服務
    sp<IHelloService> service = interface_cast<IHelloService>(binder);
    if(argv < 3){
        ALOGD("client call sayhello");
        service->sayhello();
    } else if(argv = 3){
        ALOGD("client call sayhello_to : %s", argv[2]);
        int ret = service->sayhello_to(argv[2]);
        ALOGD("service sayhello_to return ret = %d", ret);
    }
}

和service端一樣,先獲取BpServiceManager,然後調用sm中的方法得到服務。通過interface_cast轉化binder句柄得到服務,通過服務調用BpHelloService中的方法,再通過binder調用到BnHelloService中的方法。這部分的具體調用過程下節分析。

1.4 測試

t7-p1:/ # logcat | grep HelloService &
[1] 19137 19138
t7-p1:/ # cd system/bin/
t7-p1:/system/bin # ./test_server &
[2] 22678
t7-p1:/system/bin # 01-01 08:02:05.613 22678 22678 I HelloService: ServiceManager: 0xb6a99360
t7-p1:/system/bin # ./test_client hello
01-01 08:02:20.548 25031 25031 D HelloService: client call sayhello
01-01 08:02:20.548 22678 22678 D HelloService: HelloService :say hello : 0
t7-p1:/system/bin # ./test_client hello cuishang
01-01 08:02:25.947 25684 25684 D HelloService: client call sayhello_to : cuishang
01-01 08:02:25.947 22678 22691 D HelloService: HelloService:say hello to cuishang : 0
01-01 08:02:25.948 25684 25684 D HelloService: service sayhello_to return ret = 1

測試成功,先啓動server,然後執行client。能夠調用到server的方法。

這裏先梳理一波,相比c程序,使用了android的Binder驅動和ServiceManager,抽象出了IHelloService接口,BpHelloService和BnHelloService類,Bp(Binder proxy)屬於客戶端,Binder的服務代理。app通過調Bp進而調用到BnHelloService。BpHelloService屬於服務端,

2. Binder系統_c++實現_內部機制

2.1 獲取BpServiceManager的對象

  1. 無論server端還是client端首先都要,獲得BpServiceManager對象過程:
//步驟1
sp<ProcessState> proc(ProcessState::self());
//步驟2
sp<IServiceManager> sm = defaultServiceManager();

步驟1. 在Android系統中,只要涉及到Binder通訊過程都需要存在依據,也就是Android Framework經常出現的一條語句。
ProcessState::self()函數是ProcessState類中的一個靜態函數,屬於這個類,不屬於某個具體的對象。

class ProcessState : public virtual RefBase
{
public:
    static  sp<ProcessState>    self();
...    
}

具體函數:

Mutex gProcessMutex;
sp<ProcessState> gProcess;//全局變量
...
sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }
    gProcess = new ProcessState;
    return gProcess;
}

從函數中可以看到單例模式,gProcess是ProcessState類的對象,在每個進程中只有一個。
接下來看下ProcessState的構造函數:

ProcessState::ProcessState(const char *driver)
    : mDriverFD(open_driver(driver))
...
    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
...
{
    if (mDriverFD >= 0) {
        // 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);
      ...
    }
...
}

首先打開binder驅動,在binder驅動中,會爲當前進程創建binder節點,構造binder在內核空間所需要的數據結構。這部分不清楚的可以看文章 《Binder系統_驅動情景分析》

mDriverFD(open_driver(driver))

然後設置當前進程的最大線程數:

mMaxThreads(DEFAULT_MAX_BINDER_THREADS)

然後當打開binder驅動成功,對內核空間的內存進行映射到用戶空間:

mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);

其中mVMStart就是用戶空間虛擬內存的首地址。當前進程就可以通過操作此地址來直接操作內核空間的內存。

所以ProcessState::self() == gProcess,ProcessState的對象,包含當前進程的binder信息。

步驟2. 獲取sm的服務。
首先分析defaultServiceManager //IServiceManager.cpp

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

同樣也是一個單例模式,獲得一個IServiceManager的對象gDefaultServiceManager。
其中interface_cast:把BpBinder(mHandle=0)對象轉換爲IServiceManager接口實例BpServiceManager的對象。

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}

接下來繼續分析 ProcessState::self()->getContextObject(NULL)
由步驟1分析的知ProcessState::self()爲當前進程包含binder信息ProcessState的對象。
ProcessState::getContextObject(NULL);

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);
}

繼續跟蹤getStrongProxyForHandle,傳入的參數爲0:

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
...
    handle_entry* e = lookupHandleLocked(handle);
    if (e != NULL) {
...
            b = new BpBinder(handle); 
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
...
    return result;
}

繼續跟蹤b = new BpBinder(handle);

BpBinder::BpBinder(int32_t handle)
    : mHandle(handle)
    , mAlive(1)
    , mObitsSent(0)
    , mObituaries(NULL)
{
    ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);

    extendObjectLifetime(OBJECT_LIFETIME_WEAK);
    IPCThreadState::self()->incWeakHandle(handle);
}

handle = 0 = mHandle

因爲sm的binder節點handle爲0。通過interface_cast的轉化後最終得到BpServiceManager類的對象,即sm。所以BpServiceManager爲sm的代理類。

2.2 獲得BpHelloService對象

首先server端添加服務

    /*添加服務*/
    sm->addService(String16("hello"), new BnHelloService());
    /*開啓循環,線程池使用場景*/
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();

通過調用sm的方法,傳入字符串“hello”和binder本地實現類的對象,添加一個Hello服務。
然後開啓線程池使進程進入循環。

然後client端獲取服務

步驟1
    sp<IBinder> binder = sm->getService(String16("hello"));
    if(binder == 0){
        ALOGD("error: can't get hello service");
        return -1;
    }
步驟2
    //interface_cast<Interface>(binder句柄),通過句柄轉化爲服務
    sp<IHelloService> service = interface_cast<IHelloService>(binder);

步驟1. 調用BpServiceManager的getService函數獲得一個flat_binder_object。

    virtual sp<IBinder> getService(const String16& name) const
    {
        unsigned n;
        for (n = 0; n < 5; n++){
            sp<IBinder> svc = checkService(name);
            if (svc != NULL) return svc;
            ALOGI("Waiting for service %s...\n", String8(name).string());
            sleep(1);
        }
        return NULL;
    }

checkService:

    virtual sp<IBinder> checkService( const String16& name) const
    {
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);
        remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
        return reply.readStrongBinder();
    }

通過 remote()->transact發送數據,經過驅動程序後傳遞到sm的svcmgr_handler函數。這部分的具體調用放到本章節第三小節中分析。

int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
...
    switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
        if (!handle)
            break;
        bio_put_ref(reply, handle);
        return 0;
...
}

do_find_service查找服務,這裏就不繼續展開了,跟着這個函數往下追很容易追到,結果是通過掃描一個列表,對名字進行匹配,然後得到一個整數,即hello service的handle值。

分析 reply.readStrongBinder();

status_t Parcel::readStrongBinder(sp<IBinder>* val) const
{
    return unflatten_binder(ProcessState::self(), *this, val);
}

sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
    readStrongBinder(&val);
    return val;
}

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

一直調用到unflatten_binder,由於是返回handle走的是case BINDER_TYPE_HANDLE,*out = proc->getStrongProxyForHandle(flat->handle);

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
...
    handle_entry* e = lookupHandleLocked(handle);
    if (e != NULL) {
...
            b = new BpBinder(handle); 
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
...
    return result;
}

有調用到getStrongProxyForHandle,與之前不同的是,之前handle是爲0,現在的handle是helllo service在sm中的handle值。

sp<IHelloService> service = interface_cast<IHelloService>(binder);

然後通過interface_cast 把binder轉換爲IHelloService接口(BpHelloService對象)。

2.3 代理類如何發送數據

以BpHelloService爲例:

    int sayhello_to(const char *name)
    {
        Parcel data, reply;
        步驟1
        data.writeInt32(0);
        data.writeString16(String16(name));
        步驟2
        remote()->transact(HELLO_SVR_CMD_SAYHELLO_TO, data, &reply);
        return reply.readInt32();
    }

步驟1. 構造數據。
步驟2. 調用remote->transact來發送數據。
remote的來源:

class BpHelloService: public BpInterface<IHelloService>

class BpInterface : public INTERFACE, public BpRefBase

BpHelloService繼承自BpInterface,BpInterface繼承自BpRefBase。
看下BpRefBase:

class BpRefBase : public virtual RefBase
{
protected:
                            BpRefBase(const sp<IBinder>& o);
    virtual                 ~BpRefBase();
    virtual void            onFirstRef();
    virtual void            onLastStrongRef(const void* id);
    virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);

    inline  IBinder*        remote()                { return mRemote; }
    inline  IBinder*        remote() const          { return mRemote; }

private:
                            BpRefBase(const BpRefBase& o);
    BpRefBase&              operator=(const BpRefBase& o);

    IBinder* const          mRemote;
    RefBase::weakref_type*  mRefs;
    std::atomic<int32_t>    mState;
};

其中remote = mRemote 返回的是BpBinder的對象,調用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;
}

也就是調用binder中的transact發送給hello service。
下面是照抄韋東山老師畫的類圖,對於理解有很大幫助。
BpServiceManager類繼承關係:
在這裏插入圖片描述

BpBinder類繼承關係:
在這裏插入圖片描述
HelloService服務類繼承關係:

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章