First stage init

目录

概述

1. 进行第一阶段挂载工作

主要工作:
1. 读dts中的fstab,以及fstab文件
2. 创建分区的设备节点,设备节点的文件链接。dm设备
3. 配置avb,创建dm-verity设备
4. 挂载分区
5. 将根目录切换到/system目录下

源码解析

android/system/core/init/first_stage_main.cpp

android/system/core/init/first_stage_init.cpp

android/system/core/init/first_stage_mount.cpp

1. first stage init-还在内核上下文中

1.1 main

int main(int argc, char** argv) {
    return android::init::FirstStageMain(argc, argv);
}

1.2 FirstStageMain

int FirstStageMain(int argc, char** argv) {
    // 配置panic的时候重启到bootloader
    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(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);
    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到tmpfs中
    // /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"));
#undef CHECKCALL
// std的输出,输出到null
    SetStdioToDevNull(argv);
    // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
    // talk to the outside world...
    // 设置log输出到/dev/kmsg
    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
    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();
    }
// 设置串口输出,userdebug版本默认开启
    auto want_console = ALLOW_FIRST_STAGE_CONSOLE ? FirstStageConsole(cmdline) : 0;
// 加载内核模块
    if (!LoadKernelModules(IsRecoveryMode() && !ForceNormalBoot(cmdline), want_console)) {
        if (want_console != FirstStageConsoleParam::DISABLED) {
            LOG(ERROR) << "Failed to load kernel modules, starting console";
        } else {
            LOG(FATAL) << "Failed to load kernel modules";
        }
    }

    if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) {
        StartConsole();
    }

    // 注意env.cfg中要配置androidboot.force_normal_boot=1,不然的话,刷gki会进recovery
    // 限制ramdisk在/first_stage_ramdisk文件夹内
    if (ForceNormalBoot(cmdline)) {
        mkdir("/first_stage_ramdisk", 0755);
        // 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) {
            LOG(FATAL) << "Could not bind mount /first_stage_ramdisk to itself";
        }
        SwitchRoot("/first_stage_ramdisk");
    }

    // If this file 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) {
        std::error_code ec;  // to invoke the overloaded copy_file() that won't throw.
        // 将adb_debug.prop和userdebug_plat_sepolicy.cil文件拷贝到/debug_ramdisk/adb_debug.prop和/debug_ramdisk/userdebug_plat_sepolicy.cil
        if (!fs::copy_file("/adb_debug.prop", kDebugRamdiskProp, ec) ||
            !fs::copy_file("/userdebug_plat_sepolicy.cil", kDebugRamdiskSEPolicy, ec)) {
            LOG(ERROR) << "Failed to setup debug ramdisk";
        } else {
            // setenv for second-stage init to read above kDebugRamdisk* files.
            // 然后在这里设1
            setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
        }
    }

    // 1. 进行第一阶段挂载
    if (!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) {
        // 卸载了ramdisk了
        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);
    // 2. 第二阶段init,selinux_setup配置
    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;
}

bool ForceNormalBoot(const std::string& cmdline) {
    return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos;
}

1.3 DoFirstStageMount-进行第一阶段挂载

bool DoFirstStageMount() {
    // Skips first stage mount if we're in recovery mode.
    if (IsRecoveryMode()) {
        LOG(INFO) << "First stage mount skipped (recovery mode)";
        return true;
    }

    std::unique_ptr<FirstStageMount> handle = FirstStageMount::Create();
    if (!handle) {
        LOG(ERROR) << "Failed to create FirstStageMount";
        return false;
    }
    return handle->DoFirstStageMount();
}

1.4 ReadFirstStageFstab-读fstab

static Fstab ReadFirstStageFstab() {
    Fstab fstab;
    // 从dts中读取fstab的值
    if (!ReadFstabFromDt(&fstab)) {
        // 读取/vendor/etc/fstab.sun50iw10p1文件
        if (ReadDefaultFstab(&fstab)) {
            fstab.erase(std::remove_if(fstab.begin(), fstab.end(),
                                       [](const auto& entry) {
                                           // 去掉没有first_stage_mount标志的
                                           return !entry.fs_mgr_flags.first_stage_mount;
                                       }),
                        fstab.end());
        } else {
            LOG(INFO) << "Failed to fstab for first stage mount";
        }
    }
    return fstab;
}

1.5 LoadKernelModules-加载内核模块

#define MODULE_BASE_DIR "/lib/modules"
bool LoadKernelModules(bool recovery, bool want_console) {
    struct utsname uts;
    if (uname(&uts)) {
        LOG(FATAL) << "Failed to get kernel version.";
    }
    int major, minor;
    if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
        LOG(FATAL) << "Failed to parse kernel version " << uts.release;
    }

    std::unique_ptr<DIR, decltype(&closedir)> base_dir(opendir(MODULE_BASE_DIR), closedir);
    if (!base_dir) {
        LOG(INFO) << "Unable to open /lib/modules, skipping module loading.";
        return true;
    }
    dirent* entry;
    std::vector<std::string> module_dirs;
    while ((entry = readdir(base_dir.get()))) {
        if (entry->d_type != DT_DIR) {
            continue;
        }
        int dir_major, dir_minor;
        if (sscanf(entry->d_name, "%d.%d", &dir_major, &dir_minor) != 2 || dir_major != major ||
            dir_minor != minor) {
            continue;
        }
        module_dirs.emplace_back(entry->d_name);
    }

    // Sort the directories so they are iterated over during module loading
    // in a consistent order. Alphabetical sorting is fine here because the
    // kernel version at the beginning of the directory name must match the
    // current kernel version, so the sort only applies to a label that
    // follows the kernel version, for example /lib/modules/5.4 vs.
    // /lib/modules/5.4-gki.
    std::sort(module_dirs.begin(), module_dirs.end());
//module_dirs是为空的,/lib/modules/下没有文件夹
    for (const auto& module_dir : module_dirs) {
        std::string dir_path = MODULE_BASE_DIR "/";
        dir_path.append(module_dir);
        Modprobe m({dir_path}, GetModuleLoadList(recovery, dir_path));
        bool retval = m.LoadListedModules(!want_console);
        int modules_loaded = m.GetModuleCount();
        if (modules_loaded > 0) {
            return retval;
        }
    }
// "/lib/modules","modules.load"
    Modprobe m({MODULE_BASE_DIR}, GetModuleLoadList(recovery, MODULE_BASE_DIR));
    bool retval = m.LoadListedModules(!want_console);
    int modules_loaded = m.GetModuleCount();
    if (modules_loaded > 0) {
        return retval;
    }
    return true;
}

1.6 GetModuleLoadList

std::string GetModuleLoadList(bool recovery, const std::string& dir_path) {
    auto module_load_file = "modules.load";
    if (recovery) {
        struct stat fileStat;
        std::string recovery_load_path = dir_path + "/modules.load.recovery";
        if (!stat(recovery_load_path.c_str(), &fileStat)) {
            module_load_file = "modules.load.recovery";
        }
    }

    return module_load_file;
}

2. FirstStageMount类

2.1 Create-读fstab文件,创建FirstStageMountVBootV2类

std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
    // 读fstab文件
    auto fstab = ReadFirstStageFstab();
    if (IsDtVbmetaCompatible(fstab)) {
        // avb2.0走这里,走FirstStageMount类和构造函数构造函数
        return std::make_unique<FirstStageMountVBootV2>(std::move(fstab));
    } else {
        return std::make_unique<FirstStageMountVBootV1>(std::move(fstab));
    }
}

2.2 IsDtVbmetaCompatible-看dts是否配置vbmeta和fstab配置了avb

