首页 > 其他分享 >android 14开机流程详细分析(上) - Boot ROM,Boot loader,kernel,init

android 14开机流程详细分析(上) - Boot ROM,Boot loader,kernel,init

时间:2024-07-29 22:56:49浏览次数:12  
标签:kernel 14 Boot init dev system binder rc proc

android u开机流程详细分析

本文基于 android-14.0.0_r2 源码

AOSP 架构

AOSP 的软件堆栈包含以下层:

在这里插入图片描述

图 1. AOSP 软件堆栈架构

下面列出了图 1 中使用的术语的定义:

Android 应用

完全使用 Android API 开发的应用。Google Play 商店广泛用于查找和下载 Android 应用,不过也有许多其他替代方案。在某些情况下,设备制造商可能希望预安装 Android 应用以支持设备的核心功能。如果您对开发 Android 应用感兴趣,请访问 developers.android.com

特权应用

使用 Android 和系统 API 组合创建的应用。这些应用必须作为特权应用预安装在设备上。

设备制造商应用

结合使用 Android API、系统 API 并直接访问 Android 框架实现而创建的应用。由于设备制造商可能会直接访问 Android 框架中的不稳定的 API,因此这些应用必须预安装在设备上,并且只能在设备的系统软件更新时进行更新。系统 API系统 API 表示仅供合作伙伴和 OEM 纳入捆绑应用的 Android API。这些 API 在源代码中被标记为 @SystemApi。Android APIAndroid API 是面向第三方 Android 应用开发者的公开 API。如需了解 Android API,请参阅 Android API 参考文档

Android 框架

构建应用所依据的一组 Java 类、接口和其他预编译代码。框架的某些部分可通过使用 Android API 公开访问。框架的其他部分只能由 OEM 通过系统 API 来访问。Android 框架代码在应用进程内运行。系统服务系统服务是重点突出的模块化组件,例如 system_server、SurfaceFlinger 和 MediaService。Android 框架 API 提供的功能可以与系统服务进行通信,以访问底层硬件。

Android 运行时 (ART)

AOSP 提供的 Java 运行时环境。 ART 会将应用的字节码转换为由设备运行时环境执行的处理器专有指令。

硬件抽象层 (HAL)

HAL 是一个抽象层,其中包含硬件供应商要实现的标准接口。借助 HAL,Android 可以忽略较低级别的驱动程序实现。借助 HAL,您可以顺利实现相关功能,而不会影响或更改更高级别的系统。如需了解详情,请参阅 HAL 概览

原生守护程序和库

该层中的原生守护程序包括 inithealthdlogdstoraged。这些守护程序直接与内核或其他接口进行交互,并且不依赖于基于用户空间的 HAL 实现。
该层中的原生库包括 libclibloglibutilslibbinderlibselinux。这些原生库直接与内核或其他接口进行交互,并且不依赖于基于用户空间的 HAL 实现。

内核

内核是任何操作系统的中心部分,并与设备上的底层硬件进行通信。尽可能将 AOSP 内核拆分为与硬件无关的模块和特定于供应商的模块。如需了解 AOSP 内核组件的说明(包括其定义),请参阅内核概览

系统启动流程图

整个流程如下图:

在这里插入图片描述

1、Boot ROM

Boot ROM是硬编码在CPU内部固定地址的一段ROM(在一些较老的系统上也可能使用外挂Boot ROM(相对CPU来说)),这块代码是由CPU制造商提供。当用户按下电源键或者系统重启之后,触发CPU上电动作,此时其它硬件还未初始化,然而这块ROM就已经可读了。CPU首先执行PBL(Primary Boot Loader,主引导加载程序,固化在ROM上)代码。在必要的硬件初始化之后,Boot ROM开始加载Bootloader到RAM中,然后PC指针跳过去执行bootloader。在加载 Bootloader之前,PBL也可以进行验证。如果验证无法通过,则不会加载运行Bootloader,从而开机失败。

2、Boot loader

Bootloader是一个特殊的独立于内核的程序,是CPU复位后进入操作系统之前执行的一段代码。Bootloader完成由硬件启动到操作系统启动的过渡,从而为操作系统提供基本的运行环境,如初始化CPU、时钟、堆栈、存储器系统等。Bootloader功能类似于PC机的BIOS程序,其代码与CPU芯片的内核结构、具体型号、应用系统的配置及使用的操作系统等因素有关,因此不可能有通用的bootloader,开发时需要用户根据具体情况进行移植。嵌入式Linux系统中常用的Bootloader有armboot、redboot、blob、U-Boot、Bios-lt、Bootldr等,其中U-Boot是当前比较流行,功能比较强大的Bootloader,可以支持多种体系结构,但相对也比较复杂。硬件初始化完成之后,Bootloader将boot.img(kernel + ramdisk(ramdisk.img中主要是存放android启动后第一个用户进程init可执行文件和init.*.rc等相关启动脚本以及sbin目录下的adbd工具))从flash上copy到RAM里面,然后CPU执行转向kernel。

