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
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
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 默认方法
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
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 默认分发
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()
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 异常处理
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 清理身份
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 可执行阅读
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 没有同步异常返回通道。
