目录

  • 概述
  • 源码解析
  • 1. 解析fstab文件
  • 1.1 ReadFstabFromDt-从dts中读取fstab
  • 1.2 SkipMountingPartitions-gsi下不挂载/oem /product /system_ext目录
  • 1.3 is_dt_compatible-读取/proc/device-tree/firmware/android/compatible文件是否为android,firmware
  • 1.4 IsDtFstabCompatible-读取/proc/device-tree/firmware/android/fstab/compatible下的文件
  • 1.5 get_android_dt_dir-获取android的dts在哪个文件夹上,默认为/proc/device-tree/firmware/android
  • 1.6 ReadFstabFile-解析fstab文件
  • 1.7 FstabEntry结构体-支持的挂载选项
  • 1.8 ParseMountFlags-解析挂载选项
  • 1.9 ParseFsMgrFlags-解析fs_mgr的挂载选项
  • 1.10 fs_mgr_update_for_slotselect-slotselect标志处理-加上_a,为vendor_a
  • 1.11 CalculateZramSize-计算zram大小
  • 1.12 ReadDefaultFstab-读fstab文件
  • 1.13 TransformFstabForDsu-dsu相关的
  • 1.14 GetBootDevices-获取boot_devices,一般从dts那里配置的
  • 2. 解析boot_config
  • 2.1 fs_mgr_get_boot_config_from_kernel_cmdline-解析cmdline的
  • 2.2 fs_mgr_get_boot_config-读取dts和ro.boot.和androidboot.的值
  • 3. fs_mgr主模块
  • 3.1 fs_mgr_get_super_partition_name-获取super分区的名字
  • 3.2 fs_mgr_do_mount_one-挂载文件系统
  • 3.3 prepare_fs_for_mount-读文件系统的超级头看是否有效-打开某些可调的flags-ext4格式才可调
  • 3.4 read_ext4_superblock-读ext4的超级块
  • 3.5 check_fs-用e2fsck工具检查ext4-用fsck.f2fs检查f2fs文件系统
  • 3.6 tune_quota-执行tune2fs -Qusrquota,grpquota,prjquota /dev/block/mmc 命令开启quota功能
  • 3.7 fs_mgr_update_logical_partition-通过system_a获取/dev/block/dm-0
  • 3.8 fs_mgr_mount_all-挂载分区
  • 3.9 fs_mgr_set_blk_ro-设置只读标志,overlayfs会清除只读标志
  • 3.10 WrapUserdataIfNeeded-看是否需要为data分区创建dm设备
  • 3.11 mount_with_alternatives-挂载分区
  • 3.12 call_vdc-执行vdc命令
  • 4. dm_linear模块-逻辑分区相关
  • 4.1 ReadCurrentMetadata-读super分区中的metadata信息
  • 4.2 CreateLogicalPartitions
  • 4.3 CreateLogicalPartition
  • 4.4 InitDefaults-创建并初始化owner_data-就是初始化CreateLogicalPartitionParams
  • 4.5 CreateDmTableInternal-创建dm-linear设备table
  • 4.6 GetPhysicalPartitionDevicePath-返回分区的真实块设备路径
  • 5. CheckpointManager模块
  • 5.1 CheckpointManager构造函数
  • 5.2 Update-OTA阶段更新挂载选项",checkpoint=disable"
  • 5.3 NeedsCheckpoint-调用vdc checkpoint-OTA阶段需要checkpoint,返回true;正常情况不需要,为false
  • 5.4 UpdateCheckpointPartition-加上挂载选项",checkpoint=disable"
  • 5.5 Revert-对于checkpoint=fs选项,什么都没做
  • 6. 分区格式化操作
  • 6.1 fs_mgr_do_format
  • 补充
  • 1. c++特性
  • 1.1 std::string
  • 1.1.1 find_first_of函数
  • 1.2 std::remove_copy
  • 2. 系统调用
  • 2.1 fmemopen
  • 3. 库函数
  • 3.1 strtok_r
  • 问题
  • 参考

概述

android/system/core/fs_mgr,system文件系统管理的主模块

源码解析

1. 解析fstab文件

1.1 ReadFstabFromDt-从dts中读取fstab

// Returns fstab entries parsed from the device tree if they exist
bool ReadFstabFromDt(Fstab* fstab, bool log=true) {
    std::string fstab_buf = ReadFstabFromDt();
    if (fstab_buf.empty()) {
        if (log) LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
        return false;
    }

    // 字符串转换为文件
    std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
        fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
                 fstab_buf.length(), "r"), fclose);
    if (!fstab_file) {
        if (log) PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
        return false;
    }

    // is_proc_mount为false
    if (!ReadFstabFile(fstab_file.get(), false, fstab)) {
        if (log) {
            LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl
                   << fstab_buf;
        }
        return false;
    }

#ifndef NO_SKIP_MOUNT
    SkipMountingPartitions(fstab);
#endif

    return true;
}

// dts下没有配置fstab的话,直接返回空
std::string ReadFstabFromDt() {
    // 看/proc/device-tree/firmware/android/下dts文件是否配置有fstab
    if (!is_dt_compatible() || !IsDtFstabCompatible()) {
        return {};
    }

    std::string fstabdir_name = get_android_dt_dir() + "/fstab";
    std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
    if (!fstabdir) return {};

    dirent* dp;
    // Each element in fstab_dt_entries is <mount point, the line format in fstab file>.
    std::vector<std::pair<std::string, std::string>> fstab_dt_entries;
    while ((dp = readdir(fstabdir.get())) != NULL) {
        // skip over name, compatible and .
        if (dp->d_type != DT_DIR || dp->d_name[0] == '.') continue;

        // create <dev> <mnt_point>  <type>  <mnt_flags>  <fsmgr_flags>\n
        std::vector<std::string> fstab_entry;
        std::string file_name;
        std::string value;
        // skip a partition entry if the status property is present and not set to ok
        file_name = android::base::StringPrintf("%s/%s/status", fstabdir_name.c_str(), dp->d_name);
        if (ReadDtFile(file_name, &value)) {
            if (value != "okay" && value != "ok") {
                LINFO << "dt_fstab: Skip disabled entry for partition " << dp->d_name;
                continue;
            }
        }

        file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
        if (!ReadDtFile(file_name, &value)) {
            LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
            return {};
        }
        fstab_entry.push_back(value);

        std::string mount_point;
        file_name =
            android::base::StringPrintf("%s/%s/mnt_point", fstabdir_name.c_str(), dp->d_name);
        if (ReadDtFile(file_name, &value)) {
            LINFO << "dt_fstab: Using a specified mount point " << value << " for " << dp->d_name;
            mount_point = value;
        } else {
            mount_point = android::base::StringPrintf("/%s", dp->d_name);
        }
        fstab_entry.push_back(mount_point);

        file_name = android::base::StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
        if (!ReadDtFile(file_name, &value)) {
            LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
            return {};
        }
        fstab_entry.push_back(value);

        file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
        if (!ReadDtFile(file_name, &value)) {
            LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
            return {};
        }
        fstab_entry.push_back(value);

        file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
        if (!ReadDtFile(file_name, &value)) {
            LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
            return {};
        }
        fstab_entry.push_back(value);
        // Adds a fstab_entry to fstab_dt_entries, to be sorted by mount_point later.
        fstab_dt_entries.emplace_back(mount_point, android::base::Join(fstab_entry, " "));
    }

    // Sort fstab_dt entries, to ensure /vendor is mounted before /vendor/abc is attempted.
    std::sort(fstab_dt_entries.begin(), fstab_dt_entries.end(),
              [](const auto& a, const auto& b) { return a.first < b.first; });

    std::string fstab_result;
    for (const auto& [_, dt_entry] : fstab_dt_entries) {
        // 这里加了换行符
        fstab_result += dt_entry + "\n";
    }
    return fstab_result;
}

1.2 SkipMountingPartitions-gsi下不挂载/oem /product /system_ext目录

#ifndef NO_SKIP_MOUNT
// For GSI to skip mounting /product and /system_ext, until there are well-defined interfaces
// between them and /system. Otherwise, the GSI flashed on /system might not be able to work with
// device-specific /product and /system_ext. skip_mount.cfg belongs to system_ext partition because
// only common files for all targets can be put into system partition. It is under
// /system/system_ext because GSI is a single system.img that includes the contents of system_ext
// partition and product partition under /system/system_ext and /system/product, respectively.
bool SkipMountingPartitions(Fstab* fstab) {
    // gsi有skip_mount.cfg文件,不挂载/oem /product /system_ext
    constexpr const char kSkipMountConfig[] = "/system/system_ext/etc/init/config/skip_mount.cfg";

    std::string skip_config;
    auto save_errno = errno;
    if (!ReadFileToString(kSkipMountConfig, &skip_config)) {
        errno = save_errno;  // missing file is expected
        return true;
    }

    for (const auto& skip_mount_point : Split(skip_config, "\n")) {
        if (skip_mount_point.empty()) {
            continue;
        }
        auto it = std::remove_if(fstab->begin(), fstab->end(),
                                 [&skip_mount_point](const auto& entry) {
                                     return entry.mount_point == skip_mount_point;
                                 });
        if (it == fstab->end()) continue;
        fstab->erase(it, fstab->end());
        LOG(INFO) << "Skip mounting partition: " << skip_mount_point;
    }

    return true;
}
#endif

1.3 is_dt_compatible-读取/proc/device-tree/firmware/android/compatible文件是否为android,firmware

bool is_dt_compatible() {
    std::string file_name = get_android_dt_dir() + "/compatible";
    std::string dt_value;
    if (android::fs_mgr::ReadDtFile(file_name, &dt_value)) {
        if (dt_value == "android,firmware") {
            return true;
        }
    }

    return false;
}

1.4 IsDtFstabCompatible-读取/proc/device-tree/firmware/android/fstab/compatible下的文件

bool IsDtFstabCompatible() {
    std::string dt_value;
    std::string file_name = get_android_dt_dir() + "/fstab/compatible";

    if (ReadDtFile(file_name, &dt_value) && dt_value == "android,fstab") {
        // If there's no status property or its set to "ok" or "okay", then we use the DT fstab.
        std::string status_value;
        std::string status_file_name = get_android_dt_dir() + "/fstab/status";
        return !ReadDtFile(status_file_name, &status_value) || status_value == "ok" ||
               status_value == "okay";
    }

    return false;
}

dts文件配置:<dev> <mnt_point>  <type>  <mnt_flags>  <fsmgr_flags>
    // 如果没有设置mnt_point,则用dir_name则为vendor
	firmware {
		android {
			fstab {
                // 对比这个
				compatible = "android,fstab";
				name = "fstab";
				vendor {
					compatible = "android,vendor";
					dev = "/dev/block/by-name/vendor";
					fsmgr_flags = "wait,recoveryonly";
					mnt_flags = "ro,barrier=1";
					name = "vendor";
                    // 对比这个
					status = "ok";
					type = "ext4";
				};
			};
		};
	};

1.5 get_android_dt_dir-获取android的dts在哪个文件夹上,默认为/proc/device-tree/firmware/android

