Merge "filesystem_config: Add a aid/uid for UWB subsystem"
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
index 797b8ef..e93254e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
@@ -24,6 +24,8 @@
 static constexpr uint32_t kCowVersionMajor = 1;
 static constexpr uint32_t kCowVersionMinor = 0;
 
+static constexpr uint32_t kCowVersionManifest = 1;
+
 // This header appears as the first sequence of bytes in the COW. All fields
 // in the layout are little-endian encoded. The on-disk layout is:
 //
diff --git a/fs_mgr/libsnapshot/inspect_cow.cpp b/fs_mgr/libsnapshot/inspect_cow.cpp
index 453b5c6..4a84fba 100644
--- a/fs_mgr/libsnapshot/inspect_cow.cpp
+++ b/fs_mgr/libsnapshot/inspect_cow.cpp
@@ -38,7 +38,8 @@
 static void usage(void) {
     LOG(ERROR) << "Usage: inspect_cow [-sd] <COW_FILE>";
     LOG(ERROR) << "\t -s Run Silent";
-    LOG(ERROR) << "\t -d Attempt to decompress\n";
+    LOG(ERROR) << "\t -d Attempt to decompress";
+    LOG(ERROR) << "\t -b Show data for failed decompress\n";
 }
 
 // Sink that always appends to the end of a string.
@@ -59,7 +60,25 @@
     std::string stream_;
 };
 
-static bool Inspect(const std::string& path, bool silent, bool decompress) {
+static void ShowBad(CowReader& reader, const struct CowOperation& op) {
+    size_t count;
+    auto buffer = std::make_unique<uint8_t[]>(op.data_length);
+
+    if (!reader.GetRawBytes(op.source, buffer.get(), op.data_length, &count)) {
+        std::cerr << "Failed to read at all!\n";
+    } else {
+        std::cout << "The Block data is:\n";
+        for (int i = 0; i < op.data_length; i++) {
+            std::cout << std::hex << (int)buffer[i];
+        }
+        std::cout << std::dec << "\n\n";
+        if (op.data_length >= sizeof(CowOperation)) {
+            std::cout << "The start, as an op, would be " << *(CowOperation*)buffer.get() << "\n";
+        }
+    }
+}
+
+static bool Inspect(const std::string& path, bool silent, bool decompress, bool show_bad) {
     android::base::unique_fd fd(open(path.c_str(), O_RDONLY));
     if (fd < 0) {
         PLOG(ERROR) << "open failed: " << path;
@@ -107,6 +126,7 @@
             if (!reader.ReadData(op, &sink)) {
                 std::cerr << "Failed to decompress for :" << op << "\n";
                 success = false;
+                if (show_bad) ShowBad(reader, op);
             }
             sink.Reset();
         }
@@ -124,7 +144,8 @@
     int ch;
     bool silent = false;
     bool decompress = false;
-    while ((ch = getopt(argc, argv, "sd")) != -1) {
+    bool show_bad = false;
+    while ((ch = getopt(argc, argv, "sdb")) != -1) {
         switch (ch) {
             case 's':
                 silent = true;
@@ -132,6 +153,9 @@
             case 'd':
                 decompress = true;
                 break;
+            case 'b':
+                show_bad = true;
+                break;
             default:
                 android::snapshot::usage();
         }
@@ -143,7 +167,7 @@
         return 1;
     }
 
-    if (!android::snapshot::Inspect(argv[optind], silent, decompress)) {
+    if (!android::snapshot::Inspect(argv[optind], silent, decompress, show_bad)) {
         return 1;
     }
     return 0;
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 35a96f9..42d3023 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -240,25 +240,25 @@
     }
 
     // Use precompiled sepolicy only when all corresponding hashes are equal.
-    // plat_sepolicy is always checked, while system_ext and product are checked only when they
-    // exist.
     std::vector<std::pair<std::string, std::string>> sepolicy_hashes{
             {"/system/etc/selinux/plat_sepolicy_and_mapping.sha256",
              precompiled_sepolicy + ".plat_sepolicy_and_mapping.sha256"},
+            {"/system_ext/etc/selinux/system_ext_sepolicy_and_mapping.sha256",
+             precompiled_sepolicy + ".system_ext_sepolicy_and_mapping.sha256"},
+            {"/product/etc/selinux/product_sepolicy_and_mapping.sha256",
+             precompiled_sepolicy + ".product_sepolicy_and_mapping.sha256"},
     };
 
-    if (access("/system_ext/etc/selinux/system_ext_sepolicy.cil", F_OK) == 0) {
-        sepolicy_hashes.emplace_back(
-                "/system_ext/etc/selinux/system_ext_sepolicy_and_mapping.sha256",
-                precompiled_sepolicy + ".system_ext_sepolicy_and_mapping.sha256");
-    }
-
-    if (access("/product/etc/selinux/product_sepolicy.cil", F_OK) == 0) {
-        sepolicy_hashes.emplace_back("/product/etc/selinux/product_sepolicy_and_mapping.sha256",
-                                     precompiled_sepolicy + ".product_sepolicy_and_mapping.sha256");
-    }
-
     for (const auto& [actual_id_path, precompiled_id_path] : sepolicy_hashes) {
+        // Both of them should exist or both of them shouldn't exist.
+        if (access(actual_id_path.c_str(), R_OK) != 0) {
+            if (access(precompiled_id_path.c_str(), R_OK) == 0) {
+                return Error() << precompiled_id_path << " exists but " << actual_id_path
+                               << " doesn't";
+            }
+            continue;
+        }
+
         std::string actual_id;
         if (!ReadFirstLine(actual_id_path.c_str(), &actual_id)) {
             return ErrnoError() << "Failed to read " << actual_id_path;