fs_mgr模块-system文件系统管理的主模块
目录
- 概述
- 源码解析
- 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
- 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模块-逻辑分区相关
- 5. CheckpointManager模块
- 6. 分区格式化操作
- 1. 解析fstab文件
- 补充
- 问题
- 参考
概述
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