默认是/proc/device-tree/firmware/android,或者从cmdline获取androidboot.android_dt_dir的值

const std::string& get_android_dt_dir() {
    // Set once and saves time for subsequent calls to this function
    static const std::string kAndroidDtDir = android::fs_mgr::InitAndroidDtDir();
    return kAndroidDtDir;
}
std::string InitAndroidDtDir() {
    std::string android_dt_dir;
    // The platform may specify a custom Android DT path in kernel cmdline
    // 从cmdline获取androidboot.android_dt_dir的值
    if (!fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) {
        // Fall back to the standard procfs-based path
        // 如果获取不到的话,则用默认值:/proc/device-tree/firmware/android
        android_dt_dir = kDefaultAndroidDtDir;
    }
    return android_dt_dir;
}

1.6 ReadFstabFile-解析fstab文件

vendor /vendor ext4 ro,barrier=1 wait,first_stage_mount,logical,slotselect

blk_device (logical_partition_name) mount_point fs_type ParseMountFlags ParseFsMgrFlags

bool ReadFstabFile(FILE* fstab_file, bool proc_mounts, Fstab* fstab_out) {
    ssize_t len;
    size_t alloc_len = 0;
    char *line = NULL;
    const char *delim = " \t";
    char *save_ptr, *p;
    Fstab fstab;

    while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
        /* if the last character is a newline, shorten the string by 1 byte */
        if (line[len - 1] == '\n') {
            line[len - 1] = '\0';
        }

        /* Skip any leading whitespace */
        p = line;
        while (isspace(*p)) {
            p++;
        }
        /* ignore comments or empty lines */
        if (*p == '#' || *p == '\0')
            continue;

        FstabEntry entry;

        // 以空格或者tab键对字符串进行分割" \t"
        if (!(p = strtok_r(line, delim, &save_ptr))) {
            LERROR << "Error parsing mount source";
            goto err;
        }
        entry.blk_device = p;

        if (!(p = strtok_r(NULL, delim, &save_ptr))) {
            LERROR << "Error parsing mount_point";
            goto err;
        }
        entry.mount_point = p;

        if (!(p = strtok_r(NULL, delim, &save_ptr))) {
            LERROR << "Error parsing fs_type";
            goto err;
        }
        entry.fs_type = p;

        if (!(p = strtok_r(NULL, delim, &save_ptr))) {
            LERROR << "Error parsing mount_flags";
            goto err;
        }

        ParseMountFlags(p, &entry);

        // For /proc/mounts, ignore everything after mnt_freq and mnt_passno
        // 这个是啥?,读default的fstab文件,proc_mounts为true的
        if (proc_mounts) {
            p += strlen(p);
        } else if (!(p = strtok_r(NULL, delim, &save_ptr))) {
            LERROR << "Error parsing fs_mgr_options";
            goto err;
        }

        ParseFsMgrFlags(p, &entry);

        if (entry.fs_mgr_flags.logical) {
            entry.logical_partition_name = entry.blk_device;
        }

        fstab.emplace_back(std::move(entry));
    }

    if (fstab.empty()) {
        LERROR << "No entries found in fstab";
        goto err;
    }

    /* If an A/B partition, modify block device to be the real block device */
    // 读fstab的时候,就更新了,slotselect标志
    if (!fs_mgr_update_for_slotselect(&fstab)) {
        LERROR << "Error updating for slotselect";
        goto err;
    }
    free(line);
    *fstab_out = std::move(fstab);
    return true;

err:
    free(line);
    return false;
}

1.7 FstabEntry结构体-支持的挂载选项

FlagList kMountFlagsList[] = {
    // 一些通用的挂载flags
        {"noatime", MS_NOATIME},
        {"noexec", MS_NOEXEC},
        {"nosuid", MS_NOSUID},
        {"nodev", MS_NODEV},
        {"nodiratime", MS_NODIRATIME},
        {"ro", MS_RDONLY},
        {"rw", 0},
        {"sync", MS_SYNCHRONOUS},
        {"remount", MS_REMOUNT},
        {"bind", MS_BIND},
        {"rec", MS_REC},
        {"unbindable", MS_UNBINDABLE},
        {"private", MS_PRIVATE},
        {"slave", MS_SLAVE},
        {"shared", MS_SHARED},
        {"defaults", 0},
};

struct FstabEntry {
    std::string blk_device;	// /dev/block/by-name/userdata
    std::string logical_partition_name;	// 就是blk_device的值
    std::string mount_point;	// 挂载点/data
    std::string fs_type;	// 文件系统类型,f2fs,ext4等类型
    unsigned long flags = 0;	// 一些通用的挂载flags
    std::string fs_options;	// 一些不通用的flags,就放在fs_options中
    std::string fs_checkpoint_opts;
    std::string key_loc;	// encryptable=footer,forceencrypt=
    std::string metadata_key_dir;	// keydirectory=/metadata/vold/metadata_encryption
    std::string metadata_encryption;
    off64_t length = 0;	// length=
    std::string label;	// voldmanaged=extsd:auto,label为extsd
    int partnum = -1;	// voldmanaged=extsd:auto,auto时partnum为-1,第二个为partnum
    int swap_prio = -1;	// swapprio=
    int max_comp_streams = 0;
    off64_t zram_size = 0;	// zramsize=75%,百分比是物理内存的75%;还可以填个数字,单位是字节
    off64_t reserved_size = 0;	// reserve_root=的值,reservedsize=128M的值,ext4才会走进来,主要保留空间供特权进程使用是为了避免文件系统碎片
    std::string encryption_options;	// fileencryption=aes-256-xts:aes-256-cts
    off64_t erase_blk_size = 0;
    off64_t logical_blk_size = 0;
    std::string sysfs_path;
    std::string vbmeta_partition;	// avb=vbmeta,avb标志,vbmeta为指定的vbmeta分区
    uint64_t zram_backingdev_size = 0;	// zram_backingdev_size=256M
    std::string avb_keys;	// avb_keys=/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey

    struct FsMgrFlags {
        bool wait : 1;	// 等待分区设备可用
        bool check : 1;	// check会调用check_fs函数
        bool crypt : 1;	// encryptable=
        bool nonremovable : 1;
        bool vold_managed : 1;	// voldmanaged=extsd:auto
        bool recovery_only : 1;
        bool verify : 1;
        bool force_crypt : 1;	// forceencrypt=
        bool no_emulated_sd : 1;  // No emulated sdcard daemon; sd card is the only external
                                  // storage.
        bool no_trim : 1;
        bool file_encryption : 1;	// fileencryption=aes-256-xts:aes-256-cts
        bool formattable : 1;
        bool slot_select : 1;	// slotselect的话,在update_slot的时候,在后面加个_a或者_b,根据androidboot.slot_suffix定
        bool force_fde_or_fbe : 1;	// forcefdeorfbe=
        bool late_mount : 1;
        bool no_fail : 1;
        bool verify_at_boot : 1;
        bool quota : 1;		// 配置了quota
        bool avb : 1;	// avb=vbmeta,avb标志,vbmeta为指定的vbmeta分区
        bool logical : 1;
        bool checkpoint_blk : 1;
        bool checkpoint_fs : 1;
        bool first_stage_mount : 1;	// 表示first_stage_init的阶段挂载的分区
        bool slot_select_other : 1;	// other的话,在update_slot的时候,则_a变_b
        bool fs_verity : 1;
        bool ext_meta_csum : 1;
    } fs_mgr_flags = {};

    bool is_encryptable() const {
        return fs_mgr_flags.crypt || fs_mgr_flags.force_crypt || fs_mgr_flags.force_fde_or_fbe;
    }
};

1.8 ParseMountFlags-解析挂载选项

void ParseMountFlags(const std::string& flags, FstabEntry* entry) {
    std::string fs_options;
    for (const auto& flag : Split(flags, ",")) {
        if (!SetMountFlag(flag, entry)) {
            // Unknown flag, so it must be a filesystem specific option.
            if (!fs_options.empty()) {
                fs_options.append(",");  // appends a comma if not the first
            }
            fs_options.append(flag);	// 一些不通用的flags,就放在fs_options中

            if (entry->fs_type == "f2fs" && StartsWith(flag, "reserve_root=")) {
                std::string arg;
                if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
                    arg = flag.substr(equal_sign + 1);
                }
                if (!ParseInt(arg, &entry->reserved_size)) {
                    LWARNING << "Warning: reserve_root= flag malformed: " << arg;
                } else {
                    entry->reserved_size <<= 12;
                }
            }
        }
    }
    entry->fs_options = std::move(fs_options);
}

bool SetMountFlag(const std::string& flag, FstabEntry* entry) {
    // 一些通用的挂载flags
    for (const auto& [name, value] : kMountFlagsList) {
        if (flag == name) {
            entry->flags |= value;
            return true;
        }
    }
    return false;
}

1.9 ParseFsMgrFlags-解析fs_mgr的挂载选项

void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
    for (const auto& flag : Split(flags, ",")) {
        // defaults就啥都不做
        if (flag.empty() || flag == "defaults") continue;
        std::string arg;
        if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
            arg = flag.substr(equal_sign + 1);
        }

        // First handle flags that simply set a boolean.
#define CheckFlag(flag_name, value)       \
    if (flag == flag_name) {              \
        entry->fs_mgr_flags.value = true; \
        continue;                         \
    }

        CheckFlag("wait", wait);
        CheckFlag("check", check);
        CheckFlag("nonremovable", nonremovable);
        CheckFlag("recoveryonly", recovery_only);
        CheckFlag("noemulatedsd", no_emulated_sd);
        CheckFlag("notrim", no_trim);
        CheckFlag("verify", verify);
        CheckFlag("formattable", formattable);
        CheckFlag("slotselect", slot_select);
        CheckFlag("latemount", late_mount);
        CheckFlag("nofail", no_fail);
        CheckFlag("verifyatboot", verify_at_boot);
        CheckFlag("quota", quota);
        CheckFlag("avb", avb);
        CheckFlag("logical", logical);
        CheckFlag("checkpoint=block", checkpoint_blk);
        CheckFlag("checkpoint=fs", checkpoint_fs);
        CheckFlag("first_stage_mount", first_stage_mount);
        CheckFlag("slotselect_other", slot_select_other);
        CheckFlag("fsverity", fs_verity);
        CheckFlag("metadata_csum", ext_meta_csum);

