Skip to content

Binder基类详解

追踪 Java Binder 本地对象的 native holder、接口绑定、execTransact、onTransact 和调用身份边界。

基于android-17.0.0_r1
AndroidBinderJava框架Binder基类源码阅读

Binder基类详解 ​

Java Binder 是本进程拥有的 Binder 对象基类。它的 Java 字段 mObject 指向 native JavaBBinderHolder,attachInterface() 保存 owner 与 descriptor,native 事务到达后通过 JavaBBinderExt::onTransact() 回调 Java execTransact(),最终进入可覆写的 onTransact()。

本文面向已经读过 BinderProxy详解、BBinder本地对象 和 IBinder接口 的读者。本文只讲 Java 本地 Binder 的 owner、native holder、调用身份、异常和 Parcel 回收,不重复远程 proxy 的缓存。

1. 对象建立 ​

1.1 Java字段 ​

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

java
private final long mObject;
private IInterface mOwner;
@Nullable private String mDescriptor;

public Binder(@Nullable String descriptor) {
    mObject = getNativeBBinderHolder();
    NoImagePreloadHolder.sRegistry.registerNativeAllocation(
            this, mObject);
    mDescriptor = descriptor;
}

Java 对象创建时先得到 native holder,再由 NativeAllocationRegistry 绑定释放函数;mOwner 与 mDescriptor 仍由 Java 对象保存。创建 Binder 不会自动注册 ServiceManager。

1.2 attachInterface ​

java
public void attachInterface(@Nullable IInterface owner,
        @Nullable String descriptor) {
    mOwner = owner;
    mDescriptor = descriptor;
}

public @Nullable IInterface queryLocalInterface(
        @NonNull String descriptor) {
    if (mDescriptor != null && mDescriptor.equals(descriptor)) {
        return mOwner;
    }
    return null;
}

attachInterface() 建立 descriptor 到 Java owner 的本地映射。AIDL Stub 的 asInterface() 通过它判断当前 Binder 是否可以本地直连;descriptor 不匹配就返回 null 并走 Proxy。

2. 本地能力 ​

2.1 默认方法 ​

java
public String getInterfaceDescriptor() { return mDescriptor; }
public boolean pingBinder() { return true; }
public boolean isBinderAlive() { return true; }
public void linkToDeath(DeathRecipient recipient, int flags) { }

本地 Binder 的 ping/alive 恒为 true;本地 owner 不需要远程死亡通知,所以 Java linkToDeath() 默认空实现。远程 BinderProxy 才向驱动注册死亡事件。

2.2 transact ​

java
public final boolean transact(int code, Parcel data,
        Parcel reply, int flags) throws RemoteException {
    if (data != null) data.setDataPosition(0);
    boolean result = onTransact(code, data, reply, flags);
    if (reply != null) reply.setDataPosition(0);
    return result;
}

本地调用直接进入 onTransact();输入位置被重置,reply 返回前也重置到 0。跨进程调用则由 BinderProxy.transactNative() 发送,但目标 Java Binder 仍通过相同的 onTransact() 业务入口。

2.3 默认分发 ​

java
protected boolean onTransact(int code, Parcel data,
        Parcel reply, int flags) throws RemoteException {
    if (code == INTERFACE_TRANSACTION) {
        reply.writeString(getInterfaceDescriptor());
        return true;
    } else if (code == DUMP_TRANSACTION) {
        ParcelFileDescriptor fd = data.readFileDescriptor();
        String[] args = data.readStringArray();
        if (fd != null) {
            try { dump(fd.getFileDescriptor(), args); }
            finally { IoUtils.closeQuietly(fd); }
        }
        return true;
    }
    return false;
}

默认只理解 descriptor 和 dump;AIDL Stub 覆盖 onTransact() 处理业务 code,再调用父类处理标准 code。

3. execTransact路径 ​

3.1 Parcel包装 ​

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

相关函数:execTransact()

java
private boolean execTransact(int code, long dataObj,
        long replyObj, int flags) {
    Parcel data = Parcel.obtain(dataObj);
    Parcel reply = Parcel.obtain(replyObj);
    final int callingUid = data.isForRpc() ? -1 : Binder.getCallingUid();
    final long origWorkSource = callingUid == -1 ? -1
            : ThreadLocalWorkSource.setUid(callingUid);
    try {
        return execTransactInternal(code, data, reply,
                                    flags, callingUid);
    } finally {
        reply.recycle();
        data.recycle();
        if (callingUid != -1) {
            ThreadLocalWorkSource.restore(origWorkSource);
        }
    }
}

