Merge "liblp: Allow automatic slot suffixing of partition names." am: 9e04f62895
am: e655a67b08

Change-Id: I437754b4deea7483251a6a5d944669aef148166d
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 4007ad9..1e031ad 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -150,7 +150,7 @@
     return builder;
 }
 
-MetadataBuilder::MetadataBuilder() {
+MetadataBuilder::MetadataBuilder() : auto_slot_suffixing_(false) {
     memset(&geometry_, 0, sizeof(geometry_));
     geometry_.magic = LP_METADATA_GEOMETRY_MAGIC;
     geometry_.struct_size = sizeof(geometry_);
@@ -564,7 +564,12 @@
     metadata->geometry = geometry_;
 
     // Assign this early so the extent table can read it.
-    metadata->block_devices = block_devices_;
+    for (const auto& block_device : block_devices_) {
+        metadata->block_devices.emplace_back(block_device);
+        if (auto_slot_suffixing_) {
+            metadata->block_devices.back().flags |= LP_BLOCK_DEVICE_SLOT_SUFFIXED;
+        }
+    }
 
     std::map<std::string, size_t> group_indices;
     for (const auto& group : groups_) {
@@ -600,6 +605,9 @@
         part.first_extent_index = static_cast<uint32_t>(metadata->extents.size());
         part.num_extents = static_cast<uint32_t>(partition->extents().size());
         part.attributes = partition->attributes();
+        if (auto_slot_suffixing_) {
+            part.attributes |= LP_PARTITION_ATTR_SLOT_SUFFIXED;
+        }
 
         auto iter = group_indices.find(partition->group_name());
         if (iter == group_indices.end()) {
@@ -836,5 +844,9 @@
     return true;
 }
 
+void MetadataBuilder::SetAutoSlotSuffixing() {
+    auto_slot_suffixing_ = true;
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index d5e3fed..47ebf6d 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -223,6 +223,9 @@
     // Remove all partitions belonging to a group, then remove the group.
     void RemoveGroupAndPartitions(const std::string& group_name);
 
+    // Set the LP_METADATA_AUTO_SLOT_SUFFIXING flag.
+    void SetAutoSlotSuffixing();
+
     bool GetBlockDeviceInfo(const std::string& partition_name, BlockDeviceInfo* info) const;
     bool UpdateBlockDeviceInfo(const std::string& partition_name, const BlockDeviceInfo& info);
 
@@ -275,6 +278,7 @@
     std::vector<std::unique_ptr<Partition>> partitions_;
     std::vector<std::unique_ptr<PartitionGroup>> groups_;
     std::vector<LpMetadataBlockDevice> block_devices_;
+    bool auto_slot_suffixing_;
 };
 
 // Read BlockDeviceInfo for a given block device. This always returns false
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index 8723a7f..56332ab 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -95,6 +95,7 @@
 
 // Slot suffix helpers.
 uint32_t SlotNumberForSlotSuffix(const std::string& suffix);
+std::string SlotSuffixForSlotNumber(uint32_t slot_number);
 std::string GetPartitionSlotSuffix(const std::string& partition_name);
 
 }  // namespace fs_mgr
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index 1e40df3..c2e25fb 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -38,7 +38,7 @@
 #define LP_METADATA_HEADER_MAGIC 0x414C5030
 
 /* Current metadata version. */
-#define LP_METADATA_MAJOR_VERSION 8
+#define LP_METADATA_MAJOR_VERSION 9
 #define LP_METADATA_MINOR_VERSION 0
 
 /* Attributes for the LpMetadataPartition::attributes field.
@@ -47,10 +47,19 @@
  * device mapper, the block device will be created as read-only.
  */
 #define LP_PARTITION_ATTR_NONE 0x0
-#define LP_PARTITION_ATTR_READONLY 0x1
+#define LP_PARTITION_ATTR_READONLY (1 << 0)
+
+/* This flag is only intended to be used with super_empty.img and super.img on
+ * retrofit devices. On these devices there are A and B super partitions, and
+ * we don't know ahead of time which slot the image will be applied to.
+ *
+ * If set, the partition name needs a slot suffix applied. The slot suffix is
+ * determined by the metadata slot number (0 = _a, 1 = _b).
+ */
+#define LP_PARTITION_ATTR_SLOT_SUFFIXED (1 << 1)
 
 /* Mask that defines all valid attributes. */
-#define LP_PARTITION_ATTRIBUTE_MASK (LP_PARTITION_ATTR_READONLY)
+#define LP_PARTITION_ATTRIBUTE_MASK (LP_PARTITION_ATTR_READONLY | LP_PARTITION_ATTR_SLOT_SUFFIXED)
 
 /* Default name of the physical partition that holds logical partition entries.
  * The layout of this partition will look like:
@@ -302,8 +311,21 @@
 
     /* 24: Partition name in the GPT. Any unused characters must be 0. */
     char partition_name[36];
+
+    /* 60: Flags (see LP_BLOCK_DEVICE_* flags below). */
+    uint32_t flags;
 } LpMetadataBlockDevice;
 
+/* This flag is only intended to be used with super_empty.img and super.img on
+ * retrofit devices. On these devices there are A and B super partitions, and
+ * we don't know ahead of time which slot the image will be applied to.
+ *
+ * If set, the block device needs a slot suffix applied before being used with
+ * IPartitionOpener. The slot suffix is determined by the metadata slot number
+ * (0 = _a, 1 = _b).
+ */
+#define LP_BLOCK_DEVICE_SLOT_SUFFIXED (1 << 0)
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 603e5c0..459cf82 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -88,11 +88,14 @@
 }
 
 // Create a temporary disk and flash it with the default partition setup.