#undef CheckFlag

        // Then handle flags that take an argument.
        if (StartsWith(flag, "encryptable=")) {
            // The encryptable flag is followed by an = and the  location of the keys.
            entry->fs_mgr_flags.crypt = true;
            entry->key_loc = arg;
        } else if (StartsWith(flag, "voldmanaged=")) {
            // The voldmanaged flag is followed by an = and the label, a colon and the partition
            // number or the word "auto", e.g. voldmanaged=sdcard:3
            entry->fs_mgr_flags.vold_managed = true;
            auto parts = Split(arg, ":");
            if (parts.size() != 2) {
                LWARNING << "Warning: voldmanaged= flag malformed: " << arg;
                continue;
            }

            entry->label = std::move(parts[0]);
            if (parts[1] == "auto") {
                entry->partnum = -1;
            } else {
                if (!ParseInt(parts[1], &entry->partnum)) {
                    entry->partnum = -1;
                    LWARNING << "Warning: voldmanaged= flag malformed: " << arg;
                    continue;
                }
            }
        } else if (StartsWith(flag, "length=")) {
            // The length flag is followed by an = and the size of the partition.
            if (!ParseInt(arg, &entry->length)) {
                LWARNING << "Warning: length= flag malformed: " << arg;
            }
        } else if (StartsWith(flag, "swapprio=")) {
            if (!ParseInt(arg, &entry->swap_prio)) {
                LWARNING << "Warning: swapprio= flag malformed: " << arg;
            }
        } else if (StartsWith(flag, "zramsize=")) {
            if (!arg.empty() && arg.back() == '%') {
                arg.pop_back();
                int val;
                if (ParseInt(arg, &val, 0, 100)) {
                    entry->zram_size = CalculateZramSize(val);
                } else {
                    LWARNING << "Warning: zramsize= flag malformed: " << arg;
                }
            } else {
                if (!ParseInt(arg, &entry->zram_size)) {
                    LWARNING << "Warning: zramsize= flag malformed: " << arg;
                }
            }
        } else if (StartsWith(flag, "forceencrypt=")) {
            // The forceencrypt flag is followed by an = and the location of the keys.
            entry->fs_mgr_flags.force_crypt = true;
            entry->key_loc = arg;
        } else if (StartsWith(flag, "fileencryption=")) {
            ParseFileEncryption(arg, entry);
        } else if (StartsWith(flag, "forcefdeorfbe=")) {
            // The forcefdeorfbe flag is followed by an = and the location of the keys.  Get it and
            // return it.
            entry->fs_mgr_flags.force_fde_or_fbe = true;
            entry->key_loc = arg;
            entry->encryption_options = "aes-256-xts:aes-256-cts";
        } else if (StartsWith(flag, "max_comp_streams=")) {
            if (!ParseInt(arg, &entry->max_comp_streams)) {
                LWARNING << "Warning: max_comp_streams= flag malformed: " << arg;
            }
        } else if (StartsWith(flag, "reservedsize=")) {
            // The reserved flag is followed by an = and the reserved size of the partition.
            uint64_t size;
            if (!ParseByteCount(arg, &size)) {
                LWARNING << "Warning: reservedsize= flag malformed: " << arg;
            } else {
                entry->reserved_size = static_cast<off64_t>(size);
            }
        } else if (StartsWith(flag, "eraseblk=")) {
            // The erase block size flag is followed by an = and the flash erase block size. Get it,
            // check that it is a power of 2 and at least 4096, and return it.
            off64_t val;
            if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) {
                LWARNING << "Warning: eraseblk= flag malformed: " << arg;
            } else {
                entry->erase_blk_size = val;
            }
        } else if (StartsWith(flag, "logicalblk=")) {
            // The logical block size flag is followed by an = and the flash logical block size. Get
            // it, check that it is a power of 2 and at least 4096, and return it.
            off64_t val;
            if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) {
                LWARNING << "Warning: logicalblk= flag malformed: " << arg;
            } else {
                entry->logical_blk_size = val;
            }
        } else if (StartsWith(flag, "avb_keys=")) {  // must before the following "avb"
            entry->avb_keys = arg;
        } else if (StartsWith(flag, "avb")) {
            entry->fs_mgr_flags.avb = true;
            entry->vbmeta_partition = arg;
        } else if (StartsWith(flag, "keydirectory=")) {
            // The metadata flag is followed by an = and the directory for the keys.
            entry->metadata_key_dir = arg;
        } else if (StartsWith(flag, "metadata_encryption=")) {
            // Specify the cipher and flags to use for metadata encryption
            entry->metadata_encryption = arg;
        } else if (StartsWith(flag, "sysfs_path=")) {
            // The path to trigger device gc by idle-maint of vold.
            entry->sysfs_path = arg;
        } else if (StartsWith(flag, "zram_backingdev_size=")) {
            if (!ParseByteCount(arg, &entry->zram_backingdev_size)) {
                LWARNING << "Warning: zram_backingdev_size= flag malformed: " << arg;
            }
        } else {
            LWARNING << "Warning: unknown flag: " << flag;
        }
    }
}

1.10 fs_mgr_update_for_slotselect-slotselect标志处理-加上_a,为vendor_a

bool fs_mgr_update_for_slotselect(Fstab* fstab) {
    std::string ab_suffix;

    for (auto& entry : *fstab) {
        // slotselect标志
        if (!entry.fs_mgr_flags.slot_select && !entry.fs_mgr_flags.slot_select_other) {
            continue;
        }

        if (ab_suffix.empty()) {
            // androidboot.slot_suffix的值
            ab_suffix = fs_mgr_get_slot_suffix();
            // Return false if failed to get ab_suffix when MF_SLOTSELECT is specified.
            if (ab_suffix.empty()) return false;
        }

        const auto& update_suffix =
            // 没用slot_select标志,用的是slot_select_other?,则是other的
                entry.fs_mgr_flags.slot_select ? ab_suffix : other_suffix(ab_suffix);
        entry.blk_device = entry.blk_device + update_suffix;	// vendor_a
        entry.logical_partition_name = entry.logical_partition_name + update_suffix;	// vendor_a
    }
    return true;
}
std::string fs_mgr_get_slot_suffix() {
    std::string ab_suffix;

    fs_mgr_get_boot_config("slot_suffix", &ab_suffix);
    return ab_suffix;
}
// a变b,b变a
static std::string other_suffix(const std::string& slot_suffix) {
    if (slot_suffix == "_a") {
        return "_b";
    }
    if (slot_suffix == "_b") {
        return "_a";
    }
    return "";
}

1.11 CalculateZramSize-计算zram大小

off64_t CalculateZramSize(int percentage) {
    off64_t total;

    // 物理内存的内存页的数目
    total  = sysconf(_SC_PHYS_PAGES);
    total *= percentage;
    total /= 100;

    // 每个页的大小,字节为单位
    total *= sysconf(_SC_PAGESIZE);

    return total;
}

1.12 ReadDefaultFstab-读fstab文件

bool ReadDefaultFstab(Fstab* fstab) {
    Fstab dt_fstab;
    // 从dts中读取fstab
    ReadFstabFromDt(&dt_fstab, false);

    *fstab = std::move(dt_fstab);

    std::string default_fstab_path;
    // Use different fstab paths for normal boot and recovery boot, respectively
    // 如果是recovery的话,就读取/etc/recovery.fstab文件
    if (access("/system/bin/recovery", F_OK) == 0) {
        default_fstab_path = "/etc/recovery.fstab";
    } else {  // normal boot
        // 读取/vendor/etc/fstab.sun50iw10p1文件
        default_fstab_path = GetFstabPath();
    }

    Fstab default_fstab;
    if (!default_fstab_path.empty()) {
        // 读取/vendor/etc/fstab.sun50iw10p1文件的值
        ReadFstabFromFile(default_fstab_path, &default_fstab);
    } else {
        LINFO << __FUNCTION__ << "(): failed to find device default fstab";
    }

    for (auto&& entry : default_fstab) {
        fstab->emplace_back(std::move(entry));
    }

    return !fstab->empty();
}
// 返回/vendor/etc/fstab.sun50iw10p1
std::string GetFstabPath() {
    for (const char* prop : {"fstab_suffix", "hardware", "hardware.platform"}) {
        std::string suffix;
// 读取dts和ro.boot.和androidboot.的值,androidboot.hardware=sun50iw10p1
        if (!fs_mgr_get_boot_config(prop, &suffix)) continue;

        for (const char* prefix : {"/odm/etc/fstab.", "/vendor/etc/fstab.", "/fstab."}) {
            std::string fstab_path = prefix + suffix;
            if (access(fstab_path.c_str(), F_OK) == 0) {
                return fstab_path;
            }
        }
    }

    return "";
}
bool ReadFstabFromFile(const std::string& path, Fstab* fstab) {
    auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
    if (!fstab_file) {
        PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'";
        return false;
    }

    bool is_proc_mounts = path == "/proc/mounts";

    // 读取/vendor/etc/fstab.sun50iw10p1文件的值
    if (!ReadFstabFile(fstab_file.get(), is_proc_mounts, fstab)) {
        LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'";
        return false;
    }
    // /metadata/gsi/dsu/booted文件,和dsu相关
    if (!is_proc_mounts && !access(android::gsi::kGsiBootedIndicatorFile, F_OK)) {
        std::string lp_names;
        // 读取/metadata/gsi/dsu/lp_names文件的值
        ReadFileToString(gsi::kGsiLpNamesFile, &lp_names);
        // 获取gsi相关的fstab文件
        TransformFstabForDsu(fstab, Split(lp_names, ","));
    }

#ifndef NO_SKIP_MOUNT
    SkipMountingPartitions(fstab);
#endif
    EnableMandatoryFlags(fstab);

    return true;
}
// 启用强制标志
void EnableMandatoryFlags(Fstab* fstab) {
    // Devices launched in R and after should enable fs_verity on userdata. The flag causes tune2fs
    // to enable the feature. A better alternative would be to enable on mkfs at the beginning.
    if (android::base::GetIntProperty("ro.product.first_api_level", 0) >= 30) {
        std::vector<FstabEntry*> data_entries = GetEntriesForMountPoint(fstab, "/data");
        for (auto&& entry : data_entries) {
            // Besides ext4, f2fs is also supported. But the image is already created with verity
            // turned on when it was first introduced.
            if (entry->fs_type == "ext4") {
                entry->fs_mgr_flags.fs_verity = true;
            }
        }
    }
}

1.13 TransformFstabForDsu-dsu相关的

