配套系列教学视频链接:
说明
系统:Android10.0
设备: FireFly RK3399 (ROC-RK3399-PC-PLUS)
前言
Android init启动的时候会解析init.rc, 当然还有很多其他rc文件, 在init进程代码中有对应的解析器, 本章节重点介绍init.rc中所有的内容是如何被解析的,理解这个解析逻辑, 有利于你对rc文件中action和service实际的执行逻辑,方便后期根据需求做一些深度定制化。
一, 整体解析逻辑框图
整个解析过程都是面向对象, 有解析器Parser, Action,Command, ActionManger, Service对象, Option对象, ServiceList对象。
二, 解析逻辑
Init在解析RC文件的时候会有如下逻辑:
- 解析以section为单位, section包括import, action, service语句。
- 不同的section有不同的parser解析器,都继承自SectionParser, 每个parser从上往下解析, 有分析开始(ParseSection), 每一行分析(ParseLineSection), 以及结束分析(EndSection/EndFile)。
- ImportParser分析import段落, 将所有的需要导入的文件名拿到, 然后一个一个的分析里面的其他语句。
- ActionParser分析action段落, 每个action段落会构建一个Action对象, 每个Action对象包含了所有的命令对象Command, 由ActionManager负责管理和调度所有Action对象。
- ServiceParsere分析service段落, 每个service段落会构建一个Service对象, 该对象会记录服务对应的可执行文件路径和参数, 根据不同的option来初始化service对象不同的成员。 最终ServiceList进行管理和调度。
对应代码在system/core/init/init.cpp中
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
Parser parser;
// ServiceParser做的事情: 1,首先根据第一行的名字和参数创建出service对象,
// 2,然后根据选项域的内容填充service对象,
// 3.最后将创建出的service对象加入到vector类型的service链表(service_list_)中。
parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, subcontexts));
parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, subcontexts));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
return parser;
}
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
Parser parser = CreateParser(action_manager, service_list);
std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
parser.ParseConfig("/init.rc");
if (!parser.ParseConfig("/system/etc/init")) {
late_import_paths.emplace_back("/system/etc/init");
}
if (!parser.ParseConfig("/product/etc/init")) {
late_import_paths.emplace_back("/product/etc/init");
}
if (!parser.ParseConfig("/product_services/etc/init")) {
late_import_paths.emplace_back("/product_services/etc/init");
}
if (!parser.ParseConfig("/odm/etc/init")) {
late_import_paths.emplace_back("/odm/etc/init");
}
if (!parser.ParseConfig("/vendor/etc/init")) {
late_import_paths.emplace_back("/vendor/etc/init");
}
} else {
parser.ParseConfig(bootscript);
}
}
代码详细过程,我利用思维导图展开了:
所有的解析器都是继承自SectionParser:
class SectionParser {
public:
virtual ~SectionParser() {}
// 一个Section开始需要执行的, 如遇到import, on, service关键词表示开始
virtual Result<Success> ParseSection(std::vector<std::string>&& args,
const std::string& filename, int line) = 0;
// 每个section中的每一行, 除了第一行
virtual Result<Success> ParseLineSection(std::vector<std::string>&&, int) { return Success(); };
//这两个都表示section解析结束之后需要做的事情, Endfile主要针对import
virtual Result<Success> EndSection() { return Success(); };
virtual void EndFile(){};
};
大家感兴趣可以去读一下代码, 读代码只需要去阅读各个SectionParser的以上三个接口,并且按照顺序读就能理解整个逻辑了。
三, 所有Action的执行的先后顺序
启动的过程中,会解析各个Action和Service, 其中Action的执行先后顺序为如下所示:
on SetupCgroups
on early-init
on wait_for_coldboot_done
on MixHwrngIntoLinuxRng
on SetMmapRndBits
on SetKptrRestrict
on KeychordInit
on console_init
on init
on StartBoringSslSelfTest
on MixHwrngIntoLinuxRng
on InitBinder
on queue_property_triggers
on late-init
on early-fs
on fs
on post-fs
on late-fs
on post-fs-data
on zygote-start
on early-boot
on boot
这也只是一个粗略的先后顺序,给大家一个参考。
四,总结
这部分内容主要是让大家理解逻辑, 方便大家去阅读init进程代码。