-static unique_fd CreateFlashedDisk() {
+static unique_fd CreateFlashedDisk(bool auto_slot_suffix = false) {
     unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
     if (!builder || !AddDefaultPartitions(builder.get())) {
         return {};
     }
+    if (auto_slot_suffix) {
+        builder->SetAutoSlotSuffixing();
+    }
     unique_fd fd = CreateFakeDisk();
     if (fd < 0) {
         return {};
@@ -608,3 +611,24 @@
     ASSERT_NE(ReadPrimaryMetadata(fd.get(), geometry, 0), nullptr);
     ASSERT_NE(ReadBackupMetadata(fd.get(), geometry, 0), nullptr);
 }
+
+TEST(liblp, AutoSlotSuffixing) {
+    auto fd = CreateFlashedDisk(true);
+    ASSERT_GE(fd, 0);
+
+    TestPartitionOpener opener({{"super", fd}});
+
+    auto metadata = ReadMetadata(opener, "super", 1);
+    ASSERT_NE(metadata, nullptr);
+    ASSERT_EQ(metadata->partitions.size(), static_cast<size_t>(1));
+    EXPECT_EQ(GetPartitionName(metadata->partitions[0]), "system_b");
+    ASSERT_EQ(metadata->block_devices.size(), static_cast<size_t>(1));
+    EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "super_b");
+
+    metadata = ReadMetadata(opener, "super", 0);
+    ASSERT_NE(metadata, nullptr);
+    ASSERT_EQ(metadata->partitions.size(), static_cast<size_t>(1));
+    EXPECT_EQ(GetPartitionName(metadata->partitions[0]), "system_a");
+    ASSERT_EQ(metadata->block_devices.size(), static_cast<size_t>(1));
+    EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "super_a");
+}
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index a02e746..3319956 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -348,6 +348,40 @@
     return ParseMetadata(geometry, fd);
 }
 
