/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../fs_mgr_priv.h" using namespace android::fs_mgr; using namespace testing; namespace { const std::string cmdline = "rcupdate.rcu_expedited=1 rootwait ro " "init=/init androidboot.bootdevice=1d84000.ufshc " "androidboot.baseband=sdy androidboot.keymaster=1 skip_initramfs " "androidboot.serialno=BLAHBLAHBLAH androidboot.slot_suffix=_a " "androidboot.hardware.platform=sdw813 androidboot.hardware=foo " "androidboot.revision=EVT1.0 androidboot.bootloader=burp-0.1-7521 " "androidboot.hardware.sku=mary androidboot.hardware.radio.subtype=0 " "androidboot.dtbo_idx=2 androidboot.mode=normal " "androidboot.hardware.ddr=1GB,combuchi,LPDDR4X " "androidboot.ddr_info=combuchiandroidboot.ddr_size=2GB " "androidboot.hardware.ufs=2GB,combushi " "androidboot.boottime=0BLE:58,1BLL:22,1BLE:571,2BLL:105,ODT:0,AVB:123 " "androidboot.ramdump=disabled " "dm=\"1 vroot none ro 1,0 10416 verity 1 624684 fec_start 624684\" " "root=/dev/dm-0 " "androidboot.vbmeta.device=PARTUUID=aa08f1a4-c7c9-402e-9a66-9707cafa9ceb " "androidboot.vbmeta.avb_version=\"1.1\" " "androidboot.vbmeta.device_state=unlocked " "androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.size=5248 " "androidboot.vbmeta.digest=" "ac13147e959861c20f2a6da97d25fe79e60e902c022a371c5c039d31e7c68860 " "androidboot.vbmeta.invalidate_on_error=yes " "androidboot.veritymode=enforcing androidboot.verifiedbootstate=orange " "androidboot.space=\"sha256 5248 androidboot.nospace=nope\" " "printk.devkmsg=on msm_rtb.filter=0x237 ehci-hcd.park=3 " "\"string =\"\"string '\" " "service_locator.enable=1 firmware_class.path=/vendor/firmware " "cgroup.memory=nokmem lpm_levels.sleep_disabled=1 " "buildvariant=userdebug console=null " "terminator=\"truncated"; const std::vector> result_space = { {"rcupdate.rcu_expedited", "1"}, {"rootwait", ""}, {"ro", ""}, {"init", "/init"}, {"androidboot.bootdevice", "1d84000.ufshc"}, {"androidboot.baseband", "sdy"}, {"androidboot.keymaster", "1"}, {"skip_initramfs", ""}, {"androidboot.serialno", "BLAHBLAHBLAH"}, {"androidboot.slot_suffix", "_a"}, {"androidboot.hardware.platform", "sdw813"}, {"androidboot.hardware", "foo"}, {"androidboot.revision", "EVT1.0"}, {"androidboot.bootloader", "burp-0.1-7521"}, {"androidboot.hardware.sku", "mary"}, {"androidboot.hardware.radio.subtype", "0"}, {"androidboot.dtbo_idx", "2"}, {"androidboot.mode", "normal"}, {"androidboot.hardware.ddr", "1GB,combuchi,LPDDR4X"}, {"androidboot.ddr_info", "combuchiandroidboot.ddr_size=2GB"}, {"androidboot.hardware.ufs", "2GB,combushi"}, {"androidboot.boottime", "0BLE:58,1BLL:22,1BLE:571,2BLL:105,ODT:0,AVB:123"}, {"androidboot.ramdump", "disabled"}, {"dm", "1 vroot none ro 1,0 10416 verity 1 624684 fec_start 624684"}, {"root", "/dev/dm-0"}, {"androidboot.vbmeta.device", "PARTUUID=aa08f1a4-c7c9-402e-9a66-9707cafa9ceb"}, {"androidboot.vbmeta.avb_version", "1.1"}, {"androidboot.vbmeta.device_state", "unlocked"}, {"androidboot.vbmeta.hash_alg", "sha256"}, {"androidboot.vbmeta.size", "5248"}, {"androidboot.vbmeta.digest", "ac13147e959861c20f2a6da97d25fe79e60e902c022a371c5c039d31e7c68860"}, {"androidboot.vbmeta.invalidate_on_error", "yes"}, {"androidboot.veritymode", "enforcing"}, {"androidboot.verifiedbootstate", "orange"}, {"androidboot.space", "sha256 5248 androidboot.nospace=nope"}, {"printk.devkmsg", "on"}, {"msm_rtb.filter", "0x237"}, {"ehci-hcd.park", "3"}, {"string ", "string '"}, {"service_locator.enable", "1"}, {"firmware_class.path", "/vendor/firmware"}, {"cgroup.memory", "nokmem"}, {"lpm_levels.sleep_disabled", "1"}, {"buildvariant", "userdebug"}, {"console", "null"}, {"terminator", "truncated"}, }; const std::string bootconfig = R"( androidboot.bootdevice = "1d84000.ufshc" androidboot.boot_devices = "dev1", "dev2,withcomma", "dev3" androidboot.baseband = "sdy" androidboot.keymaster = "1" androidboot.serialno = "BLAHBLAHBLAH" androidboot.slot_suffix = "_a" androidboot.hardware.platform = "sdw813" androidboot.hardware = "foo" androidboot.revision = "EVT1.0" androidboot.bootloader = "burp-0.1-7521" androidboot.hardware.sku = "mary" androidboot.hardware.radio.subtype = "0" androidboot.dtbo_idx = "2" androidboot.mode = "normal" androidboot.hardware.ddr = "1GB,combuchi,LPDDR4X" androidboot.ddr_info = "combuchiandroidboot.ddr_size=2GB" androidboot.hardware.ufs = "2GB,combushi" androidboot.boottime = "0BLE:58,1BLL:22,1BLE:571,2BLL:105,ODT:0,AVB:123" androidboot.ramdump = "disabled" androidboot.vbmeta.device = "PARTUUID=aa08f1a4-c7c9-402e-9a66-9707cafa9ceb" androidboot.vbmeta.avb_version = "1.1" androidboot.vbmeta.device_state = "unlocked" androidboot.vbmeta.hash_alg = "sha256" androidboot.vbmeta.size = "5248" androidboot.vbmeta.digest = "ac13147e959861c20f2a6da97d25fe79e60e902c022a371c5c039d31e7c68860" androidboot.vbmeta.invalidate_on_error = "yes" androidboot.veritymode = "enforcing" androidboot.verifiedbootstate = "orange" androidboot.space = "sha256 5248 androidboot.nospace = nope" just.key key.empty.value = dessert.value = "ice, cream" dessert.list = "ice", "cream" ambiguous.list = ", ", ", " )"; const std::vector> bootconfig_result_space = { {"androidboot.bootdevice", "1d84000.ufshc"}, {"androidboot.boot_devices", "dev1, dev2,withcomma, dev3"}, {"androidboot.baseband", "sdy"}, {"androidboot.keymaster", "1"}, {"androidboot.serialno", "BLAHBLAHBLAH"}, {"androidboot.slot_suffix", "_a"}, {"androidboot.hardware.platform", "sdw813"}, {"androidboot.hardware", "foo"}, {"androidboot.revision", "EVT1.0"}, {"androidboot.bootloader", "burp-0.1-7521"}, {"androidboot.hardware.sku", "mary"}, {"androidboot.hardware.radio.subtype", "0"}, {"androidboot.dtbo_idx", "2"}, {"androidboot.mode", "normal"}, {"androidboot.hardware.ddr", "1GB,combuchi,LPDDR4X"}, {"androidboot.ddr_info", "combuchiandroidboot.ddr_size=2GB"}, {"androidboot.hardware.ufs", "2GB,combushi"}, {"androidboot.boottime", "0BLE:58,1BLL:22,1BLE:571,2BLL:105,ODT:0,AVB:123"}, {"androidboot.ramdump", "disabled"}, {"androidboot.vbmeta.device", "PARTUUID=aa08f1a4-c7c9-402e-9a66-9707cafa9ceb"}, {"androidboot.vbmeta.avb_version", "1.1"}, {"androidboot.vbmeta.device_state", "unlocked"}, {"androidboot.vbmeta.hash_alg", "sha256"}, {"androidboot.vbmeta.size", "5248"}, {"androidboot.vbmeta.digest", "ac13147e959861c20f2a6da97d25fe79e60e902c022a371c5c039d31e7c68860"}, {"androidboot.vbmeta.invalidate_on_error", "yes"}, {"androidboot.veritymode", "enforcing"}, {"androidboot.verifiedbootstate", "orange"}, {"androidboot.space", "sha256 5248 androidboot.nospace = nope"}, {"just.key", ""}, {"key.empty.value", ""}, {"dessert.value", "ice, cream"}, {"dessert.list", "ice,cream"}, {"ambiguous.list", ", ,, "}, }; bool CompareFlags(FstabEntry::FsMgrFlags& lhs, FstabEntry::FsMgrFlags& rhs) { // clang-format off return lhs.wait == rhs.wait && lhs.check == rhs.check && lhs.crypt == rhs.crypt && lhs.nonremovable == rhs.nonremovable && lhs.vold_managed == rhs.vold_managed && lhs.recovery_only == rhs.recovery_only && lhs.no_emulated_sd == rhs.no_emulated_sd && lhs.no_trim == rhs.no_trim && lhs.file_encryption == rhs.file_encryption && lhs.formattable == rhs.formattable && lhs.slot_select == rhs.slot_select && lhs.late_mount == rhs.late_mount && lhs.no_fail == rhs.no_fail && lhs.quota == rhs.quota && lhs.avb == rhs.avb && lhs.logical == rhs.logical && lhs.checkpoint_blk == rhs.checkpoint_blk && lhs.checkpoint_fs == rhs.checkpoint_fs && lhs.first_stage_mount == rhs.first_stage_mount && lhs.slot_select_other == rhs.slot_select_other && lhs.fs_verity == rhs.fs_verity; // clang-format on } } // namespace TEST(fs_mgr, ImportKernelCmdline) { std::vector> result; ImportKernelCmdlineFromString( cmdline, [&](std::string key, std::string value) { result.emplace_back(key, value); }); EXPECT_THAT(result, ContainerEq(result_space)); } TEST(fs_mgr, GetKernelCmdline) { std::string content; for (const auto& [key, value] : result_space) { EXPECT_TRUE(GetKernelCmdlineFromString(cmdline, key, &content)) << " for " << key; EXPECT_EQ(content, value); } const std::string kUnmodifiedToken = ""; content = kUnmodifiedToken; EXPECT_FALSE(GetKernelCmdlineFromString(cmdline, "", &content)); EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden"; content = kUnmodifiedToken; EXPECT_FALSE(GetKernelCmdlineFromString(cmdline, "androidboot.vbmeta.avb_versio", &content)); EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden"; content = kUnmodifiedToken; EXPECT_FALSE(GetKernelCmdlineFromString(bootconfig, "androidboot.nospace", &content)); EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden"; } TEST(fs_mgr, ImportBootconfig) { std::vector> result; ImportBootconfigFromString(bootconfig, [&](std::string key, std::string value) { result.emplace_back(key, value); }); EXPECT_THAT(result, ContainerEq(bootconfig_result_space)); } TEST(fs_mgr, GetBootconfig) { std::string content; for (const auto& [key, value] : bootconfig_result_space) { EXPECT_TRUE(GetBootconfigFromString(bootconfig, key, &content)) << " for " << key; EXPECT_EQ(content, value); } const std::string kUnmodifiedToken = ""; content = kUnmodifiedToken; EXPECT_FALSE(GetBootconfigFromString(bootconfig, "", &content)); EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden"; content = kUnmodifiedToken; EXPECT_FALSE(GetBootconfigFromString(bootconfig, "androidboot.vbmeta.avb_versio", &content)); EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden"; content = kUnmodifiedToken; EXPECT_FALSE(GetBootconfigFromString(bootconfig, "androidboot.nospace", &content)); EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden"; } TEST(fs_mgr, fs_mgr_read_fstab_file_proc_mounts) { Fstab fstab; ASSERT_TRUE(ReadFstabFromFile("/proc/mounts", &fstab)); std::unique_ptr mounts(setmntent("/proc/mounts", "re"), endmntent); ASSERT_NE(mounts, nullptr); mntent* mentry; size_t i = 0; while ((mentry = getmntent(mounts.get())) != nullptr) { ASSERT_LT(i, fstab.size()); auto& entry = fstab[i]; EXPECT_EQ(mentry->mnt_fsname, entry.blk_device); EXPECT_EQ(mentry->mnt_dir, entry.mount_point); EXPECT_EQ(mentry->mnt_type, entry.fs_type); std::set mnt_opts; for (auto& s : android::base::Split(mentry->mnt_opts, ",")) { mnt_opts.emplace(s); } std::set fs_options; if (!entry.fs_options.empty()) { for (auto& s : android::base::Split(entry.fs_options, ",")) { fs_options.emplace(s); } } // matches private content in fs_mgr_fstab.c static struct flag_list { const char* name; unsigned int flag; } mount_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}, {0, 0}, }; for (auto f = 0; mount_flags[f].name; ++f) { if (mount_flags[f].flag & entry.flags) { fs_options.emplace(mount_flags[f].name); } } if (!(entry.flags & MS_RDONLY)) { fs_options.emplace("rw"); } EXPECT_EQ(mnt_opts, fs_options) << "At line " << i; ++i; } EXPECT_EQ(i, fstab.size()); } TEST(fs_mgr, ReadFstabFromFile_MountOptions) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source / ext4 ro,barrier=1 wait,avb source /metadata ext4 noatime,nosuid,nodev,discard wait,formattable source /data f2fs noatime,nosuid,nodev,discard,reserve_root=32768,resgid=1065,fsync_mode=nobarrier latemount,wait,check,fileencryption=ice,keydirectory=/metadata/vold/metadata_encryption,quota,formattable,sysfs_path=/sys/devices/platform/soc/1d84000.ufshc,reservedsize=128M source /misc emmc defaults defaults source /vendor/firmware_mnt vfat ro,shortname=lower,uid=1000,gid=1000,dmask=227,fmask=337,context=u:object_r:firmware_file:s0 wait source auto vfat defaults voldmanaged=usb:auto source none swap defaults zramsize=1073741824,max_comp_streams=8 source none2 swap nodiratime,remount,bind zramsize=1073741824,max_comp_streams=8 source none3 swap unbindable,private,slave zramsize=1073741824,max_comp_streams=8 source none4 swap noexec,shared,rec zramsize=1073741824,max_comp_streams=8 source none5 swap rw zramsize=1073741824,max_comp_streams=8 )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(11U, fstab.size()); FstabEntry* entry = GetEntryForMountPoint(&fstab, "/"); ASSERT_NE(nullptr, entry); EXPECT_EQ(static_cast(MS_RDONLY), entry->flags); EXPECT_EQ("barrier=1", entry->fs_options); entry = GetEntryForMountPoint(&fstab, "/metadata"); ASSERT_NE(nullptr, entry); EXPECT_EQ(static_cast(MS_NOATIME | MS_NOSUID | MS_NODEV), entry->flags); EXPECT_EQ("discard", entry->fs_options); entry = GetEntryForMountPoint(&fstab, "/data"); ASSERT_NE(nullptr, entry); EXPECT_EQ(static_cast(MS_NOATIME | MS_NOSUID | MS_NODEV), entry->flags); EXPECT_EQ("discard,reserve_root=32768,resgid=1065,fsync_mode=nobarrier", entry->fs_options); entry = GetEntryForMountPoint(&fstab, "/misc"); ASSERT_NE(nullptr, entry); EXPECT_EQ(0U, entry->flags); EXPECT_EQ("", entry->fs_options); entry = GetEntryForMountPoint(&fstab, "/vendor/firmware_mnt"); ASSERT_NE(nullptr, entry); EXPECT_EQ(static_cast(MS_RDONLY), entry->flags); EXPECT_EQ( "shortname=lower,uid=1000,gid=1000,dmask=227,fmask=337," "context=u:object_r:firmware_file:s0", entry->fs_options); entry = GetEntryForMountPoint(&fstab, "auto"); ASSERT_NE(nullptr, entry); EXPECT_EQ(0U, entry->flags); EXPECT_EQ("", entry->fs_options); entry = GetEntryForMountPoint(&fstab, "none"); ASSERT_NE(nullptr, entry); EXPECT_EQ(0U, entry->flags); EXPECT_EQ("", entry->fs_options); entry = GetEntryForMountPoint(&fstab, "none2"); ASSERT_NE(nullptr, entry); EXPECT_EQ(static_cast(MS_NODIRATIME | MS_REMOUNT | MS_BIND), entry->flags); EXPECT_EQ("", entry->fs_options); entry = GetEntryForMountPoint(&fstab, "none3"); ASSERT_NE(nullptr, entry); EXPECT_EQ(static_cast(MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE), entry->flags); EXPECT_EQ("", entry->fs_options); entry = GetEntryForMountPoint(&fstab, "none4"); ASSERT_NE(nullptr, entry); EXPECT_EQ(static_cast(MS_NOEXEC | MS_SHARED | MS_REC), entry->flags); EXPECT_EQ("", entry->fs_options); entry = GetEntryForMountPoint(&fstab, "none5"); ASSERT_NE(nullptr, entry); // rw is the default. EXPECT_EQ(0U, entry->flags); EXPECT_EQ("", entry->fs_options); } TEST(fs_mgr, ReadFstabFromFile_FsMgrFlags) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults wait,check,nonremovable,recoveryonly source none1 swap defaults avb,noemulatedsd,notrim,formattable,nofail source none2 swap defaults first_stage_mount,latemount,quota,logical source none3 swap defaults checkpoint=block source none4 swap defaults checkpoint=fs source none5 swap defaults defaults )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(6U, fstab.size()); FstabEntry* entry = GetEntryForMountPoint(&fstab, "none0"); ASSERT_NE(nullptr, entry); { FstabEntry::FsMgrFlags flags = {}; flags.wait = true; flags.check = true; flags.nonremovable = true; flags.recovery_only = true; EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); } entry = GetEntryForMountPoint(&fstab, "none1"); ASSERT_NE(nullptr, entry); { FstabEntry::FsMgrFlags flags = {}; flags.avb = true; flags.no_emulated_sd = true; flags.no_trim = true; flags.formattable = true; flags.no_fail = true; EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); } entry = GetEntryForMountPoint(&fstab, "none2"); ASSERT_NE(nullptr, entry); { FstabEntry::FsMgrFlags flags = {}; flags.first_stage_mount = true; flags.late_mount = true; flags.quota = true; flags.logical = true; EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); } entry = GetEntryForMountPoint(&fstab, "none3"); ASSERT_NE(nullptr, entry); { FstabEntry::FsMgrFlags flags = {}; flags.checkpoint_blk = true; EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); } entry = GetEntryForMountPoint(&fstab, "none4"); ASSERT_NE(nullptr, entry); { FstabEntry::FsMgrFlags flags = {}; flags.checkpoint_fs = true; EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); } entry = GetEntryForMountPoint(&fstab, "none5"); ASSERT_NE(nullptr, entry); { FstabEntry::FsMgrFlags flags = {}; EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); } } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_AllBad) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults fileencryption,keydirectory,length,swapprio,zramsize,max_comp_streams,reservedsize,eraseblk,logicalblk,sysfs_path,zram_backingdev_size source none1 swap defaults fileencryption=,keydirectory=,length=,swapprio=,zramsize=,max_comp_streams=,avb=,reservedsize=,eraseblk=,logicalblk=,sysfs_path=,zram_backingdev_size= )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(2U, fstab.size()); auto entry = fstab.begin(); EXPECT_EQ("none0", entry->mount_point); { FstabEntry::FsMgrFlags flags = {}; flags.file_encryption = true; EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); } EXPECT_EQ("", entry->metadata_key_dir); EXPECT_EQ(0, entry->length); EXPECT_EQ("", entry->label); EXPECT_EQ(-1, entry->partnum); EXPECT_EQ(-1, entry->swap_prio); EXPECT_EQ(0, entry->max_comp_streams); EXPECT_EQ(0, entry->zram_size); EXPECT_EQ(0, entry->reserved_size); EXPECT_EQ("", entry->encryption_options); EXPECT_EQ(0, entry->erase_blk_size); EXPECT_EQ(0, entry->logical_blk_size); EXPECT_EQ("", entry->sysfs_path); EXPECT_EQ(0U, entry->zram_backingdev_size); entry++; EXPECT_EQ("none1", entry->mount_point); { FstabEntry::FsMgrFlags flags = {}; flags.file_encryption = true; flags.avb = true; EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); } EXPECT_EQ("", entry->metadata_key_dir); EXPECT_EQ(0, entry->length); EXPECT_EQ("", entry->label); EXPECT_EQ(-1, entry->partnum); EXPECT_EQ(-1, entry->swap_prio); EXPECT_EQ(0, entry->max_comp_streams); EXPECT_EQ(0, entry->zram_size); EXPECT_EQ(0, entry->reserved_size); EXPECT_EQ("", entry->encryption_options); EXPECT_EQ(0, entry->erase_blk_size); EXPECT_EQ(0, entry->logical_blk_size); EXPECT_EQ("", entry->sysfs_path); EXPECT_EQ(0U, entry->zram_backingdev_size); } // FDE is no longer supported, so an fstab with FDE enabled should be rejected. TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_FDE) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source /data ext4 noatime forceencrypt=footer )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_FALSE(ReadFstabFromFile(tf.path, &fstab)); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_AdoptableStorage) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults encryptable=userdata,voldmanaged=sdcard:auto )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(1U, fstab.size()); FstabEntry::FsMgrFlags flags = {}; flags.crypt = true; flags.vold_managed = true; auto entry = fstab.begin(); EXPECT_EQ("none0", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_VoldManaged) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults voldmanaged=: source none1 swap defaults voldmanaged=sdcard source none2 swap defaults voldmanaged=sdcard:3 source none3 swap defaults voldmanaged=sdcard:auto )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(4U, fstab.size()); FstabEntry::FsMgrFlags flags = {}; flags.vold_managed = true; auto entry = fstab.begin(); EXPECT_EQ("none0", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_TRUE(entry->label.empty()); EXPECT_EQ(-1, entry->partnum); entry++; EXPECT_EQ("none1", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_TRUE(entry->label.empty()); EXPECT_EQ(-1, entry->partnum); entry++; EXPECT_EQ("none2", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("sdcard", entry->label); EXPECT_EQ(3, entry->partnum); entry++; EXPECT_EQ("none3", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("sdcard", entry->label); EXPECT_EQ(-1, entry->partnum); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Length) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults length=blah source none1 swap defaults length=123456 )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(2U, fstab.size()); FstabEntry::FsMgrFlags flags = {}; auto entry = fstab.begin(); EXPECT_EQ("none0", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(0, entry->length); entry++; EXPECT_EQ("none1", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(123456, entry->length); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Swapprio) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults swapprio=blah source none1 swap defaults swapprio=123456 )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(2U, fstab.size()); FstabEntry::FsMgrFlags flags = {}; auto entry = fstab.begin(); EXPECT_EQ("none0", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(-1, entry->swap_prio); entry++; EXPECT_EQ("none1", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(123456, entry->swap_prio); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_ZramSize) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults zramsize=blah source none1 swap defaults zramsize=123456 source none2 swap defaults zramsize=blah% source none3 swap defaults zramsize=5% source none4 swap defaults zramsize=105% source none5 swap defaults zramsize=% )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(6U, fstab.size()); FstabEntry::FsMgrFlags flags = {}; auto entry = fstab.begin(); EXPECT_EQ("none0", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(0, entry->zram_size); entry++; EXPECT_EQ("none1", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(123456, entry->zram_size); entry++; EXPECT_EQ("none2", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(0, entry->zram_size); entry++; EXPECT_EQ("none3", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_NE(0, entry->zram_size); entry++; EXPECT_EQ("none4", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(0, entry->zram_size); entry++; EXPECT_EQ("none5", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(0, entry->zram_size); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_FileEncryption) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults fileencryption=aes-256-xts:aes-256-cts:v1 )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(1U, fstab.size()); FstabEntry::FsMgrFlags flags = {}; flags.file_encryption = true; auto entry = fstab.begin(); EXPECT_EQ("none0", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("aes-256-xts:aes-256-cts:v1", entry->encryption_options); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_MaxCompStreams) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults max_comp_streams=blah source none1 swap defaults max_comp_streams=123456 )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(2U, fstab.size()); FstabEntry::FsMgrFlags flags = {}; auto entry = fstab.begin(); EXPECT_EQ("none0", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(0, entry->max_comp_streams); entry++; EXPECT_EQ("none1", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(123456, entry->max_comp_streams); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_ReservedSize) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults reservedsize=blah source none1 swap defaults reservedsize=2 source none2 swap defaults reservedsize=1K source none3 swap defaults reservedsize=2m )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(4U, fstab.size()); FstabEntry::FsMgrFlags flags = {}; auto entry = fstab.begin(); EXPECT_EQ("none0", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(0, entry->reserved_size); entry++; EXPECT_EQ("none1", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(2, entry->reserved_size); entry++; EXPECT_EQ("none2", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(1024, entry->reserved_size); entry++; EXPECT_EQ("none3", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(2 * 1024 * 1024, entry->reserved_size); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_EraseBlk) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults eraseblk=blah source none1 swap defaults eraseblk=4000 source none2 swap defaults eraseblk=5000 source none3 swap defaults eraseblk=8192 )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(4U, fstab.size()); FstabEntry::FsMgrFlags flags = {}; auto entry = fstab.begin(); EXPECT_EQ("none0", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(0, entry->erase_blk_size); entry++; EXPECT_EQ("none1", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(0, entry->erase_blk_size); entry++; EXPECT_EQ("none2", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(0, entry->erase_blk_size); entry++; EXPECT_EQ("none3", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(8192, entry->erase_blk_size); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Logicalblk) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults logicalblk=blah source none1 swap defaults logicalblk=4000 source none2 swap defaults logicalblk=5000 source none3 swap defaults logicalblk=8192 )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(4U, fstab.size()); FstabEntry::FsMgrFlags flags = {}; auto entry = fstab.begin(); EXPECT_EQ("none0", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(0, entry->logical_blk_size); entry++; EXPECT_EQ("none1", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(0, entry->logical_blk_size); entry++; EXPECT_EQ("none2", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(0, entry->logical_blk_size); entry++; EXPECT_EQ("none3", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(8192, entry->logical_blk_size); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Avb) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults avb=vbmeta_partition source none1 swap defaults avb_keys=/path/to/test.avbpubkey )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(2U, fstab.size()); auto entry = fstab.begin(); EXPECT_EQ("none0", entry->mount_point); FstabEntry::FsMgrFlags flags = {}; flags.avb = true; EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("vbmeta_partition", entry->vbmeta_partition); entry++; EXPECT_EQ("none1", entry->mount_point); FstabEntry::FsMgrFlags empty_flags = {}; // no flags should be set for avb_keys. EXPECT_TRUE(CompareFlags(empty_flags, entry->fs_mgr_flags)); EXPECT_EQ("/path/to/test.avbpubkey", entry->avb_keys); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_KeyDirectory) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults keydirectory=/dir/key )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(1U, fstab.size()); auto entry = fstab.begin(); EXPECT_EQ("none0", entry->mount_point); FstabEntry::FsMgrFlags flags = {}; EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("/dir/key", entry->metadata_key_dir); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_MetadataEncryption) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults keydirectory=/dir/key,metadata_encryption=adiantum )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(1U, fstab.size()); auto entry = fstab.begin(); EXPECT_EQ("adiantum", entry->metadata_encryption_options); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_MetadataEncryption_WrappedKey) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults keydirectory=/dir/key,metadata_encryption=aes-256-xts:wrappedkey_v0 )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(1U, fstab.size()); auto entry = fstab.begin(); EXPECT_EQ("aes-256-xts:wrappedkey_v0", entry->metadata_encryption_options); auto parts = android::base::Split(entry->metadata_encryption_options, ":"); EXPECT_EQ(2U, parts.size()); EXPECT_EQ("aes-256-xts", parts[0]); EXPECT_EQ("wrappedkey_v0", parts[1]); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_SysfsPath) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults sysfs_path=/sys/device )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(1U, fstab.size()); auto entry = fstab.begin(); EXPECT_EQ("none0", entry->mount_point); FstabEntry::FsMgrFlags flags = {}; EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ("/sys/device", entry->sysfs_path); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Zram) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none1 swap defaults zram_backingdev_size=blah source none2 swap defaults zram_backingdev_size=2 source none3 swap defaults zram_backingdev_size=1K source none4 swap defaults zram_backingdev_size=2m )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(4U, fstab.size()); auto entry = fstab.begin(); EXPECT_EQ("none1", entry->mount_point); EXPECT_EQ(0U, entry->zram_backingdev_size); entry++; EXPECT_EQ("none2", entry->mount_point); EXPECT_EQ(2U, entry->zram_backingdev_size); entry++; EXPECT_EQ("none3", entry->mount_point); EXPECT_EQ(1024U, entry->zram_backingdev_size); entry++; EXPECT_EQ("none4", entry->mount_point); EXPECT_EQ(2U * 1024U * 1024U, entry->zram_backingdev_size); entry++; } TEST(fs_mgr, DefaultFstabContainsUserdata) { Fstab fstab; ASSERT_TRUE(ReadDefaultFstab(&fstab)) << "Failed to read default fstab"; ASSERT_NE(nullptr, GetEntryForMountPoint(&fstab, "/data")) << "Default fstab doesn't contain /data entry"; } TEST(fs_mgr, UserdataMountedFromDefaultFstab) { if (getuid() != 0) { GTEST_SKIP() << "Must be run as root."; return; } Fstab fstab; ASSERT_TRUE(ReadDefaultFstab(&fstab)) << "Failed to read default fstab"; Fstab proc_mounts; ASSERT_TRUE(ReadFstabFromFile("/proc/mounts", &proc_mounts)) << "Failed to read /proc/mounts"; auto mounted_entry = GetEntryForMountPoint(&proc_mounts, "/data"); ASSERT_NE(mounted_entry, nullptr) << "/data is not mounted"; std::string block_device; ASSERT_TRUE(android::base::Realpath(mounted_entry->blk_device, &block_device)); ASSERT_NE(nullptr, fs_mgr_get_mounted_entry_for_userdata(&fstab, block_device)) << "/data wasn't mounted from default fstab"; } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Readahead_Size_KB) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); std::string fstab_contents = R"fs( source none0 swap defaults readahead_size_kb=blah source none1 swap defaults readahead_size_kb=128 source none2 swap defaults readahead_size_kb=5% source none3 swap defaults readahead_size_kb=5kb source none4 swap defaults readahead_size_kb=16385 source none5 swap defaults readahead_size_kb=-128 source none6 swap defaults readahead_size_kb=0 )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); Fstab fstab; EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab)); ASSERT_LE(7U, fstab.size()); FstabEntry::FsMgrFlags flags = {}; auto entry = fstab.begin(); EXPECT_EQ("none0", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(-1, entry->readahead_size_kb); entry++; EXPECT_EQ("none1", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(128, entry->readahead_size_kb); entry++; EXPECT_EQ("none2", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(-1, entry->readahead_size_kb); entry++; EXPECT_EQ("none3", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(-1, entry->readahead_size_kb); entry++; EXPECT_EQ("none4", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(-1, entry->readahead_size_kb); entry++; EXPECT_EQ("none5", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(-1, entry->readahead_size_kb); entry++; EXPECT_EQ("none6", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(0, entry->readahead_size_kb); } 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 )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"}); ASSERT_EQ(4U, fstab.size()); auto entry = fstab.begin(); EXPECT_EQ("/data", entry->mount_point); EXPECT_EQ("userdata_gsi", entry->blk_device); entry++; 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); EXPECT_EQ("vendor", entry->blk_device); entry++; } TEST(fs_mgr, TransformFstabForDsu_synthesisExt4Entry) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); 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,latemount )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("/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); EXPECT_EQ("vendor", entry->blk_device); entry++; EXPECT_EQ("/data", entry->mount_point); 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("/data", entry->mount_point); EXPECT_EQ("userdata_gsi", entry->blk_device); entry++; 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++; }