本文依据 AOSP android-10.0.0_r41 版别讲解,内核版别 android-goldfish-4.14-gchips

上一节我们剖析了 init 进程的 selinux 初始化过程,最后会进入 second_stage 阶段:

int SecondStageMain(int argc, char** argv) {
    // 注册信号处理函数,呈现一些严重错误时重启
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
    }
    //规范输入输出重定向到 /dev/null 
    SetStdioToDevNull(argv); 
    // Init 阶段的 log 输出到 /dev/msg LOG PLOG
    InitKernelLogging(argv);
    LOG(INFO) << "init second stage started!";

这部分和第一阶段相似:

  • 注册信号处理函数,呈现一些严重错误时重启体系
  • 将规范输入输出重定向到 /dev/null
  • 将 Init 阶段的 log (经过 LOG PLOG 宏)输出到 /dev/msg
    // oom_adj 表明进程的优先级,值越小,优先级越大
    // 设置进程的优先级
    // Set init and its forked children's oom_adj.
    if (auto result = WriteFile("/proc/1/oom_score_adj", "-1000"); !result) {
        LOG(ERROR) << "Unable to write -1000 to /proc/1/oom_score_adj: " << result.error();
    }

这儿设置 init 进程的 oom_adj 值,oom_adj 表明进程的优先级,值越小,优先级越大。

    // Secommp (SECure COMPuting) 是 Linux 内核 2.6.12 版别引进的安全模块,首要是用来限制某一进程可用的体系调用 (system call),这儿敞开这个机制,了解即可
    // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
    GlobalSeccomp();

Secommp (SECure COMPuting) 是 Linux 内核 2.6.12 版别引进的安全模块,首要是用来限制某一进程可用的体系调用 (system call),这儿敞开这个机制,了解即可

    // 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.
    // 这儿运用到的是内核提供给用户空间运用的 密钥保存服务 (key retention service),它的首要意图是在 Linux 内核中缓存身份验证数据。远程文件体系和其他内核服务可以运用这个服务来办理密码学、身份验证符号、跨域用户映射和其他安全问题。它还使 Linux 内核可以快速拜访所需的密钥,并可以用来将密钥操作(比如增加、更新和删去)托付给用户空间。
    // 了解即可
    keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);

这儿运用到的是内核提供给用户空间运用的密钥保存服务 (key retention service),它的首要意图是在 Linux 内核中缓存身份验证数据。远程文件体系和其他内核服务可以运用这个服务来办理密码学、身份验证符号、跨域用户映射和其他安全问题。它还使 Linux 内核可以快速拜访所需的密钥,并可以用来将密钥操作(比如增加、更新和删去)托付给用户空间。了解即可

    //创建 /dev/.booting 文件,便是个符号,表明booting进行中
    // Indicate that booting is in progress to background fw loaders, etc.
    close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));

创建 /dev/.booting 文件,便是个符号,表明 booting 进行中

    // 特点体系初始化,根底组件篇现已讲过了
    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.
     //uboot发动时可以给出发动参数: androidboot.android_dt_dir 指定一个途径
    // 没有指定便是默许途径: /proc/device-tree/firmware/android/
    //一般这个途径中会设置一个 fstab, 用于指定 vendor 和其他分区的挂载点
    // 读取特定设备树信息,并设置 ro.boot. 最初的特点。
    process_kernel_dt();
    // 依据内核发动参数设置发动相关的特点:ro.boot 最初的特点
    // 将内核中 cmdline 中所有的有 = 号的参数,以及特殊的 androidboot.xx=xxx 的形式设置成相应的特点
    // 如果是模拟器, bootargs 中包含: androidboot.hardware=ranchu 和 init=/init
    // 就会设置ro.kernel.androidboot.hardware= ranchu  ro.kernel.init=/init 和ro.boot.hardware=ranchu, 
    // 如果是真机, 只针对 androidboot.xx=xx 的参数设置, 
    // 如 androidboot.storagemedia=emmc, 就会有 ro.boot.storagemedia=emmc
    process_kernel_cmdline();
    // Propagate the kernel variables to internal variables
    // used by init as well as the current required properties.
    // 将列表中特定特点的值设置到别的一个特点的值中去
    // 如将 ro.boot.serialno 的值设置到 ro.serialno 中去
    //一般 ro.boot 最初的特点许多都是来自内核的 cmdline
    export_kernel_boot_props();
    //设置 init 和 selinux 执行时间
    // 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"));
    //设置avb版别
    // 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);
    // See if need to load debug props to allow adb root, when the device is unlocked.
    const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
    if (force_debuggable_env && AvbHandle::IsDeviceUnlocked()) {
        load_debug_prop = "true"s == force_debuggable_env;
    }
    // Clean up our environment.
    unsetenv("INIT_STARTED_AT");
    unsetenv("INIT_SELINUX_TOOK");
    unsetenv("INIT_AVB_VERSION");
    unsetenv("INIT_FORCE_DEBUGGABLE");

这儿首要是设置一些特点和环境变量,了解一下

    // Now set up SELinux for second stage.
    // 第二阶段再次设置 Selinux 日志
    SelinuxSetupKernelLogging();
    // 第二阶段再次设置安全上下文
    SelabelInitialize();
    //经过restorecon设置各个文件的默许安全上下文
    SelinuxRestoreContext();

Selinx 相关的配置,和第一阶段相似。

    // 初始化epoll
    Epoll epoll;
    if (auto result = epoll.Open(); !result) {
        PLOG(FATAL) << result.error();
    }
    // 经过epoll监控子进程退出时发送SIGCHLD信号,并经过HandleSignalFd()进行处理
    InstallSignalFdHandler(&epoll);

初始化一个 epoll,然后经过 epoll 监控子进程退出时发送 SIGCHLD 信号,并经过 HandleSignalFd() 进行处理

    // 加载各个分区中的特点文件,如 prop.default, build.pro, default.prop,之前详细讲过特点文件
    property_load_boot_defaults(load_debug_prop);
    //卸载挂载点debug_ramdisk
    UmountDebugRamdisk();
    // 首要是依据 ro.vndk.version 版别号,将/system/vendor_overlay/ 和 /product/vendor_overlay/ 挂载在 vendor 上
    fs_mgr_vendor_overlay_mount_all();
    export_oem_lock_status();
    // 敞开特点服务
    StartPropertyService(&epoll);
    MountHandler mount_handler(&epoll);
    // 读取USB设备控制器的节点/sys/class/udc/xxx,如fe800000.dwc3,并设置特点sys.usb.controller=fe800000.dwc3
    set_usb_controller();
    // ......
}

这儿最中心的内容是调用 StartPropertyService 敞开特点服务.

参考资料