Appearance
01 开机到桌面:从 BootROM 到 Launcher 的全时间线
本页导读:一次按电源键,CPU 从一片死寂到画出一整张桌面壁纸,中间经历 BootROM、一级/二级 bootloader(LK 或 U-Boot,fastboot 模式是它的调试分身)、内核、init、zygote、system_server,最后由 Launcher 交出接力棒。本页按时间轴逐段拆解:每段跑什么代码、读什么文件、出错了用什么命令验证。基线 Android 16(API 36),但这段链路十年骨架未变,差异集中在 AVB、动态分区与 GKI。
读完本页你应该能回答:
- 电源键按下去后,代码控制权在谁手里、信任是怎么传递的?
sys.boot_completed=1到底意味着“什么就绪了”?- 卡 logo、卡动画、黑屏三种事故分别该从哪里开始查?
一、全景时间轴
text
按下电源键
└─ BootROM(SoC 内固化) 验签并加载一级 bootloader
└─ 一级 bootloader(sbl) 初始化 DRAM/时钟,加载二级
└─ 二级 bootloader LK / U-Boot / EDK2(厂商选择)
├─ fastboot 模式 刷机协议分身
└─ 正常启动 验签 boot.img → 跳内核入口
└─ Linux 内核 挂 ramdisk,执行 /init(PID 1)
└─ init 一阶段 挂载 system 等,切根
└─ init 二阶段 解析 rc,起 servicemanager/zygote/SF
└─ zygote 预加载 → fork system_server
└─ system_server 起服务 → systemReady
└─ 启动 Launcher(HOME)→ boot_completed经验值(AOSP 参考实现,厂商差异大):现代设备冷开机到锁屏可交互一般在 20~45 秒量级;sys.boot_completed=1 只代表系统服务就绪,不代表 Launcher 首帧已出。
二、BootROM 与 AVB:信任的起点
- BootROM 烧死在 SoC 里,做第一件事是找启动介质(eMMC/UFS/SPI),用 eFuse 里的公钥哈希验签一级 bootloader;
- Android Verified Boot(AVB)从 bootloader 接力:boot/recovery/vendor_boot 等镜像尾部挂
avbfooter,vbmeta分区集中存放各分区描述符哈希; - 校验结果通过 cmdline 告诉内核:
androidboot.verifiedbootstate=green|yellow|orange|red,framework 侧SystemProperties与ro.boot.verifiedbootstate可见; - fastboot 解锁(
fastboot flashing unlock)会把状态打成 orange,部分 OEM 会清数据——这是设计,不是 bug。
验证:adb shell getprop | grep ro.boot.(注意在表格内书写时需转义竖线),能看到 ro.boot.bootloader 等字段;串口/dmesg 里能看到 AVB 逐分区校验日志。
- 校验失败分级处置:
red直接拒绝启动;解锁后的yellow/orange由 OEM 策略决定是否警告、是否擦数据; - dm-verity 运行期发现分区被篡改会按
androidboot.verity_mode策略当场重启或 panic,日志关键字dm-verity corruption。
三、二级 bootloader:LK、U-Boot 与 fastboot
- LK(little kernel):高通/MediaTek 老平台常见,本身就是个小 RTOS,源码在 GitHub 上以
lk/little kernel名义流传(AOSP 本体不再收录,Bootable已归档);显示 logo、fastboot UI、下载模式都在这层; - U-Boot/EDK2:部分平台与虚拟设备(如 cuttlefish 用 U-Boot,虚拟机直接用 VMM);
- fastboot 协议:二级 bootloader 的分身,
fastboot flash boot boot.img刷的就是内核+ramdisk;fastboot oem命令厂商自定义; - 交给内核前的关键动作:装配 kernel cmdline(console、androidboot.* 参数)、把 DTB 放到约定地址、加载 ramdisk(GKI 平台改用
vendor_boot/vendor_dlkm与 bootconfig,不再依赖大 cmdline)。
出问题的典型症状:卡 logo 不进系统——多半是 boot/vendor_boot 验签失败或 DTB 不匹配,串口日志第一现场。
四、内核:命令行里藏着开机履历
内核解压后第一件事是挂 ramdisk(first-stage ramdisk 在 boot.img 里),然后执行 /init——它就是 PID 1。
- cmdline 上的
androidboot.hardware、androidboot.serialno、androidboot.mode=charger|fastboot等androidboot.*参数会被 init 拆成ro.boot.*属性(第 02 页 property 机制); - GKI(Android 11 起通用内核)推荐 bootconfig(
/proc/bootconfig、/sys/kernel/bootconfig)承载androidboot.*,规避 cmdline 长度限制; - 内核日志是启动排查第一现场:
adb shell dmesg,或/sys/fs/pstore/(console-ramoops 保留崩溃前日志,上次死机的证据在这里); - 有条件一定接串口(UART):framework 日志要等 logd/zygote 活着才有,而串口从 bootloader 就在,是“链路最底层 witness”;
androidboot.hardware决定 init 后续加载init.<hardware>.rc(第 02 页),这是同一份 system 镜像适配不同板子的第一个分岔点。
五、init:一阶段挂载,二阶段拉起整机
/system/core/init 的 main 分 first-stage / second-stage(Android 10 动态分区后正式分家):
- first-stage:只挂
super、解 dm-verity/dm-linear(动态分区映射表在 lpmeta),挂 system 等最小集,然后switch_root进完整 rootfs; - second-stage:挂载
/data(触发post-fs-data)、挂载 APEX(apexd,第 12 页)、加载 SELinux policy、解析 rc 文件链; - rc 编排(细节第 02 页):
early-init → init → late-init → post-fs → post-fs-data → boot-complete一串 trigger,关键服务按 class 拉起:class_start main(zygote、surfaceflinger 等)、class_start hal; - 最后阶段 init 触发
exec system_ready类动作后,servicemanager、surfaceflinger、zygote相继就绪。
每阶段验证命令:
| 阶段 | 看什么 | 命令 |
|---|---|---|
| bootloader | 版本与状态 | getprop ro.boot.bootloader;fastboot 下 fastboot getvar all |
| 内核 | cmdline/错误 | cat /proc/cmdline、dmesg 看首屏 |
| 一阶段 | 分区映射 | ls /dev/block/dm-*、dmctl dump(需 root) |
| 二阶段 | 触发链 | getprop 过滤 boottime、dmesg 过滤 init |
| SELinux | enforcing | getenforce、dmesg 过滤 avc |
六、zygote 与 system_server:Java 世界的黎明
init 二阶段读到 /system/etc/init/zygote.rc 后拉起 zygote64(app_process64),ZygoteInit.main() 在 fork system_server 前完成预加载:类(preloaded-classes 系列清单)、资源(android.R 的预载)、JNI 注册、/dev/__properties__ 映射。随后 ZygoteInit.main() 通过 forkSystemServer() 派生 system_server,它加载 SystemServer 类走三阶段启动(第 03 页)。
时间账(AOSP 参考值,以实测为准):zygote 预加载通常占开机 300ms~1s;system_server 三阶段+开机广播可占 3~8s;Launcher 冷启动 1~3s。开机慢,多半慢在 system_server 服务串行启动与 IO 扫描(PMS 全量扫描,第 08 页)。
预加载的内容大致分四类:
| 预加载项 | 清单/来源 | 效果 |
|---|---|---|
| 热类 | preloaded-classes、脏页优化版、text-init 版 | fork 后直接命中,省去类加载 |
| 资源 | android.R 常用资源、主题、预载 Drawable | 首帧 inflate 成本大降 |
| JNI/运行时 | JNI 注册、/dev/__properties__ 映射 | 系统属性读取零拷贝 |
| 其他预热 | 部分系统组件的预热钩子,具体清单以 AOSP 为准 | 降低首次使用成本 |
java
// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java(示意节选,非逐行源码)
public static void main(String[] args) {
...
preload(...); // 预加载类/资源/JNI,fork 后全继承
zygoteServer = new ZygoteServer(abiList); // 监听 /dev/socket/zygote*
if (startSystemServer) {
forkSystemServer(abiList); // fork 出 system_server,子进程走 SystemServer.main
}
Runnable r = zygoteServer.runSelectLoop(abiList, null); // 此后永久监听孵化请求
}七、Launcher 出场:HOME 解析
system_server 走完 startOtherServices 后调用 ActivityManagerService.systemReady() 收尾,链路上由 ActivityTaskManagerService 发出 HOME intent(Intent.ACTION_MAIN + CATEGORY_HOME),经第 06 页的进程启动链孵化或复用 Launcher 进程,ResumeActivityItem 下发,Launcher 首帧上屏。期间用户看到的是 bootanimation(/system/media/bootanimation.zip 或 OEM 定制,由独立 bootanimation 进程直绘 SurfaceFlinger,不依赖 system_server 全量就绪)。
boot 完成的最后一棒:AMS 发 ACTION_BOOT_COMPLETED 广播(仅系统应用与注册了开机广播的应用可收),并把 sys.boot_completed 置 1——fastboot/开机度量脚本都以它为零点。
验证三件套:
bash
adb shell dumpsys activity | grep -e "Resumed" -e "mResumedActivity" # 当前前台是否 Launcher
adb shell getprop sys.boot_completed # 应为 1
adb shell dumpsys activity | grep -i "displayed" # 各 Activity 上屏耗时Displayed 行是 Google 官方推荐的启动耗时口径(framework 统计的首帧),例如 Displayed com.android.launcher/.Launcher +812ms。
八、另外三扇门:charger、recovery 与安全模式
正常链路之外,同一台设备还有三个启动分身:
- charger 模式:cmdline 带
androidboot.mode=charger时,init 只拉起充电相关 class,画面由 rootfs 里的charger二进制直绘,不碰 zygote;验证:getprop ro.boot.mode; - recovery 模式:Android 9+ recovery 从 boot.img 拆成独立分区,里面是另一套精简 ramdisk +
update_engine/updater;经典 A/AB 全量包走 recovery 或 sideload,Virtual A/B 则完全不走 recovery,由后台update_engine在正常系统内安装 snapshot; - 安全模式(safe mode):Android 13+ 开机时长按音量下可进,禁用第三方应用,是处理“开机循环由某个坏 App 引起”的标准逃生通道。
这三扇门共同的特点:都不依赖完整 framework,所以它们是 framework 彻底瘫痪时仅剩的修复面。刷机、清数据、OTA 回滚都发生在这里,而不是在 Android 系统内部。
九、首次开机与 OTA 后的开机:两套时间线
- 首次开机(首次进桌面前的“初始化仪式”):
/data刚创建,PMS 需要全量扫描分区并首次写/data/system下的包状态;ART 对预装应用可能触发 dex2oat;多用户/工作资料初始化;所以首开机比日常开机慢好几秒很正常; - 后续开机:PMS 直接读持久化的包状态缓存,跳过全量解析(扫描与缓存机制见第 08 页);大部分包命中 profile 的 speed-profile,不重新编译;
- OTA 后首次开机:Classic A/B 只是换槽回滚;Virtual A/B 需要在开机早期做 snapshot merge,期间 IO 风暴,boot_completed 后的“假卡顿”多源于此;
- 排查建议:比较两台设备开机速度前先对齐“首开/非首开/OTA 后”这三种场景,否则数据没有可比性。
十、bootstat 与时间账本
bootstat(system/core/bootstat)在开机各里程碑打点并落入 bootcomplete_event/boot_event log 事件:
adb shell bootstat -p boot_complete:上次开机事件属性(含 subreason、duration);getprop | grep boottime:ro.boottime.init等一干内核/服务起点时间;bugreport的BOOTSTAT与ps -p 1 -o lstart可以交叉还原整机时间线;- 死机取证:
/sys/fs/pstore/console-ramoops+/data/tombstones+last_kmsg(部分内核保留)。
十一、常见故障模式与定位
| 症状 | 大概率区间 | 第一现场 |
|---|---|---|
| 完全无显示、电流无变化 | BootROM/电源 | 电流表、JTAG/串口 |
| 卡第一屏 logo | bootloader/AVB/DTB | 串口、fastboot 是否可进 |
| 进 recovery/fastboot 循环 | boot/vendor_boot 验签或 dm-verity 失败 | fastboot 重刷、dm-verity corrupt 内核日志 |
| 卡开机动画 | init 二阶段→zygote→system_server | 串口 init: ... starting service、logcat -b all(zygote 死后才有 framework 日志) |
| 动画完黑屏/桌面不出 | Launcher 崩溃/HOME 解析失败 | logcat 过滤 AndroidRuntime、dumpsys activity activities |
| 反复 system_server 重启 | Watchdog/关键服务 NPE | logcat 过滤 SystemServer/Watchdog、dropbox SYSTEM_RESTART |
十二、版本注记
- Android 8(API 26):Treble 引入,init 出现 vendor rc 链;AVB 2.0 起步。
- Android 9(API 28):AVB2.0 强制、
vbmeta独立分区;recovery 与 boot 解耦(recovery 独立分区)。 - Android 10(API 29):动态分区(super/lpmeta)、first-stage 与 second-stage init 分家、APEX 登场。
- Android 11(API 30):GKI 通用内核起步、bootconfig 替代部分 cmdline;VNDK 快照。
- Android 12(API 31):boot image v4、Virtual A/B(VAB)OTA;
vendor_boot镜像拆分。 - Android 13~16(API 33~36):HIDL HAL 清零推进;GKI 2023+ 内核版本基线抬升;Mainline 模块继续从 system 搬走能力(第 12 页)。
本页小结
本页小结:开机是一条单向信任链:BootROM 验 bootloader、AVB 验镜像、内核信 cmdline、init 信 rc、system_server 信服务、Launcher 信 HOME intent。任何一环断掉,症状都会「向上冒泡」成卡 logo、卡动画或黑屏,而定位思路永远是先问自己:现在链路走到哪一层?串口/
ro.boottime.*/Displayed分别在三个高度等着你对号入座。
参考
- AOSP 启动流程文档:source.android.com/docs/core/architecture(Boot flow 章)
- init 源码与 README:cs.android.com/android/platform/system/core/+/main/init/README.md
- ZygoteInit 源码:cs.android.com/android/platform/frameworks/base/+/main/core/java/com/android/internal/os/ZygoteInit.java
- AVB/libavb 源码:cs.android.com/android/platform/external/avb