Merge "tombstoned: log where we're writing the tombstone."
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 20c63b3..11c0ec9 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -74,13 +74,18 @@
 
     template <typename Fn>
     void PopAll(Fn fn) {
-        std::unique_lock<std::mutex> lock(mutex);
-        cv.wait(lock, [this]() { return !queue.empty(); });
+        std::vector<T> popped;
 
-        for (const T& t : queue) {
+        {
+            std::unique_lock<std::mutex> lock(mutex);
+            cv.wait(lock, [this]() { return !queue.empty(); });
+            popped = std::move(queue);
+            queue.clear();
+        }
+
+        for (const T& t : popped) {
             fn(t);
         }
-        queue.clear();
     }
 };
 
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index 7e77b5e..e7f44c6 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -180,10 +180,6 @@
     if (port_count < 0) return "";
     return StringPrintf("/dev/bus/usb/%03u/%03u", libusb_get_bus_number(device), ports[0]);
 }
-
-static bool is_device_accessible(libusb_device* device) {
-    return access(get_device_dev_path(device).c_str(), R_OK | W_OK) == 0;
-}
 #endif
 
 static bool endpoint_is_output(uint8_t endpoint) {
@@ -377,9 +373,10 @@
     {
         std::unique_lock<std::mutex> lock(usb_handles_mutex);
         usb_handles[device_address] = std::move(result);
-    }
 
-    register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), writable);
+        register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(),
+                               writable);
+    }
     LOG(INFO) << "registered new usb device '" << device_serial << "'";
 }
 
@@ -388,18 +385,12 @@
 static void device_connected(libusb_device* device) {
 #if defined(__linux__)
     // Android's host linux libusb uses netlink instead of udev for device hotplug notification,
-    // which means we can get hotplug notifications before udev has updated ownership/perms on
-    // the device. Since we're not going to be able to link against the system's libudev any
-    // time soon, hack around this by checking for accessibility in a loop.
+    // which means we can get hotplug notifications before udev has updated ownership/perms on the
+    // device. Since we're not going to be able to link against the system's libudev any time soon,
+    // hack around this by inserting a sleep.
     auto thread = std::thread([device]() {
         std::string device_path = get_device_dev_path(device);
-        auto start = std::chrono::steady_clock::now();
-        while (std::chrono::steady_clock::now() - start < 500ms) {
-            if (is_device_accessible(device)) {
-                break;
-            }
-            std::this_thread::sleep_for(10ms);
-        }
+        std::this_thread::sleep_for(1s);
 
         process_device(device);
         if (--connecting_devices == 0) {
@@ -422,8 +413,10 @@
         if (!it->second->device_handle) {
             // If the handle is null, we were never able to open the device.
             unregister_usb_transport(it->second.get());
+            usb_handles.erase(it);
+        } else {
+            // Closure of the transport will erase the usb_handle.
         }
-        usb_handles.erase(it);
     }
 }
 
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 308ee8d..2bbbefd 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -603,15 +603,15 @@
 static void transport_unref(atransport* t) {
     CHECK(t != nullptr);
 
-    std::lock_guard<std::mutex> lock(transport_lock);
-    CHECK_GT(t->ref_count, 0u);
-    t->ref_count--;
-    if (t->ref_count == 0) {
+    size_t old_refcount = t->ref_count--;
+    CHECK_GT(old_refcount, 0u);
+
+    if (old_refcount == 1u) {
         D("transport: %s unref (kicking and closing)", t->serial);
         t->close(t);
         remove_transport(t);
     } else {
-        D("transport: %s unref (count=%zu)", t->serial, t->ref_count);
+        D("transport: %s unref (count=%zu)", t->serial, old_refcount - 1);
     }
 }
 
diff --git a/adb/transport.h b/adb/transport.h
index 57fc988..4a89ed9 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -61,7 +61,7 @@
     // class in one go is a very large change. Given how bad our testing is,
     // it's better to do this piece by piece.
 
-    atransport(ConnectionState state = kCsOffline) : connection_state_(state) {
+    atransport(ConnectionState state = kCsOffline) : ref_count(0), connection_state_(state) {
         transport_fde = {};
         protocol_version = A_VERSION;
         max_payload = MAX_PAYLOAD;
@@ -88,7 +88,7 @@
     int fd = -1;
     int transport_socket = -1;
     fdevent transport_fde;
-    size_t ref_count = 0;
+    std::atomic<size_t> ref_count;
     uint32_t sync_token = 0;
     bool online = false;
     TransportType type = kTransportAny;
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index a9e583f..6cedd92 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -388,6 +388,25 @@
     D("transport: qemu_socket_thread() exiting");
     return;
 }
+
+// If adbd is running inside the emulator, it will normally use QEMUD pipe (aka
+// goldfish) as the transport. This can either be explicitly set by the
+// service.adb.transport property, or be inferred from ro.kernel.qemu that is
+// set to "1" for ranchu/goldfish.
+static bool use_qemu_goldfish() {
+    // Legacy way to detect if adbd should use the goldfish pipe is to check for
+    // ro.kernel.qemu, keep that behaviour for backward compatibility.
+    if (android::base::GetBoolProperty("ro.kernel.qemu", false)) {
+        return true;
+    }
+    // If service.adb.transport is present and is set to "goldfish", use the
+    // QEMUD pipe.
+    if (android::base::GetProperty("service.adb.transport", "") == "goldfish") {
+        return true;
+    }
+    return false;
+}
+
 #endif  // !ADB_HOST
 
 void local_init(int port)
@@ -401,13 +420,7 @@
 #else
     // For the adbd daemon in the system image we need to distinguish
     // between the device, and the emulator.
-    if (android::base::GetBoolProperty("ro.kernel.qemu", false)) {
-        // Running inside the emulator: use QEMUD pipe as the transport.
-        func = qemu_socket_thread;
-    } else {
-        // Running inside the device: use TCP socket as the transport.
-        func = server_socket_thread;
-    }
+    func = use_qemu_goldfish() ? qemu_socket_thread : server_socket_thread;
     debug_name = "server";
 #endif // !ADB_HOST
 
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 5565cfd..42c3023 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -7,6 +7,7 @@
         "-Wno-nullability-completeness",
         "-Os",
     ],
+    cpp_std: "experimental",
 
     local_include_dirs: ["include"],
 }
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 558bc72..3ca9c92 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -44,6 +44,9 @@
 #include <private/android_filesystem_config.h>
 #include <procinfo/process.h>
 
+#define ATRACE_TAG ATRACE_TAG_BIONIC
+#include <utils/Trace.h>
+
 #include "backtrace.h"
 #include "tombstone.h"
 #include "utility.h"
@@ -92,15 +95,11 @@
     return false;
   }
 
-  // Put the task into ptrace-stop state.
-  if (ptrace(PTRACE_INTERRUPT, tid, 0, 0) != 0) {
-    PLOG(FATAL) << "failed to interrupt thread " << tid;
-  }
-
   return true;
 }
 
 static bool activity_manager_notify(pid_t pid, int signal, const std::string& amfd_data) {
+  ATRACE_CALL();
   android::base::unique_fd amfd(socket_local_client(
       "/data/system/ndebugsocket", ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM));
   if (amfd.get() == -1) {
@@ -176,6 +175,7 @@
 }
 
 static void drop_capabilities() {
+  ATRACE_CALL();
   __user_cap_header_struct capheader;
   memset(&capheader, 0, sizeof(capheader));
   capheader.version = _LINUX_CAPABILITY_VERSION_3;
@@ -194,6 +194,8 @@
 }
 
 int main(int argc, char** argv) {
+  atrace_begin(ATRACE_TAG, "before reparent");
+
   pid_t target = getppid();
   bool tombstoned_connected = false;
   unique_fd tombstoned_socket;
@@ -261,6 +263,8 @@
     PLOG(FATAL) << "parent died";
   }
 
+  atrace_end(ATRACE_TAG);
+
   // Reparent ourselves to init, so that the signal handler can waitpid on the
   // original process to avoid leaving a zombie for non-fatal dumps.
   pid_t forkpid = fork();
@@ -270,19 +274,27 @@
     exit(0);
   }
 
