Merge "Revert "Revert "Remove unused String8::setPathName."""
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 3d63a44..abd2483 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -15,7 +15,10 @@
 //
 
 package {
-    default_applicable_licenses: ["system_core_fs_mgr_license"],
+    default_applicable_licenses: [
+        "Android-Apache-2.0",
+        "system_core_fs_mgr_license",
+    ],
 }
 
 // Added automatically by a large-scale-change that took the approach of
@@ -36,10 +39,9 @@
     name: "system_core_fs_mgr_license",
     visibility: [":__subpackages__"],
     license_kinds: [
-        "SPDX-license-identifier-Apache-2.0",
         "SPDX-license-identifier-MIT",
     ],
-    // large-scale-change unable to identify any license_text files
+    license_text: ["NOTICE"],
 }
 
 cc_defaults {
diff --git a/fs_mgr/NOTICE b/fs_mgr/NOTICE
new file mode 100644
index 0000000..3972a40
--- /dev/null
+++ b/fs_mgr/NOTICE
@@ -0,0 +1,21 @@
+Copyright (C) 2016 The Android Open Source Project
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index 8314ec5..541f254 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -684,13 +684,9 @@
 TEST(libdm, CreateEmptyDevice) {
     DeviceMapper& dm = DeviceMapper::Instance();
     ASSERT_TRUE(dm.CreateEmptyDevice("empty-device"));
-    auto guard = android::base::make_scope_guard([&]() { dm.DeleteDevice("empty-device", 5s); });
+    auto guard =
+            android::base::make_scope_guard([&]() { dm.DeleteDeviceIfExists("empty-device", 5s); });
 
     // Empty device should be in suspended state.
     ASSERT_EQ(DmDeviceState::SUSPENDED, dm.GetState("empty-device"));
-
-    std::string path;
-    ASSERT_TRUE(dm.WaitForDevice("empty-device", 5s, &path));
-    // Path should exist.
-    ASSERT_EQ(0, access(path.c_str(), F_OK));
 }
diff --git a/fs_mgr/libfiemap/split_fiemap_writer.cpp b/fs_mgr/libfiemap/split_fiemap_writer.cpp
index 36bb3df..8457066 100644
--- a/fs_mgr/libfiemap/split_fiemap_writer.cpp
+++ b/fs_mgr/libfiemap/split_fiemap_writer.cpp
@@ -136,6 +136,7 @@
             return FiemapStatus::FromErrno(errno);
         }
     }
+    fsync(fd.get());
 
     // Unset this bit, so we don't unlink on destruction.
     out->creating_ = false;
diff --git a/fs_mgr/libsnapshot/cow_api_test.cpp b/fs_mgr/libsnapshot/cow_api_test.cpp
index b75b154..7f7e40a 100644
--- a/fs_mgr/libsnapshot/cow_api_test.cpp
+++ b/fs_mgr/libsnapshot/cow_api_test.cpp
@@ -981,6 +981,137 @@
     ASSERT_EQ(num_clusters, 1);
 }
 
+TEST_F(CowTest, BigSeqOp) {
+    CowOptions options;
+    CowWriter writer(options);
+    const int seq_len = std::numeric_limits<uint16_t>::max() / sizeof(uint32_t) + 1;
+    uint32_t sequence[seq_len];
+    for (int i = 0; i < seq_len; i++) {
+        sequence[i] = i + 1;
+    }
+
+    ASSERT_TRUE(writer.Initialize(cow_->fd));
+
+    ASSERT_TRUE(writer.AddSequenceData(seq_len, sequence));
+    ASSERT_TRUE(writer.AddZeroBlocks(1, seq_len));
+    ASSERT_TRUE(writer.Finalize());
+
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    CowReader reader;
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+    auto iter = reader.GetRevMergeOpIter();
+
+    for (int i = 0; i < seq_len; i++) {
+        ASSERT_TRUE(!iter->Done());
+        const auto& op = iter->Get();
+
+        ASSERT_EQ(op.new_block, seq_len - i);
+
+        iter->Next();
+    }
+    ASSERT_TRUE(iter->Done());
+}
+
+TEST_F(CowTest, RevMergeOpItrTest) {
+    CowOptions options;
+    options.cluster_ops = 5;
+    options.num_merge_ops = 1;
+    CowWriter writer(options);
+    uint32_t sequence[] = {2, 10, 6, 7, 3, 5};
+
+    ASSERT_TRUE(writer.Initialize(cow_->fd));
+
+    ASSERT_TRUE(writer.AddSequenceData(6, sequence));
+    ASSERT_TRUE(writer.AddCopy(6, 3));
+    ASSERT_TRUE(writer.AddZeroBlocks(12, 1));
+    ASSERT_TRUE(writer.AddZeroBlocks(8, 1));
+    ASSERT_TRUE(writer.AddZeroBlocks(11, 1));
+    ASSERT_TRUE(writer.AddCopy(3, 5));
+    ASSERT_TRUE(writer.AddCopy(2, 1));
+    ASSERT_TRUE(writer.AddZeroBlocks(4, 1));
+    ASSERT_TRUE(writer.AddZeroBlocks(9, 1));
+    ASSERT_TRUE(writer.AddCopy(5, 6));
+    ASSERT_TRUE(writer.AddZeroBlocks(1, 1));
+    ASSERT_TRUE(writer.AddCopy(10, 2));
+    ASSERT_TRUE(writer.AddCopy(7, 4));
+    ASSERT_TRUE(writer.Finalize());
+
+    // New block in cow order is 6, 12, 8, 11, 3, 2, 4, 9, 5, 1, 10, 7
+    // New block in merge order is 2, 10, 6, 7, 3, 5, 12, 11, 9, 8, 4, 1
+    // RevMergeOrder is 1, 4, 8, 9, 11, 12, 5, 3, 7, 6, 10, 2
+    // new block 2 is "already merged", so will be left out.
+
+    std::vector<uint64_t> revMergeOpSequence = {1, 4, 8, 9, 11, 12, 5, 3, 7, 6, 10};
+
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    CowReader reader;
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+    auto iter = reader.GetRevMergeOpIter();
+    auto expected_new_block = revMergeOpSequence.begin();
+
+    while (!iter->Done() && expected_new_block != revMergeOpSequence.end()) {
+        const auto& op = iter->Get();
+
+        ASSERT_EQ(op.new_block, *expected_new_block);
+
+        iter->Next();
+        expected_new_block++;
+    }
+    ASSERT_EQ(expected_new_block, revMergeOpSequence.end());
+    ASSERT_TRUE(iter->Done());
+}
+
+TEST_F(CowTest, LegacyRevMergeOpItrTest) {
+    CowOptions options;
+    options.cluster_ops = 5;
+    options.num_merge_ops = 1;
+    CowWriter writer(options);
+
+    ASSERT_TRUE(writer.Initialize(cow_->fd));
+
+    ASSERT_TRUE(writer.AddCopy(2, 1));
+    ASSERT_TRUE(writer.AddCopy(10, 2));
+    ASSERT_TRUE(writer.AddCopy(6, 3));
+    ASSERT_TRUE(writer.AddCopy(7, 4));
+    ASSERT_TRUE(writer.AddCopy(3, 5));
+    ASSERT_TRUE(writer.AddCopy(5, 6));
+    ASSERT_TRUE(writer.AddZeroBlocks(12, 1));
+    ASSERT_TRUE(writer.AddZeroBlocks(8, 1));
+    ASSERT_TRUE(writer.AddZeroBlocks(11, 1));
+    ASSERT_TRUE(writer.AddZeroBlocks(4, 1));
+    ASSERT_TRUE(writer.AddZeroBlocks(9, 1));
+    ASSERT_TRUE(writer.AddZeroBlocks(1, 1));
+
+    ASSERT_TRUE(writer.Finalize());
+
+    // New block in cow order is 2, 10, 6, 7, 3, 5, 12, 8, 11, 4, 9, 1
+    // New block in merge order is 2, 10, 6, 7, 3, 5, 12, 11, 9, 8, 4, 1
+    // RevMergeOrder is 1, 4, 8, 9, 11, 12, 5, 3, 7, 6, 10, 2
+    // new block 2 is "already merged", so will be left out.
+
+    std::vector<uint64_t> revMergeOpSequence = {1, 4, 8, 9, 11, 12, 5, 3, 7, 6, 10};
+
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    CowReader reader;
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+    auto iter = reader.GetRevMergeOpIter();
+    auto expected_new_block = revMergeOpSequence.begin();
+
+    while (!iter->Done() && expected_new_block != revMergeOpSequence.end()) {
+        const auto& op = iter->Get();
+
+        ASSERT_EQ(op.new_block, *expected_new_block);
+
+        iter->Next();
+        expected_new_block++;
+    }
+    ASSERT_EQ(expected_new_block, revMergeOpSequence.end());
+    ASSERT_TRUE(iter->Done());
+}
+
 }  // namespace snapshot
 }  // namespace android
 
diff --git a/fs_mgr/libsnapshot/cow_format.cpp b/fs_mgr/libsnapshot/cow_format.cpp
index 0753c49..3085f80 100644
--- a/fs_mgr/libsnapshot/cow_format.cpp
+++ b/fs_mgr/libsnapshot/cow_format.cpp
@@ -37,6 +37,8 @@
         os << "kCowLabelOp,   ";
     else if (op.type == kCowClusterOp)
         os << "kCowClusterOp  ";
