Android O: init进程启动流程分析(阶段二)

本文详细分析了Android O中init进程的第二阶段,即用户态启动流程。主要内容包括初始化属性域,清空环境变量并进行selinux相关工作,创建epoll句柄,装载子进程信号处理器,以及设置默认系统属性和启动配置属性的服务端。重点讲解了signal_handler_init函数的作用以及系统属性的修改流程。
摘要由CSDN通过智能技术生成

在前一篇博客Android O: init进程启动流程分析(阶段一)中,
我们分析了init进程第一阶段(内核态)的流程。
在本篇博客中,我们来看看init进程第二阶段(用户态)的工作。


一、初始化属性域
init进程的第二阶段仍然从main函数开始入手。

int main(int argc, char** argv) {
    //同样进行一些判断及环境变量设置的工作
    ..........
    //现在is_first_stage为false了
    bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);

    //这部分工作不再执行了
    if (is_first_stage) {
        ...........
    }

    // At this point we're in the second stage of init.
    // 同样屏蔽标准输入输出及定义Kernel logger
    InitKernelLogging(argv);
    LOG(INFO) << "init second stage started!";

    // Set up a session keyring that all processes will have access to. It
    // will hold things like FBE encryption keys. No process should override
    // its session keyring.
    // 最后调用syscall,设置安全相关的值
    keyctl(KEYCTL_GET_KEYRING_ID, KEY_SPEC_SESSION_KEYRING, 1);

    // Indicate that booting is in progress to background fw loaders, etc.
    // 这里的功能类似于“锁”
    close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));

    //初始化属性域
    property_init();

    //初始化完属性域后,以下均完成一些属性的设定

    // If arguments are passed both on the command line and in DT,
    // properties set in DT always have priority over the command-line ones.
    process_kernel_dt();
    process_kernel_cmdline();

    // Propagate the kernel variables to internal variables
    // used by init as well as the current required properties.
    export_kernel_boot_props();

    // Make the time that init started available for bootstat to log.
    property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
    property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));

    // Set libavb version for Framework-only OTA match in Treble build.
    const char* avb_version = getenv("INIT_AVB_VERSION");
    if (avb_version) property_set("ro.boot.avb_version", avb_version);  
    ............
}

这部分代码主要的工作应该就是调用property_init初始化属性域,
然后设置各种属性了。

在Android平台中,为了让运行中的所有进程共享系统运行时所需要的各种设置值,
系统开辟了属性存储区域,并提供了访问该区域的API。

property_init函数定义于system/core/init/property_service.cpp中,
如下面代码所示,最终调用_system_property_area_init函数初始化属性域。

void property_init() {
    if (__system_property_area_init()) {
        LOG(ERROR) << "Failed to initialize property area";
        exit(1);
    }
}

二、清空环境变量,完成selinux相关的工作
我们回到main函数,看看接下来的工作:

.......
// Clean up our environment.
// 清除掉之前使用过的环境变量
unsetenv("INIT_SECOND_STAGE");
unsetenv("INIT_STARTED_AT");
unsetenv("INIT_SELINUX_TOOK");
unsetenv("INIT_AVB_VERSION");

// Now set up SELinux for second stage.
// 再次完成selinux相关的工作
selinux_initialize(false);
selinux_restore_context();
..............

在init进程的第一阶段,也调用selinux_initialize函数,
主要加载selinux相关的策略。
第二阶段调用selinux_initialize仅仅注册一些处理器:

static void selinux_initialize(bool in_kernel_domain) {
    Timer t;

    selinux_callback cb;
    cb.func_log = selinux_klog_callback;
    selinux_set_callback(SELINUX_CB_LOG, cb);
    cb.func_audit = audit_callback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);

    if (in_kernel_domain) {
        //第一阶段的工作
        ......
    } else {
        //注册处理器
        selinux_init_all_handles();
    }
}

selinux_restore_context()的作用主要是按selinux policy要求,
重新设置一些文件的属性:

// The files and directories that were created before initial sepolicy load
// need to have their security context restored to the proper value.
// This must happen before /dev is populated by ueventd.
// 如注释所述,以下文件在selinux被加载前就创建了
// 于是,在selinux启动后,需要重新设置一些属性
static void selinux_restore_context() {
    LOG(INFO) << "Running restorecon...";
    restorecon("/dev");
    restorecon("/dev/kmsg
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值