+namespace {
+
+bool AdjustMetadataForSlot(LpMetadata* metadata, uint32_t slot_number) {
+    std::string slot_suffix = SlotSuffixForSlotNumber(slot_number);
+    for (auto& partition : metadata->partitions) {
+        if (!(partition.attributes & LP_PARTITION_ATTR_SLOT_SUFFIXED)) {
+            continue;
+        }
+        std::string partition_name = GetPartitionName(partition) + slot_suffix;
+        if (partition_name.size() > sizeof(partition.name)) {
+            LERROR << __PRETTY_FUNCTION__ << " partition name too long: " << partition_name;
+            return false;
+        }
+        strncpy(partition.name, partition_name.c_str(), sizeof(partition.name));
+        partition.attributes &= ~LP_PARTITION_ATTR_SLOT_SUFFIXED;
+    }
+    for (auto& block_device : metadata->block_devices) {
+        if (!(block_device.flags & LP_BLOCK_DEVICE_SLOT_SUFFIXED)) {
+            continue;
+        }
+        std::string partition_name = GetBlockDevicePartitionName(block_device) + slot_suffix;
+        if (partition_name.size() > sizeof(block_device.partition_name)) {
+            LERROR << __PRETTY_FUNCTION__ << " partition name too long: " << partition_name;
+            return false;
+        }
+        strncpy(block_device.partition_name, partition_name.c_str(),
+                sizeof(block_device.partition_name));
+        block_device.flags &= ~LP_BLOCK_DEVICE_SLOT_SUFFIXED;
+    }
+    return true;
+}
+
+}  // namespace
+
 std::unique_ptr<LpMetadata> ReadMetadata(const IPartitionOpener& opener,
                                          const std::string& super_partition, uint32_t slot_number) {
     android::base::unique_fd fd = opener.Open(super_partition, O_RDONLY);
@@ -360,18 +394,30 @@
     if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
         return nullptr;
     }
-
     if (slot_number >= geometry.metadata_slot_count) {
         LERROR << __PRETTY_FUNCTION__ << " invalid metadata slot number";
         return nullptr;
     }
 
-    // Read the primary copy, and if that fails, try the backup.
-    std::unique_ptr<LpMetadata> metadata = ReadPrimaryMetadata(fd, geometry, slot_number);
-    if (metadata) {
-        return metadata;
+    std::vector<int64_t> offsets = {
+            GetPrimaryMetadataOffset(geometry, slot_number),
+            GetBackupMetadataOffset(geometry, slot_number),
+    };
+    std::unique_ptr<LpMetadata> metadata;
+
+    for (const auto& offset : offsets) {
+        if (SeekFile64(fd, offset, SEEK_SET) < 0) {
+            PERROR << __PRETTY_FUNCTION__ << " lseek failed, offset " << offset;
+            continue;
+        }
+        if ((metadata = ParseMetadata(geometry, fd)) != nullptr) {
+            break;
+        }
     }
-    return ReadBackupMetadata(fd, geometry, slot_number);
+    if (!metadata || !AdjustMetadataForSlot(metadata.get(), slot_number)) {
+        return nullptr;
+    }
+    return metadata;
 }
 
 std::unique_ptr<LpMetadata> ReadMetadata(const std::string& super_partition, uint32_t slot_number) {
diff --git a/fs_mgr/liblp/reader.h b/fs_mgr/liblp/reader.h
index d5d5188..7a2490b 100644
--- a/fs_mgr/liblp/reader.h
+++ b/fs_mgr/liblp/reader.h
@@ -38,7 +38,9 @@
 bool ReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry);
 bool ReadBackupGeometry(int fd, LpMetadataGeometry* geometry);
 
-// These functions assume a valid geometry and slot number.
+// These functions assume a valid geometry and slot number, and do not obey
+// auto-slot-suffixing. They are used for tests and for checking whether
+// the metadata is coherent across primary and backup copies.
 std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry& geometry,
                                                 uint32_t slot_number);
 std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry& geometry,
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index cce90a3..2d34ce5 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -132,5 +132,10 @@
     return (suffix == "_a" || suffix == "_b") ? suffix : "";
 }
 
+std::string SlotSuffixForSlotNumber(uint32_t slot_number) {
+    CHECK(slot_number == 0 || slot_number == 1);
+    return (slot_number == 0) ? "_a" : "_b";
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/liblp/utility_test.cpp b/fs_mgr/liblp/utility_test.cpp
index 0fa4590..15f7fff 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -32,6 +32,11 @@
     EXPECT_EQ(SlotNumberForSlotSuffix("_d"), 0);
 }
 
