之前整理过Android 7的初始化顺序,已经过时了,基于Android 11重新整理下并发布,方便查看与rc里初始化顺序有关的问题和bug.
[Android 11]
代码可看
http://aosp.opersys.com/xref/...
初始化语言可看
/system/core/init/README.md
或者
https://blog.csdn.net/u010753159/article/details/51981121
这里不讲这些, 也不分析init代码.
init rc 总体初始化顺序
FirstStageMain()
|
v
SetupSelinux()
|
v
SecondStageMain()
|
v
+----------------------+
| SetupCgroups |
| SetKptrRestrict |
| TestPerfEventSelinux |
| early-init +--> mount_all fstab.persist --early // hardware/google/pixel/common/init.pixel.rc
|wait_for_coldboot_done|
| MixHwrngIntoLinuxRng |
| SetMmapRndBits |
| KeychordInit |
| init |
| MixHwrngIntoLinuxRng |
| | |
| bootmode == "charger"|
| / \ |
| + + |
| charger late-init +--> +--------trigger---------+
| \ / | | early-fs |
| + | | fs +--> mount_all fstab.firmware --early
| | | | late-fs +--> +--------------------------------+
|queue_property_triggers| | post-fs | |mount_all fstab.firmware --late +--> queue_fs_event --> trigger nonencrypted
+-----------------------+ | post-fs-data | | class_start early_hal | |
|load_persist_props_action| +--------------------------------+ +-class_start-+
| load_bpf_programs | | main |
| zygote-start | | late_start |
|firmware_mounts_complete| +-------------+
| early-boot | ^
| boot +--> +-class_start-+ |
+------------------------+ | hal | |
| | core | |
| + ------------+ |
+------------------------------------------执行完 on boot后才执行-------------------- -+
on late-init 和 late-fs 启动具体代码
/system/core/rootdir/init.rc
on late-init
trigger early-fs
# Mount fstab in init.{$device}.rc by mount_all command. Optional parameter
# '--early' can be specified to skip entries with 'latemount'.
# /system and /vendor must be mounted by the end of the fs stage,
# while /data is optional.
trigger fs
trigger post-fs
# Mount fstab in init.{$device}.rc by mount_all with '--late' parameter
# to only mount entries with 'latemount'. This is needed if '--early' is
# specified in the previous mount_all command on the fs stage.
# With /system mounted and properties form /system + /factory available,
# some services can be started.
trigger late-fs
# Now we can mount /data. File encryption requires keymaster to decrypt
# /data, which in turn can only be loaded when system properties are present.
trigger post-fs-data
# Load persist properties and override properties (if enabled) from /data.
trigger load_persist_props_action
# Should be before netd, but after apex, properties and logging is available.
trigger load_bpf_programs
# Now we can start zygote for devices with file based encryption
trigger zygote-start
# Remove a file to wake up anything waiting for firmware.
trigger firmware_mounts_complete
trigger early-boot
trigger boot
// late-fs
on late-fs
# Ensure that tracefs has the correct permissions.
# This does not work correctly if it is called in post-fs.
chmod 0755 /sys/kernel/tracing
chmod 0755 /sys/kernel/debug/tracing
# HALs required before storage encryption can get unlocked (FBE/FDE)
class_start early_hal
early_hal类服务有:
early_hal
/system/hardware/interfaces/suspend/1.0/default/[email protected]
/system/core/trusty/keymaster/3.0/[email protected]
/system/core/trusty/keymaster/4.0/[email protected]
注意:
QueueEventTrigger和QueueBuiltinAction都是将其放放到event_queue_里,等轮到他时再执行
/system/core/init/action_manager.cpp
void ActionManager::QueueEventTrigger(const std::string& trigger) {
auto lock = std::lock_guard{event_queue_lock_};
// 加入到 event_queue_队列里
event_queue_.emplace(trigger);
}
......
void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
auto lock = std::lock_guard{event_queue_lock_};
auto action = std::make_unique(true, nullptr, "", 0, name,
std::map{});
action->AddCommand(std::move(func), {name}, 0);
// 加入到 event_queue_队列里
event_queue_.emplace(action.get());
actions_.emplace_back(std::move(action));
}
也就是说在
on late-fs --> mount_all --> trigger nonencrypted
的时候,并没有执行 on nonencrypted
而是等到之前队列里的trigger执行完后才执行它, 我们看到 on late-init
时加了一堆的trigger,
最后个是boot, 所以(如果中间没新加入的) on nonencrypted
是在 on boot
之后才执行的, 并不是在 on late-fs
之后执行的.
也即 class main
和class late_start
在 on boot后执行
on late-init
trigger early-fs
trigger fs
trigger post-fs
trigger late-fs
....
trigger boot
// on boot后执行
on nonencrypted
class_start main
class_start late_start
imports 与 目录里的相同Action执行顺序
我们知道,不同rc文件文件里是可以有相同的action的,init程序在解析时会将这些不同文件的action合并,
那这些合并后的action执行顺序是咋样的?
BTW, 解析rc文件有兴趣的可以看看, 相当于是个小型的语法解析.
代码在 /system/core/init/parser.cpp ParseData()
具体的说,就是
- init.rc 与 其 import导入的文件里相同action执行顺序
- /{system,vendor,odm}/etc/init/ 里相同action执行顺序
这个其实在/system/core/init/README.md
Imports 章节都有描述的, 建议仔细的看看.
简单来说,其先后顺序为
init.rc -> init.rc里的import -> import 本身 -> import的import -> /system/etc/init/ -> /vendor/etc/init/ -> /odm/etc/init/
^ ^
+--------递归-----+
README.md用伪代码里描述如下:
fn Import(file)
Parse(file)
for (import : file.imports)
Import(import)
Import(/init.rc)
Directories = [/system/etc/init, /vendor/etc/init, /odm/etc/init]
for (directory : Directories)
files =
for (file : files)
Import(file)
具体的代码可看下
/system/core/init/init.cpp
SecondStageMain() --> LoadBootScripts()
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("/system/etc/init/hw/init.rc");
if (!parser.ParseConfig("/system/etc/init")) {
late_import_paths.emplace_back("/system/etc/init");
}
// late_import is available only in Q and earlier release. As we don't
// have system_ext in those versions, skip late_import for system_ext.
parser.ParseConfig("/system_ext/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);
}
}
从代码里我们可看到,如果指定了ro.boot.init_rc
就用指定的,
否则就用默认那几个目录的, 其中还有对 /system/etc/init/hw/init.rc
和 system_ext
目录支持.
图就不画了,看看代码就好.
- 对同一个目录下文件解析, 其实是按升序解析的
所以如果同一目录下有相同的action, 要按照文件名升序先后执行的.
代码如下
/system/core/init/parser.cpp
bool Parser::ParseConfigDir(const std::string& path) {
LOG(INFO) << "Parsing directory " << path << "...";
......
std::vector files;
// 获取目录下文件
while ((current_file = readdir(config_dir.get()))) {
// Ignore directories and only process regular files.
if (current_file->d_type == DT_REG) {
std::string current_path =
android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
files.emplace_back(current_path);
}
}
// 按升序排序
// Sort first so we load files in a consistent order (bug 31996208)
std::sort(files.begin(), files.end());
// 挨个解析排序后的文件
for (const auto& file : files) {
if (!ParseConfigFile(file)) {
LOG(ERROR) << "could not import file '" << file << "'";
}
}
return true;
}
执行顺序调节
通过以上分析,我们大致的知道了这些rc文件和action执行先后顺序,
如果有需要调节顺序的,可以从以下几个方面考虑
- (自定义) 调节trigger顺序
- 调节服务的 class 级别 (class main, class core ....)
- 调节rc文件位置
- 调节文件名按升序方式排在前面