执行Bootloader程序过程中,如果镜像验证失败、BootLinux (&Info) 函数启动失败或者接收到启动至 fastboot 的命令(比如使用 adb reboot bootloader进行重启、在启动时按下了电源键+下音量键组合)时,会进入到Fastboot模式(Fastboot 是一种电脑通过USB数据线对手机固件进行刷写、擦除/格式化、调试、传输各种指令的固件通信协议, 俗称线刷模式或快速引导模式)。

3、kernel

Android kernel基于上游 Linux LTS (Linux Long Term Supported,长期支持) 内核。在 Google,LTS 内核会与 Android 专用补丁结合,形成所谓的“Android 通用内核 (ACK,Android Common Kernel)”。较新的 ACK(版本 5.4 及更高版本)也称为 GKI (Generic Kernel Image,通用内核镜像 )内核。 GKI项目通过统一核心内核并将 SoC 和板级支持从核心内核移至可加载模块中,解决了内核碎片化问题。GKI 内核为内核模块提供了稳定的内核模块接口 (KMI),因此模块和内核可以独立进行更新。

Android 内核基于上游 Linux 长期支持 (LTS) 内核。在 Google,LTS 内核会与 Android 专用补丁结合,形成所谓的“Android 通用内核 (ACK)”。较新的 ACK(版本 5.4 及更高版本)也称为 GKI 内核。GKI 内核支持将与硬件无关的通用核心内核代码和 GKI 模块与硬件专用供应商模块分离开来。

GKI 内核会与包含系统芯片 (SoC) 和板级代码的硬件专用供应商模块进行交互。GKI 内核与供应商模块之间的交互通过内核模块接口 (KMI) 来实现,该接口由标识供应商模块所需的函数和全局数据的符号列表组成。图 2显示了 GKI 内核和供应商模块架构:

在这里插入图片描述

图 2. GKI 架构

4、init

用户空间的第一个进程便是init进程,进程号为1。

当系统启动完成之后,init进程会作为守护进程监视其它进程。在Linux中所有的进程都是由init进程直接或间接fork出来的。在init进程启动的过程中,会相继启动servicemanager(binder服务管理者)、Zygote进程。而Zygote又会创建system_server进程以及app进程。

对于init进程的功能分为4部分:

  • 解析并运行所有的init.rc相关文件
  • 根据rc文件,生成相应的设备驱动节点
  • 处理子进程的终止(signal方式)
  • 提供属性服务的功能
    init进程涉及的主要代码文件有
system/core/init/
  -main.cpp
  -init.cpp
  -parser.cpp
/system/core/rootdir/
  -init.rc

init进程的入口为main.cpp类的main方法。

// /system/core/init/main.cpp

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);
        }
        // 2.创建安全增强型Linux(SELinux)
        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }
        // 3.解析init.rc文件、提供服务、创建epoll与处理子进程的终止等
        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }
    // 代码会执行多次,首次通过try_to_run_init_process执行时没有额外的命令行参数,所以会直接执行FirstStageMain
    // 1.挂载相关文件系统
    return FirstStageMain(argc, argv);
}

主要执行了三步

  • FirstStageMain
  • SetupSelinux
  • SecondStageMain
    init进程启动的第一步,主要是挂载相关的文件系统

4.1FirstStageMain

// /system/core/init/first_stage_init.cpp

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);

    // 创建于挂载相关文件系统
    /*
    clearenv():清除当前进程的环境变量。
    setenv():设置环境变量。
    mount():挂载文件系统。
    mkdir():创建目录。
    mknod():创建设备节点。
    */
    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 http://source.android.com/devices/storage/
    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"))
