一、整体概览:Android系统架构分层与启动流程
各位同学,今天我们来聊聊Android启动流程的“全景图”。
说实话,我刚开始接触Android底层时,也被这复杂的启动链条搞得头晕。但后来我发现,只要抓住一条主线——从硬件到软件,从底层到上层——整个流程就清晰了。
1.1 Android系统架构分层
先看一张我手绘的架构分层图(你可以在脑中想象):
+------------------------------------------+
| 应用层 (Applications) |
| (电话、短信、浏览器、第三方App...) |
+------------------------------------------+
| 应用框架层 (Application Framework) |
| (ActivityManager、WindowManager...) |
+------------------------------------------+
| 系统运行库层 (Android Runtime) |
| (ART、Core Libraries) |
+------------------------------------------+
| 硬件抽象层 (HAL) |
| (Camera HAL、Audio HAL...) |
+------------------------------------------+
| Linux内核层 (Linux Kernel) |
| (进程管理、内存管理、驱动...) |
+------------------------------------------+
| 硬件层 (Hardware) |
| (CPU、RAM、Flash、外设...) |
+------------------------------------------+
这个分层结构,说白了就是“各司其职”。
- 硬件层:物理基础,CPU、内存、存储芯片都在这里。
- Linux内核层:这是Android的“心脏”。我习惯把它看作一个超级管家,管理进程、内存、文件系统,还要驱动所有硬件。
- 硬件抽象层(HAL):一个巧妙的“中间人”。它让上层应用不用关心底层硬件是谁家的。
- 系统运行库层:ART虚拟机、核心C/C++库都在这里。嗯,这里要注意,ART负责把字节码编译成机器码。
- 应用框架层:开发者最熟悉的一层。Activity、Service、ContentProvider这些组件都在这里。
- 应用层:我们每天用的App。
- 初始化CPU、内存、时钟等基础硬件
- 从存储介质(eMMC、UFS)中读取内核镜像
- 把内核加载到内存指定位置
- 跳转到内核入口点
- 第一阶段(SPL/MLO):极简代码,初始化DDR内存。因为Boot ROM太小,放不下复杂逻辑。
- 第二阶段(U-Boot/LK):完整的引导程序,支持文件系统、网络、命令行。
- 架构初始化:设置页表、中断向量、时钟系统
- 内存管理初始化:建立伙伴系统、slab分配器
- 进程调度器初始化:创建init进程(PID=1)
- 驱动加载:根据设备树(DTB)匹配并初始化驱动
- 挂载根文件系统:通常是ramdisk或system分区
- init进程:解析init.rc脚本,启动关键服务(ueventd、servicemanager)
- Zygote进程:Android的“孵化器”。它预加载了所有Java核心类库,然后监听socket请求,fork出新的应用进程。
- SystemServer:Zygote fork出的第一个Java进程。它负责启动所有系统服务(ActivityManager、PackageManager、WindowManager等)。
- Launcher:桌面应用。当SystemServer启动完成后,会发送一个“BOOT_COMPLETED”广播,Launcher收到后显示桌面。
核心观点:Android不是纯粹的Linux,但它离不开Linux内核。没有内核,Android就是一堆代码而已。
1.2 启动流程的四个阶段
Android的启动,就像一场接力赛。四个阶段环环相扣:
| 阶段 | 主要任务 | 时间窗口(典型值) |
|---|---|---|
| Boot ROM | 固化在芯片中的代码,加载Bootloader | 几十毫秒 |
| Bootloader | 初始化硬件,加载内核到内存 | 几百毫秒 |
| Kernel | 初始化内核子系统,挂载根文件系统 | 1-3秒 |
| Android系统 | 启动init进程,加载Zygote、SystemServer | 5-15秒 |
你想想看,从按下电源键到看到桌面,这十几秒里发生了多少事?
第一阶段:Boot ROM
这是芯片出厂时就写死的代码。你改不了它,它也不会变。
它的任务很简单:找到并验证Bootloader。我记得在某个项目中,客户要求实现安全启动,Boot ROM会检查Bootloader的数字签名。如果签名不对,直接死机——这就是所谓的“安全启动链”。
避坑指南:我曾经遇到过一台设备,刷机后变砖。后来发现是Boot ROM找不到Bootloader了。原因?Bootloader被意外擦除了。所以,永远不要动Boot ROM区域,除非你清楚自己在做什么。
第二阶段:Bootloader
Bootloader是“承上启下”的角色。它负责:
我个人习惯把Bootloader分成两个阶段:
为什么会这样设计?说白了,就是“先活下来,再谈发展”。
第三阶段:Kernel
这是Linux内核的“主场”。内核启动时,会做以下几件大事:
嗯,这里要注意:内核启动的最后一步,是执行根文件系统中的init程序。这个init,就是Android世界的“第一个进程”。
警告:内核启动过程中,如果某个关键驱动加载失败(比如存储驱动),系统会直接panic。我曾经调试过一个bug,设备总是在内核启动到一半时重启。最后发现是eMMC驱动时序有问题。所以,驱动稳定性是内核启动的命门。
第四阶段:Android系统
内核启动完成后,控制权交给了init进程。Android系统的启动,从这里正式开始:
你想想看,从init到Launcher,这中间有多少个进程在接力?
1.3 Linux内核在其中的核心角色
Linux内核在Android启动中扮演了三个关键角色:
| 角色 | 具体职责 | 我的理解 |
|---|---|---|
| 硬件抽象层 | 通过驱动管理所有硬件资源 | 没有内核驱动,CPU、内存、屏幕都是摆设 |
| 进程调度器 | 决定哪个进程先运行、运行多久 | Android的“时间管理者” |
| 内存管理者 | 分配和回收物理内存 | Low Memory Killer就是基于内核的OOM机制 |
我个人觉得,内核最重要的贡献是提供了稳定的运行环境。Android上层可以频繁更新,但内核一旦稳定,很少改动。我在项目中见过一些团队,为了“优化性能”乱改内核调度参数,结果系统反而更卡了。嗯,内核这东西,能不碰就别碰。
总结一下:Android启动流程,本质上是“从硬件到软件”的层层唤醒。Boot ROM唤醒Bootloader,Bootloader唤醒Kernel,Kernel唤醒init,init唤醒Android世界。而Linux内核,就是这个链条上最核心的一环——它既是硬件的管理者,也是软件的基石。
下一章,我们会深入Boot ROM的细节,看看芯片上电后到底发生了什么。到时候我会分享一个我在调试“冷启动时序”时踩过的坑,很有意思。