Init 的启动流程

下面先看看main函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
if (!strcmp(basename(argv[0]), "watchdogd")) {
return watchdogd_main(argc, argv);
}
if (argc > 1 && !strcmp(argv[1], "subcontext")) {
InitKernelLogging(argv);
const BuiltinFunctionMap function_map;
return SubcontextMain(argc, argv, &function_map);
}
// Debug版本init crash时重启引导加载程序
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
}

// 进入init第一阶段
bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
if (is_first_stage) {
boot_clock::time_point start_time = boot_clock::now();
// 重新设置文件属性0777
umask(0);
// 清除环境变量
clearenv();
setenv("PATH", _PATH_DEFPATH, 1);
// 先获取需要在'/'上需要置于initramdisk中的基础文件系统设置,剩下的则在rc文件中处理
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
#define MAKE_STR(x) __STRING(x)
mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
// 不可将原始的commandline开放给非特权进程
chmod("/proc/cmdline", 0440);
gid_t groups[] = { AID_READPROC };
setgroups(arraysize(groups), groups);
mount("sysfs", "/sys", "sysfs", 0, NULL);
mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
if constexpr (WORLD_WRITABLE_KMSG) {
mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11));
}
mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
// 为vold挂载进程管理的设备设置临时挂载区域
mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
"mode=0755,uid=0,gid=1000");
// /mnt/vendor用于挂载不属于vendor分区的但由vendor指定的分区,因为它们会以读写权限挂载
mkdir("/mnt/vendor", 0755);
// tmpfs已被挂载在/dev路径下了,即意味着我们可使用/dev/kmsg进行kernel log初始化操作了
InitKernelLogging(argv);
LOG(INFO) << "init first stage started!";
if (!DoFirstStageMount()) {
LOG(FATAL) << "Failed to mount required partitions early ...";
}
// 在recovery下设置AVB版本
SetInitAvbVersionInRecovery();
// 若全局启动选项pass,则使能seccop,否则在zygote中使能seccomp
global_seccomp();
// 启动SELinux,加载SELinux策略
// 将selinux相关log写入kmsg
SelinuxSetupKernelLogging();
SelinuxInitialize();
// 当前处于内核域,所以在加载SELinux策略后,需重新执行init以转换至init域
if (selinux_android_restorecon("/init", 0) == -1) {
PLOG(FATAL) << "restorecon failed of /init failed";
}
// 设置第二阶段环境变量
setenv("INIT_SECOND_STAGE", "true", 1);
static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
char* path = argv[0];
char* args[] = { path, nullptr };
execv(path, args);
// `execv()`仅在发生错误的时候返回,且在该情况下会产生panic并永远无法通过该条件
PLOG(FATAL) << "execv(\"" << path << "\") failed";
}

// 开始进入init第二阶段
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";
// 设置所有进程都可以访问的会话密钥环,包括类似FBE加密相关密钥。任何进程都不会覆盖它的会话密钥环。
keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);
// 正在后台启动fw加载器等
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
// 初始化属性
property_init();
// 如果在commandline和DT中参数都是pass,则DT中设置的属性优先级总高于command line。
process_kernel_dt();
process_kernel_cmdline();
// init根据当前需要的属性,将内核变量传入内部变量
export_kernel_boot_props();
// 标记init启动的时间,并为bootstat记录
property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
// 在支持Treble的软件中,为framework ota设置libavb版本
const char* avb_version = getenv("INIT_AVB_VERSION");
if (avb_version) property_set("ro.boot.avb_version", avb_version);
// 基于kernel cmdline参数设置memcg属性值
bool memcg_enabled = android::base::GetBoolProperty("ro.boot.memcg",false);
if (memcg_enabled) {
// 设定root mem crgoup
mkdir("/dev/memcg", 0700);
chown("/dev/memcg",AID_ROOT,AID_SYSTEM);
mount("none", "/dev/memcg", "cgroup", 0, "memory");
// 设置app mem cgroups,用于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_SECOND_STAGE");
unsetenv("INIT_STARTED_AT");
unsetenv("INIT_SELINUX_TOOK");
unsetenv("INIT_AVB_VERSION");
// 为第二阶段设置SELinux
SelinuxSetupKernelLogging();
// 设置selinux上下文
SelabelInitialize();
// 在/dev之前恢复正确的selinux file context
SelinuxRestoreContext();
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd == -1) {
PLOG(FATAL) << "epoll_create1 failed";
}
// 初始化SIGCHLD信号处理程序
sigchld_handler_init();
if (!IsRebootCapable()) {
// 若init没有CAP_SYS_BOOT能力,则其运行于容器之中。这种情况下如果接收到SIGTERM则会引发系统关机
InstallSigtermHandler();
}
// 加载build.prop,default.prop,prop.default
property_load_boot_defaults();
// 导出oem lock状态
export_oem_lock_status();
// 启动属性服务
start_property_service();
// 设置usb控制器
set_usb_controller();
const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);
subcontexts = InitializeSubcontexts();
ActionManager& am = ActionManager::GetInstance();
ServiceList& sm = ServiceList::GetInstance();
// 加载解析system/odm/product/vendor目录下init.rc文件
LoadBootScripts(am, sm);
if (false) DumpState();
// 为了知晓ueventd时设置的所有/dev,所以此处会将冷启动相关操作列入队列
am.QueueEventTrigger("early-init");
am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
am.QueueBuiltinAction(keychord_init_action, "keychord_init");
am.QueueBuiltinAction(console_init_action, "console_init");
// 触发所有启动操作
am.QueueEventTrigger("init");
// 若在wait_for_coldboot_done之后/dev/hw_random或/dev/random为设置就绪,则重复mix_hwrng_into_linux_rng
am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
// 在充电模式下不挂载文件系统,也不启动核心系统服务
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) {
// 默认sleep,除非被触发
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;
}