#undef CHECKCALL

    SetStdioToDevNull(argv);
    // tmpfs已经挂载在/dev下,并且已生成/dev/kmsg,故可以与外界通信
    // 初始化日志系统
    // 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;
    if (!LoadKernelModules(IsRecoveryMode() && !ForceNormalBoot(cmdline, bootconfig), 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";
    }

    bool created_devices = false;
    if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) {
        if (!IsRecoveryMode()) {
            created_devices = 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 (!DoFirstStageMount(!created_devices)) {
        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()函数才会返回
    // 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;
}

主要通过mount挂载对应的文件系统,mkdir创建对应的文件目录,并配置相应的访问权限。

需要注意的是,这些文件只是在应用运行的时候存在,一旦应用运行结束就会随着应用一起消失。

挂载的文件系统主要有四类:

  • tmpfs: 一种虚拟内存文件系统,它会将所有的文件存储在虚拟内存中。由于tmpfs是驻留在RAM的,因此它的内容是不持久的。断电后,tmpfs 的内容就消失了,这也是被称作tmpfs的根本原因。
  • devpts: 为伪终端提供了一个标准接口,它的标准挂接点是/dev/pts。只要pty(pseudo-tty, 虚拟终端)的主复合设备/dev/ptmx被打开,就会在/dev/pts下动态的创建一个新的pty设备文件。
  • proc: 也是一个虚拟文件系统,它可以看作是内核内部数据结构的接口,通过它我们可以获得系统的信息,同时也能够在运行时修改特定的内核参数。
  • sysfs: 与proc文件系统类似,也是一个不占有任何磁盘空间的虚拟文件系统。它通常被挂接在/sys目录下。

在FirstStageMain还会通过InitKernelLogging(argv)来初始化log日志系统。此时Android还没有自己的系统日志,采用kernel的log系统,打开的设备节点/dev/kmsg, 那么可通过cat /dev/kmsg来获取内核log。

最后会通过execv方法传递对应的path与下一阶段的参数selinux_setup。

4.2SetupSelinux

// /system/system/core/init/selinux.cpp

// 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.
int SetupSelinux(char** argv) {
    SetStdioToDevNull(argv);
    // 初始化本阶段内核日志
    InitKernelLogging(argv);

    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
    }

    boot_clock::time_point start_time = boot_clock::now();

    MountMissingSystemPartitions();

    //  初始化 SELinux,加载 SELinux 策略
    SelinuxSetupKernelLogging();

    LOG(INFO) << "Opening SELinux policy";

    PrepareApexSepolicy();

    // Read the policy before potentially killing snapuserd.
    std::string policy;
    ReadPolicy(&policy);
    CleanupApexSepolicy();

    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;
    }

    // This restorecon is intentionally done before SelinuxSetEnforcement because the permissions
    // needed to transition files from tmpfs to *_contexts_file context should not be granted to
    // any process after selinux is set into enforcing mode.
    if (selinux_android_restorecon("/dev/selinux/", SELINUX_ANDROID_RESTORECON_RECURSE) == -1) {
        PLOG(FATAL) << "restorecon failed of /dev/selinux failed";
    }

    SelinuxSetEnforcement();

    //  再次调用 main 函数,并传入 second_stage 进入第二阶段
    //  而且此次启动就已经在 SELinux 上下文中运行
    // We're in the kernel domain and want to transition to the init domain.  File systems that
    // store SELabels in their xattrs, such as ext4 do not need an explicit restorecon here,
    // but other file systems do.  In particular, this is needed for ramdisks such as the
    // recovery image for A/B devices.
    if (selinux_android_restorecon("/system/bin/init", 0) == -1) {
        PLOG(FATAL) << "restorecon failed of /system/bin/init failed";
    }

    setenv(kEnvSelinuxStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(), 1);

    // 进入下一步
    const char* path = "/system/bin/init";
    const char* args[] = {path, "second_stage", nullptr};
    execv(path, const_cast<char**>(args));

    // execv() only returns if an error happened, in which case we
    // panic and never return from this function.
    PLOG(FATAL) << "execv(\"" << path << "\") failed";

    return 1;
}

这阶段主要是初始化 SELinux。SELinux 是安全加强型 Linux,能够很好的对全部进程强制执行访问控制,从而让 Android 更好的保护和限制系统服务、控制对应用数据和系统日志的访问,提高系统安全性。

接下来调用execv进入到最后阶段SecondStageMain。

4.3SecondStageMain

// /system/system/core/init/init.cpp

