init进程启动流程

189 阅读2分钟

一、按下开机键的时候,设备是如何启动的?

如果你是一个安装过操作系统(例如安装 Windows 系统或是对 Android 手机进行刷机)的 diy 小能手,在装系统的时候一定接触过类似 BIOS / ROOT 程序的概念。如果你对电脑或手机一无所知,那么你可以思考一个问题:当你按下开机键的时候,设备是如何启动的呢?

简单来说:

  • 当按下开机键后,设备开始通电,从硬盘 ROM 的指定位置存放着一段命令代码,他会将启动加载引导程序(Android 是 BootLoader)加载到 RAM 中开始执行。

  • BootLoader 是 Android 系统的引导程序,用来启动 Android 操作系统。因为 Android 操作系统是基于 Linux 操作系统,所以启动 Android 系统本质上就是启动一个定制化的 Linux 。Linux 启动时,首先要启动 Linux 内核程序。所以 Android 启动时,也会启动一个类似的内核程序。

  • Android 内核程序会进行一系列初始化操作,例如设置 RAM 、加载驱动等。当它完成系统初始化后,会首先在系统文件中寻找一个名为 init.rc 的文件,这个文件是用来启动 Android系统 的第一个进程 -- init 进程。

二、初始化进程

init 进程是 Android 系统启动过程中创建的第一个进程,进程号为 1 ,是所有进程的祖宗。

启动 init 进程,从代码层面上看,就是执行了 system/core/init/init.cpp 中的 main 函数。

Android 9 及以前,init进程的main 函数在 /system/core/init/init.cpp

Android 10 及以后,init进程的main 函数在 /system/core/init/main.cpp

int main(int argc,char ** argv){
    
    ...
    if(is_first_stage){
        //创建和挂载启动所需要的文件目录
        mount("tmpfs","/dev","tmpfs",MS_NOSUID,"mode=0755");
        mkdir("/dev/pts",0755);
        //创建和挂载很多...
        ...
    }
    
    ...
    //对属性服务进行初始化
    property_init();
    
    ...
    //用于设置子进程信号处理函数(如Zygote),如果子进程异常退出,init进程会调用该函数中设定的信号处理函数来处理
    signal_handler_init();
    
    ...

    //启动属性服务
    start_property_service();
    
    ...
    
    //解析init.rc配置文件
    parser.ParseConfig("/init.rc");
}

main 函数中做了很多事情,主要逻辑是:

  • 创建和挂载启动所需的文件目录:如 /sys 、/dev 、/proc。
  • 运行 init.rc 脚本。

三、解析 init.rc 文件

文件路径在:/system/core/rootdir/init.rc

/* ... */
// 按住系统电源键开机时,会触发此动作
on property:sys.boot_from_charger_mode=1
    class_stop charger
    trigger late-init
/* ... */
// 挂载文件系统并启动核心系统服务。
on late-init
/* .. */
// 基于文件加密的设备启动zygote进程
trigger zygote-start
/* .. */

其中,重要的步骤是启动 zygote 进程。