Merge "Provide alternate SE RoT provisioning path."
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 0737612..85adbea 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -1409,6 +1409,16 @@
   return true;
 }
 
+extern "C" void foo() {
+  LOG(INFO) << "foo";
+  std::this_thread::sleep_for(1s);
+}
+
+extern "C" void bar() {
+  LOG(INFO) << "bar";
+  std::this_thread::sleep_for(1s);
+}
+
 TEST_F(CrasherTest, seccomp_tombstone) {
   int intercept_result;
   unique_fd output_fd;
@@ -1416,6 +1426,11 @@
   static const auto dump_type = kDebuggerdTombstone;
   StartProcess(
       []() {
+        std::thread a(foo);
+        std::thread b(bar);
+
+        std::this_thread::sleep_for(100ms);
+
         raise_debugger_signal(dump_type);
         _exit(0);
       },
@@ -1430,16 +1445,8 @@
   std::string result;
   ConsumeFd(std::move(output_fd), &result);
   ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
-}
-
-extern "C" void foo() {
-  LOG(INFO) << "foo";
-  std::this_thread::sleep_for(1s);
-}
-
-extern "C" void bar() {
-  LOG(INFO) << "bar";
-  std::this_thread::sleep_for(1s);
+  ASSERT_BACKTRACE_FRAME(result, "foo");
+  ASSERT_BACKTRACE_FRAME(result, "bar");
 }
 
 TEST_F(CrasherTest, seccomp_backtrace) {
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index baf994f..4c1f9eb 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -98,32 +98,6 @@
   __linker_disable_fallback_allocator();
 }
 
-static void iterate_siblings(bool (*callback)(pid_t, int), int output_fd) {
-  pid_t current_tid = gettid();
-  char buf[BUFSIZ];
-  snprintf(buf, sizeof(buf), "/proc/%d/task", current_tid);
-  DIR* dir = opendir(buf);
-
-  if (!dir) {
-    async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to open %s: %s", buf, strerror(errno));
-    return;
-  }
-
-  struct dirent* ent;
-  while ((ent = readdir(dir))) {
-    char* end;
-    long tid = strtol(ent->d_name, &end, 10);
-    if (end == ent->d_name || *end != '\0') {
-      continue;
-    }
-
-    if (tid != current_tid) {
-      callback(tid, output_fd);
-    }
-  }
-  closedir(dir);
-}
-
 static bool forward_output(int src_fd, int dst_fd, pid_t expected_tid) {
   // Make sure the thread actually got the signal.
   struct pollfd pfd = {
@@ -216,21 +190,21 @@
   }
 
   // Only allow one thread to perform a trace at a time.
-  static pthread_mutex_t trace_mutex = PTHREAD_MUTEX_INITIALIZER;
-  int ret = pthread_mutex_trylock(&trace_mutex);
-  if (ret != 0) {
-    async_safe_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_try_lock failed: %s",
-                          strerror(ret));
+  static std::mutex trace_mutex;
+  if (!trace_mutex.try_lock()) {
+    async_safe_format_log(ANDROID_LOG_INFO, "libc", "trace lock failed");
     return;
   }
 
+  std::lock_guard<std::mutex> scoped_lock(trace_mutex, std::adopt_lock);
+
   // Fetch output fd from tombstoned.
   unique_fd tombstone_socket, output_fd;
   if (!tombstoned_connect(getpid(), &tombstone_socket, &output_fd, nullptr,
                           kDebuggerdNativeBacktrace)) {
     async_safe_format_log(ANDROID_LOG_ERROR, "libc",
                           "missing crash_dump_fallback() in selinux policy?");
-    goto exit;
+    return;
   }
 
   dump_backtrace_header(output_fd.get());
@@ -239,15 +213,15 @@
   debuggerd_fallback_trace(output_fd.get(), ucontext);
 
   // Send a signal to all of our siblings, asking them to dump their stack.
-  iterate_siblings(
-      [](pid_t tid, int output_fd) {
+  pid_t current_tid = gettid();
+  if (!iterate_tids(current_tid, [&output_fd](pid_t tid) {
         // Use a pipe, to be able to detect situations where the thread gracefully exits before
         // receiving our signal.
         unique_fd pipe_read, pipe_write;
         if (!Pipe(&pipe_read, &pipe_write)) {
           async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to create pipe: %s",
                                 strerror(errno));
-          return false;
+          return;
         }
 
         uint64_t expected = pack_thread_fd(-1, -1);
@@ -257,7 +231,7 @@
           async_safe_format_log(ANDROID_LOG_ERROR, "libc",
                                 "thread %d is already outputting to fd %d?", tid, fd);
           close(sent_fd);
-          return false;
+          return;
         }
 
         siginfo_t siginfo = {};
@@ -269,10 +243,10 @@
         if (syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
           async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to send trace signal to %d: %s",
                                 tid, strerror(errno));
-          return false;
+          return;
         }
 
-        bool success = forward_output(pipe_read.get(), output_fd, tid);
+        bool success = forward_output(pipe_read.get(), output_fd.get(), tid);
         if (!success) {
           async_safe_format_log(ANDROID_LOG_ERROR, "libc",
                                 "timeout expired while waiting for thread %d to dump", tid);
@@ -288,15 +262,14 @@
           }
         }
 
-        return true;
-      },
-      output_fd.get());
+        return;
+      })) {
+    async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to open /proc/%d/task: %s",
+                          current_tid, strerror(errno));
+  }
 
   dump_backtrace_footer(output_fd.get());
   tombstoned_notify_completion(tombstone_socket.get());
