Merge "Exporting C headers from system/core"
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 831150b..e4f88b0 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -36,7 +36,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
 #include <cutils/sockets.h>
-#include <log/logger.h>
+#include <log/log.h>
 #include <procinfo/process.h>
 #include <selinux/selinux.h>
 
@@ -57,8 +57,8 @@
 }
 
 // Attach to a thread, and verify that it's still a member of the given process
-static bool ptrace_attach_thread(pid_t pid, pid_t tid, std::string* error) {
-  if (ptrace(PTRACE_ATTACH, tid, 0, 0) != 0) {
+static bool ptrace_seize_thread(pid_t pid, pid_t tid, std::string* error) {
+  if (ptrace(PTRACE_SEIZE, tid, 0, 0) != 0) {
     *error = StringPrintf("failed to attach to thread %d: %s", tid, strerror(errno));
     return false;
   }
@@ -71,6 +71,12 @@
     *error = StringPrintf("thread %d is not in process %d", tid, pid);
     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;
 }
 
@@ -160,11 +166,15 @@
   return true;
 }
 
+static void signal_handler(int) {
+  // We can't log easily, because the heap might be corrupt.
+  // Just die and let the surrounding log context explain things.
+  _exit(1);
+}
+
 static void abort_handler(pid_t target, const bool& tombstoned_connected,
                           unique_fd& tombstoned_socket, unique_fd& output_fd,
                           const char* abort_msg) {
-  LOG(ERROR) << abort_msg;
-
   // If we abort before we get an output fd, contact tombstoned to let any
   // potential listeners know that we failed.
   if (!tombstoned_connected) {
@@ -177,7 +187,6 @@
 
   dprintf(output_fd.get(), "crash_dump failed to dump process %d: %s\n", target, abort_msg);
 
-  // Don't dump ourselves.
   _exit(1);
 }
 
@@ -203,6 +212,11 @@
     abort_handler(target, tombstoned_connected, tombstoned_socket, output_fd, abort_msg);
   });
 
+  // Don't try to dump ourselves.
+  struct sigaction action = {};
+  action.sa_handler = signal_handler;
+  debuggerd_register_handlers(&action);
+
   if (argc != 2) {
     return 1;
   }
@@ -243,10 +257,13 @@
     exit(0);
   }
 
+  // Die if we take too long.
+  alarm(20);
+
   check_process(target_proc_fd, target);
 
   std::string attach_error;
