首页
社区
课程
招聘
[原创] Android 内核启动流程分析 (13.0.0_r3)
发表于: 7小时前 236

[原创] Android 内核启动流程分析 (13.0.0_r3)

7小时前
236

本次分析代码都是基于 android-13.0.0_r3 版本进行分析

主要是分析内核的启动过程,大概将各个板块在启动过程中什么时候启动,对应的函数调用链条,方便后续进行详细分析的时候有个大概的框架概念。详细的各个板块的拆解分析,留给后面的专门的解析文章。

DAC 基于 UID/GID 的传统 Linux 权限控制,通过文件所有者和权限位控制访问。

比如我们最重要的进程的权限设置

Init进程中的DAC权限设置 - system/core/init/service_utils.cpp:235

Zygote中的DAC权限设置 - frameworks/base/core/jni/com_android_internal_os_Zygote.cpp:1891

Zygote中的MAC权限设置 - frameworks/base/core/jni/com_android_internal_os_Zygote.cpp:2133

Init 中MAC权限设置

zygote 进程是 Android 系统中的一个关键组件,主要负责应用程序的启动和管理。

在启动时,zygote 会预加载一些常用的类和资源,以提高后续应用程序的启动速度。这种预加载机制可以减少内存使用和启动时间。

zygote 使用 fork 机制来创建新的应用程序进程。当应用程序需要启动时,zygote 会复制自身的内存空间,从而快速生成新的进程。这种方式比传统的进程创建方式更高效。

预加载过程

运行在 Zygote 进程中监听 socket,fork 应用进程,管理 USAP 池等

zygote 进程在启动时会创建 SystemServer 进程,SystemServer 进程则依赖于 zygote 提供的功能来管理和启动其他服务。

SystemServer 进程负责启动和管理各种系统服务,如 ActivityManager、WindowManager、PackageManager、PowerManager 等。这些服务是 Android 系统正常运行所必需的。

┌─────────────────────────────────────────────────────────────┐
│                    Kernel 启动                                │
│              (PID 1: /init)                                  │
└────────────────────┬──────────────────────────────────────────┘
                     
                     
        ┌────────────────────────────┐
        │   main() [main.cpp:53]      │
        │   - 设置优先级 -20          │
        │   - 路由到不同阶段           │
        └────────────┬────────────────┘
                     
                     
        ┌────────────────────────────┐
        │ FirstStageMain()             │
        │ [first_stage_init.cpp:333]   │
        └────────────┬────────────────┘
                     
         ┌───────────┼───────────┐
         │           │           │
         ▼           ▼           ▼
    ┌────────┐  ┌────────┐  ┌────────┐
    │挂载文件│  │创建设备│  │加载内核│
    │系统    │  │节点    │  │模块    │
    └────────┘  └────────┘  └────────┘
         │           │           │
         └───────────┼───────────┘
                     
                     
        ┌────────────────────────────┐
        │ execv("selinux_setup")      │
        └────────────┬────────────────┘
                     
                     
        ┌────────────────────────────┐
        │ SetupSelinux()              │
        │ [selinux.cpp:701]           │
        └────────────┬────────────────┘
                     
         ┌───────────┼───────────┐
         │           │           │
         ▼           ▼           ▼
    ┌────────┐  ┌────────┐  ┌────────┐
    │挂载缺失│  │读取策略│  │加载策略│
    │分区    │  │文件    │  │到内核  │
    └────────┘  └────────┘  └────────┘
         │           │           │
         └───────────┼───────────┘
                     
                     
        ┌────────────────────────────┐
        │ execv("second_stage")       │
        └────────────┬────────────────┘
                     
                     
        ┌────────────────────────────┐
        │ SecondStageMain()           │
        │ [init.cpp:922]              │
        └────────────┬────────────────┘
                     
         ┌───────────┼───────────┐
         │           │           │
         ▼           ▼           ▼
    ┌────────┐  ┌────────┐  ┌────────┐
    │初始化属│  │加载init│  │创建epoll│
    │性服务  │  │.rc脚本 │  │事件循环 │
    └────────┘  └────────┘  └────────┘
         │           │           │
         └───────────┼───────────┘
                     
                     
        ┌────────────────────────────┐
        │ 触发启动事件                │
        │ - early-init                │
        │ - init                      │
        │ - late-init                 │
        └────────────┬────────────────┘
                     
                     
        ┌────────────────────────────┐
        │ 启动Zygote服务              │
        │ (通过init.rc)               │
        └────────────┬────────────────┘
                     
                     
        ┌────────────────────────────┐
        │ ZygoteInit.main()           │
        │ [ZygoteInit.java:796]       │
        └────────────┬────────────────┘
                     
         ┌───────────┼───────────┐
         │           │           │
         ▼           ▼           ▼
    ┌────────┐  ┌────────┐  ┌────────┐
    │预加载类│  │预加载资│  │预加载共│
    │和资源  │  │源      │  │享库    │
    └────────┘  └────────┘  └────────┘
         │           │           │
         └───────────┼───────────┘
                     
                     
        ┌────────────────────────────┐
        │ forkSystemServer()          │
        └────────────┬────────────────┘
                     
         ┌───────────┴───────────┐
         │                       │
         ▼                       ▼
    ┌──────────┐          ┌──────────┐
    │父进程    │          │子进程    │
    │(Zygote)  │          │(System   │
    │          │          │ Server)   │
    └──────────┘          └────┬─────┘
                                 
                                 
                    ┌────────────────────────────┐
                    │ SystemServer.main()         │
                    │ [SystemServer.java:682]     │
                    └────────────┬───────────────┘
                                 
                                 
                    ┌────────────────────────────┐
                    │ SystemServer.run()          │
                    │ [SystemServer.java:790]     │
                    └────────────┬───────────────┘
                                 
                     ┌───────────┼───────────┐
                     │           │           │
                     ▼           ▼           ▼
                ┌────────┐  ┌────────┐  ┌────────┐
                │启动引导│  │启动核心│  │启动其他│
                │服务    │  │服务    │  │服务    │
                └────────┘  └────────┘  └────────┘
                     │           │           │
                     └───────────┼───────────┘
                                 
                                 
                    ┌────────────────────────────┐
                    │ Looper.loop()              │
                    │ 进入主循环                  │
                    └────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│                    Kernel 启动                                │