void TransformFstabForDsu(Fstab* fstab, const std::vector<std::string>& dsu_partitions) {
    static constexpr char kDsuKeysDir[] = "/avb";
    // Convert userdata
    // Inherit fstab properties for userdata.
    FstabEntry userdata;
    if (FstabEntry* entry = GetEntryForMountPoint(fstab, "/data")) {
        userdata = *entry;
        userdata.blk_device = "userdata_gsi";
        userdata.fs_mgr_flags.logical = true;
        userdata.fs_mgr_flags.formattable = true;
        if (!userdata.metadata_key_dir.empty()) {
            userdata.metadata_key_dir += "/gsi";
        }
    } else {
        userdata = BuildDsuUserdataFstabEntry();
    }

    if (EraseFstabEntry(fstab, "/data")) {
        fstab->emplace_back(userdata);
    }

    // Convert others
    for (auto&& partition : dsu_partitions) {
        if (!EndsWith(partition, gsi::kDsuPostfix)) {
            continue;
        }
        // userdata has been handled
        if (StartsWith(partition, "user")) {
            continue;
        }
        // dsu_partition_name = corresponding_partition_name + kDsuPostfix
        // e.g.
        //    system_gsi for system
        //    product_gsi for product
        //    vendor_gsi for vendor
        std::string lp_name = partition.substr(0, partition.length() - strlen(gsi::kDsuPostfix));
        std::string mount_point = "/" + lp_name;
        std::vector<FstabEntry*> entries = GetEntriesForMountPoint(fstab, mount_point);
        if (entries.empty()) {
            FstabEntry entry = {
                    .blk_device = partition,
                    // .logical_partition_name is required to look up AVB Hashtree descriptors.
                    .logical_partition_name = "system",
                    .mount_point = mount_point,
                    .fs_type = "ext4",
                    .flags = MS_RDONLY,
                    .fs_options = "barrier=1",
                    .avb_keys = kDsuKeysDir,
            };
            entry.fs_mgr_flags.wait = true;
            entry.fs_mgr_flags.logical = true;
            entry.fs_mgr_flags.first_stage_mount = true;
        } else {
            // If the corresponding partition exists, transform all its Fstab
            // by pointing .blk_device to the DSU partition.
            for (auto&& entry : entries) {
                entry->blk_device = partition;
                // AVB keys for DSU should always be under kDsuKeysDir.
                entry->avb_keys += kDsuKeysDir;
            }
            // Make sure the ext4 is included to support GSI.
            auto partition_ext4 =
                    std::find_if(fstab->begin(), fstab->end(), [&](const auto& entry) {
                        return entry.mount_point == mount_point && entry.fs_type == "ext4";
                    });
            if (partition_ext4 == fstab->end()) {
                auto new_entry = *GetEntryForMountPoint(fstab, mount_point);
                new_entry.fs_type = "ext4";
                fstab->emplace_back(new_entry);
            }
        }
    }
}

1.14 GetBootDevices-获取boot_devices,一般从dts那里配置的

std::set<std::string> GetBootDevices() {
    // First check the kernel commandline, then try the device tree otherwise
    // /proc/device-tree/firmware/android/boot_devices: soc@2900000/4020000.sdmmc,soc@2900000/4022000.sdmmc,soc@2900000
    std::string dt_file_name = get_android_dt_dir() + "/boot_devices";
    std::string value;
    if (fs_mgr_get_boot_config_from_kernel_cmdline("boot_devices", &value) ||
        ReadDtFile(dt_file_name, &value)) {
        auto boot_devices = Split(value, ",");
        return std::set<std::string>(boot_devices.begin(), boot_devices.end());
    }

    // Fallback to extract boot devices from fstab.
    Fstab fstab;
    if (!ReadDefaultFstab(&fstab)) {
        return {};
    }

    return ExtraBootDevices(fstab);
}

2. 解析boot_config

2.1 fs_mgr_get_boot_config_from_kernel_cmdline-解析cmdline的

// 解析cmdline中的androidboot.$key的值
bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val) {
    std::string cmdline;
    if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) return false;
    if (!cmdline.empty() && cmdline.back() == '\n') {
        cmdline.pop_back();
    }
    return fs_mgr_get_boot_config_from_kernel(cmdline, key, out_val);
}
bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::string& android_key,
                                        std::string* out_val) {
    FS_MGR_CHECK(out_val != nullptr);

    const std::string cmdline_key("androidboot." + android_key);
    for (const auto& [key, value] : fs_mgr_parse_boot_config(cmdline)) {
        // 如果和key相同,则取其值
        if (key == cmdline_key) {
            *out_val = value;
            return true;
        }
    }

    *out_val = "";
    return false;
}

std::vector<std::pair<std::string, std::string>> fs_mgr_parse_boot_config(const std::string& cmdline) {
    static constexpr char quote = '"';

    std::vector<std::pair<std::string, std::string>> result;
    size_t base = 0;
    while (true) {
        // skip quoted spans
        auto found = base;
        std::cout << "before found = " << found << "  base = " << base << std::endl;
        // 寻找空格和引号;引号之后的空格,可以跳出循环
        while (((found = cmdline.find_first_of(" \"", found)) != cmdline.npos) &&
               // 如果有引号
               (cmdline[found] == quote)) {
            // unbalanced quote is ok
            // 则找配对的引号
            if ((found = cmdline.find(quote, found + 1)) == cmdline.npos) break;
            ++found;
            std::cout << "quote found = " << found << std::endl;
        }
        std::string piece;
        std::cout << "after found = " << found << "  base = " << base << std::endl;
        auto source = cmdline.substr(base, found - base);
        std::remove_copy(source.begin(), source.end(),
                         std::back_insert_iterator<std::string>(piece), quote);
        std::cout << "piece = " << piece << " source = " << source << std::endl;
        auto equal_sign = piece.find('=');
        if (equal_sign == piece.npos) {
            if (!piece.empty()) {
                // no difference between <key> and <key>=
                result.emplace_back(std::move(piece), "");
            }
        } else {
            // 解析的结果
            result.emplace_back(piece.substr(0, equal_sign), piece.substr(equal_sign + 1));
        }
        if (found == cmdline.npos) break;
        base = found + 1;
    }

    return result;
}
before found = 0  base = 0
quote found = 35
after found = 35  base = 0
piece = earlyprintk=sunxi-uart,0x05000000 source = earlyprintk="sunxi-uart,0x05000000"
before found = 36  base = 36
after found = 53  base = 36
piece = clk_ignore_unused source = clk_ignore_unused

2.2 fs_mgr_get_boot_config-读取dts和ro.boot.和androidboot.的值

bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) {
    FS_MGR_CHECK(out_val != nullptr);

    // firstly, check the device tree
    // 读取/proc/device-tree/firmware/android/compatible文件是否为android,firmware
    if (is_dt_compatible()) {
        // 读取/proc/device-tree/firmware/android/slot_suffix的值
        std::string file_name = get_android_dt_dir() + "/" + key;
        if (android::base::ReadFileToString(file_name, out_val)) {
            if (!out_val->empty()) {
                out_val->pop_back();  // Trims the trailing '\0' out.
                return true;
            }
        }
    }

    // next, check if we have "ro.boot" property already
    // 读取ro.boot.slot_suffix的值
    *out_val = android::base::GetProperty("ro.boot." + key, "");
    if (!out_val->empty()) {
        return true;
    }

    // finally, fallback to kernel cmdline, properties may not be ready yet
    // 获取androidboot.slot_suffix的值
    if (fs_mgr_get_boot_config_from_kernel_cmdline(key, out_val)) {
        return true;
    }

    return false;
}

3. fs_mgr主模块

3.1 fs_mgr_get_super_partition_name-获取super分区的名字

std::string fs_mgr_get_super_partition_name(int slot) {
    // Devices upgrading to dynamic partitions are allowed to specify a super
    // partition name. This includes cuttlefish, which is a non-A/B device.
    std::string super_partition;
    // cmdline获取androidboot.super_partition的值
    if (fs_mgr_get_boot_config_from_kernel_cmdline("super_partition", &super_partition)) {
        // cmdline获取androidboot.slot_suffix的值
        if (fs_mgr_get_slot_suffix().empty()) {
            return super_partition;
        }
        std::string suffix;
        if (slot == 0) {
            suffix = "_a";
        } else if (slot == 1) {
            suffix = "_b";
        } else if (slot == -1) {
            suffix = fs_mgr_get_slot_suffix();
        }
        return super_partition + suffix;
    }
    // 返回super的值
    return LP_METADATA_DEFAULT_PARTITION_NAME;
}

3.2 fs_mgr_do_mount_one-挂载文件系统

int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& mount_point) {
    // First check the filesystem if requested.
    // 等待分区设备可用
    if (entry.fs_mgr_flags.wait && !WaitForFile(entry.blk_device, 20s)) {
        LERROR << "Skipping mounting '" << entry.blk_device << "'";
    }

    // Run fsck if needed
    // 
    prepare_fs_for_mount(entry.blk_device, entry);

    int ret =
            __mount(entry.blk_device, mount_point.empty() ? entry.mount_point : mount_point, entry);
    if (ret) {
      ret = (errno == EBUSY) ? FS_MGR_DOMNT_BUSY : FS_MGR_DOMNT_FAILED;
    }

    return ret;
}

3.3 prepare_fs_for_mount-读文件系统的超级头看是否有效-打开某些可调的flags-ext4格式才可调

static int prepare_fs_for_mount(const std::string& blk_device, const FstabEntry& entry) {
    int fs_stat = 0;

    if (is_extfs(entry.fs_type)) {
        struct ext4_super_block sb;
// 读ext4超级块
        if (read_ext4_superblock(blk_device, &sb, &fs_stat)) {
            if ((sb.s_feature_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) != 0 ||
                (sb.s_state & EXT4_VALID_FS) == 0) {
                LINFO << "Filesystem on " << blk_device << " was not cleanly shutdown; "
                      << "state flags: 0x" << std::hex << sb.s_state << ", "
                      << "incompat feature flags: 0x" << std::hex << sb.s_feature_incompat;
                fs_stat |= FS_STAT_UNCLEAN_SHUTDOWN;
            }
// 打开quota的flags
            // Note: quotas should be enabled before running fsck.
            tune_quota(blk_device, entry, &sb, &fs_stat);
        } else {
            return fs_stat;
        }
    } else if (is_f2fs(entry.fs_type)) {
        if (!read_f2fs_superblock(blk_device, &fs_stat)) {
            return fs_stat;
        }
    }

    if (entry.fs_mgr_flags.check ||
        (fs_stat & (FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED))) {
        // 如果设置了check标志,则会执行check_fs操作
        check_fs(blk_device, entry.fs_type, entry.mount_point, &fs_stat);
    }

    if (is_extfs(entry.fs_type) &&
        (entry.reserved_size != 0 || entry.fs_mgr_flags.file_encryption ||
         entry.fs_mgr_flags.fs_verity || entry.fs_mgr_flags.ext_meta_csum)) {
        struct ext4_super_block sb;

        if (read_ext4_superblock(blk_device, &sb, &fs_stat)) {
            // 打开一堆features
            tune_reserved_size(blk_device, entry, &sb, &fs_stat);
            tune_encrypt(blk_device, entry, &sb, &fs_stat);
            tune_verity(blk_device, entry, &sb, &fs_stat);
            tune_casefold(blk_device, &sb, &fs_stat);
            tune_metadata_csum(blk_device, entry, &sb, &fs_stat);
        }
    }

    return fs_stat;
}

3.4 read_ext4_superblock-读ext4的超级块

static bool read_ext4_superblock(const std::string& blk_device, struct ext4_super_block* sb,
                                 int* fs_stat) {
    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device.c_str(), O_RDONLY | O_CLOEXEC)));

    if (fd < 0) {
        PERROR << "Failed to open '" << blk_device << "'";
        return false;
    }
