Merge "liblp: Modify NewForUpdate to accomodate two super partitions."
am: 6900fce913

Change-Id: Ic818541a0c69bc0c7932491cb8e0077d65aff804
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index b51afc1..7035f42 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -158,39 +158,48 @@
         return nullptr;
     }
 
-    // Get the list of devices we already have.
-    std::set<std::string> block_devices;
-    for (const auto& block_device : metadata->block_devices) {
-        block_devices.emplace(GetBlockDevicePartitionName(block_device));
+    // On non-retrofit devices there is only one location for metadata: the
+    // super partition. update_engine will remove and resize partitions as
+    // needed. On the other hand, for retrofit devices, we'll need to
+    // translate block device and group names to update their slot suffixes.
+    auto super_device = GetMetadataSuperBlockDevice(*metadata.get());
+    if (GetBlockDevicePartitionName(*super_device) == "super") {
+        return New(*metadata.get(), &opener);
     }
 
-    auto new_block_devices = metadata->block_devices;
+    // Clear partitions and extents, since they have no meaning on the target
+    // slot. We also clear groups since they are re-added during OTA.
+    metadata->partitions.clear();
+    metadata->extents.clear();
+    metadata->groups.clear();
 
-    // Add missing block devices.
     std::string source_slot_suffix = SlotSuffixForSlotNumber(source_slot_number);
     std::string target_slot_suffix = SlotSuffixForSlotNumber(target_slot_number);
-    for (const auto& block_device : metadata->block_devices) {
-        std::string partition_name = GetBlockDevicePartitionName(block_device);
+
+    // Translate block devices.
+    auto source_block_devices = std::move(metadata->block_devices);
+    for (const auto& source_block_device : source_block_devices) {
+        std::string partition_name = GetBlockDevicePartitionName(source_block_device);
         std::string slot_suffix = GetPartitionSlotSuffix(partition_name);
         if (slot_suffix.empty() || slot_suffix != source_slot_suffix) {
-            continue;
+            // This should never happen. It means that the source metadata
+            // refers to a target or unknown block device.
+            LERROR << "Invalid block device for slot " << source_slot_suffix << ": "
+                   << partition_name;
+            return nullptr;
         }
         std::string new_name =
                 partition_name.substr(0, partition_name.size() - slot_suffix.size()) +
                 target_slot_suffix;
-        if (block_devices.find(new_name) != block_devices.end()) {
-            continue;
-        }
 
-        auto new_device = block_device;
+        auto new_device = source_block_device;
         if (!UpdateBlockDevicePartitionName(&new_device, new_name)) {
             LERROR << "Partition name too long: " << new_name;
             return nullptr;
         }
-        new_block_devices.emplace_back(new_device);
+        metadata->block_devices.emplace_back(new_device);
     }
 
-    metadata->block_devices = new_block_devices;
     return New(*metadata.get(), &opener);
 }
 
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index b539d77..9f3314d 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -665,6 +665,7 @@
     unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
     ASSERT_NE(builder, nullptr);
     ASSERT_TRUE(AddDefaultPartitions(builder.get()));
+    ASSERT_TRUE(builder->AddGroup("example", 0));
     builder->SetAutoSlotSuffixing();
 
     auto fd = CreateFakeDisk();
@@ -682,9 +683,11 @@
     ASSERT_NE(builder, nullptr);
     auto updated = builder->Export();
     ASSERT_NE(updated, nullptr);
-    ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(2));
-    EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super_a");
-    EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[1]), "super_b");
+    ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(1));
+    EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super_b");
+    ASSERT_TRUE(updated->groups.empty());
+    ASSERT_TRUE(updated->partitions.empty());
+    ASSERT_TRUE(updated->extents.empty());
 }
 
 TEST(liblp, UpdateNonRetrofit) {
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index 305e6c7..24c6b2c 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -380,11 +380,10 @@
             continue;
         }
         std::string group_name = GetPartitionGroupName(group) + slot_suffix;
-        if (group_name.size() > sizeof(group.name)) {
+        if (!UpdatePartitionGroupName(&group, group_name)) {
             LERROR << __PRETTY_FUNCTION__ << " group name too long: " << group_name;
             return false;
         }
-        strncpy(group.name, group_name.c_str(), sizeof(group.name));
         group.flags &= ~LP_GROUP_SLOT_SUFFIXED;
     }
     return true;
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index f0a3812..9ccabe9 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -147,5 +147,13 @@
     return true;
 }
 
+bool UpdatePartitionGroupName(LpMetadataPartitionGroup* group, const std::string& name) {
+    if (name.size() > sizeof(group->name)) {
+        return false;
+    }
+    strncpy(group->name, name.c_str(), sizeof(group->name));
+    return true;
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index 55ecb5a..8b70919 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -86,6 +86,7 @@
 
 // Update names from C++ strings.
 bool UpdateBlockDevicePartitionName(LpMetadataBlockDevice* device, const std::string& name);
+bool UpdatePartitionGroupName(LpMetadataPartitionGroup* group, const std::string& name);
 
 }  // namespace fs_mgr
 }  // namespace android