Skip to content

JavaBBinder

追踪 JavaBBinderExt 的 GlobalRef、descriptor缓存、JNI execTransact、StrictMode恢复和 holder 重建。

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

JavaBBinder ​

JavaBBinderExt 是 Java Binder 在 native 层的本地 Binder 包装。它继承内部 JavaBBinderBase,持有 JVM 和 Java Binder 的 GlobalRef,实现 descriptor、业务事务和稳定性/扩展属性,并在 native Binder 线程中调用 Java execTransact()。

本文面向已经读过 JNI层android_util_Binder、Binder基类详解 和 sp与wp智能指针 的读者。本文只讲 JavaBBinder 的 native 生命周期与事务回调,不重复 Java Binder API 或整体 JNI offset 注册。

1. 类型与所有权 ​

1.1 内部基类 ​

源码文件:frameworks/native/libs/binder/include_private/binder/internal/JavaBBinderBase.h

cpp
class JavaBBinderBase : public BBinder {
public:
    static const void* getExtSubclassID();
    virtual bool checkSubclass(const void* id) const = 0;
};

基类只提供内部 subclass identification;JavaBBinderExt 继承它,javaObjectForIBinder() 可据此判断一个 native IBinder 是否本来由 Java Binder 创建。

1.2 Java GlobalRef ​

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

cpp
JavaBBinderExt(JNIEnv* env, jobject object)
      : mVM(jnienv_to_javavm(env)),
        mObject(env->NewGlobalRef(object)) {}

virtual ~JavaBBinderExt() {
    JNIEnv* env = javavm_to_jnienv(mVM);
    env->DeleteGlobalRef(mObject);
}

native 包装不能保存 JNI local reference,因为 Binder 事务可能由其他线程、很晚的时间到达;GlobalRef 让 Java Binder 在 native wrapper 存活期间保持可回调。析构时删除 GlobalRef,native weak/strong 生命周期结束后才释放 Java 根引用。

1.3 Holder弱缓存 ​

cpp
Mutex mLock;
wp<JavaBBinderExt> mBinder;
bool mVintf = false;
bool mSetExtensionCalled = false;
bool mInheritRt = false;

Java Binder 的 holder 保存 wp<JavaBBinderExt>,不是强引用。没有 native 使用者时 wrapper 可以销毁;下次需要把同一 Java Binder 转成 native 时,holder 会重新创建 wrapper,并把已记录的 stability/extension/scheduler 配置应用回去。

2. 属性与descriptor ​

2.1 延迟descriptor ​

cpp
const String16& JavaBBinderExt::getInterfaceDescriptor() const {
    call_once(mPopulateDescriptor, [this] {
        JNIEnv* env = javavm_to_jnienv(mVM);
        jstring descriptor = (jstring)env->CallObjectMethod(
                mObject, gBinderOffsets.mGetInterfaceDescriptor);
        if (descriptor == nullptr) return;
        const jchar* chars = env->GetStringChars(descriptor, nullptr);
        mDescriptor = String16(
                reinterpret_cast<const char16_t*>(chars),
                env->GetStringLength(descriptor));
        env->ReleaseStringChars(descriptor, chars);
    });
    return mDescriptor;
}

descriptor 第一次被 native 查询时才回调 Java,并由 once_flag 缓存。返回空字符串与 JNI 异常/对象销毁是不同边界;调用者应检查 descriptor 是否可用,而不是反复假设每次都会重新读取。

2.2 稳定性与扩展 ​

holder 的 markVintf()、forceDowngradeToSystemStability()、setExtension() 和 setInheritRt() 在锁内更新状态;如果 wrapper 已存在,立即应用到 JavaBBinderExt,否则等下次创建时应用。属性必须在 Binder 被发出或参与跨进程传输前完成。

3. 事务回调 ​

3.1 onTransact ​

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

相关函数:JavaBBinderExt::onTransact()

