故事:《安卓工厂的“工人”诞生记与退休制度》​

77 阅读6分钟

想象 Android 系统是一个庞大的工厂(手机),里面需要运行很多“工人”(App)。但工厂不能随便招人(创建进程),也不能养闲人(浪费内存),所以有一套严格的“工人”管理制度。

​1. 工厂的启动与“祖师爷”:Zygote (受精卵)​

  • ​故事:​​ 工厂刚通电启动(开机),第一个员工叫 init(初始化专员)。他的重要任务之一就是孵化出一个特殊的“祖师爷”工人——​​Zygote​​。Zygote 可不是普通工人,他天生就带着整个工厂的基础技能包(核心类库如 android.os.*android.view.*,基本工具如 Drawable 图片模板、颜色模板等)。他启动的方式也很特别:/system/app_process --start-system-server 这条指令就像给他的启动手册。

  • ​技术核心:​

    • Zygote 由 init 进程启动。
    • 它预加载了大量 Java 核心类(Preload Classes, 参考 frameworks/base/preloaded-classes)和系统资源(Preload Drawables/Color State List, 参考 res/values/arrays.xml)。
    • 它启动后,会建立一个“招聘信箱”(Unix Domain Socket, 名字就叫 zygote),专门用来接收来自“大管家”(后面会讲到)的招工请求。
    • Zygote 启动完,它的“大脑”(地址空间)里就装满了工厂的基础设施蓝图(预加载的类库资源)。

​2. “大管家”诞生:System Server (系统服务)​

  • ​故事:​​ Zygote 祖师爷孵化出来后,做的第一件大事就是按照“启动手册”的指示(--start-system-server),生下了工厂的“​​大管家​​”—— ​​System Server​​ 进程。这个大管家是整个工厂运作的核心,权力很大(拥有很高的权限 CAP_KILL 等,参考 capability.h)。大管家一出生(startSystemServer),就由 Zygote 帮忙配置好了身份(用户组 ID AID_SYSTEM,参考 android_filesystem_config.h)。

  • ​技术核心:​

    • System Server 是 Zygote fork 出来的第一个子进程。
    • 它继承了 Zygote 预加载的类库。
    • 它启动后,首先初始化底层硬件驱动(Init1() - Native 层服务),然后启动所有重要的 Java 层管理服务(Init2() - ServerThread.run()),比如负责管理工人的“人事部”(ActivityManagerService - AMS)、负责管理工人窗口位置的“调度部”(WindowManagerService - WMS)等等。这些服务共同构成了 Android 框架的核心。
    • 大管家启动后,它的“大脑”里也装满了基础蓝图,并且开始运行工厂的核心管理程序。

​3. 招聘新“工人”:应用程序进程启动​

  • ​故事:​​ 当用户想打开一个 App(比如微信),就相当于工厂需要招聘一个新的“微信工人”。这个请求会先提交给大管家(ActivityManagerService)。

    • 大管家(AMS)检查需求后,发出招聘指令:startProcessLocked()
    • 指令层层下达:Process.start() -> Process.startViaZygote()
    • 最终,一个“招聘请求”(包含 App 包名、需要的权限等参数)被塞进了祖师爷 Zygote 的“招聘信箱”(Socket)。
  • ​技术核心:​

    • ActivityManagerService.startProcessLocked() 是起点。

    • Process 类通过 zygote Socket 发送参数(zygoteSendArgsAndGetResult)。

    • Zygote 从 Socket (ZygoteConnection.runOnce()) 收到请求。

    • Zygote 使用 ​fork() 魔法​​(快照复制自己),瞬间“克隆”出一个新的、几乎空白的“工人胚胎”进程(handleChildProc)。

    • 新工人胚胎立刻开始“培训”(RuntimeInit.zygoteInit()):

      • 建立自己的通信渠道(nativeZygoteInit() - 启动 Binder 线程池)。
      • 加载 App 自己的技能包(applicationInit() - 调用 ActivityThread.main()),成为真正的“微信工人”开始工作。
    • ​关键魔法:​​ Zygote 的 fork() 利用了 Linux 的 ​​Copy-on-Write (COW)​​ 机制。新进程(工人)刚诞生时,和 Zygote(祖师爷)共享大部分“基础技能”(预加载的类库和资源)。只有当新工人需要修改某些“技能”时,才会真正复制一份出来。这​​极大提高了“招工”效率,节省了内存​​!

