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

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM