init 进程
启动概述
Android的第一个启动进程,init的PID为1,这个进程会解析init.rc来建构出系统的初始运作型态,其他的系统才会相继启动
- 启动电源&系统启动
当电源启动后,会从预定的地方(PC读取ROM),开始加载程序(BootLoader)到RAM中,并开始执行 - 引导程序BootLoader
引导程序BootLoader是在Android系统开始运行前的一个小程序,主要功能是把系统OS拉起并运行 - Linux 内核启动
当内核启动时,设定缓存、保护储存器、计划列表、加载驱动…在内核完成系统设置后,它会在系统中找init.rc文件,并启动init进程 - init进程启动
该进程主要是作初始化&启动系统属性服务,也用来启动Zygote进程 - Launcher App应用(桌面应用程序)
init 进程概述
init作为Android系统启动的第一个进程,通过解析init.rc来陆续启动关键的系统服务进程,其有三个重点服务进程
- ServiceManager(类似DNS功能,用来查找SystemServer中的服务句柄)
- Zygote(初始进程,加载必要Anroid resource、启动虚拟机…等等)
- SystemServer(启动系统级别服务,像是AMS、WMS…服务)
init进程会启动Zygote、SystemServer两个进程,而Zygote使用Socket监听AMS、ServiceManager使用Binder通信
创建、挂载启动所需要的文件目录
初始化、启动性服务
解析init.rc配置文件并启动Zygote进程
init 进程 - main.cpp 分析
// /init/main.cpp
#include "builtins.h"
#include "first_stage_init.h"
#include "init.h"
#include "selinux.h"
#include "subcontext.h"
#include "ueventd.h"
using namespace android::init;
... 省略部分
int main(int argc, char** argv) {
... 省略部分
// Boost prio which will be restored later
setpriority(PRIO_PROCESS, 0, -20);
if (!strcmp(basename(argv[0]), "ueventd")) { // ueventd 负责创建设备节点、权限、匿名共享內存... 等等
return ueventd_main(argc, argv);
}
if (argc > 1) {
if (!strcmp(argv[1], "subcontext")) {
// 初始化 Logger
android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
return SubcontextMain(argc, argv, &function_map);
}
// Selinux 安全相关
if (!strcmp(argv[1], "selinux_setup")) {
return SetupSelinux(argv);
}
// init 进程 (第二阶段)
if (!strcmp(argv[1], "second_stage")) {
return SecondStageMain(argc, argv);
}
}
// 启动 init 进程 (第一阶段)
return FirstStageMain(argc, argv);
}init进程第一阶段- first_stage_init#FirstStageMain文件挂载
第一阶段主要在1.创建并挂载相关的文件,这里列出几个较为重要的文件系统,详细功能可看注释、2.设定传入参数、3执行execv函数(再次加载main.cpp,但带入不同参数)
挂载的文件都在內存中(RAM),并实体文件
| 使用指令 | 挂载目录/文件名、档案管理 | 特性 | 说明 |
|---|---|---|---|
| mount | tmpfs | 存在 RAM 中,并不持久 (tmp 的取名) | 虚拟内存文件系统,它将所有的 文件存在虚拟内存中,将 tmpfs 卸载后,内部的资料就会全部消失 |
| mount | /dev/devpts | 动态挂载 devpts | 为伪终端提供了一个标准,只要pty的主复合设备 /dev/ptmx 被开启,就会去 /dev/pts 下动态创建一个新的pty设备文件 |
| mount | proc | 可在运行时修改内核参数 | 虚拟文件系统,可以看做内核内部数据结构的接口~ |
| mount | sysfs | Linux 2.6内核引入(主要针对 硬件相关参数,这就有关于devpts设备) | 虚拟文件系统,通常被挂载在/sys目录下 |
// first_stage_init.cpp
int FirstStageMain(int argc, char** argv) {
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers(); // init 错误,重启 Boot Loader
}
// 记录启动时间
boot_clock::time_point start_time = boot_clock::now();
// 记错错误
std::vector<std::pair<std::string, int>> errors;
#define CHECKCALL(x) \
if ((x) != 0) errors.emplace_back(#x " failed", errno);
// 清除 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.
// mount 挂载 tmpfs 文件系统
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)
// 挂载进程信息
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);
// 8.0 增加了用户群组
gid_t groups[] = {AID_READPROC};
// 将群组加入到目前进程的设备中
CHECKCALL(setgroups(arraysize(groups), groups));
// 挂载 sys,使用 sysfs 管理档案
CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));
// 创建节点 (mknod) 用于输出 Log
CHECKCALL(mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11)));
if constexpr (WORLD_WRITABLE_KMSG) {
CHECKCALL(mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11)));
}
CHECKCALL(mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8)));
CHECKCALL(mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9)));
// This is needed for log wrapper, which gets called before ueventd runs.
CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2)));
CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3)));
// See storage config details athttp://source.android.com/devices/storage/
// 挂载 /mnt/{vendor,product},使用 tmpfs 管理
CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
"mode=0755,uid=0,gid=1000"));
// /mnt/vendor 用于挂载特定供应商的分区
CHECKCALL(mkdir("/mnt/vendor", 0755));
// /mnt/product is used to mount product-specific partitions that can not be
// part of the product partition, e.g. because they are mounted read-write.
CHECKCALL(mkdir("/mnt/product", 0755));
// /debug_ramdisk is used to preserve additional files from the debug ramdisk
CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
"mode=0755,uid=0,gid=0"));
// /second_stage_resources is used to preserve files from first to second
// stage init
CHECKCALL(mount("tmpfs", kSecondStageRes, "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
"mode=0755,uid=0,gid=0"))
#undef CHECKCALL
SetStdioToDevNull(argv);
InitKernelLogging(argv);
if (!errors.empty()) {
for (const auto& [error_string, error_errno] : errors) {
LOG(ERROR) << error_string << " " << strerror(error_errno);
}
LOG(FATAL) << "Init encountered errors starting first stage, aborting";
}
... 省略部分
return 1;
}挂载特定分区设备
// first_stage_init.cpp
int FirstStageMain(int argc, char** argv) {
... 省略部分
if (!DoFirstStageMount(!created_devices)) {
LOG(FATAL) << "Failed to mount required partitions early ...";
}
... 省略部分
}SELinux 相关工作
// first_stage_init.cpp
int FirstStageMain(int argc, char** argv) {
... 省略部分
struct stat new_root_info;
if (stat("/", &new_root_info) != 0) {
PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
old_root_dir.reset();
}
if (old_root_dir && old_root_info.st_dev != new_root_info.st_dev) {
FreeRamdisk(old_root_dir.get(), old_root_info.st_dev);
}
// 初始化安全框架: Android Verified Boot & AVB 主要用于防止系统文件被篡改
// 防止系统回滚
SetInitAvbVersionInRecovery();
setenv(kEnvFirstStageStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(),
1);
... 省略部分
}透过execv启动init进程的SecondStageMain方法
// first_stage_init.cpp
int FirstStageMain(int argc, char** argv) {
... 省略部分
// 设定参数
const char* path = "/system/bin/init";
const char* args[] = {path, "selinux_setup", nullptr};
// Binder open (log 訊息)
auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
// 启动 init 进程,传输参数 "selinux_setup"
execv(path, const_cast<char**>(args));
}init 进程插曲 SE - selinux.cpp#SetupSelinux
在第二阶段之前会先进行SE设定
在经过first_stage_init#FirstStageMain文件挂载后,会通过execv函数再次启动main.cpp行程,再次进入main.cpp#main方法
// /init/main.cpp 档案
#include "builtins.h"
#include "first_stage_init.h"
#include "init.h"
#include "selinux.h"
#include "subcontext.h"
#include "ueventd.h"
using namespace android::init;
... 省略部分
// 再次进入后,argv 就是带 selinux_setup 字串
int main(int argc, char** argv) {
... 省略部分
// Boost prio which will be restored later
setpriority(PRIO_PROCESS, 0, -20);
// 判断参数
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
if (argc > 1) {
if (!strcmp(argv[1], "subcontext")) {
// 初始化 Log
android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
return SubcontextMain(argc, argv, &function_map);
}
// Selinux
if (!strcmp(argv[1], "selinux_setup")) {
return SetupSelinux(argv);
}
// init 进程 (第二阶段)
if (!strcmp(argv[1], "second_stage")) {
return SecondStageMain(argc, argv);
}
}
// 启动 init 进程 (第一阶段)
return FirstStageMain(argc, argv);
}SetupSelinux主要是在加载SE策略,加载SE完成后,就会设定新参数,再次透过execv启动main.cpp(如上一小节说明)
// /init/selinux.cpp
int SetupSelinux(char** argv) {
SetStdioToDevNull(argv);
// 1. 初始化核心的 Log
InitKernelLogging(argv);
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
}
boot_clock::time_point start_time = boot_clock::now();
// 2. 挂载遗矢的系统区块
MountMissingSystemPartitions();
SelinuxSetupKernelLogging();
LOG(INFO) << "Opening SELinux policy";
PrepareApexSepolicy();
// Read the policy before potentially killing snapuserd.
std::string policy;
// 读取策略
ReadPolicy(&policy);
CleanupApexSepolicy();
auto snapuserd_helper = SnapuserdSelinuxHelper::CreateIfNeeded();
if (snapuserd_helper) {
// Kill the old snapused to avoid audit messages. After this we cannot
// read from /system (or other dynamic partitions) until we call
// FinishTransition().
snapuserd_helper->StartTransition();
}
//载入 SE 策略
LoadSelinuxPolicy(policy);
... 省略部分
const char* path = "/system/bin/init";
const char* args[] = {path, "second_stage", nullptr};
// 再次启动该进程
execv(path, const_cast<char**>(args));
return 1;
}init 进程第二阶段 - init.cpp#SecondStageMain 解析 init.rc
经过first_stage_init的初始化挂载设备后,就会执行到main.cpp类的SecondStageMain函数(可以看做init进城的第二阶段)
// /init/main.cpp 档案
#include "builtins.h"
#include "first_stage_init.h"
#include "init.h"
#include "selinux.h"
#include "subcontext.h"
#include "ueventd.h"
using namespace android::init;
... 省略部分
int main(int argc, char** argv) {
... 省略部分
// Boost prio which will be restored later
setpriority(PRIO_PROCESS, 0, -20);
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
if (argc > 1) {
if (!strcmp(argv[1], "subcontext")) {
// 初始化 Log
android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
return SubcontextMain(argc, argv, &function_map);
}
// Selinux
if (!strcmp(argv[1], "selinux_setup")) {
return SetupSelinux(argv);
}
if (!strcmp(argv[1], "second_stage")) {
return SecondStageMain(argc, argv);
}
}
return FirstStageMain(argc, argv);
}开始分析init.cpp#SecondStageMain,分为10个阶段,详细请看注释
初始化属性域,主要就是做PropertyInit函数
// init/init.cpp
int SecondStageMain(int argc, char** argv) {
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers(); // init 失败 重启 Boot Loader
}
// 启动时间
boot_clock::time_point start_time = boot_clock::now();
trigger_shutdown = [](const std::string& command) { shutdown_state.TriggerShutdown(command); };
SetStdioToDevNull(argv);
// 初始化 kernel log 系统
InitKernelLogging(argv);
// 初始化系統 $PATH 路径
if (setenv("PATH", _PATH_DEFPATH, 1) != 0) {
PLOG(FATAL) << "Could not set $PATH to '" << _PATH_DEFPATH << "' in second stage";
}
{
struct sigaction action = {.sa_flags = SA_RESTART};
action.sa_handler = [](int) {};
sigaction(SIGPIPE, &action, nullptr);
}
// Set init and its forked children's oom_adj.
if (auto result =
WriteFile("/proc/1/oom_score_adj", StringPrintf("%d", DEFAULT_OOM_SCORE_ADJUST));
!result.ok()) {
LOG(ERROR) << "Unable to write " << DEFAULT_OOM_SCORE_ADJUST
<< " to /proc/1/oom_score_adj: " << result.error();
}
// Set up a session keyring that all processes will have access to. It
// will hold things like FBE encryption keys. No process should override
// its session keyring.
keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);
// Indicate that booting is in progress to background fw loaders, etc.
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
... 省略部分
PropertyInit();
... 省略部分
return 0;
}清空环境变量:清除之前写到系统属性中的环境变数
// /init/init.cpp
int SecondStageMain(int argc, char** argv) {
... 省略部分
// Clean up our environment.
unsetenv("INIT_AVB_VERSION");
unsetenv("INIT_FORCE_DEBUGGABLE");
... 省略部分
}SELinux 相关工作
// /init/init.cpp
int SecondStageMain(int argc, char** argv) {
... 省略部分
// Now set up SELinux for second stage.
SelinuxSetupKernelLogging(); // 完成第二阶段的 selinux 工作
SelabelInitialize(); // 注册部分处理器
SelinuxRestoreContext(); // SELinux 的 Context
... 省略部分
}创建 epoll 事件通知
// /init/init.cpp
int SecondStageMain(int argc, char** argv) {
... 省略部分
Epoll epoll;
// epoll.Open()
if (auto result = epoll.Open(); !result.ok()) {
PLOG(FATAL) << result.error();
}
... 省略部分
}装载子进程信号处理器:init是一个守护进程(可理解为守护线程),以该进程为主,若该init进程结束,其他子进程都会结束
// /init/init.cpp
int SecondStageMain(int argc, char** argv) {
... 省略部分
// 创建handler处理子进程终止信号,注册一个信号到epoll监听(若有改变就会对epoll)
// epoll会先收到通知,再用socket读取数据
//为了防止init进程的子进程变成僵尸进程
InstallSignalFdHandler(&epoll);
InstallInitNotifier(&epoll);
... 省略部分
}启动属性服务:主要函数StartPropertyService,启动一个socket监听属性更改
// /init/init.cpp
static int property_fd = -1;
int SecondStageMain(int argc, char** argv) {
... 省略部分
// 启动其他属性服务
StartPropertyService(&property_fd);
unsetenv("INIT_AVB_VERSION");
fs_mgr_vendor_overlay_mount_all();
export_oem_lock_status();
MountHandler mount_handler(&epoll);
SetUsbController();
... 省略部分
}匹配命令&函数之间对应关系:Cmd & Function Map,从这可以看出系统支持哪些cmd指令,还有指令实际运作的方法
// /init/init.cpp
int SecondStageMain(int argc, char** argv) {
... 省略部分
// 创建 Function & Cmd 的 Map
const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
// 在 Action 中保存 function_map 对象
// Action::set_function_map,`::` 相当于 static Function
Action::set_function_map(&function_map);
if (!SetupMountNamespaces()) {
PLOG(FATAL) << "SetupMountNamespaces failed";
}
... 省略部分
}LoadBootScripts:解析init.rc档案
// /init/init.cpp
int SecondStageMain(int argc, char** argv) {
... 省略部分
ActionManager& am = ActionManager::GetInstance();
ServiceList& sm = ServiceList::GetInstance();
// 解析脚本
LoadBootScripts(am, sm);
... 省略部分
}
// 解析 .rc 脚本
static void LoadBootScripts(ActionManager& action_manager,
ServiceList& service_list) {
// 创建解析器
Parser parser = CreateParser(action_manager, service_list);
// 预设解析 ro.boot.init_rc
std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
// 解析指定 init.rc 档案
parser.ParseConfig("/system/etc/init/hw/init.rc");
if (!parser.ParseConfig("/system/etc/init")) {
late_import_paths.emplace_back("/system/etc/init");
}
parser.ParseConfig("/system_ext/etc/init");
if (!parser.ParseConfig("/vendor/etc/init")) {
late_import_paths.emplace_back("/vendor/etc/init");
}
if (!parser.ParseConfig("/odm/etc/init")) {
late_import_paths.emplace_back("/odm/etc/init");
}
if (!parser.ParseConfig("/product/etc/init")) {
late_import_paths.emplace_back("/product/etc/init");
}
} else {
parser.ParseConfig(bootscript);
}
}添加触发事件:这边可以看到rc档的一些设定,其中常见的指令包括,1 early-init、2 init、3 late-init
// /init/init.cpp
int SecondStageMain(int argc, char** argv) {
... 省略部分
// ActionManager 解析完成
am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux");
am.QueueBuiltinAction(ConnectEarlyStageSnapuserdAction, "ConnectEarlyStageSnapuserd");
// 触发标签 early-init
am.QueueEventTrigger("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(
[&epoll, &keychords](const BuiltinArguments& args) -> Result<void> {
for (const auto& svc : ServiceList::GetInstance()) {
keychords.Register(svc->keycodes());
}
keychords.Start(&epoll, HandleKeychord);
return {};
},
"KeychordInit");
// Trigger all the boot actions to get us started.
am.QueueEventTrigger("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 {
am.QueueEventTrigger("late-init");
}
// Run all property triggers based on current state of the properties.
am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
... 省略部分
}进入循环:不断处理接收到的命令&执行Service
// /init/init.cpp
int SecondStageMain(int argc, char** argv) {
... 省略部分
while(true) {
// By default, sleep until something happens.
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);
}
... 省略部分
// 不必等待 && Service 没有正在 running || Service 是运行完毕
if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
am.ExecuteOneCommand(); // 执行一个cmd
}
... 省略部分
}
}