int SecondStageMain(int argc, char** argv) {
    if (REBOOT_BOOTLOADER_ON_PANIC) {
        InstallRebootSignalHandlers();
    }

    // No threads should be spin up until signalfd
    // is registered. If the threads are indeed required,
    // each of these threads _should_ make sure SIGCHLD signal
    // is blocked. See b/223076262
    boot_clock::time_point start_time = boot_clock::now();

    trigger_shutdown = [](const std::string& command) { shutdown_state.TriggerShutdown(command); };

    SetStdioToDevNull(argv);
    // 初始化本阶段内核日志
    InitKernelLogging(argv);
    LOG(INFO) << "init second stage started!";

    SelinuxSetupKernelLogging();

    // Update $PATH in the case the second stage init is newer than first stage init, where it is
    // first set.
    if (setenv("PATH", _PATH_DEFPATH, 1) != 0) {
        PLOG(FATAL) << "Could not set $PATH to '" << _PATH_DEFPATH << "' in second stage";
    }

    // Init should not crash because of a dependence on any other process, therefore we ignore
    // SIGPIPE and handle EPIPE at the call site directly.  Note that setting a signal to SIG_IGN
    // is inherited across exec, but custom signal handlers are not.  Since we do not want to
    // ignore SIGPIPE for child processes, we set a no-op function for the signal handler instead.
    {
        struct sigaction action = {.sa_flags = SA_RESTART};
        action.sa_handler = [](int) {};
        sigaction(SIGPIPE, &action, nullptr);
    }

    // Set init and its forked children's oom_adj.
    if (auto result =
                WriteFile("/proc/1/oom_score_adj", StringPrintf("%d", DEFAULT_OOM_SCORE_ADJUST));
        !result.ok()) {
        LOG(ERROR) << "Unable to write " << DEFAULT_OOM_SCORE_ADJUST
                   << " to /proc/1/oom_score_adj: " << result.error();
    }

    // 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.
    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));

    // 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");
    bool load_debug_prop = false;
    if (force_debuggable_env && AvbHandle::IsDeviceUnlocked()) {
        load_debug_prop = "true"s == force_debuggable_env;
    }
    unsetenv("INIT_FORCE_DEBUGGABLE");

    // Umount the debug ramdisk so property service doesn't read .prop files from there, when it
    // is not meant to.
    if (!load_debug_prop) {
        UmountDebugRamdisk();
    }

    // 系统属性初始化
    PropertyInit();

    // Umount second stage resources after property service has read the .prop files.
    UmountSecondStageRes();

    // Umount the debug ramdisk after property service has read the .prop files when it means to.
    if (load_debug_prop) {
        UmountDebugRamdisk();
    }

    // Mount extra filesystems required during second stage init
    MountExtraFilesystems();

    // Now set up SELinux for second stage.
    SelabelInitialize();
    SelinuxRestoreContext();

    //  建立 Epoll
    Epoll epoll;
    if (auto result = epoll.Open(); !result.ok()) {
        PLOG(FATAL) << result.error();
    }

    // We always reap children before responding to the other pending functions. This is to
    // prevent a race where other daemons see that a service has exited and ask init to
    // start it again via ctl.start before init has reaped it.
    epoll.SetFirstCallback(ReapAnyOutstandingChildren);

    //  注册信号处理
    InstallSignalFdHandler(&epoll);
    InstallInitNotifier(&epoll);
    StartPropertyService(&property_fd);

    // Make the time that init stages started available for bootstat to log.
    RecordStageBoottimes(start_time);

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

    fs_mgr_vendor_overlay_mount_all();
    export_oem_lock_status();
    MountHandler mount_handler(&epoll);
    SetUsbController();
    SetKernelVersion();

    const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
    Action::set_function_map(&function_map);

    if (!SetupMountNamespaces()) {
        PLOG(FATAL) << "SetupMountNamespaces failed";
    }

    InitializeSubcontext();

    //加载系统启动脚本"/init.rc"
    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();

    LoadBootScripts(am, sm);

    // Turning this on and letting the INFO logging be discarded adds 0.2s to
    // Nexus 9 boot time, so it's disabled by default.
    if (false) DumpState();

    // Make the GSI status available before scripts start running.
    auto is_running = android::gsi::IsGsiRunning() ? "1" : "0";
    SetProperty(gsi::kGsiBootedProp, is_running);
    auto is_installed = android::gsi::IsGsiInstalled() ? "1" : "0";
    SetProperty(gsi::kGsiInstalledProp, is_installed);

    am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
    am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
    am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux");
    am.QueueBuiltinAction(ConnectEarlyStageSnapuserdAction, "ConnectEarlyStageSnapuserd");
    // 触发early-init,init等流程,添加到队列中
    am.QueueEventTrigger("early-init");

    // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
    am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
    // ... so that we can start queuing up actions that require stuff from /dev.
    am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
    Keychords keychords;
    am.QueueBuiltinAction(
            [&epoll, &keychords](const BuiltinArguments& args) -> Result<void> {
                for (const auto& svc : ServiceList::GetInstance()) {
                    keychords.Register(svc->keycodes());
                }
                keychords.Start(&epoll, HandleKeychord);
                return {};
            },
            "KeychordInit");

    // Trigger all the boot actions to get us started.
    am.QueueEventTrigger("init");

    // Don't mount filesystems or start core system services in charger mode.
    std::string bootmode = GetProperty("ro.bootmode", "");
    if (bootmode == "charger") {
        am.QueueEventTrigger("charger");
    } else {
        am.QueueEventTrigger("late-init");
    }

    // Run all property triggers based on current state of the properties.
    am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");

    // Restore prio before main loop
    setpriority(PRIO_PROCESS, 0, 0);
    //解析启动脚本
    while (true) {
        // By default, sleep until something happens. Do not convert far_future into
        // std::chrono::milliseconds because that would trigger an overflow. The unit of boot_clock
        // is 1ns.
        const boot_clock::time_point far_future = boot_clock::time_point::max();
        boot_clock::time_point next_action_time = far_future;

        auto shutdown_command = shutdown_state.CheckShutdown();
        if (shutdown_command) {
            LOG(INFO) << "Got shutdown_command '" << *shutdown_command
                      << "' Calling HandlePowerctlMessage()";
            HandlePowerctlMessage(*shutdown_command);
        }

        //依次执行对应trigger的Command,会最终分步执行到所有rc文件的启动
        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
            am.ExecuteOneCommand();
            // If there's more work to do, wake up again immediately.
            if (am.HasMoreCommands()) {
                next_action_time = boot_clock::now();
            }
        }
        // Since the above code examined pending actions, no new actions must be
        // queued by the code between this line and the Epoll::Wait() call below
        // without calling WakeMainInitThread().
        if (!IsShuttingDown()) {
            auto next_process_action_time = HandleProcessActions();

            // If there's a process that needs restarting, wake up in time for that.
            if (next_process_action_time) {
                next_action_time = std::min(next_action_time, *next_process_action_time);
            }
        }

        std::optional<std::chrono::milliseconds> epoll_timeout;
        if (next_action_time != far_future) {
            epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
                    std::max(next_action_time - boot_clock::now(), 0ns));
        }
        auto epoll_result = epoll.Wait(epoll_timeout);
        if (!epoll_result.ok()) {
            LOG(ERROR) << epoll_result.error();
        }
        if (!IsShuttingDown()) {
            HandleControlMessages();
            SetUsbController();
        }
    }

    return 0;
}

SecondStageMain的主要工作总结

  • 使用epoll对init子进程的信号进行监听
  • 初始化系统属性,使用mmap共享内存
  • 开启属性服务,并注册到epoll中
  • 加载系统启动脚本”init.rc”
  • 解析启动脚本,启动相关服务

