0
点赞
收藏
分享

微信扫一扫

Android系统10 RK3399 init进程启动(四十二) init.rc文件解析逻辑


说明

系统:Android10.0

设备: FireFly RK3399 (ROC-RK3399-PC-PLUS)

前言

Android init启动的时候会解析init.rc, 当然还有很多其他rc文件, 在init进程代码中有对应的解析器, 本章节重点介绍init.rc中所有的内容是如何被解析的,理解这个解析逻辑, 有利于你对rc文件中action和service实际的执行逻辑,方便后期根据需求做一些深度定制化。

一, 整体解析逻辑框图

Android系统10 RK3399 init进程启动(四十二) init.rc文件解析逻辑_Android ROM开发


整个解析过程都是面向对象, 有解析器Parser, Action,Command, ActionManger, Service对象, Option对象, ServiceList对象。

二, 解析逻辑

Init在解析RC文件的时候会有如下逻辑:

  1. 解析以section为单位, section包括import, action, service语句。
  2. 不同的section有不同的parser解析器,都继承自SectionParser, 每个parser从上往下解析, 有分析开始(ParseSection), 每一行分析(ParseLineSection), 以及结束分析(EndSection/EndFile)。
  3. ImportParser分析import段落, 将所有的需要导入的文件名拿到, 然后一个一个的分析里面的其他语句。
  4. ActionParser分析action段落, 每个action段落会构建一个Action对象, 每个Action对象包含了所有的命令对象Command, 由ActionManager负责管理和调度所有Action对象。
  5. 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);
}
}

代码详细过程,我利用思维导图展开了: 

Android系统10 RK3399 init进程启动(四十二) init.rc文件解析逻辑_Android启动脚本_02

 所有的解析器都是继承自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进程代码。

举报

相关推荐

0 条评论