Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Android Framework 源码与进程生命周期

本篇承接四大组件, View 和 Binder 章节, 把系统服务, Activity 启动, Window 显示, 应用安装和进程死亡串成一条链. 面试重点不是背某个 Android 版本的私有方法名, 而是说明跨进程边界, 线程切换, 状态所有权和版本边界.

一, Android 系统启动与核心角色

从 init 到应用进程

Linux kernel
  -> init
     -> servicemanager / native services
     -> Zygote
        -> system_server
        -> application process
  • init: 用户空间第一个进程, 解析 rc 配置并启动 Zygote, ServiceManager 和部分 native 服务.
  • ServiceManager: Binder 服务注册与查询中心. 系统服务把 Binder 入口注册进去, Client 按名称取得代理.
  • Zygote: 预加载常用类和资源, 通过 fork 创建 system_server 与应用进程, 利用写时复制减少启动成本.
  • system_server: 承载 AMS, ATMS, WMS, PMS 等大量 Java 系统服务.
  • 应用进程: 从 ActivityThread.main() 建立主线程 Looper, 再通过 Binder 与 system_server 协作.

核心系统服务怎么分工

服务主要职责高频追问
AMS进程, Service, Broadcast, Provider 等运行管理谁创建进程, 谁维护进程状态
ATMSActivity 与 Task 调度, 启动模式和回退栈Activity 启动和任务栈如何变化
WMSWindow token, 层级, 焦点, 输入和 Surface 协调Window 如何跨进程加入屏幕
PMSAPK/Manifest 解析, 组件和权限信息, 安装更新点击图标前系统如何知道组件
SurfaceFlinger合成各应用和系统提交的图层View draw 后为什么还没有直接显示

Android 10 前后部分职责从 AMS 拆分到 ATMS. 面试可按当前架构区分职责, 同时说明旧资料可能仍把 Activity 调度统称为 AMS.

二, Activity 启动完整链路

从点击图标到目标进程

  1. Launcher 根据 PMS 返回的可启动组件构造 Intent.
  2. startActivity() 最终通过 Binder 请求 ATMS 启动目标 Activity.
  3. ATMS 解析 Intent, 权限, 启动模式, taskAffinity 和 Intent flags, 决定复用哪个 Task/Activity 或创建新实例.
  4. 如果目标进程不存在, system_server 请求 Zygote fork 应用进程.
  5. 新进程进入 ActivityThread.main(), 准备主线程 Looper, 创建 ActivityThread 并向 AMS 执行 attachApplication.
  6. system_server 通过应用侧的 Binder 入口下发生命周期事务, 应用主线程处理事务并创建目标组件.

应用进程内如何创建 Activity

现代 Android 使用 ClientTransaction 及一组 transaction item 描述启动和生命周期变更. 可以用下面的稳定心智模型回答:

system_server
  -> ApplicationThread Binder callback
     -> ActivityThread main Handler
        -> create/load Activity
           -> Instrumentation.newActivity
           -> Activity.attach
           -> Instrumentation.callActivityOnCreate
           -> onStart / onResume
  • ActivityThread: 应用进程主线程的管理者, 负责调度组件和生命周期, 它本身不是 Thread 子类.
  • ApplicationThread: 应用暴露给 system_server 的 Binder 入口, 接收系统调度.
  • Instrumentation: 参与 Activity 创建和生命周期调用, 测试框架也利用它观察或替换组件行为.
  • LoadedApk/ClassLoader: 提供 APK 的类, 资源和组件信息.
  • ClientTransaction: 把启动, 暂停, 恢复等事务统一下发; 私有 item 名称会随版本演进, 不应当作公开 API 背诵.

启动模式到底在哪里生效

