Merge "liblp: Add an attribute to indicate that a partition has been updated."

This commit is contained in:
David Anderson 2019-08-28 02:51:43 +00:00 committed by Gerrit Code Review
commit 74a6f4cf57
6 changed files with 65 additions and 7 deletions

View file

@ -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());

View file

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

View file

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

View file

@ -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);
}

View file

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

View file

@ -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);
}