-  if (!ptrace_attach_thread(target, main_tid, &attach_error)) {
+  if (!ptrace_seize_thread(target, main_tid, &attach_error)) {
     LOG(FATAL) << attach_error;
   }
 
@@ -271,9 +288,9 @@
 
   LOG(INFO) << "performing dump of process " << target << " (target tid = " << main_tid << ")";
 
-  // At this point, the thread that made the request has been PTRACE_ATTACHed
-  // and has the signal that triggered things queued. Send PTRACE_CONT, and
-  // then wait for the signal.
+  // At this point, the thread that made the request has been attached and is
+  // in ptrace-stopped state. After resumption, the triggering signal that has
+  // been queued will be delivered.
   if (ptrace(PTRACE_CONT, main_tid, 0, 0) != 0) {
     PLOG(ERROR) << "PTRACE_CONT(" << main_tid << ") failed";
     exit(1);
@@ -302,17 +319,16 @@
   // Now that we have the signal that kicked things off, attach all of the
   // sibling threads, and then proceed.
   bool fatal_signal = signo != DEBUGGER_SIGNAL;
-  int resume_signal = fatal_signal ? signo : 0;
   std::set<pid_t> siblings;
   std::set<pid_t> attached_siblings;
-  if (resume_signal == 0) {
+  if (fatal_signal) {
     if (!android::procinfo::GetProcessTids(target, &siblings)) {
       PLOG(FATAL) << "failed to get process siblings";
     }
     siblings.erase(main_tid);
 
     for (pid_t sibling_tid : siblings) {
-      if (!ptrace_attach_thread(target, sibling_tid, &attach_error)) {
+      if (!ptrace_seize_thread(target, sibling_tid, &attach_error)) {
         LOG(WARNING) << attach_error;
       } else {
         attached_siblings.insert(sibling_tid);
@@ -338,40 +354,39 @@
                       attached_siblings, abort_address, fatal_signal ? &amfd_data : nullptr);
   }
 
+  // We don't actually need to PTRACE_DETACH, as long as our tracees aren't in
+  // group-stop state, which is true as long as no stopping signals are sent.
+
   bool wait_for_gdb = android::base::GetBoolProperty("debug.debuggerd.wait_for_gdb", false);
-  if (wait_for_gdb) {
+  if (!fatal_signal || siginfo.si_code == SI_USER) {
     // Don't wait_for_gdb when the process didn't actually crash.
-    if (!fatal_signal) {
-      wait_for_gdb = false;
-    } else {
-      // Use ALOGI to line up with output from engrave_tombstone.
-      ALOGI(
-        "***********************************************************\n"
-        "* Process %d has been suspended while crashing.\n"
-        "* To attach gdbserver and start gdb, run this on the host:\n"
-        "*\n"
-        "*     gdbclient.py -p %d\n"
-        "*\n"
-        "***********************************************************",
-        target, main_tid);
-    }
+    wait_for_gdb = false;
   }
 
-  for (pid_t tid : attached_siblings) {
-    // Don't send the signal to sibling threads.
-    if (ptrace(PTRACE_DETACH, tid, 0, wait_for_gdb ? SIGSTOP : 0) != 0) {
-      PLOG(ERROR) << "ptrace detach from " << tid << " failed";
+  // If the process crashed or we need to send it SIGSTOP for wait_for_gdb,
+  // get it in a state where it can receive signals, and then send the relevant
+  // signal.
+  if (wait_for_gdb || fatal_signal) {
+    if (ptrace(PTRACE_INTERRUPT, main_tid, 0, 0) != 0) {
+      PLOG(ERROR) << "failed to use PTRACE_INTERRUPT on " << main_tid;
     }
-  }
 
-  if (ptrace(PTRACE_DETACH, main_tid, 0, wait_for_gdb ? SIGSTOP : resume_signal)) {
-    PLOG(ERROR) << "ptrace detach from main thread " << main_tid << " failed";
+    if (tgkill(target, main_tid, wait_for_gdb ? SIGSTOP : signo) != 0) {
+      PLOG(ERROR) << "failed to resend signal " << signo << " to " << main_tid;
+    }
   }
 
   if (wait_for_gdb) {
-    if (tgkill(target, main_tid, resume_signal) != 0) {
-      PLOG(ERROR) << "failed to resend signal to process " << target;
-    }
+    // Use ALOGI to line up with output from engrave_tombstone.
+    ALOGI(
+      "***********************************************************\n"
+      "* Process %d has been suspended while crashing.\n"
+      "* To attach gdbserver and start gdb, run this on the host:\n"
+      "*\n"
+      "*     gdbclient.py -p %d\n"
+      "*\n"
+      "***********************************************************",
+      target, main_tid);
   }
 
   if (fatal_signal) {
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index f51b5f2..e7503e9 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -17,6 +17,7 @@
 #include <err.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <sys/prctl.h>
 #include <sys/types.h>
 
 #include <chrono>
@@ -90,6 +91,7 @@
   // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
   void FinishIntercept(int* result);
 
+  void StartProcess(std::function<void()> function);
   void StartCrasher(const std::string& crash_type);
   void FinishCrasher();
   void AssertDeath(int signo);
@@ -166,9 +168,8 @@
   }
 }
 
-void CrasherTest::StartCrasher(const std::string& crash_type) {
-  std::string type = "wait-" + crash_type;
-
+void CrasherTest::StartProcess(std::function<void()> function) {
+  unique_fd read_pipe;
   unique_fd crasher_read_pipe;
   if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
     FAIL() << "failed to create pipe: " << strerror(errno);
@@ -182,9 +183,17 @@
     dup2(crasher_read_pipe.get(), STDIN_FILENO);
     dup2(devnull.get(), STDOUT_FILENO);
     dup2(devnull.get(), STDERR_FILENO);
+    function();
+    _exit(0);
+  }
+}
+
+void CrasherTest::StartCrasher(const std::string& crash_type) {
+  std::string type = "wait-" + crash_type;
+  StartProcess([type]() {
     execl(CRASHER_PATH, CRASHER_PATH, type.c_str(), nullptr);
     err(1, "exec failed");
-  }
+  });
 }
 
 void CrasherTest::FinishCrasher() {
@@ -340,24 +349,15 @@
   AssertDeath(SIGABRT);
 }
 
+// wait_for_gdb shouldn't trigger on manually sent signals.
 TEST_F(CrasherTest, wait_for_gdb_signal) {
   if (!android::base::SetProperty(kWaitForGdbKey, "1")) {
     FAIL() << "failed to enable wait_for_gdb";
   }
 
   StartCrasher("abort");
-  ASSERT_EQ(0, kill(crasher_pid, SIGABRT)) << strerror(errno);
-
-  std::this_thread::sleep_for(500ms);
-
-  int status;
-  ASSERT_EQ(crasher_pid, (TIMEOUT(1, waitpid(crasher_pid, &status, WUNTRACED))));
-  ASSERT_TRUE(WIFSTOPPED(status));
-  ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
-
-  ASSERT_EQ(0, kill(crasher_pid, SIGCONT)) << strerror(errno);
-
-  AssertDeath(SIGABRT);
+  ASSERT_EQ(0, kill(crasher_pid, SIGSEGV)) << strerror(errno);
+  AssertDeath(SIGSEGV);
 }
 
 TEST_F(CrasherTest, backtrace) {
@@ -388,3 +388,20 @@
   ConsumeFd(std::move(output_fd), &result);
   ASSERT_MATCH(result, R"(#00 pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX R"(/libc.so \(tgkill)");
 }
+
+TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
+  StartProcess([]() {
+    prctl(PR_SET_DUMPABLE, 0);
+    volatile char* null = static_cast<char*>(nullptr);
+    *null = '\0';
+  });
+  AssertDeath(SIGSEGV);
+}
+
+TEST_F(CrasherTest, PR_SET_DUMPABLE_0_raise) {
+  StartProcess([]() {
+    prctl(PR_SET_DUMPABLE, 0);
+    raise(SIGUSR1);
+  });
+  AssertDeath(SIGUSR1);
+}
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 6033a6b..8ea06c0 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -31,6 +31,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <linux/futex.h>
 #include <pthread.h>
 #include <sched.h>
 #include <signal.h>
@@ -46,6 +47,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include "private/bionic_futex.h"
 #include "private/libc_logging.h"
 
 // see man(2) prctl, specifically the section about PR_GET_NAME
@@ -61,6 +63,9 @@
 
 static debuggerd_callbacks_t g_callbacks;
 
+// Mutex to ensure only one crashing thread dumps itself.
+static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
+
 // Don't use __libc_fatal because it exits via abort, which might put us back into a signal handler.
 #define fatal(...)                                             \
   do {                                                         \
@@ -151,8 +156,7 @@
 }
 
 struct debugger_thread_info {
-  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-  bool crash_dump_started = false;
+  bool crash_dump_started;
   pid_t crashing_tid;
   pid_t pseudothread_tid;
   int signal_number;
@@ -228,16 +232,41 @@
     }
   }
 
-  pthread_mutex_unlock(&thread_info->mutex);
+  syscall(__NR_exit, 0);
   return 0;
 }
 
+static void resend_signal(siginfo_t* info) {
+  // Signals can either be fatal or nonfatal.
+  // For fatal signals, crash_dump will send us the signal we crashed with
+  // before resuming us, so that processes using waitpid on us will see that we
+  // exited with the correct exit status (e.g. so that sh will report
+  // "Segmentation fault" instead of "Killed"). For this to work, we need
+  // to deregister our signal handler for that signal before continuing.
+  if (info->si_signo != DEBUGGER_SIGNAL) {
+    signal(info->si_signo, SIG_DFL);
+  }
+
+  // We need to return from our signal handler so that crash_dump can see the
+  // signal via ptrace and dump the thread that crashed. However, returning
+  // does not guarantee that the signal will be thrown again, even for SIGSEGV
+  // and friends, since the signal could have been sent manually. We blocked
+  // all signals when registering the handler, so resending the signal (using
+  // rt_tgsigqueueinfo(2) to preserve SA_SIGINFO) will cause it to be delivered
+  // when our signal handler returns.
+  int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), gettid(), info->si_signo, info);
+  if (rc != 0) {
+    fatal("failed to resend signal during crash: %s", strerror(errno));
+  }
+
+  if (info->si_signo == DEBUGGER_SIGNAL) {
+    pthread_mutex_unlock(&crash_mutex);
+  }
+}
+
 // Handler that does crash dumping by forking and doing the processing in the child.
 // Do this by ptracing the relevant thread, and then execing debuggerd to do the actual dump.
 static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) {
-  // Mutex to prevent multiple crashing threads from trying to talk
-  // to debuggerd at the same time.
-  static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
   int ret = pthread_mutex_lock(&crash_mutex);
   if (ret != 0) {
     __libc_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_lock failed: %s", strerror(ret));
@@ -250,59 +279,10 @@
     info = nullptr;
   }
 
-  log_signal_summary(signal_number, info);
-  if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) {
-    // process has disabled core dumps and PTRACE_ATTACH, and does not want to be dumped.
-    // Honor that intention by not connecting to debuggerd and asking it to dump our internal state.
-    __libc_format_log(ANDROID_LOG_INFO, "libc",
-                      "Suppressing debuggerd output because prctl(PR_GET_DUMPABLE)==0");
-
-    pthread_mutex_unlock(&crash_mutex);
-    return;
-  }
-
-  void* abort_message = nullptr;
-  if (g_callbacks.get_abort_message) {
-    abort_message = g_callbacks.get_abort_message();
-  }
-
-  debugger_thread_info thread_info = {
-    .crashing_tid = gettid(),
-    .signal_number = signal_number,
-    .info = info
-  };
-  pthread_mutex_lock(&thread_info.mutex);
-
-  // Essentially pthread_create without CLONE_FILES (see debuggerd_dispatch_pseudothread).
-  pid_t child_pid = clone(debuggerd_dispatch_pseudothread, pseudothread_stack,
-                          CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_SETTID,
-                          &thread_info, nullptr, nullptr, &thread_info.pseudothread_tid);
-  if (child_pid == -1) {
-    fatal("failed to spawn debuggerd dispatch thread: %s", strerror(errno));
-  }
-
-  // Wait for the child to finish and unlock the mutex.
-  // This relies on bionic behavior that isn't guaranteed by the standard.
-  pthread_mutex_lock(&thread_info.mutex);
-
-  // Signals can either be fatal or nonfatal.
-  // For fatal signals, crash_dump will PTRACE_CONT us with the signal we
-  // crashed with, so that processes using waitpid on us will see that we
-  // exited with the correct exit status (e.g. so that sh will report
-  // "Segmentation fault" instead of "Killed"). For this to work, we need
-  // to deregister our signal handler for that signal before continuing.
-  if (signal_number != DEBUGGER_SIGNAL) {
-    signal(signal_number, SIG_DFL);
-  }
-
-  // We need to return from the signal handler so that debuggerd can dump the
-  // thread that crashed, but returning here does not guarantee that the signal
-  // will be thrown again, even for SIGSEGV and friends, since the signal could
-  // have been sent manually. Resend the signal with rt_tgsigqueueinfo(2) to
-  // preserve the SA_SIGINFO contents.
-  struct siginfo si;
+  struct siginfo si = {};
   if (!info) {
     memset(&si, 0, sizeof(si));
+    si.si_signo = signal_number;
     si.si_code = SI_USER;
     si.si_pid = getpid();
     si.si_uid = getuid();
@@ -314,23 +294,59 @@
     // check to allow all si_code values in calls coming from inside the house.
   }
 
+  log_signal_summary(signal_number, info);
+  if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) {
+    // The process has disabled core dumps and PTRACE_ATTACH, and does not want to be dumped.
+    __libc_format_log(ANDROID_LOG_INFO, "libc",
+                      "Suppressing debuggerd output because prctl(PR_GET_DUMPABLE)==0");
+
+    resend_signal(info);
+    return;
+  }
+
+  void* abort_message = nullptr;
+  if (g_callbacks.get_abort_message) {
+    abort_message = g_callbacks.get_abort_message();
+  }
   // Populate si_value with the abort message address, if found.
   if (abort_message) {
     info->si_value.sival_ptr = abort_message;
   }
 
-  // Only resend the signal if we know that either crash_dump has ptraced us or
-  // the signal was fatal.
-  if (thread_info.crash_dump_started || signal_number != DEBUGGER_SIGNAL) {
-    int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), gettid(), signal_number, info);
-    if (rc != 0) {
-      fatal("failed to resend signal during crash: %s", strerror(errno));
-    }
+  debugger_thread_info thread_info = {
+    .crash_dump_started = false,
+    .pseudothread_tid = -1,
+    .crashing_tid = gettid(),
+    .signal_number = signal_number,
+    .info = info
+  };
+
+  // Essentially pthread_create without CLONE_FILES (see debuggerd_dispatch_pseudothread).
+  pid_t child_pid =
+    clone(debuggerd_dispatch_pseudothread, pseudothread_stack,
+          CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID,
+          &thread_info, nullptr, nullptr, &thread_info.pseudothread_tid);
+  if (child_pid == -1) {
+    fatal("failed to spawn debuggerd dispatch thread: %s", strerror(errno));
   }
 
