本文依据 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 详解