4. 进程管理
4.1 模块边界与层次划分
进程管理模块位于Android架构的Native层与Java框架层之间,核心参与者包括Zygote进程、SystemServer(内含AMS)、lmkd守护进程及所有应用进程。层次划分如下:
- Zygote层(Native + Java混合):系统启动时由init进程启动,预加载核心类库与资源,通过socket监听AMS的fork请求。
- AMS层(Java框架):负责进程创建决策、进程优先级计算(oom_adj)及生命周期管理,运行于SystemServer进程。
- lmkd层(Native):监听内核vmpressure与PSI事件,根据AMS写入的oom_adj分数选择杀进程。
- 应用进程层(Java + Native):由Zygote fork产生,每个进程拥有独立的oom_adj分数,由LMK机制按需回收。
OMG:边界关键点 – Zygote仅负责进程“孵化”,不参与后续调度;AMS是进程优先级唯一的决策者;lmkd是最终执行者。三者通过Unix域Socket(Zygote ↔ AMS)和procfs(AMS ↔ lmkd)通信。
下图为进程管理核心模块之间的边界与协作概览:
4.2 核心组件职责
| 组件 | 所在进程 | 核心职责 |
|---|---|---|
| Zygote | system/zygote | 预加载Java类、资源、共享库;创建Unix域socket ‘@zygote’;fork并执行ActivityThread main()。 |
| AMS (ActivityManagerService) | SystemServer | 决策何时创建新进程(startProcessLocked);管理进程重要性排序;周期性更新oom_adj(updateOomAdjLocked);处理进程死亡与重启。 |
| lmkd | init派生 | 监听内核vmpressure/PSI事件;读取/proc/pid/oom_adj_score;根据配置阈值选择目标进程发送SIGKILL。 |
| Proc文件系统 | 内核 | 提供/proc/pid/oom_adj与oom_score_adj接口,由AMS写入,lmkd读取。 |
4.3 控制流与数据流
4.3.1 进程创建流程
- AMS发起:当应用组件(Activity/Service/BroadcastReceiver)需要运行时,AMS检查对应进程是否存在。若不存在,调用
ProcessList.startProcessLocked()。 - Socket通信:AMS通过LocalSocket连接Zygote,发送包含启动参数(类名、uid、gids等)的
ProcessStartInfo。 - Zygote fork:Zygote在子进程中
fork()并执行handleChildProc(),调用RuntimeInit.zygoteInit(),最终通过反射执行目标类的main()(如ActivityThread)。 - 进程注册:新进程首次与AMS建立Binder连接(调用
attachApplication()),AMS记录进程信息到ProcessList。
关键控制点:Zygote fork后,子进程继承父进程的预加载状态,因此启动速度远快于直接exec。但这也意味着所有Zygote派生的进程共享相同的堆初始化内容,导致“写时复制”内存开销。
4.3.2 oom_adj计算与写入
AMS在每当组件可见性、前台服务状态、最近使用等发生变化时,调用updateOomAdjLocked()。该函数遍历所有进程,按照优先级策略重新计算oom_adj(范围为[-1000, 1000]),其中:
- 前台Foreground App / Service:oom_adj = 0 ~ -17(系统根据adj值反转计算oom_score_adj)
- 感知进程(Perceptible):oom_adj = 200
- 可服务进程(Service):oom_adj = 500 ~ 900
- 缓存进程(Cached):oom_adj = 900 ~ 1000
计算完成后,AMS通过ProcessList.writeOomAdjToProc写入/proc/[pid]/oom_adj(或oom_score_adj)。lmkd进程周期性或事件驱动检查这些值,结合内存压力决定杀进程。
// 伪代码:AMS中oom_adj写入关键路径
void updateOomAdjLocked() {
for (ProcessRecord proc : mProcessList) {
int adj = computeOomAdj(proc);
proc.setOomAdj(adj);
// 写入内核接口
FileUtils.stringToFile("/proc/" + proc.pid + "/oom_score_adj", String.valueOf(adj));
}
}
风险提醒:AMS后台计算oom_adj的线程是
mProcessList.oomAdjUpdateThread,若计算逻辑过于复杂或进程数过多(> 500),可能阻塞Binder线程,导致系统ANR。Android 12+引入ProcessList.updateOomAdj的异步化改进以缓解此问题。
4.4 设计权衡
| 权衡点 | 方案 | 优势 | 代价 |
|---|---|---|---|
| Zygote预加载策略 | 预加载所有系统类、资源、通用dex | 应用启动速度提升,首次类加载全由Zygote完成 | Zygote堆内存过大(> 10MB),写时复制抢占物理内存;预加载类越多,冷启动时fork开销越大 |
| oom_adj更新时机 | 实时更新 vs 延迟批量更新 | 实时更新保证LMK迅速准确选择目标 | 频繁写入procfs增加CPU开销;延迟更新可能导致杀错进程 |
| 进程唯一性保证 | AMS维护进程映射,避免重复创建 | 组件复用进程,资源节约 | 进程死锁检测复杂;进程名相同但uid不同时难以区分 |
4.5 风险点
- Zygote Crash导致系统重启:Zygote一旦异常退出,所有应用进程成为孤儿进程,init会重新启动Zygote,但已运行的应用无法恢复。
- oom_adj误杀关键进程:如果AMS未及时更新前台Service的adj值,lmkd可能误杀包含前台通知的进程,造成用户感知卡顿。
- 进程“僵尸”残留:Zygote fork后若应用初始化失败,进程可能未完成attachApplication而与AMS失联,形成僵尸进程占满
/proc节点。 - Socket通信拥塞:高并发应用启动(如开机自启动或通知洪水)下,Zygote socket缓冲区溢出导致fork超时。
调试技巧:使用
adb shell dumpsys activity oom 查看当前所有进程的oom_adj状态;使用 adb shell cat /proc/[pid]/oom_score_adj 直接读取内核实际值,比对AMS中的预期值以定位adj不一致问题。
4.6 落地步骤
- 理解Zygote启动序列:阅读
frameworks/base/cmds/app_process/app_main.cpp及com.android.internal.os.ZygoteInit。关注ZygoteConnection.runOnce()如何解析fork请求。 - 实现AMS进程创建接口:在
ActivityManagerService.startProcessLocked中,确保通过ProcessList.processRecordForStart构建正确的ProcessRecord,并处理跨用户UID。 - 配置lmkd阈值:在
device/中调整/ /init.rc ro.lmk.*参数,例如ro.lmk.oom_adj_max和ro.lmk.swap_util_max,与AMS的adj范围对齐。 - 编写单元测试:模拟AMS计算adj的过程,使用JUnit验证前台/后台/缓存场景下adj的正确性。
- 集成测试:使用
am start启动多个组件,通过dumpsys activity oom和cat /proc/pid/oom_score_adj验证一致性。 - 性能压测:同时启动50+应用,监控Zygote socket延迟和AMS updateOomAdj耗时。
4.7 验收标准
| 验收项 | 预期结果 | 验证方法 |
|---|---|---|
| 应用冷启动时间 | 从点击到首帧绘制时间 ≤ 800ms(中端设备) | atrace 抓取,关注ActivityManager: startProcess到ActivityThread: bindApplication耗时 |
| oom_adj正确性 | 前台Activity所在进程oom_adj ≤ 0;后台缓存进程adj ≥ 900 | adb shell dumpsys activity oom 对照当前组件状态 |
| 低内存处理 | 可用内存低于200MB时,lmkd按adj降序杀进程,不误杀前台Service | 构造低内存场景(malloc大块内存),观察logcat中lmkd日志和kill 行为 |
| Zygote socket健壮性 | 同时并发启动10个进程,所有fork在3秒内完成 | 使用am start脚本批量运行,统计ProcessRecord.holdDie无僵尸 |
进程管理模块是AMS稳定性的基石,理解Zygote孵化、AMS决策与lmkd执行的闭环,是深入掌握Android系统资源管控的核心。