-  if (signal_number == DEBUGGER_SIGNAL) {
-    pthread_mutex_unlock(&crash_mutex);
+  // Wait for the child to start...
+  __futex_wait(&thread_info.pseudothread_tid, -1, nullptr);
+
+  // and then wait for it to finish.
+  __futex_wait(&thread_info.pseudothread_tid, child_pid, nullptr);
+
+  // Signals can either be fatal or nonfatal.
+  // For fatal signals, crash_dump will PTRACE_CONT us with the signal we
+  // crashed with, so that processes using waitpid on us will see that we
+  // exited with the correct exit status (e.g. so that sh will report
+  // "Segmentation fault" instead of "Killed"). For this to work, we need
+  // to deregister our signal handler for that signal before continuing.
+  if (signal_number != DEBUGGER_SIGNAL) {
+    signal(signal_number, SIG_DFL);
   }
+
+  resend_signal(info);
 }
 
 void debuggerd_init(debuggerd_callbacks_t* callbacks) {
@@ -363,15 +379,5 @@
 
   // Use the alternate signal stack if available so we can catch stack overflows.
   action.sa_flags |= SA_ONSTACK;
-
-  sigaction(SIGABRT, &action, nullptr);
-  sigaction(SIGBUS, &action, nullptr);
-  sigaction(SIGFPE, &action, nullptr);
-  sigaction(SIGILL, &action, nullptr);
-  sigaction(SIGSEGV, &action, nullptr);
-#if defined(SIGSTKFLT)
-  sigaction(SIGSTKFLT, &action, nullptr);
-#endif
-  sigaction(SIGTRAP, &action, nullptr);
-  sigaction(DEBUGGER_SIGNAL, &action, nullptr);
+  debuggerd_register_handlers(&action);
 }
