查看原文
其他

Android系统启动之init进程(一)-「Android取经之路」

大猫玩程序 IngresGe 2021-11-05


[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进程的源码进行分析。


视频 小程序 ,轻点两下取消赞 在看 ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存