system_server进程中的通信方式

30 阅读6分钟

问题:

system_server进程中有很多的系统服务,这些服务之间是如何进行通信的?是否也会存在线程争夺的问题?或者多线程的问题?


  1. system_server 里的系统服务之间主要通过两类方式通信:

    1. 同进程直接方法调用(Java 对象引用)
    2. Binder 接口调用(包括“进程内 Binder”) ,再辅以 Handler 消息、回调监听等模式。
  2. 是的,system_server 内部大量使用多线程,也一定会有“线程争夺 / 资源竞争”问题,只是通过严格的锁设计、线程模型和 Watchdog 来降风险。


一、system_server 中系统服务之间是怎么通信的?

system_server 自身就是一个 Java 进程,里面的系统服务本质上就是一些 单例 Java 对象(如 AMS、PMS、WMS 等),所以通信方式可以分为几层:

同进程直接方法调用(最常见、最高效)

服务之间最常见的是“直接持引用 + 调方法”。

class ActivityManagerService {
    final WindowManagerService mWindowManager;
    final PackageManagerService mPackageManager;

    void startSomeActivity(...) {
        // 直接调 WMS 的方法
        mWindowManager.addAppToken(...);

        // 直接调 PMS 查询包/权限
        mPackageManager.checkPermission(...);
    }
}

特征:

  • 不经过 Binder 内核层,只是普通 Java 调用;
  • 延迟、开销都很小;
  • 常见于那些紧耦合、频繁协作的服务: AMS ↔ WMS ↔ PMS ↔ PowerManagerService 等。

这也是 system_server 内部通信的主力方式。

Binder 接口调用(包括进程内 Binder)

很多系统服务对外都暴露了一个 AIDL/IBinder 接口,例如:

  • IActivityManager
  • IPackageManager
  • IWindowManager

服务之间如果走的是这些接口,也可能还是通过 Binder 调用。

但有两种情况:

  1. 跨进程 Binder

    1. app → AMS、WMS、PMS 等,必然是 Binder IPC。
  2. 进程内 Binder(in-process Binder)

  • system_server 里的某个服务拿到另一个服务的 AIDL 接口:
IActivityManager am = IActivityManager.Stub.asInterface(
    ServiceManager.getService("activity")
);
am.someRemoteCall(...);
  • 在同一个进程中,Binder 实现会做 “短路优化” : 不走真正的内核 IPC,但仍然会切到对应的 Binder 线程执行 Stub 方法。

特点:

  • 逻辑层面对外仍然是“Binder 接口”,方便统一管理、权限检查;
  • 在同进程下开销比真正 IPC 小,但 仍然涉及线程切换(Binder 线程池) ,并不是“同线程直接调用”。

一些厂商或系统代码中,为了保持接口统一,也会让服务之间通过 AIDL 接口来调用,这时就会出现这种“进程内 Binder”。

Handler 消息 / 回调 / 订阅通知

在多线程配合上,服务之间还经常使用:

  1. Handler + Message 模式

某个服务在自己的 HandlerThread 上工作:

mHandler.post(() -> doHeavyWorkFromOtherService(...));
  • 其他服务调用它的“入口函数”,入口函数只是 post 消息到内部线程,真正的逻辑在那个线程跑。

这其实是一种 线程间通信,但也是服务间协作的常见方式。

  1. 监听 / 订阅模式
  • 如:某服务注册为另一个服务的 listener / callback
mPowerManagerInternal.registerLowPowerModeObserver(observer);
  • 当被观察的服务状态变化时,会在合适的线程回调这个 observer。
  1. 广播 / ContentObserver 等“通知型”机制
  • 虽然广播/ContentObserver 多用于 app ↔ system_server,但 system_server 内部服务也会利用这些机制协调状态。

二、system_server 里会不会有线程争夺 / 多线程问题?

肯定会有,而且非常关键。system_server 是一个高度多线程的进程。

  1. system_server 的线程构成(简化)

