Android 12 init(1) 启动流程分析

文章托管在gitee上 Android Notes , 同步csdn
本文基于Android12 分析

概述

init是 Android 启动的第一个用户空间进程,它的地位非常重要,它fork产生系统的一些关键进程(如zygote,surfaceflinger进程),而zygote进一步fork产生system_server和其他应用进程,通过这套逻辑构建了Android的进程层次结构体系。init进程的功能包含但不限于以下:

  • 挂载系统分区和加载一些内核模块
  • 加载sepolicy 及使能 selinux
  • 支持属性服务
  • 启动脚本rc文件解析
  • 执行事件触发器和属性改变的事件
  • 子进程死亡监听,回收僵尸进程
  • 非oneshot服务保活

通过ps命令看看init进程信息

# ps -A|grep init 
root 1 0 10847128 4020 do_epoll_wait 0 S init # 这个是 init 进程
root 166 1 10817360 1916 do_sys_poll 0 S init # 这个是 subcontext 进程

在启动内核的start_kernel函数流程中,会调用run_init_process函数执行init程序,来启动init进程

run_init_process

在Android中执行的init是/init

/// @kernel_common/init/main.c
static int run_init_process(const char *init_filename)
{
	argv_init[0] = init_filename;
	pr_info("Run %s as init process\n", init_filename);
	return do_execve(getname_kernel(init_filename),
	(const char __user *const __user *)argv_init,
	(const char __user *const __user *)envp_init);
}

/init 实际上是一个软链接,指向的是/system/bin/init

# ls /init -lZ 
lrwxr-x--- 1 root shell u:object_r:init_exec:s0 16 2021-12-20 15:52 /init -> /system/bin/init

接下来,进入init的main函数。

main

main执行分为几个阶段:

  • FirstStage 挂载一些基础文件系统和加载内核模块等
  • selinux_setup 执行selinux的初始化
  • SecondStage 挂载其他文件系统,启动属性服务,执行boot流程等,主要逻辑都在这里实现
/// @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 which will be restored later
 setpriority(PRIO_PROCESS, 0, -20);
 if (!strcmp(basename(argv[0]), "ueventd")) { // 处理uventd启动,共用一个main
 return ueventd_main(argc, argv);
 }
 if (argc > 1) {
 if (!strcmp(argv[1], "subcontext")) { // subcontext 子进程入口,用于执行来自init的某些任务
 android::base::InitLogging(argv, &android::base::KernelLogger);
 const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
 return SubcontextMain(argc, argv, &function_map);
 }
 if (!strcmp(argv[1], "selinux_setup")) {// selinux初始化阶段
 return SetupSelinux(argv);
 }
 if (!strcmp(argv[1], "second_stage")) {// 启动第二阶段
 return SecondStageMain(argc, argv);
 }
 }
 return FirstStageMain(argc, argv); // 启动第一阶段
}

FirstStageMain

第一阶段初始化

/// @system/core/init/first_stage_init.cpp
int FirstStageMain(int argc, char** argv) {
 if (REBOOT_BOOTLOADER_ON_PANIC) {// 设置panic处理器
 InstallRebootSignalHandlers();
 }
 boot_clock::time_point start_time = boot_clock::now();
 std::vector errors;
#define CHECKCALL(x) \
 if ((x) != 0) errors.emplace_back(#x " failed", errno);
 // Clear the umask.
 umask(0);
 CHECKCALL(clearenv());
 CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));
 // 挂载一些基础文件系统
 // Get the basic filesystem setup we need put together in the initramdisk
 // on / and then we'll let the rc file figure out the rest.
 CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
 CHECKCALL(mkdir("/dev/pts", 0755));
 CHECKCALL(mkdir("/dev/socket", 0755));
 CHECKCALL(mkdir("/dev/dm-user", 0755));
 CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
#define MAKE_STR(x) __STRING(x)
 // /proc 伪文件系统,记录进程、线程相关实时状态
 CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
#undef MAKE_STR
 // Don't expose the raw commandline to unprivileged processes.
 CHECKCALL(chmod("/proc/cmdline", 0440)); // 只读
 std::string cmdline;
 android::base::ReadFileToString("/proc/cmdline", &cmdline);
 // Don't expose the raw bootconfig to unprivileged processes.
 chmod("/proc/bootconfig", 0440);
 std::string bootconfig;
 android::base::ReadFileToString("/proc/bootconfig", &bootconfig);

InstallRebootSignalHandlers

