查看原文
其他

Android 10.0系统启动之init进程(三)-「Android取经之路」

IngresGe IngresGe 2021-11-05



上一节主要讲解了Init进程的第一阶段启动过程以及SELinux规则加载。

Android取经之路——启动篇

Android系统架构-[Android取经之路]

Android是怎么启动的-[Android取经之路]

Android系统启动之init进程(一)-「Android取经之路」

Android系统启动之init进程(二)-「Android取经之路」

本节主要开始讲解Init进程的第二阶段。


4.5 init进程启动第二阶段

第二阶段主要内容:

  •  创建进程会话密钥并初始化属性系统

  •  进行SELinux第二阶段并恢复一些文件安全上下文

  •  新建epoll并初始化子进程终止信号处理函数,详细看第五节-信号处理

  •  启动匹配属性的服务端, 详细查看第六节-属性服务

  •  解析init.rc等文件,建立rc文件的action 、service,启动其他进程,详细查看第七节-rc文件解析


4.5.1  SecondStageMain

int SecondStageMain(int argc, char** argv) { /* 01. 创建进程会话密钥并初始化属性系统 */ keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1); //创建 /dev/.booting 文件,就是个标记,表示booting进行中 close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000)); // 初始化属性系统,并从指定文件读取属性 property_init(); /* 02. 进行SELinux第二阶段并恢复一些文件安全上下文 */ SelinuxRestoreContext();/* 03. 新建epoll并初始化子进程终止信号处理函数 */ Epoll epoll; if (auto result = epoll.Open(); !result) { PLOG(FATAL) << result.error(); } InstallSignalFdHandler(&epoll); /* 04. 设置其他系统属性并开启系统属性服务*/ StartPropertyService(&epoll); /* 05 解析init.rc等文件,建立rc文件的action 、service,启动其他进程*/ ActionManager& am = ActionManager::GetInstance(); ServiceList& sm = ServiceList::GetInstance(); LoadBootScripts(am, sm);}


代码流程详细解析:

代码路径:platform/system/core/init.cpp

