Android 系统启动流程

Android 系统启动流程分析。

Android 启动流程

通用的 Linux 系统流程如下图(图片来自《Androi内核剖析》):

Android 系统启动流程如下图(图片参考自 Android系统启动流程 | 风中老狼的博客):

android_startup.drawio2

关键代码

  • Linux 内核入口 /init/main.c
  • init 进程,这是第一个用户进程
    • 命令: /sbin/init
    • 代码: /system/core/init/init.cpp
    • 配置:
      • 主配置 - /system/etc/init/hw/init.rc
      • 其他配置 - /{system,system_ext,vendor,odm,product}/etc/init/ 目录下
  • zygote 进程,这是第一个 Java 进程,用于孵化后续的应用进程
    • 命令: /system/bin/app_process
    • 代码:
      • /frameworks/base/cmds/app_process/App_main.cpp
      • /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
  • SystemServer 进程,对外提供 AmS 和 WmS 等 Manager
    • 命令: - /system/bin/app_process
    • 代码:
      • /frameworks/base/core/java/android/app/ActivityThread.java
      • /frameworks/base/services/java/com/android/server/SystemServer.java
  • ServiceManager 进程,管理 Service
    • 命令:/system/bin/servicemanager
    • 代码:- /frameworks/native/cmds/servicemanager.ServiceManager.cpp

代码分析

Linux 内核

内核的入口是 /init/main.c kernel_init() ,最终通过 run_init_process() 启动 init 进程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
noinline void __ref rest_init(void)
{
...
int pid;
/*
* We need to spawn init first so that it obtains pid 1, however
* the init task will end up wanting to create kthreads, which, if
* we schedule it before we create kthreadd, will OOPS.
*/
pid = kernel_thread(kernel_init, NULL, CLONE_FS);
/*
...
/* Call into cpu_idle with preempt disabled */
cpu_startup_entry(CPUHP_ONLINE);
}

static int __ref kernel_init(void *unused)
{
...
if (CONFIG_DEFAULT_INIT[0] != '\0') {
ret = run_init_process(CONFIG_DEFAULT_INIT);
if (ret)
pr_err("Default init %s failed (error %d)\n",
CONFIG_DEFAULT_INIT, ret);
else
return 0;
}
...
}

init 进程

init README.md的描述,init 进程分3个不同的执行阶段:

init.drawio

init 命令的入口是 init/main.cpp main()

1
2
3
4
5
6
7
8
9
10
11
12
13
int main(int argc, char** argv) {
...
if (argc > 1) {
...
if (!strcmp(argv[1], "selinux_setup")) {
return SetupSelinux(argv);
}
if (!strcmp(argv[1], "second_stage")) {
return SecondStageMain(argc, argv);
}
}
return FirstStageMain(argc, argv);
}

3个不同阶段对应的代码如下。这里略去了具体的细节,但从执行流程上可以看到 first stage 和 selinux setup 两个阶段再次执行了 init 命令。

1
2
3
4
5
6
7
int FirstStageMain(int argc, char** argv) {
...
const char* path = "/system/bin/init";
const char* args[] = {path, "selinux_setup", nullptr};
execv(path, const_cast<char**>(args));
...
}
1
2
3
4
5
6
7
int SetupSelinux(char** argv) {
...
const char* path = "/system/bin/init";
const char* args[] = {path, "second_stage", nullptr};
execv(path, const_cast<char**>(args));
...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int SecondStageMain(int argc, char** argv) {
...
ActionManager& am = ActionManager::GetInstance();
...
am.QueueEventTrigger("early-init");

// Trigger all the boot actions to get us started.
am.QueueEventTrigger("init");
// Don't mount filesystems or start core system services in charger mode.
std::string bootmode = GetProperty("ro.bootmode", "");
if (bootmode == "charger") {
am.QueueEventTrigger("charger");
} else {
am.QueueEventTrigger("late-init");
}
...
}

Zygote 进程

zygote.drawio

1
2
3
4
service zygote /system/bin/app_process64 -Xzygote 
/system/bin --zygote
--start-system-server
--socket-name=zygote
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int main(int argc, char* const argv[])
{
...
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
...
bool startSystemServer = false;
...
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
}
...
}
...
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
}
...
}
  • core/java/com/android/internal/os/ZygoteInit.java - platform/frameworks/base - Git at Google
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46

    public static void main(String[] argv) {
    ZygoteServer zygoteServer = null;
    ...
    Runnable caller;
    try {
    boolean startSystemServer = false;
    String zygoteSocketName = "zygote";
    ...
    boolean enableLazyPreload = false;
    for (int i = 1; i < argv.length; i++) {
    if ("start-system-server".equals(argv[i])) {
    startSystemServer = true;
    } else if ("--enable-lazy-preload".equals(argv[i])) {
    enableLazyPreload = true;
    }
    }

    if (!enableLazyPreload) {
    ...
    preload(bootTimingsTraceLog);
    ...
    }
    zygoteServer = new ZygoteServer(isPrimaryZygote);
    if (startSystemServer) {
    Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
    // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
    // child (system_server) process.
    if (r != null) {
    r.run();
    return;
    }
    }

    ...
    // The select loop returns early in the child process after a fork and
    // loops forever in the zygote.
    caller = zygoteServer.runSelectLoop(abiList);
    ...
    }
    // We're in the child process and have exited the select loop. Proceed to execute the
    // command.
    if (caller != null) {
    caller.run();
    }
    }

FAQ

servicemanager 和 zygote 进程的先后顺序

看下图可知,

  • init 阶段启动 servicemanager 进程
  • late-init 阶段启动 zygote 进程

init.drawio

所以 servicemanager 进程先于 zygote 进程启动

servicemanager 进程先于 zygote 进程启动的原因

(以下内容来自 GPT-4o 对问题 “servicemanager 进程 和 zygote 进程,哪个先被启动” 的回答)

在 Android 系统中,servicemanager 进程会在 zygote 进程之前被启动。这是因为 servicemanager 进程是 Android 系统中非常重要的一部分,负责管理系统服务的注册和调用,包括跨进程通信和系统服务的绑定。

具体的启动顺序如下:

  1. servicemanager 进程启动:在 Android 系统启动过程中,首先会启动 servicemanager 进程。servicemanager 是 Android 中的 Binder IPC(Inter-process Communication,进程间通信)机制的守护进程,用于管理系统服务的注册和调用。

  2. zygote 进程启动:接着,zygote 进程会被启动。zygote 进程作为孵化器进程,负责预加载常用的 Java 类和系统资源,以加速应用程序的启动。

通过这种启动顺序,servicemanager 进程首先被启动可以确保系统服务的注册和通信机制在系统启动之初就已经准备就绪,为后续应用程序进程的启动提供了基础。而 zygote 进程的启动则利用了 servicemanager 进程提供的系统服务注册功能,从而更高效地加载应用程序。

因此,servicemanager 进程在 Android 系统启动时是比 zygote 进程更早被启动的重要组件之一。

Android 的 init 命令有什么不同

传统 Linux 发行版中的 /sbin/init 通常是链接到 SystemV init 或 systemd 系统,这些系统是为通用计算环境设计的,提供了更复杂的服务管理和系统初始化特性

Android 的 init 是专门为移动设备环境设计的,它主要是挂载文件系统、加载 SELinux(可选)、解析并执行 init.rc 脚本并重启某些服务

参考