static inline bool IsDtVbmetaCompatible(const Fstab& fstab) {
    if (std::any_of(fstab.begin(), fstab.end(),
                    // fstab中avb标志的
                    [](const auto& entry) { return entry.fs_mgr_flags.avb; })) {
        return true;
    }
    // 读/proc/device-tree/firmware/android/vbmeta/compatible文件,为android,vbmeta
    return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
}

2.3 FirstStageMount-构造函数,获取super分区名字,super分区不一定叫super

// fstab_的值为system,product,vendor;配了avb就是need_dm_verity_为true
FirstStageMount::FirstStageMount(Fstab fstab) : need_dm_verity_(false), fstab_(std::move(fstab)) {
    // super值
    super_partition_name_ = fs_mgr_get_super_partition_name();
}

2.4 DoFirstStageMount-创建分区设备节点,挂载分区

bool FirstStageMount::DoFirstStageMount() {
    // 配置了logical标志
    if (!IsDmLinearEnabled() && fstab_.empty()) {
        // Nothing to mount.
        LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)";
        return true;
    }
// 创建分区设备节点
    if (!InitDevices()) return false;
// 挂载分区
    if (!MountPartitions()) return false;

    return true;
}

2.5 IsDmLinearEnabled-logical标志

bool FirstStageMount::IsDmLinearEnabled() {
    for (const auto& entry : fstab_) {
        if (entry.fs_mgr_flags.logical) return true;
    }
    return false;
}

2.6 InitDevices-创建device-mapper和分区设备和super分区设备

bool FirstStageMount::InitDevices() {
    std::set<std::string> devices;
    // 加入super分区
    GetSuperDeviceName(&devices);
// vbmeta,vbmeta_system,vbmeta_vendor,boot,super分区
    if (!GetDmVerityDevices(&devices)) {
        return false;
    }
// vbmeta,vbmeta_system,vbmeta_vendor,boot,super分区
    if (!InitRequiredDevices(std::move(devices))) {
        return false;
    }

    if (IsDmLinearEnabled()) {
        auto super_symlink = "/dev/block/by-name/"s + super_partition_name_;
        // 获取/dev/block/mmcblkp04
        if (!android::base::Realpath(super_symlink, &super_path_)) {
            PLOG(ERROR) << "realpath failed: " << super_symlink;
            return false;
        }
    }
    return true;
}
void FirstStageMount::GetSuperDeviceName(std::set<std::string>* devices) {
    // Add any additional devices required for dm-linear mappings.
    if (!IsDmLinearEnabled()) {
        return;
    }
// 加入super分区
    devices->emplace(super_partition_name_);
}

2.7 InitRequiredDevices-创建device-mapper设备节点,以及vbmeta,vbmeta_system,vbmeta_vendor,boot,super块设备节点和链接

bool FirstStageMount::InitRequiredDevices(std::set<std::string> devices) {
    // 创建devicemapper设备节点
    if (!block_dev_init_.InitDeviceMapper()) {
        return false;
    }
    if (devices.empty()) {
        return true;
    }// vbmeta,vbmeta_system,vbmeta_vendor,boot,super分区块设备节点
    return block_dev_init_.InitDevices(std::move(devices));
}

2.8 MountPartitions-挂载metadata,system,product,vendor分区,以及remount相关

bool FirstStageMount::MountPartitions() {
    // Mount /metadata before creating logical partitions, since we need to
    // know whether a snapshot merge is in progress.
    auto metadata_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
        return entry.mount_point == "/metadata";
    });
    if (metadata_partition != fstab_.end()) {
        // 1. 先挂载metadata分区
        if (MountPartition(metadata_partition, true /* erase_same_mounts */)) {
            // Copies DSU AVB keys from the ramdisk to /metadata.
            // Must be done before the following TrySwitchSystemAsRoot().
            // Otherwise, ramdisk will be inaccessible after switching root.
            // 拷贝dsuavb密钥
            CopyDsuAvbKeys();
        }
    }
// 2. 创建logical分区
    if (!CreateLogicalPartitions()) return false;
// 3. 将system分区设为root
    if (!TrySwitchSystemAsRoot()) return false;
// gsi的时候,不挂载/oem /product /system_ext分区
    if (!SkipMountingPartitions(&fstab_)) return false;

    for (auto current = fstab_.begin(); current != fstab_.end();) {
        // We've already mounted /system above.
        // 省略掉system分区
        if (current->mount_point == "/system") {
            ++current;
            continue;
        }

        // Skip raw partition entries such as boot, dtbo, etc.
        // Having emmc fstab entries allows us to probe current->vbmeta_partition
        // in InitDevices() when they are AVB chained partitions.
        if (current->fs_type == "emmc") {
            ++current;
            continue;
        }

        Fstab::iterator end;
        // 挂载product和vendor分区
        if (!MountPartition(current, false /* erase_same_mounts */, &end)) {
            if (current->fs_mgr_flags.no_fail) {
                LOG(INFO) << "Failed to mount " << current->mount_point
                          << ", ignoring mount for no_fail partition";
            } else if (current->fs_mgr_flags.formattable) {
                LOG(INFO) << "Failed to mount " << current->mount_point
                          << ", ignoring mount for formattable partition";
            } else {
                PLOG(ERROR) << "Failed to mount " << current->mount_point;
                return false;
            }
        }
        current = end;
    }
// remount相关,overlayfs相关的
    // If we don't see /system or / in the fstab, then we need to create an root entry for
    // overlayfs.
    if (!GetEntryForMountPoint(&fstab_, "/system") && !GetEntryForMountPoint(&fstab_, "/")) {
        FstabEntry root_entry;
        if (GetRootEntry(&root_entry)) {
            fstab_.emplace_back(std::move(root_entry));
        }
    }

    // heads up for instantiating required device(s) for overlayfs logic
    auto init_devices = [this](std::set<std::string> devices) -> bool {
        for (auto iter = devices.begin(); iter != devices.end();) {
            if (android::base::StartsWith(*iter, "/dev/block/dm-")) {
                if (!block_dev_init_.InitDmDevice(*iter)) {
                    return false;
                }
                iter = devices.erase(iter);
            } else {
                iter++;
            }
        }
        return InitRequiredDevices(std::move(devices));
    };
    MapScratchPartitionIfNeeded(&fstab_, init_devices);

    fs_mgr_overlayfs_mount_all(&fstab_);

    return true;
}

2.9 MountPartition-创建逻辑分区,dm设备,挂载分区

bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
                                     Fstab::iterator* end) {
    // Sets end to begin + 1, so we can just return on failure below.
    if (end) {
        *end = begin + 1;
    }

    if (begin->fs_mgr_flags.logical) {
        // 更新block_device的值,system_a 变为/dev/block/dm-0设备
        if (!fs_mgr_update_logical_partition(&(*begin))) {
            return false;
        }
        // 创建dm-0设备节点,/dev/block/dm-0
        if (!block_dev_init_.InitDmDevice(begin->blk_device)) {
            return false;
        }
    }
    // 创建dm-verity设备,设置avb相关的配置
    if (!SetUpDmVerity(&(*begin))) {
        PLOG(ERROR) << "Failed to setup verity for '" << begin->mount_point << "'";
        return false;
    }
// 进行挂载
    bool mounted = (fs_mgr_do_mount_one(*begin) == 0);

    // Try other mounts with the same mount point.
    Fstab::iterator current = begin + 1;
    for (; current != fstab_.end() && current->mount_point == begin->mount_point; current++) {
        if (!mounted) {
            // blk_device is already updated to /dev/dm-<N> by SetUpDmVerity() above.
            // Copy it from the begin iterator.
            current->blk_device = begin->blk_device;
            mounted = (fs_mgr_do_mount_one(*current) == 0);
        }
    }
    if (erase_same_mounts) {
        current = fstab_.erase(begin, current);
    }
    if (end) {
        *end = current;
    }
    return mounted;
}