​4. 工厂内存紧张:“工人”退休制度 (进程回收)​

  • ​故事:​​ 工厂空间(内存)有限。当订单太多(运行 App 太多),空间快不够用时,就需要让一些不太重要的工人“退休”(杀死进程),腾出空间给更重要的工作。工厂有两套退休方案:

    • ​方案A:自动清洁机器人 - Low Memory Killer (LMK)​

      • 大管家(AMS)给每个工人贴了一个​​“重要等级”标签(oom_adj 值)​​,范围是 -16 (最重要) 到 15 (最不重要)。

      • ​等级规则:​

        • -16 (SYSTEM_ADJ):大管家自己(System Server),绝不能退休。
        • -12 (PERSISTENT_PROC_ADJ):常驻工头(如电话 App),非常重要。
        • 0 (FOREGROUND_APP_ADJ):正在和用户直接交流的工人(有前台 Activity)。
        • 1 (VISIBLE_APP_ADJ):用户能看到的工人(有可见 Activity)。
        • 2 (PERCEPTIBLE_APP_ADJ):用户能感知到的工人(比如在放音乐的服务)。
        • 5 (SERVICE_ADJ):普通后台服务工人。
        • 6 (HOME_APP_ADJ):桌面工人。
        • 7 (PREVIOUS_APP_ADJ):用户上一个使用的工人。
        • 9-15 (HIDDEN_APP_MIN_ADJ - MAX_ADJ):完全躲在后台的工人,很久没干活的等级就高(越不重要)。
      • ​特殊规则:​​ 如果一个工人(A)正在为另一个更重要的工人(B,等级低)干活(比如提供数据或服务),那么工人A的等级会被提升(降低 oom_adj),变得和工人B一样重要(或至少不会低于前台App等级)。

      • ​清洁流程:​​ LMK 机器人监控着工厂的剩余空间(内存)。当空间降到某个阈值(比如只剩很少了),它就根据预先设定的规则表(oom_adj_to_min),查找当前哪个等级(oom_adj >= j)的工人可以被清理。它会优先干掉 ​​等级最高(最不重要)且占空间最大​​ 的工人。

    • ​方案B:大管家主动裁员 - AMS / WMS​

      • 大管家(AMS)和调度部(WMS)非常聪明,它们会在工人状态发生​​关键变化时主动检查​​是否该让某些工人退休:

        • 工人停止了一项重要任务(activityStopped)。
        • 工厂规定了最多只能有多少工人(setProcessLimit)。
        • 工人注销了广播接收器(unregisterReceiver / finishReceiver)。
      • 它们也负责清理那些“公司已经倒闭”(App 被卸载)但工人还在的幽灵进程。

  • ​技术核心:​

    • oom_adj 是核心:​​ 由 AMS 根据进程中运行的组件(Activity/Service 等)状态动态计算。
    • ​LMK 驱动:​​ 内核模块,基于 oom_adj 和内存阈值进行回收。
    • ​主动回收:​​ AMS 在特定生命周期回调点调用 updateOomAdjLocked() 更新进程 oom_adj 并可能触发回收 (killProcessesLocked)。

​总结:Android 工厂的“工人”管理哲学​

  1. ​高效“造人”:​​ 利用 Zygote ​​预加载​​ + ​fork() + Copy-on-Write​​,让创建新 App 进程变得极其快速且节省内存。
  2. ​精细化管理:​​ 通过 oom_adj 值​​精确量化​​每个 App 进程的重要性(优先级)。
  3. ​内存危机应对:​​ 结合被动监控(​​Low Memory Killer​​ 驱动)和主动管理(​​AMS/WMS​​),在内存不足时,​​严格按优先级从低到高​​(oom_adj 从大到小)回收进程,优先保障前台用户体验和系统核心服务的运行。
  4. ​依赖关系处理:​​ 如果一个进程服务于更重要的进程,它的重要性会相应提升(oom_adj 降低),避免误杀关键后台服务。

这篇文章就是详细讲解了 Android 系统如何像一个精密的工厂一样,高效地创建(孵化)应用程序进程,并在内存资源紧张时,智能地根据重要性(优先级)回收(退休)进程,从而保证整个系统流畅、稳定运行的核心机制。Zygote、System Server、AMS、WMS 和 Low Memory Killer 就是这套机制的五大关键角色。