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 ba5dfd76de)
Merged-In: I8b548c8ce36a75197e7172a77f9207fd44fe4670
This commit is contained in:
Yifan Hong 2020-07-01 12:32:46 -07:00
parent d894b463f1
commit a819a3cad2
4 changed files with 59 additions and 7 deletions

View file

@ -205,11 +205,18 @@ std::unique_ptr<MetadataBuilder> 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;
}
}
}

View file

@ -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<MetadataBuilder> NewForUpdate(const IPartitionOpener& opener,
const std::string& source_partition,
uint32_t source_slot_number,

View file

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

View file

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