2.10 CopyDsuAvbKeys-拷贝avb keys到metadata目录中

void FirstStageMount::CopyDsuAvbKeys() {
    std::error_code ec;
    // Removing existing keys in gsi::kDsuAvbKeyDir as they might be stale.
    // 删除/metadata/gsi/dsu/avb/目录
    std::filesystem::remove_all(gsi::kDsuAvbKeyDir, ec);
    if (ec) {
        LOG(ERROR) << "Failed to remove directory " << gsi::kDsuAvbKeyDir << ": " << ec.message();
    }
    // Copy keys from the ramdisk /avb/* to gsi::kDsuAvbKeyDir.
    static constexpr char kRamdiskAvbKeyDir[] = "/avb";
    // 将ramdisk下的key拷贝到/metadata/gsi/dsu/avb/目录
    std::filesystem::copy(kRamdiskAvbKeyDir, gsi::kDsuAvbKeyDir, ec);
    if (ec) {
        LOG(ERROR) << "Failed to copy " << kRamdiskAvbKeyDir << " into " << gsi::kDsuAvbKeyDir
                   << ": " << ec.message();
    }
}

2.11 CreateLogicalPartitions-创建逻辑分区

bool FirstStageMount::CreateLogicalPartitions() {
    if (!IsDmLinearEnabled()) {
        return true;
    }
    if (super_path_.empty()) {
        LOG(ERROR) << "Could not locate logical partition tables in partition "
                   << super_partition_name_;
        return false;
    }
// 这个是virtual AB升级相关的,/metadata/ota/snapshot-boot目录是否存在
    if (SnapshotManager::IsSnapshotManagerNeeded()) {
        auto sm = SnapshotManager::NewForFirstStageMount();
        if (!sm) {
            return false;
        }
        if (sm->NeedSnapshotsInFirstStageMount()) {
            // When COW images are present for snapshots, they are stored on
            // the data partition.
            if (!InitRequiredDevices({"userdata"}) && !InitRequiredDevices({"UDISK"})) {
                return false;
            }
            return sm->CreateLogicalAndSnapshotPartitions(super_path_);
        }
    }
// 读super分区的metadata信息
    auto metadata = android::fs_mgr::ReadCurrentMetadata(super_path_);
    if (!metadata) {
        LOG(ERROR) << "Could not read logical partition metadata from " << super_path_;
        return false;
    }
    // 初始化blockdevice,super分区在之前早就初始化好了,所以这里什么都没做
    if (!InitDmLinearBackingDevices(*metadata.get())) {
        return false;
    }
    // 创建dm-0等逻辑设备,super_path_为/dev/block/mmcblk0p9
    return android::fs_mgr::CreateLogicalPartitions(*metadata.get(), super_path_);
}

2.12 InitDmLinearBackingDevices-初始化blockdevice,super分区在之前早就初始化好了,所以这里什么都没做

bool FirstStageMount::InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata) {
    std::set<std::string> devices;
// super分区
    auto partition_names = android::fs_mgr::GetBlockDevicePartitionNames(metadata);
    for (const auto& partition_name : partition_names) {
        // The super partition was found in the earlier pass.
        if (partition_name == super_partition_name_) {
            continue;
        }
        devices.emplace(partition_name);
    }
    if (devices.empty()) {
        return true;
    }
    return InitRequiredDevices(std::move(devices));
}

2.13 TrySwitchSystemAsRoot-挂载system分区并设为根目录

bool FirstStageMount::TrySwitchSystemAsRoot() {
    //  dsu相关的
    UseDsuIfPresent();
    // Preloading all AVB keys from the ramdisk before switching root to /system.
    // 读/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey文件,放到preload_avb_key_blobs_中
    PreloadAvbKeys();

    auto system_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
        return entry.mount_point == "/system";
    });

    if (system_partition == fstab_.end()) return true;
// 挂载system分区
    if (MountPartition(system_partition, false /* erase_same_mounts */)) {
        if (dsu_not_on_userdata_ && fs_mgr_verity_is_check_at_most_once(*system_partition)) {
            LOG(ERROR) << "check_most_at_once forbidden on external media";
            return false;
        }
        SwitchRoot("/system");
    } else {
        PLOG(ERROR) << "Failed to mount /system";
        return false;
    }

    return true;
}

2.14 PreloadAvbKeys-读/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey文件,放到preload_avb_key_blobs_中

void FirstStageMount::PreloadAvbKeys() {
    for (const auto& entry : fstab_) {
        // No need to cache the key content if it's empty, or is already cached.
        if (entry.avb_keys.empty() || preload_avb_key_blobs_.count(entry.avb_keys)) {
            continue;
        }

        // Determines all key paths first.
        std::vector<std::string> key_paths;
        if (is_dir(entry.avb_keys.c_str())) {  // fstab_keys might be a dir, e.g., /avb.
            const char* avb_key_dir = entry.avb_keys.c_str();
            std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(avb_key_dir), closedir);
            if (!dir) {
                LOG(ERROR) << "Failed to opendir: " << dir;
                continue;
            }
            // Gets all key pathes under the dir.
            struct dirent* de;
            while ((de = readdir(dir.get()))) {
                if (de->d_type != DT_REG) continue;
                std::string full_path = StringPrintf("%s/%s", avb_key_dir, de->d_name);
                key_paths.emplace_back(std::move(full_path));
            }
            std::sort(key_paths.begin(), key_paths.end());
        } else {
            // avb_keys are key paths separated by ":", if it's not a dir.
            key_paths = Split(entry.avb_keys, ":");
        }

        // Reads the key content then cache it.
        std::vector<std::string> key_blobs;
        for (const auto& path : key_paths) {
            std::string key_value;
            // 读/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey文件,放到preload_avb_key_blobs_中
            if (!ReadFileToString(path, &key_value)) {
                continue;
            }
            key_blobs.emplace_back(std::move(key_value));
        }

        // Maps entry.avb_keys to actual key blobs.
        preload_avb_key_blobs_[entry.avb_keys] = std::move(key_blobs);
    }
}

3. FirstStageMountVBootV2类

3.1 FirstStageMountVBootV2构造函数-读配置的vbmeta分区

FirstStageMountVBootV2::FirstStageMountVBootV2(Fstab fstab)
    : FirstStageMount(std::move(fstab)), avb_handle_(nullptr) {
    std::string device_tree_vbmeta_parts;
        // 读/proc/device-tree/firmware/android/ + vbmeta/parts文件
        // vbmeta验证的分区:vbmeta,vbmeta_system,vbmeta_vendor,boot
    read_android_dt_file("vbmeta/parts", &device_tree_vbmeta_parts);

    for (auto&& partition : Split(device_tree_vbmeta_parts, ",")) {
        if (!partition.empty()) {
            vbmeta_partitions_.emplace_back(std::move(partition));
        }
    }

    for (const auto& entry : fstab_) {
        // avb=vbmeta指定的分区
        if (!entry.vbmeta_partition.empty()) {
            vbmeta_partitions_.emplace_back(entry.vbmeta_partition);
        }
    }

    if (vbmeta_partitions_.empty()) {
        LOG(ERROR) << "Failed to read vbmeta partitions.";
    }
}

3.2 GetDmVerityDevices-找avb相关的分区设备

