說明
系統:Android10.0
裝置: FireFly RK3399 (ROC-RK3399-PC-PLUS)
前言
Android init啟動的時候會解析init.rc, 當然還有很多其他rc檔案, 在init程序代碼中有對應的解析器, 本章節重點介紹init.rc中所有的内容是如何被解析的,了解這個解析邏輯, 有利于你對rc檔案中action和service實際的執行邏輯,友善後期根據需求做一些深度定制化。
一, 整體解析邏輯框圖
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5SN4IzNzUWM3gjMwATNyMTNzYzX0IjMwcDMyIzLcBTMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
整個解析過程都是面向對象, 有解析器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