-
-exit:
-  pthread_mutex_unlock(&trace_mutex);
 }
 
 static void crash_handler(siginfo_t* info, ucontext_t* ucontext, void* abort_message) {
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index f21a203..14caaf6 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -23,6 +23,7 @@
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/prctl.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -73,22 +74,40 @@
 
   std::map<pid_t, ThreadInfo> threads;
   threads[tid] = ThreadInfo{
-      .registers = std::move(regs),
-      .uid = uid,
-      .tid = tid,
-      .thread_name = std::move(thread_name),
-      .pid = pid,
-      .command_line = std::move(command_line),
-      .selinux_label = std::move(selinux_label),
-      .siginfo = siginfo,
+    .registers = std::move(regs), .uid = uid, .tid = tid, .thread_name = std::move(thread_name),
+    .pid = pid, .command_line = std::move(command_line), .selinux_label = std::move(selinux_label),
+    .siginfo = siginfo,
+#if defined(__aarch64__)
+    // Only supported on aarch64 for now.
+        .tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0),
+    .pac_enabled_keys = prctl(PR_PAC_GET_ENABLED_KEYS, 0, 0, 0, 0),
+#endif
   };
+  if (pid == tid) {
+    const ThreadInfo& thread = threads[pid];
+    if (!iterate_tids(pid, [&threads, &thread](pid_t tid) {
+          threads[tid] = ThreadInfo{
+              .uid = thread.uid,
+              .tid = tid,
+              .pid = thread.pid,
+              .command_line = thread.command_line,
+              .thread_name = get_thread_name(tid),
+              .tagged_addr_ctrl = thread.tagged_addr_ctrl,
+              .pac_enabled_keys = thread.pac_enabled_keys,
+          };
+        })) {
+      async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to open /proc/%d/task: %s", pid,
+                            strerror(errno));
+    }
+  }
 
   unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid, unwindstack::Regs::CurrentArch());
   auto process_memory =
       unwindstack::Memory::CreateProcessMemoryCached(getpid());
   unwinder.SetProcessMemory(process_memory);
   if (!unwinder.Init()) {
-    async_safe_fatal("failed to init unwinder object");
+    async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to init unwinder object");
+    return;
   }
 
   ProcessInfo process_info;
diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp
index b7d5bc4..3e31bb7 100644
--- a/debuggerd/libdebuggerd/tombstone_proto.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto.cpp
@@ -48,6 +48,7 @@
 
 #include <android/log.h>
 #include <bionic/macros.h>
+#include <bionic/reserved_signals.h>
 #include <log/log.h>
 #include <log/log_read.h>
 #include <log/logprint.h>
@@ -346,6 +347,93 @@
   f->set_build_id(frame.map_info->GetPrintableBuildID());
 }
 