+    else if (op.type == kCowSequenceOp)
+        os << "kCowSequenceOp ";
     else if (op.type == kCowFooterOp)
         os << "kCowFooterOp  ";
     else
@@ -81,6 +83,16 @@
         case kCowLabelOp:
         case kCowClusterOp:
         case kCowFooterOp:
+        case kCowSequenceOp:
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool IsOrderedOp(const CowOperation& op) {
+    switch (op.type) {
+        case kCowCopyOp:
             return true;
         default:
             return false;
diff --git a/fs_mgr/libsnapshot/cow_reader.cpp b/fs_mgr/libsnapshot/cow_reader.cpp
index 2349e4a..af49c7d 100644
--- a/fs_mgr/libsnapshot/cow_reader.cpp
+++ b/fs_mgr/libsnapshot/cow_reader.cpp
@@ -19,6 +19,9 @@
 
 #include <limits>
 #include <optional>
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
 #include <vector>
 
 #include <android-base/file.h>
@@ -127,7 +130,10 @@
         return false;
     }
 
-    return ParseOps(label);
+    if (!ParseOps(label)) {
+        return false;
+    }
+    return PrepMergeOps();
 }
 
 bool CowReader::ParseOps(std::optional<uint64_t> label) {
@@ -201,6 +207,8 @@
                 current_op_num--;
                 done = true;
                 break;
+            } else if (current_op.type == kCowSequenceOp) {
+                has_seq_ops_ = true;
             }
         }
 
@@ -251,7 +259,7 @@
             LOG(ERROR) << "ops checksum does not match";
             return false;
         }
-        SHA256(ops_buffer.get()->data(), footer_->op.ops_size, csum);
+        SHA256(ops_buffer->data(), footer_->op.ops_size, csum);
         if (memcmp(csum, footer_->data.ops_checksum, sizeof(csum)) != 0) {
             LOG(ERROR) << "ops checksum does not match";
             return false;
@@ -264,138 +272,166 @@
     return true;
 }
 
