Skip to content

BinderInternal

追踪 BinderInternal 的 context object、线程池、GC、调用观察和 BinderProxy UID 计数桥接。

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

BinderInternal ​

BinderInternal 是 Java framework 的 Binder 内部控制面,不实现业务 IBinder。它把 Java 代码连接到 native ProcessState/IPCThreadState/BpBinder:获取 context object、加入线程池、修改线程上限、触发 Binder GC、观察 incoming transaction,以及按 UID 统计 BinderProxy。

本文面向已经读过 Binder基类详解、BinderProxy详解 和 ProcessState初始化 的读者。本文按调用者和状态 owner 拆分这些内部能力,不把它们当公开应用 API,也不重复 native 算法。

1. Native控制面 ​

1.1 Context对象 ​

源码文件:frameworks/base/core/java/com/android/internal/os/BinderInternal.java

java
public static final native IBinder getContextObject();

ServiceManager.getIServiceManager() 调用它取得 handle 0 对应 Java Binder,再转换为 IServiceManager。它返回的是 Binder 对象,不是直接返回 ServiceManager Java 单例。

1.2 线程池 ​

java
public static final native void joinThreadPool();
public static final native void setMaxThreads(int numThreads);
public static final native void disableBackgroundScheduling(
        boolean disable);

三者分别让当前线程加入 native Binder pool、配置驱动线程上限、改变 background scheduling 行为。它们共享 JNI 文件,但 owner 分别是当前 IPCThreadState 和进程 ProcessState。

1.3 JNI映射 ​

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

cpp
static const JNINativeMethod gBinderInternalMethods[] = {
    {"getContextObject", "()Landroid/os/IBinder;", ...},
    {"joinThreadPool", "()V", ...},
    {"disableBackgroundScheduling", "(Z)V", ...},
    {"setMaxThreads", "(I)V", ...},
    {"handleGc", "()V", ...},
};

JNI 只是桥接;例如 joinThreadPool 最终调用 IPCThreadState::self()->joinThreadPool(),并不在 Java 创建线程。

2. GC观察 ​

2.1 GcWatcher ​

源码文件:frameworks/base/core/java/com/android/internal/os/BinderInternal.java

java
static WeakReference<GcWatcher> sGcWatcher =
        new WeakReference<>(new GcWatcher());

static final class GcWatcher {
    @Override
    protected void finalize() throws Throwable {
        handleGc();
        sLastGcTime = SystemClock.uptimeMillis();
        synchronized (sGcWatchers) {
            sTmpWatchers = sGcWatchers.toArray(sTmpWatchers);
        }
        for (Runnable watcher : sTmpWatchers) {
            if (watcher != null) watcher.run();
        }
        sGcWatcher = new WeakReference<>(new GcWatcher());
    }
}

watcher 被 GC/finalize 时调用 native handleGc(),记录 uptime 并通知注册的 Runnable,随后创建下一代 watcher。这个时间是 BinderInternal 观察到的 GC 时间,不是所有 GC 阶段的精确 trace。

2.2 forceGc ​

java
public static void forceGc(String reason) {
    EventLog.writeEvent(2741, reason);
    VMRuntime.getRuntime().requestConcurrentGC();
}

forceGc() 记录原因并请求 concurrent GC;请求不等于 GC 已完成。ActivityThread 使用 getLastGcTime() 做节流判断,完成观察由 GcWatcher 更新。

3. 调用观察 ​

3.1 Observer ​

java
public interface Observer {
    CallSession callStarted(Binder binder, int code,
                            int workSourceUid);
    void callEnded(CallSession session,
                   int requestSize, int replySize,
                   int workSourceUid);
    void callThrewException(CallSession session,
                            Exception exception);
}

Java Binder.execTransactInternal() 快照全局 observer,在业务 onTransact() 前后调用它;异常回调之后仍会调用 callEnded()。Observer 只覆盖 Java Stub,源码 TODO 明确它不覆盖所有 C++/Rust transaction。

3.2 工作归因 ​

java
public interface WorkSourceProvider {
    int resolveWorkSourceUid(int untrustedWorkSourceUid);
}

provider 在 incoming transaction 关键路径执行,源码要求不能发起 Binder 调用。它把 caller 写入 Parcel 的不可信 work source 转换为最终归因 UID,不是权限检查。

3.3 调用统计 ​

该接口接收聚合调用统计和 Binder 线程 native TID,由 BinderCallsStats 等内部组件消费。它不参与单次事务是否成功的返回路径。

4. Proxy计数 ​

4.1 Native接口 ​

源码文件:frameworks/base/core/java/com/android/internal/os/BinderInternal.java

java
public static native void nSetBinderProxyCountEnabled(
        boolean enabled);
public static native SparseIntArray nGetBinderProxyPerUidCounts();
public static native int nGetBinderProxyCount(int uid);
public static native void nSetBinderProxyCountWatermarks(
        int high, int low, int warning);

这些方法控制 native BpBinder 的按 UID 计数,不是 Java BinderProxy.ProxyMap 的 entry 数。BinderProxy 调试会同时使用两层信息,但 key 和生命周期不同。

4.2 Java回调 ​

java
public static void binderProxyLimitCallbackFromNative(int uid) {
    sBinderProxyCountEventListenerDelegate.notifyLimitReached(uid);
}

native 达到 warning/high watermark 后回调静态 Java 方法;delegate 在锁内读取 listener/handler,并通过 Handler post 到指定线程。native callback 线程不直接执行业务 listener。

5. 状态边界 ​

5.1 Context与线程 ​

获得 context object 不会启动线程池;设置 max threads 不会创建线程;join 当前线程也不等于修改最大值。这些 API 必须按各自 native owner 解释。

5.2 GC与Proxy ​

force GC 可能帮助清理 Java BinderProxy weak values,但不能保证 native proxy 立即降到水位以下;仍被 Java 强引用或 native 逻辑持有的代理不会消失。

5.3 Observer异常 ​

Observer 方法位于 transaction 关键路径,尤其 callThrewException() 不应再抛异常,否则可能覆盖原业务异常。统计逻辑必须快速且不能递归 Binder 调用。

6. 测试边界 ​

6.1 Proxy计数 ​

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

测试服务通过 BinderInternal 启用计数、配置高低/警告水位并注册 Handler callback,验证指定 UID 的 proxy 数量和回调。它证明 Java-native 水位桥接,不证明 GC 何时清理所有 proxy。

6.2 调用统计 ​

  • frameworks/base/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
  • frameworks/base/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java

这些测试构造 CallSession、调用结束与异常输入,验证统计聚合;它们不执行完整 driver transaction 或 BinderInternal JNI 线程池入口。

6.3 可执行阅读 ​

bash
rg -n "joinThreadPool|getContextObject|disableBackgroundScheduling|setMaxThreads|handleGc" \
  frameworks/base/core/java/com/android/internal/os/BinderInternal.java \
  frameworks/base/core/jni/android_util_Binder.cpp

rg -n "GcWatcher|forceGc|Observer|WorkSourceProvider|CallStatsObserver" \
  frameworks/base/core/java/com/android/internal/os/BinderInternal.java

rg -n "nSetBinderProxyCount|binderProxy.*Callback|setBinderProxyCountCallback" \
  frameworks/base/core/java/com/android/internal/os/BinderInternal.java \
  frameworks/base/core/jni/android_util_Binder.cpp

排查 BinderInternal 行为时,先确认问题属于线程池、context object、GC、incoming observer 还是 proxy UID 水位;这些 API 位于同一类中只是内部封装选择,不意味着它们共享同一个状态机或生效时机。