Android启动篇 — init原理(二),androidinit
======================================================== ========================================================
= 【原创文章】:参考部分博客内容,学习之余进行了大量的筛减细化分析 = = 【特殊申明】:避讳抄袭侵权之嫌疑,特此说明,欢迎转载! =
======================================================== ========================================================
【前言】
Android启动篇 — init原理(一)中讲解分init进程分析init创建系统目录并挂在相应系统文件、初始化属性域、设置系统属性、启动配置属性服务端等一系列复杂工作,很多工作和知识点跟Linux关系很大,所以没有作过多介绍,而本此对于init.rc的解析则是重中之重,所以单独拿出来进行详细分析。
int main(int argc, char** argv) { /* 01. 创建文件系统目录并挂载相关的文件系统 */ /* 02. 屏蔽标准的输入输出/初始化内核log系统 */ /* 03. 初始化属性域 */ /* 04. 完成SELinux相关工作 */? /* 05. 重新设置属性 */ /* 06. 创建epoll句柄 */ /* 07. 装载子进程信号处理器 */ /* 08. 设置默认系统属性 */ /* 09. 启动配置属性的服务端 */ /* 10. 匹配命令和函数之间的对应关系 */
------------------------------------------------------------------------------------------- // Android启动篇 — init原理(一)中讲解
/* 11. 解析init.rc */ Parser& parser = Parser::GetInstance(); // 构造解析文件用的parser对象 // 增加ServiceParser为一个section,对应name为service parser.AddSectionParser("service",std::make_unique<ServiceParser>()); // 增加ActionParser为一个section,对应name为action parser.AddSectionParser("on", std::make_unique<ActionParser>()); // 增加ImportParser为一个section,对应name为service parser.AddSectionParser("import", std::make_unique<ImportParser>()); parser.ParseConfig("/init.rc"); // 开始实际的解析过程
【正文】
init.rc是一个配置文件,内部由Android初始化语言编写(Android Init Language)编写的脚本,主要包含五种类型语句:Action、Command、Service、Option和Import,在分析代码的过程中我们会详细介绍。
init.rc的配置代码在:system/core/rootdir/init.rc 中
init.rc文件是在init进程启动后执行的启动脚本,文件中记录着init进程需执行的操作。
init.rc文件大致分为两大部分,一部分是以“on”关键字开头的动作列表(action list):
on early-init // Action类型语句 # Set init and its forked children's oom_adj. // #:注释符号 write /proc/1/oom_score_adj -1000 ... ... start ueventd
Action类型语句格式:
on <trigger> [&& <trigger>]* // 设置触发器 <command> <command> // 动作触发之后要执行的命令
另一部分是以“service”关键字开头的服务列表(service list): 如 Zygote
service ueventd /sbin/ueventd class core critical seclabel u:r:ueventd:s0
Service类型语句格式:
service <name> <pathname> [ <argument> ]* // <service的名字><执行程序路径><传递参数> <option> // option是service的修饰词,影响什么时候、如何启动services <option> ...
借助系统环境变量或Linux命令,动作列表用于创建所需目录,以及为某些特定文件指定权限,而服务列表用来记录init进程需要启动的一些子进程。如上面代码所示,service关键字后的第一个字符串表示服务(子进程)的名称,第二个字符串表示服务的执行路径。
值得一提的是在Android 7.0中对init.rc文件进行了拆分,每个服务一个rc文件。我们要分析的zygote服务的启动脚本则在init.zygoteXX.rc中定义。
在init.rc的import段我们看到如下代码:
import /init.${ro.zygote}.rc // 可以看出init.rc不再直接引入一个固定的文件,而是根据属性ro.zygote的内容来引入不同的文件
说明:
从android5.0开始,android开始支持64位的编译,zygote本身也就有了32位和64位的区别,所以在这里用ro.zygote属性来控制启动不同版本的zygote进程。
init.rc位于/system/core/rootdir下。在这个路径下还包括四个关于zygote的rc文件。分别是Init.zygote32.rc,Init.zygote32_64.rc,Init.zygote64.rc,Init.zygote64_32.rc,由硬件决定调用哪个文件。
这里拿32位处理器为例,init.zygote32.rc的代码如下所示:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main # class是一个option,指定zygote服务的类型为main socket zygote stream 660 root system # socket关键字表示一个option,创建一个名为dev/socket/zygote,类型为stream,权限为660的socket onrestart write /sys/android_power/request_state wake # onrestart是一个option,说明在zygote重启时需要执行的command onrestart write /sys/power/state on onrestart restart audioserver onrestart restart cameraserver onrestart restart media onrestart restart netd writepid /dev/cpuset/foreground/tasks
“service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server”
在Init.zygote32.rc中,定义了一个zygote服务:zygote,由关键字service告诉init进程创建一个名为zygote的进程,这个进程要执行的程序是:/system/bin/app_process,给这个进程四个参数:
· -Xzygote:该参数将作为虚拟机启动时所需的参数
· /system/bin:代表虚拟机程序所在目录
· --zygote:指明以ZygoteInit.java类中的main函数作为虚拟机执行入口
· --start-system-server:告诉Zygote进程启动SystemServer进程
接下来,我们回到源码当中,继续分析main函数:
/* 11. 解析init.rc */ Parser& parser = Parser::GetInstance(); // 构造解析文件用的parser对象 // 增加ServiceParser为一个section,对应name为service parser.AddSectionParser("service",std::make_unique<ServiceParser>()); // 增加ActionParser为一个section,对应name为action parser.AddSectionParser("on", std::make_unique<ActionParser>()); // 增加ImportParser为一个section,对应name为service parser.AddSectionParser("import", s