Android 基础知识¶
本文档收集一些理论性知识,较为零碎,但是最终编织成一张大网。
实践固然能极快的获得成就感,但唯有理论的积累才能让你走得更远。
Android 系统分层架构与启动流程¶
相关链接
Android 是一个基于 Linux 内核的复杂操作系统。其启动过程是一个从硬件加电到显示应用界面的分层、接力过程。
1. 系统启动层¶
-
Boot ROM (引导只读存储器)
- 当按下电源键时,CPU 首先会执行固化在 ROM 中的一小段代码。
- 它会进行基本的硬件检查,然后找到并加载下一阶段的引导程序(Bootloader)到 RAM 中。
-
Bootloader (引导加载程序)
- Bootloader 负责初始化更多的硬件(如内存、闪存)。
- 最重要的是将 Android 的核心Linux Kernel从闪存加载到 RAM 中,然后跳转到内核代码开始执行。
2. 内核层¶
- Linux Kernel (Linux 内核)
- 这是 Android 系统的核心。内核启动后,它会接管 CPU,并开始初始化各种驱动程序(如显示、键盘、Wi-Fi)和核心系统功能(如进程管理、内存管理)。
- 内核启动的最后一步,是在用户空间(User Space)中启动第一个进程,即
init进程。
3. 原生用户空间 (Native User Space)¶
init进程init是 Android 系统中的第一个进程(PID 1),是所有其他用户空间进程的“祖先”。- 它会解析
.rc结尾的初始化脚本文件(例如init.rc)。 - 根据这些脚本,
init进程会启动系统运行所需的各种原生服务(Daemons),例如logd(日志服务)、vold(卷管理服务)等。 - 启动了至关重要的进程:
Zygote。
4. Java 框架层 (Framework)¶
-
Zygote(受精卵) 进程- 核心功能: 启动 Java 虚拟机 (JVM/ART),预加载 Android 框架的核心 Java 类库和系统资源。
- 通过
fork自身来创建新的进程。由于核心类库已预加载,可以直接继承给App,这使得 App 的启动速度极快。这个过程又称为“孵化”。 Zygote启动后首先会孵化出System Server进程。
-
System Server(系统服务进程)System Server是 Android 框架的核心。这是系统中第一个运行的 Java 进程。- 它负责启动和管理所有核心的系统服务。
System Server启动完成后,Android 系统真正“准备就绪”,并会发送BOOT_COMPLETED广播,同时启动 Launcher(桌面应用)。
5. 应用层 (App)¶
- App (应用程序) 进程
- 当点击一个应用时,Launcher 会通知
Activity Manager Service(在System Server进程中)。 AMS会检查该应用是否已有进程,如果没有,它会请求Zygote进程。Zygote收到请求后,会孵化出一个继承了Zygote预加载的虚拟机和核心资源的子进程,即为该应用进程,然后加载应用代码,启动应用的Activity。
- 当点击一个应用时,Launcher 会通知
Android 系统交互机制¶
-
SysCall (System Call - 系统调用)
- 这是用户空间(包括
init、Zygote、App)与 Linux 内核 交互的唯一桥梁。 - 当 App 需要访问硬件(如读写文件、打开摄像头、发送网络数据)时,它不能直接操作,必须通过 SysCall 向内核发出请求,由内核代为完成,以保证系统安全和稳定。
- 这是用户空间(包括
-
JNI (Java Native Interface - Java 本地接口)
- 这是 Android 中 Java 代码与 C/C++(Native)代码交互的桥梁。
- Android 的框架层(如
System Server)和应用(App)主要是用 Java 编写的,但它们需要调用底层的系统功能(例如图形渲染、硬件访问),这些功能通常由 C/C++ 实现。 - 流程: Java 代码 (App) → JNI → C/C++ (Native 库) → SysCall → Linux 内核。
-
Binder (进程间通信)
- 这是 Android 特有的高性能进程间通信(IPC)机制。
- 它在 Android 中无处不在:
- App 与
System Server(AMS, PMS 等)之间的通信。 - App 与 App 之间的通信。
- App 与
Zygote¶
参考资料
在 Android 启动流程中,我们已经简要介绍了 Zygote 进程的作用。大名鼎鼎的 Xposed 框架正是通过 Hook Zygote 来实现对所有 App 的代码注入。 因此我们来从代码仔细深入了解下 Zygote 的工作原理。
无特殊说明,以下源码均基于 Android 16.0.0_r2 源码 分析
Zygote 启动流程¶
1. init 进程启动 app_process¶
按照我们之前的介绍,Zygote 是由 init 进程启动的。我们可以在 init.rc 中找到对应启动:
可以看出,zygote 服务会启动 /system/bin/app_process(64) 进程,附带的参数是--zygote --start-system-server。
2. app_process 启动 ZygoteInit¶
源码网站上并没有这个文件,我从 Android 9 的实体机中提取了这个文件,是一个 ELF 文件,IDA 启动。
| /system/bin/app_process64 main() | |
|---|---|
com.android.internal.os.ZygoteInit。
app_process 对应的源码是 app_main.cpp
可以看出,在--zygote --start-system-server参数下,最终会启动Java层的 com.android.internal.os.ZygoteInit 类,并将start-system-server放在arg中传入。
应用进程孵化流程¶
1. ZygoteInit:承上启下¶
我们回到Android 16.0.0_r2源码中查看这个类:
ZygoteInit 在完成预加载、孵化 SystemServer 后,会通过 zygoteServer.runSelectLoop 方法启动一个循环,持续监听来自 AMS 的创建新应用进程的请求。
2. Java 层:请求处理与 Fork¶
当 Zygote 收到新进程创建请求时,处理流程如下:
-
ZygoteServer监听请求runSelectLoop方法负责监听和管理请求,并将具体的处理工作交给ZygoteConnection。 -
ZygoteConnection处理连接ZygoteConnection负责解析请求参数,并调用Zygote.forkAndSpecialize来执行fork操作。 -
Zygote执行 ForkforkAndSpecialize方法会调用native方法nativeForkAndSpecialize来真正执行fork。我们可以对比一下孵化普通应用进程 (
forkAndSpecialize) 和孵化SystemServer(forkSystemServer) 的代码,它们最终都依赖native方法。
3. Native 层:执行 Fork¶
Java 层的 native 方法最终会调用到 C++ 层的 ForkCommon 函数来完成进程的创建。
可以看到,它们都调用了 ForkCommon 方法。至此我们可以全心投入常规进程的孵化分析,而 SystemServer 的差异我们放在后续讨论。
我们来看 ForkCommon 的实现方法,我们先沿着进程的创建这条主线来一路看下去:
ForkCommon 调用了 fork() 方法,并且接受了返回的 pid。
4. libc 层:从 Native 陷入 内核态¶
这里的 fork 方法来源于 libc。其实这里已经是 linux 通用的系统调用流程了,但是既然到这里,就一路往下吧。
libc(C标准库)可以被看作是应用程序与 Linux 内核之间的一个“翻译层”或“接口层”。
调用的 libc 的 clone 方法:
在这里我们看到了是调用了 syscall 方法。在深入就是内核的事情了,这里我们就不继续深入了。
下面我们来看看 System Server 的孵化以及正常应用的启动流程。
System Server¶
应用启动流程¶
1. 为什么你能点开一个 App?¶
我们每天看到的桌面实际上也是一个 App,叫做 Launcher(启动器),位于 /packages/apps/Launcher3/。
图标点击事件由 BubbleTextView 或 ShortcutAndWidgetContainer 传递到 Launcher,再走 startActivitySafely() → AMS。