bool FirstStageMountVBootV2::GetDmVerityDevices(std::set<std::string>* devices) {
    need_dm_verity_ = false;

    std::set<std::string> logical_partitions;

    // fstab_rec->blk_device has A/B suffix.
    for (const auto& fstab_entry : fstab_) {
        if (fstab_entry.fs_mgr_flags.avb) {
            // avb配置
            need_dm_verity_ = true;
        }
        if (fstab_entry.fs_mgr_flags.logical) {
            // Don't try to find logical partitions via uevent regeneration.
            // logical_partitions的值为system,vendor,product
            logical_partitions.emplace(basename(fstab_entry.blk_device.c_str()));
        } else {
            devices->emplace(basename(fstab_entry.blk_device.c_str()));
        }
    }

    // Any partitions needed for verifying the partitions used in first stage mount, e.g. vbmeta
    // must be provided as vbmeta_partitions.
    if (need_dm_verity_) {
        if (vbmeta_partitions_.empty()) {
            LOG(ERROR) << "Missing vbmeta partitions";
            return false;
        }
        // 获取androidboot.slot_suffix的值
        std::string ab_suffix = fs_mgr_get_slot_suffix();
        for (const auto& partition : vbmeta_partitions_) {
            std::string partition_name = partition + ab_suffix;
            // 跳过logical_partitions分区,system,vendor,product分区
            if (logical_partitions.count(partition_name)) {
                continue;
            }
            // devices is of type std::set so it's not an issue to emplace a
            // partition twice. e.g., /vendor might be in both places:
            //   - device_tree_vbmeta_parts_ = "vbmeta,boot,system,vendor"
            //   - mount_fstab_recs_: /vendor_a
            // vbmeta,vbmeta_system,vbmeta_vendor,boot分区
            devices->emplace(partition_name);
        }
    }
    return true;
}

3.3 SetUpDmVerity-avb相关-创建dm设备

bool FirstStageMountVBootV2::SetUpDmVerity(FstabEntry* fstab_entry) {
    AvbHashtreeResult hashtree_result;

    // It's possible for a fstab_entry to have both avb_keys and avb flag.
    // In this case, try avb_keys first, then fallback to avb flag.
    if (!fstab_entry->avb_keys.empty()) {
        if (!InitAvbHandle()) return false;
        // Checks if hashtree should be disabled from the top-level /vbmeta.
        if (avb_handle_->status() == AvbHandleStatus::kHashtreeDisabled ||
            avb_handle_->status() == AvbHandleStatus::kVerificationDisabled) {
            LOG(ERROR) << "Top-level vbmeta is disabled, skip Hashtree setup for "
                       << fstab_entry->mount_point;
            return true;  // Returns true to mount the partition directly.
        } else {
            auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(
                    *fstab_entry, preload_avb_key_blobs_[fstab_entry->avb_keys]);
            if (!avb_standalone_handle) {
                LOG(ERROR) << "Failed to load offline vbmeta for " << fstab_entry->mount_point;
                // Fallbacks to built-in hashtree if fs_mgr_flags.avb is set.
                if (!fstab_entry->fs_mgr_flags.avb) return false;
                LOG(INFO) << "Fallback to built-in hashtree for " << fstab_entry->mount_point;
                hashtree_result =
                        avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
            } else {
                // Sets up hashtree via the standalone handle.
                if (IsStandaloneImageRollback(*avb_handle_, *avb_standalone_handle, *fstab_entry)) {
                    return false;
                }
                hashtree_result = avb_standalone_handle->SetUpAvbHashtree(
                        fstab_entry, false /* wait_for_verity_dev */);
            }
        }
    } else if (fstab_entry->fs_mgr_flags.avb) {
        if (!InitAvbHandle()) return false;
        hashtree_result =
                avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
    } else {
        return true;  // No need AVB, returns true to mount the partition directly.
    }

    switch (hashtree_result) {
        case AvbHashtreeResult::kDisabled:
            return true;  // Returns true to mount the partition.
        case AvbHashtreeResult::kSuccess:
            // The exact block device name (fstab_rec->blk_device) is changed to
            // "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
            // first stage.
            return block_dev_init_.InitDmDevice(fstab_entry->blk_device);
        default:
            return false;
    }
}

4. util类

4.1 is_android_dt_value_expected-dts是否配置了

bool is_android_dt_value_expected(const std::string& sub_path, const std::string& expected_content) {
    std::string dt_content;
    if (read_android_dt_file(sub_path, &dt_content)) {
        if (dt_content == expected_content) {
            return true;
        }
    }
    return false;
}
static std::string init_android_dt_dir() {
    // Use the standard procfs-based path by default
    std::string android_dt_dir = kDefaultAndroidDtDir;
    // The platform may specify a custom Android DT path in kernel cmdline
    ImportKernelCmdline([&](const std::string& key, const std::string& value) {
        if (key == "androidboot.android_dt_dir") {
            android_dt_dir = value;
        }
    });
    LOG(INFO) << "Using Android DT directory " << android_dt_dir;
    return android_dt_dir;
}

// FIXME: The same logic is duplicated in system/core/fs_mgr/
const std::string& get_android_dt_dir() {
    // Set once and saves time for subsequent calls to this function
    static const std::string kAndroidDtDir = init_android_dt_dir();
    return kAndroidDtDir;
}

4.2 read_android_dt_file-读/proc/device-tree/firmware/android/里面的东西

bool read_android_dt_file(const std::string& sub_path, std::string* dt_content) {
    // 读/proc/device-tree/firmware/android/ + vbmeta/compatible文件,为android,vbmeta
    const std::string file_name = get_android_dt_dir() + sub_path;
    if (android::base::ReadFileToString(file_name, dt_content)) {
        if (!dt_content->empty()) {
            // 在字符串末尾删除一个字符,删除'\0'字符
            dt_content->pop_back();  // Trims the trailing '\0' out.
            return true;
        }
    }
    return false;
}

4.3 mkdir_recursive-递归创建文件夹

bool mkdir_recursive(const std::string& path, mode_t mode) {
    std::string::size_type slash = 0;
    while ((slash = path.find('/', slash + 1)) != std::string::npos) {
        auto directory = path.substr(0, slash);
        struct stat info;
        // 如果文件夹不存在
        if (stat(directory.c_str(), &info) != 0) {
            // 则创建它
            auto ret = make_dir(directory, mode);
            if (!ret && errno != EEXIST) return false;
        }
    }
    auto ret = make_dir(path, mode);
    if (!ret && errno != EEXIST) return false;
    return true;
}
bool make_dir(const std::string& path, mode_t mode) {
    std::string secontext;
    // 找文件的selabel
    if (SelabelLookupFileContext(path, mode, &secontext) && !secontext.empty()) {
        setfscreatecon(secontext.c_str());
    }
// 创建文件夹
    int rc = mkdir(path.c_str(), mode);

    if (!secontext.empty()) {
        int save_errno = errno;
        setfscreatecon(nullptr);
        errno = save_errno;
    }

    return rc == 0;
}

4.4 is_dir-判断是否是文件夹

bool is_dir(const char* pathname) {
    struct stat info;
    if (stat(pathname, &info) == -1) {
        return false;
    }
    return S_ISDIR(info.st_mode);
}

4.5 SetStdioToDevNull-标准输出重定向到/dev/null

void SetStdioToDevNull(char** argv) {
    // Make stdin/stdout/stderr all point to /dev/null.
    int fd = open("/dev/null", O_RDWR);  // NOLINT(android-cloexec-open)
    if (fd == -1) {
        int saved_errno = errno;
        android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
        errno = saved_errno;
        PLOG(FATAL) << "Couldn't open /dev/null";
    }
    // 两个描述符都指向/dev/null文件,将log重定向到/dev/null中
    dup2(fd, STDIN_FILENO);
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);
    if (fd > STDERR_FILENO) close(fd);
}

4.6 InitKernelLogging-初始化串口输出

void InitKernelLogging(char** argv) {
    SetFatalRebootTarget();
    android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
}

4.7 InitAborter-fatal log的时候调用这个函数