启动模式不是 Activity 自己在 onCreate() 里决定的. ATMS 在创建实例前根据当前 Task, Manifest 配置和 Intent flags 计算启动结果:

  • singleTop: 目标已在当前栈顶时复用, 回调 onNewIntent().
  • singleTask: 寻找合适任务中的既有实例, 常伴随清理其上的 Activity.
  • FLAG_ACTIVITY_NEW_TASK: 根据调用方和 affinity 寻找或创建 Task.
  • FLAG_ACTIVITY_CLEAR_TOP: 目标存在时清除它上方实例, 是否复用还要结合启动模式和其他 flag.

面试画任务栈时要同时写出原栈, Intent flag, 最终栈和回调, 不能只背四种 launchMode 定义.

三, Window 与一帧如何显示

Activity, Window 和 View 的对象关系

Activity
  -> PhoneWindow
     -> DecorView
        -> content View tree

WindowManagerImpl
  -> WindowManagerGlobal
     -> ViewRootImpl
        -> IWindowSession / WMS
  • Activity 在 attach 阶段创建 PhoneWindow.
  • setContentView() 把业务布局放进 DecorView 的 content 区域.
  • WindowManager 把 DecorView 加入窗口系统, 应用侧为这棵 View 树创建 ViewRootImpl.
  • ViewRootImpl 通过 Binder 与 WMS 的 Session 通信, 申请窗口, Surface, 焦点和输入相关资源.

Window 是窗口能力抽象, DecorView 是 View 树根节点, ViewRootImpl 是应用侧 View 树与系统窗口服务之间的桥梁. ViewRootImpl 不是 DecorView 的父 View.

从 requestLayout 到屏幕像素

  1. View 请求布局或重绘, ViewRootImpl 安排下一次 traversal.
  2. Choreographer 接收 VSync, 在主线程执行 input, animation, traversal 等阶段.
  3. 主线程完成 measure/layout, 并记录绘制命令或更新渲染节点.
  4. RenderThread/GPU 在硬件加速路径处理渲染命令, 把结果写入 BufferQueue 对应的图形缓冲.
  5. SurfaceFlinger 收集各窗口图层, 结合 Z-order, 变换和硬件合成能力生成最终画面.
  6. 显示系统在合适的刷新时序把合成结果送到屏幕.

掉帧不只可能发生在 onDraw(). 主线程布局, RenderThread, 纹理上传, GPU, SurfaceFlinger 合成和系统调度都可能超过帧预算, 所以要用 Perfetto/Frame Timeline 确认瓶颈位置.

高刷新率下的帧预算

刷新率单帧理论预算
60Hz约 16.7ms
90Hz约 11.1ms
120Hz约 8.3ms

16.7ms 不是所有设备的固定标准. 面试应回答 “预算由当前刷新率和系统调度决定”, 并用 Frame Timeline 的实际 deadline 判断 jank.

BufferQueue, 缓冲与 VSync

BufferQueue 是生产者 (应用渲染侧) 与消费者 (通常是 SurfaceFlinger) 交换图形 buffer 的队列:

Producer(应用):       VSync -> dequeueBuffer -> 绘制 -> queueBuffer
BufferQueue(队列):              空闲 buffer <- 就绪 buffer <- 被 Consumer 获取
Consumer(SurfaceFlinger): VSync -> acquireBuffer -> 合成 -> present/release

应用渲染与 SurfaceFlinger 合成是异步节拍: Producer 的 queueBuffer 不保证被同一个 VSync 的 Consumer 合成, 队列可能等待下一次消费. 双缓冲可理解为显示和绘制各占一个 buffer; 三缓冲多保留一个就绪 buffer, 能减少生产者等待但可能增加排队延迟和内存. 它们是教学模型, 不是每台设备固定配置; 应以 Frame Timeline 的实际 deadline 判断 jank.

四, PMS 与应用安装 / 更新

系统为什么能找到 Activity

PMS 维护已安装包, 组件, IntentFilter, 权限, 签名和版本等信息. Launcher 查询可启动 Activity, ATMS 解析显式 / 隐式 Intent, 系统校验 exported 和 permission 都依赖这份包信息.

