Merge "start aconfig storage daemon" into main
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 7d20995..235fdfd 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -21,8 +21,11 @@
     local_include_dirs: ["include"],
     product_variables: {
         debuggable: {
-            cflags: ["-UANDROID_DEBUGGABLE", "-DANDROID_DEBUGGABLE=1"],
-        }
+            cflags: [
+                "-UANDROID_DEBUGGABLE",
+                "-DANDROID_DEBUGGABLE=1",
+            ],
+        },
     },
 }
 
@@ -256,7 +259,7 @@
     ],
 
     static_libs: [
-        "libdexfile_support",  // libunwindstack dependency
+        "libdexfile_support", // libunwindstack dependency
         "libunwindstack",
         "liblzma",
         "libbase",
@@ -299,7 +302,7 @@
         },
         android: {
             runtime_libs: [
-                "libdexfile",           // libdexfile_support dependency
+                "libdexfile", // libdexfile_support dependency
             ],
         },
     },
@@ -368,6 +371,11 @@
         },
     },
 
+    sanitize: {
+        memtag_heap: true,
+        memtag_stack: true,
+    },
+
     shared_libs: [
         "libbase",
         "libcutils",
@@ -494,7 +502,7 @@
 
     header_libs: [
         "bionic_libc_platform_headers",
-        "libdebuggerd_common_headers"
+        "libdebuggerd_common_headers",
     ],
 
     static_libs: [
@@ -552,7 +560,6 @@
     },
 }
 
-
 // This installs the "other" architecture (so 32-bit on 64-bit device).
 prebuilt_etc {
     name: "crash_dump.policy_other",
diff --git a/debuggerd/TEST_MAPPING b/debuggerd/TEST_MAPPING
index 8633cb8..61d7155 100644
--- a/debuggerd/TEST_MAPPING
+++ b/debuggerd/TEST_MAPPING
@@ -14,5 +14,10 @@
     {
       "name": "debuggerd_test"
     }
+  ],
+  "postsubmit": [
+    {
+      "name": "CtsCrashDetailHostTestCases"
+    }
   ]
 }
diff --git a/debuggerd/crasher/Android.bp b/debuggerd/crasher/Android.bp
index fe1689c..4c6a400 100644
--- a/debuggerd/crasher/Android.bp
+++ b/debuggerd/crasher/Android.bp
@@ -15,7 +15,7 @@
         "-fstack-protector-all",
         "-Wno-date-time",
     ],
-    tidy: false,  // crasher.cpp tests many memory access errors
+    tidy: false, // crasher.cpp tests many memory access errors
     srcs: ["crasher.cpp"],
     arch: {
         arm: {
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index f396b1d..526e2ca 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -21,6 +21,7 @@
 #include <linux/prctl.h>
 #include <malloc.h>
 #include <pthread.h>
+#include <setjmp.h>
 #include <stdlib.h>
 #include <sys/capability.h>
 #include <sys/mman.h>
@@ -601,6 +602,54 @@
 #endif
 }
 
+__attribute__((noinline)) void mte_illegal_setjmp_helper(jmp_buf& jump_buf) {
+  // This frame is at least 8 bytes for storing and restoring the LR before the
+  // setjmp below. So this can never get an empty stack frame, even if we omit
+  // the frame pointer. So, the SP of this is always less (numerically) than the
+  // calling function frame.
+  setjmp(jump_buf);
+}
+
+TEST_F(CrasherTest, mte_illegal_setjmp) {
+  // This setjmp is illegal because it jumps back into a function that already returned.
+  // Quoting man 3 setjmp:
+  //     If the function which called setjmp() returns before longjmp() is
+  //     called, the behavior is undefined.  Some kind of subtle or
+  //     unsubtle chaos is sure to result.
+  // https://man7.org/linux/man-pages/man3/longjmp.3.html
+#if defined(__aarch64__)
+  if (!mte_supported()) {
+    GTEST_SKIP() << "Requires MTE";
+  }
+
+  int intercept_result;
+  unique_fd output_fd;
+  StartProcess([&]() {
+    SetTagCheckingLevelSync();
+    jmp_buf jump_buf;
+    mte_illegal_setjmp_helper(jump_buf);
+    longjmp(jump_buf, 1);
+  });
+
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  AssertDeath(SIGABRT);
+  FinishIntercept(&intercept_result);
+
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+
+  // In our test-case, we have a NEGATIVE stack adjustment, which is being
+  // interpreted as unsigned integer, and thus is "too large".
+  // TODO(fmayer): fix the error message for this
+  ASSERT_MATCH(result, R"(memtag_handle_longjmp: stack adjustment too large)");
+#else
+  GTEST_SKIP() << "Requires aarch64";
+#endif
+}
+
 TEST_F(CrasherTest, mte_async) {
 #if defined(__aarch64__)
   if (!mte_supported()) {
@@ -2647,7 +2696,7 @@
   match_str += format_full_pointer(crash_uptr);
   ASSERT_MATCH(result, match_str);
 
-  ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
+  ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->\)\n)");
 
   // Verifies that the fault address error message is at the end of the
   // maps section. To do this, the check below looks for the start of the
@@ -2699,7 +2748,7 @@
   match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
   ASSERT_MATCH(result, match_str);
 
-  ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
+  ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->\)\n)");
 
   match_str = android::base::StringPrintf(
       R"(    %s.*\n--->Fault address falls at %s between mapped regions\n    %s)",
@@ -2737,7 +2786,7 @@
   match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
   ASSERT_MATCH(result, match_str);
 
-  ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
+  ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->\)\n)");
 
   match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
   ASSERT_MATCH(result, match_str);
diff --git a/debuggerd/proto/Android.bp b/debuggerd/proto/Android.bp
index 7be5d61..7b9e780 100644
--- a/debuggerd/proto/Android.bp
+++ b/debuggerd/proto/Android.bp
@@ -52,4 +52,3 @@
     sdk_version: "current",
     static_libs: ["libprotobuf-java-lite"],
 }