│              (PID 1: /init)                                  │
└────────────────────┬──────────────────────────────────────────┘
                     
                     
        ┌────────────────────────────┐
        │   main() [main.cpp:53]      │
        │   - 设置优先级 -20          │
        │   - 路由到不同阶段           │
        └────────────┬────────────────┘
                     
                     
        ┌────────────────────────────┐
        │ FirstStageMain()             │
        │ [first_stage_init.cpp:333]   │
        └────────────┬────────────────┘
                     
         ┌───────────┼───────────┐
         │           │           │
         ▼           ▼           ▼
    ┌────────┐  ┌────────┐  ┌────────┐
    │挂载文件│  │创建设备│  │加载内核│
    │系统    │  │节点    │  │模块    │
    └────────┘  └────────┘  └────────┘
         │           │           │
         └───────────┼───────────┘
                     
                     
        ┌────────────────────────────┐
        │ execv("selinux_setup")      │
        └────────────┬────────────────┘
                     
                     
        ┌────────────────────────────┐
        │ SetupSelinux()              │
        │ [selinux.cpp:701]           │
        └────────────┬────────────────┘
                     
         ┌───────────┼───────────┐
         │           │           │
         ▼           ▼           ▼
    ┌────────┐  ┌────────┐  ┌────────┐
    │挂载缺失│  │读取策略│  │加载策略│
    │分区    │  │文件    │  │到内核  │
    └────────┘  └────────┘  └────────┘
         │           │           │
         └───────────┼───────────┘
                     
                     
        ┌────────────────────────────┐
        │ execv("second_stage")       │
        └────────────┬────────────────┘
                     
                     
        ┌────────────────────────────┐
        │ SecondStageMain()           │
        │ [init.cpp:922]              │
        └────────────┬────────────────┘
                     
         ┌───────────┼───────────┐
         │           │           │
         ▼           ▼           ▼
    ┌────────┐  ┌────────┐  ┌────────┐
    │初始化属│  │加载init│  │创建epoll│
    │性服务  │  │.rc脚本 │  │事件循环 │
    └────────┘  └────────┘  └────────┘
         │           │           │
         └───────────┼───────────┘
                     
                     
        ┌────────────────────────────┐
        │ 触发启动事件                │
        │ - early-init                │
        │ - init                      │
        │ - late-init                 │
        └────────────┬────────────────┘
                     
                     
        ┌────────────────────────────┐
        │ 启动Zygote服务              │
        │ (通过init.rc)               │
        └────────────┬────────────────┘
                     
                     
        ┌────────────────────────────┐
        │ ZygoteInit.main()           │
        │ [ZygoteInit.java:796]       │
        └────────────┬────────────────┘
                     
         ┌───────────┼───────────┐
         │           │           │
         ▼           ▼           ▼
    ┌────────┐  ┌────────┐  ┌────────┐
    │预加载类│  │预加载资│  │预加载共│
    │和资源  │  │源      │  │享库    │
    └────────┘  └────────┘  └────────┘
         │           │           │
         └───────────┼───────────┘
                     
                     
        ┌────────────────────────────┐
        │ forkSystemServer()          │
        └────────────┬────────────────┘
                     
         ┌───────────┴───────────┐
         │                       │
         ▼                       ▼
    ┌──────────┐          ┌──────────┐
    │父进程    │          │子进程    │
    │(Zygote)  │          │(System   │
    │          │          │ Server)   │
    └──────────┘          └────┬─────┘
                                 
                                 
                    ┌────────────────────────────┐
                    │ SystemServer.main()         │
                    │ [SystemServer.java:682]     │
                    └────────────┬───────────────┘
                                 
                                 
                    ┌────────────────────────────┐
                    │ SystemServer.run()          │
                    │ [SystemServer.java:790]     │
                    └────────────┬───────────────┘
                                 
                     ┌───────────┼───────────┐
                     │           │           │
                     ▼           ▼           ▼
                ┌────────┐  ┌────────┐  ┌────────┐
                │启动引导│  │启动核心│  │启动其他│
                │服务    │  │服务    │  │服务    │
                └────────┘  └────────┘  └────────┘
                     │           │           │
                     └───────────┼───────────┘
                                 
                                 
                    ┌────────────────────────────┐
                    │ Looper.loop()              │
                    │ 进入主循环                  │
                    └────────────────────────────┘
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#elif __has_feature(hwaddress_sanitizer)
    __hwasan_set_error_report_callback(AsanReportCallback);
#endif
    // Boost prio which will be restored later
    setpriority(PRIO_PROCESS, 0, -20);
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }
 
    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
 
            return SubcontextMain(argc, argv, &function_map);
        }
 
        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }
 
        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }
 
    return FirstStageMain(argc, argv);
}
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#elif __has_feature(hwaddress_sanitizer)
    __hwasan_set_error_report_callback(AsanReportCallback);
#endif
    // Boost prio which will be restored later
    setpriority(PRIO_PROCESS, 0, -20);
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }
 
    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
 
            return SubcontextMain(argc, argv, &function_map);
        }
 
        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }
 
        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }
 
    return FirstStageMain(argc, argv);
}
int FirstStageMain(int argc, char** argv) {
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
    }
 
    boot_clock::time_point start_time = boot_clock::now();
 
    std::vector<std::pair<std::string, int>> errors;
#define CHECKCALL(x) \
    if ((x) != 0) errors.emplace_back(#x " failed", errno);
 
    // Clear the umask.
    umask(0);
 
    CHECKCALL(clearenv());
    CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));
    // Get the basic filesystem setup we need put together in the initramdisk
    // on / and then we'll let the rc file figure out the rest.
    CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
    CHECKCALL(mkdir("/dev/pts", 0755));
    CHECKCALL(mkdir("/dev/socket", 0755));
    CHECKCALL(mkdir("/dev/dm-user", 0755));
    CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
#define MAKE_STR(x) __STRING(x)
    CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
