0%

Android系统启动-Init进程启动

前言

本文是介绍Android系统启动——Init进程。(基于Android 10.0的源码)

目录

Kernel 启动过程会创建 init 进程(pid=1),是用户空间的第一个进程,是所有用户空间进程的鼻祖。init 进程会启动servicemanager(binder服务管家),Zygote 进程(Android中Java进程的鼻祖)。Zygote 进程会创建 system_server 进程以及各种app进程,下图是这几个系统重量级进程之间的层级关系:

init/main.cpp.main

system/core/init/main.cpp

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
using namespace android::init;
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
__asan_set_error_report_callback(AsanReportCallback);
#endif

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;

return SubcontextMain(argc, argv, &function_map);
}

if (!strcmp(argv[1], "selinux_setup")) {
return SetupSelinux(argv);//对SELinux进行初始化
}

if (!strcmp(argv[1], "second_stage")) {
return SecondStageMain(argc, argv);//第二阶段
}
}

return FirstStageMain(argc, argv); //第一阶段
}
FirstStageMain

system/core/init/first_stage_init.cpp

FirstStageMain方法主要工作:

  1. 设置用户组,挂载相关系统文件
  2. 根据/force_debuggable文件来判断是否允许adb root指令
  3. 执行init进程main方法,通过execv(path,{path,“selinux_setup”,nullptr})进入SetupSelinux
SetupSelinux

system/core/init/selinux.cpp

SetupSelinux方法主要工作:

  1. 初始化SELinux,然后以在init SELinux上下文中运行。
  2. 执行init进程main方法,通过execv(path,{path,“second_stage”,nullptr}) 进入SecondStageMain
SecondStageMain

system/core/init/init.cpp

SecondStageMain方法主要工作:

  1. 使用epoll对init进程的子进程(Zygote)的异常退出信号进行监听和处理
  2. 初始化系统属性,使用mmap共享内存,”/dev/properties/property_info” (重要)
  3. 开启属性服务,并注册到epoll中(重要)
  4. 加载系统启动脚本”/init.rc”
  5. 解析启动脚本,启动相关服务

总结下init里面main方法做的事情:

  • first stage 初始化环境变量和各种文件系统目录,klog初始化等
  • selinux相关初始化完成,然后切换second stage 重启init进程
  • 属性服务初始化,将各种系统属性默认值填充到属性Map中
  • 创建epoll描述符结合注册socket监听,处理显示启动进程和挂掉的子进程重启
  • 解析init.rc。把各种action、service等解析出来的填充到相应链表容器管理
  • 有序将early-init、init等各种cmd加入到执行队列action_queue链表中
  • 进入while()循环依次取出执行队列action_queue中的command执行,fork包括app_process在内的各种进程,epoll阻塞监听处理来自挂掉的子进程的消息,根据设定策略restart子进程。

总结

init进程的执行过程,调用init.main()方法:

  1. 创建和挂载启动所需的文件目录
  2. 处理子进程的终止(signal信号量方式)
  3. 初始化和启动属性服务
  4. 解析init.rc配置文件并启动Zygote进程

引用文章:

Android系统启动——init进程

深入研究源码:Android10.0系统启动流程——init进程

Android系统启动-Init篇