Android系统启动流程深度解析:从Bootloader到Zygote的完整旅程
引言
每次按下电源键,你的Android设备经历了什么?
从一片黑屏到看到开机Logo,从显示"Android"字样到进入锁屏界面,这短短几秒钟(或十几秒钟)背后,是一场精心编排的"启动大戏"。这场大戏有四幕:
第一幕: Bootloader → 加载并启动Kernel 第二幕: Kernel → 初始化硬件,启动init进程(PID 1) 第三幕: init → 挂载文件系统,启动核心服务 第四幕: Zygote → 准备应用运行环境本文将带你完整走完这段旅程,重点聚焦第二幕到第三幕——从Kernel启动init,到init启动Zygote之前的所有准备工作。
📖系列前置阅读:建议先阅读第9-11篇(Binder IPC系列),理解进程间通信机制,这是理解系统服务启动的基础。
Android启动流程全景图
在深入细节之前,先建立整体认知:
图:Android 15系统启动的4个阶段,从Bootloader到Zygote的完整旅程,总耗时约6.5秒
本文聚焦范围:从Kernel启动init到Zygote启动之前,即上图中的第3步:init进程。
Bootloader与Kernel启动(概览)
虽然不是本文重点,但理解这两个阶段有助于建立完整认知。
Bootloader阶段
Bootloader(引导加载程序)是设备上电后执行的第一段代码,由芯片厂商或设备厂商提供。
主要任务:
硬件初始化:
- CPU频率和电压配置
- 内存初始化(DDR)
- 外设初始化(Flash/eMMC/UFS)
加载Kernel:
- 从boot分区读取Kernel镜像(
boot.img) - 解压Kernel到内存
- 读取Device Tree Blob(DTB,设备树)
- 从boot分区读取Kernel镜像(
安全验证:
- Verified Boot(Android Verified Boot):验证Kernel签名
- 如果验证失败,显示警告或拒绝启动
启动Kernel:
- 设置Kernel启动参数(cmdline)
- 跳转到Kernel入口地址(通常是
0x80008000)
常见Bootloader:
- LK(Little Kernel):Qualcomm芯片常用
- U-Boot:开源,通用性强
- UEFI:PC和部分高端设备
关键日志(通过串口或fastboot查看):
[0.000000] Booting Linux on physical CPU 0x0 [0.000000] Linux version 5.15.123-android15 (build@hostname) ...Kernel启动阶段
Linux Kernel负责硬件抽象和资源管理。
主要任务:
内存管理初始化:
- 页表设置
- 内存分配器(SLAB/SLUB)初始化
进程调度器初始化:
- CFS调度器(Completely Fair Scheduler)
- 实时调度器(RT)
驱动初始化:
- 加载内置驱动(built-in)
- 初始化设备树(Device Tree)中定义的硬件
文件系统初始化:
- 挂载rootfs(根文件系统,通常是ramdisk)
- 挂载/system、/vendor等分区(由init负责)
创建init进程:
// kernel/init/main.c (简化)staticint__refkernel_init(void*unused){// ...if(!ramdisk_execute_command)ramdisk_execute_command="/init";returnrun_init_process(ramdisk_execute_command);}
关键Kernel参数(cmdline):
# 查看Kernel启动参数adb shellcat/proc/cmdline# 输出示例:# androidboot.hardware=qcom# androidboot.selinux=permissive # 或 enforcing# androidboot.verifiedbootstate=green# init=/system/bin/initinit进程:Android的"创世神"
init进程是Android用户态的第一个进程(PID 1),它的职责是创建整个用户态环境。
init的三阶段启动
Android 15的init分为三个阶段,每个阶段有独立的入口函数:
main() → FirstStageMain() → SetupSelinux() → SecondStageMain() ↓ ↓ ↓ ↓ 入口 第一阶段 SELinux设置 第二阶段(核心)让我们分析Android 15的源码:
阶段判断逻辑
// system/core/init/main.cpp (Android 15)intmain(intargc,char**argv){// 提升优先级(后续会恢复)setpriority(PRIO_PROCESS,0,-20);// 如果argv[0]是"ueventd",则以ueventd模式启动if(!strcmp(basename(argv[0]),"ueventd")){returnueventd_main(argc,argv);}if(argc>1){// 子上下文模式(用于隔离某些操作)if(!strcmp(argv[1],"subcontext")){returnSubcontextMain(argc,argv,&GetBuiltinFunctionMap());}// SELinux设置阶段if(!strcmp(argv[1],"selinux_setup")){returnSetupSelinux(argv);}// 第二阶段if(!strcmp(argv[1],"second_stage")){returnSecondStageMain(argc,argv);}}// 默认进入第一阶段returnFirstStageMain(argc,argv);}关键设计:
- init通过命令行参数判断当前应执行哪个阶段
- 每个阶段完成后,会通过
execv()重新执行自己,进入下一阶段 - 这种设计允许在SELinux加载后"重启"进程,获得新的安全上下文
第一阶段:FirstStageMain()
核心目标:创建最基础的文件系统,加载SELinux策略。
// system/core/init/first_stage_init.cpp (简化)intFirstStageMain(intargc,char**argv){// ========== 1. 挂载基础文件系统 ==========CHECKCALL(mount("tmpfs","/dev","tmpfs",MS_NOSUID,"mode=0755"));CHECKCALL(mkdir("/dev/pts",0755));CHECKCALL(mkdir("/dev/socket",0755));CHECKCALL(mount("devpts","/dev/pts","devpts",0,NULL));// 挂载proc文件系统(读取内核信息)CHECKCALL(mount("proc","/proc","proc",0,"hidepid=2,gid=3009"));// 挂载sysfs(设备和驱动信息)CHECKCALL(mount("sysfs","/sys","sysfs",0,NULL));// 挂载selinuxfs(SELinux策略文件系统)CHECKCALL(mount("selinuxfs","/sys/fs/selinux","selinuxfs",0,NULL));// ========== 2. 创建必要的设备节点 ==========CHECK