27、Android系统启动流程:BootROM、BootLoader、Kernel、init、Zygote完整链路
各位同学,今天我们来聊聊Android系统从按下电源键到Launcher界面出现的完整链路。这条链路,说白了就是一部手机从“死”到“活”的全过程。我当年刚接触Android时,觉得这玩意儿就是个黑盒,直到自己动手调过几次启动时序,才真正理解每一环的设计意图。
你想想看,一个嵌入式设备,上电时CPU内部什么都没有,连内存都还没初始化。它怎么知道该执行哪段代码?怎么把Linux内核加载起来?又怎么启动Java虚拟机、运行App?嗯,这里面的门道,我们今天一条一条捋清楚。
1. BootROM:硬件固化的第一行代码
手机按下电源键,首先通电的是PMIC(电源管理芯片)。它给CPU供电,然后CPU内部的BootROM开始执行。BootROM是芯片出厂时固化在ROM里的代码,不可修改。它的任务只有一个:找到并加载BootLoader。
BootROM会尝试从eMMC、UFS、SD卡等存储介质中读取BootLoader。读取顺序由硬件引脚或efuse决定。我记得在某个项目中,客户要求从SD卡启动用于工厂烧录,结果BootROM死活读不到,最后发现是eMMC的引脚电平拉错了——硬件设计的小坑,排查了一整天。
2. BootLoader:硬件初始化的“二传手”
BootLoader被加载到SRAM后,开始执行。它比BootROM复杂得多,主要做三件事:
- 初始化DDR内存(DRAM控制器、时序校准)
- 建立内存映射,为加载内核做准备
- 从存储中读取Linux内核镜像(boot.img)到内存
Android设备常用的BootLoader是Little Kernel(LK)或U-Boot。我个人习惯把BootLoader看作一个“跳板”——它本身不复杂,但必须稳定。我曾经遇到过一个问题:某款芯片的DDR初始化时序参数写错了,导致内核加载到一半就崩溃。排查时发现是BootLoader里DDR配置表的寄存器值少了一位,嗯,这种问题用JTAG调试才抓得到。
3. Kernel:从汇编到C的世界
BootLoader跳转到内核入口后,内核开始执行。内核启动分两个阶段:
- 汇编阶段(head.S):设置页表、使能MMU、建立C语言运行环境
- C语言阶段(start_kernel):初始化调度器、内存管理、文件系统、驱动模型等
内核启动的最后一步,是挂载根文件系统(rootfs),然后执行第一个用户空间进程——init。这里有个关键点:内核必须找到init程序,否则会panic。我记得有一次,因为ramdisk里缺少init可执行文件,内核启动后直接打印“Kernel panic - not syncing: No init found”,当时还以为是内核配置错了,查了半天才发现是打包脚本漏了文件。
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000123] Machine model: Qualcomm Technologies, Inc. MSM8998
[ 0.500456] Freeing unused kernel memory: 1024K
[ 0.500789] Run /init as init process
4. init进程:用户空间的“一号进程”
init是Linux内核启动的第一个用户空间进程,PID为1。它的核心工作是解析init.rc脚本,启动系统服务。Android的init与标准Linux的init不同,它使用自己的.rc语法,支持service、on、trigger等关键字。
init.rc中定义了大量的系统服务,比如servicemanager、surfaceflinger、media等。但最重要的,是它启动了Zygote。你想想看,如果没有Zygote,每个App启动时都要重新加载一遍Java虚拟机,那效率得多低?
5. Zygote:Java世界的“孵化器”
Zygote是Android Java世界的起点。它由init进程启动,启动时做两件事:
- 预加载Java核心类库和资源(如android.jar、主题资源)
- 创建虚拟机实例,并打开Socket监听
之后,所有App进程都由Zygote fork而来。fork时,子进程会继承Zygote的虚拟机实例和预加载资源,这样App启动就快多了。我经常跟团队说:Zygote就是Android的“母体”,所有App都是它的“子体”。
Zygote启动后,会执行SystemServer的main方法。SystemServer负责启动系统服务,比如ActivityManagerService、WindowManagerService、PackageManagerService等。这些服务都跑在system_server进程中。
6. 完整链路总结
从按下电源键到Launcher显示,整个链路可以概括为:
| 阶段 | 执行内容 | 关键输出 |
|---|---|---|
| BootROM | 硬件初始化,加载BootLoader | BootLoader镜像加载到SRAM |
| BootLoader | DDR初始化,加载内核 | 内核镜像加载到DDR |
| Kernel | 驱动初始化,挂载rootfs | init进程启动 |
| init | 解析init.rc,启动系统服务 | Zygote进程启动 |
| Zygote | 预加载Java类库,fork App | SystemServer启动 |
我个人觉得,理解这条链路的关键在于“分层”思维。每一层只做自己该做的事,然后交给下一层。BootROM只管加载BootLoader,BootLoader只管加载内核,内核只管启动init……这样设计,每一层都可以独立升级和调试。
好了,关于Android系统启动的完整链路,我们就聊到这里。下一章我们会深入Zygote的fork机制和SystemServer的启动细节,到时候再细聊。