Appearance
Android App 进程启动全流程 (Zygote → ActivityThread → 首帧)
回到总览:性能、测试、排障
相关模块:应用启动性能优化实战(拓扑排序、异步初始化与首帧治理) · Android View 绘制流程、Choreographer 与 VSync 帧同步
一句话定义
Android App 启动全流程是指从用户点击桌面 App 图标起,经过 AMS 向 Zygote 申请 fork() 孵化应用进程、加载 ART 虚拟机与 Class、调用 ActivityThread.main() 开启主线程 Looper,到执行 Application.onCreate() 并最终由 ViewRootImpl 完成首帧(First Frame)绘制上屏的完整生命全链路。
代码索引
计划补齐的实验:
labs/android/host/topics/performance/startup-tracing-demo/— 冷启动耗时打点、Trace.beginSection 分析与首帧回调监听
为什么需要
- 为什么 Android 应用进程的创建必须通过 Zygote 进行
fork,而不是像普通 Linux 进程那样execve?- 一句话答:Zygote 在系统启动时已预加载了 Android 框架公用的类(如 Activity、View)和资源,通过
fork()创建子进程可以实现 Copy-on-Write(写时复制),极大地缩短了新进程的启动耗时并节省了物理内存。
- 一句话答:Zygote 在系统启动时已预加载了 Android 框架公用的类(如 Activity、View)和资源,通过
- ContentProvider 和 Application 的
onCreate()谁先执行?为什么?- 一句话答:ContentProvider 先执行;在
ActivityThread.handleBindApplication流程中,实例化 Application 后会立刻初始化并执行所有 Provider 的onCreate(),之后才调用Application.onCreate()。
- 一句话答:ContentProvider 先执行;在
- 启动耗时分析中 TTID (Time To Initial Display) 应该以哪个节点为准?
- 一句话答:不能以 Activity 的
onResume()为准,必须以ViewRootImpl收到 VSync 脉冲完成首帧绘制(onDraw/performTraversals)上屏为准。
- 一句话答:不能以 Activity 的
底层机制
1. App 冷启动全链路六大阶段
图注补充:App: App 进程 (ActivityThread);AMS: 1. 点击图标, 发起 startActivity IPC;Zygote: 2. 通过 Socket 发送 fork 进程请求;App: 3. fork() 孵化新子进程 (继承预加载类与 ART);App: 4. 反射调用 ActivityThread.main(), 开启 Looper;App: 6. bindApplication -> 执行 ContentProvider -> Application.onCreate;App: 7. 调度 Activity.onCreate -> onStart -> onResume;VRImpl: 8. WindowManager.addView -> 触发 performTraversals 首帧绘制上屏。
各阶段关键节点详解
- SystemServer 响应阶段:点击图标,Launcher 进程通过 Binder 通知 AMS 启动目标 Activity。AMS 检查该进程是否存在,若不存在则向 Zygote 进程发 Socket 通信。
- Zygote 孵化阶段:Zygote 收到 Socket 请求后,调用
fork()孵化出全新的 App 进程。此时子进程直接共享 Zygote 已预加载的 Java 核心类库与 ART 堆空间。 ActivityThread.main()入口:子进程反射调用ActivityThread.main():- 实例化
Looper.prepareMainLooper()建立主线程消息循环。 - 调用
ActivityThread.attach(false)向 AMS 注册应用进程。
- 实例化
- Application 绑节点:AMS 收到注册后通过 Binder 回调
ActivityThread.H发送BIND_APPLICATION消息:- 创建
LoadedApk与ClassLoader。 - 实例化
Application对象。 - 执行所有已注册 ContentProvider 的
onCreate()(注意:ContentProvider 优先于 Application.onCreate 执行!)。 - 执行
Application.onCreate()。
- 创建
- Activity 启动与首帧渲染:
- AMS 发送
EXECUTE_TRANSACTION消息,驱动Activity.onCreate() -> onStart() -> onResume()。 - 在
onResume()之后,WindowManagerImpl.addView()实例化ViewRootImpl。 ViewRootImpl收到 Choreographer 的 VSync 脉冲,触发首次performTraversals()(measure/layout/draw)。- SurfaceFlinger 合成帧数据,系统将闪屏(SplashWindow)替换为真实的 App 页面。
- AMS 发送
Android / Flutter / Web / Backend 对照
| 阶段 | Android 原生 | Flutter 嵌入 | Web 浏览器 |
|---|---|---|---|
| 进程初始化 | Zygote fork() 秒级孵化 | 依赖宿主 Android 进程 | 浏览器 Renderer 进程创建 |
| 引擎预热 | ART 虚拟机预加载 | FlutterEngine 初始化、加载 libapp.so | V8 引擎解析 JS Bundle |
| 首帧指标 | TTID (Time To Initial Display) | Flutter First Frame 回调 | FCP (First Contentful Paint) |
| 容易踩坑点 | ContentProvider 被三方 SDK 滥用耗时 | FlutterEngine 未提前预热/双引擎开销 | JS 文件体积过大阻断 HTML 解析 |
常见场景
1. 正确监听“首帧渲染完成” (Time To Initial Display, TTID)
不能以 Activity.onResume() 作为启动结束节点,因为此时 View 尚未完成测量和绘制上屏。
正确打点方式:
java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 监听 ViewRootImpl 首帧绘制完成
getWindow().getDecorView().getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() {
private boolean mHandled = false;
@Override
public void onDraw() {
if (!mHandled) {
mHandled = true;
// 在此上报首帧渲染耗时 TTID!
Log.i("Startup", "Time To Initial Display (TTID) Completed!");
}
}
});
}
}常见误配、事故后果与排障
1. 事故:三方 SDK 在 ContentProvider 中隐式耗时
- 误配原因:许多三方 SDK(如 WorkManager、Firebase、各种统计 SDK)为了实现“无侵入初始化”,在
AndroidManifest.xml中注册ContentProvider,并在其onCreate()中做耗时初始化。 - 后果:ContentProvider 的
onCreate()在Application.onCreate()之前执行!所有 Provider 的耗时都会直接拉长冷启动时间,导致启动优化的Application改造收效甚微。 - 排障与修法:使用
Android App Startup库统一收口管理,或在 Manifest 中禁用 Provider 自动初始化,改为手动延迟初始化。
与相近概念对比
| 启动类型 | 是否存在进程 | 是否重新创建 Application | 平均耗时 |
|---|---|---|---|
| 冷启动 (Cold Start) | 否 | 是 | 最慢(完整经历 Zygote fork 到首帧) |
| 温启动 (Warm Start) | 是 | 否 (已存在) | 中等(进程在,但 Activity 被回收重建) |
| 热启动 (Hot Start) | 是 | 否 | 最快(Activity 仅切到前台 onResume) |
对应实验
计划补齐的实验:
labs/android/host/topics/performance/startup-tracing-demo/— 冷启动耗时打点、Trace.beginSection 分析与首帧回调监听
复习检查题
ContentProvider 的
onCreate()与 Application 的onCreate()谁先执行?答:ContentProvider 的
onCreate()先执行。在ActivityThread.handleBindApplication()流程中,系统先实例化 Application,接着立刻初始化并执行所有 ContentProvider 的onCreate(),最后才调用Application.onCreate()。为什么 Android 应用进程
fork自 Zygote 能够显著加快进程启动速度?答:Zygote 在 Android 系统启动时已经初始化了 ART 虚拟机,并提前加载了大多数常用的 Android 框架类(如 View、Activity、Resources 等)。当
fork()产生新进程时,子进程直接继承了 Zygote 的内存空间与预加载资源(通过 Linux 的 Copy-on-Write 机制共享物理内存),避免了重新启动虚拟机和加载基础类的巨大开销。
速记
- 六步链路:AMS 调度 → Zygote fork → ActivityThread → ContentProvider → Application → 首帧绘制。
- 陷阱提示:ContentProvider 优先于 Application.onCreate 执行,严禁在 Provider 中做耗时操作。
- 指标核心:TTID (Time To Initial Display) 以 ViewRootImpl 首帧绘制为准,非 onResume。