init 进程启动过程
init进程是Android系统中用户空间的第一个进程,进程号为1,它被赋予了很多重要职责,比如创建 Zygote 和属性服务等。
引入init进程
了解Android系统启动流程的前几步,可以有助于引入init进程:
- 启动电源以及系统启动。当电源按下时,引导芯片代码从预定义的地方(固化在ROM中)开始执行,加载引导程序到RAM中,然后执行。
- 引导程序BootLoader。它是Android操作系统开始运行前的一个小程序,主要作用是把系统OS拉起来。
- Linux 内核启动。linux内核启动完成系统设置后,它首先在系统文件中寻找init.rc,并启动init进程。
- init进程启动。init进程的工作比较多,主要用于初始化、启动属性服务 以及 启动Zygote进程。
init进程入口
在Linux内核加载完成后,首先在系统文件中查找init.rc,并启动init进程。init的main函数中做了很多事情,我们主要了解以下几点:
- 调用property_init 函数对属性初始化,调用 start_property_service函数启动属性服务。
- 调用 signal_handler_init 设置子进程信号处理函数,主要用于防止init进程的子进程成为僵尸进程。为了防止僵尸进程的出现,系统会在子进程暂停和终止的时候发出 SIGCHLD信号,signal_handler_init就是用来接收这个信号的。
僵尸进程:在linux中,父进程使用fork创建子线程,在子线程终止后,如果父进程并不知道子线程终止了,那么还会在系统进程表为它保留一定的信息。僵尸进程主要危害就是占用系统进程表,可能导致系统进程表被耗尽而无法创建新的进程。假设init的子进程Zygote终止了,signal_handler_init 函数会找到Zygote进程并移除所有Zygote进程信息,再重启Zygote。
解析 init.rc
init.rc 是一个配置文,是由Android 初始化语言编写的脚本,为了分析如何创建Zygote,我们主要查看其中的Service类型语句,在Android 8.0 及以后,每个Service 都对应一个rc 文件。init.rc 中定义Service 的格式如下:
service
[ ] * //<service 的名字〉〈执行程序路径〉〈传递参数〉
举个栗子,zygote的Service配置文件就是:
1 | service zygote /system/bin/app_process64 -Xzygote /system/bin -- zygote --startsystem- server |
来大概分析代码意思,Service用于通知 init 进程创建名为 zygote 的进程,这个进程执行程序的路径为 /system/bin/app_process64,其中 class main指的是Zygote 的classname 为 main。后面的代码是要传给 app_process64的参数。
解析Service类型语句
init.rc中Service类型语句使用ServiceParser类来解析,它将init.rc中的service解析生成的Service对象加入到 Service 链表中。
init 启动Zygote
我们来了解init是如何启动Service的,这里主要讲解 Zygote这个Service。前面提到,在Zygote的启动脚本中描述Zygote的classname为main,在init.rc中会遍历 解析Service类型语句 过程生成的Service链表,找到 classname 为main的Zygote,如果Zygote Service 已经运行,则不再启动,否则就调用fork函数创建子进程,并在子进程中调用Service的main函数,Zygote的main函数代码如下:
1 | int main (int argc, char* const argv []) |
从注释1处可以看到调用runtime的start函数启动了 Zygote 。
属性服务
Windows上有注册表管理器以键值对的形式记录用户软件的一些使用信息,即使系统或者软件重启,其还是能够根据之前注册表中的记录进行相应初始化工作。Android中也提供了类似机制,叫做属性服务。init 进程启动时会启动属性服务,并为其分配内存存储这些属性,如果需要这些属性直接读取即可。启动属性服务的主要代码如下:
1 | ... |
由代码可知,首先创建非阻塞的Socket,并对property_set_fd 监听,这样创建的Socket 就成为server,也就是属性服务;listener的参数意味着可以同时为8个试图设置属性的用户服务。最后使用epoll 来监听property_set_fd :当property_set_fd中有数据到来时,init进程将调用handle_property_set_fd函数处理。
epoll是linux下多路复用I/O接口,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU的利用率。
对属性进行修改时,首先判断属性的合法性,之后查找属性,如果属性存在就更新属性值,否则添加属性。
init进程启动总结
主要做了3件事:1、创建和挂载启动所需文件目录 2、启动服务属性 3、解析init.rc ,并启动 Zygote 进程。
Zygote进程启动过程
在Android系统中,DVM(或者ART)、应用程序进程、SystemServer进程等都是由Zygote进程创建的。由于Zygote在启动时会创建 DVM(或者ART),因此其fork的应用程序进程和SystemServer进程可以在内部获取一个 DVM 或者 ART。
在Zygote 中通过 JNI 调用 ZygoteInit(ZygoteInit是由Java编写的)的 main 方法后,Zygote 便进入了Java 框架层,此前没有任何代码进入Java框架层的。即Zygote开创了Java框架层。
ZygoteInit的main方法中主要代码如下:
1 | //frameworks/base/core/java/com/android/internal/os/Zygotelnit.java |
由代码可知,通过 registerServerSocket 方法创建一个Server端的Socket ,这个名为 “zygote” 的Socket 用于等待 ActivityManagerService 请求 Zygote 来创建新的应用程序进程。总结一下,ZygoteInit 的main方法总共做了4件事:
- 创建一个Server端的Socket
- 预加载类和资源
- 启动 SystemServer 进程
- 等待 AMS 请求创建新的应用程序进程
Zygote 进程启动总结
Zygote进程启动共做了以下几件事:
- 创建AppRuntime ,并调用其start方法,启动Zygote 进程
- 创建java虚拟机并未Java虚拟机注册 JNI 方法
- 通过 JNI 调用ZygoteInit 的main函数进入Zygote 的Java 框架层
- 通过 registerServerSocket 创建服务端 Socket ,循环等待AMS 请求来创建新的应用程序进程。
- 启动 SystemServer
SystemServer 处理过程
SystemServer 进程主要用于创建系统服务,如 AMS、WMS、PMS 。在 ZygoteInit.java 中启动了 SystemServer,代码如下:
1 | private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, RuntimeException{ |
由以上代码可知,SystemServer 进程复制了 Zygote 进程的地址空间,因此也会得到Zygote 创建的 server Socket,这个socket对SystemServer 没有用处,因此在代码 1处将其关闭,之后通过 handleSystemServerProcess 方法启动 SystemServer 进程。接下来,在ZygoteInit中创建了 PathClassLoader,并且通过native 方法 ZygoteInit.nativeZygotelnit 启动了Binder线程池,之后进入 SystemServer 的main 方法。
SystemServer 的run 方法中用 SystemServiceManager 启动了 ActivityManagerService、 PackageManagerService 等服务。在PackageManagerService 创建完成后,将其注册到 ServiceManager 中,ServiceManager 用于管理系统中各种Service,用于系统C/S 架构中的Binder 通信机制:Client端要使用某个Service,需要先到 ServiceManager 中查询Service 的相关信息,然后与Service 所在的Server 进程建立通信通路,这样Client就可以使用Service 了。
SystemServer 进程总结
SystemServer 进程被创建后,主要工作:
- 启动Binder 线程池,这样可以与其他进程通信。
- 创建 SystemServiceManager,创建和管理系统服务
- 启动各种服务
Launcher 启动过程
系统启动的最后一步是启动一个应用程序来显示系统中已经安装的应用程序,即 Launcher。Launcher 在启动过程中请求 PackageManagerService 获取系统中已经安装的应用程序信息,并且将信息封装成一个个快捷图标列表显示在系统屏幕上,用户就可以通过点击图标来启动相应的应用程序了。Launcher 的启动过程时序图如下:
启动Launcher的入口方法为AMS 的systemReady 方法,该方法在SystemServer 的startOtherService中被调用,之后调用 ActivityStack 的resumeTopActivityUncheckedLocked 方法,ActivityStack 用于描述Activity 栈的。最终调用到 AMS 的 startHomeActivityLocked 方法,在该方法中,创建了 Launcher 启动所需的 Intent,并且在一系列判断后,将该Intent 的 Action 设置为 Intent.ACTION_MAIN 、Category 为 Intent.CATEGORY_HOME,并且在 Launcher 的AndroidManifest 中也是这么配置的。
经过以上操作,com.android.launcher3.Launcher 的Activity 就成为了主 Activity,此时,如果Launcher 还未启动,AMS 就会调用 ActivityStarter 的 startHomeActivityLocked 来启动 Launcher 。
Android系统启动流程
结合前面几节内容,可以总结出Android系统启动流程:
启动电源以及系统启动
按下电源键,从预定义地方开始执行,加载BootLoader 到RAM。
引导程序BootLoader
主要作用是拉起系统OS。
Linux 内核启动
内核启动,设置缓存、计划表、加载驱动等,之后寻找 init.rc 文件,并启动init 进程。
init 进程启动
初始化和启动属性服务,并启动 Zygote 进程。
Zygote进程启动
创建Java虚拟机,并未Java虚拟机注册 JNI 方法,创建服务端 Socket 循环等待AMS 请求来创建新的应用程序进程
SystemServer 进程启动
启动Binder 线程池 和 SystemServiceManager ,并启动各种服务。
Launcher启动
SystemServer 进程启动的 AMS 会启动 Launcher,Launcher 会将已安装的应用显示到界面上。
用图表示就是: