概要
- Android启动流程一般流程为:BootRom > Bootloader > Kernel > Init > Zygote > SystemServer > Launcher。
- 其中,init进程是linux系统中用户空间的第一个进程,进程号为1.当bootloader启动后,启动kernel,kernel启动完后,在用户空间启动init进程,再通过init进程,来读取init.rc中的相关配置,从而来启动其他相关进程以及其他操作。
init进程启动前
/kerbel/init/main.c -> kernel_init
-
Init进程是在Kernel启动后,启动的第一个用户空间进程,PID为1。
-
kernel_init启动后,完成一些init的初始化操作,然后去系统根目录下依次找ramdisk_execute_command和execute_command设置的应用程序,如果这两个目录都找不到,就依次去根目录下找 /sbin/init,/etc/init,/bin/init,/bin/sh 这四个应用程序进行启动,只要这些应用程序有一个启动了,其他就不启动了。
-
Android系统一般会在根目录下放一个init的可执行文件,也就是说Linux系统的init进程在内核初始化完成后,就直接执行init这个文件。
init进程启动后
system/core/init/main.cp -> main()
Init进程启动后,主要分为三个阶段内容:
- 第一个阶段完成以下内容:
ueventd/watchdogd跳转及环境变量设置
挂载文件系统并创建目录
初始化日志输出、挂载分区设备
启用SELinux安全策略
开始第二阶段前的准备 - 第二个阶段完成以下内容:
初始化属性系统
执行SELinux第二阶段并恢复一些文件安全上下文
新建epoll并初始化子进程终止信号处理函数
设置其他系统属性并开启属性服务 - 第三阶段
通过init.rc机制,读取配置文件,来启动不同的进程。
源码简单分析
源码位置
关键类 | 路径 |
---|---|
init.rc | system/core/rootdir/init.rc |
main.cpp | system/core/init/main.cpp |
first_stage_init.cpp | system/core/init/first_stage_init.cpp |
first_stage_mount.cpp | system/core/init/first_stage_mount.cpp |
selinux.cpp | system/core/init/selinux.cpp |
ueventd.cpp | system/core/init/ueventd.cpp |
security.cpp | system/core/base/security.cpp |
devices.cpp | system/core/init/devices.cpp |
first_stage_main.cpp | system/core/init/first_stage_main.cpp |
service.cpp | system/core/init/service.cpp |
fs_mgr_fstab.cpp | system/core/fs_mgr/fs_mgr_fstab.cpp |
fs_mgr.cpp | system/core/ fs_mgr/fs_mgr.cpp |
init启动源码分析
init进程入口
Android 10中init进程的入口文件在system/core/init/main.cpp中,由于init是命令行程序,所以首先应从main函数开始。
[system/core/init/main.cpp]
以上main函数中分为传参与不传参
- Kernel启动init传参时,执行顺序:
参数 | 函数 | 功能 |
---|---|---|
ueventd | ueventd_main | init进程创建子进程ueventd,负责设备节点的创建、权限设定等一些列工作 |
subcontext | SubcontextMain | 初始化日志系统 |
selinux_setup | SetupSelinux | 启动Selinux安全策略 |
second_stage | SecondStageMain | 启动init进程第二阶段 |
- Kernel启动init未传参时,启动FirstStageMain(argc, argv);
FirstStageMain()中做了一些目录创建、设备节点创建和设备挂载的动作。
第一阶段
[system/core/init/first_stage_init.cpp -> FirstStageMain()]
FirstStageMain()中做了一些目录创建、设备节点创建和设备挂载的动作。
mount(“tmpfs”, “/dev”, “tmpfs”, MS_NOSUID, “mode=0755”); // 挂载tmpfs文件系统
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount(“devpts”, “/dev/pts”, “devpts”, 0, NULL); // 挂载devpts文件系统
mount(“proc”, “/proc”, “proc”, 0, “hidepid=2,gid=” MAKE_STR(AID_READPROC));
// 挂载proc文件系统
mount(“sysfs”, “/sys”, “sysfs”, 0, NULL); // 挂载sysfs文件系统
mount(“selinuxfs”, “/sys/fs/selinux”, “selinuxfs”, 0, NULL);
mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11)); // 提前创建了kmsg设备节点文件,用于输出log信息
mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
第二阶段
创建进程会话密钥并初始化属性系统; keyctl_get_keyring_ID() property_init()
进行SELinux第二阶段并恢复一些文件安全上下文;SelinuxRestoreContext()
新建epoll并初始化子进程终止信号处理函数;installSignalFdHandler(&epoll)
启动匹配属性的服务端;StartPropertuService()
解析init.rc等文件,建立rc文件的action 、service,启动其他进程。LoadBootScripts(am,sm)
[system/core/init/init.cpp -> SecondStageMain()]
int SecondStageMain(int argc, char** argv) {
/* 01. 创建进程会话密钥并初始化属性系统 */
keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);
//创建 /dev/.booting 文件,就是个标记,表示booting进行中
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
// 初始化属性系统,并从指定文件读取属性
property_init();
/* 02. 进行SELinux第二阶段并恢复一些文件安全上下文 */
SelinuxRestoreContext();
/* 03. 新建epoll并初始化子进程终止信号处理函数 */
Epoll epoll;
if (auto result = epoll.Open(); !result) {
PLOG(FATAL) << result.error();
}
InstallSignalFdHandler(&epoll);
/* 04. 设置其他系统属性并开启系统属性服务*/
StartPropertyService(&epoll);
/* 05 解析init.rc等文件,建立rc文件的action 、service,启动其他进程*/
ActionManager& am = ActionManager::GetInstance();
ServiceList& sm = ServiceList::GetInstance();
LoadBootScripts(am, sm);
}
第三阶段
加载解析rc文件,启动服务。
init.rc是一个配置文件,内部由Android初始化语言编写(Android Init Language)编写的脚本
init.rc文件是在init进程启动后执行的启动脚本,文件中记录着init进程需执行的操作。
Ueventd会最先启动,ueventd的作用是扫描/sys/下所有设备并在/dev下创建对应的设备节点工上次访问。
init.rc主要包含五种类型语句:
- Action
- Command
- Service
- Option
- Import
[system/core/rootdir/init.rc ]
在init.cpp中,启动init.rc各个阶段的顺序是early_init > init > late_init,在late_init中又会去触发其他阶段的启动,所以各个阶段在init中启动的顺序如下:
early_init > init > late_init > early-fs > fs > post-fs > late_fs > post-fs-data > zygote-start > early-boot > boot