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
This commit is contained in:
David Anderson 2023-12-12 11:25:40 -08:00
parent e2c6171f65
commit adb91b0e59
8 changed files with 67 additions and 7 deletions

View file

@ -1675,7 +1675,7 @@ bool AddResizeTasks(const FlashingPlan* fp, std::vector<std::unique_ptr<Task>>*
}
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;
}

View file

@ -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<char> 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;

View file

@ -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_; }

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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();
}

View file

@ -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);

View file

@ -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.
*/