Parcel在binder通信readStrongBinder和writeStrongBinder


Binder IPC通信中,Binder是通信的媒介,Parcel是通信的內容。遠程調用過程中,其參數都被打包成Parcel的形式來傳遞。

在IPC通信的Proxy端,我們經常可以看到下面類似的代碼,一些參數都會打包到Parcel中。看下面的data和reply。

public void publishService(IBinder token,
            Intent intent, IBinder service) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(token);
        intent.writeToParcel(data, 0);
        data.writeStrongBinder(service);
        mRemote.transact(PUBLISH_SERVICE_TRANSACTION, data, reply, 0);
        reply.readException();
        data.recycle();
        reply.recycle();
    }

在IPC通信里,android是通過Parcel類的成員函數writeStrongBinder()向Parcel寫入IBinder,再通過mRemote發送出去。

2.writeStrongBinder()

接下來就看一下writeStrongBinder()這個函數里做了什么。
/frameworks/base/core/java/android/os/Parcel.java

public final class Parcel {
    …
    /**
     * Write an object into the parcel at the current dataPosition(),
     * growing dataCapacity() if needed.
     */
    public final void writeStrongBinder(IBinder val) {
        nativeWriteStrongBinder(mNativePtr, val);
    }
    private static native void nativeWriteStrongBinder(int nativePtr, IBinder val);
    …
}

看,這里又調用了native方法,我們會發現Java 層的一些Parcel其實只是對C/C++層的一個封裝,大部分操作還是依靠JNI去調用Native的操作。
那看一下C++里對應的方法:

/frameworks/base/core/jni/android_os_Parcel.cpp

static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr, jobject object)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
        }
    }
}

最主要的就是ibinderForJavaObject 這個函數,繼續跟蹤代碼:

/frameworks/base/core/jni/android_util_Binder.cpp

sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
    if (obj == NULL) return NULL;

    if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) { //mClass指向Java層中的Binder class
        JavaBBinderHolder* jbh = (JavaBBinderHolder*)
            env->GetIntField(obj, gBinderOffsets.mObject);
        return jbh != NULL ? jbh->get(env, obj) : NULL; //get() 返回一個JavaBBinder,繼承自BBinder
    }

    if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) { //mClass 指向Java層的BinderProxy class
        return (IBinder*)
            env->GetIntField(obj, gBinderProxyOffsets.mObject); //返回一個BpBinder,mObject是它的地址值
    }
    ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
    return NULL;
}

這個函數呢,就是根據傳進來的Java對象找到對應的C++對象,這里的參數obj,可能會指向兩種對象:Binder對象或者BinderProxy對象。這兩個對象我們在RemoteService那一篇里其實就遇到過了,Binder對象呢就是Service里實現的那個mRemoteBinder,BinderProxy對象呢就是Activity里回調傳進來的那個service。

接着說,如果傳進來的是Binder對象,那么就會把gBinderOffsets.mObject轉化成JavaBBinderHolder, 並從中獲得一個JavaBBinder對象。JavaBBinder繼承自BBinder。(在RemoteService那一篇,Service會在onBind回調里把mRemoteBinder傳給AMS,這里傳遞的就是Binder對象)

如果傳進來的是BinderProxy對象。就會返回一個BpBinder,這個BpBinder的地址值就保存在gBinderProxyOffsets.mObject中。(在RemoteService那一篇,AMS要傳遞給Acticity的就是BinderProxy對象)。

到這里,你可能會奇怪,為什么Service把Binder對象傳遞給AMS,后面AMS卻是把BinderProxy對象傳遞給Activity呢?這個我們后面再說,(可以先說一下,其實是因為這些Binder對象都會經過底層傳輸,那在傳輸的過程中,Binder模塊就會根據不同的情況對這些對象進行轉化)

3.readStrongBinder()

同樣也是JNI調用:

/frameworks/base/core/jni/android_os_Parcel.cpp

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr)
{
      ...
      return javaObjectForIBinder(env, parcel->readStrongBinder());
}
/frameworks/base/core/jni/android_util_Binder.cpp
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) (1)
{
    if (val == NULL) return NULL;
    if (val->checkSubclass(&gBinderOffsets)) { (2)12         // One of our own!
        jobject object = static_cast<JavaBBinder*>(val.get())->object();
        LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
        return object;
    }
   ...
    jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
    if (object != NULL) {
        jobject res = env->CallObjectMethod(object, gWeakReferenceOffsets.mGet); (3if (res != NULL) {
            ALOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
            return res;
        }
       ...
    }
    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor); (4if (object != NULL) {
       ….
    }
    return object;
}

(1):這里的val和writeStrongBinder類似,不過是反過來,指向的可能是JavaBBinder或者BpBinder。

(2):如果是JavaBBinder,就會通過成員函數object(),返回一個Java對象,這個對象就是Java層的Binder對象。

(3):如果是BpBinder,那就先查找是否已經存在需要使用的BinderProxy對象,如果找到就返回引用

(4):如果沒找到可用的引用,就new 一個BinderProxy對象。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM