Android启动篇 — init原理(一)中讲解分init进程分析init创建系统目录并挂在相应系统文件、初始化属性域、设置系统属性、启动配置属性服务端等一系列复杂工作,很多工作和知识点跟Linux关系很大,所以没有作过多介绍,而本此对于init.rc的解析则是重中之重,所以单独拿出来进行详细分析。
Java代码
- int main(int argc, char** argv) {
-
-
-
- •
-
-
-
-
-
-
- -------------------------------------------------------------------------------------------
-
- Parser& parser = Parser::GetInstance();
-
- parser.AddSectionParser("service",std::make_unique<ServiceParser>());
-
- parser.AddSectionParser("on", std::make_unique<ActionParser>());
-
- parser.AddSectionParser("import", std::make_unique<ImportParser>());
- parser.ParseConfig("/init.rc");
【正文】
init.rc是一个配置文件,内部由Android初始化语言编写(Android Init Language)编写的脚本,主要包含五种类型语句:Action、Command、Service、Option和Import,在分析代码的过程中我们会详细介绍。
init.rc的配置代码在:system/core/rootdir/init.rc 中
init.rc文件是在init进程启动后执行的启动脚本,文件中记录着init进程需执行的操作。
init.rc文件大致分为两大部分,一部分是以“on”关键字开头的动作列表(action list):
XML/HTML代码
- on early-init // Action类型语句
- # Set init and its forked children's oom_adj. // #:注释符号
- write /proc/1/oom_score_adj -1000
- ... ...
- start ueventd
Action类型语句格式:
XML/HTML代码
- on <trigger> [&& <trigger>]* // 设置触发器
- <command>
- <command> // 动作触发之后要执行的命令
另一部分是以“service”关键字开头的服务列表(service list): 如 Zygote
XML/HTML代码
- service ueventd /sbin/ueventd
- class core
- critical
- seclabel u:r:ueventd:s0
Service类型语句格式:
XML/HTML代码
- service <name> <pathname> [ <argument> ]* // <service的名字><执行程序路径><传递参数>
- <option> // option是service的修饰词,影响什么时候、如何启动services
- <option>
- ...
借助系统环境变量或Linux命令,动作列表用于创建所需目录,以及为某些特定文件指定权限,而服务列表用来记录init进程需要启动的一些子进程。如上面代码所示,service关键字后的第一个字符串表示服务(子进程)的名称,第二个字符串表示服务的执行路径。
值得一提的是在Android 7.0中对init.rc文件进行了拆分,每个服务一个rc文件。我们要分析的zygote服务的启动脚本则在init.zygoteXX.rc中定义。
在init.rc的import段我们看到如下代码:
XML/HTML代码
- import /init.${ro.zygote}.rc // 可以看出init.rc不再直接引入一个固定的文件,而是根据属性ro.zygote的内容来引入不同的文件
说明:
从android5.0开始,android开始支持64位的编译,zygote本身也就有了32位和64位的区别,所以在这里用ro.zygote属性来控制启动不同版本的zygote进程。
init.rc位于/system/core/rootdir下。在这个路径下还包括四个关于zygote的rc文件。分别是Init.zygote32.rc,Init.zygote32_64.rc,Init.zygote64.rc,Init.zygote64_32.rc,由硬件决定调用哪个文件。
这里拿32位处理器为例,init.zygote32.rc的代码如下所示:
XML/HTML代码
- service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
- class main # class是一个option,指定zygote服务的类型为main
- socket zygote stream 660 root system # socket关键字表示一个option,创建一个名为dev/socket/zygote,类型为stream,权限为660的socket
- onrestart write /sys/android_power/request_state wake # onrestart是一个option,说明在zygote重启时需要执行的command
- onrestart write /sys/power/state on
- onrestart restart audioserver
- onrestart restart cameraserver
- onrestart restart media
- onrestart restart netd
- writepid /dev/cpuset/foreground/tasks
“service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server”
在Init.zygote32.rc中,定义了一个zygote服务:zygote,由关键字service告诉init进程创建一个名为zygote的进程,这个进程要执行的程序是:/system/bin/app_process,给这个进程四个参数:
· -Xzygote:该参数将作为虚拟机启动时所需的参数
· /system/bin:代表虚拟机程序所在目录
· --zygote:指明以ZygoteInit.java类中的main函数作为虚拟机执行入口
· --start-system-server:告诉Zygote进程启动SystemServer进程
接下来,我们回到源码当中,继续分析main函数:
Java代码
-
- Parser& parser = Parser::GetInstance();
-
- parser.AddSectionParser("service",std::make_unique<ServiceParser>());
-
- parser.AddSectionParser("on", std::make_unique<ActionParser>());
-
- parser.AddSectionParser("import", std::make_unique<ImportParser>());
- parser.ParseConfig("/init.rc");
说明:
上面在解析init.rc文件时使用了Parser类(在init目录下的init_parser.h中定义), 初始化ServiceParser用来解析 “service”块,ActionParser用来解析"on"块,ImportParser用来解析“import”块,“import”是用来引入一个init配置文件,来扩展当前配置的。
/system/core/init/readme.txt 中对init文件中的所有关键字做了介绍,主要包含了Actions, Commands, Services, Options, and Imports等,可自行学习解读。
分析init.rc的解析过程:函数定义于system/core/init/ init_parser.cpp中
Java代码
- bool Parser::ParseConfig(const std::string& path) {
- if (is_dir(path.c_str())) {
- return ParseConfigDir(path);
- }
- return ParseConfigFile(path);
- }
继续分析ParseConfigFile():
Java代码
- bool Parser::ParseConfigFile(const std::string& path) {
- ... ...
- Timer t;
- std::string data;
- if (!read_file(path.c_str(), &data)) {
- return false;
- }
- ... ...
- ParseData(path, data);
- ... ...
- }
跟踪ParseData():
Java代码
- void Parser::ParseData(const std::string& filename, const std::string& data) {
- ... ...
- parse_state state;
- ... ...
- std::vector<std::string> args;
-
- for (;;) {
- switch (next_token(&state)) {
- case T_EOF:
- if (section_parser) {
- section_parser->EndSection();
- }
- return;
- case T_NEWLINE:
- state.line++;
- if (args.empty()) {
- break;
- }
-
-
- if (section_parsers_.count(args[0])) {
- if (section_parser) {
-
- section_parser->EndSection();
- }
-
- section_parser = section_parsers_[args[0]].get();
- std::string ret_err;
-
- if (!section_parser->ParseSection(args, &ret_err)) {
- parse_error(&state, "%s\n", ret_err.c_str());
- section_parser = nullptr;
- }
- } else if (section_parser) {
- std::string ret_err;
-
-
-
- if (!section_parser->ParseLineSection(args, state.filename,
- state.line, &ret_err)) {
- parse_error(&state, "%s\n", ret_err.c_str());
- }
- }
- args.clear();
- break;
- case T_TEXT:
- args.emplace_back(state.text);
- break;
- }
- }
- }
至此,init.rc解析完,接下来init会执行几个重要的阶段:
Java代码
- int main(int argc, char** argv) {
-
-
-
- •
-
-
-
-
-
-
-
- ----------------------------------------------------------------------------
-
-
- ActionManager& am = ActionManager::GetInstance();
-
- am.QueueEventTrigger("early-init");
-
-
- am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
-
- am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
- am.QueueBuiltinAction(keychord_init_action, "keychord_init");
- am.QueueBuiltinAction(console_init_action, "console_init");
-
-
- am.QueueEventTrigger("init");
-
-
-
- am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
-
-
- if (bootmode == "charger") {
- am.QueueEventTrigger("charger");
- } else if (strncmp(bootmode.c_str(), "ffbm", 4) == 0) {
- NOTICE("Booting into ffbm mode\n");
- am.QueueEventTrigger("ffbm");
- } else {
- am.QueueEventTrigger("late-init");
- }
-
-
- am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
在last-init最后阶段有如下代码:
XML/HTML代码
- # Mount filesystems and start core system services.
- 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
-
- # Load properties from /system/ + /factory after fs mount. Place
- # this in another action so that the load will be scheduled after the prior
- # issued fs triggers have completed.
- trigger load_system_props_action
-
- # 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
-
- # Remove a file to wake up anything waiting for firmware.
- trigger firmware_mounts_complete
-
- trigger early-boot
- trigger boot
可见出发了on early-boot和on boot两个Action。
我们看一下on boot:
XML/HTML代码
- on boot
- # basic network init
- ifup lo
- hostname localhost
- domainname localdomain
- ... ...
- class_start core
在on boot 的最后class_start core 会启动class为core的服务,这些服务包括ueventd、logd、healthd、adbd(disabled)、lmkd(LowMemoryKiller)、servicemanager、vold、debuggerd、surfaceflinger、bootanim(disabled)等。
回到主题,分析trigger触发器的代码,QueueEventTrigger():位于system/core/init/action.cpp
Java代码
- void ActionManager::QueueEventTrigger(const std::string& trigger) {
- trigger_queue_.push(std::make_unique<EventTrigger>(trigger));
- }
此处QueueEventTrigger函数就是利用参数构造EventTrigger,然后加入到trigger_queue_中。后续init进程处理trigger事件时,将会触发相应的操作。
再看一下QueueBuiltinAction()函数:同样位于system/core/init/action.cpp
Java代码
- void ActionManager::QueueBuiltinAction(BuiltinFunction func,
- const std::string& name) {
-
- auto action = std::make_unique<Action>(true);
- std::vector<std::string> name_vector{name};
-
-
- if (!action->InitSingleTrigger(name)) {
- return;
- }
-
-
- action->AddCommand(func, name_vector);
-
- trigger_queue_.push(std::make_unique<BuiltinTrigger>(action.get()));
- actions_.emplace_back(std::move(action));
- }
QueueBuiltinAction函数中构造新的action加入到actions_中,第一个参数作为新建action携带cmd的执行函数;第二个参数既作为action的trigger name,也作为action携带cmd的参数。
接下来继续分析main函数:
Java代码
- int main(int argc, char** argv) {
-
-
-
- •
-
-
-
-
-
-
-
-
- -------------------------------------------------------------------
-
- while (true) {
-
- if (!waiting_for_exec) {
-
- am.ExecuteOneCommand();
-
- restart_processes();
- }
-
-
- int timeout = -1;
-
- if (process_needs_restart) {
- timeout = (process_needs_restart - gettime()) * 1000;
- if (timeout < 0)
- timeout = 0;
- }
-
-
- if (am.HasMoreCommands()) {
- timeout = 0;
- }
-
-
- bootchart_sample(&timeout);
-
- epoll_event ev;
-
- int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
- if (nr == -1) {
- ERROR("epoll_wait failed: %s\n", strerror(errno));
- } else if (nr == 1) {
-
-
- ((void (*)()) ev.data.ptr)();
- }
- }
- return 0;
- }
看一下ExecuteOneComand()函数:同样位于system/core/init/action.cpp
Java代码
- void ActionManager::ExecuteOneCommand() {
-
-
- while (current_executing_actions_.empty() && !trigger_queue_.empty()) {
-
- for (const auto& action : actions_) {
-
- if (trigger_queue_.front()->CheckTriggers(*action)) {
-
- current_executing_actions_.emplace(action.get());
- }
- }
-
- trigger_queue_.pop();
- }
-
- if (current_executing_actions_.empty()) {
- return;
- }
-
- auto action = current_executing_actions_.front();
-
- if (current_command_ == 0) {
- std::string trigger_name = action->BuildTriggersString();
- INFO("processing action (%s)\n", trigger_name.c_str());
- }
-
- action->ExecuteOneCommand(current_command_);
-
-
-
-
- ++current_command_;
- if (current_command_ == action->NumCommands()) {
- current_executing_actions_.pop();
- current_command_ = 0;
- if (action->oneshot()) {
- auto eraser = [&action] (std::unique_ptr<Action>& a) {
- return a.get() == action;
- };
- actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser));
- }
- }
- }
我们来观察一下init.rc的开头部分:
Java代码
- import /init.environ.rc
- import /init.usb.rc
- import /init.${ro.hardware}.rc
- import /init.usb.configfs.rc
- import /init.${ro.zygote}.rc
通过ro.zygote的属性import对应的zygote的rc文件。
我们查看init.zygote64_32.rc:
XML/HTML代码
- service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
- class main
- socket zygote stream 660 root system
- onrestart write /sys/android_power/request_state wake
- onrestart write /sys/power/state on
- onrestart restart audioserver
- onrestart restart cameraserver
- onrestart restart media
- onrestart restart netd
- writepid /dev/cpuset/foreground/tasks
-
- service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
- class main
- socket zygote_secondary stream 660 root system
- onrestart restart zygote
- writepid /dev/cpuset/foreground/tasks
可以看到zygote的class是main, 它是在on nonencrypted时被启动的,如下:
XML/HTML代码
- on boot
- # basic network init
- ifup lo
- hostname localhost
- domainname localdomain
- ... ...
- class_start core
-
- on nonencrypted
- # A/B update verifier that marks a successful boot.
- exec - root cache -- /system/bin/update_verifier nonencrypted
- class_start main
- class_start late_start
至此,Init.cpp的main函数分析完毕!init进程已经启动完成,一些重要的服务如core服务和main服务也都启动起来,并启动了zygote(/system/bin/app_process64)进程,zygote初始化时会创建虚拟机,启动systemserver等。