2. Android系统启动全景
Android设备的开机过程并不是“按下电源键就进入桌面”这么简单,而是一条跨越硬件、固件、内核、用户空间和框架层的多级接力链。每一级都负责初始化一部分资源,然后把控制权交给下一级。理解这条链路,是进行启动性能优化的前提——因为只有知道时间花在哪一级,才能判断优化应该落在Bootloader、Kernel、Init、Zygote还是SystemServer。
一、完整启动链路的七个阶段
从按下电源键到用户看到Launcher,Android系统大致经历以下七个阶段:
- BootROM:芯片上电后运行固化在ROM中的第一段代码,负责最基本的硬件初始化和加载Bootloader。
- Bootloader:初始化DDR、时钟、存储等,校验并加载Kernel镜像,同时可能处理fastboot、recovery等模式。
- Kernel:解压并启动Linux内核,初始化内存管理、调度器、驱动、文件系统,最后挂载根文件系统并启动第一个用户空间进程init。
- Init:解析init.rc,创建目录、设置权限、启动native服务(如servicemanager、vold、logd),并启动Zygote。
- Zygote:预加载常用类和资源,创建Socket等待AMS请求,通过fork快速孵化应用进程。
- SystemServer:由Zygote fork出来,启动AMS、PMS、WMS等核心系统服务,是框架层启动的核心。
- Launcher:SystemServer完成启动后,AMS启动Home应用,用户看到桌面,启动流程结束。
下面这张图展示了各阶段之间的接力关系与关键产物:
二、各阶段的关键任务与耗时特征
不同阶段的耗时特征差异很大,优化手段也完全不同。下表总结了各阶段的核心任务、典型耗时和主要优化方向:
| 阶段 | 核心任务 | 典型耗时 | 主要优化方向 |
|---|---|---|---|
| BootROM | 上电自检、加载Bootloader | <500ms | 基本不可优化,由芯片决定 |
| Bootloader | 初始化DDR、校验并加载Kernel | 1~2s | 精简镜像、关闭冗余校验、优化存储读取 |
| Kernel | 驱动初始化、挂载根文件系统 | 0.5~1.5s | 裁剪驱动、延迟初始化非关键模块 |
| Init | 解析init.rc、启动native服务 | 0.5~1s | 并行启动服务、减少阻塞式操作 |
| Zygote | 预加载类与资源、创建Socket | 0.5~1s | 精简预加载类、优化资源加载 |
| SystemServer | 启动AMS/PMS/WMS等核心服务 | 2~5s | 服务启动顺序优化、异步化、延迟启动 |
| Launcher | 加载桌面、渲染首帧 | 0.5~2s | 布局优化、数据预加载、减少主线程阻塞 |
三、核心原理:为什么启动是串行的
Android启动链的串行性来源于资源依赖。Bootloader必须等DDR初始化完成才能加载Kernel;Kernel必须等驱动就绪才能挂载文件系统;Init必须等文件系统挂载完成才能启动Zygote;Zygote必须完成预加载才能fork SystemServer;SystemServer必须启动AMS才能启动Launcher。这种依赖关系决定了启动链的关键路径。
但串行并不意味着所有工作都必须严格按顺序完成。在Init阶段,多个native服务可以并行启动;在SystemServer阶段,部分系统服务可以异步初始化或延迟启动。优化的核心思路是:识别关键路径,把非关键路径的工作移出关键路径,或者并行化。
四、实操:如何抓取启动各阶段耗时
在优化之前,必须先测量。Android提供了多种工具来抓取启动各阶段的时间戳:
# 查看内核启动日志中的时间戳
adb shell dmesg | grep -E "init|zygote|system_server"
# 查看init阶段各服务的启动时间
adb shell logcat -b events | grep "boot_progress"
# 关键boot_progress事件
# boot_progress_start : init开始
# boot_progress_preload_start: Zygote预加载开始
# boot_progress_preload_end : Zygote预加载结束
# boot_progress_system_run : SystemServer开始
# boot_progress_pms_start : PMS开始
# boot_progress_pms_ready : PMS就绪
# boot_progress_ams_ready : AMS就绪
# boot_progress_enable_screen: 屏幕可用
# 查看整体启动时间
adb shell logcat -b events | grep "boot_progress_enable_screen"
通过这些事件时间戳,可以计算出每个阶段的耗时,从而定位瓶颈。例如,如果boot_progress_preload_start到boot_progress_preload_end耗时超过1秒,说明Zygote预加载过重;如果boot_progress_system_run到boot_progress_ams_ready耗时过长,说明SystemServer服务启动需要优化。
五、案例场景:某设备开机慢的排查过程
某Android设备开机时间约25秒,远高于同类产品的15秒。通过抓取boot_progress事件,发现:
- Bootloader到Kernel启动:3秒(正常)
- Kernel到Init启动:2秒(正常)
- Init到Zygote预加载开始:1秒(正常)
- Zygote预加载:2.5秒(偏长)
- SystemServer启动到AMS就绪:12秒(严重偏长)
- AMS就绪到Launcher显示:4秒(偏长)
进一步分析SystemServer日志,发现某个第三方系统服务在初始化时进行了同步网络请求,阻塞了主线程。将其改为异步初始化后,SystemServer阶段耗时从12秒降到5秒,整体开机时间从25秒降到17秒。
六、复盘与关键要点
Android启动链是一条从硬件到应用层的完整接力链,七个阶段环环相扣。理解这条链路的价值在于:
- 定位问题:通过boot_progress事件可以快速判断瓶颈在哪个阶段。
- 选择手段:不同阶段的优化手段完全不同,Bootloader阶段关注镜像和存储,Kernel阶段关注驱动,Init阶段关注服务启动顺序,Zygote阶段关注预加载,SystemServer阶段关注服务初始化,Launcher阶段关注渲染。
- 避免误判:不要凭感觉优化,要用时间戳数据说话。
- 关注关键路径:只有关键路径上的优化才能缩短开机时间,非关键路径的优化可能毫无效果。
下一阶段的学习将深入Init、Zygote和SystemServer这三个用户空间阶段,它们是启动优化中最常被调整、也最容易产生收益的部分。