init進程的一個核心部分,是通過解析rc文件,執行Action和啓動Service。在分析init進程前,有必要先學習rc文件的配置和解析的原理。
初始化rc文件解析相關工具
int main(int argc, char** argv) {
...
// 設置Action內建函數跳轉表
const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);
// 創建供應商子進程
subcontexts = InitializeSubcontexts();
// ActionManager實例, 維護rc文件解析的Action數據
ActionManager& am = ActionManager::GetInstance();
// ServiceList實例, 維護rc文件解析的Service數據
ServiceList& sm = ServiceList::GetInstance();
// 開始解析RC文件
LoadBootScripts(am, sm);
...
}
-
BuiltinFunctionMap
Action數據的內建函數映射表,維護了Action數據中,Command的命令函數映射關係和目標函數配置。例如 /system/core/logd/logd.rc 中:
chmod 0644 /dev/event-log-tags
Commond的命令是
chmod
,對應參數爲0644
,/dev/event-log-tags
。在BuiltinFunctionMap中的映射配置爲:// chmod: Key, 命令名稱 // {2, 2, {}}: Value, FunctionInfo, 命令映射的函數信息 // 參數1: 最少參數量,即參數量下限 // 參數2: 最多參數量,即參數量上限 // 參數3: Function, 具體函數和執行環境 // {true, do_chmod}: // 參數1: 是否需要在vendor_init域的子進程中運行,SELinux相關 // 參數2: 具體需要調用的方法 {"chmod", {2, 2, {true, do_chmod}}},
-
subcontexts
init子進程集合。
/system/core/init/subcontext.cppconst std::string kVendorContext = "u:r:vendor_init:s0"; const char* const paths_and_secontexts[2][2] = { {"/vendor", kVendorContext.c_str()}, {"/odm", kVendorContext.c_str()}, };
通過分析源碼,subcontexts對應2個子進程,SELinux context都爲
"u:r:vendor_init:s0"
。
目標函數將根據BuiltinFunctionMap的配置,運行在init進程或上述init子進程中。這個設計,主要解決供應商自己的初始化邏輯引入的安全風險,針對性的引入權限收窄的vendor_init域子進程,供給供應商運行自己的初始化邏輯。
參考資料:
供應商 init | Android 開源項目 | Android Open Source Project (google.cn) ActionManager
用於維護解析後的Action數據鏈表ServiceList
用於維護解析後的Service數據鏈表
解析RC文件
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("/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);
}
}
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
Parser parser;
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;
}
通過CreateParser
, 創建了Parser
解析器對象,其解析規則如下:
匹配項 | 解析器 | 示例 |
---|---|---|
service |
ServiceParser |
service ueventd /sbin/ueventd |
on |
ActionParser |
on early-init |
import |
ImportParser |
import /init.${ro.zygote}.rc |
然後開始執行解析過程
- 設備有定義
ro.boot.init_rc
屬性,直接加載屬性配置的rc文件。 - 設備沒定義
ro.boot.init_rc
屬性,加載/init.rc
文件。然後嘗試加載/system/etc/init
,/vendor/etc/init
,/odm/etc/init
。加載失敗時,則把文件路徑加入late_import_paths
隊列,延後加載。
最後調用Parser
解析器的ParseConfig
函數執行解析。