AMS中的线程模型跟同步机制

3 阅读3分钟

一、 AMS 线程模型的演进史

AMS 的线程模型核心从未改变:Binder 线程池处理请求 + 专用 Looper 线程串行化任务。但其具体实现和类结构经历了几个关键阶段。

第一阶段:单体架构时代 (Android 5.0 - Android 9.0)

Android 7.0 (Nougat) 源码为例:

  • 线程模型:
  1. SystemServer 主线程: 负责启动 AMS,但在启动后,AMS 的核心业务逻辑并不依赖此线程。
  • AMS 专用线程 ("ActivityManager"):

    • AMS 在构造函数中创建 ⁠mHandlerThread = new ServiceThread(TAG, ...)。

    • ⁠mHandler (即 ⁠MainHandler) 绑定的是这个 ⁠mHandlerThread 的 Looper。

  • 作用: 处理广播超时、Service 生命周期调度、进程查杀等。

  • UI 线程 ("android.ui"):

    • ⁠UiHandler 绑定的是 ⁠UiThread 的 Looper。

    • 作用: 仅处理系统级 UI(ANR 弹窗、“应用停止运行”弹窗)。

  • 源码佐证 (Android 7.0 ActivityManagerService.java):

public ActivityManagerService(Context systemContext) {

    // ...

    // 创建名为 "ActivityManager" 的专用线程

    mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_FOREGROUND, false);

    mHandlerThread.start();

    mHandler = new MainHandler(mHandlerThread.getLooper()); // <--- 关键点:MainHandler 不在 SystemServer 主线程

    mUiHandler = new UiHandler(); // 内部使用 UiThread.get()

    // ...

}

第二阶段:ATMS 分离时代 (Android 10 - Android 12)

Google 开始重构,将 Activity 的管理从 AMS 中剥离,成立 ⁠ActivityTaskManagerService (ATMS)。

  • 变化特征:
  • AMS 依然保留自己的 ⁠ServiceThread ("ActivityManager") 和 ⁠MainHandler。

  • ATMS 引入了 ⁠mH (内部 Handler),且通常利用 ⁠android.display 线程或 ⁠android.ui 线程来处理部分窗口相关逻辑。

  • 目的: 试图解耦 Activity 栈管理(重 UI/窗口)与 Service/ContentProvider 管理(重后台/IO)。

第三阶段:细粒度锁与并发优化 (Android 13/14+)

线程结构基本稳定,主要变化在于同步机制(锁的优化)。

  • 当前状态:

    • AMS 依然运行在名为 ⁠ActivityManager 的 ⁠ServiceThread 上。

    • 大量工作被分流到 ⁠BiometricThread, ⁠IoThread 等辅助线程。

    • 引入了无锁数据结构和更细粒度的锁对象。

二、 AMS 的同步机制(核心修正)

这才是最复杂的部分。既然 ⁠MainHandler 一直都是独立的,那为什么我们总觉得 SystemServer 很“卡”?因为

1. 锁对象的演进

  • Android 9.0 及之前:一把大锁 (The Global Lock)
  • 机制: ⁠synchronized(this)。

    • AMS 对象本身就是锁。任何 Binder 线程进入 AMS 的 API(如 ⁠startActivity),或者 ⁠MainHandler 处理消息,几乎都需要先拿到 ⁠this 锁。

    • 后果: 即便 ⁠MainHandler 在独立线程,只要它拿着 ⁠AMS 锁(例如正在遍历 ⁠mProcessNames 列表),Binder 线程池里的 ⁠startActivity 请求就得等着。线程虽独立,但锁是共享的。

  • Android 10+:锁的分离 (AMS Lock vs. WM Lock)

  • 机制:

    • AMS 锁: ⁠synchronized(this) 用于保护 Service, Provider, Broadcast, ProcessList。

    • WM 全局锁 (WindowManagerGlobalLock): 用于保护 Activity 栈、Window 布局。ATMS 和 WMS 共享这把锁。

  • 后果: 启动 Service(AMS 锁)和 启动 Activity(WM 锁)在大部分情况下可以并发执行了,减少了竞争。

2. 死锁与 Watchdog 的监控对象

不同版本的 Watchdog 监控策略也侧面印证了线程模型:

  • Monitor 接口: AMS 实现了 ⁠Watchdog.Monitor。

  • 监控逻辑: Watchdog 线程会定期请求 AMS 去获取它的锁。

  • 如果 AMS 的 ⁠ServiceThread(即 ⁠MainHandler 所在线程)因为逻辑死循环卡死,Watchdog 即使能拿到锁也没用,因为 Monitor 检查通常包含 Handler 消息的派发检查。

  • 如果 Binder 线程池因为死锁(如 AMS 等 WMS,WMS 等 AMS)卡死,Watchdog 尝试拿锁会超时,从而触发重启。

三、 总结:正确的 AMS 线程模型视图

1.MainHandler 所在的线程:

  • 始终是独立的。自 Android 4.x/5.x 以来,它就运行在一个名为 ⁠"ActivityManager" 的 ⁠ServiceThread 中,绝不是 ⁠system_server 进程的主线程。

2.线程独立性:

  • ⁠system_server 主线程(UI Thread)

  • AMS 线程 (⁠ActivityManager ServiceThread)

  • System UI 辅助线程 (⁠android.ui ServiceThread)

  • 它们三者在 OS 层面完全独立,拥有各自的 Looper 和 Stack。

3.同步的核心痛点:

  • 虽然线程独立,但数据不独立

  • ⁠MainHandler 处理消息时(如处理 ⁠SERVICE_TIMEOUT_MSG),需要 ⁠synchronized(AMS)。

  • ⁠UiHandler 弹出 ANR 框时,需要读取进程信息,往往也需要 ⁠synchronized(AMS)。

  • 结论: 如果 AMS 线程因为逻辑错误(死循环)空转,UiHandler 不受影响。但如果 AMS 线程因为持锁阻塞(Waiting on I/O or other Locks),UiHandler 试图拿锁时也会被卡死。