在secondstage期间会初始化系统的property服务,最终调用LoadBootScripts方法读取解析init.rc文件。根据配置的init.rc文件去分阶段启动对应的servicemanager和zygote服务。

// /system/system/core/init/init.cpp

static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser = CreateParser(action_manager, service_list);

    // 获取系统属性ro.boot.init_rc的值作为脚本的路径,如果为空则按顺序解析脚本
    // 1 /system/etc/init/   用于核心系统项,例如 SurfaceFlinger, MediaService, Zygote和logd。
    // 2 /vendor/etc/init/   是针对SoC供应商的项目,如SoC核心功能所需的actions或守护进程。
    // 3 /odm/etc/init/      用于设备制造商的项目,如actions或运动传感器或其他外围功能所需的守护进程。
    // 4 /product/etc/init   用于定制化产品的启动配置和操作
    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    if (bootscript.empty()) {
        //解析时根据找到路径读取到的文件按照顺序排序后放到一个Vector中,再遍历此Vector,调用ReadFile函数将rc文件的内容全部保存为字符串,存在data中,然后调用ParseData进行解析
        parser.ParseConfig("/system/etc/init/hw/init.rc");
        if (!parser.ParseConfig("/system/etc/init")) {
            late_import_paths.emplace_back("/system/etc/init");
        }
        // late_import is available only in Q and earlier release. As we don't
        // have system_ext in those versions, skip late_import for system_ext.
        parser.ParseConfig("/system_ext/etc/init");
        if (!parser.ParseConfig("/vendor/etc/init")) {
            late_import_paths.emplace_back("/vendor/etc/init");
        }
        if (!parser.ParseConfig("/odm/etc/init")) {
            late_import_paths.emplace_back("/odm/etc/init");
        }
        if (!parser.ParseConfig("/product/etc/init")) {
            late_import_paths.emplace_back("/product/etc/init");
        }
    } else {
        parser.ParseConfig(bootscript);
    }
}

通过ParseConfig来解析init.rc配置文件。.rc文件以行为单位,以空格为间隔,以#开始代表注释行。.rc文件主要包含Action、Service、Command、Options、Import,其中对于Action和Service的名称都是唯一的,对于重复的命名视为无效。init.rc中的Action、Service语句都有相应的类来解析,即ActionParser、ServiceParser。 以下为init.rc配置文件的部分内容。

# /system/core/rootdir/init.rc

import /init.environ.rc
import /system/etc/init/hw/init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /system/etc/init/hw/init.usb.configfs.rc
import /system/etc/init/hw/init.${ro.zygote}.rc

# Cgroups are mounted right before early-init using list from /etc/cgroups.json
on early-init
    start ueventd

on init
    sysclktz 0
    # Start essential services.
    start servicemanager
    start hwservicemanager
    start vndservicemanager

# Mount filesystems and start core system services.
on late-init
    trigger early-fs

    # Mount fstab in init.{$device}.rc by mount_all command. Optional parameter
    # '--early' can be specified to skip entries with 'latemount'.
    # /system and /vendor must be mounted by the end of the fs stage,
    # while /data is optional.
    trigger fs
    trigger post-fs

    # Mount fstab in init.{$device}.rc by mount_all with '--late' parameter
    # to only mount entries with 'latemount'. This is needed if '--early' is
    # specified in the previous mount_all command on the fs stage.
    # With /system mounted and properties form /system + /factory available,
    # some services can be started.
    trigger late-fs

    # Now we can mount /data. File encryption requires keymaster to decrypt
    # /data, which in turn can only be loaded when system properties are present.
    trigger post-fs-data

    # Should be before netd, but after apex, properties and logging is available.
    trigger load_bpf_programs

    # 这里启动zygote-start
    # Now we can start zygote for devices with file based encryption
    trigger zygote-start

    # Remove a file to wake up anything waiting for firmware.
    trigger firmware_mounts_complete

    trigger early-boot
    trigger boot

# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
on zygote-start && property:ro.crypto.state=unencrypted
    wait_for_prop odsign.verification.done 1
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start statsd
    start netd
    start zygote
    start zygote_secondary

可以看到,在解析init.rc的配置中,在late-init阶段启动了Zygote进程。

servicemanager.rc

# frameworks/native/cmds/servicemanager/servicemanager.rc

service servicemanager /system/bin/servicemanager
    class core animation
    user system
    group system readproc
    critical
    file /dev/kmsg w
    onrestart setprop servicemanager.ready false
    onrestart restart --only-if-running apexd
    onrestart restart audioserver
    onrestart restart gatekeeperd
    onrestart class_restart --only-enabled main
    onrestart class_restart --only-enabled hal
    onrestart class_restart --only-enabled early_hal
    task_profiles ServiceCapacityLow
    shutdown critical

Service Manager的主程序,负责初始化Binder服务管理器和处理Binder通信相关的操作,确保Binder服务正常运行并处理通信事件。

初始化Binder驱动和Binder服务管理器。
注册Service Manager服务。
设置Binder通信的上下文对象和回调函数。
进入事件处理循环,等待和处理Binder通信的事件。

4.4servicemanager

在 Android 系统中,Service Manager 进程会先于 Zygote 进程启动。