// 从offset开始读,从1024个字节开始读超级块
    if (TEMP_FAILURE_RETRY(pread(fd, sb, sizeof(*sb), 1024)) != sizeof(*sb)) {
        PERROR << "Can't read '" << blk_device << "' superblock";
        return false;
    }

    if (!is_ext4_superblock_valid(sb)) {
        LINFO << "Invalid ext4 superblock on '" << blk_device << "'";
        // not a valid fs, tune2fs, fsck, and mount  will all fail.
        *fs_stat |= FS_STAT_INVALID_MAGIC;
        return false;
    }
    *fs_stat |= FS_STAT_IS_EXT4;
    LINFO << "superblock s_max_mnt_count:" << sb->s_max_mnt_count << "," << blk_device;
    if (sb->s_max_mnt_count == 0xffff) {  // -1 (int16) in ext2, but uint16 in ext4
        *fs_stat |= FS_STAT_NEW_IMAGE_VERSION;
    }
    return true;
}

3.5 check_fs-用e2fsck工具检查ext4-用fsck.f2fs检查f2fs文件系统

static void check_fs(const std::string& blk_device, const std::string& fs_type,
                     const std::string& target, int* fs_stat) {
    int status;
    int ret;
    long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
    auto tmpmnt_opts = "errors=remount-ro"s;
    const char* e2fsck_argv[] = {E2FSCK_BIN, "-y", blk_device.c_str()};
    const char* e2fsck_forced_argv[] = {E2FSCK_BIN, "-f", "-y", blk_device.c_str()};

    if (*fs_stat & FS_STAT_INVALID_MAGIC) {  // will fail, so do not try
        return;
    }

    Timer t;
    /* Check for the types of filesystems we know how to check */
    if (is_extfs(fs_type)) {
        /*
         * First try to mount and unmount the filesystem.  We do this because
         * the kernel is more efficient than e2fsck in running the journal and
         * processing orphaned inodes, and on at least one device with a
         * performance issue in the emmc firmware, it can take e2fsck 2.5 minutes
         * to do what the kernel does in about a second.
         *
         * After mounting and unmounting the filesystem, run e2fsck, and if an
         * error is recorded in the filesystem superblock, e2fsck will do a full
         * check.  Otherwise, it does nothing.  If the kernel cannot mount the
         * filesytsem due to an error, e2fsck is still run to do a full check
         * fix the filesystem.
         */
        // 挂载失败的时候,进到check_fs函数
        if (!(*fs_stat & FS_STAT_FULL_MOUNT_FAILED)) {  // already tried if full mount failed
            errno = 0;
            if (fs_type == "ext4") {
                // This option is only valid with ext4
                tmpmnt_opts += ",nomblk_io_submit";
            }
            ret = mount(blk_device.c_str(), target.c_str(), fs_type.c_str(), tmpmnt_flags,
                        tmpmnt_opts.c_str());
            PINFO << __FUNCTION__ << "(): mount(" << blk_device << "," << target << "," << fs_type
                  << ")=" << ret;
            // 重新挂载之后,挂载成功了
            if (!ret) {
                bool umounted = false;
                // 重试5次
                int retry_count = 5;
                while (retry_count-- > 0) {
                    // 卸载也成功了
                    umounted = umount(target.c_str()) == 0;
                    if (umounted) {
                        LINFO << __FUNCTION__ << "(): unmount(" << target << ") succeeded";
                        break;
                    }
                    PERROR << __FUNCTION__ << "(): umount(" << target << ") failed";
                    // 睡眠1s后,重试
                    if (retry_count) sleep(1);
                }
                if (!umounted) {
                    // boot may fail but continue and leave it to later stage for now.
                    PERROR << __FUNCTION__ << "(): umount(" << target << ") timed out";
                    *fs_stat |= FS_STAT_RO_UNMOUNT_FAILED;
                }
            } else {
                *fs_stat |= FS_STAT_RO_MOUNT_FAILED;
            }
        }

        /*
         * Some system images do not have e2fsck for licensing reasons
         * (e.g. recent SDK system images). Detect these and skip the check.
         */
        if (access(E2FSCK_BIN, X_OK)) {
            LINFO << "Not running " << E2FSCK_BIN << " on " << realpath(blk_device)
                  << " (executable not in system image)";
        } else {
            LINFO << "Running " << E2FSCK_BIN << " on " << realpath(blk_device);
            if (should_force_check(*fs_stat)) {
                // 执行e2fsck来检查文件系统
                ret = logwrap_fork_execvp(ARRAY_SIZE(e2fsck_forced_argv), e2fsck_forced_argv,
                                          &status, false, LOG_KLOG | LOG_FILE, false,
                                          FSCK_LOG_FILE);
            } else {
                ret = logwrap_fork_execvp(ARRAY_SIZE(e2fsck_argv), e2fsck_argv, &status, false,
                                          LOG_KLOG | LOG_FILE, false, FSCK_LOG_FILE);
            }

            if (ret < 0) {
                /* No need to check for error in fork, we can't really handle it now */
                LERROR << "Failed trying to run " << E2FSCK_BIN;
                *fs_stat |= FS_STAT_E2FSCK_FAILED;
            } else if (status != 0) {
                LINFO << "e2fsck returned status 0x" << std::hex << status;
                *fs_stat |= FS_STAT_E2FSCK_FS_FIXED;
            }
        }
    } else if (is_f2fs(fs_type)) {
        const char* f2fs_fsck_argv[] = {F2FS_FSCK_BIN,     "-a", "-c", "10000", "--debug-cache",
                                        blk_device.c_str()};
        const char* f2fs_fsck_forced_argv[] = {
                F2FS_FSCK_BIN, "-f", "-c", "10000", "--debug-cache", blk_device.c_str()};

        if (should_force_check(*fs_stat)) {
            LINFO << "Running " << F2FS_FSCK_BIN << " -f -c 10000 --debug-cache"
                  << realpath(blk_device);
            // 执行fsck.f2fs命令来检查
            ret = logwrap_fork_execvp(ARRAY_SIZE(f2fs_fsck_forced_argv), f2fs_fsck_forced_argv,
                                      &status, false, LOG_KLOG | LOG_FILE, false, FSCK_LOG_FILE);
        } else {
            LINFO << "Running " << F2FS_FSCK_BIN << " -a -c 10000 --debug-cache"
                  << realpath(blk_device);
            ret = logwrap_fork_execvp(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv, &status, false,
                                      LOG_KLOG | LOG_FILE, false, FSCK_LOG_FILE);
        }
        if (ret < 0) {
            /* No need to check for error in fork, we can't really handle it now */
            LERROR << "Failed trying to run " << F2FS_FSCK_BIN;
        }
    }
    // 设置ro.boottime.init.fsck.属性
    android::base::SetProperty("ro.boottime.init.fsck." + Basename(target),
                               std::to_string(t.duration().count()));
    return;
}

3.6 tune_quota-执行tune2fs -Qusrquota,grpquota,prjquota /dev/block/mmc 命令开启quota功能

// Enable/disable quota support on the filesystem if needed.
static void tune_quota(const std::string& blk_device, const FstabEntry& entry,
                       const struct ext4_super_block* sb, int* fs_stat) {
    bool has_quota = (sb->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_QUOTA)) != 0;
    bool want_quota = entry.fs_mgr_flags.quota;
    bool want_projid = android::base::GetBoolProperty("external_storage.projid.enabled", false);

    if (has_quota == want_quota) {
        return;
    }

    if (!tune2fs_available()) {
        LERROR << "Unable to " << (want_quota ? "enable" : "disable") << " quotas on " << blk_device
               << " because " TUNE2FS_BIN " is missing";
        return;
    }

    const char* argv[] = {TUNE2FS_BIN, nullptr, nullptr, blk_device.c_str()};

    if (want_quota) {
        LINFO << "Enabling quotas on " << blk_device;
        argv[1] = "-Oquota";
        // Once usr/grp unneeded, make just prjquota to save overhead
        if (want_projid)
            argv[2] = "-Qusrquota,grpquota,prjquota";
        else
            argv[2] = "-Qusrquota,grpquota";
        *fs_stat |= FS_STAT_QUOTA_ENABLED;
    } else {
        LINFO << "Disabling quotas on " << blk_device;
        argv[1] = "-O^quota";
        argv[2] = "-Q^usrquota,^grpquota,^prjquota";
    }

    if (!run_command(argv, ARRAY_SIZE(argv))) {
        LERROR << "Failed to run " TUNE2FS_BIN " to " << (want_quota ? "enable" : "disable")
               << " quotas on " << blk_device;
        *fs_stat |= FS_STAT_TOGGLE_QUOTAS_FAILED;
    }
}

3.7 fs_mgr_update_logical_partition-通过system_a获取/dev/block/dm-0

bool fs_mgr_update_logical_partition(FstabEntry* entry) {
    // Logical partitions are specified with a named partition rather than a
    // block device, so if the block device is a path, then it has already
    // been updated.
    // system
    if (entry->blk_device[0] == '/') {
        return true;
    }

    DeviceMapper& dm = DeviceMapper::Instance();
    std::string device_name;
    // blk_device为system_a,通过system_a获取/dev/block/dm-0
    if (!dm.GetDmDevicePathByName(entry->blk_device, &device_name)) {
        return false;
    }

    entry->blk_device = device_name;
    return true;
}

3.8 fs_mgr_mount_all-挂载分区

