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 等运行管理 | 谁创建进程, 谁维护进程状态 |
| ATMS | Activity 与 Task 调度, 启动模式和回退栈 | Activity 启动和任务栈如何变化 |
| WMS | Window token, 层级, 焦点, 输入和 Surface 协调 | Window 如何跨进程加入屏幕 |
| PMS | APK/Manifest 解析, 组件和权限信息, 安装更新 | 点击图标前系统如何知道组件 |
| SurfaceFlinger | 合成各应用和系统提交的图层 | View draw 后为什么还没有直接显示 |
Android 10 前后部分职责从 AMS 拆分到 ATMS. 面试可按当前架构区分职责, 同时说明旧资料可能仍把 Activity 调度统称为 AMS.
二, Activity 启动完整链路
从点击图标到目标进程
- Launcher 根据 PMS 返回的可启动组件构造 Intent.
startActivity()最终通过 Binder 请求 ATMS 启动目标 Activity.- ATMS 解析 Intent, 权限, 启动模式, taskAffinity 和 Intent flags, 决定复用哪个 Task/Activity 或创建新实例.
- 如果目标进程不存在, system_server 请求 Zygote fork 应用进程.
- 新进程进入
ActivityThread.main(), 准备主线程 Looper, 创建 ActivityThread 并向 AMS 执行attachApplication. - 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 到屏幕像素
- View 请求布局或重绘, ViewRootImpl 安排下一次 traversal.
- Choreographer 接收 VSync, 在主线程执行 input, animation, traversal 等阶段.
- 主线程完成 measure/layout, 并记录绘制命令或更新渲染节点.
- RenderThread/GPU 在硬件加速路径处理渲染命令, 把结果写入 BufferQueue 对应的图形缓冲.
- SurfaceFlinger 收集各窗口图层, 结合 Z-order, 变换和硬件合成能力生成最终画面.
- 显示系统在合适的刷新时序把合成结果送到屏幕.
掉帧不只可能发生在 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 实例 | ViewModel | SavedState | 持久化数据 |
|---|---|---|---|---|---|
| 旋转等配置变更 | 通常保留 | 重建 | 同 owner 可保留 | 可恢复 | 保留 |
| 后台进程被杀后返回 | 已重建 | 重建 | 旧实例丢失 | 系统保留的少量状态可恢复 | 保留 |
| 用户返回键退出 / 清除业务 | 可能保留 | 销毁 | 清除 | 不应依赖自动恢复 | 按业务决定 |
- ViewModel: 解决配置变更期间的内存状态保留, 不能跨进程死亡保存实例.
- SavedStateHandle/Bundle: 保存少量可序列化 UI 状态, 受 Binder/Bundle 大小与恢复时机约束.
- Room/DataStore/文件: 保存必须跨进程和设备重启存在的数据.
- Repository: 决定恢复时从网络, 本地数据库或缓存重建页面状态.
推荐把页面状态拆成三层:
- 可由业务数据重新计算的派生 UI 状态, 不持久化.
- 当前 tab, 输入草稿, 滚动锚点等轻量状态, 使用 SavedState.
- 订单, 消息, 上传进度等关键状态, 持久化并设计幂等恢复.
七, Framework 源码题的答题方法
- 先说业务入口和最终结果.
- 标出进程边界: 应用进程, system_server, Zygote/SurfaceFlinger.
- 标出 Binder 调用和线程切换: Binder 线程还是应用主线程.
- 说清状态归属: Task 在系统侧, View 树在应用侧, 图层由 SurfaceFlinger 合成.
- 最后补版本边界, 不把私有类名和方法名说成稳定 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 会随版本变化, 回答重点应是跨进程模型和职责边界.