int SecondStageMain(int argc, char** argv) { /* *init crash时重启引导加载程序 *这个函数主要作用将各种信号量,如SIGABRT,SIGBUS等的行为设置为SA_RESTART,一旦监听到这些信号即执行重启系统 */ if (REBOOT_BOOTLOADER_ON_PANIC) { InstallRebootSignalHandlers(); }
//把标准输入、标准输出和标准错误重定向到空设备文件"/dev/null" SetStdioToDevNull(argv); //在/dev目录下挂载好 tmpfs 以及 kmsg //这样就可以初始化 /kernel Log 系统,供用户打印log InitKernelLogging(argv); LOG(INFO) << "init second stage started!";
// 01. 创建进程会话密钥并初始化属性系统 keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);
//创建 /dev/.booting 文件,就是个标记,表示booting进行中 close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
// 初始化属性系统,并从指定文件读取属性 property_init();
/* * 1.如果参数同时从命令行和DT传过来,DT的优先级总是大于命令行的 * 2.DT即device-tree,中文意思是设备树,这里面记录自己的硬件配置和系统运行参数, */ process_kernel_dt(); // 处理 DT属性 process_kernel_cmdline(); // 处理命令行属性
// 处理一些其他的属性 export_kernel_boot_props();
// Make the time that init started available for bootstat to log. property_set("ro.boottime.init", getenv("INIT_STARTED_AT")); property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
// Set libavb version for Framework-only OTA match in Treble build. const char* avb_version = getenv("INIT_AVB_VERSION"); if (avb_version) property_set("ro.boot.avb_version", avb_version);
// See if need to load debug props to allow adb root, when the device is unlocked. const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE"); if (force_debuggable_env && AvbHandle::IsDeviceUnlocked()) { load_debug_prop = "true"s == force_debuggable_env; }
// 基于cmdline设置memcg属性 bool memcg_enabled = android::base::GetBoolProperty("ro.boot.memcg",false); if (memcg_enabled) { // root memory control cgroup mkdir("/dev/memcg", 0700); chown("/dev/memcg",AID_ROOT,AID_SYSTEM); mount("none", "/dev/memcg", "cgroup", 0, "memory"); // app mem cgroups, used by activity manager, lmkd and zygote mkdir("/dev/memcg/apps/",0755); chown("/dev/memcg/apps/",AID_SYSTEM,AID_SYSTEM); mkdir("/dev/memcg/system",0550); chown("/dev/memcg/system",AID_SYSTEM,AID_SYSTEM); }
// 清空这些环境变量,之前已经存到了系统属性中去了 unsetenv("INIT_STARTED_AT"); unsetenv("INIT_SELINUX_TOOK"); unsetenv("INIT_AVB_VERSION"); unsetenv("INIT_FORCE_DEBUGGABLE");
// Now set up SELinux for second stage. SelinuxSetupKernelLogging(); SelabelInitialize();
/* * 02. 进行SELinux第二阶段并恢复一些文件安全上下文 * 恢复相关文件的安全上下文,因为这些文件是在SELinux安全机制初始化前创建的, * 所以需要重新恢复上下文 */ SelinuxRestoreContext();
/* * 03. 新建epoll并初始化子进程终止信号处理函数 * 创建epoll实例,并返回epoll的文件描述符 */ Epoll epoll; if (auto result = epoll.Open(); !result) { PLOG(FATAL) << result.error(); }
/* *主要是创建handler处理子进程终止信号,注册一个signal到epoll进行监听 *进行子继承处理 */ InstallSignalFdHandler(&epoll);
// 进行默认属性配置相关的工作 property_load_boot_defaults(load_debug_prop); UmountDebugRamdisk(); fs_mgr_vendor_overlay_mount_all(); export_oem_lock_status();
/* *04. 设置其他系统属性并开启系统属性服务 */ StartPropertyService(&epoll); MountHandler mount_handler(&epoll);
//为USB存储设置udc Contorller, sys/class/udc set_usb_controller();
// 匹配命令和函数之间的对应关系 const BuiltinFunctionMap function_map; Action::set_function_map(&function_map);
if (!SetupMountNamespaces()) { PLOG(FATAL) << "SetupMountNamespaces failed"; }
// 初始化文件上下文 subcontexts = InitializeSubcontexts();
/* *05 解析init.rc等文件,建立rc文件的action 、service,启动其他进程 */ ActionManager& am = ActionManager::GetInstance(); ServiceList& sm = ServiceList::GetInstance();
LoadBootScripts(am, sm);
// Turning this on and letting the INFO logging be discarded adds 0.2s to // Nexus 9 boot time, so it's disabled by default. if (false) DumpState();
// 当GSI脚本running时,确保GSI状态可用. if (android::gsi::IsGsiRunning()) { property_set("ro.gsid.image_running", "1"); } else { property_set("ro.gsid.image_running", "0"); }

am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
// 执行rc文件中触发器为 on early-init 的语句 am.QueueEventTrigger("early-init");
// 等冷插拔设备初始化完成 am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
// 开始查询来自 /dev的 action am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng"); am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits"); am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
// 设备组合键的初始化操作 Keychords keychords; am.QueueBuiltinAction( [&epoll, &keychords](const BuiltinArguments& args) -> Result<Success> { for (const auto& svc : ServiceList::GetInstance()) { keychords.Register(svc->keycodes()); } keychords.Start(&epoll, HandleKeychord); return Success(); }, "KeychordInit");
//在屏幕上显示Android 静态LOGO am.QueueBuiltinAction(console_init_action, "console_init");
// 执行rc文件中触发器为on init的语句 am.QueueEventTrigger("init");
// Starting the BoringSSL self test, for NIAP certification compliance. am.QueueBuiltinAction(StartBoringSslSelfTest, "StartBoringSslSelfTest");
// Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random // wasn't ready immediately after wait_for_coldboot_done am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
// Initialize binder before bringing up other system services am.QueueBuiltinAction(InitBinder, "InitBinder");
// 当设备处于充电模式时,不需要mount文件系统或者启动系统服务 // 充电模式下,将charger假如执行队列,否则把late-init假如执行队列 std::string bootmode = GetProperty("ro.bootmode", ""); if (bootmode == "charger") { am.QueueEventTrigger("charger"); } else { am.QueueEventTrigger("late-init"); }
// 基于属性当前状态 运行所有的属性触发器. am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
while (true) { // By default, sleep until something happens. auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
if (do_shutdown && !shutting_down) { do_shutdown = false; if (HandlePowerctlMessage(shutdown_command)) { shutting_down = true; } }
//依次执行每个action中携带command对应的执行函数 if (!(waiting_for_prop || Service::is_exec_service_running())) { am.ExecuteOneCommand(); } if (!(waiting_for_prop || Service::is_exec_service_running())) { if (!shutting_down) { auto next_process_action_time = HandleProcessActions();
// If there's a process that needs restarting, wake up in time for that. if (next_process_action_time) { epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>( *next_process_action_time - boot_clock::now()); if (*epoll_timeout < 0ms) epoll_timeout = 0ms; } }
// If there's more work to do, wake up again immediately. if (am.HasMoreCommands()) epoll_timeout = 0ms; }
// 循环等待事件发生 if (auto result = epoll.Wait(epoll_timeout); !result) { LOG(ERROR) << result.error(); } }
return 0;}


5. 信号处理

    init是一个守护进程,为了防止init的子进程成为僵尸进程(zombie process),需要init在子进程在结束时获取子进程的结束码,通过结束码将程序表中的子进程移除,防止成为僵尸进程的子进程占用程序表的空间(程序表的空间达到上限时,系统就不能再启动新的进程了,会引起严重的系统问题)。

信号处理主要工作:

  • 初始化信号signal句柄

  • 循环处理子进程

  • 注册epoll句柄

  • 处理子进程终止

注:

EPOLL类似于POLL,是Linux中用来做事件触发的,跟EventBus功能差不多

linux很长的时间都在使用select来做事件触发,它是通过轮询来处理的,轮询的fd数目越多,自然耗时越多,对于大量的描述符处理,EPOLL更有优势


5.1 InstallSignalFdHandler

    在linux当中,父进程是通过捕捉SIGCHLD信号来得知子进程运行结束的情况,SIGCHLD信号会在子进程终止的时候发出,了解这些背景后,我们来看看init进程如何处理这个信号。

    首先,新建一个sigaction结构体,sa_handler是信号处理函数,指向内核指定的函数指针SIG_DFL。 和Android 9.0及之前的版本不同,这里不再通过socket的读写句柄进行接收信号,改成了内核的信号处理函数SIG_DFL。

    然后,sigaction(SIGCHLD, &act, nullptr) 这个是建立信号绑定关系,也就是说当监听到SIGCHLD信号时,由act这个sigaction结构体处理

    最后,RegisterHandler 的作用就是signal_read_fd(之前的s[1])收到信号,触发handle_signal

    终上所述,InstallSignalFdHandler函数的作用就是,接收到SIGCHLD信号时触发HandleSignalFd进行信号处理

代码路径:platform/system/core/init.cpp

作用:该函数主要的作用是初始化子进程终止信号处理过程

static void InstallSignalFdHandler(Epoll* epoll) { // SA_NOCLDSTOP使init进程只有在其子进程终止时才会受到SIGCHLD信号 const struct sigaction act { .sa_handler = SIG_DFL, .sa_flags = SA_NOCLDSTOP }; sigaction(SIGCHLD, &act, nullptr); sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGCHLD); if (!IsRebootCapable()) { // 如果init不具有 CAP_SYS_BOOT的能力,则它此时正值容器中运行 // 在这种场景下,接收SIGTERM 将会导致系统关闭 sigaddset(&mask, SIGTERM); } if (sigprocmask(SIG_BLOCK, &mask, nullptr) == -1) { PLOG(FATAL) << "failed to block signals"; } // 注册处理程序以解除对子进程中的信号的阻止 const int result = pthread_atfork(nullptr, nullptr, &UnblockSignals); if (result != 0) { LOG(FATAL) << "Failed to register a fork handler: " << strerror(result); } //创建信号句柄 signal_fd = signalfd(-1, &mask, SFD_CLOEXEC); if (signal_fd == -1) { PLOG(FATAL) << "failed to create signalfd"; } //信号注册,当signal_fd收到信号时,触发HandleSignalFd if (auto result = epoll->RegisterHandler(signal_fd, HandleSignalFd); !result) { LOG(FATAL) << result.error(); }}



5.2 RegisterHandler

代码路径:/platform/system/core/epoll.cpp

作用:信号注册,把fd句柄加入到 epoll_fd_的监听队列中

Result<void> Epoll::RegisterHandler(int fd, std::function<void()> handler, uint32_t events) { if (!events) { return Error() << "Must specify events"; } auto [it, inserted] = epoll_handlers_.emplace(fd, std::move(handler)); if (!inserted) { return Error() << "Cannot specify two epoll handlers for a given FD"; } epoll_event ev; ev.events = events; // std::map's iterators do not get invalidated until erased, so we use the // pointer to the std::function in the map directly for epoll_ctl. ev.data.ptr = reinterpret_cast<void*>(&it->second); // 将fd的可读事件加入到epoll_fd_的监听队列中 if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &ev) == -1) { Result<void> result = ErrnoError() << "epoll_ctl failed to add fd"; epoll_handlers_.erase(fd); return result; } return {};}



5.3 HandleSignalFd

代码路径:platform/system/core/init.cpp

作用:监控SIGCHLD信号,调用 ReapAnyOutstandingChildren 来 终止出现问题的子进程

static void HandleSignalFd() { signalfd_siginfo siginfo; ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo))); if (bytes_read != sizeof(siginfo)) { PLOG(ERROR) << "Failed to read siginfo from signal_fd"; return; }//监控SIGCHLD信号 switch (siginfo.ssi_signo) { case SIGCHLD: ReapAnyOutstandingChildren(); break; case SIGTERM: HandleSigtermSignal(siginfo); break; default: PLOG(ERROR) << "signal_fd: received unexpected signal " << siginfo.ssi_signo; break; }}



5.4 ReapOneProcess

代码路径:/platform/system/core/sigchld_handle.cpp

作用:ReapOneProcess是最终的处理函数了,这个函数先用waitpid找出挂掉进程的pid,然后根据pid找到对应Service,

最后调用Service的Reap方法清除资源,根据进程对应的类型,决定是否重启机器或重启进程

void ReapAnyOutstandingChildren() { while (ReapOneProcess()) { }}static bool ReapOneProcess() { siginfo_t siginfo = {}; //用waitpid函数获取状态发生变化的子进程pid //waitpid的标记为WNOHANG,即非阻塞,返回为正值就说明有进程挂掉了 if (TEMP_FAILURE_RETRY(waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG | WNOWAIT)) != 0) { PLOG(ERROR) << "waitid failed"; return false; } auto pid = siginfo.si_pid; if (pid == 0) return false; // 当我们知道当前有一个僵尸pid,我们使用scopeguard来清楚该pid auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); }); std::string name; std::string wait_string; Service* service = nullptr; if (SubcontextChildReap(pid)) { name = "Subcontext"; } else { //通过pid找到对应的service service = ServiceList::GetInstance().FindService(pid, &Service::pid); if (service) { name = StringPrintf("Service '%s' (pid %d)", service->name().c_str(), pid); if (service->flags() & SVC_EXEC) { auto exec_duration = boot_clock::now() - service->time_started(); auto exec_duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>(exec_duration).count(); wait_string = StringPrintf(" waiting took %f seconds", exec_duration_ms / 1000.0f); } else if (service->flags() & SVC_ONESHOT) { auto exec_duration = boot_clock::now() - service->time_started(); auto exec_duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>(exec_duration) .count(); wait_string = StringPrintf(" oneshot service took %f seconds in background", exec_duration_ms / 1000.0f); } } else { name = StringPrintf("Untracked pid %d", pid); } } if (siginfo.si_code == CLD_EXITED) { LOG(INFO) << name << " exited with status " << siginfo.si_status << wait_string; } else { LOG(INFO) << name << " received signal " << siginfo.si_status << wait_string; } //没有找到service,说明已经结束了,退出 if (!service) return true; service->Reap(siginfo);//清除子进程相关的资源 if (service->flags() & SVC_TEMPORARY) { ServiceList::GetInstance().RemoveService(*service); //移除该service } return true;}


下一节主要会讲解属性服务启动、init.rc解析流程以及zygote的启动浅析。

视频 小程序 ,轻点两下取消赞 在看 ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存