liblp: Add an attribute to indicate that a partition has been updated.
When the bootloader (or fastbootd) flashes the super partition, we need to make sure that init doesn't re-map any snapshot or snapshot-merge targets. A simple way to do this is to introduce an attribute that is only added by update_engine. When this flag is present, we know the partition has not been flashed. This bumps the minor version of LpMetadata. To make this as uninvasive as possible, the new minor version is only used when MetadataBuilder detects the new attribute. The new liblp can read older metadata, but will reject it if it contains an illegal attribute set. Bug: 139154795 Test: liblp_test gtest Change-Id: I5ae15d11219b41575a9f71d7dbdb43cbf07a3529
This commit is contained in:
parent
9966699af7
commit
cd7a635dc7
6 changed files with 65 additions and 7 deletions
|
|
@ -232,7 +232,7 @@ MetadataBuilder::MetadataBuilder() : auto_slot_suffixing_(false) {
|
|||
memset(&header_, 0, sizeof(header_));
|
||||
header_.magic = LP_METADATA_HEADER_MAGIC;
|
||||
header_.major_version = LP_METADATA_MAJOR_VERSION;
|
||||
header_.minor_version = LP_METADATA_MINOR_VERSION;
|
||||
header_.minor_version = LP_METADATA_MINOR_VERSION_MIN;
|
||||
header_.header_size = sizeof(header_);
|
||||
header_.partitions.entry_size = sizeof(LpMetadataPartition);
|
||||
header_.extents.entry_size = sizeof(LpMetadataExtent);
|
||||
|
|
@ -796,6 +796,11 @@ std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (partition->attributes() & LP_PARTITION_ATTR_UPDATED) {
|
||||
static const uint16_t kMinVersion = LP_METADATA_VERSION_FOR_UPDATED_ATTR;
|
||||
metadata->header.minor_version = std::max(metadata->header.minor_version, kMinVersion);
|
||||
}
|
||||
|
||||
strncpy(part.name, partition->name().c_str(), sizeof(part.name));
|
||||
part.first_extent_index = static_cast<uint32_t>(metadata->extents.size());
|
||||
part.num_extents = static_cast<uint32_t>(partition->extents().size());
|
||||
|
|
|
|||
|
|
@ -349,7 +349,7 @@ TEST_F(BuilderTest, BuilderExport) {
|
|||
const LpMetadataHeader& header = exported->header;
|
||||
EXPECT_EQ(header.magic, LP_METADATA_HEADER_MAGIC);
|
||||
EXPECT_EQ(header.major_version, LP_METADATA_MAJOR_VERSION);
|
||||
EXPECT_EQ(header.minor_version, LP_METADATA_MINOR_VERSION);
|
||||
EXPECT_EQ(header.minor_version, LP_METADATA_MINOR_VERSION_MIN);
|
||||
|
||||
ASSERT_EQ(exported->partitions.size(), 2);
|
||||
ASSERT_EQ(exported->extents.size(), 3);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,11 @@ extern "C" {
|
|||
|
||||
/* Current metadata version. */
|
||||
#define LP_METADATA_MAJOR_VERSION 10
|
||||
#define LP_METADATA_MINOR_VERSION 0
|
||||
#define LP_METADATA_MINOR_VERSION_MIN 0
|
||||
#define LP_METADATA_MINOR_VERSION_MAX 1
|
||||
|
||||
/* Metadata version needed to use the UPDATED partition attribute. */
|
||||
#define LP_METADATA_VERSION_FOR_UPDATED_ATTR 1
|
||||
|
||||
/* Attributes for the LpMetadataPartition::attributes field.
|
||||
*
|
||||
|
|
@ -58,8 +62,20 @@ extern "C" {
|
|||
*/
|
||||
#define LP_PARTITION_ATTR_SLOT_SUFFIXED (1 << 1)
|
||||
|
||||
/* Mask that defines all valid attributes. */
|
||||
#define LP_PARTITION_ATTRIBUTE_MASK (LP_PARTITION_ATTR_READONLY | LP_PARTITION_ATTR_SLOT_SUFFIXED)
|
||||
/* This flag is applied automatically when using MetadataBuilder::NewForUpdate.
|
||||
* It signals that the partition was created (or modified) for a snapshot-based
|
||||
* update. If this flag is not present, the partition was likely flashed via
|
||||
* fastboot.
|
||||
*/
|
||||
#define LP_PARTITION_ATTR_UPDATED (1 << 2)
|
||||
|
||||
/* Mask that defines all valid attributes. When changing this, make sure to
|
||||
* update ParseMetadata().
|
||||
*/
|
||||
#define LP_PARTITION_ATTRIBUTE_MASK_V0 \
|
||||
(LP_PARTITION_ATTR_READONLY | LP_PARTITION_ATTR_SLOT_SUFFIXED)
|
||||
#define LP_PARTITION_ATTRIBUTE_MASK_V1 (LP_PARTITION_ATTRIBUTE_MASK_V0 | LP_PARTITION_ATTR_UPDATED)
|
||||
#define LP_PARTITION_ATTRIBUTE_MASK LP_PARTITION_ATTRIBUTE_MASK_V1
|
||||
|
||||
/* Default name of the physical partition that holds logical partition entries.
|
||||
* The layout of this partition will look like:
|
||||
|
|
|
|||
|
|
@ -713,3 +713,32 @@ TEST_F(LiblpTest, UpdateNonRetrofit) {
|
|||
ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(1));
|
||||
EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super");
|
||||
}
|
||||
|
||||
TEST_F(LiblpTest, UpdateVirtualAB) {
|
||||
ON_CALL(*GetMockedPropertyFetcher(), GetBoolProperty("ro.virtual_ab.enabled", _))
|
||||
.WillByDefault(Return(true));
|
||||
|
||||
unique_fd fd = CreateFlashedDisk();
|
||||
ASSERT_GE(fd, 0);
|
||||
|
||||
DefaultPartitionOpener opener(fd);
|
||||
auto builder = MetadataBuilder::NewForUpdate(opener, "super", 0, 1);
|
||||
ASSERT_NE(builder, nullptr);
|
||||
auto updated = builder->Export();
|
||||
ASSERT_NE(updated, nullptr);
|
||||
ASSERT_TRUE(UpdatePartitionTable(opener, "super", *updated.get(), 1));
|
||||
|
||||
// Validate old slot.
|
||||
auto metadata = ReadMetadata(opener, "super", 0);
|
||||
ASSERT_NE(metadata, nullptr);
|
||||
ASSERT_EQ(metadata->header.minor_version, 0);
|
||||
ASSERT_GE(metadata->partitions.size(), 1);
|
||||
ASSERT_EQ(metadata->partitions[0].attributes & LP_PARTITION_ATTR_UPDATED, 0);
|
||||
|
||||
// Validate new slot.
|
||||
metadata = ReadMetadata(opener, "super", 1);
|
||||
ASSERT_NE(metadata, nullptr);
|
||||
ASSERT_EQ(metadata->header.minor_version, 1);
|
||||
ASSERT_GE(metadata->partitions.size(), 1);
|
||||
ASSERT_NE(metadata->partitions[0].attributes & LP_PARTITION_ATTR_UPDATED, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ static bool ValidateMetadataHeader(const LpMetadataHeader& header) {
|
|||
}
|
||||
// Check that the version is compatible.
|
||||
if (header.major_version != LP_METADATA_MAJOR_VERSION ||
|
||||
header.minor_version > LP_METADATA_MINOR_VERSION) {
|
||||
header.minor_version > LP_METADATA_MINOR_VERSION_MAX) {
|
||||
LERROR << "Logical partition metadata has incompatible version.";
|
||||
return false;
|
||||
}
|
||||
|
|
@ -245,6 +245,13 @@ static std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geome
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t valid_attributes = 0;
|
||||
if (metadata->header.minor_version >= LP_METADATA_VERSION_FOR_UPDATED_ATTR) {
|
||||
valid_attributes = LP_PARTITION_ATTRIBUTE_MASK_V1;
|
||||
} else {
|
||||
valid_attributes = LP_PARTITION_ATTRIBUTE_MASK_V0;
|
||||
}
|
||||
|
||||
// ValidateTableSize ensured that |cursor| is valid for the number of
|
||||
// entries in the table.
|
||||
uint8_t* cursor = buffer.get() + header.partitions.offset;
|
||||
|
|
@ -253,7 +260,7 @@ static std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geome
|
|||
memcpy(&partition, cursor, sizeof(partition));
|
||||
cursor += header.partitions.entry_size;
|
||||
|
||||
if (partition.attributes & ~LP_PARTITION_ATTRIBUTE_MASK) {
|
||||
if (partition.attributes & ~valid_attributes) {
|
||||
LERROR << "Logical partition has invalid attribute set.";
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -269,6 +269,7 @@ bool UpdateMetadataForInPlaceSnapshot(LpMetadata* metadata, uint32_t source_slot
|
|||
<< "; this partition should not belong to this group!";
|
||||
continue; // not adding to new_partition_ptrs
|
||||
}
|
||||
partition.attributes |= LP_PARTITION_ATTR_UPDATED;
|
||||
partition.group_index = std::distance(new_group_ptrs.begin(), it);
|
||||
new_partition_ptrs.push_back(&partition);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue