接上文
二、init进程执行rc文件
rc文件处理的大概表述:
将init.rc文件解析后,对于的执行,init进程主要通过以下几个角色实现:
- Epoll(core/init/epoll.h):对<sys/epoll.h>的封装,用于事件的分发控制
- ActionManager(core/init/action_manager.h):Action事件的队列管理、事件执行。
- ServiceList(core/init/service_list.cpp):Service事件的队列管理、事件执行。
- property_service(core/init/property_service.cpp):Property变化事件的管理
首先,我们回顾下,kernel在启动init进程后,依次调用core/init/init.cpp中的FirstStageMain、SetupSelinux后,会调用到SecondStageMain函数。SecondStageMain是解析执行init.rc文件的核心函数。
1. 关键角色的初始化
core/init/init.cpp
int SecondStageMain(int argc, char** argv) {
...
// 创建epoll
Epoll epoll;
if (auto result = epoll.Open(); !result.ok()) {
PLOG(FATAL) << result.error();
}
...
// 初始化一个空的epoll事件,主要用来唤醒epoll
InstallInitNotifier(&epoll);
// 启动property服务,创建socket监听property变化,并通知回来进行trigger的匹配响应。
StartPropertyService(&property_fd);
...
// 用来管理Action和Service的队列
ActionManager& am = ActionManager::GetInstance();
ServiceList& sm = ServiceList::GetInstance();
// 解析rc文件
LoadBootScripts(am, sm);
// 开始将一系列所谓Buildin内建action加入队列
am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux");
// 将rc文件里early-init这个trigger所对应的Action加入队列
am.QueueEventTrigger("early-init");
am.QueueBuiltinAction(ConnectEarlyStageSnapuserdAction, "ConnectEarlyStageSnapuserd");
am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
Keychords keychords;
am.QueueBuiltinAction(
[&epoll, &keychords](const BuiltinArguments& args) -> Result<void> {
for (const auto& svc : ServiceList::GetInstance()) {
keychords.Register(svc->keycodes());
}
keychords.Start(&epoll, HandleKeychord);
return {};
},
"KeychordInit");
// Trigger all the boot actions to get us started.
am.QueueEventTrigger("init");
上面的代码做了几个事情:
1)epoll.Open()
我们看下Epoll倒地是咋封装sys/epoll的:
Result<void> Epoll::Open() {
if (epoll_fd_ >= 0) return {};
epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC));
if (epoll_fd_ == -1) {
return ErrnoError() << "epoll_create1 failed";
}
return {};
}
本质就是调用epoll_create1(EPOLL_CLOEXEC)创建了个epoll_fd_
2)InstallInitNotifier(&epoll);
core/init/init.cpp
// Init epolls various FDs to wait for various inputs. It previously waited on property changes
// with a blocking socket that contained the information related to the change, however, it was easy
// to fill that socket and deadlock the system. Now we use locks to handle the property changes
// directly in the property thread, however we still must wake the epoll to inform init that there
// is a change to process, so we use this FD. It is non-blocking, since we do not care how many
// times WakeMainInitThread() is called, only that the epoll will wake.
static int wake_main_thread_fd = -1;
static void InstallInitNotifier(Epoll* epoll) {
wake_main_thread_fd = eventfd(0, EFD_CLOEXEC);
if (wake_main_thread_fd == -1) {
PLOG(FATAL) << "Failed to create eventfd for waking init";
}
auto clear_eventfd = [] {
uint64_t counter;
TEMP_FAILURE_RETRY(read(wake_main_thread_fd, &counter, sizeof(counter)));
};
if (auto result = epoll->RegisterHandler(wake_main_thread_fd, clear_eventfd); !result.ok()) {
LOG(FATAL) << result.error();
}
}
注释部分理解为:原来在直接将监听property变化的socket注册进init的epoll,socket是阻塞的,而且该socket先于其他fd注册,因此很容易导致整个系统阻塞。所以改为:业务都在property线程里处理了,这里只是触发一个空的fd(wake_main_thread_fd)处理函数,只是用来唤醒epoll。
至于wake_main_thread_fd是在哪里写的:
// core/init/init.cpp
static void WakeMainInitThread() {
uint64_t counter = 1;
TEMP_FAILURE_RETRY(write(wake_main_thread_fd, &counter, sizeof(counter)));
}
WakeMainInitThread被掉用的地方在后面说明。
3)StartPropertyService(&property_fd);
前面提到的property的socket,就是在这里创建的。看下具体代码:
core/init/property_service.cpp
void StartPropertyService(int* epoll_socket) {
...
*epoll_socket = from_init_socket = sockets[0];
if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
/*passcred=*/false, /*should_listen=*/false, 0666, /*uid=*/0,
/*gid=*/0, /*socketcon=*/{});
listen(property_set_fd, 8);
auto new_thread = std::thread{PropertyServiceThread};
property_service_thread.swap(new_thread);
...
}
static void PropertyServiceThread() {
Epoll epoll;
if (auto result = epoll.Open(); !result.ok()) {
LOG(FATAL) << result.error();
}
if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd);
...
即创建了PROP_SERVICE_NAME这个socket,监听property的设置,同时创建PropertyServiceThread线程,在该线程内单独创建了个Epoll来处理socket消息。这里的socket是消息的读取方, 而写入方,在/bionic/libc/bionic/system_property_set.cpp,也就是处理通过setprop设置property的地方。
我们再看看PropertyServiceThread内socket的处理函数handle_property_set_fd
static void handle_property_set_fd() {
...
int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC);
...
auto result = HandlePropertySet(name, value, source_context, cr, &socket, &error);
...
}
最终会调用HandlePropertySet函数, 而这个HandlePropertySet在经历PropertySet -> NotifyPropertyChange 的调用后,会调用core/init/init.cpp内的PropertyChanged:
core/init/init.cpp
void PropertyChanged(const std::string& name, const std::string& value) {
...
if (property_triggers_enabled) {
ActionManager::GetInstance().QueuePropertyChange(name, value);
WakeMainInitThread();
}
prop_waiter_state.CheckAndResetWait(name, value);
}
我们看到,显示ActionManager::GetInstance().QueuePropertyChange(name, value);将property变更消息加入队列,然后调用WakeMainInitThread唤醒init的epoll。
2. 事件加入队列
1)将rc文件内的事件加入队列
init.cpp中SecondStageMain函数 -> LoadBootScripts()触发了对rc文件的解析
int SecondStageMain(int argc, char** argv) {
...
ActionManager& am = ActionManager::GetInstance();
ServiceList& sm = ServiceList::GetInstance();
LoadBootScripts(am, sm);
...
}
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
Parser parser = CreateParser(action_manager, service_list);
...
}
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
Parser parser;
parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, GetSubcontext(), std::nullopt));
parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, GetSubcontext()));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
return parser;
}
我们知道,rc文件中,主要有两类事件,即所谓的可被执行的Section -- Action和Service。
在上面代码中分别对Action和Service的解析器ActionParser和ServiceParser做了初始化
这两个解析器在解析出“on”语法的Action和“service”语法的Service后,会构造响应的两个对象,然后分别加入到传进来的service_list和action_manager, 也就是ServiceList::GetInstance()和ActionManager::GetInstance()
首先看下Action和Service的构造函数:
core/init/action.capp
Action::Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line,
const std::string& event_trigger,
const std::map<std::string, std::string>& property_triggers)
: property_triggers_(property_triggers),
event_trigger_(event_trigger),
oneshot_(oneshot),
subcontext_(subcontext),
filename_(filename),
line_(line) {}
core/init/service.cpp
Service::Service(const std::string& name, unsigned flags, std::optional<uid_t> uid, gid_t gid,
const std::vector<gid_t>& supp_gids, int namespace_flags,
const std::string& seclabel, Subcontext* subcontext_for_restart_commands,
const std::string& filename, const std::vector<std::string>& args)
: name_(name),
classnames_({"default"}),
flags_(flags),
pid_(0),
crash_count_(0),
proc_attr_{.ioprio_class = IoSchedClass_NONE,
.ioprio_pri = 0,
.parsed_uid = uid,
.gid = gid,
.supp_gids = supp_gids,
.priority = 0},
namespaces_{.flags = namespace_flags},
seclabel_(seclabel),
subcontext_(subcontext_for_restart_commands),
onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0,
"onrestart", {}),
oom_score_adjust_(DEFAULT_OOM_SCORE_ADJUST),
start_order_(0),
args_(args),
filename_(filename) {}
我们看看这两个事件分别怎么放入队列等待执行的。
对Action的解析在core/init/action_parser.cpp
core/init/action_parser.cpp
Result<void> ActionParser::ParseSection(std::vector<std::string>&& args,const std::string& filename, int line) {
...
auto action = std::make_unique<Action>(false, action_subcontext, filename, line, event_trigger,
property_triggers);
action_ = std::move(action);
}
Result<void> ActionParser::ParseLineSection(std::vector<std::string>&& args, int line) {
return action_ ? action_->AddCommand(std::move(args), line) : Result<void>{};
}
Result<void> ActionParser::EndSection() {
action_manager_->AddAction(std::move(action_));
}
首先,在ParseSection中构建了Action,随后在ParseLineSection中将每行的command通过AddCommand加入到action内部的command_队列等待执行。后调用ActionManager的AddAction将action加入到ActionManager的队列中。
core/init/action_manager.cpp
void ActionManager::AddAction(std::unique_ptr<Action> action) {
actions_.emplace_back(std::move(action));
}
放入了ActionManager的actions_
另外,我们有必要看下AddCommand的细节:
core/init/action.cpp
Result<void> Action::AddCommand(std::vector<std::string>&& args, int line) {
if (!function_map_) {
return Error() << "no function map available";
}
auto map_result = function_map_->Find(args);
if (!map_result.ok()) {
return Error() << map_result.error();
}
commands_.emplace_back(map_result->function, map_result->run_in_subcontext, std::move(args),
line);
return {};
}
function_map_是一个内置的指令表,事先声明了所有comand对应的函数:
// Builtin-function-map start
const BuiltinFunctionMap& GetBuiltinFunctionMap() {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
// clang-format off
static const BuiltinFunctionMap builtin_functions = {
{"bootchart", {1, 1, {false, do_bootchart}}},
{"chmod", {2, 2, {true, do_chmod}}},
{"chown", {2, 3, {true, do_chown}}},
{"class_reset", {1, 1, {false, do_class_reset}}},
{"class_restart", {1, 2, {false, do_class_restart}}},
{"class_start", {1, 1, {false, do_class_start}}},
{"class_stop", {1, 1, {false, do_class_stop}}},
{"copy", {2, 2, {true, do_copy}}},
{"copy_per_line", {2, 2, {true, do_copy_per_line}}},
{"domainname", {1, 1, {true, do_domainname}}},
{"enable", {1, 1, {false, do_enable}}},
{"exec", {1, kMax, {false, do_exec}}},
{"exec_background", {1, kMax, {false, do_exec_background}}},
{"exec_start", {1, 1, {false, do_exec_start}}},
{"export", {2, 2, {false, do_export}}},
{"hostname", {1, 1, {true, do_hostname}}},
{"ifup", {1, 1, {true, do_ifup}}},
{"init_user0", {0, 0, {false, do_init_user0}}},
{"insmod", {1, kMax, {true, do_insmod}}},
{"installkey", {1, 1, {false, do_installkey}}},
{"interface_restart", {1, 1, {false, do_interface_restart}}},
{"interface_start", {1, 1, {false, do_interface_start}}},
{"interface_stop", {1, 1, {false, do_interface_stop}}},
{"load_exports", {1, 1, {false, do_load_exports}}},
{"load_persist_props", {0, 0, {false, do_load_persist_props}}},
{"load_system_props", {0, 0, {false, do_load_system_props}}},
{"loglevel", {1, 1, {false, do_loglevel}}},
{"mark_post_data", {0, 0, {false, do_mark_post_data}}},
{"mkdir", {1, 6, {true, do_mkdir}}},
// TODO: Do mount operations in vendor_init.
// mount_all is currently too complex to run in vendor_init as it queues action triggers,
// imports rc scripts, etc. It should be simplified and run in vendor_init context.
// mount and umount are run in the same context as mount_all for symmetry.
{"mount_all", {0, kMax, {false, do_mount_all}}},
{"mount", {3, kMax, {false, do_mount}}},
{"perform_apex_config", {0, 1, {false, do_perform_apex_config}}},
{"umount", {1, 1, {false, do_umount}}},
{"umount_all", {0, 1, {false, do_umount_all}}},
{"update_linker_config", {0, 0, {false, do_update_linker_config}}},
{"readahead", {1, 2, {true, do_readahead}}},
{"remount_userdata", {0, 0, {false, do_remount_userdata}}},
{"restart", {1, 2, {false, do_restart}}},
{"restorecon", {1, kMax, {true, do_restorecon}}},
{"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}},
{"rm", {1, 1, {true, do_rm}}},
{"rmdir", {1, 1, {true, do_rmdir}}},
{"setprop", {2, 2, {true, do_setprop}}},
{"setrlimit", {3, 3, {false, do_setrlimit}}},
{"start", {1, 1, {false, do_start}}},
{"stop", {1, 1, {false, do_stop}}},
{"swapon_all", {0, 1, {false, do_swapon_all}}},
{"enter_default_mount_ns", {0, 0, {false, do_enter_default_mount_ns}}},
{"symlink", {2, 2, {true, do_symlink}}},
{"sysclktz", {1, 1, {false, do_sysclktz}}},
{"trigger", {1, 1, {false, do_trigger}}},
{"verity_update_state", {0, 0, {false, do_verity_update_state}}},
{"wait", {1, 2, {true, do_wait}}},
{"wait_for_prop", {2, 2, {false, do_wait_for_prop}}},
{"write", {2, 2, {true, do_write}}},
};
// clang-format on
return builtin_functions;
}
也就是说,AddCommand函数里,通过rc里面声明的指令,从GetBuiltinFunctionMap里取出对应的函数,加入到action.cpp的commands_中。
再来看看Service:
core\init\service_parser.cpp
Result<void> ServiceParser::ParseSection(std::vector<std::string>&& args, const std::string& filename, int line) {
...
ervice_ = std::make_unique<Service>(name, restart_action_subcontext, filename, str_args);
}
Result<void> ServiceParser::EndSection() {
...
service_list_->AddService(std::move(service_));
}
构建了Service后,加入到service_list_,也就是ServiceList::GetInstance()
2)代码内直接添加Action到队列
Action事件除了在rc里面声明,还可以在代码里直接调用。
在SecondStageMain函数中,在经过上面的初始化后,我们看到其后有下面这些调用:
am.QueueBuiltinAction(... : 构建Buildin(内建)Action,也就是代码方式直接将Action对象加入队列执行。
am.QueueEventTrigger(... :将trigger加入队列,实际上是触发rc文件里的某个匹配trigger的Action执行。
加上上面提到的QueuePropertyChange:触发property trigger的执行。
看下ActionManager类里面的实现:
void ActionManager::QueueEventTrigger(const std::string& trigger) {
auto lock = std::lock_guard{event_queue_lock_};
event_queue_.emplace(trigger);
}
QueueEventTrigger是把trigger加入到event_queue_队列;
void ActionManager::QueuePropertyChange(const std::string& name, const std::string& value) {
auto lock = std::lock_guard{event_queue_lock_};
event_queue_.emplace(std::make_pair(name, value));
}
QueuePropertyChange是把name-value构建pair后加入event_queue_队列
void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
auto lock = std::lock_guard{event_queue_lock_};
auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0, name,std::map<std::string, std::string>{});
action->AddCommand(std::move(func), {name}, 0);
event_queue_.emplace(action.get());
actions_.emplace_back(std::move(action));
}
QueueBuiltinAction中,新建了个Action,然后把func参数当做一个command加入到action。随后将action加入event_queue_队列,同时加入到actions_维护。
我们看看core/init/action_manager.h中event_queue_的声明:
std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_
可以看到队列接受EventTrigger, PropertyChange, BuiltinAction这三个类型,关于类型声明在core/init/action.h中:
using EventTrigger = std::string;
using PropertyChange = std::pair<std::string, std::string>;
using BuiltinAction = class Action*;
3. 事件的执行
在SecondStageMain函数的最后,有一个while死循环:
core/init/init.cpp
while (true) {
// Action的执行
if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
am.ExecuteOneCommand();
if (am.HasMoreCommands()) {
next_action_time = boot_clock::now();
}
}
// 计算Service的超时、重启
if (!IsShuttingDown()) {
auto next_process_action_time = HandleProcessActions();
}
...
// 计算下次执行事件
if (next_action_time != far_future) {
epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
std::max(next_action_time - boot_clock::now(), 0ns));
}
auto epoll_result = epoll.Wait(epoll_timeout);
...
}
会调用am.ExecuteOneCommand(); 执行Action。每执行完一次,会在epoll.Wait(epoll_timeout);阻塞,等待下一次唤醒。
看看am.ExecuteOneCommand:
core/init/action_manager.cpp
void ActionManager::ExecuteOneCommand() {
while (current_executing_actions_.empty() && !event_queue_.empty()) {
for (const auto& action : actions_) {
if (std::visit([&action](const auto& event) { return action->CheckEvent(event); }, event_queue_.front())) {
current_executing_actions_.emplace(action.get());
}
}
event_queue_.pop();
}
...
auto action = current_executing_actions_.front();
action->ExecuteOneCommand(current_command_);
}
即从actions_队列中取出每个Action,最终执行action的ExecuteOneCommand。
Service的执行,则依赖于Action的start命令。例如rc中:
on zygote-start
...
start zygote
这里的start zygote即启动之前声明好的service zygote服务。对于start命令,其对应的执行函数在
GetBuiltinFunctionMap()中声明:
core/init/builtins.cpp
// Builtin-function-map start
const BuiltinFunctionMap& GetBuiltinFunctionMap() {
static const BuiltinFunctionMap builtin_functions = {
...
{"start", {1, 1, {false, do_start}}},
...
}
}
do_start函数内容:
static Result<void> do_start(const BuiltinArguments& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
errno = 0;
if (auto result = svc->Start(); !result.ok()) {
return ErrorIgnoreEnoent() << "Could not start service: " << result.error();
}
return {};
}
可以看到实际从ServiceList::GetInstance()中取出对应Servie,调用其Start()函数执行。执行了Service的Start函数
core/init/service.cpp
Result<void> Service::Start() {
...
pid_t pid = -1;
if (namespaces_.flags) {
pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr);
} else {
pid = fork();
}
if (pid == 0) {
umask(077);
cgroups_activated.CloseWriteFd();
setsid_finished.CloseReadFd();
RunService(descriptors, std::move(cgroups_activated), std::move(setsid_finished));
_exit(127);
} else {
cgroups_activated.CloseReadFd();
setsid_finished.CloseWriteFd();
}
}
根据是否设置了namespaces_.flags(在options中指定)来选择用clone还是fork创建一个新进程。随后在新进程中执行RunService函数执行具体Service内容