Android 启动流程【1】init 进程

863 阅读5分钟

Google AOSP 源码查询网站: cs.android.com/?hl=zh-cn

如果你是一个安装过操作系统(例如安装 Windows 系统或是对 Android 手机进行刷机)的 diy 小能手,在装系统的时候一定接触过类似 BIOS / ROOT 程序的概念。如果你对电脑或手机一无所知,那么你可以思考一个问题:当你按下开机键的时候,设备是如何启动的呢?

简单来说,当按下开机键后,设备开始通电,从硬盘 ROM 的指定位置存放着一段命令代码,他会将启动加载引导程序(Android 是 BootLoader)加载到 RAM 中开始执行。

BootLoader 是 Android 系统的引导程序,用来启动 Android 操作系统。因为 Android 操作系统是基于 Linux 操作系统,所以启动 Android 系统本质上就是启动一个定制化的 Linux 。Linux 启动时,首先要启动 Linux 内核程序。所以 Android 启动时,也会启动一个类似的内核程序。

Android 内核程序会进行一系列初始化操作,例如设置 RAM 、加载驱动等。当它完成系统初始化后,会首先在系统文件中寻找一个名为 init.rc 的文件,这个文件是用来启动 Android 启动的第一个进程 -- init 进程的。

虽然 Android 基于 Linux ,但是 Android 的内核程序会有一些不同之处,以下是 Android 项目对 Linux 内核所做的更改:

  • Binder:Android 特有的进程间通信机制和远程调用方法。
  • Android 共享内存:新的共享内存分配器。
  • 进程内存分配器:用于管理在用户空间和内核空间之间共享的 1 - 16+ M 文件物理上连续的内存区域。
  • logger:logcat 命令的内核支持。
  • 唤醒锁:用于电源管理文件。
  • OOM 处理器:当可用内存变低时,会杀死进程。
  • 警报管理:它让用户空间告诉内核它什么时候想要唤醒。
  • RAM_CONSOLE :允许将内核 printk 消息保存到 RAM 中的缓冲区,以便在内核崩溃后可以在下一次内核调用中查看它们。
  • 用于 ADB 的 USB 小工具驱动程序
  • yaffs2 闪存文件系统

总结一下 Android 操作系统的启动流程:

  1. 加载引导程序 BootLoader 启动电源后,引导芯片代码从预定义的位置开始执行**加载引导程序 BootLoader **到 RAM 中,并开始执行。BootLoader 是 Android 系统的引导程序,用来启动操作系统。引导加载程序是制造商放置锁定和限制的地方。引导加载程序分两个阶段执行。
    • 在第一阶段,它检测 RAM 并加载有助于第二阶段的程序。
    • 在第二阶段,引导加载程序设置网络、内存等,这需要运行 Linux 内核。引导加载程序能够为特定目的向内核提供配置参数或输入。
  2. 启动 Android 内核程序 Android 系统是基于 Linux 操作系统, Android 内核的启动方式与 Linux 内核程序类似,Linux 内核启动会进行如: 设置缓存、被保护存储器、计划列表、加载驱动等一系列操作,内外完成系统预设置后,会首先在系统文件中寻找 init.rc 文件,创建 init 进程,并在 init 进程中处理该文件。
  3. 启动 init 进程 根据 init.cpp 文件去创建 init 进程并执行初始化,主要用来初始化和启动属性服务,也用来启动 Zygote 进程。

初始化进程

init 进程是 Android 系统启动过程中创建的第一个进程,进程号为 1 ,是所有进程的祖宗。 init 进程有两个主要职责:

  1. 挂载目录,如 /sys 、/dev 、/proc 。
  2. 运行 init.rc 脚本。

启动 init 进程,从代码层面上看,就是执行了 system/core/init/init.cpp 中的 main 函数。

main 函数中做了很多事情,主要逻辑是:

  1. 创建和挂载启动所需的文件目录,其中挂载了 tmpfs、devpts、proc、sysfs 和 selinuxfs 共五种文件系统。这些都是系统运行时目录。系统停止时会消失。

  2. 属性初始化,调用 property_init 函数对属性进行初始化。这里的属性后续会与后续属性服务中有联动。

  3. 设置子进程信号处理函数,用于防止 init 进程的子进程成为僵尸进程。系统会在子进程暂停或终止时发出 SIGGHLD 信号,信号处理函数接收信号调用处理逻辑:找到子进程并移除所有子进程的信息,再重新启动该子进程。

僵尸进程:在 Linux/UNIX 系统中,父进程使用 fork 函数创建子进程,在子进程终止后,如果父进程不知道子进程已经终止,这时虽然子进程已经退出了但在系统进程表中还为其保留了一定的信息(如进程号等),这种情况等子进程称之为僵尸进程。系统进程表是一个有限的资源,如果系统进程表被僵尸进程耗尽,系统就可能无法创建新的进程。

  1. 启动属性服务。

  2. 解析并运行 init.rc 文件。

在 Android 8.0 版本后, 对 init.rc 文件进行了拆分,每个服务对应一个 rc 文件。

init.XXX.rc 文件:这里的 XXX 代指不同的服务,是多个非常重要的配置文件。该文件是由 Android 初始化语言 Android Init Language 编写的脚本。例如 Zygote 启动脚本在 init.zygoteXX.rc 中定义,XX 是处理器位数,例如 64 位处理器是 init.zygote64.rc 。

另外,Android 对 init.rc 文件有特定的格式和规则。有关此规则的更多信息,请参见:init.rc 中的内容及其用途。

欢迎关注微信公众号:ToNextLandscape,这里更新更快哦。