大概有几类核心线程:

  1. 主线程(system_server main looper)

    1. SystemServer.run() 所在线程;
    2. 启动系统服务、处理一些关键调度消息。
  2. Binder 线程池

  • 处理 来自应用和其他进程的 Binder 调用
  • 这些线程执行到 AMS/PMS/WMS 等服务的方法时,就会去争抢它们的锁/资源。
  1. 各服务自己的 HandlerThread / 专用线程
  • 比如:

    • AMS 业务线程;
    • WMS / Display 相关线程;
    • Sensor、Power、Alarm 等的一些内部线程;
  • 用来处理本服务的耗时逻辑、复杂状态机,不阻塞 main 或 Binder 线程。

  1. 其他线程池 / 后台线程
  • 一些服务会用 ExecutorService/线程池来做异步任务。

所以:system_server 内部是一个多线程“巨无霸”,多服务共享同一个进程地址空间,自然会有锁竞争、线程争用等问题。

  1. 典型的“争夺 / 多线程”问题有哪些?

  1. 锁竞争 / 临界区竞争

  • 各服务内部有大量 synchronizedReentrantLock 控制共享数据:

    • 如 AMS 全局进程/Activity 列表;
    • WMS 窗口/显示设备状态;
  • 不同线程(main、Binder 线程、各 HandlerThread)进入这些代码时会争夺锁,若锁粒度过粗,会造成严重阻塞。

  1. 死锁风险

  • 场景类似:

    • 线程 A:持有 AMS 的锁 → 再去调用 WMS;
    • 线程 B:持有 WMS 的锁 → 再去调用 AMS;
  • 如果锁顺序不一致,很容易产生相互等待死锁;

  • 为此 Framework 里有严格的 锁获取顺序规范(并在注释中写得很清楚),不允许随意改。

  1. Binder 线程池耗尽 / 队列堵塞

  • 如果很多请求都卡在 system_server 的某个耗时代码里,Binder 线程可能会被占满;
  • 新来的 Binder 请求得不到处理,表现为系统层面“卡顿”甚至 ANR;
  • Watchdog 主要就是盯着这类“长时间不响应”的情况。
  1. 主线程消息队列堆积

  • 如果某服务不小心在 main 线程做了大量耗时操作(比如 I/O、大循环),会导致:

    • 主线程 MessageQueue 处理不过来;
    • 整个系统表现为“系统界面卡死”,最后被 Watchdog 认为 system_server 卡死。
  1. Framework 是如何控制这些多线程问题的?

为了控制 system_server 内部复杂的多线程和锁竞争,Android 做了很多设计和规范:

  1. 统一/约束锁模型
  • 引入共享“全局锁”或一组核心锁,并明确锁获取顺序;

  • 文档和代码注释中严格强调:

    • “持有哪个锁时禁止再调用谁的接口”
    • “不要在持锁状态下做 Binder 调用 / IPC” ,防止“锁 + IPC”组合导致跨进程死锁。
  1. 大量使用 Handler 切线程
  • 耗时逻辑、复杂状态机尽量放到服务内部的 HandlerThread;
  • 对外暴露的 Binder 接口通常只做参数校验、轻量操作,然后 post 到内部线程执行。
  1. Watchdog 监控
  • Watchdog 定期检查:

    • system_server 主线程;
    • 一些标记为“关键”的 HandlerThread;
  • 如果发现它们长时间卡在某处不动(比如锁等待),就打印堆栈并最终杀死 system_server 重启 framework。

  1. StrictMode / 开发阶段检测
  • 开启 StrictMode 后,主线程上的磁盘 IO / 网络访问等会被严格检测;
  • 内部开发和 CTS 测试会帮助发现不合理的耗时逻辑。

三、总结:你可以怎么理解这件事?

  1. 通信方式

    1. system_server 内的系统服务之间,主要是同进程直接方法调用,辅以 进程内 Binder 调用、Handler 消息、回调监听 等。
    2. 对外(app、native 服务)则几乎都是 Binder IPC
  2. 多线程与争夺

    1. 是的,system_server 本质上就是一个高度多线程系统:主线程、Binder 线程池、各种 HandlerThread 等共同工作;
    2. 服务之间共享数据结构、锁,自然会有线程争夺、锁竞争、死锁风险
    3. Android 通过 锁顺序规范、线程模型设计、Handler 切线程、Watchdog 监控 等手段,把这套系统“勉强维持在可控范围”。