Merge "Reland "Add a core configuration that disables the zygote.""
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index edcea44..a541f6e 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -391,6 +391,9 @@
     apex_available: [
         "com.android.runtime",
     ],
+
+    // Required for tests.
+    required: ["crash_dump.policy"],
 }
 
 cc_binary {
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_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 2da5b0f..7deb763 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>
 
@@ -1396,18 +1397,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 +1435,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 +1451,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 +1466,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 +1624,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..7ccdbf9 100644
--- a/fs_mgr/libfiemap/image_manager.cpp
+++ b/fs_mgr/libfiemap/image_manager.cpp
@@ -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/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/snapuserd/user-space-merge/snapuserd_core.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
index 9dd52b4..b988c7b 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
@@ -694,8 +694,10 @@
     // During selinux init transition, libsnapshot will propagate the
     // status of io_uring enablement. As properties are not initialized,
     // we cannot query system property.
+    //
+    // TODO: b/219642530: Intermittent I/O failures observed
     if (is_io_uring_enabled_) {
-        return true;
+        return false;
     }
 
     // Finally check the system property
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
index d4d4efe..ffb982a 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
@@ -461,6 +461,14 @@
         return false;
     }
 
+    {
+        // TODO: b/219642530 - Disable io_uring for merge
+        // until we figure out the cause of intermittent
+        // IO failures.
+        merge_async_ = false;
+        return true;
+    }
+
     ring_ = std::make_unique<struct io_uring>();
 
     int ret = io_uring_queue_init(queue_depth_, ring_.get(), 0);
diff --git a/init/service.cpp b/init/service.cpp
index f7318cb..f6dd9b9 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -397,6 +397,14 @@
     return {};
 }
 