-void CowReader::InitializeMerge() {
-    uint64_t num_copy_ops = 0;
+//
+// This sets up the data needed for MergeOpIter. MergeOpIter presents
+// data in the order we intend to merge in.
+//
+// We merge all order sensitive ops up front, and sort the rest to allow for
+// batch merging. Order sensitive ops can either be presented in their proper
+// order in the cow, or be ordered by sequence ops (kCowSequenceOp), in which
+// case we want to merge those ops first, followed by any ops not specified by
+// new_block value by the sequence op, in sorted order.
+// We will re-arrange the vector in such a way that
+// kernel can batch merge. Ex:
+//
+// Existing COW format; All the copy operations
+// are at the beginning.
+// =======================================
+// Copy-op-1    - cow_op->new_block = 1
+// Copy-op-2    - cow_op->new_block = 2
+// Copy-op-3    - cow_op->new_block = 3
+// Replace-op-4 - cow_op->new_block = 6
+// Replace-op-5 - cow_op->new_block = 4
+// Replace-op-6 - cow_op->new_block = 8
+// Replace-op-7 - cow_op->new_block = 9
+// Zero-op-8    - cow_op->new_block = 7
+// Zero-op-9    - cow_op->new_block = 5
+// =======================================
+//
+// First find the operation which isn't a copy-op
+// and then sort all the operations in descending order
+// with the key being cow_op->new_block (source block)
+//
+// The data-structure will look like:
+//
+// =======================================
+// Copy-op-1    - cow_op->new_block = 1
+// Copy-op-2    - cow_op->new_block = 2
+// Copy-op-3    - cow_op->new_block = 3
+// Replace-op-7 - cow_op->new_block = 9
+// Replace-op-6 - cow_op->new_block = 8
+// Zero-op-8    - cow_op->new_block = 7
+// Replace-op-4 - cow_op->new_block = 6
+// Zero-op-9    - cow_op->new_block = 5
+// Replace-op-5 - cow_op->new_block = 4
+// =======================================
+//
+// Daemon will read the above data-structure in reverse-order
+// when reading metadata. Thus, kernel will get the metadata
+// in the following order:
+//
+// ========================================
+// Replace-op-5 - cow_op->new_block = 4
+// Zero-op-9    - cow_op->new_block = 5
+// Replace-op-4 - cow_op->new_block = 6
+// Zero-op-8    - cow_op->new_block = 7
+// Replace-op-6 - cow_op->new_block = 8
+// Replace-op-7 - cow_op->new_block = 9
+// Copy-op-3    - cow_op->new_block = 3
+// Copy-op-2    - cow_op->new_block = 2
+// Copy-op-1    - cow_op->new_block = 1
+// ===========================================
+//
+// When merging begins, kernel will start from the last
+// metadata which was read: In the above format, Copy-op-1
+// will be the first merge operation.
+//
+// Now, batching of the merge operations happens only when
+// 1: origin block numbers in the base device are contiguous
+// (cow_op->new_block) and,
+// 2: cow block numbers which are assigned by daemon in ReadMetadata()
+// are contiguous. These are monotonically increasing numbers.
+//
+// When both (1) and (2) are true, kernel will batch merge the operations.
+// In the above case, we have to ensure that the copy operations
+// are merged first before replace operations are done. Hence,
+// we will not change the order of copy operations. Since,
+// cow_op->new_block numbers are contiguous, we will ensure that the
+// cow block numbers assigned in ReadMetadata() for these respective copy
+// operations are not contiguous forcing kernel to issue merge for each
+// copy operations without batch merging.
+//
+// For all the other operations viz. Replace and Zero op, the cow block
+// numbers assigned by daemon will be contiguous allowing kernel to batch
+// merge.
+//
+// The final format after assiging COW block numbers by the daemon will
+// look something like:
+//
+// =========================================================
+// Replace-op-5 - cow_op->new_block = 4  cow-block-num = 2
+// Zero-op-9    - cow_op->new_block = 5  cow-block-num = 3
+// Replace-op-4 - cow_op->new_block = 6  cow-block-num = 4
+// Zero-op-8    - cow_op->new_block = 7  cow-block-num = 5
+// Replace-op-6 - cow_op->new_block = 8  cow-block-num = 6
+// Replace-op-7 - cow_op->new_block = 9  cow-block-num = 7
+// Copy-op-3    - cow_op->new_block = 3  cow-block-num = 9
+// Copy-op-2    - cow_op->new_block = 2  cow-block-num = 11
+// Copy-op-1    - cow_op->new_block = 1  cow-block-num = 13
+// ==========================================================
+//
+// Merge sequence will look like:
+//
+// Merge-1 - Batch-merge { Copy-op-1, Copy-op-2, Copy-op-3 }
+// Merge-2 - Batch-merge {Replace-op-7, Replace-op-6, Zero-op-8,
+//                        Replace-op-4, Zero-op-9, Replace-op-5 }
+//==============================================================
+bool CowReader::PrepMergeOps() {
+    auto merge_op_blocks = std::make_shared<std::vector<uint32_t>>();
+    std::set<int, std::greater<int>> other_ops;
+    auto seq_ops_set = std::unordered_set<uint32_t>();
+    auto block_map = std::make_shared<std::unordered_map<uint32_t, int>>();
+    size_t num_seqs = 0;
+    size_t read;
 
-    // Remove all the metadata operations
-    ops_->erase(std::remove_if(ops_.get()->begin(), ops_.get()->end(),
-                               [](CowOperation& op) { return IsMetadataOp(op); }),
-                ops_.get()->end());
-
-    set_total_data_ops(ops_->size());
-    // We will re-arrange the vector in such a way that
-    // kernel can batch merge. Ex:
-    //
-    // Existing COW format; All the copy operations
-    // are at the beginning.
-    // =======================================
-    // Copy-op-1    - cow_op->new_block = 1
-    // Copy-op-2    - cow_op->new_block = 2
-    // Copy-op-3    - cow_op->new_block = 3
-    // Replace-op-4 - cow_op->new_block = 6
-    // Replace-op-5 - cow_op->new_block = 4
-    // Replace-op-6 - cow_op->new_block = 8
-    // Replace-op-7 - cow_op->new_block = 9
-    // Zero-op-8    - cow_op->new_block = 7
-    // Zero-op-9    - cow_op->new_block = 5
-    // =======================================
-    //
-    // First find the operation which isn't a copy-op
-    // and then sort all the operations in descending order
-    // with the key being cow_op->new_block (source block)
-    //
-    // The data-structure will look like:
-    //
-    // =======================================
-    // Copy-op-1    - cow_op->new_block = 1
-    // Copy-op-2    - cow_op->new_block = 2
-    // Copy-op-3    - cow_op->new_block = 3
-    // Replace-op-7 - cow_op->new_block = 9
-    // Replace-op-6 - cow_op->new_block = 8
-    // Zero-op-8    - cow_op->new_block = 7
-    // Replace-op-4 - cow_op->new_block = 6
-    // Zero-op-9    - cow_op->new_block = 5
-    // Replace-op-5 - cow_op->new_block = 4
-    // =======================================
-    //
-    // Daemon will read the above data-structure in reverse-order
-    // when reading metadata. Thus, kernel will get the metadata
-    // in the following order:
-    //
-    // ========================================
-    // Replace-op-5 - cow_op->new_block = 4
-    // Zero-op-9    - cow_op->new_block = 5
-    // Replace-op-4 - cow_op->new_block = 6
-    // Zero-op-8    - cow_op->new_block = 7
-    // Replace-op-6 - cow_op->new_block = 8
-    // Replace-op-7 - cow_op->new_block = 9
-    // Copy-op-3    - cow_op->new_block = 3
-    // Copy-op-2    - cow_op->new_block = 2
-    // Copy-op-1    - cow_op->new_block = 1
-    // ===========================================
-    //
-    // When merging begins, kernel will start from the last
-    // metadata which was read: In the above format, Copy-op-1
-    // will be the first merge operation.
-    //
-    // Now, batching of the merge operations happens only when
-    // 1: origin block numbers in the base device are contiguous
-    // (cow_op->new_block) and,
-    // 2: cow block numbers which are assigned by daemon in ReadMetadata()
-    // are contiguous. These are monotonically increasing numbers.
-    //
-    // When both (1) and (2) are true, kernel will batch merge the operations.
-    // In the above case, we have to ensure that the copy operations
-    // are merged first before replace operations are done. Hence,
-    // we will not change the order of copy operations. Since,
-    // cow_op->new_block numbers are contiguous, we will ensure that the
-    // cow block numbers assigned in ReadMetadata() for these respective copy
-    // operations are not contiguous forcing kernel to issue merge for each
-    // copy operations without batch merging.
-    //
-    // For all the other operations viz. Replace and Zero op, the cow block
-    // numbers assigned by daemon will be contiguous allowing kernel to batch
-    // merge.
-    //
-    // The final format after assiging COW block numbers by the daemon will
-    // look something like:
-    //
-    // =========================================================
-    // Replace-op-5 - cow_op->new_block = 4  cow-block-num = 2
-    // Zero-op-9    - cow_op->new_block = 5  cow-block-num = 3
-    // Replace-op-4 - cow_op->new_block = 6  cow-block-num = 4
-    // Zero-op-8    - cow_op->new_block = 7  cow-block-num = 5
-    // Replace-op-6 - cow_op->new_block = 8  cow-block-num = 6
-    // Replace-op-7 - cow_op->new_block = 9  cow-block-num = 7
-    // Copy-op-3    - cow_op->new_block = 3  cow-block-num = 9
-    // Copy-op-2    - cow_op->new_block = 2  cow-block-num = 11
-    // Copy-op-1    - cow_op->new_block = 1  cow-block-num = 13
-    // ==========================================================
-    //
-    // Merge sequence will look like:
-    //
-    // Merge-1 - Batch-merge { Copy-op-1, Copy-op-2, Copy-op-3 }
-    // Merge-2 - Batch-merge {Replace-op-7, Replace-op-6, Zero-op-8,
-    //                        Replace-op-4, Zero-op-9, Replace-op-5 }
-    //==============================================================
-
-    num_copy_ops = FindNumCopyops();
-
-    std::sort(ops_.get()->begin() + num_copy_ops, ops_.get()->end(),
-              [](CowOperation& op1, CowOperation& op2) -> bool {
-                  return op1.new_block > op2.new_block;
-              });
-
-    if (header_.num_merge_ops > 0) {
-        ops_->erase(ops_.get()->begin(), ops_.get()->begin() + header_.num_merge_ops);
-    }
-
-    num_copy_ops = FindNumCopyops();
-    set_copy_ops(num_copy_ops);
-}
-
-uint64_t CowReader::FindNumCopyops() {
-    uint64_t num_copy_ops = 0;
-
-    for (uint64_t i = 0; i < ops_->size(); i++) {
+    for (size_t i = 0; i < ops_->size(); i++) {
         auto& current_op = ops_->data()[i];
-        if (current_op.type != kCowCopyOp) {
-            break;
+
+        if (current_op.type == kCowSequenceOp) {
+            size_t seq_len = current_op.data_length / sizeof(uint32_t);
+
+            merge_op_blocks->resize(merge_op_blocks->size() + seq_len);
+            if (!GetRawBytes(current_op.source, &merge_op_blocks->data()[num_seqs],
+                             current_op.data_length, &read)) {
+                PLOG(ERROR) << "Failed to read sequence op!";
+                return false;
+            }
+            for (size_t j = num_seqs; j < num_seqs + seq_len; j++) {
+                seq_ops_set.insert(merge_op_blocks->data()[j]);
+            }
+            num_seqs += seq_len;
         }
-        num_copy_ops += 1;
+
+        if (IsMetadataOp(current_op)) {
+            continue;
+        }
+
+        if (!has_seq_ops_ && IsOrderedOp(current_op)) {
+            merge_op_blocks->emplace_back(current_op.new_block);
+        } else if (seq_ops_set.count(current_op.new_block) == 0) {
+            other_ops.insert(current_op.new_block);
+        }
+        block_map->insert({current_op.new_block, i});
+    }
+    if (merge_op_blocks->size() > header_.num_merge_ops) {
+        num_ordered_ops_to_merge_ = merge_op_blocks->size() - header_.num_merge_ops;
+    } else {
+        num_ordered_ops_to_merge_ = 0;
+    }
+    merge_op_blocks->reserve(merge_op_blocks->size() + other_ops.size());
+    for (auto block : other_ops) {
+        merge_op_blocks->emplace_back(block);
     }
 
-    return num_copy_ops;
+    num_total_data_ops_ = merge_op_blocks->size();
+    if (header_.num_merge_ops > 0) {
+        merge_op_blocks->erase(merge_op_blocks->begin(),
+                               merge_op_blocks->begin() + header_.num_merge_ops);
+    }
+
+    block_map_ = block_map;
+    merge_op_blocks_ = merge_op_blocks;
+    return true;
 }
 
 bool CowReader::GetHeader(CowHeader* header) {
@@ -430,11 +466,11 @@
 
 CowOpIter::CowOpIter(std::shared_ptr<std::vector<CowOperation>>& ops) {
     ops_ = ops;
-    op_iter_ = ops_.get()->begin();
+    op_iter_ = ops_->begin();
 }
 
 bool CowOpIter::Done() {
-    return op_iter_ == ops_.get()->end();
+    return op_iter_ == ops_->end();
 }
 
 void CowOpIter::Next() {
@@ -447,9 +483,11 @@
     return (*op_iter_);
 }
 
-class CowOpReverseIter final : public ICowOpReverseIter {
+class CowRevMergeOpIter final : public ICowOpIter {
   public:
-    explicit CowOpReverseIter(std::shared_ptr<std::vector<CowOperation>> ops);
+    explicit CowRevMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
+                               std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
+                               std::shared_ptr<std::unordered_map<uint32_t, int>> map);
 
     bool Done() override;
     const CowOperation& Get() override;
@@ -457,34 +495,41 @@
 
   private:
     std::shared_ptr<std::vector<CowOperation>> ops_;
-    std::vector<CowOperation>::reverse_iterator op_riter_;
+    std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
+    std::shared_ptr<std::unordered_map<uint32_t, int>> map_;
+    std::vector<uint32_t>::reverse_iterator block_riter_;
 };
 
-CowOpReverseIter::CowOpReverseIter(std::shared_ptr<std::vector<CowOperation>> ops) {
+CowRevMergeOpIter::CowRevMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
+                                     std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
+                                     std::shared_ptr<std::unordered_map<uint32_t, int>> map) {
     ops_ = ops;
-    op_riter_ = ops_.get()->rbegin();
+    merge_op_blocks_ = merge_op_blocks;
+    map_ = map;
+
+    block_riter_ = merge_op_blocks->rbegin();
 }
 
-bool CowOpReverseIter::Done() {
-    return op_riter_ == ops_.get()->rend();
+bool CowRevMergeOpIter::Done() {
+    return block_riter_ == merge_op_blocks_->rend();
 }
 
-void CowOpReverseIter::Next() {
+void CowRevMergeOpIter::Next() {
     CHECK(!Done());
-    op_riter_++;
+    block_riter_++;
 }
 
-const CowOperation& CowOpReverseIter::Get() {
+const CowOperation& CowRevMergeOpIter::Get() {
     CHECK(!Done());
-    return (*op_riter_);
+    return ops_->data()[map_->at(*block_riter_)];
 }
 
 std::unique_ptr<ICowOpIter> CowReader::GetOpIter() {
     return std::make_unique<CowOpIter>(ops_);
 }
 
-std::unique_ptr<ICowOpReverseIter> CowReader::GetRevOpIter() {
-    return std::make_unique<CowOpReverseIter>(ops_);
+std::unique_ptr<ICowOpIter> CowReader::GetRevMergeOpIter() {
+    return std::make_unique<CowRevMergeOpIter>(ops_, merge_op_blocks_, block_map_);
 }
 
 bool CowReader::GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read) {
diff --git a/fs_mgr/libsnapshot/cow_writer.cpp b/fs_mgr/libsnapshot/cow_writer.cpp
index 526fede..ef30e32 100644
--- a/fs_mgr/libsnapshot/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/cow_writer.cpp
@@ -58,8 +58,8 @@
     return EmitRawBlocks(new_block_start, data, size);
 }
 
-bool AddXorBlocks(uint32_t /*new_block_start*/, const void* /*data*/, size_t /*size*/,
-                  uint32_t /*old_block*/, uint16_t /*offset*/) {
+bool ICowWriter::AddXorBlocks(uint32_t /*new_block_start*/, const void* /*data*/, size_t /*size*/,
+                              uint32_t /*old_block*/, uint16_t /*offset*/) {
     LOG(ERROR) << "AddXorBlocks not yet implemented";
     return false;
 }
@@ -76,9 +76,8 @@
     return EmitLabel(label);
 }
 
-bool ICowWriter::AddSequenceData(size_t /*num_ops*/, const uint32_t* /*data*/) {
-    LOG(ERROR) << "AddSequenceData not yet implemented";
-    return false;
+bool ICowWriter::AddSequenceData(size_t num_ops, const uint32_t* data) {
+    return EmitSequenceData(num_ops, data);
 }
 
 bool ICowWriter::ValidateNewBlock(uint64_t new_block) {
@@ -103,7 +102,7 @@
     header_.footer_size = sizeof(CowFooter);
     header_.op_size = sizeof(CowOperation);
     header_.block_size = options_.block_size;
-    header_.num_merge_ops = 0;
+    header_.num_merge_ops = options_.num_merge_ops;
     header_.cluster_ops = options_.cluster_ops;
     header_.buffer_size = 0;
     footer_ = {};
@@ -337,6 +336,26 @@
     return WriteOperation(op) && Sync();
 }
 
+bool CowWriter::EmitSequenceData(size_t num_ops, const uint32_t* data) {
+    CHECK(!merge_in_progress_);
+    size_t to_add = 0;
+    size_t max_ops = std::numeric_limits<uint16_t>::max() / sizeof(uint32_t);
+    while (num_ops > 0) {
+        CowOperation op = {};
+        op.type = kCowSequenceOp;
+        op.source = next_data_pos_;
+        to_add = std::min(num_ops, max_ops);
+        op.data_length = static_cast<uint16_t>(to_add * sizeof(uint32_t));
+        if (!WriteOperation(op, data, op.data_length)) {
+            PLOG(ERROR) << "AddSequenceData: write failed";
+            return false;
+        }
+        num_ops -= to_add;
+        data += to_add;
+    }
+    return true;
+}
+
 bool CowWriter::EmitCluster() {
     CowOperation op = {};
     op.type = kCowClusterOp;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
index 000e5e1..464046b 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
@@ -148,6 +148,7 @@
 static constexpr uint8_t kCowZeroOp = 3;
 static constexpr uint8_t kCowLabelOp = 4;
 static constexpr uint8_t kCowClusterOp = 5;
+static constexpr uint8_t kCowSequenceOp = 7;
 static constexpr uint8_t kCowFooterOp = -1;
 
 static constexpr uint8_t kCowCompressNone = 0;
@@ -184,7 +185,10 @@
 int64_t GetNextOpOffset(const CowOperation& op, uint32_t cluster_size);
 int64_t GetNextDataOffset(const CowOperation& op, uint32_t cluster_size);
 
+// Ops that are internal to the Cow Format and not OTA data
 bool IsMetadataOp(const CowOperation& op);
+// Ops that have dependencies on old blocks, and must take care in their merge order
+bool IsOrderedOp(const CowOperation& op);
 
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index 669e58a..6c3059c 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -19,6 +19,7 @@
 #include <functional>
 #include <memory>
 #include <optional>
+#include <unordered_map>
 
 #include <android-base/unique_fd.h>
 #include <libsnapshot/cow_format.h>
@@ -27,7 +28,6 @@
 namespace snapshot {
 
 class ICowOpIter;
-class ICowOpReverseIter;
 
 // A ByteSink object handles requests for a buffer of a specific size. It
 // always owns the underlying buffer. It's designed to minimize potential
@@ -75,8 +75,8 @@
     // Return an iterator for retrieving CowOperation entries.
     virtual std::unique_ptr<ICowOpIter> GetOpIter() = 0;
 
-    // Return an reverse iterator for retrieving CowOperation entries.
-    virtual std::unique_ptr<ICowOpReverseIter> GetRevOpIter() = 0;
+    // Return an iterator for retrieving CowOperation entries in merge order
+    virtual std::unique_ptr<ICowOpIter> GetRevMergeOpIter() = 0;
 
     // Get decoded bytes from the data section, handling any decompression.
     // All retrieved data is passed to the sink.
@@ -98,21 +98,6 @@
     virtual void Next() = 0;
 };
 
-// Reverse Iterate over a sequence of COW operations.
-class ICowOpReverseIter {
-  public:
-    virtual ~ICowOpReverseIter() {}
-
-    // True if there are more items to read, false otherwise.
-    virtual bool Done() = 0;
-
-    // Read the current operation.
-    virtual const CowOperation& Get() = 0;
-
-    // Advance to the next item.
-    virtual void Next() = 0;
-};
-
 class CowReader : public ICowReader {
   public:
     CowReader();
@@ -135,25 +120,25 @@
     // whose lifetime depends on the CowOpIter object; the return
     // value of these will never be null.
     std::unique_ptr<ICowOpIter> GetOpIter() override;
-    std::unique_ptr<ICowOpReverseIter> GetRevOpIter() override;
+    std::unique_ptr<ICowOpIter> GetRevMergeOpIter() override;
 
     bool ReadData(const CowOperation& op, IByteSink* sink) override;
 
     bool GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read);
 
-    void InitializeMerge();
+    // Returns the total number of data ops that should be merged. This is the
+    // count of the merge sequence before removing already-merged operations.
+    // It may be different than the actual data op count, for example, if there
+    // are duplicate ops in the stream.
+    uint64_t get_num_total_data_ops() { return num_total_data_ops_; }
 
-    // Number of copy, replace, and zero ops. Set if InitializeMerge is called.
-    void set_total_data_ops(uint64_t size) { total_data_ops_ = size; }
-    uint64_t total_data_ops() { return total_data_ops_; }
-    // Number of copy ops. Set if InitializeMerge is called.
-    void set_copy_ops(uint64_t size) { copy_ops_ = size; }
-    uint64_t total_copy_ops() { return copy_ops_; }
+    uint64_t get_num_ordered_ops_to_merge() { return num_ordered_ops_to_merge_; }
 
     void CloseCowFd() { owned_fd_ = {}; }
 
   private:
     bool ParseOps(std::optional<uint64_t> label);
+    bool PrepMergeOps();
     uint64_t FindNumCopyops();
 
     android::base::unique_fd owned_fd_;
@@ -163,8 +148,11 @@
     uint64_t fd_size_;
     std::optional<uint64_t> last_label_;
     std::shared_ptr<std::vector<CowOperation>> ops_;
-    uint64_t total_data_ops_;
-    uint64_t copy_ops_;
+    std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
+    std::shared_ptr<std::unordered_map<uint32_t, int>> block_map_;
+    uint64_t num_total_data_ops_;
+    uint64_t num_ordered_ops_to_merge_;
+    bool has_seq_ops_;
 };
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index fbe6461..4a807fb 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -38,6 +38,9 @@
     uint32_t cluster_ops = 200;
 
     bool scratch_space = true;
+
+    // Preset the number of merged ops. Only useful for testing.
+    uint64_t num_merge_ops = 0;
 };
 
 // Interface for writing to a snapuserd COW. All operations are ordered; merges
@@ -85,6 +88,7 @@
     virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) = 0;
     virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) = 0;
     virtual bool EmitLabel(uint64_t label) = 0;
+    virtual bool EmitSequenceData(size_t num_ops, const uint32_t* data) = 0;
 
     bool ValidateNewBlock(uint64_t new_block);
 
@@ -120,6 +124,7 @@
     virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
     virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
     virtual bool EmitLabel(uint64_t label) override;
+    virtual bool EmitSequenceData(size_t num_ops, const uint32_t* data) override;
 
   private:
     bool EmitCluster();
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
new file mode 100644
index 0000000..0457986
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
@@ -0,0 +1,52 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <gmock/gmock.h>
+#include <libsnapshot/snapshot_writer.h>
+
+namespace android::snapshot {
+
+class MockSnapshotWriter : public ISnapshotWriter {
+  public:
+    using FileDescriptor = ISnapshotWriter::FileDescriptor;
+
+    explicit MockSnapshotWriter(const CowOptions& options) : ISnapshotWriter(options) {}
+    MockSnapshotWriter() : ISnapshotWriter({}) {}
+
+    MOCK_METHOD(bool, Finalize, (), (override));
+
+    // Return number of bytes the cow image occupies on disk.
+    MOCK_METHOD(uint64_t, GetCowSize, (), (override));
+
+    // Returns true if AddCopy() operations are supported.
+    MOCK_METHOD(bool, SupportsCopyOperation, (), (const override));
+
+    MOCK_METHOD(bool, EmitCopy, (uint64_t, uint64_t), (override));
+    MOCK_METHOD(bool, EmitRawBlocks, (uint64_t, const void*, size_t), (override));
+    MOCK_METHOD(bool, EmitZeroBlocks, (uint64_t, uint64_t), (override));
+    MOCK_METHOD(bool, EmitLabel, (uint64_t), (override));
+    MOCK_METHOD(bool, EmitSequenceData, (size_t, const uint32_t*), (override));
+
+    // Open the writer in write mode (no append).
+    MOCK_METHOD(bool, Initialize, (), (override));
+
+    // Open the writer in append mode, with the last label to resume
+    // from. See CowWriter::InitializeAppend.
+    MOCK_METHOD(bool, InitializeAppend, (uint64_t label), (override));
+
+    MOCK_METHOD(std::unique_ptr<FileDescriptor>, OpenReader, (), (override));
+};
+}  // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
index bf5ce8b..c00dafa 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
@@ -76,6 +76,7 @@
     bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
     bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
     bool EmitLabel(uint64_t label) override;
+    bool EmitSequenceData(size_t num_ops, const uint32_t* data) override;
 
   private:
     android::base::unique_fd cow_device_;
@@ -103,6 +104,7 @@
     bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
     bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
     bool EmitLabel(uint64_t label) override;
+    bool EmitSequenceData(size_t num_ops, const uint32_t* data) override;
 
   private:
     android::base::unique_fd snapshot_fd_;
diff --git a/fs_mgr/libsnapshot/inspect_cow.cpp b/fs_mgr/libsnapshot/inspect_cow.cpp
index 1dc61af..ed86c87 100644
--- a/fs_mgr/libsnapshot/inspect_cow.cpp
+++ b/fs_mgr/libsnapshot/inspect_cow.cpp
@@ -40,8 +40,18 @@
     LOG(ERROR) << "\t -s Run Silent";
     LOG(ERROR) << "\t -d Attempt to decompress";
     LOG(ERROR) << "\t -b Show data for failed decompress\n";
+    LOG(ERROR) << "\t -m Show ops in reverse merge order\n";
 }
 
+enum OpIter { Normal, RevMerge };
+
+struct Options {
+    bool silent;
+    bool decompress;
+    bool show_bad;
+    OpIter iter_type;
+};
+
 // Sink that always appends to the end of a string.
 class StringSink : public IByteSink {
   public:
@@ -78,7 +88,7 @@
     }
 }
 
-static bool Inspect(const std::string& path, bool silent, bool decompress, bool show_bad) {
+static bool Inspect(const std::string& path, Options opt) {
     android::base::unique_fd fd(open(path.c_str(), O_RDONLY));
     if (fd < 0) {
         PLOG(ERROR) << "open failed: " << path;
@@ -100,7 +110,7 @@
     bool has_footer = false;
     if (reader.GetFooter(&footer)) has_footer = true;
 
-    if (!silent) {
+    if (!opt.silent) {
         std::cout << "Major version: " << header.major_version << "\n";
         std::cout << "Minor version: " << header.minor_version << "\n";
         std::cout << "Header size: " << header.header_size << "\n";
@@ -116,19 +126,24 @@
         }
     }
 
-    auto iter = reader.GetOpIter();
+    std::unique_ptr<ICowOpIter> iter;
+    if (opt.iter_type == Normal) {
+        iter = reader.GetOpIter();
+    } else if (opt.iter_type == RevMerge) {
+        iter = reader.GetRevMergeOpIter();
+    }
     StringSink sink;
     bool success = true;
     while (!iter->Done()) {
         const CowOperation& op = iter->Get();
 
-        if (!silent) std::cout << op << "\n";
+        if (!opt.silent) std::cout << op << "\n";
 
-        if (decompress && op.type == kCowReplaceOp && op.compression != kCowCompressNone) {
+        if (opt.decompress && op.type == kCowReplaceOp && op.compression != kCowCompressNone) {
             if (!reader.ReadData(op, &sink)) {
                 std::cerr << "Failed to decompress for :" << op << "\n";
                 success = false;
-                if (show_bad) ShowBad(reader, op);
+                if (opt.show_bad) ShowBad(reader, op);
             }
             sink.Reset();
         }
@@ -144,19 +159,24 @@
 
 int main(int argc, char** argv) {
     int ch;
-    bool silent = false;
-    bool decompress = false;
-    bool show_bad = false;
-    while ((ch = getopt(argc, argv, "sdb")) != -1) {
+    struct android::snapshot::Options opt;
+    opt.silent = false;
+    opt.decompress = false;
+    opt.show_bad = false;
+    opt.iter_type = android::snapshot::Normal;
+    while ((ch = getopt(argc, argv, "sdbm")) != -1) {
         switch (ch) {
             case 's':
-                silent = true;
+                opt.silent = true;
                 break;
             case 'd':
-                decompress = true;
+                opt.decompress = true;
                 break;
             case 'b':
-                show_bad = true;
+                opt.show_bad = true;
+                break;
+            case 'm':
+                opt.iter_type = android::snapshot::RevMerge;
                 break;
             default:
                 android::snapshot::usage();
@@ -169,7 +189,7 @@
         return 1;
     }
 
-    if (!android::snapshot::Inspect(argv[optind], silent, decompress, show_bad)) {
+    if (!android::snapshot::Inspect(argv[optind], opt)) {
         return 1;
     }
     return 0;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 0e36da1..c3db32e 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -1193,11 +1193,7 @@
             return MergeFailureCode::ParseCowConsistencyCheck;
         }
 
-        for (auto iter = reader.GetOpIter(); !iter->Done(); iter->Next()) {
-            if (!IsMetadataOp(iter->Get())) {
-                num_ops++;
-            }
-        }
+        num_ops = reader.get_num_total_data_ops();
     }
 
     // Second pass, try as hard as we can to get the actual number of blocks
@@ -2534,6 +2530,7 @@
         SnapshotUpdateStatus old_status = ReadSnapshotUpdateStatus(lock);
         status.set_compression_enabled(old_status.compression_enabled());
         status.set_source_build_fingerprint(old_status.source_build_fingerprint());
+        status.set_merge_phase(old_status.merge_phase());
     }
     return WriteSnapshotUpdateStatus(lock, status);
 }
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 6018643..b2203fe 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1184,6 +1184,53 @@
     }
 }
 
+TEST_F(SnapshotUpdateTest, DuplicateOps) {
+    if (!IsCompressionEnabled()) {
+        GTEST_SKIP() << "Compression-only test";
+    }
+
+    // OTA client blindly unmaps all partitions that are possibly mapped.
+    for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+        ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
+    }
+
+    // Execute the update.
+    ASSERT_TRUE(sm->BeginUpdate());
+    ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
+
+    // Write some data to target partitions.
+    for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+        ASSERT_TRUE(WriteSnapshotAndHash(name));
+    }
+
+    std::vector<PartitionUpdate*> partitions = {sys_, vnd_, prd_};
+    for (auto* partition : partitions) {
+        AddOperation(partition);
+
+        std::unique_ptr<ISnapshotWriter> writer;
+        auto res = MapUpdateSnapshot(partition->partition_name() + "_b", &writer);
+        ASSERT_TRUE(res);
+        ASSERT_TRUE(writer->AddZeroBlocks(0, 1));
+        ASSERT_TRUE(writer->AddZeroBlocks(0, 1));
+        ASSERT_TRUE(writer->Finalize());
+    }
+
+    ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
+
+    // Simulate shutting down the device.
+    ASSERT_TRUE(UnmapAll());
+
+    // After reboot, init does first stage mount.
+    auto init = NewManagerForFirstStageMount("_b");
+    ASSERT_NE(init, nullptr);
+    ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
+
+    // Initiate the merge and wait for it to be completed.
+    ASSERT_TRUE(init->InitiateMerge());
+    ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
+}
+
 // Test that shrinking and growing partitions at the same time is handled
 // correctly in VABC.
 TEST_F(SnapshotUpdateTest, SpaceSwapUpdate) {
diff --git a/fs_mgr/libsnapshot/snapshot_writer.cpp b/fs_mgr/libsnapshot/snapshot_writer.cpp
index 080f3b7..34b3e87 100644
--- a/fs_mgr/libsnapshot/snapshot_writer.cpp
+++ b/fs_mgr/libsnapshot/snapshot_writer.cpp
@@ -114,6 +114,10 @@
     return cow_->AddLabel(label);
 }
 
+bool CompressedSnapshotWriter::EmitSequenceData(size_t num_ops, const uint32_t* data) {
+    return cow_->AddSequenceData(num_ops, data);
+}
+
 bool CompressedSnapshotWriter::Initialize() {
     return cow_->Initialize(cow_device_);
 }
@@ -183,6 +187,11 @@
     return true;
 }
 
+bool OnlineKernelSnapshotWriter::EmitSequenceData(size_t, const uint32_t*) {
+    // Not Needed
+    return true;
+}
+
 std::unique_ptr<FileDescriptor> OnlineKernelSnapshotWriter::OpenReader() {
     unique_fd fd(dup(snapshot_fd_.get()));
     if (fd < 0) {
diff --git a/fs_mgr/libsnapshot/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd.cpp
index 03c2ef6..a09b111 100644
--- a/fs_mgr/libsnapshot/snapuserd.cpp
+++ b/fs_mgr/libsnapshot/snapuserd.cpp
@@ -64,7 +64,7 @@
 
     int ret = msync(mapped_addr_, BLOCK_SZ, MS_SYNC);
     if (ret < 0) {
-        PLOG(ERROR) << "msync header failed: " << ret;
+        SNAP_PLOG(ERROR) << "msync header failed: " << ret;
         return false;
     }
 
@@ -266,14 +266,15 @@
 
 void Snapuserd::CheckMergeCompletionStatus() {
     if (!merge_initiated_) {
-        SNAP_LOG(INFO) << "Merge was not initiated. Total-data-ops: " << reader_->total_data_ops();
+        SNAP_LOG(INFO) << "Merge was not initiated. Total-data-ops: "
+                       << reader_->get_num_total_data_ops();
         return;
     }
 
     struct CowHeader* ch = reinterpret_cast<struct CowHeader*>(mapped_addr_);
 
     SNAP_LOG(INFO) << "Merge-status: Total-Merged-ops: " << ch->num_merge_ops
-                   << " Total-data-ops: " << reader_->total_data_ops();
+                   << " Total-data-ops: " << reader_->get_num_total_data_ops();
 }
 
 /*
@@ -352,7 +353,6 @@
         return false;
     }
 
-    reader_->InitializeMerge();
     SNAP_LOG(DEBUG) << "Merge-ops: " << header.num_merge_ops;
 
     if (!MmapMetadata()) {
@@ -361,7 +361,7 @@
     }
 
     // Initialize the iterator for reading metadata
-    cowop_riter_ = reader_->GetRevOpIter();
+    std::unique_ptr<ICowOpIter> cowop_rm_iter = reader_->GetRevMergeOpIter();
 
     exceptions_per_area_ = (CHUNK_SIZE << SECTOR_SHIFT) / sizeof(struct disk_exception);
 
@@ -379,23 +379,18 @@
     // this memset will ensure that metadata read is completed.
     memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception)));
 
-    while (!cowop_riter_->Done()) {
-        const CowOperation* cow_op = &cowop_riter_->Get();
+    while (!cowop_rm_iter->Done()) {
+        const CowOperation* cow_op = &cowop_rm_iter->Get();
         struct disk_exception* de =
                 reinterpret_cast<struct disk_exception*>((char*)de_ptr.get() + offset);
 
-        if (IsMetadataOp(*cow_op)) {
-            cowop_riter_->Next();
-            continue;
-        }
-
         metadata_found = true;
         // This loop will handle all the replace and zero ops.
         // We will handle the copy ops later as it requires special
         // handling of assigning chunk-id's. Furthermore, we make
         // sure that replace/zero and copy ops are not batch merged; hence,
         // the bump in the chunk_id before break of this loop
-        if (cow_op->type == kCowCopyOp) {
+        if (IsOrderedOp(*cow_op)) {
             data_chunk_id = GetNextAllocatableChunkId(data_chunk_id);
             break;
         }
@@ -415,7 +410,7 @@
         chunk_vec_.push_back(std::make_pair(ChunkToSector(data_chunk_id), cow_op));
         num_ops += 1;
         offset += sizeof(struct disk_exception);
-        cowop_riter_->Next();
+        cowop_rm_iter->Next();
 
         SNAP_LOG(DEBUG) << num_ops << ":"
                         << " Old-chunk: " << de->old_chunk << " New-chunk: " << de->new_chunk;
@@ -432,7 +427,7 @@
                                                  sizeof(struct disk_exception));
             memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception)));
 
-            if (cowop_riter_->Done()) {
+            if (cowop_rm_iter->Done()) {
                 vec_.push_back(std::move(de_ptr));
             }
         }
@@ -445,18 +440,15 @@
     std::map<uint64_t, const CowOperation*> map;
     std::set<uint64_t> dest_blocks;
     size_t pending_copy_ops = exceptions_per_area_ - num_ops;
-    uint64_t total_copy_ops = reader_->total_copy_ops();
+    uint64_t total_copy_ops = reader_->get_num_ordered_ops_to_merge();
 
     SNAP_LOG(DEBUG) << " Processing copy-ops at Area: " << vec_.size()
                     << " Number of replace/zero ops completed in this area: " << num_ops
                     << " Pending copy ops for this area: " << pending_copy_ops;
-    while (!cowop_riter_->Done()) {
+
+    while (!cowop_rm_iter->Done()) {
         do {
-            const CowOperation* cow_op = &cowop_riter_->Get();
-            if (IsMetadataOp(*cow_op)) {
-                cowop_riter_->Next();
-                continue;
-            }
+            const CowOperation* cow_op = &cowop_rm_iter->Get();
 
             // We have two cases specific cases:
             //
@@ -572,8 +564,8 @@
             map[cow_op->new_block] = cow_op;
             dest_blocks.insert(cow_op->source);
             prev_id = cow_op->new_block;
-            cowop_riter_->Next();
-        } while (!cowop_riter_->Done() && pending_copy_ops);
+            cowop_rm_iter->Next();
+        } while (!cowop_rm_iter->Done() && pending_copy_ops);
 
         data_chunk_id = GetNextAllocatableChunkId(data_chunk_id);
         SNAP_LOG(DEBUG) << "Batch Merge copy-ops of size: " << map.size()
@@ -611,7 +603,7 @@
                                                      sizeof(struct disk_exception));
                 memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception)));
 
-                if (cowop_riter_->Done()) {
+                if (cowop_rm_iter->Done()) {
                     vec_.push_back(std::move(de_ptr));
                     SNAP_LOG(DEBUG) << "ReadMetadata() completed; Number of Areas: " << vec_.size();
                 }
@@ -661,7 +653,7 @@
                    << " Replace-ops: " << replace_ops << " Zero-ops: " << zero_ops
                    << " Copy-ops: " << copy_ops << " Areas: " << vec_.size()
                    << " Num-ops-merged: " << header.num_merge_ops
-                   << " Total-data-ops: " << reader_->total_data_ops();
+                   << " Total-data-ops: " << reader_->get_num_total_data_ops();
 
     // Total number of sectors required for creating dm-user device
     num_sectors_ = ChunkToSector(data_chunk_id);
diff --git a/fs_mgr/libsnapshot/snapuserd.h b/fs_mgr/libsnapshot/snapuserd.h
index 212c78e..5d86e4f 100644
--- a/fs_mgr/libsnapshot/snapuserd.h
+++ b/fs_mgr/libsnapshot/snapuserd.h
@@ -306,8 +306,6 @@
     uint32_t exceptions_per_area_;
     uint64_t num_sectors_;
 
-    std::unique_ptr<ICowOpIter> cowop_iter_;
-    std::unique_ptr<ICowOpReverseIter> cowop_riter_;
     std::unique_ptr<CowReader> reader_;
 
     // Vector of disk exception which is a
diff --git a/init/devices.cpp b/init/devices.cpp
index ce6298a..56c6623 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -264,6 +264,8 @@
         setfscreatecon(secontext.c_str());
     }
 
+    gid_t new_group = -1;
+
     dev_t dev = makedev(major, minor);
     /* Temporarily change egid to avoid race condition setting the gid of the
      * device node. Unforunately changing the euid would prevent creation of
@@ -291,10 +293,21 @@
             PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path
                         << "' device";
         }
+
+        struct stat s;
+        if (stat(path.c_str(), &s) == 0) {
+            if (gid != s.st_gid) {
+                new_group = gid;
+            }
+        } else {
+            PLOG(ERROR) << "Cannot stat " << path;
+        }
     }
 
 out:
-    chown(path.c_str(), uid, -1);
+    if (chown(path.c_str(), uid, new_group) < 0) {
+        PLOG(ERROR) << "Cannot chown " << path << " " << uid << " " << new_group;
+    }
     if (setegid(AID_ROOT)) {
         PLOG(FATAL) << "setegid(AID_ROOT) failed";
     }
diff --git a/init/main.cpp b/init/main.cpp
index 23f5530..b01a3ee 100644
--- a/init/main.cpp
+++ b/init/main.cpp
@@ -25,9 +25,11 @@
 
 #if __has_feature(address_sanitizer)
 #include <sanitizer/asan_interface.h>
+#elif __has_feature(hwaddress_sanitizer)
+#include <sanitizer/hwasan_interface.h>
 #endif
 
-#if __has_feature(address_sanitizer)
+#if __has_feature(address_sanitizer) || __has_feature(hwaddress_sanitizer)
 // Load asan.options if it exists since these are not yet in the environment.
 // Always ensure detect_container_overflow=0 as there are false positives with this check.
 // Always ensure abort_on_error=1 to ensure we reboot to bootloader for development builds.
@@ -51,6 +53,8 @@
 int main(int argc, char** argv) {
 #if __has_feature(address_sanitizer)
     __asan_set_error_report_callback(AsanReportCallback);
+#elif __has_feature(hwaddress_sanitizer)
+    __hwasan_set_error_report_callback(AsanReportCallback);
 #endif
     // Boost prio which will be restored later
     setpriority(PRIO_PROCESS, 0, -20);
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 15252a6..2a57808 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -158,7 +158,8 @@
     auto on_activate = [&](const std::string& apex_path,
                            const apex::proto::ApexManifest& apex_manifest) {
         apex_infos.emplace_back(apex_manifest.name(), apex_path, apex_path, apex_manifest.version(),
-                                apex_manifest.versionname(), /*isFactory=*/true, /*isActive=*/true);
+                                apex_manifest.versionname(), /*isFactory=*/true, /*isActive=*/true,
+                                /* lastUpdateMillis= */ 0);
     };
 
     for (const auto& dir : kBuiltinDirsForApexes) {
diff --git a/init/util.cpp b/init/util.cpp
index a40d104..9f7bfdb 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -253,8 +253,10 @@
     for (const auto& entry : android::base::Split(bootconfig, "\n")) {
         std::vector<std::string> pieces = android::base::Split(entry, "=");
         if (pieces.size() == 2) {
-            pieces[1].erase(std::remove(pieces[1].begin(), pieces[1].end(), '"'), pieces[1].end());
-            fn(android::base::Trim(pieces[0]), android::base::Trim(pieces[1]));
+            // get rid of the extra space between a list of values and remove the quotes.
+            std::string value = android::base::StringReplace(pieces[1], "\", \"", ",", true);
+            value.erase(std::remove(value.begin(), value.end(), '"'), value.end());
+            fn(android::base::Trim(pieces[0]), android::base::Trim(value));
         }
     }
 }
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 5c7a75d..c824376 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -224,7 +224,11 @@
  * transferred for the user/group passed as uid/gid before system_server can properly access them.
  */
 static bool MkdirAndChown(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
-    if (mkdir(path.c_str(), mode) == -1 && errno != EEXIST) {
+    if (mkdir(path.c_str(), mode) == -1) {
+        if (errno == EEXIST) {
+            // Directory already exists and permissions have been set at the time it was created
+            return true;
+        }
         return false;
     }
 
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index b5fa475..449a505 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -584,7 +584,7 @@
           }
         }
       ]
-    },
+    }
   ],
 
   "AggregateProfiles": [
@@ -635,6 +635,10 @@
     {
       "Name": "CPUSET_SP_RESTRICTED",
       "Profiles": [ "ServiceCapacityRestricted", "TimerSlackNormal" ]
+    },
+    {
+      "Name": "Dex2OatBootComplete",
+      "Profiles": [ "SCHED_SP_BACKGROUND" ]
     }
   ]
 }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a8bef42..a7322fa 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -750,8 +750,7 @@
     mkdir /data/misc/odrefresh 0777 system system
     # directory used for on-device signing key blob
     mkdir /data/misc/odsign 0700 root root
