你点了一下图标,App 是怎么从零跑起来的?从 Launcher 到 Activity.onCreate 的完整启动链路拆解(附启动优化实战)
目录
- 一、三种启动状态------冷、温、热
- 二、冷启动五阶段总览
- [三、阶段一:Launcher 通知 AMS](#三、阶段一:Launcher 通知 AMS)
- [四、阶段二:AMS 让 Zygote fork 新进程](#四、阶段二:AMS 让 Zygote fork 新进程)
- [五、阶段三:ActivityThread.main ------ App 的 Java 入口](#五、阶段三:ActivityThread.main —— App 的 Java 入口)
- [六、阶段四:Application 和 Activity 的生命周期](#六、阶段四:Application 和 Activity 的生命周期)
- [七、阶段五:首帧渲染 ------ 用户真正看到界面](#七、阶段五:首帧渲染 —— 用户真正看到界面)
- 八、完整时序图
- 九、实战:精准测量冷启动耗时
- 十、实战:启动速度优化
- [十一、启动优化中 Application 的坑](#十一、启动优化中 Application 的坑)
- 十二、常见踩坑记录
- 十三、总结
一、三种启动状态------冷、温、热
App 启动不是只有一种情况。Android 官方把它分三类:
| 状态 | 进程是否存在 | Activity 是否存在 | 耗时 | 场景 |
|---|---|---|---|---|
| 冷启动 | 不存在 | 不存在 | 最慢,500ms ~ 2s+ | 第一次打开、被系统杀了之后 |
| 温启动 | 存在 | 不存在 | 中等,200ms ~ 500ms | 按返回键退出后重新打开 |
| 热启动 | 存在 | onStop 状态 | 最快,50ms ~ 200ms | 多任务切回来 |
#mermaid-svg-gawd4kDu4QlplYe4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gawd4kDu4QlplYe4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gawd4kDu4QlplYe4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gawd4kDu4QlplYe4 .error-icon{fill:#552222;}#mermaid-svg-gawd4kDu4QlplYe4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gawd4kDu4QlplYe4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gawd4kDu4QlplYe4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gawd4kDu4QlplYe4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gawd4kDu4QlplYe4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gawd4kDu4QlplYe4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gawd4kDu4QlplYe4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gawd4kDu4QlplYe4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gawd4kDu4QlplYe4 .marker.cross{stroke:#333333;}#mermaid-svg-gawd4kDu4QlplYe4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gawd4kDu4QlplYe4 p{margin:0;}#mermaid-svg-gawd4kDu4QlplYe4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-gawd4kDu4QlplYe4 .cluster-label text{fill:#333;}#mermaid-svg-gawd4kDu4QlplYe4 .cluster-label span{color:#333;}#mermaid-svg-gawd4kDu4QlplYe4 .cluster-label span p{background-color:transparent;}#mermaid-svg-gawd4kDu4QlplYe4 .label text,#mermaid-svg-gawd4kDu4QlplYe4 span{fill:#333;color:#333;}#mermaid-svg-gawd4kDu4QlplYe4 .node rect,#mermaid-svg-gawd4kDu4QlplYe4 .node circle,#mermaid-svg-gawd4kDu4QlplYe4 .node ellipse,#mermaid-svg-gawd4kDu4QlplYe4 .node polygon,#mermaid-svg-gawd4kDu4QlplYe4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gawd4kDu4QlplYe4 .rough-node .label text,#mermaid-svg-gawd4kDu4QlplYe4 .node .label text,#mermaid-svg-gawd4kDu4QlplYe4 .image-shape .label,#mermaid-svg-gawd4kDu4QlplYe4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-gawd4kDu4QlplYe4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gawd4kDu4QlplYe4 .rough-node .label,#mermaid-svg-gawd4kDu4QlplYe4 .node .label,#mermaid-svg-gawd4kDu4QlplYe4 .image-shape .label,#mermaid-svg-gawd4kDu4QlplYe4 .icon-shape .label{text-align:center;}#mermaid-svg-gawd4kDu4QlplYe4 .node.clickable{cursor:pointer;}#mermaid-svg-gawd4kDu4QlplYe4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gawd4kDu4QlplYe4 .arrowheadPath{fill:#333333;}#mermaid-svg-gawd4kDu4QlplYe4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gawd4kDu4QlplYe4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gawd4kDu4QlplYe4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gawd4kDu4QlplYe4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gawd4kDu4QlplYe4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gawd4kDu4QlplYe4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gawd4kDu4QlplYe4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gawd4kDu4QlplYe4 .cluster text{fill:#333;}#mermaid-svg-gawd4kDu4QlplYe4 .cluster span{color:#333;}#mermaid-svg-gawd4kDu4QlplYe4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-gawd4kDu4QlplYe4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gawd4kDu4QlplYe4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-gawd4kDu4QlplYe4 .icon-shape,#mermaid-svg-gawd4kDu4QlplYe4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gawd4kDu4QlplYe4 .icon-shape p,#mermaid-svg-gawd4kDu4QlplYe4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gawd4kDu4QlplYe4 .icon-shape .label rect,#mermaid-svg-gawd4kDu4QlplYe4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gawd4kDu4QlplYe4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gawd4kDu4QlplYe4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gawd4kDu4QlplYe4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 不存在
存在
不存在
onStop 状态
用户点击图标
App 进程存在?
冷启动
Zygote fork 新进程
Application 初始化
Activity 创建
首帧渲染
500ms ~ 2s+
Activity 内存中存在?
温启动
无需 fork
只创建 Activity
200ms ~ 500ms
热启动
直接 onRestart → onResume
50ms ~ 200ms
冷启动是最慢的,也是优化重点。下面所有内容默认讲冷启动。
二、冷启动五阶段总览
从点图标到界面可见,一共五个阶段:
#mermaid-svg-ah0dF3mnJN1SEwdA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ah0dF3mnJN1SEwdA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ah0dF3mnJN1SEwdA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ah0dF3mnJN1SEwdA .error-icon{fill:#552222;}#mermaid-svg-ah0dF3mnJN1SEwdA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ah0dF3mnJN1SEwdA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ah0dF3mnJN1SEwdA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ah0dF3mnJN1SEwdA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ah0dF3mnJN1SEwdA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ah0dF3mnJN1SEwdA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ah0dF3mnJN1SEwdA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ah0dF3mnJN1SEwdA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ah0dF3mnJN1SEwdA .marker.cross{stroke:#333333;}#mermaid-svg-ah0dF3mnJN1SEwdA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ah0dF3mnJN1SEwdA p{margin:0;}#mermaid-svg-ah0dF3mnJN1SEwdA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ah0dF3mnJN1SEwdA .cluster-label text{fill:#333;}#mermaid-svg-ah0dF3mnJN1SEwdA .cluster-label span{color:#333;}#mermaid-svg-ah0dF3mnJN1SEwdA .cluster-label span p{background-color:transparent;}#mermaid-svg-ah0dF3mnJN1SEwdA .label text,#mermaid-svg-ah0dF3mnJN1SEwdA span{fill:#333;color:#333;}#mermaid-svg-ah0dF3mnJN1SEwdA .node rect,#mermaid-svg-ah0dF3mnJN1SEwdA .node circle,#mermaid-svg-ah0dF3mnJN1SEwdA .node ellipse,#mermaid-svg-ah0dF3mnJN1SEwdA .node polygon,#mermaid-svg-ah0dF3mnJN1SEwdA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ah0dF3mnJN1SEwdA .rough-node .label text,#mermaid-svg-ah0dF3mnJN1SEwdA .node .label text,#mermaid-svg-ah0dF3mnJN1SEwdA .image-shape .label,#mermaid-svg-ah0dF3mnJN1SEwdA .icon-shape .label{text-anchor:middle;}#mermaid-svg-ah0dF3mnJN1SEwdA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ah0dF3mnJN1SEwdA .rough-node .label,#mermaid-svg-ah0dF3mnJN1SEwdA .node .label,#mermaid-svg-ah0dF3mnJN1SEwdA .image-shape .label,#mermaid-svg-ah0dF3mnJN1SEwdA .icon-shape .label{text-align:center;}#mermaid-svg-ah0dF3mnJN1SEwdA .node.clickable{cursor:pointer;}#mermaid-svg-ah0dF3mnJN1SEwdA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ah0dF3mnJN1SEwdA .arrowheadPath{fill:#333333;}#mermaid-svg-ah0dF3mnJN1SEwdA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ah0dF3mnJN1SEwdA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ah0dF3mnJN1SEwdA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ah0dF3mnJN1SEwdA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ah0dF3mnJN1SEwdA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ah0dF3mnJN1SEwdA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ah0dF3mnJN1SEwdA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ah0dF3mnJN1SEwdA .cluster text{fill:#333;}#mermaid-svg-ah0dF3mnJN1SEwdA .cluster span{color:#333;}#mermaid-svg-ah0dF3mnJN1SEwdA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ah0dF3mnJN1SEwdA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ah0dF3mnJN1SEwdA rect.text{fill:none;stroke-width:0;}#mermaid-svg-ah0dF3mnJN1SEwdA .icon-shape,#mermaid-svg-ah0dF3mnJN1SEwdA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ah0dF3mnJN1SEwdA .icon-shape p,#mermaid-svg-ah0dF3mnJN1SEwdA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ah0dF3mnJN1SEwdA .icon-shape .label rect,#mermaid-svg-ah0dF3mnJN1SEwdA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ah0dF3mnJN1SEwdA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ah0dF3mnJN1SEwdA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ah0dF3mnJN1SEwdA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 1. Launcher 通知 AMS
startActivity() 跨进程调用
2. AMS 通知 Zygote fork
Socket 发 fork 命令 + 参数
3. 新进程启动
ActivityThread.main()
主线程 Looper + attach
4. 生命周期回调
Application.onCreate
Activity.onCreate/onStart/onResume
5. 首帧渲染
ViewRootImpl.performTraversals
用户看到界面
三、阶段一:Launcher 通知 AMS
点图标之后,Launcher 做了一件再普通不过的事------调 startActivity:
java
// Launcher 里(Launcher3 简化逻辑)
Intent intent = getPackageManager().getLaunchIntentForPackage(packageName);
startActivity(intent);
这个调用是跨进程的------Launcher 通过 Binder 把 Intent 发给 SystemServer 进程里的 AMS:
#mermaid-svg-wISJKKIY6NEOYIrf{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-wISJKKIY6NEOYIrf .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wISJKKIY6NEOYIrf .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wISJKKIY6NEOYIrf .error-icon{fill:#552222;}#mermaid-svg-wISJKKIY6NEOYIrf .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wISJKKIY6NEOYIrf .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wISJKKIY6NEOYIrf .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wISJKKIY6NEOYIrf .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wISJKKIY6NEOYIrf .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wISJKKIY6NEOYIrf .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wISJKKIY6NEOYIrf .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wISJKKIY6NEOYIrf .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wISJKKIY6NEOYIrf .marker.cross{stroke:#333333;}#mermaid-svg-wISJKKIY6NEOYIrf svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wISJKKIY6NEOYIrf p{margin:0;}#mermaid-svg-wISJKKIY6NEOYIrf .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-wISJKKIY6NEOYIrf .cluster-label text{fill:#333;}#mermaid-svg-wISJKKIY6NEOYIrf .cluster-label span{color:#333;}#mermaid-svg-wISJKKIY6NEOYIrf .cluster-label span p{background-color:transparent;}#mermaid-svg-wISJKKIY6NEOYIrf .label text,#mermaid-svg-wISJKKIY6NEOYIrf span{fill:#333;color:#333;}#mermaid-svg-wISJKKIY6NEOYIrf .node rect,#mermaid-svg-wISJKKIY6NEOYIrf .node circle,#mermaid-svg-wISJKKIY6NEOYIrf .node ellipse,#mermaid-svg-wISJKKIY6NEOYIrf .node polygon,#mermaid-svg-wISJKKIY6NEOYIrf .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wISJKKIY6NEOYIrf .rough-node .label text,#mermaid-svg-wISJKKIY6NEOYIrf .node .label text,#mermaid-svg-wISJKKIY6NEOYIrf .image-shape .label,#mermaid-svg-wISJKKIY6NEOYIrf .icon-shape .label{text-anchor:middle;}#mermaid-svg-wISJKKIY6NEOYIrf .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-wISJKKIY6NEOYIrf .rough-node .label,#mermaid-svg-wISJKKIY6NEOYIrf .node .label,#mermaid-svg-wISJKKIY6NEOYIrf .image-shape .label,#mermaid-svg-wISJKKIY6NEOYIrf .icon-shape .label{text-align:center;}#mermaid-svg-wISJKKIY6NEOYIrf .node.clickable{cursor:pointer;}#mermaid-svg-wISJKKIY6NEOYIrf .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-wISJKKIY6NEOYIrf .arrowheadPath{fill:#333333;}#mermaid-svg-wISJKKIY6NEOYIrf .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-wISJKKIY6NEOYIrf .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-wISJKKIY6NEOYIrf .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wISJKKIY6NEOYIrf .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-wISJKKIY6NEOYIrf .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wISJKKIY6NEOYIrf .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-wISJKKIY6NEOYIrf .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-wISJKKIY6NEOYIrf .cluster text{fill:#333;}#mermaid-svg-wISJKKIY6NEOYIrf .cluster span{color:#333;}#mermaid-svg-wISJKKIY6NEOYIrf div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-wISJKKIY6NEOYIrf .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-wISJKKIY6NEOYIrf rect.text{fill:none;stroke-width:0;}#mermaid-svg-wISJKKIY6NEOYIrf .icon-shape,#mermaid-svg-wISJKKIY6NEOYIrf .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wISJKKIY6NEOYIrf .icon-shape p,#mermaid-svg-wISJKKIY6NEOYIrf .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-wISJKKIY6NEOYIrf .icon-shape .label rect,#mermaid-svg-wISJKKIY6NEOYIrf .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wISJKKIY6NEOYIrf .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-wISJKKIY6NEOYIrf .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-wISJKKIY6NEOYIrf :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Binder IPC
不存在
存在
Launcher 进程
startActivity()
AMS(SystemServer 进程)
ActivityStarter
解析 Intent / 权限检查
目标 App 进程
存在吗?
★ startProcessAsync()
去 Zygote 那 fork 一个
直接在已有进程
启动 Activity
AMS 端的核心调用链:
ActivityManagerService.startActivity()
→ ActivityTaskManagerService.startActivity()
→ ActivityStarter.execute()
→ ActivityStarter.startActivityUnchecked()
→ ActivityStackSupervisor.startSpecificActivity()
→ 发现进程不存在,调 startProcessAsync()
如果进程已经在了(温/热启动),直接跳到阶段四。冷启动需要往下走。
四、阶段二:AMS 让 Zygote fork 新进程
AMS 通过 Zygote Socket(/dev/socket/zygote)发 fork 命令。前文《Android Zygote 启动过程》详细拆解过这个通信机制。
#mermaid-svg-Z3pHVXcEkjm2wcXj{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Z3pHVXcEkjm2wcXj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Z3pHVXcEkjm2wcXj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Z3pHVXcEkjm2wcXj .error-icon{fill:#552222;}#mermaid-svg-Z3pHVXcEkjm2wcXj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Z3pHVXcEkjm2wcXj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Z3pHVXcEkjm2wcXj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Z3pHVXcEkjm2wcXj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Z3pHVXcEkjm2wcXj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Z3pHVXcEkjm2wcXj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Z3pHVXcEkjm2wcXj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Z3pHVXcEkjm2wcXj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Z3pHVXcEkjm2wcXj .marker.cross{stroke:#333333;}#mermaid-svg-Z3pHVXcEkjm2wcXj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Z3pHVXcEkjm2wcXj p{margin:0;}#mermaid-svg-Z3pHVXcEkjm2wcXj .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Z3pHVXcEkjm2wcXj .cluster-label text{fill:#333;}#mermaid-svg-Z3pHVXcEkjm2wcXj .cluster-label span{color:#333;}#mermaid-svg-Z3pHVXcEkjm2wcXj .cluster-label span p{background-color:transparent;}#mermaid-svg-Z3pHVXcEkjm2wcXj .label text,#mermaid-svg-Z3pHVXcEkjm2wcXj span{fill:#333;color:#333;}#mermaid-svg-Z3pHVXcEkjm2wcXj .node rect,#mermaid-svg-Z3pHVXcEkjm2wcXj .node circle,#mermaid-svg-Z3pHVXcEkjm2wcXj .node ellipse,#mermaid-svg-Z3pHVXcEkjm2wcXj .node polygon,#mermaid-svg-Z3pHVXcEkjm2wcXj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Z3pHVXcEkjm2wcXj .rough-node .label text,#mermaid-svg-Z3pHVXcEkjm2wcXj .node .label text,#mermaid-svg-Z3pHVXcEkjm2wcXj .image-shape .label,#mermaid-svg-Z3pHVXcEkjm2wcXj .icon-shape .label{text-anchor:middle;}#mermaid-svg-Z3pHVXcEkjm2wcXj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Z3pHVXcEkjm2wcXj .rough-node .label,#mermaid-svg-Z3pHVXcEkjm2wcXj .node .label,#mermaid-svg-Z3pHVXcEkjm2wcXj .image-shape .label,#mermaid-svg-Z3pHVXcEkjm2wcXj .icon-shape .label{text-align:center;}#mermaid-svg-Z3pHVXcEkjm2wcXj .node.clickable{cursor:pointer;}#mermaid-svg-Z3pHVXcEkjm2wcXj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Z3pHVXcEkjm2wcXj .arrowheadPath{fill:#333333;}#mermaid-svg-Z3pHVXcEkjm2wcXj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Z3pHVXcEkjm2wcXj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Z3pHVXcEkjm2wcXj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Z3pHVXcEkjm2wcXj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Z3pHVXcEkjm2wcXj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Z3pHVXcEkjm2wcXj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Z3pHVXcEkjm2wcXj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Z3pHVXcEkjm2wcXj .cluster text{fill:#333;}#mermaid-svg-Z3pHVXcEkjm2wcXj .cluster span{color:#333;}#mermaid-svg-Z3pHVXcEkjm2wcXj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Z3pHVXcEkjm2wcXj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Z3pHVXcEkjm2wcXj rect.text{fill:none;stroke-width:0;}#mermaid-svg-Z3pHVXcEkjm2wcXj .icon-shape,#mermaid-svg-Z3pHVXcEkjm2wcXj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Z3pHVXcEkjm2wcXj .icon-shape p,#mermaid-svg-Z3pHVXcEkjm2wcXj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Z3pHVXcEkjm2wcXj .icon-shape .label rect,#mermaid-svg-Z3pHVXcEkjm2wcXj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Z3pHVXcEkjm2wcXj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Z3pHVXcEkjm2wcXj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Z3pHVXcEkjm2wcXj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Zygote(父进程)
新进程(子进程)
AMS.startProcessAsync()
ZygoteProcess.start()
连接 Zygote Socket
/dev/socket/zygote
发送 fork 参数
--nice-name=com.example.app
--setuid=10086
--setgid=10086
Zygote 收到
Zygote.forkAndSpecialize()
fork() 返回值
返回此 PID 给 AMS
继续 accept 等待
★ RuntimeInit.zygoteInit()
→ ActivityThread.main()
AMS 发给 Zygote 的参数:
--runtime-args
--setuid=10086
--setgid=10086
--target-sdk-version=34
--nice-name=com.example.app
--seinfo=default:targetSdkVersion=34
这些参数决定了新进程的身份------UID、GID、进程名、SELinux 上下文。Zygote fork 后在子进程里设好这些值,新进程就有了独立的身份。
五、阶段三:ActivityThread.main ------ App 的 Java 入口
新进程从 Zygote fork 出来后,不走平常的 main 函数,而是从 ActivityThread.main() 开始执行。这是 Android App 进程真正的 Java 入口。
java
// frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
Looper.prepareMainLooper(); // 1. 准备主线程 Looper
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq); // 2. ★ 通过 Binder 向 AMS 报到
Looper.loop(); // 3. 进入消息循环
}
attach() 做的事------向 AMS 报到:
#mermaid-svg-lRQa3huEbCVcMgbh{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-lRQa3huEbCVcMgbh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-lRQa3huEbCVcMgbh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-lRQa3huEbCVcMgbh .error-icon{fill:#552222;}#mermaid-svg-lRQa3huEbCVcMgbh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-lRQa3huEbCVcMgbh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-lRQa3huEbCVcMgbh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-lRQa3huEbCVcMgbh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-lRQa3huEbCVcMgbh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-lRQa3huEbCVcMgbh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-lRQa3huEbCVcMgbh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-lRQa3huEbCVcMgbh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-lRQa3huEbCVcMgbh .marker.cross{stroke:#333333;}#mermaid-svg-lRQa3huEbCVcMgbh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-lRQa3huEbCVcMgbh p{margin:0;}#mermaid-svg-lRQa3huEbCVcMgbh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-lRQa3huEbCVcMgbh .cluster-label text{fill:#333;}#mermaid-svg-lRQa3huEbCVcMgbh .cluster-label span{color:#333;}#mermaid-svg-lRQa3huEbCVcMgbh .cluster-label span p{background-color:transparent;}#mermaid-svg-lRQa3huEbCVcMgbh .label text,#mermaid-svg-lRQa3huEbCVcMgbh span{fill:#333;color:#333;}#mermaid-svg-lRQa3huEbCVcMgbh .node rect,#mermaid-svg-lRQa3huEbCVcMgbh .node circle,#mermaid-svg-lRQa3huEbCVcMgbh .node ellipse,#mermaid-svg-lRQa3huEbCVcMgbh .node polygon,#mermaid-svg-lRQa3huEbCVcMgbh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-lRQa3huEbCVcMgbh .rough-node .label text,#mermaid-svg-lRQa3huEbCVcMgbh .node .label text,#mermaid-svg-lRQa3huEbCVcMgbh .image-shape .label,#mermaid-svg-lRQa3huEbCVcMgbh .icon-shape .label{text-anchor:middle;}#mermaid-svg-lRQa3huEbCVcMgbh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-lRQa3huEbCVcMgbh .rough-node .label,#mermaid-svg-lRQa3huEbCVcMgbh .node .label,#mermaid-svg-lRQa3huEbCVcMgbh .image-shape .label,#mermaid-svg-lRQa3huEbCVcMgbh .icon-shape .label{text-align:center;}#mermaid-svg-lRQa3huEbCVcMgbh .node.clickable{cursor:pointer;}#mermaid-svg-lRQa3huEbCVcMgbh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-lRQa3huEbCVcMgbh .arrowheadPath{fill:#333333;}#mermaid-svg-lRQa3huEbCVcMgbh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-lRQa3huEbCVcMgbh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-lRQa3huEbCVcMgbh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lRQa3huEbCVcMgbh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-lRQa3huEbCVcMgbh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lRQa3huEbCVcMgbh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-lRQa3huEbCVcMgbh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-lRQa3huEbCVcMgbh .cluster text{fill:#333;}#mermaid-svg-lRQa3huEbCVcMgbh .cluster span{color:#333;}#mermaid-svg-lRQa3huEbCVcMgbh div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-lRQa3huEbCVcMgbh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-lRQa3huEbCVcMgbh rect.text{fill:none;stroke-width:0;}#mermaid-svg-lRQa3huEbCVcMgbh .icon-shape,#mermaid-svg-lRQa3huEbCVcMgbh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lRQa3huEbCVcMgbh .icon-shape p,#mermaid-svg-lRQa3huEbCVcMgbh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-lRQa3huEbCVcMgbh .icon-shape .label rect,#mermaid-svg-lRQa3huEbCVcMgbh .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lRQa3huEbCVcMgbh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-lRQa3huEbCVcMgbh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-lRQa3huEbCVcMgbh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ActivityThread.attach()
AMS.attachApplication()
(通过 Binder)
AMS 收到新进程报到
记住它的 ApplicationThread Binder
AMS 给 App 发消息
★ bindApplication
(创建 Application)
AMS 给 App 发消息
★ scheduleLaunchActivity
(启动目标 Activity)
attach是关键节点------App 进程通过 Binder 告诉 AMS "我起来了,派活吧"。AMS 收到报到后,通过 App 的ApplicationThread(也是一个 Binder 对象)发了两条消息:先 bindApplication 创建 Application,再启动目标 Activity。
六、阶段四:Application 和 Activity 的生命周期
AMS 发的两条消息在 App 主线程的消息队列里排队执行:
消息 1:bindApplication → 创建 Application
java
// ActivityThread.handleBindApplication()
private void handleBindApplication(AppBindData data) {
// 1. 创建 Application 实例
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
// 2. ★ 回调 Application.onCreate()
// 你的代码在这里跑!
app.onCreate();
// 3. 注册 ContentProvider(如果有的话)
installContentProviders(app, data.providers);
}
消息 2:scheduleLaunchActivity → 创建 Activity
java
// ActivityThread.handleLaunchActivity()
public Activity handleLaunchActivity(...) {
// 1. performLaunchActivity ------ 创建 Activity,调 onCreate
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
// 2. ★ handleResumeActivity ------ 调 onStart / onResume
handleResumeActivity(...);
}
return a;
}
两条消息的执行顺序:
#mermaid-svg-eppnKmzpnss3eOWA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-eppnKmzpnss3eOWA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eppnKmzpnss3eOWA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eppnKmzpnss3eOWA .error-icon{fill:#552222;}#mermaid-svg-eppnKmzpnss3eOWA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eppnKmzpnss3eOWA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eppnKmzpnss3eOWA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eppnKmzpnss3eOWA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eppnKmzpnss3eOWA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eppnKmzpnss3eOWA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eppnKmzpnss3eOWA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eppnKmzpnss3eOWA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eppnKmzpnss3eOWA .marker.cross{stroke:#333333;}#mermaid-svg-eppnKmzpnss3eOWA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eppnKmzpnss3eOWA p{margin:0;}#mermaid-svg-eppnKmzpnss3eOWA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-eppnKmzpnss3eOWA .cluster-label text{fill:#333;}#mermaid-svg-eppnKmzpnss3eOWA .cluster-label span{color:#333;}#mermaid-svg-eppnKmzpnss3eOWA .cluster-label span p{background-color:transparent;}#mermaid-svg-eppnKmzpnss3eOWA .label text,#mermaid-svg-eppnKmzpnss3eOWA span{fill:#333;color:#333;}#mermaid-svg-eppnKmzpnss3eOWA .node rect,#mermaid-svg-eppnKmzpnss3eOWA .node circle,#mermaid-svg-eppnKmzpnss3eOWA .node ellipse,#mermaid-svg-eppnKmzpnss3eOWA .node polygon,#mermaid-svg-eppnKmzpnss3eOWA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eppnKmzpnss3eOWA .rough-node .label text,#mermaid-svg-eppnKmzpnss3eOWA .node .label text,#mermaid-svg-eppnKmzpnss3eOWA .image-shape .label,#mermaid-svg-eppnKmzpnss3eOWA .icon-shape .label{text-anchor:middle;}#mermaid-svg-eppnKmzpnss3eOWA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-eppnKmzpnss3eOWA .rough-node .label,#mermaid-svg-eppnKmzpnss3eOWA .node .label,#mermaid-svg-eppnKmzpnss3eOWA .image-shape .label,#mermaid-svg-eppnKmzpnss3eOWA .icon-shape .label{text-align:center;}#mermaid-svg-eppnKmzpnss3eOWA .node.clickable{cursor:pointer;}#mermaid-svg-eppnKmzpnss3eOWA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-eppnKmzpnss3eOWA .arrowheadPath{fill:#333333;}#mermaid-svg-eppnKmzpnss3eOWA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-eppnKmzpnss3eOWA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-eppnKmzpnss3eOWA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eppnKmzpnss3eOWA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-eppnKmzpnss3eOWA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eppnKmzpnss3eOWA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-eppnKmzpnss3eOWA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-eppnKmzpnss3eOWA .cluster text{fill:#333;}#mermaid-svg-eppnKmzpnss3eOWA .cluster span{color:#333;}#mermaid-svg-eppnKmzpnss3eOWA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-eppnKmzpnss3eOWA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-eppnKmzpnss3eOWA rect.text{fill:none;stroke-width:0;}#mermaid-svg-eppnKmzpnss3eOWA .icon-shape,#mermaid-svg-eppnKmzpnss3eOWA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eppnKmzpnss3eOWA .icon-shape p,#mermaid-svg-eppnKmzpnss3eOWA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-eppnKmzpnss3eOWA .icon-shape .label rect,#mermaid-svg-eppnKmzpnss3eOWA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eppnKmzpnss3eOWA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-eppnKmzpnss3eOWA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-eppnKmzpnss3eOWA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} AMS 发 bindApplication
App 主线程
handleBindApplication()
Application.attach()
Application.onCreate()★
AMS 发 scheduleLaunchActivity
performLaunchActivity()
Activity.onCreate()★
handleResumeActivity()
Activity.onStart()
Activity.onResume()★
★ 生命周期结束
进入阶段五:渲染
Application.onCreate 跑完才会跑 Activity.onCreate。所以 Application 里做太多事会直接拖慢 Activity 的显示。
七、阶段五:首帧渲染 ------ 用户真正看到界面
onResume 回调回来不代表用户能看到界面了。真正显示在屏幕上,还需要一次渲染流程:
#mermaid-svg-jpUFIm1dOUNwA338{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jpUFIm1dOUNwA338 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jpUFIm1dOUNwA338 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jpUFIm1dOUNwA338 .error-icon{fill:#552222;}#mermaid-svg-jpUFIm1dOUNwA338 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jpUFIm1dOUNwA338 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jpUFIm1dOUNwA338 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jpUFIm1dOUNwA338 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jpUFIm1dOUNwA338 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jpUFIm1dOUNwA338 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jpUFIm1dOUNwA338 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jpUFIm1dOUNwA338 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jpUFIm1dOUNwA338 .marker.cross{stroke:#333333;}#mermaid-svg-jpUFIm1dOUNwA338 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jpUFIm1dOUNwA338 p{margin:0;}#mermaid-svg-jpUFIm1dOUNwA338 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jpUFIm1dOUNwA338 .cluster-label text{fill:#333;}#mermaid-svg-jpUFIm1dOUNwA338 .cluster-label span{color:#333;}#mermaid-svg-jpUFIm1dOUNwA338 .cluster-label span p{background-color:transparent;}#mermaid-svg-jpUFIm1dOUNwA338 .label text,#mermaid-svg-jpUFIm1dOUNwA338 span{fill:#333;color:#333;}#mermaid-svg-jpUFIm1dOUNwA338 .node rect,#mermaid-svg-jpUFIm1dOUNwA338 .node circle,#mermaid-svg-jpUFIm1dOUNwA338 .node ellipse,#mermaid-svg-jpUFIm1dOUNwA338 .node polygon,#mermaid-svg-jpUFIm1dOUNwA338 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jpUFIm1dOUNwA338 .rough-node .label text,#mermaid-svg-jpUFIm1dOUNwA338 .node .label text,#mermaid-svg-jpUFIm1dOUNwA338 .image-shape .label,#mermaid-svg-jpUFIm1dOUNwA338 .icon-shape .label{text-anchor:middle;}#mermaid-svg-jpUFIm1dOUNwA338 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jpUFIm1dOUNwA338 .rough-node .label,#mermaid-svg-jpUFIm1dOUNwA338 .node .label,#mermaid-svg-jpUFIm1dOUNwA338 .image-shape .label,#mermaid-svg-jpUFIm1dOUNwA338 .icon-shape .label{text-align:center;}#mermaid-svg-jpUFIm1dOUNwA338 .node.clickable{cursor:pointer;}#mermaid-svg-jpUFIm1dOUNwA338 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jpUFIm1dOUNwA338 .arrowheadPath{fill:#333333;}#mermaid-svg-jpUFIm1dOUNwA338 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jpUFIm1dOUNwA338 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jpUFIm1dOUNwA338 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jpUFIm1dOUNwA338 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jpUFIm1dOUNwA338 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jpUFIm1dOUNwA338 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jpUFIm1dOUNwA338 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jpUFIm1dOUNwA338 .cluster text{fill:#333;}#mermaid-svg-jpUFIm1dOUNwA338 .cluster span{color:#333;}#mermaid-svg-jpUFIm1dOUNwA338 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jpUFIm1dOUNwA338 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jpUFIm1dOUNwA338 rect.text{fill:none;stroke-width:0;}#mermaid-svg-jpUFIm1dOUNwA338 .icon-shape,#mermaid-svg-jpUFIm1dOUNwA338 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jpUFIm1dOUNwA338 .icon-shape p,#mermaid-svg-jpUFIm1dOUNwA338 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jpUFIm1dOUNwA338 .icon-shape .label rect,#mermaid-svg-jpUFIm1dOUNwA338 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jpUFIm1dOUNwA338 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jpUFIm1dOUNwA338 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jpUFIm1dOUNwA338 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Activity.onResume()
WindowManager.addView()
创建 ViewRootImpl
ViewRootImpl.requestLayout()
scheduleTraversals()
注册 VSync 信号回调
doTraversal()
★ performMeasure()
测量 View 大小
★ performLayout()
摆放 View 位置
★ performDraw()
绘制到 Surface
SurfaceFlinger 合成
帧送到屏幕
★ 用户看到界面
onResume 到首帧显示之间还有一段距离。布局越复杂、层级越深,这段距离越长。
八、完整时序图
把五个阶段串成一根完整的线:
SurfaceFlinger App ActivityThread Zygote AMS Launcher SurfaceFlinger App ActivityThread Zygote AMS Launcher #mermaid-svg-e5cSDVAKCmVmlpXo{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-e5cSDVAKCmVmlpXo .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-e5cSDVAKCmVmlpXo .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-e5cSDVAKCmVmlpXo .error-icon{fill:#552222;}#mermaid-svg-e5cSDVAKCmVmlpXo .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-e5cSDVAKCmVmlpXo .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-e5cSDVAKCmVmlpXo .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-e5cSDVAKCmVmlpXo .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-e5cSDVAKCmVmlpXo .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-e5cSDVAKCmVmlpXo .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-e5cSDVAKCmVmlpXo .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-e5cSDVAKCmVmlpXo .marker{fill:#333333;stroke:#333333;}#mermaid-svg-e5cSDVAKCmVmlpXo .marker.cross{stroke:#333333;}#mermaid-svg-e5cSDVAKCmVmlpXo svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-e5cSDVAKCmVmlpXo p{margin:0;}#mermaid-svg-e5cSDVAKCmVmlpXo .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-e5cSDVAKCmVmlpXo text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-e5cSDVAKCmVmlpXo .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-e5cSDVAKCmVmlpXo .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-e5cSDVAKCmVmlpXo .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-e5cSDVAKCmVmlpXo .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-e5cSDVAKCmVmlpXo #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-e5cSDVAKCmVmlpXo .sequenceNumber{fill:white;}#mermaid-svg-e5cSDVAKCmVmlpXo #sequencenumber{fill:#333;}#mermaid-svg-e5cSDVAKCmVmlpXo #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-e5cSDVAKCmVmlpXo .messageText{fill:#333;stroke:none;}#mermaid-svg-e5cSDVAKCmVmlpXo .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-e5cSDVAKCmVmlpXo .labelText,#mermaid-svg-e5cSDVAKCmVmlpXo .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-e5cSDVAKCmVmlpXo .loopText,#mermaid-svg-e5cSDVAKCmVmlpXo .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-e5cSDVAKCmVmlpXo .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-e5cSDVAKCmVmlpXo .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-e5cSDVAKCmVmlpXo .noteText,#mermaid-svg-e5cSDVAKCmVmlpXo .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-e5cSDVAKCmVmlpXo .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-e5cSDVAKCmVmlpXo .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-e5cSDVAKCmVmlpXo .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-e5cSDVAKCmVmlpXo .actorPopupMenu{position:absolute;}#mermaid-svg-e5cSDVAKCmVmlpXo .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-e5cSDVAKCmVmlpXo .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-e5cSDVAKCmVmlpXo .actor-man circle,#mermaid-svg-e5cSDVAKCmVmlpXo line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-e5cSDVAKCmVmlpXo :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 1. startActivity() Binder 解析 Intent,权限检查 2. fork 命令 Socket 3. fork 子进程,ActivityThread.main() Looper.prepareMainLooper() 3. attachApplication() Binder,报到 4. bindApplication Binder Application.onCreate() 4. scheduleLaunchActivity Binder Activity.onCreate() → onStart() → onResume() 5. ViewRootImpl.performTraversals 合成,送帧到屏幕 ★ 用户看到界面
九、实战:精准测量冷启动耗时
方法一:用 am start -W(命令行)
bash
adb shell am start -W com.example.app/.MainActivity
# 输出:
# Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.example.app/.MainActivity }
# Status: ok
# Activity: com.example.app/.MainActivity
# ThisTime: 452 ← 最后一个 Activity 的启动耗时
# TotalTime: 786 ← 从 AMS 收到请求到 Activity 启动完成
# WaitTime: 824 ← 从 AMS 收到请求到首帧绘制完成 + 后台等待
- ThisTime:最后一个 Activity 自身启动耗时,一般比 TotalTime 小
- TotalTime:从 AMS 开始处理到 Activity 启动完成,包含 Application 创建时间
- WaitTime:最接近用户体感的时间------从 startActivity 到首帧显示
方法二:用 Android Studio Profiler
Run → Profile app → 选 CPU / Memory → 点击"Capture Startup" → 启动 App → 自动记录启动各阶段时间轴。
方法三:代码打点
java
// Application
public class MyApp extends Application {
public static long APP_START_TIME;
@Override
public void onCreate() {
APP_START_TIME = SystemClock.uptimeMillis();
super.onCreate();
}
}
// Activity
public class MainActivity extends AppCompatActivity {
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
long cost = SystemClock.uptimeMillis() - MyApp.APP_START_TIME;
Log.d("Startup", "冷启动总耗时: " + cost + "ms");
}
}
}
onWindowFocusChanged(hasFocus=true)是首帧渲染完成后的第一个回调,用它算启动耗时最接近用户体感。
方法四:系统日志自动打印
bash
adb logcat -b events | grep am_activity_launch_time
# 输出:
# am_activity_launch_time: [0,12345678,com.example.app/.MainActivity,350,200,550]
# ↑ 最后一个数 550 就是 TotalTime
十、实战:启动速度优化
方向一:Application.onCreate 做减法
这是启动优化的头号目标。很多第三方 SDK 在 Application.onCreate 里做初始化------网络、数据库、埋点、图片库......全部挤在一条线上等。
java
// ❌ 在 Application.onCreate 里串行初始化所有东西
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
initNetwork(); // 100ms
initDatabase(); // 150ms
initImageLoader(); // 200ms
initCrashReport(); // 80ms
initAnalytics(); // 60ms
// 总共 590ms ------ 太长了
}
}
// ✓ 能异步的丢子线程、能懒加载的等用到再说
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
// 必须在主线程且启动时就用的
initCrashReport();
// 可以异步的------丢子线程
new Thread(() -> {
initAnalytics();
initNetwork();
}).start();
// 用到再初始化的------去掉 onCreate 里的调用
}
// 懒加载
private ImageLoader getImageLoader() {
if (imageLoader == null) {
imageLoader = initImageLoader();
}
return imageLoader;
}
}
方向二:Theme 优化------干掉白屏/黑屏
冷启动时 Zygote 在 fork,系统会先显示一个预览窗口(Starting Window),这个窗口的颜色取决于你的 Theme:
xml
<!-- ❌ 默认深色主题 → 启动时闪黑屏 -->
<item name="android:windowBackground">@color/black</item>
<!-- ✓ 设成跟启动页一样的背景 → 视觉上"秒开" -->
<style name="AppTheme.Launcher">
<item name="android:windowBackground">@drawable/brand_bg</item>
<!-- 如果启动页显示 Logo,把这个背景做成 Logo 占位图 -->
</style>
方向三:布局懒加载 / ViewStub
首页不一定需要一次性把全部 View 都创建出来:
xml
<!-- 那些一开始不显示的布局,用 ViewStub 延迟创建 -->
<ViewStub
android:id="@+id/stub_detail"
android:layout="@layout/detail_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inflatedId="@+id/detail_section" />
java
// 在 onResume 之后或者用户操作时才 inflate
viewStub.inflate();
方向四:PreDrawListener 延迟非关键操作
java
// 在首帧绘制完成后再执行非关键初始化
ViewCompat.setOnApplyWindowInsetsListener(findViewById(android.R.id.content), (v, insets) -> {
// 此时首帧已经渲染
initNonCriticalStuff();
return insets;
});
优化效果对比:
| 优化项 | 优化前 | 优化后 | 省了多少 |
|---|---|---|---|
| Application.onCreate 异步 | 590ms | 180ms | -410ms |
| Theme 去白屏 | 白屏 ~200ms | 0(视觉秒开) | -200ms 感知 |
| 布局 ViewStub | 创建 40 个 View | 创建 12 个 View | -80ms |
| 合计 | ~870ms | ~260ms + 视觉秒开 | 省了 600ms |
十一、启动优化中 Application 的坑
坑 1:ContentProvider 默认在主线程 onCreate
Application 里声明的 ContentProvider 会在 Application.onCreate 之前被执行(主线程),这又多了一个启动耗时的来源。
java
// 你的 ContentProvider ------ 在 Application.onCreate 之前跑!
public class InitProvider extends ContentProvider {
@Override
public boolean onCreate() {
// ★ 这里在主线程跑,而且是 Application 创建之前
initSomething(); // 如果这里耗时,启动直接慢了
return false;
}
}
你用的一些第三方 SDK 可能就是用 ContentProvider 来初始化的------Google Firebase、LeakCanary 都是这么干的。检查一下你的 AndroidManifest:
bash
adb shell dumpsys package <your_package> | grep -A 5 "ContentProvider"
坑 2:Application.onCreate 调到了 Activity 里的东西
Application 创建时 Activity 还没影。如果在 Application.onCreate 里调任何跟 Activity 相关的方法,直接崩溃。
十二、常见踩坑记录
坑 1:用 System.currentTimeMillis 打点不准
java
// ❌ 用墙钟(受用户改时间影响)
long start = System.currentTimeMillis();
// ✓ 用 uptimeMillis(系统启动后的时间,单调递增)
long start = SystemClock.uptimeMillis();
坑 2:onResume 里做耗时操作导致 ANR
onResume 受 Input 事件限制------5 秒内没返回就 ANR。不要在 onResume 里做 IO 或复杂计算。
坑 3:启动页跳转到主页时没有 finish
java
// ❌ 启动页调 startActivity 后没 finish
startActivity(new Intent(this, MainActivity.class));
// 用户在 MainActivity 按返回键,又回到启动页------体验很差
// ✓ 启动页 finish 自己
startActivity(new Intent(this, MainActivity.class));
finish();
坑 4:am start -W 测出来的时间跟用户体感不一样
am start -W 的 TotalTime 是从 AMS 收到请求算起。用户体感是从点图标算起。加上 Launcher → AMS 的 Binder 调用 + Input 分发延迟,用户体感会多出 总量 ~100ms。
坑 5:以为多重几层布局不影响
一个 RelativeLayout 嵌套两层 LinearLayout,整个层级树多出几十个 measure/layout 调用。冷启动阶段 View 树本来就要全量遍历,层级越深耗时成倍增长:
bash
# 用 systrace 看 View 渲染耗时
python systrace.py -a com.example.app gfx view
# 或者 Android Studio Layout Inspector
# 看 View 树深度------超过 7 层就该扁平化了
十三、总结
冷启动五阶段速记:
#mermaid-svg-tTvTrcd2saJa6uLV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tTvTrcd2saJa6uLV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tTvTrcd2saJa6uLV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tTvTrcd2saJa6uLV .error-icon{fill:#552222;}#mermaid-svg-tTvTrcd2saJa6uLV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tTvTrcd2saJa6uLV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tTvTrcd2saJa6uLV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tTvTrcd2saJa6uLV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tTvTrcd2saJa6uLV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tTvTrcd2saJa6uLV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tTvTrcd2saJa6uLV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tTvTrcd2saJa6uLV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tTvTrcd2saJa6uLV .marker.cross{stroke:#333333;}#mermaid-svg-tTvTrcd2saJa6uLV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tTvTrcd2saJa6uLV p{margin:0;}#mermaid-svg-tTvTrcd2saJa6uLV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-tTvTrcd2saJa6uLV .cluster-label text{fill:#333;}#mermaid-svg-tTvTrcd2saJa6uLV .cluster-label span{color:#333;}#mermaid-svg-tTvTrcd2saJa6uLV .cluster-label span p{background-color:transparent;}#mermaid-svg-tTvTrcd2saJa6uLV .label text,#mermaid-svg-tTvTrcd2saJa6uLV span{fill:#333;color:#333;}#mermaid-svg-tTvTrcd2saJa6uLV .node rect,#mermaid-svg-tTvTrcd2saJa6uLV .node circle,#mermaid-svg-tTvTrcd2saJa6uLV .node ellipse,#mermaid-svg-tTvTrcd2saJa6uLV .node polygon,#mermaid-svg-tTvTrcd2saJa6uLV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-tTvTrcd2saJa6uLV .rough-node .label text,#mermaid-svg-tTvTrcd2saJa6uLV .node .label text,#mermaid-svg-tTvTrcd2saJa6uLV .image-shape .label,#mermaid-svg-tTvTrcd2saJa6uLV .icon-shape .label{text-anchor:middle;}#mermaid-svg-tTvTrcd2saJa6uLV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-tTvTrcd2saJa6uLV .rough-node .label,#mermaid-svg-tTvTrcd2saJa6uLV .node .label,#mermaid-svg-tTvTrcd2saJa6uLV .image-shape .label,#mermaid-svg-tTvTrcd2saJa6uLV .icon-shape .label{text-align:center;}#mermaid-svg-tTvTrcd2saJa6uLV .node.clickable{cursor:pointer;}#mermaid-svg-tTvTrcd2saJa6uLV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-tTvTrcd2saJa6uLV .arrowheadPath{fill:#333333;}#mermaid-svg-tTvTrcd2saJa6uLV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-tTvTrcd2saJa6uLV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-tTvTrcd2saJa6uLV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tTvTrcd2saJa6uLV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-tTvTrcd2saJa6uLV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tTvTrcd2saJa6uLV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-tTvTrcd2saJa6uLV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-tTvTrcd2saJa6uLV .cluster text{fill:#333;}#mermaid-svg-tTvTrcd2saJa6uLV .cluster span{color:#333;}#mermaid-svg-tTvTrcd2saJa6uLV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-tTvTrcd2saJa6uLV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-tTvTrcd2saJa6uLV rect.text{fill:none;stroke-width:0;}#mermaid-svg-tTvTrcd2saJa6uLV .icon-shape,#mermaid-svg-tTvTrcd2saJa6uLV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tTvTrcd2saJa6uLV .icon-shape p,#mermaid-svg-tTvTrcd2saJa6uLV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-tTvTrcd2saJa6uLV .icon-shape .label rect,#mermaid-svg-tTvTrcd2saJa6uLV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tTvTrcd2saJa6uLV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-tTvTrcd2saJa6uLV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-tTvTrcd2saJa6uLV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 点击图标
Launcher → AMS
AMS → Zygote
fork 新进程
ActivityThread.main
Looper + attach
Application.onCreate
Activity.onCreate → onResume
performTraversals
★ 首帧可见
各阶段耗时和优化方向:
| 阶段 | 耗时 | 优化什么 |
|---|---|---|
| Launcher → AMS | ~20ms | 基本不用管 |
| AMS → Zygote fork | ~50ms | 基本不用管 |
| ActivityThread → attach | ~100ms | 基本不用管 |
| Application.onCreate | 100ms ~ 500ms+ | 异步 + 懒加载 + 砍 SDK 初始化 |
| Activity.onCreate | 100ms ~ 500ms+ | 减布局层级 + ViewStub |
| 首帧渲染 | 50ms ~ 300ms+ | 扁平化布局 + Theme 优化 |
| 总计 | ~420ms ~ 1.7s+ |
三个关键源码位置:
| 文件 | 位置 |
|---|---|
| ActivityThread.main() | frameworks/base/core/java/android/app/ActivityThread.java |
| AMS.startProcessAsync | frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java |
| ZygoteProcess.start | frameworks/base/core/java/android/os/ZygoteProcess.java |
一句话总结: 冷启动慢,基本就慢在两个地方------Application.onCreate 里初始化了太多东西,首帧渲染的布局层级太深。能异步的丢子线程、能懒加载的等用到再说、布局能扁平化的别嵌套。三点搞好了,启动快个几百毫秒是常事。