安装链路的稳定模型

PackageInstaller session
  -> 校验安装请求和包结构
  -> 复制/准备 APK 与 native library
  -> 解析 Manifest 和组件
  -> 校验签名,版本和权限
  -> 注册包信息并准备 dex 优化
  -> 发送包变更通知
  • 覆盖安装通常要求 applicationId 一致, 签名兼容且 versionCode 满足系统策略.
  • APK Signature Scheme v2/v3/v4 覆盖范围和增量安装能力不同, 但业务面试重点是 “签名保护身份和完整性, 更新必须维持签名连续性”.
  • DEX 优化会随 Android 版本, 安装方式, 设备状态和 ART Service 策略变化, 不要把 dex2oat 的某个命令流程说成所有版本都固定.
  • 四大组件, Provider authority, 权限和 exported 配置在安装 / 扫描阶段进入系统可查询的数据结构.

五, 进程优先级与 LMK

Android 会根据组件状态和用户可见性调整进程重要性, 再由系统内存管理与 lmkd 在压力下选择回收目标.

常见层级例子被回收风险
前台进程顶部 Activity, 执行关键前台回调最低
可见进程Activity 可见但未获得焦点较低
服务进程执行受系统认可的 Service 工作中等
缓存进程没有活跃组件, 仅为下次启动缓存最高

进程被杀时通常不会给应用可靠的 Application.onTerminate() 或完整清理回调. 关键数据必须在业务操作时持久化, 不能把希望寄托在 “被杀前保存”.

进程优先级不是固定五档枚举实现. Android Framework 内部会计算进程 adj, 再最终映射为内核暴露的 oom_score_adj; 旧资料中的 oom_adj 是历史接口 / 术语, 不能与 oom_score_adj 混称. 系统还会结合组件关系, 前台服务, 厂商策略和实时内存压力计算, 面试应使用层级模型而不是承诺固定阈值.

oom_adj 与任务栈推演

oom_score_adj 是内核 OOM 选择使用的调整值, 数值通常越大越易被杀. 以 Android 10+ AOSP 的概念性区间示例, 前台/可见/服务/缓存常见值约在 0, 100, 500, 900 一带; 这不是 API 或设备承诺. 应在目标设备读取 adb shell cat /proc/<pid>/oom_score_adj, 并结合 dumpsys activity processes 验证.

假设性演练, 非设备实测: Task 为 [A, B], B 在顶端; 从 B 启动 B 且 B 为 singleTop, 最终仍为 [A, B], 既有 B 收到 onNewIntent(). 从 B 用 CLEAR_TOP 启动 A 会清除 A 之上的 B, A 是否复用还受启动模式影响. 推演先写初始栈, 调用方, manifest/flags, 再写最终栈和回调, 不能把 singleTask 说成永远全局唯一.

六, 配置变更, 进程死亡与状态恢复

三类 “重建” 必须分开

场景进程Activity 实例ViewModelSavedState持久化数据
旋转等配置变更通常保留重建同 owner 可保留可恢复保留
后台进程被杀后返回已重建重建旧实例丢失系统保留的少量状态可恢复保留
用户返回键退出 / 清除业务可能保留销毁清除不应依赖自动恢复按业务决定
  • ViewModel: 解决配置变更期间的内存状态保留, 不能跨进程死亡保存实例.
  • SavedStateHandle/Bundle: 保存少量可序列化 UI 状态, 受 Binder/Bundle 大小与恢复时机约束.
  • Room/DataStore/文件: 保存必须跨进程和设备重启存在的数据.
  • Repository: 决定恢复时从网络, 本地数据库或缓存重建页面状态.

推荐把页面状态拆成三层:

  1. 可由业务数据重新计算的派生 UI 状态, 不持久化.
  2. 当前 tab, 输入草稿, 滚动锚点等轻量状态, 使用 SavedState.
  3. 订单, 消息, 上传进度等关键状态, 持久化并设计幂等恢复.