-    # Directory for VirtualizationService temporary image files. Ensure that it is empty.
-    exec -- /bin/rm -rf /data/misc/virtualizationservice
+    # Directory for VirtualizationService temporary image files.
     mkdir /data/misc/virtualizationservice 0700 virtualizationservice virtualizationservice
 
     mkdir /data/preloads 0775 system system encryption=None
diff --git a/trusty/confirmationui/fuzz/msg_fuzzer.cpp b/trusty/confirmationui/fuzz/msg_fuzzer.cpp
index 8e4443c..ee55f82 100644
--- a/trusty/confirmationui/fuzz/msg_fuzzer.cpp
+++ b/trusty/confirmationui/fuzz/msg_fuzzer.cpp
@@ -37,7 +37,7 @@
 #define CONFIRMATIONUI_MODULE_NAME "confirmationui.syms.elf"
 
 /* A request to render to screen may take a while. */
-const size_t kTimeoutSeconds = 30;
+const size_t kTimeoutSeconds = 60;
 
 /* ConfirmationUI TA's UUID is 7dee2364-c036-425b-b086-df0f6c233c1b */
 static struct uuid confirmationui_uuid = {
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 58dfa94..ff6460d 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -100,6 +100,7 @@
         "ipc/trusty_keymaster_ipc.cpp",
         "keymint/TrustyKeyMintDevice.cpp",
         "keymint/TrustyKeyMintOperation.cpp",
+        "keymint/TrustyRemotelyProvisionedComponentDevice.cpp",
         "keymint/TrustySecureClock.cpp",
         "keymint/TrustySharedSecret.cpp",
         "keymint/service.cpp",
@@ -118,7 +119,6 @@
         "libtrusty",
     ],
     required: [
-        "RemoteProvisioner",
         "android.hardware.hardware_keystore.xml",
     ],
 }