-
diff --git a/debuggerd/rust/tombstoned_client/Android.bp b/debuggerd/rust/tombstoned_client/Android.bp
index 2007f39..bf19bb7 100644
--- a/debuggerd/rust/tombstoned_client/Android.bp
+++ b/debuggerd/rust/tombstoned_client/Android.bp
@@ -8,7 +8,7 @@
         "wrapper.cpp",
     ],
     generated_sources: [
-        "libtombstoned_client_rust_bridge_code"
+        "libtombstoned_client_rust_bridge_code",
     ],
     header_libs: [
         "libbase_headers",
diff --git a/debuggerd/seccomp_policy/crash_dump.policy.def b/debuggerd/seccomp_policy/crash_dump.policy.def
index 972a575..dc751da 100644
--- a/debuggerd/seccomp_policy/crash_dump.policy.def
+++ b/debuggerd/seccomp_policy/crash_dump.policy.def
@@ -25,8 +25,8 @@
 faccessat: 1
 recvmsg: 1
 recvfrom: 1
-sysinfo: 1
 setsockopt: 1
+sysinfo: 1
 
 process_vm_readv: 1
 
@@ -53,20 +53,29 @@
 
 #if 0
 libminijail on vendor partitions older than P does not have constants from <sys/mman.h>.
-Define the values of PROT_READ and PROT_WRITE ourselves to maintain backwards compatibility.
+Define values for PROT_READ, PROT_WRITE and PROT_MTE ourselves to maintain backwards compatibility.
 #else
 #define PROT_READ 0x1
 #define PROT_WRITE 0x2
+#define PROT_MTE 0x20
 #endif
 
 madvise: 1
+#if defined(__aarch64__)
+mprotect: arg2 in PROT_READ|PROT_WRITE|PROT_MTE
+#else
 mprotect: arg2 in PROT_READ|PROT_WRITE
+#endif
 munmap: 1
 
 #if defined(__LP64__)
 getuid: 1
 fstat: 1
+#if defined(__aarch64__)
+mmap: arg2 in PROT_READ|PROT_WRITE|PROT_MTE
+#else
 mmap: arg2 in PROT_READ|PROT_WRITE
+#endif
 #else
 getuid32: 1
 fstat64: 1
diff --git a/debuggerd/test_permissive_mte/Android.bp b/debuggerd/test_permissive_mte/Android.bp
index d3f7520..0ad3243 100644
--- a/debuggerd/test_permissive_mte/Android.bp
+++ b/debuggerd/test_permissive_mte/Android.bp
@@ -17,22 +17,28 @@
 }
 
 cc_binary {
-  name: "mte_crash",
-  tidy: false,
-  srcs: ["mte_crash.cpp"],
-  sanitize: {
-    memtag_heap: true,
-    diag: {
-      memtag_heap: true,
+    name: "mte_crash",
+    tidy: false,
+    srcs: ["mte_crash.cpp"],
+    sanitize: {
+        memtag_heap: true,
+        diag: {
+            memtag_heap: true,
+        },
     },
-  },
 }
 
 java_test_host {
     name: "permissive_mte_test",
     libs: ["tradefed"],
-    static_libs: ["frameworks-base-hostutils", "cts-install-lib-host"],
-    srcs:  ["src/**/PermissiveMteTest.java", ":libtombstone_proto-src"],
+    static_libs: [
+        "frameworks-base-hostutils",
+        "cts-install-lib-host",
+    ],
+    srcs: [
+        "src/**/PermissiveMteTest.java",
+        ":libtombstone_proto-src",
+    ],
     data: [":mte_crash"],
     test_config: "AndroidTest.xml",
     test_suites: ["general-tests"],
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index cf7904f..e2a67a2 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -61,7 +61,6 @@
 
 struct CrashArtifact {
   unique_fd fd;
-  std::optional<std::string> temporary_path;
 
   static CrashArtifact devnull() {
     CrashArtifact result;
@@ -145,16 +144,13 @@
     std::optional<std::string> path;
     result.fd.reset(openat(dir_fd_, ".", O_WRONLY | O_APPEND | O_TMPFILE | O_CLOEXEC, 0660));
     if (result.fd == -1) {
-      // We might not have O_TMPFILE. Try creating with an arbitrary filename instead.
-      static size_t counter = 0;
-      std::string tmp_filename = StringPrintf(".temporary%zu", counter++);
-      result.fd.reset(openat(dir_fd_, tmp_filename.c_str(),
-                             O_WRONLY | O_APPEND | O_CREAT | O_TRUNC | O_CLOEXEC, 0660));
-      if (result.fd == -1) {
-        PLOG(FATAL) << "failed to create temporary tombstone in " << dir_path_;
-      }
+      PLOG(FATAL) << "failed to create temporary tombstone in " << dir_path_;
+    }
 
-      result.temporary_path = std::move(tmp_filename);
+    // We need to fchmodat after creating to avoid getting the umask applied.
+    std::string fd_path = StringPrintf("/proc/self/fd/%d", result.fd.get());
+    if (fchmodat(dir_fd_, fd_path.c_str(), 0664, 0) != 0) {
+      PLOG(ERROR) << "Failed to make tombstone world-readable";
     }
 
     return std::move(result);
@@ -417,6 +413,7 @@
     return false;
   }
 
+  // This fd is created inside of dirfd in CrashQueue::create_temporary_file.
   std::string fd_path = StringPrintf("/proc/self/fd/%d", fd.get());
   rc = linkat(AT_FDCWD, fd_path.c_str(), dirfd.get(), path.c_str(), AT_SYMLINK_FOLLOW);
   if (rc != 0) {
@@ -471,20 +468,6 @@
       rename_tombstone_fd(crash->output.proto->fd, queue->dir_fd(), *paths.proto);
     }
   }
-
-  // If we don't have O_TMPFILE, we need to clean up after ourselves.
-  if (crash->output.text.temporary_path) {
-    rc = unlinkat(queue->dir_fd().get(), crash->output.text.temporary_path->c_str(), 0);
-    if (rc != 0) {
-      PLOG(ERROR) << "failed to unlink temporary tombstone at " << paths.text;
-    }
-  }
-  if (crash->output.proto && crash->output.proto->temporary_path) {
-    rc = unlinkat(queue->dir_fd().get(), crash->output.proto->temporary_path->c_str(), 0);
-    if (rc != 0) {
-      PLOG(ERROR) << "failed to unlink temporary proto tombstone";
-    }
-  }
 }
 
 static void crash_completed_cb(evutil_socket_t sockfd, short ev, void* arg) {
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index 90d91a0..1f6bd1a 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -61,6 +61,10 @@
     return block_device_ + " " + std::to_string(physical_sector_);
 }
 
+std::string DmTargetStripe::GetParameterString() const {
+    return "2 " + std::to_string(chunksize) + " " + block_device0_ + " 0 " + block_device1_ + " 0";
+}
+
 DmTargetVerity::DmTargetVerity(uint64_t start, uint64_t length, uint32_t version,
                                const std::string& block_device, const std::string& hash_device,
                                uint32_t data_block_size, uint32_t hash_block_size,
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index a0129c2..d043be6 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -181,6 +181,13 @@
     ASSERT_EQ(dm.GetState(dev.name()), DmDeviceState::ACTIVE);
 }
 
+TEST_F(DmTest, StripeArgs) {
+    DmTargetStripe target(0, 4096, 1024, "/dev/loop0", "/dev/loop1");
+    ASSERT_EQ(target.name(), "striped");
+    ASSERT_TRUE(target.Valid());
+    ASSERT_EQ(target.GetParameterString(), "2 1024 /dev/loop0 0 /dev/loop1 0");
+}
+
 TEST_F(DmTest, DmVerityArgsAvb2) {
     std::string device = "/dev/block/platform/soc/1da4000.ufshc/by-name/vendor_a";
     std::string algorithm = "sha1";
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index 09fe200..97f3c13 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -116,6 +116,24 @@
     uint64_t physical_sector_;
 };
 
+class DmTargetStripe final : public DmTarget {
+  public:
+    DmTargetStripe(uint64_t start, uint64_t length, uint64_t chunksize,
+                   const std::string& block_device0, const std::string& block_device1)
+        : DmTarget(start, length),
+          chunksize(chunksize),
+          block_device0_(block_device0),
+          block_device1_(block_device1) {}
+
+    std::string name() const override { return "striped"; }
+    std::string GetParameterString() const override;
+
+  private:
+    uint64_t chunksize;
+    std::string block_device0_;
+    std::string block_device1_;
+};
+
 class DmTargetVerity final : public DmTarget {
   public:
     DmTargetVerity(uint64_t start, uint64_t length, uint32_t version,
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
index 30c5135..de2e528 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
@@ -603,41 +603,47 @@
 std::vector<CowWriterV3::CompressedBuffer> CowWriterV3::ProcessBlocksWithThreadedCompression(
         const size_t num_blocks, const void* data, CowOperationType type) {
     const size_t num_threads = num_compress_threads_;
-    const size_t blocks_per_thread = DivRoundUp(num_blocks, num_threads);
     const uint8_t* iter = reinterpret_cast<const uint8_t*>(data);
 
+    // We will alternate which thread to send compress work to. E.g. alternate between T1 and T2
+    // until all blocks are processed
     std::vector<CompressedBuffer> compressed_vec;
-    // Submit the blocks per thread. The retrieval of
-    // compressed buffers has to be done in the same order.
-    // We should not poll for completed buffers in a different order as the
-    // buffers are tightly coupled with block ordering.
-    for (size_t i = 0; i < num_threads; i++) {
-        CompressWorker* worker = compress_threads_[i].get();
-        auto blocks_in_batch = std::min(num_blocks - i * blocks_per_thread, blocks_per_thread);
-        // Enqueue the blocks to be compressed for each thread.
-        while (blocks_in_batch) {
-            CompressedBuffer buffer;
+    int iteration = 0;
+    int blocks_to_compress = static_cast<int>(num_blocks);
+    while (blocks_to_compress) {
+        CompressedBuffer buffer;
+        CompressWorker* worker = compress_threads_[iteration % num_threads].get();
 
-            const size_t compression_factor = GetCompressionFactor(blocks_in_batch, type);
-            size_t num_blocks = compression_factor / header_.block_size;
+        const size_t compression_factor = GetCompressionFactor(blocks_to_compress, type);
+        size_t num_blocks = compression_factor / header_.block_size;
 
-            buffer.compression_factor = compression_factor;
-            worker->EnqueueCompressBlocks(iter, compression_factor, 1);
-            compressed_vec.push_back(std::move(buffer));
-            blocks_in_batch -= num_blocks;
-            iter += compression_factor;
-        }
+        worker->EnqueueCompressBlocks(iter, compression_factor, 1);
+        buffer.compression_factor = compression_factor;
+        compressed_vec.push_back(std::move(buffer));
+
+        iteration++;
+        iter += compression_factor;
+        blocks_to_compress -= num_blocks;
     }
 
-    // Fetch compressed buffers from the threads
     std::vector<std::vector<uint8_t>> compressed_buf;
+    std::vector<std::vector<std::vector<uint8_t>>> worker_buffers(num_threads);
     compressed_buf.clear();
     for (size_t i = 0; i < num_threads; i++) {
         CompressWorker* worker = compress_threads_[i].get();
-        if (!worker->GetCompressedBuffers(&compressed_buf)) {
+        if (!worker->GetCompressedBuffers(&worker_buffers[i])) {
             return {};
         }
     }
+    // compressed_vec | CB 1 | CB 2 | CB 3 | CB 4 | <-compressed buffers
+    //                   t1     t2     t1     t2    <- processed by these threads
+    // Ordering is important here. We need to retrieve the compressed data in the same order we
+    // processed it and assume that that we submit data beginning with the first thread and then
+    // round robin the consecutive data calls. We need to Fetch compressed buffers from the threads
+    // via the same ordering
+    for (size_t i = 0; i < compressed_vec.size(); i++) {
+        compressed_buf.emplace_back(worker_buffers[i % num_threads][i / num_threads]);
+    }
 
     if (compressed_vec.size() != compressed_buf.size()) {
         LOG(ERROR) << "Compressed buffer size: " << compressed_buf.size()
diff --git a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
index cf26a16..a4a2c1a 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
@@ -39,6 +39,7 @@
 namespace android {
 namespace snapshot {
 
+// @VsrTest = 3.7.6
 class PartitionCowCreatorTest : public ::testing::Test {
   public:
     void SetUp() override {
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index cbe8285..e6c4de6 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -508,8 +508,6 @@
         // When snapshots are on current slot, we determine the size
         // of block device based on the number of COW operations. We cannot
         // use base device as it will be from older image.
-        size_t num_ops = 0;
-        uint64_t dev_sz = 0;
         unique_fd fd(open(cow_file.c_str(), O_RDONLY | O_CLOEXEC));
         if (fd < 0) {
             PLOG(ERROR) << "Failed to open " << cow_file;
@@ -522,13 +520,18 @@
             return false;
         }
 
+        uint64_t dev_sz = 0;
         const auto& header = reader.GetHeader();
-        if (header.prefix.major_version > 2) {
-            LOG(ERROR) << "COW format not supported";
-            return false;
+        if (header.prefix.major_version == 2) {
+            const size_t num_ops = reader.get_num_total_data_ops();
+            dev_sz = (num_ops * header.block_size);
+        } else {
+            // create_snapshot will skip in-place copy ops. Hence, fetch this
+            // information directly from v3 header.
+            const auto& v3_header = reader.header_v3();
+            dev_sz = v3_header.op_count_max * v3_header.block_size;
         }
-        num_ops = reader.get_num_total_data_ops();
-        dev_sz = (num_ops * header.block_size);
+
         base_sectors = dev_sz >> 9;
     } else {
         // For userspace snapshots, the size of the base device is taken as the
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index e538d50..47e6ce9 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -104,6 +104,7 @@
 
 void MountMetadata();
 
+// @VsrTest = 3.7.6
 class SnapshotTest : public ::testing::Test {
   public:
     SnapshotTest() : dm_(DeviceMapper::Instance()) {}
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index 0396a55..5d3f96c 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -15,6 +15,7 @@
 //
 
 #include <sysexits.h>
+#include <unistd.h>
 
 #include <chrono>
 #include <filesystem>
@@ -46,13 +47,14 @@
 
 #include "partition_cow_creator.h"
 
-#ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
 #include <BootControlClient.h>
-#endif
 
 using namespace std::chrono_literals;
 using namespace std::string_literals;
 using namespace android::storage_literals;
+using android::base::LogdLogger;
+using android::base::StderrLogger;
+using android::base::TeeLogger;
 using android::fs_mgr::CreateLogicalPartitionParams;
 using android::fs_mgr::FindPartition;
 using android::fs_mgr::GetPartitionSize;
@@ -79,7 +81,11 @@
                  "  revert-snapshots\n"
                  "    Prepares devices to boot without snapshots on next boot.\n"
                  "    This does not delete the snapshot. It only removes the indicators\n"
-                 "    so that first stage init will not mount from snapshots.\n";
+                 "    so that first stage init will not mount from snapshots.\n"
+                 "  apply-update\n"
+                 "    Apply the incremental OTA update wherein the snapshots are\n"
+                 "    directly written to COW block device. This will bypass update-engine\n"
+                 "    and the device will be ready to boot from the target build.\n";
     return EX_USAGE;
 }
 
@@ -96,14 +102,22 @@
     bool DeleteSnapshots();
     bool CleanupSnapshot() { return sm_->PrepareDeviceToBootWithoutSnapshot(); }
     bool BeginUpdate();
+    bool ApplyUpdate();
 
   private:
     std::optional<std::string> GetCowImagePath(std::string& name);
+    bool PrepareUpdate();
     bool WriteSnapshotPatch(std::string cow_device, std::string patch);
+    std::string GetGroupName(const android::fs_mgr::LpMetadata& pt,
+                             const std::string& partiton_name);
     std::unique_ptr<SnapshotManager::LockedFile> lock_;
     std::unique_ptr<SnapshotManager> sm_;
     std::vector<std::future<bool>> threads_;
     std::string snapshot_dir_path_;
+    std::unordered_map<std::string, chromeos_update_engine::DynamicPartitionGroup*> group_map_;
+
+    std::vector<std::string> patchfiles_;
+    chromeos_update_engine::DeltaArchiveManifest manifest_;
 };
 
 MapSnapshots::MapSnapshots(std::string path) {
@@ -115,6 +129,178 @@
     snapshot_dir_path_ = path + "/";
 }
 
+std::string MapSnapshots::GetGroupName(const android::fs_mgr::LpMetadata& pt,
+                                       const std::string& partition_name) {
+    std::string group_name;
+    for (const auto& partition : pt.partitions) {
+        std::string name = android::fs_mgr::GetPartitionName(partition);
+        auto suffix = android::fs_mgr::GetPartitionSlotSuffix(name);
+        std::string pname = name.substr(0, name.size() - suffix.size());
+        if (pname == partition_name) {
+            std::string group_name =
+                    android::fs_mgr::GetPartitionGroupName(pt.groups[partition.group_index]);
+            return group_name.substr(0, group_name.size() - suffix.size());
+        }
+    }
+    return "";
+}
+
+bool MapSnapshots::PrepareUpdate() {
+    auto source_slot = fs_mgr_get_slot_suffix();
+    auto source_slot_number = SlotNumberForSlotSuffix(source_slot);
+    auto super_source = fs_mgr_get_super_partition_name(source_slot_number);
+
+    // Get current partition information.
+    PartitionOpener opener;
+    auto source_metadata = ReadMetadata(opener, super_source, source_slot_number);
+    if (!source_metadata) {
+        LOG(ERROR) << "Could not read source partition metadata.\n";
+        return false;
+    }
+
+    auto dap = manifest_.mutable_dynamic_partition_metadata();
+    dap->set_snapshot_enabled(true);
+    dap->set_vabc_enabled(true);
+    dap->set_vabc_compression_param("lz4");
+    dap->set_cow_version(3);
+
+    for (const auto& entry : std::filesystem::directory_iterator(snapshot_dir_path_)) {
+        if (android::base::EndsWith(entry.path().generic_string(), ".patch")) {
+            patchfiles_.push_back(android::base::Basename(entry.path().generic_string()));
+        }
+    }
+
+    for (auto& patchfile : patchfiles_) {
+        std::string parsing_file = snapshot_dir_path_ + patchfile;
+        android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(parsing_file.c_str(), O_RDONLY)));
+        if (fd < 0) {
+            LOG(ERROR) << "Failed to open file: " << parsing_file;
+            return false;
+        }
+        uint64_t dev_sz = lseek(fd.get(), 0, SEEK_END);
+        if (!dev_sz) {
+            LOG(ERROR) << "Could not determine block device size: " << parsing_file;
+            return false;
+        }
+
+        const int block_sz = 4_KiB;
+        dev_sz += block_sz - 1;
+        dev_sz &= ~(block_sz - 1);
+
+        auto npos = patchfile.rfind(".patch");
+        auto partition_name = patchfile.substr(0, npos);
+
+        chromeos_update_engine::DynamicPartitionGroup* group = nullptr;
+        std::string group_name = GetGroupName(*source_metadata.get(), partition_name);
+        if (group_map_.find(group_name) != group_map_.end()) {
+            group = group_map_[group_name];
+        } else {
+            group = dap->add_groups();
+            group->set_name(group_name);
+            group_map_[group_name] = group;
+        }
+        group->add_partition_names(partition_name);
+
+        auto pu = manifest_.mutable_partitions()->Add();
+        pu->set_partition_name(partition_name);
+        pu->set_estimate_cow_size(dev_sz);
+
+        CowReader reader;
+        if (!reader.Parse(fd)) {
+            LOG(ERROR) << "COW reader parse failed";
+            return false;
+        }
+
+        uint64_t new_device_size = 0;
+        const auto& header = reader.GetHeader();
+        if (header.prefix.major_version == 2) {
+            size_t num_ops = reader.get_num_total_data_ops();
+            new_device_size = (num_ops * header.block_size);
+        } else {
+            const auto& v3_header = reader.header_v3();
+            new_device_size = v3_header.op_count_max * v3_header.block_size;
+        }
+
+        LOG(INFO) << "Partition: " << partition_name << " Group_name: " << group_name
+                  << " size: " << new_device_size << " COW-size: " << dev_sz;
+        pu->mutable_new_partition_info()->set_size(new_device_size);
+    }
+    return true;
+}
+
+bool MapSnapshots::ApplyUpdate() {
+    if (!PrepareUpdate()) {
+        LOG(ERROR) << "PrepareUpdate failed";
+        return false;
+    }
+    if (!sm_->BeginUpdate()) {
+        LOG(ERROR) << "BeginUpdate failed";
+        return false;
+    }
+    if (!sm_->CreateUpdateSnapshots(manifest_)) {
+        LOG(ERROR) << "Could not apply snapshots";
+        return false;
+    }
+
+    LOG(INFO) << "CreateUpdateSnapshots success";
+    if (!sm_->MapAllSnapshots(10s)) {
+        LOG(ERROR) << "MapAllSnapshots failed";
+        return false;
+    }
+
+    LOG(INFO) << "MapAllSnapshots success";
+
+    auto& dm = android::dm::DeviceMapper::Instance();
+    auto target_slot = fs_mgr_get_other_slot_suffix();
+    for (auto& patchfile : patchfiles_) {
+        auto npos = patchfile.rfind(".patch");
+        auto partition_name = patchfile.substr(0, npos) + target_slot;
+        auto cow_device = partition_name + "-cow";
+        std::string cow_path;
+        if (!dm.GetDmDevicePathByName(cow_device, &cow_path)) {
+            LOG(ERROR) << "Failed to cow path";
+            return false;
+        }
+        threads_.emplace_back(std::async(std::launch::async, &MapSnapshots::WriteSnapshotPatch,
+                                         this, cow_path, patchfile));
+    }
+
+    bool ret = true;
+    for (auto& t : threads_) {
+        ret = t.get() && ret;
+    }
+    if (!ret) {
+        LOG(ERROR) << "Snapshot writes failed";
+        return false;
+    }
+    if (!sm_->UnmapAllSnapshots()) {
+        LOG(ERROR) << "UnmapAllSnapshots failed";
+        return false;
+    }
+
+    LOG(INFO) << "Pre-created snapshots successfully copied";
+    // All snapshots have been written.
+    if (!sm_->FinishedSnapshotWrites(false /* wipe */)) {
+        LOG(ERROR) << "Could not finalize snapshot writes.\n";
+        return false;
+    }
+
+    auto hal = hal::BootControlClient::WaitForService();
+    if (!hal) {
+        LOG(ERROR) << "Could not find IBootControl HAL.\n";
+        return false;
+    }
+    auto target_slot_number = SlotNumberForSlotSuffix(target_slot);
+    auto cr = hal->SetActiveBootSlot(target_slot_number);
+    if (!cr.IsOk()) {
+        LOG(ERROR) << "Could not set active boot slot: " << cr.errMsg;
+        return false;
+    }
+
+    LOG(INFO) << "ApplyUpdate success";
+    return true;
+}
+
 bool MapSnapshots::BeginUpdate() {
     lock_ = sm_->LockExclusive();
     std::vector<std::string> snapshots;
@@ -227,11 +413,10 @@
         if (file_offset >= dev_sz) {
             break;
         }
-
-        if (fsync(cfd.get()) < 0) {
-            PLOG(ERROR) << "Fsync failed at offset: " << file_offset << " size: " << to_read;
-            return false;
-        }
+    }
+    if (fsync(cfd.get()) < 0) {
+        PLOG(ERROR) << "Fsync failed";
+        return false;
     }
     return true;
 }
@@ -279,23 +464,23 @@
 }
 
 bool DumpCmdHandler(int /*argc*/, char** argv) {
-    android::base::InitLogging(argv, &android::base::StderrLogger);
+    android::base::InitLogging(argv, TeeLogger(LogdLogger(), &StderrLogger));
     return SnapshotManager::New()->Dump(std::cout);
 }
 
 bool MapCmdHandler(int, char** argv) {
-    android::base::InitLogging(argv, &android::base::StderrLogger);
+    android::base::InitLogging(argv, TeeLogger(LogdLogger(), &StderrLogger));
     using namespace std::chrono_literals;
     return SnapshotManager::New()->MapAllSnapshots(5000ms);
 }
 
 bool UnmapCmdHandler(int, char** argv) {
-    android::base::InitLogging(argv, &android::base::StderrLogger);
+    android::base::InitLogging(argv, TeeLogger(LogdLogger(), &StderrLogger));
     return SnapshotManager::New()->UnmapAllSnapshots();
 }
 
 bool MergeCmdHandler(int /*argc*/, char** argv) {
-    android::base::InitLogging(argv, &android::base::StderrLogger);
+    android::base::InitLogging(argv, TeeLogger(LogdLogger(), &StderrLogger));
     LOG(WARNING) << "Deprecated. Call update_engine_client --merge instead.";
     return false;
 }
@@ -367,6 +552,30 @@
     return snapshot.DeleteSnapshots();
 }
 
+bool ApplyUpdate(int argc, char** argv) {
+    android::base::InitLogging(argv, &android::base::KernelLogger);
+
+    // Make sure we are root.
+    if (::getuid() != 0) {
+        LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
+        return EXIT_FAILURE;
+    }
+
+    if (argc < 3) {
+        std::cerr << " apply-update <directory location where snapshot patches are present>"
+                     "    Apply the snapshots to the COW block device\n";
+        return false;
+    }
+
+    std::string path = std::string(argv[2]);
+    MapSnapshots cow(path);
+    if (!cow.ApplyUpdate()) {
+        return false;
+    }
+    LOG(INFO) << "Apply update success. Please reboot the device";
+    return true;
+}
+
 bool MapPrecreatedSnapshots(int argc, char** argv) {
     android::base::InitLogging(argv, &android::base::KernelLogger);
 
@@ -554,6 +763,7 @@
         {"test-blank-ota", TestOtaHandler},
 #endif
         {"unmap", UnmapCmdHandler},
+        {"apply-update", ApplyUpdate},
         {"map-snapshots", MapPrecreatedSnapshots},
         {"unmap-snapshots", UnMapPrecreatedSnapshots},
         {"delete-snapshots", DeletePrecreatedSnapshots},
diff --git a/fs_mgr/libsnapshot/vts_ota_config_test.cpp b/fs_mgr/libsnapshot/vts_ota_config_test.cpp
index d387eb3..b5618c4 100755
--- a/fs_mgr/libsnapshot/vts_ota_config_test.cpp
+++ b/fs_mgr/libsnapshot/vts_ota_config_test.cpp
@@ -21,6 +21,7 @@
     return android::base::GetIntProperty("ro.vendor.api_level", -1);
 }
 
+// @VsrTest = 3.7.6
 TEST(VAB, Enabled) {
     if (!android::base::GetBoolProperty("ro.build.ab_update", false) && (GetVsrLevel() < __ANDROID_API_T__)) {
         GTEST_SKIP();
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 7ac7a16..526c761 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -1081,7 +1081,9 @@
 LOG RUN "Testing adb disable-verity -R"
 
 T=$(adb_date)
-adb_su disable-verity -R >&2 ||
+adb_su disable-verity -R >&2
+err=${?}
+[[ ${err} -eq 0 || ${err} -eq 255 ]] ||
   die -t "${T}" "disable-verity -R failed"
 sleep 2
 adb_wait "${ADB_WAIT}" ||
@@ -1192,7 +1194,9 @@
 LOG RUN "Testing adb remount -R"
 
 T=$(adb_date)
-adb_su remount -R </dev/null >&2 ||
+adb_su remount -R </dev/null >&2
+err=${?}
+[[ ${err} -eq 0 || ${err} -eq 255 ]] ||
   die -t "${T}" "adb remount -R failed"
 sleep 2
 adb_wait "${ADB_WAIT}" ||
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 7273087..9dc8c24 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -115,6 +115,21 @@
             std::string block_device = NextArg();
             return std::make_unique<DmTargetAndroidVerity>(start_sector, num_sectors, keyid,
                                                            block_device);
+        } else if (target_type == "striped") {
+            if (!HasArgs(3)) {
+                std::cerr << "Expected \"striped\" <block_device0> <block_device1> <chunksize>"
+                          << std::endl;
+                return nullptr;
+            }
+            std::string block_device0 = NextArg();
+            std::string block_device1 = NextArg();
+            uint64_t chunk_size;
+            if (!android::base::ParseUint(NextArg(), &chunk_size)) {
+                std::cerr << "Expected start sector, got: " << PreviousArg() << std::endl;
+                return nullptr;
+            }
+            return std::make_unique<DmTargetStripe>(start_sector, num_sectors, chunk_size,
+                                                    block_device0, block_device1);
         } else if (target_type == "bow") {
             if (!HasArgs(1)) {
                 std::cerr << "Expected \"bow\" <block_device>" << std::endl;
diff --git a/init/Android.bp b/init/Android.bp
index 2d16f60..12ca15a 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -162,6 +162,7 @@
     },
     static_libs: [
         "libavb",
+        "libavf_cc_flags",
         "libbootloader_message",
         "libc++fs",
         "libcgrouprc_format",
@@ -359,6 +360,7 @@
     static_libs: [
         "libc++fs",
         "libfs_avb",
+        "libavf_cc_flags",
         "libfs_mgr",
         "libfec",
         "libfec_rs",
@@ -459,7 +461,10 @@
 
 cc_binary {
     name: "init_first_stage.microdroid",
-    defaults: ["init_first_stage_defaults"],
+    defaults: [
+        "avf_build_flags_cc",
+        "init_first_stage_defaults",
+    ],
     cflags: ["-DMICRODROID=1"],
     installable: false,
 }
@@ -597,7 +602,6 @@
     },
     generated_headers: [
         "generated_stub_builtin_function_map",
-        "generated_android_ids",
     ],
     target: {
         android: {
@@ -613,6 +617,9 @@
     name: "host_init_verifier",
     defaults: ["init_host_defaults"],
     srcs: ["host_init_verifier.cpp"] + init_common_sources + init_host_sources,
+    generated_headers: [
+        "generated_android_ids",
+    ],
 }
 
 cc_library_host_static {
diff --git a/init/block_dev_initializer.cpp b/init/block_dev_initializer.cpp
index 05e00ed..a686d05 100644
--- a/init/block_dev_initializer.cpp
+++ b/init/block_dev_initializer.cpp
@@ -132,11 +132,19 @@
 bool BlockDevInitializer::InitDmDevice(const std::string& device) {
     const std::string device_name(basename(device.c_str()));
     const std::string syspath = "/sys/block/" + device_name;
+    return InitDevice(syspath, device_name);
+}
+
+bool BlockDevInitializer::InitPlatformDevice(const std::string& dev_name) {
+    return InitDevice("/sys/devices/platform", dev_name);
+}
+
+bool BlockDevInitializer::InitDevice(const std::string& syspath, const std::string& device_name) {
     bool found = false;
 
-    auto uevent_callback = [&device_name, &device, this, &found](const Uevent& uevent) {
+    auto uevent_callback = [&device_name, this, &found](const Uevent& uevent) {
         if (uevent.device_name == device_name) {
-            LOG(VERBOSE) << "Creating device-mapper device : " << device;
+            LOG(VERBOSE) << "Creating device : " << device_name;
             device_handler_->HandleUevent(uevent);
             found = true;
             return ListenerAction::kStop;
@@ -146,13 +154,13 @@
 
     uevent_listener_.RegenerateUeventsForPath(syspath, uevent_callback);
     if (!found) {
-        LOG(INFO) << "dm device '" << device << "' not found in /sys, waiting for its uevent";
+        LOG(INFO) << "device '" << device_name << "' not found in /sys, waiting for its uevent";
         Timer t;
         uevent_listener_.Poll(uevent_callback, 10s);
-        LOG(INFO) << "wait for dm device '" << device << "' returned after " << t;
+        LOG(INFO) << "wait for device '" << device_name << "' returned after " << t;
     }
     if (!found) {
-        LOG(ERROR) << "dm device '" << device << "' not found after polling timeout";
+        LOG(ERROR) << "device '" << device_name << "' not found after polling timeout";
         return false;
     }
     return true;
diff --git a/init/block_dev_initializer.h b/init/block_dev_initializer.h
index ec39ce0..d5b1f60 100644
--- a/init/block_dev_initializer.h
+++ b/init/block_dev_initializer.h
@@ -24,6 +24,7 @@
 namespace android {
 namespace init {
 
+// TODO: should this be renamed to FirstStageDevInitialize?
 class BlockDevInitializer final {
   public:
     BlockDevInitializer();
@@ -32,11 +33,13 @@
     bool InitDmUser(const std::string& name);
     bool InitDevices(std::set<std::string> devices);
     bool InitDmDevice(const std::string& device);
+    bool InitPlatformDevice(const std::string& device);
 
   private:
     ListenerAction HandleUevent(const Uevent& uevent, std::set<std::string>* devices);
 
     bool InitMiscDevice(const std::string& name);
+    bool InitDevice(const std::string& syspath, const std::string& device);
 
     std::unique_ptr<DeviceHandler> device_handler_;
     UeventListener uevent_listener_;
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index c4d0f75..356aaa0 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -37,6 +37,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
+#include <android/avf_cc_flags.h>
 #include <modprobe/modprobe.h>
 #include <private/android_filesystem_config.h>
 
@@ -385,7 +386,12 @@
     // /second_stage_resources is used to preserve files from first to second
     // stage init
     CHECKCALL(mount("tmpfs", kSecondStageRes, "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
-                    "mode=0755,uid=0,gid=0"))
+                    "mode=0755,uid=0,gid=0"));
+
+    if (IsMicrodroid() && android::virtualization::IsOpenDiceChangesFlagEnabled()) {
+        CHECKCALL(mount("tmpfs", "/microdroid_resources", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
+                        "mode=0750,uid=0,gid=0"));
+    }
 #undef CHECKCALL
 
     SetStdioToDevNull(argv);
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index c0b9281..836d536 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -16,6 +16,7 @@
 
 #include "first_stage_mount.h"
 
+#include <signal.h>
 #include <stdlib.h>
 #include <sys/mount.h>
 #include <unistd.h>
@@ -33,6 +34,7 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android/avf_cc_flags.h>
 #include <fs_avb/fs_avb.h>
 #include <fs_mgr.h>
 #include <fs_mgr_dm_linear.h>
@@ -272,6 +274,11 @@
     return true;
 }
 
+// TODO: should this be in a library in packages/modules/Virtualization first_stage_init links?
+static bool IsMicrodroidStrictBoot() {
+    return access("/proc/device-tree/chosen/avf,strict-boot", F_OK) == 0;
+}
+
 bool FirstStageMountVBootV2::InitDevices() {
     std::set<std::string> devices;
     GetSuperDeviceName(&devices);
@@ -283,6 +290,14 @@
         return false;
     }
 
+    if (IsMicrodroid() && android::virtualization::IsOpenDiceChangesFlagEnabled()) {
+        if (IsMicrodroidStrictBoot()) {
+            if (!block_dev_init_.InitPlatformDevice("open-dice0")) {
+                return false;
+            }
+        }
+    }
+
     if (IsDmLinearEnabled()) {
         auto super_symlink = "/dev/block/by-name/"s + super_partition_name_;
         if (!android::base::Realpath(super_symlink, &super_path_)) {
@@ -527,9 +542,48 @@
     return true;
 }
 
+static bool MaybeDeriveMicrodroidVendorDiceNode(Fstab* fstab) {
+    std::optional<std::string> microdroid_vendor_block_dev;
+    for (auto entry = fstab->begin(); entry != fstab->end(); entry++) {
+        if (entry->mount_point == "/vendor") {
+            microdroid_vendor_block_dev.emplace(entry->blk_device);
+            break;
+        }
+    }
+    if (!microdroid_vendor_block_dev.has_value()) {
+        LOG(VERBOSE) << "No microdroid vendor partition to mount";
+        return true;
+    }
+    // clang-format off
+    const std::array<const char*, 7> args = {
+        "/system/bin/derive_microdroid_vendor_dice_node",
+                "--dice-driver", "/dev/open-dice0",
+                "--microdroid-vendor-disk-image", microdroid_vendor_block_dev->data(),
+                "--output", "/microdroid_resources/dice_chain.raw",
+    };
+    // clang-format-on
+    // ForkExecveAndWaitForCompletion calls waitpid to wait for the fork-ed process to finish.
+    // The first_stage_console adds SA_NOCLDWAIT flag to the SIGCHLD handler, which means that
+    // waitpid will always return -ECHLD. Here we re-register a default handler, so that waitpid
+    // works.
+    LOG(INFO) << "Deriving dice node for microdroid vendor partition";
+    signal(SIGCHLD, SIG_DFL);
+    if (!ForkExecveAndWaitForCompletion(args[0], (char**)args.data())) {
+        LOG(ERROR) << "Failed to derive microdroid vendor dice node";
+        return false;
+    }
+    return true;
+}
+
 bool FirstStageMountVBootV2::MountPartitions() {
     if (!TrySwitchSystemAsRoot()) return false;
 
+    if (IsMicrodroid() && android::virtualization::IsOpenDiceChangesFlagEnabled()) {
+        if (!MaybeDeriveMicrodroidVendorDiceNode(&fstab_)) {
+            return false;
+        }
+    }
+
     if (!SkipMountingPartitions(&fstab_, true /* verbose */)) return false;
 
     for (auto current = fstab_.begin(); current != fstab_.end();) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index bc4ef42..58a0a7f 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -58,6 +58,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <fs_mgr.h>
+#include <private/android_filesystem_config.h>
 #include <property_info_parser/property_info_parser.h>
 #include <property_info_serializer/property_info_serializer.h>
 #include <selinux/android.h>
@@ -117,12 +118,13 @@
 
 static bool persistent_properties_loaded = false;
 
-static int property_set_fd = -1;
 static int from_init_socket = -1;
 static int init_socket = -1;
 static bool accept_messages = false;
 static std::mutex accept_messages_lock;
+static std::mutex selinux_check_access_lock;
 static std::thread property_service_thread;
+static std::thread property_service_for_system_thread;
 
 static std::unique_ptr<PersistWriteThread> persist_write_thread;
 
@@ -167,6 +169,7 @@
     ucred cr = {.pid = 0, .uid = 0, .gid = 0};
     audit_data.cr = &cr;
 
+    auto lock = std::lock_guard{selinux_check_access_lock};
     return selinux_check_access(source_context.c_str(), target_context, "file", "read",
                                 &audit_data) == 0;
 }
@@ -182,10 +185,9 @@
     audit_data.name = name.c_str();
     audit_data.cr = &cr;
 
-    bool has_access = (selinux_check_access(source_context, target_context, "property_service",
-                                            "set", &audit_data) == 0);
-
-    return has_access;
+    auto lock = std::lock_guard{selinux_check_access_lock};
+    return selinux_check_access(source_context, target_context, "property_service", "set",
+                                &audit_data) == 0;
 }
 
 void NotifyPropertyChange(const std::string& name, const std::string& value) {
@@ -400,30 +402,38 @@
         return {PROP_ERROR_INVALID_VALUE};
     }
 
-    prop_info* pi = (prop_info*)__system_property_find(name.c_str());
-    if (pi != nullptr) {
-        // ro.* properties are actually "write-once".
-        if (StartsWith(name, "ro.")) {
-            *error = "Read-only property was already set";
-            return {PROP_ERROR_READ_ONLY_PROPERTY};
-        }
-
-        __system_property_update(pi, value.c_str(), valuelen);
+    if (name == "sys.powerctl") {
+        // No action here - NotifyPropertyChange will trigger the appropriate action, and since this
+        // can come to the second thread, we mustn't call out to the __system_property_* functions
+        // which support multiple readers but only one mutator.
     } else {
-        int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
-        if (rc < 0) {
-            *error = "__system_property_add failed";
-            return {PROP_ERROR_SET_FAILED};
-        }
-    }
+        prop_info* pi = (prop_info*)__system_property_find(name.c_str());
+        if (pi != nullptr) {
+            // ro.* properties are actually "write-once".
+            if (StartsWith(name, "ro.")) {
+                *error = "Read-only property was already set";
+                return {PROP_ERROR_READ_ONLY_PROPERTY};
+            }
 
-    bool need_persist = StartsWith(name, "persist.") || StartsWith(name, "next_boot.");
-    if (socket && persistent_properties_loaded && need_persist) {
-        if (persist_write_thread) {
-            persist_write_thread->Write(name, value, std::move(*socket));
-            return {};
+            __system_property_update(pi, value.c_str(), valuelen);
+        } else {
+            int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
+            if (rc < 0) {
+                *error = "__system_property_add failed";
+                return {PROP_ERROR_SET_FAILED};
+            }
         }
-        WritePersistentProperty(name, value);
+
+        // Don't write properties to disk until after we have read all default
+        // properties to prevent them from being overwritten by default values.
+        bool need_persist = StartsWith(name, "persist.") || StartsWith(name, "next_boot.");
+        if (socket && persistent_properties_loaded && need_persist) {
+            if (persist_write_thread) {
+                persist_write_thread->Write(name, value, std::move(*socket));
+                return {};
+            }
+            WritePersistentProperty(name, value);
+        }
     }
 
     NotifyPropertyChange(name, value);
@@ -584,10 +594,10 @@
     return *ret;
 }
 
-static void handle_property_set_fd() {
+static void handle_property_set_fd(int fd) {
     static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
 
-    int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC);
+    int s = accept4(fd, nullptr, nullptr, SOCK_CLOEXEC);
     if (s == -1) {
         return;
     }
@@ -1090,6 +1100,12 @@
     // required to support.
     constexpr auto VENDOR_API_LEVEL_PROP = "ro.vendor.api_level";
 
+    if (__system_property_find(VENDOR_API_LEVEL_PROP) != nullptr) {
+        // The device already have ro.vendor.api_level in its vendor/build.prop.
+        // Skip initializing the ro.vendor.api_level property.
+        return;
+    }
+
     auto vendor_api_level = GetIntProperty("ro.board.first_api_level", __ANDROID_VENDOR_API_MAX__);
     if (vendor_api_level != __ANDROID_VENDOR_API_MAX__) {
         // Update the vendor_api_level with "ro.board.api_level" only if both "ro.board.api_level"
@@ -1295,7 +1311,7 @@
     mkdir(APPCOMPAT_OVERRIDE_PROP_FOLDERNAME, S_IRWXU | S_IXGRP | S_IXOTH);
     if (!WriteStringToFile(serialized_contexts, APPCOMPAT_OVERRIDE_PROP_TREE_FILE, 0444, 0, 0,
                            false)) {
-        PLOG(ERROR) << "Unable to write vendor overrides to file";
+        PLOG(ERROR) << "Unable to write appcompat override property infos to file";
     }
     selinux_android_restorecon(APPCOMPAT_OVERRIDE_PROP_TREE_FILE, 0);
 }
@@ -1432,19 +1448,21 @@
     }
 }
 
-static void PropertyServiceThread() {
+static void PropertyServiceThread(int fd, bool listen_init) {
     Epoll epoll;
     if (auto result = epoll.Open(); !result.ok()) {
         LOG(FATAL) << result.error();
     }
 
-    if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd);
+    if (auto result = epoll.RegisterHandler(fd, std::bind(handle_property_set_fd, fd));
         !result.ok()) {
         LOG(FATAL) << result.error();
     }
 
-    if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) {
-        LOG(FATAL) << result.error();
+    if (listen_init) {
+        if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) {
+            LOG(FATAL) << result.error();
+        }
     }
 
     while (true) {
@@ -1493,6 +1511,23 @@
     cv_.notify_all();
 }
 
+void StartThread(const char* name, int mode, int gid, std::thread& t, bool listen_init) {
+    int fd = -1;
+    if (auto result = CreateSocket(name, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+                                   /*passcred=*/false, /*should_listen=*/false, mode, /*uid=*/0,
+                                   /*gid=*/gid, /*socketcon=*/{});
+        result.ok()) {
+        fd = *result;
+    } else {
+        LOG(FATAL) << "start_property_service socket creation failed: " << result.error();
+    }
+
+    listen(fd, 8);
+
+    auto new_thread = std::thread(PropertyServiceThread, fd, listen_init);
+    t.swap(new_thread);
+}
+
 void StartPropertyService(int* epoll_socket) {
     InitPropertySet("ro.property_service.version", "2");
 
@@ -1504,19 +1539,9 @@
     init_socket = sockets[1];
     StartSendingMessages();
 
-    if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
-                                   /*passcred=*/false, /*should_listen=*/false, 0666, /*uid=*/0,
-                                   /*gid=*/0, /*socketcon=*/{});
-        result.ok()) {
-        property_set_fd = *result;
-    } else {
-        LOG(FATAL) << "start_property_service socket creation failed: " << result.error();
-    }
-
-    listen(property_set_fd, 8);
-
-    auto new_thread = std::thread{PropertyServiceThread};
-    property_service_thread.swap(new_thread);
+    StartThread(PROP_SERVICE_FOR_SYSTEM_NAME, 0660, AID_SYSTEM, property_service_for_system_thread,
+                true);
+    StartThread(PROP_SERVICE_NAME, 0666, 0, property_service_thread, false);
 
     auto async_persist_writes =
             android::base::GetBoolProperty("ro.property_service.async_persist_writes", false);
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 1a26c4d..150f8f4 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -1083,7 +1083,8 @@
                         return;
                     }
                 }
-            } else if (reboot_target == "quiescent") {
+            } else if (std::find(cmd_params.begin(), cmd_params.end(), "quiescent")
+                    != cmd_params.end()) { // Quiescent can be either subreason or details.
                 bootloader_message boot = {};
                 if (std::string err; !read_bootloader_message(&boot, &err)) {
                     LOG(ERROR) << "Failed to read bootloader message: " << err;
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 1f211dd..e191b60 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -111,97 +111,6 @@
     return true;
 }
 
-// Forks, executes the provided program in the child, and waits for the completion in the parent.
-// Child's stderr is captured and logged using LOG(ERROR).
-bool ForkExecveAndWaitForCompletion(const char* filename, char* const argv[]) {
-    // Create a pipe used for redirecting child process's output.
-    // * pipe_fds[0] is the FD the parent will use for reading.
-    // * pipe_fds[1] is the FD the child will use for writing.
-    int pipe_fds[2];
-    if (pipe(pipe_fds) == -1) {
-        PLOG(ERROR) << "Failed to create pipe";
-        return false;
-    }
-
-    pid_t child_pid = fork();
-    if (child_pid == -1) {
-        PLOG(ERROR) << "Failed to fork for " << filename;
-        return false;
-    }
-
-    if (child_pid == 0) {
-        // fork succeeded -- this is executing in the child process
-
-        // Close the pipe FD not used by this process
-        close(pipe_fds[0]);
-
-        // Redirect stderr to the pipe FD provided by the parent
-        if (TEMP_FAILURE_RETRY(dup2(pipe_fds[1], STDERR_FILENO)) == -1) {
-            PLOG(ERROR) << "Failed to redirect stderr of " << filename;
-            _exit(127);
-            return false;
-        }
-        close(pipe_fds[1]);
-
-        if (execv(filename, argv) == -1) {
-            PLOG(ERROR) << "Failed to execve " << filename;
-            return false;
-        }
-        // Unreachable because execve will have succeeded and replaced this code
-        // with child process's code.
-        _exit(127);
-        return false;
-    } else {
-        // fork succeeded -- this is executing in the original/parent process
-
-        // Close the pipe FD not used by this process
-        close(pipe_fds[1]);
-
-        // Log the redirected output of the child process.
-        // It's unfortunate that there's no standard way to obtain an istream for a file descriptor.
-        // As a result, we're buffering all output and logging it in one go at the end of the
-        // invocation, instead of logging it as it comes in.
-        const int child_out_fd = pipe_fds[0];
-        std::string child_output;
-        if (!android::base::ReadFdToString(child_out_fd, &child_output)) {
-            PLOG(ERROR) << "Failed to capture full output of " << filename;
-        }
-        close(child_out_fd);
-        if (!child_output.empty()) {
-            // Log captured output, line by line, because LOG expects to be invoked for each line
-            std::istringstream in(child_output);
-            std::string line;
-            while (std::getline(in, line)) {
-                LOG(ERROR) << filename << ": " << line;
-            }
-        }
-
-        // Wait for child to terminate
-        int status;
-        if (TEMP_FAILURE_RETRY(waitpid(child_pid, &status, 0)) != child_pid) {
-            PLOG(ERROR) << "Failed to wait for " << filename;
-            return false;
-        }
-
-        if (WIFEXITED(status)) {
-            int status_code = WEXITSTATUS(status);
-            if (status_code == 0) {
-                return true;
-            } else {
-                LOG(ERROR) << filename << " exited with status " << status_code;
-            }
-        } else if (WIFSIGNALED(status)) {
-            LOG(ERROR) << filename << " killed by signal " << WTERMSIG(status);
-        } else if (WIFSTOPPED(status)) {
-            LOG(ERROR) << filename << " stopped by signal " << WSTOPSIG(status);
-        } else {
-            LOG(ERROR) << "waitpid for " << filename << " returned unexpected status: " << status;
-        }
-
-        return false;
-    }
-}
-
 bool ReadFirstLine(const char* file, std::string* line) {
     line->clear();
 
diff --git a/init/util.cpp b/init/util.cpp
index e760a59..e5efc7d 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -27,6 +27,7 @@
 #include <string.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <sys/wait.h>
 #include <time.h>
 #include <unistd.h>
 
@@ -747,5 +748,96 @@
     return filtered_configs;
 }
 
+// Forks, executes the provided program in the child, and waits for the completion in the parent.
+// Child's stderr is captured and logged using LOG(ERROR).
+bool ForkExecveAndWaitForCompletion(const char* filename, char* const argv[]) {
+    // Create a pipe used for redirecting child process's output.
+    // * pipe_fds[0] is the FD the parent will use for reading.
+    // * pipe_fds[1] is the FD the child will use for writing.
+    int pipe_fds[2];
+    if (pipe(pipe_fds) == -1) {
+        PLOG(ERROR) << "Failed to create pipe";
+        return false;
+    }
+
+    pid_t child_pid = fork();
+    if (child_pid == -1) {
+        PLOG(ERROR) << "Failed to fork for " << filename;
+        return false;
+    }
+
+    if (child_pid == 0) {
+        // fork succeeded -- this is executing in the child process
+
+        // Close the pipe FD not used by this process
+        close(pipe_fds[0]);
+
+        // Redirect stderr to the pipe FD provided by the parent
+        if (TEMP_FAILURE_RETRY(dup2(pipe_fds[1], STDERR_FILENO)) == -1) {
+            PLOG(ERROR) << "Failed to redirect stderr of " << filename;
+            _exit(127);
+            return false;
+        }
+        close(pipe_fds[1]);
+
+        if (execv(filename, argv) == -1) {
+            PLOG(ERROR) << "Failed to execve " << filename;
+            return false;
+        }
+        // Unreachable because execve will have succeeded and replaced this code
+        // with child process's code.
+        _exit(127);
+        return false;
+    } else {
+        // fork succeeded -- this is executing in the original/parent process
+
+        // Close the pipe FD not used by this process
+        close(pipe_fds[1]);
+
+        // Log the redirected output of the child process.
+        // It's unfortunate that there's no standard way to obtain an istream for a file descriptor.
+        // As a result, we're buffering all output and logging it in one go at the end of the
+        // invocation, instead of logging it as it comes in.
+        const int child_out_fd = pipe_fds[0];
+        std::string child_output;
+        if (!android::base::ReadFdToString(child_out_fd, &child_output)) {
+            PLOG(ERROR) << "Failed to capture full output of " << filename;
+        }
+        close(child_out_fd);
+        if (!child_output.empty()) {
+            // Log captured output, line by line, because LOG expects to be invoked for each line
+            std::istringstream in(child_output);
+            std::string line;
+            while (std::getline(in, line)) {
+                LOG(ERROR) << filename << ": " << line;
+            }
+        }
+
+        // Wait for child to terminate
+        int status;
+        if (TEMP_FAILURE_RETRY(waitpid(child_pid, &status, 0)) != child_pid) {
+            PLOG(ERROR) << "Failed to wait for " << filename;
+            return false;
+        }
+
+        if (WIFEXITED(status)) {
+            int status_code = WEXITSTATUS(status);
+            if (status_code == 0) {
+                return true;
+            } else {
+                LOG(ERROR) << filename << " exited with status " << status_code;
+            }
+        } else if (WIFSIGNALED(status)) {
+            LOG(ERROR) << filename << " killed by signal " << WTERMSIG(status);
+        } else if (WIFSTOPPED(status)) {
+            LOG(ERROR) << filename << " stopped by signal " << WSTOPSIG(status);
+        } else {
+            LOG(ERROR) << "waitpid for " << filename << " returned unexpected status: " << status;
+        }
+
+        return false;
+    }
+}
+
 }  // namespace init
 }  // namespace android
diff --git a/init/util.h b/init/util.h
index 2d02182..aa24123 100644
--- a/init/util.h
+++ b/init/util.h
@@ -117,5 +117,10 @@
 // (.rc == .0rc for ranking purposes)
 std::vector<std::string> FilterVersionedConfigs(const std::vector<std::string>& configs,
                                                   int active_sdk);
+
+// Forks, executes the provided program in the child, and waits for the completion in the parent.
+// Child's stderr is captured and logged using LOG(ERROR).
+bool ForkExecveAndWaitForCompletion(const char* filename, char* const argv[]);
+
 }  // namespace init
 }  // namespace android
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 8ae7d9e..b7752d9 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -116,27 +116,6 @@
     },
 }
 
-cc_test {
-    name: "libcutils_sockets_test",
-    test_suites: ["device-tests"],
-    static_libs: ["libbase", "libcutils_sockets"],
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-    ],
-
-    srcs: ["sockets_test.cpp"],
-    target: {
-        android: {
-            srcs: [
-                "android_get_control_file_test.cpp",
-                "android_get_control_socket_test.cpp",
-            ],
-        },
-    },
-}
-
 // some files must not be compiled when building against Mingw
 // they correspond to features not used by our host development tools
 // which are also hard or even impossible to port to native Win32
@@ -347,7 +326,10 @@
 
 cc_test {
     name: "KernelLibcutilsTest",
-    test_suites: ["general-tests", "vts"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
     defaults: ["libcutils_test_static_defaults"],
     test_config: "KernelLibcutilsTest.xml",
 }
diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp
index 410dbfd..46b8ef2 100644
--- a/libcutils/ashmem-dev.cpp
+++ b/libcutils/ashmem-dev.cpp
@@ -301,6 +301,12 @@
         return -1;
     }
 
+    // forbid size changes to match ashmem behaviour
+    if (fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK) == -1) {
+        ALOGE("memfd_create(%s, %zd) F_ADD_SEALS failed: %m", name, size);
+        return -1;
+    }
+
     if (debug_log) {
         ALOGE("memfd_create(%s, %zd) success. fd=%d\n", name, size, fd.get());
     }
@@ -352,14 +358,29 @@
 }
 
 static int memfd_set_prot_region(int fd, int prot) {
-    /* Only proceed if an fd needs to be write-protected */
+    int seals = fcntl(fd, F_GET_SEALS);
+    if (seals == -1) {
+        ALOGE("memfd_set_prot_region(%d, %d): F_GET_SEALS failed: %s\n", fd, prot, strerror(errno));
+        return -1;
+    }
+
     if (prot & PROT_WRITE) {
+        /* Now we want the buffer to be read-write, let's check if the buffer
+         * has been previously marked as read-only before, if so return error
+         */
+        if (seals & F_SEAL_FUTURE_WRITE) {
+            ALOGE("memfd_set_prot_region(%d, %d): region is write protected\n", fd, prot);
+            errno = EINVAL;  // inline with ashmem error code, if already in
+                             // read-only mode
+            return -1;
+        }
         return 0;
     }
 
-    if (fcntl(fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE) == -1) {
-        ALOGE("memfd_set_prot_region(%d, %d): F_SEAL_FUTURE_WRITE seal failed: %s\n", fd, prot,
-              strerror(errno));
+    /* We would only allow read-only for any future file operations */
+    if (fcntl(fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE | F_SEAL_SEAL) == -1) {
+        ALOGE("memfd_set_prot_region(%d, %d): F_SEAL_FUTURE_WRITE | F_SEAL_SEAL seal failed: %s\n",
+              fd, prot, strerror(errno));
         return -1;
     }
 
diff --git a/libmodprobe/include/modprobe/modprobe.h b/libmodprobe/include/modprobe/modprobe.h
index 5d79d6a..d7a90c4 100644
--- a/libmodprobe/include/modprobe/modprobe.h
+++ b/libmodprobe/include/modprobe/modprobe.h
@@ -41,6 +41,7 @@
                             std::vector<std::string>* post_dependencies);
     void ResetModuleCount() { module_count_ = 0; }
     int GetModuleCount() { return module_count_; }
+    bool IsBlocklisted(const std::string& module_name);
 
   private:
     std::string MakeCanonical(const std::string& module_path);
@@ -52,7 +53,6 @@
     void AddOption(const std::string& module_name, const std::string& option_name,
                    const std::string& value);
     std::string GetKernelCmdline();
-    bool IsBlocklisted(const std::string& module_name);
 
     bool ParseDepCallback(const std::string& base_path, const std::vector<std::string>& args);
     bool ParseAliasCallback(const std::vector<std::string>& args);
diff --git a/libutils/include/utils/CallStack.h b/libutils/include/utils/CallStack.h
index 54d559b..0239b68 100644
--- a/libutils/include/utils/CallStack.h
+++ b/libutils/include/utils/CallStack.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_CALLSTACK_H
-#define ANDROID_CALLSTACK_H
+#pragma once
 
 #include <memory>
 
@@ -27,14 +26,14 @@
 #include <sys/types.h>
 
 #if !defined(__APPLE__) && !defined(_WIN32)
-# define WEAKS_AVAILABLE 1
+# define CALLSTACK_WEAKS_AVAILABLE 1
 #endif
 #ifndef CALLSTACK_WEAK
-# ifdef WEAKS_AVAILABLE
+# ifdef CALLSTACK_WEAKS_AVAILABLE
 #   define CALLSTACK_WEAK __attribute__((weak))
-# else // !WEAKS_AVAILABLE
+# else // !CALLSTACK_WEAKS_AVAILABLE
 #   define CALLSTACK_WEAK
-# endif // !WEAKS_AVAILABLE
+# endif // !CALLSTACK_WEAKS_AVAILABLE
 #endif // CALLSTACK_WEAK predefined
 
 #ifndef CALLSTACK_ALWAYS_INLINE
@@ -91,7 +90,7 @@
     //
     // DO NOT USE THESE. They will disappear.
     struct StackDeleter {
-#ifdef WEAKS_AVAILABLE
+#ifdef CALLSTACK_WEAKS_AVAILABLE
         void operator()(CallStack* stack) {
             deleteStack(stack);
         }
@@ -103,7 +102,7 @@
     typedef std::unique_ptr<CallStack, StackDeleter> CallStackUPtr;
 
     // Return current call stack if possible, nullptr otherwise.
-#ifdef WEAKS_AVAILABLE
+#ifdef CALLSTACK_WEAKS_AVAILABLE
     static CallStackUPtr CALLSTACK_ALWAYS_INLINE getCurrent(int32_t ignoreDepth = 1) {
         if (reinterpret_cast<uintptr_t>(getCurrentInternal) == 0) {
             ALOGW("CallStack::getCurrentInternal not linked, returning null");
@@ -112,13 +111,13 @@
             return getCurrentInternal(ignoreDepth);
         }
     }
-#else // !WEAKS_AVAILABLE
+#else // !CALLSTACK_WEAKS_AVAILABLE
     static CallStackUPtr CALLSTACK_ALWAYS_INLINE getCurrent(int32_t = 1) {
         return CallStackUPtr(nullptr);
     }
-#endif // !WEAKS_AVAILABLE
+#endif // !CALLSTACK_WEAKS_AVAILABLE
 
-#ifdef WEAKS_AVAILABLE
+#ifdef CALLSTACK_WEAKS_AVAILABLE
     static void CALLSTACK_ALWAYS_INLINE logStack(const char* logtag,
                                                  CallStack* stack = getCurrent().get(),
                                                  android_LogPriority priority = ANDROID_LOG_DEBUG) {
@@ -135,9 +134,9 @@
                                                  android_LogPriority = ANDROID_LOG_DEBUG) {
         ALOG(LOG_WARN, logtag, "CallStack::logStackInternal not linked");
     }
-#endif // !WEAKS_AVAILABLE
+#endif // !CALLSTACK_WEAKS_AVAILABLE
 
-#ifdef WEAKS_AVAILABLE
+#ifdef CALLSTACK_WEAKS_AVAILABLE
     static String8 CALLSTACK_ALWAYS_INLINE
     stackToString(const char* prefix = nullptr, const CallStack* stack = getCurrent().get()) {
         if (reinterpret_cast<uintptr_t>(stackToStringInternal) != 0 && stack != nullptr) {
@@ -146,15 +145,15 @@
             return String8::format("%s<CallStack package not linked>", (prefix ? prefix : ""));
         }
     }
-#else // !WEAKS_AVAILABLE
+#else // !CALLSTACK_WEAKS_AVAILABLE
     static String8 CALLSTACK_ALWAYS_INLINE stackToString(const char* prefix = nullptr,
                                                          const CallStack* = getCurrent().get()) {
         return String8::format("%s<CallStack package not linked>", (prefix ? prefix : ""));
     }
-#endif // !WEAKS_AVAILABLE
+#endif // !CALLSTACK_WEAKS_AVAILABLE
 
   private:
-#ifdef WEAKS_AVAILABLE
+#ifdef CALLSTACK_WEAKS_AVAILABLE
     static CallStackUPtr CALLSTACK_WEAK getCurrentInternal(int32_t ignoreDepth);
     static void CALLSTACK_WEAK logStackInternal(const char* logtag, const CallStack* stack,
                                                 android_LogPriority priority);
@@ -162,13 +161,13 @@
     // The deleter is only invoked on non-null pointers. Hence it will never be
     // invoked if CallStack is not linked.
     static void CALLSTACK_WEAK deleteStack(CallStack* stack);
-#endif // WEAKS_AVAILABLE
+#endif // CALLSTACK_WEAKS_AVAILABLE
 
     Vector<String8> mFrameLines;
 };
 
 }  // namespace android
 
+#undef CALLSTACK_WEAKS_AVAILABLE
+#undef CALLSTACK_WEAK
 #undef CALLSTACK_ALWAYS_INLINE
-
-#endif // ANDROID_CALLSTACK_H
diff --git a/libvendorsupport/Android.bp b/libvendorsupport/Android.bp
index b4457b1..e87959e 100644
--- a/libvendorsupport/Android.bp
+++ b/libvendorsupport/Android.bp
@@ -34,3 +34,32 @@
         "liblog",
     ],
 }
+
+cc_library_headers {
+    name: "libvendorsupport_llndk_headers",
+    host_supported: true,
+    vendor_available: true,
+    recovery_available: true,
+    ramdisk_available: true,
+    vendor_ramdisk_available: true,
+    native_bridge_supported: true,
+
+    export_include_dirs: ["include_llndk"],
+    llndk: {
+        llndk_headers: true,
+    },
+
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    min_sdk_version: "apex_inherit",
+
+    system_shared_libs: [],
+    stl: "none",
+
+    // This header library is used for libc and must be available to any sdk
+    // versions.
+    // Setting sdk_version to the lowest version allows the dependencies.
+    sdk_version: "1",
+}
diff --git a/libvendorsupport/include_llndk/android/llndk-versioning.h b/libvendorsupport/include_llndk/android/llndk-versioning.h
new file mode 100644
index 0000000..b500149
--- /dev/null
+++ b/libvendorsupport/include_llndk/android/llndk-versioning.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2024 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 <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#if defined(__ANDROID_VENDOR__)
+
+// LLNDK (https://source.android.com/docs/core/architecture/vndk/build-system#ll-ndk) is similar to
+// NDK, but uses its own versioning of YYYYMM format for vendor builds. The LLNDK symbols are
+// enabled when the vendor api level is equal to or newer than the ro.board.api_level.
+#define __INTRODUCED_IN_LLNDK(vendor_api_level)                                             \
+    _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wgcc-compat\"")   \
+            __attribute__((enable_if(                                                       \
+                    __ANDROID_VENDOR_API__ >= vendor_api_level,                             \
+                    "available in vendor API level " #vendor_api_level " that "             \
+                    "is newer than the current vendor API level. Guard the API "            \
+                    "call with '#if (__ANDROID_VENDOR_API__ >= " #vendor_api_level ")'."))) \
+            _Pragma("clang diagnostic pop")
+
+// Use this macro as an `if` statement to call an API that are available to both NDK and LLNDK.
+// This returns true for the vendor modules if the vendor_api_level is less than or equal to the
+// ro.board.api_level.
+#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) \
+    constexpr(__ANDROID_VENDOR_API__ >= vendor_api_level)
+
+#else  // __ANDROID_VENDOR__
+
+// __INTRODUCED_IN_LLNDK is for LLNDK only but not for NDK. Ignore this for non-vendor modules.
+// It leaves a no-op annotation for ABI analysis.
+#if !defined(__INTRODUCED_IN_LLNDK)
+#define __INTRODUCED_IN_LLNDK(vendor_api_level) \
+    __attribute__((annotate("introduced_in_llndk=" #vendor_api_level)))
+#endif
+
+// For non-vendor modules, API_LEVEL_AT_LEAST is replaced with __builtin_available(sdk_api_level) to
+// guard the API for __INTRODUCED_IN.
+#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) \
+    (__builtin_available(android sdk_api_level, *))
+
+#endif  // __ANDROID_VENDOR__
+
+__END_DECLS
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 2b29e7d..70bb38a 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -247,6 +247,7 @@
     write /dev/blkio/background/blkio.bfq.weight 10
     write /dev/blkio/blkio.group_idle 0
     write /dev/blkio/background/blkio.group_idle 0
+    write /dev/blkio/blkio.prio.class promote-to-rt
     write /dev/blkio/background/blkio.prio.class restrict-to-be
 
     restorecon_recursive /mnt
@@ -303,6 +304,9 @@
     mkdir /mnt/runtime/full 0755 root root
     mkdir /mnt/runtime/full/self 0755 root root
 
+    # For Pre-reboot Dexopt
+    mkdir /mnt/pre_reboot_dexopt 0755 artd artd
+
     # Symlink to keep legacy apps working in multi-user world
     symlink /storage/self/primary /mnt/sdcard
     symlink /mnt/user/0/primary /mnt/runtime/default/self/primary
@@ -710,7 +714,7 @@
 
     # Start tombstoned early to be able to store tombstones.
     mkdir /data/anr 0775 system system encryption=Require
-    mkdir /data/tombstones 0771 system system encryption=Require
+    mkdir /data/tombstones 0775 system system encryption=Require
     mkdir /data/vendor/tombstones 0771 root root
     mkdir /data/vendor/tombstones/wifi 0771 wifi wifi
     start tombstoned
@@ -1359,3 +1363,16 @@
   write /sys/kernel/mm/lru_gen/enabled 5
 on property:persist.device_config.mglru_native.lru_gen_config=all
   write /sys/kernel/mm/lru_gen/enabled 7
+
+# Allow other processes to run `snapshotctl` through `init`. This requires
+# `set_prop` permission on `snapshotctl_prop`.
+on property:sys.snapshotctl.map=requested
+    # "root" is needed to talk to gsid and pass its check on uid.
+    # "system" is needed to write to "/dev/socket/snapuserd" to talk to
+    # snapuserd.
+    exec - root root system -- /system/bin/snapshotctl map
+    setprop sys.snapshotctl.map "finished"
+
+on property:sys.snapshotctl.unmap=requested
+    exec - root root system -- /system/bin/snapshotctl unmap
+    setprop sys.snapshotctl.unmap "finished"
diff --git a/toolbox/modprobe.cpp b/toolbox/modprobe.cpp
index 17d4e31..56cf140 100644
--- a/toolbox/modprobe.cpp
+++ b/toolbox/modprobe.cpp
@@ -257,6 +257,7 @@
         switch (mode) {
             case AddModulesMode:
                 if (!m.LoadWithAliases(module, true, module_parameters)) {
+                    if (m.IsBlocklisted(module)) continue;
                     PLOG(ERROR) << "Failed to load module " << module;
                     rv = EXIT_FAILURE;
                 }
diff --git a/trusty/metrics/include/trusty/metrics/tipc.h b/trusty/metrics/include/trusty/metrics/tipc.h
index b29628e..e2cf57b 100644
--- a/trusty/metrics/include/trusty/metrics/tipc.h
+++ b/trusty/metrics/include/trusty/metrics/tipc.h
@@ -39,14 +39,17 @@
  * repository. They must be kept in sync.
  */
 
-#define METRICS_PORT "com.android.trusty.metrics"
+#define METRICS_PORT "com.android.trusty.metrics.consumer"
+
+#define UUID_STR_SIZE (37)
 
 /**
  * enum metrics_cmd - command identifiers for metrics interface
- * @METRICS_CMD_RESP_BIT:          message is a response
- * @METRICS_CMD_REQ_SHIFT:         number of bits used by @METRICS_CMD_RESP_BIT
- * @METRICS_CMD_REPORT_EVENT_DROP: report gaps in the event stream
- * @METRICS_CMD_REPORT_CRASH:      report an app crash event
+ * @METRICS_CMD_RESP_BIT:             message is a response
+ * @METRICS_CMD_REQ_SHIFT:            number of bits used by @METRICS_CMD_RESP_BIT
+ * @METRICS_CMD_REPORT_EVENT_DROP:    report gaps in the event stream
+ * @METRICS_CMD_REPORT_CRASH:         report an app crash event
+ * @METRICS_CMD_REPORT_STORAGE_ERROR: report trusty storage error
  */
 enum metrics_cmd {
     METRICS_CMD_RESP_BIT = 1,
@@ -54,6 +57,7 @@
 
     METRICS_CMD_REPORT_EVENT_DROP = (1 << METRICS_CMD_REQ_SHIFT),
     METRICS_CMD_REPORT_CRASH = (2 << METRICS_CMD_REQ_SHIFT),
+    METRICS_CMD_REPORT_STORAGE_ERROR = (3 << METRICS_CMD_REQ_SHIFT),
 };
 
 /**
@@ -90,17 +94,70 @@
 /**
  * struct metrics_report_crash_req - arguments of %METRICS_CMD_REPORT_CRASH
  *                                   requests
- * @app_id_len: length of app ID that follows this structure
+ * @app_id: uuid of the app that crashed
  * @crash_reason: architecture-specific code representing the reason for the
  *                crash
  */
 struct metrics_report_crash_req {
-    uint32_t app_id_len;
+    char app_id[UUID_STR_SIZE];
     uint32_t crash_reason;
 } __attribute__((__packed__));
 
-#define METRICS_MAX_APP_ID_LEN 256
+enum TrustyStorageErrorType {
+  TRUSTY_STORAGE_ERROR_UNKNOWN = 0,
+  TRUSTY_STORAGE_ERROR_SUPERBLOCK_INVALID = 1,
+  TRUSTY_STORAGE_ERROR_BLOCK_MAC_MISMATCH = 2,
+  TRUSTY_STORAGE_ERROR_BLOCK_HEADER_INVALID = 3,
+  TRUSTY_STORAGE_ERROR_RPMB_COUNTER_MISMATCH = 4,
+  TRUSTY_STORAGE_ERROR_RPMB_COUNTER_MISMATCH_RECOVERED = 5,
+  TRUSTY_STORAGE_ERROR_RPMB_COUNTER_READ_FAILURE = 6,
+  TRUSTY_STORAGE_ERROR_RPMB_MAC_MISMATCH = 7,
+  TRUSTY_STORAGE_ERROR_RPMB_ADDR_MISMATCH = 8,
+  TRUSTY_STORAGE_ERROR_RPMB_FAILURE_RESPONSE = 9,
+  TRUSTY_STORAGE_ERROR_RPMB_UNKNOWN = 10,
+  TRUSTY_STORAGE_ERROR_RPMB_SCSI_ERROR = 11,
+  TRUSTY_STORAGE_ERROR_IO_ERROR = 12,
+  TRUSTY_STORAGE_ERROR_PROXY_COMMUNICATION_FAILURE = 13,
+};
 
-#define METRICS_MAX_MSG_SIZE                                                \
-    (sizeof(struct metrics_req) + sizeof(struct metrics_report_crash_req) + \
-     METRICS_MAX_APP_ID_LEN)
+enum TrustyFileSystem {
+  TRUSTY_FS_UNKNOWN = 0,
+  TRUSTY_FS_TP = 1,
+  TRUSTY_FS_TD = 2,
+  TRUSTY_FS_TDP = 3,
+  TRUSTY_FS_TDEA = 4,
+  TRUSTY_FS_NSP = 5,
+};
+
+enum TrustyBlockType {
+  TRUSTY_BLOCKTYPE_UNKNOWN = 0,
+  TRUSTY_BLOCKTYPE_FILES_ROOT = 1,
+  TRUSTY_BLOCKTYPE_FREE_ROOT = 2,
+  TRUSTY_BLOCKTYPE_FILES_INTERNAL = 3,
+  TRUSTY_BLOCKTYPE_FREE_INTERNAL = 4,
+  TRUSTY_BLOCKTYPE_FILE_ENTRY = 5,
+  TRUSTY_BLOCKTYPE_FILE_BLOCK_MAP = 6,
+  TRUSTY_BLOCKTYPE_FILE_DATA = 7,
+  TRUSTY_BLOCKTYPE_CHECKPOINT_ROOT = 8,
+  TRUSTY_BLOCKTYPE_CHECKPOINT_FILES_ROOT = 9,
+  TRUSTY_BLOCKTYPE_CHECKPOINT_FREE_ROOT = 10,
+};
+
+struct metrics_report_storage_error_req {
+    enum TrustyStorageErrorType error;
+    char app_id[UUID_STR_SIZE];
+    char client_app_id[UUID_STR_SIZE];
+    uint32_t write;
+    enum TrustyFileSystem file_system;
+    uint64_t file_path_hash;
+    enum TrustyBlockType block_type;
+    uint64_t repair_counter;
+} __attribute__((__packed__));
+
+struct metrics_msg {
+    struct metrics_req req;
+    union {
+        struct metrics_report_crash_req crash_args;
+        struct metrics_report_storage_error_req storage_args;
+    };
+} __attribute__((__packed__));
\ No newline at end of file
diff --git a/trusty/metrics/metrics.cpp b/trusty/metrics/metrics.cpp
index 3ac128a..d2f0b0a 100644
--- a/trusty/metrics/metrics.cpp
+++ b/trusty/metrics/metrics.cpp
@@ -78,9 +78,8 @@
         return Error() << "connection to Metrics TA has not been initialized yet";
     }
 
-    uint8_t msg[METRICS_MAX_MSG_SIZE];
-
-    auto rc = read(metrics_fd_, msg, sizeof(msg));
+    struct metrics_msg metrics_msg;
+    int rc = read(metrics_fd_, &metrics_msg, sizeof(metrics_msg));
     if (rc < 0) {
         return ErrnoError() << "failed to read metrics message";
     }
@@ -89,23 +88,14 @@
     if (msg_len < sizeof(metrics_req)) {
         return Error() << "message too small: " << rc;
     }
-    auto req = reinterpret_cast<metrics_req*>(msg);
-    size_t offset = sizeof(metrics_req);
+    uint32_t cmd = metrics_msg.req.cmd;
     uint32_t status = METRICS_NO_ERROR;
 
-    switch (req->cmd) {
+    switch (cmd) {
         case METRICS_CMD_REPORT_CRASH: {
-            if (msg_len < offset + sizeof(metrics_report_crash_req)) {
-                return Error() << "message too small: " << rc;
-            }
-            auto crash_args = reinterpret_cast<metrics_report_crash_req*>(msg + offset);
-            offset += sizeof(metrics_report_crash_req);
-
-            if (msg_len < offset + crash_args->app_id_len) {
-                return Error() << "message too small: " << rc;
-            }
-            auto app_id_ptr = reinterpret_cast<char*>(msg + offset);
-            std::string app_id(app_id_ptr, crash_args->app_id_len);
+            struct metrics_report_crash_req crash_args = metrics_msg.crash_args;
+            auto app_id_ptr = crash_args.app_id;
+            std::string app_id(app_id_ptr, UUID_STR_SIZE);
 
             HandleCrash(app_id);
             break;
@@ -121,7 +111,7 @@
     }
 
     metrics_resp resp = {
-            .cmd = req->cmd | METRICS_CMD_RESP_BIT,
+            .cmd = cmd | METRICS_CMD_RESP_BIT,
             .status = status,
     };