static void InitAborter(const char* abort_message) {
    // When init forks, it continues to use this aborter for LOG(FATAL), but we want children to
    // simply abort instead of trying to reboot the system.
    if (getpid() != 1) {
        android::base::DefaultAborter(abort_message);
        return;
    }

    InitFatalReboot(SIGABRT);
}

5. BlockDevInitializer类

5.1 BlockDevInitializer构造函数-读boot_devices

BlockDevInitializer::BlockDevInitializer() : uevent_listener_(16 * 1024 * 1024) {
    auto boot_devices = android::fs_mgr::GetBootDevices();
    device_handler_ = std::make_unique<DeviceHandler>(
            std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{},
            std::move(boot_devices), false);
}

5.2 InitDeviceMapper-往/sys目录下的所有设备发送uevent事件,创建device-mapper设备节点

bool BlockDevInitializer::InitDeviceMapper() {
    const std::string dm_path = "/devices/virtual/misc/device-mapper";
    bool found = false;
    auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
        if (uevent.path == dm_path) {
            // 如果是device-mapper设备的话,则调用HandleUevent函数处理信息
            // { 'add'(action), '/devices/virtual/misc/device-mapper'(path), 'misc'(subsystem), ''(firmware), 10(major), 236(minor) }
            device_handler_->HandleUevent(uevent);
            found = true;
            return ListenerAction::kStop;
        }
        return ListenerAction::kContinue;
    };
    // 触发/sys目录下所有设备的uevent事件
    uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
    if (!found) {
        LOG(INFO) << "device-mapper device not found in /sys, waiting for its uevent";
        Timer t;
        uevent_listener_.Poll(dm_callback, 10s);
        LOG(INFO) << "Wait for device-mapper returned after " << t;
    }
    if (!found) {
        LOG(ERROR) << "device-mapper device not found after polling timeout";
        return false;
    }
    return true;
}

5.3 InitDevices-创建dts中的vbmeta,vbmeta_system,vbmeta_vendor,boot,super分区设备

bool BlockDevInitializer::InitDevices(std::set<std::string> devices) {
    auto uevent_callback = [&, this](const Uevent& uevent) -> ListenerAction {
        return HandleUevent(uevent, &devices);
    };
    uevent_listener_.RegenerateUevents(uevent_callback);

    // UeventCallback() will remove found partitions from |devices|. So if it
    // isn't empty here, it means some partitions are not found.
    if (!devices.empty()) {
        LOG(INFO) << __PRETTY_FUNCTION__
                  << ": partition(s) not found in /sys, waiting for their uevent(s): "
                  << android::base::Join(devices, ", ");
        Timer t;
        uevent_listener_.Poll(uevent_callback, 10s);
        LOG(INFO) << "Wait for partitions returned after " << t;
    }

    if (!devices.empty()) {
        LOG(ERROR) << __PRETTY_FUNCTION__ << ": partition(s) not found after polling timeout: "
                   << android::base::Join(devices, ", ");
        return false;
    }
    return true;
}

6.5 HandleUevent-看uevent中的partition_name是否和devices中的匹配

ListenerAction BlockDevInitializer::HandleUevent(const Uevent& uevent,
                                                 std::set<std::string>* devices) {
    // Ignore everything that is not a block device.
    // 忽略不是block的uevent事件
    if (uevent.subsystem != "block") {
        return ListenerAction::kContinue;
    }

    auto name = uevent.partition_name;
    if (name.empty()) {
        size_t base_idx = uevent.path.rfind('/');
        if (base_idx == std::string::npos) {
            return ListenerAction::kContinue;
        }
        name = uevent.path.substr(base_idx + 1);
    }
// vbmeta,vbmeta_system,vbmeta_vendor,boot,super分区设备中找
    auto iter = devices->find(name);
    if (iter == devices->end()) {
        // 没有找到就返回
        return ListenerAction::kContinue;
    }

    LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << name;
// 找到了就擦掉
    devices->erase(iter);
    // 然后处理它的uevent事件
    device_handler_->HandleUevent(uevent);
    return devices->empty() ? ListenerAction::kStop : ListenerAction::kContinue;
}

6.6 InitDmDevice-往/sys/block/dm-0发uevent信息

// Creates "/dev/block/dm-XX" for dm nodes by running coldboot on /sys/block/dm-XX.
bool BlockDevInitializer::InitDmDevice(const std::string& device) {
    // dm-0
    const std::string device_name(basename(device.c_str()));
    const std::string syspath = "/sys/block/" + device_name;
    bool found = false;

    auto uevent_callback = [&device_name, &device, this, &found](const Uevent& uevent) {
        if (uevent.device_name == device_name) {
            LOG(VERBOSE) << "Creating device-mapper device : " << device;
            // 创建links和/dev/block/dm-0设备
            device_handler_->HandleUevent(uevent);
            found = true;
            return ListenerAction::kStop;
        }
        return ListenerAction::kContinue;
    };

    uevent_listener_.RegenerateUeventsForPath(syspath, uevent_callback);
    if (!found) {
        LOG(INFO) << "dm device '" << device << "' not found in /sys, waiting for its uevent";
        Timer t;
        uevent_listener_.Poll(uevent_callback, 10s);
        LOG(INFO) << "wait for dm device '" << device << "' returned after " << t;
    }
    if (!found) {
        LOG(ERROR) << "dm device '" << device << "' not found after polling timeout";
        return false;
    }
    return true;
}

6. DeviceHandler类

6.1 DeviceHandler构造函数

DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions,
                             std::vector<SysfsPermissions> sysfs_permissions,
                             std::vector<Subsystem> subsystems, std::set<std::string> boot_devices,
                             bool skip_restorecon)
    : dev_permissions_(std::move(dev_permissions)),
      sysfs_permissions_(std::move(sysfs_permissions)),
      subsystems_(std::move(subsystems)),
// soc@2900000/4020000.sdmmc,soc@2900000/4022000.sdmmc,soc@2900000
      boot_devices_(std::move(boot_devices)),
      skip_restorecon_(skip_restorecon),
      sysfs_mount_point_("/sys") {}

{ 'add'(action), '/devices/virtual/misc/device-mapper'(path), 'misc'(subsystem), ''(firmware), 10(major), 236(minor) }事件

{'add'(action), '/devices/platform/soc@2900000/4022000.sdmmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p16', 'block', '', 259, 8}事件

{ 'add', '/devices/virtual/block/dm-0', 'block', '', 254, 0 }

void DeviceHandler::HandleUevent(const Uevent& uevent) {
    if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
        // selinux相关的,
        FixupSysPermissions(uevent.path, uevent.subsystem);
    }

    // if it's not a /dev device, nothing to do
    if (uevent.major < 0 || uevent.minor < 0) return;

    std::string devpath;
    std::vector<std::string> links;
    bool block = false;

    if (uevent.subsystem == "block") {
        block = true;
        // /dev/block/mmcblk0p16
        devpath = "/dev/block/" + Basename(uevent.path);

        if (StartsWith(uevent.path, "/devices")) {
            // 创建links,dm也要创建
            links = GetBlockDeviceSymlinks(uevent);
        }
    } else if (const auto subsystem =
                   std::find(subsystems_.cbegin(), subsystems_.cend(), uevent.subsystem);
               subsystem != subsystems_.cend()) {
        devpath = subsystem->ParseDevPath(uevent);
    } else if (uevent.subsystem == "usb") {
        if (!uevent.device_name.empty()) {
            devpath = "/dev/" + uevent.device_name;
        } else {
            // This imitates the file system that would be created
            // if we were using devfs instead.
            // Minors are broken up into groups of 128, starting at "001"
            int bus_id = uevent.minor / 128 + 1;
            int device_id = uevent.minor % 128 + 1;
            devpath = StringPrintf("/dev/bus/usb/%03d/%03d", bus_id, device_id);
        }
    } else if (StartsWith(uevent.subsystem, "usb")) {
        // ignore other USB events
        return;
    } else {
        // misc走这里,devpath=/dev/device-mapper
        devpath = "/dev/" + Basename(uevent.path);
    }