native 传入的 dataObj/replyObj 被包装成 Java Parcel;调用 UID 在进入 Java 业务前用于默认 work source,返回时无论成功还是异常都 recycle Parcel 并恢复线程 work source。

3.2 Observer与AppOps ​

execTransactInternal() 先快照 BinderInternal.Observer,再调用 onTransact();如果 flags 带 FLAG_COLLECT_NOTED_APP_OPS,事务期间包住 AppOps 收集。observer 的 callStarted/callEnded 覆盖整个 Java 分发区间,reply 大小检查在 finally 中执行。

3.3 异常处理 ​

java
try {
    res = onTransact(code, data, reply, flags);
} catch (RemoteException | RuntimeException e) {
    if ((flags & FLAG_ONEWAY) != 0) {
        Log.w(TAG, "Binder call failed.", e);
    } else {
        reply.setDataSize(0);
        reply.setDataPosition(0);
        reply.writeException(e);
    }
    res = true;
}

同步事务把异常编码进 reply;oneway 没有 reply 可写,只记录异常。返回 true 表示 Java 层完成了事务处理包装,不等于业务没有抛异常。

4. 身份与清理 ​

4.1 Calling UID ​

getCallingUid()/getCallingPid() 读取当前 Binder 事务的调用者;oneway 不保证 PID 有效。getCallingUidOrThrow() 在当前线程不处于 incoming transaction 且没有 clearCallingIdentity() 显式身份时抛异常,避免业务在错误线程上下文使用调用者身份。

4.2 清理身份 ​

java
public static final void withCleanCallingIdentity(
        @NonNull ThrowingRunnable action) {
    final long token = clearCallingIdentity();
    try { action.runOrThrow(); }
    finally { restoreCallingIdentity(token); }
}

清理调用身份只影响当前线程后续 permission check/本地调用的身份视图;它不修改原始 Binder transaction 的发送者,也不延长事务生命周期。

4.3 flush与线程池 ​

flushPendingCommands() 把当前线程待发送 Binder 命令刷入驱动;joinThreadPool() 交给 BinderInternal,直到进程退出。Binder 对象创建和线程池加入是分离动作,创建 Java Binder 并不会自动让进程消费 incoming transaction。

5. Native holder ​

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

相关类型:JavaBBinderHolder、JavaBBinderExt

JavaBBinderHolder 以 wp<JavaBBinderExt> 缓存 native 包装;首次 ibinderForJavaObject() 时在锁外构造,锁内再次 promote 检查竞态,已有实例则丢弃新构造者。JavaBBinderExt::onTransact() 通过 JNI 调用 Java execTransact(),若 Java 抛异常则报告 remote exception 并返回失败结果。

6. 测试边界 ​

6.1 本地行为 ​

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

Java core tests 重点覆盖 Binder 的调用身份、线程和 Parcel 行为;本篇关键 native holder 竞态由 android_util_Binder.cpp 源码控制流支撑,不能把 Java 单元测试外推为完整 native 生命周期证明。

6.2 远程对照 ​

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

Native 测试覆盖远程 transaction、死亡通知和线程池;它们证明 native Binder 对端可消费 Java/Native Binder 事务,但不覆盖 Java execTransactInternal() 的 AppOps、Observer 和异常编码组合。

6.3 可执行阅读 ​

bash
rg -n "mObject|attachInterface|queryLocalInterface|transact\(|onTransact|execTransact" \
  frameworks/base/core/java/android/os/Binder.java

rg -n "JavaBBinderHolder|JavaBBinderExt|execTransact|ibinderForJavaObject" \
  frameworks/base/core/jni/android_util_Binder.cpp

rg -n "getCallingUidOrThrow|clearCallingIdentity|withCleanCallingIdentity|flushPendingCommands" \
  frameworks/base/core/java/android/os/Binder.java

排查 Java Binder 服务收到请求但业务没有执行时,沿 native holder、JNI execTransact、Parcel 包装、调用身份和 onTransact 逐层检查;若只在 oneway 请求中看不到异常 reply,应查看 log 和 observer,因为 oneway 没有同步异常返回通道。