Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e8e7b3bb authored by Yi-yo Chiang's avatar Yi-yo Chiang Committed by Gerrit Code Review
Browse files

Merge "TransformFstabForDsu: Support erofs GSI and refactor"

parents afffa03f c46c8922
Loading
Loading
Loading
Loading
+64 −43
Original line number Diff line number Diff line
@@ -539,6 +539,20 @@ bool EraseFstabEntry(Fstab* fstab, const std::string& mount_point) {
    return false;
}

template <typename Pred>
std::vector<FstabEntry*> GetEntriesByPred(Fstab* fstab, const Pred& pred) {
    if (fstab == nullptr) {
        return {};
    }
    std::vector<FstabEntry*> entries;
    for (auto&& entry : *fstab) {
        if (pred(entry)) {
            entries.push_back(&entry);
        }
    }
    return entries;
}

}  // namespace

bool ParseFstabFromString(const std::string& fstab_str, bool proc_mounts, Fstab* fstab_out) {
@@ -614,11 +628,7 @@ void TransformFstabForDsu(Fstab* fstab, const std::string& dsu_slot,
        userdata = BuildDsuUserdataFstabEntry();
    }

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

    // Convert others
    // Convert RO partitions.
    for (auto&& partition : dsu_partitions) {
        if (!EndsWith(partition, gsi::kDsuPostfix)) {
            continue;
@@ -638,48 +648,59 @@ void TransformFstabForDsu(Fstab* fstab, const std::string& dsu_slot,
        //    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,

        // List of fs_type entries we're lacking, need to synthesis these later.
        std::vector<std::string> lack_fs_list = {"ext4", "erofs"};

        // Only support early mount (first_stage_mount) partitions.
        auto pred = [&mount_point](const FstabEntry& entry) {
            return entry.fs_mgr_flags.first_stage_mount && entry.mount_point == mount_point;
        };
            entry.fs_mgr_flags.wait = true;
            entry.fs_mgr_flags.logical = true;
            entry.fs_mgr_flags.first_stage_mount = true;
            fstab->emplace_back(entry);
        } else {
            // If the corresponding partition exists, transform all its Fstab
            // by pointing .blk_device to the DSU partition.
            for (auto&& entry : entries) {

        // Transform all matching entries and assume they are all adjacent for simplicity.
        for (auto&& entry : GetEntriesByPred(fstab, pred)) {
            // .blk_device is replaced with the DSU partition.
            entry->blk_device = partition;
                // AVB keys for DSU should always be under kDsuKeysDir.
            // .avb_keys hints first_stage_mount to load the chained-vbmeta image from partition
            // footer. See aosp/932779 for more details.
            entry->avb_keys = kDsuKeysDir;
            // .logical_partition_name is required to look up AVB Hashtree descriptors.
            entry->logical_partition_name = lp_name;
            entry->fs_mgr_flags.logical = true;
            entry->fs_mgr_flags.slot_select = false;
            entry->fs_mgr_flags.slot_select_other = false;

            if (auto it = std::find(lack_fs_list.begin(), lack_fs_list.end(), entry->fs_type);
                it != lack_fs_list.end()) {
                lack_fs_list.erase(it);
            }
        }
            // 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";
                auto it = std::find_if(fstab->rbegin(), fstab->rend(),
                                       [&mount_point](const auto& entry) {
                                           return entry.mount_point == mount_point;
                                       });
                auto end_of_mount_point_group = fstab->begin() + std::distance(it, fstab->rend());
                fstab->insert(end_of_mount_point_group, new_entry);

        if (!lack_fs_list.empty()) {
            // Insert at the end of the existing mountpoint group, or at the end of fstab.
            // We assume there is at most one matching mountpoint group, which is the common case.
            auto it = std::find_if_not(std::find_if(fstab->begin(), fstab->end(), pred),
                                       fstab->end(), pred);
            for (const auto& fs_type : lack_fs_list) {
                it = std::next(fstab->insert(it, {.blk_device = partition,
                                                  .logical_partition_name = lp_name,
                                                  .mount_point = mount_point,
                                                  .fs_type = fs_type,
                                                  .flags = MS_RDONLY,
                                                  .avb_keys = kDsuKeysDir,
                                                  .fs_mgr_flags{
                                                          .wait = true,
                                                          .logical = true,
                                                          .first_stage_mount = true,
                                                  }}));
            }
        }
    }

    // Always append userdata last for stable ordering.
    if (EraseFstabEntry(fstab, "/data")) {
        fstab->emplace_back(userdata);
    }
}

void EnableMandatoryFlags(Fstab* fstab) {
+43 −2
Original line number Diff line number Diff line
@@ -1109,14 +1109,17 @@ TEST(fs_mgr, TransformFstabForDsu) {
    TemporaryFile tf;
    ASSERT_TRUE(tf.fd != -1);
    std::string fstab_contents = R"fs(
data   /data        f2fs    noatime     wait,latemount
system /system      erofs   ro  wait,logical,first_stage_mount
system /system      ext4    ro  wait,logical,first_stage_mount
vendor /vendor      ext4    ro  wait,logical,first_stage_mount
data   /data        f2fs    noatime     wait
)fs";

    ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));

    // If GSI is installed, ReadFstabFromFile() would have called TransformFstabForDsu() implicitly.
    // In other words, TransformFstabForDsu() would be called two times if running CTS-on-GSI,
    // which implies TransformFstabForDsu() should be idempotent.
    Fstab fstab;
    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
    TransformFstabForDsu(&fstab, "dsu", {"system_gsi", "userdata_gsi"});
@@ -1126,10 +1129,12 @@ data /data f2fs noatime wait

    EXPECT_EQ("/system", entry->mount_point);
    EXPECT_EQ("system_gsi", entry->blk_device);
    EXPECT_EQ("erofs", entry->fs_type);
    entry++;

    EXPECT_EQ("/system", entry->mount_point);
    EXPECT_EQ("system_gsi", entry->blk_device);
    EXPECT_EQ("ext4", entry->fs_type);
    entry++;

    EXPECT_EQ("/vendor", entry->mount_point);
@@ -1147,7 +1152,7 @@ TEST(fs_mgr, TransformFstabForDsu_synthesisExt4Entry) {
    std::string fstab_contents = R"fs(
system /system      erofs   ro  wait,logical,first_stage_mount
vendor /vendor      ext4    ro  wait,logical,first_stage_mount
data   /data        f2fs    noatime     wait
data   /data        f2fs    noatime     wait,latemount
)fs";

    ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
@@ -1177,3 +1182,39 @@ data /data f2fs noatime wait
    EXPECT_EQ("userdata_gsi", entry->blk_device);
    entry++;
}

TEST(fs_mgr, TransformFstabForDsu_synthesisAllMissingEntries) {
    TemporaryFile tf;
    ASSERT_TRUE(tf.fd != -1);
    std::string fstab_contents = R"fs(
data   /data        f2fs    noatime     wait,latemount
vendor /vendor      ext4    ro  wait,logical,first_stage_mount
)fs";

    ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));

    Fstab fstab;
    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
    TransformFstabForDsu(&fstab, "dsu", {"system_gsi", "userdata_gsi"});
    ASSERT_EQ(4U, fstab.size());

    auto entry = fstab.begin();

    EXPECT_EQ("/vendor", entry->mount_point);
    EXPECT_EQ("vendor", entry->blk_device);
    entry++;

    EXPECT_EQ("/system", entry->mount_point);
    EXPECT_EQ("system_gsi", entry->blk_device);
    EXPECT_EQ("ext4", entry->fs_type);
    entry++;

    EXPECT_EQ("/system", entry->mount_point);
    EXPECT_EQ("system_gsi", entry->blk_device);
    EXPECT_EQ("erofs", entry->fs_type);
    entry++;

    EXPECT_EQ("/data", entry->mount_point);
    EXPECT_EQ("userdata_gsi", entry->blk_device);
    entry++;
}