Android 的 init 进程是 Android 系统的第一个用户空间进程,也是整个系统的启动进程。它是 Linux 系统中 init 进程(进程ID为1)的一个实例,负责系统的初始化和启动整个 Android 系统的各个组件。
init 进程在系统引导时被内核加载并执行,它会读取 Android 的 init 脚本(位于 /system/etc/init 目录下),并按照脚本中的指令来初始化系统。
Android的init进程的一些主要职责包括:
1)启动和运行各个关键服务(如Zygote、SurfaceFlinger、PackageManager等)和守护进程(如adbd、rild等)。
2)挂载文件系统和设备节点,并设置文件权限。
3)执行各个设备的硬件初始化,如设置IO调度、加载硬件驱动等。
4)创建和启动Android系统的各个组件,如应用程序进程、系统服务进程等。
5)处理系统运行过程中的一些事件和信号,如处理低内存、重启系统等。
总的来说,Android 的 init 进程在整个系统启动过程中起着重要的作用,它负责协调和管理系统中的各个组件,确保系统能正常初始化和启动。
一、源码解析
首先,对于入口函数都是调用 main() 函数,但对于不同的 Android 版本还是有些区别的,我们先来看一下 Android 9.0 版本的,init 初始化。
1、Android 9.0 init初始化
init.cpp
源码位置:/system/core/init/init.cpp
int main(int argc, char** argv) {
bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
// 第一次挂载
if (is_first_stage) {
……
// 挂载和创建一系列文件夹
// 初始化Kernel日志
InitKernelLogging(argv);
LOG(INFO) << "init first stage started!";
……
}
// 此时,我们处于init的第二阶段。
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";
……
// 创建一块共享的内存空间,用于属性服务
property_init();
……
// 初始化epoll功能
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd == -1) {
PLOG(FATAL) << "epoll_create1 failed";
}
// 初始化子进程退出的信号处理函数,并调用epoll_ctl设置signal fd可读的回调函数
sigchld_handler_init();
……
// 加载default.prop文件
property_load_boot_defaults();
export_oem_lock_status();
// 启动属性服务器,此处会调用epoll_ctl设置property fd可读的回调函数
start_property_service();
set_usb_controller();
……
ActionManager& am = ActionManager::GetInstance();
ServiceList& sm = ServiceList::GetInstance();
// 该方法内解析init.rc文件
LoadBootScripts(am, sm);
// 执行rc文件中触发器为on early-init的语句
am.QueueEventTrigger("early-init");
// 等冷插拔设备初始化完成
am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
// ... so that we can start queuing up actions that require stuff from /dev.
am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
// 设备组合键的初始化操作,此处会调用epoll_ctl设置keychord fd可读的回调函数
am.QueueBuiltinAction(keychord_init_action, "keychord_init");
// 屏幕上显示Android静态Logo
am.QueueBuiltinAction(console_init_action, "console_init");
// 执行rc文件中触发器为on init的语句
am.QueueEventTrigger("init");
// 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");
// 当处于充电模式,则charger加入执行队列;否则late-init加入队列。
std::string bootmode = GetProperty("ro.bootmode", "");
if (bootmode == "charger") {
am.QueueEventTrigger("charger");
} else {
am.QueueEventTrigger("late-init");
}
// Run all property triggers based on current state of the properties.
am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
while (true) {
// 默认情况下,休眠直到有事情发生
int epoll_timeout_ms = -1;
if (do_shutdown && !shutting_down) {
do_shutdown = false;
if (HandlePowerctlMessage(shutdown_command)) {
shutting_down = true;
}
}
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_restart_time = RestartProcesses();
// 如果有一个进程需要重新启动,及时唤醒
if (next_process_restart_time) {
epoll_timeout_ms = std::chrono::ceil<std::chrono::milliseconds>(*next_process_restart_time - boot_clock::now()).count();
if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
}
}
// 如果有更多的工作要做,马上唤醒
if (am.HasMoreCommands()) epoll_timeout_ms = 0;
}
epoll_event ev;
// 循环等待事件发生
int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
if (nr == -1) {
PLOG(ERROR) << "epoll_wait failed";
} else if (nr == 1) {
((void (*)()) ev.data.ptr)();
}
}
return 0;
}
接下来我们看一下 Android 12 init 初始化流程。
2、Android 12 init初始化
首先他的初始 main() 函数就就没在 init.cpp 中,而是在 main.cpp 中。
main.cpp
源码位置:/system/core/init/main.cpp
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
__asan_set_error_report_callback(AsanReportCallback);
#endif
// 稍后将恢复Boost prio
// 设置进程的优先级
setpriority(PRIO_PROCESS, 0, -20);
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
if (argc > 1) {
if (!strcmp(argv[1], "subcontext")) {
android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
return SubcontextMain(argc, argv, &function_map);
}
if (!strcmp(argv[1], "selinux_setup")) {
return SetupSelinux(argv);
}
if (!strcmp(argv[1], "second_stage")) {
return SecondStageMain(argc, argv);
}
}
return FirstStageMain(argc, argv);
}
这是整个 Android 系统的入口点。它包含 main()
函数,是进程的入口函数。在这个文件中,主要进行一些初始化的准备工作,然后根据命令行参数的不同分发到不同的逻辑处理代码。
subcontext.cpp
源码位置:/system/core/init/subcontext.cpp
int SubcontextMain(int argc, char** argv, const BuiltinFunctionMap* function_map) {
if (argc < 4) LOG(FATAL) << "Fewer than 4 args specified to subcontext (" << argc << ")";
auto context = std::string(argv[2]);
auto init_fd = std::atoi(argv[3]);
SelabelInitialize();
trigger_shutdown = [](const std::string& command) { shutdown_command = command; };
auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
// 在主循环之前恢复prio
setpriority(PRIO_PROCESS, 0, 0);
subcontext_process.MainLoop();
return 0;
}
它是关于子上下文(subcontext)的初始化实现。在 Android 系统中,子上下文是由 init 进程创建和管理的一个独立的子进程。子上下文通常用于在系统初始化时执行较早的一些任务,比如设置一些特殊的属性、启动一些特定的服务等
selinux.cpp
源码位置:/system/core/init/selinux.cpp
int SetupSelinux(char** argv) {
……
// 挂载缺失的系统分区
MountMissingSystemPartitions();
// 设置 SELinux 内核日志记录。
SelinuxSetupKernelLogging();
// 读取策略文件
std::string policy;
ReadPolicy(&policy);
// 根据需要创建辅助类
auto snapuserd_helper = SnapuserdSelinuxHelper::CreateIfNeeded();
……
// 加载 SELinux 策略
LoadSelinuxPolicy(policy);
……
// 设置 SELinux 强制执行
SelinuxSetEnforcement();
……
const char* path = "/system/bin/init";
const char* args[] = {path, "second_stage", nullptr};
// 执行 /system/bin/init
execv(path, const_cast<char**>(args));
……
return 1;
}
其中包含了与 SELinux(Security-Enhanced Linux)安全机制相关的初始化逻辑。
SELinux 是一种 Linux 内核的安全模块,用于实现强制访问控制(MAC)机制。在 Android 系统中,SELinux 被广泛用于加强系统的安全性,限制各个进程之间的访问和操作。在该文件中,会包含与 SELinux 初始化相关的函数、变量和逻辑。具体的实现会依赖于 Android 系统的版本和设备的要求,用于配置和启动 SELinux 的相关功能。
first_stage_init.cpp
源码位置:/system/core/init/first_stage_init.cpp
int FirstStageMain(int argc, char** argv) {
……
}
这里主要进行 Android 系统的第一阶段初始化的实现。第一阶段初始化是在 Linux 内核引导进程(Kernel Init Process)执行后,init进程开始运行之前的阶段。它仅负责最基本的硬件初始化和文件系统挂载。这部分代码其实就是上面 Android 9.0 中 if (is_first_stage) 部分的代码。
init.cpp
源码位置:/system/core/init/init.cpp
int SecondStageMain(int argc, char** argv) {
……
// 初始化Kernel日志
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";
……
// 初始化系统属性
PropertyInit();
……
// 安装信号文件描述符处理程序
InstallSignalFdHandler(&epoll);
// 启动属性服务
StartPropertyService(&property_fd);
// 记录系统启动时间
RecordStageBoottimes(start_time);
// 设置 USB 控制器
SetUsbController();
// 该方法内解析init.rc文件
LoadBootScripts(am, sm);
while (true) {
// 默认情况下,休眠直到有事情发生
auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
auto shutdown_command = shutdown_state.CheckShutdown();
if (shutdown_command) {
HandlePowerctlMessage(*shutdown_command);
shutdown_state.set_do_shutdown(false);
}
if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
am.ExecuteOneCommand();
}
if (!IsShuttingDown()) {
auto next_process_action_time = HandleProcessActions();
// 如果有一个进程需要重新启动,及时唤醒
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 (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
// If there's more work to do, wake up again immediately.
if (am.HasMoreCommands()) epoll_timeout = 0ms;
}
auto pending_functions = epoll.Wait(epoll_timeout);
if (!pending_functions.ok()) {
LOG(ERROR) << pending_functions.error();
} else if (!pending_functions->empty()) {
// 我们总是在响应其他挂起函数之前收获子函数。这是为了防止其他守护进程看到服务已经退出并要求init通过ctl重新启动它的竞争。在init获取它之前启动。
ReapAnyOutstandingChildren();
for (const auto& function : *pending_functions) {
(*function)();
}
}
if (!IsShuttingDown()) {
HandleControlMessages();
SetUsbController();
}
}
return 0;
}
这里主要进行了Android系统的init进程的主要逻辑实现。init进程是在Linux内核启动后作为第一个用户空间进程运行的,它负责初始化系统服务、加载设备配置、解析init.rc文件以及其他一些系统启动任务。
总结
可以看到,Android 12 主要是是将 Android 9.0 的 init.cpp 中 main() 函数不同功能进行了拆分,分别完成初始化工作。