本文基于 android-14.0.0_r1 AOSP 源码 ,对 AMS(ActivityManagerService)如何在 Android 14 中管控进程优先级(OOM 优先级) 进行一次完整、系统、可落源码的总结。
重点覆盖:
- AMS 的设计定位与职责边界
- Activity 启动后如何触发进程优先级重新评估
- OomAdjuster 的完整执行流程(含 LSP)
- OOM 优先级如何最终写入内核
- 一个完整、确定的 Activity 启动示例
一、总体设计思想
在 Android 14 中,进程优先级管控遵循一个清晰的分层原则:
Activity / Window 决定 "用户感知的重要性",AMS 负责把这种重要性转化为内核可理解的 OOM 优先级。
系统被拆分为三层职责:
| 层级 | 职责 | 关键模块 |
|---|---|---|
| UI / 状态层 | Activity 是否可见、是否可交互 | TaskFragment / ATS / ATMS |
| 决策层 | 进程重要性评估(adj /procState) | AMS / OomAdjuster |
| 生效层 | 内核 OOM 参数写入与回收 | ProcessList / lmkd / Kernel |
AMS 不管理 Activity 生命周期,只管理 "进程在内存回收中的生死顺序"。
二、进程优先级的核心表示方式
Android 使用两套状态共同描述 "进程优先级"。
1️⃣ oom_score_adj(给内核 /lmkd 使用)
- 取值范围:
-1000 ~ +1000 - 值越小 → 越不容易被杀
- 最终写入路径:
/proc/pid/oom_score_adj
2️⃣ procState(Framework 内部使用)
-
例如:
PROCESS_STATE_TOPPROCESS_STATE_VISIBLEPROCESS_STATE_CACHED
-
用途:
- OOM 决策
- 后台限制
- Job / Alarm 策略
- 进程统计(ProcessStats)
三、AMS 管控进程优先级的核心组件
在 Android 14 中,AMS 内部唯一负责进程优先级计算与调整的核心组件是: OomAdjuster
其职责包括:
- 接收 "需要重新评估进程优先级" 的请求
- 统一计算进程的
adj / procState - 判断是否需要把结果同步到 lmkd
- 触发后置的统计记录(ProcessStats)
四、Activity 启动后触发 AMS 重新评估的真实执行链路
基于 android-14.0.0_r1 源码,Activity 启动后触发 AMS 进行进程优先级更新的正确链路是
plaintext
TaskFragment.setResumedActivity
↓
ActivityTaskSupervisor.updateTopResumedActivityIfNeeded
↓
ActivityTaskManagerService.updateOomAdj
↓
ActivityManagerInternal.LocalService.updateOomAdj
↓
ActivityManagerService.updateOomAdjLocked
↓
OomAdjuster.updateOomAdjLocked
关键结论
- Activity 生命周期变化 不会自动通知 AMS
- 由 ATMS 在关键状态变化时显式调用
updateOomAdj - AMS 是被动进行 OOM 重新评估,而非监听 Activity 生命周期
五、OomAdjuster 内部的完整执行流程(Android 14)
1️⃣ 总入口
java
OomAdjuster.updateOomAdjLocked(...)
职责:
- 判断更新范围(单进程 / 全量)
- 防止递归和频繁抖动
- 驱动后续执行流程
2️⃣ 进入 LSP(Low-level Synchronized Path)
updateOomAdjLSP(...)目的:
- 减少 AMS 大锁持有时间
- 将计算逻辑与提交逻辑解耦
3️⃣ 实际执行路径
plaintext
updateOomAdjLSP
↓
performUpdateOomAdjLSP
↓
updateOomAdjInnerLSP
↓
computeOomAdjLSP ← 核心算法
4️⃣ computeOomAdjLSP:优先级计算核心逻辑
计算遵循 "从最低假设一路抬升" 的原则:
-
默认值:
- adj = CACHED_APP_ADJ
- procState = PROCESS_STATE_CACHED_EMPTY
-
Activity 相关(最重要):
- 读取 WindowProcessController
- hasForegroundActivities() → FOREGROUND_APP_ADJ
- hasVisibleActivities() → VISIBLE_APP_ADJ
-
Service 相关:
- 前台 Service(FGS)
- 后台 Service
-
依赖传播:
- bindService () → adj 继承
- ContentProvider → 链式传播
-
得到最终结果:
- curAdj
- curProcState
5️⃣ 是否需要真正生效
java
// We don't need to apply the update for the process which didn't get computed
if (state.getCompletedAdjSeq() == mAdjSeq) {
applyOomAdjLSP(app, doingAll, now, nowElapsed, oomAdjReason, true);
}
仅当结果发生变化时才继续。
六、真正的生效路径:applyOomAdjLSP → lmkd → 内核
1️⃣ applyOomAdjLSP
ProcessList.setOomAdj(pid, uid, adj, procState)
2️⃣ ProcessList:system_server 中的 lmkd 直接客户端
在 android-14.0.0_r1 中:
-
ProcessList 在 system_server 启动时:
- 通过 LocalSocket
- 建立到 /dev/socket/lmkd 的长连接
-
不经过 JNI / Binder
-
直接通过 socket 向 lmkd 写入 OOM 信息
3️⃣ socket 协议(简化)
plaintext
LMK_SET_PROC_ADJ
pid
uid
adj
procState
- 二进制协议
- system_server → lmkd
4️⃣ lmkd 的职责
- 接收 LMK_SET_PROC_ADJ
- 更新内部进程表
- 唯一允许写入 /proc//oom_score_adj 的用户态进程
七、完整示例:Activity 启动后的进程优先级调整(Android 14)
场景
- 后台进程 P(cached)
- 启动 Activity A
- A 成为用户可见、可交互的 Activity
1️⃣ Activity 进入 Resume
plaintext
TaskFragment.setResumedActivity
↓
ActivityTaskSupervisor.updateTopResumedActivityIfNeeded
2️⃣ ATMS 请求重新评估 OOM
plaintext
ActivityTaskManagerService.updateOomAdj
↓
AMS.updateOomAdjLocked
3️⃣ AMS 内部执行
plaintext
OomAdjuster.updateOomAdjLocked
↓
updateOomAdjLSP
↓
computeOomAdjLSP
→ hasForegroundActivities == true
→ adj = FOREGROUND_APP_ADJ (0)
→ procState = PROCESS_STATE_TOP
4️⃣ 生效路径
plaintext
applyOomAdjLSP
↓
ProcessList.setOomAdj
↓
LocalSocket → lmkd
↓
/proc/<pid>/oom_score_adj = 0
八、最终总结
在 Android 14(android-14.0.0_r1)中,AMS 通过 OomAdjuster 对进程优先级进行集中管控;Activity 成为 Top Resumed 后,由 ATMS 显式触发 OOM 重新评估,OomAdjuster 在 LSP 路径中计算进程 adj,并由 ProcessList 通过 socket 直接通知 lmkd 写入 /proc/pid/oom_score_adj,从而完成进程优先级在内核侧的最终生效,而 ProcessStatsService 仅承担事后统计记录的角色。