init信号处理器,调试版本当init crash,默认重启到 bootLoader

void InstallRebootSignalHandlers() {
 // Instead of panic'ing the kernel as is the default behavior when init crashes,
 // we prefer to reboot to bootloader on development builds, as this will prevent
 // boot looping bad configurations and allow both developers and test farms to easily
 // recover.
 struct sigaction action;
 memset(&action, 0, sizeof(action));
 sigfillset(&action.sa_mask);
 action.sa_handler = [](int signal) {
 // These signal handlers are also caught for processes forked from init, however we do not
 // want them to trigger reboot, so we directly call _exit() for children processes here.
 if (getpid() != 1) { // 非init直接退出
 _exit(signal);
 }
 // Calling DoReboot() or LOG(FATAL) is not a good option as this is a signal handler.
 // RebootSystem uses syscall() which isn't actually async-signal-safe, but our only option
 // and probably good enough given this is already an error case and only enabled for
 // development builds.
 InitFatalReboot(signal); // 执行重启操作
 };
 action.sa_flags = SA_RESTART;
 // 设置信号处理器
 sigaction(SIGABRT, &action, nullptr);
 sigaction(SIGBUS, &action, nullptr);
 sigaction(SIGFPE, &action, nullptr);
 sigaction(SIGILL, &action, nullptr);
 sigaction(SIGSEGV, &action, nullptr);
#if defined(SIGSTKFLT)
 sigaction(SIGSTKFLT, &action, nullptr);
#endif
 sigaction(SIGSYS, &action, nullptr);
 sigaction(SIGTRAP, &action, nullptr);
}

InitFatalReboot

默认执行重启的 init_fatal_reboot_target 的值是 bootloader