+static void dump_registers(unwindstack::Unwinder* unwinder,
+                           const std::unique_ptr<unwindstack::Regs>& regs, Thread& thread,
+                           bool memory_dump) {
+  if (regs == nullptr) {
+    return;
+  }
+
+  unwindstack::Maps* maps = unwinder->GetMaps();
+  unwindstack::Memory* memory = unwinder->GetProcessMemory().get();
+
+  regs->IterateRegisters([&thread, memory_dump, maps, memory](const char* name, uint64_t value) {
+    Register r;
+    r.set_name(name);
+    r.set_u64(value);
+    *thread.add_registers() = r;
+
+    if (memory_dump) {
+      MemoryDump dump;
+
+      dump.set_register_name(name);
+      std::shared_ptr<unwindstack::MapInfo> map_info = maps->Find(untag_address(value));
+      if (map_info) {
+        dump.set_mapping_name(map_info->name());
+      }
+
+      constexpr size_t kNumBytesAroundRegister = 256;
+      constexpr size_t kNumTagsAroundRegister = kNumBytesAroundRegister / kTagGranuleSize;
+      char buf[kNumBytesAroundRegister];
+      uint8_t tags[kNumTagsAroundRegister];
+      ssize_t bytes = dump_memory(buf, sizeof(buf), tags, sizeof(tags), &value, memory);
+      if (bytes == -1) {
+        return;
+      }
+      dump.set_begin_address(value);
+      dump.set_memory(buf, bytes);
+
+      bool has_tags = false;
+#if defined(__aarch64__)
+      for (size_t i = 0; i < kNumTagsAroundRegister; ++i) {
+        if (tags[i] != 0) {
+          has_tags = true;
+        }
+      }
+#endif  // defined(__aarch64__)
+
+      if (has_tags) {
+        dump.mutable_arm_mte_metadata()->set_memory_tags(tags, kNumTagsAroundRegister);
+      }
+
+      *thread.add_memory_dump() = std::move(dump);
+    }
+  });
+}
+
+static void log_unwinder_error(unwindstack::Unwinder* unwinder) {
+  if (unwinder->LastErrorCode() == unwindstack::ERROR_NONE) {
+    return;
+  }
+
+  async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "  error code: %s",
+                        unwinder->LastErrorCodeString());
+  async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "  error address: 0x%" PRIx64,
+                        unwinder->LastErrorAddress());
+}
+
+static void dump_thread_backtrace(unwindstack::Unwinder* unwinder, Thread& thread) {
+  if (unwinder->NumFrames() == 0) {
+    async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to unwind");
+    log_unwinder_error(unwinder);
+    return;
+  }
+
+  if (unwinder->elf_from_memory_not_file()) {
+    auto backtrace_note = thread.mutable_backtrace_note();
+    *backtrace_note->Add() =
+        "Function names and BuildId information is missing for some frames due";
+    *backtrace_note->Add() = "to unreadable libraries. For unwinds of apps, only shared libraries";
+    *backtrace_note->Add() = "found under the lib/ directory are readable.";
+    *backtrace_note->Add() = "On this device, run setenforce 0 to make the libraries readable.";
+  }
+  unwinder->SetDisplayBuildID(true);
+  for (const auto& frame : unwinder->frames()) {
+    BacktraceFrame* f = thread.add_current_backtrace();
+    fill_in_backtrace_frame(f, frame);
+  }
+}
+
 static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder,
                         const ThreadInfo& thread_info, bool memory_dump = false) {
   Thread thread;
@@ -355,97 +443,32 @@
   thread.set_tagged_addr_ctrl(thread_info.tagged_addr_ctrl);
   thread.set_pac_enabled_keys(thread_info.pac_enabled_keys);
 
-  unwindstack::Maps* maps = unwinder->GetMaps();
-  unwindstack::Memory* memory = unwinder->GetProcessMemory().get();
-
-  thread_info.registers->IterateRegisters(
-      [&thread, memory_dump, maps, memory](const char* name, uint64_t value) {
-        Register r;
-        r.set_name(name);
-        r.set_u64(value);
-        *thread.add_registers() = r;
-
-        if (memory_dump) {
-          MemoryDump dump;
-
-          dump.set_register_name(name);
-          std::shared_ptr<unwindstack::MapInfo> map_info = maps->Find(untag_address(value));
-          if (map_info) {
-            dump.set_mapping_name(map_info->name());
-          }
-
-          constexpr size_t kNumBytesAroundRegister = 256;
-          constexpr size_t kNumTagsAroundRegister = kNumBytesAroundRegister / kTagGranuleSize;
-          char buf[kNumBytesAroundRegister];
-          uint8_t tags[kNumTagsAroundRegister];
-          size_t start_offset = 0;
-          ssize_t bytes = dump_memory(buf, sizeof(buf), tags, sizeof(tags), &value, memory);
-          if (bytes == -1) {
-            return;
-          }
-          dump.set_begin_address(value);
-
-          if (start_offset + bytes > sizeof(buf)) {
-            async_safe_fatal("dump_memory overflowed? start offset = %zu, bytes read = %zd",
-                             start_offset, bytes);
-          }
-
-          dump.set_memory(buf, bytes);
-
-          bool has_tags = false;
-#if defined(__aarch64__)
-          for (size_t i = 0; i < kNumTagsAroundRegister; ++i) {
-            if (tags[i] != 0) {
-              has_tags = true;
-            }
-          }
-#endif  // defined(__aarch64__)
-
-          if (has_tags) {
-            dump.mutable_arm_mte_metadata()->set_memory_tags(tags, kNumTagsAroundRegister);
-          }
-
-          *thread.add_memory_dump() = std::move(dump);
-        }
-      });
-
-  std::unique_ptr<unwindstack::Regs> regs_copy(thread_info.registers->Clone());
-  unwinder->SetRegs(regs_copy.get());
-  unwinder->Unwind();
-  if (unwinder->NumFrames() == 0) {
-    async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to unwind");
-    if (unwinder->LastErrorCode() != unwindstack::ERROR_NONE) {
-      async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "  error code: %s",
-                            unwinder->LastErrorCodeString());
-      async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "  error address: 0x%" PRIx64,
-                            unwinder->LastErrorAddress());
+  if (thread_info.pid == getpid() && thread_info.pid != thread_info.tid) {
+    // Fallback path for non-main thread, doing unwind from running process.
+    unwindstack::ThreadUnwinder thread_unwinder(kMaxFrames, unwinder->GetMaps());
+    if (!thread_unwinder.Init()) {
+      async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                            "Unable to initialize ThreadUnwinder object.");
+      log_unwinder_error(&thread_unwinder);
+      return;
     }
+
+    std::unique_ptr<unwindstack::Regs> initial_regs;
+    thread_unwinder.UnwindWithSignal(BIONIC_SIGNAL_BACKTRACE, thread_info.tid, &initial_regs);
+    dump_registers(&thread_unwinder, initial_regs, thread, memory_dump);
+    dump_thread_backtrace(&thread_unwinder, thread);
   } else {
-    if (unwinder->elf_from_memory_not_file()) {
-      auto backtrace_note = thread.mutable_backtrace_note();
-      *backtrace_note->Add() =
-          "Function names and BuildId information is missing for some frames due";
-      *backtrace_note->Add() =
-          "to unreadable libraries. For unwinds of apps, only shared libraries";
-      *backtrace_note->Add() = "found under the lib/ directory are readable.";
-      *backtrace_note->Add() = "On this device, run setenforce 0 to make the libraries readable.";
-    }
-    unwinder->SetDisplayBuildID(true);
-    for (const auto& frame : unwinder->frames()) {
-      BacktraceFrame* f = thread.add_current_backtrace();
-      fill_in_backtrace_frame(f, frame);
-    }
+    dump_registers(unwinder, thread_info.registers, thread, memory_dump);
+    std::unique_ptr<unwindstack::Regs> regs_copy(thread_info.registers->Clone());
+    unwinder->SetRegs(regs_copy.get());
+    unwinder->Unwind();
+    dump_thread_backtrace(unwinder, thread);
   }
 
   auto& threads = *tombstone->mutable_threads();
   threads[thread_info.tid] = thread;
 }
 
