Refactor partition and image handling.

Currently the image creation/extent mapping process is hardcoded to two
partitions, system_gsi and userdata_gsi. Adding a third case stretches
the maintainability of this code, so this patch refactors things. Each
image/partition gets added to an ImageMap that can be handed off to
CreateMetadata.

Bug: 123777418
Test: builds
Change-Id: I5824674faddc4b2cf2f639f18cae974a870025fb
diff --git a/gsi_service.cpp b/gsi_service.cpp
index 8945294..fae6acb 100644
--- a/gsi_service.cpp
+++ b/gsi_service.cpp
@@ -122,7 +122,11 @@
     std::lock_guard<std::mutex> guard(progress_lock_);
 
     progress_.status = status;
-    progress_.bytes_processed = bytes_processed;
+    if (status == STATUS_COMPLETE) {
+        progress_.bytes_processed = progress_.total_bytes;
+    } else {
+        progress_.bytes_processed = bytes_processed;
+    }
 }
 
 binder::Status GsiService::getInstallProgress(::android::gsi::GsiProgress* _aidl_return) {
@@ -343,6 +347,28 @@
     // TODO: trigger GC from fiemap writer.
 
     // Create fallocated files.
+    ImageMap partitions;
+    if (int status = PreallocateUserdata(&partitions)) {
+        return status;
+    }
+    if (int status = PreallocateSystem(&partitions)) {
+        return status;
+    }
+
+    // Save the extent information in liblp.
+    metadata_ = CreateMetadata(partitions);
+    if (!metadata_) {
+        return INSTALL_ERROR_GENERIC;
+    }
+
+    UpdateProgress(STATUS_COMPLETE, 0);
+
+    // We're ready to start streaming data in.
+    gsi_bytes_written_ = 0;
+    return INSTALL_OK;
+}
+
+int GsiService::PreallocateUserdata(ImageMap* partitions) {
     int error;
     FiemapUniquePtr userdata_image;
     if (wipe_userdata_ || access(kUserdataFile, F_OK)) {
@@ -370,23 +396,24 @@
         userdata_size_ = userdata_image->size();
     }
 
+    userdata_block_size_ = userdata_image->block_size();
+
+    partitions->emplace(std::make_pair("userdata_gsi", std::move(userdata_image)));
+    return INSTALL_OK;
+}
+
+int GsiService::PreallocateSystem(ImageMap* partitions) {
     StartAsyncOperation("create system", gsi_size_);
+
+    int error;
     auto system_image = CreateFiemapWriter(kSystemFile, gsi_size_, &error);
     if (!system_image) {
         return error;
     }
-    UpdateProgress(STATUS_COMPLETE, gsi_size_);
 
-    // Save the extent information in liblp.
-    metadata_ = CreateMetadata(userdata_image.get(), system_image.get());
-    if (!metadata_) {
-        return INSTALL_ERROR_GENERIC;
-    }
-
-    // We're ready to start streaming data in.
-    gsi_bytes_written_ = 0;
-    userdata_block_size_ = userdata_image->block_size();
     system_block_size_ = system_image->block_size();
+
+    partitions->emplace(std::make_pair("system_gsi", std::move(system_image)));
     return INSTALL_OK;
 }
 
@@ -533,19 +560,24 @@
         return INSTALL_ERROR_GENERIC;
     }
 
+    ImageMap partitions;
+
     int error;
     auto userdata_image = CreateFiemapWriter(kUserdataFile, 0, &error);
     if (!userdata_image) {
         LOG(ERROR) << "could not find userdata image";
         return error;
     }
+    partitions.emplace(std::make_pair("userdata_gsi", std::move(userdata_image)));
+
     auto system_image = CreateFiemapWriter(kSystemFile, 0, &error);
     if (!system_image) {
         LOG(ERROR) << "could not find system image";
         return error;
     }
+    partitions.emplace(std::make_pair("system_gsi", std::move(system_image)));
 
-    auto metadata = CreateMetadata(userdata_image.get(), system_image.get());
+    auto metadata = CreateMetadata(partitions);
     if (!metadata) {
         return INSTALL_ERROR_GENERIC;
     }
@@ -592,8 +624,7 @@
     return true;
 }
 
-std::unique_ptr<LpMetadata> GsiService::CreateMetadata(FiemapWriter* userdata_image,
-                                                       FiemapWriter* system_image) {
+std::unique_ptr<LpMetadata> GsiService::CreateMetadata(const ImageMap& partitions) {
     PartitionOpener opener;
     BlockDeviceInfo userdata_device;
     if (!opener.GetInfo("userdata", &userdata_device)) {
@@ -609,15 +640,19 @@
     }
     builder->IgnoreSlotSuffixing();
 
-    Partition* userdata = builder->AddPartition("userdata_gsi", LP_PARTITION_ATTR_NONE);
-    Partition* system = builder->AddPartition("system_gsi", LP_PARTITION_ATTR_READONLY);
-    if (!userdata || !system) {
-        LOG(ERROR) << "Error creating partition table";
-        return nullptr;
-    }
-    if (!AddPartitionFiemap(builder.get(), userdata, userdata_image) ||
-        !AddPartitionFiemap(builder.get(), system, system_image)) {
-        return nullptr;
+    for (const auto& [name, image] : partitions) {
+        uint32_t flags = LP_PARTITION_ATTR_NONE;
+        if (name == "system_gsi") {
+            flags |= LP_PARTITION_ATTR_READONLY;
+        }
+        Partition* partition = builder->AddPartition(name, flags);
+        if (!partition) {
+            LOG(ERROR) << "Error adding " << name << " to partition table";
+            return nullptr;
+        }
+        if (!AddPartitionFiemap(builder.get(), partition, image.get())) {
+            return nullptr;
+        }
     }
 
     auto metadata = builder->Export();
diff --git a/gsi_service.h b/gsi_service.h
index a69f72d..55c83b1 100644
--- a/gsi_service.h
+++ b/gsi_service.h
@@ -15,9 +15,11 @@
  */
 #pragma once
 
+#include <map>
 #include <memory>
 #include <mutex>
 #include <sstream>
+#include <string>
 #include <vector>
 
 #include <android-base/unique_fd.h>
@@ -60,10 +62,13 @@
   private:
     using LpMetadata = android::fs_mgr::LpMetadata;
     using MetadataBuilder = android::fs_mgr::MetadataBuilder;
+    using ImageMap = std::map<std::string, android::fiemap_writer::FiemapUniquePtr>;
 
     int StartInstall(int64_t gsi_size, int64_t userdata_size, bool wipe_userdata);
     int PerformSanityChecks();
     int PreallocateFiles();
+    int PreallocateUserdata(ImageMap* partitions);
+    int PreallocateSystem(ImageMap* partitions);
     bool FormatUserdata();
     bool CommitGsiChunk(int stream_fd, int64_t bytes);
     bool CommitGsiChunk(const void* data, size_t bytes);
@@ -74,8 +79,7 @@
     bool AddPartitionFiemap(android::fs_mgr::MetadataBuilder* builder,
                             android::fs_mgr::Partition* partition,
                             android::fiemap_writer::FiemapWriter* writer);
-    std::unique_ptr<LpMetadata> CreateMetadata(android::fiemap_writer::FiemapWriter* userdata,
-                                               android::fiemap_writer::FiemapWriter* system);
+    std::unique_ptr<LpMetadata> CreateMetadata(const ImageMap& partitions);
     fiemap_writer::FiemapUniquePtr CreateFiemapWriter(const std::string& path, uint64_t size,
                                                       int* error);
     bool CreateInstallStatusFile();