一、InstallRebootSignalHandlers函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
static void InstallRebootSignalHandlers() {
// 当init发生crash时,debug版本会重启bootloader,而不是kernel panic这种默认行为。
// 因为这样能有效的防止软件以错误的配置循环启动,以确保开发者/测试人员更方便的恢复设备。
struct sigaction action;
memset(&action, 0, sizeof(action));
sigfillset(&action.sa_mask);
action.sa_handler = [](int signal) {
// 这些信号处理程序也会从init进程中fork子进程,但是我们并不希望设备重启,而是直接在此处调用子进程的`_exit()`方法
if (getpid() != 1) {
_exit(signal);
}
// 对于信号处理程序来说,直接调用`DoReboot()`或`LOG(FATAL)`并不是好的选择。
// RebootSystem使用`syscall()`实际上并非安全的异步处理,但是在debug版本上这可能是唯一合适的相较于异常情况下。
RebootSystem(ANDROID_RB_RESTART2, "bootloader");
};
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);
}

二、SetInitAvbVersionInRecovery函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void SetInitAvbVersionInRecovery() {
if (!IsRecoveryMode()) {
LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not in recovery mode)";
return;
}
if (!IsDtVbmetaCompatible()) {
LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not vbmeta compatible)";
return;
}
// 初始化后续FsManagerAvbHandle::Open()所需要的设备,借助验证链验证所有分区上的AVB元数据,
// 当AVB验证成功时,只能设置INIT_AVB_VERSION,且在recovery模式下无需挂载分区。
FirstStageMountVBootV2 avb_first_mount;
if (!avb_first_mount.InitDevices()) {
LOG(ERROR) << "Failed to init devices for INIT_AVB_VERSION";
return;
}
FsManagerAvbUniquePtr avb_handle =
FsManagerAvbHandle::Open(std::move(avb_first_mount.by_name_symlink_map_));
if (!avb_handle) {
PLOG(ERROR) << "Failed to open FsManagerAvbHandle for INIT_AVB_VERSION";
return;
}
setenv("INIT_AVB_VERSION", avb_handle->avb_version().c_str(), 1);
}

三、SelinuxInitialize函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void SelinuxInitialize() {
Timer t;
LOG(INFO) << "Loading SELinux policy";
if (!LoadPolicy()) {
LOG(FATAL) << "Unable to load SELinux policy";
}
bool kernel_enforcing = (security_getenforce() == 1);
// ALLOW_PERMISSIVE_SELINUX
bool is_enforcing = IsEnforcing();
if (kernel_enforcing != is_enforcing) {
if (security_setenforce(is_enforcing)) {
PLOG(FATAL) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false");
}
}
if (auto result = WriteFile("/sys/fs/selinux/checkreqprot", "0"); !result) {
LOG(FATAL) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error();
}
// 鉴于init的第一阶段不能设置属性,所以此处将设置属性动作移至第二阶段
setenv("INIT_SELINUX_TOOK", std::to_string(t.duration().count()).c_str(), 1);
}