Write cow merge sequence at beginning of update

As part of the design for go/vabc-xor , update_engine needs to
tell libsnapshot what the merge sequence is. To do that, we represent
the merge sequence with increasing block numbers(of new partitions),
and hand the giant array to libsnapshot.

Test: th
Bug: 177104308

Change-Id: Idd74ed54a8bf74443c40d8c2025657fd7c35561d
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_;