From 99995cddb36738da2c6f4a89f140d4f2f5fde501 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Wed, 1 Jul 2020 12:32:46 -0700 Subject: [PATCH] liblp: Force 10.0 metadata on downgrade to Q. Q liblp only supports 10.0 super partition metadata, so forcefully downgrade the current metadata version too. On retrofit Virtual A/B devices, the metadata version is at most 10.1, because the new VIRTUAL_AB flag is not set on retrofit devices. In version 10.1, two per-partition flags: UPDATED and DISABLED are introduced. - The updated flag is set when the device undergoes a Virtual A/B update before. Clear it. - The disabled flag should only be set on metadata files used by libfiemap ImageManager. It shouldn't be used on super partition metadata. Hence, this CL should only clear UPDATED flag. Test: R->R->Q OTA Bug: 159590481 Change-Id: I8b548c8ce36a75197e7172a77f9207fd44fe4670 Former-commit-id: ba5dfd76ded0502660e4cf695a4c249516adecdf --- fs_mgr/liblp/builder.cpp | 17 ++++++++---- fs_mgr/liblp/include/liblp/builder.h | 6 +++-- fs_mgr/liblp/utility.cpp | 39 ++++++++++++++++++++++++++++ fs_mgr/liblp/utility.h | 4 +++ 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp index 2f516fa9b..5554f7794 100644 --- a/fs_mgr/liblp/builder.cpp +++ b/fs_mgr/liblp/builder.cpp @@ -204,11 +204,18 @@ std::unique_ptr MetadataBuilder::NewForUpdate(const IPartitionO } } - if (IPropertyFetcher::GetInstance()->GetBoolProperty("ro.virtual_ab.enabled", false) && - !always_keep_source_slot) { - if (!UpdateMetadataForInPlaceSnapshot(metadata.get(), source_slot_number, - target_slot_number)) { - return nullptr; + if (IPropertyFetcher::GetInstance()->GetBoolProperty("ro.virtual_ab.enabled", false)) { + if (always_keep_source_slot) { + // always_keep_source_slot implies the target build does not support snapshots. + // Clear unsupported attributes. + SetMetadataHeaderV0(metadata.get()); + } else { + // !always_keep_source_slot implies the target build supports snapshots. Do snapshot + // updates. + if (!UpdateMetadataForInPlaceSnapshot(metadata.get(), source_slot_number, + target_slot_number)) { + return nullptr; + } } } diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h index bd3915061..6c7a70728 100644 --- a/fs_mgr/liblp/include/liblp/builder.h +++ b/fs_mgr/liblp/include/liblp/builder.h @@ -209,8 +209,10 @@ class MetadataBuilder { // metadata may not have the target slot's devices listed yet, in which // case, it is automatically upgraded to include all available block // devices. - // If |always_keep_source_slot| is set, on a Virtual A/B device, source slot - // partitions are kept. This is useful when applying a downgrade package. + // If |always_keep_source_slot| is set, on a Virtual A/B device + // - source slot partitions are kept. + // - UPDATED flag is cleared. + // This is useful when applying a downgrade package. static std::unique_ptr NewForUpdate(const IPartitionOpener& opener, const std::string& source_partition, uint32_t source_slot_number, diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp index 48c5c8318..d8e171b10 100644 --- a/fs_mgr/liblp/utility.cpp +++ b/fs_mgr/liblp/utility.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -29,6 +30,7 @@ #include #include +#include #include #include @@ -285,5 +287,42 @@ bool UpdateMetadataForInPlaceSnapshot(LpMetadata* metadata, uint32_t source_slot return true; } +inline std::string ToHexString(uint64_t value) { + return android::base::StringPrintf("0x%" PRIx64, value); +} + +void SetMetadataHeaderV0(LpMetadata* metadata) { + if (metadata->header.minor_version <= LP_METADATA_MINOR_VERSION_MIN) { + return; + } + LINFO << "Forcefully setting metadata header version " << LP_METADATA_MAJOR_VERSION << "." + << metadata->header.minor_version << " to " << LP_METADATA_MAJOR_VERSION << "." + << LP_METADATA_MINOR_VERSION_MIN; + metadata->header.minor_version = LP_METADATA_MINOR_VERSION_MIN; + metadata->header.header_size = sizeof(LpMetadataHeaderV1_0); + + // Retrofit Virtual A/B devices should have version 10.1, so flags shouldn't be set. + // Warn if this is the case, but zero it out anyways. + if (metadata->header.flags) { + LWARN << "Zeroing unexpected flags: " << ToHexString(metadata->header.flags); + } + + // Zero out all fields beyond LpMetadataHeaderV0. + static_assert(sizeof(metadata->header) > sizeof(LpMetadataHeaderV1_0)); + memset(reinterpret_cast(&metadata->header) + sizeof(LpMetadataHeaderV1_0), 0, + sizeof(metadata->header) - sizeof(LpMetadataHeaderV1_0)); + + // Clear partition attributes unknown to V0. + // On retrofit Virtual A/B devices, UPDATED flag may be set, so only log info here. + for (auto& partition : metadata->partitions) { + if (partition.attributes & ~LP_PARTITION_ATTRIBUTE_MASK_V0) { + LINFO << "Clearing " << GetPartitionName(partition) + << " partition attribute: " << ToHexString(partition.attributes); + } + + partition.attributes &= LP_PARTITION_ATTRIBUTE_MASK_V0; + } +} + } // namespace fs_mgr } // namespace android diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h index 06617696c..1d86edd4e 100644 --- a/fs_mgr/liblp/utility.h +++ b/fs_mgr/liblp/utility.h @@ -103,6 +103,10 @@ ::android::base::unique_fd GetControlFileOrOpen(std::string_view path, int flags bool UpdateMetadataForInPlaceSnapshot(LpMetadata* metadata, uint32_t source_slot_number, uint32_t target_slot_number); +// Forcefully set metadata header version to 1.0, clearing any incompatible flags and attributes +// so that when downgrading to a build with liblp V0, the device still boots. +void SetMetadataHeaderV0(LpMetadata* metadata); + } // namespace fs_mgr } // namespace android