Service Manager 进程在 Binder 进程间通信机制中是一个非常重要的守护进程,它用于管理系统中的各种服务,其最核心的两个功能是查询和注册服务。

Service Manager 进程的启动过程主要分为以下三步:

  1. 打开 binder 驱动:通过调用 binder_open 函数,使用 open 系统调用打开 binder 设备驱动,并进行内存映射。
  2. 注册成为 binder 服务的大管家:使用 binder_become_context_manager 函数,通过 ioctl 与 binder 驱动进行交互,完成相关注册操作。
  3. 进入无限循环,处理 client 端发来的请求:调用 binder_loop 函数,在循环中等待并处理客户端的请求。
// /frameworks/native/cmds/servicemanager/main.cpp

int main(int argc, char** argv) {
    android::base::InitLogging(argv, android::base::KernelLogger);

    if (argc > 2) {
        LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
    }

    // 根据参数确认代码的设备是binder还是vndbinder
    const char* driver = argc == 2 ? argv[1] : "/dev/binder";

    LOG(INFO) << "Starting sm instance on " << driver;

    //进行binder驱动的初始化
    sp<ProcessState> ps = ProcessState::initWithDriver(driver);
    // 告知驱动最大线程数,并设定servicemanager的线程最大数
    ps->setThreadPoolMaxThreadCount(0);
    // 设置调用限制,FATAL_IF_NOT_ONEWA意思是:在阻塞调用时中止进程
    // oneway 限制,ServiceManager发起的 Binder 调用必须是单向,否则打印堆栈日志提示
    ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);

    //实例化ServiceManager,ServiceManager是Binder服务的管理类,它允许注册和获取服务实例,传入access类用于selinux鉴权
    sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());
    //将manager对象自己注册成名字是"manager"的服务,作为一个特殊service添加进来
    if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
        LOG(ERROR) << "Could not self register servicemanager";
    }

    //将manager对象设置为当前线程的上下文对象,IPCThreadState是Binder的线程状态类,用来管理每个线程的Binder环境
    IPCThreadState::self()->setTheContextObject(manager);
    //将当前线程设置为上下文管理器,使得当前线程成为 Binder 的上下文管理器
    ps->becomeContextManager();

    sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);

    //将BinderCallback 设置到looper中,用于处理Binder通信的回调。BinderCallback是自定义的回调类,用于处理Binder通信的回调事件
    BinderCallback::setupTo(looper);
    //将ClientCallbackCallback设置到looper中,用于处理客户端回调的回调事件。ClientCallbackCallback是自定义的回调类,用于处理客户端回调的回调事件
    ClientCallbackCallback::setupTo(looper, manager);

#ifndef VENDORSERVICEMANAGER
    if (!SetProperty("servicemanager.ready", "true")) {
        LOG(ERROR) << "Failed to set servicemanager ready property";
    }
#endif

    while(true) {
        //通过 looper->pollAll(-1) 等待和处理事件。pollAll(-1) 表示等待直到有事件到达才返回
        looper->pollAll(-1);
    }

    // should not be reached
    return EXIT_FAILURE;
}

initWithDriver

// /frameworks/native/libs/binder/ProcessState.cpp

sp<ProcessState> ProcessState::initWithDriver(const char* driver)
{
    return init(driver, true /*requireDefault*/);
}
...
// sp智能指针引用的ProcessState进程单例
[[clang::no_destroy]] static sp<ProcessState> gProcess;
...
sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
{
#ifdef BINDER_IPC_32BIT
    LOG_ALWAYS_FATAL("32-bit binder IPC is not supported for new devices starting in Android P. If "
                     "you do need to use this mode, please see b/232423610 or file an issue with "
                     "AOSP upstream as otherwise this will be removed soon.");
#endif

    if (driver == nullptr) {
        std::lock_guard<std::mutex> l(gProcessMutex);
        if (gProcess) {
            verifyNotForked(gProcess->mForked);
        }
        return gProcess;
    }

    [[clang::no_destroy]] static std::once_flag gProcessOnce;
    // call_onece确保函数或代码片段在多线程环境下,只需要执行一次
    std::call_once(gProcessOnce, [&](){
        if (access(driver, R_OK) == -1) {
            ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);
            driver = "/dev/binder";
        }

        if (0 == strcmp(driver, "/dev/vndbinder") && !isVndservicemanagerEnabled()) {
            ALOGE("vndservicemanager is not started on this device, you can save resources/threads "
                  "by not initializing ProcessState with /dev/vndbinder.");
        }

        // we must install these before instantiating the gProcess object,
        // otherwise this would race with creating it, and there could be the
        // possibility of an invalid gProcess object forked by another thread
        // before these are installed
        int ret = pthread_atfork(ProcessState::onFork, ProcessState::parentPostFork,
                                 ProcessState::childPostFork);
        LOG_ALWAYS_FATAL_IF(ret != 0, "pthread_atfork error %s", strerror(ret));

        std::lock_guard<std::mutex> l(gProcessMutex);
        // 1.创建sp智能指针引用的ProcessState对象
        gProcess = sp<ProcessState>::make(driver);
    });

    if (requireDefault) {
        // Detect if we are trying to initialize with a different driver, and
        // consider that an error. ProcessState will only be initialized once above.
        LOG_ALWAYS_FATAL_IF(gProcess->getDriverName() != driver,
                            "ProcessState was already initialized with %s,"
                            " can't initialize with %s.",
                            gProcess->getDriverName().c_str(), driver);
    }

    verifyNotForked(gProcess->mForked);
    return gProcess;
}
...
static base::Result<int> open_driver(const char* driver) {
    // 3.open系统调用打开/dev/binder驱动设备, 以读写方式,以及为新建的文件描述符使能 close-on-exec(执行exec时关闭) 标志,避免文件描述符无意间泄漏给了fork创建的子进程
    int fd = open(driver, O_RDWR | O_CLOEXEC);
    if (fd < 0) {
        return base::ErrnoError() << "Opening '" << driver << "' failed";
    }
    int vers = 0;
    // 检查版本号
    status_t result = ioctl(fd, BINDER_VERSION, &vers);
    if (result == -1) {
        close(fd);
        return base::ErrnoError() << "Binder ioctl to obtain version failed";
    }
    if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
        close(fd);
        return base::Error() << "Binder driver protocol(" << vers
                             << ") does not match user space protocol("
                             << BINDER_CURRENT_PROTOCOL_VERSION
                             << ")! ioctl() return value: " << result;
    }
    size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
    // 设置最大线程数,该数值为15
    result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
    if (result == -1) {
        ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
    }
    uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
    result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
    if (result == -1) {
        ALOGE_IF(ProcessState::isDriverFeatureEnabled(
                     ProcessState::DriverFeature::ONEWAY_SPAM_DETECTION),
                 "Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
    }
    return fd;
}