diff --git a/debuggerd/include/debuggerd/handler.h b/debuggerd/include/debuggerd/handler.h
index 302f4c2..7196e0a 100644
--- a/debuggerd/include/debuggerd/handler.h
+++ b/debuggerd/include/debuggerd/handler.h
@@ -39,4 +39,18 @@
 // to the log.
 #define DEBUGGER_SIGNAL (__SIGRTMIN + 3)
 
+static void __attribute__((__unused__)) debuggerd_register_handlers(struct sigaction* action) {
+  sigaction(SIGABRT, action, nullptr);
+  sigaction(SIGBUS, action, nullptr);
+  sigaction(SIGFPE, action, nullptr);
+  sigaction(SIGILL, action, nullptr);
+  sigaction(SIGSEGV, action, nullptr);
+#if defined(SIGSTKFLT)
+  sigaction(SIGSTKFLT, action, nullptr);
+#endif
+  sigaction(SIGSYS, action, nullptr);
+  sigaction(SIGTRAP, action, nullptr);
+  sigaction(DEBUGGER_SIGNAL, action, nullptr);
+}
+
 __END_DECLS
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index 63e3dbd..8705ece 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -85,7 +85,13 @@
     std::string path = android::base::StringPrintf("%stombstone_%02zu", kTombstoneDirectory, i);
     struct stat st;
     if (stat(path.c_str(), &st) != 0) {
-      PLOG(ERROR) << "failed to stat " << path;
+      if (errno == ENOENT) {
+        oldest_tombstone = i;
+        break;
+      } else {
+        PLOG(ERROR) << "failed to stat " << path;
+        continue;
+      }
     }
 
     if (st.st_mtime < oldest_time) {
diff --git a/debuggerd/tombstoned/tombstoned.rc b/debuggerd/tombstoned/tombstoned.rc
index eaae9c4..b8345ca 100644
--- a/debuggerd/tombstoned/tombstoned.rc
+++ b/debuggerd/tombstoned/tombstoned.rc
@@ -2,6 +2,9 @@
     user tombstoned
     group system
 
+    # Don't start tombstoned until after the real /data is mounted.
+    class late_start
+
     socket tombstoned_crash seqpacket 0666 system system
     socket tombstoned_intercept seqpacket 0666 system system
     writepid /dev/cpuset/system-background/tasks
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 9a53d62..e699b71 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -407,7 +407,7 @@
     return ret;
 }
 
