Skip to content

javaObjectForIBinder

追踪 native IBinder 转换为原 Java Binder 或缓存 BinderProxy 时的对象身份、竞争和 ownership。

基于android-17.0.0_r1
AndroidBinderJNIBinderProxyJava框架源码阅读

javaObjectForIBinder ​

javaObjectForIBinder() 决定一个 native sp<IBinder> 在 Java 世界中的对象身份。若对象本来是当前 JVM 创建的 JavaBBinderExt,函数直接返回原 Java Binder;否则创建候选 BinderProxyNativeData,调用 Java BinderProxy.getInstance() 按 native 指针复用或创建 proxy,再处理竞争失败候选的释放。

本文承接 JNI层android_util_Binder、JavaBBinder 和 BinderProxy详解。本文只深挖 native→Java 转换的对象身份与 ownership,不重复 transact 和 death callback 业务。

1. 输入边界 ​

源码文件:frameworks/base/core/jni/android_util_Binder.cpp

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

输入使用 sp<IBinder>,函数执行期间 native 对象有强引用保护。null 映射为 Java null,不创建 holder 或 proxy。

2. 本地对象 ​

2.1 子类识别 ​

cpp
if (val->checkSubclass(
        JavaBBinderBase::getExtSubclassID())) {
    jobject object =
            static_cast<JavaBBinderExt*>(
                    val.get())->object();
    return object;
}

checkSubclass() 使用内部稳定 ID 判断对象是否为 JavaBBinderExt,不是靠 descriptor 或 C++ RTTI 名称。命中后返回 wrapper 持有的原 Java GlobalRef 对象。

2.2 身份闭环 ​

Java Binder 经 ibinderForJavaObject() 变成 JavaBBinderExt,再经本函数返回时仍是原 Java Binder,不创建 BinderProxy。这保证本地 Binder 往返 Parcel 后保持 Java 对象身份。

3. Proxy候选 ​

3.1 NativeData内容 ​

cpp
struct BinderProxyNativeData {
    sp<IBinder> mObject;
    sp<DeathRecipientList> mOrgue;
    sp<FrozenStateChangeCallbackList>
            mFrozenStateChangeCallbackList;
};

nativeData 强持有目标 IBinder 以及两类回调列表。Java BinderProxy 的单个 long 字段指向这个聚合对象,由一个 NativeAllocationRegistry finalizer 统一释放。

3.2 创建候选 ​

cpp
BinderProxyNativeData* nativeData =
        new BinderProxyNativeData;
nativeData->mOrgue =
        sp<DeathRecipientList>::make();
nativeData->mFrozenStateChangeCallbackList =
        sp<FrozenStateChangeCallbackList>::make();
nativeData->mObject = val;

jobject object = env->CallStaticObjectMethod(
        gBinderProxyOffsets.mClass,
        gBinderProxyOffsets.mGetInstance,
        (jlong)nativeData, (jlong)val.get());

候选在进入 Java 前已经拥有完整 native 引用。Java getInstance() 负责决定该候选是否成为实际 proxy 的 nativeData。

4. Java仲裁 ​

源码文件:frameworks/base/core/java/android/os/BinderProxy.java

java
private static BinderProxy getInstance(
        long nativeData, long iBinder) {
    synchronized (sProxyMap) {
        BinderProxy result = sProxyMap.get(iBinder);
        if (result != null) return result;

        result = new BinderProxy(nativeData);
        sRegistry.registerNativeAllocation(
                result, nativeData);
        sProxyMap.set(iBinder, result);
        return result;
    }
}

key 是 native IBinder 指针,value 是 Java proxy 弱引用。锁保证同时只有一个活跃 proxy 成为正式对象;候选 nativeData 是否被接管,需要回到 native 比较实际字段。

5. Ownership收束 ​

5.1 竞争结果 ​

cpp
BinderProxyNativeData* actual =
        getBPNativeData(env, object);

if (actual == nativeData) {
    nativeData->tryTagObject();
} else {
    delete nativeData;
}

字段仍等于候选指针,说明新 Java proxy 接管了它;否则 Java 返回的是已有 proxy,当前候选必须删除。删除会释放其 sp<IBinder> 和 callback lists,避免并发转换泄漏 native 引用。

5.2 Java异常 ​

如果 getInstance() 抛异常,它负责通过 free function 清理 nativeData;native 看到 pending exception 后直接返回 null,不能再次 delete,否则 double free。

5.3 对象tag ​

胜出候选调用 tryTagObject() 给 RefBase 控制块设置 Java proxy tag。并发旧 proxy 尚未 finalizer 时 tag 可能失败,这是一种诊断竞争,不影响返回 proxy 的功能。

6. 消费入口 ​

该函数被 Parcel Binder 读取、ServiceManager context object、输入 token、SurfaceControl token、WindowManager token、死亡和 frozen callback 等多个 JNI 入口调用。所有消费者共享同一身份规则:JavaBBinder 回原对象,其他 IBinder 进 ProxyMap。

7. 测试边界 ​

7.1 Parcel往返 ​

源码文件:frameworks/base/core/tests/coretests/src/android/os/ParcelTest.java

测试写入/读取 Java Binder,并比较返回对象身份,覆盖本地 JavaBBinder 直返和远程 Binder proxy 转换的可观察结果;它不直接强制制造两个线程同时竞争 nativeData。

7.2 Proxy计数 ​

BinderProxyCountingTest 验证 Java/native proxy 数和 UID 水位,但不证明每次转换是否命中同一 weak value 的具体 GC 时序。

7.3 可执行阅读 ​

bash
rg -n "javaObjectForIBinder|BinderProxyNativeData|getBPNativeData|tryTagObject" \
  frameworks/base/core/jni/android_util_Binder.cpp

rg -n "getInstance|sProxyMap|registerNativeAllocation|mNativeData" \
  frameworks/base/core/java/android/os/BinderProxy.java

rg -n "writeStrongBinder|readStrongBinder|BinderProxyCounting" \
  frameworks/base/core/tests/coretests/src/android/os

排查 native Binder 转 Java 出现重复对象或泄漏时,先确认是否是 JavaBBinder 本地直返,再检查 ProxyMap weak value、实际 mNativeData 是否接管候选、异常分支是否由 Java free function 清理;不能只按 descriptor 判断对象身份。