Android binder機制學習總結

       binder通信機制是Android系統最重要的一種通信機制,也是一種C/S架構的通信機制,客戶端和服務器端通過binder驅動進行通信。其架構如下圖所示。

      在binder通信機制中,客戶端使用的是一個代理類BpBinder,而服務器端使用的是BBinder類,這兩個類都是繼承了抽象類IBinder。而BpBiner類中的成員函數transact用來向服務器端發送請求(實際上是往binder驅動發的),而binder驅動在收到請求後會通知相應的服務端,該服務端的BBinder的成員函數OnTransact函數會被調用來處理客戶端發送過來的數據。這兩個成員函數一般都會被具體的代理類和本地類重載。這是業務層的事情了。

       在binder通信機制中有一個抽象類非常重要,且要自己實現。這個類一般使用Ixxx來表示如(IServiceManager),個人認爲這個抽象類最重要的有兩點,第一定義業務層需要用的純虛函數(如IServiceManager裏的addService和getService)。第二定義和實現兩個宏。DECLEAR_META_INTERFACE和IMPLEMENT_META_INTERFACE.在獲取代理類的時候需要用到asinterface這個函數。

#define DECLARE_META_INTERFACE(INTERFACE)                               \
    static const android::String16 descriptor;                          \
    static android::sp<I##INTERFACE> asInterface(                       \
            const android::sp<android::IBinder>& obj);                  \
    virtual const android::String16& getInterfaceDescriptor() const;    \
    I##INTERFACE();                                                     \
    virtual ~I##INTERFACE();                                            \


#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
    const android::String16 I##INTERFACE::descriptor(NAME);             \
    const android::String16&                                            \
            I##INTERFACE::getInterfaceDescriptor() const {              \
        return I##INTERFACE::descriptor;                                \
    }                                                                   \
    android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \
            const android::sp<android::IBinder>& obj)                   \
    {                                                                   \
        android::sp<I##INTERFACE> intr;                                 \
        if (obj != NULL) {                                              \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == NULL) {                                         \
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    } 

一、ServiceManager

        ServiceManager是一個管理者的角色,服務器端用它來註冊服務,而客戶端用它來獲取服務,通過獲取服務可以得到一個IBinder類,從而在客戶端可以獲取代理類。服務器端註冊服務和客戶端獲取服務時,無論時客戶端還是服務器端均可看成是客戶端,而ServiceManager則是對應的服務器端。ServiceManager和普通的服務器端不一樣,不是用Bnxxx類來處理數據的。

(1)、獲取ServiceManager的代理類

      defaultServiceManager函數中調用模板函數interface_cast獲取ServiceManager的代理類BpServiceManager,而interface_cast函數就是調用了IMPLEMENT_META_INTERFACE宏中實現的asinterface函數來獲取的,而BpServiceManager的mRemoter成員則是使用ProcessSate類的成員函數getContextObject來獲得的。

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;
}
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);
}

 

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);

    handle_entry* e = lookupHandleLocked(handle);

    if (e != NULL) {
        // We need to create a new BpBinder if there isn't currently one, OR we
        // are unable to acquire a weak reference on this current one.  See comment
        // in getWeakProxyForHandle() for more info about this.
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            if (handle == 0) {
                // Special case for context manager...
                // The context manager is the only object for which we create
                // a BpBinder proxy without already holding a reference.
                // Perform a dummy transaction to ensure the context manager
                // is registered before we create the first local reference
                // to it (which will occur when creating the BpBinder).
                // If a local reference is created for the BpBinder when the
                // context manager is not present, the driver will fail to
                // provide a reference to the context manager, but the
                // driver API does not return status.
                //
                // Note that this is not race-free if the context manager
                // dies while this code runs.
                //
                // TODO: add a driver API to wait for context manager, or
                // stop special casing handle 0 for context manager and add
                // a driver API to get a handle to the context manager with
                // proper reference counting.

                Parcel data;
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }

            b = new BpBinder(handle); 
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            // This little bit of nastyness is to allow us to add a primary
            // reference to the remote proxy when this team doesn't have one
            // but another team is sending the handle to us.
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }

    return result;
}

        需要注意handle的值,在binder驅動中根據該值來查找相應的本地類。

(2)、ServiceManager本地端

       ServiceManager本地端沒有對應的本地類BnServiceManager,而且其本地端是用C語言而非C++來寫的。他是通過循環讀取binder驅動的數據然後解析來獲得代理類發過來的消息的。具體的可以通過/framework/native/cmds/servicemanager/service_manager.c來查看它的源碼。

(3)、添加Service服務

        服務端通過IserviceManager的成員函數addService來通知ServiceManager來註冊對應的服務。

 virtual status_t addService(const String16& name, const sp<IBinder>& service,
            bool allowIsolated)
 {
    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);
    return err == NO_ERROR ? reply.readExceptionCode() : err;
 }                

 (4)、獲取Service服務

       客戶端通過IServiceManager抽象類的成員函數getService來通知ServiceManager來獲取服務(其實就是獲取BpBinder)。

template<typename INTERFACE>
status_t getService(const String16& name, sp<INTERFACE>* outService)
{
    const sp<IServiceManager> sm = defaultServiceManager();
    if (sm != NULL) {
        *outService = interface_cast<INTERFACE>(sm->getService(name));
        if ((*outService) != NULL) return NO_ERROR;
    }
    return NAME_NOT_FOUND;
}

特別需要關注的addService函數和getService函數的name參數必須是一致的才能把本地類和代理類對應起來。

二、client 

       客戶端通過代理類來發送數據給服務端,最終是通過BpBinder類的成員函數transact向服務端發送數據。BpBinder的獲取是向ServiceManager獲得的,然後通過函數asInterface函數來獲取其自身的代理類。其過程如下。

      第一步,使用defaultServiceManager獲得ServiceManager的代理類BpServiceManager。

      第二步,使用BpServiceManager的getService獲取其自己的BpBinder。BpServiceManager是繼承IServiceManager,所以IServiceManager的成員函數getService也是BpServiceManager的成員函數。

      第三步,通過其自己的抽象類中定義的asInterface函數獲取自己的代理類,而後可以通過代理類進行通信。

      代理類的繼承關係如下圖所示:

三、服務端

       服務端的service繼承了他的本地類,而其對應的代理類發送數據過來通信的時候本地類的成員函數OnTransact被調用,可以通過這個函數真正操作一些設備。另外服務端還要想ServiceManager註冊服務,才能讓其對應的客戶端找到相應的代理類。另外service類要實現函數OnTransact,addService函數裏第二個參數不用Bnxxx而使用service類xxx。

本地類的繼承關係如下圖所示:

總結:這是個人對binder機制的理解,可能有些地方寫的不是很好,有錯誤的地方也希望各位能夠指正。另外binder機制裏面代理類和本地類的繼承關係,相當重要,只有搞懂了這些繼承關係才能真正的運用好這些類。

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