// When multiple fstab records share the same mount_point, it will try to mount each
// one in turn, and ignore any duplicates after a first successful mount.
// Returns -1 on error, and  FS_MGR_MNTALL_* otherwise.
int fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
    int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
    int error_count = 0;
    CheckpointManager checkpoint_manager;
    AvbUniquePtr avb_handle(nullptr);

    if (fstab->empty()) {
        return FS_MGR_MNTALL_FAIL;
    }

    // Keep i int to prevent unsigned integer overflow from (i = top_idx - 1),
    // where top_idx is 0. It will give SIGABRT
    for (int i = 0; i < static_cast<int>(fstab->size()); i++) {
        auto& current_entry = (*fstab)[i];

        // If a filesystem should have been mounted in the first stage, we
        // ignore it here. With one exception, if the filesystem is
        // formattable, then it can only be formatted in the second stage,
        // so we allow it to mount here.
        // 第一阶段挂载的,像system,product,vendor,metadata分区;不是formattable的,就跳过
        // firststage的,是formattable的,并且还没挂载的。就可以接下来挂载
        if (current_entry.fs_mgr_flags.first_stage_mount &&
            (!current_entry.fs_mgr_flags.formattable ||
             IsMountPointMounted(current_entry.mount_point))) {
            continue;
        }

        // Don't mount entries that are managed by vold or not for the mount mode.
        // voldmanaged会从这跳过;recoveryonly也会跳过
        if (current_entry.fs_mgr_flags.vold_managed || current_entry.fs_mgr_flags.recovery_only ||
            // --late阶段,并且没配置latemount的,会跳过
            ((mount_mode == MOUNT_MODE_LATE) && !current_entry.fs_mgr_flags.late_mount) ||
            // --early阶段,配置了latemount的,会从这里跳过
            ((mount_mode == MOUNT_MODE_EARLY) && current_entry.fs_mgr_flags.late_mount)) {
            continue;
        }

        // Skip swap and raw partition entries such as boot, recovery, etc.
        // swap,emmc,mtd的会跳过
        if (current_entry.fs_type == "swap" || current_entry.fs_type == "emmc" ||
            current_entry.fs_type == "mtd") {
            continue;
        }

        // Skip mounting the root partition, as it will already have been mounted.
        // fs_mgr: overlayfs clears readonly on scratch devices
        if (current_entry.mount_point == "/" || current_entry.mount_point == "/system") {
            if ((current_entry.flags & MS_RDONLY) != 0) {
                // 设置只读
                fs_mgr_set_blk_ro(current_entry.blk_device);
            }
            continue;
        }

        // Terrible hack to make it possible to remount /data.
        // TODO: refact fs_mgr_mount_all and get rid of this.
        // remount相关
        if (mount_mode == MOUNT_MODE_ONLY_USERDATA && current_entry.mount_point != "/data") {
            continue;
        }

        // Translate LABEL= file system labels into block devices.
        // ext4转换label相关
        if (is_extfs(current_entry.fs_type)) {
            if (!TranslateExtLabels(¤t_entry)) {
                LERROR << "Could not translate label to block device";
                continue;
            }
        }
// 逻辑分区相关
        if (current_entry.fs_mgr_flags.logical) {
            if (!fs_mgr_update_logical_partition(¤t_entry)) {
                LERROR << "Could not set up logical partition, skipping!";
                continue;
            }
        }
// virtual A/B相关的,会创建img文件到data分区,然后first_stage阶段要用到,但是又不能挂载data分区
        // 所以需要创建一个dm设备来wrap它
        WrapUserdataIfNeeded(¤t_entry);
// init: Calling: /system/bin/vdc checkpoint needsCheckpoint
        // checkpoint相关
        if (!checkpoint_manager.Update(¤t_entry)) {
            continue;
        }
// 等待块设备可用
        if (current_entry.fs_mgr_flags.wait && !WaitForFile(current_entry.blk_device, 20s)) {
            LERROR << "Skipping '" << current_entry.blk_device << "' during mount_all";
            continue;
        }
// avb相关的
        if (current_entry.fs_mgr_flags.avb) {
            if (!avb_handle) {
                avb_handle = AvbHandle::Open();
                if (!avb_handle) {
                    LERROR << "Failed to open AvbHandle";
                    return FS_MGR_MNTALL_FAIL;
                }
            }
            if (avb_handle->SetUpAvbHashtree(¤t_entry, true /* wait_for_verity_dev */) ==
                AvbHashtreeResult::kFail) {
                LERROR << "Failed to set up AVB on partition: " << current_entry.mount_point
                       << ", skipping!";
                // Skips mounting the device.
                continue;
            }
        } else if (!current_entry.avb_keys.empty()) {
            if (AvbHandle::SetUpStandaloneAvbHashtree(¤t_entry) == AvbHashtreeResult::kFail) {
                LERROR << "Failed to set up AVB on standalone partition: "
                       << current_entry.mount_point << ", skipping!";
                // Skips mounting the device.
                continue;
            }
        } else if ((current_entry.fs_mgr_flags.verify)) {
            int rc = fs_mgr_setup_verity(¤t_entry, true);
            if (rc == FS_MGR_SETUP_VERITY_DISABLED || rc == FS_MGR_SETUP_VERITY_SKIPPED) {
                LINFO << "Verity disabled";
            } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
                LERROR << "Could not set up verified partition, skipping!";
                continue;
            }
        }// 自己添加的代码,resize用的,容易引起系统不稳定
        if (current_entry.mount_point == "/data") {
	    bool crypt_footer = false;
            if (current_entry.is_encryptable() && current_entry.key_loc == KEY_IN_FOOTER) {
                crypt_footer = true;
	    }
            if (fs_mgr_do_resize(current_entry, crypt_footer) == 0) {
                LINFO << "Resize success";
            } else {
                LERROR << __FUNCTION__ << "(): Resize failed. ";
            }
        }

        int last_idx_inspected;
        int top_idx = i;
        int attempted_idx = -1;
// 挂载分区
        // metadata加密,这里挂载是会失败的
        // init: [libfs_mgr]mount_with_alternatives(): skipping mount due to invalid magic, mountpoint=/data blk_dev=/dev/block/mmcblk0p24 rec[3].fs_type=f2fs
        bool mret = mount_with_alternatives(*fstab, i, &last_idx_inspected, &attempted_idx);
        auto& attempted_entry = (*fstab)[attempted_idx];	// 尝试的idx
        i = last_idx_inspected;	// last_idx
        int mount_errno = errno;

        // Handle success and deal with encryptability.
        // 挂载成功的情况,metadata加密不走这里
        if (mret) {
            int status = handle_encryptable(attempted_entry);

            if (status == FS_MGR_MNTALL_FAIL) {
                // Fatal error - no point continuing.
                return status;
            }
// 第一次烧固件,在下面格式化之后;第二次走上面那个流程就会挂载成功了,就走这里来了;
            // 由于是metadata加密,所以走这里
            if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
                if (encryptable != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
                    // Log and continue
                    LERROR << "Only one encryptable/encrypted partition supported";
                }
                encryptable = status;// 这里处理metadata加密的
                if (status == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
                    // 注意这里是:/system/bin/vdc cryptfs encryptFstab /dev/block/by-name/userdata /data
                    if (!call_vdc({"cryptfs", "encryptFstab", attempted_entry.blk_device,
                                   attempted_entry.mount_point},
                                  nullptr)) {
                        LERROR << "Encryption failed";
                        return FS_MGR_MNTALL_FAIL;
                    }
                }
            }

            // Success!  Go get the next one.
            continue;
        }
// 挂载失败的情况,metadata加密走这里
        // Mounting failed, understand why and retry.
        // 判断分区是否被擦除了-读4096个字节,看是否全部是0或者全部是1,全部是0或1就是被擦除了
        // 被擦除是第一次烧固件的时候
        bool wiped = partition_wiped(current_entry.blk_device.c_str());
        bool crypt_footer = false;
        if (mount_errno != EBUSY && mount_errno != EACCES &&
            current_entry.fs_mgr_flags.formattable && wiped) {	// 第一次烧固件之后,进入这里
            // current_entry and attempted_entry point at the same partition, but sometimes
            // at two different lines in the fstab.  Use current_entry for formatting
            // as that is the preferred one.
            LERROR << __FUNCTION__ << "(): " << realpath(current_entry.blk_device)
                   << " is wiped and " << current_entry.mount_point << " " << current_entry.fs_type
                   << " is formattable. Format it.";
// 对于checkpoint=fs选项,什么都没做
            checkpoint_manager.Revert(¤t_entry);
// is_encryptable是:encryptable=  forceencrypt=  forcefdeorfbe=这三种情况,我们是fileencryption=,所以其为false
            if (current_entry.is_encryptable() && current_entry.key_loc != KEY_IN_FOOTER) {
                unique_fd fd(TEMP_FAILURE_RETRY(
                        open(current_entry.key_loc.c_str(), O_WRONLY | O_CLOEXEC)));
                if (fd >= 0) {
                    LINFO << __FUNCTION__ << "(): also wipe " << current_entry.key_loc;
                    wipe_block_device(fd, get_file_size(fd));
                } else {
                    PERROR << __FUNCTION__ << "(): " << current_entry.key_loc << " wouldn't open";
                }// 不走这里
            } else if (current_entry.is_encryptable() && current_entry.key_loc == KEY_IN_FOOTER) {
                crypt_footer = true;
            }// 第一次烧固件,进行分区格式化操作,crypt_footer为false
            if (fs_mgr_do_format(current_entry, crypt_footer) == 0) {
                // Let's replay the mount actions.
                // 注意这里,格式化之后,又重新走一次流程了
                i = top_idx - 1;
                continue;
            } else {
                LERROR << __FUNCTION__ << "(): Format failed. "
                       << "Suggest recovery...";
                encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY;
                continue;
            }
        }

        // mount(2) returned an error, handle the encryptable/formattable case.
        // 不是is_encryptable的,见上面,不走这里
        if (mount_errno != EBUSY && mount_errno != EACCES && attempted_entry.is_encryptable()) {
            if (wiped) {
                LERROR << __FUNCTION__ << "(): " << attempted_entry.blk_device << " is wiped and "
                       << attempted_entry.mount_point << " " << attempted_entry.fs_type
                       << " is encryptable. Suggest recovery...";
                encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY;
                continue;
            } else {
                // Need to mount a tmpfs at this mountpoint for now, and set
                // properties that vold will query later for decrypting
                LERROR << __FUNCTION__ << "(): possibly an encryptable blkdev "
                       << attempted_entry.blk_device << " for mount " << attempted_entry.mount_point
                       << " type " << attempted_entry.fs_type;
                if (fs_mgr_do_tmpfs_mount(attempted_entry.mount_point.c_str()) < 0) {
                    ++error_count;
                    continue;
                }
            }
            encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
        } else if (mount_errno != EBUSY && mount_errno != EACCES &&
                   should_use_metadata_encryption(attempted_entry)) {// 是metadata加密的,走这里
            // 注意,这是串行执行的,需要等待metadata加密结束之后返回这里
            // 注意这里是:/system/bin/vdc cryptfs mountFstab /dev/block/by-name/userdata /data
            // 和第一次烧固件是不一样的,参数
            if (!call_vdc({"cryptfs", "mountFstab", attempted_entry.blk_device,
                           attempted_entry.mount_point},
                          nullptr)) {
                ++error_count;
            }
            encryptable = FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED;
            continue;
        } else {
            // fs_options might be null so we cannot use PERROR << directly.
            // Use StringPrintf to output "(null)" instead.
            if (attempted_entry.fs_mgr_flags.no_fail) {
                PERROR << android::base::StringPrintf(
                        "Ignoring failure to mount an un-encryptable or wiped "
                        "partition on %s at %s options: %s",
                        attempted_entry.blk_device.c_str(), attempted_entry.mount_point.c_str(),
                        attempted_entry.fs_options.c_str());
            } else {
                PERROR << android::base::StringPrintf(
                        "Failed to mount an un-encryptable or wiped partition "
                        "on %s at %s options: %s",
                        attempted_entry.blk_device.c_str(), attempted_entry.mount_point.c_str(),
                        attempted_entry.fs_options.c_str());
                ++error_count;
            }
            continue;
        }
    }

#if ALLOW_ADBD_DISABLE_VERITY == 1  // "userdebug" build // remount相关的
    fs_mgr_overlayfs_mount_all(fstab);
#endif

    if (error_count) {
        return FS_MGR_MNTALL_FAIL;
    } else {
        return encryptable;
    }
}

3.9 fs_mgr_set_blk_ro-设置只读标志,overlayfs会清除只读标志

bool fs_mgr_set_blk_ro(const std::string& blockdev, bool readonly) {
    unique_fd fd(TEMP_FAILURE_RETRY(open(blockdev.c_str(), O_RDONLY | O_CLOEXEC)));
    if (fd < 0) {
        return false;
    }

    int ON = readonly;
    return ioctl(fd, BLKROSET, &ON) == 0;
}

3.10 WrapUserdataIfNeeded-看是否需要为data分区创建dm设备