/// @system/core/init/reboot_utils.cpp
static std::string init_fatal_reboot_target = "bootloader";
void __attribute__((noreturn)) InitFatalReboot(int signal_number) {
 auto pid = fork();
 if (pid == -1) {
 // Couldn't fork, don't even try to backtrace, just reboot.
 RebootSystem(ANDROID_RB_RESTART2, init_fatal_reboot_target);
 } else if (pid == 0) { // 子进程确保能重启
 // Fork a child for safety, since we always want to shut down if something goes wrong, but
 // its worth trying to get the backtrace, even in the signal handler, since typically it
 // does work despite not being async-signal-safe.
 sleep(5);
 RebootSystem(ANDROID_RB_RESTART2, init_fatal_reboot_target);
 }
 // 先尝试获取 backtrace ,然后执行重启,
 // In the parent, let's try to get a backtrace then shutdown.
 LOG(ERROR) 

DoFirstStageMount

这里探究一下,在这个first stage挂载了那些分区

/// @system/core/init/first_stage_mount.cpp
// Mounts partitions specified by fstab in device tree.
bool DoFirstStageMount(bool create_devices) {
 // Skips first stage mount if we're in recovery mode.
 if (IsRecoveryMode()) {
 LOG(INFO) 

FirstStageMount::DoFirstStageMount

FirstStageMount::MountPartitions

bool FirstStageMount::MountPartitions() {
	 // 挂载 /system
 if (!TrySwitchSystemAsRoot()) return false;
	// 移除不需要挂载的分区
 if (!SkipMountingPartitions(&fstab_, true /* verbose */)) return false;

从上面分析可知,挂载的信息存储在fstab_ 里面,它是在FirstStageMount::Create函数中读取的

Result FirstStageMount::Create() {
 auto fstab = ReadFirstStageFstab(); // 此处读取 fstab
 if (!fstab.ok()) {
 return fstab.error();
 }
 if (IsDtVbmetaCompatible(*fstab)) { // 根据 compatible 创建不同对象
 return std::make_unique(std::move(*fstab));
 } else {
 return std::make_unique(std::move(*fstab));
 }
}

ReadFirstStageFstab

/// @system/core/init/first_stage_mount.cpp
static Result ReadFirstStageFstab() {
 Fstab fstab;
 if (!ReadFstabFromDt(&fstab)) { // 首先读取device tree, 默认值 /proc/device-tree/firmware/android/fstab
 if (ReadDefaultFstab(&fstab)) { // 没有读到,再读默认Fstab
 fstab.erase(std::remove_if(fstab.begin(), fstab.end(),
 [](const auto& entry) {
 return !entry.fs_mgr_flags.first_stage_mount;
 }),
 fstab.end());
 } else {
 return Error() 

ReadFstabFromDt

/// @system/core/fs_mgr/fs_mgr_fstab.cpp
std::string ReadFstabFromDt() {
 if (!is_dt_compatible() || !IsDtFstabCompatible()) {
 return {};
 }
	// 默认值 /proc/device-tree/firmware/android/fstab
 std::string fstabdir_name = get_android_dt_dir() + "/fstab";
 std::unique_ptr fstabdir(opendir(fstabdir_name.c_str()), closedir);
 if (!fstabdir) return {};
 dirent* dp;
 // Each element in fstab_dt_entries is .
 std::vector fstab_dt_entries;
 while ((dp = readdir(fstabdir.get())) != NULL) { // 读取 fstab 信息
 // skip over name, compatible and .
 if (dp->d_type != DT_DIR || dp->d_name[0] == '.') continue;
 // create \n
	...
	}
}

ReadDefaultFstab

/// @system/core/fs_mgr/fs_mgr_fstab.cpp
// Loads the fstab file and combines with fstab entries passed in from device tree.
bool ReadDefaultFstab(Fstab* fstab) {
 fstab->clear();
 ReadFstabFromDt(fstab, false /* verbose */); // 重新从 device tree 读取一次 ??
 std::string default_fstab_path;
 // Use different fstab paths for normal boot and recovery boot, respectively
 if (access("/system/bin/recovery", F_OK) == 0) { // recovery模式
 default_fstab_path = "/etc/recovery.fstab";
 } else { // normal boot
 default_fstab_path = GetFstabPath(); // 获取 fstab 文件路径
 }
 Fstab default_fstab;
	// 从 fstab 文件读取 fstab信息
 if (!default_fstab_path.empty() & ReadFstabFromFile(default_fstab_path, &default_fstab)) {
 for (auto&& entry : default_fstab) {
 fstab->emplace_back(std::move(entry));
 }
 } else {
 LINFO 

看看GetFstabPath实现,决定从哪读取fstab

// Return the path to the fstab file. There may be multiple fstab files; the
// one that is returned will be the first that exists of fstab.,
// fstab., and fstab.. The fstab is searched for
// in /odm/etc/ and /vendor/etc/, as well as in the locations where it may be in
// the first stage ramdisk during early boot. Previously, the first stage
// ramdisk's copy of the fstab had to be located in the root directory, but now
// the system/etc directory is supported too and is the preferred location.
std::string GetFstabPath() {
 for (const char* prop : {"fstab_suffix", "hardware", "hardware.platform"}) {
 std::string suffix;
	// 从 ro.boot.(prop值)或 kernel cmdline 等处读取文件名后缀,
	// 从我的模拟器测试获取 ro.boot.hardware 为 ranchu
 if (!fs_mgr_get_boot_config(prop, &suffix)) continue;
	// 遍历访问 prefix + suffix 路径的文件是否存在, 比如 /vendor/etc/fstab.ranchu
 for (const char* prefix : {// late-boot/post-boot locations
 "/odm/etc/fstab.", "/vendor/etc/fstab.",
 // early boot locations
 "/system/etc/fstab.", "/first_stage_ramdisk/system/etc/fstab.",
 "/fstab.", "/first_stage_ramdisk/fstab."}) {
 std::string fstab_path = prefix + suffix;
 if (access(fstab_path.c_str(), F_OK) == 0) {
 return fstab_path;
 }
 }
 }
 return "";
}

查看 /vendor/etc/fstab.ranchu , 看其中相关分区信息, 比如 /system、/data

$ cat /vendor/etc/fstab.ranchu
# Android fstab file.
# 
system /system ext4 ro,barrier=1 wait,logical,avb=vbmeta,first_stage_mount
vendor /vendor ext4 ro,barrier=1 wait,logical,first_stage_mount
product /product ext4 ro,barrier=1 wait,logical,first_stage_mount
system_ext /system_ext ext4 ro,barrier=1 wait,logical,first_stage_mount
/dev/block/vdc /data ext4 noatime,nosuid,nodev,nomblk_io_submit,errors=panic wait,check,quota,fileencryption=aes-256-xts:aes-256-cts,reservedsize=128M,fsverity,keydirectory=/metadata/vold/metadata_encryption,latemount
/dev/block/pci/pci0000:00/0000:00:06.0/by-name/metadata /metadata ext4 noatime,nosuid,nodev wait,formattable,first_stage_mount
/devices/\*\/block/vdf auto auto defaults voldmanaged=sdcard:auto,encryptable=userdata
dev/block/zram0 none swap defaults zramsize=75%

SetupSelinux

初始化 selinux 阶段

/// @system/core/init/selinux.cpp
// The SELinux setup process is carefully orchestrated around snapuserd. Policy
// must be loaded off dynamic partitions, and during an OTA, those partitions
// cannot be read without snapuserd. But, with kernel-privileged snapuserd
// running, loading the policy will immediately trigger audits.
//
// We use a five-step process to address this:
// (1) Read the policy into a string, with snapuserd running.
// (2) Rewrite the snapshot device-mapper tables, to generate new dm-user
// devices and to flush I/O.
// (3) Kill snapuserd, which no longer has any dm-user devices to attach to.
// (4) Load the sepolicy and issue critical restorecons in /dev, carefully
// avoiding anything that would read from /system.
// (5) Re-launch snapuserd and attach it to the dm-user devices from step (2).
//
// After this sequence, it is safe to enable enforcing mode and continue booting.
int SetupSelinux(char** argv) {
 SetStdioToDevNull(argv);
 InitKernelLogging(argv);
 if (REBOOT_BOOTLOADER_ON_PANIC) { // panic 重启到 BootLoader
 InstallRebootSignalHandlers();
 }
 boot_clock::time_point start_time = boot_clock::now();
 MountMissingSystemPartitions();
 SelinuxSetupKernelLogging();
 LOG(INFO) StartTransition();
 }
 LoadSelinuxPolicy(policy); // 加载 selinux policy
 if (snapuserd_helper) { // resume snapused
 // Before enforcing, finish the pending snapuserd transition.
 snapuserd_helper->FinishTransition();
 snapuserd_helper = nullptr;
 }
 SelinuxSetEnforcement(); // 设置 selinux policy 启动状态, 写 /sys/fs/selinux/enforce
 // We're in the kernel domain and want to transition to the init domain. File systems that
 // store SELabels in their xattrs, such as ext4 do not need an explicit restorecon here,
 // but other file systems do. In particular, this is needed for ramdisks such as the
 // recovery image for A/B devices.
 if (selinux_android_restorecon("/system/bin/init", 0) == -1) {
 PLOG(FATAL) 

SecondStageMain

第二阶段执行

/// system/core/init/init.cpp
int SecondStageMain(int argc, char** argv) {
 if (REBOOT_BOOTLOADER_ON_PANIC) {
 InstallRebootSignalHandlers();// 设置Signal处理器
 }
 boot_clock::time_point start_time = boot_clock::now();
 // shutdown 处理函数
 trigger_shutdown = [](const std::string& command) { shutdown_state.TriggerShutdown(command); };
 SetStdioToDevNull(argv);
 InitKernelLogging(argv);
 LOG(INFO) 

接下来看一些主要流程

PropertyInit

void PropertyInit() {
 selinux_callback cb;
 cb.func_audit = PropertyAuditCallback;
 selinux_set_callback(SELINUX_CB_AUDIT, cb);
 mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
 CreateSerializedPropertyInfo(); // 创建property se contexts
 if (__system_property_area_init()) { // 将 /dev/__properties__/properties_serial 映射到内存, 创建 ContextNodes,对每个node打开映射
 LOG(FATAL) 

StartPropertyService

启动系统服务,建立与init之间通信socket,以及设置属性监听

/// @system/core/init/property_service.cpp
void StartPropertyService(int* epoll_socket) {
 InitPropertySet("ro.property_service.version", "2");
 int sockets[2];
 // 创建 socket 对,用于init和属性服务间通信
 if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {
 PLOG(FATAL) 

LoadBootScripts

加载并解析 init rc 脚本

static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
 Parser parser = CreateParser(action_manager, service_list);
 std::string bootscript = GetProperty("ro.boot.init_rc", "");
 if (bootscript.empty()) {
 parser.ParseConfig("/system/etc/init/hw/init.rc"); // 首先解析 init.rc
 if (!parser.ParseConfig("/system/etc/init")) { // 解析 /system/etc/init 目录
 late_import_paths.emplace_back("/system/etc/init"); // 解析失败延时解析
 }
 // late_import is available only in Q and earlier release. As we don't
 // have system_ext in those versions, skip late_import for system_ext.
 parser.ParseConfig("/system_ext/etc/init"); // 解析 /system_ext/etc/init 目录
 if (!parser.ParseConfig("/vendor/etc/init")) { // 解析 /vendor/etc/init 目录
 late_import_paths.emplace_back("/vendor/etc/init");
 }
 if (!parser.ParseConfig("/odm/etc/init")) { // 解析 /odm/etc/init 目录
 late_import_paths.emplace_back("/odm/etc/init");
 }
 if (!parser.ParseConfig("/product/etc/init")) { // 解析 /product/etc/init 目录
 late_import_paths.emplace_back("/product/etc/init");
 }
 } else {
 parser.ParseConfig(bootscript);
 }
}

添加内置动作和事件触发器

  • 内置动作(Builtin Action)
    只在代码里面调用QueueBuiltinAction的action,其他action在rc里使用 on 声明。action通常需要一些事件来触发
  • 事件触发器(Trigger)
    调用QueueEventTrigger插入事件触发器
// 添加相关action,会同时添加到 事件队列 和 action队列
am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux");
am.QueueEventTrigger("early-init"); // 触发 early-init
// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
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(SetMmapRndBitsAction, "SetMmapRndBits");
Keychords keychords;
am.QueueBuiltinAction(...,"KeychordInit");
// Trigger all the boot actions to get us started.
am.QueueEventTrigger("init"); // 触发 init
// Don't mount filesystems or start core system services in charger mode.
std::string bootmode = GetProperty("ro.bootmode", "");
if (bootmode == "charger") { // 充电模式
	am.QueueEventTrigger("charger");
} else { // 正常模式, 触发 late-init
	am.QueueEventTrigger("late-init");
}
// Run all property triggers based on current state of the properties.
// 添加属性触发器。在queue_property_triggers_action中添加的trigger执行之后开始处理属性变化事件, 同时将已匹配的属性事件触发
am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");

以上操作实际上只是向事件队列和action集合添加,而没有真正的去执行,真正触发执行是在主循环中,通过调用 ActionManager#ExecuteOneCommand。

SecondStageMain 循环处理事件

如下是 init 主循环,负责处理相关事件。

int SecondStageMain(int argc, char** argv) {
...
// Restore prio before main loop
setpriority(PRIO_PROCESS, 0, 0);
while (true) {
 // By default, sleep until something happens. 计算epool超时
 auto epoll_timeout = std::optional{};
 auto shutdown_command = shutdown_state.CheckShutdown();
 if (shutdown_command) { // 处理关机请求
 LOG(INFO) 

内置action和触发器执行

当初次进入会直接调用 ActionManager::ExecuteOneCommand,去执行之前的事件,因此会依次执行

  • 触发SetKptrRestrict, 调用 SetupCgroupsAction

  • 触发SetKptrRestrict, 调用 SetKptrRestrictAction

  • 触发 early-init

    • 启动 ueventd
  • 触发wait_for_coldboot_done,调用 wait_for_coldboot_done_action

    • 等待ro.cold_boot_done=true,即ueventd执行完
  • 触发SetMmapRndBits,调用 SetMmapRndBitsAction

  • 触发KeychordInit

  • 触发init

    • 启动logd、servicemanager、hwservicemanager、vndservicemanager
  • 触发late-init / charger(充电模式下),下面都是在 late-init 情况下触发

    • trigger early-fs
    • trigger fs
    • trigger post-fs
    • trigger late-fs
    • trigger post-fs-data
    • trigger load_bpf_programs
    • trigger zygote-start # 触发启动zygote 框架
    • trigger firmware_mounts_complete
    • trigger early-boot
    • trigger boot
  • 触发queue_property_triggers, 调用queue_property_triggers_action

late-init

# Mount filesystems and start core system services.
on late-init
 trigger early-fs	// 启动 vold
 # 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	// 如 mount_all /vendor/etc/fstab.ranchu --early
 trigger post-fs	 // 创建和挂载一些目录 如 /mnt/user/0 -> /storage
 # 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 // 如 mount_all /vendor/etc/fstab.ranchu --late , /data配置的latemount
 # 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	// 挂载 /data,创建一些主要目录
 # Should be before netd, but after apex, properties and logging is available.
 trigger load_bpf_programs
 # Now we can start zygote for devices with file based encryption
 trigger zygote-start	//启动zygote和相关服务
 # Remove a file to wake up anything waiting for firmware.
 trigger firmware_mounts_complete
 trigger early-boot
 trigger boot 	// 启动 hal、core 类别的 service,也就是 native daemons

trigger 会触发调用do_trigger,向事件队列添加相关触发器,之后会依次取出相关事件执行对应的action

/// @system/core/init/builtins.cpp
static Result do_trigger(const BuiltinArguments& args) {
 ActionManager::GetInstance().QueueEventTrigger(args[1]);
 return {};
}
/// system/core/init/action_manager.cpp
void ActionManager::QueueEventTrigger(const std::string& trigger) {
 auto lock = std::lock_guard{event_queue_lock_};
 event_queue_.emplace(trigger);
}

queue_property_triggers

这个触发器是在 late-init 触发器之后加入事件队列的,早于late-init的action中添加的触发器,比如early-fs。该触发器对应的action是queue_property_triggers_action

/// @system/core/init/init.cpp
static Result queue_property_triggers_action(const BuiltinArguments& args) {
	// 添加一个enable_property_trigger,将触发init使能处理属性事件。 从时序来看,将晚于 boot trigger 执行
	// late-init -> queue_property_triggers -> boot -> enable_property_trigger
 ActionManager::GetInstance().QueueBuiltinAction(property_enable_triggers_action, "enable_property_trigger");
 ActionManager::GetInstance().QueueAllPropertyActions(); // 将所有属性满足的action添加到队列
 return {};
}
static Result property_enable_triggers_action(const BuiltinArguments& args) {
 /* Enable property triggers. */
 property_triggers_enabled = 1;
 return {};
}

将所有属性匹配的action添加到队列。

/// @system/core/init/action_manager.cpp
void ActionManager::QueueAllPropertyActions() {
 QueuePropertyChange("", "");
}
// 比如当此时 persist.traced_perf.enable 的值已经为1 ,则会添加相关action到队列,最终会执行 start traced_perf
// init/traced_perf.rc
on property:persist.traced_perf.enable=1
 start traced_perf

trigger zygote-start

zygote-start触发器是用来启动zygote和相关进程的,整个action的执行会依赖加密状态来执行,这些encrypted状态是在执行 mount_all 操作中设置的。可以看到,依次启动了statsd、netd和zygote等进程,zygote的启动会建立系统服务system_server进程的创建。

trigger boot

触发boot事件

on boot
	...
	# Update dm-verity state and set partition.*.verified properties.
	verity_update_state
	# Start standard binderized HAL daemons
	class_start hal	// 启动类别为hal的服务(在rc中使用 class hal定义), 比如vendor.audio-hal
	class_start core	// 启动类别为core的服务,比如 surfaceflinger

总结

init是kernel启动的第一个用户空间进程(pid为1),它在经历FirstStage、selinux_setup和SecondStage后,进入loop循环等待事件发生,比如属性事件或者子进程死亡处理。流程大致如下(正常开机模式):

  • FirstStage 挂载一些基础文件系统和加载内核模块等
  • selinux_setup 执行selinux的初始化
  • SecondStage 挂载其他文件系统,启动属性服务,执行boot流程等,主要逻辑都在这里实现
    • PropertyInit - StartPropertyService 初始化和启动属性服务
    • LoadBootScripts 解析开机脚本 rc文件
    • early-init 早期init阶段,执行启动 ueventd
    • init init阶段,在此阶段会启动logd、servicemanager、hwservicemanager、vndservicemanager
    • late-init 末期init
      • early-fs 启动 vold
      • fs 使用mount_all挂载 init.{$device}.rc 中的fstab相关分区,使用 --early 参数
      • post-fs 创建和挂载一些目录 如 /mnt/user/0 -> /storage
      • late-fs 使用mount_all挂载 init.{$device}.rc 中的fstab相关分区,使用 --late 参数
      • post-fs-data 创建/data一些主要目录
      • load_bpf_programs
      • zygote-start 触发启动zygote 框架
      • firmware_mounts_complete
      • early-boot 在boot之前的一个事件
      • boot 启动核心native服务,如 surfaceflinger、audioserver
    • queue_property_triggers 添加property_triggers,早于early-fs 晚于late-init
      • enable_property_trigger 晚于boot trigger添加,在其之后执行。触发使能init处理属性事件
      • QueueAllPropertyActions 将所有属性匹配的action添加到队列
    • 进入loop循环等待事件发生并处理(主要以下几种)
      • 处理build-in action,在执行结束后被移除(oneshot)
      • 处理唤醒事件
      • 处理属性事件
      • 处理子进程死亡事件
作者:pecuyu原文地址:https://blog.csdn.net/qq_28261343/article/details/128107048

%s 个评论

要回复文章请先登录注册