1. 程式人生 > 其它 >由淺入深 學習 Android Binder(四)- ibinderForJavaObject 與 javaObjectForIBinder

由淺入深 學習 Android Binder(四)- ibinderForJavaObject 與 javaObjectForIBinder

技術標籤:【Android】androidbinderipc多程序程序

概述

前文已經解析了java層binder在native層的形式。

前文地址:由淺入深 學習 Android Binder(三)- java binder深究(從java到native)

前文由於篇幅限制,沒有繼續探索JavaBBinder與BinderProxy,此文則將繼續深入相關邏輯。

ibinderForJavaObject 與 javaObjectForIBinder

java與native之間通過JNI來實現資料的傳遞與互動。
主要就是通過native層的ibinderForJavaObject與javaObjectForIBinder方法。

整個流程大概就是下面兩張圖,先列出便於讀者有一個整理的認知.

在這裡插入圖片描述
在這裡插入圖片描述

android_util_Binder.ibinderForJavaObject

邏輯如下:

  1. 如果這個java物件是 java Binder物件,那麼先獲取到本地的JavaBBinderHolder物件,然後從JavaBBinderHolder中get到IBinder物件返回。
  2. 如果這個java物件是 java BinderProxy物件,那麼通過getBPNativeData()方法獲取到某個物件後返回其mObject。

接著我們看下getBPNativeData這個方法。

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

    // Instance of Binder?
    if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
        JavaBBinderHolder* jbh = (JavaBBinderHolder*)
            env->GetLongField(obj, gBinderOffsets.mObject);
        return jbh->get(env, obj);
    }

    // Instance of BinderProxy?
    if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
        return getBPNativeData(env, obj)->mObject;
    }

    ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
    return NULL;
}

android_util_Binder.getBPNativeData

最終返回的其實是一個BinderProxyNativeData,而mObject則是其中儲存的mObject物件。
通過註釋可知,是在呼叫javaObjectForIBinder方法的時候建立的。

於是我們就直接看下javaObjectForIBinder程式碼


BinderProxyNativeData* getBPNativeData(JNIEnv* env, jobject obj) {
    return (BinderProxyNativeData *) env->GetLongField(obj, gBinderProxyOffsets.mNativeData);
}

struct BinderProxyNativeData {
    // Both fields are constant and not null once javaObjectForIBinder returns this as
    // part of a BinderProxy.
    
    // The native IBinder proxied by this BinderProxy.
    sp<IBinder> mObject;

    // Death recipients for mObject. Reference counted only because DeathRecipients
    // hold a weak reference that can be temporarily promoted.
    sp<DeathRecipientList> mOrgue;  // Death recipients for mObject.
};

android_util_Binder.javaObjectForIBinder

這個類有以下要點:

  1. 通過gBinderOffsets來判斷是否是JavaBBinder物件。如果是就直接return。
  2. 如果前面的判斷不是JavaBBinder物件。那麼就會走到BinderProxy的邏輯中。
    這裡BinderProxy是通過gBinderProxyOffsets呼叫java層BinderProxy的初始化方法建立的,其中還傳入了BinderProxyNativeData物件。
    (另外還有一系列的BinderProxyNativeData物件相關的邏輯,這裡讀者只要知道一個BinderProxy對應一個BinderProxyNativeData物件就可以了)

此處的需要繼續探索的點有以下幾個:

  1. checkSubclass是什麼邏輯?以及gBinderOffsets是什麼?
  2. gBinderProxyOffsets是什麼結構?
  3. BinderProxyNativeData是什麼結構?
  4. getBPNativeData()的邏輯是什麼?

我們接下來一一分析。

jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    if (val == NULL) return NULL;

    if (val->checkSubclass(&gBinderOffsets)) {
        // It's a JavaBBinder created by ibinderForJavaObject. Already has Java object.
        jobject object = static_cast<JavaBBinder*>(val.get())->object();
        LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
        return object;
    }

    // For the rest of the function we will hold this lock, to serialize
    // looking/creation/destruction of Java proxies for native Binder proxies.
    AutoMutex _l(gProxyLock);

    BinderProxyNativeData* nativeData = gNativeDataCache;
    if (nativeData == nullptr) {
        nativeData = new BinderProxyNativeData();
    }
    // gNativeDataCache is now logically empty.
    jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
            gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
    if (env->ExceptionCheck()) {
        // In the exception case, getInstance still took ownership of nativeData.
        gNativeDataCache = nullptr;
        return NULL;
    }
    BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);
    if (actualNativeData == nativeData) {
        // New BinderProxy; we still have exclusive access.
        nativeData->mOrgue = new DeathRecipientList;
        nativeData->mObject = val;
        gNativeDataCache = nullptr;
        ++gNumProxies;
        if (gNumProxies >= gProxiesWarned + PROXY_WARN_INTERVAL) {
            ALOGW("Unexpectedly many live BinderProxies: %d\n", gNumProxies);
            gProxiesWarned = gNumProxies;
        }
    } else {
        // nativeData wasn't used. Reuse it the next time.
        gNativeDataCache = nativeData;
    }

    return object;
}

IBinder.checkSubclass()與gBinderOffsets

全域性中定義了checkSubclass程式碼的只有兩個地方,IBinder與JavaBBinder。

IBinder是BBinder的父類,BBinder是JavaBBinder的父類。

IBinder.checkSubClass()

bool IBinder::checkSubclass(const void* /*subclassID*/) const
{
    return false;
}