#undef MAKE_STR
    // Don't expose the raw commandline to unprivileged processes.
    CHECKCALL(chmod("/proc/cmdline", 0440));
    std::string cmdline;
    android::base::ReadFileToString("/proc/cmdline", &cmdline);
    // Don't expose the raw bootconfig to unprivileged processes.
    chmod("/proc/bootconfig", 0440);
    std::string bootconfig;
    android::base::ReadFileToString("/proc/bootconfig", &bootconfig);
    gid_t groups[] = {AID_READPROC};
    CHECKCALL(setgroups(arraysize(groups), groups));
    CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
    CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));
 
    CHECKCALL(mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11)));
 
    if constexpr (WORLD_WRITABLE_KMSG) {
        CHECKCALL(mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11)));
    }
 
    CHECKCALL(mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8)));
    CHECKCALL(mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9)));
 
    // This is needed for log wrapper, which gets called before ueventd runs.
    CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2)));
    CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3)));
 
    // These below mounts are done in first stage init so that first stage mount can mount
    // subdirectories of /mnt/{vendor,product}/.  Other mounts, not required by first stage mount,
    // should be done in rc files.
    // Mount staging areas for devices managed by vold
    // See storage config details at 24fK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4y4G2N6i4u0U0k6g2)9J5k6h3q4F1k6s2u0G2K9h3c8Q4x3X3g2U0L8$3#2Q4x3V1k6V1k6i4k6A6j5$3g2K6i4K6u0r3M7%4c8G2M7X3q4Y4k6g2)9J5c8R3`.`.
    CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                    "mode=0755,uid=0,gid=1000"));
    // /mnt/vendor is used to mount vendor-specific partitions that can not be
    // part of the vendor partition, e.g. because they are mounted read-write.
    CHECKCALL(mkdir("/mnt/vendor", 0755));
    // /mnt/product is used to mount product-specific partitions that can not be
    // part of the product partition, e.g. because they are mounted read-write.
    CHECKCALL(mkdir("/mnt/product", 0755));
 
    // /debug_ramdisk is used to preserve additional files from the debug ramdisk
    CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                    "mode=0755,uid=0,gid=0"));
 
    // /second_stage_resources is used to preserve files from first to second
    // stage init
    CHECKCALL(mount("tmpfs", kSecondStageRes, "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                    "mode=0755,uid=0,gid=0"));
 
    if (IsMicrodroid() && android::virtualization::IsOpenDiceChangesFlagEnabled()) {
        CHECKCALL(mount("tmpfs", "/microdroid_resources", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                        "mode=0750,uid=0,gid=0"));
    }
#undef CHECKCALL
 
    SetStdioToDevNull(argv);
    // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
    // talk to the outside world...
    InitKernelLogging(argv);
 
    if (!errors.empty()) {
        for (const auto& [error_string, error_errno] : errors) {
            LOG(ERROR) << error_string << " " << strerror(error_errno);
        }
        LOG(FATAL) << "Init encountered errors starting first stage, aborting";
    }
 
    LOG(INFO) << "init first stage started!";
 
    auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir};
    if (!old_root_dir) {
        PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk";
    }
 
    struct stat old_root_info {};
    if (stat("/", &old_root_info) != 0) {
        PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
        old_root_dir.reset();
    }
 
    auto want_console = ALLOW_FIRST_STAGE_CONSOLE ? FirstStageConsole(cmdline, bootconfig) : 0;
    auto want_parallel =
            bootconfig.find("androidboot.load_modules_parallel = \"true\"") != std::string::npos;
 
    boot_clock::time_point module_start_time = boot_clock::now();
    int module_count = 0;
    BootMode boot_mode = GetBootMode(cmdline, bootconfig);
    if (!LoadKernelModules(boot_mode, want_console,
                           want_parallel, module_count)) {
        if (want_console != FirstStageConsoleParam::DISABLED) {
            LOG(ERROR) << "Failed to load kernel modules, starting console";
        } else {
            LOG(FATAL) << "Failed to load kernel modules";
        }
    }
    if (module_count > 0) {
        auto module_elapse_time = std::chrono::duration_cast<std::chrono::milliseconds>(
                boot_clock::now() - module_start_time);
        setenv(kEnvInitModuleDurationMs, std::to_string(module_elapse_time.count()).c_str(), 1);
        LOG(INFO) << "Loaded " << module_count << " kernel modules took "
                  << module_elapse_time.count() << " ms";
    }
 
    MaybeResumeFromHibernation(bootconfig);
 
    std::unique_ptr<FirstStageMount> fsm;
 
    bool created_devices = false;
    if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) {
        if (!IsRecoveryMode()) {
            fsm = CreateFirstStageMount(cmdline);
            if (fsm) {
                created_devices = fsm->DoCreateDevices();
                if (!created_devices) {
                    LOG(ERROR) << "Failed to create device nodes early";
                }
            }
        }
        StartConsole(cmdline);
    }
 
    if (access(kBootImageRamdiskProp, F_OK) == 0) {
        std::string dest = GetRamdiskPropForSecondStage();
        std::string dir = android::base::Dirname(dest);
        std::error_code ec;
        if (!fs::create_directories(dir, ec) && !!ec) {
            LOG(FATAL) << "Can't mkdir " << dir << ": " << ec.message();
        }
        if (!fs::copy_file(kBootImageRamdiskProp, dest, ec)) {
            LOG(FATAL) << "Can't copy " << kBootImageRamdiskProp << " to " << dest << ": "
                       << ec.message();
        }
        LOG(INFO) << "Copied ramdisk prop to " << dest;
    }
 
    // If "/force_debuggable" is present, the second-stage init will use a userdebug
    // sepolicy and load adb_debug.prop to allow adb root, if the device is unlocked.
    if (access("/force_debuggable", F_OK) == 0) {
        constexpr const char adb_debug_prop_src[] = "/adb_debug.prop";
        constexpr const char userdebug_plat_sepolicy_cil_src[] = "/userdebug_plat_sepolicy.cil";
        std::error_code ec;  // to invoke the overloaded copy_file() that won't throw.
        if (access(adb_debug_prop_src, F_OK) == 0 &&
            !fs::copy_file(adb_debug_prop_src, kDebugRamdiskProp, ec)) {
            LOG(WARNING) << "Can't copy " << adb_debug_prop_src << " to " << kDebugRamdiskProp
                         << ": " << ec.message();
        }
        if (access(userdebug_plat_sepolicy_cil_src, F_OK) == 0 &&
            !fs::copy_file(userdebug_plat_sepolicy_cil_src, kDebugRamdiskSEPolicy, ec)) {
            LOG(WARNING) << "Can't copy " << userdebug_plat_sepolicy_cil_src << " to "
                         << kDebugRamdiskSEPolicy << ": " << ec.message();
        }
        // setenv for second-stage init to read above kDebugRamdisk* files.
        setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
    }
 
    if (ForceNormalBoot(cmdline, bootconfig)) {
        mkdir("/first_stage_ramdisk", 0755);
        PrepareSwitchRoot();
        // SwitchRoot() must be called with a mount point as the target, so we bind mount the
        // target directory to itself here.
        if (mount("/first_stage_ramdisk", "/first_stage_ramdisk", nullptr, MS_BIND, nullptr) != 0) {
            PLOG(FATAL) << "Could not bind mount /first_stage_ramdisk to itself";
        }
        SwitchRoot("/first_stage_ramdisk");
    }
 
    if (IsRecoveryMode()) {
        LOG(INFO) << "First stage mount skipped (recovery mode)";
    } else {
        if (!fsm) {
            fsm = CreateFirstStageMount(cmdline);
        }
        if (!fsm) {
            LOG(FATAL) << "FirstStageMount not available";
        }
 
        if (!created_devices && !fsm->DoCreateDevices()) {
            LOG(FATAL) << "Failed to create devices required for first stage mount";
        }
 
        if (!fsm->DoFirstStageMount()) {
            LOG(FATAL) << "Failed to mount required partitions early ...";
        }
    }
 
    struct stat new_root_info {};
    if (stat("/", &new_root_info) != 0) {
        PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
        old_root_dir.reset();
    }
 
    if (old_root_dir && old_root_info.st_dev != new_root_info.st_dev) {
        FreeRamdisk(old_root_dir.get(), old_root_info.st_dev);
    }
 
    SetInitAvbVersionInRecovery();
 
    setenv(kEnvFirstStageStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(),
           1);
 
    const char* path = "/system/bin/init";
    const char* args[] = {path, "selinux_setup", nullptr};
    auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);
    close(fd);
    execv(path, const_cast<char**>(args));
 
    // execv() only returns if an error happened, in which case we
    // panic and never fall through this conditional.
    PLOG(FATAL) << "execv(\"" << path << "\") failed";
 
    return 1;
}
int FirstStageMain(int argc, char** argv) {
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
    }
 
    boot_clock::time_point start_time = boot_clock::now();
 
    std::vector<std::pair<std::string, int>> errors;
#define CHECKCALL(x) \
    if ((x) != 0) errors.emplace_back(#x " failed", errno);
 
    // Clear the umask.
    umask(0);
 
    CHECKCALL(clearenv());
    CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));
    // Get the basic filesystem setup we need put together in the initramdisk
    // on / and then we'll let the rc file figure out the rest.
    CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
    CHECKCALL(mkdir("/dev/pts", 0755));
    CHECKCALL(mkdir("/dev/socket", 0755));
    CHECKCALL(mkdir("/dev/dm-user", 0755));
    CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
