前面四篇,我们已经建立了 Android 系统最基础的地图:
AOSP
↓
Repo / Git / Manifest
↓
AOSP 源码目录
↓
Android 系统分层
我们也已经知道:
App
↓
Framework
↓
System Service
↓
Native / HAL
↓
Linux Kernel
↓
Hardware
但是还有一个非常重要的问题:
这些东西到底是什么时候运行起来的?
手机刚刚通电的时候:
AMS 在哪里?
SystemServer 在哪里?
Zygote 又是什么时候出现的?
Linux Kernel 谁启动?
Launcher 为什么最后会显示出来?
这一篇就解决这个问题:
Android 从按下开机键,到桌面 Launcher 出现,中间到底经历了什么?
第一阶段依然不钻源码。
我们先把整条启动链路串起来。
一、先看 Android 开机主流程
Android 开机过程可以先概括成:
Boot ROM
↓
Bootloader
↓
Linux Kernel
↓
init
↓
Zygote
↓
system_server
↓
System Services
↓
Launcher / Home
现在先不要管每一步的具体实现。
只建立一个感觉:
Android 开机其实就是一场"接力赛"。
前一个启动后一个。
最后整个 Android 系统才真正活起来。
二、第一棒:Boot ROM
严格来说,最早运行的通常还不是 Bootloader。
芯片上电之后,CPU 会先执行芯片内部固化的一小段代码:
Boot ROM
它的任务非常基础。
例如:
初始化最基础的硬件环境
↓
找到可启动介质
↓
加载下一阶段 Bootloader
你可以把 Boot ROM 理解成:
设备通电后最先执行的"出厂启动代码"。
它通常由 SoC 芯片厂商提供,并不是我们学习 Android Framework 时重点关注的东西。
第一阶段知道名字即可。
三、第二棒:Bootloader
接下来进入:
Bootloader
Bootloader 中文一般叫:
引导加载程序。
它的核心目标就是:
把 Linux Kernel 准备好并启动起来。
可以粗略理解:
Boot ROM
↓
找到 Bootloader
Bootloader
↓
准备硬件环境
↓
验证启动镜像
↓
加载 Linux Kernel
四、你可能听过 fastboot
如果以后真正开始搞 AOSP、刷机、系统开发,很容易碰到:
fastboot
例如:
fastboot flash boot boot.img
或者:
fastboot reboot
为什么 fastboot 会和刷系统关系这么大?
因为它和:
Bootloader
阶段密切相关。
所以以后可以建立:
App 开发
↓
adb 经常见
刷机 / Bootloader
↓
fastboot 经常见
第一阶段不用学 fastboot。
这里只是把它挂到地图上。
五、第三棒:Linux Kernel
Bootloader 把:
Linux Kernel
加载到内存以后:
Kernel 开始接管机器。
这一步非常重要。
Kernel 启动以后,会逐渐准备:
CPU 调度
内存管理
中断
设备驱动
文件系统
进程管理
安全机制
等等。
六、Kernel 起来了,但 Android 还远远没起来
这是一个很重要的概念。
这时候:
Linux Kernel
已经运行。
但你熟悉的这些东西:
Activity
AMS
WMS
PMS
SystemServer
Launcher
Settings
统统还没有真正准备好。
所以:
Kernel 启动成功
≠
Android 系统已经启动完成
Kernel 只是:
把操作系统最底层的地基铺好了。
接下来才开始构建 Android 用户空间。
七、第四棒:init
Kernel 接下来需要启动用户空间。
Android 这里会进入一个极其重要的进程:
init
以后学习 Android 系统启动,会反复碰到这个名字。
可以先记一句:
init 是 Android 用户空间启动过程中的总管。
它负责很多基础初始化工作,并根据配置启动后续系统进程和服务。
八、init 是 Native 程序
这里正好和上一篇讲的 Native 联系起来。
init 不是:
Java
Kotlin
程序。
它属于:
Native
世界。
源码主要位于:
system/core/init/
所以前面的 AOSP 目录知识也开始串起来了:
system/
↓
系统底层基础组件
↓
system/core/init
↓
Android init
这就是为什么我们之前说:
system/开始逐渐靠近 Android 底层和 Linux 世界。
九、init.rc 又是什么?
以后一定会经常看到:
init.rc
它不是 Java 代码。
可以先把它理解成:
Android init 的启动配置脚本。
里面会描述:
什么时候执行什么动作
启动什么 Service
Service 使用什么用户
Service 属于什么 class
什么时候启动
什么条件下重启
比如以后可能看到类似:
service xxx /system/bin/xxx
class core
user system
group system
大体可以理解成:
init,帮我管理一个叫 xxx 的系统服务。
现在不需要学习 init 语法。
十、init 不只是读一个 init.rc
不要简单理解成:
Android
↓
只有一个巨大的 init.rc
现代 Android 会加载多个位置中的 .rc 配置,例如:
/system/etc/init/
/vendor/etc/init/
/odm/etc/init/
/product/etc/init/
...
所以真实情况更像:
init
↓
读取很多 .rc
↓
启动 Android 各种基础进程和服务
十一、init 启动的东西很多
不要理解成:
init
↓
只负责启动 Zygote
不是。
它还会启动很多系统级 Native Daemon / Service。
例如可能涉及:
logd
servicemanager
surfaceflinger
vold
netd
...
不同 Android 版本、不同设备会有所差异。
可以先理解:
init
│
┌───────────┼───────────┐
↓ ↓ ↓
Native Native Zygote
Service Daemon
init 是 Android 用户空间启动非常重要的总入口之一。
十二、但是 Framework 开发最关注的是 Zygote
对于 Android App / Framework 开发者来说,启动流程里最重要的转折点之一就是:
Zygote
因为从这里开始:
我们终于要进入 ART / Java 世界了。
前面:
Bootloader
Kernel
init
整体更加偏:
Native / Linux
从 Zygote 开始:
ART
Java Framework
App Process
逐渐出现。
十三、第五棒:Zygote
Zygote 中文原意是:
受精卵。
为什么叫这个名字?
因为它会成为大量 Android Java/ART 进程的共同"父辈"。
可以先这样理解:
Zygote
↓
fork
├── system_server
├── App A
├── App B
├── App C
└── ...
这里最核心的两个概念就是:
Zygote
=
已经提前准备好的进程底座
以及:
fork()
=
基于这个进程底座创建新的子进程
所以"受精卵"这个名字非常形象:
一个共同起点
↓
不断产生新的子进程
十四、是谁启动 Zygote?
这个问题现在已经可以回答了:
init
也就是:
Kernel
↓
init
↓
Zygote
所以不要理解成:
Kernel
↓
直接启动 Zygote
中间还有 Android 用户空间非常关键的:
init
十五、Zygote 为什么不让每个 App 从零启动?
假设没有 Zygote。
用户打开 App A:
创建 Linux 进程
↓
启动 ART
↓
初始化 Java Runtime
↓
加载 Java 基础类
↓
加载 Android Framework 类
↓
初始化公共资源
↓
加载 App A 自己的代码
↓
运行 App A
再打开 App B:
再创建 Linux 进程
↓
再启动 ART
↓
再初始化 Runtime
↓
再加载 Framework
↓
再初始化公共资源
↓
加载 App B
你会发现:
前面大量工作每个 App 都是重复的。
例如:
ART
Java 基础类
Android Framework 类
公共资源
这些都是很多 App 共用的基础环境。
于是 Android 使用了 Zygote:
公共环境先准备一次,以后新的 App 进程直接从这个底座产生。
十六、Zygote 会提前准备公共环境
Zygote 启动以后,会提前进行:
ART / Runtime 初始化
↓
预加载大量 Java 类
↓
预加载 Android Framework 类
↓
预加载部分公共资源
于是:
┌────────────────────────┐
│ Zygote │
│ │
│ ART 已经准备 │
│ Java 基础类已准备 │
│ Framework 已准备 │
│ 公共资源已准备 │
└────────────────────────┘
可以把它理解成:
一个已经预热好的 Android Java/ART 进程模板。
十七、fork 到底做了什么?
当系统需要一个新的 App Process 时:
system_server
↓
需要启动 App
↓
请求 Zygote
↓
Zygote 调用 fork()
↓
产生新的子进程
第一阶段可以先把:
fork()
理解成:
基于当前 Zygote 进程,生成一个新的子进程。
新进程会继承 Zygote 已经准备好的大量运行环境。
所以:
Zygote
│
公共环境准备好
│
┌─────────┼─────────┐
↓ ↓ ↓
App A App B App C
每个 App 都不用再完全从零准备 ART 和公共 Framework 环境。
十八、fork 并不会立刻完整复制全部内存
这里补一个非常重要,但目前不用深入的概念:
COW
全称:
Copy-On-Write
中文:
写时复制。
fork 在逻辑上可以理解成:
"基于 Zygote 复制出一个新的进程。"
但 Linux 并不会在 fork 瞬间,把 Zygote 的所有物理内存完整复制一遍。
而是:
fork
↓
父子进程先共享大量物理内存页
↓
哪个进程真正修改某个内存页
↓
Linux 才给它复制对应的那一页
例如:
修改前:
Zygote ─┐
├── 共享 Page A
App A ─┘
如果 App A 要修改这一页:
Zygote
↓
Page A
App A
↓
Page A'
只复制发生修改的内存页。
不是把整个 Zygote 内存重新复制一遍。
所以:
Zygote
+
fork
+
COW
组合起来可以实现两个重要效果:
App 进程创建更快
+
减少大量重复内存
这一部分下一篇会专门展开。
十九、Zygote 和 Linux fork 联系起来了
如果以后学习 Linux:
fork()
你会发现:
Zygote 本质上大量利用了 Linux 的进程机制。
所以 Android:
App Process
的产生,本质上也离不开:
Linux Process
体系。
这又验证了前面讲过的:
Android
=
Java / Kotlin
+
C / C++
+
Linux Kernel
二十、Zygote 不只是产生普通 App
Zygote 启动后,还有一个非常重要的任务:
创建 system_server 进程。
可以先理解成:
init
↓
Zygote
↓
fork
↓
system_server
之后 system_server 进入:
com.android.server.SystemServer
开始建立 Android Framework 系统服务体系。
二十一、第六棒:system_server
终于到 Android 系统最重要的进程之一:
system_server
大量 Android Framework 核心系统服务都运行在:
system_server
进程中。
例如:
AMS
ATMS
PMS
WMS
PowerManagerService
DisplayManagerService
...
所以可以把它理解成:
Android Framework 系统服务的大本营。
二十二、SystemServer 和 system_server 要区分
这两个名字非常容易混。
system_server
是:
Linux Process
也就是:
进程名
=
system_server
SystemServer
是:
Java Class
即:
com.android.server.SystemServer
负责初始化并启动大量 System Service。
所以:
Zygote
↓
fork
↓
system_server 进程
↓
执行 SystemServer.main()
↓
启动大量系统服务
这条关系一定要搞清楚。
二十三、SystemServer 开始启动 Android 核心服务
SystemServer 启动以后,会开始构建整个 Framework 服务体系。
例如会分阶段启动:
Bootstrap Services
Core Services
Other Services
里面逐渐出现:
ActivityManagerService
PackageManagerService
PowerManagerService
DisplayManagerService
WindowManagerService
ActivityTaskManagerService
...
所以可以理解:
SystemServer
│
├── AMS
├── PMS
├── WMS
├── ATMS
├── PowerManagerService
└── ...
Android 这时候才开始真正变成:
我们熟悉的 Android Framework 系统。
二十四、为什么 SystemServer 这么重要?
因为没有这些 Service:
App 不知道怎么启动
Package 不知道怎么管理
Window 不知道怎么显示
Power 不知道怎么管理
Activity 不知道怎么调度
所以:
Linux Kernel 启动
只是:
Linux 活了。
而:
SystemServer + System Services 启动
才越来越接近:
Android 活了。
二十五、普通 App 进程怎么产生?
这里把角色再理一次。
init
↓
启动 Zygote
然后:
Zygote
↓
fork system_server
以后系统需要启动普通 App:
system_server
↓
发现需要 App Process
↓
请求 Zygote
↓
Zygote fork
↓
App Process
所以:
system_server 负责决定"需要启动哪个 App",Zygote 负责真正创建 App 进程。
可以把 Zygote 理解成:
Android Java/ART 进程生产工厂。
二十六、现在 Launcher 还没出来
到:
SystemServer
启动了一大堆服务之后:
Activity 系统
Package 系统
Window 系统
Input 系统
等逐渐准备完成。
这时候 Android 才真正具备启动 App 的基础能力。
接下来就会出现:
Launcher
也就是我们平时看到的:
Android 桌面。
二十七、第七棒:Launcher
Launcher 本质上是什么?
这点 App 开发者非常容易理解:
Launcher 本质上也是一个 Android 应用。
只是它非常特殊。
它承担:
桌面
App 图标
Workspace
应用入口
Home
等功能。
二十八、Launcher 为什么叫 Home?
Android 中有:
HOME Activity
这个概念。
一个应用可以通过相关 Intent Filter 成为 Home 应用候选。
所以我们按下:
Home
键之后,系统最终回到的其实就是:
Home Activity / Launcher。
因此:
Launcher
≈
默认 Home App
是非常好理解的入门模型。
二十九、是谁启动 Launcher?
不是:
init
直接启动 Launcher。
也不是:
Zygote
自己决定启动桌面。
而是当 Framework 系统逐渐 ready 后:
SystemServer
↓
System Services Ready
↓
AMS / ATMS
↓
找到 Home Activity
↓
启动 Launcher
所以 Launcher 的启动已经属于:
Android Framework / Activity 管理体系
负责的事情了。
三十、那 Launcher 进程怎么创建?
假设 Launcher 进程还不存在:
AMS / ATMS
↓
需要 Launcher
↓
需要创建 Launcher Process
↓
请求 Zygote
↓
Zygote fork
↓
Launcher Process
↓
Launcher Activity
这里就形成了闭环:
SystemServer
↓
决定启动 App
Zygote
↓
负责创建进程
三十一、终于看到桌面
当:
Launcher Activity
真正启动,并完成:
Window
Surface
绘制
以后:
用户终于看到了 Android 桌面。
从用户视角:
按开机键
↓
Logo
↓
开机动画
↓
锁屏 / Launcher
可能只是几秒或者十几秒。
但背后已经完成:
Bootloader
Kernel
文件系统
init
Native Service
ART
Zygote
SystemServer
System Services
App Process
Window
Graphics
一整套复杂启动流程。
三十二、所以 Android 开机不是"启动一个程序"
普通 App:
点击图标
↓
启动一个应用
Android 开机:
不是:
启动 Android.exe
而是:
一层一层建立整个操作系统环境
从:
硬件
一路构建:
Linux
再构建:
Android Native
再构建:
ART / Framework
最后才能:
运行 App
三十三、架构图和启动流程不要混
第四篇讲:
Android 系统有哪些层。
也就是:
App
↓
Framework
↓
System Service
↓
Native / HAL
↓
Kernel
↓
Hardware
这是:
系统架构图。
而这一篇:
Bootloader
↓
Kernel
↓
init
↓
Zygote
↓
SystemServer
↓
Launcher
讲的是:
时间顺序 / 启动流程。
一个回答:
Android 由什么组成?
一个回答:
Android 怎么启动起来?
三十四、把两张图放在一起
Android 系统架构
Application
↓
Framework
↓
System Services
↓
Native / HAL
↓
Kernel
↓
Hardware
Android 启动过程
Boot ROM
↓
Bootloader
↓
Kernel
↓
init
↓
Zygote
↓
system_server
↓
System Services
↓
Launcher
以后学习系统层,这两张图会反复出现。
三十五、第五篇最值得记住的三个人
这一篇如果最后只记三个东西:
init
Android 用户空间启动总管
主要偏:
Linux / Native 世界
Zygote
Android Java/ART 进程底座
+
进程生产工厂
主要负责:
准备 Runtime
预加载公共环境
fork system_server
fork App Process
SystemServer
Android Framework 系统服务启动中心
负责:
启动 AMS
启动 PMS
启动 WMS
启动 ATMS
...
所以:
init
=
用户空间启动总管
Zygote
=
Java/ART 进程工厂
SystemServer
=
Framework 服务启动中心
三十六、为什么不让 init 直接启动每个 App?
既然:
init
能启动进程。
为什么不:
init
↓
App A
init
↓
App B
init
↓
App C
?
因为 Android App 需要:
ART
Java Runtime
Framework Class
Android App Runtime
而 Zygote 已经提前准备好了这些环境。
所以:
Native Daemon
很多可以由:
init
直接管理。
而:
Android Java / Kotlin App Process
通常通过:
Zygote
产生。
三十七、init 和 Zygote 可以这样区分
init
偏:
Linux / Android Native 世界
负责:
Android 用户空间初始化
挂载
属性
Native Service
启动 Zygote
Zygote
偏:
ART / Java 世界
负责:
准备 Runtime
预加载 Framework
fork system_server
fork App Process
于是:
Kernel
↓
init
↓
Native 世界
↓
Zygote
↓
ART / Java 世界
这个理解非常好用。
三十八、为什么手机开机时会看到开机动画?
Android 启动过程中通常还会存在:
BootAnimation
也就是:
开机动画。
因为从:
Kernel
启动到:
Launcher
真正 ready,中间需要时间。
总不能让用户一直看到黑屏。
所以系统会在 Framework 完全启动完成之前显示开机动画。
第一阶段知道存在即可。
三十九、init 自身其实也有多个阶段
以后真正深入启动流程,会发现:
init
本身也不是一句:
启动 init
就结束。
现代 Android init 还会经历类似:
First Stage Init
↓
SELinux Setup
↓
Second Stage Init
第二阶段真正跟启动源码的时候再学。
现在不用深入。
四十、init 还存在很多 Trigger
以后看:
init.rc
会遇到:
early-init
init
late-init
early-fs
fs
post-fs
post-fs-data
zygote-start
boot
这些东西。
现在只需要产生一个印象:
init 不是简单从上到下执行一个 shell 脚本,而是有自己的事件、Trigger 和 Service 管理机制。
第二阶段再展开。
四十一、第一阶段不要开始啃源码
这一篇看完,不要马上:
打开 init.rc
打开 init.cpp
打开 ZygoteInit.java
打开 SystemServer.java
然后一头扎进去。
当前只要求:
看到 init
↓
知道它负责 Android 用户空间启动
看到 Zygote
↓
知道它是 Java/ART 进程底座
看到 system_server
↓
知道它承载大量系统服务
够了。
四十二、这一篇最核心的启动图
手机上电
│
↓
Boot ROM
│
找到启动程序
↓
Bootloader
│
加载 Kernel
↓
Linux Kernel
│
建立操作系统底层环境
↓
init
│
初始化 Android 用户空间
启动 Native Services
│
↓
Zygote
│
初始化 ART / Framework
│
┌──────┴──────┐
↓ ↓
system_server App Process
│
↓
SystemServer
│
┌──────┼─────────────┐
↓ ↓ ↓
AMS WMS PMS
│
↓
System Ready
│
↓
启动 Home / Launcher
│
↓
用户看到 Android 桌面
四十三、和 App 开发联系起来
这时候再看平时的 App:
点击 App 图标
它的前提其实是:
Kernel 已经运行
↓
init 已经运行
↓
Zygote 已经运行
↓
system_server 已经运行
↓
AMS / ATMS / PMS / WMS 已经运行
↓
Launcher 已经运行
然后:
Launcher
↓
请求启动 App
↓
AMS / ATMS
↓
发现 App 进程不存在
↓
请求 Zygote
↓
Zygote fork App Process
↓
进入 ActivityThread
↓
创建 Application
↓
创建 Activity
这已经开始接近我们后面的:
Activity 启动流程。
所有知识最终都会串起来。
四十四、一句话总结
Android 开机可以先粗暴记成:
Bootloader 把 Linux 拉起来,Kernel 把 init 拉起来,init 把 Zygote 拉起来,Zygote 基于预热好的 ART/Framework 环境 fork 出 system_server,SystemServer 再把 Android Framework 服务体系建立起来,最后系统启动 Launcher。
压缩成:
Bootloader
↓
Kernel
↓
init
↓
Zygote
↓
system_server
↓
SystemServer
↓
AMS / WMS / PMS / ...
↓
Launcher
其中:
Zygote
=
预热好的 Java/ART 进程底座
fork
=
基于这个底座产生子进程
COW
=
fork 后先共享内存页,
真正写入时再复制
第一阶段理解到这里已经完全够用。
下一篇:
《Android 系统层扫盲 06:Zygote 到底是什么?为什么 Android App 都喜欢从"受精卵"里 fork 出来?》
下一篇会专门把:
Zygote
↓
ART / Framework 预加载
↓
fork
↓
父进程 / 子进程
↓
COW(Copy-On-Write)
↓
虚拟内存 / 物理内存
↓
App Process
这一整套真正讲透。
重点解决:
为什么 Zygote 能让 Android App 进程启动得更快,同时还能节约大量内存?