@@ -129,6 +129,27 @@
     src: "set_attestation_key/keymaster_soft_attestation_keys.xml",
 }
 
+cc_library {
+    name: "libtrusty_ipc",
+    vendor: true,
+    srcs: ["ipc/trusty_keymaster_ipc.cpp"],
+    local_include_dirs: ["include"],
+    shared_libs: [
+        "libc",
+        "libcrypto",
+        "liblog",
+        "libtrusty",
+        "libhardware",
+        "libkeymaster_messages",
+        "libxml2",
+    ],
+    export_include_dirs: ["include"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
+
 cc_binary {
     name: "trusty_keymaster_set_attestation_key",
     vendor: true,
diff --git a/trusty/keymaster/TrustyKeymaster.cpp b/trusty/keymaster/TrustyKeymaster.cpp
index ef5fc3f..aee3333 100644
--- a/trusty/keymaster/TrustyKeymaster.cpp
+++ b/trusty/keymaster/TrustyKeymaster.cpp
@@ -158,6 +158,16 @@
     }
 }
 
+void TrustyKeymaster::GenerateRkpKey(const GenerateRkpKeyRequest& request,
+                                     GenerateRkpKeyResponse* response) {
+    ForwardCommand(KM_GENERATE_RKP_KEY, request, response);
+}
+
+void TrustyKeymaster::GenerateCsr(const GenerateCsrRequest& request,
+                                  GenerateCsrResponse* response) {
+    ForwardCommand(KM_GENERATE_CSR, request, response);
+}
+
 void TrustyKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
                                             GetKeyCharacteristicsResponse* response) {
     ForwardCommand(KM_GET_KEY_CHARACTERISTICS, request, response);
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
index 45ebf7f..35eda45 100644
--- a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
@@ -42,6 +42,8 @@
     void AddRngEntropy(const AddEntropyRequest& request, AddEntropyResponse* response);
     void Configure(const ConfigureRequest& request, ConfigureResponse* response);
     void GenerateKey(const GenerateKeyRequest& request, GenerateKeyResponse* response);
+    void GenerateRkpKey(const GenerateRkpKeyRequest& request, GenerateRkpKeyResponse* response);
+    void GenerateCsr(const GenerateCsrRequest& request, GenerateCsrResponse* response);
     void GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
                                GetKeyCharacteristicsResponse* response);
     void ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response);
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyRemotelyProvisionedComponentDevice.h b/trusty/keymaster/include/trusty_keymaster/TrustyRemotelyProvisionedComponentDevice.h
new file mode 100644
index 0000000..d544b51
--- /dev/null
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyRemotelyProvisionedComponentDevice.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/security/keymint/BnRemotelyProvisionedComponent.h>
+#include <aidl/android/hardware/security/keymint/RpcHardwareInfo.h>
+#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
+
+#include <trusty_keymaster/TrustyKeymaster.h>
+
+namespace aidl::android::hardware::security::keymint::trusty {
+
+using ::keymaster::TrustyKeymaster;
+using ::ndk::ScopedAStatus;
+using ::std::shared_ptr;
+
+class TrustyRemotelyProvisionedComponentDevice : public BnRemotelyProvisionedComponent {
+  public:
+    explicit TrustyRemotelyProvisionedComponentDevice(shared_ptr<TrustyKeymaster> impl)
+        : impl_(std::move(impl)) {}
+    virtual ~TrustyRemotelyProvisionedComponentDevice() = default;
+
+    ScopedAStatus getHardwareInfo(RpcHardwareInfo* info) override;
+
+    ScopedAStatus generateEcdsaP256KeyPair(bool testMode, MacedPublicKey* macedPublicKey,
+                                           std::vector<uint8_t>* privateKeyHandle) override;
+
+    ScopedAStatus generateCertificateRequest(bool testMode,
+                                             const std::vector<MacedPublicKey>& keysToSign,
+                                             const std::vector<uint8_t>& endpointEncCertChain,
+                                             const std::vector<uint8_t>& challenge,
+                                             DeviceInfo* deviceInfo, ProtectedData* protectedData,
+                                             std::vector<uint8_t>* keysToSignMac) override;
+
+  private:
+    std::shared_ptr<::keymaster::TrustyKeymaster> impl_;
+};
+
+}  // namespace aidl::android::hardware::security::keymint::trusty
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
index a1229a3..17fee15 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
@@ -56,6 +56,8 @@
     KM_GET_VERSION_2                = (28 << KEYMASTER_REQ_SHIFT),
     KM_EARLY_BOOT_ENDED             = (29 << KEYMASTER_REQ_SHIFT),
     KM_DEVICE_LOCKED                = (30 << KEYMASTER_REQ_SHIFT),
