Android init启动流程初识(基于Android10源码分析)

概要

  • 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_commandexecute_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.rcsystem/core/rootdir/init.rc
main.cppsystem/core/init/main.cpp
first_stage_init.cppsystem/core/init/first_stage_init.cpp
first_stage_mount.cppsystem/core/init/first_stage_mount.cpp
selinux.cppsystem/core/init/selinux.cpp
ueventd.cppsystem/core/init/ueventd.cpp
security.cppsystem/core/base/security.cpp
devices.cppsystem/core/init/devices.cpp
first_stage_main.cppsystem/core/init/first_stage_main.cpp
service.cppsystem/core/init/service.cpp
fs_mgr_fstab.cppsystem/core/fs_mgr/fs_mgr_fstab.cpp
fs_mgr.cppsystem/core/ fs_mgr/fs_mgr.cpp

init启动源码分析

init进程入口

Android 10中init进程的入口文件在system/core/init/main.cpp中,由于init是命令行程序,所以首先应从main函数开始。
[system/core/init/main.cpp]
init进程的入口
以上main函数中分为传参与不传参

  • Kernel启动init传参时,执行顺序:
参数函数功能
ueventdueventd_maininit进程创建子进程ueventd,负责设备节点的创建、权限设定等一些列工作
subcontextSubcontextMain初始化日志系统
selinux_setupSetupSelinux启动Selinux安全策略
second_stageSecondStageMain启动init进程第二阶段
  • Kernel启动init未传参时,启动FirstStageMain(argc, argv);
    FirstStageMain()中做了一些目录创建、设备节点创建和设备挂载的动作。

第一阶段

[system/core/init/first_stage_init.cpp -> FirstStageMain()]
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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值