+  ATRACE_NAME("after reparent");
+
   // Die if we take too long.
   alarm(2);
 
+  std::string process_name = get_process_name(main_tid);
   std::string attach_error;
 
-  // Seize the main thread.
-  if (!ptrace_seize_thread(target_proc_fd, main_tid, &attach_error)) {
-    LOG(FATAL) << attach_error;
-  }
-
-  // Seize the siblings.
   std::map<pid_t, std::string> threads;
+
   {
+    ATRACE_NAME("ptrace_interrupt");
+
+    // Seize the main thread.
+    if (!ptrace_seize_thread(target_proc_fd, main_tid, &attach_error)) {
+      LOG(FATAL) << attach_error;
+    }
+
+    threads.emplace(main_tid, get_thread_name(main_tid));
+
+    // Seize its siblings.
     std::set<pid_t> siblings;
     if (!android::procinfo::GetProcessTids(target, &siblings)) {
       PLOG(FATAL) << "failed to get process siblings";
@@ -296,31 +308,48 @@
     for (pid_t sibling_tid : siblings) {
       if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) {
         LOG(WARNING) << attach_error;
-      } else {
-        threads.emplace(sibling_tid, get_thread_name(sibling_tid));
+        continue;
       }
+      threads.emplace(sibling_tid, get_thread_name(sibling_tid));
     }
   }
 
   // Collect the backtrace map, open files, and process/thread names, while we still have caps.