// When using Virtual A/B, partitions can be backed by /data and mapped with
// device-mapper in first-stage init. This can happen when merging an OTA or
// when using adb remount to house "scratch". In this case, /data cannot be
// mounted directly off the userdata block device, and e2fsck will refuse to
// scan it, because the kernel reports the block device as in-use.
//
// As a workaround, when mounting /data, we create a trivial dm-linear wrapper
// if the underlying block device already has dependencies. Note that we make
// an exception for metadata-encrypted devices, since dm-default-key is already
// a wrapper.
static void WrapUserdataIfNeeded(FstabEntry* entry, const std::string& actual_block_device = {}) {
    const auto& block_device =
            actual_block_device.empty() ? entry->blk_device : actual_block_device;
    // 不是data分区;metadata加密的(metadata加密自带dm设备,不需要创建dm设备了);已经是dm设备了,就跳过
    if (entry->mount_point != "/data" || !entry->metadata_key_dir.empty() ||
        android::base::StartsWith(block_device, "/dev/block/dm-")) {
        return;
    }

    struct stat st;
    if (stat(block_device.c_str(), &st) < 0) {
        PLOG(ERROR) << "stat failed: " << block_device;
        return;
    }
// /sys/dev/block/179:15/holders
    std::string path = android::base::StringPrintf("/sys/dev/block/%u:%u/holders",
                                                   major(st.st_rdev), minor(st.st_rdev));
    std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
    if (!dir) {
        PLOG(ERROR) << "opendir failed: " << path;
        return;
    }

    struct dirent* d;
    bool has_holders = false;
    while ((d = readdir(dir.get())) != nullptr) {
        // /sys/dev/block/179:15/holders文件夹有文件存在
        if (strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0) {
            has_holders = true;
            break;
        }
    }

    if (has_holders) {
        // 就创建dm设备
        WrapUserdata(entry, st.st_rdev, block_device);
    }
}
static void WrapUserdata(FstabEntry* entry, dev_t dev, const std::string& block_device) {
    DeviceMapper& dm = DeviceMapper::Instance();
    if (dm.GetState(kUserdataWrapperName) != DmDeviceState::INVALID) {
        // This will report failure for us. If we do fail to get the path,
        // we leave the device unwrapped.
        dm.GetDmDevicePathByName(kUserdataWrapperName, &entry->blk_device);
        return;
    }

    unique_fd fd(open(block_device.c_str(), O_RDONLY | O_CLOEXEC));
    if (fd < 0) {
        PLOG(ERROR) << "open failed: " << entry->blk_device;
        return;
    }

    auto dev_str = android::base::StringPrintf("%u:%u", major(dev), minor(dev));
    uint64_t sectors = get_block_device_size(fd) / 512;

    android::dm::DmTable table;
    table.Emplace<DmTargetLinear>(0, sectors, dev_str, 0);

    std::string dm_path;
    // 创建线性dm设备
    if (!dm.CreateDevice(kUserdataWrapperName, table, &dm_path, 20s)) {
        LOG(ERROR) << "Failed to create userdata wrapper device";
        return;
    }
    entry->blk_device = dm_path;
}

3.11 mount_with_alternatives-挂载分区

// Tries to mount any of the consecutive fstab entries that match
// the mountpoint of the one given by fstab[start_idx].
//
// end_idx: On return, will be the last entry that was looked at.
// attempted_idx: On return, will indicate which fstab entry
//     succeeded. In case of failure, it will be the start_idx.
// Sets errno to match the 1st mount failure on failure.
static bool mount_with_alternatives(const Fstab& fstab, int start_idx, int* end_idx,
                                    int* attempted_idx) {
    unsigned long i;
    int mount_errno = 0;
    bool mounted = false;

    // Hunt down an fstab entry for the same mount point that might succeed.
    for (i = start_idx;
         // We required that fstab entries for the same mountpoint be consecutive.
         // 从fstab中查找和start_idx相匹配的mount_point
         i < fstab.size() && fstab[start_idx].mount_point == fstab[i].mount_point; i++) {
        // Don't try to mount/encrypt the same mount point again.
        // Deal with alternate entries for the same point which are required to be all following
        // each other.
        if (mounted) {
            LERROR << __FUNCTION__ << "(): skipping fstab dup mountpoint=" << fstab[i].mount_point
                   << " rec[" << i << "].fs_type=" << fstab[i].fs_type << " already mounted as "
                   << fstab[*attempted_idx].fs_type;
            continue;
        }
// 看是否能读到文件系统,如果读到了,就直接返回;读不到就进行fsck检查文件系统
        int fs_stat = prepare_fs_for_mount(fstab[i].blk_device, fstab[i]);
        if (fs_stat & FS_STAT_INVALID_MAGIC) {
            LERROR << __FUNCTION__
                   << "(): skipping mount due to invalid magic, mountpoint=" << fstab[i].mount_point
                   << " blk_dev=" << realpath(fstab[i].blk_device) << " rec[" << i
                   << "].fs_type=" << fstab[i].fs_type;
            mount_errno = EINVAL;  // continue bootup for FDE
            continue;
        }

        int retry_count = 2;
        while (retry_count-- > 0) {
            // 先挂载
            if (!__mount(fstab[i].blk_device, fstab[i].mount_point, fstab[i])) {
                *attempted_idx = i;
                // 挂载成功了,就直接退出
                mounted = true;
                if (i != start_idx) {
                    LERROR << __FUNCTION__ << "(): Mounted " << fstab[i].blk_device << " on "
                           << fstab[i].mount_point << " with fs_type=" << fstab[i].fs_type
                           << " instead of " << fstab[start_idx].fs_type;
                }
                fs_stat &= ~FS_STAT_FULL_MOUNT_FAILED;
                mount_errno = 0;
                break;
            } else {
                // 挂载失败了
                if (retry_count <= 0) break;  // run check_fs only once
                fs_stat |= FS_STAT_FULL_MOUNT_FAILED;
                // back up the first errno for crypto decisions.
                if (mount_errno == 0) {
                    mount_errno = errno;
                }
                // retry after fsck
                // fsck检查文件系统
                check_fs(fstab[i].blk_device, fstab[i].fs_type, fstab[i].mount_point, &fs_stat);
            }
        }
        log_fs_stat(fstab[i].blk_device, fs_stat);
    }

    /* Adjust i for the case where it was still withing the recs[] */
    if (i < fstab.size()) --i;

    *end_idx = i;	// 最后尝试的idx
    if (!mounted) {
        // 挂载失败了
        *attempted_idx = start_idx;
        errno = mount_errno;
        return false;
    }
    return true;
}

3.12 call_vdc-执行vdc命令

call_vdc({"cryptfs", "encryptFstab", attempted_entry.blk_device,
                                   attempted_entry.mount_point},
                                  nullptr)

static bool call_vdc(const std::vector<std::string>& args, int* ret) {
    std::vector<char const*> argv;
    argv.emplace_back("/system/bin/vdc");
    for (auto& arg : args) {
        argv.emplace_back(arg.c_str());
    }
    LOG(INFO) << "Calling: " << android::base::Join(argv, ' ');
    // 执行vdc命令
    int err = logwrap_fork_execvp(argv.size(), argv.data(), ret, false, LOG_ALOG, false, nullptr);
    if (err != 0) {
        LOG(ERROR) << "vdc call failed with error code: " << err;
        return false;
    }
    LOG(DEBUG) << "vdc finished successfully";
    if (ret != nullptr) {
        *ret = WEXITSTATUS(*ret);
    }
    return true;
}

4. dm_linear模块-逻辑分区相关

4.1 ReadCurrentMetadata-读super分区中的metadata信息

super分区:/dev/block/mmcblk0p5

std::unique_ptr<LpMetadata> ReadCurrentMetadata(const std::string& block_device) {
    // androidboot.slot_suffix的值
    uint32_t slot = SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix());
    // /dev/block/mmcblk0p5和0,读super分区的metadata信息
    return ReadMetadata(block_device.c_str(), slot);
}

4.2 CreateLogicalPartitions

// super_device为:/dev/block/mmcblk0p9
bool CreateLogicalPartitions(const LpMetadata& metadata, const std::string& super_device) {
    CreateLogicalPartitionParams params = {
            .block_device = super_device,
            .metadata = &metadata,
       // 加一个partition
    };
    // system_a vendor_a product_a分区
    for (const auto& partition : metadata.partitions) {
        if (!partition.num_extents) {
            LINFO << "Skipping zero-length logical partition: " << GetPartitionName(partition);
            continue;
        }
        if (partition.attributes & LP_PARTITION_ATTR_DISABLED) {
            LINFO << "Skipping disabled partition: " << GetPartitionName(partition);
            continue;
        }
// 每次的partition都是不一样的
        params.partition = &partition;

        std::string ignore_path;
        // 创建dm-0设备
        if (!CreateLogicalPartition(params, &ignore_path)) {
            LERROR << "Could not create logical partition: " << GetPartitionName(partition);
            return false;
        }
    }
    return true;
}

4.3 CreateLogicalPartition

bool CreateLogicalPartition(CreateLogicalPartitionParams params, std::string* path) {
    CreateLogicalPartitionParams::OwnedData owned_data;
    // 创建owned_data,并进行初始化-就是初始化CreateLogicalPartitionParams
    if (!params.InitDefaults(&owned_data)) return false;

    DmTable table;
    // 创建dm-linear的tables
    if (!CreateDmTableInternal(params, &table)) {
        return false;
    }
// 打开/dev/device-mapper设备
    DeviceMapper& dm = DeviceMapper::Instance();
    // device_name为system_a,table,
    if (!dm.CreateDevice(params.device_name, table, path, params.timeout_ms)) {
        return false;
    }
    LINFO << "Created logical partition " << params.device_name << " on device " << *path;
    return true;
}

4.4 InitDefaults-创建并初始化owner_data-就是初始化CreateLogicalPartitionParams

bool CreateLogicalPartitionParams::InitDefaults(CreateLogicalPartitionParams::OwnedData* owned) {
    if (block_device.empty()) {
        LOG(ERROR) << "block_device is required for CreateLogicalPartition";
        return false;
    }
// 创建一个PartitionOpener
    if (!partition_opener) {
        owned->partition_opener = std::make_unique<PartitionOpener>();
        partition_opener = owned->partition_opener.get();
    }

    // Read metadata if needed.,为非空
    if (!metadata) {
        if (!metadata_slot) {
            LOG(ERROR) << "Either metadata or a metadata slot must be specified.";
            return false;
        }
        auto slot = *metadata_slot;
        if (owned->metadata = ReadMetadata(*partition_opener, block_device, slot);
            !owned->metadata) {
            LOG(ERROR) << "Could not read partition table for: " << block_device;
            return false;
        }
        metadata = owned->metadata.get();
    }

    // Find the partition by name if needed.,为非空
    if (!partition) {
        for (const auto& metadata_partition : metadata->partitions) {
            if (android::fs_mgr::GetPartitionName(metadata_partition) == partition_name) {
                partition = &metadata_partition;
                break;
            }
        }
    }
    if (!partition) {// 为非空
        LERROR << "Could not find any partition with name: " << partition_name;
        return false;
    }
    if (partition_name.empty()) {// 走这里,一开始都没赋值,system_a
        partition_name = android::fs_mgr::GetPartitionName(*partition);
    } else if (partition_name != android::fs_mgr::GetPartitionName(*partition)) {
        LERROR << "Inconsistent partition_name " << partition_name << " with partition "
               << android::fs_mgr::GetPartitionName(*partition);
        return false;
    }

    if (device_name.empty()) {
        device_name = partition_name;
    }

    return true;
}