-static int fs_match(char *in1, char *in2)
+static int fs_match(const char *in1, const char *in2)
 {
     char *n1;
     char *n2;
@@ -837,7 +837,7 @@
  * If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
  * in turn, and stop on 1st success, or no more match.
  */
-int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
                     char *tmp_mount_point)
 {
     int i = 0;
diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c
index 33a7496..4bfe202 100644
--- a/fs_mgr/fs_mgr_main.c
+++ b/fs_mgr/fs_mgr_main.c
@@ -14,12 +14,17 @@
  * limitations under the License.
  */
 
+#define _GNU_SOURCE
+
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <libgen.h>
 #include "fs_mgr_priv.h"
 
+#ifdef _LIBGEN_H
+#warning "libgen.h must not be included"
+#endif
+
 char *me = "";
 
 static void usage(void)
@@ -32,10 +37,10 @@
  * and exit the program, do not return to the caller.
  * Return the number of argv[] entries consumed.
  */
-static void parse_options(int argc, char *argv[], int *a_flag, int *u_flag, int *n_flag,
-                     char **n_name, char **n_blk_dev)
+static void parse_options(int argc, char * const argv[], int *a_flag, int *u_flag, int *n_flag,
+                     const char **n_name, const char **n_blk_dev)
 {
-    me = basename(strdup(argv[0]));
+    me = basename(argv[0]);
 
     if (argc <= 1) {
         usage();
@@ -75,14 +80,14 @@
     return;
 }
 
-int main(int argc, char *argv[])
+int main(int argc, char * const argv[])
 {
     int a_flag=0;
     int u_flag=0;
     int n_flag=0;
-    char *n_name=NULL;
-    char *n_blk_dev=NULL;
-    char *fstab_file=NULL;
+    const char *n_name=NULL;
+    const char *n_blk_dev=NULL;
+    const char *fstab_file=NULL;
     struct fstab *fstab=NULL;
 
     klog_set_level(6);
@@ -97,7 +102,7 @@
     if (a_flag) {
         return fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
     } else if (n_flag) {
-        return fs_mgr_do_mount(fstab, n_name, n_blk_dev, 0);
+        return fs_mgr_do_mount(fstab, n_name, (char *)n_blk_dev, 0);
     } else if (u_flag) {
         return fs_mgr_unmount_all(fstab);
     } else {
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index e7a0a1d..ef7fdd3 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -99,7 +99,7 @@
 #define FS_MGR_DOMNT_FAILED (-1)
 #define FS_MGR_DOMNT_BUSY (-2)
 
-int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
                     char *tmp_mount_point);
 int fs_mgr_do_tmpfs_mount(char *n_name);
 int fs_mgr_unmount_all(struct fstab *fstab);
diff --git a/init/init.cpp b/init/init.cpp
index ddc707f..1ce3c35 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -835,7 +835,12 @@
     parser.AddSectionParser("service",std::make_unique<ServiceParser>());
     parser.AddSectionParser("on", std::make_unique<ActionParser>());
     parser.AddSectionParser("import", std::make_unique<ImportParser>());
-    parser.ParseConfig("/init.rc");
+    std::string bootscript = property_get("ro.boot.init_rc");
+    if (bootscript.empty()) {
+        parser.ParseConfig("/init.rc");
+    } else {
+        parser.ParseConfig(bootscript);
+    }
 
     ActionManager& am = ActionManager::GetInstance();
 
diff --git a/init/seccomp.cpp b/init/seccomp.cpp
index d9f2f79..d632302 100644
--- a/init/seccomp.cpp
+++ b/init/seccomp.cpp
@@ -170,6 +170,12 @@
     // Needed for trusty
     AllowSyscall(f, __NR_syncfs);
 
+    // Needed for strace
+    AllowSyscall(f, __NR_tkill);  // __NR_tkill
+
+    // Needed for kernel to restart syscalls
+    AllowSyscall(f, __NR_restart_syscall);
+
      // arm64-only filter - autogenerated from bionic syscall usage
     for (size_t i = 0; i < arm64_filter_size; ++i)
         f.push_back(arm64_filter[i]);
@@ -201,6 +207,12 @@
     // Syscalls needed to run GFXBenchmark
     AllowSyscall(f, 190); // __NR_vfork
 
+    // Needed for strace
+    AllowSyscall(f, 238);  // __NR_tkill
+
+    // Needed for kernel to restart syscalls
+    AllowSyscall(f, 0);  // __NR_restart_syscall
+
     // arm32-on-arm64 only filter - autogenerated from bionic syscall usage
     for (size_t i = 0; i < arm_filter_size; ++i)
         f.push_back(arm_filter[i]);
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index c204a16..d9935c3 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -581,24 +581,36 @@
 
 } /* namespace android */
 
+void reportErrorName(const char **current,
+                     const char* name,
+                     bool blockSecurity) {
+    if (*current) {
+       return;
+    }
+    if (blockSecurity && (android_name_to_log_id(name) == LOG_ID_SECURITY)) {
+       return;
+    }
+    *current = name;
+}
 
 int main(int argc, char **argv)
 {
     using namespace android;
     int err;
     int hasSetLogFormat = 0;
-    int clearLog = 0;
-    int getLogSize = 0;
+    bool clearLog = false;
+    bool allSelected = false;
+    bool getLogSize = false;
+    bool getPruneList = false;
+    bool printStatistics = false;
+    bool printDividers = false;
     unsigned long setLogSize = 0;
-    int getPruneList = 0;
     char *setPruneList = NULL;
     char *setId = NULL;
-    int printStatistics = 0;
     int mode = ANDROID_LOG_RDONLY;
     const char *forceFilters = NULL;
     log_device_t* devices = NULL;
     log_device_t* dev;
-    bool printDividers = false;
     struct logger_list *logger_list;
     size_t tail_lines = 0;
     log_time tail_time(log_time::EPOCH);
@@ -710,7 +722,7 @@
             break;
 
             case 'c':
-                clearLog = 1;
+                clearLog = true;
                 mode |= ANDROID_LOG_WRONLY;
             break;
 
@@ -771,7 +783,7 @@
 
             case 'g':
                 if (!optarg) {
-                    getLogSize = 1;
+                    getLogSize = true;
                     break;
                 }
                 // FALLTHRU
@@ -813,7 +825,7 @@
 
             case 'p':
                 if (!optarg) {
-                    getPruneList = 1;
+                    getPruneList = true;
                     break;
                 }
                 // FALLTHRU
@@ -830,6 +842,7 @@
                                   (1 << LOG_ID_SYSTEM) |
                                   (1 << LOG_ID_CRASH);
                     } else if (strcmp(optarg, "all") == 0) {
+                        allSelected = true;
                         idMask = (unsigned)-1;
                     } else {
                         log_id_t log_id = android_name_to_log_id(optarg);
@@ -839,6 +852,7 @@
                             logcat_panic(HELP_TRUE,
                                          "unknown buffer %s\n", optarg);
                         }
+                        if (log_id == LOG_ID_SECURITY) allSelected = false;
                         idMask |= (1 << log_id);
                     }
                     optarg = NULL;
@@ -992,7 +1006,7 @@
                 break;
 
             case 'S':
-                printStatistics = 1;
+                printStatistics = true;
                 break;
 
             case ':':
@@ -1114,7 +1128,7 @@
         dev->logger = android_logger_open(logger_list,
                                           android_name_to_log_id(dev->device));
         if (!dev->logger) {
-            openDeviceFail = openDeviceFail ?: dev->device;
+            reportErrorName(&openDeviceFail, dev->device, allSelected);
             dev = dev->next;
             continue;
         }
@@ -1136,7 +1150,7 @@
 
                     if (file.length() == 0) {
                         perror("while clearing log files");
-                        clearFail = clearFail ?: dev->device;
+                        reportErrorName(&clearFail, dev->device, allSelected);
                         break;
                     }
 
@@ -1144,17 +1158,17 @@
 
                     if (err < 0 && errno != ENOENT && clearFail == NULL) {
                         perror("while clearing log files");
-                        clearFail = dev->device;
+                        reportErrorName(&clearFail, dev->device, allSelected);
                     }
                 }
             } else if (android_logger_clear(dev->logger)) {
-                clearFail = clearFail ?: dev->device;
+                reportErrorName(&clearFail, dev->device, allSelected);
             }
         }
 
         if (setLogSize) {
             if (android_logger_set_log_size(dev->logger, setLogSize)) {
-                setSizeFail = setSizeFail ?: dev->device;
+                reportErrorName(&setSizeFail, dev->device, allSelected);
             }
         }
 