-  std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(main_tid));
-  if (!backtrace_map) {
-    LOG(FATAL) << "failed to create backtrace map";
+  std::unique_ptr<BacktraceMap> backtrace_map;
+  {
+    ATRACE_NAME("backtrace map");
+    backtrace_map.reset(BacktraceMap::Create(main_tid));
+    if (!backtrace_map) {
+      LOG(FATAL) << "failed to create backtrace map";
+    }
   }
 
   // Collect the list of open files.
   OpenFilesList open_files;
-  populate_open_files_list(target, &open_files);
-
-  std::string process_name = get_process_name(main_tid);
-  threads.emplace(main_tid, get_thread_name(main_tid));
+  {
+    ATRACE_NAME("open files");
+    populate_open_files_list(target, &open_files);
+  }
 
   // Drop our capabilities now that we've attached to the threads we care about.
   drop_capabilities();
 
-  const DebuggerdDumpType dump_type_enum = static_cast<DebuggerdDumpType>(dump_type);
-  LOG(INFO) << "obtaining output fd from tombstoned, type: " << dump_type_enum;
-  tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd, dump_type_enum);
+  {
+    ATRACE_NAME("tombstoned_connect");
+    const DebuggerdDumpType dump_type_enum = static_cast<DebuggerdDumpType>(dump_type);
+    LOG(INFO) << "obtaining output fd from tombstoned, type: " << dump_type_enum;
+    tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd, dump_type_enum);
+  }
+
+  // Pause the threads.
+  {
+    ATRACE_NAME("ptrace_interrupt");
+    for (const auto& [sibling_tid, _] : threads) {
+      if (ptrace(PTRACE_INTERRUPT, sibling_tid, 0, 0) != 0) {
+        PLOG(FATAL) << "failed to interrupt thread " << sibling_tid;
+      }
+    }
+  }
 
   // Write a '\1' to stdout to tell the crashing process to resume.
   // It also restores the value of PR_SET_DUMPABLE at this point.
@@ -349,9 +378,12 @@
   }
 
   siginfo_t siginfo = {};
-  if (!wait_for_signal(main_tid, &siginfo)) {
-    printf("failed to wait for signal in tid %d: %s\n", main_tid, strerror(errno));
-    exit(1);
+  {
+    ATRACE_NAME("wait_for_signal");
+    if (!wait_for_signal(main_tid, &siginfo)) {
+      printf("failed to wait for signal in tid %d: %s\n", main_tid, strerror(errno));
+      exit(1);
+    }
   }
 
   int signo = siginfo.si_signo;
@@ -373,8 +405,10 @@
 
   std::string amfd_data;
   if (backtrace) {
+    ATRACE_NAME("dump_backtrace");
     dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, process_name, threads, 0);
   } else {
+    ATRACE_NAME("engrave_tombstone");
     engrave_tombstone(output_fd.get(), backtrace_map.get(), &open_files, target, main_tid,
                       process_name, threads, abort_address, fatal_signal ? &amfd_data : nullptr);
   }
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 9008b95..da8ad37 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -89,7 +89,7 @@
   } while (0)
 
 static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
-                                 DebuggerdDumpType intercept_type) {
+                                 InterceptStatus* status, DebuggerdDumpType intercept_type) {
   intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
                                           ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
   if (intercept_fd->get() == -1) {
@@ -136,7 +136,7 @@
            << ", received " << rc;
   }
 
-  ASSERT_EQ(InterceptStatus::kRegistered, response.status);
+  *status = response.status;
 }
 
 class CrasherTest : public ::testing::Test {
@@ -180,7 +180,9 @@
     FAIL() << "crasher hasn't been started";
   }
 
-  tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, intercept_type);
+  InterceptStatus status;
+  tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
+  ASSERT_EQ(InterceptStatus::kRegistered, status);
 }
 
 void CrasherTest::FinishIntercept(int* result) {
@@ -598,7 +600,9 @@
     pid_t pid = 123'456'789 + i;
 
     unique_fd intercept_fd, output_fd;
-    tombstoned_intercept(pid, &intercept_fd, &output_fd, kDebuggerdTombstone);
+    InterceptStatus status;
+    tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
+    ASSERT_EQ(InterceptStatus::kRegistered, status);
 
     {
       unique_fd tombstoned_socket, input_fd;
@@ -630,7 +634,9 @@
       pid_t pid = pid_base + dump;
 
       unique_fd intercept_fd, output_fd;
-      tombstoned_intercept(pid, &intercept_fd, &output_fd, kDebuggerdTombstone);
+      InterceptStatus status;
+      tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
+      ASSERT_EQ(InterceptStatus::kRegistered, status);
 
       // Pretend to crash, and then immediately close the socket.
       unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
@@ -661,7 +667,9 @@
       pid_t pid = pid_base + dump;
 
       unique_fd intercept_fd, output_fd;
-      tombstoned_intercept(pid, &intercept_fd, &output_fd, kDebuggerdTombstone);
+      InterceptStatus status;
+      tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
+      ASSERT_EQ(InterceptStatus::kRegistered, status);
 
       {
         unique_fd tombstoned_socket, input_fd;
@@ -685,3 +693,65 @@
     thread.join();
   }
 }
+
+TEST(tombstoned, java_trace_intercept_smoke) {
+  // Using a "real" PID is a little dangerous here - if the test fails
+  // or crashes, we might end up getting a bogus / unreliable stack
+  // trace.
+  const pid_t self = getpid();
+
+  unique_fd intercept_fd, output_fd;
+  InterceptStatus status;
+  tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
+  ASSERT_EQ(InterceptStatus::kRegistered, status);
+
+  // First connect to tombstoned requesting a native backtrace. This
+  // should result in a "regular" FD and not the installed intercept.
+  const char native[] = "native";
+  unique_fd tombstoned_socket, input_fd;
+  ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdNativeBacktrace));
+  ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
+  tombstoned_notify_completion(tombstoned_socket.get());
+
+  // Then, connect to tombstoned asking for a java backtrace. This *should*
+  // trigger the intercept.
+  const char java[] = "java";
+  ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
+  ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
+  tombstoned_notify_completion(tombstoned_socket.get());
+
+  char outbuf[sizeof(java)];
+  ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
+  ASSERT_STREQ("java", outbuf);
+}
+
+TEST(tombstoned, multiple_intercepts) {
+  const pid_t fake_pid = 1'234'567;
+  unique_fd intercept_fd, output_fd;
+  InterceptStatus status;
+  tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
+  ASSERT_EQ(InterceptStatus::kRegistered, status);
+
+  unique_fd intercept_fd_2, output_fd_2;
+  tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
+  ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
+}
+
+TEST(tombstoned, intercept_any) {
+  const pid_t fake_pid = 1'234'567;
+
+  unique_fd intercept_fd, output_fd;
+  InterceptStatus status;
+  tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
+  ASSERT_EQ(InterceptStatus::kRegistered, status);
+
+  const char any[] = "any";
+  unique_fd tombstoned_socket, input_fd;
+  ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
+  ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
+  tombstoned_notify_completion(tombstoned_socket.get());
+
+  char outbuf[sizeof(any)];
+  ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
+  ASSERT_STREQ("any", outbuf);
+}
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index b4a2bde..b920ebc 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -165,7 +165,7 @@
 };
 
 // Whether java trace dumps are produced via tombstoned.