-static void dump_main_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder,
-                             const ThreadInfo& thread_info) {
-  dump_thread(tombstone, unwinder, thread_info, true);
-}
-
 static void dump_mappings(Tombstone* tombstone, unwindstack::Unwinder* unwinder) {
   unwindstack::Maps* maps = unwinder->GetMaps();
   std::shared_ptr<unwindstack::Memory> process_memory = unwinder->GetProcessMemory();
@@ -663,7 +686,8 @@
 
   dump_abort_message(&result, unwinder, process_info);
 
-  dump_main_thread(&result, unwinder, main_thread);
+  // Dump the main thread, but save the memory around the registers.
+  dump_thread(&result, unwinder, main_thread, /* memory_dump */ true);
 
   for (const auto& [tid, thread_info] : threads) {
     if (tid != target_thread) {
diff --git a/debuggerd/seccomp_policy/crash_dump.arm64.policy b/debuggerd/seccomp_policy/crash_dump.arm64.policy
index 858a338..4e8fdf9 100644
--- a/debuggerd/seccomp_policy/crash_dump.arm64.policy
+++ b/debuggerd/seccomp_policy/crash_dump.arm64.policy
@@ -25,7 +25,7 @@
 rt_sigprocmask: 1
 rt_sigaction: 1
 rt_tgsigqueueinfo: 1
-prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41 || arg0 == PR_PAC_RESET_KEYS
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41 || arg0 == PR_PAC_RESET_KEYS || arg0 == PR_GET_TAGGED_ADDR_CTRL || arg0 == PR_PAC_GET_ENABLED_KEYS
 madvise: 1
 mprotect: arg2 in 0x1|0x2
 munmap: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.policy.def b/debuggerd/seccomp_policy/crash_dump.policy.def
index 152697c..4eb996e 100644
--- a/debuggerd/seccomp_policy/crash_dump.policy.def
+++ b/debuggerd/seccomp_policy/crash_dump.policy.def
@@ -37,7 +37,7 @@
 #define PR_SET_VMA 0x53564d41
 #if defined(__aarch64__)
 // PR_PAC_RESET_KEYS happens on aarch64 in pthread_create path.
-prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == PR_SET_VMA || arg0 == PR_PAC_RESET_KEYS
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == PR_SET_VMA || arg0 == PR_PAC_RESET_KEYS || arg0 == PR_GET_TAGGED_ADDR_CTRL || arg0 == PR_PAC_GET_ENABLED_KEYS
 #else
 prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == PR_SET_VMA
 #endif
diff --git a/debuggerd/util.cpp b/debuggerd/util.cpp
index ce0fd30..5c6abc9 100644
--- a/debuggerd/util.cpp
+++ b/debuggerd/util.cpp
@@ -18,6 +18,7 @@
 
 #include <time.h>
 
+#include <functional>
 #include <string>
 #include <utility>
 
@@ -74,3 +75,24 @@
   n = strftime(s, sz, "%z", &tm), s += n, sz -= n;
   return buf;
 }
+
+bool iterate_tids(pid_t pid, std::function<void(pid_t)> callback) {
+  char buf[BUFSIZ];
+  snprintf(buf, sizeof(buf), "/proc/%d/task", pid);
+  std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(buf), closedir);
+  if (dir == nullptr) {
+    return false;
+  }
+
+  struct dirent* entry;
+  while ((entry = readdir(dir.get())) != nullptr) {
+    pid_t tid = atoi(entry->d_name);
+    if (tid == 0) {
+      continue;
+    }
+    if (pid != tid) {
+      callback(tid);
+    }
+  }
+  return true;
+}
diff --git a/debuggerd/util.h b/debuggerd/util.h
index ec2862a..4375870 100644
--- a/debuggerd/util.h
+++ b/debuggerd/util.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <functional>
 #include <string>
 #include <vector>
 
@@ -27,3 +28,4 @@
 std::string get_thread_name(pid_t tid);
 
 std::string get_timestamp();
+bool iterate_tids(pid_t, std::function<void(pid_t)>);
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index 44dc81f..22f8363 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -186,6 +186,11 @@
     return result;
 }
 
+static void RemoveScratchPartition() {
+    AutoMountMetadata mount_metadata;
+    android::fs_mgr::TeardownAllOverlayForMountPoint();
+}
+
 bool UpdateSuper(FastbootDevice* device, const std::string& super_name, bool wipe) {
     std::vector<char> data = std::move(device->download_data());
     if (data.empty()) {
@@ -218,7 +223,7 @@
         if (!FlashPartitionTable(super_name, *new_metadata.get())) {
             return device->WriteFail("Unable to flash new partition table");
         }
-        android::fs_mgr::TeardownAllOverlayForMountPoint();
+        RemoveScratchPartition();
         sync();
         return device->WriteOkay("Successfully flashed partition table");
     }
@@ -262,7 +267,7 @@
     if (!UpdateAllPartitionMetadata(device, super_name, *new_metadata.get())) {
         return device->WriteFail("Unable to write new partition table");
     }
-    android::fs_mgr::TeardownAllOverlayForMountPoint();
+    RemoveScratchPartition();
     sync();
     return device->WriteOkay("Successfully updated partition table");
 }
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 0ca1946..143e980 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -657,7 +657,12 @@
             if (partition_ext4 == fstab->end()) {
                 auto new_entry = *GetEntryForMountPoint(fstab, mount_point);
                 new_entry.fs_type = "ext4";
-                fstab->emplace_back(new_entry);
+                auto it = std::find_if(fstab->rbegin(), fstab->rend(),
+                                       [&mount_point](const auto& entry) {
+                                           return entry.mount_point == mount_point;
+                                       });
+                auto end_of_mount_point_group = fstab->begin() + std::distance(it, fstab->rend());
+                fstab->insert(end_of_mount_point_group, new_entry);
             }
         }
     }
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 2da5b0f..996fa5e 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -33,6 +33,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <optional>
 #include <string>
 #include <vector>
 
@@ -1121,6 +1122,23 @@
     return true;
 }
 
+static inline uint64_t GetIdealDataScratchSize() {
+    BlockDeviceInfo super_info;
+    PartitionOpener opener;
+    if (!opener.GetInfo(fs_mgr_get_super_partition_name(), &super_info)) {
+        LERROR << "could not get block device info for super";
+        return 0;
+    }
+
+    struct statvfs s;
+    if (statvfs("/data", &s) < 0) {
+        PERROR << "could not statfs /data";
+        return 0;
+    }
+
+    return std::min(super_info.size, (uint64_t(s.f_frsize) * s.f_bfree) / 2);
+}
+
 static bool CreateScratchOnData(std::string* scratch_device, bool* partition_exists, bool* change) {
     *partition_exists = false;
     if (change) *change = false;
@@ -1136,13 +1154,6 @@
         return true;
     }
 
-    BlockDeviceInfo info;
-    PartitionOpener opener;
-    if (!opener.GetInfo(fs_mgr_get_super_partition_name(), &info)) {
-        LERROR << "could not get block device info for super";
-        return false;
-    }
-
     if (change) *change = true;
 
     // Note: calling RemoveDisabledImages here ensures that we do not race with
