第二章 Android 系统启动.md
2.1 init 进程启动过程
init 进程是 Android 系统中用户空间的第一个进程,进程号是 1 。该进程由多个源文件构成,位于 system/core/init 中:
2.1.1 引入 init 进程
Android 启动流程:
-
启动电源,系统启动
加载 BootLoader 到 RAM 中,并开始执行
-
引导程序 BootLoader
把系统 OS 拉起并运行
-
Linux 内核启动
设置缓存,被保护储存器,计划列表以及加载驱动。加载完成后,在系统文件中寻找 init.rc 文件,并启动 init 进程
-
init 进程启动
init 进程主要用来初始化和启动属性服务,也用来启动 Zygote 进程。
2.1.2 init 进程入口函数
init 进程入口文件位于 system/core/init/init.cpp
其中做了许多事情,但我们只需要关注几点:
- 创建和挂在启动所需的文件目录,其中挂载了 tmpfs, devpts, proc, sysfs 和 selinuxfs 五种文件系统,在系统停止时这些目录的会消失
- 调用 property_init 函数对属性进行初始化,调用 start_property_service 函数启动属性服务
- 调用 signal_handler_init 函数用于设置子进程信号处理函数,函数位于 system/core/init/singnal_handler.cpp 中,主要防止 init 进程的子进程成为僵尸进程。系统会在子进程暂停和终时发出 SIGCHLD 信号,而 signal_handler_init 函数接收该信号。
- 解析 init.rc 文件,解析的代码位于 system/core/init/init_parse.cpp 中。
僵尸进程的危害
在 UNIX/Linux 中,父进程使用 fork 创建子进程,在子进程终止后,如果父进程不知道子进程已经终止,则此时子进程的信息依然保留在系统进程表中。如果系统进程表被耗尽,则系统无法创建新的进程。(类似内存泄漏)
2.1.3 解析 init.rc
init.rc 由 Android 初始化语言 (Android Init Language) 编写的脚本,主要包含五种语句:Action, Command, Service, Option 和 Import 。
# system/core/rootdir/init.rc
on init
sysclktz 0
# Mix device-specific information into the entropy pool
copy /proc/cmdline /dev/urandom
copy /system/etc/prop.default /dev/urandom
……
on boot
# basic network init
ifup lo
hostname localhost
domainname localdomain
……
以上只截取一部分,on init 和 on boot 是 Action 类型,格式如下:
on <trigger> [&& <trigger>]* # 设置触发器
<command>
<command> # 动作触发后执行的命令
为了分析如何创建 Zygote,我们主要查看 Service 类型语句,格式如下:
service <name> <pathname> [<argument>]* # <service 名字> <执行程序路径> <传递参数>
<option>
<option> # service 修饰,影响何时,如何启动 service
Android 8.0 中对 init.rc 文件进行了拆分,每个服务对应要给 rc 文件,我们要分析的 Zygote 启动脚本在 init.zygoteXX.rc 中定义,这里以 init.zygote64.rc 文件为例:
# system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
这里通知 init 进程创建名为 zygote 的服务(实际上是子进程),执行程序的路径为 /system/bin/app_process64,之后为参数, class main 指的是 Zygtote 的 classname 为 main 。后面会深入分析。
2.1.4 解析 Service 类型语句
init.rc 中 Action 类型语句由 ActionParser 进行解析,Service 类型语句采用 ServiceParser 进行解析
2.1.5 init 启动 Zygote
这里主要讲解 Zygote 这个 Service 的启动流程,在 Zygote 的启动脚本中,我们看见 Zygote 的 classname 为 main 。在 init.rc 中有如下代码:
# system/core/rootdir/init.rc
on nonencrypted
class_start main # 1
class_start late_start
class_start 是一个 command,对应函数为 do_class_start,最终会解析该文件创建进程并执行对应的函数 。
2.1.6 属性服务
Windows 平台上有一个注册表管理器,注册表的内容采用键值对的形式来记录用户、软件的一些使用信息。即使系统或软件重启,其还是能够根据之前注册表中的记录,进行相应的初始化工作 。Android 也提供了一个类似的服务,叫做属性服务。
init 进程启动时会启动属性服务,并为其分配内存,用来存储这些信息,如果需要直接读取即可。之前我们提到 init.cpp 的 main 函数中与属性服务相关的代码有如下两行:
// system/core/init/init.cpp#main()
property_init(); // 初始化
start_property_service(); // 启动
这里属性服务实际上会启动一个 SocketServer,其他进程通过 Socket 与属性服务进行通讯 。同时这里使用了 epolll 。
Linux 新内核中,epoll 用来替换 select,epoll 是 Linux 内核为处理大批量文件描述符而做了改进的 poll,是 Linux 下多路复用 I/O 接口 select/poll 的增强版本。 epoll 内部使用红黑树来保存事件,select 使用数组。
2.1.7 init 进程启动总结
- 创建和挂载启动所需文件目录
- 初始化和启动属性服务
- 解析 init.rc 配置文件并启动 Zygote 进程
2.2 Zygote 进程启动过程
2.2.1 Zygote 概述
在 init.rc 文件中采用了 Import 类型语句来引入 Zygote 启动脚本,这些脚本都是 Android 初始化语音
import /init.${ro.zygote}.rc
可以看到这里文件名含有变量,其中 ro.zygote 的取值有以下四种:
- init.zygote32.rc
- init.zygote32_64.rc
- init.zygote64.rc
- init.zygote64_32.rc
这些启动脚本都位于 system/core/rootdir 中 。
先来回顾一下 Android 初始化语言中 service 类型的语句:
service <name> <pathname> [ <argument> ]* # <service 名字> <执行程序路径> <参数>
<option>
<option> # 是 service 的修饰词,决定什么时候,如何启动 Service
下面分别介绍以下 Zygote 启动脚本:
-
init.zygote32.rc
表示支持纯 32 位程序,文件内容如下:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main priority -20 user root group root readproc socket zygote stream 660 root system onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart audioserver onrestart restart cameraserver onrestart restart media onrestart restart netd onrestart restart wificond writepid /dev/cpuset/foreground/tasks
进程名字为 zygote,执行程序为 app_process,classname 为 main。如果 audioserver 等进程终止,就需要 restart
-
init.zygote32_64.rc
表示既支持 32 位程序也支持 64 位程序,内容如下:
service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote class main priority -20 user root group root readproc socket zygote stream 660 root system onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart audioserver onrestart restart cameraserver onrestart restart media onrestart restart netd onrestart restart wificond writepid /dev/cpuset/foreground/tasks service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary class main priority -20 user root group root readproc socket zygote_secondary stream 660 root system onrestart restart zygote writepid /dev/cpuset/foreground/tasks
会启动两个 service,其中一个为 zygote,执行程序为 app_process32 ,为主模式,另一个为 zygote_secondary,执行程序为 app_process64,为辅模式。
2.2.3 Zygote 进程启动过程介绍
init 启动 Zygote 时主要是调用 app_main.cpp 的 main 函数中的 AppRuntime 的 start 方法来启动,其时序图如下:
- 创建 AppRuntime 并调用其 start 方法,启动 Zygote 进程
- 创建 Java 虚拟机并为 Java 虚拟机注册 JNI 方法
- 通过 JNI 调用 ZygoteInit 的 main 方法进入 Zygote 的 Java 层
- 通过 registerZygoteSocket 方法创建 SocketServer,并通过 runSelectLoop 方法等待 AMS 的请求来创建新的应用进程
- 启动 SystemServer 进程
2.3 SystemServer 处理过程
SystemServer 进程主要用于创建系统服务,例如 AMS,WMS 和 PMS 。
2.3.1 Zygote 处理 SystemServer 进程
SystemServer 进程创建后,主要进行以下工作:
- 启动 Binder 线程池
- 创建 SystemServiceManager ,类似各种系统服务的微服务注册中心
- 启动各种系统服务
其中各种系统服务分为三类
- 引导服务,主要为 AMS,PMS,PowerManagerServices 等服务
- 核心服务,主要为 DropBoxManagerService,BatteryService,UsageStatsService 和 WebViewUpdateService 服务
- 其他服务,CameraService,AlarmManagerService,VrManagerService 等服务,这些服务都是 SystemService 的派生类
其中其他服务总共有 100 多个,这里只列出部分
因表格较大,这里直接拍照,有需要时在进行记录
2.4 Launcher 启动过程
2.4.1 Launcher 概述
launcher 就是启动器。
2.4.2 Launcher 启动过程介绍
SystemServer 启动过程中会启动 PMS,PMS 启动时会安装系统中已经安装的所有应用(将安装应用的信息或数据从非运行内存中拉入内存中)。在此之前会将 Launcher 应用启动 。
因为启动器实际上也是一个 APP,桌面实际上也是一个 Activity ,因此这里过程可能会和 Activity 启动流程有点像,不过作为启动器还是有些许不同。以下是启动过程时序图:
这里给出进程通讯图:
2.5 Android 系统启动流程
-
启动电源以及系统启动
-
引导程序 BootLoader
-
Linux 内核启动
设置缓存、被保护存储器、计划列表、加载启动。当完成设置时,会在系统中寻找 init.rc 文件并解析,启动 init 进程 进入下一过程。
-
init 进程启动
初始化和启动属性服务,启动 Zygote 进程
-
Zygote 进程启动
创建 Java 虚拟机并未 Java 虚拟机注册 JNI 方法,创建 SocketServer,启动 SystemServer 进程
-
SystemServer 进程启动
启动 Binder 线程池和 SystemServiceManager,启动各种系统服务 。
-
Launcher 启动
AMS 会启动 Launcher,Launcher 启动后,系统启动完毕,用户可使用 Launcher 启动其他 App 。