Merge "Dump the root digest of hashtree for dm-verity partitions"
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 7ae526f..cb74ae0 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -215,7 +215,6 @@
     static_libs: [
         "libavb_user",
         "libgsid",
-        "libutils",
         "libvold_binder",
     ],
     shared_libs: [
@@ -230,6 +229,7 @@
         "liblog",
         "liblp",
         "libselinux",
+        "libutils",
     ],
     header_libs: [
         "libcutils_headers",
diff --git a/fs_mgr/libsnapshot/inspect_cow.cpp b/fs_mgr/libsnapshot/inspect_cow.cpp
index ed86c87..3c0ba16 100644
--- a/fs_mgr/libsnapshot/inspect_cow.cpp
+++ b/fs_mgr/libsnapshot/inspect_cow.cpp
@@ -16,8 +16,10 @@
 #include <stdio.h>
 #include <unistd.h>
 
+#include <iomanip>
 #include <iostream>
 #include <string>
+#include <vector>
 
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
@@ -39,8 +41,10 @@
     LOG(ERROR) << "Usage: inspect_cow [-sd] <COW_FILE>";
     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";
+    LOG(ERROR) << "\t -b Show data for failed decompress";
+    LOG(ERROR) << "\t -l Show ops";
+    LOG(ERROR) << "\t -m Show ops in reverse merge order";
+    LOG(ERROR) << "\t -o Shows sequence op block order\n";
 }
 
 enum OpIter { Normal, RevMerge };
@@ -48,7 +52,9 @@
 struct Options {
     bool silent;
     bool decompress;
+    bool show_ops;
     bool show_bad;
+    bool show_seq;
     OpIter iter_type;
 };
 
@@ -137,7 +143,7 @@
     while (!iter->Done()) {
         const CowOperation& op = iter->Get();
 
-        if (!opt.silent) std::cout << op << "\n";
+        if (!opt.silent && opt.show_ops) std::cout << op << "\n";
 
         if (opt.decompress && op.type == kCowReplaceOp && op.compression != kCowCompressNone) {
             if (!reader.ReadData(op, &sink)) {
@@ -148,6 +154,24 @@
             sink.Reset();
         }
 
+        if (op.type == kCowSequenceOp && opt.show_seq) {
+            size_t read;
+            std::vector<uint32_t> merge_op_blocks;
+            size_t seq_len = op.data_length / sizeof(uint32_t);
+            merge_op_blocks.resize(seq_len);
+            if (!reader.GetRawBytes(op.source, merge_op_blocks.data(), op.data_length, &read)) {
+                PLOG(ERROR) << "Failed to read sequence op!";
+                return false;
+            }
+            if (!opt.silent) {
+                std::cout << "Sequence for " << op << " is :\n";
+                for (size_t i = 0; i < seq_len; i++) {
+                    std::cout << std::setfill('0') << std::setw(6) << merge_op_blocks[i] << ", ";
+                    if ((i + 1) % 10 == 0 || i + 1 == seq_len) std::cout << "\n";
+                }
+            }
+        }
+
         iter->Next();
     }
 
@@ -164,7 +188,7 @@
     opt.decompress = false;
     opt.show_bad = false;
     opt.iter_type = android::snapshot::Normal;
-    while ((ch = getopt(argc, argv, "sdbm")) != -1) {
+    while ((ch = getopt(argc, argv, "sdbmol")) != -1) {
         switch (ch) {
             case 's':
                 opt.silent = true;
@@ -178,6 +202,12 @@
             case 'm':
                 opt.iter_type = android::snapshot::RevMerge;
                 break;
+            case 'o':
+                opt.show_seq = true;
+                break;
+            case 'l':
+                opt.show_ops = true;
+                break;
             default:
                 android::snapshot::usage();
         }