Added support for FlashSuperLayoutTask

Test: testing flashall code with this change
Bug: 194686221
Change-Id: Ibb96980402db51b48c9a296338f29195f68c65bf
diff --git a/fastboot/task.cpp b/fastboot/task.cpp
index a4aa637..e77fa4a 100644
--- a/fastboot/task.cpp
+++ b/fastboot/task.cpp
@@ -14,11 +14,12 @@
 // limitations under the License.
 //
 #include "task.h"
+#include <iostream>
 #include "fastboot.h"
-#include "util.h"
+#include "filesystem.h"
+#include "super_flash_helper.h"
 
-#include "fastboot.h"
-#include "util.h"
+using namespace std::string_literals;
 
 FlashTask::FlashTask(const std::string& _slot, const std::string& _pname)
     : pname_(_pname), fname_(find_item(_pname)), slot_(_slot) {
@@ -66,3 +67,78 @@
         syntax_error("unknown reboot target %s", reboot_target_.c_str());
     }
 }
+
+FlashSuperLayoutTask::FlashSuperLayoutTask(const std::string& super_name,
+                                           std::unique_ptr<SuperFlashHelper> helper,
+                                           SparsePtr sparse_layout)
+    : super_name_(super_name),
+      helper_(std::move(helper)),
+      sparse_layout_(std::move(sparse_layout)) {}
+
+void FlashSuperLayoutTask::Run() {
+    std::vector<SparsePtr> files;
+    if (int limit = get_sparse_limit(sparse_file_len(sparse_layout_.get(), false, false))) {
+        files = resparse_file(sparse_layout_.get(), limit);
+    } else {
+        files.emplace_back(std::move(sparse_layout_));
+    }
+
+    // Send the data to the device.
+    flash_partition_files(super_name_, files);
+}
+
+std::unique_ptr<FlashSuperLayoutTask> FlashSuperLayoutTask::Initialize(
+        FlashingPlan* fp, std::vector<ImageEntry>& os_images) {
+    if (!supports_AB()) {
+        LOG(VERBOSE) << "Cannot optimize flashing super on non-AB device";
+        return nullptr;
+    }
+    if (fp->slot == "all") {
+        LOG(VERBOSE) << "Cannot optimize flashing super for all slots";
+        return nullptr;
+    }
+
+    // Does this device use dynamic partitions at all?
+    unique_fd fd = fp->source->OpenFile("super_empty.img");
+
+    if (fd < 0) {
+        LOG(VERBOSE) << "could not open super_empty.img";
+        return nullptr;
+    }
+
+    std::string super_name;
+    // Try to find whether there is a super partition.
+    if (fp->fb->GetVar("super-partition-name", &super_name) != fastboot::SUCCESS) {
+        super_name = "super";
+    }
+    std::string partition_size_str;
+
+    if (fp->fb->GetVar("partition-size:" + super_name, &partition_size_str) != fastboot::SUCCESS) {
+        LOG(VERBOSE) << "Cannot optimize super flashing: could not determine super partition";
+        return nullptr;
+    }
+    std::unique_ptr<SuperFlashHelper> helper = std::make_unique<SuperFlashHelper>(*fp->source);
+    if (!helper->Open(fd)) {
+        return nullptr;
+    }
+
+    for (const auto& entry : os_images) {
+        auto partition = GetPartitionName(entry, fp->current_slot);
+        auto image = entry.first;
+
+        if (!helper->AddPartition(partition, image->img_name, image->optional_if_no_image)) {
+            return nullptr;
+        }
+    }
+
+    auto s = helper->GetSparseLayout();
+    if (!s) return nullptr;
+
+    // Remove images that we already flashed, just in case we have non-dynamic OS images.
+    auto remove_if_callback = [&](const ImageEntry& entry) -> bool {
+        return helper->WillFlash(GetPartitionName(entry, fp->current_slot));
+    };
+    os_images.erase(std::remove_if(os_images.begin(), os_images.end(), remove_if_callback),
+                    os_images.end());
+    return std::make_unique<FlashSuperLayoutTask>(super_name, std::move(helper), std::move(s));
+}