cpp
status_t JavaBBinderExt::onTransact(
        uint32_t code, const Parcel& data,
        Parcel* reply, uint32_t flags) {
    JNIEnv* env = javavm_to_jnienv(mVM);
    LOG_ALWAYS_FATAL_IF(env == nullptr,
                        "env null. Attach JVM?");
    IPCThreadState* state = IPCThreadState::self();
    const int32_t strictBefore =
            state->getStrictModePolicy();

    jboolean res = env->CallBooleanMethod(
            mObject, gBinderOffsets.mExecTransact,
            code, reinterpret_cast<jlong>(&data),
            reinterpret_cast<jlong>(reply), flags);
    ...
    return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
}

native Binder 线程需要有 JNIEnv;没有 attach JVM 是进程级错误。native 把 Parcel 地址和 flags 传给 Java execTransact,Java 执行身份、observer、异常和 Parcel recycle,返回 boolean 后再转为 native status。

3.2 StrictMode恢复 ​

cpp
if (state->getStrictModePolicy() != strictBefore) {
    set_dalvik_blockguard_policy(env, strictBefore);
}

Binder underlying state 会恢复 native strict policy,但 Dalvik/Java BlockGuard 状态需要 JNI 层额外同步。否则一次 incoming transaction 修改的策略可能泄漏到下一次使用同一 Binder 线程。

3.3 系统属性命令 ​

SYSPROPS_TRANSACTION 即使 Java execTransact 返回,也会额外调用 BBinder::onTransact() 的 native 实现。这是特殊协议命令,不能套成所有业务 code 都会双重分发。

4. 资源与竞态 ​

4.1 构造竞态 ​

Holder 在锁外构造 wrapper,因为构造可能触发 GC;两个线程可能同时构造,但锁内二次 promote 只保留一个,另一个通过 sp 析构释放 GlobalRef。构造期间不能把 holder mutex 传入会触发 Java/GC 的路径。

4.2 wrapper销毁 ​

JavaBBinderExt 析构删除 GlobalRef;holder 的 Java Binder 仍可能存在,但 native wrapper 已不在。下一次 ibinderForJavaObject() 会重新创建 wrapper,不代表 Java Binder identity 改变。

4.3 Java异常 ​

如果 Java execTransact 抛异常,JNI 取得 throwable 并调用 binder_report_exception(),返回 JNI false。同步异常由 Java Binder 写入 reply;oneway 没有同步 reply,只能记录/报告。

5. 测试边界 ​

5.1 Java转换 ​

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

Parcel Binder 写入/读取覆盖 Java Binder 与 native conversion 的主线,但不直接断言 holder 并发构造胜负。

5.2 远程事务 ​

源码文件:frameworks/native/libs/binder/tests/binderLibTest.cpp

Native Binder 测试通过远程服务调用 Java/Native Binder 对象,覆盖事务、线程和死亡通知边界;不单独验证 Java StrictMode restore 或 descriptor lazy cache。

5.3 可执行阅读 ​

bash
rg -n "JavaBBinderBase|JavaBBinderExt|JavaBBinderHolder|GlobalRef|mBinder.promote" \
  frameworks/base/core/jni/android_util_Binder.cpp \
  frameworks/native/libs/binder/include_private/binder/internal/JavaBBinderBase.h

rg -n "execTransact|StrictMode|SYSPROPS_TRANSACTION|binder_report_exception" \
  frameworks/base/core/jni/android_util_Binder.cpp

rg -n "writeStrongBinder|readStrongBinder|BinderDeath" \
  frameworks/base/core/tests/coretests/src/android/os/ParcelTest.java \
  frameworks/native/libs/binder/tests/binderLibTest.cpp

排查 Java Binder 本地对象没有响应时,先确认 holder 是否能 promote/create wrapper,再检查 JNIEnv、descriptor、execTransact 和 StrictMode restore;不要只检查 Java Binder 对象仍然可达就断言 native wrapper仍然存在。