@@ -1152,10 +1163,11 @@
         return false;
     }
     if (!images->BackingImageExists(partition_name)) {
-        static constexpr uint64_t kMinimumSize = 64_MiB;
-        static constexpr uint64_t kMaximumSize = 2_GiB;
+        uint64_t size = GetIdealDataScratchSize();
+        if (!size) {
+            size = 2_GiB;
+        }
 
-        uint64_t size = std::clamp(info.size / 2, kMinimumSize, kMaximumSize);
         auto flags = IImageManager::CREATE_IMAGE_DEFAULT;
 
         if (!images->CreateBackingImage(partition_name, size, flags)) {
@@ -1396,18 +1408,35 @@
     return ret;
 }
 
+struct MapInfo {
+    // If set, partition is owned by ImageManager.
+    std::unique_ptr<IImageManager> images;
+    // If set, and images is null, this is a DAP partition.
+    std::string name;
+    // If set, and images and name are empty, this is a non-dynamic partition.
+    std::string device;
+
+    MapInfo() = default;
+    MapInfo(MapInfo&&) = default;
+    ~MapInfo() {
+        if (images) {
+            images->UnmapImageDevice(name);
+        } else if (!name.empty()) {
+            DestroyLogicalPartition(name);
+        }
+    }
+};
+
 // Note: This function never returns the DSU scratch device in recovery or fastbootd,
 // because the DSU scratch is created in the first-stage-mount, which is not run in recovery.
-static bool EnsureScratchMapped(std::string* device, bool* mapped) {
-    *mapped = false;
-    *device = GetBootScratchDevice();
-    if (!device->empty()) {
-        return true;
+static std::optional<MapInfo> EnsureScratchMapped() {
+    MapInfo info;
+    info.device = GetBootScratchDevice();
+    if (!info.device.empty()) {
+        return {std::move(info)};
     }
-
     if (!fs_mgr_in_recovery()) {
-        errno = EINVAL;
-        return false;
+        return {};
     }
 
     auto partition_name = android::base::Basename(kScratchMountPoint);
@@ -1417,11 +1446,15 @@
     // would otherwise always be mapped.
     auto images = IImageManager::Open("remount", 10s);
     if (images && images->BackingImageExists(partition_name)) {
-        if (!images->MapImageDevice(partition_name, 10s, device)) {
-            return false;
+        if (images->IsImageDisabled(partition_name)) {
+            return {};
         }
-        *mapped = true;
-        return true;
+        if (!images->MapImageDevice(partition_name, 10s, &info.device)) {
+            return {};
+        }
+        info.name = partition_name;
+        info.images = std::move(images);
+        return {std::move(info)};
     }
 
     // Avoid uart spam by first checking for a scratch partition.
@@ -1429,12 +1462,12 @@
     auto super_device = fs_mgr_overlayfs_super_device(metadata_slot);
     auto metadata = ReadCurrentMetadata(super_device);
     if (!metadata) {
-        return false;
+        return {};
     }
 
     auto partition = FindPartition(*metadata.get(), partition_name);
     if (!partition) {
-        return false;
+        return {};
     }
 
     CreateLogicalPartitionParams params = {
@@ -1444,11 +1477,11 @@
             .force_writable = true,
             .timeout_ms = 10s,
     };
-    if (!CreateLogicalPartition(params, device)) {
-        return false;
+    if (!CreateLogicalPartition(params, &info.device)) {
+        return {};
     }
-    *mapped = true;
-    return true;
+    info.name = partition_name;
+    return {std::move(info)};
 }
 
 // This should only be reachable in recovery, where DSU scratch is not
@@ -1602,26 +1635,35 @@
         fs_mgr_overlayfs_teardown_one(overlay_mount_point, teardown_dir, ignore_change);
     }
 
-    // Map scratch device, mount kScratchMountPoint and teardown kScratchMountPoint.
-    bool mapped = false;
-    std::string scratch_device;
-    if (EnsureScratchMapped(&scratch_device, &mapped)) {
+    if (mount_point.empty()) {
+        // Throw away the entire partition.
+        auto partition_name = android::base::Basename(kScratchMountPoint);
+        auto images = IImageManager::Open("remount", 10s);
+        if (images && images->BackingImageExists(partition_name)) {
+            if (images->DisableImage(partition_name)) {
+                LOG(INFO) << "Disabled scratch partition for: " << kScratchMountPoint;
+            } else {
+                LOG(ERROR) << "Unable to disable scratch partition for " << kScratchMountPoint;
+            }
+        }
+    }
+
+    if (auto info = EnsureScratchMapped(); info.has_value()) {
+        // Map scratch device, mount kScratchMountPoint and teardown kScratchMountPoint.
         fs_mgr_overlayfs_umount_scratch();
-        if (fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type())) {
+        if (fs_mgr_overlayfs_mount_scratch(info->device, fs_mgr_overlayfs_scratch_mount_type())) {
             bool should_destroy_scratch = false;
             fs_mgr_overlayfs_teardown_one(kScratchMountPoint, teardown_dir, ignore_change,
                                           &should_destroy_scratch);
+            fs_mgr_overlayfs_umount_scratch();
             if (should_destroy_scratch) {
                 fs_mgr_overlayfs_teardown_scratch(kScratchMountPoint, nullptr);
             }
-            fs_mgr_overlayfs_umount_scratch();
-        }
-        if (mapped) {
-            DestroyLogicalPartition(android::base::Basename(kScratchMountPoint));
         }
     }
 
     // Teardown DSU overlay if present.
+    std::string scratch_device;
     if (MapDsuScratchDevice(&scratch_device)) {
         fs_mgr_overlayfs_umount_scratch();
         if (fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type())) {
diff --git a/fs_mgr/libfiemap/binder.cpp b/fs_mgr/libfiemap/binder.cpp
index 31a57a8..003e6ed 100644
--- a/fs_mgr/libfiemap/binder.cpp
+++ b/fs_mgr/libfiemap/binder.cpp
@@ -66,6 +66,7 @@
     bool RemoveDisabledImages() override;
     bool GetMappedImageDevice(const std::string& name, std::string* device) override;
     bool MapAllImages(const std::function<bool(std::set<std::string>)>& init) override;
+    bool IsImageDisabled(const std::string& name) override;
 
     std::vector<std::string> GetAllBackingImages() override;
 
@@ -219,6 +220,17 @@
     return !device->empty();
 }
 
+bool ImageManagerBinder::IsImageDisabled(const std::string& name) {
+    bool retval;
+    auto status = manager_->isImageDisabled(name, &retval);
+    if (!status.isOk()) {
+        LOG(ERROR) << __PRETTY_FUNCTION__
+                   << " binder returned: " << status.exceptionMessage().string();
+        return false;
+    }
+    return retval;
+}
+
 bool ImageManagerBinder::MapAllImages(const std::function<bool(std::set<std::string>)>&) {
     LOG(ERROR) << __PRETTY_FUNCTION__ << " not available over binder";
     return false;
diff --git a/fs_mgr/libfiemap/image_manager.cpp b/fs_mgr/libfiemap/image_manager.cpp
index e3f5716..c416f4d 100644
--- a/fs_mgr/libfiemap/image_manager.cpp
+++ b/fs_mgr/libfiemap/image_manager.cpp
@@ -79,7 +79,7 @@
     partition_opener_ = std::make_unique<android::fs_mgr::PartitionOpener>();
 
     // Allow overriding whether ImageManager thinks it's in recovery, for testing.
-#ifdef __ANDROID_RECOVERY__
+#ifdef __ANDROID_RAMDISK__
     device_info_.is_recovery = {true};
 #else
     if (!device_info_.is_recovery.has_value()) {
@@ -523,7 +523,7 @@
 
     auto image_header = GetImageHeaderPath(name);
 
-#if !defined __ANDROID_RECOVERY__
+#ifndef __ANDROID_RAMDISK__
     // If there is a device-mapper node wrapping the block device, then we're
     // able to create another node around it; the dm layer does not carry the
     // exclusion lock down the stack when a mount occurs.
@@ -854,6 +854,24 @@
     return true;
 }
 
+bool ImageManager::IsImageDisabled(const std::string& name) {
+    if (!MetadataExists(metadata_dir_)) {
+        return true;
+    }
+
+    auto metadata = OpenMetadata(metadata_dir_);
+    if (!metadata) {
+        return false;
+    }
+
+    auto partition = FindPartition(*metadata.get(), name);
+    if (!partition) {
+        return false;
+    }
+
+    return !!(partition->attributes & LP_PARTITION_ATTR_DISABLED);
+}
+
 std::unique_ptr<MappedDevice> MappedDevice::Open(IImageManager* manager,
                                                  const std::chrono::milliseconds& timeout_ms,
                                                  const std::string& name) {
diff --git a/fs_mgr/libfiemap/image_test.cpp b/fs_mgr/libfiemap/image_test.cpp
index 6d09751..7472949 100644
--- a/fs_mgr/libfiemap/image_test.cpp
+++ b/fs_mgr/libfiemap/image_test.cpp
@@ -119,6 +119,7 @@
     ASSERT_TRUE(manager_->CreateBackingImage(base_name_, kTestImageSize, false, nullptr));
     ASSERT_TRUE(manager_->BackingImageExists(base_name_));
     ASSERT_TRUE(manager_->DisableImage(base_name_));
+    ASSERT_TRUE(manager_->IsImageDisabled(base_name_));
     ASSERT_TRUE(manager_->RemoveDisabledImages());
     ASSERT_TRUE(!manager_->BackingImageExists(base_name_));
 }
diff --git a/fs_mgr/libfiemap/include/libfiemap/image_manager.h b/fs_mgr/libfiemap/include/libfiemap/image_manager.h
index b23a7f7..00dd661 100644
--- a/fs_mgr/libfiemap/include/libfiemap/image_manager.h
+++ b/fs_mgr/libfiemap/include/libfiemap/image_manager.h
@@ -131,6 +131,9 @@
     virtual bool RemoveAllImages() = 0;
 
     virtual bool UnmapImageIfExists(const std::string& name);
+
+    // Returns whether DisableImage() was called.
+    virtual bool IsImageDisabled(const std::string& name) = 0;
 };
 
 class ImageManager final : public IImageManager {
@@ -162,6 +165,7 @@
     bool RemoveDisabledImages() override;
     bool GetMappedImageDevice(const std::string& name, std::string* device) override;
     bool MapAllImages(const std::function<bool(std::set<std::string>)>& init) override;
+    bool IsImageDisabled(const std::string& name) override;
 
     std::vector<std::string> GetAllBackingImages();
 
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 8b269cd..6db8f13 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -275,6 +275,24 @@
     ],
 }
 
+cc_test {
+    name: "vts_ota_config_test",
+    srcs: [
+        "vts_ota_config_test.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+    ],
+    test_suites: [
+        "vts",
+    ],
+    test_options: {
+        min_shipping_api_level: 33,
+    },
+    auto_gen_config: true,
+    require_root: true,
+}
+
 cc_binary {
     name: "snapshotctl",
     srcs: [
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
index c1a5af7..a648384 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
+++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
@@ -199,6 +199,7 @@
     bool UnmapImageIfExists(const std::string& name) override {
         return impl_->UnmapImageIfExists(name);
     }
+    bool IsImageDisabled(const std::string& name) override { return impl_->IsImageDisabled(name); }
 
   private:
     std::unique_ptr<android::fiemap::IImageManager> impl_;
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index d76558b..04d228d 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -46,8 +46,6 @@
 #include "partition_cow_creator.h"
 #include "utility.h"
 
-#include <android-base/properties.h>
-
 // Mock classes are not used. Header included to ensure mocked class definition aligns with the
 // class itself.
 #include <libsnapshot/mock_device_info.h>
diff --git a/fs_mgr/libsnapshot/vts_ota_config_test.cpp b/fs_mgr/libsnapshot/vts_ota_config_test.cpp
new file mode 100644
index 0000000..afc2d81
--- /dev/null
+++ b/fs_mgr/libsnapshot/vts_ota_config_test.cpp
@@ -0,0 +1,23 @@
+//
+// Copyright (C) 2022 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 <android-base/properties.h>
+#include <gtest/gtest.h>
+
+TEST(VAB, Enabled) {
+    ASSERT_TRUE(android::base::GetBoolProperty("ro.virtual_ab.enabled", false));
+    ASSERT_TRUE(android::base::GetBoolProperty("ro.virtual_ab.userspace.snapshots.enabled", false));
+}
diff --git a/fs_mgr/tests/Android.bp b/fs_mgr/tests/Android.bp
index 262beaa..7e3924a 100644
--- a/fs_mgr/tests/Android.bp
+++ b/fs_mgr/tests/Android.bp
@@ -96,7 +96,7 @@
         "device-tests",
     ],
     test_options: {
-        min_shipping_api_level: 33,
+        min_shipping_api_level: 31,
     },
     require_root: true,
     auto_gen_config: true,
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index eccb902..1dbee75 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -1104,3 +1104,76 @@
     EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
     EXPECT_EQ(0, entry->readahead_size_kb);
 }
+
+TEST(fs_mgr, TransformFstabForDsu) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+system /system      erofs   ro  wait,logical,first_stage_mount
+system /system      ext4    ro  wait,logical,first_stage_mount
+vendor /vendor      ext4    ro  wait,logical,first_stage_mount
+data   /data        f2fs    noatime     wait
+)fs";
+
+    ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    TransformFstabForDsu(&fstab, "dsu", {"system_gsi", "userdata_gsi"});
+    ASSERT_EQ(4U, fstab.size());
+
+    auto entry = fstab.begin();
+
+    EXPECT_EQ("/system", entry->mount_point);
+    EXPECT_EQ("system_gsi", entry->blk_device);
+    entry++;
+
+    EXPECT_EQ("/system", entry->mount_point);
+    EXPECT_EQ("system_gsi", entry->blk_device);
+    entry++;
+
+    EXPECT_EQ("/vendor", entry->mount_point);
+    EXPECT_EQ("vendor", entry->blk_device);
+    entry++;
+
+    EXPECT_EQ("/data", entry->mount_point);
+    EXPECT_EQ("userdata_gsi", entry->blk_device);
+    entry++;
+}
+
+TEST(fs_mgr, TransformFstabForDsu_synthesisExt4Entry) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+system /system      erofs   ro  wait,logical,first_stage_mount
+vendor /vendor      ext4    ro  wait,logical,first_stage_mount
+data   /data        f2fs    noatime     wait
+)fs";
+
+    ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    TransformFstabForDsu(&fstab, "dsu", {"system_gsi", "userdata_gsi"});
+    ASSERT_EQ(4U, fstab.size());
+
+    auto entry = fstab.begin();
+
+    EXPECT_EQ("/system", entry->mount_point);
+    EXPECT_EQ("system_gsi", entry->blk_device);
+    EXPECT_EQ("erofs", entry->fs_type);
+    entry++;
+
+    EXPECT_EQ("/system", entry->mount_point);
+    EXPECT_EQ("system_gsi", entry->blk_device);
+    EXPECT_EQ("ext4", entry->fs_type);
+    entry++;
+
+    EXPECT_EQ("/vendor", entry->mount_point);
+    EXPECT_EQ("vendor", entry->blk_device);
+    entry++;
+
+    EXPECT_EQ("/data", entry->mount_point);
+    EXPECT_EQ("userdata_gsi", entry->blk_device);
+    entry++;
+}
diff --git a/fs_mgr/tests/vts_fs_test.cpp b/fs_mgr/tests/vts_fs_test.cpp
index 77900df..415e67e 100644
--- a/fs_mgr/tests/vts_fs_test.cpp
+++ b/fs_mgr/tests/vts_fs_test.cpp
@@ -29,7 +29,7 @@
 
 TEST(fs, ErofsSupported) {
     // S and higher for this test.
-    if (GetVsrLevel() < 31) {
+    if (GetVsrLevel() < __ANDROID_API_S__) {
         GTEST_SKIP();
     }
 
@@ -85,10 +85,10 @@
             continue;
         }
 
-        if (vsr_level <= 32) {
+        if (vsr_level < __ANDROID_API_T__) {
             continue;
         }
-        if (vsr_level == 33 && parent_bdev != super_bdev) {
+        if (vsr_level == __ANDROID_API_T__ && parent_bdev != super_bdev) {
             // Only check for dynamic partitions at this VSR level.
             continue;
         }
@@ -100,3 +100,12 @@
         }
     }
 }
+
+TEST(fs, NoDtFstab) {
+    if (GetVsrLevel() <= __ANDROID_API_S__) {
+        GTEST_SKIP();
+    }
+
+    android::fs_mgr::Fstab fstab;
+    EXPECT_FALSE(android::fs_mgr::ReadFstabFromDt(&fstab, false));
+}
diff --git a/libcutils/include/cutils/trace.h b/libcutils/include/cutils/trace.h
index 97e93f8..17a0070 100644
--- a/libcutils/include/cutils/trace.h
+++ b/libcutils/include/cutils/trace.h
@@ -75,7 +75,8 @@
 #define ATRACE_TAG_AIDL             (1<<24)
 #define ATRACE_TAG_NNAPI            (1<<25)
 #define ATRACE_TAG_RRO              (1<<26)
-#define ATRACE_TAG_LAST             ATRACE_TAG_RRO
+#define ATRACE_TAG_THERMAL          (1 << 27)
+#define ATRACE_TAG_LAST             ATRACE_TAG_THERMAL
 
 // Reserved for initialization.
 #define ATRACE_TAG_NOT_READY        (1ULL<<63)
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index c17ef52..11f414f 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -199,15 +199,9 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
 LOCAL_MODULE_STEM := $(LOCAL_MODULE)
 include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := $(addsuffix .so,\
-  $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
-  $(HWADDRESS_SANITIZER_RUNTIME_LIBRARY) \
-  $(UBSAN_RUNTIME_LIBRARY) \
-  $(TSAN_RUNTIME_LIBRARY) \
-  $(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
-  $(2ND_HWADDRESS_SANITIZER_RUNTIME_LIBRARY) \
-  $(2ND_UBSAN_RUNTIME_LIBRARY) \
-  $(2ND_TSAN_RUNTIME_LIBRARY))
+$(LOCAL_BUILT_MODULE): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := \
+    $(SANITIZER_STEMS) \
+    $(2ND_SANITIZER_STEMS)
 $(LOCAL_BUILT_MODULE):
 	@echo "Generate: $@"
 	@mkdir -p $(dir $@)
diff --git a/rootdir/init.no_zygote.rc b/rootdir/init.no_zygote.rc
new file mode 100644
index 0000000..8e0afcb
--- /dev/null
+++ b/rootdir/init.no_zygote.rc
@@ -0,0 +1,2 @@
+# This is an empty file that does not specify any zygote services.
+# It exists to support targets that do not include a zygote.
diff --git a/trusty/test/driver/Android.bp b/trusty/test/driver/Android.bp
new file mode 100644
index 0000000..b813a04
--- /dev/null
+++ b/trusty/test/driver/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2022 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.
+
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+python_test {
+    name: "trusty_driver_test",
+    srcs: [
+        "**/*.py",
+    ],
+    test_suites: ["general-tests"],
+    version: {
+        py3: {
+            embedded_launcher: true,
+            enabled: true,
+        },
+    },
+}
diff --git a/trusty/test/driver/trusty_driver_test.py b/trusty/test/driver/trusty_driver_test.py
new file mode 100644
index 0000000..608fd47
--- /dev/null
+++ b/trusty/test/driver/trusty_driver_test.py
@@ -0,0 +1,81 @@
+#!/usr/bin/python
+#
+# Copyright 2022 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.
+
+"""Test cases for Trusty Linux Driver."""
+
+import os
+import unittest
+
+def ReadFile(file_path):
+    with open(file_path, 'r') as f:
+        # Strip all trailing spaces, newline and null characters.
+        return f.read().rstrip(' \n\x00')
+
+def WriteFile(file_path, s):
+    with open(file_path, 'w') as f:
+        f.write(s)
+
+def IsTrustySupported():
+    return os.path.exists("/dev/trusty-ipc-dev0")
+
+@unittest.skipIf(not IsTrustySupported(), "Device does not support Trusty")
+class TrustyDriverTest(unittest.TestCase):
+    def testIrqDriverBinding(self):
+        WriteFile("/sys/bus/platform/drivers/trusty-irq/unbind", "trusty:irq")
+        WriteFile("/sys/bus/platform/drivers/trusty-irq/bind", "trusty:irq")
+
+    def testLogDriverBinding(self):
+        WriteFile("/sys/bus/platform/drivers/trusty-log/unbind", "trusty:log")
+        WriteFile("/sys/bus/platform/drivers/trusty-log/bind", "trusty:log")
+
+    @unittest.skip("TODO(b/142275662): virtio remove currently hangs")
+    def testVirtioDriverBinding(self):
+        WriteFile("/sys/bus/platform/drivers/trusty-virtio/unbind",
+                  "trusty:virtio")
+        WriteFile("/sys/bus/platform/drivers/trusty-virtio/bind",
+                  "trusty:virtio")
+
+    @unittest.skip("TODO(b/142275662): virtio remove currently hangs")
+    def testTrustyDriverBinding(self):
+        WriteFile("/sys/bus/platform/drivers/trusty/unbind", "trusty")
+        WriteFile("/sys/bus/platform/drivers/trusty/bind", "trusty")
+
+    def testTrustyDriverVersion(self):
+        ver = ReadFile("/sys/bus/platform/devices/trusty/trusty_version")
+        self.assertTrue(ver.startswith("Project:"))
+
+    def testUntaintedLinux(self):
+        tainted = ReadFile("/proc/sys/kernel/tainted")
+        self.assertEqual(tainted, "0")
+
+    # stdcall test with shared memory buffers.
+    # Each test run takes up to 4 arguments:
+    # <obj_size>,<obj_count=1>,<repeat_share=1>,<repeat_access=3>
+    #
+    # Test single 4K shared memory object.
+    # Test 10 8MB objects, shared twice, each accessed twice. (8MB non-
+    # contiguous object is large enough to need several 4KB messages to
+    # describe)
+    # Test sharing 2 8MB objects 100 times without accessing it.
+    # Test 10 4K shared memory objects, shared 10 times, each accessed
+    # 10 times.
+    def testStdCall(self):
+        test = "/sys/devices/platform/trusty/trusty:test/trusty_test_run"
+        args = "0x1000 0x800000,10,2,2 0x800000,2,100,0 0x1000,10,10,10"
+        WriteFile(test, args)
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/trusty/trusty-test.mk b/trusty/trusty-test.mk
index 74106ec..3a43774 100644
--- a/trusty/trusty-test.mk
+++ b/trusty/trusty-test.mk
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 PRODUCT_PACKAGES += \
-	spiproxyd \
-	trusty_keymaster_set_attestation_key \
 	keymaster_soft_attestation_keys.xml \
-
+	spiproxyd \
+	trusty_driver_test \
+	trusty_keymaster_set_attestation_key \