+static void ClosePipe(const std::array<int, 2>* pipe) {
+    for (const auto fd : *pipe) {
+        if (fd >= 0) {
+            close(fd);
+        }
+    }
+}
+
 Result<void> Service::Start() {
     auto reboot_on_failure = make_scope_guard([this] {
         if (on_failure_reboot_target_) {
@@ -428,6 +436,12 @@
         return {};
     }
 
+    std::unique_ptr<std::array<int, 2>, decltype(&ClosePipe)> pipefd(new std::array<int, 2>{-1, -1},
+                                                                     ClosePipe);
+    if (pipe(pipefd->data()) < 0) {
+        return ErrnoError() << "pipe()";
+    }
+
     bool needs_console = (flags_ & SVC_CONSOLE);
     if (needs_console) {
         if (proc_attr_.console.empty()) {
@@ -532,6 +546,13 @@
             LOG(ERROR) << "failed to write pid to files: " << result.error();
         }
 
+        // Wait until the cgroups have been created and until the cgroup controllers have been
+        // activated.
+        if (std::byte byte; read((*pipefd)[0], &byte, 1) < 0) {
+            PLOG(ERROR) << "failed to read from notification channel";
+        }
+        pipefd.reset();
+
         if (task_profiles_.size() > 0 && !SetTaskProfiles(getpid(), task_profiles_)) {
             LOG(ERROR) << "failed to set task profiles";
         }
@@ -618,6 +639,10 @@
         LmkdRegister(name_, proc_attr_.uid, pid_, oom_score_adjust_);
     }
 
+    if (write((*pipefd)[1], "", 1) < 0) {
+        return ErrnoError() << "sending notification failed";
+    }
+
     NotifyStateChange("running");
     reboot_on_failure.Disable();
     return {};
diff --git a/libcutils/include/cutils/qtaguid.h b/libcutils/include/cutils/qtaguid.h
index 3f5e41f..a5ffb03 100644
--- a/libcutils/include/cutils/qtaguid.h
+++ b/libcutils/include/cutils/qtaguid.h
@@ -34,24 +34,6 @@
 extern int qtaguid_untagSocket(int sockfd);
 
 /*
- * For the given uid, switch counter sets.
- * The kernel only keeps a limited number of sets.
- * 2 for now.
- */
-extern int qtaguid_setCounterSet(int counterSetNum, uid_t uid);
-
-/*
- * Delete all tag info that relates to the given tag an uid.
- * If the tag is 0, then ALL info about the uid is freed.
- * The delete data also affects active tagged sockets, which are
- * then untagged.
- * The calling process can only operate on its own tags.
- * Unless it is part of the happy AID_NET_BW_ACCT group.
- * In which case it can clobber everything.
- */
-extern int qtaguid_deleteTagData(int tag, uid_t uid);
-
-/*
  * Enable/disable qtaguid functionnality at a lower level.
  * When pacified, the kernel will accept commands but do nothing.
  */
diff --git a/libcutils/qtaguid.cpp b/libcutils/qtaguid.cpp
index 2fe877c..a987b85 100644
--- a/libcutils/qtaguid.cpp
+++ b/libcutils/qtaguid.cpp
@@ -34,8 +34,6 @@
   public:
     int (*netdTagSocket)(int, uint32_t, uid_t);
     int (*netdUntagSocket)(int);
-    int (*netdSetCounterSet)(uint32_t, uid_t);
-    int (*netdDeleteTagData)(uint32_t, uid_t);
 };
 
 int stubTagSocket(int, uint32_t, uid_t) {
@@ -46,16 +44,8 @@
     return -EREMOTEIO;
 }
 
-int stubSetCounterSet(uint32_t, uid_t) {
-    return -EREMOTEIO;
-}
-
-int stubDeleteTagData(uint32_t, uid_t) {
-    return -EREMOTEIO;
-}
-
 netdHandler initHandler(void) {
-    netdHandler handler = {stubTagSocket, stubUntagSocket, stubSetCounterSet, stubDeleteTagData};
+    netdHandler handler = {stubTagSocket, stubUntagSocket};
 
     void* netdClientHandle = dlopen("libnetd_client.so", RTLD_NOW);
     if (!netdClientHandle) {
@@ -73,15 +63,6 @@
         ALOGE("load netdUntagSocket handler failed: %s", dlerror());
     }
 
-    handler.netdSetCounterSet = (int (*)(uint32_t, uid_t))dlsym(netdClientHandle, "setCounterSet");
-    if (!handler.netdSetCounterSet) {
-        ALOGE("load netdSetCounterSet handler failed: %s", dlerror());
-    }
-
-    handler.netdDeleteTagData = (int (*)(uint32_t, uid_t))dlsym(netdClientHandle, "deleteTagData");
-    if (!handler.netdDeleteTagData) {
-        ALOGE("load netdDeleteTagData handler failed: %s", dlerror());
-    }
     return handler;
 }
 
@@ -114,13 +95,3 @@
     ALOGV("Untagging socket %d", sockfd);
     return getHandler().netdUntagSocket(sockfd);
 }
-
-int qtaguid_setCounterSet(int counterSetNum, uid_t uid) {
-    ALOGV("Setting counters to set %d for uid %d", counterSetNum, uid);
-    return getHandler().netdSetCounterSet(counterSetNum, uid);
-}
-
-int qtaguid_deleteTagData(int tag, uid_t uid) {
-    ALOGV("Deleting tag data with tag %u for uid %d", tag, uid);
-    return getHandler().netdDeleteTagData(tag, uid);
-}
diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp
index 352847a..8c00326 100644
--- a/libprocessgroup/cgroup_map.cpp
+++ b/libprocessgroup/cgroup_map.cpp
@@ -231,7 +231,8 @@
             const ACgroupController* controller = ACgroupFile_getController(i);
             if (ACgroupController_getFlags(controller) &
                 CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION) {
-                std::string str = std::string("+") + ACgroupController_getName(controller);
+                std::string str("+");
+                str.append(ACgroupController_getName(controller));
                 if (!WriteStringToFile(str, path + "/cgroup.subtree_control")) {
                     return -errno;
                 }
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index cb2fe0a..76d5e13 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -85,7 +85,7 @@
 
 bool CgroupGetAttributePath(const std::string& attr_name, std::string* path) {
     const TaskProfiles& tp = TaskProfiles::GetInstance();
-    const ProfileAttribute* attr = tp.GetAttribute(attr_name);
+    const IProfileAttribute* attr = tp.GetAttribute(attr_name);
 
     if (attr == nullptr) {
         return false;
@@ -100,7 +100,7 @@
 
 bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path) {
     const TaskProfiles& tp = TaskProfiles::GetInstance();
-    const ProfileAttribute* attr = tp.GetAttribute(attr_name);
+    const IProfileAttribute* attr = tp.GetAttribute(attr_name);
 
     if (attr == nullptr) {
         return false;
@@ -211,7 +211,7 @@
     for (std::string cgroup_root_path : cgroups) {
         std::unique_ptr<DIR, decltype(&closedir)> root(opendir(cgroup_root_path.c_str()), closedir);
         if (root == NULL) {
-            PLOG(ERROR) << "Failed to open " << cgroup_root_path;
+            PLOG(ERROR) << __func__ << " failed to open " << cgroup_root_path;
         } else {
             dirent* dir;
             while ((dir = readdir(root.get())) != nullptr) {
@@ -297,7 +297,8 @@
             // This happens when process is already dead
             return 0;
         }
-        PLOG(WARNING) << "Failed to open process cgroup uid " << uid << " pid " << initialPid;
+        PLOG(WARNING) << __func__ << " failed to open process cgroup uid " << uid << " pid "
+                      << initialPid;
         return -1;
     }
 
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 74ba7f6..ffcfeb8 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -112,6 +112,8 @@
     return path.find("<uid>", 0) != std::string::npos || path.find("<pid>", 0) != std::string::npos;
 }
 
+IProfileAttribute::~IProfileAttribute() = default;
+
 void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name) {
     controller_ = controller;
     file_name_ = file_name;
@@ -183,6 +185,12 @@
     return true;
 }
 
+#else
+
+bool SetTimerSlackAction::ExecuteForTask(int) const {
+    return true;
+};
+
 #endif
 
 bool SetAttributeAction::ExecuteForProcess(uid_t, pid_t pid) const {
@@ -720,7 +728,7 @@
     return nullptr;
 }
 
-const ProfileAttribute* TaskProfiles::GetAttribute(const std::string& name) const {
+const IProfileAttribute* TaskProfiles::GetAttribute(const std::string& name) const {
     auto iter = attributes_.find(name);
 
     if (iter != attributes_.end()) {
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index 1aaa196..2f48664 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -26,16 +26,26 @@
 #include <android-base/unique_fd.h>
 #include <cgroup_map.h>
 
-class ProfileAttribute {
+class IProfileAttribute {
+  public:
+    virtual ~IProfileAttribute() = 0;
+    virtual void Reset(const CgroupController& controller, const std::string& file_name) = 0;
+    virtual const CgroupController* controller() const = 0;
+    virtual const std::string& file_name() const = 0;
+    virtual bool GetPathForTask(int tid, std::string* path) const = 0;
+};
+
+class ProfileAttribute : public IProfileAttribute {
   public:
     ProfileAttribute(const CgroupController& controller, const std::string& file_name)
         : controller_(controller), file_name_(file_name) {}
+    ~ProfileAttribute() = default;
 
-    const CgroupController* controller() const { return &controller_; }
-    const std::string& file_name() const { return file_name_; }
-    void Reset(const CgroupController& controller, const std::string& file_name);
+    const CgroupController* controller() const override { return &controller_; }
+    const std::string& file_name() const override { return file_name_; }
+    void Reset(const CgroupController& controller, const std::string& file_name) override;
 
-    bool GetPathForTask(int tid, std::string* path) const;
+    bool GetPathForTask(int tid, std::string* path) const override;
 
   private:
     CgroupController controller_;
@@ -65,22 +75,19 @@
   public:
     SetClampsAction(int boost, int clamp) noexcept : boost_(boost), clamp_(clamp) {}
 
-    virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
-    virtual bool ExecuteForTask(int tid) const;
+    bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
+    bool ExecuteForTask(int tid) const override;
 
   protected:
     int boost_;
     int clamp_;
 };
 
-// To avoid issues in sdk_mac build
-#if defined(__ANDROID__)
-
 class SetTimerSlackAction : public ProfileAction {
   public:
     SetTimerSlackAction(unsigned long slack) noexcept : slack_(slack) {}
 
-    virtual bool ExecuteForTask(int tid) const;
+    bool ExecuteForTask(int tid) const override;
 
   private:
     unsigned long slack_;
@@ -88,28 +95,17 @@
     static bool IsTimerSlackSupported(int tid);
 };
 
-#else
-
-class SetTimerSlackAction : public ProfileAction {
-  public:
-    SetTimerSlackAction(unsigned long) noexcept {}
-
-    virtual bool ExecuteForTask(int) const { return true; }
-};
-
-#endif
-
 // Set attribute profile element
 class SetAttributeAction : public ProfileAction {
   public:
-    SetAttributeAction(const ProfileAttribute* attribute, const std::string& value)
+    SetAttributeAction(const IProfileAttribute* attribute, const std::string& value)
         : attribute_(attribute), value_(value) {}
 
-    virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
-    virtual bool ExecuteForTask(int tid) const;
+    bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
+    bool ExecuteForTask(int tid) const override;
 
   private:
-    const ProfileAttribute* attribute_;
+    const IProfileAttribute* attribute_;
     std::string value_;
 };
 
@@ -118,10 +114,10 @@
   public:
     SetCgroupAction(const CgroupController& c, const std::string& p);
 
-    virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
-    virtual bool ExecuteForTask(int tid) const;
-    virtual void EnableResourceCaching(ResourceCacheType cache_type);
-    virtual void DropResourceCaching(ResourceCacheType cache_type);
+    bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
+    bool ExecuteForTask(int tid) const override;
+    void EnableResourceCaching(ResourceCacheType cache_type) override;
+    void DropResourceCaching(ResourceCacheType cache_type) override;
 
     const CgroupController* controller() const { return &controller_; }
 
@@ -140,10 +136,10 @@
   public:
     WriteFileAction(const std::string& path, const std::string& value, bool logfailures);
 
-    virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
-    virtual bool ExecuteForTask(int tid) const;
-    virtual void EnableResourceCaching(ResourceCacheType cache_type);
-    virtual void DropResourceCaching(ResourceCacheType cache_type);
+    bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
+    bool ExecuteForTask(int tid) const override;
+    void EnableResourceCaching(ResourceCacheType cache_type) override;
+    void DropResourceCaching(ResourceCacheType cache_type) override;
 
   private:
     std::string path_, value_;
@@ -179,10 +175,10 @@
     ApplyProfileAction(const std::vector<std::shared_ptr<TaskProfile>>& profiles)
         : profiles_(profiles) {}
 
-    virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
-    virtual bool ExecuteForTask(int tid) const;
-    virtual void EnableResourceCaching(ProfileAction::ResourceCacheType cache_type);
-    virtual void DropResourceCaching(ProfileAction::ResourceCacheType cache_type);
+    bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
+    bool ExecuteForTask(int tid) const override;
+    void EnableResourceCaching(ProfileAction::ResourceCacheType cache_type) override;
+    void DropResourceCaching(ProfileAction::ResourceCacheType cache_type) override;
 
   private:
     std::vector<std::shared_ptr<TaskProfile>> profiles_;
@@ -194,7 +190,7 @@
     static TaskProfiles& GetInstance();
 
     TaskProfile* GetProfile(const std::string& name) const;
-    const ProfileAttribute* GetAttribute(const std::string& name) const;
+    const IProfileAttribute* GetAttribute(const std::string& name) const;
     void DropResourceCaching(ProfileAction::ResourceCacheType cache_type) const;
     bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
                             bool use_fd_cache);
@@ -202,7 +198,7 @@
 
   private:
     std::map<std::string, std::shared_ptr<TaskProfile>> profiles_;
-    std::map<std::string, std::unique_ptr<ProfileAttribute>> attributes_;
+    std::map<std::string, std::unique_ptr<IProfileAttribute>> attributes_;
 
     TaskProfiles();
 
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index d592366..c17ef52 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -1,5 +1,7 @@
 LOCAL_PATH:= $(call my-dir)
 
+$(eval $(call declare-1p-copy-files,system/core/rootdir,))
+
 #######################################
 # init-debug.rc
 include $(CLEAR_VARS)