七, Framework 源码题的答题方法

  1. 先说业务入口和最终结果.
  2. 标出进程边界: 应用进程, system_server, Zygote/SurfaceFlinger.
  3. 标出 Binder 调用和线程切换: Binder 线程还是应用主线程.
  4. 说清状态归属: Task 在系统侧, View 树在应用侧, 图层由 SurfaceFlinger 合成.
  5. 最后补版本边界, 不把私有类名和方法名说成稳定 API.

帧预算统一口径

一帧 16.7 ms 仅是 60 Hz 示例, 不能作为固定性能标准. View/Compose/动画章节统一用实际显示刷新率, FrameTimeline 和用户可见 jank 证据说明 deadline; 详细排查见 ANR 与卡顿排查. Framework 调用链应标注所读 AOSP tag, 不把内部实现当稳定 API.

高频面试题

Q1: ActivityThread 是线程吗? 不是. 它是应用进程主线程的组件调度管理者, 真正的主线程从 ActivityThread.main() 启动并进入 Looper. ApplicationThread 则是提供给 system_server 的 Binder 回调入口.

Q2: AMS 和 ATMS 有什么区别? AMS 更关注进程以及 Service, Broadcast, Provider 等运行管理; ATMS 从 AMS 中拆出, 专门处理 Activity, Task, 启动模式和窗口容器相关调度. 旧资料可能把两者统称为 AMS 链路.

Q3: Activity 的生命周期是谁调用的? system_server 决定生命周期事务, 通过应用侧 Binder 入口下发; ActivityThread 在应用主线程处理事务, 并通过 Instrumentation 调用 Activity 的生命周期方法.

Q4: ViewRootImpl 是 View 吗? 是 DecorView 的父节点吗? 都不是. ViewRootImpl 是应用侧 View 树与 WindowManager/WMS 之间的桥梁, 驱动 traversal, 输入和 Surface 协作; DecorView 仍是 View 树的根 View.

Q5: View 调用 draw 后为什么还没有直接显示到屏幕? 应用生成绘制命令并把缓冲提交到 Surface, SurfaceFlinger 还要把多个窗口图层按层级和变换合成, 再交给显示系统. 主线程, RenderThread, GPU 和合成都可能影响一帧.

Q6: 进程被系统杀死前一定会回调 onDestroy/onTerminate 吗? 不一定. 内存压力下系统可以直接终止缓存进程, 不能依赖清理回调保存关键数据. 状态应在发生变化时持久化, 返回页面时按持久状态和 SavedState 重建.

Q7: ViewModel 能解决进程死亡吗? 不能保存旧实例. ViewModel 只保证同一 owner 在配置变更中的保留语义. 进程死亡后需要 SavedStateHandle 恢复少量 UI 状态, 用 Room/DataStore/文件恢复关键业务数据.

Q8: 安装 APK 时系统主要做什么? 接收 PackageInstaller session, 校验包结构, 签名, 版本和权限, 解析 Manifest 与组件, 准备 APK/native library 和 dex 优化, 更新 PMS 包信息并通知包变化. 具体内部服务和优化时机会随 Android 版本变化.

易错点 / 追问

  • 不要说 AMS 负责所有 Activity 细节; 新版本应说明 ATMS 的拆分.
  • 不要把 ActivityThread 说成 Thread 子类, 也不要把 ApplicationThread 当作应用主线程.
  • 不要说 ViewRootImpl 是 View 或 DecorView 的父 View.
  • 不要把 onSaveInstanceState 当数据库使用, 大对象会增加事务和恢复风险.
  • 不要依赖 onDestroy(), Application.onTerminate() 保存关键状态.
  • 源码类名和事务 item 会随版本变化, 回答重点应是跨进程模型和职责边界.