From a819a3cad239dfd18724c79cc3a4c8646e2f0ead 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 (cherry picked from commit ba5dfd76ded0502660e4cf695a4c249516adecdf) Merged-In: I8b548c8ce36a75197e7172a77f9207fd44fe4670 --- 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 c37d70e05..ace6210db 100644 --- a/fs_mgr/liblp/builder.cpp +++ b/fs_mgr/liblp/builder.cpp @@ -205,11 +205,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 89a47b112..f2e73704f 100644 --- a/fs_mgr/liblp/include/liblp/builder.h +++ b/fs_mgr/liblp/include/liblp/builder.h @@ -208,8 +208,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 c4fe3edfc..aa3a6a0a7 100644 --- a/fs_mgr/liblp/utility.h +++ b/fs_mgr/liblp/utility.h @@ -103,6 +103,10 @@ bool SetBlockReadonly(int fd, bool readonly); 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