// 创建/dev/device-mapper
    mkdir_recursive(Dirname(devpath), 0755);

    HandleDevice(uevent.action, devpath, block, uevent.major, uevent.minor, links);

    // Duplicate /dev/ashmem device and name it /dev/ashmem<boot_id>.
    // TODO(b/111903542): remove once all users of /dev/ashmem are migrated to libcutils API.
    // device_name == "ashmem"才走这里
    HandleAshmemUevent(uevent);
}
void DeviceHandler::FixupSysPermissions(const std::string& upath,
                                        const std::string& subsystem) const {
    // upaths omit the "/sys" that paths in this list
    // contain, so we prepend it...
    std::string path = "/sys" + upath;
// sysfs_permissions_是空的,不会走这里
    for (const auto& s : sysfs_permissions_) {
        if (s.MatchWithSubsystem(path, subsystem)) s.SetPermissions(path);
    }
// skip_restorecon_为false
    if (!skip_restorecon_ && access(path.c_str(), F_OK) == 0) {
        LOG(VERBOSE) << "restorecon_recursive: " << path;
        // 会对path路径进行restorecon,修正selinux的selabel
        if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
            PLOG(ERROR) << "selinux_android_restorecon(" << path << ") failed";
        }
    }
}
void DeviceHandler::HandleDevice(const std::string& action, const std::string& devpath, bool block,
                                 int major, int minor, const std::vector<std::string>& links) const {
    if (action == "add") {
        // 创建节点
        MakeDevice(devpath, block, major, minor, links);
    }

    // We don't have full device-mapper information until a change event is fired.
    if (action == "add" || (action == "change" && StartsWith(devpath, "/dev/block/dm-"))) {
        // device-mapper的时候links为空的
        // links都链接到/dev/block/mmcblkp16
        for (const auto& link : links) {
            if (!mkdir_recursive(Dirname(link), 0755)) {
                PLOG(ERROR) << "Failed to create directory " << Dirname(link);
            }

            if (symlink(devpath.c_str(), link.c_str())) {
                if (errno != EEXIST) {
                    PLOG(ERROR) << "Failed to symlink " << devpath << " to " << link;
                } else if (std::string link_path;
                           Readlink(link, &link_path) && link_path != devpath) {
                    PLOG(ERROR) << "Failed to symlink " << devpath << " to " << link
                                << ", which already links to: " << link_path;
                }
            }
        }
    }

    if (action == "remove") {
        if (StartsWith(devpath, "/dev/block/dm-")) {
            RemoveDeviceMapperLinks(devpath);
        }
        for (const auto& link : links) {
            std::string link_path;
            if (Readlink(link, &link_path) && link_path == devpath) {
                unlink(link.c_str());
            }
        }
        unlink(devpath.c_str());
    }
}

6.4 MakeDevice-创建设备节点

void DeviceHandler::MakeDevice(const std::string& path, bool block, int major, int minor,
                               const std::vector<std::string>& links) const {
    auto[mode, uid, gid] = GetDevicePermissions(path, links);
    // 字符设备或者块设备
    mode |= (block ? S_IFBLK : S_IFCHR);

    std::string secontext;
    // selinux相关
    if (!SelabelLookupFileContextBestMatch(path, links, mode, &secontext)) {
        PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
        return;
    }
    if (!secontext.empty()) {
        setfscreatecon(secontext.c_str());
    }
// 创建设备ID,用来创建设备节点
    dev_t dev = makedev(major, minor);
    /* Temporarily change egid to avoid race condition setting the gid of the
     * device node. Unforunately changing the euid would prevent creation of
     * some device nodes, so the uid has to be set with chown() and is still
     * racy. Fixing the gid race at least fixed the issue with system_server
     * opening dynamic input devices under the AID_INPUT gid. */
    // 将用户转为gid
    if (setegid(gid)) {
        PLOG(ERROR) << "setegid(" << gid << ") for " << path << " device failed";
        goto out;
    }
    /* If the node already exists update its SELinux label to handle cases when
     * it was created with the wrong context during coldboot procedure. */
    // 创建设备节点
    if (mknod(path.c_str(), mode, dev) && (errno == EEXIST) && !secontext.empty()) {
        char* fcon = nullptr;
        int rc = lgetfilecon(path.c_str(), &fcon);
        if (rc < 0) {
            PLOG(ERROR) << "Cannot get SELinux label on '" << path << "' device";
            goto out;
        }

        bool different = fcon != secontext;
        freecon(fcon);

        if (different && lsetfilecon(path.c_str(), secontext.c_str())) {
            PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path
                        << "' device";
        }
    }

out:
    chown(path.c_str(), uid, -1);
    // 又换回root用户
    if (setegid(AID_ROOT)) {
        PLOG(FATAL) << "setegid(AID_ROOT) failed";
    }

    if (!secontext.empty()) {
        setfscreatecon(nullptr);
    }
}
std::vector<std::string> DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uevent) const {
    std::string device;
    std::string type;
    std::string partition;
    std::string uuid;
// /devices/platform/soc@2900000/4022000.sdmmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p16
    if (FindPlatformDevice(uevent.path, &device)) {
        // Skip /devices/platform or /devices/ if present
        static const std::string devices_platform_prefix = "/devices/platform/";
        static const std::string devices_prefix = "/devices/";
// /devices/platform/soc@2900000/4022000.sdmmc
        if (StartsWith(device, devices_platform_prefix)) {
            // soc@2900000/4022000.sdmmc
            device = device.substr(devices_platform_prefix.length());
        } else if (StartsWith(device, devices_prefix)) {
            device = device.substr(devices_prefix.length());
        }

        type = "platform";
    } else if (FindPciDevicePrefix(uevent.path, &device)) {
        type = "pci";
    } else if (FindVbdDevicePrefix(uevent.path, &device)) {
        type = "vbd";
        // dm设备走这里,/devices/virtual/block/dm-0
        // /sys/devices/virtual/block/dm-0/dm/name获得partition,system_a和uuid
    } else if (FindDmDevice(uevent.path, &partition, &uuid)) {
        // 创建两个链接:/dev/block/mapper/system_a -> /dev/block/dm-0
        std::vector<std::string> symlinks = {"/dev/block/mapper/" + partition};
        if (!uuid.empty()) {
            symlinks.emplace_back("/dev/block/mapper/by-uuid/" + uuid);
        }
        return symlinks;
    } else {
        return {};
    }

    std::vector<std::string> links;

    LOG(VERBOSE) << "found " << type << " device " << device;
// /dev/block/platform/soc@2900000/4022000.sdmmc
    auto link_path = "/dev/block/" + type + "/" + device;
// is_boot_device为true
    bool is_boot_device = boot_devices_.find(device) != boot_devices_.end();
    // partition_name 为dtbo
    // dm设备为空的
    if (!uevent.partition_name.empty()) {
        std::string partition_name_sanitized(uevent.partition_name);
        // 将不可接受的,替换为_
        SanitizePartitionName(&partition_name_sanitized);
        if (partition_name_sanitized != uevent.partition_name) {
            LOG(VERBOSE) << "Linking partition '" << uevent.partition_name << "' as '"
                         << partition_name_sanitized << "'";
        }
        // /dev/block/platform/soc@2900000/4022000.sdmmc/by-name/dtbo
        links.emplace_back(link_path + "/by-name/" + partition_name_sanitized);
        // Adds symlink: /dev/block/by-name/<partition_name>.
        if (is_boot_device) {
            // /dev/block/by-name/dtbo
            links.emplace_back("/dev/block/by-name/" + partition_name_sanitized);
        }
        if ((partition_name_sanitized == "userdata") || (partition_name_sanitized == "UDISK")) {
            links.emplace_back(link_path + "/by-name/userdata");
            // Adds symlink: /dev/block/by-name/<partition_name>.
            if (is_boot_device) {
                links.emplace_back("/dev/block/by-name/userdata");
            }
        }
    } else if (is_boot_device) {
        // If we don't have a partition name but we are a partition on a boot device, create a
        // symlink of /dev/block/by-name/<device_name> for symmetry.
        links.emplace_back("/dev/block/by-name/" + uevent.device_name);
    }
// /dev/block/platform/soc@2900000/4022000.sdmmc/mmcblk0p16 -> /dev/block/mmcblk0p16
    auto last_slash = uevent.path.rfind('/');
    links.emplace_back(link_path + "/" + uevent.path.substr(last_slash + 1));

    return links;
}