4.5 CreateDmTableInternal-创建dm-linear设备table

bool CreateDmTableInternal(const CreateLogicalPartitionParams& params, DmTable* table) {
    const auto& super_device = params.block_device;

    uint64_t sector = 0;
    for (size_t i = 0; i < params.partition->num_extents; i++) {
        const auto& extent = params.metadata->extents[params.partition->first_extent_index + i];
        std::unique_ptr<DmTarget> target;
        switch (extent.target_type) {
            case LP_TARGET_TYPE_ZERO:
                target = std::make_unique<DmTargetZero>(sector, extent.num_sectors);
                break;// 走这里,线性映射
            case LP_TARGET_TYPE_LINEAR: {
                const auto& block_device = params.metadata->block_devices[extent.target_source];
                std::string dev_string;
                // /dev/block/mmcblk0p5-dev_string
                if (!GetPhysicalPartitionDevicePath(params, block_device, super_device,
                                                    &dev_string)) {
                    LOG(ERROR) << "Unable to complete device-mapper table, unknown block device";
                    return false;
                }
                // 创建dmlinear设备,它可能由很多部分组成
                // sector为0,num_sectors为有多少个扇区,target_data为物理分区的扇区号
                // The sector on the physical partition that this extent maps onto.
                target = std::make_unique<DmTargetLinear>(sector, extent.num_sectors, dev_string,
                                                          extent.target_data);
                break;
            }
            default:
                LOG(ERROR) << "Unknown target type in metadata: " << extent.target_type;
                return false;
        }// 所以一个table有很多个targets
        if (!table->AddTarget(std::move(target))) {
            return false;
        }
        // 然后这里加起来
        sector += extent.num_sectors;
    }// system分区一般是只读的
    if (params.partition->attributes & LP_PARTITION_ATTR_READONLY) {
        table->set_readonly(true);
    }
    if (params.force_writable) {
        table->set_readonly(false);
    }
    return true;
}

4.6 GetPhysicalPartitionDevicePath-返回分区的真实块设备路径

static bool GetPhysicalPartitionDevicePath(const CreateLogicalPartitionParams& params,
                                           const LpMetadataBlockDevice& block_device,	// super
                                           const std::string& super_device, std::string* result) { //super
    // If the super device is the source of this block device's metadata,
    // make sure we use the correct super device (and not just "super",
    // which might not exist.)
    std::string name = GetBlockDevicePartitionName(block_device);
    // name为super,不走这里
    if (android::base::StartsWith(name, "dm-")) {
        // Device-mapper nodes are not normally allowed in LpMetadata, since
        // they are not consistent across reboots. However for the purposes of
        // testing it's useful to handle them. For example when running DSUs,
        // userdata is a device-mapper device, and some stacking will result
        // when using libfiemap.
        *result = "/dev/block/" + name;
        return true;
    }

    auto opener = params.partition_opener;
    // /dev/block/mmcblk0p5
    std::string dev_string = opener->GetDeviceString(name);
    if (GetMetadataSuperBlockDevice(*params.metadata) == &block_device) {
        // /dev/block/mmcblk0p5
        dev_string = opener->GetDeviceString(super_device);
    }

    // Note: device-mapper will not accept symlinks, so we must use realpath
    // here. If the device string is a major:minor sequence, we don't need to
    // to call Realpath (it would not work anyway).
    if (android::base::StartsWith(dev_string, "/")) {
        if (!android::base::Realpath(dev_string, result)) {
            PERROR << "realpath: " << dev_string;
            return false;
        }
    } else {
        *result = dev_string;
    }
    return true;
}

5. CheckpointManager模块

5.1 CheckpointManager构造函数

CheckpointManager(int needs_checkpoint = -1, bool metadata_encrypted = false)
        : needs_checkpoint_(needs_checkpoint), metadata_encrypted_(metadata_encrypted) {}

5.2 Update-OTA阶段更新挂载选项",checkpoint=disable"

bool Update(FstabEntry* entry, const std::string& block_device = std::string()) {
    // checkpoint=fs标志的
        if (!SupportsCheckpoint(entry)) {
            return true;
        }

        if (entry->fs_mgr_flags.checkpoint_blk && !metadata_encrypted_) {
            call_vdc({"checkpoint", "restoreCheckpoint", entry->blk_device}, nullptr);
        }
// 调用vdc checkpoint-OTA阶段需要checkpoint,返回true;正常情况不需要,为false
        if (!NeedsCheckpoint()) {
            // 正常情况下,走这里
            return true;
        }
// OTA阶段走这里,加上挂载选项",checkpoint=disable",如果失败了,就可以恢复到这个点上。
        if (!UpdateCheckpointPartition(entry, block_device)) {
            LERROR << "Could not set up checkpoint partition, skipping!";
            return false;
        }

        return true;
    }

5.3 NeedsCheckpoint-调用vdc checkpoint-OTA阶段需要checkpoint,返回true;正常情况不需要,为false

bool NeedsCheckpoint() {
        if (needs_checkpoint_ != UNKNOWN) {
            return needs_checkpoint_ == YES;
        } // init: Calling: /system/bin/vdc checkpoint needsCheckpoint
        if (!call_vdc({"checkpoint", "needsCheckpoint"}, &needs_checkpoint_)) {
            LERROR << "Failed to find if checkpointing is needed. Assuming no.";
            needs_checkpoint_ = NO;
        }// YES是1,就是needsCheckpoint函数返回1
        return needs_checkpoint_ == YES;
    }

5.4 UpdateCheckpointPartition-加上挂载选项",checkpoint=disable"

bool UpdateCheckpointPartition(FstabEntry* entry, const std::string& block_device) {
        // 走这里
        if (entry->fs_mgr_flags.checkpoint_fs) {
            if (is_f2fs(entry->fs_type)) {
                // 加上挂载选项",checkpoint=disable"
                entry->fs_checkpoint_opts = ",checkpoint=disable";
            } else {
                LERROR << entry->fs_type << " does not implement checkpoints.";
            }
        } else if (entry->fs_mgr_flags.checkpoint_blk) {
            auto actual_block_device = block_device.empty() ? entry->blk_device : block_device;
            if (fs_mgr_find_bow_device(actual_block_device).empty()) {
                unique_fd fd(
                        TEMP_FAILURE_RETRY(open(entry->blk_device.c_str(), O_RDONLY | O_CLOEXEC)));
                if (fd < 0) {
                    PERROR << "Cannot open device " << entry->blk_device;
                    return false;
                }

                uint64_t size = get_block_device_size(fd) / 512;
                if (!size) {
                    PERROR << "Cannot get device size";
                    return false;
                }

                android::dm::DmTable table;
                auto bowTarget =
                        std::make_unique<android::dm::DmTargetBow>(0, size, entry->blk_device);

                // dm-bow uses the first block as a log record, and relocates the real first block
                // elsewhere. For metadata encrypted devices, dm-bow sits below dm-default-key, and
                // for post Android Q devices dm-default-key uses a block size of 4096 always.
                // So if dm-bow's block size, which by default is the block size of the underlying
                // hardware, is less than dm-default-key's, blocks will get broken up and I/O will
                // fail as it won't be data_unit_size aligned.
                // However, since it is possible there is an already shipping non
                // metadata-encrypted device with smaller blocks, we must not change this for
                // devices shipped with Q or earlier unless they explicitly selected dm-default-key
                // v2
                constexpr unsigned int pre_gki_level = __ANDROID_API_Q__;
                unsigned int options_format_version = android::base::GetUintProperty<unsigned int>(
                        "ro.crypto.dm_default_key.options_format.version",
                        (android::fscrypt::GetFirstApiLevel() <= pre_gki_level ? 1 : 2));
                if (options_format_version > 1) {
                    bowTarget->SetBlockSize(4096);
                }

                if (!table.AddTarget(std::move(bowTarget))) {
                    LERROR << "Failed to add bow target";
                    return false;
                }

                DeviceMapper& dm = DeviceMapper::Instance();
                if (!dm.CreateDevice("bow", table)) {
                    PERROR << "Failed to create bow device";
                    return false;
                }

                std::string name;
                if (!dm.GetDmDevicePathByName("bow", &name)) {
                    PERROR << "Failed to get bow device name";
                    return false;
                }

                device_map_[name] = entry->blk_device;
                entry->blk_device = name;
            }
        }
        return true;
    }

5.5 Revert-对于checkpoint=fs选项,什么都没做

bool Revert(FstabEntry* entry) {
        // checkpoint=fs,表示支持checkpoint的
        if (!SupportsCheckpoint(entry)) {
            return true;
        }
// 这是checkpoint_blk的流程,所以这里是找不到的,返回true
        if (device_map_.find(entry->blk_device) == device_map_.end()) {
            return true;
        }

        std::string bow_device = entry->blk_device;
        entry->blk_device = device_map_[bow_device];
        device_map_.erase(bow_device);

        DeviceMapper& dm = DeviceMapper::Instance();
        if (!dm.DeleteDevice("bow")) {
            PERROR << "Failed to remove bow device";
        }

        return true;
    }

6. 分区格式化操作

6.1 fs_mgr_do_format

int fs_mgr_do_format(const FstabEntry& entry, bool crypt_footer) {
    LERROR << __FUNCTION__ << ": Format " << entry.blk_device << " as '" << entry.fs_type << "'";

    bool needs_casefold = false;
    bool needs_projid = false;

    if (entry.mount_point == "/data") {// 一些格式化的特性
        needs_casefold = android::base::GetBoolProperty("external_storage.casefold.enabled", false);
        needs_projid = android::base::GetBoolProperty("external_storage.projid.enabled", false);
    }

    if (entry.fs_type == "f2fs") {// data为f2fs的格式,走这里进行格式化操作
        return format_f2fs(entry.blk_device, entry.length, crypt_footer, needs_projid,
                           needs_casefold);
    } else if (entry.fs_type == "ext4") {
        return format_ext4(entry.blk_device, entry.mount_point, crypt_footer, needs_projid,
                           entry.fs_mgr_flags.ext_meta_csum);
    } else {
        LERROR << "File system type '" << entry.fs_type << "' is not supported";
        return -EINVAL;
    }
}

补充

1. c++特性

1.1 std::string

1.1.1 find_first_of函数

1.2 std::remove_copy

2. 系统调用

2.1 fmemopen

3. 库函数

3.1 strtok_r

问题

参考

1. Reasonable size for “filesystem reserved blocks” for non-OS disks?
https://askubuntu.com/questions/19504/reasonable-size-for-filesystem-reserved-blocks-for-non-os-disks