联系我们
简单又实用的WordPress网站制作教学
当前位置:网站首页 > 程序开发学习 > 正文

Android 系统启动之 Init 进程启动分析三

作者:访客发布时间:2023-12-24分类:程序开发学习浏览:91


导读:本文基于AOSPandroid-10.0.0_r41版本讲解,内核版本android-goldfish-4.14-gchips上一节我们分析了init进程的seli...

本文基于 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 开启属性服务.

参考资料

  • Android系统10 RK3399 init进程启动(四十九) init第二阶段分析
  • Android系统开发进阶-init.rc 详解

标签:系统启动进程安卓系统Init


程序开发学习排行
最近发表
网站分类
标签列表