#define MAKE_STR(x) __STRING(x)
    CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
#undef MAKE_STR
    // Don't expose the raw commandline to unprivileged processes.
    CHECKCALL(chmod("/proc/cmdline", 0440));
    std::string cmdline;
    android::base::ReadFileToString("/proc/cmdline", &cmdline);
    // Don't expose the raw bootconfig to unprivileged processes.
    chmod("/proc/bootconfig", 0440);
    std::string bootconfig;
    android::base::ReadFileToString("/proc/bootconfig", &bootconfig);
    gid_t groups[] = {AID_READPROC};
    CHECKCALL(setgroups(arraysize(groups), groups));
    CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
    CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));
 
    CHECKCALL(mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11)));
 
    if constexpr (WORLD_WRITABLE_KMSG) {
        CHECKCALL(mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11)));
    }
 
    CHECKCALL(mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8)));
    CHECKCALL(mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9)));
 
    // This is needed for log wrapper, which gets called before ueventd runs.
    CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2)));
    CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3)));
 
    // These below mounts are done in first stage init so that first stage mount can mount
    // subdirectories of /mnt/{vendor,product}/.  Other mounts, not required by first stage mount,
    // should be done in rc files.
    // Mount staging areas for devices managed by vold
    // See storage config details at f73K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4y4G2N6i4u0U0k6g2)9J5k6h3q4F1k6s2u0G2K9h3c8Q4x3X3g2U0L8$3#2Q4x3V1k6V1k6i4k6A6j5$3g2K6i4K6u0r3M7%4c8G2M7X3q4Y4k6g2)9J5c8R3`.`.
    CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                    "mode=0755,uid=0,gid=1000"));
    // /mnt/vendor is used to mount vendor-specific partitions that can not be
    // part of the vendor partition, e.g. because they are mounted read-write.
    CHECKCALL(mkdir("/mnt/vendor", 0755));
    // /mnt/product is used to mount product-specific partitions that can not be
    // part of the product partition, e.g. because they are mounted read-write.
    CHECKCALL(mkdir("/mnt/product", 0755));
 
    // /debug_ramdisk is used to preserve additional files from the debug ramdisk
    CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                    "mode=0755,uid=0,gid=0"));
 
    // /second_stage_resources is used to preserve files from first to second
    // stage init
    CHECKCALL(mount("tmpfs", kSecondStageRes, "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                    "mode=0755,uid=0,gid=0"));
 
    if (IsMicrodroid() && android::virtualization::IsOpenDiceChangesFlagEnabled()) {
        CHECKCALL(mount("tmpfs", "/microdroid_resources", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                        "mode=0750,uid=0,gid=0"));
    }
#undef CHECKCALL
 
    SetStdioToDevNull(argv);
    // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
    // talk to the outside world...
    InitKernelLogging(argv);
 
    if (!errors.empty()) {
        for (const auto& [error_string, error_errno] : errors) {
            LOG(ERROR) << error_string << " " << strerror(error_errno);
        }
        LOG(FATAL) << "Init encountered errors starting first stage, aborting";
    }
 
    LOG(INFO) << "init first stage started!";
 
    auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir};
    if (!old_root_dir) {
        PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk";
    }
 
    struct stat old_root_info {};
    if (stat("/", &old_root_info) != 0) {
        PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
        old_root_dir.reset();
    }
 
    auto want_console = ALLOW_FIRST_STAGE_CONSOLE ? FirstStageConsole(cmdline, bootconfig) : 0;
    auto want_parallel =
            bootconfig.find("androidboot.load_modules_parallel = \"true\"") != std::string::npos;
 
    boot_clock::time_point module_start_time = boot_clock::now();
    int module_count = 0;
    BootMode boot_mode = GetBootMode(cmdline, bootconfig);
    if (!LoadKernelModules(boot_mode, want_console,
                           want_parallel, module_count)) {
        if (want_console != FirstStageConsoleParam::DISABLED) {
            LOG(ERROR) << "Failed to load kernel modules, starting console";
        } else {
            LOG(FATAL) << "Failed to load kernel modules";
        }
    }
    if (module_count > 0) {
        auto module_elapse_time = std::chrono::duration_cast<std::chrono::milliseconds>(
                boot_clock::now() - module_start_time);
        setenv(kEnvInitModuleDurationMs, std::to_string(module_elapse_time.count()).c_str(), 1);
        LOG(INFO) << "Loaded " << module_count << " kernel modules took "
                  << module_elapse_time.count() << " ms";
    }
 
    MaybeResumeFromHibernation(bootconfig);
 
    std::unique_ptr<FirstStageMount> fsm;
 
    bool created_devices = false;
    if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) {
        if (!IsRecoveryMode()) {
            fsm = CreateFirstStageMount(cmdline);
            if (fsm) {
                created_devices = fsm->DoCreateDevices();
                if (!created_devices) {
                    LOG(ERROR) << "Failed to create device nodes early";
                }
            }
        }
        StartConsole(cmdline);
    }
 
    if (access(kBootImageRamdiskProp, F_OK) == 0) {
        std::string dest = GetRamdiskPropForSecondStage();
        std::string dir = android::base::Dirname(dest);
        std::error_code ec;
        if (!fs::create_directories(dir, ec) && !!ec) {
            LOG(FATAL) << "Can't mkdir " << dir << ": " << ec.message();
        }
        if (!fs::copy_file(kBootImageRamdiskProp, dest, ec)) {
            LOG(FATAL) << "Can't copy " << kBootImageRamdiskProp << " to " << dest << ": "
                       << ec.message();
        }
        LOG(INFO) << "Copied ramdisk prop to " << dest;
    }
 
    // If "/force_debuggable" is present, the second-stage init will use a userdebug
    // sepolicy and load adb_debug.prop to allow adb root, if the device is unlocked.
    if (access("/force_debuggable", F_OK) == 0) {
        constexpr const char adb_debug_prop_src[] = "/adb_debug.prop";
        constexpr const char userdebug_plat_sepolicy_cil_src[] = "/userdebug_plat_sepolicy.cil";
        std::error_code ec;  // to invoke the overloaded copy_file() that won't throw.
        if (access(adb_debug_prop_src, F_OK) == 0 &&
            !fs::copy_file(adb_debug_prop_src, kDebugRamdiskProp, ec)) {
            LOG(WARNING) << "Can't copy " << adb_debug_prop_src << " to " << kDebugRamdiskProp
                         << ": " << ec.message();
        }
        if (access(userdebug_plat_sepolicy_cil_src, F_OK) == 0 &&
            !fs::copy_file(userdebug_plat_sepolicy_cil_src, kDebugRamdiskSEPolicy, ec)) {
            LOG(WARNING) << "Can't copy " << userdebug_plat_sepolicy_cil_src << " to "
                         << kDebugRamdiskSEPolicy << ": " << ec.message();
        }
        // setenv for second-stage init to read above kDebugRamdisk* files.
        setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
    }
 
    if (ForceNormalBoot(cmdline, bootconfig)) {
        mkdir("/first_stage_ramdisk", 0755);
        PrepareSwitchRoot();
        // SwitchRoot() must be called with a mount point as the target, so we bind mount the
        // target directory to itself here.
        if (mount("/first_stage_ramdisk", "/first_stage_ramdisk", nullptr, MS_BIND, nullptr) != 0) {
            PLOG(FATAL) << "Could not bind mount /first_stage_ramdisk to itself";
        }
        SwitchRoot("/first_stage_ramdisk");
    }
 
    if (IsRecoveryMode()) {
        LOG(INFO) << "First stage mount skipped (recovery mode)";
    } else {
        if (!fsm) {
            fsm = CreateFirstStageMount(cmdline);
        }
        if (!fsm) {
            LOG(FATAL) << "FirstStageMount not available";
        }
 
        if (!created_devices && !fsm->DoCreateDevices()) {
            LOG(FATAL) << "Failed to create devices required for first stage mount";
        }
 
        if (!fsm->DoFirstStageMount()) {
            LOG(FATAL) << "Failed to mount required partitions early ...";
        }
    }
 
    struct stat new_root_info {};
    if (stat("/", &new_root_info) != 0) {
        PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
        old_root_dir.reset();
    }
 
    if (old_root_dir && old_root_info.st_dev != new_root_info.st_dev) {
        FreeRamdisk(old_root_dir.get(), old_root_info.st_dev);
    }
 
    SetInitAvbVersionInRecovery();
 
    setenv(kEnvFirstStageStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(),
           1);
 
    const char* path = "/system/bin/init";
    const char* args[] = {path, "selinux_setup", nullptr};
    auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);
    close(fd);
    execv(path, const_cast<char**>(args));
 
    // execv() only returns if an error happened, in which case we
    // panic and never fall through this conditional.
    PLOG(FATAL) << "execv(\"" << path << "\") failed";
 
    return 1;
}
┌─────────────────────────────────────────────────────────┐
│          SetupSelinux() 入口                           │
│  [system/core/init/selinux.cpp:701]                    │
└────────────────┬──────────────────────────────────────┘
                 
                 
        ┌────────────────┐
        │ 初始化日志系统  │
        │ SelinuxSetupKernelLogging()
        └────────┬───────┘
                 
                 
        ┌─────────────────────────────┐
        │  判断设备类型                │
        │  IsMicrodroid()?            │
        └──────┬──────────────┬───────┘
               │              │
        ┌──────▼──────┐  ┌───▼──────────────────┐
        │ Microdroid  │  │  Android设备         │
        │ 加载策略     │  │  LoadSelinuxPolicyAndroid()
        └─────────────┘  └──────┬───────────────┘
                                 
                    ┌────────────┴────────────┐
                    │                         │
                    ▼                         ▼
        ┌──────────────────────┐  ┌──────────────────────┐
        │ 挂载缺失分区          │  │ 读取策略文件          │
        │ MountMissingSystem   │  │ ReadPolicy()         │
        │ Partitions()         │  └──────┬───────────────┘
        └──────────────────────┘         │
                                          
                    ┌─────────────────────┴─────────────────────┐
                    │                                           │
                    ▼                                           ▼
        ┌──────────────────────┐              ┌──────────────────────┐
        │ Split Policy设备?    │              │ Monolithic Policy    │
        │ IsSplitPolicyDevice()│              │ OpenMonolithicPolicy()│
        └──────┬───────────────┘              │ 打开 /sepolicy        │
               │                               └──────────────────────┘
               
        ┌──────────────────────┐
        │ OpenSplitPolicy()    │
        └──────┬───────────────┘
               
               ├──────────────────────────────┐
               │                              │
               ▼                              ▼
        ┌──────────────────┐        ┌──────────────────────┐
        │ 查找预编译策略    │        │ 编译策略              │
        │ FindPrecompiled  │        │ 调用secic编译CIL文件  │
        │ SplitPolicy()    │        │ ForkExecveAndWaitFor │
        │                  │        │ Completion(secilc)   │
        │ 验证SHA256哈希    │        └──────────────────────┘
        └──────────────────┘
               
               
        ┌──────────────────────┐
        │ Snapuserd过渡处理    │
        │ StartTransition()    │
        │ (停止snapuserd)      │
        └──────┬───────────────┘
               
               
        ┌──────────────────────┐
        │ 加载策略到内核        │
        │ LoadSelinuxPolicy()  │
        │ security_load_policy()│
        └──────┬───────────────┘
               
               
        ┌──────────────────────┐
        │ 完成Snapuserd过渡    │
        │ FinishTransition()   │
        │ (重启snapuserd)      │
        └──────┬───────────────┘
               
               
        ┌──────────────────────┐
        │ 设置Enforcing模式    │
        │ SelinuxSetEnforcement()│
        │ security_setenforce() │
        └──────┬───────────────┘
               
               
        ┌──────────────────────┐
        │ 恢复init文件上下文    │
        │ restorecon("/system/  │
        │ bin/init")           │
        └──────┬───────────────┘
               
               
        ┌──────────────────────┐
        │ execv到second_stage  │
        │ execv("/system/bin/  │
        │ init", "second_stage")│
        └──────────────────────┘
┌─────────────────────────────────────────────────────────┐
│          SetupSelinux() 入口                           │
│  [system/core/init/selinux.cpp:701]                    │
└────────────────┬──────────────────────────────────────┘
                 
                 
        ┌────────────────┐
        │ 初始化日志系统  │
        │ SelinuxSetupKernelLogging()
        └────────┬───────┘
                 
                 
        ┌─────────────────────────────┐
        │  判断设备类型                │
        │  IsMicrodroid()?            │
        └──────┬──────────────┬───────┘
               │              │
        ┌──────▼──────┐  ┌───▼──────────────────┐
        │ Microdroid  │  │  Android设备         │
        │ 加载策略     │  │  LoadSelinuxPolicyAndroid()
        └─────────────┘  └──────┬───────────────┘
                                 
                    ┌────────────┴────────────┐
                    │                         │
                    ▼                         ▼
        ┌──────────────────────┐  ┌──────────────────────┐
        │ 挂载缺失分区          │  │ 读取策略文件          │
        │ MountMissingSystem   │  │ ReadPolicy()         │
        │ Partitions()         │  └──────┬───────────────┘
        └──────────────────────┘         │
                                          
                    ┌─────────────────────┴─────────────────────┐
                    │                                           │
                    ▼                                           ▼
        ┌──────────────────────┐              ┌──────────────────────┐
        │ Split Policy设备?    │              │ Monolithic Policy    │
        │ IsSplitPolicyDevice()│              │ OpenMonolithicPolicy()│
        └──────┬───────────────┘              │ 打开 /sepolicy        │
               │                               └──────────────────────┘
               
        ┌──────────────────────┐
        │ OpenSplitPolicy()    │
        └──────┬───────────────┘
               
               ├──────────────────────────────┐
               │                              │
               ▼                              ▼
        ┌──────────────────┐        ┌──────────────────────┐
        │ 查找预编译策略    │        │ 编译策略              │
        │ FindPrecompiled  │        │ 调用secic编译CIL文件  │
        │ SplitPolicy()    │        │ ForkExecveAndWaitFor │
        │                  │        │ Completion(secilc)   │
        │ 验证SHA256哈希    │        └──────────────────────┘
        └──────────────────┘
               
               
        ┌──────────────────────┐
        │ Snapuserd过渡处理    │
        │ StartTransition()    │
        │ (停止snapuserd)      │
        └──────┬───────────────┘
               
               
        ┌──────────────────────┐
        │ 加载策略到内核        │
        │ LoadSelinuxPolicy()  │
        │ security_load_policy()│
        └──────┬───────────────┘
               
               
        ┌──────────────────────┐
        │ 完成Snapuserd过渡    │
        │ FinishTransition()   │
        │ (重启snapuserd)      │
        └──────┬───────────────┘
               
               
        ┌──────────────────────┐
        │ 设置Enforcing模式    │
        │ SelinuxSetEnforcement()│
        │ security_setenforce() │
        └──────┬───────────────┘
               
               
        ┌──────────────────────┐
        │ 恢复init文件上下文    │
        │ restorecon("/system/  │
        │ bin/init")           │
        └──────┬───────────────┘
               
               
        ┌──────────────────────┐
        │ execv到second_stage  │
        │ execv("/system/bin/  │
        │ init", "second_stage")│
        └──────────────────────┘
int SetupSelinux(char** argv) {
    // 重定向标准输入输出,避免干扰启动过程
    SetStdioToDevNull(argv);
    // 初始化内核日志,确保SELinux日志能正确输出
    InitKernelLogging(argv);
 
    // 如果启用了panic时重启到bootloader,安装信号处理器
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
    }
 
    // 记录SELinux设置开始时间,用于性能分析
    boot_clock::time_point start_time = boot_clock::now();
 
    // 设置SELinux日志回调,将SELinux日志输出到内核日志
    SelinuxSetupKernelLogging();
 
    // 根据设备类型选择不同的策略加载方式
    // Microdroid是Android虚拟化容器,使用简化的策略加载
    if (IsMicrodroid()) {
        LoadSelinuxPolicyMicrodroid();
    } else {
        LoadSelinuxPolicyAndroid();
    }
 
    // 设置SELinux enforcing模式
    // enforcing: 拒绝未授权的访问
    // permissive: 允许访问但记录日志(用于调试)
    SelinuxSetEnforcement();
 
    // Microdroid特殊处理:恢复microdroid_resources的上下文
    if (IsMicrodroid() && android::virtualization::IsOpenDiceChangesFlagEnabled()) {
        const int flags = SELINUX_ANDROID_RESTORECON_RECURSE;
        if (selinux_android_restorecon("/microdroid_resources", flags) == -1) {
            PLOG(FATAL) << "restorecon of /microdroid_resources failed";
        }
    }
 
    // 恢复init文件的SELinux上下文
    // 这是关键步骤:init进程需要从kernel domain转换到init domain
    // ext4等支持xattr的文件系统可能不需要,但ramdisk需要
    if (selinux_android_restorecon("/system/bin/init", 0) == -1) {
        PLOG(FATAL) << "restorecon failed of /system/bin/init failed";
    }
 
    // 记录SELinux设置完成时间,供后续性能分析使用
    setenv(kEnvSelinuxStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(), 1);
 
    // 执行第二阶段init,此时SELinux已完全启用
    const char* path = "/system/bin/init";
    const char* args[] = {path, "second_stage", nullptr};
    execv(path, const_cast<char**>(args));
 
    // execv()只在出错时返回
    PLOG(FATAL) << "execv(\"" << path << "\") failed";
    return 1;
}
int SetupSelinux(char** argv) {
    // 重定向标准输入输出,避免干扰启动过程
    SetStdioToDevNull(argv);
    // 初始化内核日志,确保SELinux日志能正确输出
    InitKernelLogging(argv);
 
    // 如果启用了panic时重启到bootloader,安装信号处理器
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
    }
 
    // 记录SELinux设置开始时间,用于性能分析
    boot_clock::time_point start_time = boot_clock::now();
 
    // 设置SELinux日志回调,将SELinux日志输出到内核日志
    SelinuxSetupKernelLogging();
 
    // 根据设备类型选择不同的策略加载方式
    // Microdroid是Android虚拟化容器,使用简化的策略加载
    if (IsMicrodroid()) {
        LoadSelinuxPolicyMicrodroid();
    } else {
        LoadSelinuxPolicyAndroid();
    }
 
    // 设置SELinux enforcing模式
    // enforcing: 拒绝未授权的访问
    // permissive: 允许访问但记录日志(用于调试)
    SelinuxSetEnforcement();
 
    // Microdroid特殊处理:恢复microdroid_resources的上下文
    if (IsMicrodroid() && android::virtualization::IsOpenDiceChangesFlagEnabled()) {
        const int flags = SELINUX_ANDROID_RESTORECON_RECURSE;
        if (selinux_android_restorecon("/microdroid_resources", flags) == -1) {
            PLOG(FATAL) << "restorecon of /microdroid_resources failed";
        }
    }
 
    // 恢复init文件的SELinux上下文
    // 这是关键步骤:init进程需要从kernel domain转换到init domain
    // ext4等支持xattr的文件系统可能不需要,但ramdisk需要
    if (selinux_android_restorecon("/system/bin/init", 0) == -1) {
        PLOG(FATAL) << "restorecon failed of /system/bin/init failed";
    }
 
    // 记录SELinux设置完成时间,供后续性能分析使用
    setenv(kEnvSelinuxStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(), 1);
 
    // 执行第二阶段init,此时SELinux已完全启用
    const char* path = "/system/bin/init";
    const char* args[] = {path, "second_stage", nullptr};
    execv(path, const_cast<char**>(args));
 
    // execv()只在出错时返回
    PLOG(FATAL) << "execv(\"" << path << "\") failed";
    return 1;
}
// Encapsulates steps to load SELinux policy in Microdroid.
// So far the process is very straightforward - just load the precompiled policy from /system.
void LoadSelinuxPolicyMicrodroid() {
    constexpr const char kMicrodroidPrecompiledSepolicy[] =
            "/system/etc/selinux/microdroid_precompiled_sepolicy";
 
    LOG(INFO) << "Opening SELinux policy from " << kMicrodroidPrecompiledSepolicy;
    unique_fd policy_fd(open(kMicrodroidPrecompiledSepolicy, O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
    if (policy_fd < 0) {
        PLOG(FATAL) << "Failed to open " << kMicrodroidPrecompiledSepolicy;
    }
 
    std::string policy;
    if (!android::base::ReadFdToString(policy_fd, &policy)) {
        PLOG(FATAL) << "Failed to read policy file: " << kMicrodroidPrecompiledSepolicy;
    }
 
    LoadSelinuxPolicy(policy);
}
// Encapsulates steps to load SELinux policy in Microdroid.
// So far the process is very straightforward - just load the precompiled policy from /system.
void LoadSelinuxPolicyMicrodroid() {
    constexpr const char kMicrodroidPrecompiledSepolicy[] =
            "/system/etc/selinux/microdroid_precompiled_sepolicy";
 
    LOG(INFO) << "Opening SELinux policy from " << kMicrodroidPrecompiledSepolicy;
    unique_fd policy_fd(open(kMicrodroidPrecompiledSepolicy, O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
    if (policy_fd < 0) {
        PLOG(FATAL) << "Failed to open " << kMicrodroidPrecompiledSepolicy;
    }
 
    std::string policy;
    if (!android::base::ReadFdToString(policy_fd, &policy)) {
        PLOG(FATAL) << "Failed to read policy file: " << kMicrodroidPrecompiledSepolicy;
    }
 
    LoadSelinuxPolicy(policy);
}
// The SELinux setup process is carefully orchestrated around snapuserd. Policy
// must be loaded off dynamic partitions, and during an OTA, those partitions
// cannot be read without snapuserd. But, with kernel-privileged snapuserd
// running, loading the policy will immediately trigger audits.
//
// We use a five-step process to address this:
//  (1) Read the policy into a string, with snapuserd running.
//  (2) Rewrite the snapshot device-mapper tables, to generate new dm-user
//      devices and to flush I/O.
//  (3) Kill snapuserd, which no longer has any dm-user devices to attach to.
//  (4) Load the sepolicy and issue critical restorecons in /dev, carefully
//      avoiding anything that would read from /system.
//  (5) Re-launch snapuserd and attach it to the dm-user devices from step (2).
//
// After this sequence, it is safe to enable enforcing mode and continue booting.
void LoadSelinuxPolicyAndroid() {
    MountMissingSystemPartitions();
 
    LOG(INFO) << "Opening SELinux policy";
 
    // Read the policy before potentially killing snapuserd.
    std::string policy;
    ReadPolicy(&policy);
 
    auto snapuserd_helper = SnapuserdSelinuxHelper::CreateIfNeeded();
    if (snapuserd_helper) {
        // Kill the old snapused to avoid audit messages. After this we cannot read from /system
        // (or other dynamic partitions) until we call FinishTransition().
        snapuserd_helper->StartTransition();
    }
 
    LoadSelinuxPolicy(policy);
 
    if (snapuserd_helper) {
        // Before enforcing, finish the pending snapuserd transition.
        snapuserd_helper->FinishTransition();
        snapuserd_helper = nullptr;
    }
}
// The SELinux setup process is carefully orchestrated around snapuserd. Policy
// must be loaded off dynamic partitions, and during an OTA, those partitions
// cannot be read without snapuserd. But, with kernel-privileged snapuserd
// running, loading the policy will immediately trigger audits.
//
// We use a five-step process to address this:
//  (1) Read the policy into a string, with snapuserd running.
//  (2) Rewrite the snapshot device-mapper tables, to generate new dm-user
//      devices and to flush I/O.
//  (3) Kill snapuserd, which no longer has any dm-user devices to attach to.
//  (4) Load the sepolicy and issue critical restorecons in /dev, carefully
//      avoiding anything that would read from /system.
//  (5) Re-launch snapuserd and attach it to the dm-user devices from step (2).
//
// After this sequence, it is safe to enable enforcing mode and continue booting.
void LoadSelinuxPolicyAndroid() {
    MountMissingSystemPartitions();
 
    LOG(INFO) << "Opening SELinux policy";
 
    // Read the policy before potentially killing snapuserd.
    std::string policy;
    ReadPolicy(&policy);
 
    auto snapuserd_helper = SnapuserdSelinuxHelper::CreateIfNeeded();
    if (snapuserd_helper) {
        // Kill the old snapused to avoid audit messages. After this we cannot read from /system
        // (or other dynamic partitions) until we call FinishTransition().
        snapuserd_helper->StartTransition();
    }
 
    LoadSelinuxPolicy(policy);
 
    if (snapuserd_helper) {
        // Before enforcing, finish the pending snapuserd transition.
        snapuserd_helper->FinishTransition();
        snapuserd_helper = nullptr;
    }
}
bool OpenSplitPolicy(PolicyFile* policy_file) {
    // IMPLEMENTATION NOTE: Split policy consists of three or more CIL files:
    // * platform -- policy needed due to logic contained in the system image,
    // * vendor -- policy needed due to logic contained in the vendor image,
    // * mapping -- mapping policy which helps preserve forward-compatibility of non-platform policy
    //   with newer versions of platform policy.
    // * (optional) policy needed due to logic on product, system_ext, or odm images.
    // secilc is invoked to compile the above three policy files into a single monolithic policy
    // file. This file is then loaded into the kernel.
 
    const auto userdebug_plat_sepolicy = GetUserdebugPlatformPolicyFile();
    const bool use_userdebug_policy = userdebug_plat_sepolicy.has_value();
    if (use_userdebug_policy) {
        LOG(INFO) << "Using userdebug system sepolicy " << *userdebug_plat_sepolicy;
    }
 
    // Load precompiled policy from vendor image, if a matching policy is found there. The policy
    // must match the platform policy on the system image.
    // use_userdebug_policy requires compiling sepolicy with userdebug_plat_sepolicy.cil.
    // Thus it cannot use the precompiled policy from vendor image.
    if (!use_userdebug_policy) {
        if (auto res = FindPrecompiledSplitPolicy(); res.ok()) {
            unique_fd fd(open(res->c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
            if (fd != -1) {
                policy_file->fd = std::move(fd);
                policy_file->path = std::move(*res);
                return true;
            }
        } else {
            LOG(INFO) << res.error();
        }
    }
    // No suitable precompiled policy could be loaded
 
    LOG(INFO) << "Compiling SELinux policy";
 
    // We store the output of the compilation on /dev because this is the most convenient tmpfs
    // storage mount available this early in the boot sequence.
    char compiled_sepolicy[] = "/dev/sepolicy.XXXXXX";
    unique_fd compiled_sepolicy_fd(mkostemp(compiled_sepolicy, O_CLOEXEC));
    if (compiled_sepolicy_fd < 0) {
        PLOG(ERROR) << "Failed to create temporary file " << compiled_sepolicy;
        return false;
    }
 
    // Determine which mapping file to include
    std::string vend_plat_vers;
    if (!GetVendorMappingVersion(&vend_plat_vers)) {
        return false;
    }
    std::string plat_mapping_file("/system/etc/selinux/mapping/" + vend_plat_vers + ".cil");
 
    std::string plat_compat_cil_file("/system/etc/selinux/mapping/" + vend_plat_vers +
                                     ".compat.cil");
    if (access(plat_compat_cil_file.c_str(), F_OK) == -1) {
        plat_compat_cil_file.clear();
    }
 
    std::string system_ext_policy_cil_file("/system_ext/etc/selinux/system_ext_sepolicy.cil");
    if (access(system_ext_policy_cil_file.c_str(), F_OK) == -1) {
        system_ext_policy_cil_file.clear();
    }
 
    std::string system_ext_mapping_file("/system_ext/etc/selinux/mapping/" + vend_plat_vers +
                                        ".cil");
    if (access(system_ext_mapping_file.c_str(), F_OK) == -1) {
        system_ext_mapping_file.clear();
    }
 
    std::string system_ext_compat_cil_file("/system_ext/etc/selinux/mapping/" + vend_plat_vers +
                                           ".compat.cil");
    if (access(system_ext_compat_cil_file.c_str(), F_OK) == -1) {
        system_ext_compat_cil_file.clear();
    }
 
    std::string product_policy_cil_file("/product/etc/selinux/product_sepolicy.cil");
    if (access(product_policy_cil_file.c_str(), F_OK) == -1) {
        product_policy_cil_file.clear();
    }
 
    std::string product_mapping_file("/product/etc/selinux/mapping/" + vend_plat_vers + ".cil");
    if (access(product_mapping_file.c_str(), F_OK) == -1) {
        product_mapping_file.clear();
    }
 
    std::string vendor_policy_cil_file("/vendor/etc/selinux/vendor_sepolicy.cil");
    if (access(vendor_policy_cil_file.c_str(), F_OK) == -1) {
        LOG(ERROR) << "Missing " << vendor_policy_cil_file;
        return false;
    }
 
    std::string plat_pub_versioned_cil_file("/vendor/etc/selinux/plat_pub_versioned.cil");
    if (access(plat_pub_versioned_cil_file.c_str(), F_OK) == -1) {
        LOG(ERROR) << "Missing " << plat_pub_versioned_cil_file;
        return false;
    }
 
    // odm_sepolicy.cil is default but optional.
    std::string odm_policy_cil_file("/odm/etc/selinux/odm_sepolicy.cil");
    if (access(odm_policy_cil_file.c_str(), F_OK) == -1) {
        odm_policy_cil_file.clear();
    }
    const std::string version_as_string = std::to_string(SEPOLICY_VERSION);
 
    std::vector<std::string> genfs_cil_files;
 
    int vendor_genfs_version = get_genfs_labels_version();
    std::string genfs_cil_file =
            std::format("/system/etc/selinux/plat_sepolicy_genfs_{}.cil", vendor_genfs_version);
    if (access(genfs_cil_file.c_str(), F_OK) != 0) {
        LOG(INFO) << "Missing " << genfs_cil_file << "; skipping";
        genfs_cil_file.clear();
    } else {
        LOG(INFO) << "Using " << genfs_cil_file << " for genfs labels";
    }
 
    // clang-format off
    std::vector<const char*> compile_args {
        "/system/bin/secilc",
        use_userdebug_policy ? *userdebug_plat_sepolicy : plat_policy_cil_file,
        "-m", "-M", "true", "-G", "-N",
        "-c", version_as_string.c_str(),
        plat_mapping_file.c_str(),
        "-o", compiled_sepolicy,
        // We don't care about file_contexts output by the compiler
        "-f", "/sys/fs/selinux/null"// /dev/null is not yet available
    };
    // clang-format on
 
    if (!plat_compat_cil_file.empty()) {
        compile_args.push_back(plat_compat_cil_file.c_str());
    }
    if (!system_ext_policy_cil_file.empty()) {
        compile_args.push_back(system_ext_policy_cil_file.c_str());
    }
    if (!system_ext_mapping_file.empty()) {
        compile_args.push_back(system_ext_mapping_file.c_str());
    }
    if (!system_ext_compat_cil_file.empty()) {
        compile_args.push_back(system_ext_compat_cil_file.c_str());
    }
    if (!product_policy_cil_file.empty()) {
        compile_args.push_back(product_policy_cil_file.c_str());
    }
    if (!product_mapping_file.empty()) {
        compile_args.push_back(product_mapping_file.c_str());
    }
    if (!plat_pub_versioned_cil_file.empty()) {
        compile_args.push_back(plat_pub_versioned_cil_file.c_str());
    }
    if (!vendor_policy_cil_file.empty()) {
        compile_args.push_back(vendor_policy_cil_file.c_str());
    }
    if (!odm_policy_cil_file.empty()) {
        compile_args.push_back(odm_policy_cil_file.c_str());
    }
    if (!genfs_cil_file.empty()) {
        compile_args.push_back(genfs_cil_file.c_str());
    }
    compile_args.push_back(nullptr);
 
    if (!ForkExecveAndWaitForCompletion(compile_args[0], (char**)compile_args.data())) {
        unlink(compiled_sepolicy);
        return false;
    }
    unlink(compiled_sepolicy);
 
    policy_file->fd = std::move(compiled_sepolicy_fd);
    policy_file->path = compiled_sepolicy;
    return true;
}
bool OpenSplitPolicy(PolicyFile* policy_file) {
    // IMPLEMENTATION NOTE: Split policy consists of three or more CIL files:
    // * platform -- policy needed due to logic contained in the system image,
    // * vendor -- policy needed due to logic contained in the vendor image,
    // * mapping -- mapping policy which helps preserve forward-compatibility of non-platform policy
    //   with newer versions of platform policy.
    // * (optional) policy needed due to logic on product, system_ext, or odm images.
    // secilc is invoked to compile the above three policy files into a single monolithic policy
    // file. This file is then loaded into the kernel.
 
    const auto userdebug_plat_sepolicy = GetUserdebugPlatformPolicyFile();
    const bool use_userdebug_policy = userdebug_plat_sepolicy.has_value();
    if (use_userdebug_policy) {
        LOG(INFO) << "Using userdebug system sepolicy " << *userdebug_plat_sepolicy;
    }
 
    // Load precompiled policy from vendor image, if a matching policy is found there. The policy
    // must match the platform policy on the system image.
    // use_userdebug_policy requires compiling sepolicy with userdebug_plat_sepolicy.cil.
    // Thus it cannot use the precompiled policy from vendor image.
    if (!use_userdebug_policy) {
        if (auto res = FindPrecompiledSplitPolicy(); res.ok()) {
            unique_fd fd(open(res->c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
            if (fd != -1) {
                policy_file->fd = std::move(fd);
                policy_file->path = std::move(*res);
                return true;
            }
        } else {
            LOG(INFO) << res.error();
        }
    }
    // No suitable precompiled policy could be loaded
 
    LOG(INFO) << "Compiling SELinux policy";
 
    // We store the output of the compilation on /dev because this is the most convenient tmpfs
    // storage mount available this early in the boot sequence.
    char compiled_sepolicy[] = "/dev/sepolicy.XXXXXX";
    unique_fd compiled_sepolicy_fd(mkostemp(compiled_sepolicy, O_CLOEXEC));
    if (compiled_sepolicy_fd < 0) {
        PLOG(ERROR) << "Failed to create temporary file " << compiled_sepolicy;
        return false;
    }
 
    // Determine which mapping file to include
    std::string vend_plat_vers;
    if (!GetVendorMappingVersion(&vend_plat_vers)) {
        return false;
    }
    std::string plat_mapping_file("/system/etc/selinux/mapping/" + vend_plat_vers + ".cil");
 
    std::string plat_compat_cil_file("/system/etc/selinux/mapping/" + vend_plat_vers +
                                     ".compat.cil");
    if (access(plat_compat_cil_file.c_str(), F_OK) == -1) {
        plat_compat_cil_file.clear();
    }
 
    std::string system_ext_policy_cil_file("/system_ext/etc/selinux/system_ext_sepolicy.cil");
    if (access(system_ext_policy_cil_file.c_str(), F_OK) == -1) {
        system_ext_policy_cil_file.clear();

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 4
支持
分享
最新回复 (1)
雪    币: 144
活跃值: (2153)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
666
6小时前
0
游客
登录 | 注册 方可回帖
返回