文章目录
- BootRom
- BootLoader
- Kernel
- init
- init入口函数
- init.rc
- 解析service
- init启动zygote
- 属性服务
- init进程总结
BootRom
当系统上电或复位时,CPU首先执行BootRom中的代码,它是一个小型的固件程序,存储在只读存储器(ROM)中,用于初始化硬件并加载和启动操作系统或引导加载程序(BootLoader)。
BootLoader
为加载Linux Kernel做准备,并最终加载Linux Kernel。
在加载Kernel 前做的准备如下:
检测RAM,并加载一段程序用于后面的准备工作
装载网络、内存模块,建立内存映射,为内核启动做准备
在Android中,BootLoader也即fastboot、厂商的锁业是在这里实现的。
准备工作做好后,启动内核。内核放在/boot分区下。
Kernel
内核启动后,会启动第一个进程
- idle进程(pid=0),又称swapper 进程。idle 进程会初始化进程管理、内存管理,Binder 驱动、相机驱动、Display等硬件驱动。创建init进程、kthreadd进程。
- init 进程(pid=1),是第一个用户空间进程。
- kthreadd 进程(pid=2),是第一个内核空间进程。它始终运行在内核空间,负责所有内核线程的调度与管理。
这三个进程是内核的基础,init进程是Android用户空间的始祖进程,让代码从kernel层运行到native层的代码,然后再通过fork去孵化Java进程的始祖进程zygote,后续的app进程的启动都是由zygote进行fork孵化出来。
我们的操作系统在运行的时候,为了系统的稳定。会将整块内存区域分成两份,一份是内核空间,另一份是用户空间。
- 内核空间:运行操作系统的内核,负责系统资源的管理和调度,处理硬件抽象和硬件接口,以及提供系统调用接口供用户进程调用。
- 用户空间:运行用户应用程序,不能直接访问内核,需要通过系统调用(System Call)间接访问内核提供的服务。
这么设计的目的是:
为了保证系统的安全稳定。如果客户随便点开一个APP,这个APP是一个恶意程序,它修改了你系统运行的某些内存数据,导致你的系统崩溃死机。这用户肯定是不能接受的。
因为我们主要是做Android 开发,所以主要研究init 进程即可。
init
init入口函数
init的入口函数为main,代码如下所示。
system/core/init/init.cpp
init的main方法做了很多事情,我们只需要关注主要的几点
注释1处 调用 property_init来对属性进行初始化
注释2处 启动selinux安全策略
注释3处 调用start_property_service启动属性服务,关于属性服务,后面会讲到。
注释4处 parser.ParseConfig(“/init.rc”)用来解析init.rc。解析init.rc的文件为system/core/init/init_parse.cpp文件
接下来我们查看init.rc里做了什么。
init.rc
init.rc是一个配置文件,内部由Android初始化语言编写(Android Init Language)编写的脚本,它主要包含五种类型语句:
Action、Commands、Services、Options和Import。init.rc的配置代码如下所示。
system/core/rootdir/init.rc
这里只截取了一部分代码,其中#是注释符号。on init和on boot是Action类型语句,它的格式为:
为了分析如何创建zygote,我们主要查看Services类型语句,它的格式如下所示:
需要注意的是在Android 7.0中对init.rc文件进行了拆分,每个服务一个rc文件。我们要分析的zygote服务的启动脚本则在init.zygoteXX.rc中定义,这里拿64位处理器为例,init.zygote64.rc的代码如下所示。
system/core/rootdir/init.zygote64.rc
其中service用于通知init进程创建名zygote的进程,这个zygote进程执行程序的路径为/system/bin/app_process64,后面的则是要传给app_process64的参数。class main指的是zygote的class name为main,后文会用到它。
解析service
接下来我们来解析service,会用到两个函数,一个是ParseSection,它会解析service的rc文件,比如上文讲到的init.zygote64.rc,ParseSection函数主要用来搭建service的架子。另一个是ParseLineSection,用于解析子项。代码如下所示。
system/core/init/service.cpp
注释1处,根据参数,构造出一个service对象,它的classname为”default”。当解析完毕时会调用EndSection:
接着查看AddService做了什么:
注释1处的代码将service对象加入到services链表中。上面的解析过程总体来讲就是根据参数创建出service对象,然后根据选项域的内容填充service对象,最后将service对象加入到vector类型的services链表中。
init启动zygote
讲完了解析service,接下来该讲init是如何启动service,在这里我们主要讲解启动zygote这个service。在zygote的启动脚本中我们得知zygote的class name为main。在init.rc有如下配置代码:
system/core/rootdir/init.rc
其中class_start是一个COMMAND,对应的函数为do_class_start。我们知道main指的就是zygote,因此class_start main用来启动zygote。do_class_start函数在builtins.cpp中定义,如下所示。
system/core/init/builtins.cpp
来查看StartIfNotDisabled做了什么:
system/core/init/service.cpp
接着查看Start方法,如下所示。
通过注释1和2的代码,我们得知在Start方法中调用fork函数来创建子进程,并在子进程中调用execve执行system/bin/app_process,这样就会进入framework/cmds/app_process/app_main.cpp的main函数,如下所示。
frameworks/base/cmds/app_process/app_main.cpp
从注释1处的代码可以得知调用runtime(AppRuntime)的start来启动zygote。
属性服务
Windows平台上有一个注册表管理器,注册表的内容采用键值对的形式来记录用户、软件的一些使用信息。即使系统或者软件重启,它还是能够根据之前在注册表中的记录,进行相应的初始化工作。Android也提供了一个类似的机制,叫做属性服务。
在本文的开始,我们提到在init.cpp代码中和属性服务相关的代码有:
system/core/init/init.cpp
这两句代码用来初始化属性服务配置并启动属性服务。首先我们来学习服务配置的初始化和启动。
属性服务初始化与启动
property_init函数具体实现的代码如下所示。
system/core/init/property_service.cpp
__system_property_area_init函数用来初始化属性内存区域。接下来查看start_property_service函数的具体代码:
注释1处用来创建非阻塞的socket。注释2处调用listen函数对property_set_fd进行监听,这样创建的socket就成为了server,也就是属性服务;listen函数的第二个参数设置8意味着属性服务最多可以同时为8个试图设置属性的用户提供服务。注释3处的代码将property_set_fd放入了epoll句柄中,用epoll来监听property_set_fd:当property_set_fd中有数据到来时,init进程将用handle_property_set_fd函数进行处理。
在linux新的内核中,epoll用来替换select,epoll最大的好处在于它不会随着监听fd数目的增长而降低效率。因为内核中的select实现是采用轮询来处理的,轮询的fd数目越多,自然耗时越多。
属性服务处理请求
从上文我们得知,属性服务接收到客户端的请求时,会调用handle_property_set_fd函数进行处理:
system/core/init/property_service.cpp
注释1处的代码用来检查客户端进程权限,在注释2处则调用property_set函数对属性进行修改,代码如下所示。
property_set函数主要调用了property_set_impl函数:
property_set_impl函数主要用来对属性进行修改,并对以ro、net和persist开头的属性进行相应的处理。到这里,属性服务处理请求的源码就讲到这。
init进程总结
- 创建一些文件夹并挂载设备
- 启动selinux安全策略
- 初始化和启动属性服务
- 解析init.rc配置文件并启动zygote进程
参考资料:
Android系统启动流程(一)解析init进程启动过程
从源码解析-Android系统启动流程概述 init进程zygote进程SystemServer进程启动流程
Android启动流程 Android12源码—— init进程 Android启动流程分析(1)-init进程