Android系统启动流程(一)解析init
进程
前言
作为“Android框架层”这个大系列中的第一个系列,我们首先要了解的是Android系统启动流程,在这个流程中会涉及到很多重要的知识点,这个系列我们就来一一讲解它们,这一篇我们就来学习init进程。
1.init简介
init进程是Android系统中用户空间的第一个进程,作为第一个进程,它被赋予了很多极其重要的工作职责,比如创建zygote(孵化器)和属性服务等。init进程是由多个源文件共同组成的,这些文件位于源码目录system/core/init。本文将基于Android7.0源码来分析Init进程。
2.引入init进程
说到init进程,首先要提到Android系统启动流程的前几步: 1.启动电源以及系统启动
当电源按下时引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序Bootloader到RAM,然后执行。 2.引导程序Bootloader
引导程序是在Android操作系统开始运行前的一个小程序,它的主要作用是把系统OS拉起来并运行。
3.Linux内核启动
内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第一个进程。 4.init进程启动
讲到第四步就发现我们这一节要讲的init进程了。关于Android系统启动流程的所有步骤会在本系列的最后一篇做讲解。
3.init入口函数
init的入口函数为main,代码如下所示。 system/core/init/init.cpp
int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), \ return ueventd_main(argc, argv); }
if (!strcmp(basename(argv[0]), \ return watchdogd_main(argc, argv);
}
umask(0);
add_environment(\
bool is_first_stage = (argc == 1) || (strcmp(argv[1], \ //创建文件并挂载 if (is_first_stage) {
mount(\ mkdir(\ mkdir(\
mount(\ #define MAKE_STR(x) __STRING(x)
mount(\ mount(\ }
open_devnull_stdio(); klog_init();
klog_set_level(KLOG_NOTICE_LEVEL);
NOTICE(\ if (!is_first_stage) {
// Indicate that booting is in progress to background fw loaders, etc.
close(open(\Y | O_CREAT | O_CLOEXEC, 0000)); //初始化属性相关资源 property_init();//1 process_kernel_dt();
process_kernel_cmdline(); export_kernel_boot_props(); } ...
//启动属性服务
start_property_service();//2
const BuiltinFunctionMap function_map; Action::set_function_map(&function_map); Parser& parser = Parser::GetInstance();
parser.AddSectionParser(\ parser.AddSectionParser(\ parser.AddSectionParser(\ //解析init.rc配置文件
parser.ParseConfig(\ ...
while (true) {
if (!waiting_for_exec) {
am.ExecuteOneCommand(); restart_processes(); }
int timeout = -1;
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000; if (timeout < 0) timeout = 0; }
if (am.HasMoreCommands()) { timeout = 0; }
bootchart_sample(&timeout); epoll_event ev;
int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout)); if (nr == -1) {
ERROR(\ } else if (nr == 1) {
((void (*)()) ev.data.ptr)(); } }
return 0; }
init的main方法做了很多事情,我们只需要关注主要的几点,在注释1处调用 property_init来对属性进行初始化并在注释2处的 调用start_property_service启动属性服务,关于属性服务,后面会讲到。注释3处 parser.ParseConfig(“/init.rc”)用来解析init.rc。解析init.rc的文件为system/core/init/init_parse.cpp文件,接下来我们查看init.rc里做了什么。
4.init.rc
init.rc是一个配置文件,内部由Android初始化语言编写(Android Init Language)编写的脚本,它主要包含五种类型语句:
Action、Commands、Services、Options和Import。init.rc的配置代码如下所示。 system/core/rootdir/init.rc
on init
sysclktz 0
# Mix device-specific information into the entropy pool copy /proc/cmdline /dev/urandom copy /default.prop /dev/urandom ...
on boot
# basic network init ifup lo
hostname localhost
domainname localdomain
# set RLIMIT_NICE to allow priorities from 19 to -20 setrlimit 13 40 40 ...
这里只截取了一部分代码,其中#是注释符号。on init和on boot是Action类型语句,它的格式为:
on
为了分析如何创建zygote,我们主要查看Services类型语句,它的格式如下所示:
service
需要注意的是在Android 7.0中对init.rc文件进行了拆分,每个服务一个rc文件。我们要分析的zygote服务的启动脚本则在init.zygoteXX.rc中定义,这里拿64位处理器为例,init.zygote64.rc的代码如下所示。 system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server class main
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
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
其中service用于通知init进程创建名zygote的进程,这个zygote进程执行程序的路径为/system/bin/app_process64,后面的则是要传给app_process64的参数。class main指的是zygote的class name为main,后文会用到它。
5.解析service
接下来我们来解析service,会用到两个函数,一个是ParseSection,它会解析service的rc文件,比如上文讲到的init.zygote64.rc,ParseSection函数主要用来搭建service的架子。