一、上电,启动BootLoader
在按下电源按钮后,会经历如下过程
CPU复位,并从一个固定地址(由CPU厂商指定)开始执行指令。该地址指向的是芯片上一块ROM(只读存储区),称为Boot Rom
Boot Rom:存储一小段程序,即Firmware,该程序会引导到一个预定义地址(该地址可通过软件改写),去加载BootLoader。
BootLoader:为加载Linux Kernel做准备,并最终加载Linux Kernel。在加载Kernel前做的准备如下:
检测外部RAM,并加载一段程序用于后面的准备工作
装载网络、内存模块,建立内存映射,为内核启动做准备
在Android中,BootLoader也即fastboot。厂商的锁也是在这里实现的。
准备工作做好后,启动内核。内核放在/boot分区下。
Kernel: 内核启动后,以start_kernel()为入口,会初始化系统cache、schedulers、安装内存、驱动、内核守护进程、挂载基本文件系统(/etc、/bin、/sbin、/lib、/dev等)、输入输出设备、进程表等等一些列准备工作,随后,启动两个重要进程:
init(pid=1): 用户空间进程的鼻祖。
kthreadd(pid=2):内核空间进程的鼻祖。
以kernel/arm64 - android-amber-intel-linux--android11分支为例:
kernel/arm64/init/main.c
asmlinkage __visible void __init start_kernel(void)
{
...
cgroup_init_early();
...
boot_cpu_init();
page_address_init();
mm_init_cpumask(&init_mm);
setup_command_line(command_line);
setup_nr_cpu_ids();
setup_per_cpu_areas();
boot_cpu_state_init();
...
page_alloc_init();
..
mm_init_cpumask(&init_mm);
sched_init();
...
kmem_cache_init_late();
...
fork_init(); // 指定最大进程数
...
signals_init();
...
cpuset_init();
cgroup_init();
...
rest_init(); // 启动init和kthreadd进程
}
static noinline void __init_refok rest_init(void)
{
...
kernel_thread(kernel_init, NULL, CLONE_FS); // 启动init进程,此时pid=1
...
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);// 启动kthreadd进程,此时pid=2。见kernel/arm64/kernel/kthread.c
...
}
static int __ref kernel_init(void *unused)
{
...
// 从以下目录中,一次查找init可执行文件,如果找到则运行
if (!try_to_run_init_process("/sbin/init") ||
!try_to_run_init_process("/etc/init") ||
!try_to_run_init_process("/bin/init") ||
!try_to_run_init_process("/bin/sh")) {
mnh_trace(MNH_TRACE_INIT_RUNNING);
return 0;
}
}
static int try_to_run_init_process(const char *init_filename)
{
int ret;
ret = run_init_process(init_filename);
return ret;
}
static int run_init_process(const char *init_filename)
{
argv_init[0] = init_filename;
// 最终通过do_execve运行init可执行文件,启动init进程
return do_execve(getname_kernel(init_filename),
(const char __user *const __user *)argv_init,
(const char __user *const __user *)envp_init);
}
如上,在经历start_kernel -> rest_init -> kernel_init的调用后,会遍历以下目录,寻找init可执行文件:
/sbin/init
/etc/init
/bin/init
/bin/sh
最终调用do_execve执行init文件。
这里需要注意的是,上述调动过程中,pid是在kernel_thread(kernel_init...)时创建的,do_execve使用新进程覆盖当前进程,pid不变。
二、Init进程
init进程是Linux的第一个用户空间进程。
init进程的入口:
core/init/init.cpp
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")) {
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);
}
init可执行文件是一个多次被执行的文件。
1. kernel执行init文件,参数为空,执行FirstStageMain函数
core/init/first_stage_init.cpp
int FirstStageMain(int argc, char** argv) {
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("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=1000"));
CHECKCALL(mkdir("/mnt/vendor", 0755));
CHECKCALL(mkdir("/mnt/product", 0755));
CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0"));
CHECKCALL(mount("tmpfs", kSecondStageRes, "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0"))
...
// 执行selinux_setup分支
const char* path = "/system/bin/init";
const char* args[] = {path, "selinux_setup", nullptr};
auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
execv(path, const_cast<char**>(args));
主要做以下工作:
创建、挂载一系列基础文件目录、设置相关访问权限
在FirstStageMain中执行selinux_setup分支。
2. SetupSelinux中调用second_stage分支
core/init/selinux.cpp
int SetupSelinux(char** argv) {
...
const char* path = "/system/bin/init";
const char* args[] = {path, "second_stage", nullptr};
execv(path, const_cast<char**>(args));
3. 执行second_stage分支,即SecondStageMain函数
core/init/init.cpp
int SecondStageMain(int argc, char** argv) {
...
// 初始化自身及子进程oom_score_adj,DEFAULT_OOM_SCORE_ADJUST = MIN_OOM_SCORE_ADJUST = -1000
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();
}
...
// 初始化epoll
Epoll epoll;
if (auto result = epoll.Open(); !result.ok()) {
PLOG(FATAL) << result.error();
}
// 初始化
InstallSignalFdHandler(&epoll);
...
// 初始化subcontext分支
InitializeSubcontext();
...
ActionManager& am = ActionManager::GetInstance();
ServiceList& sm = ServiceList::GetInstance();
// 解析init.rc
LoadBootScripts(am, sm);
...
// 将一系列Action、Event放入队列依次执行
am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux");
// 此处执行的是rc里的early-init事件
am.QueueEventTrigger("early-init");
am.QueueBuiltinAction(ConnectEarlyStageSnapuserdAction, "ConnectEarlyStageSnapuserd");
am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
...
// 处理epoll
while (true) {
// By default, sleep until something happens. Do not convert far_future into
// std::chrono::milliseconds because that would trigger an overflow. The unit of boot_clock
// is 1ns.
const boot_clock::time_point far_future = boot_clock::time_point::max();
boot_clock::time_point next_action_time = far_future;
auto shutdown_command = shutdown_state.CheckShutdown();
if (shutdown_command) {
LOG(INFO) << "Got shutdown_command '" << *shutdown_command
<< "' Calling HandlePowerctlMessage()";
HandlePowerctlMessage(*shutdown_command);
}
if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
// 执行队列里的EventTrigger, PropertyChange, BuiltinAction
am.ExecuteOneCommand();
// If there's more work to do, wake up again immediately.
if (am.HasMoreCommands()) {
next_action_time = boot_clock::now();
}
}
// Since the above code examined pending actions, no new actions must be
// queued by the code between this line and the Epoll::Wait() call below
// without calling WakeMainInitThread().
if (!IsShuttingDown()) {
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) {
next_action_time = std::min(next_action_time, *next_process_action_time);
}
}
std::optional<std::chrono::milliseconds> epoll_timeout;
if (next_action_time != far_future) {
epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
std::max(next_action_time - boot_clock::now(), 0ns));
}
auto epoll_result = epoll.Wait(epoll_timeout);
if (!epoll_result.ok()) {
LOG(ERROR) << epoll_result.error();
}
if (!IsShuttingDown()) {
HandleControlMessages();
SetUsbController();
}
}
}
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
parser.ParseConfig("/system/etc/init/hw/init.rc");
if (!parser.ParseConfig("/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");
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);
}
}
在SecondStageMain中
1)初始化了Subcontext分支;
subcontext用于执行init交给其的一些任务(比如后面执行的某些Command),通过socket与init进行通信
2)执行了LoadBootScripts。LoadBootScripts中依次解析多个rc文件,其中,/system/etc/init/hw/init.rc是主文件。
在源码“core/init/README.md”中,有对rc文件的详细描述。
/system/etc/init/hw/init.rc被执行后,其他rc文件会被执行。README.md对于其他rc文件的
说明:
1. /system/etc/init/ is for core system items such as
SurfaceFlinger, MediaService, and logd.
2. /vendor/etc/init/ is for SoC vendor items such as actions or
daemons needed for core SoC functionality.
3. /odm/etc/init/ is for device manufacturer items such as
actions or daemons needed for motion sensor or other peripheral
functionality.
3)通过epoll和ActionManager的设计,将一些列事件放入队列,依次执行。
4. init.rc
在/system/etc/init/hw/init.rc中,启动一系列核心进程和服务,包括重要的zygote进程。
init.rc说明:core/init/README.md
对zygote的启动:
on userspace-reboot-resume
trigger userspace-reboot-fs-remount
trigger post-fs-data
trigger zygote-start
trigger early-boot
trigger boot
对ueventd进程的启动:
service ueventd /system/bin/ueventd
class core
critical
seclabel u:r:ueventd:s0
user root
shutdown critical
/system/bin/ueventd是init的一个链接,即最终会执行core/init/init.cpp中ueventd分支。
ueventd是一个守护进程,主要作用是接收uevent来管理/dev/(设备节点)
至此,init所有分支已启动完毕。