第1章 AMS与WMS基础与性能模型:服务职责、通信链路、性能影响因子
1.1 服务职责全景
Android 系统中,AMS(ActivityManagerService) 与 WMS(WindowManagerService) 是两大核心系统服务,分别掌管应用生命周期与窗口管理。理解它们的职责边界是性能调优的第一步。
| 维度 | AMS | WMS |
|---|---|---|
| 核心职能 | Activity 栈管理、进程调度、Intent 解析、权限校验 | 窗口层级管理、输入事件分发、屏幕旋转、壁纸管理 |
| 关键数据结构 | ActivityStack、TaskRecord、ProcessRecord | WindowState、WindowToken、DisplayContent |
| IPC 通道 | IActivityManager(Binder) | IWindowManager(Binder) |
| 性能敏感路径 | startActivity、bindService、进程杀/拉 | relayoutWindow、setWindowLayout、input dispatch |
| 线程模型 | ActivityManagerThread(主线程)+ 多个 Worker | WindowManagerThread(主线程)+ 动画线程 |
调优认知起点: AMS 的瓶颈通常出现在 栈遍历 和 进程 OOM 调整 场景;WMS 的瓶颈集中在 窗口重新布局 和 输入事件分发链路 上。调优前必须能区分两类延迟来源。
1.2 通信链路分析
AMS 与 WMS 各自通过独立 Binder 通道与应用进程通信,同时两者之间通过内部回调互相协作。下面从链路层面拆解一次典型 Activity 启动过程中的关键通信节点。
1.2.1 链路全景
- 应用进程发起 Intent → 通过 Binder 调用 AMS.startActivity()
- AMS 解析栈与进程状态 → 若目标进程未启动,通过 Zygote 孵化新进程
- AMS 通知 WMS 准备窗口 → 调用 WMS.prepareAppTransition() + setAppVisibility()
- WMS 计算窗口层级与动画 → 向 SurfaceFlinger 提交事务
- 应用进程通过 relayoutWindow() 获取 Surface → 开始渲染第一帧
- WMS 回调 AMS.reportActivityVisible() → AMS 完成启动时序
链路关键时延点: 第3步 AMS→WMS 跨服务调用是串行阻塞的;第5步 relayoutWindow() 涉及 Buffer 分配与 Layer 创建,是 WMS 侧 CPU 峰值消耗点。
1.2.2 Binder 通信开销实测经验
使用 dumpsys binder 可以查看 AMS/WMS 对应 Binder 通道的调用频率与耗时:
adb shell dumpsys binder --stats | grep -E "android.app.IActivityManager|android.view.IWindowManager"
典型输出片段中,procStartTime 与 replySize 可直接反映通信负载。若单次调用 > 5ms 且频率 > 200次/秒,说明 Binder 线程池已接近饱和。
1.3 性能影响因子矩阵
从系统资源视角,将 AMS 与 WMS 的性能影响因子归纳为以下四类:
| 影响因子 | AMS 敏感度 | WMS 敏感度 | 典型症状 |
|---|---|---|---|
| Binder 线程池耗尽 | 高 | 高 | Activity 启动卡顿、窗口无响应 |
| 主线程锁竞争(AMS/WMS 内部锁) | 极高 | 极高 | 串行排队导致 ANR |
| SurfaceFlinger 事务积压 | 低 | 高 | 窗口创建/旋转掉帧 |
| 进程 OOM 优先级调整 | 高 | 低 | 后台进程频繁被杀/重启 |
| 窗口层级深度 | 低 | 高 | 输入事件分发延迟 |
| ContentProvider 冷启动 | 中 | 低 | 首次启动速度慢 |
常见误判: 开发者经常将 WMS 侧的 窗口布局延迟 误判为 GPU 渲染问题。区分方法:抓取
systrace 中 WMS.relayoutWindow 与 SurfaceFlinger 的间隔,若前者 > 4ms 而后者正常,则瓶颈在 WMS 而非 GPU。
1.4 AMS 与 WMS 性能模型
建立量化性能模型有助于定位调优优先级。将 AMS 与 WMS 的请求处理抽象为三阶段流水线:
- 入队阶段(Enqueue):Binder 从应用进程接收调用,放入服务端工作队列。耗时取决于 Binder 线程池空闲数。
- 处理阶段(Process):服务主线程或 Worker 执行核心逻辑(栈操作/窗口计算)。耗时取决于内部锁持有时间与数据结构大小。
- 回写阶段(Reply):将结果序列化写回 Binder 缓冲区。耗时与 reply 数据量成正比。
模型公式(经验参考):
Ttotal = Tenqueue + Tprocess + Treply
当 Tenqueue / Ttotal > 0.4 时,优先扩容 Binder 线程池(
当 Tprocess / Ttotal > 0.5 时,聚焦代码路径优化或锁拆分。
Ttotal = Tenqueue + Tprocess + Treply
当 Tenqueue / Ttotal > 0.4 时,优先扩容 Binder 线程池(
maxThreads 从 16 调至 24);当 Tprocess / Ttotal > 0.5 时,聚焦代码路径优化或锁拆分。
1.5 系统架构与通信链路图
1.6 调优切入路径
基于上述性能模型与影响因子矩阵,给出三条可立即落地的调优切入路径:
- Binder 线程池扩容 —— 在
system_server启动参数中调整-Dandroid.binder.maxThreads=24,适用于多并发 Activity 启动场景。 - WMS 锁拆分 —— 针对
WindowManagerService.java中的mWindowMap锁,将窗口遍历与布局计算拆分为读写锁,减少主线程阻塞。 - AMS 栈剪枝 —— 对于超过 8 层的 Activity 栈,启用
FLAG_ACTIVITY_CLEAR_TOP或主动收缩栈深度,降低 startActivity 时的栈遍历耗时。
快速验证命令:
查看当前 AMS/WMS Binder 调用统计:
查看当前 AMS/WMS Binder 调用统计:
adb shell dumpsys activity processes
adb shell dumpsys window --layout
关注 mBinderTransactionCount 与 mRelayoutCount 两个计数器,若超过 5000次/分钟 则需要介入优化。
1.7 常见错误与避坑
| 错误认知 | 实际原理 | 后果 |
|---|---|---|
| 「ANR 都是应用主线程阻塞」 | AMS 主线程持有锁时,应用 Binder 调用也会排队阻塞,间接导致应用 ANR | 误抓应用侧堆栈,忽略 system_server 锁竞争 |
| 「窗口卡顿就是 GPU 丢帧」 | WMS relayoutWindow 耗时 > 8ms 会导致应用无法及时获取有效 Surface,即使 GPU 空闲也会掉帧 | 盲目优化 GPU 渲染,浪费精力 |
| 「后台进程越多越好」 | AMS 维护的 ProcessRecord 越多,OOM 调整与栈遍历的线性开销越大,拖慢前台启动性能 | 启动速度随后台进程数增加而劣化 |
调优红线: 不要直接修改
ActivityManagerService.java 或 WindowManagerService.java 中的 synchronized 块作用域——错误的锁粒度调整可能引发死锁或 visibility 问题。建议先在 systrace 中锁定热点锁,再通过 ReentrantReadWriteLock 或 StampedLock 渐进替换。
1.8 本章小结
- AMS 负责应用生命周期与进程调度,WMS 负责窗口层级与输入分发;两者的 Binder 通信链路是性能瓶颈的集中区域。
- 性能影响因子包括 Binder 线程池、内部锁竞争、SurfaceFlinger 事务积压和进程 OOM 调整优先级。
- 建立 Tenqueue + Tprocess + Treply 三阶段模型,可量化定位调优方向。
- 三条切入路径:Binder 线程扩容、WMS 锁拆分、AMS 栈剪枝;使用
dumpsys命令快速验证效果。