Android 系统层扫盲 05:Android 开机后发生了什么?从 Bootloader 到 Launcher

前面四篇,我们已经建立了 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 进程启动得更快,同时还能节约大量内存?

相关推荐
hunterandroid2 小时前
Android 线上卡顿治理:从布局层级到主线程负载的全链路排查
android
恋猫de小郭3 小时前
Dart Skills CLI 1.0 :AI 时代的 Dart 交付支持
android·前端·flutter
2501_916007473 小时前
使用Apple Dashboards显示和自定iOS应用性能指标与数据可视化指南
android·ios·小程序·https·uni-app·iphone·webview
蜡台3 小时前
# 已解决|MySQL 8\.4\.11 密码正确仍报错1045 \(28000\) Access denied 终极修复方案
android·mysql·adb
JMchen1234 小时前
2026年六款主流AI编程工具深度实测:Cursor、Copilot、Claude Code等对比与选型思考
android·kotlin·copilot·ai编程·开发工具·cursor·claude code
mmsx4 小时前
osmdroid 地图实战 05|让地图动起来:三个实时能力 + 六条工程排雷清单
android
码农coding4 小时前
android12 SystemUI组件之StatusBar启动
android
hai_android4 小时前
Kotlin 协程上下文:从 plus 到 CombinedContext,彻底搞懂左偏结构
android·kotlin
淡淡的香烟5 小时前
AndroidKMP之网络请求
android·网络