1. 程式人生 > >Binder通訊相關的類簡要分析

Binder通訊相關的類簡要分析

一、BpBinder

這個類通常作為IPC通訊的Client端,或者說Remote端,提供實際的IPC基礎通訊服務。在程式碼中通常不直接使用到該類,一般以成員變數的形式,包含於BpRefBase類中,通過remote()方法引用該成員變數。繼承關係如下:

BpXXX --> BpInterface<IXXX> --> BpRefBase

在BpXXX方法中,就可以直接通過remote()方法引用到BpBinder例項,繼而利用其提供的IPC通訊功能,通過Binder協議與另一端進行通訊。

BpBinder類的定義說明

成員變數分析:

const   int32_t             mHandle;//handle for remote obj

            void                reportOneDeath(const Obituary& obit);
            bool                isDescriptorCached() const;

    mutable Mutex               mLock;
            volatile int32_t    mAlive;
            volatile int32_t    mObitsSent; //we have already send Obit? can notify is object is already dead
            Vector<Obituary>*   mObituaries;//dead notification listerners
            ObjectManager       mObjects;
            Parcel*             mConstantData;
    mutable String16            mDescriptorCache;

mHandle: 這是一個重要的成員變數,代表Binder驅動為一個遠端物件分配的一個控制代碼,在Binder驅動中,通過該控制代碼號,找到對應的Binder引用結點,通過Binder引用結點,找到其引用的位於不同程序中的一個Binder結點,從而將利用該Binder結點將通訊資料路由到通訊的另一端所在的程序。

mLock:保護BpBinder物件的一些方法的訪問,從而保證任何時刻不會同時執行兩個或以上方法。

mAlive:Binder IPC通訊是否處於活躍狀態。

mObjects:物件管理,主要是對Java Binder物件的管理。

mConstantData:未使用

mDescriptorCache:儲存介面描述資訊。

主要方法分析:

  virtual status_t    transact(   uint32_t code,

                                    const Parcel&data,

                                    Parcel*reply,

                                    uint32_tflags = 0);

  該方法是Binder IPC通訊的入口,其實質上是呼叫IPCThreadState類的transact方法。

如下兩個介面則是提供監聽遠端物件死亡通知的介面。

   virtual status_t   linkToDeath(const sp<DeathRecipient>& recipient,

                                    void*cookie = NULL,

                                    uint32_tflags = 0);

   virtual status_t   unlinkToDeath(  constwp<DeathRecipient>& recipient,

                                        void*cookie = NULL,

                                       uint32_t flags = 0,

                                       wp<DeathRecipient>* outRecipient = NULL);

BpBinder物件作為遠端物件的代理,它會跟蹤遠端物件的狀態(實質上是在驅動中,跟蹤Binder通訊結點,結點死亡的資訊也是通過驅動層向用戶空間傳送的),一旦接收到死亡通知,則會呼叫如下介面通知所有監聽者:

void  sendObituary();

其會呼叫如下方法呼叫所有監聽者提供的回撥函式:

void reportOneDeath(const Obituary& obit);


二、BBinder

BBinder類作為Binder IPC通訊的Server端或Local端,處理來自Client端或Remote端的服務請求。它的主要方法就是處理請求:

status_t BBinder::transact(

   uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

在IPCThreadState中,是通過如下方式呼叫到上述的介面的:


IPCThreadState(979):         
case BR_TRANSACTION:
           …   
if (tr.target.ptr) {//local 
                sp<BBinder> b((BBinder*)tr.cookie);
                const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
                if (error < NO_ERROR) reply.setError(error);

            } else {//remote
                const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
                if (error < NO_ERROR) reply.setError(error);
            }

三、Java層類

Java層的類主要有Binder和BinderProxy,其中Binder跟BBinder一樣,屬於Server或Local端,而BinderProxy則與BpBinder一樣,屬於Client端或Remote端。

對於BinderProxy類物件,跟BpBinder一樣,同樣是作為XXXProxy的成員變數的形式包含於其中。

XXXProxy --> IXXX --> IInterface.

在JNI層,定義了兩個轉換函式:

jobject javaObjectForIBinder(JNIEnv* env,const sp<IBinder>& val);

sp<IBinder>ibinderForJavaObject(JNIEnv* env, jobject obj);

上述兩種函式提供了Java物件(主要是Binder和BinderProxy物件)與Native層IBinder物件之間的相互轉換介面。


當我們呼叫transact方法時,會經歷如下一些過程:

in BinderProxy.java

public native boolean transact(int code,Parcel data, Parcel reply,

           int flags) throws RemoteException;

-->

in android_util_Binder.cpp

static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
     …
    IBinder* target = (IBinder*)
        env->GetIntField(obj, gBinderProxyOffsets.mObject);
    …
    //printf("Transact from Java code to %p sending: ", target); data->print();
    status_t err = target->transact(code, *data, reply, flags);
    …
    return JNI_FALSE;
}

其中gBinderProxyOffsets.mObject是通過javaObjectForIBinder設定的,它的原型如下:

jobject javaObjectForIBinder(JNIEnv* env,const sp<IBinder>& val);

對於上述函式,除非引數val是JavaBBinder(繼承自BBinder)物件,否則,就建立一個BinderProxy物件,它與一個BpBinder物件關聯。

-->

接下來就會呼叫某個IBinder(C++類)物件的transact方法。

這個IBinder物件是BpBinder型別的,即:

BpBinder::transact(…)

--> IPCThreadState::transact(…)

它會向Binder驅動傳送一個BC_TRANSACTION命令,Binder驅動進行處理,將請求路由給通訊的另一端,並通過命令BR_TRANSACTION告知使用者空間,有新的通訊請求。在介紹BBinder的時候,我們提到過,接收端會呼叫BBinder::transact(…)來處理請求,對於Java層的通訊來說,則會實際呼叫JavaBBinder::transact(…)來處理請求,而實際上會呼叫onTransact(…)(過載了BBinder的方法),如下所示:


class JavaBBinder : public BBinder
{
…
protected:
…

    virtual status_t onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
    {
        …

        //printf("Transact from %p to Java code sending: ", this);
        //data.print();
        //printf("\n");
        jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
            code, (int32_t)&data, (int32_t)reply, flags);
      
        …

        // Need to always call through the native implementation of
        // SYSPROPS_TRANSACTION.
        if (code == SYSPROPS_TRANSACTION) {
            BBinder::onTransact(code, data, reply, flags);
        }

       …
    }

…
};

-->

in Binder.java

// Entry point from android_util_Binder.cpp's onTransact
    private boolean execTransact(int code, int dataObj, int replyObj,
            int flags) {
        …
        boolean res;
        try {
            res = onTransact(code, data, reply, flags);
        } …

        return res;
    }

最終呼叫到了Binder類的onTransact方法。從Binder類派生的類都會過載該方法。