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
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index c37d70e..ace6210 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -205,11 +205,18 @@
}
}
- 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 89a47b1..f2e7370 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -208,8 +208,10 @@
// 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<MetadataBuilder> 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 48c5c83..d8e171b 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -15,6 +15,7 @@
*/
#include <fcntl.h>
+#include <inttypes.h>
#include <stdint.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -29,6 +30,7 @@
#include <vector>
#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <ext4_utils/ext4_utils.h>
#include <openssl/sha.h>
@@ -285,5 +287,42 @@
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<uint8_t*>(&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 c4fe3ed..aa3a6a0 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -103,6 +103,10 @@
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