+TEST(liblp, SlotSuffixForSlotNumber) {
+    EXPECT_EQ(SlotSuffixForSlotNumber(0), "_a");
+    EXPECT_EQ(SlotSuffixForSlotNumber(1), "_b");
+}
+
 TEST(liblp, GetMetadataOffset) {
     LpMetadataGeometry geometry = {LP_METADATA_GEOMETRY_MAGIC,
                                    sizeof(geometry),
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index f4c9b99..e72cdfa 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -83,7 +83,7 @@
 // Perform sanity checks so we don't accidentally overwrite valid metadata
 // with potentially invalid metadata, or random partition data with metadata.
 static bool ValidateAndSerializeMetadata(const IPartitionOpener& opener, const LpMetadata& metadata,
-                                         std::string* blob) {
+                                         const std::string& slot_suffix, std::string* blob) {
     const LpMetadataHeader& header = metadata.header;
     const LpMetadataGeometry& geometry = metadata.geometry;
 
@@ -114,6 +114,15 @@
     }
     for (const auto& block_device : metadata.block_devices) {
         std::string partition_name = GetBlockDevicePartitionName(block_device);
+        if (block_device.flags & LP_BLOCK_DEVICE_SLOT_SUFFIXED) {
+            if (slot_suffix.empty()) {
+                LERROR << "Block device " << partition_name << " requires a slot suffix,"
+                       << " which could not be derived from the super partition name.";
+                return false;
+            }
+            partition_name += slot_suffix;
+        }
+
         if ((block_device.first_logical_sector + 1) * LP_SECTOR_SIZE > block_device.size) {
             LERROR << "Block device " << partition_name << " has invalid first sector "
                    << block_device.first_logical_sector << " for size " << block_device.size;
@@ -234,11 +243,16 @@
         return false;
     }
 
+    // This is only used in update_engine and fastbootd, where the super
+    // partition should be specified as a name (or by-name link), and
+    // therefore, we should be able to extract a slot suffix.
+    std::string slot_suffix = GetPartitionSlotSuffix(super_partition);
+
     // Before writing geometry and/or logical partition tables, perform some
     // basic checks that the geometry and tables are coherent, and will fit
     // on the given block device.
     std::string metadata_blob;
-    if (!ValidateAndSerializeMetadata(opener, metadata, &metadata_blob)) {
+    if (!ValidateAndSerializeMetadata(opener, metadata, slot_suffix, &metadata_blob)) {
         return false;
     }
 
@@ -299,11 +313,13 @@
         return false;
     }
 
+    std::string slot_suffix = SlotSuffixForSlotNumber(slot_number);
+
     // Before writing geometry and/or logical partition tables, perform some
     // basic checks that the geometry and tables are coherent, and will fit
     // on the given block device.
     std::string blob;
-    if (!ValidateAndSerializeMetadata(opener, metadata, &blob)) {
+    if (!ValidateAndSerializeMetadata(opener, metadata, slot_suffix, &blob)) {
         return false;
     }
 
@@ -335,7 +351,7 @@
         // synchronize the backup copy. This guarantees that a partial write
         // still leaves one copy intact.
         std::string old_blob;
-        if (!ValidateAndSerializeMetadata(opener, *primary.get(), &old_blob)) {
+        if (!ValidateAndSerializeMetadata(opener, *primary.get(), slot_suffix, &old_blob)) {
             LERROR << "Error serializing primary metadata to repair corrupted backup";
             return false;
         }
@@ -347,7 +363,7 @@
         // The backup copy is coherent, and the primary is not. Sync it for
         // safety.
         std::string old_blob;
-        if (!ValidateAndSerializeMetadata(opener, *backup.get(), &old_blob)) {
+        if (!ValidateAndSerializeMetadata(opener, *backup.get(), slot_suffix, &old_blob)) {
             LERROR << "Error serializing primary metadata to repair corrupted backup";
             return false;
         }