Write cow merge sequence at beginning of update am: a37aafc80f

Original change: https://android-review.googlesource.com/c/platform/system/update_engine/+/1736934

Change-Id: I1d9a75c4ac5778d58341e94e5575b1609d4c18ca
diff --git a/payload_consumer/partition_writer_factory_android.cc b/payload_consumer/partition_writer_factory_android.cc
index 0a9a3fb..6736620 100644
--- a/payload_consumer/partition_writer_factory_android.cc
+++ b/payload_consumer/partition_writer_factory_android.cc
@@ -35,11 +35,8 @@
     LOG(INFO)
         << "Virtual AB Compression Enabled, using VABC Partition Writer for `"
         << install_part.name << '`';
-    return std::make_unique<VABCPartitionWriter>(partition_update,
-                                                 install_part,
-                                                 dynamic_control,
-                                                 block_size,
-                                                 is_interactive);
+    return std::make_unique<VABCPartitionWriter>(
+        partition_update, install_part, dynamic_control, block_size);
   } else {
     LOG(INFO) << "Virtual AB Compression disabled, using Partition Writer for `"
               << install_part.name << '`';
diff --git a/payload_consumer/vabc_partition_writer.cc b/payload_consumer/vabc_partition_writer.cc
index d181c75..5130d7a 100644
--- a/payload_consumer/vabc_partition_writer.cc
+++ b/payload_consumer/vabc_partition_writer.cc
@@ -30,6 +30,9 @@
 #include "update_engine/payload_consumer/install_plan.h"
 #include "update_engine/payload_consumer/partition_writer.h"
 #include "update_engine/payload_consumer/snapshot_extent_writer.h"
+#include "update_engine/payload_generator/extent_ranges.h"
+#include "update_engine/payload_generator/extent_utils.h"
+#include "update_engine/update_metadata.pb.h"
 
 namespace chromeos_update_engine {
 // Expected layout of COW file:
@@ -56,16 +59,17 @@
 // label 3, Which contains all operation 2's data, but none of operation 3's
 // data.
 
+using android::snapshot::ICowWriter;
+using ::google::protobuf::RepeatedPtrField;
+
 VABCPartitionWriter::VABCPartitionWriter(
     const PartitionUpdate& partition_update,
     const InstallPlan::Partition& install_part,
     DynamicPartitionControlInterface* dynamic_control,
-    size_t block_size,
-    bool is_interactive)
+    size_t block_size)
     : partition_update_(partition_update),
       install_part_(install_part),
       dynamic_control_(dynamic_control),
-      interactive_(is_interactive),
       block_size_(block_size),
       executor_(block_size),
       verified_source_fd_(block_size, install_part.source_path) {}
@@ -101,8 +105,14 @@
   }
 
   // ==============================================
+  if (!partition_update_.merge_operations().empty()) {
+    TEST_AND_RETURN_FALSE(WriteMergeSequence(
+        partition_update_.merge_operations(), cow_writer_.get()));
+  }
 
   // TODO(zhangkelvin) Rewrite this in C++20 coroutine once that's available.
+  // TODO(177104308) Don't write all COPY ops up-front if merge sequence is
+  // written
   auto converted = ConvertToCowOperations(partition_update_.operations(),
                                           partition_update_.merge_operations());
 
@@ -114,14 +124,42 @@
     TEST_AND_RETURN_FALSE_ERRNO(
         source_fd->Open(install_part_.source_path.c_str(), O_RDONLY));
     WriteAllCowOps(block_size_, converted, cow_writer_.get(), source_fd);
+    cow_writer_->AddLabel(0);
   }
   return true;
 }
 
+bool VABCPartitionWriter::WriteMergeSequence(
+    const RepeatedPtrField<CowMergeOperation>& merge_sequence,
+    ICowWriter* cow_writer) {
+  std::vector<uint32_t> blocks_merge_order;
+  for (const auto& merge_op : merge_sequence) {
+    const auto& dst_extent = merge_op.dst_extent();
+    // In place copy are basically noops, they do not need to be "merged" at
+    // all, don't include them in merge sequence.
+    if (merge_op.type() == CowMergeOperation::COW_COPY &&
+        merge_op.src_extent() == merge_op.dst_extent()) {
+      continue;
+    }
+    // libsnapshot doesn't like us include REPLACE blocks in merge sequence,
+    // since we don't support XOR ops at this CL, skip them! Remove once we
+    // write XOR ops.
+    if (merge_op.type() == CowMergeOperation::COW_XOR) {
+      continue;
+    }
+    // libsnapshot prefers blocks in reverse order
+    for (int i = dst_extent.num_blocks() - 1; i >= 0; i--) {
+      blocks_merge_order.push_back(dst_extent.start_block() + i);
+    }
+  }
+  return cow_writer->AddSequenceData(blocks_merge_order.size(),
+                                     blocks_merge_order.data());
+}
+
 bool VABCPartitionWriter::WriteAllCowOps(
     size_t block_size,
     const std::vector<CowOperation>& converted,
-    android::snapshot::ICowWriter* cow_writer,
+    ICowWriter* cow_writer,
     FileDescriptorPtr source_fd) {
   std::vector<uint8_t> buffer(block_size);
 
diff --git a/payload_consumer/vabc_partition_writer.h b/payload_consumer/vabc_partition_writer.h
index e8601a9..c73bd4d 100644
--- a/payload_consumer/vabc_partition_writer.h
+++ b/payload_consumer/vabc_partition_writer.h
@@ -34,8 +34,7 @@
   VABCPartitionWriter(const PartitionUpdate& partition_update,
                       const InstallPlan::Partition& install_part,
                       DynamicPartitionControlInterface* dynamic_control,
-                      size_t block_size,
-                      bool is_interactive);
+                      size_t block_size);
   [[nodiscard]] bool Init(const InstallPlan* install_plan,
                           bool source_may_exist,
                           size_t next_op_index) override;
@@ -72,11 +71,14 @@
 
   [[nodiscard]] bool FinishedInstallOps() override;
   int Close() override;
+  // Send merge sequence data to cow writer
+  static bool WriteMergeSequence(
+      const ::google::protobuf::RepeatedPtrField<CowMergeOperation>& merge_ops,
+      android::snapshot::ICowWriter* cow_writer);
 
  private:
   std::unique_ptr<android::snapshot::ISnapshotWriter> cow_writer_;
 
-  bool OpenCurrentECCPartition();
   [[nodiscard]] std::unique_ptr<ExtentWriter> CreateBaseExtentWriter();
 
   const PartitionUpdate& partition_update_;
@@ -85,7 +87,6 @@
   // Path to source partition
   std::string source_path_;
 
-  const bool interactive_;
   const size_t block_size_;
   InstallOperationExecutor executor_;
   VerifiedSourceFd verified_source_fd_;