Merge "Enable seccomp in init with generated policy"
diff --git a/Android.bp b/Android.bp
index b44c296..c6f6251 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1 +1,6 @@
+filegroup {
+    name: "android_filesystem_config_header",
+    srcs: ["include/private/android_filesystem_config.h"],
+}
+
 subdirs = ["*"]
diff --git a/adb/Android.mk b/adb/Android.mk
index fab8c87..2f5a2ee 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -336,13 +336,13 @@
     libfec_rs \
     libselinux \
     liblog \
-    libext4_utils_static \
+    libext4_utils \
     libsquashfs_utils \
     libcutils \
     libbase \
     libcrypto_utils \
     libcrypto \
     libminijail \
-    libdebuggerd_client \
+    libdebuggerd_handler \
 
 include $(BUILD_EXECUTABLE)
diff --git a/adb/adb.h b/adb/adb.h
index 19f09a3..7db3b15 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -218,8 +218,6 @@
 #define CHUNK_SIZE (64*1024)
 
 #if !ADB_HOST
-#define USB_ADB_PATH     "/dev/android_adb"
-
 #define USB_FFS_ADB_PATH  "/dev/usb-ffs/adb/"
 #define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH#x
 
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index a064de2..2befa0c 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -91,9 +91,9 @@
         "global options:\n"
         " -a         listen on all network interfaces, not just localhost\n"
         " -d         use USB device (error if multiple devices connected)\n"
-        " -e         use emulator (error if multiple emulators running)\n"
+        " -e         use TCP/IP device (error if multiple TCP/IP devices available)\n"
         " -s SERIAL\n"
-        "     use device/emulator with given serial number (overrides $ANDROID_SERIAL)\n"
+        "     use device with given serial number (overrides $ANDROID_SERIAL)\n"
         " -p PRODUCT\n"
         "     name or path ('angler'/'out/target/product/angler');\n"
         "     default $ANDROID_PRODUCT_OUT\n"
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 78434a0..6382b67 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -34,9 +34,9 @@
 #include <libminijail.h>
 #include <scoped_minijail.h>
 
-#include "debuggerd/client.h"
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
+#include "debuggerd/handler.h"
 #include "selinux/android.h"
 
 #include "adb.h"
@@ -170,7 +170,7 @@
     drop_privileges(server_port);
 
     bool is_usb = false;
-    if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) {
+    if (access(USB_FFS_ADB_EP0, F_OK) == 0) {
         // Listen on USB.
         usb_init();
         is_usb = true;
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index 1cc7f68..a21a193 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -74,9 +74,6 @@
     void (*kick)(usb_handle *h);
     void (*close)(usb_handle *h);
 
-    // Legacy f_adb
-    int fd = -1;
-
     // FunctionFS
     int control = -1;
     int bulk_out = -1; /* "out" from the host's perspective => source for adbd */
@@ -248,141 +245,7 @@
     },
 };
 
-static void usb_adb_open_thread(void* x) {
-    struct usb_handle *usb = (struct usb_handle *)x;
-    int fd;
-
-    adb_thread_setname("usb open");
-
-    while (true) {
-        // wait until the USB device needs opening
-        std::unique_lock<std::mutex> lock(usb->lock);
-        while (!usb->open_new_connection) {
-            usb->notify.wait(lock);
-        }
-        usb->open_new_connection = false;
-        lock.unlock();
-
-        D("[ usb_thread - opening device ]");
-        do {
-            /* XXX use inotify? */
-            fd = unix_open("/dev/android_adb", O_RDWR);
-            if (fd < 0) {
-                // to support older kernels
-                fd = unix_open("/dev/android", O_RDWR);
-            }
-            if (fd < 0) {
-                std::this_thread::sleep_for(1s);
-            }
-        } while (fd < 0);
-        D("[ opening device succeeded ]");
-
-        close_on_exec(fd);
-        usb->fd = fd;
-
-        D("[ usb_thread - registering device ]");
-        register_usb_transport(usb, 0, 0, 1);
-    }
-
-    // never gets here
-    abort();
-}
-
-static int usb_adb_write(usb_handle *h, const void *data, int len)
-{
-    int n;
-
-    D("about to write (fd=%d, len=%d)", h->fd, len);
-    n = unix_write(h->fd, data, len);
-    if(n != len) {
-        D("ERROR: fd = %d, n = %d, errno = %d (%s)",
-            h->fd, n, errno, strerror(errno));
-        return -1;
-    }
-    if (h->kicked) {
-        D("usb_adb_write finished due to kicked");
-        return -1;
-    }
-    D("[ done fd=%d ]", h->fd);
-    return 0;
-}
-
-static int usb_adb_read(usb_handle *h, void *data, int len)
-{
-    D("about to read (fd=%d, len=%d)", h->fd, len);
-    while (len > 0) {
-        // The kernel implementation of adb_read in f_adb.c doesn't support
-        // reads larger then 4096 bytes. Read the data in 4096 byte chunks to
-        // avoid the issue. (The ffs implementation doesn't have this limit.)
-        int bytes_to_read = len < 4096 ? len : 4096;
-        int n = unix_read(h->fd, data, bytes_to_read);
-        if (n != bytes_to_read) {
-            D("ERROR: fd = %d, n = %d, errno = %d (%s)",
-                h->fd, n, errno, strerror(errno));
-            return -1;
-        }
-        if (h->kicked) {
-            D("usb_adb_read finished due to kicked");
-            return -1;
-        }
-        len -= n;
-        data = ((char*)data) + n;
-    }
-    D("[ done fd=%d ]", h->fd);
-    return 0;
-}
-
-static void usb_adb_kick(usb_handle *h) {
-    D("usb_kick");
-    // Other threads may be calling usb_adb_read/usb_adb_write at the same time.
-    // If we close h->fd, the file descriptor will be reused to open other files,
-    // and the read/write thread may operate on the wrong file. So instead
-    // we set the kicked flag and reopen h->fd to a dummy file here. After read/write
-    // threads finish, we close h->fd in usb_adb_close().
-    h->kicked = true;
-    TEMP_FAILURE_RETRY(dup2(dummy_fd, h->fd));
-}
-
-static void usb_adb_close(usb_handle *h) {
-    h->kicked = false;
-    adb_close(h->fd);
-    // Notify usb_adb_open_thread to open a new connection.
-    h->lock.lock();
-    h->open_new_connection = true;
-    h->lock.unlock();
-    h->notify.notify_one();
-}
-
-static void usb_adb_init()
-{
-    usb_handle* h = new usb_handle();
-
-    h->write = usb_adb_write;
-    h->read = usb_adb_read;
-    h->kick = usb_adb_kick;
-    h->close = usb_adb_close;
-
-    // Open the file /dev/android_adb_enable to trigger
-    // the enabling of the adb USB function in the kernel.
-    // We never touch this file again - just leave it open
-    // indefinitely so the kernel will know when we are running
-    // and when we are not.
-    int fd = unix_open("/dev/android_adb_enable", O_RDWR);
-    if (fd < 0) {
-       D("failed to open /dev/android_adb_enable");
-    } else {
-        close_on_exec(fd);
-    }
-
-    D("[ usb_init - starting thread ]");
-    if (!adb_thread_create(usb_adb_open_thread, h)) {
-        fatal_errno("cannot create usb thread");
-    }
-}
-
-
-static bool init_functionfs(struct usb_handle *h)
-{
+static bool init_functionfs(struct usb_handle* h) {
     ssize_t ret;
     struct desc_v1 v1_descriptor;
     struct desc_v2 v2_descriptor;
@@ -463,7 +326,7 @@
 }
 
 static void usb_ffs_open_thread(void* x) {
-    struct usb_handle *usb = (struct usb_handle *)x;
+    struct usb_handle* usb = (struct usb_handle*)x;
 
     adb_thread_setname("usb ffs open");
 
@@ -530,8 +393,7 @@
     return 0;
 }
 
-static void usb_ffs_kick(usb_handle *h)
-{
+static void usb_ffs_kick(usb_handle* h) {
     int err;
 
     err = ioctl(h->bulk_in, FUNCTIONFS_CLEAR_HALT);
@@ -553,7 +415,7 @@
     TEMP_FAILURE_RETRY(dup2(dummy_fd, h->bulk_in));
 }
 
-static void usb_ffs_close(usb_handle *h) {
+static void usb_ffs_close(usb_handle* h) {
     h->kicked = false;
     adb_close(h->bulk_out);
     adb_close(h->bulk_in);
@@ -564,8 +426,7 @@
     h->notify.notify_one();
 }
 
-static void usb_ffs_init()
-{
+static void usb_ffs_init() {
     D("[ usb_init - using FunctionFS ]");
 
     usb_handle* h = new usb_handle();
@@ -581,33 +442,25 @@
     }
 }
 
-void usb_init()
-{
+void usb_init() {
     dummy_fd = adb_open("/dev/null", O_WRONLY);
     CHECK_NE(dummy_fd, -1);
-    if (access(USB_FFS_ADB_EP0, F_OK) == 0)
-        usb_ffs_init();
-    else
-        usb_adb_init();
+    usb_ffs_init();
 }
 
-int usb_write(usb_handle *h, const void *data, int len)
-{
+int usb_write(usb_handle* h, const void* data, int len) {
     return h->write(h, data, len);
 }
 
-int usb_read(usb_handle *h, void *data, int len)
-{
+int usb_read(usb_handle* h, void* data, int len) {
     return h->read(h, data, len);
 }
 
-int usb_close(usb_handle *h)
-{
+int usb_close(usb_handle* h) {
     h->close(h);
     return 0;
 }
 
-void usb_kick(usb_handle *h)
-{
+void usb_kick(usb_handle* h) {
     h->kick(h);
 }
diff --git a/adf/libadfhwc/adfhwc.cpp b/adf/libadfhwc/adfhwc.cpp
index 7d5b555..a97862a 100644
--- a/adf/libadfhwc/adfhwc.cpp
+++ b/adf/libadfhwc/adfhwc.cpp
@@ -20,7 +20,7 @@
 #include <pthread.h>
 #include <sys/resource.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <utils/Vector.h>
 
 #include <adf/adf.h>
diff --git a/base/file_test.cpp b/base/file_test.cpp
index f741d89..ed39ce9 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -134,7 +134,11 @@
   // Linux doesn't allow empty symbolic links.
   std::string min("x");
   // ext2 and ext4 both have PAGE_SIZE limits.
-  std::string max(static_cast<size_t>(4096 - 1), 'x');
+  // If file encryption is enabled, there's extra overhead to store the
+  // size of the encrypted symlink target. There's also an off-by-one
+  // in current kernels (and marlin/sailfish where we're seeing this
+  // failure are still on 3.18, far from current). http://b/33306057.
+  std::string max(static_cast<size_t>(4096 - 2 - 1 - 1), 'x');
 
   TemporaryDir td;
   std::string min_path{std::string(td.path) + "/" + "min"};
diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h
index b8a9289..f5f5c11 100644
--- a/base/include/android-base/strings.h
+++ b/base/include/android-base/strings.h
@@ -64,6 +64,9 @@
 bool EndsWith(const std::string& s, const char* suffix);
 bool EndsWithIgnoreCase(const std::string& s, const char* suffix);
 
+// Tests whether 'lhs' equals 'rhs', ignoring case.
+bool EqualsIgnoreCase(const std::string& lhs, const std::string& rhs);
+
 }  // namespace base
 }  // namespace android
 
diff --git a/base/strings.cpp b/base/strings.cpp
index 7a94ad7..46fe939 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -112,5 +112,9 @@
   return EndsWith(s, suffix, false);
 }
 
+bool EqualsIgnoreCase(const std::string& lhs, const std::string& rhs) {
+  return strcasecmp(lhs.c_str(), rhs.c_str()) == 0;
+}
+
 }  // namespace base
 }  // namespace android
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 5fb21dd..7a65a00 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -244,3 +244,10 @@
   ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "OBA"));
   ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "FOO"));
 }
+
+TEST(strings, EqualsIgnoreCase) {
+  ASSERT_TRUE(android::base::EqualsIgnoreCase("foo", "FOO"));
+  ASSERT_TRUE(android::base::EqualsIgnoreCase("FOO", "foo"));
+  ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "bar"));
+  ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "fool"));
+}
diff --git a/bootstat/bootstat.rc b/bootstat/bootstat.rc
index c96e996..ca8bea2 100644
--- a/bootstat/bootstat.rc
+++ b/bootstat/bootstat.rc
@@ -11,8 +11,26 @@
 on post-fs-data && property:init.svc.bootanim=running
     exec - root root -- /system/bin/bootstat -r post_decrypt_time_elapsed
 
+# sys.logbootcomplete is a signal to enable the bootstat logging mechanism.
+# This signaling is necessary to prevent logging boot metrics after a soft
+# reboot (e.g., adb shell stop && adb shell start).  /proc/uptime is not reset
+# during a soft reboot, which leads to false boot time metrics being reported.
+#
+# The 'on boot' event occurs once per hard boot (device power on), which
+# switches the flag on. If the device performs a soft reboot, the flag is
+# switched off and cannot be switched on until the device hard boots again.
+
+# Enable bootstat logging on boot.
+on boot
+    setprop sys.logbootcomplete 1
+
+# Disable further bootstat logging on a soft reboot. A soft reboot is
+# signaled by the zygote stopping.
+on property:init.svc.zygote=stopping
+    setprop sys.logbootcomplete 0
+
 # Record boot complete metrics.
-on property:sys.boot_completed=1
+on property:sys.boot_completed=1 && property:sys.logbootcomplete=1
     # Record boot_complete and related stats (decryption, etc).
     exec - root root -- /system/bin/bootstat --record_boot_complete
 
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index f0131b8..6dc6675 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -1,25 +1,197 @@
+cc_defaults {
+    name: "debuggerd_defaults",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Wno-error",
+        "-Wno-nullability-completeness",
+        "-Os",
+    ],
+
+    local_include_dirs: ["include"],
+}
+
 cc_library_static {
-  name: "libdebuggerd_client",
-  srcs: ["client/debuggerd_client.cpp"],
+    name: "libdebuggerd_handler",
+    defaults: ["debuggerd_defaults"],
+    srcs: ["handler/debuggerd_handler.cpp"],
 
-  cflags: [
-    "-Wall",
-    "-Wextra",
-    "-Werror",
-    "-Os",
-  ],
+    // libdebuggerd_handler gets async signal safe logging via libc_logging,
+    // which defines its interface in bionic private headers.
+    include_dirs: ["bionic/libc"],
+    static_libs: ["libc_logging"],
 
-  target: {
-    android64: {
-      cflags: ["-DTARGET_IS_64_BIT"],
+    export_include_dirs: ["include"],
+}
+
+cc_library {
+    name: "libdebuggerd_client",
+    defaults: ["debuggerd_defaults"],
+    srcs: [
+        "client/debuggerd_client.cpp",
+        "util.cpp",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libcutils",
+    ],
+    export_include_dirs: ["include"],
+}
+
+cc_library {
+    name: "libdebuggerd",
+    defaults: ["debuggerd_defaults"],
+
+    srcs: [
+        "libdebuggerd/backtrace.cpp",
+        "libdebuggerd/elf_utils.cpp",
+        "libdebuggerd/open_files_list.cpp",
+        "libdebuggerd/tombstone.cpp",
+        "libdebuggerd/utility.cpp",
+    ],
+
+    target: {
+        android_arm: {
+            srcs: ["libdebuggerd/arm/machine.cpp"],
+        },
+        android_arm64: {
+            srcs: ["libdebuggerd/arm64/machine.cpp"],
+        },
+        android_mips: {
+            srcs: ["libdebuggerd/mips/machine.cpp"],
+        },
+        android_mips64: {
+            srcs: ["libdebuggerd/mips64/machine.cpp"],
+        },
+        android_x86: {
+            srcs: ["libdebuggerd/x86/machine.cpp"],
+        },
+        android_x86_64: {
+            srcs: ["libdebuggerd/x86_64/machine.cpp"],
+        },
     },
-  },
 
-  local_include_dirs: ["include"],
-  export_include_dirs: ["include"],
+    local_include_dirs: ["libdebuggerd/include"],
+    export_include_dirs: ["libdebuggerd/include"],
 
-  // libdebuggerd_client gets async signal safe logging via libc_logging,
-  // which defines its interface in bionic private headers.
-  include_dirs: ["bionic/libc"],
-  static_libs: ["libc_logging"],
+    shared_libs: [
+        "libbacktrace",
+        "libbase",
+        "libcutils",
+        "liblog",
+    ],
+}
+
+cc_test {
+    name: "debuggerd_test",
+    defaults: ["debuggerd_defaults"],
+
+    cflags: ["-Wno-missing-field-initializers"],
+    srcs: [
+        "libdebuggerd/test/dump_memory_test.cpp",
+        "libdebuggerd/test/elf_fake.cpp",
+        "libdebuggerd/test/log_fake.cpp",
+        "libdebuggerd/test/open_files_list_test.cpp",
+        "libdebuggerd/test/property_fake.cpp",
+        "libdebuggerd/test/ptrace_fake.cpp",
+        "libdebuggerd/test/tombstone_test.cpp",
+    ],
+
+    target: {
+        android: {
+            srcs: [
+                "debuggerd_test.cpp",
+                "util.cpp"
+            ],
+        },
+    },
+
+    shared_libs: [
+        "libbacktrace",
+        "libbase",
+        "libcutils",
+    ],
+
+    static_libs: [
+        "libdebuggerd"
+    ],
+
+    local_include_dirs: [
+        "libdebuggerd",
+    ],
+
+    compile_multilib: "both",
+    multilib: {
+        lib32: {
+            stem: "debuggerd_test32",
+        },
+        lib64: {
+            stem: "debuggerd_test64",
+        },
+    },
+}
+
+cc_binary {
+    name: "crash_dump",
+    srcs: [
+        "crash_dump.cpp",
+        "util.cpp",
+    ],
+    defaults: ["debuggerd_defaults"],
+
+    compile_multilib: "both",
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+
+    shared_libs: [
+        "libbacktrace",
+        "libbase",
+        "libdebuggerd",
+        "liblog",
+        "libprocinfo",
+        "libselinux",
+    ],
+}
+
+cc_binary {
+    name: "debuggerd",
+    srcs: [
+        "debuggerd.cpp",
+    ],
+    defaults: ["debuggerd_defaults"],
+
+    shared_libs: [
+        "libbase",
+        "libdebuggerd_client",
+        "liblog",
+        "libselinux",
+    ],
+
+    local_include_dirs: ["include"],
+}
+
+cc_binary {
+    name: "tombstoned",
+    srcs: [
+        "util.cpp",
+        "tombstoned/intercept_manager.cpp",
+        "tombstoned/tombstoned.cpp",
+    ],
+    defaults: ["debuggerd_defaults"],
+
+    static_libs: [
+        "libbase",
+        "libcutils",
+        "libevent",
+        "liblog",
+    ],
+
+    init_rc: ["tombstoned/tombstoned.rc"]
 }
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
deleted file mode 100644
index e3bdd43..0000000
--- a/debuggerd/Android.mk
+++ /dev/null
@@ -1,167 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-common_cppflags := \
-    -W \
-    -Wall \
-    -Wextra \
-    -Wunused \
-    -Werror \
-
-ifeq ($(TARGET_IS_64_BIT),true)
-common_cppflags += -DTARGET_IS_64_BIT
-endif
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    backtrace.cpp \
-    debuggerd.cpp \
-    elf_utils.cpp \
-    getevent.cpp \
-    open_files_list.cpp \
-    signal_sender.cpp \
-    tombstone.cpp \
-    utility.cpp \
-
-LOCAL_SRC_FILES_arm    := arm/machine.cpp
-LOCAL_SRC_FILES_arm64  := arm64/machine.cpp
-LOCAL_SRC_FILES_mips   := mips/machine.cpp
-LOCAL_SRC_FILES_mips64 := mips64/machine.cpp
-LOCAL_SRC_FILES_x86    := x86/machine.cpp
-LOCAL_SRC_FILES_x86_64 := x86_64/machine.cpp
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CPPFLAGS := $(common_cppflags)
-
-LOCAL_INIT_RC_32 := debuggerd.rc
-LOCAL_INIT_RC_64 := debuggerd64.rc
-
-LOCAL_SHARED_LIBRARIES := \
-    libbacktrace \
-    libbase \
-    libcutils \
-    liblog \
-    libselinux \
-
-LOCAL_CLANG := true
-
-LOCAL_MODULE := debuggerd
-LOCAL_MODULE_STEM_32 := debuggerd
-LOCAL_MODULE_STEM_64 := debuggerd64
-LOCAL_MULTILIB := both
-
-include $(BUILD_EXECUTABLE)
-
-crasher_cppflags := $(common_cppflags) -O0 -fstack-protector-all -Wno-free-nonheap-object
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := crasher.cpp
-LOCAL_SRC_FILES_arm    := arm/crashglue.S
-LOCAL_SRC_FILES_arm64  := arm64/crashglue.S
-LOCAL_SRC_FILES_mips   := mips/crashglue.S
-LOCAL_SRC_FILES_mips64 := mips64/crashglue.S
-LOCAL_SRC_FILES_x86    := x86/crashglue.S
-LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
-LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := optional
-LOCAL_CPPFLAGS := $(crasher_cppflags)
-LOCAL_SHARED_LIBRARIES := libbase liblog
-
-# The arm emulator has VFP but not VFPv3-D32.
-ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
-LOCAL_ASFLAGS_arm += -DHAS_VFP_D32
-endif
-
-LOCAL_MODULE := crasher
-LOCAL_MODULE_STEM_32 := crasher
-LOCAL_MODULE_STEM_64 := crasher64
-LOCAL_MULTILIB := both
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := crasher.cpp
-LOCAL_SRC_FILES_arm    := arm/crashglue.S
-LOCAL_SRC_FILES_arm64  := arm64/crashglue.S
-LOCAL_SRC_FILES_mips   := mips/crashglue.S
-LOCAL_SRC_FILES_mips64 := mips64/crashglue.S
-LOCAL_SRC_FILES_x86    := x86/crashglue.S
-LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
-LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := optional
-LOCAL_CPPFLAGS := $(crasher_cppflags) -DSTATIC_CRASHER
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-
-# The arm emulator has VFP but not VFPv3-D32.
-ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
-LOCAL_ASFLAGS_arm += -DHAS_VFP_D32
-endif
-
-LOCAL_MODULE := static_crasher
-LOCAL_MODULE_STEM_32 := static_crasher
-LOCAL_MODULE_STEM_64 := static_crasher64
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_LIBRARIES := libdebuggerd_client libbase liblog
-
-include $(BUILD_EXECUTABLE)
-
-debuggerd_test_src_files := \
-    utility.cpp \
-    open_files_list.cpp \
-    test/dump_memory_test.cpp \
-    test/elf_fake.cpp \
-    test/log_fake.cpp \
-    test/open_files_list_test.cpp \
-    test/property_fake.cpp \
-    test/ptrace_fake.cpp \
-    test/tombstone_test.cpp \
-    test/selinux_fake.cpp \
-
-debuggerd_shared_libraries := \
-    libbacktrace \
-    libbase \
-    libcutils \
-    liblog
-
-debuggerd_c_includes := \
-    $(LOCAL_PATH)/test \
-
-debuggerd_cpp_flags := \
-    $(common_cppflags) \
-    -Wno-missing-field-initializers \
-    -fno-rtti \
-
-# Bug: http://b/29823425 Disable -Wvarargs for Clang update to r271374
-debuggerd_cpp_flags += -Wno-varargs
-
-# Only build the host tests on linux.
-ifeq ($(HOST_OS),linux)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := debuggerd_test
-LOCAL_SRC_FILES := $(debuggerd_test_src_files)
-LOCAL_SHARED_LIBRARIES := $(debuggerd_shared_libraries)
-LOCAL_C_INCLUDES := $(debuggerd_c_includes)
-LOCAL_CPPFLAGS := $(debuggerd_cpp_flags)
-
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-LOCAL_MULTILIB := both
-include $(BUILD_HOST_NATIVE_TEST)
-
-endif
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := debuggerd_test
-LOCAL_SRC_FILES := $(debuggerd_test_src_files)
-LOCAL_SHARED_LIBRARIES := $(debuggerd_shared_libraries)
-LOCAL_C_INCLUDES := $(debuggerd_c_includes)
-LOCAL_CPPFLAGS := $(debuggerd_cpp_flags)
-
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-LOCAL_MULTILIB := both
-include $(BUILD_NATIVE_TEST)
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index c67d747..81d70df 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -1,379 +1,189 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
+ * Copyright 2016, The Android Open Source Project
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
-#include "debuggerd/client.h"
+#include <debuggerd/client.h>
 
-#include <errno.h>
-#include <inttypes.h>
-#include <pthread.h>
-#include <sched.h>
+#include <fcntl.h>
 #include <signal.h>
-#include <stddef.h>
-#include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <sys/syscall.h>
-#include <sys/un.h>
-#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
-#include "private/libc_logging.h"
+#include <chrono>
 
-#if defined(TARGET_IS_64_BIT) && !defined(__LP64__)
-#define SOCKET_NAME "android:debuggerd32"
-#else
-#define SOCKET_NAME "android:debuggerd"
-#endif
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <cutils/sockets.h>
+#include <debuggerd/handler.h>
+#include <debuggerd/protocol.h>
+#include <debuggerd/util.h>
 
-// see man(2) prctl, specifically the section about PR_GET_NAME
-#define MAX_TASK_NAME_LEN (16)
+using android::base::unique_fd;
 
-static debuggerd_callbacks_t g_callbacks;
-
-// Don't use __libc_fatal because it exits via abort, which might put us back into a signal handler.
-#define fatal(...)                                             \
-  do {                                                         \
-    __libc_format_log(ANDROID_LOG_FATAL, "libc", __VA_ARGS__); \
-    _exit(1);                                                  \
-  } while (0)
-
-static int socket_abstract_client(const char* name, int type) {
-  sockaddr_un addr;
-
-  // Test with length +1 for the *initial* '\0'.
-  size_t namelen = strlen(name);
-  if ((namelen + 1) > sizeof(addr.sun_path)) {
-    errno = EINVAL;
-    return -1;
-  }
-
-  // This is used for abstract socket namespace, we need
-  // an initial '\0' at the start of the Unix socket path.
-  //
-  // Note: The path in this case is *not* supposed to be
-  // '\0'-terminated. ("man 7 unix" for the gory details.)
-  memset(&addr, 0, sizeof(addr));
-  addr.sun_family = AF_LOCAL;
-  addr.sun_path[0] = 0;
-  memcpy(addr.sun_path + 1, name, namelen);
-
-  socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
-
-  int s = socket(AF_LOCAL, type, 0);
-  if (s == -1) {
-    return -1;
-  }
-
-  int rc = TEMP_FAILURE_RETRY(connect(s, reinterpret_cast<sockaddr*>(&addr), alen));
-  if (rc == -1) {
-    close(s);
-    return -1;
-  }
-
-  return s;
-}
-
-/*
- * Writes a summary of the signal to the log file.  We do this so that, if
- * for some reason we're not able to contact debuggerd, there is still some
- * indication of the failure in the log.
- *
- * We could be here as a result of native heap corruption, or while a
- * mutex is being held, so we don't want to use any libc functions that
- * could allocate memory or hold a lock.
- */
-static void log_signal_summary(int signum, const siginfo_t* info) {
-  const char* signal_name = "???";
-  bool has_address = false;
-  switch (signum) {
-    case SIGABRT:
-      signal_name = "SIGABRT";
-      break;
-    case SIGBUS:
-      signal_name = "SIGBUS";
-      has_address = true;
-      break;
-    case SIGFPE:
-      signal_name = "SIGFPE";
-      has_address = true;
-      break;
-    case SIGILL:
-      signal_name = "SIGILL";
-      has_address = true;
-      break;
-    case SIGSEGV:
-      signal_name = "SIGSEGV";
-      has_address = true;
-      break;
-#if defined(SIGSTKFLT)
-    case SIGSTKFLT:
-      signal_name = "SIGSTKFLT";
-      break;
-#endif
-    case SIGSYS:
-      signal_name = "SIGSYS";
-      break;
-    case SIGTRAP:
-      signal_name = "SIGTRAP";
-      break;
-  }
-
-  char thread_name[MAX_TASK_NAME_LEN + 1];  // one more for termination
-  if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) {
-    strcpy(thread_name, "<name unknown>");
-  } else {
-    // short names are null terminated by prctl, but the man page
-    // implies that 16 byte names are not.
-    thread_name[MAX_TASK_NAME_LEN] = 0;
-  }
-
-  // "info" will be null if the siginfo_t information was not available.
-  // Many signals don't have an address or a code.
-  char code_desc[32];  // ", code -6"
-  char addr_desc[32];  // ", fault addr 0x1234"
-  addr_desc[0] = code_desc[0] = 0;
-  if (info != nullptr) {
-    // For a rethrown signal, this si_code will be right and the one debuggerd shows will
-    // always be SI_TKILL.
-    __libc_format_buffer(code_desc, sizeof(code_desc), ", code %d", info->si_code);
-    if (has_address) {
-      __libc_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
-    }
-  }
-  __libc_format_log(ANDROID_LOG_FATAL, "libc", "Fatal signal %d (%s)%s%s in tid %d (%s)", signum,
-                    signal_name, code_desc, addr_desc, gettid(), thread_name);
-}
-
-/*
- * Returns true if the handler for signal "signum" has SA_SIGINFO set.
- */
-static bool have_siginfo(int signum) {
-  struct sigaction old_action, new_action;
-
-  memset(&new_action, 0, sizeof(new_action));
-  new_action.sa_handler = SIG_DFL;
-  new_action.sa_flags = SA_RESTART;
-  sigemptyset(&new_action.sa_mask);
-
-  if (sigaction(signum, &new_action, &old_action) < 0) {
-    __libc_format_log(ANDROID_LOG_WARN, "libc", "Failed testing for SA_SIGINFO: %s",
-                      strerror(errno));
+static bool send_signal(pid_t pid, bool backtrace) {
+  sigval val;
+  val.sival_int = backtrace;
+  if (sigqueue(pid, DEBUGGER_SIGNAL, val) != 0) {
+    PLOG(ERROR) << "libdebuggerd_client: failed to send signal to pid " << pid;
     return false;
   }
-  bool result = (old_action.sa_flags & SA_SIGINFO) != 0;
-
-  if (sigaction(signum, &old_action, nullptr) == -1) {
-    __libc_format_log(ANDROID_LOG_WARN, "libc", "Restore failed in test for SA_SIGINFO: %s",
-                      strerror(errno));
-  }
-  return result;
+  return true;
 }
 
-static void send_debuggerd_packet(pid_t crashing_tid, pid_t pseudothread_tid) {
-  // 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_trylock(&crash_mutex);
-  if (ret != 0) {
-    if (ret == EBUSY) {
-      __libc_format_log(ANDROID_LOG_INFO, "libc",
-                        "Another thread contacted debuggerd first; not contacting debuggerd.");
-      // This will never complete since the lock is never released.
-      pthread_mutex_lock(&crash_mutex);
-    } else {
-      __libc_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_trylock failed: %s", strerror(ret));
+static bool check_dumpable(pid_t pid) {
+  // /proc/<pid> is owned by the effective UID of the process.
+  // Ownership of most of the other files in /proc/<pid> varies based on PR_SET_DUMPABLE.
+  // If PR_GET_DUMPABLE would return 0, they're owned by root, instead.
+  std::string proc_pid_path = android::base::StringPrintf("/proc/%d/", pid);
+  std::string proc_pid_status_path = proc_pid_path + "/status";
+
+  unique_fd proc_pid_fd(open(proc_pid_path.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC));
+  if (proc_pid_fd == -1) {
+    return false;
+  }
+  unique_fd proc_pid_status_fd(openat(proc_pid_fd, "status", O_RDONLY | O_CLOEXEC));
+  if (proc_pid_status_fd == -1) {
+    return false;
+  }
+
+  struct stat proc_pid_st;
+  struct stat proc_pid_status_st;
+  if (fstat(proc_pid_fd.get(), &proc_pid_st) != 0 ||
+      fstat(proc_pid_status_fd.get(), &proc_pid_status_st) != 0) {
+    return false;
+  }
+
+  // We can't figure out if a process is dumpable if its effective UID is root, but that's fine
+  // because being root bypasses the PR_SET_DUMPABLE check for ptrace.
+  if (proc_pid_st.st_uid == 0) {
+    return true;
+  }
+
+  if (proc_pid_status_st.st_uid == 0) {
+    return false;
+  }
+
+  return true;
+}
+
+bool debuggerd_trigger_dump(pid_t pid, unique_fd output_fd, DebuggerdDumpType dump_type,
+                            int timeout_ms) {
+  LOG(INFO) << "libdebuggerd_client: started dumping process " << pid;
+  unique_fd sockfd;
+  const auto end = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeout_ms);
+  auto set_timeout = [timeout_ms, &sockfd, &end]() {
+    if (timeout_ms <= 0) {
+      return true;
     }
-    return;
-  }
 
-  int s = socket_abstract_client(SOCKET_NAME, SOCK_STREAM | SOCK_CLOEXEC);
-  if (s == -1) {
-    __libc_format_log(ANDROID_LOG_FATAL, "libc", "Unable to open connection to debuggerd: %s",
-                      strerror(errno));
-    return;
-  }
-
-  // debuggerd knows our pid from the credentials on the
-  // local socket but we need to tell it the tid of the crashing thread.
-  // debuggerd will be paranoid and verify that we sent a tid
-  // that's actually in our process.
-  debugger_msg_t msg;
-  msg.action = DEBUGGER_ACTION_CRASH;
-  msg.tid = crashing_tid;
-  msg.ignore_tid = pseudothread_tid;
-  msg.abort_msg_address = 0;
-
-  if (g_callbacks.get_abort_message) {
-    msg.abort_msg_address = reinterpret_cast<uintptr_t>(g_callbacks.get_abort_message());
-  }
-
-  ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg)));
-  if (ret == sizeof(msg)) {
-    char debuggerd_ack;
-    ret = TEMP_FAILURE_RETRY(read(s, &debuggerd_ack, 1));
-    if (g_callbacks.post_dump) {
-      g_callbacks.post_dump();
+    auto now = std::chrono::steady_clock::now();
+    if (now > end) {
+      return false;
     }
-  } else {
-    // read or write failed -- broken connection?
-    __libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed while talking to debuggerd: %s",
-                      strerror(errno));
-  }
 
-  close(s);
-}
+    auto time_left = std::chrono::duration_cast<std::chrono::microseconds>(end - now);
+    auto seconds = std::chrono::duration_cast<std::chrono::seconds>(time_left);
+    auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(time_left - seconds);
+    struct timeval timeout = {
+      .tv_sec = static_cast<long>(seconds.count()),
+      .tv_usec = static_cast<long>(microseconds.count()),
+    };
 
-struct debugger_thread_info {
-  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-  pid_t crashing_tid;
-  pid_t pseudothread_tid;
-  int signal_number;
-  siginfo_t* info;
-};
+    if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) != 0) {
+      return false;
+    }
+    if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) != 0) {
+      return false;
+    }
 
-// Logging and contacting debuggerd requires free file descriptors, which we might not have.
-// Work around this by spawning a "thread" that shares its parent's address space, but not its file
-// descriptor table, so that we can close random file descriptors without affecting the original
-// process. Note that this doesn't go through pthread_create, so TLS is shared with the spawning
-// process.
-static void* pseudothread_stack;
-static int debuggerd_dispatch_pseudothread(void* arg) {
-  debugger_thread_info* thread_info = static_cast<debugger_thread_info*>(arg);
-
-  for (int i = 3; i < 1024; ++i) {
-    close(i);
-  }
-
-  log_signal_summary(thread_info->signal_number, thread_info->info);
-  send_debuggerd_packet(thread_info->crashing_tid, thread_info->pseudothread_tid);
-  pthread_mutex_unlock(&thread_info->mutex);
-  return 0;
-}
-
-/*
- * Catches fatal signals so we can ask debuggerd to ptrace us before
- * we crash.
- */
-static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) {
-  // It's possible somebody cleared the SA_SIGINFO flag, which would mean
-  // our "info" arg holds an undefined value.
-  if (!have_siginfo(signal_number)) {
-    info = nullptr;
-  }
-
-  debugger_thread_info thread_info = {
-    .crashing_tid = gettid(),
-    .signal_number = signal_number,
-    .info = info
+    return true;
   };
 
-  pthread_mutex_lock(&thread_info.mutex);
-  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));
+  if (!check_dumpable(pid)) {
+    dprintf(output_fd.get(), "target pid %d is not dumpable\n", pid);
+    return true;
   }
 
-  // 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);
-
-
-  // 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.
-  signal(signal_number, SIG_DFL);
-
-  struct siginfo si;
-  if (!info) {
-    memset(&si, 0, sizeof(si));
-    si.si_code = SI_USER;
-    si.si_pid = getpid();
-    si.si_uid = getuid();
-    info = &si;
-  } else if (info->si_code >= 0 || info->si_code == SI_TKILL) {
-    // rt_tgsigqueueinfo(2)'s documentation appears to be incorrect on kernels
-    // that contain commit 66dd34a (3.9+). The manpage claims to only allow
-    // negative si_code values that are not SI_TKILL, but 66dd34a changed the
-    // check to allow all si_code values in calls coming from inside the house.
+  sockfd.reset(socket(AF_LOCAL, SOCK_SEQPACKET, 0));
+  if (sockfd == -1) {
+    PLOG(ERROR) << "libdebugger_client: failed to create socket";
+    return false;
   }
 
-  int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), gettid(), signal_number, info);
-  if (rc != 0) {
-    fatal("failed to resend signal during crash: %s", strerror(errno));
+  if (!set_timeout()) {
+    PLOG(ERROR) << "libdebugger_client: failed to set timeout";
+    return false;
   }
+
+  if (socket_local_client_connect(sockfd.get(), kTombstonedInterceptSocketName,
+                                  ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET) == -1) {
+    PLOG(ERROR) << "libdebuggerd_client: failed to connect to tombstoned";
+    return false;
+  }
+
+  InterceptRequest req = {.pid = pid };
+  if (!set_timeout()) {
+    PLOG(ERROR) << "libdebugger_client: failed to set timeout";
+  }
+
+  if (send_fd(sockfd.get(), &req, sizeof(req), std::move(output_fd)) != sizeof(req)) {
+    PLOG(ERROR) << "libdebuggerd_client: failed to send output fd to tombstoned";
+    return false;
+  }
+
+  bool backtrace = dump_type == kDebuggerdBacktrace;
+  send_signal(pid, backtrace);
+
+  if (!set_timeout()) {
+    PLOG(ERROR) << "libdebugger_client: failed to set timeout";
+  }
+
+  InterceptResponse response;
+  ssize_t rc = TEMP_FAILURE_RETRY(recv(sockfd.get(), &response, sizeof(response), MSG_TRUNC));
+  if (rc == 0) {
+    LOG(ERROR) << "libdebuggerd_client: failed to read response from tombstoned: timeout reached?";
+    return false;
+  } else if (rc != sizeof(response)) {
+    LOG(ERROR)
+      << "libdebuggerd_client: received packet of unexpected length from tombstoned: expected "
+      << sizeof(response) << ", received " << rc;
+    return false;
+  }
+
+  if (response.success != 1) {
+    response.error_message[sizeof(response.error_message) - 1] = '\0';
+    LOG(ERROR) << "libdebuggerd_client: tombstoned reported failure: " << response.error_message;
+  }
+
+  LOG(INFO) << "libdebuggerd_client: done dumping process " << pid;
+
+  return true;
 }
 
-void debuggerd_init(debuggerd_callbacks_t* callbacks) {
-  if (callbacks) {
-    g_callbacks = *callbacks;
+int dump_backtrace_to_file(pid_t tid, int fd) {
+  return dump_backtrace_to_file_timeout(tid, fd, 0);
+}
+
+int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs) {
+  android::base::unique_fd copy(dup(fd));
+  if (copy == -1) {
+    return -1;
   }
-
-  void* thread_stack_allocation =
-    mmap(nullptr, PAGE_SIZE * 3, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
-  if (thread_stack_allocation == MAP_FAILED) {
-    fatal("failed to allocate debuggerd thread stack");
-  }
-
-  char* stack = static_cast<char*>(thread_stack_allocation) + PAGE_SIZE;
-  if (mprotect(stack, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) {
-    fatal("failed to mprotect debuggerd thread stack");
-  }
-
-  // Stack grows negatively, set it to the last byte in the page...
-  stack = (stack + PAGE_SIZE - 1);
-  // and align it.
-  stack -= 15;
-  pseudothread_stack = stack;
-
-  struct sigaction action;
-  memset(&action, 0, sizeof(action));
-  sigemptyset(&action.sa_mask);
-  action.sa_sigaction = debuggerd_signal_handler;
-  action.sa_flags = SA_RESTART | SA_SIGINFO;
-
-  // 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);
+  int timeout_ms = timeout_secs > 0 ? timeout_secs * 1000 : 0;
+  return debuggerd_trigger_dump(tid, std::move(copy), kDebuggerdBacktrace, timeout_ms) ? 0 : -1;
 }
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
new file mode 100644
index 0000000..b9dfedb
--- /dev/null
+++ b/debuggerd/crash_dump.cpp
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <syscall.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <limits>
+#include <memory>
+#include <set>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <cutils/sockets.h>
+#include <log/logger.h>
+#include <procinfo/process.h>
+#include <selinux/selinux.h>
+
+#include "backtrace.h"
+#include "tombstone.h"
+#include "utility.h"
+
+#include "debuggerd/handler.h"
+#include "debuggerd/protocol.h"
+#include "debuggerd/util.h"
+
+using android::base::unique_fd;
+using android::base::StringPrintf;
+
+static bool pid_contains_tid(pid_t pid, pid_t tid) {
+  std::string task_path = StringPrintf("/proc/%d/task/%d", pid, tid);
+  return access(task_path.c_str(), F_OK) == 0;
+}
+
+// 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) {
+  if (ptrace(PTRACE_ATTACH, tid, 0, 0) != 0) {
+    return false;
+  }
+
+  // Make sure that the task we attached to is actually part of the pid we're dumping.
+  if (!pid_contains_tid(pid, tid)) {
+    if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
+      PLOG(FATAL) << "failed to detach from thread " << tid;
+    }
+    errno = ECHILD;
+    return false;
+  }
+  return true;
+}
+
+static bool activity_manager_notify(int pid, int signal, const std::string& amfd_data) {
+  android::base::unique_fd amfd(socket_local_client("/data/system/ndebugsocket", ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM));
+  if (amfd.get() == -1) {
+    PLOG(ERROR) << "unable to connect to activity manager";
+    return false;
+  }
+
+  struct timeval tv = {
+    .tv_sec = 1,
+    .tv_usec = 0,
+  };
+  if (setsockopt(amfd.get(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) {
+    PLOG(ERROR) << "failed to set send timeout on activity manager socket";
+    return false;
+  }
+  tv.tv_sec = 3;  // 3 seconds on handshake read
+  if (setsockopt(amfd.get(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
+    PLOG(ERROR) << "failed to set receive timeout on activity manager socket";
+    return false;
+  }
+
+  // Activity Manager protocol: binary 32-bit network-byte-order ints for the
+  // pid and signal number, followed by the raw text of the dump, culminating
+  // in a zero byte that marks end-of-data.
+  uint32_t datum = htonl(pid);
+  if (!android::base::WriteFully(amfd, &datum, 4)) {
+    PLOG(ERROR) << "AM pid write failed";
+    return false;
+  }
+  datum = htonl(signal);
+  if (!android::base::WriteFully(amfd, &datum, 4)) {
+    PLOG(ERROR) << "AM signal write failed";
+    return false;
+  }
+  if (!android::base::WriteFully(amfd, amfd_data.c_str(), amfd_data.size() + 1)) {
+    PLOG(ERROR) << "AM data write failed";
+    return false;
+  }
+
+  // 3 sec timeout reading the ack; we're fine if the read fails.
+  char ack;
+  android::base::ReadFully(amfd, &ack, 1);
+  return true;
+}
+
+static bool tombstoned_connect(pid_t pid, unique_fd* tombstoned_socket, unique_fd* output_fd) {
+  unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
+                                       ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
+  if (sockfd == -1) {
+    PLOG(ERROR) << "failed to connect to tombstoned";
+    return false;
+  }
+
+  TombstonedCrashPacket packet = {};
+  packet.packet_type = CrashPacketType::kDumpRequest;
+  packet.packet.dump_request.pid = pid;
+  if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
+    PLOG(ERROR) << "failed to write DumpRequest packet";
+    return false;
+  }
+
+  unique_fd tmp_output_fd;
+  ssize_t rc = recv_fd(sockfd, &packet, sizeof(packet), &tmp_output_fd);
+  if (rc == -1) {
+    PLOG(ERROR) << "failed to read response to DumpRequest packet";
+    return false;
+  } else if (rc != sizeof(packet)) {
+    LOG(ERROR) << "read DumpRequest response packet of incorrect length (expected "
+               << sizeof(packet) << ", got " << rc << ")";
+    return false;
+  }
+
+  *tombstoned_socket = std::move(sockfd);
+  *output_fd = std::move(tmp_output_fd);
+  return true;
+}
+
+static bool tombstoned_notify_completion(int tombstoned_socket) {
+  TombstonedCrashPacket packet = {};
+  packet.packet_type = CrashPacketType::kCompletedDump;
+  if (TEMP_FAILURE_RETRY(write(tombstoned_socket, &packet, sizeof(packet))) != sizeof(packet)) {
+    return false;
+  }
+  return true;
+}
+
+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) {
+    if (!tombstoned_connect(target, &tombstoned_socket, &output_fd)) {
+      // We failed to connect, not much we can do.
+      LOG(ERROR) << "failed to connected to tombstoned to report failure";
+      _exit(1);
+    }
+  }
+
+  dprintf(output_fd.get(), "crash_dump failed to dump process %d: %s\n", target, abort_msg);
+
+  // Don't dump ourselves.
+  _exit(1);
+}
+
+static void check_process(int proc_fd, pid_t expected_pid) {
+  android::procinfo::ProcessInfo proc_info;
+  if (!android::procinfo::GetProcessInfoFromProcPidFd(proc_fd, &proc_info)) {
+    LOG(FATAL) << "failed to fetch process info";
+  }
+
+  if (proc_info.pid != expected_pid) {
+    LOG(FATAL) << "pid mismatch: expected " << expected_pid << ", actual " << proc_info.ppid;
+  }
+}
+
+int main(int argc, char** argv) {
+  pid_t target = getppid();
+  bool tombstoned_connected = false;
+  unique_fd tombstoned_socket;
+  unique_fd output_fd;
+
+  android::base::InitLogging(argv);
+  android::base::SetAborter([&](const char* abort_msg) {
+    abort_handler(target, tombstoned_connected, tombstoned_socket, output_fd, abort_msg);
+  });
+
+  if (argc != 2) {
+    return 1;
+  }
+
+  pid_t main_tid;
+
+  if (target == 1) {
+    LOG(FATAL) << "target died before we could attach";
+  }
+
+  if (!android::base::ParseInt(argv[1], &main_tid, 1, std::numeric_limits<pid_t>::max())) {
+    LOG(FATAL) << "invalid main tid: " << argv[1];
+  }
+
+  android::procinfo::ProcessInfo target_info;
+  if (!android::procinfo::GetProcessInfo(main_tid, &target_info)) {
+    LOG(FATAL) << "failed to fetch process info for target " << main_tid;
+  }
+
+  if (main_tid != target_info.tid || target != target_info.pid) {
+    LOG(FATAL) << "target info mismatch, expected pid " << target << ", tid " << main_tid
+               << ", received pid " << target_info.pid << ", tid " << target_info.tid;
+  }
+
+  // Open /proc/`getppid()` in the original process, and pass it down to the forked child.
+  std::string target_proc_path = "/proc/" + std::to_string(target);
+  int target_proc_fd = open(target_proc_path.c_str(), O_DIRECTORY | O_RDONLY);
+  if (target_proc_fd == -1) {
+    PLOG(FATAL) << "failed to open " << target_proc_path;
+  }
+
+  // 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();
+  if (forkpid == -1) {
+    PLOG(FATAL) << "fork failed";
+  } else if (forkpid != 0) {
+    exit(0);
+  }
+
+  check_process(target_proc_fd, target);
+
+  int attach_error = 0;
+  if (!ptrace_attach_thread(target, main_tid)) {
+    PLOG(FATAL) << "failed to attach to thread " << main_tid << " in process " << target;
+  }
+
+  check_process(target_proc_fd, target);
+
+  LOG(INFO) << "obtaining output fd from tombstoned";
+  tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd);
+
+  // Write a '\1' to stdout to tell the crashing process to resume.
+  if (TEMP_FAILURE_RETRY(write(STDOUT_FILENO, "\1", 1)) == -1) {
+    PLOG(ERROR) << "failed to communicate to target process";
+  }
+
+  if (tombstoned_connected) {
+    if (TEMP_FAILURE_RETRY(dup2(output_fd.get(), STDOUT_FILENO)) == -1) {
+      PLOG(ERROR) << "failed to dup2 output fd (" << output_fd.get() << ") to STDOUT_FILENO";
+    }
+  } else {
+    unique_fd devnull(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
+    TEMP_FAILURE_RETRY(dup2(devnull.get(), STDOUT_FILENO));
+  }
+
+  if (attach_error != 0) {
+    PLOG(FATAL) << "failed to attach to thread " << main_tid << " in process " << target;
+  }
+
+  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.
+  if (ptrace(PTRACE_CONT, main_tid, 0, 0) != 0) {
+    PLOG(ERROR) << "PTRACE_CONT(" << main_tid << ") failed";
+    exit(1);
+  }
+
+  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);
+  }
+
+  int signo = siginfo.si_signo;
+  bool backtrace = false;
+  uintptr_t abort_address = 0;
+
+  // si_value can represent three things:
+  //   0: dump tombstone
+  //   1: dump backtrace
+  //   everything else: abort message address (implies dump tombstone)
+  if (siginfo.si_value.sival_int == 1) {
+    backtrace = true;
+  } else if (siginfo.si_value.sival_ptr != nullptr) {
+    abort_address = reinterpret_cast<uintptr_t>(siginfo.si_value.sival_ptr);
+  }
+
+  // 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;
+  if (resume_signal == 0) {
+    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)) {
+        PLOG(FATAL) << "failed to attach to thread " << main_tid << " in process " << target;
+      }
+    }
+  }
+
+  check_process(target_proc_fd, target);
+
+  // TODO: Use seccomp to lock ourselves down.
+
+  std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(main_tid));
+  std::string amfd_data;
+
+  if (backtrace) {
+    dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, siblings, 0);
+  } else {
+    // Collect the list of open files.
+    OpenFilesList open_files;
+    populate_open_files_list(target, &open_files);
+
+    engrave_tombstone(output_fd.get(), backtrace_map.get(), open_files, target, main_tid, siblings,
+                      abort_address, fatal_signal ? &amfd_data : nullptr);
+  }
+
+  bool wait_for_gdb = android::base::GetBoolProperty("debug.debuggerd.wait_for_gdb", false);
+  if (wait_for_gdb) {
+    // 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);
+    }
+  }
+
+  for (pid_t tid : 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 (ptrace(PTRACE_DETACH, main_tid, 0, wait_for_gdb ? SIGSTOP : resume_signal)) {
+    PLOG(ERROR) << "ptrace detach from main thread " << main_tid << " failed";
+  }
+
+  if (wait_for_gdb) {
+    if (tgkill(target, main_tid, resume_signal) != 0) {
+      PLOG(ERROR) << "failed to resend signal to process " << target;
+    }
+  }
+
+  if (fatal_signal) {
+    activity_manager_notify(target, signo, amfd_data);
+  }
+
+  // Close stdout before we notify tombstoned of completion.
+  close(STDOUT_FILENO);
+  if (!tombstoned_notify_completion(tombstoned_socket.get())) {
+    LOG(ERROR) << "failed to notify tombstoned of completion";
+  }
+
+  return 0;
+}
diff --git a/debuggerd/crasher/Android.mk b/debuggerd/crasher/Android.mk
new file mode 100644
index 0000000..b8b786b
--- /dev/null
+++ b/debuggerd/crasher/Android.mk
@@ -0,0 +1,66 @@
+LOCAL_PATH := $(call my-dir)
+
+crasher_cppflags := \
+    -std=gnu++14 \
+    -W \
+    -Wall \
+    -Wextra \
+    -Wunused \
+    -Werror \
+    -O0 \
+    -fstack-protector-all \
+    -Wno-free-nonheap-object \
+    -Wno-date-time
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := crasher.cpp
+LOCAL_SRC_FILES_arm    := arm/crashglue.S
+LOCAL_SRC_FILES_arm64  := arm64/crashglue.S
+LOCAL_SRC_FILES_mips   := mips/crashglue.S
+LOCAL_SRC_FILES_mips64 := mips64/crashglue.S
+LOCAL_SRC_FILES_x86    := x86/crashglue.S
+LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPPFLAGS := $(crasher_cppflags)
+LOCAL_SHARED_LIBRARIES := libbase liblog
+
+# The arm emulator has VFP but not VFPv3-D32.
+ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
+LOCAL_ASFLAGS_arm += -DHAS_VFP_D32
+endif
+
+LOCAL_MODULE := crasher
+LOCAL_MODULE_STEM_32 := crasher
+LOCAL_MODULE_STEM_64 := crasher64
+LOCAL_MULTILIB := both
+
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := crasher.cpp
+LOCAL_SRC_FILES_arm    := arm/crashglue.S
+LOCAL_SRC_FILES_arm64  := arm64/crashglue.S
+LOCAL_SRC_FILES_mips   := mips/crashglue.S
+LOCAL_SRC_FILES_mips64 := mips64/crashglue.S
+LOCAL_SRC_FILES_x86    := x86/crashglue.S
+LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPPFLAGS := $(crasher_cppflags) -DSTATIC_CRASHER
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_SHARED_LIBRARIES := libbase liblog
+
+# The arm emulator has VFP but not VFPv3-D32.
+ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
+LOCAL_ASFLAGS_arm += -DHAS_VFP_D32
+endif
+
+LOCAL_MODULE := static_crasher
+LOCAL_MODULE_STEM_32 := static_crasher
+LOCAL_MODULE_STEM_64 := static_crasher64
+LOCAL_MULTILIB := both
+
+LOCAL_STATIC_LIBRARIES := libdebuggerd_handler libbase liblog
+
+include $(BUILD_EXECUTABLE)
diff --git a/debuggerd/arm/crashglue.S b/debuggerd/crasher/arm/crashglue.S
similarity index 100%
rename from debuggerd/arm/crashglue.S
rename to debuggerd/crasher/arm/crashglue.S
diff --git a/debuggerd/arm64/crashglue.S b/debuggerd/crasher/arm64/crashglue.S
similarity index 100%
rename from debuggerd/arm64/crashglue.S
rename to debuggerd/crasher/arm64/crashglue.S
diff --git a/debuggerd/crasher.cpp b/debuggerd/crasher/crasher.cpp
similarity index 99%
rename from debuggerd/crasher.cpp
rename to debuggerd/crasher/crasher.cpp
index e650f22..288f116 100644
--- a/debuggerd/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -29,11 +29,11 @@
 #include <unistd.h>
 
 // We test both kinds of logging.
-#include <android/log.h>
 #include <android-base/logging.h>
+#include <log/log.h>
 
 #if defined(STATIC_CRASHER)
-#include "debuggerd/client.h"
+#include "debuggerd/handler.h"
 #endif
 
 #define noinline __attribute__((__noinline__))
diff --git a/debuggerd/mips/crashglue.S b/debuggerd/crasher/mips/crashglue.S
similarity index 100%
rename from debuggerd/mips/crashglue.S
rename to debuggerd/crasher/mips/crashglue.S
diff --git a/debuggerd/mips64/crashglue.S b/debuggerd/crasher/mips64/crashglue.S
similarity index 100%
rename from debuggerd/mips64/crashglue.S
rename to debuggerd/crasher/mips64/crashglue.S
diff --git a/debuggerd/x86/crashglue.S b/debuggerd/crasher/x86/crashglue.S
similarity index 100%
rename from debuggerd/x86/crashglue.S
rename to debuggerd/crasher/x86/crashglue.S
diff --git a/debuggerd/x86_64/crashglue.S b/debuggerd/crasher/x86_64/crashglue.S
similarity index 100%
rename from debuggerd/x86_64/crashglue.S
rename to debuggerd/crasher/x86_64/crashglue.S
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 9b82f64..3208230 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006, The Android Open Source Project
+ * Copyright 2016, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,937 +14,68 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "debuggerd"
-
-#include <arpa/inet.h>
-#include <dirent.h>
-#include <elf.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/input.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdarg.h>
+#include <err.h>
 #include <stdio.h>
-#include <sys/poll.h>
-#include <sys/prctl.h>
-#include <sys/ptrace.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/un.h>
-#include <time.h>
+#include <stdlib.h>
+#include <string.h>
 
-#include <memory>
-#include <set>
-#include <string>
+#include <limits>
+#include <thread>
 
-#include <selinux/android.h>
-
-#include <android/log.h>
 #include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
 #include <android-base/unique_fd.h>
-#include <cutils/debugger.h>
-#include <cutils/properties.h>
-#include <cutils/sockets.h>
-
-#include <private/android_filesystem_config.h>
-
 #include <debuggerd/client.h>
+#include <debuggerd/util.h>
+#include <selinux/selinux.h>
 
-#include "backtrace.h"
-#include "getevent.h"
-#include "open_files_list.h"
-#include "signal_sender.h"
-#include "tombstone.h"
-#include "utility.h"
+using android::base::unique_fd;
 
-// If the 32 bit executable is compiled on a 64 bit system,
-// use the 32 bit socket name.
-#if defined(TARGET_IS_64_BIT) && !defined(__LP64__)
-#define SOCKET_NAME DEBUGGER32_SOCKET_NAME
-#else
-#define SOCKET_NAME DEBUGGER_SOCKET_NAME
-#endif
+static void usage(int exit_code) {
+  fprintf(stderr, "usage: debuggerd [-b] PID\n");
+  _exit(exit_code);
+}
 
-struct debugger_request_t {
-  debugger_action_t action;
-  pid_t pid, tid;
-  uid_t uid, gid;
-  pid_t ignore_tid;
-  uintptr_t abort_msg_address;
-};
+static std::thread spawn_redirect_thread(unique_fd fd) {
+  return std::thread([fd{ std::move(fd) }]() {
+    while (true) {
+      char buf[BUFSIZ];
+      ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), buf, sizeof(buf)));
+      if (rc <= 0) {
+        return;
+      }
 
-static void wait_for_user_action(const debugger_request_t& request) {
-  // Explain how to attach the debugger.
-  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"
-        "* Wait for gdb to start, then press the VOLUME DOWN key\n"
-        "* to let the process continue crashing.\n"
-        "***********************************************************",
-        request.pid, request.tid);
-
-  // Wait for VOLUME DOWN.
-  while (true) {
-    input_event e;
-    if (get_event(&e, -1) == 0) {
-      if (e.type == EV_KEY && e.code == KEY_VOLUMEDOWN && e.value == 0) {
-        break;
+      if (!android::base::WriteFully(STDOUT_FILENO, buf, rc)) {
+        return;
       }
     }
-  }
-
-  ALOGI("debuggerd resuming process %d", request.pid);
+  });
 }
 
-static int get_process_info(pid_t tid, pid_t* out_pid, uid_t* out_uid, uid_t* out_gid) {
-  char path[64];
-  snprintf(path, sizeof(path), "/proc/%d/status", tid);
+int main(int argc, char* argv[]) {
+  if (argc <= 1) usage(0);
+  if (argc > 3) usage(1);
+  if (argc == 3 && strcmp(argv[1], "-b") != 0) usage(1);
 
-  FILE* fp = fopen(path, "r");
-  if (!fp) {
-    return -1;
+  pid_t pid;
+  if (!android::base::ParseInt(argv[argc - 1], &pid, 1, std::numeric_limits<pid_t>::max())) {
+    usage(1);
   }
 
-  int fields = 0;
-  char line[1024];
-  while (fgets(line, sizeof(line), fp)) {
-    size_t len = strlen(line);
-    if (len > 6 && !memcmp(line, "Tgid:\t", 6)) {
-      *out_pid = atoi(line + 6);
-      fields |= 1;
-    } else if (len > 5 && !memcmp(line, "Uid:\t", 5)) {
-      *out_uid = atoi(line + 5);
-      fields |= 2;
-    } else if (len > 5 && !memcmp(line, "Gid:\t", 5)) {
-      *out_gid = atoi(line + 5);
-      fields |= 4;
-    }
-  }
-  fclose(fp);
-  return fields == 7 ? 0 : -1;
-}
-
-/*
- * Corresponds with debugger_action_t enum type in
- * include/cutils/debugger.h.
- */
-static const char *debuggerd_perms[] = {
-  NULL, /* crash is only used on self, no check applied */
-  "dump_tombstone",
-  "dump_backtrace"
-};
-
-static int audit_callback(void* data, security_class_t /* cls */, char* buf, size_t len)
-{
-    struct debugger_request_t* req = reinterpret_cast<debugger_request_t*>(data);
-
-    if (!req) {
-        ALOGE("No debuggerd request audit data");
-        return 0;
-    }
-
-    snprintf(buf, len, "pid=%d uid=%d gid=%d", req->pid, req->uid, req->gid);
-    return 0;
-}
-
-static bool selinux_action_allowed(int s, debugger_request_t* request)
-{
-  char *scon = NULL, *tcon = NULL;
-  const char *tclass = "debuggerd";
-  const char *perm;
-  bool allowed = false;
-
-  if (request->action <= 0 || request->action >= (sizeof(debuggerd_perms)/sizeof(debuggerd_perms[0]))) {
-    ALOGE("SELinux:  No permission defined for debugger action %d", request->action);
-    return false;
+  unique_fd piperead, pipewrite;
+  if (!Pipe(&piperead, &pipewrite)) {
+    err(1, "failed to create pipe");
   }
 
-  perm = debuggerd_perms[request->action];
-
-  if (getpeercon(s, &scon) < 0) {
-    ALOGE("Cannot get peer context from socket\n");
-    goto out;
+  std::thread redirect_thread = spawn_redirect_thread(std::move(piperead));
+  bool backtrace = argc == 3;
+  if (!debuggerd_trigger_dump(pid, std::move(pipewrite),
+                              backtrace ? kDebuggerdBacktrace : kDebuggerdBacktrace, 0)) {
+    redirect_thread.join();
+    errx(1, "failed to dump process %d", pid);
   }
 
-  if (getpidcon(request->tid, &tcon) < 0) {
-    ALOGE("Cannot get context for tid %d\n", request->tid);
-    goto out;
-  }
-
-  allowed = (selinux_check_access(scon, tcon, tclass, perm, reinterpret_cast<void*>(request)) == 0);
-
-out:
-   freecon(scon);
-   freecon(tcon);
-   return allowed;
-}
-
-static bool pid_contains_tid(pid_t pid, pid_t tid) {
-  char task_path[PATH_MAX];
-  if (snprintf(task_path, PATH_MAX, "/proc/%d/task/%d", pid, tid) >= PATH_MAX) {
-    ALOGE("debuggerd: task path overflow (pid = %d, tid = %d)\n", pid, tid);
-    exit(1);
-  }
-
-  return access(task_path, F_OK) == 0;
-}
-
-static int read_request(int fd, debugger_request_t* out_request) {
-  ucred cr;
-  socklen_t len = sizeof(cr);
-  int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
-  if (status != 0) {
-    ALOGE("cannot get credentials");
-    return -1;
-  }
-
-  ALOGV("reading tid");
-  pollfd pollfds[1];
-  pollfds[0].fd = fd;
-  pollfds[0].events = POLLIN;
-  pollfds[0].revents = 0;
-  status = TEMP_FAILURE_RETRY(poll(pollfds, 1, 3000));
-  if (status != 1) {
-    ALOGE("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid);
-    return -1;
-  }
-
-  debugger_msg_t msg;
-  memset(&msg, 0, sizeof(msg));
-  status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg)));
-  if (status < 0) {
-    ALOGE("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid);
-    return -1;
-  }
-  if (status != sizeof(debugger_msg_t)) {
-    ALOGE("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid);
-    return -1;
-  }
-
-  out_request->action = static_cast<debugger_action_t>(msg.action);
-  out_request->tid = msg.tid;
-  out_request->ignore_tid = msg.ignore_tid;
-  out_request->pid = cr.pid;
-  out_request->uid = cr.uid;
-  out_request->gid = cr.gid;
-  out_request->abort_msg_address = msg.abort_msg_address;
-
-  if (msg.action == DEBUGGER_ACTION_CRASH) {
-    // Ensure that the tid reported by the crashing process is valid.
-    // This check needs to happen again after ptracing the requested thread to prevent a race.
-    if (!pid_contains_tid(out_request->pid, out_request->tid)) {
-      ALOGE("tid %d does not exist in pid %d. ignoring debug request\n", out_request->tid,
-            out_request->pid);
-      return -1;
-    }
-  } else if (cr.uid == 0 || (cr.uid == AID_SYSTEM && msg.action == DEBUGGER_ACTION_DUMP_BACKTRACE)) {
-    // Only root or system can ask us to attach to any process and dump it explicitly.
-    // However, system is only allowed to collect backtraces but cannot dump tombstones.
-    status = get_process_info(out_request->tid, &out_request->pid,
-                              &out_request->uid, &out_request->gid);
-    if (status < 0) {
-      ALOGE("tid %d does not exist. ignoring explicit dump request\n", out_request->tid);
-      return -1;
-    }
-
-    if (!selinux_action_allowed(fd, out_request))
-      return -1;
-  } else {
-    // No one else is allowed to dump arbitrary processes.
-    return -1;
-  }
+  redirect_thread.join();
   return 0;
 }
-
-static int activity_manager_connect() {
-  android::base::unique_fd amfd(socket(PF_UNIX, SOCK_STREAM, 0));
-  if (amfd.get() < -1) {
-    ALOGE("debuggerd: Unable to connect to activity manager (socket failed: %s)", strerror(errno));
-    return -1;
-  }
-
-  struct sockaddr_un address;
-  memset(&address, 0, sizeof(address));
-  address.sun_family = AF_UNIX;
-  // The path used here must match the value defined in NativeCrashListener.java.
-  strncpy(address.sun_path, "/data/system/ndebugsocket", sizeof(address.sun_path));
-  if (TEMP_FAILURE_RETRY(connect(amfd.get(), reinterpret_cast<struct sockaddr*>(&address),
-                                 sizeof(address))) == -1) {
-    ALOGE("debuggerd: Unable to connect to activity manager (connect failed: %s)", strerror(errno));
-    return -1;
-  }
-
-  struct timeval tv;
-  memset(&tv, 0, sizeof(tv));
-  tv.tv_sec = 1;  // tight leash
-  if (setsockopt(amfd.get(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) {
-    ALOGE("debuggerd: Unable to connect to activity manager (setsockopt SO_SNDTIMEO failed: %s)",
-          strerror(errno));
-    return -1;
-  }
-
-  tv.tv_sec = 3;  // 3 seconds on handshake read
-  if (setsockopt(amfd.get(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
-    ALOGE("debuggerd: Unable to connect to activity manager (setsockopt SO_RCVTIMEO failed: %s)",
-          strerror(errno));
-    return -1;
-  }
-
-  return amfd.release();
-}
-
-static void activity_manager_write(int pid, int signal, int amfd, const std::string& amfd_data) {
-  if (amfd == -1) {
-    return;
-  }
-
-  // Activity Manager protocol: binary 32-bit network-byte-order ints for the
-  // pid and signal number, followed by the raw text of the dump, culminating
-  // in a zero byte that marks end-of-data.
-  uint32_t datum = htonl(pid);
-  if (!android::base::WriteFully(amfd, &datum, 4)) {
-    ALOGE("AM pid write failed: %s\n", strerror(errno));
-    return;
-  }
-  datum = htonl(signal);
-  if (!android::base::WriteFully(amfd, &datum, 4)) {
-    ALOGE("AM signal write failed: %s\n", strerror(errno));
-    return;
-  }
-
-  if (!android::base::WriteFully(amfd, amfd_data.c_str(), amfd_data.size())) {
-    ALOGE("AM data write failed: %s\n", strerror(errno));
-    return;
-  }
-
-  // Send EOD to the Activity Manager, then wait for its ack to avoid racing
-  // ahead and killing the target out from under it.
-  uint8_t eodMarker = 0;
-  if (!android::base::WriteFully(amfd, &eodMarker, 1)) {
-    ALOGE("AM eod write failed: %s\n", strerror(errno));
-    return;
-  }
-  // 3 sec timeout reading the ack; we're fine if the read fails.
-  android::base::ReadFully(amfd, &eodMarker, 1);
-}
-
-static bool should_attach_gdb(const debugger_request_t& request) {
-  if (request.action == DEBUGGER_ACTION_CRASH) {
-    return property_get_bool("debug.debuggerd.wait_for_gdb", false);
-  }
-  return false;
-}
-
-#if defined(__LP64__)
-static bool is32bit(pid_t tid) {
-  char* exeline;
-  if (asprintf(&exeline, "/proc/%d/exe", tid) == -1) {
-    return false;
-  }
-  int fd = TEMP_FAILURE_RETRY(open(exeline, O_RDONLY | O_CLOEXEC));
-  int saved_errno = errno;
-  free(exeline);
-  if (fd == -1) {
-    ALOGW("Failed to open /proc/%d/exe %s", tid, strerror(saved_errno));
-    return false;
-  }
-
-  char ehdr[EI_NIDENT];
-  ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, &ehdr, sizeof(ehdr)));
-  close(fd);
-  if (bytes != (ssize_t) sizeof(ehdr) || memcmp(ELFMAG, ehdr, SELFMAG) != 0) {
-    return false;
-  }
-  if (ehdr[EI_CLASS] == ELFCLASS32) {
-    return true;
-  }
-  return false;
-}
-
-static void redirect_to_32(int fd, debugger_request_t* request) {
-  debugger_msg_t msg;
-  memset(&msg, 0, sizeof(msg));
-  msg.tid = request->tid;
-  msg.action = request->action;
-
-  int sock_fd = socket_local_client(DEBUGGER32_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT,
-                                    SOCK_STREAM | SOCK_CLOEXEC);
-  if (sock_fd < 0) {
-    ALOGE("Failed to connect to debuggerd32: %s", strerror(errno));
-    return;
-  }
-
-  if (TEMP_FAILURE_RETRY(write(sock_fd, &msg, sizeof(msg))) != (ssize_t) sizeof(msg)) {
-    ALOGE("Failed to write request to debuggerd32 socket: %s", strerror(errno));
-    close(sock_fd);
-    return;
-  }
-
-  char ack;
-  if (TEMP_FAILURE_RETRY(read(sock_fd, &ack, 1)) == -1) {
-    ALOGE("Failed to read ack from debuggerd32 socket: %s", strerror(errno));
-    close(sock_fd);
-    return;
-  }
-
-  char buffer[1024];
-  ssize_t bytes_read;
-  while ((bytes_read = TEMP_FAILURE_RETRY(read(sock_fd, buffer, sizeof(buffer)))) > 0) {
-    ssize_t bytes_to_send = bytes_read;
-    ssize_t bytes_written;
-    do {
-      bytes_written = TEMP_FAILURE_RETRY(write(fd, buffer + bytes_read - bytes_to_send,
-                                               bytes_to_send));
-      if (bytes_written == -1) {
-        if (errno == EAGAIN) {
-          // Retry the write.
-          continue;
-        }
-        ALOGE("Error while writing data to fd: %s", strerror(errno));
-        break;
-      }
-      bytes_to_send -= bytes_written;
-    } while (bytes_written != 0 && bytes_to_send > 0);
-    if (bytes_to_send != 0) {
-        ALOGE("Failed to write all data to fd: read %zd, sent %zd", bytes_read, bytes_to_send);
-        break;
-    }
-  }
-  close(sock_fd);
-}
-#endif
-
-// 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) {
-  if (ptrace(PTRACE_ATTACH, tid, 0, 0) != 0) {
-    return false;
-  }
-
-  // Make sure that the task we attached to is actually part of the pid we're dumping.
-  if (!pid_contains_tid(pid, tid)) {
-    if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
-      ALOGE("debuggerd: failed to detach from thread '%d'", tid);
-      exit(1);
-    }
-    return false;
-  }
-
-  return true;
-}
-
-static void ptrace_siblings(pid_t pid, pid_t main_tid, pid_t ignore_tid, std::set<pid_t>& tids) {
-  char task_path[PATH_MAX];
-
-  if (snprintf(task_path, PATH_MAX, "/proc/%d/task", pid) >= PATH_MAX) {
-    ALOGE("debuggerd: task path overflow (pid = %d)\n", pid);
-    abort();
-  }
-
-  std::unique_ptr<DIR, int (*)(DIR*)> d(opendir(task_path), closedir);
-
-  // Bail early if the task directory cannot be opened.
-  if (!d) {
-    ALOGE("debuggerd: failed to open /proc/%d/task: %s", pid, strerror(errno));
-    return;
-  }
-
-  struct dirent* de;
-  while ((de = readdir(d.get())) != NULL) {
-    // Ignore "." and "..".
-    if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
-      continue;
-    }
-
-    char* end;
-    pid_t tid = strtoul(de->d_name, &end, 10);
-    if (*end) {
-      continue;
-    }
-
-    if (tid == main_tid || tid == ignore_tid) {
-      continue;
-    }
-
-    if (!ptrace_attach_thread(pid, tid)) {
-      ALOGE("debuggerd: ptrace attach to %d failed: %s", tid, strerror(errno));
-      continue;
-    }
-
-    tids.insert(tid);
-  }
-}
-
-static bool perform_dump(const debugger_request_t& request, int fd, int tombstone_fd,
-                         BacktraceMap* backtrace_map, const OpenFilesList& open_files,
-                         const std::set<pid_t>& siblings,
-                         int* crash_signal, std::string* amfd_data) {
-  if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
-    ALOGE("debuggerd: failed to respond to client: %s\n", strerror(errno));
-    return false;
-  }
-
-  while (true) {
-    // wait_for_signal waits for forever, but the watchdog process will kill us
-    // if it takes too long.
-    int signal = wait_for_signal(request.tid);
-    switch (signal) {
-      case -1:
-        ALOGE("debuggerd: timed out waiting for signal");
-        return false;
-
-      case SIGSTOP:
-        if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
-          ALOGV("debuggerd: stopped -- dumping to tombstone");
-          engrave_tombstone(tombstone_fd, backtrace_map, open_files,
-                            request.pid, request.tid, siblings,
-                            request.abort_msg_address, amfd_data);
-        } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
-          ALOGV("debuggerd: stopped -- dumping to fd");
-          dump_backtrace(fd, backtrace_map, request.pid, request.tid, siblings, nullptr);
-        } else {
-          ALOGV("debuggerd: stopped -- continuing");
-          if (ptrace(PTRACE_CONT, request.tid, 0, 0) != 0) {
-            ALOGE("debuggerd: ptrace continue failed: %s", strerror(errno));
-            return false;
-          }
-          continue;  // loop again
-        }
-        break;
-
-      case SIGABRT:
-      case SIGBUS:
-      case SIGFPE:
-      case SIGILL:
-      case SIGSEGV:
-#ifdef SIGSTKFLT
-      case SIGSTKFLT:
-#endif
-      case SIGSYS:
-      case SIGTRAP:
-        ALOGV("stopped -- fatal signal\n");
-        *crash_signal = signal;
-        engrave_tombstone(tombstone_fd, backtrace_map, open_files,
-                          request.pid, request.tid, siblings,
-                          request.abort_msg_address, amfd_data);
-        break;
-
-      default:
-        ALOGE("debuggerd: process stopped due to unexpected signal %d\n", signal);
-        break;
-    }
-    break;
-  }
-
-  return true;
-}
-
-static bool drop_privileges() {
-  // AID_LOG: for reading the logs data associated with the crashing process.
-  // AID_READPROC: for reading /proc/<PID>/{comm,cmdline}.
-  gid_t groups[] = { AID_DEBUGGERD, AID_LOG, AID_READPROC };
-  if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
-    ALOGE("debuggerd: failed to setgroups: %s", strerror(errno));
-    return false;
-  }
-
-  if (setresgid(AID_DEBUGGERD, AID_DEBUGGERD, AID_DEBUGGERD) != 0) {
-    ALOGE("debuggerd: failed to setresgid: %s", strerror(errno));
-    return false;
-  }
-
-  if (setresuid(AID_DEBUGGERD, AID_DEBUGGERD, AID_DEBUGGERD) != 0) {
-    ALOGE("debuggerd: failed to setresuid: %s", strerror(errno));
-    return false;
-  }
-
-  return true;
-}
-
-static void worker_process(int fd, debugger_request_t& request) {
-  // Open the tombstone file if we need it.
-  std::string tombstone_path;
-  int tombstone_fd = -1;
-  switch (request.action) {
-    case DEBUGGER_ACTION_DUMP_TOMBSTONE:
-    case DEBUGGER_ACTION_CRASH:
-      tombstone_fd = open_tombstone(&tombstone_path);
-      if (tombstone_fd == -1) {
-        ALOGE("debuggerd: failed to open tombstone file: %s\n", strerror(errno));
-        exit(1);
-      }
-      break;
-
-    case DEBUGGER_ACTION_DUMP_BACKTRACE:
-      break;
-
-    default:
-      ALOGE("debuggerd: unexpected request action: %d", request.action);
-      exit(1);
-  }
-
-  // At this point, the thread that made the request is blocked in
-  // a read() call.  If the thread has crashed, then this gives us
-  // time to PTRACE_ATTACH to it before it has a chance to really fault.
-  //
-  // The PTRACE_ATTACH sends a SIGSTOP to the target process, but it
-  // won't necessarily have stopped by the time ptrace() returns.  (We
-  // currently assume it does.)  We write to the file descriptor to
-  // ensure that it can run as soon as we call PTRACE_CONT below.
-  // See details in client/debuggerd_client.cpp, in function
-  // debugger_signal_handler().
-
-  // Attach to the target process.
-  if (!ptrace_attach_thread(request.pid, request.tid)) {
-    ALOGE("debuggerd: ptrace attach failed: %s", strerror(errno));
-    exit(1);
-  }
-
-  // DEBUGGER_ACTION_CRASH requests can come from arbitrary processes and the tid field in the
-  // request is sent from the other side. If an attacker can cause a process to be spawned with the
-  // pid of their process, they could trick debuggerd into dumping that process by exiting after
-  // sending the request. Validate the trusted request.uid/gid to defend against this.
-  if (request.action == DEBUGGER_ACTION_CRASH) {
-    pid_t pid;
-    uid_t uid;
-    gid_t gid;
-    if (get_process_info(request.tid, &pid, &uid, &gid) != 0) {
-      ALOGE("debuggerd: failed to get process info for tid '%d'", request.tid);
-      exit(1);
-    }
-
-    if (pid != request.pid || uid != request.uid || gid != request.gid) {
-      ALOGE(
-        "debuggerd: attached task %d does not match request: "
-        "expected pid=%d,uid=%d,gid=%d, actual pid=%d,uid=%d,gid=%d",
-        request.tid, request.pid, request.uid, request.gid, pid, uid, gid);
-      exit(1);
-    }
-  }
-
-  // Don't attach to the sibling threads if we want to attach gdb.
-  // Supposedly, it makes the process less reliable.
-  bool attach_gdb = should_attach_gdb(request);
-  if (attach_gdb) {
-    // Open all of the input devices we need to listen for VOLUMEDOWN before dropping privileges.
-    if (init_getevent() != 0) {
-      ALOGE("debuggerd: failed to initialize input device, not waiting for gdb");
-      attach_gdb = false;
-    }
-
-  }
-
-  std::set<pid_t> siblings;
-  if (!attach_gdb) {
-    ptrace_siblings(request.pid, request.tid, request.ignore_tid, siblings);
-  }
-
-  // Generate the backtrace map before dropping privileges.
-  std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(request.pid));
-
-  // Collect the list of open files before dropping privileges.
-  OpenFilesList open_files;
-  populate_open_files_list(request.pid, &open_files);
-
-  int amfd = -1;
-  std::unique_ptr<std::string> amfd_data;
-  if (request.action == DEBUGGER_ACTION_CRASH) {
-    // Connect to the activity manager before dropping privileges.
-    amfd = activity_manager_connect();
-    amfd_data.reset(new std::string);
-  }
-
-  bool succeeded = false;
-
-  // Now that we've done everything that requires privileges, we can drop them.
-  if (!drop_privileges()) {
-    ALOGE("debuggerd: failed to drop privileges, exiting");
-    _exit(1);
-  }
-
-  int crash_signal = SIGKILL;
-  succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), open_files,
-                           siblings, &crash_signal, amfd_data.get());
-  if (succeeded) {
-    if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
-      if (!tombstone_path.empty()) {
-        android::base::WriteFully(fd, tombstone_path.c_str(), tombstone_path.length());
-      }
-    }
-  }
-
-  if (attach_gdb) {
-    // Tell the signal process to send SIGSTOP to the target.
-    if (!send_signal(request.pid, 0, SIGSTOP)) {
-      ALOGE("debuggerd: failed to stop process for gdb attach: %s", strerror(errno));
-      attach_gdb = false;
-    }
-  }
-
-  if (!attach_gdb) {
-    // Tell the Activity Manager about the crashing process. If we are
-    // waiting for gdb to attach, do not send this or Activity Manager
-    // might kill the process before anyone can attach.
-    activity_manager_write(request.pid, crash_signal, amfd, *amfd_data.get());
-  }
-
-  if (ptrace(PTRACE_DETACH, request.tid, 0, 0) != 0) {
-    ALOGE("debuggerd: ptrace detach from %d failed: %s", request.tid, strerror(errno));
-  }
-
-  for (pid_t sibling : siblings) {
-    ptrace(PTRACE_DETACH, sibling, 0, 0);
-  }
-
-  // Send the signal back to the process if it crashed and we're not waiting for gdb.
-  if (!attach_gdb && request.action == DEBUGGER_ACTION_CRASH) {
-    if (!send_signal(request.pid, request.tid, crash_signal)) {
-      ALOGE("debuggerd: failed to kill process %d: %s", request.pid, strerror(errno));
-    }
-  }
-
-  // Wait for gdb, if requested.
-  if (attach_gdb) {
-    wait_for_user_action(request);
-
-    // Now tell the activity manager about this process.
-    activity_manager_write(request.pid, crash_signal, amfd, *amfd_data.get());
-
-    // Tell the signal process to send SIGCONT to the target.
-    if (!send_signal(request.pid, 0, SIGCONT)) {
-      ALOGE("debuggerd: failed to resume process %d: %s", request.pid, strerror(errno));
-    }
-
-    uninit_getevent();
-  }
-
-  close(amfd);
-
-  exit(!succeeded);
-}
-
-static void monitor_worker_process(int child_pid, const debugger_request_t& request) {
-  struct timespec timeout = {.tv_sec = 10, .tv_nsec = 0 };
-  if (should_attach_gdb(request)) {
-    // If wait_for_gdb is enabled, set the timeout to something large.
-    timeout.tv_sec = INT_MAX;
-  }
-
-  sigset_t signal_set;
-  sigemptyset(&signal_set);
-  sigaddset(&signal_set, SIGCHLD);
-
-  bool kill_worker = false;
-  bool kill_target = false;
-  bool kill_self = false;
-
-  int status;
-  siginfo_t siginfo;
-  int signal = TEMP_FAILURE_RETRY(sigtimedwait(&signal_set, &siginfo, &timeout));
-  if (signal == SIGCHLD) {
-    pid_t rc = waitpid(-1, &status, WNOHANG | WUNTRACED);
-    if (rc != child_pid) {
-      ALOGE("debuggerd: waitpid returned unexpected pid (%d), committing murder-suicide", rc);
-
-      if (WIFEXITED(status)) {
-        ALOGW("debuggerd: pid %d exited with status %d", rc, WEXITSTATUS(status));
-      } else if (WIFSIGNALED(status)) {
-        ALOGW("debuggerd: pid %d received signal %d", rc, WTERMSIG(status));
-      } else if (WIFSTOPPED(status)) {
-        ALOGW("debuggerd: pid %d stopped by signal %d", rc, WSTOPSIG(status));
-      } else if (WIFCONTINUED(status)) {
-        ALOGW("debuggerd: pid %d continued", rc);
-      }
-
-      kill_worker = true;
-      kill_target = true;
-      kill_self = true;
-    } else if (WIFSIGNALED(status)) {
-      ALOGE("debuggerd: worker process %d terminated due to signal %d", child_pid, WTERMSIG(status));
-      kill_worker = false;
-      kill_target = true;
-    } else if (WIFSTOPPED(status)) {
-      ALOGE("debuggerd: worker process %d stopped due to signal %d", child_pid, WSTOPSIG(status));
-      kill_worker = true;
-      kill_target = true;
-    }
-  } else {
-    ALOGE("debuggerd: worker process %d timed out", child_pid);
-    kill_worker = true;
-    kill_target = true;
-  }
-
-  if (kill_worker) {
-    // Something bad happened, kill the worker.
-    if (kill(child_pid, SIGKILL) != 0) {
-      ALOGE("debuggerd: failed to kill worker process %d: %s", child_pid, strerror(errno));
-    } else {
-      waitpid(child_pid, &status, 0);
-    }
-  }
-
-  int exit_signal = SIGCONT;
-  if (kill_target && request.action == DEBUGGER_ACTION_CRASH) {
-    ALOGE("debuggerd: killing target %d", request.pid);
-    exit_signal = SIGKILL;
-  } else {
-    ALOGW("debuggerd: resuming target %d", request.pid);
-  }
-
-  if (kill(request.pid, exit_signal) != 0) {
-    ALOGE("debuggerd: failed to send signal %d to target: %s", exit_signal, strerror(errno));
-  }
-
-  if (kill_self) {
-    stop_signal_sender();
-    _exit(1);
-  }
-}
-
-static void handle_request(int fd) {
-  ALOGV("handle_request(%d)\n", fd);
-
-  android::base::unique_fd closer(fd);
-  debugger_request_t request;
-  memset(&request, 0, sizeof(request));
-  int status = read_request(fd, &request);
-  if (status != 0) {
-    return;
-  }
-
-  ALOGW("debuggerd: handling request: pid=%d uid=%d gid=%d tid=%d\n", request.pid, request.uid,
-        request.gid, request.tid);
-
-#if defined(__LP64__)
-  // On 64 bit systems, requests to dump 32 bit and 64 bit tids come
-  // to the 64 bit debuggerd. If the process is a 32 bit executable,
-  // redirect the request to the 32 bit debuggerd.
-  if (is32bit(request.tid)) {
-    // Only dump backtrace and dump tombstone requests can be redirected.
-    if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE ||
-        request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
-      redirect_to_32(fd, &request);
-    } else {
-      ALOGE("debuggerd: Not allowed to redirect action %d to 32 bit debuggerd\n", request.action);
-    }
-    return;
-  }
-#endif
-
-  // Fork a child to handle the rest of the request.
-  pid_t fork_pid = fork();
-  if (fork_pid == -1) {
-    ALOGE("debuggerd: failed to fork: %s\n", strerror(errno));
-  } else if (fork_pid == 0) {
-    worker_process(fd, request);
-  } else {
-    monitor_worker_process(fork_pid, request);
-  }
-}
-
-static int do_server() {
-  // debuggerd crashes can't be reported to debuggerd.
-  // Reset all of the crash handlers.
-  signal(SIGABRT, SIG_DFL);
-  signal(SIGBUS, SIG_DFL);
-  signal(SIGFPE, SIG_DFL);
-  signal(SIGILL, SIG_DFL);
-  signal(SIGSEGV, SIG_DFL);
-#ifdef SIGSTKFLT
-  signal(SIGSTKFLT, SIG_DFL);
-#endif
-  signal(SIGTRAP, SIG_DFL);
-
-  // Ignore failed writes to closed sockets
-  signal(SIGPIPE, SIG_IGN);
-
-  // Block SIGCHLD so we can sigtimedwait for it.
-  sigset_t sigchld;
-  sigemptyset(&sigchld);
-  sigaddset(&sigchld, SIGCHLD);
-  sigprocmask(SIG_SETMASK, &sigchld, nullptr);
-
-  int s = socket_local_server(SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT,
-                              SOCK_STREAM | SOCK_CLOEXEC);
-  if (s == -1) return 1;
-
-  // Fork a process that stays root, and listens on a pipe to pause and resume the target.
-  if (!start_signal_sender()) {
-    ALOGE("debuggerd: failed to fork signal sender");
-    return 1;
-  }
-
-  ALOGI("debuggerd: starting\n");
-
-  for (;;) {
-    ALOGV("waiting for connection\n");
-    int fd = accept4(s, nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK);
-    if (fd == -1) {
-      ALOGE("accept failed: %s\n", strerror(errno));
-      continue;
-    }
-
-    handle_request(fd);
-  }
-  return 0;
-}
-
-static int do_explicit_dump(pid_t tid, bool dump_backtrace) {
-  fprintf(stdout, "Sending request to dump task %d...\n", tid);
-  fflush(stdout);
-
-  // TODO: we could have better error reporting if debuggerd sent an error string back.
-  if (dump_backtrace) {
-    if (dump_backtrace_to_file(tid, fileno(stdout)) < 0) {
-      fputs("Error dumping backtrace (check logcat).\n", stderr);
-      return 1;
-    }
-  } else {
-    char tombstone_path[PATH_MAX];
-    if (dump_tombstone(tid, tombstone_path, sizeof(tombstone_path)) < 0) {
-      fputs("Error dumping tombstone (check logcat).\n", stderr);
-      return 1;
-    }
-    fprintf(stderr, "Tombstone written to: %s\n", tombstone_path);
-  }
-  return 0;
-}
-
-static int usage() {
-  fputs("usage: debuggerd [-b] [<tid>]\n"
-        "\n"
-        "Given a thread id, sends a request to debuggerd to dump that thread.\n"
-        "Otherwise, starts the debuggerd server.\n"
-        "\n"
-        "-b\tdump backtrace to console, otherwise generate tombstone\n", stderr);
-  return EXIT_FAILURE;
-}
-
-int main(int argc, char** argv) {
-  union selinux_callback cb;
-  if (argc == 1) {
-    cb.func_audit = audit_callback;
-    selinux_set_callback(SELINUX_CB_AUDIT, cb);
-    cb.func_log = selinux_log_callback;
-    selinux_set_callback(SELINUX_CB_LOG, cb);
-    return do_server();
-  }
-
-  bool dump_backtrace = false;
-  pid_t tid = 0;
-  for (int i = 1; i < argc; i++) {
-    if (!strcmp(argv[i], "-b")) {
-      dump_backtrace = true;
-    } else if (tid != 0 || (tid = atoi(argv[i])) == 0) {
-      // Only one tid is allowed. (And 0 isn't a valid tid.)
-      // atoi(3) returns 0 on failure to parse, so this catches anything else too.
-      return usage();
-    }
-  }
-  return (tid != 0) ? do_explicit_dump(tid, dump_backtrace) : usage();
-}
diff --git a/debuggerd/debuggerd.rc b/debuggerd/debuggerd.rc
deleted file mode 100644
index 1c6b9ff..0000000
--- a/debuggerd/debuggerd.rc
+++ /dev/null
@@ -1,3 +0,0 @@
-service debuggerd /system/bin/debuggerd
-    group root readproc
-    writepid /dev/cpuset/system-background/tasks
diff --git a/debuggerd/debuggerd64.rc b/debuggerd/debuggerd64.rc
deleted file mode 100644
index 3e8847a..0000000
--- a/debuggerd/debuggerd64.rc
+++ /dev/null
@@ -1,3 +0,0 @@
-service debuggerd64 /system/bin/debuggerd64
-    group root readproc
-    writepid /dev/cpuset/system-background/tasks
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
new file mode 100644
index 0000000..f51b5f2
--- /dev/null
+++ b/debuggerd/debuggerd_test.cpp
@@ -0,0 +1,390 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <err.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <chrono>
+#include <regex>
+#include <thread>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <cutils/sockets.h>
+#include <debuggerd/handler.h>
+#include <debuggerd/protocol.h>
+#include <debuggerd/util.h>
+#include <gtest/gtest.h>
+
+using namespace std::chrono_literals;
+using android::base::unique_fd;
+
+#if defined(__LP64__)
+#define CRASHER_PATH  "/system/xbin/crasher64"
+#define ARCH_SUFFIX "64"
+#else
+#define CRASHER_PATH "/system/xbin/crasher"
+#define ARCH_SUFFIX ""
+#endif
+
+constexpr char kWaitForGdbKey[] = "debug.debuggerd.wait_for_gdb";
+
+#define TIMEOUT(seconds, expr)                                     \
+  [&]() {                                                          \
+    struct sigaction old_sigaction;                                \
+    struct sigaction new_sigaction = {};                           \
+    new_sigaction.sa_handler = [](int) {};                         \
+    if (sigaction(SIGALRM, &new_sigaction, &new_sigaction) != 0) { \
+      err(1, "sigaction failed");                                  \
+    }                                                              \
+    alarm(seconds);                                                \
+    auto value = expr;                                             \
+    int saved_errno = errno;                                       \
+    if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) {        \
+      err(1, "sigaction failed");                                  \
+    }                                                              \
+    alarm(0);                                                      \
+    errno = saved_errno;                                           \
+    return value;                                                  \
+  }()
+
+#define ASSERT_MATCH(str, pattern)                                              \
+  do {                                                                          \
+    std::regex r((pattern));                                                    \
+    if (!std::regex_search((str), r)) {                                         \
+      FAIL() << "regex mismatch: expected " << (pattern) << " in: \n" << (str); \
+    }                                                                           \
+  } while (0)
+
+class CrasherTest : public ::testing::Test {
+ public:
+  pid_t crasher_pid = -1;
+  bool previous_wait_for_gdb;
+  unique_fd crasher_pipe;
+  unique_fd intercept_fd;
+
+  CrasherTest();
+  ~CrasherTest();
+
+  void StartIntercept(unique_fd* output_fd);
+
+  // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
+  void FinishIntercept(int* result);
+
+  void StartCrasher(const std::string& crash_type);
+  void FinishCrasher();
+  void AssertDeath(int signo);
+};
+
+CrasherTest::CrasherTest() {
+  previous_wait_for_gdb = android::base::GetBoolProperty(kWaitForGdbKey, false);
+  android::base::SetProperty(kWaitForGdbKey, "0");
+}
+
+CrasherTest::~CrasherTest() {
+  if (crasher_pid != -1) {
+    kill(crasher_pid, SIGKILL);
+    int status;
+    waitpid(crasher_pid, &status, WUNTRACED);
+  }
+
+  android::base::SetProperty(kWaitForGdbKey, previous_wait_for_gdb ? "1" : "0");
+}
+
+void CrasherTest::StartIntercept(unique_fd* output_fd) {
+  if (crasher_pid == -1) {
+    FAIL() << "crasher hasn't been started";
+  }
+
+  intercept_fd.reset(socket_local_client(kTombstonedInterceptSocketName,
+                                         ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
+  if (intercept_fd == -1) {
+    FAIL() << "failed to contact tombstoned: " << strerror(errno);
+  }
+
+  InterceptRequest req = {.pid = crasher_pid };
+
+  unique_fd output_pipe_write;
+  if (!Pipe(output_fd, &output_pipe_write)) {
+    FAIL() << "failed to create output pipe: " << strerror(errno);
+  }
+
+  std::string pipe_size_str;
+  int pipe_buffer_size;
+  if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
+    FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
+  }
+
+  pipe_size_str = android::base::Trim(pipe_size_str);
+
+  if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
+    FAIL() << "failed to parse pipe max size";
+  }
+
+  if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
+    FAIL() << "failed to set pipe size: " << strerror(errno);
+  }
+
+  if (send_fd(intercept_fd.get(), &req, sizeof(req), std::move(output_pipe_write)) != sizeof(req)) {
+    FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
+  }
+}
+
+void CrasherTest::FinishIntercept(int* result) {
+  InterceptResponse response;
+
+  // Timeout for tombstoned intercept is 10 seconds.
+  ssize_t rc = TIMEOUT(20, read(intercept_fd.get(), &response, sizeof(response)));
+  if (rc == -1) {
+    FAIL() << "failed to read response from tombstoned: " << strerror(errno);
+  } else if (rc == 0) {
+    *result = -1;
+  } else if (rc != sizeof(response)) {
+    FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
+           << ", received " << rc;
+  } else {
+    *result = response.success;
+  }
+}
+
+void CrasherTest::StartCrasher(const std::string& crash_type) {
+  std::string type = "wait-" + crash_type;
+
+  unique_fd crasher_read_pipe;
+  if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
+    FAIL() << "failed to create pipe: " << strerror(errno);
+  }
+
+  crasher_pid = fork();
+  if (crasher_pid == -1) {
+    FAIL() << "fork failed: " << strerror(errno);
+  } else if (crasher_pid == 0) {
+    unique_fd devnull(open("/dev/null", O_WRONLY));
+    dup2(crasher_read_pipe.get(), STDIN_FILENO);
+    dup2(devnull.get(), STDOUT_FILENO);
+    dup2(devnull.get(), STDERR_FILENO);
+    execl(CRASHER_PATH, CRASHER_PATH, type.c_str(), nullptr);
+    err(1, "exec failed");
+  }
+}
+
+void CrasherTest::FinishCrasher() {
+  if (crasher_pipe == -1) {
+    FAIL() << "crasher pipe uninitialized";
+  }
+
+  ssize_t rc = write(crasher_pipe.get(), "\n", 1);
+  if (rc == -1) {
+    FAIL() << "failed to write to crasher pipe: " << strerror(errno);
+  } else if (rc == 0) {
+    FAIL() << "crasher pipe was closed";
+  }
+}
+
+void CrasherTest::AssertDeath(int signo) {
+  int status;
+  pid_t pid = TIMEOUT(5, waitpid(crasher_pid, &status, 0));
+  if (pid != crasher_pid) {
+    FAIL() << "failed to wait for crasher: " << strerror(errno);
+  }
+
+  if (!WIFSIGNALED(status)) {
+    FAIL() << "crasher didn't terminate via a signal";
+  }
+  ASSERT_EQ(signo, WTERMSIG(status));
+  crasher_pid = -1;
+}
+
+static void ConsumeFd(unique_fd fd, std::string* output) {
+  constexpr size_t read_length = PAGE_SIZE;
+  std::string result;
+
+  while (true) {
+    size_t offset = result.size();
+    result.resize(result.size() + PAGE_SIZE);
+    ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length));
+    if (rc == -1) {
+      FAIL() << "read failed: " << strerror(errno);
+    } else if (rc == 0) {
+      result.resize(result.size() - PAGE_SIZE);
+      break;
+    }
+
+    result.resize(result.size() - PAGE_SIZE + rc);
+  }
+
+  *output = std::move(result);
+}
+
+TEST_F(CrasherTest, smoke) {
+  int intercept_result;
+  unique_fd output_fd;
+  StartCrasher("SIGSEGV");
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  AssertDeath(SIGSEGV);
+  FinishIntercept(&intercept_result);
+
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+  ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
+}
+
+TEST_F(CrasherTest, abort) {
+  int intercept_result;
+  unique_fd output_fd;
+  StartCrasher("abort");
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  AssertDeath(SIGABRT);
+  FinishIntercept(&intercept_result);
+
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+  ASSERT_MATCH(result, R"(#00 pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX R"(/libc.so \(tgkill)");
+}
+
+TEST_F(CrasherTest, signal) {
+  int intercept_result;
+  unique_fd output_fd;
+  StartCrasher("abort");
+  StartIntercept(&output_fd);
+
+  // Wait for a bit, or we might end up killing the process before the signal
+  // handler even gets a chance to be registered.
+  std::this_thread::sleep_for(100ms);
+  ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
+
+  AssertDeath(SIGSEGV);
+  FinishIntercept(&intercept_result);
+
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+  ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER\), fault addr --------)");
+  ASSERT_MATCH(result, R"(backtrace:)");
+}
+
+TEST_F(CrasherTest, abort_message) {
+  int intercept_result;
+  unique_fd output_fd;
+  StartCrasher("smash-stack");
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  AssertDeath(SIGABRT);
+  FinishIntercept(&intercept_result);
+
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+  ASSERT_MATCH(result, R"(Abort message: 'stack corruption detected \(-fstack-protector\)')");
+}
+
+TEST_F(CrasherTest, intercept_timeout) {
+  int intercept_result;
+  unique_fd output_fd;
+  StartCrasher("abort");
+  StartIntercept(&output_fd);
+
+  // Don't let crasher finish until we timeout.
+  FinishIntercept(&intercept_result);
+
+  ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
+                                 << intercept_result << ")";
+
+  FinishCrasher();
+  AssertDeath(SIGABRT);
+}
+
+TEST_F(CrasherTest, wait_for_gdb) {
+  if (!android::base::SetProperty(kWaitForGdbKey, "1")) {
+    FAIL() << "failed to enable wait_for_gdb";
+  }
+  sleep(1);
+
+  StartCrasher("abort");
+  FinishCrasher();
+
+  int status;
+  ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, WUNTRACED));
+  ASSERT_TRUE(WIFSTOPPED(status));
+  ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
+
+  ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
+
+  AssertDeath(SIGABRT);
+}
+
+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);
+}
+
+TEST_F(CrasherTest, backtrace) {
+  std::string result;
+  int intercept_result;
+  unique_fd output_fd;
+  StartCrasher("abort");
+  StartIntercept(&output_fd);
+
+  std::this_thread::sleep_for(500ms);
+
+  sigval val;
+  val.sival_int = 1;
+  ASSERT_EQ(0, sigqueue(crasher_pid, DEBUGGER_SIGNAL, val)) << strerror(errno);
+  FinishIntercept(&intercept_result);
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+  ConsumeFd(std::move(output_fd), &result);
+  ASSERT_MATCH(result, R"(#00 pc [0-9a-f]+  /system/lib)" ARCH_SUFFIX R"(/libc.so \(read\+)");
+
+  int status;
+  ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
+
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  AssertDeath(SIGABRT);
+  FinishIntercept(&intercept_result);
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+  ConsumeFd(std::move(output_fd), &result);
+  ASSERT_MATCH(result, R"(#00 pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX R"(/libc.so \(tgkill)");
+}
diff --git a/debuggerd/getevent.cpp b/debuggerd/getevent.cpp
deleted file mode 100644
index dbb878a..0000000
--- a/debuggerd/getevent.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/input.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/inotify.h>
-#include <sys/ioctl.h>
-#include <sys/limits.h>
-#include <sys/poll.h>
-#include <unistd.h>
-
-#include <memory>
-
-#include <android/log.h>
-
-static struct pollfd* ufds;
-static char** device_names;
-static int nfds;
-
-static int open_device(const char* device) {
-  int version;
-  int fd;
-  struct pollfd* new_ufds;
-  char** new_device_names;
-  char name[80];
-  char location[80];
-  char idstr[80];
-  struct input_id id;
-
-  fd = open(device, O_RDWR);
-  if (fd < 0) {
-    return -1;
-  }
-
-  if (ioctl(fd, EVIOCGVERSION, &version)) {
-    return -1;
-  }
-  if (ioctl(fd, EVIOCGID, &id)) {
-    return -1;
-  }
-  name[sizeof(name) - 1] = '\0';
-  location[sizeof(location) - 1] = '\0';
-  idstr[sizeof(idstr) - 1] = '\0';
-  if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
-    name[0] = '\0';
-  }
-  if (ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
-    location[0] = '\0';
-  }
-  if (ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
-    idstr[0] = '\0';
-  }
-
-  new_ufds = reinterpret_cast<pollfd*>(realloc(ufds, sizeof(ufds[0]) * (nfds + 1)));
-  if (new_ufds == NULL) {
-    fprintf(stderr, "out of memory\n");
-    return -1;
-  }
-  ufds = new_ufds;
-  new_device_names = reinterpret_cast<char**>(realloc(
-      device_names, sizeof(device_names[0]) * (nfds + 1)));
-  if (new_device_names == NULL) {
-    fprintf(stderr, "out of memory\n");
-    return -1;
-  }
-  device_names = new_device_names;
-  ufds[nfds].fd = fd;
-  ufds[nfds].events = POLLIN;
-  device_names[nfds] = strdup(device);
-  nfds++;
-
-  return 0;
-}
-
-int close_device(const char* device) {
-  int i;
-  for (i = 1; i < nfds; i++) {
-    if (strcmp(device_names[i], device) == 0) {
-      int count = nfds - i - 1;
-      free(device_names[i]);
-      memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
-      memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
-      nfds--;
-      return 0;
-    }
-  }
-  return -1;
-}
-
-static int read_notify(const char* dirname, int nfd) {
-  int res;
-  char devname[PATH_MAX];
-  char* filename;
-  char event_buf[512];
-  int event_size;
-  int event_pos = 0;
-  struct inotify_event *event;
-
-  res = read(nfd, event_buf, sizeof(event_buf));
-  if (res < (int)sizeof(*event)) {
-    if (errno == EINTR)
-      return 0;
-    fprintf(stderr, "could not get event, %s\n", strerror(errno));
-    return 1;
-  }
-
-  strcpy(devname, dirname);
-  filename = devname + strlen(devname);
-  *filename++ = '/';
-
-  while (res >= (int)sizeof(*event)) {
-    event = reinterpret_cast<struct inotify_event*>(event_buf + event_pos);
-    if (event->len) {
-      strcpy(filename, event->name);
-      if (event->mask & IN_CREATE) {
-        open_device(devname);
-      } else {
-        close_device(devname);
-      }
-    }
-    event_size = sizeof(*event) + event->len;
-    res -= event_size;
-    event_pos += event_size;
-  }
-  return 0;
-}
-
-static int scan_dir(const char* dirname) {
-  char devname[PATH_MAX];
-  char* filename;
-  struct dirent* de;
-  std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname), closedir);
-  if (dir == NULL)
-    return -1;
-  strcpy(devname, dirname);
-  filename = devname + strlen(devname);
-  *filename++ = '/';
-  while ((de = readdir(dir.get()))) {
-    if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
-        (de->d_name[1] == '.' && de->d_name[2] == '\0'))
-      continue;
-    strcpy(filename, de->d_name);
-    open_device(devname);
-  }
-  return 0;
-}
-
-int init_getevent() {
-  int res;
-  const char* device_path = "/dev/input";
-
-  nfds = 1;
-  ufds = reinterpret_cast<pollfd*>(calloc(1, sizeof(ufds[0])));
-  ufds[0].fd = inotify_init();
-  ufds[0].events = POLLIN;
-
-  res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
-  if (res < 0) {
-    return 1;
-  }
-  res = scan_dir(device_path);
-  if (res < 0) {
-    return 1;
-  }
-  return 0;
-}
-
-void uninit_getevent() {
-  int i;
-  for (i = 0; i < nfds; i++) {
-    close(ufds[i].fd);
-  }
-  free(ufds);
-  ufds = 0;
-  nfds = 0;
-}
-
-int get_event(struct input_event* event, int timeout) {
-  int res;
-  int i;
-  int pollres;
-  const char* device_path = "/dev/input";
-  while (1) {
-    pollres = poll(ufds, nfds, timeout);
-    if (pollres == 0) {
-      return 1;
-    }
-    if (ufds[0].revents & POLLIN) {
-      read_notify(device_path, ufds[0].fd);
-    }
-    for (i = 1; i < nfds; i++) {
-      if (ufds[i].revents) {
-        if (ufds[i].revents & POLLIN) {
-          res = read(ufds[i].fd, event, sizeof(*event));
-          if (res < static_cast<int>(sizeof(event))) {
-            fprintf(stderr, "could not get event\n");
-            return -1;
-          }
-          return 0;
-        }
-      }
-    }
-  }
-  return 0;
-}
diff --git a/debuggerd/getevent.h b/debuggerd/getevent.h
deleted file mode 100644
index 426139d..0000000
--- a/debuggerd/getevent.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _DEBUGGERD_GETEVENT_H
-#define _DEBUGGERD_GETEVENT_H
-
-int init_getevent();
-void uninit_getevent();
-int get_event(struct input_event* event, int timeout);
-
-#endif // _DEBUGGERD_GETEVENT_H
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
new file mode 100644
index 0000000..6033a6b
--- /dev/null
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "debuggerd/handler.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "private/libc_logging.h"
+
+// see man(2) prctl, specifically the section about PR_GET_NAME
+#define MAX_TASK_NAME_LEN (16)
+
+#if defined(__LP64__)
+#define CRASH_DUMP_NAME "crash_dump64"
+#else
+#define CRASH_DUMP_NAME "crash_dump32"
+#endif
+
+#define CRASH_DUMP_PATH "/system/bin/" CRASH_DUMP_NAME
+
+static debuggerd_callbacks_t g_callbacks;
+
+// Don't use __libc_fatal because it exits via abort, which might put us back into a signal handler.
+#define fatal(...)                                             \
+  do {                                                         \
+    __libc_format_log(ANDROID_LOG_FATAL, "libc", __VA_ARGS__); \
+    _exit(1);                                                  \
+  } while (0)
+
+/*
+ * Writes a summary of the signal to the log file.  We do this so that, if
+ * for some reason we're not able to contact debuggerd, there is still some
+ * indication of the failure in the log.
+ *
+ * We could be here as a result of native heap corruption, or while a
+ * mutex is being held, so we don't want to use any libc functions that
+ * could allocate memory or hold a lock.
+ */
+static void log_signal_summary(int signum, const siginfo_t* info) {
+  const char* signal_name = "???";
+  bool has_address = false;
+  switch (signum) {
+    case SIGABRT:
+      signal_name = "SIGABRT";
+      break;
+    case SIGBUS:
+      signal_name = "SIGBUS";
+      has_address = true;
+      break;
+    case SIGFPE:
+      signal_name = "SIGFPE";
+      has_address = true;
+      break;
+    case SIGILL:
+      signal_name = "SIGILL";
+      has_address = true;
+      break;
+    case SIGSEGV:
+      signal_name = "SIGSEGV";
+      has_address = true;
+      break;
+#if defined(SIGSTKFLT)
+    case SIGSTKFLT:
+      signal_name = "SIGSTKFLT";
+      break;
+#endif
+    case SIGSYS:
+      signal_name = "SIGSYS";
+      break;
+    case SIGTRAP:
+      signal_name = "SIGTRAP";
+      break;
+  }
+
+  char thread_name[MAX_TASK_NAME_LEN + 1];  // one more for termination
+  if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) {
+    strcpy(thread_name, "<name unknown>");
+  } else {
+    // short names are null terminated by prctl, but the man page
+    // implies that 16 byte names are not.
+    thread_name[MAX_TASK_NAME_LEN] = 0;
+  }
+
+  // "info" will be null if the siginfo_t information was not available.
+  // Many signals don't have an address or a code.
+  char code_desc[32];  // ", code -6"
+  char addr_desc[32];  // ", fault addr 0x1234"
+  addr_desc[0] = code_desc[0] = 0;
+  if (info != nullptr) {
+    __libc_format_buffer(code_desc, sizeof(code_desc), ", code %d", info->si_code);
+    if (has_address) {
+      __libc_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
+    }
+  }
+  __libc_format_log(ANDROID_LOG_FATAL, "libc", "Fatal signal %d (%s)%s%s in tid %d (%s)", signum,
+                    signal_name, code_desc, addr_desc, gettid(), thread_name);
+}
+
+/*
+ * Returns true if the handler for signal "signum" has SA_SIGINFO set.
+ */
+static bool have_siginfo(int signum) {
+  struct sigaction old_action;
+  if (sigaction(signum, nullptr, &old_action) < 0) {
+    __libc_format_log(ANDROID_LOG_WARN, "libc", "Failed testing for SA_SIGINFO: %s",
+                      strerror(errno));
+    return false;
+  }
+  return (old_action.sa_flags & SA_SIGINFO) != 0;
+}
+
+struct debugger_thread_info {
+  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+  bool crash_dump_started = false;
+  pid_t crashing_tid;
+  pid_t pseudothread_tid;
+  int signal_number;
+  siginfo_t* info;
+};
+
+// Logging and contacting debuggerd requires free file descriptors, which we might not have.
+// Work around this by spawning a "thread" that shares its parent's address space, but not its file
+// descriptor table, so that we can close random file descriptors without affecting the original
+// process. Note that this doesn't go through pthread_create, so TLS is shared with the spawning
+// process.
+static void* pseudothread_stack;
+
+static int debuggerd_dispatch_pseudothread(void* arg) {
+  debugger_thread_info* thread_info = static_cast<debugger_thread_info*>(arg);
+
+  for (int i = 0; i < 1024; ++i) {
+    close(i);
+  }
+
+  int devnull = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
+
+  // devnull will be 0.
+  TEMP_FAILURE_RETRY(dup2(devnull, STDOUT_FILENO));
+  TEMP_FAILURE_RETRY(dup2(devnull, STDERR_FILENO));
+
+  int pipefds[2];
+  if (pipe(pipefds) != 0) {
+    fatal("failed to create pipe");
+  }
+
+  // Don't use fork(2) to avoid calling pthread_atfork handlers.
+  int forkpid = clone(nullptr, nullptr, SIGCHLD, nullptr);
+  if (forkpid == -1) {
+    __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to fork in debuggerd signal handler: %s",
+                      strerror(errno));
+  } else if (forkpid == 0) {
+    TEMP_FAILURE_RETRY(dup2(pipefds[1], STDOUT_FILENO));
+    close(pipefds[0]);
+    close(pipefds[1]);
+
+    char buf[10];
+    snprintf(buf, sizeof(buf), "%d", thread_info->crashing_tid);
+    execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, buf, nullptr);
+
+    fatal("exec failed: %s", strerror(errno));
+  } else {
+    close(pipefds[1]);
+    char buf[4];
+    ssize_t rc = TEMP_FAILURE_RETRY(read(pipefds[0], &buf, sizeof(buf)));
+    if (rc == -1) {
+      __libc_format_log(ANDROID_LOG_FATAL, "libc", "read of IPC pipe failed: %s", strerror(errno));
+    } else if (rc == 0) {
+      __libc_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper failed to exec");
+    } else if (rc != 1) {
+      __libc_format_log(ANDROID_LOG_FATAL, "libc",
+                        "read of IPC pipe returned unexpected value: %zd", rc);
+    } else {
+      if (buf[0] != '\1') {
+        __libc_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper reported failure");
+      } else {
+        thread_info->crash_dump_started = true;
+      }
+    }
+    close(pipefds[0]);
+
+    // Don't leave a zombie child.
+    siginfo_t child_siginfo;
+    if (TEMP_FAILURE_RETRY(waitid(P_PID, forkpid, &child_siginfo, WEXITED)) != 0) {
+      __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s",
+                        strerror(errno));
+      thread_info->crash_dump_started = false;
+    }
+  }
+
+  pthread_mutex_unlock(&thread_info->mutex);
+  return 0;
+}
+
+// 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));
+    return;
+  }
+
+  // It's possible somebody cleared the SA_SIGINFO flag, which would mean
+  // our "info" arg holds an undefined value.
+  if (!have_siginfo(signal_number)) {
+    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;
+  if (!info) {
+    memset(&si, 0, sizeof(si));
+    si.si_code = SI_USER;
+    si.si_pid = getpid();
+    si.si_uid = getuid();
+    info = &si;
+  } else if (info->si_code >= 0 || info->si_code == SI_TKILL) {
+    // rt_tgsigqueueinfo(2)'s documentation appears to be incorrect on kernels
+    // that contain commit 66dd34a (3.9+). The manpage claims to only allow
+    // negative si_code values that are not SI_TKILL, but 66dd34a changed the
+    // check to allow all si_code values in calls coming from inside the house.
+  }
+
+  // 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));
+    }
+  }
+
+  if (signal_number == DEBUGGER_SIGNAL) {
+    pthread_mutex_unlock(&crash_mutex);
+  }
+}
+
+void debuggerd_init(debuggerd_callbacks_t* callbacks) {
+  if (callbacks) {
+    g_callbacks = *callbacks;
+  }
+
+  void* thread_stack_allocation =
+    mmap(nullptr, PAGE_SIZE * 3, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+  if (thread_stack_allocation == MAP_FAILED) {
+    fatal("failed to allocate debuggerd thread stack");
+  }
+
+  char* stack = static_cast<char*>(thread_stack_allocation) + PAGE_SIZE;
+  if (mprotect(stack, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) {
+    fatal("failed to mprotect debuggerd thread stack");
+  }
+
+  // Stack grows negatively, set it to the last byte in the page...
+  stack = (stack + PAGE_SIZE - 1);
+  // and align it.
+  stack -= 15;
+  pseudothread_stack = stack;
+
+  struct sigaction action;
+  memset(&action, 0, sizeof(action));
+  sigfillset(&action.sa_mask);
+  action.sa_sigaction = debuggerd_signal_handler;
+  action.sa_flags = SA_RESTART | SA_SIGINFO;
+
+  // 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);
+}
diff --git a/debuggerd/include/debuggerd/client.h b/debuggerd/include/debuggerd/client.h
index aeb723b..91f143b 100644
--- a/debuggerd/include/debuggerd/client.h
+++ b/debuggerd/include/debuggerd/client.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 The Android Open Source Project
+ * Copyright 2016, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,44 +16,21 @@
 
 #pragma once
 
-#include <stdint.h>
+#include <stdbool.h>
 #include <sys/cdefs.h>
-#include <sys/types.h>
+#include <unistd.h>
 
-// On 32-bit devices, DEBUGGER_SOCKET_NAME is a 32-bit debuggerd.
-// On 64-bit devices, DEBUGGER_SOCKET_NAME is a 64-bit debuggerd.
-#define DEBUGGER_SOCKET_NAME "android:debuggerd"
+#include <android-base/unique_fd.h>
 
-// Used only on 64-bit devices for debuggerd32.
-#define DEBUGGER32_SOCKET_NAME "android:debuggerd32"
+enum DebuggerdDumpType {
+  kDebuggerdBacktrace,
+  kDebuggerdTombstone,
+};
 
-__BEGIN_DECLS
+// Trigger a dump of specified process to output_fd.
+// output_fd is *not* consumed, timeouts <= 0 will wait forever.
+bool debuggerd_trigger_dump(pid_t pid, android::base::unique_fd output_fd,
+                            enum DebuggerdDumpType dump_type, int timeout_ms);
 
-typedef enum {
-  // dump a crash
-  DEBUGGER_ACTION_CRASH,
-  // dump a tombstone file
-  DEBUGGER_ACTION_DUMP_TOMBSTONE,
-  // dump a backtrace only back to the socket
-  DEBUGGER_ACTION_DUMP_BACKTRACE,
-} debugger_action_t;
-
-// Make sure that all values have a fixed size so that this structure
-// is the same for 32 bit and 64 bit processes.
-typedef struct __attribute__((packed)) {
-  int32_t action;
-  pid_t tid;
-  pid_t ignore_tid;
-  uint64_t abort_msg_address;
-} debugger_msg_t;
-
-// These callbacks are called in a signal handler, and thus must be async signal safe.
-// If null, the callbacks will not be called.
-typedef struct {
-  struct abort_msg_t* (*get_abort_message)();
-  void (*post_dump)();
-} debuggerd_callbacks_t;
-
-void debuggerd_init(debuggerd_callbacks_t* callbacks);
-
-__END_DECLS
+int dump_backtrace_to_file(pid_t tid, int fd);
+int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs);
diff --git a/debuggerd/include/debuggerd/handler.h b/debuggerd/include/debuggerd/handler.h
new file mode 100644
index 0000000..302f4c2
--- /dev/null
+++ b/debuggerd/include/debuggerd/handler.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <signal.h>
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+// These callbacks are called in a signal handler, and thus must be async signal safe.
+// If null, the callbacks will not be called.
+typedef struct {
+  struct abort_msg_t* (*get_abort_message)();
+  void (*post_dump)();
+} debuggerd_callbacks_t;
+
+void debuggerd_init(debuggerd_callbacks_t* callbacks);
+
+// DEBUGGER_ACTION_DUMP_TOMBSTONE and DEBUGGER_ACTION_DUMP_BACKTRACE are both
+// triggered via DEBUGGER_SIGNAL. The debugger_action_t is sent via si_value
+// using sigqueue(2) or equivalent. If no si_value is specified (e.g. if the
+// signal is sent by kill(2)), the default behavior is to print the backtrace
+// to the log.
+#define DEBUGGER_SIGNAL (__SIGRTMIN + 3)
+
+__END_DECLS
diff --git a/debuggerd/include/debuggerd/protocol.h b/debuggerd/include/debuggerd/protocol.h
new file mode 100644
index 0000000..bb2ab0d
--- /dev/null
+++ b/debuggerd/include/debuggerd/protocol.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+// Sockets in the ANDROID_SOCKET_NAMESPACE_RESERVED namespace.
+// Both sockets are SOCK_SEQPACKET sockets, so no explicit length field is needed.
+constexpr char kTombstonedCrashSocketName[] = "tombstoned_crash";
+constexpr char kTombstonedInterceptSocketName[] = "tombstoned_intercept";
+
+enum class CrashPacketType : uint8_t {
+  // Initial request from crash_dump.
+  kDumpRequest = 0,
+
+  // Notification of a completed crash dump.
+  // Sent after a dump is completed and the process has been untraced, but
+  // before it has been resumed with SIGCONT.
+  kCompletedDump,
+
+  // Responses to kRequest.
+  // kPerformDump sends along an output fd via cmsg(3).
+  kPerformDump = 128,
+  kAbortDump,
+};
+
+struct DumpRequest {
+  int32_t pid;
+};
+
+// The full packet must always be written, regardless of whether the union is used.
+struct TombstonedCrashPacket {
+  CrashPacketType packet_type;
+  union {
+    DumpRequest dump_request;
+  } packet;
+};
+
+// Comes with a file descriptor via SCM_RIGHTS.
+// This packet should be sent before an actual dump happens.
+struct InterceptRequest {
+  int32_t pid;
+};
+
+// Sent either immediately upon failure, or when the intercept has been used.
+struct InterceptResponse {
+  uint8_t success;          // 0 or 1
+  char error_message[127];  // always null-terminated
+};
diff --git a/debuggerd/include/debuggerd/util.h b/debuggerd/include/debuggerd/util.h
new file mode 100644
index 0000000..6051714
--- /dev/null
+++ b/debuggerd/include/debuggerd/util.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <android-base/unique_fd.h>
+
+// *** WARNING ***
+// tombstoned's sockets are SOCK_SEQPACKET sockets.
+// Short reads are treated as errors and short writes are assumed to not happen.
+
+// Sends a packet with an attached fd.
+ssize_t send_fd(int sockfd, const void* _Nonnull data, size_t len, android::base::unique_fd fd);
+
+// Receives a packet and optionally, its attached fd.
+// If out_fd is non-null, packets can optionally have an attached fd.
+// If out_fd is null, received packets must not have an attached fd.
+//
+// Errors:
+//   EOVERFLOW: sockfd is SOCK_DGRAM or SOCK_SEQPACKET and buffer is too small.
+//              The first len bytes of the packet are stored in data, but the
+//              rest of the packet is dropped.
+//   ERANGE:    too many file descriptors were attached to the packet.
+//   ENOMSG:    not enough file descriptors were attached to the packet.
+//
+//   plus any errors returned by the underlying recvmsg.
+ssize_t recv_fd(int sockfd, void* _Nonnull data, size_t len,
+                android::base::unique_fd* _Nullable out_fd);
+
+bool Pipe(android::base::unique_fd* read, android::base::unique_fd* write);
diff --git a/debuggerd/arm/machine.cpp b/debuggerd/libdebuggerd/arm/machine.cpp
similarity index 98%
rename from debuggerd/arm/machine.cpp
rename to debuggerd/libdebuggerd/arm/machine.cpp
index 292edcb..78c2306 100644
--- a/debuggerd/arm/machine.cpp
+++ b/debuggerd/libdebuggerd/arm/machine.cpp
@@ -22,8 +22,8 @@
 #include <string.h>
 #include <sys/ptrace.h>
 
-#include <android/log.h>
 #include <backtrace/Backtrace.h>
+#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
diff --git a/debuggerd/arm64/machine.cpp b/debuggerd/libdebuggerd/arm64/machine.cpp
similarity index 98%
rename from debuggerd/arm64/machine.cpp
rename to debuggerd/libdebuggerd/arm64/machine.cpp
index cd1bd52..e7bf79a 100644
--- a/debuggerd/arm64/machine.cpp
+++ b/debuggerd/libdebuggerd/arm64/machine.cpp
@@ -24,8 +24,8 @@
 #include <sys/ptrace.h>
 #include <sys/uio.h>
 
-#include <android/log.h>
 #include <backtrace/Backtrace.h>
+#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
diff --git a/debuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
similarity index 98%
rename from debuggerd/backtrace.cpp
rename to debuggerd/libdebuggerd/backtrace.cpp
index 06c1efe..0664442 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -31,8 +31,8 @@
 #include <memory>
 #include <string>
 
-#include <android/log.h>
 #include <backtrace/Backtrace.h>
+#include <log/log.h>
 
 #include "backtrace.h"
 
diff --git a/debuggerd/elf_utils.cpp b/debuggerd/libdebuggerd/elf_utils.cpp
similarity index 99%
rename from debuggerd/elf_utils.cpp
rename to debuggerd/libdebuggerd/elf_utils.cpp
index d760a37..4e798e2 100644
--- a/debuggerd/elf_utils.cpp
+++ b/debuggerd/libdebuggerd/elf_utils.cpp
@@ -23,9 +23,9 @@
 
 #include <string>
 
-#include <android/log.h>
 #include <android-base/stringprintf.h>
 #include <backtrace/Backtrace.h>
+#include <log/log.h>
 
 #include "elf_utils.h"
 
diff --git a/debuggerd/backtrace.h b/debuggerd/libdebuggerd/include/backtrace.h
similarity index 100%
rename from debuggerd/backtrace.h
rename to debuggerd/libdebuggerd/include/backtrace.h
diff --git a/debuggerd/elf_utils.h b/debuggerd/libdebuggerd/include/elf_utils.h
similarity index 100%
rename from debuggerd/elf_utils.h
rename to debuggerd/libdebuggerd/include/elf_utils.h
diff --git a/debuggerd/machine.h b/debuggerd/libdebuggerd/include/machine.h
similarity index 100%
rename from debuggerd/machine.h
rename to debuggerd/libdebuggerd/include/machine.h
diff --git a/debuggerd/open_files_list.h b/debuggerd/libdebuggerd/include/open_files_list.h
similarity index 100%
rename from debuggerd/open_files_list.h
rename to debuggerd/libdebuggerd/include/open_files_list.h
diff --git a/debuggerd/tombstone.h b/debuggerd/libdebuggerd/include/tombstone.h
similarity index 97%
rename from debuggerd/tombstone.h
rename to debuggerd/libdebuggerd/include/tombstone.h
index 126f804..4ff24af 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/libdebuggerd/include/tombstone.h
@@ -23,6 +23,8 @@
 #include <set>
 #include <string>
 
+#include "open_files_list.h"
+
 class BacktraceMap;
 
 /* Create and open a tombstone file for writing.
diff --git a/debuggerd/utility.h b/debuggerd/libdebuggerd/include/utility.h
similarity index 96%
rename from debuggerd/utility.h
rename to debuggerd/libdebuggerd/include/utility.h
index f7a3f73..bbc4546 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/utility.h
@@ -18,6 +18,7 @@
 #ifndef _DEBUGGERD_UTILITY_H
 #define _DEBUGGERD_UTILITY_H
 
+#include <signal.h>
 #include <stdbool.h>
 #include <sys/types.h>
 
@@ -78,7 +79,7 @@
 void _LOG(log_t* log, logtype ltype, const char *fmt, ...)
         __attribute__ ((format(printf, 3, 4)));
 
-int wait_for_signal(pid_t tid);
+bool wait_for_signal(pid_t tid, siginfo_t* siginfo);
 
 void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...);
 
diff --git a/debuggerd/mips/machine.cpp b/debuggerd/libdebuggerd/mips/machine.cpp
similarity index 99%
rename from debuggerd/mips/machine.cpp
rename to debuggerd/libdebuggerd/mips/machine.cpp
index 99a9d65..cbf272a 100644
--- a/debuggerd/mips/machine.cpp
+++ b/debuggerd/libdebuggerd/mips/machine.cpp
@@ -22,8 +22,8 @@
 #include <string.h>
 #include <sys/ptrace.h>
 
-#include <android/log.h>
 #include <backtrace/Backtrace.h>
+#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
diff --git a/debuggerd/mips64/machine.cpp b/debuggerd/libdebuggerd/mips64/machine.cpp
similarity index 99%
rename from debuggerd/mips64/machine.cpp
rename to debuggerd/libdebuggerd/mips64/machine.cpp
index ecd1ca2..0a8d532 100644
--- a/debuggerd/mips64/machine.cpp
+++ b/debuggerd/libdebuggerd/mips64/machine.cpp
@@ -22,8 +22,8 @@
 #include <string.h>
 #include <sys/ptrace.h>
 
-#include <android/log.h>
 #include <backtrace/Backtrace.h>
+#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
diff --git a/debuggerd/open_files_list.cpp b/debuggerd/libdebuggerd/open_files_list.cpp
similarity index 98%
rename from debuggerd/open_files_list.cpp
rename to debuggerd/libdebuggerd/open_files_list.cpp
index 5ef2abc..5c7ea70 100644
--- a/debuggerd/open_files_list.cpp
+++ b/debuggerd/libdebuggerd/open_files_list.cpp
@@ -29,7 +29,7 @@
 #include <vector>
 
 #include <android-base/file.h>
-#include <android/log.h>
+#include <log/log.h>
 
 #include "open_files_list.h"
 
diff --git a/debuggerd/test/BacktraceMock.h b/debuggerd/libdebuggerd/test/BacktraceMock.h
similarity index 100%
rename from debuggerd/test/BacktraceMock.h
rename to debuggerd/libdebuggerd/test/BacktraceMock.h
diff --git a/debuggerd/test/dump_memory_test.cpp b/debuggerd/libdebuggerd/test/dump_memory_test.cpp
similarity index 100%
rename from debuggerd/test/dump_memory_test.cpp
rename to debuggerd/libdebuggerd/test/dump_memory_test.cpp
diff --git a/debuggerd/test/elf_fake.cpp b/debuggerd/libdebuggerd/test/elf_fake.cpp
similarity index 100%
rename from debuggerd/test/elf_fake.cpp
rename to debuggerd/libdebuggerd/test/elf_fake.cpp
diff --git a/debuggerd/test/elf_fake.h b/debuggerd/libdebuggerd/test/elf_fake.h
similarity index 100%
rename from debuggerd/test/elf_fake.h
rename to debuggerd/libdebuggerd/test/elf_fake.h
diff --git a/debuggerd/test/host_signal_fixup.h b/debuggerd/libdebuggerd/test/host_signal_fixup.h
similarity index 100%
rename from debuggerd/test/host_signal_fixup.h
rename to debuggerd/libdebuggerd/test/host_signal_fixup.h
diff --git a/debuggerd/test/log_fake.cpp b/debuggerd/libdebuggerd/test/log_fake.cpp
similarity index 100%
rename from debuggerd/test/log_fake.cpp
rename to debuggerd/libdebuggerd/test/log_fake.cpp
diff --git a/debuggerd/test/log_fake.h b/debuggerd/libdebuggerd/test/log_fake.h
similarity index 100%
rename from debuggerd/test/log_fake.h
rename to debuggerd/libdebuggerd/test/log_fake.h
diff --git a/debuggerd/test/open_files_list_test.cpp b/debuggerd/libdebuggerd/test/open_files_list_test.cpp
similarity index 100%
rename from debuggerd/test/open_files_list_test.cpp
rename to debuggerd/libdebuggerd/test/open_files_list_test.cpp
diff --git a/debuggerd/test/property_fake.cpp b/debuggerd/libdebuggerd/test/property_fake.cpp
similarity index 100%
rename from debuggerd/test/property_fake.cpp
rename to debuggerd/libdebuggerd/test/property_fake.cpp
diff --git a/debuggerd/test/ptrace_fake.cpp b/debuggerd/libdebuggerd/test/ptrace_fake.cpp
similarity index 100%
rename from debuggerd/test/ptrace_fake.cpp
rename to debuggerd/libdebuggerd/test/ptrace_fake.cpp
diff --git a/debuggerd/test/ptrace_fake.h b/debuggerd/libdebuggerd/test/ptrace_fake.h
similarity index 100%
rename from debuggerd/test/ptrace_fake.h
rename to debuggerd/libdebuggerd/test/ptrace_fake.h
diff --git a/debuggerd/test/sys/system_properties.h b/debuggerd/libdebuggerd/test/sys/system_properties.h
similarity index 100%
rename from debuggerd/test/sys/system_properties.h
rename to debuggerd/libdebuggerd/test/sys/system_properties.h
diff --git a/debuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
similarity index 100%
rename from debuggerd/test/tombstone_test.cpp
rename to debuggerd/libdebuggerd/test/tombstone_test.cpp
diff --git a/debuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
similarity index 98%
rename from debuggerd/tombstone.cpp
rename to debuggerd/libdebuggerd/tombstone.cpp
index e76edb9..01e9cf6 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -32,6 +32,7 @@
 #include <memory>
 #include <string>
 
+#include <android/log.h>
 #include <android-base/stringprintf.h>
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
@@ -39,9 +40,8 @@
 #include <log/log.h>
 #include <log/logprint.h>
 #include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
 
-#include <selinux/android.h>
+#include "debuggerd/handler.h"
 
 #include "backtrace.h"
 #include "elf_utils.h"
@@ -86,6 +86,7 @@
     case SIGSTOP: return "SIGSTOP";
     case SIGSYS: return "SIGSYS";
     case SIGTRAP: return "SIGTRAP";
+    case DEBUGGER_SIGNAL: return "<debuggerd signal>";
     default: return "?";
   }
 }
@@ -625,7 +626,9 @@
                        const OpenFilesList& open_files, pid_t pid, pid_t tid,
                        const std::set<pid_t>& siblings, uintptr_t abort_msg_address) {
   // don't copy log messages to tombstone unless this is a dev device
-  bool want_logs = __android_log_is_debuggable();
+  char value[PROPERTY_VALUE_MAX];
+  property_get("ro.debuggable", value, "0");
+  bool want_logs = (value[0] == '1');
 
   _LOG(log, logtype::HEADER,
        "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
diff --git a/debuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
similarity index 95%
rename from debuggerd/utility.cpp
rename to debuggerd/libdebuggerd/utility.cpp
index 419d36c..57209aa 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -71,21 +71,25 @@
   }
 }
 
-int wait_for_signal(pid_t tid) {
+bool wait_for_signal(pid_t tid, siginfo_t* siginfo) {
   while (true) {
     int status;
     pid_t n = TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL));
     if (n == -1) {
       ALOGE("waitpid failed: tid %d, %s", tid, strerror(errno));
-      return -1;
+      return false;
     } else if (n == tid) {
       if (WIFSTOPPED(status)) {
-        return WSTOPSIG(status);
+        if (ptrace(PTRACE_GETSIGINFO, tid, nullptr, siginfo) != 0) {
+          ALOGE("PTRACE_GETSIGINFO failed: %s", strerror(errno));
+          return false;
+        }
+        return true;
       } else {
         ALOGE("unexpected waitpid response: n=%d, status=%08x\n", n, status);
         // This is the only circumstance under which we can allow a detach
         // to fail with ESRCH, which indicates the tid has exited.
-        return -1;
+        return false;
       }
     }
   }
diff --git a/debuggerd/x86/machine.cpp b/debuggerd/libdebuggerd/x86/machine.cpp
similarity index 98%
rename from debuggerd/x86/machine.cpp
rename to debuggerd/libdebuggerd/x86/machine.cpp
index a6f21e1..af10817 100644
--- a/debuggerd/x86/machine.cpp
+++ b/debuggerd/libdebuggerd/x86/machine.cpp
@@ -21,8 +21,8 @@
 #include <string.h>
 #include <sys/ptrace.h>
 
-#include <android/log.h>
 #include <backtrace/Backtrace.h>
+#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
diff --git a/debuggerd/x86_64/machine.cpp b/debuggerd/libdebuggerd/x86_64/machine.cpp
similarity index 98%
rename from debuggerd/x86_64/machine.cpp
rename to debuggerd/libdebuggerd/x86_64/machine.cpp
index 705e12d..bf2c2b4 100644
--- a/debuggerd/x86_64/machine.cpp
+++ b/debuggerd/libdebuggerd/x86_64/machine.cpp
@@ -18,12 +18,12 @@
 
 #include <errno.h>
 #include <stdint.h>
-#include <sys/ptrace.h>
 #include <string.h>
+#include <sys/ptrace.h>
 #include <sys/user.h>
 
-#include <android/log.h>
 #include <backtrace/Backtrace.h>
+#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
diff --git a/debuggerd/signal_sender.cpp b/debuggerd/signal_sender.cpp
index 7fe4dee..42a8e77 100644
--- a/debuggerd/signal_sender.cpp
+++ b/debuggerd/signal_sender.cpp
@@ -27,7 +27,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "signal_sender.h"
 
diff --git a/debuggerd/signal_sender.h b/debuggerd/signal_sender.h
deleted file mode 100644
index 0443272..0000000
--- a/debuggerd/signal_sender.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _DEBUGGERD_SIGNAL_SENDER_H
-#define _DEBUGGERD_SIGNAL_SENDER_H
-
-#include <sys/types.h>
-
-bool start_signal_sender();
-bool stop_signal_sender();
-
-// Sends a signal to a target process or thread.
-// If tid is greater than zero, this performs tgkill(pid, tid, signal).
-// Otherwise, it performs kill(pid, signal).
-bool send_signal(pid_t pid, pid_t tid, int signal);
-
-#endif
diff --git a/debuggerd/test/selinux/android.h b/debuggerd/test/selinux/android.h
deleted file mode 100644
index abed087..0000000
--- a/debuggerd/test/selinux/android.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-extern "C" int selinux_android_restorecon(const char*, unsigned int);
diff --git a/debuggerd/test/selinux_fake.cpp b/debuggerd/test/selinux_fake.cpp
deleted file mode 100644
index acdd0a9..0000000
--- a/debuggerd/test/selinux_fake.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-extern "C" int selinux_android_restorecon(const char*, unsigned int) {
-  return 0;
-}
diff --git a/debuggerd/tombstoned/intercept_manager.cpp b/debuggerd/tombstoned/intercept_manager.cpp
new file mode 100644
index 0000000..789260d
--- /dev/null
+++ b/debuggerd/tombstoned/intercept_manager.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "intercept_manager.h"
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+#include <unordered_map>
+
+#include <event2/event.h>
+#include <event2/listener.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <cutils/sockets.h>
+
+#include "debuggerd/protocol.h"
+#include "debuggerd/util.h"
+
+using android::base::unique_fd;
+
+static void intercept_close_cb(evutil_socket_t sockfd, short event, void* arg) {
+  auto intercept = reinterpret_cast<Intercept*>(arg);
+  InterceptManager* intercept_manager = intercept->intercept_manager;
+
+  CHECK_EQ(sockfd, intercept->sockfd.get());
+
+  // If we can read, either we received unexpected data from the other side, or the other side
+  // closed their end of the socket. Either way, kill the intercept.
+
+  // Ownership of intercept differs based on whether we've registered it with InterceptManager.
+  if (!intercept->registered) {
+    delete intercept;
+  } else {
+    auto it = intercept_manager->intercepts.find(intercept->intercept_pid);
+    if (it == intercept_manager->intercepts.end()) {
+      LOG(FATAL) << "intercept close callback called after intercept was already removed?";
+    }
+    if (it->second.get() != intercept) {
+      LOG(FATAL) << "intercept close callback has different Intercept from InterceptManager?";
+    }
+
+    const char* reason;
+    if ((event & EV_TIMEOUT) != 0) {
+      reason = "due to timeout";
+    } else {
+      reason = "due to input";
+    }
+
+    LOG(INFO) << "intercept for pid " << intercept->intercept_pid << " terminated " << reason;
+    intercept_manager->intercepts.erase(it);
+  }
+}
+
+static void intercept_request_cb(evutil_socket_t sockfd, short ev, void* arg) {
+  auto intercept = reinterpret_cast<Intercept*>(arg);
+  InterceptManager* intercept_manager = intercept->intercept_manager;
+
+  CHECK_EQ(sockfd, intercept->sockfd.get());
+
+  if ((ev & EV_TIMEOUT) != 0) {
+    LOG(WARNING) << "tombstoned didn't receive InterceptRequest before timeout";
+    goto fail;
+  } else if ((ev & EV_READ) == 0) {
+    LOG(WARNING) << "tombstoned received unexpected event on intercept socket";
+    goto fail;
+  }
+
+  {
+    unique_fd rcv_fd;
+    InterceptRequest intercept_request;
+    ssize_t result = recv_fd(sockfd, &intercept_request, sizeof(intercept_request), &rcv_fd);
+
+    if (result == -1) {
+      PLOG(WARNING) << "failed to read from intercept socket";
+      goto fail;
+    } else if (result != sizeof(intercept_request)) {
+      LOG(WARNING) << "intercept socket received short read of length " << result << " (expected "
+                   << sizeof(intercept_request) << ")";
+      goto fail;
+    }
+
+    // Move the received FD to the upper half, in order to more easily notice FD leaks.
+    int moved_fd = fcntl(rcv_fd.get(), F_DUPFD, 512);
+    if (moved_fd == -1) {
+      LOG(WARNING) << "failed to move received fd (" << rcv_fd.get() << ")";
+      goto fail;
+    }
+    rcv_fd.reset(moved_fd);
+
+    // We trust the other side, so only do minimal validity checking.
+    if (intercept_request.pid <= 0 || intercept_request.pid > std::numeric_limits<pid_t>::max()) {
+      InterceptResponse response = {};
+      snprintf(response.error_message, sizeof(response.error_message), "invalid pid %" PRId32,
+               intercept_request.pid);
+      TEMP_FAILURE_RETRY(write(sockfd, &response, sizeof(response)));
+      goto fail;
+    }
+
+    intercept->intercept_pid = intercept_request.pid;
+
+    // Register the intercept with the InterceptManager.
+    if (intercept_manager->intercepts.count(intercept_request.pid) > 0) {
+      InterceptResponse response = {};
+      snprintf(response.error_message, sizeof(response.error_message),
+               "pid %" PRId32 " already intercepted", intercept_request.pid);
+      TEMP_FAILURE_RETRY(write(sockfd, &response, sizeof(response)));
+      LOG(WARNING) << response.error_message;
+      goto fail;
+    }
+
+    intercept->output_fd = std::move(rcv_fd);
+    intercept_manager->intercepts[intercept_request.pid] = std::unique_ptr<Intercept>(intercept);
+    intercept->registered = true;
+
+    LOG(INFO) << "tombstoned registered intercept for pid " << intercept_request.pid;
+
+    // Register a different read event on the socket so that we can remove intercepts if the socket
+    // closes (e.g. if a user CTRL-C's the process that requested the intercept).
+    event_assign(intercept->intercept_event, intercept_manager->base, sockfd, EV_READ | EV_TIMEOUT,
+                 intercept_close_cb, arg);
+
+    struct timeval timeout = { .tv_sec = 10, .tv_usec = 0 };
+    event_add(intercept->intercept_event, &timeout);
+  }
+
+  return;
+
+fail:
+  delete intercept;
+}
+
+static void intercept_accept_cb(evconnlistener* listener, evutil_socket_t sockfd, sockaddr*, int,
+                                void* arg) {
+  Intercept* intercept = new Intercept();
+  intercept->intercept_manager = static_cast<InterceptManager*>(arg);
+  intercept->sockfd.reset(sockfd);
+
+  struct timeval timeout = { 1, 0 };
+  event_base* base = evconnlistener_get_base(listener);
+  event* intercept_event =
+    event_new(base, sockfd, EV_TIMEOUT | EV_READ, intercept_request_cb, intercept);
+  intercept->intercept_event = intercept_event;
+  event_add(intercept_event, &timeout);
+}
+
+InterceptManager::InterceptManager(event_base* base, int intercept_socket) : base(base) {
+  this->listener = evconnlistener_new(base, intercept_accept_cb, this, -1, LEV_OPT_CLOSE_ON_FREE,
+                                      intercept_socket);
+}
+
+bool InterceptManager::GetIntercept(pid_t pid, android::base::unique_fd* out_fd) {
+  auto it = this->intercepts.find(pid);
+  if (it == this->intercepts.end()) {
+    return false;
+  }
+
+  auto intercept = std::move(it->second);
+  this->intercepts.erase(it);
+
+  LOG(INFO) << "found intercept fd " << intercept->output_fd.get() << " for pid " << pid;
+  InterceptResponse response = {};
+  response.success = 1;
+  TEMP_FAILURE_RETRY(write(intercept->sockfd, &response, sizeof(response)));
+  *out_fd = std::move(intercept->output_fd);
+
+  return true;
+}
diff --git a/debuggerd/tombstoned/intercept_manager.h b/debuggerd/tombstoned/intercept_manager.h
new file mode 100644
index 0000000..cb5db62
--- /dev/null
+++ b/debuggerd/tombstoned/intercept_manager.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+
+#include <unordered_map>
+
+#include <event2/event.h>
+#include <event2/listener.h>
+
+#include <android-base/unique_fd.h>
+
+struct InterceptManager;
+
+struct Intercept {
+  ~Intercept() {
+    event_free(intercept_event);
+  }
+
+  InterceptManager* intercept_manager = nullptr;
+  event* intercept_event = nullptr;
+  android::base::unique_fd sockfd;
+
+  pid_t intercept_pid = -1;
+  android::base::unique_fd output_fd;
+  bool registered = false;
+};
+
+struct InterceptManager {
+  event_base* base;
+  std::unordered_map<pid_t, std::unique_ptr<Intercept>> intercepts;
+  evconnlistener* listener = nullptr;
+
+  InterceptManager(event_base* _Nonnull base, int intercept_socket);
+  InterceptManager(InterceptManager& copy) = delete;
+  InterceptManager(InterceptManager&& move) = delete;
+
+  bool GetIntercept(pid_t pid, android::base::unique_fd* out_fd);
+};
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
new file mode 100644
index 0000000..3c1dcaf
--- /dev/null
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <array>
+#include <deque>
+#include <unordered_map>
+
+#include <event2/event.h>
+#include <event2/listener.h>
+#include <event2/thread.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <cutils/sockets.h>
+
+#include "debuggerd/protocol.h"
+#include "debuggerd/util.h"
+
+#include "intercept_manager.h"
+
+using android::base::StringPrintf;
+using android::base::unique_fd;
+
+static InterceptManager* intercept_manager;
+
+enum CrashStatus {
+  kCrashStatusRunning,
+  kCrashStatusQueued,
+};
+
+// Ownership of Crash is a bit messy.
+// It's either owned by an active event that must have a timeout, or owned by
+// queued_requests, in the case that multiple crashes come in at the same time.
+struct Crash {
+  ~Crash() {
+    event_free(crash_event);
+  }
+
+  unique_fd crash_fd;
+  pid_t crash_pid;
+  event* crash_event = nullptr;
+};
+
+static constexpr char kTombstoneDirectory[] = "/data/tombstones/";
+static constexpr size_t kTombstoneCount = 10;
+static int tombstone_directory_fd = -1;
+static int next_tombstone = 0;
+
+static constexpr size_t kMaxConcurrentDumps = 1;
+static size_t num_concurrent_dumps = 0;
+
+static std::deque<Crash*> queued_requests;
+
+// Forward declare the callbacks so they can be placed in a sensible order.
+static void crash_accept_cb(evconnlistener* listener, evutil_socket_t sockfd, sockaddr*, int, void*);
+static void crash_request_cb(evutil_socket_t sockfd, short ev, void* arg);
+static void crash_completed_cb(evutil_socket_t sockfd, short ev, void* arg);
+
+static void find_oldest_tombstone() {
+  size_t oldest_tombstone = 0;
+  time_t oldest_time = std::numeric_limits<time_t>::max();
+
+  for (size_t i = 0; i < kTombstoneCount; ++i) {
+    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 (st.st_mtime < oldest_time) {
+      oldest_tombstone = i;
+      oldest_time = st.st_mtime;
+    }
+  }
+
+  next_tombstone = oldest_tombstone;
+}
+
+static unique_fd get_tombstone_fd() {
+  // If kMaxConcurrentDumps is greater than 1, then theoretically the same
+  // filename could be handed out to multiple processes. Unlink and create the
+  // file, instead of using O_TRUNC, to avoid two processes interleaving their
+  // output.
+  unique_fd result;
+  char buf[PATH_MAX];
+  snprintf(buf, sizeof(buf), "tombstone_%02d", next_tombstone);
+  if (unlinkat(tombstone_directory_fd, buf, 0) != 0 && errno != ENOENT) {
+    PLOG(FATAL) << "failed to unlink tombstone at " << kTombstoneDirectory << buf;
+  }
+
+  result.reset(
+    openat(tombstone_directory_fd, buf, O_CREAT | O_EXCL | O_WRONLY | O_APPEND, O_CLOEXEC, 0700));
+  if (result == -1) {
+    PLOG(FATAL) << "failed to create tombstone at " << kTombstoneDirectory << buf;
+  }
+
+  next_tombstone = (next_tombstone + 1) % kTombstoneCount;
+  return result;
+}
+
+static void dequeue_request(Crash* crash) {
+  ++num_concurrent_dumps;
+
+  unique_fd output_fd;
+  if (!intercept_manager->GetIntercept(crash->crash_pid, &output_fd)) {
+    output_fd = get_tombstone_fd();
+  }
+
+  TombstonedCrashPacket response = {
+    .packet_type = CrashPacketType::kPerformDump
+  };
+  ssize_t rc = send_fd(crash->crash_fd, &response, sizeof(response), std::move(output_fd));
+  if (rc == -1) {
+    PLOG(WARNING) << "failed to send response to CrashRequest";
+    goto fail;
+  } else if (rc != sizeof(response)) {
+    PLOG(WARNING) << "crash socket write returned short";
+    goto fail;
+  } else {
+    // TODO: Make this configurable by the interceptor?
+    struct timeval timeout = { 10, 0 };
+
+    event_base* base = event_get_base(crash->crash_event);
+    event_assign(crash->crash_event, base, crash->crash_fd, EV_TIMEOUT | EV_READ,
+                 crash_completed_cb, crash);
+    event_add(crash->crash_event, &timeout);
+  }
+  return;
+
+fail:
+  delete crash;
+}
+
+static void crash_accept_cb(evconnlistener* listener, evutil_socket_t sockfd, sockaddr*, int,
+                            void*) {
+  event_base* base = evconnlistener_get_base(listener);
+  Crash* crash = new Crash();
+
+  struct timeval timeout = { 1, 0 };
+  event* crash_event = event_new(base, sockfd, EV_TIMEOUT | EV_READ, crash_request_cb, crash);
+  crash->crash_fd.reset(sockfd);
+  crash->crash_event = crash_event;
+  event_add(crash_event, &timeout);
+}
+
+static void crash_request_cb(evutil_socket_t sockfd, short ev, void* arg) {
+  ssize_t rc;
+  Crash* crash = static_cast<Crash*>(arg);
+  TombstonedCrashPacket request = {};
+
+  if ((ev & EV_TIMEOUT) != 0) {
+    LOG(WARNING) << "crash request timed out";
+    goto fail;
+  } else if ((ev & EV_READ) == 0) {
+    LOG(WARNING) << "tombstoned received unexpected event from crash socket";
+    goto fail;
+  }
+
+  rc = TEMP_FAILURE_RETRY(read(sockfd, &request, sizeof(request)));
+  if (rc == -1) {
+    PLOG(WARNING) << "failed to read from crash socket";
+    goto fail;
+  } else if (rc != sizeof(request)) {
+    LOG(WARNING) << "crash socket received short read of length " << rc << " (expected "
+                 << sizeof(request) << ")";
+    goto fail;
+  }
+
+  if (request.packet_type != CrashPacketType::kDumpRequest) {
+    LOG(WARNING) << "unexpected crash packet type, expected kDumpRequest, received  "
+                 << StringPrintf("%#2hhX", request.packet_type);
+    goto fail;
+  }
+
+  crash->crash_pid = request.packet.dump_request.pid;
+  LOG(INFO) << "received crash request for pid " << crash->crash_pid;
+
+  if (num_concurrent_dumps == kMaxConcurrentDumps) {
+    LOG(INFO) << "enqueueing crash request for pid " << crash->crash_pid;
+    queued_requests.push_back(crash);
+  } else {
+    dequeue_request(crash);
+  }
+
+  return;
+
+fail:
+  delete crash;
+}
+
+static void crash_completed_cb(evutil_socket_t sockfd, short ev, void* arg) {
+  ssize_t rc;
+  Crash* crash = static_cast<Crash*>(arg);
+  TombstonedCrashPacket request = {};
+
+  --num_concurrent_dumps;
+
+  if ((ev & EV_READ) == 0) {
+    goto fail;
+  }
+
+  rc = TEMP_FAILURE_RETRY(read(sockfd, &request, sizeof(request)));
+  if (rc == -1) {
+    PLOG(WARNING) << "failed to read from crash socket";
+    goto fail;
+  } else if (rc != sizeof(request)) {
+    LOG(WARNING) << "crash socket received short read of length " << rc << " (expected "
+                 << sizeof(request) << ")";
+    goto fail;
+  }
+
+  if (request.packet_type != CrashPacketType::kCompletedDump) {
+    LOG(WARNING) << "unexpected crash packet type, expected kCompletedDump, received "
+                 << uint32_t(request.packet_type);
+    goto fail;
+  }
+
+fail:
+  delete crash;
+
+  // If there's something queued up, let them proceed.
+  if (!queued_requests.empty()) {
+    Crash* next_crash = queued_requests.front();
+    queued_requests.pop_front();
+    dequeue_request(next_crash);
+  }
+}
+
+int main(int, char* []) {
+  tombstone_directory_fd = open(kTombstoneDirectory, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+  if (tombstone_directory_fd == -1) {
+    PLOG(FATAL) << "failed to open tombstone directory";
+  }
+
+  find_oldest_tombstone();
+
+  int intercept_socket = android_get_control_socket(kTombstonedInterceptSocketName);
+  int crash_socket = android_get_control_socket(kTombstonedCrashSocketName);
+
+  if (intercept_socket == -1 || crash_socket == -1) {
+    PLOG(FATAL) << "failed to get socket from init";
+  }
+
+  evutil_make_socket_nonblocking(intercept_socket);
+  evutil_make_socket_nonblocking(crash_socket);
+
+  event_base* base = event_base_new();
+  if (!base) {
+    LOG(FATAL) << "failed to create event_base";
+  }
+
+  intercept_manager = new InterceptManager(base, intercept_socket);
+
+  evconnlistener* listener =
+    evconnlistener_new(base, crash_accept_cb, nullptr, -1, LEV_OPT_CLOSE_ON_FREE, crash_socket);
+  if (!listener) {
+    LOG(FATAL) << "failed to create evconnlistener";
+  }
+
+  LOG(INFO) << "tombstoned successfully initialized";
+  event_base_dispatch(base);
+}
diff --git a/debuggerd/tombstoned/tombstoned.rc b/debuggerd/tombstoned/tombstoned.rc
new file mode 100644
index 0000000..3aacf33
--- /dev/null
+++ b/debuggerd/tombstoned/tombstoned.rc
@@ -0,0 +1,9 @@
+service tombstoned /system/bin/tombstoned
+    class core
+
+    user tombstoned
+    group system
+
+    socket tombstoned_crash seqpacket 0666 system system
+    socket tombstoned_intercept seqpacket 0666 system system
+    writepid /dev/cpuset/system-background/tasks
diff --git a/debuggerd/util.cpp b/debuggerd/util.cpp
new file mode 100644
index 0000000..738abdf
--- /dev/null
+++ b/debuggerd/util.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "debuggerd/util.h"
+
+#include <sys/socket.h>
+
+#include <utility>
+
+#include <android-base/unique_fd.h>
+#include <cutils/sockets.h>
+
+ssize_t send_fd(int sockfd, const void* data, size_t len, android::base::unique_fd fd) {
+  char cmsg_buf[CMSG_SPACE(sizeof(int))];
+
+  iovec iov = { .iov_base = const_cast<void*>(data), .iov_len = len };
+  msghdr msg = {
+    .msg_iov = &iov, .msg_iovlen = 1, .msg_control = cmsg_buf, .msg_controllen = sizeof(cmsg_buf),
+  };
+  auto cmsg = CMSG_FIRSTHDR(&msg);
+  cmsg->cmsg_level = SOL_SOCKET;
+  cmsg->cmsg_type = SCM_RIGHTS;
+  cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+  *reinterpret_cast<int*>(CMSG_DATA(cmsg)) = fd.get();
+
+  return TEMP_FAILURE_RETRY(sendmsg(sockfd, &msg, 0));
+}
+
+ssize_t recv_fd(int sockfd, void* _Nonnull data, size_t len,
+                android::base::unique_fd* _Nullable out_fd) {
+  char cmsg_buf[CMSG_SPACE(sizeof(int))];
+
+  iovec iov = { .iov_base = const_cast<void*>(data), .iov_len = len };
+  msghdr msg = {
+    .msg_iov = &iov,
+    .msg_iovlen = 1,
+    .msg_control = cmsg_buf,
+    .msg_controllen = sizeof(cmsg_buf),
+    .msg_flags = 0,
+  };
+  auto cmsg = CMSG_FIRSTHDR(&msg);
+  cmsg->cmsg_level = SOL_SOCKET;
+  cmsg->cmsg_type = SCM_RIGHTS;
+  cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+
+  ssize_t result = TEMP_FAILURE_RETRY(recvmsg(sockfd, &msg, 0));
+  if (result == -1) {
+    return -1;
+  }
+
+  android::base::unique_fd fd;
+  bool received_fd = msg.msg_controllen == sizeof(cmsg_buf);
+  if (received_fd) {
+    fd.reset(*reinterpret_cast<int*>(CMSG_DATA(cmsg)));
+  }
+
+  if ((msg.msg_flags & MSG_TRUNC) != 0) {
+    errno = EFBIG;
+    return -1;
+  } else if ((msg.msg_flags & MSG_CTRUNC) != 0) {
+    errno = ERANGE;
+    return -1;
+  }
+
+  if (out_fd) {
+    *out_fd = std::move(fd);
+  } else if (received_fd) {
+    errno = ERANGE;
+    return -1;
+  }
+
+  return result;
+}
+
+bool Pipe(android::base::unique_fd* read, android::base::unique_fd* write) {
+  int pipefds[2];
+  if (pipe(pipefds) != 0) {
+    return false;
+  }
+  read->reset(pipefds[0]);
+  write->reset(pipefds[1]);
+  return true;
+}
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 286de5b..5610cc0 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -57,8 +57,8 @@
 
 LOCAL_STATIC_LIBRARIES := \
     libziparchive \
-    libext4_utils_host \
-    libsparse_host \
+    libext4_utils \
+    libsparse \
     libutils \
     liblog \
     libz \
diff --git a/fastboot/README.md b/fastboot/README.md
new file mode 100644
index 0000000..022d34b
--- /dev/null
+++ b/fastboot/README.md
@@ -0,0 +1,453 @@
+Fastboot
+--------
+
+The fastboot protocol is a mechanism for communicating with bootloaders
+over USB or ethernet.  It is designed to be very straightforward to implement,
+to allow it to be used across a wide range of devices and from hosts running
+Linux, macOS, or Windows.
+
+
+## Basic Requirements
+
+* USB
+  * Two bulk endpoints (in, out) are required
+  * Max packet size must be 64 bytes for full-speed, 512 bytes for
+    high-speed and 1024 bytes for Super Speed USB.
+  * The protocol is entirely host-driven and synchronous (unlike the
+    multi-channel, bi-directional, asynchronous ADB protocol)
+
+* TCP or UDP
+  * Device must be reachable via IP.
+  * Device will act as the server, fastboot will be the client.
+  * Fastboot data is wrapped in a simple protocol; see below for details.
+
+
+## Transport and Framing
+
+1. Host sends a command, which is an ascii string in a single
+   packet no greater than 64 bytes.
+
+2. Client response with a single packet no greater than 64 bytes.
+   The first four bytes of the response are "OKAY", "FAIL", "DATA",
+   or "INFO".  Additional bytes may contain an (ascii) informative
+   message.
+
+   a. INFO -> the remaining 60 bytes are an informative message
+      (providing progress or diagnostic messages).  They should
+      be displayed and then step #2 repeats
+
+   b. FAIL -> the requested command failed.  The remaining 60 bytes
+      of the response (if present) provide a textual failure message
+      to present to the user.  Stop.
+
+   c. OKAY -> the requested command completed successfully.  Go to #5
+
+   d. DATA -> the requested command is ready for the data phase.
+      A DATA response packet will be 12 bytes long, in the form of
+      DATA00000000 where the 8 digit hexadecimal number represents
+      the total data size to transfer.
+
+3. Data phase.  Depending on the command, the host or client will
+   send the indicated amount of data.  Short packets are always
+   acceptable and zero-length packets are ignored.  This phase continues
+   until the client has sent or received the number of bytes indicated
+   in the "DATA" response above.
+
+4. Client responds with a single packet no greater than 64 bytes.
+   The first four bytes of the response are "OKAY", "FAIL", or "INFO".
+   Similar to #2:
+
+   a. INFO -> display the remaining 60 bytes and return to #4
+
+   b. FAIL -> display the remaining 60 bytes (if present) as a failure
+      reason and consider the command failed.  Stop.
+
+   c. OKAY -> success.  Go to #5
+
+5. Success.  Stop.
+
+
+## Example Session
+
+    Host:    "getvar:version"        request version variable
+
+    Client:  "OKAY0.4"               return version "0.4"
+
+    Host:    "getvar:nonexistant"    request some undefined variable
+
+    Client:  "FAILUnknown variable"  getvar failure; see getvar details below
+
+    Host:    "download:00001234"     request to send 0x1234 bytes of data
+
+    Client:  "DATA00001234"          ready to accept data
+
+    Host:    < 0x1234 bytes >        send data
+
+    Client:  "OKAY"                  success
+
+    Host:    "flash:bootloader"      request to flash the data to the bootloader
+
+    Client:  "INFOerasing flash"     indicate status / progress
+             "INFOwriting flash"
+             "OKAY"                  indicate success
+
+    Host:    "powerdown"             send a command
+
+    Client:  "FAILunknown command"   indicate failure
+
+
+## Command Reference
+
+* Command parameters are indicated by printf-style escape sequences.
+
+* Commands are ascii strings and sent without the quotes (which are
+  for illustration only here) and without a trailing 0 byte.
+
+* Commands that begin with a lowercase letter are reserved for this
+  specification.  OEM-specific commands should not begin with a
+  lowercase letter, to prevent incompatibilities with future specs.
+
+The various currently defined commands are:
+
+    getvar:%s          Read a config/version variable from the bootloader.
+                       The variable contents will be returned after the
+                       OKAY response. If the variable is unknown, the bootloader
+                       should return a FAIL response, optionally with an error
+                       message.
+
+                       Previous versions of this document indicated that getvar
+                       should return an empty OKAY response for unknown
+                       variables, so older devices might exhibit this behavior,
+                       but new implementations should return FAIL instead.
+
+    download:%08x      Write data to memory which will be later used
+                       by "boot", "ramdisk", "flash", etc.  The client
+                       will reply with "DATA%08x" if it has enough
+                       space in RAM or "FAIL" if not.  The size of
+                       the download is remembered.
+
+    verify:%08x        Send a digital signature to verify the downloaded
+                       data.  Required if the bootloader is "secure"
+                       otherwise "flash" and "boot" will be ignored.
+
+    flash:%s           Write the previously downloaded image to the
+                       named partition (if possible).
+
+    erase:%s           Erase the indicated partition (clear to 0xFFs)
+
+    boot               The previously downloaded data is a boot.img
+                       and should be booted according to the normal
+                       procedure for a boot.img
+
+    continue           Continue booting as normal (if possible)
+
+    reboot             Reboot the device.
+
+    reboot-bootloader
+                       Reboot back into the bootloader.
+                       Useful for upgrade processes that require upgrading
+                       the bootloader and then upgrading other partitions
+                       using the new bootloader.
+
+    powerdown          Power off the device.
+
+
+
+## Client Variables
+
+The "getvar:%s" command is used to read client variables which
+represent various information about the device and the software
+on it.
+
+The various currently defined names are:
+
+    version             Version of FastBoot protocol supported.
+                        It should be "0.4" for this document.
+
+    version-bootloader  Version string for the Bootloader.
+
+    version-baseband    Version string of the Baseband Software
+
+    product             Name of the product
+
+    serialno            Product serial number
+
+    secure              If the value is "yes", this is a secure
+                        bootloader requiring a signature before
+                        it will install or boot images.
+
+Names starting with a lowercase character are reserved by this
+specification.  OEM-specific names should not start with lowercase
+characters.
+
+
+## TCP Protocol v1
+
+The TCP protocol is designed to be a simple way to use the fastboot protocol
+over ethernet if USB is not available.
+
+The device will open a TCP server on port 5554 and wait for a fastboot client
+to connect.
+
+### Handshake
+Upon connecting, both sides will send a 4-byte handshake message to ensure they
+are speaking the same protocol. This consists of the ASCII characters "FB"
+followed by a 2-digit base-10 ASCII version number. For example, the version 1
+handshake message will be [FB01].
+
+If either side detects a malformed handshake, it should disconnect.
+
+The protocol version to use must be the minimum of the versions sent by each
+side; if either side cannot speak this protocol version, it should disconnect.
+
+### Fastboot Data
+Once the handshake is complete, fastboot data will be sent as follows:
+
+    [data_size][data]
+
+Where data\_size is an unsigned 8-byte big-endian binary value, and data is the
+fastboot packet. The 8-byte length is intended to provide future-proofing even
+though currently fastboot packets have a 4-byte maximum length.
+
+### Example
+In this example the fastboot host queries the device for two variables,
+"version" and "none".
+
+    Host    <connect to the device on port 5555>
+    Host    FB01
+    Device  FB01
+    Host    [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x0E]getvar:version
+    Device  [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x07]OKAY0.4
+    Host    [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x0B]getvar:none
+    Device  [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x14]FAILUnknown variable
+    Host    <disconnect>
+
+
+## UDP Protocol v1
+
+The UDP protocol is more complex than TCP since we must implement reliability
+to ensure no packets are lost, but the general concept of wrapping the fastboot
+protocol is the same.
+
+Overview:
+  1. As with TCP, the device will listen on UDP port 5554.
+  2. Maximum UDP packet size is negotiated during initialization.
+  3. The host drives all communication; the device may only send a packet as a
+     response to a host packet.
+  4. If the host does not receive a response in 500ms it will re-transmit.
+
+### UDP Packet format
+
+    +----------+----+-------+-------+--------------------+
+    | Byte #   | 0  |   1   | 2 - 3 |  4+                |
+    +----------+----+-------+-------+--------------------+
+    | Contents | ID | Flags | Seq # | Data               |
+    +----------+----+-------+-------+--------------------+
+
+    ID      Packet ID:
+              0x00: Error.
+              0x01: Query.
+              0x02: Initialization.
+              0x03: Fastboot.
+
+            Packet types are described in more detail below.
+
+    Flags   Packet flags: 0 0 0 0 0 0 0 C
+              C=1 indicates a continuation packet; the data is too large and will
+                  continue in the next packet.
+
+              Remaining bits are reserved for future use and must be set to 0.
+
+    Seq #   2-byte packet sequence number (big-endian). The host will increment
+            this by 1 with each new packet, and the device must provide the
+            corresponding sequence number in the response packets.
+
+    Data    Packet data, not present in all packets.
+
+### Packet Types
+
+    Query
+          The host sends a query packet once on startup to sync with the device.
+          The host will not know the current sequence number, so the device must
+          respond to all query packets regardless of sequence number.
+
+          The response data field should contain a 2-byte big-endian value
+          giving the next expected sequence number.
+
+    Init
+          The host sends an init packet once the query response is returned. The
+          device must abort any in-progress operation and prepare for a new
+          fastboot session. This message is meant to allow recovery if a
+          previous session failed, e.g. due to network error or user Ctrl+C.
+
+          The data field contains two big-endian 2-byte values, a protocol
+          version and the max UDP packet size (including the 4-byte header).
+          Both the host and device will send these values, and in each case
+          the minimum of the sent values must be used.
+
+    Fastboot
+          These packets wrap the fastboot protocol. To write, the host will
+          send a packet with fastboot data, and the device will reply with an
+          empty packet as an ACK. To read, the host will send an empty packet,
+          and the device will reply with fastboot data. The device may not give
+          any data in the ACK packet.
+
+    Error
+          The device may respond to any packet with an error packet to indicate
+          a UDP protocol error. The data field should contain an ASCII string
+          describing the error. This is the only case where a device is allowed
+          to return a packet ID other than the one sent by the host.
+
+### Packet Size
+The maximum packet size is negotiated by the host and device in the Init packet.
+Devices must support at least 512-byte packets, but packet size has a direct
+correlation with download speed, so devices are strongly suggested to support at
+least 1024-byte packets. On a local network with 0.5ms round-trip time this will
+provide transfer rates of ~2MB/s. Over WiFi it will likely be significantly
+less.
+
+Query and Initialization packets, which are sent before size negotiation is
+complete, must always be 512 bytes or less.
+
+### Packet Re-Transmission
+The host will re-transmit any packet that does not receive a response. The
+requirement of exactly one device response packet per host packet is how we
+achieve reliability and in-order delivery of packets.
+
+For simplicity of implementation, there is no windowing of multiple
+unacknowledged packets in this version of the protocol. The host will continue
+to send the same packet until a response is received. Windowing functionality
+may be implemented in future versions if necessary to increase performance.
+
+The first Query packet will only be attempted a small number of times, but
+subsequent packets will attempt to retransmit for at least 1 minute before
+giving up. This means a device may safely ignore host UDP packets for up to 1
+minute during long operations, e.g. writing to flash.
+
+### Continuation Packets
+Any packet may set the continuation flag to indicate that the data is
+incomplete. Large data such as downloading an image may require many
+continuation packets. The receiver should respond to a continuation packet with
+an empty packet to acknowledge receipt. See examples below.
+
+### Summary
+The host starts with a Query packet, then an Initialization packet, after
+which only Fastboot packets are sent. Fastboot packets may contain data from
+the host for writes, or from the device for reads, but not both.
+
+Given a next expected sequence number S and a received packet P, the device
+behavior should be:
+
+    if P is a Query packet:
+      * respond with a Query packet with S in the data field
+    else if P has sequence == S:
+      * process P and take any required action
+      * create a response packet R with the same ID and sequence as P, containing
+        any response data required.
+      * transmit R and save it in case of re-transmission
+      * increment S
+    else if P has sequence == S - 1:
+      * re-transmit the saved response packet R from above
+    else:
+      * ignore the packet
+
+### Examples
+
+In the examples below, S indicates the starting client sequence number.
+
+    Host                                    Client
+    ======================================================================
+    [Initialization, S = 0x55AA]
+    [Host: version 1, 2048-byte packets. Client: version 2, 1024-byte packets.]
+    [Resulting values to use: version = 1, max packet size = 1024]
+    ID   Flag SeqH SeqL Data                ID   Flag SeqH SeqL Data
+    ----------------------------------------------------------------------
+    0x01 0x00 0x00 0x00
+                                            0x01 0x00 0x00 0x00 0x55 0xAA
+    0x02 0x00 0x55 0xAA 0x00 0x01 0x08 0x00
+                                            0x02 0x00 0x55 0xAA 0x00 0x02 0x04 0x00
+
+    ----------------------------------------------------------------------
+    [fastboot "getvar" commands, S = 0x0001]
+    ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
+    ----------------------------------------------------------------------
+    0x03  0x00  0x00  0x01  getvar:version
+                                            0x03  0x00  0x00  0x01
+    0x03  0x00  0x00  0x02
+                                            0x03  0x00  0x00  0x02  OKAY0.4
+    0x03  0x00  0x00  0x03  getvar:none
+                                            0x03  0x00  0x00  0x03
+    0x03  0x00  0x00  0x04
+                                            0x03  0x00  0x00  0x04  FAILUnknown var
+
+    ----------------------------------------------------------------------
+    [fastboot "INFO" responses, S = 0x0000]
+    ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
+    ----------------------------------------------------------------------
+    0x03  0x00  0x00  0x00  <command>
+                                            0x03  0x00  0x00  0x00
+    0x03  0x00  0x00  0x01
+                                            0x03  0x00  0x00  0x01  INFOWait1
+    0x03  0x00  0x00  0x02
+                                            0x03  0x00  0x00  0x02  INFOWait2
+    0x03  0x00  0x00  0x03
+                                            0x03  0x00  0x00  0x03  OKAY
+
+    ----------------------------------------------------------------------
+    [Chunking 2100 bytes of data, max packet size = 1024, S = 0xFFFF]
+    ID   Flag SeqH SeqL Data                ID   Flag SeqH SeqL Data
+    ----------------------------------------------------------------------
+    0x03 0x00 0xFF 0xFF download:0000834
+                                            0x03 0x00 0xFF 0xFF
+    0x03 0x00 0x00 0x00
+                                            0x03 0x00 0x00 0x00 DATA0000834
+    0x03 0x01 0x00 0x01 <1020 bytes>
+                                            0x03 0x00 0x00 0x01
+    0x03 0x01 0x00 0x02 <1020 bytes>
+                                            0x03 0x00 0x00 0x02
+    0x03 0x00 0x00 0x03 <60 bytes>
+                                            0x03 0x00 0x00 0x03
+    0x03 0x00 0x00 0x04
+                                            0x03 0x00 0x00 0x04 OKAY
+
+    ----------------------------------------------------------------------
+    [Unknown ID error, S = 0x0000]
+    ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
+    ----------------------------------------------------------------------
+    0x10  0x00  0x00  0x00
+                                            0x00  0x00  0x00  0x00  <error message>
+
+    ----------------------------------------------------------------------
+    [Host packet loss and retransmission, S = 0x0000]
+    ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
+    ----------------------------------------------------------------------
+    0x03  0x00  0x00  0x00  getvar:version [lost]
+    0x03  0x00  0x00  0x00  getvar:version [lost]
+    0x03  0x00  0x00  0x00  getvar:version
+                                            0x03  0x00  0x00  0x00
+    0x03  0x00  0x00  0x01
+                                            0x03  0x00  0x00  0x01  OKAY0.4
+
+    ----------------------------------------------------------------------
+    [Client packet loss and retransmission, S = 0x0000]
+    ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
+    ----------------------------------------------------------------------
+    0x03  0x00  0x00  0x00  getvar:version
+                                            0x03  0x00  0x00  0x00 [lost]
+    0x03  0x00  0x00  0x00  getvar:version
+                                            0x03  0x00  0x00  0x00 [lost]
+    0x03  0x00  0x00  0x00  getvar:version
+                                            0x03  0x00  0x00  0x00
+    0x03  0x00  0x00  0x01
+                                            0x03  0x00  0x00  0x01  OKAY0.4
+
+    ----------------------------------------------------------------------
+    [Host packet delayed, S = 0x0000]
+    ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
+    ----------------------------------------------------------------------
+    0x03  0x00  0x00  0x00  getvar:version [delayed]
+    0x03  0x00  0x00  0x00  getvar:version
+                                            0x03  0x00  0x00  0x00
+    0x03  0x00  0x00  0x01
+                                            0x03  0x00  0x00  0x01  OKAY0.4
+    0x03  0x00  0x00  0x00  getvar:version [arrives late with old seq#, is ignored]
diff --git a/fastboot/fastboot_protocol.txt b/fastboot/fastboot_protocol.txt
deleted file mode 100644
index b12e420..0000000
--- a/fastboot/fastboot_protocol.txt
+++ /dev/null
@@ -1,449 +0,0 @@
-FastBoot  Version  0.4
-----------------------
-
-The fastboot protocol is a mechanism for communicating with bootloaders
-over USB or ethernet.  It is designed to be very straightforward to implement,
-to allow it to be used across a wide range of devices and from hosts running
-Linux, Windows, or OSX.
-
-
-Basic Requirements
-------------------
-
-* USB
-  * Two bulk endpoints (in, out) are required
-  * Max packet size must be 64 bytes for full-speed, 512 bytes for
-    high-speed and 1024 bytes for Super Speed USB.
-  * The protocol is entirely host-driven and synchronous (unlike the
-    multi-channel, bi-directional, asynchronous ADB protocol)
-
-* TCP or UDP
-  * Device must be reachable via IP.
-  * Device will act as the server, fastboot will be the client.
-  * Fastboot data is wrapped in a simple protocol; see below for details.
-
-
-Transport and Framing
----------------------
-
-1. Host sends a command, which is an ascii string in a single
-   packet no greater than 64 bytes.
-
-2. Client response with a single packet no greater than 64 bytes.
-   The first four bytes of the response are "OKAY", "FAIL", "DATA", 
-   or "INFO".  Additional bytes may contain an (ascii) informative
-   message.
-
-   a. INFO -> the remaining 60 bytes are an informative message
-      (providing progress or diagnostic messages).  They should 
-      be displayed and then step #2 repeats
-
-   b. FAIL -> the requested command failed.  The remaining 60 bytes 
-      of the response (if present) provide a textual failure message 
-      to present to the user.  Stop.
-
-   c. OKAY -> the requested command completed successfully.  Go to #5
-
-   d. DATA -> the requested command is ready for the data phase.
-      A DATA response packet will be 12 bytes long, in the form of
-      DATA00000000 where the 8 digit hexadecimal number represents
-      the total data size to transfer.
-
-3. Data phase.  Depending on the command, the host or client will 
-   send the indicated amount of data.  Short packets are always 
-   acceptable and zero-length packets are ignored.  This phase continues
-   until the client has sent or received the number of bytes indicated
-   in the "DATA" response above.
-
-4. Client responds with a single packet no greater than 64 bytes.  
-   The first four bytes of the response are "OKAY", "FAIL", or "INFO".  
-   Similar to #2:
-
-   a. INFO -> display the remaining 60 bytes and return to #4
-   
-   b. FAIL -> display the remaining 60 bytes (if present) as a failure
-      reason and consider the command failed.  Stop.
-
-   c. OKAY -> success.  Go to #5
-
-5. Success.  Stop.
-
-
-Example Session
----------------
-
-Host:    "getvar:version"        request version variable
-
-Client:  "OKAY0.4"               return version "0.4"
-
-Host:    "getvar:nonexistant"    request some undefined variable
-
-Client:  "FAILUnknown variable"  getvar failure; see getvar details below
-
-Host:    "download:00001234"     request to send 0x1234 bytes of data
-
-Client:  "DATA00001234"          ready to accept data
-
-Host:    < 0x1234 bytes >        send data
-
-Client:  "OKAY"                  success
-
-Host:    "flash:bootloader"      request to flash the data to the bootloader
-
-Client:  "INFOerasing flash"     indicate status / progress
-         "INFOwriting flash"
-         "OKAY"                  indicate success
-
-Host:    "powerdown"             send a command
-
-Client:  "FAILunknown command"   indicate failure
-
-
-Command Reference
------------------
-
-* Command parameters are indicated by printf-style escape sequences.
-
-* Commands are ascii strings and sent without the quotes (which are
-  for illustration only here) and without a trailing 0 byte.
-
-* Commands that begin with a lowercase letter are reserved for this
-  specification.  OEM-specific commands should not begin with a 
-  lowercase letter, to prevent incompatibilities with future specs.
-
- "getvar:%s"           Read a config/version variable from the bootloader.
-                       The variable contents will be returned after the
-                       OKAY response. If the variable is unknown, the bootloader
-                       should return a FAIL response, optionally with an error
-                       message.
-
-                       Previous versions of this document indicated that getvar
-                       should return an empty OKAY response for unknown
-                       variables, so older devices might exhibit this behavior,
-                       but new implementations should return FAIL instead.
-
- "download:%08x"       Write data to memory which will be later used
-                       by "boot", "ramdisk", "flash", etc.  The client
-                       will reply with "DATA%08x" if it has enough 
-                       space in RAM or "FAIL" if not.  The size of
-                       the download is remembered.
-
-  "verify:%08x"        Send a digital signature to verify the downloaded
-                       data.  Required if the bootloader is "secure"
-                       otherwise "flash" and "boot" will be ignored.
-
-  "flash:%s"           Write the previously downloaded image to the
-                       named partition (if possible).
-
-  "erase:%s"           Erase the indicated partition (clear to 0xFFs)
-
-  "boot"               The previously downloaded data is a boot.img
-                       and should be booted according to the normal
-                       procedure for a boot.img
-
-  "continue"           Continue booting as normal (if possible)
-
-  "reboot"             Reboot the device.
-
-  "reboot-bootloader"  Reboot back into the bootloader.
-                       Useful for upgrade processes that require upgrading
-                       the bootloader and then upgrading other partitions
-                       using the new bootloader.
-
-  "powerdown"          Power off the device.
-
-
-
-Client Variables
-----------------
-
-The "getvar:%s" command is used to read client variables which
-represent various information about the device and the software
-on it.
-
-The various currently defined names are:
-
-  version             Version of FastBoot protocol supported.
-                      It should be "0.4" for this document.
-
-  version-bootloader  Version string for the Bootloader.
-
-  version-baseband    Version string of the Baseband Software
-
-  product             Name of the product
-
-  serialno            Product serial number
-
-  secure              If the value is "yes", this is a secure
-                      bootloader requiring a signature before
-                      it will install or boot images.
-
-Names starting with a lowercase character are reserved by this
-specification.  OEM-specific names should not start with lowercase
-characters.
-
-
-TCP Protocol v1
----------------
-
-The TCP protocol is designed to be a simple way to use the fastboot protocol
-over ethernet if USB is not available.
-
-The device will open a TCP server on port 5554 and wait for a fastboot client
-to connect.
-
--- Handshake --
-Upon connecting, both sides will send a 4-byte handshake message to ensure they
-are speaking the same protocol. This consists of the ASCII characters "FB"
-followed by a 2-digit base-10 ASCII version number. For example, the version 1
-handshake message will be [FB01].
-
-If either side detects a malformed handshake, it should disconnect.
-
-The protocol version to use must be the minimum of the versions sent by each
-side; if either side cannot speak this protocol version, it should disconnect.
-
--- Fastboot Data --
-Once the handshake is complete, fastboot data will be sent as follows:
-
-  [data_size][data]
-
-Where data_size is an unsigned 8-byte big-endian binary value, and data is the
-fastboot packet. The 8-byte length is intended to provide future-proofing even
-though currently fastboot packets have a 4-byte maximum length.
-
--- Example --
-In this example the fastboot host queries the device for two variables,
-"version" and "none".
-
-Host    <connect to the device on port 5555>
-Host    FB01
-Device  FB01
-Host    [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x0E]getvar:version
-Device  [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x07]OKAY0.4
-Host    [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x0B]getvar:none
-Device  [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x14]FAILUnknown variable
-Host    <disconnect>
-
-
-UDP Protocol v1
----------------
-
-The UDP protocol is more complex than TCP since we must implement reliability
-to ensure no packets are lost, but the general concept of wrapping the fastboot
-protocol is the same.
-
-Overview:
-  1. As with TCP, the device will listen on UDP port 5554.
-  2. Maximum UDP packet size is negotiated during initialization.
-  3. The host drives all communication; the device may only send a packet as a
-     response to a host packet.
-  4. If the host does not receive a response in 500ms it will re-transmit.
-
--- UDP Packet format --
-  +----------+----+-------+-------+--------------------+
-  | Byte #   | 0  |   1   | 2 - 3 |  4+                |
-  +----------+----+-------+-------+--------------------+
-  | Contents | ID | Flags | Seq # | Data               |
-  +----------+----+-------+-------+--------------------+
-
-  ID      Packet ID:
-            0x00: Error.
-            0x01: Query.
-            0x02: Initialization.
-            0x03: Fastboot.
-
-          Packet types are described in more detail below.
-
-  Flags   Packet flags: 0 0 0 0 0 0 0 C
-            C=1 indicates a continuation packet; the data is too large and will
-                continue in the next packet.
-
-            Remaining bits are reserved for future use and must be set to 0.
-
-  Seq #   2-byte packet sequence number (big-endian). The host will increment
-          this by 1 with each new packet, and the device must provide the
-          corresponding sequence number in the response packets.
-
-  Data    Packet data, not present in all packets.
-
--- Packet Types --
-Query     The host sends a query packet once on startup to sync with the device.
-          The host will not know the current sequence number, so the device must
-          respond to all query packets regardless of sequence number.
-
-          The response data field should contain a 2-byte big-endian value
-          giving the next expected sequence number.
-
-Init      The host sends an init packet once the query response is returned. The
-          device must abort any in-progress operation and prepare for a new
-          fastboot session. This message is meant to allow recovery if a
-          previous session failed, e.g. due to network error or user Ctrl+C.
-
-          The data field contains two big-endian 2-byte values, a protocol
-          version and the max UDP packet size (including the 4-byte header).
-          Both the host and device will send these values, and in each case
-          the minimum of the sent values must be used.
-
-Fastboot  These packets wrap the fastboot protocol. To write, the host will
-          send a packet with fastboot data, and the device will reply with an
-          empty packet as an ACK. To read, the host will send an empty packet,
-          and the device will reply with fastboot data. The device may not give
-          any data in the ACK packet.
-
-Error     The device may respond to any packet with an error packet to indicate
-          a UDP protocol error. The data field should contain an ASCII string
-          describing the error. This is the only case where a device is allowed
-          to return a packet ID other than the one sent by the host.
-
--- Packet Size --
-The maximum packet size is negotiated by the host and device in the Init packet.
-Devices must support at least 512-byte packets, but packet size has a direct
-correlation with download speed, so devices are strongly suggested to support at
-least 1024-byte packets. On a local network with 0.5ms round-trip time this will
-provide transfer rates of ~2MB/s. Over WiFi it will likely be significantly
-less.
-
-Query and Initialization packets, which are sent before size negotiation is
-complete, must always be 512 bytes or less.
-
--- Packet Re-Transmission --
-The host will re-transmit any packet that does not receive a response. The
-requirement of exactly one device response packet per host packet is how we
-achieve reliability and in-order delivery of packets.
-
-For simplicity of implementation, there is no windowing of multiple
-unacknowledged packets in this version of the protocol. The host will continue
-to send the same packet until a response is received. Windowing functionality
-may be implemented in future versions if necessary to increase performance.
-
-The first Query packet will only be attempted a small number of times, but
-subsequent packets will attempt to retransmit for at least 1 minute before
-giving up. This means a device may safely ignore host UDP packets for up to 1
-minute during long operations, e.g. writing to flash.
-
--- Continuation Packets --
-Any packet may set the continuation flag to indicate that the data is
-incomplete. Large data such as downloading an image may require many
-continuation packets. The receiver should respond to a continuation packet with
-an empty packet to acknowledge receipt. See examples below.
-
--- Summary --
-The host starts with a Query packet, then an Initialization packet, after
-which only Fastboot packets are sent. Fastboot packets may contain data from
-the host for writes, or from the device for reads, but not both.
-
-Given a next expected sequence number S and a received packet P, the device
-behavior should be:
-  if P is a Query packet:
-    * respond with a Query packet with S in the data field
-  else if P has sequence == S:
-    * process P and take any required action
-    * create a response packet R with the same ID and sequence as P, containing
-      any response data required.
-    * transmit R and save it in case of re-transmission
-    * increment S
-  else if P has sequence == S - 1:
-    * re-transmit the saved response packet R from above
-  else:
-    * ignore the packet
-
--- Examples --
-In the examples below, S indicates the starting client sequence number.
-
-Host                                    Client
-======================================================================
-[Initialization, S = 0x55AA]
-[Host: version 1, 2048-byte packets. Client: version 2, 1024-byte packets.]
-[Resulting values to use: version = 1, max packet size = 1024]
-ID   Flag SeqH SeqL Data                ID   Flag SeqH SeqL Data
-----------------------------------------------------------------------
-0x01 0x00 0x00 0x00
-                                        0x01 0x00 0x00 0x00 0x55 0xAA
-0x02 0x00 0x55 0xAA 0x00 0x01 0x08 0x00
-                                        0x02 0x00 0x55 0xAA 0x00 0x02 0x04 0x00
-
-----------------------------------------------------------------------
-[fastboot "getvar" commands, S = 0x0001]
-ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
-----------------------------------------------------------------------
-0x03  0x00  0x00  0x01  getvar:version
-                                        0x03  0x00  0x00  0x01
-0x03  0x00  0x00  0x02
-                                        0x03  0x00  0x00  0x02  OKAY0.4
-0x03  0x00  0x00  0x03  getvar:none
-                                        0x03  0x00  0x00  0x03
-0x03  0x00  0x00  0x04
-                                        0x03  0x00  0x00  0x04  FAILUnknown var
-
-----------------------------------------------------------------------
-[fastboot "INFO" responses, S = 0x0000]
-ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
-----------------------------------------------------------------------
-0x03  0x00  0x00  0x00  <command>
-                                        0x03  0x00  0x00  0x00
-0x03  0x00  0x00  0x01
-                                        0x03  0x00  0x00  0x01  INFOWait1
-0x03  0x00  0x00  0x02
-                                        0x03  0x00  0x00  0x02  INFOWait2
-0x03  0x00  0x00  0x03
-                                        0x03  0x00  0x00  0x03  OKAY
-
-----------------------------------------------------------------------
-[Chunking 2100 bytes of data, max packet size = 1024, S = 0xFFFF]
-ID   Flag SeqH SeqL Data                ID   Flag SeqH SeqL Data
-----------------------------------------------------------------------
-0x03 0x00 0xFF 0xFF download:0000834
-                                        0x03 0x00 0xFF 0xFF
-0x03 0x00 0x00 0x00
-                                        0x03 0x00 0x00 0x00 DATA0000834
-0x03 0x01 0x00 0x01 <1020 bytes>
-                                        0x03 0x00 0x00 0x01
-0x03 0x01 0x00 0x02 <1020 bytes>
-                                        0x03 0x00 0x00 0x02
-0x03 0x00 0x00 0x03 <60 bytes>
-                                        0x03 0x00 0x00 0x03
-0x03 0x00 0x00 0x04
-                                        0x03 0x00 0x00 0x04 OKAY
-
-----------------------------------------------------------------------
-[Unknown ID error, S = 0x0000]
-ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
-----------------------------------------------------------------------
-0x10  0x00  0x00  0x00
-                                        0x00  0x00  0x00  0x00  <error message>
-
-----------------------------------------------------------------------
-[Host packet loss and retransmission, S = 0x0000]
-ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
-----------------------------------------------------------------------
-0x03  0x00  0x00  0x00  getvar:version [lost]
-0x03  0x00  0x00  0x00  getvar:version [lost]
-0x03  0x00  0x00  0x00  getvar:version
-                                        0x03  0x00  0x00  0x00
-0x03  0x00  0x00  0x01
-                                        0x03  0x00  0x00  0x01  OKAY0.4
-
-----------------------------------------------------------------------
-[Client packet loss and retransmission, S = 0x0000]
-ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
-----------------------------------------------------------------------
-0x03  0x00  0x00  0x00  getvar:version
-                                        0x03  0x00  0x00  0x00 [lost]
-0x03  0x00  0x00  0x00  getvar:version
-                                        0x03  0x00  0x00  0x00 [lost]
-0x03  0x00  0x00  0x00  getvar:version
-                                        0x03  0x00  0x00  0x00
-0x03  0x00  0x00  0x01
-                                        0x03  0x00  0x00  0x01  OKAY0.4
-
-----------------------------------------------------------------------
-[Host packet delayed, S = 0x0000]
-ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
-----------------------------------------------------------------------
-0x03  0x00  0x00  0x00  getvar:version [delayed]
-0x03  0x00  0x00  0x00  getvar:version
-                                        0x03  0x00  0x00  0x00
-0x03  0x00  0x00  0x01
-                                        0x03  0x00  0x00  0x01  OKAY0.4
-0x03  0x00  0x00  0x00  getvar:version [arrives late with old seq#, is ignored]
diff --git a/fingerprintd/fingerprintd.cpp b/fingerprintd/fingerprintd.cpp
index 05109b7..2fc2d0a 100644
--- a/fingerprintd/fingerprintd.cpp
+++ b/fingerprintd/fingerprintd.cpp
@@ -16,7 +16,6 @@
 
 #define LOG_TAG "fingerprintd"
 
-#include <android/log.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/PermissionCache.h>
@@ -25,6 +24,7 @@
 #include <hardware/hw_auth_token.h>
 #include <keystore/IKeystoreService.h>
 #include <keystore/keystore.h> // for error codes
+#include <log/log.h>
 #include <utils/Log.h>
 #include <utils/String16.h>
 
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index d6b699b..8d5b51b 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -9,7 +9,7 @@
     libbase \
     libcrypto_utils \
     libcrypto \
-    libext4_utils_static \
+    libext4_utils \
     libsquashfs_utils \
     libselinux
 
@@ -18,6 +18,7 @@
 LOCAL_SANITIZE := integer
 LOCAL_SRC_FILES:= \
     fs_mgr.c \
+    fs_mgr_dm_ioctl.cpp \
     fs_mgr_format.c \
     fs_mgr_fstab.c \
     fs_mgr_slotselect.c \
@@ -26,12 +27,16 @@
     $(LOCAL_PATH)/include \
     system/vold \
     system/extras/ext4_utils \
-    external/openssl/include \
     bootable/recovery
 LOCAL_MODULE:= libfs_mgr
 LOCAL_STATIC_LIBRARIES := $(common_static_libraries)
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_CFLAGS := -Werror
+ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
+  ifeq ($(TARGET_USES_MKE2FS), true)
+    LOCAL_CFLAGS += -DTARGET_USES_MKE2FS
+  endif
+endif
 ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT)))
 LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
 endif
@@ -52,7 +57,7 @@
     libcutils \
     liblog \
     libc \
-    libsparse_static \
+    libsparse \
     libz \
     libselinux
 LOCAL_CXX_STL := libc++_static
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index ba44a5a..9a53d62 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -101,7 +101,9 @@
     char tmpmnt_opts[64] = "errors=remount-ro";
     char *e2fsck_argv[] = {
         E2FSCK_BIN,
+#ifndef TARGET_USES_MKE2FS // "-f" only for old ext4 generation tool
         "-f",
+#endif
         "-y",
         blk_device
     };
@@ -644,6 +646,17 @@
     }
 }
 
+int fs_mgr_test_access(const char *device) {
+    int tries = 25;
+    while (tries--) {
+        if (!access(device, F_OK) || errno != ENOENT) {
+            return 0;
+        }
+        usleep(40 * 1000);
+    }
+    return -1;
+}
+
 /* When multiple fstab records share the same mount_point, it will
  * try to mount each one in turn, and ignore any duplicates after a
  * first successful mount.
@@ -701,7 +714,7 @@
         }
 
         if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
-            int rc = fs_mgr_setup_verity(&fstab->recs[i]);
+            int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
             if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
                 INFO("Verity disabled");
             } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
@@ -870,7 +883,7 @@
         }
 
         if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
-            int rc = fs_mgr_setup_verity(&fstab->recs[i]);
+            int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
             if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
                 INFO("Verity disabled");
             } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
@@ -1086,7 +1099,7 @@
 int fs_mgr_early_setup_verity(struct fstab_rec *fstab_rec)
 {
     if ((fstab_rec->fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
-        int rc = fs_mgr_setup_verity(fstab_rec);
+        int rc = fs_mgr_setup_verity(fstab_rec, false);
         if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
             INFO("Verity disabled");
             return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY;
diff --git a/fs_mgr/fs_mgr_dm_ioctl.cpp b/fs_mgr/fs_mgr_dm_ioctl.cpp
new file mode 100644
index 0000000..75ce621
--- /dev/null
+++ b/fs_mgr/fs_mgr_dm_ioctl.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <android-base/logging.h>
+#include <sys/ioctl.h>
+
+#include "fs_mgr_priv.h"
+#include "fs_mgr_priv_dm_ioctl.h"
+
+void fs_mgr_verity_ioctl_init(struct dm_ioctl *io,
+                              const std::string &name,
+                              unsigned flags)
+{
+    memset(io, 0, DM_BUF_SIZE);
+    io->data_size = DM_BUF_SIZE;
+    io->data_start = sizeof(struct dm_ioctl);
+    io->version[0] = 4;
+    io->version[1] = 0;
+    io->version[2] = 0;
+    io->flags = flags | DM_READONLY_FLAG;
+    if (!name.empty()) {
+        strlcpy(io->name, name.c_str(), sizeof(io->name));
+    }
+}
+
+bool fs_mgr_create_verity_device(struct dm_ioctl *io,
+                                 const std::string &name,
+                                 int fd)
+{
+    fs_mgr_verity_ioctl_init(io, name, 1);
+    if (ioctl(fd, DM_DEV_CREATE, io)) {
+        ERROR("Error creating device mapping (%s)", strerror(errno));
+        return false;
+    }
+    return true;
+}
+
+bool fs_mgr_destroy_verity_device(struct dm_ioctl *io,
+                                  const std::string &name,
+                                  int fd)
+{
+    fs_mgr_verity_ioctl_init(io, name, 0);
+    if (ioctl(fd, DM_DEV_REMOVE, io)) {
+        ERROR("Error removing device mapping (%s)", strerror(errno));
+        return false;
+    }
+    return true;
+}
+
+bool fs_mgr_get_verity_device_name(struct dm_ioctl *io,
+                                   const std::string &name,
+                                   int fd,
+                                   std::string *out_dev_name)
+{
+    CHECK(out_dev_name != nullptr);
+
+    fs_mgr_verity_ioctl_init(io, name, 0);
+    if (ioctl(fd, DM_DEV_STATUS, io)) {
+        ERROR("Error fetching verity device number (%s)", strerror(errno));
+        return false;
+    }
+
+    int dev_num = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
+    *out_dev_name = "/dev/block/dm-" + std::to_string(dev_num);
+
+    return true;
+}
+
+bool fs_mgr_resume_verity_table(struct dm_ioctl *io,
+                                const std::string &name,
+                                int fd)
+{
+    fs_mgr_verity_ioctl_init(io, name, 0);
+    if (ioctl(fd, DM_DEV_SUSPEND, io)) {
+        ERROR("Error activating verity device (%s)", strerror(errno));
+        return false;
+    }
+    return true;
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index db86afa..7f917d9 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -93,6 +93,7 @@
 #define DM_BUF_SIZE 4096
 
 int fs_mgr_set_blk_ro(const char *blockdev);
+int fs_mgr_test_access(const char *device);
 int fs_mgr_update_for_slotselect(struct fstab *fstab);
 
 __END_DECLS
diff --git a/fs_mgr/fs_mgr_priv_dm_ioctl.h b/fs_mgr/fs_mgr_priv_dm_ioctl.h
new file mode 100644
index 0000000..eeae4dd
--- /dev/null
+++ b/fs_mgr/fs_mgr_priv_dm_ioctl.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CORE_FS_MGR_PRIV_DM_IOCTL_H
+#define __CORE_FS_MGR_PRIV_DM_IOCTL_H
+
+#include <string>
+#include <linux/dm-ioctl.h>
+
+void fs_mgr_verity_ioctl_init(struct dm_ioctl *io,
+                              const std::string &name,
+                              unsigned flags);
+
+bool fs_mgr_create_verity_device(struct dm_ioctl *io,
+                                 const std::string &name,
+                                 int fd);
+
+bool fs_mgr_destroy_verity_device(struct dm_ioctl *io,
+                                  const std::string &name,
+                                  int fd);
+
+bool fs_mgr_get_verity_device_name(struct dm_ioctl *io,
+                                   const std::string &name,
+                                   int fd,
+                                   std::string *out_dev_name);
+
+bool fs_mgr_resume_verity_table(struct dm_ioctl *io,
+                                const std::string &name,
+                                int fd);
+
+#endif /* __CORE_FS_MGR_PRIV_DM_IOCTL_H */
diff --git a/fs_mgr/fs_mgr_priv_verity.h b/fs_mgr/fs_mgr_priv_verity.h
index d9e17bb..1a6d215 100644
--- a/fs_mgr/fs_mgr_priv_verity.h
+++ b/fs_mgr/fs_mgr_priv_verity.h
@@ -22,6 +22,6 @@
 
 __BEGIN_DECLS
 
-int fs_mgr_setup_verity(struct fstab_rec *fstab);
+int fs_mgr_setup_verity(struct fstab_rec *fstab, bool verify_dev);
 
 __END_DECLS
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 031b042..e368a82 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -31,6 +31,7 @@
 
 #include <android-base/file.h>
 #include <android-base/strings.h>
+#include <android-base/unique_fd.h>
 #include <crypto_utils/android_pubkey.h>
 #include <cutils/properties.h>
 #include <logwrap/logwrap.h>
@@ -43,6 +44,7 @@
 
 #include "fs_mgr.h"
 #include "fs_mgr_priv.h"
+#include "fs_mgr_priv_dm_ioctl.h"
 #include "fs_mgr_priv_verity.h"
 
 #define FSTAB_PREFIX "/fstab."
@@ -73,6 +75,8 @@
 #define VERITY_KMSG_RESTART "dm-verity device corrupted"
 #define VERITY_KMSG_BUFSIZE 1024
 
+#define READ_BUF_SIZE 4096
+
 #define __STRINGIFY(x) #x
 #define STRINGIFY(x) __STRINGIFY(x)
 
@@ -181,45 +185,6 @@
     return -1;
 }
 
-static void verity_ioctl_init(struct dm_ioctl *io, const char *name, unsigned flags)
-{
-    memset(io, 0, DM_BUF_SIZE);
-    io->data_size = DM_BUF_SIZE;
-    io->data_start = sizeof(struct dm_ioctl);
-    io->version[0] = 4;
-    io->version[1] = 0;
-    io->version[2] = 0;
-    io->flags = flags | DM_READONLY_FLAG;
-    if (name) {
-        strlcpy(io->name, name, sizeof(io->name));
-    }
-}
-
-static int create_verity_device(struct dm_ioctl *io, char *name, int fd)
-{
-    verity_ioctl_init(io, name, 1);
-    if (ioctl(fd, DM_DEV_CREATE, io)) {
-        ERROR("Error creating device mapping (%s)", strerror(errno));
-        return -1;
-    }
-    return 0;
-}
-
-static int get_verity_device_name(struct dm_ioctl *io, char *name, int fd, char **dev_name)
-{
-    verity_ioctl_init(io, name, 0);
-    if (ioctl(fd, DM_DEV_STATUS, io)) {
-        ERROR("Error fetching verity device number (%s)", strerror(errno));
-        return -1;
-    }
-    int dev_num = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
-    if (asprintf(dev_name, "/dev/block/dm-%u", dev_num) < 0) {
-        ERROR("Error getting verity block device name (%s)", strerror(errno));
-        return -1;
-    }
-    return 0;
-}
-
 struct verity_table_params {
     char *table;
     int mode;
@@ -288,14 +253,15 @@
     return true;
 }
 
-static int load_verity_table(struct dm_ioctl *io, char *name, uint64_t device_size, int fd,
+static int load_verity_table(struct dm_ioctl *io, const std::string &name,
+                             uint64_t device_size, int fd,
         const struct verity_table_params *params, format_verity_table_func format)
 {
     char *verity_params;
     char *buffer = (char*) io;
     size_t bufsize;
 
-    verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG);
+    fs_mgr_verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG);
 
     struct dm_target_spec *tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
 
@@ -331,27 +297,6 @@
     return 0;
 }
 
-static int resume_verity_table(struct dm_ioctl *io, char *name, int fd)
-{
-    verity_ioctl_init(io, name, 0);
-    if (ioctl(fd, DM_DEV_SUSPEND, io)) {
-        ERROR("Error activating verity device (%s)", strerror(errno));
-        return -1;
-    }
-    return 0;
-}
-
-static int test_access(char *device) {
-    int tries = 25;
-    while (tries--) {
-        if (!access(device, F_OK) || errno != ENOENT) {
-            return 0;
-        }
-        usleep(40 * 1000);
-    }
-    return -1;
-}
-
 static int check_verity_restart(const char *fname)
 {
     char buffer[VERITY_KMSG_BUFSIZE + 1];
@@ -606,6 +551,30 @@
     return rc;
 }
 
+static int read_partition(const char *path, uint64_t size)
+{
+    char buf[READ_BUF_SIZE];
+    ssize_t size_read;
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC)));
+
+    if (fd == -1) {
+        ERROR("Failed to open %s: %s\n", path, strerror(errno));
+        return -errno;
+    }
+
+    while (size) {
+        size_read = TEMP_FAILURE_RETRY(read(fd, buf, READ_BUF_SIZE));
+        if (size_read == -1) {
+            ERROR("Error in reading partition %s: %s\n", path,
+                  strerror(errno));
+            return -errno;
+        }
+        size -= size_read;
+    }
+
+    return 0;
+}
+
 static int compare_last_signature(struct fstab_rec *fstab, int *match)
 {
     char tag[METADATA_TAG_MAX_LENGTH + 1];
@@ -786,9 +755,9 @@
     alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
     bool system_root = false;
     char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
-    const char *mount_point;
+    std::string mount_point;
     char propbuf[PROPERTY_VALUE_MAX];
-    char *status;
+    const char *status;
     int fd = -1;
     int i;
     int mode;
@@ -835,18 +804,22 @@
             mount_point = basename(fstab->recs[i].mount_point);
         }
 
-        verity_ioctl_init(io, mount_point, 0);
+        fs_mgr_verity_ioctl_init(io, mount_point, 0);
 
         if (ioctl(fd, DM_TABLE_STATUS, io)) {
-            ERROR("Failed to query DM_TABLE_STATUS for %s (%s)\n", mount_point,
-                strerror(errno));
-            continue;
+            if (fstab->recs[i].fs_mgr_flags & MF_VERIFYATBOOT) {
+                status = "V";
+            } else {
+                ERROR("Failed to query DM_TABLE_STATUS for %s (%s)\n",
+                      mount_point.c_str(), strerror(errno));
+                continue;
+            }
         }
 
         status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
 
         if (*status == 'C' || *status == 'V') {
-            callback(&fstab->recs[i], mount_point, mode, *status);
+            callback(&fstab->recs[i], mount_point.c_str(), mode, *status);
         }
     }
 
@@ -892,18 +865,19 @@
     *table = strdup(result.c_str());
 }
 
-int fs_mgr_setup_verity(struct fstab_rec *fstab)
+int fs_mgr_setup_verity(struct fstab_rec *fstab, bool verify_dev)
 {
     int retval = FS_MGR_SETUP_VERITY_FAIL;
     int fd = -1;
-    char *verity_blk_name = NULL;
+    std::string verity_blk_name;
     struct fec_handle *f = NULL;
     struct fec_verity_metadata verity;
     struct verity_table_params params = { .table = NULL };
 
     alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
     struct dm_ioctl *io = (struct dm_ioctl *) buffer;
-    char *mount_point = basename(fstab->mount_point);
+    const std::string mount_point(basename(fstab->mount_point));
+    bool verified_at_boot = false;
 
     if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
             FEC_DEFAULT_ROOTS) < 0) {
@@ -941,13 +915,13 @@
     }
 
     // create the device
-    if (create_verity_device(io, mount_point, fd) < 0) {
+    if (!fs_mgr_create_verity_device(io, mount_point, fd)) {
         ERROR("Couldn't create verity device!\n");
         goto out;
     }
 
     // get the name of the device file
-    if (get_verity_device_name(io, mount_point, fd, &verity_blk_name) < 0) {
+    if (!fs_mgr_get_verity_device_name(io, mount_point, fd, &verity_blk_name)) {
         ERROR("Couldn't get verity device number!\n");
         goto out;
     }
@@ -983,7 +957,8 @@
         }
     }
 
-    INFO("Enabling dm-verity for %s (mode %d)\n", mount_point, params.mode);
+    INFO("Enabling dm-verity for %s (mode %d)\n",
+         mount_point.c_str(), params.mode);
 
     if (fstab->fs_mgr_flags & MF_SLOTSELECT) {
         // Update the verity params using the actual block device path
@@ -998,7 +973,7 @@
 
     if (params.ecc.valid) {
         // kernel may not support error correction, try without
-        INFO("Disabling error correction for %s\n", mount_point);
+        INFO("Disabling error correction for %s\n", mount_point.c_str());
         params.ecc.valid = false;
 
         if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
@@ -1015,7 +990,7 @@
 
     if (params.mode != VERITY_MODE_EIO) {
         // as a last resort, EIO mode should always be supported
-        INFO("Falling back to EIO mode for %s\n", mount_point);
+        INFO("Falling back to EIO mode for %s\n", mount_point.c_str());
         params.mode = VERITY_MODE_EIO;
 
         if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
@@ -1024,26 +999,41 @@
         }
     }
 
-    ERROR("Failed to load verity table for %s\n", mount_point);
+    ERROR("Failed to load verity table for %s\n", mount_point.c_str());
     goto out;
 
 loaded:
 
     // activate the device
-    if (resume_verity_table(io, mount_point, fd) < 0) {
+    if (!fs_mgr_resume_verity_table(io, mount_point, fd)) {
         goto out;
     }
 
     // mark the underlying block device as read-only
     fs_mgr_set_blk_ro(fstab->blk_device);
 
+    // Verify the entire partition in one go
+    // If there is an error, allow it to mount as a normal verity partition.
+    if (fstab->fs_mgr_flags & MF_VERIFYATBOOT) {
+        INFO("Verifying partition %s at boot\n", fstab->blk_device);
+        int err = read_partition(verity_blk_name.c_str(), verity.data_size);
+        if (!err) {
+            INFO("Verified verity partition %s at boot\n", fstab->blk_device);
+            verified_at_boot = true;
+        }
+    }
+
     // assign the new verity block device as the block device
-    free(fstab->blk_device);
-    fstab->blk_device = verity_blk_name;
-    verity_blk_name = 0;
+    if (!verified_at_boot) {
+        free(fstab->blk_device);
+        fstab->blk_device = strdup(verity_blk_name.c_str());
+    } else if (!fs_mgr_destroy_verity_device(io, mount_point, fd)) {
+        ERROR("Failed to remove verity device %s\n", mount_point.c_str());
+        goto out;
+    }
 
     // make sure we've set everything up properly
-    if (test_access(fstab->blk_device) < 0) {
+    if (verify_dev && fs_mgr_test_access(fstab->blk_device) < 0) {
         goto out;
     }
 
@@ -1056,7 +1046,6 @@
 
     fec_close(f);
     free(params.table);
-    free(verity_blk_name);
 
     return retval;
 }
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index 4107f55..d4a92e5 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -24,7 +24,6 @@
 #include <stdint.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/PermissionCache.h>
@@ -33,6 +32,7 @@
 #include <hardware/hw_auth_token.h>
 #include <keystore/IKeystoreService.h>
 #include <keystore/keystore.h> // For error code
+#include <log/log.h>
 #include <utils/Log.h>
 #include <utils/String16.h>
 
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h
deleted file mode 100644
index 20e8796..0000000
--- a/include/cutils/debugger.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __CUTILS_DEBUGGER_H
-#define __CUTILS_DEBUGGER_H
-
-#include <sys/cdefs.h>
-#include <sys/types.h>
-
-#include "debuggerd/client.h"
-
-__BEGIN_DECLS
-
-/* Dumps a process backtrace, registers, and stack to a tombstone file (requires root).
- * Stores the tombstone path in the provided buffer.
- * Returns 0 on success, -1 on error.
- */
-int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen);
-
-/* Dumps a process backtrace, registers, and stack to a tombstone file (requires root).
- * Stores the tombstone path in the provided buffer.
- * If reading debugger data from debuggerd ever takes longer than timeout_secs
- * seconds, then stop and return an error.
- * Returns 0 on success, -1 on error.
- */
-int dump_tombstone_timeout(pid_t tid, char* pathbuf, size_t pathlen, int timeout_secs);
-
-/* Dumps a process backtrace only to the specified file (requires root).
- * Returns 0 on success, -1 on error.
- */
-int dump_backtrace_to_file(pid_t tid, int fd);
-
-/* Dumps a process backtrace only to the specified file (requires root).
- * If reading debugger data from debuggerd ever takes longer than timeout_secs
- * seconds, then stop and return an error.
- * Returns 0 on success, -1 on error.
- */
-int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs);
-
-__END_DECLS
-
-#endif /* __CUTILS_DEBUGGER_H */
diff --git a/include/cutils/klog.h b/include/cutils/klog.h
index c837edb..e7cd300 100644
--- a/include/cutils/klog.h
+++ b/include/cutils/klog.h
@@ -44,6 +44,4 @@
 #define KLOG_INFO(tag,x...)    klog_write(KLOG_INFO_LEVEL, "<6>" tag ": " x)
 #define KLOG_DEBUG(tag,x...)   klog_write(KLOG_DEBUG_LEVEL, "<7>" tag ": " x)
 
-#define KLOG_DEFAULT_LEVEL  3  /* messages <= this level are logged */
-
 #endif
diff --git a/include/cutils/multiuser.h b/include/cutils/multiuser.h
index 4f23776..5bd9c7b 100644
--- a/include/cutils/multiuser.h
+++ b/include/cutils/multiuser.h
@@ -32,6 +32,7 @@
 extern uid_t multiuser_get_uid(userid_t user_id, appid_t app_id);
 
 extern gid_t multiuser_get_cache_gid(userid_t user_id, appid_t app_id);
+extern gid_t multiuser_get_ext_gid(userid_t user_id, appid_t app_id);
 extern gid_t multiuser_get_shared_gid(userid_t user_id, appid_t app_id);
 
 /* TODO: switch callers over to multiuser_get_shared_gid() */
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index f7cf9b8..8e2bc1c 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -126,6 +126,8 @@
 #define AID_MEDIA_AUDIO   1055 /* GID for audio files on internal media storage */
 #define AID_MEDIA_VIDEO   1056 /* GID for video files on internal media storage */
 #define AID_MEDIA_IMAGE   1057 /* GID for image files on internal media storage */
+#define AID_TOMBSTONED    1058  /* tombstoned user */
+#define AID_MEDIA_OBB     1059 /* GID for OBB files on internal media storage */
 /* Changes to this file must be made in AOSP, *not* in internal branches. */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
@@ -164,6 +166,9 @@
 #define AID_CACHE_GID_START  20000 /* start of gids for apps to mark cached data */
 #define AID_CACHE_GID_END    29999 /* end of gids for apps to mark cached data */
 
+#define AID_EXT_GID_START    30000 /* start of gids for apps to mark external data */
+#define AID_EXT_GID_END      39999 /* end of gids for apps to mark external data */
+
 #define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
 #define AID_SHARED_GID_END   59999 /* end of gids for apps in each user to share */
 
@@ -173,104 +178,15 @@
 #define AID_USER            100000 /* TODO: switch users over to AID_USER_OFFSET */
 #define AID_USER_OFFSET     100000 /* offset for uid ranges for each user */
 
-#if !defined(EXCLUDE_FS_CONFIG_STRUCTURES)
 /*
- * Used in:
- *  bionic/libc/bionic/stubs.cpp
- *  external/libselinux/src/android.c
- *  system/core/logd/LogStatistics.cpp
- *  system/core/init/ueventd.cpp
- *  system/core/init/util.cpp
+ * android_ids has moved to pwd/grp functionality.
+ * If you need to add one, the structure is now
+ * auto-generated based on the AID_ constraints
+ * documented at the top of this header file.
+ * Also see build/tools/fs_config for more details.
  */
-struct android_id_info {
-    const char *name;
-    unsigned aid;
-};
 
-static const struct android_id_info android_ids[] = {
-    { "root",          AID_ROOT, },
-
-    { "system",        AID_SYSTEM, },
-
-    { "radio",         AID_RADIO, },
-    { "bluetooth",     AID_BLUETOOTH, },
-    { "graphics",      AID_GRAPHICS, },
-    { "input",         AID_INPUT, },
-    { "audio",         AID_AUDIO, },
-    { "camera",        AID_CAMERA, },
-    { "log",           AID_LOG, },
-    { "compass",       AID_COMPASS, },
-    { "mount",         AID_MOUNT, },
-    { "wifi",          AID_WIFI, },
-    { "adb",           AID_ADB, },
-    { "install",       AID_INSTALL, },
-    { "media",         AID_MEDIA, },
-    { "dhcp",          AID_DHCP, },
-    { "sdcard_rw",     AID_SDCARD_RW, },
-    { "vpn",           AID_VPN, },
-    { "keystore",      AID_KEYSTORE, },
-    { "usb",           AID_USB, },
-    { "drm",           AID_DRM, },
-    { "mdnsr",         AID_MDNSR, },
-    { "gps",           AID_GPS, },
-    // AID_UNUSED1
-    { "media_rw",      AID_MEDIA_RW, },
-    { "mtp",           AID_MTP, },
-    // AID_UNUSED2
-    { "drmrpc",        AID_DRMRPC, },
-    { "nfc",           AID_NFC, },
-    { "sdcard_r",      AID_SDCARD_R, },
-    { "clat",          AID_CLAT, },
-    { "loop_radio",    AID_LOOP_RADIO, },
-    { "mediadrm",      AID_MEDIA_DRM, },
-    { "package_info",  AID_PACKAGE_INFO, },
-    { "sdcard_pics",   AID_SDCARD_PICS, },
-    { "sdcard_av",     AID_SDCARD_AV, },
-    { "sdcard_all",    AID_SDCARD_ALL, },
-    { "logd",          AID_LOGD, },
-    { "shared_relro",  AID_SHARED_RELRO, },
-    { "dbus",          AID_DBUS, },
-    { "tlsdate",       AID_TLSDATE, },
-    { "mediaex",       AID_MEDIA_EX, },
-    { "audioserver",   AID_AUDIOSERVER, },
-    { "metrics_coll",  AID_METRICS_COLL },
-    { "metricsd",      AID_METRICSD },
-    { "webserv",       AID_WEBSERV },
-    { "debuggerd",     AID_DEBUGGERD, },
-    { "mediacodec",    AID_MEDIA_CODEC, },
-    { "cameraserver",  AID_CAMERASERVER, },
-    { "firewall",      AID_FIREWALL, },
-    { "trunks",        AID_TRUNKS, },
-    { "nvram",         AID_NVRAM, },
-    { "dns",           AID_DNS, },
-    { "dns_tether",    AID_DNS_TETHER, },
-    { "webview_zygote", AID_WEBVIEW_ZYGOTE, },
-    { "vehicle_network", AID_VEHICLE_NETWORK, },
-    { "media_audio",   AID_MEDIA_AUDIO, },
-    { "media_video",   AID_MEDIA_VIDEO, },
-    { "media_image",   AID_MEDIA_IMAGE, },
-
-    { "shell",         AID_SHELL, },
-    { "cache",         AID_CACHE, },
-    { "diag",          AID_DIAG, },
-
-    { "net_bt_admin",  AID_NET_BT_ADMIN, },
-    { "net_bt",        AID_NET_BT, },
-    { "inet",          AID_INET, },
-    { "net_raw",       AID_NET_RAW, },
-    { "net_admin",     AID_NET_ADMIN, },
-    { "net_bw_stats",  AID_NET_BW_STATS, },
-    { "net_bw_acct",   AID_NET_BW_ACCT, },
-    { "readproc",      AID_READPROC, },
-    { "wakelock",      AID_WAKELOCK, },
-
-    { "everybody",     AID_EVERYBODY, },
-    { "misc",          AID_MISC, },
-    { "nobody",        AID_NOBODY, },
-};
-
-#define android_id_count \
-    (sizeof(android_ids) / sizeof(android_ids[0]))
+#if !defined(EXCLUDE_FS_CONFIG_STRUCTURES)
 
 struct fs_path_config {
     unsigned mode;
diff --git a/include/system/radio.h b/include/system/radio.h
index d73d3ae..03b252e 100644
--- a/include/system/radio.h
+++ b/include/system/radio.h
@@ -84,7 +84,7 @@
 typedef unsigned int radio_handle_t;
 
 /* Opaque meta data structure used by radio meta data API (see system/radio_metadata.h) */
-typedef struct radio_medtadata radio_metadata_t;
+typedef struct radio_metadata radio_metadata_t;
 
 
 /* Additional attributes for an FM band configuration */
@@ -170,7 +170,8 @@
     bool             stereo;    /* program is stereo or not */
     bool             digital;   /* digital program or not (e.g HD Radio program) */
     unsigned int     signal_strength; /* signal strength from 0 to 100 */
-    radio_metadata_t *metadata; /* non null if meta data are present (e.g PTY, song title ...) */
+                                /* meta data (e.g PTY, song title ...), must not be NULL */
+    __attribute__((aligned(8))) radio_metadata_t *metadata;
 } radio_program_info_t;
 
 
diff --git a/include/utils/KeyedVector.h b/include/utils/KeyedVector.h
index 42de401..f93ad6e 100644
--- a/include/utils/KeyedVector.h
+++ b/include/utils/KeyedVector.h
@@ -21,7 +21,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <utils/Errors.h>
 #include <utils/SortedVector.h>
 #include <utils/TypeHelpers.h>
diff --git a/init/Android.mk b/init/Android.mk
index 2122880..35e6f4f 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -93,7 +93,7 @@
     libsquashfs_utils \
     liblogwrap \
     libcutils \
-    libext4_utils_static \
+    libext4_utils \
     libbase \
     libc \
     libselinux \
@@ -103,7 +103,7 @@
     libcrypto \
     libc++_static \
     libdl \
-    libsparse_static \
+    libsparse \
     libz \
     libprocessgroup \
     libnl \
diff --git a/init/README.md b/init/README.md
new file mode 100644
index 0000000..cef0dbc
--- /dev/null
+++ b/init/README.md
@@ -0,0 +1,560 @@
+Android Init Language
+---------------------
+
+The Android Init Language consists of five broad classes of statements:
+Actions, Commands, Services, Options, and Imports.
+
+All of these are line-oriented, consisting of tokens separated by
+whitespace.  The c-style backslash escapes may be used to insert
+whitespace into a token.  Double quotes may also be used to prevent
+whitespace from breaking text into multiple tokens.  The backslash,
+when it is the last character on a line, may be used for line-folding.
+
+Lines which start with a # (leading whitespace allowed) are comments.
+
+Actions and Services implicitly declare a new section.  All commands
+or options belong to the section most recently declared.  Commands
+or options before the first section are ignored.
+
+Actions and Services have unique names.  If a second Action is defined
+with the same name as an existing one, its commands are appended to
+the commands of the existing action.  If a second Service is defined
+with the same name as an existing one, it is ignored and an error
+message is logged.
+
+
+Init .rc Files
+--------------
+The init language is used in plain text files that take the .rc file
+extension.  These are typically multiple of these in multiple
+locations on the system, described below.
+
+/init.rc is the primary .rc file and is loaded by the init executable
+at the beginning of its execution.  It is responsible for the initial
+set up of the system.  It imports /init.${ro.hardware}.rc which is the
+primary vendor supplied .rc file.
+
+During the mount\_all command, the init executable loads all of the
+files contained within the /{system,vendor,odm}/etc/init/ directories.
+These directories are intended for all Actions and Services used after
+file system mounting.
+
+One may specify paths in the mount\_all command line to have it import
+.rc files at the specified paths instead of the default ones listed above.
+This is primarily for supporting factory mode and other non-standard boot
+modes.  The three default paths should be used for the normal boot process.
+
+The intention of these directories is:
+
+   1. /system/etc/init/ is for core system items such as
+      SurfaceFlinger, MediaService, and logcatd.
+   2. /vendor/etc/init/ is for SoC vendor items such as actions or
+      daemons needed for core SoC functionality.
+   3. /odm/etc/init/ is for device manufacturer items such as
+      actions or daemons needed for motion sensor or other peripheral
+      functionality.
+
+All services whose binaries reside on the system, vendor, or odm
+partitions should have their service entries placed into a
+corresponding init .rc file, located in the /etc/init/
+directory of the partition where they reside.  There is a build
+system macro, LOCAL\_INIT\_RC, that handles this for developers.  Each
+init .rc file should additionally contain any actions associated with
+its service.
+
+An example is the logcatd.rc and Android.mk files located in the
+system/core/logcat directory.  The LOCAL\_INIT\_RC macro in the
+Android.mk file places logcatd.rc in /system/etc/init/ during the
+build process.  Init loads logcatd.rc during the mount\_all command and
+allows the service to be run and the action to be queued when
+appropriate.
+
+This break up of init .rc files according to their daemon is preferred
+to the previously used monolithic init .rc files.  This approach
+ensures that the only service entries that init reads and the only
+actions that init performs correspond to services whose binaries are in
+fact present on the file system, which was not the case with the
+monolithic init .rc files.  This additionally will aid in merge
+conflict resolution when multiple services are added to the system, as
+each one will go into a separate file.
+
+There are two options "early" and "late" in mount\_all command
+which can be set after optional paths. With "--early" set, the
+init executable will skip mounting entries with "latemount" flag
+and triggering fs encryption state event. With "--late" set,
+init executable will only mount entries with "latemount" flag but skip
+importing rc files. By default, no option is set, and mount\_all will
+process all entries in the given fstab.
+
+Actions
+-------
+Actions are named sequences of commands.  Actions have a trigger which
+is used to determine when the action should occur.  When an event
+occurs which matches an action's trigger, that action is added to
+the tail of a to-be-executed queue (unless it is already on the
+queue).
+
+Each action in the queue is dequeued in sequence and each command in
+that action is executed in sequence.  Init handles other activities
+(device creation/destruction, property setting, process restarting)
+"between" the execution of the commands in activities.
+
+Actions take the form of:
+
+    on <trigger> [&& <trigger>]*
+       <command>
+       <command>
+       <command>
+
+
+Services
+--------
+Services are programs which init launches and (optionally) restarts
+when they exit.  Services take the form of:
+
+    service <name> <pathname> [ <argument> ]*
+       <option>
+       <option>
+       ...
+
+
+Options
+-------
+Options are modifiers to services.  They affect how and when init
+runs the service.
+
+`console [<console>]`
+> This service needs a console. The optional second parameter chooses a
+  specific console instead of the default. The default "/dev/console" can
+  be changed by setting the "androidboot.console" kernel parameter. In
+  all cases the leading "/dev/" should be omitted, so "/dev/tty0" would be
+  specified as just "console tty0".
+
+`critical`
+> This is a device-critical service. If it exits more than four times in
+  four minutes, the device will reboot into recovery mode.
+
+`disabled`
+> This service will not automatically start with its class.
+  It must be explicitly started by name.
+
+`setenv <name> <value>`
+> Set the environment variable _name_ to _value_ in the launched process.
+
+`socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]`
+> Create a unix domain socket named /dev/socket/_name_ and pass its fd to the
+  launched process.  _type_ must be "dgram", "stream" or "seqpacket".  User and
+  group default to 0.  'seclabel' is the SELinux security context for the
+  socket.  It defaults to the service security context, as specified by
+  seclabel or computed based on the service executable file security context.
+  For native executables see libcutils android\_get\_control\_socket().
+
+`file <path> <type>`
+> Open a file path and pass its fd to the launched process. _type_ must be
+  "r", "w" or "rw".  For native executables see libcutils
+  android\_get\_control\_file().
+
+`user <username>`
+> Change to 'username' before exec'ing this service.
+  Currently defaults to root.  (??? probably should default to nobody)
+  As of Android M, processes should use this option even if they
+  require Linux capabilities.  Previously, to acquire Linux
+  capabilities, a process would need to run as root, request the
+  capabilities, then drop to its desired uid.  There is a new
+  mechanism through fs\_config that allows device manufacturers to add
+  Linux capabilities to specific binaries on a file system that should
+  be used instead. This mechanism is described on
+  <http://source.android.com/devices/tech/config/filesystem.html>.  When
+  using this new mechanism, processes can use the user option to
+  select their desired uid without ever running as root.
+  As of Android O, processes can also request capabilities directly in their .rc
+  files. See the "capabilities" option below.
+
+`group <groupname> [ <groupname>\* ]`
+> Change to 'groupname' before exec'ing this service.  Additional
+  groupnames beyond the (required) first one are used to set the
+  supplemental groups of the process (via setgroups()).
+  Currently defaults to root.  (??? probably should default to nobody)
+
+`capabilities <capability> [ <capability>\* ]`
+> Set capabilities when exec'ing this service. 'capability' should be a Linux
+  capability without the "CAP\_" prefix, like "NET\_ADMIN" or "SETPCAP". See
+  http://man7.org/linux/man-pages/man7/capabilities.7.html for a list of Linux
+  capabilities.
+
+`seclabel <seclabel>`
+> Change to 'seclabel' before exec'ing this service.
+  Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
+  Services on the system partition can instead use policy-defined transitions
+  based on their file security context.
+  If not specified and no transition is defined in policy, defaults to the init context.
+
+`oneshot`
+> Do not restart the service when it exits.
+
+`class <name>`
+> Specify a class name for the service.  All services in a
+  named class may be started or stopped together.  A service
+  is in the class "default" if one is not specified via the
+  class option.
+
+`onrestart`
+> Execute a Command (see below) when service restarts.
+
+`writepid <file...>`
+> Write the child's pid to the given files when it forks. Meant for
+  cgroup/cpuset usage.
+
+`priority <priority>`
+> Scheduling priority of the service process. This value has to be in range
+  -20 to 19. Default priority is 0. Priority is set via setpriority().
+
+`namespace <pid|mnt>`
+> Enter a new PID or mount namespace when forking the service.
+
+`oom_score_adjust <value>`
+> Sets the child's /proc/self/oom\_score\_adj to the specified value,
+  which must range from -1000 to 1000.
+
+
+Triggers
+--------
+Triggers are strings which can be used to match certain kinds of
+events and used to cause an action to occur.
+
+Triggers are subdivided into event triggers and property triggers.
+
+Event triggers are strings triggered by the 'trigger' command or by
+the QueueEventTrigger() function within the init executable.  These
+take the form of a simple string such as 'boot' or 'late-init'.
+
+Property triggers are strings triggered when a named property changes
+value to a given new value or when a named property changes value to
+any new value.  These take the form of 'property:<name>=<value>' and
+'property:<name>=\*' respectively.  Property triggers are additionally
+evaluated and triggered accordingly during the initial boot phase of
+init.
+
+An Action can have multiple property triggers but may only have one
+event trigger.
+
+For example:
+`on boot && property:a=b` defines an action that is only executed when
+the 'boot' event trigger happens and the property a equals b.
+
+`on property:a=b && property:c=d` defines an action that is executed
+at three times:
+
+   1. During initial boot if property a=b and property c=d.
+   2. Any time that property a transitions to value b, while property c already equals d.
+   3. Any time that property c transitions to value d, while property a already equals b.
+
+
+Commands
+--------
+
+`bootchart [start|stop]`
+> Start/stop bootcharting. These are present in the default init.rc files,
+  but bootcharting is only active if the file /data/bootchart/enabled exists;
+  otherwise bootchart start/stop are no-ops.
+
+`chmod <octal-mode> <path>`
+> Change file access permissions.
+
+`chown <owner> <group> <path>`
+> Change file owner and group.
+
+`class_start <serviceclass>`
+> Start all services of the specified class if they are
+  not already running.
+
+`class_stop <serviceclass>`
+> Stop and disable all services of the specified class if they are
+  currently running.
+
+`class_reset <serviceclass>`
+> Stop all services of the specified class if they are
+  currently running, without disabling them. They can be restarted
+  later using `class_start`.
+
+`copy <src> <dst>`
+> Copies a file. Similar to write, but useful for binary/large
+  amounts of data.
+
+`domainname <name>`
+> Set the domain name.
+
+`enable <servicename>`
+> Turns a disabled service into an enabled one as if the service did not
+  specify disabled.
+  If the service is supposed to be running, it will be started now.
+  Typically used when the bootloader sets a variable that indicates a specific
+  service should be started when needed. E.g.
+
+    on property:ro.boot.myfancyhardware=1
+        enable my_fancy_service_for_my_fancy_hardware
+
+`exec [ <seclabel> [ <user> [ <group>\* ] ] ] -- <command> [ <argument>\* ]`
+> Fork and execute command with the given arguments. The command starts
+  after "--" so that an optional security context, user, and supplementary
+  groups can be provided. No other commands will be run until this one
+  finishes. _seclabel_ can be a - to denote default.
+
+`export <name> <value>`
+> Set the environment variable _name_ equal to _value_ in the
+  global environment (which will be inherited by all processes
+  started after this command is executed)
+
+`hostname <name>`
+> Set the host name.
+
+`ifup <interface>`
+> Bring the network interface _interface_ online.
+
+`insmod [-f] <path> [<options>]`
+> Install the module at _path_ with the specified options.
+  -f: force installation of the module even if the version of the running kernel
+  and the version of the kernel for which the module was compiled do not match.
+
+`load_all_props`
+> Loads properties from /system, /vendor, et cetera.
+  This is included in the default init.rc.
+
+`load_persist_props`
+> Loads persistent properties when /data has been decrypted.
+  This is included in the default init.rc.
+
+`loglevel <level>`
+> Sets the kernel log level to level. Properties are expanded within _level_.
+
+`mkdir <path> [mode] [owner] [group]`
+> Create a directory at _path_, optionally with the given mode, owner, and
+  group. If not provided, the directory is created with permissions 755 and
+  owned by the root user and root group. If provided, the mode, owner and group
+  will be updated if the directory exists already.
+
+`mount_all <fstab> [ <path> ]\* [--<option>]`
+> Calls fs\_mgr\_mount\_all on the given fs\_mgr-format fstab and imports .rc files
+  at the specified paths (e.g., on the partitions just mounted) with optional
+  options "early" and "late".
+  Refer to the section of "Init .rc Files" for detail.
+
+`mount <type> <device> <dir> [ <flag>\* ] [<options>]`
+> Attempt to mount the named device at the directory _dir_
+  _flag_s include "ro", "rw", "remount", "noatime", ...
+  _options_ include "barrier=1", "noauto\_da\_alloc", "discard", ... as
+  a comma separated string, eg: barrier=1,noauto\_da\_alloc
+
+`powerctl`
+> Internal implementation detail used to respond to changes to the
+  "sys.powerctl" system property, used to implement rebooting.
+
+`restart <service>`
+> Like stop, but doesn't disable the service.
+
+`restorecon <path> [ <path>\* ]`
+> Restore the file named by _path_ to the security context specified
+  in the file\_contexts configuration.
+  Not required for directories created by the init.rc as these are
+  automatically labeled correctly by init.
+
+`restorecon_recursive <path> [ <path>\* ]`
+> Recursively restore the directory tree named by _path_ to the
+  security contexts specified in the file\_contexts configuration.
+
+`rm <path>`
+> Calls unlink(2) on the given path. You might want to
+  use "exec -- rm ..." instead (provided the system partition is
+  already mounted).
+
+`rmdir <path>`
+> Calls rmdir(2) on the given path.
+
+`setprop <name> <value>`
+> Set system property _name_ to _value_. Properties are expanded
+  within _value_.
+
+`setrlimit <resource> <cur> <max>`
+> Set the rlimit for a resource.
+
+`start <service>`
+> Start a service running if it is not already running.
+
+`stop <service>`
+> Stop a service from running if it is currently running.
+
+`swapon_all <fstab>`
+> Calls fs\_mgr\_swapon\_all on the given fstab file.
+
+`symlink <target> <path>`
+> Create a symbolic link at _path_ with the value _target_
+
+`sysclktz <mins_west_of_gmt>`
+> Set the system clock base (0 if system clock ticks in GMT)
+
+`trigger <event>`
+> Trigger an event.  Used to queue an action from another
+  action.
+
+`umount <path>`
+> Unmount the filesystem mounted at that path.
+
+`verity_load_state`
+> Internal implementation detail used to load dm-verity state.
+
+`verity_update_state <mount-point>`
+> Internal implementation detail used to update dm-verity state and
+  set the partition._mount-point_.verified properties used by adb remount
+  because fs\_mgr can't set them directly itself.
+
+`wait <path> [ <timeout> ]`
+> Poll for the existence of the given file and return when found,
+  or the timeout has been reached. If timeout is not specified it
+  currently defaults to five seconds.
+
+`write <path> <content>`
+> Open the file at _path_ and write a string to it with write(2).
+  If the file does not exist, it will be created. If it does exist,
+  it will be truncated. Properties are expanded within _content_.
+
+
+Imports
+-------
+The import keyword is not a command, but rather its own section and is
+handled immediately after the .rc file that contains it has finished
+being parsed.  It takes the below form:
+
+`import <path>`
+> Parse an init config file, extending the current configuration.
+  If _path_ is a directory, each file in the directory is parsed as
+  a config file. It is not recursive, nested directories will
+  not be parsed.
+
+There are only two times where the init executable imports .rc files:
+
+   1. When it imports /init.rc during initial boot
+   2. When it imports /{system,vendor,odm}/etc/init/ or .rc files at specified
+      paths during mount_all
+
+
+Properties
+----------
+Init provides information about the services that it is responsible
+for via the below properties.
+
+`init.svc.<name>`
+> State of a named service ("stopped", "stopping", "running", "restarting")
+
+
+Boot timing
+-----------
+Init records some boot timing information in system properties.
+
+`ro.boottime.init`
+> Time after boot in ns (via the CLOCK\_BOOTTIME clock) at which the first
+  stage of init started.
+
+`ro.boottime.init.selinux`
+> How long it took the first stage to initialize SELinux.
+
+`ro.boottime.init.cold_boot_wait`
+> How long init waited for ueventd's coldboot phase to end.
+
+`ro.boottime.<service-name>`
+> Time after boot in ns (via the CLOCK\_BOOTTIME clock) that the service was
+  first started.
+
+
+Bootcharting
+------------
+This version of init contains code to perform "bootcharting": generating log
+files that can be later processed by the tools provided by <http://www.bootchart.org/>.
+
+On the emulator, use the -bootchart _timeout_ option to boot with bootcharting
+activated for _timeout_ seconds.
+
+On a device:
+
+    adb shell 'touch /data/bootchart/enabled'
+
+Don't forget to delete this file when you're done collecting data!
+
+The log files are written to /data/bootchart/. A script is provided to
+retrieve them and create a bootchart.tgz file that can be used with the
+bootchart command-line utility:
+
+    sudo apt-get install pybootchartgui
+    # grab-bootchart.sh uses $ANDROID_SERIAL.
+    $ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
+
+One thing to watch for is that the bootchart will show init as if it started
+running at 0s. You'll have to look at dmesg to work out when the kernel
+actually started init.
+
+
+Comparing two bootcharts
+------------------------
+A handy script named compare-bootcharts.py can be used to compare the
+start/end time of selected processes. The aforementioned grab-bootchart.sh
+will leave a bootchart tarball named bootchart.tgz at /tmp/android-bootchart.
+If two such barballs are preserved on the host machine under different
+directories, the script can list the timestamps differences. For example:
+
+Usage: system/core/init/compare-bootcharts.py _base-bootchart-dir_ _exp-bootchart-dir_
+
+    process: baseline experiment (delta) - Unit is ms (a jiffy is 10 ms on the system)
+    ------------------------------------
+    /init: 50 40 (-10)
+    /system/bin/surfaceflinger: 4320 4470 (+150)
+    /system/bin/bootanimation: 6980 6990 (+10)
+    zygote64: 10410 10640 (+230)
+    zygote: 10410 10640 (+230)
+    system_server: 15350 15150 (-200)
+    bootanimation ends at: 33790 31230 (-2560)
+
+
+Systrace
+--------
+Systrace (<http://developer.android.com/tools/help/systrace.html>) can be
+used for obtaining performance analysis reports during boot
+time on userdebug or eng builds.
+
+Here is an example of trace events of "wm" and "am" categories:
+
+    $ANDROID_BUILD_TOP/external/chromium-trace/systrace.py \
+          wm am --boot
+
+This command will cause the device to reboot. After the device is rebooted and
+the boot sequence has finished, the trace report is obtained from the device
+and written as trace.html on the host by hitting Ctrl+C.
+
+Limitation: recording trace events is started after persistent properties are loaded, so
+the trace events that are emitted before that are not recorded. Several
+services such as vold, surfaceflinger, and servicemanager are affected by this
+limitation since they are started before persistent properties are loaded.
+Zygote initialization and the processes that are forked from the zygote are not
+affected.
+
+
+Debugging init
+--------------
+By default, programs executed by init will drop stdout and stderr into
+/dev/null. To help with debugging, you can execute your program via the
+Android program logwrapper. This will redirect stdout/stderr into the
+Android logging system (accessed via logcat).
+
+For example
+service akmd /system/bin/logwrapper /sbin/akmd
+
+For quicker turnaround when working on init itself, use:
+
+    mm -j &&
+    m ramdisk-nodeps &&
+    m bootimage-nodeps &&
+    adb reboot bootloader &&
+    fastboot boot $ANDROID_PRODUCT_OUT/boot.img
+
+Alternatively, use the emulator:
+
+    emulator -partition-size 1024 \
+        -verbose -show-kernel -no-window
diff --git a/init/readme.txt b/init/readme.txt
deleted file mode 100644
index 530b392..0000000
--- a/init/readme.txt
+++ /dev/null
@@ -1,560 +0,0 @@
-Android Init Language
----------------------
-
-The Android Init Language consists of five broad classes of statements,
-which are Actions, Commands, Services, Options, and Imports.
-
-All of these are line-oriented, consisting of tokens separated by
-whitespace.  The c-style backslash escapes may be used to insert
-whitespace into a token.  Double quotes may also be used to prevent
-whitespace from breaking text into multiple tokens.  The backslash,
-when it is the last character on a line, may be used for line-folding.
-
-Lines which start with a # (leading whitespace allowed) are comments.
-
-Actions and Services implicitly declare a new section.  All commands
-or options belong to the section most recently declared.  Commands
-or options before the first section are ignored.
-
-Actions and Services have unique names.  If a second Action is defined
-with the same name as an existing one, its commands are appended to
-the commands of the existing action.  If a second Service is defined
-with the same name as an existing one, it is ignored and an error
-message is logged.
-
-
-Init .rc Files
---------------
-The init language is used in plaintext files that take the .rc file
-extension.  These are typically multiple of these in multiple
-locations on the system, described below.
-
-/init.rc is the primary .rc file and is loaded by the init executable
-at the beginning of its execution.  It is responsible for the initial
-set up of the system.  It imports /init.${ro.hardware}.rc which is the
-primary vendor supplied .rc file.
-
-During the mount_all command, the init executable loads all of the
-files contained within the /{system,vendor,odm}/etc/init/ directories.
-These directories are intended for all Actions and Services used after
-file system mounting.
-
-One may specify paths in the mount_all command line to have it import
-.rc files at the specified paths instead of the default ones listed above.
-This is primarily for supporting factory mode and other non-standard boot
-modes.  The three default paths should be used for the normal boot process.
-
-The intention of these directories is as follows
-   1) /system/etc/init/ is for core system items such as
-      SurfaceFlinger, MediaService, and logcatd.
-   2) /vendor/etc/init/ is for SoC vendor items such as actions or
-      daemons needed for core SoC functionality.
-   3) /odm/etc/init/ is for device manufacturer items such as
-      actions or daemons needed for motion sensor or other peripheral
-      functionality.
-
-All services whose binaries reside on the system, vendor, or odm
-partitions should have their service entries placed into a
-corresponding init .rc file, located in the /etc/init/
-directory of the partition where they reside.  There is a build
-system macro, LOCAL_INIT_RC, that handles this for developers.  Each
-init .rc file should additionally contain any actions associated with
-its service.
-
-An example is the logcatd.rc and Android.mk files located in the
-system/core/logcat directory.  The LOCAL_INIT_RC macro in the
-Android.mk file places logcatd.rc in /system/etc/init/ during the
-build process.  Init loads logcatd.rc during the mount_all command and
-allows the service to be run and the action to be queued when
-appropriate.
-
-This break up of init .rc files according to their daemon is preferred
-to the previously used monolithic init .rc files.  This approach
-ensures that the only service entries that init reads and the only
-actions that init performs correspond to services whose binaries are in
-fact present on the file system, which was not the case with the
-monolithic init .rc files.  This additionally will aid in merge
-conflict resolution when multiple services are added to the system, as
-each one will go into a separate file.
-
-There are two options "early" and "late" in mount_all command
-which can be set after optional paths. With "--early" set, the
-init executable will skip mounting entries with "latemount" flag
-and triggering fs encryption state event. With "--late" set,
-init executable will only mount entries with "latemount" flag but skip
-importing rc files. By default, no option is set, and mount_all will
-mount_all will process all entries in the given fstab.
-
-Actions
--------
-Actions are named sequences of commands.  Actions have a trigger which
-is used to determine when the action should occur.  When an event
-occurs which matches an action's trigger, that action is added to
-the tail of a to-be-executed queue (unless it is already on the
-queue).
-
-Each action in the queue is dequeued in sequence and each command in
-that action is executed in sequence.  Init handles other activities
-(device creation/destruction, property setting, process restarting)
-"between" the execution of the commands in activities.
-
-Actions take the form of:
-
-on <trigger> [&& <trigger>]*
-   <command>
-   <command>
-   <command>
-
-
-Services
---------
-Services are programs which init launches and (optionally) restarts
-when they exit.  Services take the form of:
-
-service <name> <pathname> [ <argument> ]*
-   <option>
-   <option>
-   ...
-
-
-Options
--------
-Options are modifiers to services.  They affect how and when init
-runs the service.
-
-console [<console>]
-  This service needs a console. The optional second parameter chooses a
-  specific console instead of the default. The default "/dev/console" can
-  be changed by setting the "androidboot.console" kernel parameter. In
-  all cases the leading "/dev/" should be omitted, so "/dev/tty0" would be
-  specified as just "console tty0".
-
-critical
-  This is a device-critical service. If it exits more than four times in
-  four minutes, the device will reboot into recovery mode.
-
-disabled
-  This service will not automatically start with its class.
-  It must be explicitly started by name.
-
-setenv <name> <value>
-  Set the environment variable <name> to <value> in the launched process.
-
-socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
-  Create a unix domain socket named /dev/socket/<name> and pass its fd to the
-  launched process.  <type> must be "dgram", "stream" or "seqpacket".  User and
-  group default to 0.  'seclabel' is the SELinux security context for the
-  socket.  It defaults to the service security context, as specified by
-  seclabel or computed based on the service executable file security context.
-  For native executables see libcutils android_get_control_socket().
-
-file <path> <type>
-  Open a file path and pass its fd to the launched process.  <type> must be
-  "r", "w" or "rw".  For native executables see libcutils
-  android_get_control_file().
-
-user <username>
-  Change to 'username' before exec'ing this service.
-  Currently defaults to root.  (??? probably should default to nobody)
-  As of Android M, processes should use this option even if they
-  require Linux capabilities.  Previously, to acquire Linux
-  capabilities, a process would need to run as root, request the
-  capabilities, then drop to its desired uid.  There is a new
-  mechanism through fs_config that allows device manufacturers to add
-  Linux capabilities to specific binaries on a file system that should
-  be used instead. This mechanism is described on
-  http://source.android.com/devices/tech/config/filesystem.html.  When
-  using this new mechanism, processes can use the user option to
-  select their desired uid without ever running as root.
-  As of Android O, processes can also request capabilities directly in their .rc
-  files. See the "capabilities" option below.
-
-group <groupname> [ <groupname> ]*
-  Change to 'groupname' before exec'ing this service.  Additional
-  groupnames beyond the (required) first one are used to set the
-  supplemental groups of the process (via setgroups()).
-  Currently defaults to root.  (??? probably should default to nobody)
-
-capabilities <capability> [ <capability> ]*
-  Set capabilities when exec'ing this service. 'capability' should be a Linux
-  capability without the "CAP_" prefix, like "NET_ADMIN" or "SETPCAP". See
-  http://man7.org/linux/man-pages/man7/capabilities.7.html for a list of Linux
-  capabilities.
-
-seclabel <seclabel>
-  Change to 'seclabel' before exec'ing this service.
-  Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
-  Services on the system partition can instead use policy-defined transitions
-  based on their file security context.
-  If not specified and no transition is defined in policy, defaults to the init context.
-
-oneshot
-  Do not restart the service when it exits.
-
-class <name>
-  Specify a class name for the service.  All services in a
-  named class may be started or stopped together.  A service
-  is in the class "default" if one is not specified via the
-  class option.
-
-onrestart
-  Execute a Command (see below) when service restarts.
-
-writepid <file...>
-  Write the child's pid to the given files when it forks. Meant for
-  cgroup/cpuset usage.
-
-priority <priority>
-  Scheduling priority of the service process. This value has to be in range
-  -20 to 19. Default priority is 0. Priority is set via setpriority().
-
-namespace <pid|mnt>
-  Enter a new PID or mount namespace when forking the service.
-
-oom_score_adjust <value>
-   Sets the child's /proc/self/oom_score_adj to the specified value,
-   which must range from -1000 to 1000.
-
-
-Triggers
---------
-Triggers are strings which can be used to match certain kinds of
-events and used to cause an action to occur.
-
-Triggers are subdivided into event triggers and property triggers.
-
-Event triggers are strings triggered by the 'trigger' command or by
-the QueueEventTrigger() function within the init executable.  These
-take the form of a simple string such as 'boot' or 'late-init'.
-
-Property triggers are strings triggered when a named property changes
-value to a given new value or when a named property changes value to
-any new value.  These take the form of 'property:<name>=<value>' and
-'property:<name>=*' respectively.  Property triggers are additionally
-evaluated and triggered accordingly during the initial boot phase of
-init.
-
-An Action can have multiple property triggers but may only have one
-event trigger.
-
-For example:
-'on boot && property:a=b' defines an action that is only executed when
-the 'boot' event trigger happens and the property a equals b.
-
-'on property:a=b && property:c=d' defines an action that is executed
-at three times,
-   1) During initial boot if property a=b and property c=d
-   2) Any time that property a transitions to value b, while property
-      c already equals d.
-   3) Any time that property c transitions to value d, while property
-      a already equals b.
-
-
-Commands
---------
-
-bootchart [start|stop]
-   Start/stop bootcharting. These are present in the default init.rc files,
-   but bootcharting is only active if the file /data/bootchart/enabled exists;
-   otherwise bootchart start/stop are no-ops.
-
-chmod <octal-mode> <path>
-   Change file access permissions.
-
-chown <owner> <group> <path>
-   Change file owner and group.
-
-class_start <serviceclass>
-   Start all services of the specified class if they are
-   not already running.
-
-class_stop <serviceclass>
-   Stop and disable all services of the specified class if they are
-   currently running.
-
-class_reset <serviceclass>
-   Stop all services of the specified class if they are
-   currently running, without disabling them. They can be restarted
-   later using class_start.
-
-copy <src> <dst>
-   Copies a file. Similar to write, but useful for binary/large
-   amounts of data.
-
-domainname <name>
-   Set the domain name.
-
-enable <servicename>
-   Turns a disabled service into an enabled one as if the service did not
-   specify disabled.
-   If the service is supposed to be running, it will be started now.
-   Typically used when the bootloader sets a variable that indicates a specific
-   service should be started when needed. E.g.
-     on property:ro.boot.myfancyhardware=1
-        enable my_fancy_service_for_my_fancy_hardware
-
-exec [ <seclabel> [ <user> [ <group> ]* ] ] -- <command> [ <argument> ]*
-   Fork and execute command with the given arguments. The command starts
-   after "--" so that an optional security context, user, and supplementary
-   groups can be provided. No other commands will be run until this one
-   finishes. <seclabel> can be a - to denote default.
-
-export <name> <value>
-   Set the environment variable <name> equal to <value> in the
-   global environment (which will be inherited by all processes
-   started after this command is executed)
-
-hostname <name>
-   Set the host name.
-
-ifup <interface>
-   Bring the network interface <interface> online.
-
-insmod [-f] <path> [<options>]
-   Install the module at <path> with the specified options.
-   -f
-   Force installation of the module even if the version of the running kernel
-   and the version of the kernel for which the module was compiled do not match.
-
-load_all_props
-   Loads properties from /system, /vendor, et cetera.
-   This is included in the default init.rc.
-
-load_persist_props
-   Loads persistent properties when /data has been decrypted.
-   This is included in the default init.rc.
-
-loglevel <level>
-   Sets the kernel log level to level. Properties are expanded within <level>.
-
-mkdir <path> [mode] [owner] [group]
-   Create a directory at <path>, optionally with the given mode, owner, and
-   group. If not provided, the directory is created with permissions 755 and
-   owned by the root user and root group. If provided, the mode, owner and group
-   will be updated if the directory exists already.
-
-mount_all <fstab> [ <path> ]* [--<option>]
-   Calls fs_mgr_mount_all on the given fs_mgr-format fstab and imports .rc files
-   at the specified paths (e.g., on the partitions just mounted) with optional
-   options "early" and "late".
-   Refer to the section of "Init .rc Files" for detail.
-
-mount <type> <device> <dir> [ <flag> ]* [<options>]
-   Attempt to mount the named device at the directory <dir>
-   <flag>s include "ro", "rw", "remount", "noatime", ...
-   <options> include "barrier=1", "noauto_da_alloc", "discard", ... as
-   a comma separated string, eg: barrier=1,noauto_da_alloc
-
-powerctl
-   Internal implementation detail used to respond to changes to the
-   "sys.powerctl" system property, used to implement rebooting.
-
-restart <service>
-   Like stop, but doesn't disable the service.
-
-restorecon <path> [ <path> ]*
-   Restore the file named by <path> to the security context specified
-   in the file_contexts configuration.
-   Not required for directories created by the init.rc as these are
-   automatically labeled correctly by init.
-
-restorecon_recursive <path> [ <path> ]*
-   Recursively restore the directory tree named by <path> to the
-   security contexts specified in the file_contexts configuration.
-
-rm <path>
-   Calls unlink(2) on the given path. You might want to
-   use "exec -- rm ..." instead (provided the system partition is
-   already mounted).
-
-rmdir <path>
-   Calls rmdir(2) on the given path.
-
-setprop <name> <value>
-   Set system property <name> to <value>. Properties are expanded
-   within <value>.
-
-setrlimit <resource> <cur> <max>
-   Set the rlimit for a resource.
-
-start <service>
-   Start a service running if it is not already running.
-
-stop <service>
-   Stop a service from running if it is currently running.
-
-swapon_all <fstab>
-   Calls fs_mgr_swapon_all on the given fstab file.
-
-symlink <target> <path>
-   Create a symbolic link at <path> with the value <target>
-
-sysclktz <mins_west_of_gmt>
-   Set the system clock base (0 if system clock ticks in GMT)
-
-trigger <event>
-   Trigger an event.  Used to queue an action from another
-   action.
-
-umount <path>
-   Unmount the filesystem mounted at that path.
-
-verity_load_state
-   Internal implementation detail used to load dm-verity state.
-
-verity_update_state <mount_point>
-   Internal implementation detail used to update dm-verity state and
-   set the partition.<mount_point>.verified properties used by adb remount
-   because fs_mgr can't set them directly itself.
-
-wait <path> [ <timeout> ]
-   Poll for the existence of the given file and return when found,
-   or the timeout has been reached. If timeout is not specified it
-   currently defaults to five seconds.
-
-write <path> <content>
-   Open the file at <path> and write a string to it with write(2).
-   If the file does not exist, it will be created. If it does exist,
-   it will be truncated. Properties are expanded within <content>.
-
-
-Imports
--------
-The import keyword is not a command, but rather its own section and is
-handled immediately after the .rc file that contains it has finished
-being parsed.  It takes the below form:
-
-import <path>
-   Parse an init config file, extending the current configuration.
-   If <path> is a directory, each file in the directory is parsed as
-   a config file. It is not recursive, nested directories will
-   not be parsed.
-
-There are only two times where the init executable imports .rc files,
-   1) When it imports /init.rc during initial boot
-   2) When it imports /{system,vendor,odm}/etc/init/ or .rc files at specified
-      paths during mount_all
-
-
-Properties
-----------
-Init provides information about the services that it is responsible
-for via the below properties.
-
-init.svc.<name>
-  State of a named service ("stopped", "stopping", "running", "restarting")
-
-
-Boot timing
------------
-Init records some boot timing information in system properties.
-
-ro.boottime.init
-  Time after boot in ns (via the CLOCK_BOOTTIME clock) at which the first
-  stage of init started.
-
-ro.boottime.init.selinux
-  How long it took the first stage to initialize SELinux.
-
-ro.boottime.init.cold_boot_wait
-  How long init waited for ueventd's coldboot phase to end.
-
-ro.boottime.<service-name>
-  Time after boot in ns (via the CLOCK_BOOTTIME clock) that the service was
-  first started.
-
-
-Bootcharting
-------------
-This version of init contains code to perform "bootcharting": generating log
-files that can be later processed by the tools provided by www.bootchart.org.
-
-On the emulator, use the -bootchart <timeout> option to boot with bootcharting
-activated for <timeout> seconds.
-
-On a device:
-
-  adb shell 'touch /data/bootchart/enabled'
-
-Don't forget to delete this file when you're done collecting data!
-
-The log files are written to /data/bootchart/. A script is provided to
-retrieve them and create a bootchart.tgz file that can be used with the
-bootchart command-line utility:
-
-  sudo apt-get install pybootchartgui
-  # grab-bootchart.sh uses $ANDROID_SERIAL.
-  $ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
-
-One thing to watch for is that the bootchart will show init as if it started
-running at 0s. You'll have to look at dmesg to work out when the kernel
-actually started init.
-
-
-Comparing two bootcharts
-------------------------
-A handy script named compare-bootcharts.py can be used to compare the
-start/end time of selected processes. The aforementioned grab-bootchart.sh
-will leave a bootchart tarball named bootchart.tgz at /tmp/android-bootchart.
-If two such barballs are preserved on the host machine under different
-directories, the script can list the timestamps differences. For example:
-
-Usage: system/core/init/compare-bootcharts.py base_bootchart_dir
-       exp_bootchart_dir
-
-process: baseline experiment (delta)
- - Unit is ms (a jiffy is 10 ms on the system)
-------------------------------------
-/init: 50 40 (-10)
-/system/bin/surfaceflinger: 4320 4470 (+150)
-/system/bin/bootanimation: 6980 6990 (+10)
-zygote64: 10410 10640 (+230)
-zygote: 10410 10640 (+230)
-system_server: 15350 15150 (-200)
-bootanimation ends at: 33790 31230 (-2560)
-
-
-Systrace
---------
-Systrace [1] can be used for obtaining performance analysis reports during boot
-time on userdebug or eng builds.
-Here is an example of trace events of "wm" and "am" categories:
-
-  $ANDROID_BUILD_TOP/external/chromium-trace/systrace.py wm am --boot
-
-This command will cause the device to reboot. After the device is rebooted and
-the boot sequence has finished, the trace report is obtained from the device
-and written as trace.html on the host by hitting Ctrl+C.
-
-LIMITATION
-Recording trace events is started after persistent properties are loaded, so
-the trace events that are emitted before that are not recorded. Several
-services such as vold, surfaceflinger, and servicemanager are affected by this
-limitation since they are started before persistent properties are loaded.
-Zygote initialization and the processes that are forked from the zygote are not
-affected.
-
-[1] http://developer.android.com/tools/help/systrace.html
-
-
-Debugging init
---------------
-By default, programs executed by init will drop stdout and stderr into
-/dev/null. To help with debugging, you can execute your program via the
-Android program logwrapper. This will redirect stdout/stderr into the
-Android logging system (accessed via logcat).
-
-For example
-service akmd /system/bin/logwrapper /sbin/akmd
-
-For quicker turnaround when working on init itself, use:
-
-  mm -j &&
-  m ramdisk-nodeps &&
-  m bootimage-nodeps &&
-  adb reboot bootloader &&
-  fastboot boot $ANDROID_PRODUCT_OUT/boot.img
-
-Alternatively, use the emulator:
-
-  emulator -partition-size 1024 -verbose -show-kernel -no-window
diff --git a/libbacktrace/BacktraceLog.h b/libbacktrace/BacktraceLog.h
index 0a27982..5c39f1c 100644
--- a/libbacktrace/BacktraceLog.h
+++ b/libbacktrace/BacktraceLog.h
@@ -19,7 +19,7 @@
 
 #define LOG_TAG "libbacktrace"
 
-#include <android/log.h>
+#include <log/log.h>
 
 // Macro to log the function name along with the warning message.
 #define BACK_LOGW(format, ...) \
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 4496375..0e31495 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -22,7 +22,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <android/log.h>
+#include <log/log.h>
+
 #include <backtrace/backtrace_constants.h>
 #include <backtrace/BacktraceMap.h>
 
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 39f8aba..b96e3ae 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -78,7 +78,6 @@
             srcs: libcutils_nonwindows_sources + [
                 "android_reboot.c",
                 "ashmem-dev.c",
-                "debugger.c",
                 "klog.cpp",
                 "partition_utils.c",
                 "properties.c",
@@ -86,9 +85,6 @@
                 "trace-dev.c",
                 "uevent.c",
             ],
-
-            static_libs: ["libdebuggerd_client"],
-            export_static_lib_headers: ["libdebuggerd_client"],
         },
 
         android_arm: {
diff --git a/libcutils/ashmem-dev.c b/libcutils/ashmem-dev.c
index db4ed11..92717c0 100644
--- a/libcutils/ashmem-dev.c
+++ b/libcutils/ashmem-dev.c
@@ -31,8 +31,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/ashmem.h>
+#include <log/log.h>
 
 #define ASHMEM_DEVICE "/dev/ashmem"
 
diff --git a/libcutils/debugger.c b/libcutils/debugger.c
deleted file mode 100644
index c6bdd1a..0000000
--- a/libcutils/debugger.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "DEBUG"
-
-#include <fcntl.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <android/log.h>
-#include <cutils/debugger.h>
-#include <cutils/sockets.h>
-
-static int send_request(int sock_fd, void* msg_ptr, size_t msg_len) {
-  int result = 0;
-  if (TEMP_FAILURE_RETRY(write(sock_fd, msg_ptr, msg_len)) != (ssize_t) msg_len) {
-    result = -1;
-  } else {
-    char ack;
-    if (TEMP_FAILURE_RETRY(read(sock_fd, &ack, 1)) != 1) {
-      result = -1;
-    }
-  }
-  return result;
-}
-
-static int make_dump_request(debugger_action_t action, pid_t tid, int timeout_secs) {
-  debugger_msg_t msg;
-  memset(&msg, 0, sizeof(msg));
-  msg.tid = tid;
-  msg.action = action;
-
-  int sock_fd = socket_local_client(DEBUGGER_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT,
-      SOCK_STREAM | SOCK_CLOEXEC);
-  if (sock_fd < 0) {
-    return -1;
-  }
-
-  if (timeout_secs > 0) {
-    struct timeval tm;
-    tm.tv_sec = timeout_secs;
-    tm.tv_usec = 0;
-    if (setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &tm, sizeof(tm)) == -1) {
-      ALOGE("WARNING: Cannot set receive timeout value on socket: %s", strerror(errno));
-    }
-
-    if (setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, &tm, sizeof(tm)) == -1) {
-      ALOGE("WARNING: Cannot set send timeout value on socket: %s", strerror(errno));
-    }
-  }
-
-  if (send_request(sock_fd, &msg, sizeof(msg)) < 0) {
-    close(sock_fd);
-    return -1;
-  }
-
-  return sock_fd;
-}
-
-int dump_backtrace_to_file(pid_t tid, int fd) {
-  return dump_backtrace_to_file_timeout(tid, fd, 0);
-}
-
-int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs) {
-  int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_BACKTRACE, tid, timeout_secs);
-  if (sock_fd < 0) {
-    return -1;
-  }
-
-  /* Write the data read from the socket to the fd. */
-  int result = 0;
-  char buffer[1024];
-  ssize_t n;
-  while ((n = TEMP_FAILURE_RETRY(read(sock_fd, buffer, sizeof(buffer)))) > 0) {
-    if (TEMP_FAILURE_RETRY(write(fd, buffer, n)) != n) {
-      result = -1;
-      break;
-    }
-  }
-  close(sock_fd);
-  return result;
-}
-
-int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen) {
-  return dump_tombstone_timeout(tid, pathbuf, pathlen, 0);
-}
-
-int dump_tombstone_timeout(pid_t tid, char* pathbuf, size_t pathlen, int timeout_secs) {
-  int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_TOMBSTONE, tid, timeout_secs);
-  if (sock_fd < 0) {
-    return -1;
-  }
-
-  /* Read the tombstone file name. */
-  char buffer[100]; /* This is larger than the largest tombstone path. */
-  int result = 0;
-  ssize_t n = TEMP_FAILURE_RETRY(read(sock_fd, buffer, sizeof(buffer) - 1));
-  if (n <= 0) {
-    result = -1;
-  } else {
-    if (pathbuf && pathlen) {
-      if (n >= (ssize_t) pathlen) {
-        n = pathlen - 1;
-      }
-      buffer[n] = '\0';
-      memcpy(pathbuf, buffer, n + 1);
-    }
-  }
-  close(sock_fd);
-  return result;
-}
diff --git a/libcutils/dlmalloc_stubs.c b/libcutils/dlmalloc_stubs.c
index 6c07bed..2cff9dd 100644
--- a/libcutils/dlmalloc_stubs.c
+++ b/libcutils/dlmalloc_stubs.c
@@ -16,7 +16,7 @@
 
 #define LOG_TAG "dlmalloc-stubs"
 
-#include "android/log.h"
+#include "log/log.h"
 
 #define UNUSED __attribute__((__unused__))
 
diff --git a/libcutils/fs.c b/libcutils/fs.c
index c49233e..488fdfc 100644
--- a/libcutils/fs.c
+++ b/libcutils/fs.c
@@ -32,8 +32,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/fs.h>
+#include <log/log.h>
 
 #define ALL_PERMS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
 #define BUF_SIZE 64
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 6155d16..594b23d 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -33,7 +33,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <private/android_filesystem_config.h>
 #include <utils/Compat.h>
 
@@ -163,6 +163,10 @@
                                            CAP_MASK_LONG(CAP_NET_RAW),
                                               "system/bin/hw/android.hardware.wifi@1.0-service" },
 
+    /* Support Bluetooth legacy hal accessing /sys/class/rfkill */
+    { 00700, AID_BLUETOOTH, AID_BLUETOOTH, CAP_MASK_LONG(CAP_NET_ADMIN),
+                                              "system/bin/hw/android.hardware.bluetooth@1.0-service" },
+
     /* A non-privileged zygote that spawns isolated processes for web rendering. */
     { 0750,  AID_ROOT,      AID_ROOT,      CAP_MASK_LONG(CAP_SETUID) |
                                            CAP_MASK_LONG(CAP_SETGID) |
@@ -173,6 +177,9 @@
                                            CAP_MASK_LONG(CAP_SETPCAP),
                                               "system/bin/webview_zygote64" },
 
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/crash_dump32" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/crash_dump64" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/debuggerd" },
     { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/uncrypt" },
     { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/install-recovery.sh" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
diff --git a/libcutils/klog.cpp b/libcutils/klog.cpp
index 4bad28a..15adf6b 100644
--- a/libcutils/klog.cpp
+++ b/libcutils/klog.cpp
@@ -27,7 +27,7 @@
 #include <cutils/android_get_control_file.h>
 #include <cutils/klog.h>
 
-static int klog_level = KLOG_DEFAULT_LEVEL;
+static int klog_level = KLOG_INFO_LEVEL;
 
 int klog_get_level(void) {
     return klog_level;
diff --git a/libcutils/multiuser.c b/libcutils/multiuser.c
index 0ef337d..08d4d6c 100644
--- a/libcutils/multiuser.c
+++ b/libcutils/multiuser.c
@@ -37,6 +37,14 @@
     }
 }
 
+gid_t multiuser_get_ext_gid(userid_t user_id, appid_t app_id) {
+    if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
+        return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_EXT_GID_START);
+    } else {
+        return -1;
+    }
+}
+
 gid_t multiuser_get_shared_gid(userid_t user_id, appid_t app_id) {
     if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
         return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_SHARED_GID_START);
diff --git a/libcutils/properties.c b/libcutils/properties.c
index 740c7a9..bdbddd0 100644
--- a/libcutils/properties.c
+++ b/libcutils/properties.c
@@ -26,9 +26,9 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
+#include <log/log.h>
 
 int8_t property_get_bool(const char *key, int8_t default_value) {
     if (!key) {
diff --git a/libcutils/qtaguid.c b/libcutils/qtaguid.c
index ae5a503..22b8325 100644
--- a/libcutils/qtaguid.c
+++ b/libcutils/qtaguid.c
@@ -26,7 +26,7 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <cutils/qtaguid.h>
 
 static const char* CTRL_PROCPATH = "/proc/net/xt_qtaguid/ctrl";
diff --git a/libcutils/sockets_unix.cpp b/libcutils/sockets_unix.cpp
index 5a14a5c..e91f358 100644
--- a/libcutils/sockets_unix.cpp
+++ b/libcutils/sockets_unix.cpp
@@ -25,9 +25,9 @@
 #include <time.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/android_get_control_file.h>
 #include <cutils/sockets.h>
+#include <log/log.h>
 
 #include "android_get_control_env.h"
 
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
index 6bb7e58..8dafded 100644
--- a/libcutils/str_parms.c
+++ b/libcutils/str_parms.c
@@ -24,10 +24,10 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <android/log.h>
 #include <cutils/hashmap.h>
 #include <cutils/memory.h>
 #include <cutils/str_parms.h>
+#include <log/log.h>
 
 #define UNUSED __attribute__((unused))
 
diff --git a/libcutils/tests/multiuser_test.cpp b/libcutils/tests/multiuser_test.cpp
index 2307ea8..c5f58b4 100644
--- a/libcutils/tests/multiuser_test.cpp
+++ b/libcutils/tests/multiuser_test.cpp
@@ -58,6 +58,14 @@
     EXPECT_EQ(1020000, multiuser_get_cache_gid(10, 10000));
 }
 
+TEST(MultiuserTest, TestExt) {
+    EXPECT_EQ(-1, multiuser_get_ext_gid(0, 0));
+    EXPECT_EQ(-1, multiuser_get_ext_gid(0, 1000));
+    EXPECT_EQ(30000, multiuser_get_ext_gid(0, 10000));
+    EXPECT_EQ(-1, multiuser_get_ext_gid(0, 50000));
+    EXPECT_EQ(1030000, multiuser_get_ext_gid(10, 10000));
+}
+
 TEST(MultiuserTest, TestShared) {
     EXPECT_EQ(-1, multiuser_get_shared_gid(0, 0));
     EXPECT_EQ(-1, multiuser_get_shared_gid(0, 1000));
diff --git a/libdiskconfig/config_mbr.c b/libdiskconfig/config_mbr.c
index 1d3cd20..ace9bbf 100644
--- a/libdiskconfig/config_mbr.c
+++ b/libdiskconfig/config_mbr.c
@@ -22,8 +22,8 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <android/log.h>
 #include <diskconfig/diskconfig.h>
+#include <log/log.h>
 
 /* start and len are in LBA units */
 static void
diff --git a/libdiskconfig/diskconfig.c b/libdiskconfig/diskconfig.c
index 2d59ad9..c7e1b43 100644
--- a/libdiskconfig/diskconfig.c
+++ b/libdiskconfig/diskconfig.c
@@ -28,8 +28,8 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/config_utils.h>
+#include <log/log.h>
 
 #include <diskconfig/diskconfig.h>
 
diff --git a/libdiskconfig/diskutils.c b/libdiskconfig/diskutils.c
index 3a27601..fe1b4c1 100644
--- a/libdiskconfig/diskutils.c
+++ b/libdiskconfig/diskutils.c
@@ -26,7 +26,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include <diskconfig/diskconfig.h>
 
diff --git a/libdiskconfig/dump_diskconfig.c b/libdiskconfig/dump_diskconfig.c
index c94e7f4..3c4f620 100644
--- a/libdiskconfig/dump_diskconfig.c
+++ b/libdiskconfig/dump_diskconfig.c
@@ -19,7 +19,7 @@
 
 #include <stdio.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "diskconfig.h"
 
diff --git a/libdiskconfig/write_lst.c b/libdiskconfig/write_lst.c
index 21d4a31..c3d5c0a 100644
--- a/libdiskconfig/write_lst.c
+++ b/libdiskconfig/write_lst.c
@@ -23,8 +23,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <diskconfig/diskconfig.h>
+#include <log/log.h>
 
 struct write_list *
 alloc_wl(uint32_t data_len)
diff --git a/libion/ion.c b/libion/ion.c
index a7b22b8..9aaa6f2 100644
--- a/libion/ion.c
+++ b/libion/ion.c
@@ -29,8 +29,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <ion/ion.h>
+#include <log/log.h>
 
 int ion_open()
 {
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 02feb97..ec0352e 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -1831,7 +1831,7 @@
         return;
     }
 
-    setuid(AID_SYSTEM); // only one that can read security buffer
+    EXPECT_EQ(0, setuid(AID_SYSTEM)); // only one that can read security buffer
 
     pid_t pid = getpid();
 
diff --git a/libmemtrack/memtrack.c b/libmemtrack/memtrack.c
index 29cc92c..9ed9451 100644
--- a/libmemtrack/memtrack.c
+++ b/libmemtrack/memtrack.c
@@ -22,8 +22,8 @@
 #include <malloc.h>
 #include <string.h>
 
-#include <android/log.h>
 #include <hardware/memtrack.h>
+#include <log/log.h>
 
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
 
diff --git a/libmemunreachable/log.h b/libmemunreachable/log.h
index dd146b6..cdfbfd9 100644
--- a/libmemunreachable/log.h
+++ b/libmemunreachable/log.h
@@ -19,6 +19,6 @@
 
 #define LOG_TAG "libmemunreachable"
 
-#include <android/log.h>
+#include <log/log.h>
 
 #endif // LIBMEMUNREACHABLE_LOG_H_
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index eafc53d..83f35b1 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -28,7 +28,7 @@
 
 #include <cstring>
 
-#include <android/log.h>
+#include <log/log.h>
 
 namespace android {
 
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 15fe054..94c46fc 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -19,10 +19,10 @@
 
 #include <dlfcn.h>
 #ifdef __ANDROID__
-#include "dlext_namespaces.h"
 #define LOG_TAG "libnativeloader"
-#include "android/log.h"
+#include "dlext_namespaces.h"
 #include "cutils/properties.h"
+#include "log/log.h"
 #endif
 #include "nativebridge/native_bridge.h"
 
diff --git a/libnetutils/dhcpclient.c b/libnetutils/dhcpclient.c
index d17bdd3..11c116a 100644
--- a/libnetutils/dhcpclient.c
+++ b/libnetutils/dhcpclient.c
@@ -31,8 +31,8 @@
 #include <time.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/properties.h>
+#include <log/log.h>
 
 #include <netutils/ifc.h>
 #include "dhcpmsg.h"
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index 275327a..a098d59 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -38,8 +38,8 @@
 
 #ifdef ANDROID
 #define LOG_TAG "NetUtils"
-#include <android/log.h>
 #include <cutils/properties.h>
+#include <log/log.h>
 #else
 #define ALOGD printf
 #define ALOGW printf
diff --git a/libnetutils/packet.c b/libnetutils/packet.c
index 56168e8..e53a4c8 100644
--- a/libnetutils/packet.c
+++ b/libnetutils/packet.c
@@ -28,7 +28,7 @@
 
 #ifdef ANDROID
 #define LOG_TAG "DHCP"
-#include <android/log.h>
+#include <log/log.h>
 #else
 #include <stdio.h>
 #define ALOGD printf
diff --git a/libpackagelistparser/packagelistparser.c b/libpackagelistparser/packagelistparser.c
index f74b8b4..3e1a3d1 100644
--- a/libpackagelistparser/packagelistparser.c
+++ b/libpackagelistparser/packagelistparser.c
@@ -27,7 +27,7 @@
 #include <string.h>
 #include <sys/limits.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <packagelistparser/packagelistparser.h>
 
 #define CLOGE(fmt, ...) \
diff --git a/libpixelflinger/codeflinger/ARMAssembler.cpp b/libpixelflinger/codeflinger/ARMAssembler.cpp
index 36c1326..ac009a9 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.cpp
+++ b/libpixelflinger/codeflinger/ARMAssembler.cpp
@@ -20,8 +20,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <android/log.h>
 #include <cutils/properties.h>
+#include <log/log.h>
 #include <private/pixelflinger/ggl_context.h>
 
 #include "ARMAssembler.h"
diff --git a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp b/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
index e212f1b..c96cf4b 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
+++ b/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
@@ -21,7 +21,7 @@
 #include <stdlib.h>
 #include <sys/types.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "ARMAssemblerInterface.h"
 
diff --git a/libpixelflinger/codeflinger/Arm64Assembler.cpp b/libpixelflinger/codeflinger/Arm64Assembler.cpp
index fb297ec..bff87bb 100644
--- a/libpixelflinger/codeflinger/Arm64Assembler.cpp
+++ b/libpixelflinger/codeflinger/Arm64Assembler.cpp
@@ -32,8 +32,8 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <android/log.h>
 #include <cutils/properties.h>
+#include <log/log.h>
 #include <private/pixelflinger/ggl_context.h>
 
 #include "codeflinger/Arm64Assembler.h"
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
index 37bd074..8516640 100644
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ b/libpixelflinger/codeflinger/CodeCache.cpp
@@ -23,8 +23,8 @@
 #include <sys/mman.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/ashmem.h>
+#include <log/log.h>
 
 #include "CodeCache.h"
 
diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp
index 0b9b5a4..91fbd53 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.cpp
+++ b/libpixelflinger/codeflinger/GGLAssembler.cpp
@@ -23,7 +23,7 @@
 #include <stdlib.h>
 #include <sys/types.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "GGLAssembler.h"
 
diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.cpp b/libpixelflinger/codeflinger/MIPS64Assembler.cpp
index a7bbaf7..d5e4cea 100644
--- a/libpixelflinger/codeflinger/MIPS64Assembler.cpp
+++ b/libpixelflinger/codeflinger/MIPS64Assembler.cpp
@@ -30,8 +30,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <android/log.h>
 #include <cutils/properties.h>
+#include <log/log.h>
 #include <private/pixelflinger/ggl_context.h>
 
 #include "MIPS64Assembler.h"
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.cpp b/libpixelflinger/codeflinger/MIPSAssembler.cpp
index 4cddcc8..865a568 100644
--- a/libpixelflinger/codeflinger/MIPSAssembler.cpp
+++ b/libpixelflinger/codeflinger/MIPSAssembler.cpp
@@ -47,14 +47,13 @@
 ** functions in ARMAssemblerInterface.cpp so they could be used as static initializers).
 */
 
-
 #define LOG_TAG "MIPSAssembler"
 
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <android/log.h>
 #include <cutils/properties.h>
+#include <log/log.h>
 #include <private/pixelflinger/ggl_context.h>
 
 #include "CodeCache.h"
diff --git a/libpixelflinger/codeflinger/blending.cpp b/libpixelflinger/codeflinger/blending.cpp
index 092f140..a55dfe3 100644
--- a/libpixelflinger/codeflinger/blending.cpp
+++ b/libpixelflinger/codeflinger/blending.cpp
@@ -23,7 +23,7 @@
 #include <stdlib.h>
 #include <sys/types.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "GGLAssembler.h"
 
diff --git a/libpixelflinger/codeflinger/load_store.cpp b/libpixelflinger/codeflinger/load_store.cpp
index b8a0e55..da21e1d 100644
--- a/libpixelflinger/codeflinger/load_store.cpp
+++ b/libpixelflinger/codeflinger/load_store.cpp
@@ -20,7 +20,7 @@
 #include <assert.h>
 #include <stdio.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "GGLAssembler.h"
 
diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp
index f4f4657..4c357af 100644
--- a/libpixelflinger/codeflinger/texturing.cpp
+++ b/libpixelflinger/codeflinger/texturing.cpp
@@ -23,7 +23,7 @@
 #include <stdlib.h>
 #include <sys/types.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "GGLAssembler.h"
 
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index 1a2f6fb..c6cf5bf 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -22,8 +22,8 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <android/log.h>
 #include <cutils/memory.h>
+#include <log/log.h>
 
 #include "buffer.h"
 #include "scanline.h"
diff --git a/libpixelflinger/trap.cpp b/libpixelflinger/trap.cpp
index fa6338a..234bfdd 100644
--- a/libpixelflinger/trap.cpp
+++ b/libpixelflinger/trap.cpp
@@ -21,8 +21,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <android/log.h>
 #include <cutils/memory.h>
+#include <log/log.h>
 
 #include "trap.h"
 #include "picker.h"
diff --git a/libsparse/Android.bp b/libsparse/Android.bp
index 7a6ae8a..dd8b5fd 100644
--- a/libsparse/Android.bp
+++ b/libsparse/Android.bp
@@ -1,7 +1,9 @@
 // Copyright 2010 The Android Open Source Project
 
-cc_defaults {
-    name: "libsparse_defaults",
+cc_library {
+    name: "libsparse",
+    host_supported: true,
+    unique_host_soname: true,
     srcs: [
         "backed_block.c",
         "output_file.c",
@@ -13,32 +15,19 @@
     cflags: ["-Werror"],
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
-}
-
-cc_library_host_static {
-    name: "libsparse_host",
-    defaults: ["libsparse_defaults"],
-    static_libs: ["libz"],
     target: {
+        host: {
+            shared_libs: ["libz-host"],
+        },
+        android: {
+            shared_libs: ["libz"],
+        },
         windows: {
             enabled: true,
         },
     },
 }
 
-cc_library_shared {
-    name: "libsparse",
-    defaults: ["libsparse_defaults"],
-    shared_libs: ["libz"],
-}
-
-cc_library_static {
-    name: "libsparse_static",
-    host_supported: true,
-    defaults: ["libsparse_defaults"],
-    static_libs: ["libz"],
-}
-
 cc_binary {
     name: "simg2img",
     host_supported: true,
@@ -47,7 +36,7 @@
         "sparse_crc32.c",
     ],
     static_libs: [
-        "libsparse_static",
+        "libsparse",
         "libz",
     ],
 
@@ -59,7 +48,7 @@
     host_supported: true,
     srcs: ["img2simg.c"],
     static_libs: [
-        "libsparse_static",
+        "libsparse",
         "libz",
     ],
 
@@ -70,7 +59,7 @@
     name: "append2simg",
     srcs: ["append2simg.c"],
     static_libs: [
-        "libsparse_static",
+        "libsparse",
         "libz",
     ],
 
diff --git a/libsuspend/autosuspend.c b/libsuspend/autosuspend.c
index 64d1bfc..54730c2 100644
--- a/libsuspend/autosuspend.c
+++ b/libsuspend/autosuspend.c
@@ -18,7 +18,7 @@
 
 #include <stdbool.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include <suspend/autosuspend.h>
 
diff --git a/libsuspend/autosuspend_autosleep.c b/libsuspend/autosuspend_autosleep.c
index 97109ac..77d8db0 100644
--- a/libsuspend/autosuspend_autosleep.c
+++ b/libsuspend/autosuspend_autosleep.c
@@ -24,7 +24,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "autosuspend_ops.h"
 
diff --git a/libsuspend/autosuspend_earlysuspend.c b/libsuspend/autosuspend_earlysuspend.c
index 9519e51..809ee82 100644
--- a/libsuspend/autosuspend_earlysuspend.c
+++ b/libsuspend/autosuspend_earlysuspend.c
@@ -26,7 +26,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "autosuspend_ops.h"
 
diff --git a/libsuspend/autosuspend_wakeup_count.c b/libsuspend/autosuspend_wakeup_count.c
index 3457d5b..2da204a 100644
--- a/libsuspend/autosuspend_wakeup_count.c
+++ b/libsuspend/autosuspend_wakeup_count.c
@@ -29,7 +29,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "autosuspend_ops.h"
 
diff --git a/libsync/include/sync/sync.h b/libsync/include/sync/sync.h
index 2e5d82f..50ed0ac 100644
--- a/libsync/include/sync/sync.h
+++ b/libsync/include/sync/sync.h
@@ -22,9 +22,16 @@
 #include <sys/cdefs.h>
 #include <stdint.h>
 
+#include <linux/types.h>
+
 __BEGIN_DECLS
 
-// XXX: These structs are copied from the header "linux/sync.h".
+struct sync_legacy_merge_data {
+ int32_t fd2;
+ char name[32];
+ int32_t fence;
+};
+
 struct sync_fence_info_data {
  uint32_t len;
  char name[32];
@@ -41,6 +48,108 @@
  uint8_t driver_data[0];
 };
 
+#define SYNC_IOC_MAGIC		'>'
+
+/**
+ * DOC: SYNC_IOC_LEGACY_WAIT - wait for a fence to signal
+ *
+ * pass timeout in milliseconds.  Waits indefinitely timeout < 0.
+ *
+ * This is the legacy version of the Sync API before the de-stage that happened
+ * on Linux kernel 4.7.
+ */
+#define SYNC_IOC_LEGACY_WAIT	_IOW(SYNC_IOC_MAGIC, 0, __s32)
+
+/**
+ * DOC: SYNC_IOC_MERGE - merge two fences
+ *
+ * Takes a struct sync_merge_data.  Creates a new fence containing copies of
+ * the sync_pts in both the calling fd and sync_merge_data.fd2.  Returns the
+ * new fence's fd in sync_merge_data.fence
+ *
+ * This is the legacy version of the Sync API before the de-stage that happened
+ * on Linux kernel 4.7.
+ */
+#define SYNC_IOC_LEGACY_MERGE	_IOWR(SYNC_IOC_MAGIC, 1, \
+	struct sync_legacy_merge_data)
+
+/**
+ * DOC: SYNC_IOC_LEGACY_FENCE_INFO - get detailed information on a fence
+ *
+ * Takes a struct sync_fence_info_data with extra space allocated for pt_info.
+ * Caller should write the size of the buffer into len.  On return, len is
+ * updated to reflect the total size of the sync_fence_info_data including
+ * pt_info.
+ *
+ * pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence.
+ * To iterate over the sync_pt_infos, use the sync_pt_info.len field.
+ *
+ * This is the legacy version of the Sync API before the de-stage that happened
+ * on Linux kernel 4.7.
+ */
+#define SYNC_IOC_LEGACY_FENCE_INFO	_IOWR(SYNC_IOC_MAGIC, 2,\
+	struct sync_fence_info_data)
+
+struct sync_merge_data {
+ char name[32];
+ int32_t fd2;
+ int32_t fence;
+ uint32_t flags;
+ uint32_t pad;
+};
+
+struct sync_file_info {
+ char name[32];
+ int32_t status;
+ uint32_t flags;
+ uint32_t num_fences;
+ uint32_t pad;
+
+ uint64_t sync_fence_info;
+};
+
+struct sync_fence_info {
+ char obj_name[32];
+ char driver_name[32];
+ int32_t status;
+ uint32_t flags;
+ uint64_t timestamp_ns;
+};
+
+/**
+ * Mainline API:
+ *
+ * Opcodes  0, 1 and 2 were burned during a API change to avoid users of the
+ * old API to get weird errors when trying to handling sync_files. The API
+ * change happened during the de-stage of the Sync Framework when there was
+ * no upstream users available.
+ */
+
+/**
+ * DOC: SYNC_IOC_MERGE - merge two fences
+ *
+ * Takes a struct sync_merge_data.  Creates a new fence containing copies of
+ * the sync_pts in both the calling fd and sync_merge_data.fd2.  Returns the
+ * new fence's fd in sync_merge_data.fence
+ *
+ * This is the new version of the Sync API after the de-stage that happened
+ * on Linux kernel 4.7.
+ */
+#define SYNC_IOC_MERGE		_IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)
+
+/**
+ * DOC: SYNC_IOC_FILE_INFO - get detailed information on a sync_file
+ *
+ * Takes a struct sync_file_info. If num_fences is 0, the field is updated
+ * with the actual number of fences. If num_fences is > 0, the system will
+ * use the pointer provided on sync_fence_info to return up to num_fences of
+ * struct sync_fence_info, with detailed fence information.
+ *
+ * This is the new version of the Sync API after the de-stage that happened
+ * on Linux kernel 4.7.
+ */
+#define SYNC_IOC_FILE_INFO	_IOWR(SYNC_IOC_MAGIC, 4, struct sync_file_info)
+
 /* timeout in msecs */
 int sync_wait(int fd, int timeout);
 int sync_merge(const char *name, int fd1, int fd2);
diff --git a/libsync/sync.c b/libsync/sync.c
index 6281b20..9ed03db 100644
--- a/libsync/sync.c
+++ b/libsync/sync.c
@@ -20,6 +20,8 @@
 #include <malloc.h>
 #include <stdint.h>
 #include <string.h>
+#include <errno.h>
+#include <poll.h>
 
 #include <sys/ioctl.h>
 #include <sys/stat.h>
@@ -27,18 +29,6 @@
 
 #include <sync/sync.h>
 
-// The sync code is undergoing a major change. Add enough in to get
-// everything to compile wih the latest uapi headers.
-struct sync_merge_data {
-  int32_t fd2;
-  char name[32];
-  int32_t fence;
-};
-
-#define SYNC_IOC_MAGIC '>'
-#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32)
-#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data)
-#define SYNC_IOC_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2, struct sync_fence_info_data)
 
 struct sw_sync_create_fence_data {
   __u32 value;
@@ -52,43 +42,133 @@
 
 int sync_wait(int fd, int timeout)
 {
-    __s32 to = timeout;
+    struct pollfd fds;
+    int ret;
 
-    return ioctl(fd, SYNC_IOC_WAIT, &to);
+    if (fd < 0) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    fds.fd = fd;
+    fds.events = POLLIN;
+
+    do {
+        ret = poll(&fds, 1, timeout);
+        if (ret > 0) {
+            if (fds.revents & (POLLERR | POLLNVAL)) {
+                errno = EINVAL;
+                return -1;
+            }
+            return 0;
+        } else if (ret == 0) {
+            errno = ETIME;
+            return -1;
+        }
+    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+
+    return ret;
 }
 
 int sync_merge(const char *name, int fd1, int fd2)
 {
+    struct sync_legacy_merge_data legacy_data;
     struct sync_merge_data data;
-    int err;
+    int ret;
 
     data.fd2 = fd2;
     strlcpy(data.name, name, sizeof(data.name));
+    data.flags = 0;
+    data.pad = 0;
 
-    err = ioctl(fd1, SYNC_IOC_MERGE, &data);
-    if (err < 0)
-        return err;
+    ret = ioctl(fd1, SYNC_IOC_MERGE, &data);
+    if (ret < 0 && errno == ENOTTY) {
+        legacy_data.fd2 = fd2;
+        strlcpy(legacy_data.name, name, sizeof(legacy_data.name));
+
+        ret = ioctl(fd1, SYNC_IOC_LEGACY_MERGE, &legacy_data);
+        if (ret < 0)
+            return ret;
+
+        return legacy_data.fence;
+    } else if (ret < 0) {
+        return ret;
+    }
 
     return data.fence;
 }
 
 struct sync_fence_info_data *sync_fence_info(int fd)
 {
-    struct sync_fence_info_data *info;
-    int err;
+    struct sync_fence_info_data *legacy_info;
+    struct sync_pt_info *legacy_pt_info;
+    struct sync_file_info *info;
+    struct sync_fence_info *fence_info;
+    int err, num_fences, i;
 
-    info = malloc(4096);
-    if (info == NULL)
+    legacy_info = malloc(4096);
+    if (legacy_info == NULL)
         return NULL;
 
-    info->len = 4096;
-    err = ioctl(fd, SYNC_IOC_FENCE_INFO, info);
-    if (err < 0) {
-        free(info);
+    legacy_info->len = 4096;
+    err = ioctl(fd, SYNC_IOC_LEGACY_FENCE_INFO, legacy_info);
+    if (err < 0 && errno != ENOTTY) {
+        free(legacy_info);
         return NULL;
+    } else if (err == 0) {
+        return legacy_info;
     }
 
-    return info;
+    info = calloc(1, sizeof(*info));
+    if (info == NULL)
+        goto free;
+
+    err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
+    if (err < 0)
+        goto free;
+
+    num_fences = info->num_fences;
+
+    if (num_fences) {
+        info->flags = 0;
+        info->num_fences = num_fences;
+        info->sync_fence_info = (uint64_t) calloc(num_fences,
+                                        sizeof(struct sync_fence_info));
+        if ((void *)info->sync_fence_info == NULL)
+            goto free;
+
+        err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
+        if (err < 0) {
+            free((void *)info->sync_fence_info);
+            goto free;
+        }
+    }
+
+    legacy_info->len = sizeof(*legacy_info) +
+                        num_fences * sizeof(struct sync_fence_info);
+    strlcpy(legacy_info->name, info->name, sizeof(legacy_info->name));
+    legacy_info->status = info->status;
+
+    legacy_pt_info = (struct sync_pt_info *)legacy_info->pt_info;
+    fence_info = (struct sync_fence_info *)info->sync_fence_info;
+    for (i = 0 ; i < num_fences ; i++) {
+        legacy_pt_info[i].len = sizeof(*legacy_pt_info);
+        strlcpy(legacy_pt_info[i].obj_name, fence_info[i].obj_name,
+                sizeof(legacy_pt_info->obj_name));
+        strlcpy(legacy_pt_info[i].driver_name, fence_info[i].driver_name,
+                sizeof(legacy_pt_info->driver_name));
+        legacy_pt_info[i].status = fence_info[i].status;
+        legacy_pt_info[i].timestamp_ns = fence_info[i].timestamp_ns;
+    }
+
+    free((void *)info->sync_fence_info);
+    free(info);
+    return legacy_info;
+
+free:
+    free(legacy_info);
+    free(info);
+    return NULL;
 }
 
 struct sync_pt_info *sync_pt_info(struct sync_fence_info_data *info,
@@ -113,7 +193,13 @@
 
 int sw_sync_timeline_create(void)
 {
-    return open("/dev/sw_sync", O_RDWR);
+    int ret;
+
+    ret = open("/sys/kernel/debug/sync/sw_sync", O_RDWR);
+    if (ret < 0)
+        ret = open("/dev/sw_sync", O_RDWR);
+
+    return ret;
 }
 
 int sw_sync_timeline_inc(int fd, unsigned count)
diff --git a/libsync/tests/sync_test.cpp b/libsync/tests/sync_test.cpp
index 2c409dc..ff8a300 100644
--- a/libsync/tests/sync_test.cpp
+++ b/libsync/tests/sync_test.cpp
@@ -348,33 +348,6 @@
     ASSERT_EQ(selfMergeFence.getSignaledCount(), 1);
 }
 
-TEST(FenceTest, WaitOnDestroyedTimeline) {
-    SyncTimeline timeline;
-    ASSERT_TRUE(timeline.isValid());
-
-    SyncFence fenceSig(timeline, 100);
-    SyncFence fenceKill(timeline, 200);
-
-    // Spawn a thread to wait on a fence when the timeline is killed.
-    thread waitThread{
-        [&]() {
-            ASSERT_EQ(timeline.inc(100), 0);
-
-            ASSERT_EQ(fenceKill.wait(-1), -1);
-            ASSERT_EQ(errno, ENOENT);
-        }
-    };
-
-    // Wait for the thread to spool up.
-    fenceSig.wait();
-
-    // Kill the timeline.
-    timeline.destroy();
-
-    // wait for the thread to clean up.
-    waitThread.join();
-}
-
 TEST(FenceTest, PollOnDestroyedTimeline) {
     SyncTimeline timeline;
     ASSERT_TRUE(timeline.isValid());
@@ -391,8 +364,7 @@
             struct pollfd fds;
             fds.fd = fenceKill.getFd();
             fds.events = POLLIN | POLLERR;
-            ASSERT_EQ(poll(&fds, 1, -1), 1);
-            ASSERT_TRUE(fds.revents & POLLERR);
+            ASSERT_EQ(poll(&fds, 1, 0), 0);
         }
     };
 
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index 26e27cf..77e69e4 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -21,7 +21,7 @@
 #include <sys/eventfd.h>
 #include <unistd.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <utils/Looper.h>
 #include <utils/Timers.h>
 
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index 269326a..957aedb 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -19,7 +19,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "SharedBuffer.h"
 
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index c32f462..f1a41b9 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -19,7 +19,7 @@
 #include <limits.h>
 #include <stddef.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <utils/Unicode.h>
 
 #if defined(_WIN32)
diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp
index 893e4f2..f7ca8f4 100644
--- a/libutils/VectorImpl.cpp
+++ b/libutils/VectorImpl.cpp
@@ -20,7 +20,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <utils/Errors.h>
 #include <utils/VectorImpl.h>
 
diff --git a/libziparchive/zip_archive_stream_entry.cc b/libziparchive/zip_archive_stream_entry.cc
index 64b24c3..3f336a6 100644
--- a/libziparchive/zip_archive_stream_entry.cc
+++ b/libziparchive/zip_archive_stream_entry.cc
@@ -26,8 +26,9 @@
 #include <memory>
 #include <vector>
 
-#include <android/log.h>
 #include <android-base/file.h>
+#include <log/log.h>
+
 #include <ziparchive/zip_archive.h>
 #include <ziparchive/zip_archive_stream_entry.h>
 #include <zlib.h>
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 49746b3..8a6168c 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -31,8 +31,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/sockets.h>
+#include <log/log.h>
 #include <processgroup/processgroup.h>
 
 #ifndef __unused
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 1bfecd6..3ad0983 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -28,8 +28,8 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/klog.h>
+#include <log/log.h>
 #include <logwrap/logwrap.h>
 #include <private/android_filesystem_config.h>
 
diff --git a/logwrapper/logwrapper.c b/logwrapper/logwrapper.c
index 28fe530..33454c6 100644
--- a/logwrapper/logwrapper.c
+++ b/logwrapper/logwrapper.c
@@ -20,8 +20,8 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/klog.h>
+#include <log/log.h>
 #include <logwrap/logwrap.h>
 
 void fatal(const char *msg) {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index c0a0fce..791d67f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -312,6 +312,7 @@
     # Make sure /sys/kernel/debug (if present) is labeled properly
     # Note that tracefs may be mounted under debug, so we need to cross filesystems
     restorecon --recursive --cross-filesystems /sys/kernel/debug
+    chmod 0755 /sys/kernel/debug/tracing
 
     # We chown/chmod /cache again so because mount is run as root + defaults
     chown system cache /cache
diff --git a/rootdir/init.usb.configfs.rc b/rootdir/init.usb.configfs.rc
index dc875b4..32f0198 100644
--- a/rootdir/init.usb.configfs.rc
+++ b/rootdir/init.usb.configfs.rc
@@ -70,7 +70,7 @@
 
 on property:sys.usb.config=audio_source && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "audiosource"
-    symlink /config/usb_gadget/g1/functions/audio_source.gs2 /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/audio_source.gs3 /config/usb_gadget/g1/configs/b.1/f1
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
     setprop sys.usb.state ${sys.usb.config}
 
@@ -79,7 +79,7 @@
 
 on property:sys.usb.ffs.ready=1 && property:sys.usb.config=audio_source,adb && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "audiosource_adb"
-    symlink /config/usb_gadget/g1/functions/audio_source.gs2 /config/usb_gadget/g1/configs/b.1/f1
+    symlink /config/usb_gadget/g1/functions/audio_source.gs3 /config/usb_gadget/g1/configs/b.1/f1
     symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
     setprop sys.usb.state ${sys.usb.config}
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 8725113..0633a68 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -38,8 +38,6 @@
 # these should not be world writable
 /dev/diag                 0660   radio      radio
 /dev/diag_arm9            0660   radio      radio
-/dev/android_adb          0660   adb        adb
-/dev/android_adb_enable   0660   adb        adb
 /dev/ttyMSM0              0600   bluetooth  bluetooth
 /dev/uhid                 0660   system     bluetooth
 /dev/uinput               0660   system     bluetooth
diff --git a/trusty/gatekeeper/trusty_gatekeeper.cpp b/trusty/gatekeeper/trusty_gatekeeper.cpp
index 7e55fb1..b3fbfa9 100644
--- a/trusty/gatekeeper/trusty_gatekeeper.cpp
+++ b/trusty/gatekeeper/trusty_gatekeeper.cpp
@@ -19,9 +19,10 @@
 #include <assert.h>
 #include <errno.h>
 #include <stdio.h>
+
 #include <type_traits>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "trusty_gatekeeper.h"
 #include "trusty_gatekeeper_ipc.h"
diff --git a/trusty/gatekeeper/trusty_gatekeeper_ipc.c b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
index 45e65a7..f67944b 100644
--- a/trusty/gatekeeper/trusty_gatekeeper_ipc.c
+++ b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
@@ -22,7 +22,7 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <trusty/tipc.h>
 
 #include "trusty_gatekeeper_ipc.h"
diff --git a/trusty/keymaster/trusty_keymaster_device.cpp b/trusty/keymaster/trusty_keymaster_device.cpp
index de5e463..1368f88 100644
--- a/trusty/keymaster/trusty_keymaster_device.cpp
+++ b/trusty/keymaster/trusty_keymaster_device.cpp
@@ -27,9 +27,9 @@
 
 #include <type_traits>
 
-#include <android/log.h>
 #include <hardware/keymaster0.h>
 #include <keymaster/authorization_set.h>
+#include <log/log.h>
 
 #include "trusty_keymaster_device.h"
 #include "trusty_keymaster_ipc.h"
diff --git a/trusty/keymaster/trusty_keymaster_ipc.c b/trusty/keymaster/trusty_keymaster_ipc.c
index 8755093..88546af 100644
--- a/trusty/keymaster/trusty_keymaster_ipc.c
+++ b/trusty/keymaster/trusty_keymaster_ipc.c
@@ -23,7 +23,7 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <trusty/tipc.h>
 
 #include "trusty_keymaster_ipc.h"
diff --git a/trusty/libtrusty/trusty.c b/trusty/libtrusty/trusty.c
index 2398a53..a6238af 100644
--- a/trusty/libtrusty/trusty.c
+++ b/trusty/libtrusty/trusty.c
@@ -25,7 +25,7 @@
 #include <sys/ioctl.h>
 #include <unistd.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "tipc_ioctl.h"
 
diff --git a/trusty/nvram/trusty_nvram_implementation.cpp b/trusty/nvram/trusty_nvram_implementation.cpp
index ddaf333..9215c85 100644
--- a/trusty/nvram/trusty_nvram_implementation.cpp
+++ b/trusty/nvram/trusty_nvram_implementation.cpp
@@ -22,8 +22,8 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <hardware/nvram.h>
+#include <log/log.h>
 #include <trusty/tipc.h>
 
 #include <nvram/messages/blob.h>
diff --git a/trusty/storage/lib/storage.c b/trusty/storage/lib/storage.c
index 3002c0b..915bc17 100644
--- a/trusty/storage/lib/storage.c
+++ b/trusty/storage/lib/storage.c
@@ -23,7 +23,7 @@
 #include <string.h>
 #include <sys/uio.h>
 
-#include <android/log.h>
+#include <log/log.h>
 #include <trusty/tipc.h>
 #include <trusty/lib/storage.h>
 
diff --git a/trusty/storage/proxy/log.h b/trusty/storage/proxy/log.h
index 3d2e654..c81beab 100644
--- a/trusty/storage/proxy/log.h
+++ b/trusty/storage/proxy/log.h
@@ -16,5 +16,5 @@
 
 #define LOG_TAG "storageproxyd"
 
-#include <android/log.h>
+#include <log/log.h>
 
diff --git a/tzdatacheck/tzdatacheck.cpp b/tzdatacheck/tzdatacheck.cpp
index c1ab2ac..fb5c84b 100644
--- a/tzdatacheck/tzdatacheck.cpp
+++ b/tzdatacheck/tzdatacheck.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
 #include <errno.h>
 #include <ftw.h>
 #include <libgen.h>
@@ -29,47 +30,105 @@
 
 #include "android-base/logging.h"
 
+static const char* BUNDLE_VERSION_FILENAME = "/bundle_version";
+// bundle_version is an ASCII file consisting of 17 bytes in the form: AAA.BBB|CCCCC|DDD
+// AAA.BBB is the major/minor version of the bundle format (e.g. 001.001),
+// CCCCC is the rules version (e.g. 2016g)
+// DDD is the android revision for this rules version to allow for bundle corrections (e.g. 001)
+// We only need the first 13 to determine if it is suitable for the device.
+static const int BUNDLE_VERSION_LENGTH = 13;
+// The major version of the bundle format supported by this code as a null-terminated char[].
+static const char REQUIRED_BUNDLE_VERSION[] = "001";
+static const size_t REQUIRED_BUNDLE_VERSION_LEN = sizeof(REQUIRED_BUNDLE_VERSION) - 1; // exclude \0
+// The length of the IANA rules version bytes. e.g. 2016a
+static const size_t RULES_VERSION_LEN = 5;
+// Bundle version bytes are: AAA.BBB|CCCCC - the rules version is CCCCC
+static const size_t BUNDLE_VERSION_RULES_IDX = 8;
+
 static const char* TZDATA_FILENAME = "/tzdata";
 // tzdata file header (as much as we need for the version):
 // byte[11] tzdata_version  -- e.g. "tzdata2012f"
 static const int TZ_HEADER_LENGTH = 11;
+// The major version of the bundle format supported by this code as a null-terminated char[].
+static const char TZ_DATA_HEADER_PREFIX[] = "tzdata";
+static const size_t TZ_DATA_HEADER_PREFIX_LEN = sizeof(TZ_DATA_HEADER_PREFIX) - 1; // exclude \0
+
 
 static void usage() {
     std::cerr << "Usage: tzdatacheck SYSTEM_TZ_DIR DATA_TZ_DIR\n"
             "\n"
-            "Compares the headers of two tzdata files. If the one in SYSTEM_TZ_DIR is the\n"
-            "same or a higher version than the one in DATA_TZ_DIR the DATA_TZ_DIR is renamed\n"
-            "and then deleted.\n";
+            "Checks whether any timezone update bundle in DATA_TZ_DIR is compatible with the\n"
+            "current Android release and better than or the same as base system timezone rules in\n"
+            "SYSTEM_TZ_DIR. If the timezone rules in SYSTEM_TZ_DIR are a higher version than the\n"
+            "one in DATA_TZ_DIR the DATA_TZ_DIR is renamed and then deleted.\n";
     exit(1);
 }
 
 /*
- * Opens a file and fills headerBytes with the first byteCount bytes from the file. It is a fatal
- * error if the file is too small or cannot be opened. If the file does not exist false is returned.
+ * Opens a file and fills buffer with the first byteCount bytes from the file.
+ * If the file does not exist or cannot be opened or is too short then false is returned.
  * If the bytes were read successfully then true is returned.
  */
-static bool readHeader(const std::string& tzDataFileName, char* headerBytes, size_t byteCount) {
-    FILE* tzDataFile = fopen(tzDataFileName.c_str(), "r");
-    if (tzDataFile == nullptr) {
-        if (errno == ENOENT) {
-            return false;
-        } else {
-            PLOG(FATAL) << "Error opening tzdata file " << tzDataFileName;
+static bool readBytes(const std::string& fileName, char* buffer, size_t byteCount) {
+    FILE* file = fopen(fileName.c_str(), "r");
+    if (file == nullptr) {
+        if (errno != ENOENT) {
+            PLOG(WARNING) << "Error opening file " << fileName;
         }
+        return false;
     }
-    size_t bytesRead = fread(headerBytes, 1, byteCount, tzDataFile);
+    size_t bytesRead = fread(buffer, 1, byteCount, file);
+    fclose(file);
     if (bytesRead != byteCount) {
-        LOG(FATAL) << tzDataFileName << " is too small. " << byteCount << " bytes required";
+        LOG(WARNING) << fileName << " is too small. " << byteCount << " bytes required";
+        return false;
     }
-    fclose(tzDataFile);
     return true;
 }
 
-/* Checks the contents of headerBytes. It is a fatal error if it not a tzdata header. */
-static void checkValidHeader(const std::string& fileName, char* headerBytes) {
+/*
+ * Checks the contents of headerBytes. Returns true if it is valid (starts with "tzdata"), false
+ * otherwise.
+ */
+static bool checkValidTzDataHeader(const std::string& fileName, const char* headerBytes) {
     if (strncmp("tzdata", headerBytes, 6) != 0) {
-        LOG(FATAL) << fileName << " does not start with the expected bytes (tzdata)";
+        LOG(WARNING) << fileName << " does not start with the expected bytes (tzdata)";
+        return false;
     }
+    return true;
+}
+
+static bool checkDigits(const char* buffer, const size_t count, size_t* i) {
+    for (size_t j = 0; j < count; j++) {
+      char toCheck = buffer[(*i)++];
+      if (!isdigit(toCheck)) {
+        return false;
+      }
+    }
+    return true;
+}
+
+static bool checkValidBundleVersion(const char* buffer) {
+    // See BUNDLE_VERSION_LENGTH comments above for a description of the format.
+    size_t i = 0;
+    if (!checkDigits(buffer, 3, &i)) {
+      return false;
+    }
+    if (buffer[i++] != '.') {
+      return false;
+    }
+    if (!checkDigits(buffer, 3, &i)) {
+      return false;
+    }
+    if (buffer[i++] != '|') {
+      return false;
+    }
+    if (!checkDigits(buffer, 4, &i)) {
+      return false;
+    }
+    // Ignore the last character. It is assumed to be a letter but we don't check because it's not
+    // obvious what would happen at 'z'.
+    return true;
 }
 
 /* Return the parent directory of dirName. */
@@ -103,9 +162,24 @@
     return 0;
 }
 
+enum PathStatus { ERR, NONE, IS_DIR, NOT_DIR };
+
+static PathStatus checkPath(const std::string& path) {
+    struct stat buf;
+    if (stat(path.c_str(), &buf) != 0) {
+        if (errno != ENOENT) {
+            PLOG(WARNING) << "Unable to stat " << path;
+            return ERR;
+        }
+        return NONE;
+    }
+    return S_ISDIR(buf.st_mode) ? IS_DIR : NOT_DIR;
+}
+
 /*
  * Deletes dirToDelete and returns true if it is successful in removing or moving the directory out
- * of the way. If dirToDelete does not exist this function does nothing and returns true.
+ * of the way. If dirToDelete does not exist this function does nothing and returns true. If
+ * dirToDelete is not a directory or cannot be accessed this method returns false.
  *
  * During deletion, this function first renames the directory to a temporary name. If the temporary
  * directory cannot be created, or the directory cannot be renamed, false is returned. After the
@@ -114,23 +188,18 @@
  */
 static bool deleteDir(const std::string& dirToDelete) {
     // Check whether the dir exists.
-    struct stat buf;
-    if (stat(dirToDelete.c_str(), &buf) == 0) {
-      if (!S_ISDIR(buf.st_mode)) {
-        LOG(WARNING) << dirToDelete << " is not a directory";
+    int pathStatus = checkPath(dirToDelete);
+    if (pathStatus == NONE) {
+        LOG(INFO) << "Path " << dirToDelete << " does not exist";
+        return true;
+    }
+    if (pathStatus != IS_DIR) {
+        LOG(WARNING) << "Path " << dirToDelete << " failed to stat() or is not a directory.";
         return false;
-      }
-    } else {
-      if (errno == ENOENT) {
-          PLOG(INFO) << "Directory does not exist: " << dirToDelete;
-          return true;
-      } else {
-          PLOG(WARNING) << "Unable to stat " << dirToDelete;
-          return false;
-      }
     }
 
     // First, rename dirToDelete.
+
     std::string tempDirNameTemplate = getParentDir(dirToDelete);
     tempDirNameTemplate += "/tempXXXXXX";
 
@@ -142,7 +211,7 @@
         return false;
     }
 
-    // Rename dirToDelete to tempDirName.
+    // Rename dirToDelete to tempDirName (replacing the empty tempDirName directory created above).
     int rc = rename(dirToDelete.c_str(), &tempDirName[0]);
     if (rc == -1) {
         PLOG(WARNING) << "Unable to rename directory from " << dirToDelete << " to "
@@ -151,6 +220,7 @@
     }
 
     // Recursively delete contents of tempDirName.
+
     rc = nftw(&tempDirName[0], deleteFn, 10 /* openFiles */,
             FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
     if (rc == -1) {
@@ -160,9 +230,36 @@
 }
 
 /*
+ * Deletes the ConfigInstaller metadata directory.
+ * TODO(nfuller). http://b/31008728 Remove this when ConfigInstaller is no longer used.
+ */
+static void deleteConfigUpdaterMetadataDir(const char* dataZoneInfoDir) {
+    // Delete the update metadata
+    std::string dataUpdatesDirName(dataZoneInfoDir);
+    dataUpdatesDirName += "/updates";
+    LOG(INFO) << "Removing: " << dataUpdatesDirName;
+    bool deleted = deleteDir(dataUpdatesDirName);
+    if (!deleted) {
+        LOG(WARNING) << "Deletion of install metadata " << dataUpdatesDirName
+                << " was not successful";
+    }
+}
+
+/*
+ * Deletes the timezone update bundle directory.
+ */
+static void deleteUpdateBundleDir(std::string& bundleDirName) {
+    LOG(INFO) << "Removing: " << bundleDirName;
+    bool deleted = deleteDir(bundleDirName);
+    if (!deleted) {
+        LOG(WARNING) << "Deletion of bundle dir " << bundleDirName << " was not successful";
+    }
+}
+
+/*
  * After a platform update it is likely that timezone data found on the system partition will be
  * newer than the version found in the data partition. This tool detects this case and removes the
- * version in /data along with any update metadata.
+ * version in /data.
  *
  * Note: This code is related to code in com.android.server.updates.TzDataInstallReceiver. The
  * paths for the metadata and current timezone data must match.
@@ -175,62 +272,103 @@
 int main(int argc, char* argv[]) {
     if (argc != 3) {
         usage();
+        return 1;
     }
 
     const char* systemZoneInfoDir = argv[1];
     const char* dataZoneInfoDir = argv[2];
 
+    // Check the bundle directory exists. If it does not, exit quickly: nothing to do.
     std::string dataCurrentDirName(dataZoneInfoDir);
     dataCurrentDirName += "/current";
-    std::string dataTzDataFileName(dataCurrentDirName);
-    dataTzDataFileName += TZDATA_FILENAME;
-
-    std::vector<char> dataTzDataHeader;
-    dataTzDataHeader.reserve(TZ_HEADER_LENGTH);
-
-    bool dataFileExists = readHeader(dataTzDataFileName, dataTzDataHeader.data(), TZ_HEADER_LENGTH);
-    if (!dataFileExists) {
-        LOG(INFO) << "tzdata file " << dataTzDataFileName << " does not exist. No action required.";
+    int dataCurrentDirStatus = checkPath(dataCurrentDirName);
+    if (dataCurrentDirStatus == NONE) {
+        LOG(INFO) << "timezone bundle dir " << dataCurrentDirName
+                << " does not exist. No action required.";
         return 0;
     }
-    checkValidHeader(dataTzDataFileName, dataTzDataHeader.data());
+    // If the bundle directory path is not a directory or we can't stat() the path, exit with a
+    // warning: either there's a problem accessing storage or the world is not as it should be;
+    // nothing to do.
+    if (dataCurrentDirStatus != IS_DIR) {
+        LOG(WARNING) << "Current bundle dir " << dataCurrentDirName
+                << " could not be accessed or is not a directory. result=" << dataCurrentDirStatus;
+        return 2;
+    }
 
+    // Check the installed bundle version.
+    std::string bundleVersionFileName(dataCurrentDirName);
+    bundleVersionFileName += BUNDLE_VERSION_FILENAME;
+    std::vector<char> bundleVersion;
+    bundleVersion.reserve(BUNDLE_VERSION_LENGTH);
+    bool bundleVersionReadOk =
+            readBytes(bundleVersionFileName, bundleVersion.data(), BUNDLE_VERSION_LENGTH);
+    if (!bundleVersionReadOk) {
+        LOG(WARNING) << "bundle version file " << bundleVersionFileName
+                << " does not exist or is too short. Deleting bundle dir.";
+        // Implies the contents of the data partition is corrupt in some way. Try to clean up.
+        deleteConfigUpdaterMetadataDir(dataZoneInfoDir);
+        deleteUpdateBundleDir(dataCurrentDirName);
+        return 3;
+    }
+
+    if (!checkValidBundleVersion(bundleVersion.data())) {
+        LOG(WARNING) << "bundle version file " << bundleVersionFileName
+                << " is not valid. Deleting bundle dir.";
+        // Implies the contents of the data partition is corrupt in some way. Try to clean up.
+        deleteConfigUpdaterMetadataDir(dataZoneInfoDir);
+        deleteUpdateBundleDir(dataCurrentDirName);
+        return 4;
+    }
+
+    // Check the first 3 bytes of the bundleVersionHeader: these are the major version (e.g. 001).
+    // It must match exactly to be ok. The minor version is currently ignored.
+    if (strncmp(&bundleVersion[0], REQUIRED_BUNDLE_VERSION, REQUIRED_BUNDLE_VERSION_LEN) != 0) {
+        LOG(INFO) << "bundle version file " << bundleVersionFileName
+                << " is not the required version " << REQUIRED_BUNDLE_VERSION
+                << ". Deleting bundle dir.";
+        // This shouldn't happen with 001, but it in future, this will imply there has been an OTA
+        // and the installed bundle is not compatible with the new version of Android. Remove the
+        // installed bundle.
+        deleteConfigUpdaterMetadataDir(dataZoneInfoDir);
+        deleteUpdateBundleDir(dataCurrentDirName);
+        return 5;
+    }
+
+    // Read the system rules version out of the /system tzdata file.
     std::string systemTzDataFileName(systemZoneInfoDir);
     systemTzDataFileName += TZDATA_FILENAME;
     std::vector<char> systemTzDataHeader;
     systemTzDataHeader.reserve(TZ_HEADER_LENGTH);
     bool systemFileExists =
-            readHeader(systemTzDataFileName, systemTzDataHeader.data(), TZ_HEADER_LENGTH);
+            readBytes(systemTzDataFileName, systemTzDataHeader.data(), TZ_HEADER_LENGTH);
     if (!systemFileExists) {
-        LOG(FATAL) << systemTzDataFileName << " does not exist or could not be opened";
+        // Implies the contents of the system partition is corrupt in some way. Nothing we can do.
+        LOG(WARNING) << systemTzDataFileName << " does not exist or could not be opened";
+        return 6;
     }
-    checkValidHeader(systemTzDataFileName, systemTzDataHeader.data());
-
-    if (strncmp(&systemTzDataHeader[0], &dataTzDataHeader[0], TZ_HEADER_LENGTH) < 0) {
-        LOG(INFO) << "tzdata file " << dataTzDataFileName << " is the newer than "
-                << systemTzDataFileName << ". No action required.";
-    } else {
-        // We have detected the case this tool is intended to prevent. Go fix it.
-        LOG(INFO) << "tzdata file " << dataTzDataFileName << " is the same as or older than "
-                << systemTzDataFileName << "; fixing...";
-
-        // Delete the update metadata
-        std::string dataUpdatesDirName(dataZoneInfoDir);
-        dataUpdatesDirName += "/updates";
-        LOG(INFO) << "Removing: " << dataUpdatesDirName;
-        bool deleted = deleteDir(dataUpdatesDirName);
-        if (!deleted) {
-            LOG(WARNING) << "Deletion of install metadata " << dataUpdatesDirName
-                    << " was not successful";
-        }
-
-        // Delete the TZ data
-        LOG(INFO) << "Removing: " << dataCurrentDirName;
-        deleted = deleteDir(dataCurrentDirName);
-        if (!deleted) {
-            LOG(WARNING) << "Deletion of tzdata " << dataCurrentDirName << " was not successful";
-        }
+    if (!checkValidTzDataHeader(systemTzDataFileName, systemTzDataHeader.data())) {
+        // Implies the contents of the system partition is corrupt in some way. Nothing we can do.
+        LOG(WARNING) << systemTzDataFileName << " does not have a valid header.";
+        return 7;
     }
 
+    // Compare the bundle rules version against the system rules version.
+    if (strncmp(
+            &systemTzDataHeader[TZ_DATA_HEADER_PREFIX_LEN],
+            &bundleVersion[BUNDLE_VERSION_RULES_IDX],
+            RULES_VERSION_LEN) <= 0) {
+        LOG(INFO) << "Found an installed bundle but it is valid. No action taken.";
+        // Implies there is an installed update, but it is good.
+        return 0;
+    }
+
+    // Implies there has been an OTA and the system version of the timezone rules is now newer
+    // than the version installed in /data. Remove the installed bundle.
+    LOG(INFO) << "timezone bundle in " << dataCurrentDirName << " is older than data in "
+            << systemTzDataFileName << "; fixing...";
+
+    deleteConfigUpdaterMetadataDir(dataZoneInfoDir);
+    deleteUpdateBundleDir(dataCurrentDirName);
     return 0;
 }