@@ -1163,7 +1177,7 @@
             long readable = android_logger_get_log_readable_size(dev->logger);
 
             if ((size < 0) || (readable < 0)) {
-                getSizeFail = getSizeFail ?: dev->device;
+                reportErrorName(&getSizeFail, dev->device, allSelected);
             } else {
                 printf("%s: ring buffer is %ld%sb (%ld%sb consumed), "
                        "max entry is %db, max payload is %db\n", dev->device,
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index 99c2e0a..cb8b061 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -55,6 +55,6 @@
 LOCAL_MODULE := $(test_module_prefix)unit-tests
 LOCAL_MODULE_TAGS := $(test_tags)
 LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libbase
 LOCAL_SRC_FILES := $(test_src_files)
 include $(BUILD_NATIVE_TEST)
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 725d76e..337861e 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -23,10 +23,12 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <unistd.h>
 
 #include <memory>
 #include <string>
 
+#include <android-base/file.h>
 #include <gtest/gtest.h>
 #include <log/log.h>
 #include <log/log_event_list.h>
@@ -53,6 +55,11 @@
 TEST(logcat, buckets) {
     FILE *fp;
 
+#undef LOG_TAG
+#define LOG_TAG "inject"
+    RLOGE("logcat.buckets");
+    sleep(1);
+
     ASSERT_TRUE(NULL != (fp = popen(
       "logcat -b radio -b events -b system -b main -d 2>/dev/null",
       "r")));
@@ -164,13 +171,39 @@
         if (!ep) {
             continue;
         }
-        ep -= 7;
+        static const size_t tag_field_width = 7;
+        ep -= tag_field_width;
         *ep = '\0';
         return cp;
     }
     return NULL;
 }
 
+// If there is not enough background noise in the logs, then spam the logs to
+// permit tail checking so that the tests can progress.
+static size_t inject(ssize_t count) {
+    if (count <= 0) return 0;
+
+    static const size_t retry = 3;
+    size_t errors = retry;
+    size_t num = 0;
+    for(;;) {
+        log_time ts(CLOCK_MONOTONIC);
+        if (__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) >= 0) {
+            if (++num >= (size_t)count) {
+                sleep(1); // let data settle end-to-end
+                return num;
+            }
+            errors = retry;
+            usleep(50);
+        } else if (--errors <= 0) {
+            return num;
+        }
+    }
+    // NOTREACH
+    return num;
+}
+
 TEST(logcat, tz) {
 
     if (android_log_clockid() == CLOCK_MONOTONIC) {
@@ -200,7 +233,7 @@
 
         pclose(fp);
 
-    } while ((count < 3) && --tries && (sleep(1), true));
+    } while ((count < 3) && --tries && inject(3 - count));
 
     ASSERT_EQ(3, count);
 }