6.6 FindPlatformDevice-获取platform_device_path

bool DeviceHandler::FindPlatformDevice(std::string path, std::string* platform_device_path) const {
    platform_device_path->clear();
// /devices/platform/soc@2900000/4022000.sdmmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p16
    // Uevents don't contain the mount point, so we need to add it here.
    // 加上/sys
    path.insert(0, sysfs_mount_point_);

    std::string directory = Dirname(path);

    while (directory != "/" && directory != ".") {
        std::string subsystem_link_path;
        if (Realpath(directory + "/subsystem", &subsystem_link_path) &&
            subsystem_link_path == sysfs_mount_point_ + "/bus/platform") {
            // We need to remove the mount point that we added above before returning.
            directory.erase(0, sysfs_mount_point_.size());
            // /devices/platform/soc@2900000/4022000.sdmmc
            *platform_device_path = directory;
            return true;
        }

        auto last_slash = path.rfind('/');
        if (last_slash == std::string::npos) return false;
// 一层层的去掉,直到找到subsystem为/bus/platform的
        path.erase(last_slash);
        directory = Dirname(path);
    }

    return false;
}

6.7 FindDmDevice-获得分区名和uuid

static bool FindDmDevice(const std::string& path, std::string* name, std::string* uuid) {
    // /devices/virtual/block/dm-0
    if (!StartsWith(path, "/devices/virtual/block/dm-")) return false;
// system_a
    if (!ReadFileToString("/sys" + path + "/dm/name", name)) {
        return false;
    }
    // uuid
    ReadFileToString("/sys" + path + "/dm/uuid", uuid);

    *name = android::base::Trim(*name);
    *uuid = android::base::Trim(*uuid);
    return true;
}

7. UeventListener类

7.1 RegenerateUeventsForPath-往path目录下的所有子目录的uevent节点发送add事件

ListenerAction UeventListener::RegenerateUeventsForPath(const std::string& path,
                                                        const ListenerCallback& callback) const {
    std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path.c_str()), closedir);
    if (!d) return ListenerAction::kContinue;

    return RegenerateUeventsForDir(d.get(), callback);
}
ListenerAction UeventListener::RegenerateUeventsForDir(DIR* d,
                                                       const ListenerCallback& callback) const {
    int dfd = dirfd(d);

    // 打开uevent
    int fd = openat(dfd, "uevent", O_WRONLY | O_CLOEXEC);
    if (fd >= 0) {
        // 写add
        write(fd, "add\n", 4);
        close(fd);

        Uevent uevent;
        // 分析uevent事件
        while (ReadUevent(&uevent)) {
            // 并调用callback函数
            if (callback(uevent) == ListenerAction::kStop) return ListenerAction::kStop;
        }
    }

    dirent* de;
    // 循环读/sys目录下的文件
    while ((de = readdir(d)) != nullptr) {
        if (de->d_type != DT_DIR || de->d_name[0] == '.') continue;

        fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
        if (fd < 0) continue;

        std::unique_ptr<DIR, decltype(&closedir)> d2(fdopendir(fd), closedir);
        if (d2 == 0) {
            close(fd);
        } else {
            if (RegenerateUeventsForDir(d2.get(), callback) == ListenerAction::kStop) {
                return ListenerAction::kStop;
            }
        }
    }

    // default is always to continue looking for uevents
    return ListenerAction::kContinue;
}

7.2 ReadUevent-从uevent socket中读uevent事件

bool UeventListener::ReadUevent(Uevent* uevent) const {
    char msg[UEVENT_MSG_LEN + 2];
    // 读uevent的信息
    int n = uevent_kernel_multicast_recv(device_fd_, msg, UEVENT_MSG_LEN);
    if (n <= 0) {
        if (errno != EAGAIN && errno != EWOULDBLOCK) {
            PLOG(ERROR) << "Error reading from Uevent Fd";
        }
        return false;
    }
    if (n >= UEVENT_MSG_LEN) {
        LOG(ERROR) << "Uevent overflowed buffer, discarding";
        // Return true here even if we discard as we may have more uevents pending and we
        // want to keep processing them.
        return true;
    }

    msg[n] = '\0';
    msg[n + 1] = '\0';

    // 解析uevent的信息
    ParseEvent(msg, uevent);

    return true;
}
static void ParseEvent(const char* msg, Uevent* uevent) {
    uevent->partition_num = -1;
    uevent->major = -1;
    uevent->minor = -1;
    uevent->action.clear();
    uevent->path.clear();
    uevent->subsystem.clear();
    uevent->firmware.clear();
    uevent->partition_name.clear();
    uevent->device_name.clear();
    uevent->modalias.clear();
    // currently ignoring SEQNUM
    while (*msg) {
        if (!strncmp(msg, "ACTION=", 7)) {
            msg += 7;
            uevent->action = msg;
        } else if (!strncmp(msg, "DEVPATH=", 8)) {
            msg += 8;
            // 比对这个path
            uevent->path = msg;
        } else if (!strncmp(msg, "SUBSYSTEM=", 10)) {
            msg += 10;
            uevent->subsystem = msg;
        } else if (!strncmp(msg, "FIRMWARE=", 9)) {
            msg += 9;
            uevent->firmware = msg;
        } else if (!strncmp(msg, "MAJOR=", 6)) {
            msg += 6;
            uevent->major = atoi(msg);
        } else if (!strncmp(msg, "MINOR=", 6)) {
            msg += 6;
            uevent->minor = atoi(msg);
        } else if (!strncmp(msg, "PARTN=", 6)) {
            msg += 6;
            uevent->partition_num = atoi(msg);
        } else if (!strncmp(msg, "PARTNAME=", 9)) {
            msg += 9;
            uevent->partition_name = msg;
        } else if (!strncmp(msg, "DEVNAME=", 8)) {
            msg += 8;
            uevent->device_name = msg;
        } else if (!strncmp(msg, "MODALIAS=", 9)) {
            msg += 9;
            uevent->modalias = msg;
        }

        // advance to after the next \0
        while (*msg++)
            ;
    }

    if (LOG_UEVENTS) {
        // 可以打开这个打印,通过串口看发了哪个uevent了
        LOG(INFO) << "event { '" << uevent->action << "', '" << uevent->path << "', '"
                  << uevent->subsystem << "', '" << uevent->firmware << "', " << uevent->major
                  << ", " << uevent->minor << " }";
    }
}

7.3 UeventListener构造函数