JavaBBinder.checkSubClass()

    bool    checkSubclass(const void* subclassID) const
    {
        return subclassID == &gBinderOffsets;
    }

於是,根據程式碼可知,checkSubClass這個方法,只有當這個IBinder物件是JavaBBinder,並且傳進來的subclassID是gBinderOffsets的時候,才會返回true。
gBinderOffsets這個結構體也可以直接在原始碼中看到。

static struct bindernative_offsets_t
{
    // Class state.
    jclass mClass;
    jmethodID mExecTransact;

    // Object state.
    jfieldID mObject;

} gBinderOffsets;

在android_util_Binder中也可以找到初始化的方法。
因此bindernative_offsets_t這個結構體其實儲存了以下內容:

  • java層的Binder物件
  • java層Binder的execTransact方法
  • java層Binder的mObject物件
static int int_register_android_os_Binder(JNIEnv* env)
{
    jclass clazz = FindClassOrDie(env, kBinderPathName);

    gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
    gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");

    return RegisterMethodsOrDie(
        env, kBinderPathName,
        gBinderMethods, NELEM(gBinderMethods));
}

binderproxy_offsets_t 與 gBinderProxyOffsets

根據原始碼可知gBinderProxyOffsets這個物件儲存了以下內容:

  • java層的BinderProxy物件
  • BinderProxy的getInstance方法
  • BinderProxy的sendDeathNotice方法
  • BinderProxy的dumpProxyDebugInfo方法
  • BinderProxy的mNativeData物件,實際上指向的就是native層這個BinderProxy對應的BinderProxyNativeData
static struct binderproxy_offsets_t
{
    // Class state.
    jclass mClass;
    jmethodID mGetInstance;
    jmethodID mSendDeathNotice;
    jmethodID mDumpProxyDebugInfo;

    // Object state.
    jfieldID mNativeData;  // Field holds native pointer to BinderProxyNativeData.
} gBinderProxyOffsets;
static int int_register_android_os_BinderProxy(JNIEnv* env)
{
    jclass clazz = FindClassOrDie(env, "java/lang/Error");
    gErrorOffsets.mClass = MakeGlobalRefOrDie(env, clazz);

    clazz = FindClassOrDie(env, kBinderProxyPathName);
    gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    gBinderProxyOffsets.mGetInstance = GetStaticMethodIDOrDie(env, clazz, "getInstance",
            "(JJ)Landroid/os/BinderProxy;");
    gBinderProxyOffsets.mSendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
            "(Landroid/os/IBinder$DeathRecipient;)V");
    gBinderProxyOffsets.mDumpProxyDebugInfo = GetStaticMethodIDOrDie(env, clazz, "dumpProxyDebugInfo",
            "()V");
    gBinderProxyOffsets.mNativeData = GetFieldIDOrDie(env, clazz, "mNativeData", "J");

    clazz = FindClassOrDie(env, "java/lang/Class");
    gClassOffsets.mGetName = GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");

    return RegisterMethodsOrDie(
        env, kBinderProxyPathName,
        gBinderProxyMethods, NELEM(gBinderProxyMethods));
}

android_util_Binder.BinderProxyNativeData

這個類就兩個屬性,根據註釋有以下要點:

  • 每個BinderProxy物件對應一個BinderProxyNativeData
  • 儲存了native層對應的Binder物件
  • 儲存了該Binder物件的死亡回撥
// We aggregate native pointer fields for BinderProxy in a single object to allow
// management with a single NativeAllocationRegistry, and to reduce the number of JNI
// Java field accesses. This costs us some extra indirections here.
struct BinderProxyNativeData {
    // Both fields are constant and not null once javaObjectForIBinder returns this as
    // part of a BinderProxy.

    // The native IBinder proxied by this BinderProxy.
    sp<IBinder> mObject;

    // Death recipients for mObject. Reference counted only because DeathRecipients
    // hold a weak reference that can be temporarily promoted.
    sp<DeathRecipientList> mOrgue;  // Death recipients for mObject.
};

android_util_Binder.getBPNativeData()

在前面瞭解了gBinderProxyOffsets物件之後,這邊邏輯其實很簡單。
這裡就是把java層BinderProxy.mNativeData轉化成native層的BinderProxyNativeData.

BinderProxyNativeData* getBPNativeData(JNIEnv* env, jobject obj) {
    return (BinderProxyNativeData *) env->GetLongField(obj, gBinderProxyOffsets.mNativeData);
}

ibinderForJavaObject 與 javaObjectForIBinder總結

要點:

  • java層直接與native層互動的物件有兩個——Binder物件與BinderProxy物件。
    Binder對應“Binder在本程序”的場景,BinderProxy對應“Binder在其他程序”的場景。
  • native層javaBBinder與java層的Binder一一對應。
    native層的BinderProxyNativeData與java層的BinderProxy一一對應。
  • 在native層,gBinderProxyOffsets(binderproxy_offsets_t)儲存了java層binderProxy的物件與需要呼叫的方法和屬性。gBinderOffsets(binderproxy_offsets_t)儲存了java層binder的物件與需要呼叫的方法和屬性。
  • ibinderForJavaObject負責通過java的Binder或者BinderProxy物件,找到並返回native層的IBinder物件。
  • javaObjectForIBinder通過native層的IBinder物件,找到或者封裝成java物件返回。
    在這裡插入圖片描述
    在這裡插入圖片描述