+    KM_GENERATE_RKP_KEY             = (31 << KEYMASTER_REQ_SHIFT),
+    KM_GENERATE_CSR                 = (32 << KEYMASTER_REQ_SHIFT),
 
     // Bootloader/provisioning calls.
     KM_SET_BOOT_PARAMS = (0x1000 << KEYMASTER_REQ_SHIFT),
@@ -69,6 +71,7 @@
     KM_SET_PRODUCT_ID = (0x9000 << KEYMASTER_REQ_SHIFT),
     KM_CLEAR_ATTESTATION_CERT_CHAIN = (0xa000 << KEYMASTER_REQ_SHIFT),
     KM_SET_WRAPPED_ATTESTATION_KEY = (0xb000 << KEYMASTER_REQ_SHIFT),
+    KM_SET_ATTESTATION_IDS = (0xc000 << KEYMASTER_REQ_SHIFT)
 };
 
 #ifdef __ANDROID__
diff --git a/trusty/keymaster/keymint/TrustyRemotelyProvisionedComponentDevice.cpp b/trusty/keymaster/keymint/TrustyRemotelyProvisionedComponentDevice.cpp
new file mode 100644
index 0000000..5664829
--- /dev/null
+++ b/trusty/keymaster/keymint/TrustyRemotelyProvisionedComponentDevice.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <trusty_keymaster/TrustyRemotelyProvisionedComponentDevice.h>
+
+#include <assert.h>
+#include <variant>
+
+#include <KeyMintUtils.h>
+#include <keymaster/keymaster_configuration.h>
+
+#include <trusty_keymaster/TrustyKeyMintDevice.h>
+
+namespace aidl::android::hardware::security::keymint::trusty {
+
+using keymaster::GenerateCsrRequest;
+using keymaster::GenerateCsrResponse;
+using keymaster::GenerateRkpKeyRequest;
+using keymaster::GenerateRkpKeyResponse;
+using keymaster::KeymasterBlob;
+using ::std::string;
+using ::std::unique_ptr;
+using ::std::vector;
+using bytevec = ::std::vector<uint8_t>;
+
+namespace {
+
+constexpr auto STATUS_FAILED = IRemotelyProvisionedComponent::STATUS_FAILED;
+
+struct AStatusDeleter {
+    void operator()(AStatus* p) { AStatus_delete(p); }
+};
+
+class Status {
+  public:
+    Status() : status_(AStatus_newOk()) {}
+    Status(int32_t errCode, const std::string& errMsg)
+        : status_(AStatus_fromServiceSpecificErrorWithMessage(errCode, errMsg.c_str())) {}
+    explicit Status(const std::string& errMsg)
+        : status_(AStatus_fromServiceSpecificErrorWithMessage(STATUS_FAILED, errMsg.c_str())) {}
+    explicit Status(AStatus* status) : status_(status ? status : AStatus_newOk()) {}
+
+    Status(Status&&) = default;
+    Status(const Status&) = delete;
+
+    operator ::ndk::ScopedAStatus() && {  // NOLINT(google-explicit-constructor)
+        return ndk::ScopedAStatus(status_.release());
+    }
+
+    bool isOk() const { return AStatus_isOk(status_.get()); }
+
+    const char* getMessage() const { return AStatus_getMessage(status_.get()); }
+
+  private:
+    std::unique_ptr<AStatus, AStatusDeleter> status_;
+};
+
+}  // namespace
+
+ScopedAStatus TrustyRemotelyProvisionedComponentDevice::getHardwareInfo(RpcHardwareInfo* info) {
+    info->versionNumber = 1;
+    info->rpcAuthorName = "Google";
+    info->supportedEekCurve = RpcHardwareInfo::CURVE_25519;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyRemotelyProvisionedComponentDevice::generateEcdsaP256KeyPair(
+        bool testMode, MacedPublicKey* macedPublicKey, bytevec* privateKeyHandle) {
+    GenerateRkpKeyRequest request(impl_->message_version());
+    request.test_mode = testMode;
+    GenerateRkpKeyResponse response(impl_->message_version());
+    impl_->GenerateRkpKey(request, &response);
+    if (response.error != KM_ERROR_OK) {
+        return Status(-static_cast<int32_t>(response.error), "Failure in key generation.");
+    }
+
+    macedPublicKey->macedKey = km_utils::kmBlob2vector(response.maced_public_key);
+    *privateKeyHandle = km_utils::kmBlob2vector(response.key_blob);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus TrustyRemotelyProvisionedComponentDevice::generateCertificateRequest(
+        bool testMode, const vector<MacedPublicKey>& keysToSign,
+        const bytevec& endpointEncCertChain, const bytevec& challenge, DeviceInfo* deviceInfo,
+        ProtectedData* protectedData, bytevec* keysToSignMac) {
+    GenerateCsrRequest request(impl_->message_version());
+    request.test_mode = testMode;
+    request.num_keys = keysToSign.size();
+    request.keys_to_sign_array = new KeymasterBlob[keysToSign.size()];
+    for (size_t i = 0; i < keysToSign.size(); i++) {
+        request.SetKeyToSign(i, keysToSign[i].macedKey.data(), keysToSign[i].macedKey.size());
+    }
+    request.SetEndpointEncCertChain(endpointEncCertChain.data(), endpointEncCertChain.size());
+    request.SetChallenge(challenge.data(), challenge.size());
+    GenerateCsrResponse response(impl_->message_version());
+    impl_->GenerateCsr(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        return Status(-static_cast<int32_t>(response.error), "Failure in CSR Generation.");
+    }
+    deviceInfo->deviceInfo = km_utils::kmBlob2vector(response.device_info_blob);
+    protectedData->protectedData = km_utils::kmBlob2vector(response.protected_data_blob);
+    *keysToSignMac = km_utils::kmBlob2vector(response.keys_to_sign_mac);
+    return ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::security::keymint::trusty
diff --git a/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml
index 0ab3d64..7ca5050 100644
--- a/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml
+++ b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml
@@ -11,4 +11,8 @@
         <name>android.hardware.security.sharedsecret</name>
         <fqname>ISharedSecret/default</fqname>
     </hal>
+    <hal format="aidl">
+        <name>android.hardware.security.keymint</name>
+        <fqname>IRemotelyProvisionedComponent/default</fqname>
+    </hal>
 </manifest>
diff --git a/trusty/keymaster/keymint/service.cpp b/trusty/keymaster/keymint/service.cpp
index 8f5f0f8..4060278 100644
--- a/trusty/keymaster/keymint/service.cpp
+++ b/trusty/keymaster/keymint/service.cpp
@@ -20,10 +20,12 @@
 #include <android/binder_process.h>
 
 #include <trusty_keymaster/TrustyKeyMintDevice.h>
+#include <trusty_keymaster/TrustyRemotelyProvisionedComponentDevice.h>
 #include <trusty_keymaster/TrustySecureClock.h>
 #include <trusty_keymaster/TrustySharedSecret.h>
 
 using aidl::android::hardware::security::keymint::trusty::TrustyKeyMintDevice;
+using aidl::android::hardware::security::keymint::trusty::TrustyRemotelyProvisionedComponentDevice;
 using aidl::android::hardware::security::secureclock::trusty::TrustySecureClock;
 using aidl::android::hardware::security::sharedsecret::trusty::TrustySharedSecret;
 
@@ -52,7 +54,8 @@
     auto keyMint = addService<TrustyKeyMintDevice>(trustyKeymaster);
     auto secureClock = addService<TrustySecureClock>(trustyKeymaster);
     auto sharedSecret = addService<TrustySharedSecret>(trustyKeymaster);
-
+    auto remotelyProvisionedComponent =
+            addService<TrustyRemotelyProvisionedComponentDevice>(trustyKeymaster);
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
 }
diff --git a/trusty/storage/proxy/Android.bp b/trusty/storage/proxy/Android.bp
index a471435..d67089f 100644
--- a/trusty/storage/proxy/Android.bp
+++ b/trusty/storage/proxy/Android.bp
@@ -29,7 +29,10 @@
         "proxy.c",
     ],
 
-    shared_libs: ["liblog"],
+    shared_libs: [
+        "liblog",
+        "libhardware_legacy",
+    ],
     header_libs: ["libcutils_headers"],
 
     static_libs: [
diff --git a/trusty/storage/proxy/rpmb.c b/trusty/storage/proxy/rpmb.c
index d1ed649..b59fb67 100644
--- a/trusty/storage/proxy/rpmb.c
+++ b/trusty/storage/proxy/rpmb.c
@@ -29,6 +29,8 @@
 #include <linux/major.h>
 #include <linux/mmc/ioctl.h>
 
+#include <hardware_legacy/power.h>
+
 #include "ipc.h"
 #include "log.h"
 #include "rpmb.h"
@@ -100,6 +102,8 @@
 static uint8_t read_buf[4096];
 static enum dev_type dev_type = UNKNOWN_RPMB;
 
+static const char* UFS_WAKE_LOCK_NAME = "ufs_seq_wakelock";
+
 #ifdef RPMB_DEBUG
 
 static void print_buf(const char* prefix, const uint8_t* buf, size_t size) {
@@ -194,6 +198,7 @@
 
 static int send_ufs_rpmb_req(int sg_fd, const struct storage_rpmb_send_req* req) {
     int rc;
+    int wl_rc;
     const uint8_t* write_buf = req->payload;
     /*
      * Meaning of member values are stated on the definition of struct sec_proto_cdb.
@@ -202,6 +207,12 @@
     struct sec_proto_cdb out_cdb = {0xB5, 0xEC, 0x00, 0x01, 0x00, 0x00, 0, 0x00, 0x00};
     unsigned char sense_buffer[32];
 
+    wl_rc = acquire_wake_lock(PARTIAL_WAKE_LOCK, UFS_WAKE_LOCK_NAME);
+    if (wl_rc < 0) {
+        ALOGE("%s: failed to acquire wakelock: %d, %s\n", __func__, wl_rc, strerror(errno));
+        return wl_rc;
+    }
+
     if (req->reliable_write_size) {
         /* Prepare SECURITY PROTOCOL OUT command. */
         out_cdb.length = __builtin_bswap32(req->reliable_write_size);
@@ -212,6 +223,7 @@
         rc = ioctl(sg_fd, SG_IO, &io_hdr);
         if (rc < 0) {
             ALOGE("%s: ufs ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
+            goto err_op;
         }
         write_buf += req->reliable_write_size;
     }
@@ -225,6 +237,7 @@
         rc = ioctl(sg_fd, SG_IO, &io_hdr);
         if (rc < 0) {
             ALOGE("%s: ufs ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
+            goto err_op;
         }
         write_buf += req->write_size;
     }
@@ -240,6 +253,13 @@
             ALOGE("%s: ufs ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
         }
     }
+
+err_op:
+    wl_rc = release_wake_lock(UFS_WAKE_LOCK_NAME);
+    if (wl_rc < 0) {
+        ALOGE("%s: failed to release wakelock: %d, %s\n", __func__, wl_rc, strerror(errno));
+    }
+
     return rc;
 }