• Android源码分析挖掘-开天辟地init进程


    序言

    PC启动一般会通过BIOS或者EFI引导程序启动,Android一般作为移动设备,没有PC的BIOS或者EFI,取而代之的是BootLoader。

    BootLoader

    按下电源键CPU上电完成后,会从固定地址加载一段程序,就是BootLoader,不通的CPU可能地址段会有差异,BootLoader是一段引导程序,常见的就是U-boot。

    U-boot程序启动后,一般会先检测是否同时按下了触发U-boot功能的按键,比如进入Recovery模式等, 这些按键一般是在U-boot中事先编码好的。

    如果没有按下这些按键,U-boot会从nand flash中装载linux内核,装载的地址也是在编译uboot时预定好的。linux内核启动后,会创建第一个进程:idle。

    idle进程

    idle进程是linux进程启动后创建的第一个进程,其pid=0,idle进程被创建后会创建init进程和kthreadd进程,然后idle会在cpu没有任务时进行空转。

    kthreadd进程

    kthreadd被创建后,其pid=2,运行在内核空间,负责所有内核线程的调度和管理。

    init进程

    init进程是linux系统的第一个用户进程,其pid=1,是系统所有用户进程的根进程,其源码在/system/core/init/main.cpp中,以main方法为入口:

    1. using namespace android::init;
    2. int main(int argc, char** argv) {
    3. #if __has_feature(address_sanitizer)
    4. __asan_set_error_report_callback(AsanReportCallback);
    5. #endif
    6. // Boost prio which will be restored later
    7. setpriority(PRIO_PROCESS, 0, -20);
    8. if (!strcmp(basename(argv[0]), "ueventd")) {
    9. return ueventd_main(argc, argv);
    10. }
    11. if (argc > 1) {
    12. if (!strcmp(argv[1], "subcontext")) {
    13. android::base::InitLogging(argv, &android::base::KernelLogger);
    14. const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
    15. return SubcontextMain(argc, argv, &function_map);
    16. }
    17. if (!strcmp(argv[1], "selinux_setup")) {
    18. return SetupSelinux(argv);
    19. }
    20. if (!strcmp(argv[1], "second_stage")) {
    21. return SecondStageMain(argc, argv);
    22. }
    23. }
    24. return FirstStageMain(argc, argv);
    25. }

    默认启动无参数,会进入init的第一阶段,会调用FirstStageMain函数,通过命令搜索FirstStageMain函数所在文件:

    1. //输入以下搜索命令,然后点击Enter
    2. grep FirstStageMain ./ -rn

    搜索结果如下:

    1. ./first_stage_main.cpp:20: return android::init::FirstStageMain(argc, argv);
    2. ./first_stage_init.h:22:int FirstStageMain(int argc, char** argv);
    3. ./main.cpp:78: return FirstStageMain(argc, argv);
    4. ./first_stage_init.cpp:183:int FirstStageMain(int argc, char** argv) {

    可以知道是在./first_stage_init.cpp第183行,输入如下命令定位到函数所在行

    vi ./first_stage_init.cpp +183

    FirstStageMain函数中可以看到,会先对文件系统进行一系列的权限设定,然后通过执行execv再次调用init,传入参数selinux_setup,进入到init的第二阶段

    1. int FirstStageMain(int argc, char** argv) {
    2. ...
    3. // Clear the umask.
    4. //权限掩码设置为0,则都是111,其他授权时最终的规则就是:(xxx & ~掩码 = 最终权限)
    5. umask(0);
    6. //文件系统授权
    7. CHECKCALL(clearenv());
    8. CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));
    9. // Get the basic filesystem setup we need put together in the initramdisk
    10. // on / and then we'll let the rc file figure out the rest.
    11. CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
    12. CHECKCALL(mkdir("/dev/pts", 0755));
    13. CHECKCALL(mkdir("/dev/socket", 0755));
    14. CHECKCALL(mkdir("/dev/dm-user", 0755));
    15. CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
    16. #define MAKE_STR(x) __STRING(x)
    17. CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
    18. #undef MAKE_STR
    19. // Don't expose the raw commandline to unprivileged processes.
    20. CHECKCALL(chmod("/proc/cmdline", 0440));
    21. std::string cmdline;
    22. android::base::ReadFileToString("/proc/cmdline", &cmdline);
    23. // Don't expose the raw bootconfig to unprivileged processes.
    24. chmod("/proc/bootconfig", 0440);
    25. std::string bootconfig;
    26. android::base::ReadFileToString("/proc/bootconfig", &bootconfig);
    27. gid_t groups[] = {AID_READPROC};
    28. CHECKCALL(setgroups(arraysize(groups), groups));
    29. CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
    30. CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));
    31. ...
    32. //通过execv再次执行init,传入参数selinux_setup,进入到init的第二阶段
    33. const char* path = "/system/bin/init";
    34. const char* args[] = {path, "selinux_setup", nullptr};
    35. auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
    36. dup2(fd, STDOUT_FILENO);
    37. dup2(fd, STDERR_FILENO);
    38. close(fd);
    39. execv(path, const_cast<char**>(args));
    40. }

    再次回看/system/core/init/main.cpp源码,由于本次传入的参数是selinux_setup,结合代码可以看到,会进入到SetupSelinux这个函数中

    1. using namespace android::init;
    2. int main(int argc, char** argv) {
    3. ...
    4. if (argc > 1) {
    5. if (!strcmp(argv[1], "subcontext")) {
    6. android::base::InitLogging(argv, &android::base::KernelLogger);
    7. const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
    8. return SubcontextMain(argc, argv, &function_map);
    9. }
    10. if (!strcmp(argv[1], "selinux_setup")) {
    11. return SetupSelinux(argv);
    12. }
    13. if (!strcmp(argv[1], "second_stage")) {
    14. return SecondStageMain(argc, argv);
    15. }
    16. }
    17. ...
    18. }

    通过命令搜索

    grep SetupSelinux ./ -rn

    搜索结果如下

    1. ./selinux.cpp:730:int SetupSelinux(char** argv) {
    2. ./main.cpp:70: return SetupSelinux(argv);
    3. ./selinux.h:23:int SetupSelinux(char** argv);

    使用命令定位到行

    vi ./selinux.cpp +730

    代码如下,此阶段主要是启动Selinux安全机制,初始化selinux,加载SELinux规则和配置SELinux相关log输出,然后通过执行execv再次调用init,传入参数selinux_setup,进入到init的第三阶段

    1. int SetupSelinux(char** argv) {
    2. SetStdioToDevNull(argv);
    3. InitKernelLogging(argv);
    4. if (REBOOT_BOOTLOADER_ON_PANIC) {
    5. InstallRebootSignalHandlers();
    6. }
    7. boot_clock::time_point start_time = boot_clock::now();
    8. MountMissingSystemPartitions();
    9. SelinuxSetupKernelLogging();
    10. LOG(INFO) << "Opening SELinux policy";
    11. ...
    12. LoadSelinuxPolicy(policy);
    13. if (snapuserd_helper) {
    14. snapuserd_helper->FinishTransition();
    15. snapuserd_helper = nullptr;
    16. }
    17. SelinuxSetEnforcement();
    18. setenv(kEnvSelinuxStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(), 1);
    19. //通过execv再次执行init,传入参数second_stage,进入到init的第三阶段
    20. const char* path = "/system/bin/init";
    21. const char* args[] = {path, "second_stage", nullptr};
    22. execv(path, const_cast<char**>(args));
    23. ...
    24. return 1;
    25. }

    再次回看/system/core/init/main.cpp源码,本次传入的参数是second_stage,结合代码可以看到,会进入到SecondStageMain这个函数中,同样的方式,搜索

    grep SecondStageMain ./ -rn

    搜索结果

    1. ./init.h:47:int SecondStageMain(int argc, char** argv);
    2. ./main.cpp:74: return SecondStageMain(argc, argv);
    3. ./init.cpp:742:int SecondStageMain(int argc, char** argv) {

    使用命令定位到行

    vi ./init.cpp +742

    代码如下,此阶段主要是初始化了一些属性和解析init.rc,以及守护服务

    1. int SecondStageMain(int argc, char** argv) {
    2. ...
    3. // Indicate that booting is in progress to background fw loaders, etc.
    4. //设置启动中标记
    5. close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
    6. ...
    7. //初始化系统属性
    8. PropertyInit();
    9. ...
    10. // Mount extra filesystems required during second stage init
    11. //挂载额外的文件系统
    12. MountExtraFilesystems();
    13. // Now set up SELinux for second stage.
    14. //设置SElinux相关
    15. SelinuxSetupKernelLogging();
    16. SelabelInitialize();
    17. SelinuxRestoreContext();
    18. //使用epoll注册信号处理函数,守护进程服务
    19. Epoll epoll;
    20. if (auto result = epoll.Open(); !result.ok()) {
    21. PLOG(FATAL) << result.error();
    22. }
    23. InstallSignalFdHandler(&epoll);
    24. InstallInitNotifier(&epoll);
    25. //启动系统属性服务
    26. StartPropertyService(&property_fd);
    27. ...
    28. //设置commands指令对应的函数map,用于在后面解析init.rc文件中的指令查找
    29. const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
    30. Action::set_function_map(&function_map);
    31. ...
    32. //解析init.rc脚本
    33. ActionManager& am = ActionManager::GetInstance();
    34. ServiceList& sm = ServiceList::GetInstance();
    35. LoadBootScripts(am, sm);
    36. ...
    37. while (true) {
    38. // By default, sleep until something happens.
    39. auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
    40. ...
    41. //执行从init.rc脚本解析出来的每条指令
    42. if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
    43. am.ExecuteOneCommand();
    44. }
    45. ...
    46. if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
    47. // If there's more work to do, wake up again immediately.
    48. if (am.HasMoreCommands()) epoll_timeout = 0ms;
    49. }
    50. auto pending_functions = epoll.Wait(epoll_timeout);
    51. if (!pending_functions.ok()) {
    52. LOG(ERROR) << pending_functions.error();
    53. } else if (!pending_functions->empty()) {
    54. // We always reap children before responding to the other pending functions. This is to
    55. // prevent a race where other daemons see that a service has exited and ask init to
    56. // start it again via ctl.start before init has reaped it.
    57. //子进程退出后的处理
    58. ReapAnyOutstandingChildren();
    59. for (const auto& function : *pending_functions) {
    60. (*function)();
    61. }
    62. }
    63. ...
    64. }
    65. return 0;
    66. }

    其他的可先不做分析,重点分析一下两点:

    1.先看一下GetBuiltinFunctionMap函数做了什么,源码在/system/core/init/builtins.cpp,这个函数保存了指令与函数的对应关系,当发起key的调用时,会调用value对应的函数。

    1. // Builtin-function-map start
    2. const BuiltinFunctionMap& GetBuiltinFunctionMap() {
    3. constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
    4. // clang-format off
    5. static const BuiltinFunctionMap builtin_functions = {
    6. {"bootchart", {1, 1, {false, do_bootchart}}},
    7. {"chmod", {2, 2, {true, do_chmod}}},
    8. {"chown", {2, 3, {true, do_chown}}},
    9. {"class_reset", {1, 1, {false, do_class_reset}}},
    10. {"class_reset_post_data", {1, 1, {false, do_class_reset_post_data}}},
    11. {"class_restart", {1, 1, {false, do_class_restart}}},
    12. {"class_start", {1, 1, {false, do_class_start}}},
    13. {"class_start_post_data", {1, 1, {false, do_class_start_post_data}}},
    14. {"class_stop", {1, 1, {false, do_class_stop}}},
    15. {"copy", {2, 2, {true, do_copy}}},
    16. {"copy_per_line", {2, 2, {true, do_copy_per_line}}},
    17. {"domainname", {1, 1, {true, do_domainname}}},
    18. {"enable", {1, 1, {false, do_enable}}},
    19. {"exec", {1, kMax, {false, do_exec}}},
    20. {"exec_background", {1, kMax, {false, do_exec_background}}},
    21. {"exec_start", {1, 1, {false, do_exec_start}}},
    22. {"export", {2, 2, {false, do_export}}},
    23. {"hostname", {1, 1, {true, do_hostname}}},
    24. {"ifup", {1, 1, {true, do_ifup}}},
    25. {"init_user0", {0, 0, {false, do_init_user0}}},
    26. {"insmod", {1, kMax, {true, do_insmod}}},
    27. {"installkey", {1, 1, {false, do_installkey}}},
    28. {"interface_restart", {1, 1, {false, do_interface_restart}}},
    29. {"interface_start", {1, 1, {false, do_interface_start}}},
    30. {"interface_stop", {1, 1, {false, do_interface_stop}}},
    31. {"load_exports", {1, 1, {false, do_load_exports}}},
    32. {"load_persist_props", {0, 0, {false, do_load_persist_props}}},
    33. {"load_system_props", {0, 0, {false, do_load_system_props}}},
    34. {"loglevel", {1, 1, {false, do_loglevel}}},
    35. {"mark_post_data", {0, 0, {false, do_mark_post_data}}},
    36. {"mkdir", {1, 6, {true, do_mkdir}}},
    37. // TODO: Do mount operations in vendor_init.
    38. // mount_all is currently too complex to run in vendor_init as it queues action triggers,
    39. // imports rc scripts, etc. It should be simplified and run in vendor_init context.
    40. // mount and umount are run in the same context as mount_all for symmetry.
    41. {"mount_all", {0, kMax, {false, do_mount_all}}},
    42. {"mount", {3, kMax, {false, do_mount}}},
    43. {"perform_apex_config", {0, 0, {false, do_perform_apex_config}}},
    44. {"umount", {1, 1, {false, do_umount}}},
    45. {"umount_all", {0, 1, {false, do_umount_all}}},
    46. {"update_linker_config", {0, 0, {false, do_update_linker_config}}},
    47. {"readahead", {1, 2, {true, do_readahead}}},
    48. {"remount_userdata", {0, 0, {false, do_remount_userdata}}},
    49. {"restart", {1, 1, {false, do_restart}}},
    50. {"restorecon", {1, kMax, {true, do_restorecon}}},
    51. {"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}},
    52. {"rm", {1, 1, {true, do_rm}}},
    53. {"rmdir", {1, 1, {true, do_rmdir}}},
    54. {"setprop", {2, 2, {true, do_setprop}}},
    55. {"setrlimit", {3, 3, {false, do_setrlimit}}},
    56. {"start", {1, 1, {false, do_start}}},
    57. {"stop", {1, 1, {false, do_stop}}},
    58. {"swapon_all", {0, 1, {false, do_swapon_all}}},
    59. {"enter_default_mount_ns", {0, 0, {false, do_enter_default_mount_ns}}},
    60. {"symlink", {2, 2, {true, do_symlink}}},
    61. {"sysclktz", {1, 1, {false, do_sysclktz}}},
    62. {"trigger", {1, 1, {false, do_trigger}}},
    63. {"verity_update_state", {0, 0, {false, do_verity_update_state}}},
    64. {"wait", {1, 2, {true, do_wait}}},
    65. {"wait_for_prop", {2, 2, {false, do_wait_for_prop}}},
    66. {"write", {2, 2, {true, do_write}}},
    67. };
    68. // clang-format on
    69. return builtin_functions;
    70. }
    71. // Builtin-function-map end

    2.init.rc中的服务是如何被启动的

    首先以ActionManager和ServiceList通过GetInstance分别创建单例,然后调用LoadBootScripts函数传入参数,LoadBootScripts代码如下,可以看到会先去ro.boot.init_rc中读取配置,如果为空,会进入解析init.rc的流程,否则解析配置

    1. static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
    2. //创建解析器
    3. Parser parser = CreateParser(action_manager, service_list);
    4. //获取ro.boot.init_rc配置
    5. std::string bootscript = GetProperty("ro.boot.init_rc", "");
    6. if (bootscript.empty()) {
    7. //解析init.rc
    8. parser.ParseConfig("/system/etc/init/hw/init.rc");
    9. //如果init分区没有挂载,添加到late_import_paths
    10. if (!parser.ParseConfig("/system/etc/init")) {
    11. late_import_paths.emplace_back("/system/etc/init");
    12. }
    13. // late_import is available only in Q and earlier release. As we don't
    14. // have system_ext in those versions, skip late_import for system_ext.
    15. parser.ParseConfig("/system_ext/etc/init");
    16. //如果vender分区没有挂载,添加到late_import_paths
    17. if (!parser.ParseConfig("/vendor/etc/init")) {
    18. late_import_paths.emplace_back("/vendor/etc/init");
    19. }
    20. //如果odm分区没有挂载,添加到late_import_paths
    21. if (!parser.ParseConfig("/odm/etc/init")) {
    22. late_import_paths.emplace_back("/odm/etc/init");
    23. }
    24. //如果product分区没有挂载,添加到late_import_paths
    25. if (!parser.ParseConfig("/product/etc/init")) {
    26. late_import_paths.emplace_back("/product/etc/init");
    27. }
    28. } else {
    29. //解析ro.boot.init_rc
    30. parser.ParseConfig(bootscript);
    31. }
    32. }

    Android Init Language

    init.rc文件是用Android Init Language编写的特殊文件,使用这种语法编写的文件,统一用.rc作为文件后缀,其语法指令规则可参考源码system/core/init/README.md文档,其中包含Commands、Options等,

    Commands定义在system/core/init/builtins.cpp

    Options定义在system/core/init/service_parser.cpp

    后续会单独篇幅说明这个语法规则,本篇暂不展开说明。

    init.rc文件在源码中的位置:system/core/rootdir/init.rc

    回到SecondStageMain方法中,am.ExecuteOneCommand()函数会执行从.rc文件中解析出来的指令,跟一下这个函数,函数在./action_manager.cpp第67行:

    1. void ActionManager::ExecuteOneCommand() {
    2. {
    3. auto lock = std::lock_guard{event_queue_lock_};
    4. // Loop through the event queue until we have an action to execute
    5. while (current_executing_actions_.empty() && !event_queue_.empty()) {
    6. for (const auto& action : actions_) {
    7. if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
    8. event_queue_.front())) {
    9. current_executing_actions_.emplace(action.get());
    10. }
    11. }
    12. event_queue_.pop();
    13. }
    14. }
    15. if (current_executing_actions_.empty()) {
    16. return;
    17. }
    18. //从队列头获得一个action
    19. auto action = current_executing_actions_.front();
    20. if (current_command_ == 0) {
    21. std::string trigger_name = action->BuildTriggersString();
    22. LOG(INFO) << "processing action (" << trigger_name << ") from (" << action->filename()
    23. << ":" << action->line() << ")";
    24. }
    25. //调用到action的ExecuteOneCommand中,current_command_代表行数
    26. action->ExecuteOneCommand(current_command_);
    27. // If this was the last command in the current action, then remove
    28. // the action from the executing list.
    29. // If this action was oneshot, then also remove it from actions_.
    30. ++current_command_;
    31. if (current_command_ == action->NumCommands()) {
    32. current_executing_actions_.pop();
    33. current_command_ = 0;
    34. if (action->oneshot()) {
    35. auto eraser = [&action](std::unique_ptr<Action>& a) { return a.get() == action; };
    36. actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser),
    37. actions_.end());
    38. }
    39. }
    40. }

    会调用到action->ExecuteOneCommand()函数,继续跟./action.cpp:146行:

    1. void Action::ExecuteOneCommand(std::size_t command) const {
    2. // We need a copy here since some Command execution may result in
    3. // changing commands_ vector by importing .rc files through parser
    4. Command cmd = commands_[command];
    5. //继续跟
    6. ExecuteCommand(cmd);
    7. }
    8. void Action::ExecuteCommand(const Command& command) const {
    9. android::base::Timer t;
    10. //执行了InvokeFunc
    11. auto result = command.InvokeFunc(subcontext_);
    12. auto duration = t.duration();
    13. // Any action longer than 50ms will be warned to user as slow operation
    14. if (!result.has_value() || duration > 50ms ||
    15. android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
    16. std::string trigger_name = BuildTriggersString();
    17. std::string cmd_str = command.BuildCommandString();
    18. LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << " (" << filename_
    19. << ":" << command.line() << ") took " << duration.count() << "ms and "
    20. << (result.ok() ? "succeeded" : "failed: " + result.error().message());
    21. }
    22. }

    调用到command.InvokeFunc()函数中,看看做了什么:

    1. Result<void> Command::InvokeFunc(Subcontext* subcontext) const {
    2. //从vendor 或 oem 解析出来的rc文件都会走这里,会有一定限制
    3. if (subcontext) {
    4. if (execute_in_subcontext_) {
    5. return subcontext->Execute(args_);
    6. }
    7. auto expanded_args = subcontext->ExpandArgs(args_);
    8. if (!expanded_args.ok()) {
    9. return expanded_args.error();
    10. }
    11. return RunBuiltinFunction(func_, *expanded_args, subcontext->context());
    12. }
    13. //原生init.rc文件命令会走这里
    14. return RunBuiltinFunction(func_, args_, kInitContext);
    15. }
    16. Result<void> RunBuiltinFunction(const BuiltinFunction& function,
    17. const std::vector<std::string>& args, const std::string& context) {
    18. auto builtin_arguments = BuiltinArguments(context);
    19. builtin_arguments.args.resize(args.size());
    20. builtin_arguments.args[0] = args[0];
    21. for (std::size_t i = 1; i < args.size(); ++i) {
    22. auto expanded_arg = ExpandProps(args[i]);
    23. if (!expanded_arg.ok()) {
    24. return expanded_arg.error();
    25. }
    26. builtin_arguments.args[i] = std::move(*expanded_arg);
    27. }
    28. //执行这个函数
    29. return function(builtin_arguments);
    30. }

    function就是上面第一点提到的,当触发map中元素key调用时,会对应调用value对应的函数,这里以init.rc中一段脚本举例,先不看启动条件,仅看一下单纯指令,看一下服务是如何启动的:

    1. on zygote-start && ...
    2. ...
    3. start statsd
    4. start netd
    5. start zygote
    6. start zygote_secondary

    结合上面map中的key-value对应关系,发现start对应着do_start函数,源码位置/system/core/init/builtins.cpp:

    1. static Result<void> do_start(const BuiltinArguments& args) {
    2. //通过传入的arg,查找对应服务
    3. Service* svc = ServiceList::GetInstance().FindService(args[1]);
    4. if (!svc) return Error() << "service " << args[1] << " not found";
    5. //通过调用start执行
    6. if (auto result = svc->Start(); !result.ok()) {
    7. return ErrorIgnoreEnoent() << "Could not start service: " << result.error();
    8. }
    9. return {};
    10. }

    通过命令搜索

    1. grep "::Start()" ./ -rn
    2. 搜索结果
    3. ./service.cpp:397:Result<void> Service::Start() {

    函数如下

    1. Result<void> Service::Start() {
    2. ...
    3. pid_t pid = -1;
    4. //通过克隆或者fork子进程
    5. if (namespaces_.flags) {
    6. pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr);
    7. } else {
    8. pid = fork();
    9. }
    10. //子进程创建成功
    11. if (pid == 0) {
    12. //设置权限掩码
    13. umask(077);
    14. if (auto result = EnterNamespaces(namespaces_, name_, override_mount_namespace);
    15. !result.ok()) {
    16. LOG(FATAL) << "Service '" << name_
    17. << "' failed to set up namespaces: " << result.error();
    18. }
    19. for (const auto& [key, value] : environment_vars_) {
    20. setenv(key.c_str(), value.c_str(), 1);
    21. }
    22. for (const auto& descriptor : descriptors) {
    23. descriptor.Publish();
    24. }
    25. if (auto result = WritePidToFiles(&writepid_files_); !result.ok()) {
    26. LOG(ERROR) << "failed to write pid to files: " << result.error();
    27. }
    28. if (task_profiles_.size() > 0 && !SetTaskProfiles(getpid(), task_profiles_)) {
    29. LOG(ERROR) << "failed to set task profiles";
    30. }
    31. // As requested, set our gid, supplemental gids, uid, context, and
    32. // priority. Aborts on failure.
    33. SetProcessAttributesAndCaps();
    34. //内部调用的execv来启动的程序
    35. if (!ExpandArgsAndExecv(args_, sigstop_)) {
    36. PLOG(ERROR) << "cannot execv('" << args_[0]
    37. << "'). See the 'Debugging init' section of init's README.md for tips";
    38. }
    39. _exit(127);
    40. }
    41. if (pid < 0) {
    42. pid_ = 0;
    43. return ErrnoError() << "Failed to fork";
    44. }
    45. ...
    46. return {};
    47. }

    追一下ExpandArgsAndExecv函数:

    1. static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigstop) {
    2. std::vector<std::string> expanded_args;
    3. std::vector<char*> c_strings;
    4. expanded_args.resize(args.size());
    5. c_strings.push_back(const_cast<char*>(args[0].data()));
    6. for (std::size_t i = 1; i < args.size(); ++i) {
    7. auto expanded_arg = ExpandProps(args[i]);
    8. if (!expanded_arg.ok()) {
    9. LOG(FATAL) << args[0] << ": cannot expand arguments': " << expanded_arg.error();
    10. }
    11. expanded_args[i] = *expanded_arg;
    12. c_strings.push_back(expanded_args[i].data());
    13. }
    14. c_strings.push_back(nullptr);
    15. if (sigstop) {
    16. kill(getpid(), SIGSTOP);
    17. }
    18. //有没有很熟悉,最终还是通过执行execv来执行程序文件的
    19. return execv(c_strings[0], c_strings.data()) == 0;
    20. }

    先通过克隆或者fork子进程,然后调用execv函数启动程序文件,由此一个服务就启动起来了。

    至此一个完整的init进程启动服务就分析完成了,下一篇分析一下zygote的启动及zygote启动后做了哪些事情!

  • 相关阅读:
    通过自学可以搭建量化交易模型吗?
    AtCoder ABC 319E 中国剩余定理
    JAVA【注解】 自定义注解
    Jenkins实现基础CI操作
    JVM第二讲:JVM 基础 - 字节码详解
    HashMap实现原理, 扩容机制,面试题和总结
    双软认证需要材料,怎么办理
    tcp的建立连接和断开连接
    TEMPEST HDMI泄漏接收 5
    游戏网页设计成品 学校班级网页制作模板 大学生静态HTML网页源码 dreamweaver网页作业 简单网页课程成品
  • 原文地址:https://blog.csdn.net/qq_34508943/article/details/133685949