@@ -235,8 +268,7 @@
         char buffer[BIG_BUFFER];
 
         snprintf(buffer, sizeof(buffer),
-          "logcat -v long -b radio -b events -b system -b main -t %d 2>/dev/null",
-          num);
+                 "logcat -v long -b all -t %d 2>/dev/null", num);
 
         FILE *fp;
         ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
@@ -249,7 +281,7 @@
 
         pclose(fp);
 
-    } while ((count < num) && --tries && (sleep(1), true));
+    } while ((count < num) && --tries && inject(num - count));
 
     ASSERT_EQ(num, count);
 }
@@ -272,26 +304,34 @@
 
 TEST(logcat, tail_time) {
     FILE *fp;
-
-    ASSERT_TRUE(NULL != (fp = popen("logcat -v long -b all -t 10 2>&1", "r")));
-
+    int count;
     char buffer[BIG_BUFFER];
     char *last_timestamp = NULL;
     char *first_timestamp = NULL;
-    int count = 0;
-
     char *cp;
-    while ((cp = fgetLongTime(buffer, sizeof(buffer), fp))) {
-        ++count;
-        if (!first_timestamp) {
-            first_timestamp = strdup(cp);
-        }
-        free(last_timestamp);
-        last_timestamp = strdup(cp);
-    }
-    pclose(fp);
 
-    EXPECT_EQ(10, count);
+    int tries = 3; // in case run too soon after system start or buffer clear
+
+    // Do not be tempted to use -v usec because that increases the
+    // chances of an occasional test failure by 1000 (see below).
+    do {
+        ASSERT_TRUE(NULL != (fp = popen("logcat -v long -b all -t 10 2>&1", "r")));
+
+        count = 0;
+
+        while ((cp = fgetLongTime(buffer, sizeof(buffer), fp))) {
+            ++count;
+            if (!first_timestamp) {
+                first_timestamp = strdup(cp);
+            }
+            free(last_timestamp);
+            last_timestamp = strdup(cp);
+        }
+        pclose(fp);
+
+    } while ((count < 10) && --tries && inject(10 - count));
+
+    EXPECT_EQ(10, count); // We want _some_ history, too small, falses below
     EXPECT_TRUE(last_timestamp != NULL);
     EXPECT_TRUE(first_timestamp != NULL);
 
@@ -1412,3 +1452,22 @@
         EXPECT_TRUE(End_to_End(sync.tagStr, ""));
     }
 }
+
+static bool reportedSecurity(const char* command) {
+    FILE* fp = popen(command, "r");
+    if (!fp) return true;
+
+    std::string ret;
+    bool val = android::base::ReadFdToString(fileno(fp), &ret);
+    pclose(fp);
+
+    if (!val) return true;
+    return std::string::npos != ret.find("'security'");
+}
+
+TEST(logcat, security) {
+    EXPECT_FALSE(reportedSecurity("logcat -b all -g 2>&1"));
+    EXPECT_TRUE(reportedSecurity("logcat -b security -g 2>&1"));
+    EXPECT_TRUE(reportedSecurity("logcat -b security -c 2>&1"));
+    EXPECT_TRUE(reportedSecurity("logcat -b security -G 256K 2>&1"));
+}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 8d974fa..d6ae6f0 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -359,9 +359,6 @@
     start vold
     installkey /data
 
-    # start tombstoned to record early-boot crashes.
-    start tombstoned
-
     # Start bootcharting as soon as possible after the data partition is
     # mounted to collect more data.
     mkdir /data/bootchart 0755 shell shell