-static constexpr bool kJavaTraceDumpsEnabled = false;
+static constexpr bool kJavaTraceDumpsEnabled = true;
 
 /* static */ CrashQueue* const CrashQueue::tombstone =
     new CrashQueue("/data/tombstones", "tombstone_" /* file_name_prefix */, 10 /* max_artifacts */,
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 70cd608..7a41b14 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -337,16 +337,8 @@
 
     dirent* dp;
     while ((dp = readdir(fstabdir.get())) != NULL) {
-        // skip over name and compatible
-        if (dp->d_type != DT_DIR) {
-            continue;
-        }
-
-        // skip if its not 'vendor', 'odm' or 'system'
-        if (strcmp(dp->d_name, "odm") && strcmp(dp->d_name, "system") &&
-            strcmp(dp->d_name, "vendor")) {
-            continue;
-        }
+        // skip over name, compatible and .
+        if (dp->d_type != DT_DIR || dp->d_name[0] == '.') continue;
 
         // create <dev> <mnt_point>  <type>  <mnt_flags>  <fsmgr_flags>\n
         std::vector<std::string> fstab_entry;
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 5fa10bc..0177fdf 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -689,27 +689,55 @@
     return read_verity_state(fstab->verity_loc, offset, mode);
 }
 
-static void update_verity_table_blk_device(char *blk_device, char **table)
-{
-    std::string result, word;
+// Update the verity table using the actual block device path.
+// Two cases:
+// Case-1: verity table is shared for devices with different by-name prefix.
+// Example:
+//   verity table token:       /dev/block/bootdevice/by-name/vendor
+//   blk_device-1 (non-A/B):   /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor
+//   blk_device-2 (A/B):       /dev/block/platform/soc.0/f9824900.sdhci/by-name/vendor_a
+//
+// Case-2: append A/B suffix in the verity table.
+// Example:
+//   verity table token: /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor
+//   blk_device:         /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor_a
+static void update_verity_table_blk_device(const std::string& blk_device, char** table,
+                                           bool slot_select) {
+    bool updated = false;
+    std::string result, ab_suffix;
     auto tokens = android::base::Split(*table, " ");
 
+    // If slot_select is set, it means blk_device is already updated with ab_suffix.
+    if (slot_select) ab_suffix = fs_mgr_get_slot_suffix();
+
     for (const auto& token : tokens) {
-        if (android::base::StartsWith(token, "/dev/block/") &&
-            android::base::StartsWith(blk_device, token.c_str())) {
-            word = blk_device;
+        std::string new_token;
+        if (android::base::StartsWith(token, "/dev/block/")) {
+            if (token == blk_device) return;  // no need to update if they're already the same.
+            std::size_t found1 = blk_device.find("by-name");
+            std::size_t found2 = token.find("by-name");
+            if (found1 != std::string::npos && found2 != std::string::npos &&
+                blk_device.substr(found1) == token.substr(found2) + ab_suffix) {
+                new_token = blk_device;
+            }
+        }
+
+        if (!new_token.empty()) {
+            updated = true;
+            LINFO << "Verity table: updated block device from '" << token << "' to '" << new_token
+                  << "'";
         } else {
-            word = token;
+            new_token = token;
         }
 
         if (result.empty()) {
-            result = word;
+            result = new_token;
         } else {
-            result += " " + word;
+            result += " " + new_token;
         }
     }
 
-    if (result.empty()) {
+    if (!updated) {
         return;
     }
 
@@ -825,10 +853,9 @@
     LINFO << "Enabling dm-verity for " << mount_point.c_str()
           << " (mode " << params.mode << ")";
 
-    if (fstab->fs_mgr_flags & MF_SLOTSELECT) {
-        // Update the verity params using the actual block device path
-        update_verity_table_blk_device(fstab->blk_device, &params.table);
-    }
+    // Update the verity params using the actual block device path
+    update_verity_table_blk_device(fstab->blk_device, &params.table,
+                                   fstab->fs_mgr_flags & MF_SLOTSELECT);
 
     // load the verity mapping table
     if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
diff --git a/init/devices.cpp b/init/devices.cpp
index 40f9740..c52d8f8 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -175,7 +175,7 @@
         if (s.MatchWithSubsystem(path, subsystem)) s.SetPermissions(path);
     }
 
-    if (access(path.c_str(), F_OK) == 0) {
+    if (!skip_restorecon_ && access(path.c_str(), F_OK) == 0) {
         LOG(VERBOSE) << "restorecon_recursive: " << path;
         if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
             PLOG(ERROR) << "selinux_android_restorecon(" << path << ") failed";
@@ -467,12 +467,13 @@
 
 DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions,
                              std::vector<SysfsPermissions> sysfs_permissions,
-                             std::vector<Subsystem> subsystems)
+                             std::vector<Subsystem> subsystems, bool skip_restorecon)
     : dev_permissions_(std::move(dev_permissions)),
       sysfs_permissions_(std::move(sysfs_permissions)),
       subsystems_(std::move(subsystems)),
-      sehandle_(selinux_android_file_context_handle()) {}
+      sehandle_(selinux_android_file_context_handle()),
+      skip_restorecon_(skip_restorecon) {}
 
 DeviceHandler::DeviceHandler()
     : DeviceHandler(std::vector<Permissions>{}, std::vector<SysfsPermissions>{},
-                    std::vector<Subsystem>{}) {}
+                    std::vector<Subsystem>{}, false) {}
diff --git a/init/devices.h b/init/devices.h
index 50f49fc..09a0ce3 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -114,14 +114,21 @@
     DeviceHandler();
     DeviceHandler(std::vector<Permissions> dev_permissions,
                   std::vector<SysfsPermissions> sysfs_permissions,
-                  std::vector<Subsystem> subsystems);
+                  std::vector<Subsystem> subsystems, bool skip_restorecon);
     ~DeviceHandler(){};
 
     void HandleDeviceEvent(const Uevent& uevent);
+
+    void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const;
+
+    void HandlePlatformDeviceEvent(const Uevent& uevent);
+    void HandleBlockDeviceEvent(const Uevent& uevent) const;
+    void HandleGenericDeviceEvent(const Uevent& uevent) const;
+
     std::vector<std::string> GetBlockDeviceSymlinks(const Uevent& uevent) const;
+    void set_skip_restorecon(bool value) { skip_restorecon_ = value; }
 
   private:
-    void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const;
     std::tuple<mode_t, uid_t, gid_t> GetDevicePermissions(
         const std::string& path, const std::vector<std::string>& links) const;
     void MakeDevice(const std::string& path, int block, int major, int minor,
@@ -129,15 +136,13 @@
     std::vector<std::string> GetCharacterDeviceSymlinks(const Uevent& uevent) const;
     void HandleDevice(const std::string& action, const std::string& devpath, int block, int major,
                       int minor, const std::vector<std::string>& links) const;
-    void HandlePlatformDeviceEvent(const Uevent& uevent);
-    void HandleBlockDeviceEvent(const Uevent& uevent) const;
-    void HandleGenericDeviceEvent(const Uevent& uevent) const;
 
     std::vector<Permissions> dev_permissions_;
     std::vector<SysfsPermissions> sysfs_permissions_;
     std::vector<Subsystem> subsystems_;
     PlatformDeviceList platform_devices_;
     selabel_handle* sehandle_;
+    bool skip_restorecon_;
 };
 
 // Exposed for testing
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index 1471aeb..844c605 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -18,6 +18,7 @@
 
 #include <fcntl.h>
 #include <sys/sendfile.h>
+#include <sys/wait.h>
 #include <unistd.h>
 
 #include <string>
@@ -103,14 +104,29 @@
     if (uevent.subsystem != "firmware" || uevent.action != "add") return;
 
     // Loading the firmware in a child means we can do that in parallel...
-    // (We ignore SIGCHLD rather than wait for our children.)
+    // We double fork instead of waiting for these processes.
     pid_t pid = fork();
-    if (pid == 0) {
-        Timer t;
-        ProcessFirmwareEvent(uevent);
-        LOG(INFO) << "loading " << uevent.path << " took " << t;
-        _exit(EXIT_SUCCESS);
-    } else if (pid == -1) {
+    if (pid == -1) {
         PLOG(ERROR) << "could not fork to process firmware event for " << uevent.firmware;
+        return;
     }
+
+    if (pid == 0) {
+        pid = fork();
+        if (pid == -1) {
+            PLOG(ERROR) << "could not fork a sceond time to process firmware event for "
+                        << uevent.firmware;
+            _exit(EXIT_FAILURE);
+        }
+        if (pid == 0) {
+            Timer t;
+            ProcessFirmwareEvent(uevent);
+            LOG(INFO) << "loading " << uevent.path << " took " << t;
+            _exit(EXIT_SUCCESS);
+        }
+
+        _exit(EXIT_SUCCESS);
+    }
+
+    waitpid(pid, nullptr, 0);
 }
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 8a7d9a2..0f2b1f3 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -60,9 +60,8 @@
     virtual bool SetUpDmVerity(fstab_rec* fstab_rec) = 0;
 
     bool need_dm_verity_;
-    // Device tree fstab entries.
+
     std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> device_tree_fstab_;
-    // Eligible first stage mount candidates, only allow /system, /vendor and/or /odm.
     std::vector<fstab_rec*> mount_fstab_recs_;
     std::set<std::string> required_devices_partition_names_;
     DeviceHandler device_handler_;
@@ -115,12 +114,10 @@
         LOG(ERROR) << "Failed to read fstab from device tree";
         return;
     }
-    for (auto mount_point : {"/system", "/vendor", "/odm"}) {
-        fstab_rec* fstab_rec =
-            fs_mgr_get_entry_for_mount_point(device_tree_fstab_.get(), mount_point);
-        if (fstab_rec != nullptr) {
-            mount_fstab_recs_.push_back(fstab_rec);
-        }
+    // Stores device_tree_fstab_->recs[] into mount_fstab_recs_ (vector<fstab_rec*>)
+    // for easier manipulation later, e.g., range-base for loop.
+    for (int i = 0; i < device_tree_fstab_->num_entries; i++) {
+        mount_fstab_recs_.push_back(&device_tree_fstab_->recs[i]);
     }
 }
 
@@ -420,7 +417,7 @@
 
 // Public functions
 // ----------------
-// Mounts /system, /vendor, and/or /odm if they are present in the fstab provided by device tree.
+// Mounts partitions specified by fstab in device tree.
 bool DoFirstStageMount() {
     // Skips first stage mount if we're in recovery mode.
     if (IsRecoveryMode()) {
diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp
index 27c5d23..01b8250 100644
--- a/init/uevent_listener.cpp
+++ b/init/uevent_listener.cpp
@@ -165,7 +165,7 @@
     return RegenerateUeventsForDir(d.get(), callback);
 }
 
-static const char* kRegenerationPaths[] = {"/sys/class", "/sys/block", "/sys/devices"};
+const char* kRegenerationPaths[] = {"/sys/class", "/sys/block", "/sys/devices"};
 
 void UeventListener::RegenerateUevents(RegenerateCallback callback) const {
     for (const auto path : kRegenerationPaths) {
diff --git a/init/uevent_listener.h b/init/uevent_listener.h
index ba31aaa..8e6f3b4 100644
--- a/init/uevent_listener.h
+++ b/init/uevent_listener.h
@@ -35,6 +35,8 @@
 using RegenerateCallback = std::function<RegenerationAction(const Uevent&)>;
 using PollCallback = std::function<void(const Uevent&)>;
 
+extern const char* kRegenerationPaths[3];
+
 class UeventListener {
   public:
     UeventListener();
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index bd21a3e..31e4106 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -22,10 +22,15 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/wait.h>
+
+#include <set>
+#include <thread>
 
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <selinux/android.h>
 #include <selinux/selinux.h>
 
 #include "devices.h"
@@ -35,6 +40,194 @@
 #include "ueventd_parser.h"
 #include "util.h"
 
+// At a high level, ueventd listens for uevent messages generated by the kernel through a netlink
+// socket.  When ueventd receives such a message it handles it by taking appropriate actions,
+// which can typically be creating a device node in /dev, setting file permissions, setting selinux
+// labels, etc.
+// Ueventd also handles loading of firmware that the kernel requests, and creates symlinks for block
+// and character devices.
+
+// When ueventd starts, it regenerates uevents for all currently registered devices by traversing
+// /sys and writing 'add' to each 'uevent' file that it finds.  This causes the kernel to generate
+// and resend uevent messages for all of the currently registered devices.  This is done, because
+// ueventd would not have been running when these devices were registered and therefore was unable
+// to receive their uevent messages and handle them appropriately.  This process is known as
+// 'cold boot'.
+
+// 'init' currently waits synchronously on the cold boot process of ueventd before it continues
+// its boot process.  For this reason, cold boot should be as quick as possible.  One way to achieve
+// a speed up here is to parallelize the handling of ueventd messages, which consume the bulk of the
+// time during cold boot.
+
+// Handling of uevent messages has two unique properties:
+// 1) It can be done in isolation; it doesn't need to read or write any status once it is started.
+// 2) It uses setegid() and setfscreatecon() so either care (aka locking) must be taken to ensure
+//    that no file system operations are done while the uevent process has an abnormal egid or
+//    fscreatecon or this handling must happen in a separate process.
+// Given the above two properties, it is best to fork() subprocesses to handle the uevents.  This
+// reduces the overhead and complexity that would be required in a solution with threads and locks.
+// In testing, a racy multithreaded solution has the same performance as the fork() solution, so
+// there is no reason to deal with the complexity of the former.
+
+// One other important caveat during the boot process is the handling of SELinux restorecon.
+// Since many devices have child devices, calling selinux_android_restorecon() recursively for each
+// device when its uevent is handled, results in multiple restorecon operations being done on a
+// given file.  It is more efficient to simply do restorecon recursively on /sys during cold boot,
+// than to do restorecon on each device as its uevent is handled.  This only applies to cold boot;
+// once that has completed, restorecon is done for each device as its uevent is handled.
+
+// With all of the above considered, the cold boot process has the below steps:
+// 1) ueventd regenerates uevents by doing the /sys traversal and listens to the netlink socket for
+//    the generated uevents.  It writes these uevents into a queue represented by a vector.
+//
+// 2) ueventd forks 'n' separate uevent handler subprocesses and has each of them to handle the
+//    uevents in the queue based on a starting offset (their process number) and a stride (the total
+//    number of processes).  Note that no IPC happens at this point and only const functions from
+//    DeviceHandler should be called from this context.
+//
+// 3) In parallel to the subprocesses handling the uevents, the main thread of ueventd calls
+//    selinux_android_restorecon() recursively on /sys/class, /sys/block, and /sys/devices.
+//
+// 4) Once the restorecon operation finishes, the main thread calls waitpid() to wait for all
+//    subprocess handlers to complete and exit.  Once this happens, it marks coldboot as having
+//    completed.
+//
+// At this point, ueventd is single threaded, poll()'s and then handles any future uevents.
+
+// Lastly, it should be noted that uevents that occur during the coldboot process are handled
+// without issue after the coldboot process completes.  This is because the uevent listener is
+// paused while the uevent handler and restorecon actions take place.  Once coldboot completes,
+// the uevent listener resumes in polling mode and will handle the uevents that occurred during
+// coldboot.
+
+class ColdBoot {
+  public:
+    ColdBoot(UeventListener& uevent_listener, DeviceHandler& device_handler)
+        : uevent_listener_(uevent_listener),
+          device_handler_(device_handler),
+          num_handler_subprocesses_(std::thread::hardware_concurrency() ?: 4) {}
+
+    void Run();
+
+  private:
+    void UeventHandlerMain(unsigned int process_num, unsigned int total_processes);
+    void RegenerateUevents();
+    void ForkSubProcesses();
+    void DoRestoreCon();
+    void WaitForSubProcesses();
+
+    UeventListener& uevent_listener_;
+    DeviceHandler& device_handler_;
+
+    unsigned int num_handler_subprocesses_;
+    std::vector<Uevent> uevent_queue_;
+
+    std::set<pid_t> subprocess_pids_;
+};
+
+void ColdBoot::UeventHandlerMain(unsigned int process_num, unsigned int total_processes) {
+    for (unsigned int i = process_num; i < uevent_queue_.size(); i += total_processes) {
+        auto& uevent = uevent_queue_[i];
+        if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
+            device_handler_.FixupSysPermissions(uevent.path, uevent.subsystem);
+        }
+
+        if (uevent.subsystem == "block") {
+            device_handler_.HandleBlockDeviceEvent(uevent);
+        } else {
+            device_handler_.HandleGenericDeviceEvent(uevent);
+        }
+    }
+    _exit(EXIT_SUCCESS);
+}
+
+void ColdBoot::RegenerateUevents() {
+    uevent_listener_.RegenerateUevents([this](const Uevent& uevent) {
+        HandleFirmwareEvent(uevent);
+
+        // This is the one mutable part of DeviceHandler, in which platform devices are
+        // added to a vector for later reference.  Since there is no communication after
+        // fork()'ing subprocess handlers, all platform devices must be in the vector before
+        // we fork, and therefore they must be handled in this loop.
+        if (uevent.subsystem == "platform") {
+            device_handler_.HandlePlatformDeviceEvent(uevent);
+        }
+
+        uevent_queue_.emplace_back(std::move(uevent));
+        return RegenerationAction::kContinue;
+    });
+}
+
+void ColdBoot::ForkSubProcesses() {
+    for (unsigned int i = 0; i < num_handler_subprocesses_; ++i) {
+        auto pid = fork();
+        if (pid < 0) {
+            PLOG(FATAL) << "fork() failed!";
+        }
+
+        if (pid == 0) {
+            UeventHandlerMain(i, num_handler_subprocesses_);
+        }
+
+        subprocess_pids_.emplace(pid);
+    }
+}
+
+void ColdBoot::DoRestoreCon() {
+    for (const char* path : kRegenerationPaths) {
+        selinux_android_restorecon(path, SELINUX_ANDROID_RESTORECON_RECURSE);
+    }
+    device_handler_.set_skip_restorecon(false);
+}
+
+void ColdBoot::WaitForSubProcesses() {
+    // Treat subprocesses that crash or get stuck the same as if ueventd itself has crashed or gets
+    // stuck.
+    //
+    // When a subprocess crashes, we fatally abort from ueventd.  init will restart ueventd when
+    // init reaps it, and the cold boot process will start again.  If this continues to fail, then
+    // since ueventd is marked as a critical service, init will reboot to recovery.
+    //
+    // When a subprocess gets stuck, keep ueventd spinning waiting for it.  init has a timeout for
+    // cold boot and will reboot to the bootloader if ueventd does not complete in time.
+    while (!subprocess_pids_.empty()) {
+        int status;
+        pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, 0));
+        if (pid == -1) {
+            PLOG(ERROR) << "waitpid() failed";
+            continue;
+        }
+
+        auto it = std::find(subprocess_pids_.begin(), subprocess_pids_.end(), pid);
+        if (it == subprocess_pids_.end()) continue;
+
+        if (WIFEXITED(status)) {
+            if (WEXITSTATUS(status) == EXIT_SUCCESS) {
+                subprocess_pids_.erase(it);
+            } else {
+                LOG(FATAL) << "subprocess exited with status " << WEXITSTATUS(status);
+            }
+        } else if (WIFSIGNALED(status)) {
+            LOG(FATAL) << "subprocess killed by signal " << WTERMSIG(status);
+        }
+    }
+}
+
+void ColdBoot::Run() {
+    Timer cold_boot_timer;
+
+    RegenerateUevents();
+
+    ForkSubProcesses();
+
+    DoRestoreCon();
+
+    WaitForSubProcesses();
+
+    close(open(COLDBOOT_DONE, O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
+    LOG(INFO) << "Coldboot took " << cold_boot_timer;
+}
+
 DeviceHandler CreateDeviceHandler() {
     Parser parser;
 
@@ -64,11 +257,10 @@
     parser.ParseConfig("/ueventd." + hardware + ".rc");
 
     return DeviceHandler(std::move(dev_permissions), std::move(sysfs_permissions),
-                         std::move(subsystems));
+                         std::move(subsystems), true);
 }
 
-int ueventd_main(int argc, char **argv)
-{
+int ueventd_main(int argc, char** argv) {
     /*
      * init sets the umask to 077 for forked processes. We need to
      * create files with exact permissions, without modification by
@@ -76,13 +268,6 @@
      */
     umask(000);
 
-    /* Prevent fire-and-forget children from becoming zombies.
-     * If we should need to wait() for some children in the future
-     * (as opposed to none right now), double-forking here instead
-     * of ignoring SIGCHLD may be the better solution.
-     */
-    signal(SIGCHLD, SIG_IGN);
-
     InitKernelLogging(argv);
 
     LOG(INFO) << "ueventd started!";
@@ -95,16 +280,8 @@
     UeventListener uevent_listener;
 
     if (access(COLDBOOT_DONE, F_OK) != 0) {
-        Timer t;
-
-        uevent_listener.RegenerateUevents([&device_handler](const Uevent& uevent) {
-            HandleFirmwareEvent(uevent);
-            device_handler.HandleDeviceEvent(uevent);
-            return RegenerationAction::kContinue;
-        });
-
-        close(open(COLDBOOT_DONE, O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
-        LOG(INFO) << "Coldboot took " << t;
+        ColdBoot cold_boot(uevent_listener, device_handler);
+        cold_boot.Run();
     }
 
     uevent_listener.DoPolling([&device_handler](const Uevent& uevent) {
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 7dd9227..a643a29 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -113,6 +113,7 @@
             static_libs: ["libasync_safe", "libcutils"],
         },
     },
+    whole_static_libs: ["libdemangle"],
 }
 
 cc_library_shared {
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 3545661..e46d353 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -27,6 +27,8 @@
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
+#include <demangle.h>
+
 #include "BacktraceLog.h"
 #include "thread_utils.h"
 #include "UnwindCurrent.h"
@@ -62,8 +64,7 @@
   if (map->start == 0 || (map->flags & PROT_DEVICE_MAP)) {
     return "";
   }
-  std::string func_name = GetFunctionNameRaw(pc, offset);
-  return func_name;
+  return demangle(GetFunctionNameRaw(pc, offset).c_str());
 }
 
 bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) {
diff --git a/libcutils/sched_policy.cpp b/libcutils/sched_policy.cpp
index e29a844..7e38535 100644
--- a/libcutils/sched_policy.cpp
+++ b/libcutils/sched_policy.cpp
@@ -340,7 +340,7 @@
     return 0;
 }
 
-static void set_timerslack_ns(int tid, unsigned long long slack) {
+static void set_timerslack_ns(int tid, unsigned long slack) {
     // v4.6+ kernels support the /proc/<tid>/timerslack_ns interface.
     // TODO: once we've backported this, log if the open(2) fails.
     if (__sys_supports_timerslack) {
@@ -348,7 +348,7 @@
         snprintf(buf, sizeof(buf), "/proc/%d/timerslack_ns", tid);
         int fd = open(buf, O_WRONLY | O_CLOEXEC);
         if (fd != -1) {
-            int len = snprintf(buf, sizeof(buf), "%llu", slack);
+            int len = snprintf(buf, sizeof(buf), "%lu", slack);
             if (write(fd, buf, len) != len) {
                 SLOGE("set_timerslack_ns write failed: %s\n", strerror(errno));
             }
diff --git a/liblog/include/log/log_event_list.h b/liblog/include/log/log_event_list.h
index 057be5d..bb1ce34 100644
--- a/liblog/include/log/log_event_list.h
+++ b/liblog/include/log/log_event_list.h
@@ -177,6 +177,12 @@
     return *this;
   }
 
+  android_log_event_list& operator<<(bool value) {
+    int retval = android_log_write_int32(ctx, value ? 1 : 0);
+    if (retval < 0) ret = retval;
+    return *this;
+  }
+
   android_log_event_list& operator<<(int64_t value) {
     int retval = android_log_write_int64(ctx, value);
     if (retval < 0) ret = retval;