diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp index 77c9c2878..8a74745dd 100644 --- a/fs_mgr/liblp/builder.cpp +++ b/fs_mgr/liblp/builder.cpp @@ -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 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(metadata->extents.size()); part.num_extents = static_cast(partition->extents().size()); diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp index dde6d07c9..c5b404766 100644 --- a/fs_mgr/liblp/builder_test.cpp +++ b/fs_mgr/liblp/builder_test.cpp @@ -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); diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h index 8934aaff2..6e928b486 100644 --- a/fs_mgr/liblp/include/liblp/metadata_format.h +++ b/fs_mgr/liblp/include/liblp/metadata_format.h @@ -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: diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp index df89e9c90..22f674678 100644 --- a/fs_mgr/liblp/io_test.cpp +++ b/fs_mgr/liblp/io_test.cpp @@ -713,3 +713,32 @@ TEST_F(LiblpTest, UpdateNonRetrofit) { ASSERT_EQ(updated->block_devices.size(), static_cast(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); +} diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp index 8dbe955fa..aecf6852e 100644 --- a/fs_mgr/liblp/reader.cpp +++ b/fs_mgr/liblp/reader.cpp @@ -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 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 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; } diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp index 17f05aa7c..afcce8f0a 100644 --- a/fs_mgr/liblp/utility.cpp +++ b/fs_mgr/liblp/utility.cpp @@ -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); }