From adb91b0e5979148b4c141b7e966e375615fce62d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 12 Dec 2023 11:25:40 -0800 Subject: [PATCH] remount: Detect when flashall has happened in the bootloader. This adds a new metadata header flag to the super partition. This flag is set when "adb remount" is used, and is implicitly cleared when flashing. If there is a scratch partition present on /data, we require that the flag be set in order to proceed using overlays. If not set, scratch is not mapped in first-stage init, and scratch images are removed later during startup. Bug: 297923468 Test: adb remount -R, touch file in out/, sync, flashall Change-Id: I9cc411a1632101b5fc043193b38db8ffb9c20e7f --- fastboot/fastboot.cpp | 2 +- fastboot/task.cpp | 4 +- fastboot/task.h | 2 +- fastboot/task_test.cpp | 6 +-- fs_mgr/fs_mgr_overlayfs_control.cpp | 46 ++++++++++++++++++++ fs_mgr/liblp/builder.cpp | 9 ++++ fs_mgr/liblp/include/liblp/builder.h | 2 + fs_mgr/liblp/include/liblp/metadata_format.h | 3 ++ 8 files changed, 67 insertions(+), 7 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 1bc7b7513..235d7234f 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1675,7 +1675,7 @@ bool AddResizeTasks(const FlashingPlan* fp, std::vector>* } for (size_t i = 0; i < tasks->size(); i++) { if (auto flash_task = tasks->at(i)->AsFlashTask()) { - if (FlashTask::IsDynamicParitition(fp->source.get(), flash_task)) { + if (FlashTask::IsDynamicPartition(fp->source.get(), flash_task)) { if (!loc) { loc = i; } diff --git a/fastboot/task.cpp b/fastboot/task.cpp index 0947ff90f..ea78a01b5 100644 --- a/fastboot/task.cpp +++ b/fastboot/task.cpp @@ -30,7 +30,7 @@ FlashTask::FlashTask(const std::string& slot, const std::string& pname, const st const bool apply_vbmeta, const FlashingPlan* fp) : pname_(pname), fname_(fname), slot_(slot), apply_vbmeta_(apply_vbmeta), fp_(fp) {} -bool FlashTask::IsDynamicParitition(const ImageSource* source, const FlashTask* task) { +bool FlashTask::IsDynamicPartition(const ImageSource* source, const FlashTask* task) { std::vector contents; if (!source->ReadFile("super_empty.img", &contents)) { return false; @@ -152,7 +152,7 @@ bool OptimizedFlashSuperTask::CanOptimize(const ImageSource* source, continue; } auto flash_task = tasks[i + 2]->AsFlashTask(); - if (!FlashTask::IsDynamicParitition(source, flash_task)) { + if (!FlashTask::IsDynamicPartition(source, flash_task)) { continue; } return true; diff --git a/fastboot/task.h b/fastboot/task.h index a98c87419..7a713cf2b 100644 --- a/fastboot/task.h +++ b/fastboot/task.h @@ -52,7 +52,7 @@ class FlashTask : public Task { const bool apply_vbmeta, const FlashingPlan* fp); virtual FlashTask* AsFlashTask() override { return this; } - static bool IsDynamicParitition(const ImageSource* source, const FlashTask* task); + static bool IsDynamicPartition(const ImageSource* source, const FlashTask* task); void Run() override; std::string ToString() const override; std::string GetPartition() const { return pname_; } diff --git a/fastboot/task_test.cpp b/fastboot/task_test.cpp index 81154c68e..519d4edd9 100644 --- a/fastboot/task_test.cpp +++ b/fastboot/task_test.cpp @@ -233,7 +233,7 @@ TEST_F(ParseTest, CorrectTaskLists) { << "size of fastboot-info task list: " << fastboot_info_tasks.size() << " size of hardcoded task list: " << hardcoded_tasks.size(); } -TEST_F(ParseTest, IsDynamicParitiontest) { +TEST_F(ParseTest, IsDynamicPartitiontest) { if (!get_android_product_out()) { GTEST_SKIP(); } @@ -258,7 +258,7 @@ TEST_F(ParseTest, IsDynamicParitiontest) { ParseFastbootInfoLine(fp.get(), android::base::Tokenize(test.first, " ")); auto flash_task = task->AsFlashTask(); ASSERT_FALSE(flash_task == nullptr); - ASSERT_EQ(FlashTask::IsDynamicParitition(fp->source.get(), flash_task), test.second); + ASSERT_EQ(FlashTask::IsDynamicPartition(fp->source.get(), flash_task), test.second); } } @@ -358,7 +358,7 @@ TEST_F(ParseTest, OptimizedFlashSuperPatternMatchTest) { contains_optimized_task = true; } if (auto flash_task = task->AsFlashTask()) { - if (FlashTask::IsDynamicParitition(fp->source.get(), flash_task)) { + if (FlashTask::IsDynamicPartition(fp->source.get(), flash_task)) { return false; } } diff --git a/fs_mgr/fs_mgr_overlayfs_control.cpp b/fs_mgr/fs_mgr_overlayfs_control.cpp index 06214ef25..08ad80caa 100644 --- a/fs_mgr/fs_mgr_overlayfs_control.cpp +++ b/fs_mgr/fs_mgr_overlayfs_control.cpp @@ -219,6 +219,35 @@ OverlayfsTeardownResult TeardownDataScratch(IImageManager* images, return OverlayfsTeardownResult::Ok; } +bool GetOverlaysActiveFlag() { + auto slot_number = fs_mgr_overlayfs_slot_number(); + const auto super_device = kPhysicalDevice + fs_mgr_get_super_partition_name(); + + auto metadata = ReadMetadata(super_device, slot_number); + if (!metadata) { + return false; + } + return !!(metadata->header.flags & LP_HEADER_FLAG_OVERLAYS_ACTIVE); +} + +bool SetOverlaysActiveFlag(bool flag) { + // Mark overlays as active in the partition table, to detect re-flash. + auto slot_number = fs_mgr_overlayfs_slot_number(); + const auto super_device = kPhysicalDevice + fs_mgr_get_super_partition_name(); + auto builder = MetadataBuilder::New(super_device, slot_number); + if (!builder) { + LERROR << "open " << super_device << " metadata"; + return false; + } + builder->SetOverlaysActiveFlag(flag); + auto metadata = builder->Export(); + if (!metadata || !UpdatePartitionTable(super_device, *metadata.get(), slot_number)) { + LERROR << "update super metadata"; + return false; + } + return true; +} + OverlayfsTeardownResult fs_mgr_overlayfs_teardown_scratch(const std::string& overlay, bool* change) { // umount and delete kScratchMountPoint storage if we have logical partitions @@ -232,6 +261,10 @@ OverlayfsTeardownResult fs_mgr_overlayfs_teardown_scratch(const std::string& ove return OverlayfsTeardownResult::Error; } + // Note: we don't care if SetOverlaysActiveFlag fails, since + // the overlays are removed no matter what. + SetOverlaysActiveFlag(false); + bool was_mounted = fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false); if (was_mounted) { fs_mgr_overlayfs_umount_scratch(); @@ -448,6 +481,7 @@ static bool CreateDynamicScratch(std::string* scratch_device, bool* partition_ex } } } + // land the update back on to the partition if (changed) { auto metadata = builder->Export(); @@ -592,6 +626,12 @@ bool fs_mgr_overlayfs_setup_scratch(const Fstab& fstab) { return false; } + if (!SetOverlaysActiveFlag(true)) { + LOG(ERROR) << "Failed to update dynamic partition data"; + fs_mgr_overlayfs_teardown_scratch(kScratchMountPoint, nullptr); + return false; + } + // If the partition exists, assume first that it can be mounted. if (partition_exists) { if (MountScratch(scratch_device)) { @@ -856,6 +896,9 @@ void MapScratchPartitionIfNeeded(Fstab* fstab, return; } + if (!GetOverlaysActiveFlag()) { + return; + } if (ScratchIsOnData()) { if (auto images = IImageManager::Open("remount", 0ms)) { images->MapAllImages(init); @@ -879,6 +922,9 @@ void CleanupOldScratchFiles() { } if (auto images = IImageManager::Open("remount", 0ms)) { images->RemoveDisabledImages(); + if (!GetOverlaysActiveFlag()) { + fs_mgr_overlayfs_teardown_scratch(kScratchMountPoint, nullptr); + } } } diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp index 6cb2c5172..4e6e97b67 100644 --- a/fs_mgr/liblp/builder.cpp +++ b/fs_mgr/liblp/builder.cpp @@ -1211,6 +1211,15 @@ void MetadataBuilder::SetVirtualABDeviceFlag() { header_.flags |= LP_HEADER_FLAG_VIRTUAL_AB_DEVICE; } +void MetadataBuilder::SetOverlaysActiveFlag(bool flag) { + RequireExpandedMetadataHeader(); + if (flag) { + header_.flags |= LP_HEADER_FLAG_OVERLAYS_ACTIVE; + } else { + header_.flags &= ~LP_HEADER_FLAG_OVERLAYS_ACTIVE; + } +} + bool MetadataBuilder::IsABDevice() { return !IPropertyFetcher::GetInstance()->GetProperty("ro.boot.slot_suffix", "").empty(); } diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h index 54f31bc36..957b96b09 100644 --- a/fs_mgr/liblp/include/liblp/builder.h +++ b/fs_mgr/liblp/include/liblp/builder.h @@ -346,6 +346,8 @@ class MetadataBuilder { void SetAutoSlotSuffixing(); // Set the LP_HEADER_FLAG_VIRTUAL_AB_DEVICE flag. void SetVirtualABDeviceFlag(); + // Set or unset the LP_HEADER_FLAG_OVERLAYS_ACTIVE flag. + void SetOverlaysActiveFlag(bool flag); bool GetBlockDeviceInfo(const std::string& partition_name, BlockDeviceInfo* info) const; bool UpdateBlockDeviceInfo(const std::string& partition_name, const BlockDeviceInfo& info); diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h index 41d8b0cd5..8d77097ed 100644 --- a/fs_mgr/liblp/include/liblp/metadata_format.h +++ b/fs_mgr/liblp/include/liblp/metadata_format.h @@ -240,6 +240,9 @@ typedef struct LpMetadataHeader { */ #define LP_HEADER_FLAG_VIRTUAL_AB_DEVICE 0x1 +/* This device has overlays activated via "adb remount". */ +#define LP_HEADER_FLAG_OVERLAYS_ACTIVE 0x2 + /* This struct defines a logical partition entry, similar to what would be * present in a GUID Partition Table. */