一句话总结:
ApplicationThreadProxy (代理) 和 ApplicationThread (存根) 是 Binder 代理-存根模式 的一体两面。该模式通过一个共享的 AIDL 接口,为系统服务(AMS)屏蔽了跨进程调用的所有复杂性,使其能像调用本地方法一样,透明地“命令”远端的应用进程。
一、问题的根源:无法跨越的“进程鸿沟”
Android 的安全基石是“进程隔离”。系统服务 AMS 运行在 system_server 进程,而我们的应用运行在独立的 App 进程。这两个进程的内存空间完全独立。那么,AMS 如何才能调用到我们 App 进程中 ActivityThread 对象的方法呢?
直接的方法调用是不可能的。这需要一个“翻译”和“运输”系统,这就是 Binder 的代理-存根模式。
二、核心架构:Binder 的代理-存根 (Proxy-Stub) 模式
这个模式由三部分组成,共同跨越了“进程鸿沟”:
-
共同的“契约” (IApplicationThread.aidl):
这是一个双方都认可的接口定义文件。它规定了“可以做什么”(方法)和“参数是什么”(数据)。
-
“接旨”的本地实体 (
ApplicationThreadas Stub - 存根):- 运行在应用进程中,是
IApplicationThread.Stub的实现类。 - 它是真正拥有业务逻辑的对象(虽然它的逻辑只是把任务转发给 Handler)。
- 它扮演着 Binder 通信的服务端,时刻准备接收来自系统的指令。
- 运行在应用进程中,是
-
“传旨”的远程代表 (
ApplicationThreadProxyas Proxy - 代理):- 运行在系统进程中,由 AIDL 工具根据
.aidl文件自动生成。 - 它也实现了
IApplicationThread接口,但它的所有方法都是**“空壳”**。 - 它的唯一职责,就是将方法的调用,打包成
Parcel数据,然后通过底层的 Binder 驱动,发送给远在应用进程中的ApplicationThread(Stub)。
- 运行在系统进程中,由 AIDL 工具根据
结论: 对于 AMS 来说,它感觉自己只是在和一个本地的 IApplicationThread 对象打交道,这个对象就是 ApplicationThreadProxy。而这个 Proxy,则像一个忠实的“外交官”,将 AMS 的所有意图都远程传达给了应用进程中的“实体”。
三、连接“代理”与“存根”的魔法——asInterface()
AMS 是如何获得这个不多不少、正好指向特定 App 进程的 ApplicationThreadProxy 对象的呢?魔法就在 AIDL 生成的 asInterface() 静态方法中。
当 AMS 获得一个代表应用进程通信句柄的 IBinder 对象后,它会这样调用:
IApplicationThread appThread = IApplicationThread.Stub.asInterface(binder);
这个 asInterface() 方法内部的逻辑(伪代码)是:
public static IApplicationThread asInterface(IBinder obj) {
if (obj == null) {
return null;
}
// 检查这个 binder 是否就在当前进程
// 如果是,说明是本地调用,直接返回 Stub 自身
IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (iin != null && iin instanceof IApplicationThread) {
return (IApplicationThread) iin;
}
// 如果不在当前进程,就创建一个新的 Proxy 对象来“代理”这个远程 binder
return new ApplicationThreadProxy(obj);
}
这就是“位置透明性”的核心: AMS 无需关心 binder 对象到底在哪里,asInterface() 会自动判断,并返回一个正确的、可直接调用的 IApplicationThread 实例。
四、一次完整的跨界之旅:scheduleLaunchActivity
graph TD
subgraph "System Server 进程"
AMS --> |1. 调用本地方法| Proxy(ApplicationThreadProxy);
Proxy --> |2. 打包参数为 Parcel| BinderDriver;
end
subgraph "App 进程"
BinderDriver --> |3. 传输 Parcel, 唤醒 Binder 线程| Stub(ApplicationThread);
Stub --> |4. 解包 Parcel, 执行 Stub 方法| H(Handler H);
H --> |5. 发送消息到主线程| MainLooper[主线程 Looper];
end
MainLooper --> |6. 在主线程处理消息| YourActivity[Activity.onCreate()];
AMS调用:AMS调用它持有的appThread.scheduleLaunchActivity(...)。它以为这是一个普通的本地调用。Proxy工作:ApplicationThreadProxy内部,将所有参数打包进Parcel,并通过mRemote.transact()将数据和调用指令发给 Binder 驱动。Binder驱动工作: 驱动将数据拷贝到目标(App)进程,并从其 Binder 线程池中唤醒一个线程。Stub工作: App 进程的ApplicationThread(Stub) 的onTransact方法被回调。它解开Parcel,发现这是一个scheduleLaunchActivity指令。- 线程切换:
ApplicationThread将任务封装成Message,发送给主线程的Handler。 - 最终执行: 主线程的
Looper处理该消息,最终调用到Activity的生命周期方法。
通过这套精妙的组合拳,一次跨进程调用被安全、有序、且对调用者透明地完成了。理解这个模式,就理解了整个 Android 系统服务的通信基石。