Android系统启动之init进程(一)-「Android取经之路」
[Android取经之路的源码都基于Android-Q(10.0) 进行分析]
Android init 启动进程主要分三个阶段分析:
概述,Init如何被启动
Init进程启动的源码分析
rc语法分析
1.概述:
init进程是linux系统中用户空间的第一个进程,进程号为1.
当bootloader启动后,启动kernel,kernel启动完后,在用户空间启动init进程,再通过init进程,来读取init.rc中的相关配置,从而来启动其他相关进程以及其他操作。
init进程被赋予了很多重要工作,init进程启动主要分为两个阶段:
第一个阶段完成以下内容:
ueventd/watchdogd跳转及环境变量设置
挂载文件系统并创建目录
初始化日志输出、挂载分区设备
启用SELinux安全策略
开始第二阶段前的准备
第二个阶段完成以下内容:
初始化属性系统
执行SELinux第二阶段并恢复一些文件安全上下文
新建epoll并初始化子进程终止信号处理函数
设置其他系统属性并开启属性服务
2.架构
2.1 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这个文件。
2.2Init进程启动后,做了哪些事?
Init进程启动后,首先挂载文件系统、再挂载相应的分区,启动SELinux安全策略,启动属性服务,解析rc文件,并启动相应属性服务进程,初始化epoll,依次设置signal、property、keychord这3个fd可读时相对应的回调函数。进入无线循环,用来响应各个进程的变化与重建。
3.kernel启动init进程 源码分析
kernel/msm-4.19/init/main.c
kernel_init()
|
run_init_process(ramdisk_execute_command) //运行可执行文件,启动init进程
static int __ref kernel_init(void *unused)
{
kernel_init_freeable(); //进行init进程的一些初始化操作
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();// 等待所有异步调用执行完成,,在释放内存前,必须完成所有的异步 __init 代码
free_initmem();// 释放所有init.* 段中的内存
mark_rodata_ro(); //arm64空实现
system_state = SYSTEM_RUNNING;// 设置系统状态为运行状态
numa_default_policy(); // 设定NUMA系统的默认内存访问策略
flush_delayed_fput(); // 释放所有延时的struct file结构体
if (ramdisk_execute_command) { //ramdisk_execute_command的值为"/init"
if (!run_init_process(ramdisk_execute_command)) //运行根目录下的init程序
return 0;
pr_err("Failed to execute %s\n", ramdisk_execute_command);
}
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command) { //execute_command的值如果有定义就去根目录下找对应的应用程序,然后启动
if (!run_init_process(execute_command))
return 0;
pr_err("Failed to execute %s. Attempting defaults...\n",
execute_command);
}
if (!run_init_process("/sbin/init") || //如果ramdisk_execute_command和execute_command定义的应用程序都没有找到,
//就到根目录下找 /sbin/init,/etc/init,/bin/init,/bin/sh 这四个应用程序进行启动
!run_init_process("/etc/init") ||
!run_init_process("/bin/init") ||
!run_init_process("/bin/sh"))
return 0;
panic("No init found. Try passing init= option to kernel. "
"See Linux Documentation/init.txt for guidance.");
}
kernel_init_freeable()
|
do_basic_setup()
static void __init do_basic_setup(void)
{
cpuset_init_smp();//针对SMP系统,初始化内核control group的cpuset子系统。
usermodehelper_init();// 创建khelper单线程工作队列,用于协助新建和运行用户空间程序
shmem_init();// 初始化共享内存
driver_init();// 初始化设备驱动
init_irq_proc();//创建/proc/irq目录, 并初始化系统中所有中断对应的子目录
do_ctors();// 执行内核的构造函数
usermodehelper_enable();// 启用usermodehelper
do_initcalls();//遍历initcall_levels数组,调用里面的initcall函数,这里主要是对设备、驱动、文件系统进行初始化,
//之所有将函数封装到数组进行遍历,主要是为了好扩展
random_int_secret_init();//初始化随机数生成池
}
小结:
本节主要介绍了Init进程的一些概况,包括启动后的具体功能,下一节主要针对Init进程的源码进行分析。