ProcessState::ProcessState(const char* driver)
      : mDriverName(String8(driver)),
        mDriverFD(-1),
        mVMStart(MAP_FAILED),
        mThreadCountLock(PTHREAD_MUTEX_INITIALIZER),
        mThreadCountDecrement(PTHREAD_COND_INITIALIZER),
        mExecutingThreadsCount(0),
        mWaitingForThreads(0),
        mMaxThreads(DEFAULT_MAX_BINDER_THREADS),
        mCurrentThreads(0),
        mKernelStartedThreads(0),
        mStarvationStartTimeMs(0),
        mForked(false),
        mThreadPoolStarted(false),
        mThreadPoolSeq(1),
        mCallRestriction(CallRestriction::NONE) {
    // 2.构造方法里调用open_driver执行打开Binder驱动逻辑
    base::Result<int> opened = open_driver(driver);

    if (opened.ok()) {
        // mmap the binder, providing a chunk of virtual address space to receive transactions.
        mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,
                        opened.value(), 0);
        if (mVMStart == MAP_FAILED) {
            close(opened.value());
            // *sigh*
            opened = base::Error()
                    << "Using " << driver << " failed: unable to mmap transaction memory.";
            mDriverName.clear();
        }
    }

#ifdef __ANDROID__
    LOG_ALWAYS_FATAL_IF(!opened.ok(), "Binder driver '%s' could not be opened. Terminating: %s",
                        driver, opened.error().message().c_str());
#endif

    if (opened.ok()) {
        mDriverFD = opened.value();
    }
}

打开Binder驱动

这里看一下打开Binder驱动的代码:

// 注意这是Kernel代码,AOSP把Kernel分离出来了
// drivers/android/binder.c 5.10

static int binder_open(struct inode *nodp, struct file *filp)
{
	struct binder_proc *proc, *itr;
	struct binder_proc_ext *eproc;
	struct binder_device *binder_dev;
	struct binderfs_info *info;
	struct dentry *binder_binderfs_dir_entry_proc = NULL;
	bool existing_pid = false;

	binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d:%d\n", __func__,
		     current->group_leader->pid, current->pid);

	eproc = kzalloc(sizeof(*eproc), GFP_KERNEL);
	proc = &eproc->proc;
	if (proc == NULL)
		return -ENOMEM;
	spin_lock_init(&proc->inner_lock);
	spin_lock_init(&proc->outer_lock);
	get_task_struct(current->group_leader);
	// 这里的current表示的是当前的进程
	proc->tsk = current->group_leader;
	eproc->cred = get_cred(filp->f_cred);
	INIT_LIST_HEAD(&proc->todo);
	init_waitqueue_head(&proc->freeze_wait);
	if (binder_supported_policy(current->policy)) {
		proc->default_priority.sched_policy = current->policy;
		proc->default_priority.prio = current->normal_prio;
	} else {
		proc->default_priority.sched_policy = SCHED_NORMAL;
		proc->default_priority.prio = NICE_TO_PRIO(0);
	}

	/* binderfs stashes devices in i_private */
	if (is_binderfs_device(nodp)) {
		binder_dev = nodp->i_private;
		info = nodp->i_sb->s_fs_info;
		binder_binderfs_dir_entry_proc = info->proc_log_dir;
	} else {
		binder_dev = container_of(filp->private_data,
					  struct binder_device, miscdev);
	}
	refcount_inc(&binder_dev->ref);
	proc->context = &binder_dev->context;
	binder_alloc_init(&proc->alloc);

	binder_stats_created(BINDER_STAT_PROC);
	proc->pid = current->group_leader->pid;
	INIT_LIST_HEAD(&proc->delivered_death);
	INIT_LIST_HEAD(&proc->waiting_threads);
	filp->private_data = proc;

	mutex_lock(&binder_procs_lock);
	hlist_for_each_entry(itr, &binder_procs, proc_node) {
		if (itr->pid == proc->pid) {
			existing_pid = true;
			break;
		}
	}
	hlist_add_head(&proc->proc_node, &binder_procs);
	mutex_unlock(&binder_procs_lock);
	trace_android_vh_binder_preset(&binder_procs, &binder_procs_lock);
	if (binder_debugfs_dir_entry_proc && !existing_pid) {
		char strbuf[11];

		snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
		/*
		 * proc debug entries are shared between contexts.
		 * Only create for the first PID to avoid debugfs log spamming
		 * The printing code will anyway print all contexts for a given
		 * PID so this is not a problem.
		 */
		proc->debugfs_entry = debugfs_create_file(strbuf, 0444,
			binder_debugfs_dir_entry_proc,
			(void *)(unsigned long)proc->pid,
			&proc_fops);
	}

	if (binder_binderfs_dir_entry_proc && !existing_pid) {
		char strbuf[11];
		struct dentry *binderfs_entry;

		snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
		/*
		 * Similar to debugfs, the process specific log file is shared
		 * between contexts. Only create for the first PID.
		 * This is ok since same as debugfs, the log file will contain
		 * information on all contexts of a given PID.
		 */
		binderfs_entry = binderfs_create_file(binder_binderfs_dir_entry_proc,
			strbuf, &proc_fops, (void *)(unsigned long)proc->pid);
		if (!IS_ERR(binderfs_entry)) {
			proc->binderfs_entry = binderfs_entry;
		} else {
			int error;

			error = PTR_ERR(binderfs_entry);
			pr_warn("Unable to create file %s in binderfs (error %d)\n",
				strbuf, error);
		}
	}

	return 0;
}

