Write blocks in increasing order if src/dst extent start at same block

This is because xor ops can have non-zero offsets, which means dst block
depends on src_block and the block right after that.

Test: th
Bug: 200076590
Bug: 177104308

Change-Id: I9f40a52ff667ebc5f1b334d9d204ac2d5ccb2c6b
diff --git a/payload_consumer/vabc_partition_writer.cc b/payload_consumer/vabc_partition_writer.cc
index 07eff92..6ca94c1 100644
--- a/payload_consumer/vabc_partition_writer.cc
+++ b/payload_consumer/vabc_partition_writer.cc
@@ -170,7 +170,7 @@
     // If this is self-overlapping op and |dst_extent| comes before
     // |src_extent|, we must write in ascending order for correctness.
     if (ExtentRanges::ExtentsOverlap(src_extent, dst_extent) &&
-        dst_extent.start_block() < src_extent.start_block()) {
+        dst_extent.start_block() <= src_extent.start_block()) {
       for (size_t i = 0; i < dst_extent.num_blocks(); i++) {
         blocks_merge_order.push_back(dst_extent.start_block() + i);
       }
diff --git a/payload_consumer/vabc_partition_writer_unittest.cc b/payload_consumer/vabc_partition_writer_unittest.cc
index a39098a..7a3fc9b 100644
--- a/payload_consumer/vabc_partition_writer_unittest.cc
+++ b/payload_consumer/vabc_partition_writer_unittest.cc
@@ -50,10 +50,10 @@
   void SetUp() override { ftruncate(source_part_.fd, FAKE_PART_SIZE); }
 
  protected:
-  void AddMergeOp(PartitionUpdate* partition,
-                  std::array<size_t, 2> src_extent,
-                  std::array<size_t, 2> dst_extent,
-                  CowMergeOperation_Type type) {
+  CowMergeOperation* AddMergeOp(PartitionUpdate* partition,
+                                std::array<size_t, 2> src_extent,
+                                std::array<size_t, 2> dst_extent,
+                                CowMergeOperation_Type type) {
     auto merge_op = partition->add_merge_operations();
     auto src = merge_op->mutable_src_extent();
     src->set_start_block(src_extent[0]);
@@ -62,6 +62,7 @@
     dst->set_start_block(dst_extent[0]);
     dst->set_num_blocks(dst_extent[1]);
     merge_op->set_type(type);
+    return merge_op;
   }
 
   android::snapshot::CowOptions options_ = {
@@ -103,6 +104,29 @@
   ASSERT_TRUE(writer_.Init(&install_plan_, true, 0));
 }
 
+TEST_F(VABCPartitionWriterTest, MergeSequenceXorSameBlock) {
+  AddMergeOp(&partition_update_, {19, 4}, {19, 3}, CowMergeOperation::COW_XOR)
+      ->set_src_offset(1);
+  VABCPartitionWriter writer_{
+      partition_update_, install_part_, &dynamic_control_, kBlockSize};
+  EXPECT_CALL(dynamic_control_, OpenCowWriter(fake_part_name, _, false))
+      .WillOnce(Invoke(
+          [](const std::string&, const std::optional<std::string>&, bool) {
+            auto cow_writer =
+                std::make_unique<android::snapshot::MockSnapshotWriter>(
+                    android::snapshot::CowOptions{});
+            auto expected_merge_sequence = {19, 20, 21};
+            EXPECT_CALL(*cow_writer, Initialize()).WillOnce(Return(true));
+            EXPECT_CALL(*cow_writer, EmitSequenceData(_, _))
+                .With(Args<1, 0>(ElementsAreArray(expected_merge_sequence)))
+                .WillOnce(Return(true));
+            ON_CALL(*cow_writer, EmitCopy(_, _)).WillByDefault(Return(true));
+            ON_CALL(*cow_writer, EmitLabel(_)).WillByDefault(Return(true));
+            return cow_writer;
+          }));
+  ASSERT_TRUE(writer_.Init(&install_plan_, true, 0));
+}
+
 TEST_F(VABCPartitionWriterTest, EmitBlockTest) {
   AddMergeOp(&partition_update_, {5, 1}, {10, 1}, CowMergeOperation::COW_COPY);
   AddMergeOp(&partition_update_, {10, 1}, {15, 1}, CowMergeOperation::COW_COPY);