UeventListener::UeventListener(size_t uevent_socket_rcvbuf_size) {
    // 打开uevent的socket
    device_fd_.reset(uevent_open_socket(uevent_socket_rcvbuf_size, true));
    if (device_fd_ == -1) {
        LOG(FATAL) << "Could not open uevent socket";
    }
// 设置为非阻塞的形式
    fcntl(device_fd_, F_SETFL, O_NONBLOCK);
}

7.4 RegenerateUevents-往/sys/devices发uevent事件-add事件

static const char* kRegenerationPaths[] = {"/sys/devices"};

void UeventListener::RegenerateUevents(const ListenerCallback& callback) const {
    for (const auto path : kRegenerationPaths) {
        if (RegenerateUeventsForPath(path, callback) == ListenerAction::kStop) return;
    }
}

8. switch root模块

8.1 SwitchRoot-切换根目录

std::vector<std::string> GetMounts(const std::string& new_root) {
    auto fp = std::unique_ptr<std::FILE, decltype(&endmntent)>{setmntent("/proc/mounts", "re"),
                                                               endmntent};
    if (fp == nullptr) {
        PLOG(FATAL) << "Failed to open /proc/mounts";
    }

    std::vector<std::string> result;
    mntent* mentry;
    while ((mentry = getmntent(fp.get())) != nullptr) {
        // We won't try to move rootfs.
        // 去掉root
        if (mentry->mnt_dir == "/"s) {
            continue;
        }

        // The new root mount is handled separately.
        // /system的去掉
        if (mentry->mnt_dir == new_root) {
            continue;
        }

        // Move operates on subtrees, so do not try to move children of other mounts.
        // /sys/fs/cgroup/devices和/sys/fs/cgroup/memory都算/sys
        if (std::find_if(result.begin(), result.end(), [&mentry](const auto& older_mount) {
                return StartsWith(mentry->mnt_dir, older_mount);
            }) != result.end()) {
            continue;
        }

        result.emplace_back(mentry->mnt_dir);
    }

    return result;
}

void SwitchRoot(const std::string& new_root) {
    auto mounts = GetMounts(new_root);

    LOG(INFO) << "Switching root to '" << new_root << "'";

    for (const auto& mount_path : mounts) {
        auto new_mount_path = new_root + mount_path;
        mkdir(new_mount_path.c_str(), 0755);
        // 使用MS_MOVE标志,将/sys移到/system/sys目录下
        if (mount(mount_path.c_str(), new_mount_path.c_str(), nullptr, MS_MOVE, nullptr) != 0) {
            PLOG(FATAL) << "Unable to move mount at '" << mount_path << "'";
        }
    }
// 将工作目录改变到/system目录下
    if (chdir(new_root.c_str()) != 0) {
        PLOG(FATAL) << "Could not chdir to new_root, '" << new_root << "'";
    }
// 然后将/system目录移到/目录下
    if (mount(new_root.c_str(), "/", nullptr, MS_MOVE, nullptr) != 0) {
        PLOG(FATAL) << "Unable to move root mount to new_root, '" << new_root << "'";
    }
// 然后改变root文件夹
    if (chroot(".") != 0) {
        PLOG(FATAL) << "Unable to chroot to new root";
    }
}

9. FirstStageConsole模块

9.1 FirstStageConsole构造函数

int FirstStageConsole(const std::string& cmdline) {
    auto pos = cmdline.find("androidboot.first_stage_console=");
    if (pos != std::string::npos) {
        int val = 0;
        // 加载内核模块,fail的时候才打开串口
        if (sscanf(cmdline.c_str() + pos, "androidboot.first_stage_console=%d", &val) != 1) {
            return FirstStageConsoleParam::DISABLED;
        }
        if (val <= FirstStageConsoleParam::MAX_PARAM_VALUE && val >= 0) {
            return val;
        }
    }
    return FirstStageConsoleParam::DISABLED;
}
enum FirstStageConsoleParam {
    DISABLED = 0,
    CONSOLE_ON_FAILURE = 1,
    IGNORE_FAILURE = 2,
    MAX_PARAM_VALUE = IGNORE_FAILURE,
};

9.2 StartConsole-创建/dev/console设备,然后打开/dev/console设备,执行/first_stage.sh文件,或者sh

void StartConsole() {
    // 创建设备
    if (mknod("/dev/console", S_IFCHR | 0600, makedev(5, 1))) {
        PLOG(ERROR) << "unable to create /dev/console";
        return;
    }
    pid_t pid = fork();
    if (pid != 0) {
        int status;
        waitpid(pid, &status, 0);
        LOG(ERROR) << "console shell exited with status " << status;
        return;
    }
    int fd = -1;
    int tries = 50; // should timeout after 5s
    // The device driver for console may not be ready yet so retry for a while in case of failure.
    while (tries--) {
        // 打开设备
        fd = open("/dev/console", O_RDWR);
        if (fd != -1) {
            break;
        }
        std::this_thread::sleep_for(100ms);
    }
    if (fd == -1) {
        LOG(ERROR) << "Could not open /dev/console, errno = " << errno;
        _exit(127);
    }
    ioctl(fd, TIOCSCTTY, 0);
    dup2(fd, STDIN_FILENO);
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);
    close(fd);
// 执行/first_stage.sh文件
    RunScript();
    // 执行sh
    const char* path = "/system/bin/sh";
    const char* args[] = {path, nullptr};
    int rv = execv(path, const_cast<char**>(args));
    LOG(ERROR) << "unable to execv, returned " << rv << " errno " << errno;
    _exit(127);
}
static void RunScript() {
    LOG(INFO) << "Attempting to run /first_stage.sh...";
    pid_t pid = fork();
    if (pid != 0) {
        int status;
        waitpid(pid, &status, 0);
        LOG(INFO) << "/first_stage.sh exited with status " << status;
        return;
    }
    const char* path = "/system/bin/sh";
    const char* args[] = {path, "/first_stage.sh", nullptr};
    int rv = execv(path, const_cast<char**>(args));
    LOG(ERROR) << "unable to execv /first_stage.sh, returned " << rv << " errno " << errno;
}

补充

1. c++

1.1 成员变量的构造函数调用

先调用成员变量的构造函数,然后调用本类的构造函数

问题

1. Android P system-as-root-内核挂载分区失败

system-as-root方式需要在内核init阶段挂载system分区,由于mmc还没有初始化完成,导致没有分区。需要在env.cfg文件的mmc那里加上rootwait

而Android Q之后,使用的是ramdisk的方式,所以不需要rootwait标志。

[    2.241183] VFS: Cannot open root device "mmcblk0p4" or unknown-block(0,0): error -6
[    2.249997] Please append a correct "root=" boot option; here are the available partitions:

2. 卡启动需要配置dts-不然会显示找不到super分区-boot_devices要配置上sdcard的

	firmware {
		android {
			compatible = "android,firmware";
			name = "android";
			boot_devices = "soc@2900000/4020000.sdmmc,soc@2900000/4022000.sdmmc,soc@2900000";
		};
		optee {
			compatible = "linaro,optee-tz";
			method = "smc";
		};
	};

3. uevent事件不对

"device-mapper device not found in /sys, waiting for its uevent"
一般是产生的uevent事件和dts里面配置的分区,或者device-mapper的uevent没有上来导致的
或者是根本就没有产生uevent事件,这时候只需要把uevent相关的debug log打开即可
    if (LOG_UEVENTS) {
        // 可以打开这个打印,通过串口看发了哪个uevent了
        LOG(INFO) << "event { '" << uevent->action << "', '" << uevent->path << "', '"
                  << uevent->subsystem << "', '" << uevent->firmware << "', " << uevent->major
                  << ", " << uevent->minor << " }";
    }

forcenormalboot

参考

posted @ 2021-06-10 19:21  pyjetson  阅读(3659)  评论(0编辑  收藏  举报