这样Client进程打开Binder驱动时调用binder_open(),就将当前进程的task_struct进程描述符绑定到了对应的binder_proc的tsk字段里。也就能获取Client进程的uid了。

接下来请阅读:android u开机流程详细分析(中) - zygote

标签:kernel,14,Boot,init,dev,system,binder,rc,proc
From: https://blog.csdn.net/qq_45845172/article/details/140782899

相关文章

  • 基于SpringBoot+Vue的宠物医院管理系统设计与实现(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我自己的网站自己的小程序(小蔡coding)代码参考数据库参考源码获取前言......
  • 基于SpringBoot+Vue的高校实验室教学管理系统的设计和实现(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示论文参考具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我自己的网站自己的小程序(小蔡coding)代码参考数据库参考源码获取前言......
  • 基于SpringBoot+Vue+uniapp的竞赛报名系统的详细设计和实现(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • 免费【2024】springboot宠物美容机构CRM系统设计与实现
    博主介绍:✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌技术范围:SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数......
  • 免费【2024】springboot 宠物领养救助平台的开发与设计
    博主介绍:✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌技术范围:SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数......
  • P8314 Parkovi 题解
    题意:树,边有边权,求一种选出\(k\)个点染色的方案,使得每个点到最近的一个被染色点的距离的最大值最小,\(n\le2\cdot10^5\).Solution先看部分分:\(n\le20\):直接\(C_n^k\)爆搜.\(k=1\):对每个点\(u\)求出\(f(u)\)和\(g(u)\)分别表示\(u\)到子树内点距离的最大值、\(u\)......
  • 毕业设计|基于springboot的房屋租赁系统|代码讲解
    收藏点赞不迷路 关注作者有好处文末获取源码一、系统展示二、万字文档展示开发语言:Java数据库:MySQL技术:Spring+SpringMVC+MyBatis+Vue工具:IDEA/Ecilpse、Navicat、Maven 编号:springboot028一、系统展示二、万字文档展示5.1租客功能模块的实现5.1.1系统主......
  • JAVA毕业设计|springboot房屋租赁系统包含文档代码讲解
     收藏点赞不迷路 关注作者有好处文末获取源码一、系统展示二、万字文档展示开发语言:Java数据库:MySQL技术:Spring+SpringMVC+MyBatis+Vue工具:IDEA/Ecilpse、Navicat、Maven 编号:springboot008一、系统展示二、万字文档展示第5章系统详细设计5.1管理员功能模......
  • JAVA毕业设计|springboot在线宠物用品交易网站的设计与实现包含文档代码讲解
    收藏点赞不迷路 关注作者有好处文末获取源码一、系统展示二、万字文档展示开发语言:Java数据库:MySQL技术:Spring+SpringMVC+MyBatis+Vue工具:IDEA/Ecilpse、Navicat、Maven 编号:springboot082一、系统展示二、万字文档展示第5章系统详细设计5.1管理员模块的......
  • Javaweb项目|springboot大学生就业招聘系统的设计与实现
    收藏点赞不迷路 关注作者有好处文末获取源码一、系统展示二、万字文档展示 基于springboot大学生就业招聘系统的设计与实现开发语言:Java数据库:MySQL技术:Spring+SpringMVC+MyBatis+Vue工具:IDEA/Ecilpse、Navicat、Maven 编号:springboot047一、系统展示二、万......