Merge "sdcard: Properly handle deleted nodes"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 7f9536e..b3661e4 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -55,3 +55,4 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/default.prop)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/lmkd_intermediates/import_includes)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libsysutils_intermediates/import_includes)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/grep $(PRODUCT_OUT)/system/bin/toolbox)
diff --git a/adb/.clang-format b/adb/.clang-format
new file mode 100644
index 0000000..0395c8e
--- /dev/null
+++ b/adb/.clang-format
@@ -0,0 +1,11 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
+PenaltyExcessCharacter: 32
diff --git a/adb/Android.mk b/adb/Android.mk
index 6d18d26..3733ae3 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -5,6 +5,8 @@
 
 LOCAL_PATH:= $(call my-dir)
 
+ADB_CLANG :=
+
 # libadb
 # =========================================================
 
@@ -15,117 +17,150 @@
 # small by moving common files into a static library. Hopefully some day we can
 # get enough of adb in here that we no longer need minadb. https://b/17626262
 LIBADB_SRC_FILES := \
-    adb.c \
-    adb_auth.c \
-    adb_listeners.c \
-    sockets.c \
-    transport.c \
-    transport_usb.c \
+    adb.cpp \
+    adb_auth.cpp \
+    adb_io.cpp \
+    adb_listeners.cpp \
+    sockets.cpp \
+    transport.cpp \
+    transport_local.cpp \
+    transport_usb.cpp \
 
-LIBADB_C_FLAGS := \
+LIBADB_CFLAGS := \
     -Wall -Werror \
-    -D_XOPEN_SOURCE -D_GNU_SOURCE \
+    -Wno-unused-parameter \
+    -Wno-missing-field-initializers \
     -fvisibility=hidden \
 
-LIBADB_LINUX_SRC_FILES := fdevent.cpp
-LIBADB_WINDOWS_SRC_FILES := sysdeps_win32.c
+LIBADB_darwin_SRC_FILES := \
+    fdevent.cpp \
+    get_my_path_darwin.c \
+    usb_osx.c \
+
+LIBADB_linux_SRC_FILES := \
+    fdevent.cpp \
+    get_my_path_linux.cpp \
+    usb_linux.cpp \
+
+LIBADB_windows_SRC_FILES := \
+    get_my_path_windows.cpp \
+    sysdeps_win32.c \
+    usb_windows.cpp \
 
 include $(CLEAR_VARS)
+LOCAL_CLANG := $(ADB_CLANG)
 LOCAL_MODULE := libadbd
 LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
 LOCAL_SRC_FILES := \
     $(LIBADB_SRC_FILES) \
-    $(LIBADB_LINUX_SRC_FILES) \
-    adb_auth_client.c \
-    jdwp_service.c \
-    qemu_tracing.c \
+    adb_auth_client.cpp \
+    fdevent.cpp \
+    jdwp_service.cpp \
+    qemu_tracing.cpp \
     usb_linux_client.c \
 
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
+LOCAL_CLANG := $(ADB_CLANG)
 LOCAL_MODULE := libadb
 LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=1
 LOCAL_SRC_FILES := \
     $(LIBADB_SRC_FILES) \
-    adb_auth_host.c \
+    $(LIBADB_$(HOST_OS)_SRC_FILES) \
+    adb_auth_host.cpp \
 
 # Even though we're building a static library (and thus there's no link step for
 # this to take effect), this adds the SSL includes to our path.
 LOCAL_STATIC_LIBRARIES := libcrypto_static
 
 ifeq ($(HOST_OS),windows)
-    LOCAL_SRC_FILES += $(LIBADB_WINDOWS_SRC_FILES)
-else
-    LOCAL_SRC_FILES += $(LIBADB_LINUX_SRC_FILES)
+    LOCAL_C_INCLUDES += development/host/windows/usb/api/
 endif
+
 include $(BUILD_HOST_STATIC_LIBRARY)
 
+LIBADB_TEST_SRCS := \
+    adb_io_test.cpp \
+    transport_test.cpp \
+
+include $(CLEAR_VARS)
+LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_MODULE := adbd_test
+LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS)
+LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS)
+LOCAL_STATIC_LIBRARIES := libadbd
+LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_MODULE := adb_test
+LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
+LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS) services.cpp
+LOCAL_SHARED_LIBRARIES := liblog libbase
+LOCAL_STATIC_LIBRARIES := \
+    libadb \
+    libcrypto_static \
+    libcutils \
+
+ifeq ($(HOST_OS),linux)
+  LOCAL_LDLIBS += -lrt -ldl -lpthread
+endif
+
+include $(BUILD_HOST_NATIVE_TEST)
+
 # adb host tool
 # =========================================================
 include $(CLEAR_VARS)
 
-# Default to a virtual (sockets) usb interface
-USB_SRCS :=
-EXTRA_SRCS :=
-
 ifeq ($(HOST_OS),linux)
-  USB_SRCS := usb_linux.c
-  EXTRA_SRCS := get_my_path_linux.c
   LOCAL_LDLIBS += -lrt -ldl -lpthread
   LOCAL_CFLAGS += -DWORKAROUND_BUG6558362
 endif
 
 ifeq ($(HOST_OS),darwin)
-  USB_SRCS := usb_osx.c
-  EXTRA_SRCS := get_my_path_darwin.c
   LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
   LOCAL_CFLAGS += -Wno-sizeof-pointer-memaccess -Wno-unused-parameter
 endif
 
 ifeq ($(HOST_OS),windows)
-  USB_SRCS := usb_windows.c
-  EXTRA_SRCS := get_my_path_windows.c
   EXTRA_STATIC_LIBS := AdbWinApi
   ifneq ($(strip $(USE_MINGW)),)
     # MinGW under Linux case
     LOCAL_LDLIBS += -lws2_32 -lgdi32
     USE_SYSDEPS_WIN32 := 1
   endif
-  LOCAL_C_INCLUDES += development/host/windows/usb/api/
 endif
 
+LOCAL_CLANG := $(ADB_CLANG)
+
 LOCAL_SRC_FILES := \
-	adb_main.c \
-	console.c \
-	transport_local.c \
-	commandline.c \
-	adb_client.c \
-	services.c \
-	file_sync_client.c \
-	$(EXTRA_SRCS) \
-	$(USB_SRCS) \
+    adb_main.cpp \
+    console.cpp \
+    commandline.cpp \
+    adb_client.cpp \
+    services.cpp \
+    file_sync_client.cpp \
 
-ifneq ($(USE_SYSDEPS_WIN32),)
-  LOCAL_SRC_FILES += sysdeps_win32.c
-endif
+LOCAL_CFLAGS += \
+    -Wall -Werror \
+    -Wno-unused-parameter \
+    -D_GNU_SOURCE \
+    -DADB_HOST=1 \
 
-LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter -Werror
-LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
 LOCAL_MODULE := adb
 LOCAL_MODULE_TAGS := debug
 
 LOCAL_STATIC_LIBRARIES := \
     libadb \
-    libzipfile \
     libcrypto_static \
     $(EXTRA_STATIC_LIBS) \
 
 ifeq ($(USE_SYSDEPS_WIN32),)
-	LOCAL_STATIC_LIBRARIES += libcutils
+    LOCAL_STATIC_LIBRARIES += libcutils
 endif
 
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_EXECUTABLE)
 
 $(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE))
@@ -142,29 +177,28 @@
 
 include $(CLEAR_VARS)
 
+LOCAL_CLANG := $(ADB_CLANG)
+
 LOCAL_SRC_FILES := \
-	adb_main.c \
-	transport_local.c \
-	services.c \
-	file_sync_service.c \
-	framebuffer_service.c \
-	remount_service.c \
-	set_verity_enable_state_service.c \
-	usb_linux_client.c
+    adb_main.cpp \
+    services.cpp \
+    file_sync_service.cpp \
+    framebuffer_service.cpp \
+    remount_service.cpp \
+    set_verity_enable_state_service.cpp \
 
 LOCAL_CFLAGS := \
-	-O2 \
-	-g \
-	-DADB_HOST=0 \
-	-D_XOPEN_SOURCE \
-	-D_GNU_SOURCE \
-	-Wall -Wno-unused-parameter -Werror -Wno-deprecated-declarations \
+    -DADB_HOST=0 \
+    -D_GNU_SOURCE \
+    -Wall -Werror \
+    -Wno-unused-parameter \
+    -Wno-deprecated-declarations \
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
 LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1
 endif
 
-ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT)))
+ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
 LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
 endif
 
@@ -173,10 +207,11 @@
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
-LOCAL_C_INCLUDES += system/extras/ext4_utils system/core/fs_mgr/include
+LOCAL_C_INCLUDES += system/extras/ext4_utils
 
 LOCAL_STATIC_LIBRARIES := \
     libadbd \
+    libbase \
     libfs_mgr \
     liblog \
     libcutils \
@@ -185,6 +220,4 @@
     libselinux \
     libext4_utils_static \
 
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
 include $(BUILD_EXECUTABLE)
diff --git a/adb/CPPLINT.cfg b/adb/CPPLINT.cfg
index b981cd4..9b906e8 100644
--- a/adb/CPPLINT.cfg
+++ b/adb/CPPLINT.cfg
@@ -1,2 +1,2 @@
 set noparent
-filter=-build/header_guard,-readability/function
+filter=-build/header_guard,-build/include,-readability/function
diff --git a/adb/adb.c b/adb/adb.cpp
similarity index 89%
rename from adb/adb.c
rename to adb/adb.cpp
index d1f05e4..ad85184f 100644
--- a/adb/adb.c
+++ b/adb/adb.cpp
@@ -14,23 +14,28 @@
  * limitations under the License.
  */
 
-#define  TRACE_TAG   TRACE_ADB
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <stddef.h>
-#include <string.h>
-#include <time.h>
-#include <sys/time.h>
-#include <stdint.h>
+#define TRACE_TAG TRACE_ADB
 
 #include "sysdeps.h"
 #include "adb.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <string>
+
 #include "adb_auth.h"
+#include "adb_io.h"
 #include "adb_listeners.h"
+#include "transport.h"
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
@@ -72,17 +77,68 @@
     exit(-1);
 }
 
-int   adb_trace_mask;
+#if !ADB_HOST
+void start_device_log(void) {
+    struct tm now;
+    time_t t;
+    tzset();
+    time(&t);
+    localtime_r(&t, &now);
 
-/* read a comma/space/colum/semi-column separated list of tags
- * from the ADB_TRACE environment variable and build the trace
- * mask from it. note that '1' and 'all' are special cases to
- * enable all tracing
- */
-void  adb_trace_init(void)
-{
-    const char*  p = getenv("ADB_TRACE");
-    const char*  q;
+    char timestamp[PATH_MAX];
+    strftime(timestamp, sizeof(timestamp), "%Y-%m-%d-%H-%M-%S", &now);
+
+    char path[PATH_MAX];
+    snprintf(path, sizeof(path), "/data/adb/adb-%s-%d", timestamp, getpid());
+
+    int fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0640);
+    if (fd == -1) {
+        return;
+    }
+
+    // redirect stdout and stderr to the log file
+    dup2(fd, STDOUT_FILENO);
+    dup2(fd, STDERR_FILENO);
+    fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid());
+    adb_close(fd);
+}
+#endif
+
+int adb_trace_mask;
+
+std::string get_trace_setting_from_env() {
+    const char* setting = getenv("ADB_TRACE");
+    if (setting == nullptr) {
+        setting = "";
+    }
+
+    return std::string(setting);
+}
+
+#if !ADB_HOST
+std::string get_trace_setting_from_prop() {
+    char buf[PROPERTY_VALUE_MAX];
+    property_get("persist.adb.trace_mask", buf, "");
+    return std::string(buf);
+}
+#endif
+
+std::string get_trace_setting() {
+#if ADB_HOST
+    return get_trace_setting_from_env();
+#else
+    return get_trace_setting_from_prop();
+#endif
+}
+
+// Split the comma/space/colum/semi-column separated list of tags from the trace
+// setting and build the trace mask from it. note that '1' and 'all' are special
+// cases to enable all tracing.
+//
+// adb's trace setting comes from the ADB_TRACE environment variable, whereas
+// adbd's comes from the system property persist.adb.trace_mask.
+void adb_trace_init() {
+    const std::string trace_setting = get_trace_setting();
 
     static const struct {
         const char*  tag;
@@ -104,25 +160,25 @@
         { NULL, 0 }
     };
 
-    if (p == NULL)
-            return;
+    if (trace_setting.empty()) {
+        return;
+    }
 
-    /* use a comma/column/semi-colum/space separated list */
+    // Use a comma/colon/semi-colon/space separated list
+    const char* p = trace_setting.c_str();
     while (*p) {
         int  len, tagn;
 
-        q = strpbrk(p, " ,:;");
+        const char* q = strpbrk(p, " ,:;");
         if (q == NULL) {
             q = p + strlen(p);
         }
         len = q - p;
 
-        for (tagn = 0; tags[tagn].tag != NULL; tagn++)
-        {
+        for (tagn = 0; tags[tagn].tag != NULL; tagn++) {
             int  taglen = strlen(tags[tagn].tag);
 
-            if (len == taglen && !memcmp(tags[tagn].tag, p, len) )
-            {
+            if (len == taglen && !memcmp(tags[tagn].tag, p, len)) {
                 int  flag = tags[tagn].flag;
                 if (flag == 0) {
                     adb_trace_mask = ~0;
@@ -136,12 +192,19 @@
         if (*p)
             p++;
     }
+
+#if !ADB_HOST
+    start_device_log();
+#endif
 }
 
-apacket *get_apacket(void)
+apacket* get_apacket(void)
 {
-    apacket *p = malloc(sizeof(apacket));
-    if(p == 0) fatal("failed to allocate an apacket");
+    apacket* p = reinterpret_cast<apacket*>(malloc(sizeof(apacket)));
+    if (p == nullptr) {
+      fatal("failed to allocate an apacket");
+    }
+
     memset(p, 0, sizeof(apacket) - MAX_PAYLOAD);
     return p;
 }
@@ -262,8 +325,8 @@
     if (msglen > 0xffff)
         msglen = 0xffff;
     snprintf(header, sizeof(header), "%04x", (unsigned)msglen);
-    writex(fd, header, 4);
-    writex(fd, msg, msglen);
+    WriteFdExactly(fd, header, 4);
+    WriteFdExactly(fd, msg, msglen);
 }
 #endif
 
@@ -273,8 +336,8 @@
     if (msglen > 0xffff)
         msglen = 0xffff;
     snprintf(header, sizeof(header), "OKAY%04x", (unsigned)msglen);
-    writex(fd, header, 8);
-    writex(fd, msg, msglen);
+    WriteFdExactly(fd, header, 8);
+    WriteFdExactly(fd, msg, msglen);
 }
 #endif // ADB_HOST
 
@@ -291,7 +354,7 @@
 }
 
 #if ADB_HOST
-static char *connection_state_name(atransport *t)
+static const char* connection_state_name(atransport *t)
 {
     if (t == NULL) {
         return "unknown";
@@ -711,8 +774,8 @@
         // Create the list of forward redirections.
         int buffer_size = format_listeners(NULL, 0);
         // Add one byte for the trailing zero.
-        char* buffer = malloc(buffer_size + 1);
-        if (buffer == NULL) {
+        char* buffer = reinterpret_cast<char*>(malloc(buffer_size + 1));
+        if (buffer == nullptr) {
             sendfailmsg(reply_fd, "not enough memory");
             return 1;
         }
@@ -738,7 +801,7 @@
 
     if (!strncmp(service, "forward:",8) ||
         !strncmp(service, "killforward:",12)) {
-        char *local, *remote, *err;
+        char *local, *remote;
         int r;
         atransport *transport;
 
@@ -775,6 +838,7 @@
             }
         }
 
+        const char* err;
         transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
         if (!transport) {
             sendfailmsg(reply_fd, err);
@@ -789,9 +853,9 @@
         if(r == 0) {
 #if ADB_HOST
             /* On the host: 1st OKAY is connect, 2nd OKAY is status */
-            writex(reply_fd, "OKAY", 4);
+            WriteFdExactly(reply_fd, "OKAY", 4);
 #endif
-            writex(reply_fd, "OKAY", 4);
+            WriteFdExactly(reply_fd, "OKAY", 4);
             return 1;
         }
 
@@ -833,7 +897,6 @@
     // "transport-local:" is used for switching transport to the only local transport
     // "transport-any:" is used for switching transport to the only transport
     if (!strncmp(service, "transport", strlen("transport"))) {
-        char* error_string = "unknown failure";
         transport_type type = kTransportAny;
 
         if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
@@ -847,6 +910,7 @@
             serial = service;
         }
 
+        const char* error_string = "unknown failure";
         transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
 
         if (transport) {
@@ -909,8 +973,8 @@
     }
 
     if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
-        char *out = "unknown";
-         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+        const char *out = "unknown";
+        transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
        if (transport && transport->serial) {
             out = transport->serial;
         }
@@ -918,8 +982,8 @@
         return 0;
     }
     if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
-        char *out = "unknown";
-         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+        const char *out = "unknown";
+        transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
        if (transport && transport->devpath) {
             out = transport->devpath;
         }
@@ -936,7 +1000,7 @@
 
     if(!strncmp(service,"get-state",strlen("get-state"))) {
         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
-        char *state = connection_state_name(transport);
+        const char *state = connection_state_name(transport);
         send_msg_with_okay(reply_fd, state, strlen(state));
         return 0;
     }
diff --git a/adb/adb.h b/adb/adb.h
index 4181fbc..749515c 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -18,10 +18,10 @@
 #define __ADB_H
 
 #include <limits.h>
+#include <sys/types.h>
 
 #include "adb_trace.h"
 #include "fdevent.h"
-#include "transport.h"  /* readx(), writex() */
 
 #ifdef __cplusplus
 extern "C" {
@@ -37,12 +37,15 @@
 #define A_WRTE 0x45545257
 #define A_AUTH 0x48545541
 
-#define A_VERSION 0x01000000        // ADB protocol version
+// ADB protocol version.
+#define A_VERSION 0x01000000
 
-#define ADB_VERSION_MAJOR 1         // Used for help/version information
-#define ADB_VERSION_MINOR 0         // Used for help/version information
+// Used for help/version information.
+#define ADB_VERSION_MAJOR 1
+#define ADB_VERSION_MINOR 0
 
-#define ADB_SERVER_VERSION    32    // Increment this when we want to force users to start a new adb server
+// Increment this when we want to force users to start a new adb server.
+#define ADB_SERVER_VERSION 32
 
 typedef struct amessage amessage;
 typedef struct apacket apacket;
@@ -236,8 +239,8 @@
     fdevent fde;
     int fd;
 
-    const char *local_name;
-    const char *connect_to;
+    char *local_name;
+    char *connect_to;
     atransport *transport;
     adisconnect  disconnect;
 };
@@ -263,33 +266,11 @@
 void fatal_errno(const char *fmt, ...);
 
 void handle_packet(apacket *p, atransport *t);
-void send_packet(apacket *p, atransport *t);
 
 void get_my_path(char *s, size_t maxLen);
 int launch_server(int server_port);
 int adb_main(int is_daemon, int server_port);
 
-
-/* transports are ref-counted
-** get_device_transport does an acquire on your behalf before returning
-*/
-void init_transport_registration(void);
-int  list_transports(char *buf, size_t  bufsize, int long_listing);
-void update_transports(void);
-
-asocket*  create_device_tracker(void);
-
-/* Obtain a transport from the available transports.
-** If state is != CS_ANY, only transports in that state are considered.
-** If serial is non-NULL then only the device with that serial will be chosen.
-** If no suitable transport is found, error is set.
-*/
-atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out);
-void   add_transport_disconnect( atransport*  t, adisconnect*  dis );
-void   remove_transport_disconnect( atransport*  t, adisconnect*  dis );
-void   run_transport_disconnects( atransport*  t );
-void   kick_transport( atransport*  t );
-
 /* initialize a transport object's func pointers and state */
 #if ADB_HOST
 int get_available_local_transport_index();
@@ -297,22 +278,6 @@
 int  init_socket_transport(atransport *t, int s, int port, int local);
 void init_usb_transport(atransport *t, usb_handle *usb, int state);
 
-/* for MacOS X cleanup */
-void close_usb_devices();
-
-/* cause new transports to be init'd and added to the list */
-int register_socket_transport(int s, const char *serial, int port, int local);
-
-/* these should only be used for the "adb disconnect" command */
-void unregister_transport(atransport *t);
-void unregister_all_tcp_transports();
-
-void register_usb_transport(usb_handle *h, const char *serial, const char *devpath, unsigned writeable);
-
-/* this should only be used for transports with connection_state == CS_NOPERM */
-void unregister_usb_transport(usb_handle *usb);
-
-atransport *find_transport(const char *serial);
 #if ADB_HOST
 atransport* find_emulator_transport_by_adb_port(int adb_port);
 #endif
@@ -333,9 +298,6 @@
 
 #if !ADB_HOST
 void framebuffer_service(int fd, void *cookie);
-// Allow enable-verity to write to system and vendor block devices
-int make_block_device_writable(const char* dev);
-void remount_service(int fd, void *cookie);
 void set_verity_enabled_state_service(int fd, void* cookie);
 #endif
 
@@ -343,9 +305,6 @@
 apacket *get_apacket(void);
 void put_apacket(apacket *p);
 
-int check_header(apacket *p);
-int check_data(apacket *p);
-
 // Define it if you want to dump packets.
 #define DEBUG_PACKETS 0
 
@@ -386,7 +345,7 @@
 int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
 #endif
 
-int adb_commandline(int argc, char **argv);
+int adb_commandline(int argc, const char **argv);
 
 int connection_state(atransport *t);
 
diff --git a/adb/adb_auth.c b/adb/adb_auth.cpp
similarity index 97%
rename from adb/adb_auth.c
rename to adb/adb_auth.cpp
index 11a89b0..dc01825 100644
--- a/adb/adb_auth.c
+++ b/adb/adb_auth.cpp
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
-#define  TRACE_TAG   TRACE_ADB
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
+#include "adb_auth.h"
 
 #include <errno.h>
 #include <stdio.h>
@@ -23,8 +26,7 @@
 #include <unistd.h>
 
 #include "adb.h"
-#include "adb_auth.h"
-#include "sysdeps.h"
+#include "transport.h"
 
 int auth_enabled = 0;
 
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index cece5e3..635556e 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -17,13 +17,14 @@
 #ifndef __ADB_AUTH_H
 #define __ADB_AUTH_H
 
+#include "adb.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 extern int auth_enabled;
 
-void adb_auth_init(void);
 int adb_auth_keygen(const char* filename);
 void adb_auth_verified(atransport *t);
 
@@ -40,7 +41,9 @@
 
 #if ADB_HOST
 
-int adb_auth_sign(void *key, void *token, size_t token_size, void *sig);
+void adb_auth_init(void);
+int adb_auth_sign(void *key, const unsigned char* token, size_t token_size,
+                  unsigned char* sig);
 void *adb_auth_nextkey(void *current);
 int adb_auth_get_userkey(unsigned char *data, size_t len);
 
@@ -50,12 +53,17 @@
 
 #else // !ADB_HOST
 
-static inline int adb_auth_sign(void* key, void *token, size_t token_size, void *sig) { return 0; }
+static inline int adb_auth_sign(void* key, const unsigned char* token,
+                                size_t token_size, unsigned char* sig) {
+    return 0;
+}
 static inline void *adb_auth_nextkey(void *current) { return NULL; }
 static inline int adb_auth_get_userkey(unsigned char *data, size_t len) { return 0; }
 
+void adbd_auth_init(void);
+void adbd_cloexec_auth_socket();
 int adb_auth_generate_token(void *token, size_t token_size);
-int adb_auth_verify(void *token, void *sig, int siglen);
+int adb_auth_verify(uint8_t* token, uint8_t* sig, int siglen);
 void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t);
 
 #endif // ADB_HOST
diff --git a/adb/adb_auth_client.c b/adb/adb_auth_client.cpp
similarity index 87%
rename from adb/adb_auth_client.c
rename to adb/adb_auth_client.cpp
index 55e9dca..8e7d38b 100644
--- a/adb/adb_auth_client.c
+++ b/adb/adb_auth_client.cpp
@@ -14,28 +14,30 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <string.h>
-#include <resolv.h>
-#include <cutils/list.h>
-#include <cutils/sockets.h>
+#define TRACE_TAG TRACE_AUTH
 
 #include "sysdeps.h"
-#include "adb.h"
 #include "adb_auth.h"
-#include "fdevent.h"
+
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "cutils/list.h"
+#include "cutils/sockets.h"
 #include "mincrypt/rsa.h"
 #include "mincrypt/sha.h"
 
-#define TRACE_TAG TRACE_AUTH
-
+#include "adb.h"
+#include "fdevent.h"
+#include "transport.h"
 
 struct adb_public_key {
     struct listnode node;
     RSAPublicKey key;
 };
 
-static char *key_paths[] = {
+static const char *key_paths[] = {
     "/adb_keys",
     "/data/misc/adb/adb_keys",
     NULL
@@ -51,7 +53,6 @@
 
 static void read_keys(const char *file, struct listnode *list)
 {
-    struct adb_public_key *key;
     FILE *f;
     char buf[MAX_PAYLOAD];
     char *sep;
@@ -65,8 +66,9 @@
 
     while (fgets(buf, sizeof(buf), f)) {
         /* Allocate 4 extra bytes to decode the base64 data in-place */
-        key = calloc(1, sizeof(*key) + 4);
-        if (!key) {
+        auto key = reinterpret_cast<adb_public_key*>(
+            calloc(1, sizeof(adb_public_key) + 4));
+        if (key == nullptr) {
             D("Can't malloc key\n");
             break;
         }
@@ -107,8 +109,8 @@
 
 static void load_keys(struct listnode *list)
 {
-    char *path;
-    char **paths = key_paths;
+    const char* path;
+    const char** paths = key_paths;
     struct stat buf;
 
     list_init(list);
@@ -136,10 +138,9 @@
     return ret * token_size;
 }
 
-int adb_auth_verify(void *token, void *sig, int siglen)
+int adb_auth_verify(uint8_t* token, uint8_t* sig, int siglen)
 {
     struct listnode *item;
-    struct adb_public_key *key;
     struct listnode key_list;
     int ret = 0;
 
@@ -149,7 +150,7 @@
     load_keys(&key_list);
 
     list_for_each(item, &key_list) {
-        key = node_to_item(item, struct adb_public_key, node);
+        adb_public_key* key = node_to_item(item, struct adb_public_key, node);
         ret = RSA_verify(&key->key, sig, siglen, token, SHA_DIGEST_SIZE);
         if (ret)
             break;
@@ -248,19 +249,23 @@
     }
 }
 
-void adb_auth_init(void)
-{
-    int fd, ret;
-
-    fd = android_get_control_socket("adbd");
-    if (fd < 0) {
+void adbd_cloexec_auth_socket() {
+    int fd = android_get_control_socket("adbd");
+    if (fd == -1) {
         D("Failed to get adbd socket\n");
         return;
     }
     fcntl(fd, F_SETFD, FD_CLOEXEC);
+}
 
-    ret = listen(fd, 4);
-    if (ret < 0) {
+void adbd_auth_init(void) {
+    int fd = android_get_control_socket("adbd");
+    if (fd == -1) {
+        D("Failed to get adbd socket\n");
+        return;
+    }
+
+    if (listen(fd, 4) == -1) {
         D("Failed to listen on '%d'\n", fd);
         return;
     }
diff --git a/adb/adb_auth_host.c b/adb/adb_auth_host.cpp
similarity index 91%
rename from adb/adb_auth_host.c
rename to adb/adb_auth_host.cpp
index 1d48667..7c2bcfb 100644
--- a/adb/adb_auth_host.c
+++ b/adb/adb_auth_host.cpp
@@ -14,8 +14,14 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_AUTH
+
+#include "sysdeps.h"
+#include "adb_auth.h"
+
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #ifdef _WIN32
 #  ifndef WIN32_LEAN_AND_MEAN
@@ -28,11 +34,8 @@
 #  include <sys/stat.h>
 #  include <unistd.h>
 #endif
-#include <string.h>
 
-#include "sysdeps.h"
 #include "adb.h"
-#include "adb_auth.h"
 
 /* HACK: we need the RSAPublicKey struct
  * but RSA_verify conflits with openssl */
@@ -52,12 +55,9 @@
 #include <openssl/base64.h>
 #endif
 
-#define TRACE_TAG TRACE_AUTH
-
 #define ANDROID_PATH   ".android"
 #define ADB_KEY_FILE   "adbkey"
 
-
 struct adb_private_key {
     struct listnode node;
     RSA *rsa;
@@ -157,7 +157,7 @@
     RSAPublicKey pkey;
     FILE *outfile = NULL;
     char path[PATH_MAX], info[MAX_PAYLOAD];
-    uint8_t *encoded = NULL;
+    uint8_t* encoded = nullptr;
     size_t encoded_length;
     int ret = 0;
 
@@ -191,8 +191,8 @@
     encoded_length = 1 + ((sizeof(pkey) + 2) / 3 * 4);
 #endif
 
-    encoded = malloc(encoded_length);
-    if (encoded == NULL) {
+    encoded = reinterpret_cast<uint8_t*>(malloc(encoded_length));
+    if (encoded == nullptr) {
         D("Allocation failure");
         goto out;
     }
@@ -272,18 +272,16 @@
 
 static int read_key(const char *file, struct listnode *list)
 {
-    struct adb_private_key *key;
-    FILE *f;
-
     D("read_key '%s'\n", file);
 
-    f = fopen(file, "r");
+    FILE* f = fopen(file, "r");
     if (!f) {
         D("Failed to open '%s'\n", file);
         return 0;
     }
 
-    key = malloc(sizeof(*key));
+    adb_private_key* key = reinterpret_cast<adb_private_key*>(
+        malloc(sizeof(adb_private_key)));
     if (!key) {
         D("Failed to alloc key\n");
         fclose(f);
@@ -390,7 +388,8 @@
     }
 }
 
-int adb_auth_sign(void *node, void *token, size_t token_size, void *sig)
+int adb_auth_sign(void *node, const unsigned char* token, size_t token_size,
+                  unsigned char* sig)
 {
     unsigned int len;
     struct adb_private_key *key = node_to_item(node, struct adb_private_key, node);
@@ -433,31 +432,33 @@
 int adb_auth_get_userkey(unsigned char *data, size_t len)
 {
     char path[PATH_MAX];
-    char *file;
-    int ret;
-
-    ret = get_user_keyfilepath(path, sizeof(path) - 4);
+    int ret = get_user_keyfilepath(path, sizeof(path) - 4);
     if (ret < 0 || ret >= (signed)(sizeof(path) - 4)) {
         D("Error getting user key filename");
         return 0;
     }
     strcat(path, ".pub");
 
-    file = load_file(path, (unsigned*)&ret);
-    if (!file) {
+    // TODO(danalbert): ReadFileToString
+    unsigned size;
+    char* file_data = reinterpret_cast<char*>(load_file(path, &size));
+    if (file_data == nullptr) {
         D("Can't load '%s'\n", path);
         return 0;
     }
 
-    if (len < (size_t)(ret + 1)) {
-        D("%s: Content too large ret=%d\n", path, ret);
+    if (len < (size_t)(size + 1)) {
+        D("%s: Content too large ret=%d\n", path, size);
+        free(file_data);
         return 0;
     }
 
-    memcpy(data, file, ret);
-    data[ret] = '\0';
+    memcpy(data, file_data, size);
+    free(file_data);
+    file_data = nullptr;
+    data[size] = '\0';
 
-    return ret + 1;
+    return size + 1;
 }
 
 int adb_auth_keygen(const char* filename) {
diff --git a/adb/adb_client.c b/adb/adb_client.cpp
similarity index 86%
rename from adb/adb_client.c
rename to adb/adb_client.cpp
index ac5e15a..4751bff 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.cpp
@@ -1,17 +1,34 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+/*
+ * 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.
+ */
+
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
+#include "adb_client.h"
+
 #include <errno.h>
 #include <limits.h>
 #include <stdarg.h>
-#include <zipfile/zipfile.h>
-#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 
-#include "sysdeps.h"
-
-#define  TRACE_TAG  TRACE_ADB
-#include "adb_client.h"
+#include "adb_io.h"
 
 static transport_type __adb_transport = kTransportAny;
 static const char* __adb_serial = NULL;
@@ -98,7 +115,7 @@
     if (__adb_serial)
         snprintf(service, sizeof service, "host:transport:%s", __adb_serial);
     else {
-        char* transport_type = "???";
+        const char* transport_type = "???";
 
          switch (__adb_transport) {
             case kTransportUsb:
@@ -121,7 +138,7 @@
     len = strlen(service);
     snprintf(tmp, sizeof tmp, "%04x", len);
 
-    if(writex(fd, tmp, 4) || writex(fd, service, len)) {
+    if(!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, service, len)) {
         strcpy(__adb_error, "write failure during connection");
         adb_close(fd);
         return -1;
@@ -142,7 +159,7 @@
     unsigned char buf[5];
     unsigned len;
 
-    if(readx(fd, buf, 4)) {
+    if(!ReadFdExactly(fd, buf, 4)) {
         strcpy(__adb_error, "protocol fault (no status)");
         return -1;
     }
@@ -158,14 +175,14 @@
         return -1;
     }
 
-    if(readx(fd, buf, 4)) {
+    if(!ReadFdExactly(fd, buf, 4)) {
         strcpy(__adb_error, "protocol fault (status len)");
         return -1;
     }
     buf[4] = 0;
     len = strtoul((char*)buf, 0, 16);
     if(len > 255) len = 255;
-    if(readx(fd, __adb_error, len)) {
+    if(!ReadFdExactly(fd, __adb_error, len)) {
         strcpy(__adb_error, "protocol fault (status read)");
         return -1;
     }
@@ -201,7 +218,7 @@
         return -1;
     }
 
-    if(writex(fd, tmp, 4) || writex(fd, service, len)) {
+    if(!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, service, len)) {
         strcpy(__adb_error, "write failure during connection");
         adb_close(fd);
         return -1;
@@ -246,12 +263,12 @@
 
         // if we have a file descriptor, then parse version result
         if(fd >= 0) {
-            if(readx(fd, buf, 4)) goto error;
+            if(!ReadFdExactly(fd, buf, 4)) goto error;
 
             buf[4] = 0;
             n = strtoul(buf, 0, 16);
             if(n > sizeof(buf)) goto error;
-            if(readx(fd, buf, n)) goto error;
+            if(!ReadFdExactly(fd, buf, n)) goto error;
             adb_close(fd);
 
             if (sscanf(buf, "%04x", &version) != 1) goto error;
@@ -311,8 +328,8 @@
 char *adb_query(const char *service)
 {
     char buf[5];
-    unsigned n;
-    char *tmp;
+    unsigned long n;
+    char* tmp;
 
     D("adb_query: %s\n", service);
     int fd = adb_connect(service);
@@ -321,7 +338,7 @@
         return 0;
     }
 
-    if(readx(fd, buf, 4)) goto oops;
+    if(!ReadFdExactly(fd, buf, 4)) goto oops;
 
     buf[4] = 0;
     n = strtoul(buf, 0, 16);
@@ -330,10 +347,10 @@
         goto oops;
     }
 
-    tmp = malloc(n + 1);
+    tmp = reinterpret_cast<char*>(malloc(n + 1));
     if(tmp == 0) goto oops;
 
-    if(readx(fd, tmp, n) == 0) {
+    if(!ReadFdExactly(fd, tmp, n) == 0) {
         tmp[n] = 0;
         adb_close(fd);
         return tmp;
diff --git a/adb/adb_client.h b/adb/adb_client.h
index 6ba3b38..9af176f 100644
--- a/adb/adb_client.h
+++ b/adb/adb_client.h
@@ -47,7 +47,7 @@
  * is zero, or more than one emulator connected (or if you use -s <serial>
  * with a <serial> that does not designate an emulator)
  */
-int  adb_send_emulator_command(int  argc, char**  argv);
+int  adb_send_emulator_command(int  argc, const char**  argv);
 
 /* return verbose error string from last operation */
 const char *adb_error(void);
diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp
new file mode 100644
index 0000000..d89f304
--- /dev/null
+++ b/adb/adb_io.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#define TRACE_TAG TRACE_RWX
+
+#include "sysdeps.h"
+#include "adb_io.h"
+
+#include <unistd.h>
+
+#include "adb_trace.h"
+#include "transport.h"
+
+bool ReadFdExactly(int fd, void* buf, size_t len) {
+    char* p = reinterpret_cast<char*>(buf);
+
+#if ADB_TRACE
+    size_t len0 = len;
+#endif
+
+    D("readx: fd=%d wanted=%zu\n", fd, len);
+    while (len > 0) {
+        int r = adb_read(fd, p, len);
+        if (r > 0) {
+            len -= r;
+            p += r;
+        } else if (r == -1) {
+            D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno));
+            return false;
+        } else {
+            D("readx: fd=%d disconnected\n", fd);
+            errno = 0;
+            return false;
+        }
+    }
+
+#if ADB_TRACE
+    D("readx: fd=%d wanted=%zu got=%zu\n", fd, len0, len0 - len);
+    if (ADB_TRACING) {
+        dump_hex(reinterpret_cast<const unsigned char*>(buf), len0);
+    }
+#endif
+
+    return true;
+}
+
+bool WriteFdExactly(int fd, const void* buf, size_t len) {
+    const char* p = reinterpret_cast<const char*>(buf);
+    int r;
+
+#if ADB_TRACE
+    D("writex: fd=%d len=%d: ", fd, (int)len);
+    if (ADB_TRACING) {
+        dump_hex(reinterpret_cast<const unsigned char*>(buf), len);
+    }
+#endif
+
+    while (len > 0) {
+        r = adb_write(fd, p, len);
+        if (r == -1) {
+            D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno));
+            if (errno == EAGAIN) {
+                adb_sleep_ms(1); // just yield some cpu time
+                continue;
+            } else if (errno == EPIPE) {
+                D("writex: fd=%d disconnected\n", fd);
+                errno = 0;
+                return false;
+            } else {
+                return false;
+            }
+        } else {
+            len -= r;
+            p += r;
+        }
+    }
+    return true;
+}
+
+bool WriteStringFully(int fd, const char* str) {
+    return WriteFdExactly(fd, str, strlen(str));
+}
diff --git a/adb/adb_io.h b/adb/adb_io.h
new file mode 100644
index 0000000..7d09e7b
--- /dev/null
+++ b/adb/adb_io.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef ADB_IO_H
+#define ADB_IO_H
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Reads exactly len bytes from fd into buf.
+ *
+ * Returns false if there is an error or if EOF was reached before len bytes
+ * were read. If EOF was found, errno will be set to 0.
+ *
+ * If this function fails, the contents of buf are undefined.
+ */
+bool ReadFdExactly(int fd, void *buf, size_t len);
+
+/*
+ * Writes exactly len bytes from buf to fd.
+ *
+ * Returns false if there is an error or if the fd was closed before the write
+ * completed. If the other end of the fd (such as in a socket, pipe, or fifo),
+ * is closed, errno will be set to 0.
+ */
+bool WriteFdExactly(int fd, const void *buf, size_t len);
+
+/* Same as WriteFdExactly, but with an implicit len = strlen(buf). */
+bool WriteStringFully(int fd, const char* str);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ADB_IO_H */
diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp
new file mode 100644
index 0000000..da340b2
--- /dev/null
+++ b/adb/adb_io_test.cpp
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+#include "adb_io.h"
+
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "base/file.h"
+
+class TemporaryFile {
+ public:
+  TemporaryFile() {
+    init("/data/local/tmp");
+    if (fd == -1) {
+      init("/tmp");
+    }
+  }
+
+  ~TemporaryFile() {
+    close(fd);
+    unlink(filename);
+  }
+
+  int fd;
+  char filename[1024];
+
+ private:
+  void init(const char* tmp_dir) {
+    snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir);
+    fd = mkstemp(filename);
+  }
+};
+
+TEST(io, ReadFdExactly_whole) {
+  const char expected[] = "Foobar";
+  TemporaryFile tf;
+  ASSERT_NE(-1, tf.fd);
+
+  ASSERT_TRUE(android::base::WriteStringToFd(expected, tf.fd)) << strerror(errno);
+  ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
+
+  // Test reading the whole file.
+  char buf[sizeof(expected)] = {};
+  ASSERT_TRUE(ReadFdExactly(tf.fd, buf, sizeof(buf) - 1)) << strerror(errno);
+  EXPECT_STREQ(expected, buf);
+}
+
+TEST(io, ReadFdExactly_eof) {
+  const char expected[] = "Foobar";
+  TemporaryFile tf;
+  ASSERT_NE(-1, tf.fd);
+
+  ASSERT_TRUE(android::base::WriteStringToFd(expected, tf.fd)) << strerror(errno);
+  ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
+
+  // Test that not having enough data will fail.
+  char buf[sizeof(expected) + 1] = {};
+  ASSERT_FALSE(ReadFdExactly(tf.fd, buf, sizeof(buf)));
+  EXPECT_EQ(0, errno) << strerror(errno);
+}
+
+TEST(io, ReadFdExactly_partial) {
+  const char input[] = "Foobar";
+  TemporaryFile tf;
+  ASSERT_NE(-1, tf.fd);
+
+  ASSERT_TRUE(android::base::WriteStringToFd(input, tf.fd)) << strerror(errno);
+  ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
+
+  // Test reading a partial file.
+  char buf[sizeof(input) - 1] = {};
+  ASSERT_TRUE(ReadFdExactly(tf.fd, buf, sizeof(buf) - 1));
+
+  std::string expected(input);
+  expected.pop_back();
+  EXPECT_STREQ(expected.c_str(), buf);
+}
+
+TEST(io, WriteFdExactly_whole) {
+  const char expected[] = "Foobar";
+  TemporaryFile tf;
+  ASSERT_NE(-1, tf.fd);
+
+  // Test writing the whole string to the file.
+  ASSERT_TRUE(WriteFdExactly(tf.fd, expected, sizeof(expected)))
+    << strerror(errno);
+  ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
+
+  std::string s;
+  ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s));
+  EXPECT_STREQ(expected, s.c_str());
+}
+
+TEST(io, WriteFdExactly_partial) {
+  const char buf[] = "Foobar";
+  TemporaryFile tf;
+  ASSERT_NE(-1, tf.fd);
+
+  // Test writing a partial string to the file.
+  ASSERT_TRUE(WriteFdExactly(tf.fd, buf, sizeof(buf) - 2)) << strerror(errno);
+  ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
+
+  std::string expected(buf);
+  expected.pop_back();
+
+  std::string s;
+  ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s));
+  EXPECT_EQ(expected, s);
+}
+
+TEST(io, WriteFdExactly_ENOSPC) {
+    int fd = open("/dev/full", O_WRONLY);
+    ASSERT_NE(-1, fd);
+
+    char buf[] = "foo";
+    ASSERT_FALSE(WriteFdExactly(fd, buf, sizeof(buf)));
+    ASSERT_EQ(ENOSPC, errno);
+}
+
+TEST(io, WriteStringFully) {
+  const char str[] = "Foobar";
+  TemporaryFile tf;
+  ASSERT_NE(-1, tf.fd);
+
+  // Test writing a partial string to the file.
+  ASSERT_TRUE(WriteStringFully(tf.fd, str)) << strerror(errno);
+  ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
+
+  std::string s;
+  ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s));
+  EXPECT_STREQ(str, s.c_str());
+}
diff --git a/adb/adb_listeners.c b/adb/adb_listeners.cpp
similarity index 75%
rename from adb/adb_listeners.c
rename to adb/adb_listeners.cpp
index 76a03eb..84b9c64 100644
--- a/adb/adb_listeners.c
+++ b/adb/adb_listeners.cpp
@@ -16,7 +16,11 @@
 
 #include "adb_listeners.h"
 
+#include <stdio.h>
+#include <stdlib.h>
+
 #include "sysdeps.h"
+#include "transport.h"
 
 int gListenAll = 0; /* Not static because it is used in commandline.c. */
 
@@ -50,24 +54,26 @@
     }
 }
 
-void listener_event_func(int _fd, unsigned ev, void *_l)
+void listener_event_func(int _fd, unsigned ev, void* _l)
 {
-    alistener *l = _l;
+    alistener* listener = reinterpret_cast<alistener*>(_l);
     asocket *s;
 
-    if(ev & FDE_READ) {
+    if (ev & FDE_READ) {
         struct sockaddr addr;
         socklen_t alen;
         int fd;
 
         alen = sizeof(addr);
         fd = adb_socket_accept(_fd, &addr, &alen);
-        if(fd < 0) return;
+        if (fd < 0) {
+            return;
+        }
 
         s = create_local_socket(fd);
-        if(s) {
-            s->transport = l->transport;
-            connect_to_remote(s, l->connect_to);
+        if (s) {
+            s->transport = listener->transport;
+            connect_to_remote(s, listener->connect_to);
             return;
         }
 
@@ -98,11 +104,9 @@
     free(l);
 }
 
-void listener_disconnect(void*  _l, atransport*  t)
+void listener_disconnect(void* listener, atransport*  t)
 {
-    alistener*  l = _l;
-
-    free_listener(l);
+    free_listener(reinterpret_cast<alistener*>(listener));
 }
 
 int local_name_to_fd(const char *name)
@@ -216,20 +220,16 @@
                                   atransport* transport,
                                   int no_rebind)
 {
-    alistener *l;
+    for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
+        if (strcmp(local_name, l->local_name) == 0) {
+            char* cto;
 
-    //printf("install_listener('%s','%s')\n", local_name, connect_to);
-
-    for(l = listener_list.next; l != &listener_list; l = l->next){
-        if(strcmp(local_name, l->local_name) == 0) {
-            char *cto;
-
-                /* can't repurpose a smartsocket */
+            /* can't repurpose a smartsocket */
             if(l->connect_to[0] == '*') {
                 return INSTALL_STATUS_INTERNAL_ERROR;
             }
 
-                /* can't repurpose a listener if 'no_rebind' is true */
+            /* can't repurpose a listener if 'no_rebind' is true */
             if (no_rebind) {
                 return INSTALL_STATUS_CANNOT_REBIND;
             }
@@ -239,7 +239,6 @@
                 return INSTALL_STATUS_INTERNAL_ERROR;
             }
 
-            //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
             free((void*) l->connect_to);
             l->connect_to = cto;
             if (l->transport != transport) {
@@ -251,38 +250,51 @@
         }
     }
 
-    if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
-    if((l->local_name = strdup(local_name)) == 0) goto nomem;
-    if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
+    alistener* listener = reinterpret_cast<alistener*>(
+        calloc(1, sizeof(alistener)));
+    if (listener == nullptr) {
+        goto nomem;
+    }
 
+    listener->local_name = strdup(local_name);
+    if (listener->local_name == nullptr) {
+        goto nomem;
+    }
 
-    l->fd = local_name_to_fd(local_name);
-    if(l->fd < 0) {
-        free((void*) l->local_name);
-        free((void*) l->connect_to);
-        free(l);
+    listener->connect_to = strdup(connect_to);
+    if (listener->connect_to == nullptr) {
+        goto nomem;
+    }
+
+    listener->fd = local_name_to_fd(local_name);
+    if (listener->fd < 0) {
+        free(listener->local_name);
+        free(listener->connect_to);
+        free(listener);
         printf("cannot bind '%s'\n", local_name);
-        return -2;
+        return INSTALL_STATUS_CANNOT_BIND;
     }
 
-    close_on_exec(l->fd);
-    if(!strcmp(l->connect_to, "*smartsocket*")) {
-        fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
+    close_on_exec(listener->fd);
+    if (!strcmp(listener->connect_to, "*smartsocket*")) {
+        fdevent_install(&listener->fde, listener->fd, ss_listener_event_func,
+                        listener);
     } else {
-        fdevent_install(&l->fde, l->fd, listener_event_func, l);
+        fdevent_install(&listener->fde, listener->fd, listener_event_func,
+                        listener);
     }
-    fdevent_set(&l->fde, FDE_READ);
+    fdevent_set(&listener->fde, FDE_READ);
 
-    l->next = &listener_list;
-    l->prev = listener_list.prev;
-    l->next->prev = l;
-    l->prev->next = l;
-    l->transport = transport;
+    listener->next = &listener_list;
+    listener->prev = listener_list.prev;
+    listener->next->prev = listener;
+    listener->prev->next = listener;
+    listener->transport = transport;
 
     if (transport) {
-        l->disconnect.opaque = l;
-        l->disconnect.func   = listener_disconnect;
-        add_transport_disconnect(transport, &l->disconnect);
+        listener->disconnect.opaque = listener;
+        listener->disconnect.func   = listener_disconnect;
+        add_transport_disconnect(transport, &listener->disconnect);
     }
     return INSTALL_STATUS_OK;
 
diff --git a/adb/adb_main.c b/adb/adb_main.cpp
similarity index 90%
rename from adb/adb_main.c
rename to adb/adb_main.cpp
index 02acae2..fb17e89 100644
--- a/adb/adb_main.c
+++ b/adb/adb_main.cpp
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-#define  TRACE_TAG   TRACE_ADB
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
 
 #include <errno.h>
 #include <signal.h>
@@ -24,7 +26,7 @@
 #include "adb.h"
 #include "adb_auth.h"
 #include "adb_listeners.h"
-#include "sysdeps.h"
+#include "transport.h"
 
 #if !ADB_HOST
 #include <getopt.h>
@@ -153,42 +155,6 @@
     return true; // "adb root" not allowed, always drop privileges.
 #endif /* ALLOW_ADBD_ROOT */
 }
-
-void start_device_log(void)
-{
-    int fd;
-    char    path[PATH_MAX];
-    struct tm now;
-    time_t t;
-    char value[PROPERTY_VALUE_MAX];
-
-    // read the trace mask from persistent property persist.adb.trace_mask
-    // give up if the property is not set or cannot be parsed
-    property_get("persist.adb.trace_mask", value, "");
-    if (sscanf(value, "%x", &adb_trace_mask) != 1)
-        return;
-
-    adb_mkdir("/data/adb", 0775);
-    tzset();
-    time(&t);
-    localtime_r(&t, &now);
-    strftime(path, sizeof(path),
-                "/data/adb/adb-%Y-%m-%d-%H-%M-%S.txt",
-                &now);
-    fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640);
-    if (fd < 0)
-        return;
-
-    // redirect stdout and stderr to the log file
-    dup2(fd, 1);
-    dup2(fd, 2);
-    fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
-    adb_close(fd);
-
-    fd = unix_open("/dev/null", O_RDONLY);
-    dup2(fd, 0);
-    adb_close(fd);
-}
 #endif /* ADB_HOST */
 
 /* Constructs a local name of form tcp:port.
@@ -278,10 +244,14 @@
         exit(1);
     }
 #else
+    // We need to call this even if auth isn't enabled because the file
+    // descriptor will always be open.
+    adbd_cloexec_auth_socket();
+
     property_get("ro.adb.secure", value, "0");
     auth_enabled = !strcmp(value, "1");
     if (auth_enabled)
-        adb_auth_init();
+        adbd_auth_init();
 
     // Our external storage path may be different than apps, since
     // we aren't able to bind mount after dropping root.
@@ -386,18 +356,34 @@
     return 0;
 }
 
-int main(int argc, char **argv)
-{
+#if !ADB_HOST
+void close_stdin() {
+    int fd = unix_open("/dev/null", O_RDONLY);
+    if (fd == -1) {
+        perror("failed to open /dev/null, stdin will remain open");
+        return;
+    }
+    dup2(fd, 0);
+    adb_close(fd);
+}
+#endif
+
+int main(int argc, char **argv) {
 #if ADB_HOST
     adb_sysdeps_init();
+#else
+    close_stdin();
+#endif
     adb_trace_init();
+
+#if ADB_HOST
     D("Handling commandline()\n");
-    return adb_commandline(argc - 1, argv + 1);
+    return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
 #else
     /* If adbd runs inside the emulator this will enable adb tracing via
      * adb-debug qemud service in the emulator. */
     adb_qemu_trace_init();
-    while(1) {
+    while (1) {
         int c;
         int option_index = 0;
         static struct option opts[] = {
@@ -419,7 +405,6 @@
         }
     }
 
-    start_device_log();
     D("Handling main()\n");
     return adb_main(0, DEFAULT_ADB_PORT);
 #endif
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index 69b6c69..ef5dc24 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -19,6 +19,8 @@
 
 #if !ADB_HOST
 #include <android/log.h>
+#else
+#include <stdio.h>
 #endif
 
 #ifdef __cplusplus
diff --git a/adb/commandline.c b/adb/commandline.cpp
similarity index 91%
rename from adb/commandline.c
rename to adb/commandline.cpp
index 830f290..f9ca5ed 100644
--- a/adb/commandline.c
+++ b/adb/commandline.cpp
@@ -14,56 +14,58 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <ctype.h>
-#include <assert.h>
+#define TRACE_TAG TRACE_ADB
 
 #include "sysdeps.h"
 
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
 #if !defined(_WIN32)
 #include <termios.h>
+#include <unistd.h>
 #endif
 
-#define  TRACE_TAG  TRACE_ADB
 #include "adb.h"
-#include "adb_client.h"
 #include "adb_auth.h"
+#include "adb_client.h"
+#include "adb_io.h"
 #include "file_sync_service.h"
 
-static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
+static int do_cmd(transport_type ttype, const char* serial, const char *cmd, ...);
 
-void get_my_path(char *s, size_t maxLen);
 int find_sync_dirs(const char *srcarg,
-        char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out);
-int install_app(transport_type transport, char* serial, int argc, char** argv);
-int install_multiple_app(transport_type transport, char* serial, int argc, char** argv);
-int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
+        char **system_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out,
+        char **oem_srcdir_out);
+int install_app(transport_type transport, const char* serial, int argc,
+                const char** argv);
+int install_multiple_app(transport_type transport, const char* serial, int argc,
+                         const char** argv);
+int uninstall_app(transport_type transport, const char* serial, int argc,
+                  const char** argv);
 
 static const char *gProductOutPath = NULL;
 extern int gListenAll;
 
 static char *product_file(const char *extra)
 {
-    int n;
-    char *x;
-
     if (gProductOutPath == NULL) {
         fprintf(stderr, "adb: Product directory not specified; "
                 "use -p or define ANDROID_PRODUCT_OUT\n");
         exit(1);
     }
 
-    n = strlen(gProductOutPath) + strlen(extra) + 2;
-    x = malloc(n);
+    int n = strlen(gProductOutPath) + strlen(extra) + 2;
+    char* x = reinterpret_cast<char*>(malloc(n));
     if (x == 0) {
         fprintf(stderr, "adb: Out of memory (product_file())\n");
         exit(1);
@@ -206,8 +208,12 @@
         "  adb get-serialno             - prints: <serial-number>\n"
         "  adb get-devpath              - prints: <device-path>\n"
         "  adb status-window            - continuously print device status for a specified device\n"
-        "  adb remount                  - remounts the /system and /vendor (if present) partitions on the device read-write\n"
-        "  adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
+        "  adb remount                  - remounts the /system, /vendor (if present) and /oem (if present) partitions on the device read-write\n"
+        "  adb reboot [bootloader|recovery]\n"
+        "                               - reboots the device, optionally into the bootloader or recovery program.\n"
+        "  adb reboot sideload          - reboots the device into the sideload mode in recovery program (adb root required).\n"
+        "  adb reboot sideload-auto-reboot\n"
+        "                               - reboots into the sideload mode, then reboots automatically after the sideload regardless of the result.\n"
         "  adb reboot-bootloader        - reboots the device into the bootloader\n"
         "  adb root                     - restarts the adbd daemon with root permissions\n"
         "  adb unroot                   - restarts the adbd daemon without root permissions\n"
@@ -222,9 +228,9 @@
         "adb sync notes: adb sync [ <directory> ]\n"
         "  <localdir> can be interpreted in several ways:\n"
         "\n"
-        "  - If <directory> is not specified, /system, /vendor (if present), and /data partitions will be updated.\n"
+        "  - If <directory> is not specified, /system, /vendor (if present), /oem (if present) and /data partitions will be updated.\n"
         "\n"
-        "  - If it is \"system\", \"vendor\" or \"data\", only the corresponding partition\n"
+        "  - If it is \"system\", \"vendor\", \"oem\" or \"data\", only the corresponding partition\n"
         "    is updated.\n"
         "\n"
         "environmental variables:\n"
@@ -243,13 +249,10 @@
 
 #if defined(_WIN32)
 
-// Windows does not have <termio.h>.
-static void stdin_raw_init(int fd) {
-
-}
-
-static void stdin_raw_restore(int fd) {
-
+// Implemented in sysdeps_win32.c.
+extern "C" {
+void stdin_raw_init(int fd);
+void stdin_raw_restore(int fd);
 }
 
 #else
@@ -421,7 +424,6 @@
 {
     adb_thread_t thr;
     int fdi, fd;
-    int *fds;
 
     fd = adb_connect("shell:");
     if(fd < 0) {
@@ -430,7 +432,7 @@
     }
     fdi = 0; //dup(0);
 
-    fds = malloc(sizeof(int) * 2);
+    int* fds = reinterpret_cast<int*>(malloc(sizeof(int) * 2));
     fds[0] = fd;
     fds[1] = fdi;
 
@@ -463,7 +465,6 @@
     char buf[4096];
     unsigned total;
     int fd;
-    const unsigned char *ptr;
 
     sprintf(buf,"%s:%d", service, sz);
     fd = adb_connect(buf);
@@ -476,7 +477,7 @@
     opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
 
     total = sz;
-    ptr = data;
+    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data);
 
     if(progress) {
         char *x = strrchr(service, ':');
@@ -485,7 +486,7 @@
 
     while(sz > 0) {
         unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz;
-        if(writex(fd, ptr, xfer)) {
+        if(!WriteFdExactly(fd, ptr, xfer)) {
             adb_status(fd);
             fprintf(stderr,"* failed to write data '%s' *\n", adb_error());
             return -1;
@@ -501,7 +502,7 @@
         printf("\n");
     }
 
-    if(readx(fd, buf, 4)){
+    if(!ReadFdExactly(fd, buf, 4)){
         fprintf(stderr,"* error reading response *\n");
         adb_close(fd);
         return -1;
@@ -556,14 +557,15 @@
  *   we hang up.
  */
 int adb_sideload_host(const char* fn) {
-    uint8_t* data;
     unsigned sz;
     size_t xfer = 0;
     int status;
+    int last_percent = -1;
+    int opt = SIDELOAD_HOST_BLOCK_SIZE;
 
     printf("loading: '%s'", fn);
     fflush(stdout);
-    data = load_file(fn, &sz);
+    uint8_t* data = reinterpret_cast<uint8_t*>(load_file(fn, &sz));
     if (data == 0) {
         printf("\n");
         fprintf(stderr, "* cannot read '%s' *\n", fn);
@@ -581,12 +583,10 @@
         goto done;
     }
 
-    int opt = SIDELOAD_HOST_BLOCK_SIZE;
     opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
 
-    int last_percent = -1;
     for (;;) {
-        if (readx(fd, buf, 8)) {
+        if (!ReadFdExactly(fd, buf, 8)) {
             fprintf(stderr, "* failed to read command: %s\n", adb_error());
             status = -1;
             goto done;
@@ -613,7 +613,7 @@
             to_write = sz - offset;
         }
 
-        if(writex(fd, start, to_write)) {
+        if(!WriteFdExactly(fd, start, to_write)) {
             adb_status(fd);
             fprintf(stderr,"* failed to write data '%s' *\n", adb_error());
             status = -1;
@@ -738,13 +738,12 @@
  * ppp dev:/dev/omap_csmi_tty0 <ppp options>
  *
  */
-int ppp(int argc, char **argv)
+int ppp(int argc, const char **argv)
 {
 #if defined(_WIN32)
     fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
     return -1;
 #else
-    char *adb_service_name;
     pid_t pid;
     int fd;
 
@@ -755,8 +754,7 @@
         return 1;
     }
 
-    adb_service_name = argv[1];
-
+    const char* adb_service_name = argv[1];
     fd = adb_connect(adb_service_name);
 
     if(fd < 0) {
@@ -806,7 +804,8 @@
 #endif /* !defined(_WIN32) */
 }
 
-static int send_shellcommand(transport_type transport, char* serial, char* buf)
+static int send_shellcommand(transport_type transport, const char* serial,
+                             char* buf)
 {
     int fd, ret;
 
@@ -827,7 +826,8 @@
     return ret;
 }
 
-static int logcat(transport_type transport, char* serial, int argc, char **argv)
+static int logcat(transport_type transport, const char* serial, int argc,
+                  const char** argv)
 {
     char buf[4096];
 
@@ -876,7 +876,7 @@
     return 0;
 }
 
-static int backup(int argc, char** argv) {
+static int backup(int argc, const char** argv) {
     char buf[4096];
     char default_name[32];
     const char* filename = strcpy(default_name, "./backup.ab");
@@ -932,7 +932,7 @@
     return 0;
 }
 
-static int restore(int argc, char** argv) {
+static int restore(int argc, const char** argv) {
     const char* filename;
     int fd, tarFd;
 
@@ -1101,8 +1101,9 @@
     return path_buf;
 }
 
-static void parse_push_pull_args(char **arg, int narg, char const **path1, char const **path2,
-                                 int *show_progress, int *copy_attrs) {
+static void parse_push_pull_args(const char **arg, int narg, char const **path1,
+                                 char const **path2, int *show_progress,
+                                 int *copy_attrs) {
     *show_progress = 0;
     *copy_attrs = 0;
 
@@ -1129,7 +1130,18 @@
     }
 }
 
-int adb_commandline(int argc, char **argv)
+static int adb_connect_command(const char* command) {
+    int fd = adb_connect(command);
+    if (fd != -1) {
+        read_and_dump(fd);
+        adb_close(fd);
+        return 0;
+    }
+    fprintf(stderr, "Error: %s\n", adb_error());
+    return 1;
+}
+
+int adb_commandline(int argc, const char **argv)
 {
     char buf[4096];
     int no_daemon = 0;
@@ -1138,8 +1150,8 @@
     int persist = 0;
     int r;
     transport_type ttype = kTransportAny;
-    char* serial = NULL;
-    char* server_port_str = NULL;
+    const char* serial = NULL;
+    const char* server_port_str = NULL;
 
         /* If defined, this should be an absolute path to
          * the directory containing all of the various system images
@@ -1273,7 +1285,7 @@
 
     /* handle wait-for-* prefix */
     if (!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
-        char* service = argv[0];
+        const char* service = argv[0];
         if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
             if (ttype == kTransportUsb) {
                 service = "wait-for-usb";
@@ -1307,7 +1319,7 @@
     /* adb_connect() commands */
     if (!strcmp(argv[0], "devices")) {
         char *tmp;
-        char *listopt;
+        const char *listopt;
         if (argc < 2)
             listopt = "";
         else if (argc == 2 && !strcmp(argv[1], "-l"))
@@ -1478,20 +1490,14 @@
              !strcmp(argv[0], "disable-verity") ||
              !strcmp(argv[0], "enable-verity")) {
         char command[100];
-        if (!strcmp(argv[0], "reboot-bootloader"))
+        if (!strcmp(argv[0], "reboot-bootloader")) {
             snprintf(command, sizeof(command), "reboot:bootloader");
-        else if (argc > 1)
+        } else if (argc > 1) {
             snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
-        else
+        } else {
             snprintf(command, sizeof(command), "%s:", argv[0]);
-        int fd = adb_connect(command);
-        if (fd >= 0) {
-            read_and_dump(fd);
-            adb_close(fd);
-            return 0;
         }
-        fprintf(stderr,"error: %s\n", adb_error());
-        return 1;
+        return adb_connect_command(command);
     }
     else if (!strcmp(argv[0], "bugreport")) {
         if (argc != 1) return usage();
@@ -1634,7 +1640,9 @@
         return uninstall_app(ttype, serial, argc, argv);
     }
     else if (!strcmp(argv[0], "sync")) {
-        char *srcarg, *android_srcpath, *data_srcpath, *vendor_srcpath;
+        const char* srcarg;
+        char *system_srcpath, *data_srcpath, *vendor_srcpath, *oem_srcpath;
+
         int listonly = 0;
 
         int ret;
@@ -1654,18 +1662,22 @@
         } else {
             return usage();
         }
-        ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath, &vendor_srcpath);
+        ret = find_sync_dirs(srcarg, &system_srcpath, &data_srcpath, &vendor_srcpath,
+                &oem_srcpath);
         if (ret != 0) return usage();
 
-        if (android_srcpath != NULL)
-            ret = do_sync_sync(android_srcpath, "/system", listonly);
+        if (system_srcpath != NULL)
+            ret = do_sync_sync(system_srcpath, "/system", listonly);
         if (ret == 0 && vendor_srcpath != NULL)
             ret = do_sync_sync(vendor_srcpath, "/vendor", listonly);
+        if(ret == 0 && oem_srcpath != NULL)
+            ret = do_sync_sync(oem_srcpath, "/oem", listonly);
         if (ret == 0 && data_srcpath != NULL)
             ret = do_sync_sync(data_srcpath, "/data", listonly);
 
-        free(android_srcpath);
+        free(system_srcpath);
         free(vendor_srcpath);
+        free(oem_srcpath);
         free(data_srcpath);
         return ret;
     }
@@ -1710,15 +1722,7 @@
         return adb_auth_keygen(argv[1]);
     }
     else if (!strcmp(argv[0], "jdwp")) {
-        int  fd = adb_connect("jdwp");
-        if (fd >= 0) {
-            read_and_dump(fd);
-            adb_close(fd);
-            return 0;
-        } else {
-            fprintf(stderr, "error: %s\n", adb_error());
-            return -1;
-        }
+        return adb_connect_command("jdwp");
     }
     /* "adb /?" is a common idiom under Windows */
     else if (!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
@@ -1735,9 +1739,9 @@
 }
 
 #define MAX_ARGV_LENGTH 16
-static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
+static int do_cmd(transport_type ttype, const char* serial, const char *cmd, ...)
 {
-    char *argv[MAX_ARGV_LENGTH];
+    const char *argv[MAX_ARGV_LENGTH];
     int argc;
     va_list ap;
 
@@ -1771,54 +1775,65 @@
 }
 
 int find_sync_dirs(const char *srcarg,
-        char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out)
+        char **system_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out,
+        char **oem_srcdir_out)
 {
-    char *android_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL;
+    char *system_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL, *oem_srcdir = NULL;
     struct stat st;
 
     if(srcarg == NULL) {
-        android_srcdir = product_file("system");
+        system_srcdir = product_file("system");
         data_srcdir = product_file("data");
         vendor_srcdir = product_file("vendor");
-        /* Check if vendor partition exists */
+        oem_srcdir = product_file("oem");
+        // Check if vendor partition exists.
         if (lstat(vendor_srcdir, &st) || !S_ISDIR(st.st_mode))
             vendor_srcdir = NULL;
+        // Check if oem partition exists.
+        if (lstat(oem_srcdir, &st) || !S_ISDIR(st.st_mode))
+            oem_srcdir = NULL;
     } else {
-        /* srcarg may be "data", "system" or NULL.
-         * if srcarg is NULL, then both data and system are synced
-         */
+        // srcarg may be "data", "system", "vendor", "oem" or NULL.
+        // If srcarg is NULL, then all partitions are synced.
         if(strcmp(srcarg, "system") == 0) {
-            android_srcdir = product_file("system");
+            system_srcdir = product_file("system");
         } else if(strcmp(srcarg, "data") == 0) {
             data_srcdir = product_file("data");
         } else if(strcmp(srcarg, "vendor") == 0) {
             vendor_srcdir = product_file("vendor");
+        } else if(strcmp(srcarg, "oem") == 0) {
+            oem_srcdir = product_file("oem");
         } else {
-            /* It's not "system", "vendor", or "data".
-             */
+            // It's not "system", "data", "vendor", or "oem".
             return 1;
         }
     }
 
-    if(android_srcdir_out != NULL)
-        *android_srcdir_out = android_srcdir;
+    if(system_srcdir_out != NULL)
+        *system_srcdir_out = system_srcdir;
     else
-        free(android_srcdir);
+        free(system_srcdir);
 
     if(vendor_srcdir_out != NULL)
         *vendor_srcdir_out = vendor_srcdir;
     else
         free(vendor_srcdir);
 
+    if(oem_srcdir_out != NULL)
+        *oem_srcdir_out = oem_srcdir;
+    else
+        free(oem_srcdir);
+
     if(data_srcdir_out != NULL)
-            *data_srcdir_out = data_srcdir;
-        else
-            free(data_srcdir);
+        *data_srcdir_out = data_srcdir;
+    else
+        free(data_srcdir);
+
     return 0;
 }
 
-static int pm_command(transport_type transport, char* serial,
-                      int argc, char** argv)
+static int pm_command(transport_type transport, const char* serial,
+                      int argc, const char** argv)
 {
     char buf[4096];
 
@@ -1835,7 +1850,8 @@
     return 0;
 }
 
-int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
+int uninstall_app(transport_type transport, const char* serial, int argc,
+                  const char** argv)
 {
     /* if the user choose the -k option, we refuse to do it until devices are
        out with the option to uninstall the remaining data somehow (adb/ui) */
@@ -1853,7 +1869,7 @@
     return pm_command(transport, serial, argc, argv);
 }
 
-static int delete_file(transport_type transport, char* serial, char* filename)
+static int delete_file(transport_type transport, const char* serial, char* filename)
 {
     char buf[4096];
     char* quoted;
@@ -1878,7 +1894,8 @@
     }
 }
 
-int install_app(transport_type transport, char* serial, int argc, char** argv)
+int install_app(transport_type transport, const char* serial, int argc,
+                const char** argv)
 {
     static const char *const DATA_DEST = "/data/local/tmp/%s";
     static const char *const SD_DEST = "/sdcard/tmp/%s";
@@ -1896,7 +1913,7 @@
     // All other arguments passed through verbatim.
     int last_apk = -1;
     for (i = argc - 1; i >= 0; i--) {
-        char* file = argv[i];
+        const char* file = argv[i];
         char* dot = strrchr(file, '.');
         if (dot && !strcasecmp(dot, ".apk")) {
             if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
@@ -1914,7 +1931,7 @@
         return -1;
     }
 
-    char* apk_file = argv[last_apk];
+    const char* apk_file = argv[last_apk];
     char apk_dest[PATH_MAX];
     snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
     int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */);
@@ -1931,7 +1948,8 @@
     return err;
 }
 
-int install_multiple_app(transport_type transport, char* serial, int argc, char** argv)
+int install_multiple_app(transport_type transport, const char* serial, int argc,
+                         const char** argv)
 {
     char buf[1024];
     int i;
@@ -1942,7 +1960,7 @@
     // All other arguments passed through verbatim.
     int first_apk = -1;
     for (i = argc - 1; i >= 0; i--) {
-        char* file = argv[i];
+        const char* file = argv[i];
         char* dot = strrchr(file, '.');
         if (dot && !strcasecmp(dot, ".apk")) {
             if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
@@ -1997,7 +2015,7 @@
     // Valid session, now stream the APKs
     int success = 1;
     for (i = first_apk; i < argc; i++) {
-        char* file = argv[i];
+        const char* file = argv[i];
         if (stat(file, &sb) == -1) {
             fprintf(stderr, "Failed to stat %s\n", file);
             success = 0;
diff --git a/adb/console.c b/adb/console.cpp
similarity index 93%
rename from adb/console.c
rename to adb/console.cpp
index b813d33..452ee41 100644
--- a/adb/console.c
+++ b/adb/console.cpp
@@ -24,7 +24,7 @@
 }
 
 
-int  adb_send_emulator_command(int  argc, char**  argv)
+int  adb_send_emulator_command(int  argc, const char**  argv)
 {
     int   fd, nn;
 
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index bd0f3b2..0c43c5e 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -15,25 +15,23 @@
 ** limitations under the License.
 */
 
-#include <sys/ioctl.h>
+#define TRACE_TAG TRACE_FDEVENT
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
+#include "sysdeps.h"
+#include "fdevent.h"
+
 #include <errno.h>
-
 #include <fcntl.h>
-
 #include <stdarg.h>
 #include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
 
+#include "adb_io.h"
 #include "adb_trace.h"
-#include "fdevent.h"
-#include "transport.h"
-#include "sysdeps.h"
-
-#define TRACE_TAG  TRACE_FDEVENT
 
 /* !!! Do not enable DEBUG for the adb that will run as the server:
 ** both stdout and stderr are used to communicate between the client
@@ -528,7 +526,7 @@
     if(ev & FDE_READ){
       int subproc_fd;
 
-      if(readx(fd, &subproc_fd, sizeof(subproc_fd))) {
+      if(!ReadFdExactly(fd, &subproc_fd, sizeof(subproc_fd))) {
           FATAL("Failed to read the subproc's fd from fd=%d\n", fd);
       }
       if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) {
@@ -587,6 +585,7 @@
         FATAL("fde %p not created by fdevent_create()\n", fde);
     }
     fdevent_remove(fde);
+    free(fde);
 }
 
 void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.cpp
similarity index 90%
rename from adb/file_sync_client.c
rename to adb/file_sync_client.cpp
index f93c876..4ba730b 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.cpp
@@ -14,25 +14,25 @@
  * limitations under the License.
  */
 
+#include <dirent.h>
+#include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <errno.h>
 #include <sys/stat.h>
 #include <sys/time.h>
-#include <time.h>
-#include <dirent.h>
-#include <limits.h>
 #include <sys/types.h>
-#include <zipfile/zipfile.h>
+#include <time.h>
 #include <utime.h>
 
 #include "sysdeps.h"
+
 #include "adb.h"
 #include "adb_client.h"
+#include "adb_io.h"
 #include "file_sync_service.h"
 
-
 static unsigned long long total_bytes;
 static long long start_time;
 
@@ -86,7 +86,7 @@
     msg.req.id = ID_QUIT;
     msg.req.namelen = 0;
 
-    writex(fd, &msg.req, sizeof(msg.req));
+    WriteFdExactly(fd, &msg.req, sizeof(msg.req));
 }
 
 typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
@@ -103,20 +103,20 @@
     msg.req.id = ID_LIST;
     msg.req.namelen = htoll(len);
 
-    if(writex(fd, &msg.req, sizeof(msg.req)) ||
-       writex(fd, path, len)) {
+    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
+       !WriteFdExactly(fd, path, len)) {
         goto fail;
     }
 
     for(;;) {
-        if(readx(fd, &msg.dent, sizeof(msg.dent))) break;
+        if(!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break;
         if(msg.dent.id == ID_DONE) return 0;
         if(msg.dent.id != ID_DENT) break;
 
         len = ltohl(msg.dent.namelen);
         if(len > 256) break;
 
-        if(readx(fd, buf, len)) break;
+        if(!ReadFdExactly(fd, buf, len)) break;
         buf[len] = 0;
 
         func(ltohl(msg.dent.mode),
@@ -149,12 +149,12 @@
     msg.req.id = ID_STAT;
     msg.req.namelen = htoll(len);
 
-    if(writex(fd, &msg.req, sizeof(msg.req)) ||
-       writex(fd, path, len)) {
+    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
+       !WriteFdExactly(fd, path, len)) {
         return -1;
     }
 
-    if(readx(fd, &msg.stat, sizeof(msg.stat))) {
+    if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
         return -1;
     }
 
@@ -175,8 +175,8 @@
     msg.req.id = ID_STAT;
     msg.req.namelen = htoll(len);
 
-    if(writex(fd, &msg.req, sizeof(msg.req)) ||
-       writex(fd, path, len)) {
+    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
+       !WriteFdExactly(fd, path, len)) {
         return -1;
     }
 
@@ -188,7 +188,7 @@
 {
     syncmsg msg;
 
-    if(readx(fd, &msg.stat, sizeof(msg.stat)))
+    if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat)))
         return -1;
 
     if(msg.stat.id != ID_STAT)
@@ -209,12 +209,12 @@
     msg.req.id = ID_STAT;
     msg.req.namelen = htoll(len);
 
-    if(writex(fd, &msg.req, sizeof(msg.req)) ||
-       writex(fd, path, len)) {
+    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
+       !WriteFdExactly(fd, path, len)) {
         return -1;
     }
 
-    if(readx(fd, &msg.stat, sizeof(msg.stat))) {
+    if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
         return -1;
     }
 
@@ -264,7 +264,7 @@
         }
 
         sbuf->size = htoll(ret);
-        if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){
+        if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + ret)){
             err = -1;
             break;
         }
@@ -294,7 +294,7 @@
 
         memcpy(sbuf->data, &file_buffer[total], count);
         sbuf->size = htoll(count);
-        if(writex(fd, sbuf, sizeof(unsigned) * 2 + count)){
+        if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + count)){
             err = -1;
             break;
         }
@@ -326,7 +326,7 @@
     sbuf->size = htoll(len + 1);
     sbuf->id = ID_DATA;
 
-    ret = writex(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
+    ret = !WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
     if(ret)
         return -1;
 
@@ -355,8 +355,8 @@
     msg.req.id = ID_SEND;
     msg.req.namelen = htoll(len + r);
 
-    if(writex(fd, &msg.req, sizeof(msg.req)) ||
-       writex(fd, rpath, len) || writex(fd, tmp, r)) {
+    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
+       !WriteFdExactly(fd, rpath, len) || !WriteFdExactly(fd, tmp, r)) {
         free(file_buffer);
         goto fail;
     }
@@ -373,17 +373,17 @@
 
     msg.data.id = ID_DONE;
     msg.data.size = htoll(mtime);
-    if(writex(fd, &msg.data, sizeof(msg.data)))
+    if(!WriteFdExactly(fd, &msg.data, sizeof(msg.data)))
         goto fail;
 
-    if(readx(fd, &msg.status, sizeof(msg.status)))
+    if(!ReadFdExactly(fd, &msg.status, sizeof(msg.status)))
         return -1;
 
     if(msg.status.id != ID_OKAY) {
         if(msg.status.id == ID_FAIL) {
             len = ltohl(msg.status.msglen);
             if(len > 256) len = 256;
-            if(readx(fd, sbuf->data, len)) {
+            if(!ReadFdExactly(fd, sbuf->data, len)) {
                 return -1;
             }
             sbuf->data[len] = 0;
@@ -439,12 +439,12 @@
         stat_msg.req.id = ID_STAT;
         stat_msg.req.namelen = htoll(len);
 
-        if (writex(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
-            writex(fd, rpath, len)) {
+        if (!WriteFdExactly(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
+            !WriteFdExactly(fd, rpath, len)) {
             return -1;
         }
 
-        if (readx(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
+        if (!ReadFdExactly(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
             return -1;
         }
 
@@ -455,12 +455,12 @@
 
     msg.req.id = ID_RECV;
     msg.req.namelen = htoll(len);
-    if(writex(fd, &msg.req, sizeof(msg.req)) ||
-       writex(fd, rpath, len)) {
+    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
+       !WriteFdExactly(fd, rpath, len)) {
         return -1;
     }
 
-    if(readx(fd, &msg.data, sizeof(msg.data))) {
+    if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
         return -1;
     }
     id = msg.data.id;
@@ -479,7 +479,7 @@
     }
 
     for(;;) {
-        if(readx(fd, &msg.data, sizeof(msg.data))) {
+        if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
             return -1;
         }
         id = msg.data.id;
@@ -494,12 +494,12 @@
             return -1;
         }
 
-        if(readx(fd, buffer, len)) {
+        if(!ReadFdExactly(fd, buffer, len)) {
             adb_close(lfd);
             return -1;
         }
 
-        if(writex(lfd, buffer, len)) {
+        if(!WriteFdExactly(lfd, buffer, len)) {
             fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
             adb_close(lfd);
             return -1;
@@ -522,24 +522,19 @@
     if(id == ID_FAIL) {
         len = ltohl(msg.data.size);
         if(len > 256) len = 256;
-        if(readx(fd, buffer, len)) {
+        if(!ReadFdExactly(fd, buffer, len)) {
             return -1;
         }
         buffer[len] = 0;
     } else {
         memcpy(buffer, &id, 4);
         buffer[4] = 0;
-//        strcpy(buffer,"unknown reason");
     }
     fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
     return 0;
 }
 
-
-
 /* --- */
-
-
 static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
                           const char *name, void *cookie)
 {
@@ -573,7 +568,6 @@
     unsigned int mode;
     unsigned int size;
     int flag;
-    //char data[0];
 };
 
 copyinfo *mkcopyinfo(const char *spath, const char *dpath,
@@ -585,7 +579,8 @@
     int ssize = slen + nlen + 2;
     int dsize = dlen + nlen + 2;
 
-    copyinfo *ci = malloc(sizeof(copyinfo) + ssize + dsize);
+    copyinfo *ci = reinterpret_cast<copyinfo*>(
+        malloc(sizeof(copyinfo) + ssize + dsize));
     if(ci == 0) {
         fprintf(stderr,"out of memory\n");
         abort();
@@ -601,7 +596,6 @@
     snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
     snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
 
-//    fprintf(stderr,"mkcopyinfo('%s','%s')\n", ci->src, ci->dst);
     return ci;
 }
 
@@ -615,8 +609,6 @@
     copyinfo *dirlist = 0;
     copyinfo *ci, *next;
 
-//    fprintf(stderr,"local_build_list('%s','%s')\n", lpath, rpath);
-
     d = opendir(lpath);
     if(d == 0) {
         fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
@@ -692,14 +684,14 @@
     if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
     if(lpath[strlen(lpath) - 1] != '/') {
         int  tmplen = strlen(lpath)+2;
-        char *tmp = malloc(tmplen);
+        char *tmp = reinterpret_cast<char*>(malloc(tmplen));
         if(tmp == 0) return -1;
         snprintf(tmp, tmplen, "%s/",lpath);
         lpath = tmp;
     }
     if(rpath[strlen(rpath) - 1] != '/') {
         int tmplen = strlen(rpath)+2;
-        char *tmp = malloc(tmplen);
+        char *tmp = reinterpret_cast<char*>(malloc(tmplen));
         if(tmp == 0) return -1;
         snprintf(tmp, tmplen, "%s/",rpath);
         rpath = tmp;
@@ -792,7 +784,8 @@
                 name++;
             }
             int  tmplen = strlen(name) + strlen(rpath) + 2;
-            char *tmp = malloc(strlen(name) + strlen(rpath) + 2);
+            char *tmp = reinterpret_cast<char*>(
+                malloc(strlen(name) + strlen(rpath) + 2));
             if(tmp == 0) return 1;
             snprintf(tmp, tmplen, "%s/%s", rpath, name);
             rpath = tmp;
@@ -880,7 +873,7 @@
     return 0;
 }
 
-static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int mode)
+static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
 {
     struct utimbuf times = { time, time };
     int r1 = utime(lpath, &times);
@@ -898,7 +891,7 @@
 {
     if (path[strlen(path) - 1] != '/') {
         size_t len = strlen(path) + 2;
-        char *path_with_slash = malloc(len);
+        char *path_with_slash = reinterpret_cast<char*>(malloc(len));
         if (path_with_slash == NULL)
             return NULL;
         snprintf(path_with_slash, len, "%s/", path);
@@ -1007,7 +1000,7 @@
                     name++;
                 }
                 int  tmplen = strlen(name) + strlen(lpath) + 2;
-                char *tmp = malloc(tmplen);
+                char *tmp = reinterpret_cast<char*>(malloc(tmplen));
                 if(tmp == 0) return 1;
                 snprintf(tmp, tmplen, "%s/%s", lpath, name);
                 lpath = tmp;
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.cpp
similarity index 85%
rename from adb/file_sync_service.c
rename to adb/file_sync_service.cpp
index 7de82b7..e8e9a0f 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.cpp
@@ -14,34 +14,31 @@
  * limitations under the License.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#define TRACE_TAG TRACE_SYNC
 
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <utime.h>
-#include <unistd.h>
-
-#include <errno.h>
-#include <private/android_filesystem_config.h>
-#include <selinux/android.h>
 #include "sysdeps.h"
-
-#define TRACE_TAG  TRACE_SYNC
-#include "adb.h"
 #include "file_sync_service.h"
 
-/* TODO: use fs_config to configure permissions on /data */
-static bool is_on_system(const char *name) {
-    const char *SYSTEM = "/system/";
-    return (strncmp(SYSTEM, name, strlen(SYSTEM)) == 0);
-}
+#include <dirent.h>
+#include <errno.h>
+#include <selinux/android.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utime.h>
 
-static bool is_on_vendor(const char *name) {
-    const char *VENDOR = "/vendor/";
-    return (strncmp(VENDOR, name, strlen(VENDOR)) == 0);
+#include "adb.h"
+#include "adb_io.h"
+#include "private/android_filesystem_config.h"
+
+static bool should_use_fs_config(const char* path) {
+    // TODO: use fs_config to configure permissions on /data.
+    return strncmp("/system/", path, strlen("/system/")) == 0 ||
+           strncmp("/vendor/", path, strlen("/vendor/")) == 0 ||
+           strncmp("/oem/", path, strlen("/oem/")) == 0;
 }
 
 static int mkdirs(char *name)
@@ -59,7 +56,7 @@
         x = adb_dirstart(x);
         if(x == 0) return 0;
         *x = 0;
-        if (is_on_system(name) || is_on_vendor(name)) {
+        if (should_use_fs_config(name)) {
             fs_config(name, 1, &uid, &gid, &mode, &cap);
         }
         ret = adb_mkdir(name, mode);
@@ -97,7 +94,7 @@
         msg.stat.time = htoll(st.st_mtime);
     }
 
-    return writex(s, &msg.stat, sizeof(msg.stat));
+    return WriteFdExactly(s, &msg.stat, sizeof(msg.stat)) ? 0 : -1;
 }
 
 static int do_list(int s, const char *path)
@@ -135,8 +132,8 @@
             msg.dent.time = htoll(st.st_mtime);
             msg.dent.namelen = htoll(len);
 
-            if(writex(s, &msg.dent, sizeof(msg.dent)) ||
-               writex(s, de->d_name, len)) {
+            if(!WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ||
+               !WriteFdExactly(s, de->d_name, len)) {
                 closedir(d);
                 return -1;
             }
@@ -151,7 +148,7 @@
     msg.dent.size = 0;
     msg.dent.time = 0;
     msg.dent.namelen = 0;
-    return writex(s, &msg.dent, sizeof(msg.dent));
+    return WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ? 0 : -1;
 }
 
 static int fail_message(int s, const char *reason)
@@ -163,8 +160,8 @@
 
     msg.data.id = ID_FAIL;
     msg.data.size = htoll(len);
-    if(writex(s, &msg.data, sizeof(msg.data)) ||
-       writex(s, reason, len)) {
+    if(!WriteFdExactly(s, &msg.data, sizeof(msg.data)) ||
+       !WriteFdExactly(s, reason, len)) {
         return -1;
     } else {
         return 0;
@@ -217,7 +214,7 @@
     for(;;) {
         unsigned int len;
 
-        if(readx(s, &msg.data, sizeof(msg.data)))
+        if(!ReadFdExactly(s, &msg.data, sizeof(msg.data)))
             goto fail;
 
         if(msg.data.id != ID_DATA) {
@@ -233,12 +230,12 @@
             fail_message(s, "oversize data message");
             goto fail;
         }
-        if(readx(s, buffer, len))
+        if(!ReadFdExactly(s, buffer, len))
             goto fail;
 
         if(fd < 0)
             continue;
-        if(writex(fd, buffer, len)) {
+        if(!WriteFdExactly(fd, buffer, len)) {
             int saved_errno = errno;
             adb_close(fd);
             if (do_unlink) adb_unlink(path);
@@ -258,7 +255,7 @@
 
         msg.status.id = ID_OKAY;
         msg.status.msglen = 0;
-        if(writex(s, &msg.status, sizeof(msg.status)))
+        if(!WriteFdExactly(s, &msg.status, sizeof(msg.status)))
             return -1;
     }
     return 0;
@@ -279,7 +276,7 @@
     unsigned int len;
     int ret;
 
-    if(readx(s, &msg.data, sizeof(msg.data)))
+    if(!ReadFdExactly(s, &msg.data, sizeof(msg.data)))
         return -1;
 
     if(msg.data.id != ID_DATA) {
@@ -292,7 +289,7 @@
         fail_message(s, "oversize data message");
         return -1;
     }
-    if(readx(s, buffer, len))
+    if(!ReadFdExactly(s, buffer, len))
         return -1;
 
     ret = symlink(buffer, path);
@@ -308,13 +305,13 @@
         return -1;
     }
 
-    if(readx(s, &msg.data, sizeof(msg.data)))
+    if(!ReadFdExactly(s, &msg.data, sizeof(msg.data)))
         return -1;
 
     if(msg.data.id == ID_DONE) {
         msg.status.id = ID_OKAY;
         msg.status.msglen = 0;
-        if(writex(s, &msg.status, sizeof(msg.status)))
+        if(!WriteFdExactly(s, &msg.status, sizeof(msg.status)))
             return -1;
     } else {
         fail_message(s, "invalid data message: expected ID_DONE");
@@ -368,7 +365,7 @@
     if(*tmp == '/') {
         tmp++;
     }
-    if (is_on_system(path) || is_on_vendor(path)) {
+    if (should_use_fs_config(path)) {
         fs_config(tmp, 0, &uid, &gid, &mode, &cap);
     }
     return handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
@@ -396,8 +393,8 @@
             return r;
         }
         msg.data.size = htoll(r);
-        if(writex(s, &msg.data, sizeof(msg.data)) ||
-           writex(s, buffer, r)) {
+        if(!WriteFdExactly(s, &msg.data, sizeof(msg.data)) ||
+           !WriteFdExactly(s, buffer, r)) {
             adb_close(fd);
             return -1;
         }
@@ -407,7 +404,7 @@
 
     msg.data.id = ID_DONE;
     msg.data.size = 0;
-    if(writex(s, &msg.data, sizeof(msg.data))) {
+    if(!WriteFdExactly(s, &msg.data, sizeof(msg.data))) {
         return -1;
     }
 
@@ -420,13 +417,13 @@
     char name[1025];
     unsigned namelen;
 
-    char *buffer = malloc(SYNC_DATA_MAX);
+    char *buffer = reinterpret_cast<char*>(malloc(SYNC_DATA_MAX));
     if(buffer == 0) goto fail;
 
     for(;;) {
         D("sync: waiting for command\n");
 
-        if(readx(fd, &msg.req, sizeof(msg.req))) {
+        if(!ReadFdExactly(fd, &msg.req, sizeof(msg.req))) {
             fail_message(fd, "command read failure");
             break;
         }
@@ -435,7 +432,7 @@
             fail_message(fd, "invalid namelen");
             break;
         }
-        if(readx(fd, name, namelen)) {
+        if(!ReadFdExactly(fd, name, namelen)) {
             fail_message(fd, "filename read failure");
             break;
         }
diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.cpp
similarity index 89%
rename from adb/framebuffer_service.c
rename to adb/framebuffer_service.cpp
index 61578aa..7baad8b 100644
--- a/adb/framebuffer_service.c
+++ b/adb/framebuffer_service.cpp
@@ -14,21 +14,23 @@
  * limitations under the License.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
 #include <errno.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include "fdevent.h"
-#include "adb.h"
-
+#include <fcntl.h>
 #include <linux/fb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "sysdeps.h"
+
+#include "adb.h"
+#include "adb_io.h"
+#include "fdevent.h"
 
 /* TODO:
 ** - sync with vsync to avoid tearing
@@ -60,29 +62,30 @@
     int fd_screencap;
     int w, h, f;
     int fds[2];
+    pid_t pid;
 
     if (pipe2(fds, O_CLOEXEC) < 0) goto pipefail;
 
-    pid_t pid = fork();
+    pid = fork();
     if (pid < 0) goto done;
 
     if (pid == 0) {
         dup2(fds[1], STDOUT_FILENO);
-        close(fds[0]);
-        close(fds[1]);
+        adb_close(fds[0]);
+        adb_close(fds[1]);
         const char* command = "screencap";
         const char *args[2] = {command, NULL};
         execvp(command, (char**)args);
         exit(1);
     }
 
-    close(fds[1]);
+    adb_close(fds[1]);
     fd_screencap = fds[0];
 
     /* read w, h & format */
-    if(readx(fd_screencap, &w, 4)) goto done;
-    if(readx(fd_screencap, &h, 4)) goto done;
-    if(readx(fd_screencap, &f, 4)) goto done;
+    if(!ReadFdExactly(fd_screencap, &w, 4)) goto done;
+    if(!ReadFdExactly(fd_screencap, &h, 4)) goto done;
+    if(!ReadFdExactly(fd_screencap, &f, 4)) goto done;
 
     fbinfo.version = DDMS_RAWIMAGE_VERSION;
     /* see hardware/hardware.h */
@@ -162,21 +165,21 @@
     }
 
     /* write header */
-    if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done;
+    if(!WriteFdExactly(fd, &fbinfo, sizeof(fbinfo))) goto done;
 
     /* write data */
     for(i = 0; i < fbinfo.size; i += bsize) {
       bsize = sizeof(buf);
       if (i + bsize > fbinfo.size)
         bsize = fbinfo.size - i;
-      if(readx(fd_screencap, buf, bsize)) goto done;
-      if(writex(fd, buf, bsize)) goto done;
+      if(!ReadFdExactly(fd_screencap, buf, bsize)) goto done;
+      if(!WriteFdExactly(fd, buf, bsize)) goto done;
     }
 
 done:
-    close(fds[0]);
+    adb_close(fds[0]);
 
     TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
 pipefail:
-    close(fd);
+    adb_close(fd);
 }
diff --git a/adb/get_my_path_darwin.c b/adb/get_my_path_darwin.c
index ff1396c..b0c962e 100644
--- a/adb/get_my_path_darwin.c
+++ b/adb/get_my_path_darwin.c
@@ -17,6 +17,8 @@
 #import <Carbon/Carbon.h>
 #include <unistd.h>
 
+#include "adb.h"
+
 void get_my_path(char *s, size_t maxLen)
 {
     CFBundleRef mainBundle = CFBundleGetMainBundle();
diff --git a/adb/get_my_path_linux.c b/adb/get_my_path_linux.cpp
similarity index 97%
rename from adb/get_my_path_linux.c
rename to adb/get_my_path_linux.cpp
index 179c3dd..11c0b21 100644
--- a/adb/get_my_path_linux.c
+++ b/adb/get_my_path_linux.cpp
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
-#include <sys/types.h>
-#include <unistd.h>
 #include <limits.h>
 #include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "adb.h"
 
 void get_my_path(char *exe, size_t maxLen)
 {
diff --git a/adb/get_my_path_windows.c b/adb/get_my_path_windows.cpp
similarity index 97%
rename from adb/get_my_path_windows.c
rename to adb/get_my_path_windows.cpp
index ddf2816..9d23e1c 100644
--- a/adb/get_my_path_windows.c
+++ b/adb/get_my_path_windows.cpp
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
-#include <limits.h>
 #include <assert.h>
+#include <limits.h>
 #include <windows.h>
 
+#include "adb.h"
+
 void get_my_path(char *exe, size_t maxLen)
 {
     char  *r;
diff --git a/adb/jdwp_service.c b/adb/jdwp_service.cpp
similarity index 94%
rename from adb/jdwp_service.c
rename to adb/jdwp_service.cpp
index 3074e42..9cf084e 100644
--- a/adb/jdwp_service.c
+++ b/adb/jdwp_service.cpp
@@ -1,12 +1,32 @@
+/*
+ * 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.
+ */
+
 /* implement the "debug-ports" and "track-debug-ports" device services */
+
+#define TRACE_TAG TRACE_JDWP
+
 #include "sysdeps.h"
-#define  TRACE_TAG   TRACE_JDWP
-#include "adb.h"
+
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 
+#include "adb.h"
+
 /* here's how these things work.
 
    when adbd starts, it creates a unix server socket
@@ -194,7 +214,8 @@
 static JdwpProcess*
 jdwp_process_alloc( int  socket )
 {
-    JdwpProcess*  proc = calloc(1,sizeof(*proc));
+    JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(
+        calloc(1, sizeof(*proc)));
 
     if (proc == NULL) {
         D("not enough memory to create new JDWP process\n");
@@ -234,7 +255,7 @@
 static void
 jdwp_process_event( int  socket, unsigned  events, void*  _proc )
 {
-    JdwpProcess*  proc = _proc;
+    JdwpProcess*  proc = reinterpret_cast<JdwpProcess*>(_proc);
 
     if (events & FDE_READ) {
         if (proc->pid < 0) {
@@ -601,7 +622,7 @@
 asocket*
 create_jdwp_service_socket( void )
 {
-    JdwpSocket*  s = calloc(sizeof(*s),1);
+    JdwpSocket* s = reinterpret_cast<JdwpSocket*>(calloc(sizeof(*s), 1));
 
     if (s == NULL)
         return NULL;
@@ -696,7 +717,7 @@
 asocket*
 create_jdwp_tracker_service_socket( void )
 {
-    JdwpTracker*  t = calloc(sizeof(*t),1);
+    JdwpTracker* t = reinterpret_cast<JdwpTracker*>(calloc(sizeof(*t), 1));
 
     if (t == NULL)
         return NULL;
diff --git a/adb/qemu_tracing.c b/adb/qemu_tracing.cpp
similarity index 100%
rename from adb/qemu_tracing.c
rename to adb/qemu_tracing.cpp
diff --git a/adb/remount_service.c b/adb/remount_service.c
deleted file mode 100644
index d7b0dd1..0000000
--- a/adb/remount_service.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2008 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 "sysdeps.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <mntent.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mount.h>
-#include <unistd.h>
-
-#include "cutils/properties.h"
-
-#define  TRACE_TAG  TRACE_ADB
-#include "adb.h"
-
-
-static int system_ro = 1;
-static int vendor_ro = 1;
-
-/* Returns the device used to mount a directory in /proc/mounts */
-static char *find_mount(const char *dir)
-{
-    FILE* fp;
-    struct mntent* mentry;
-    char* device = NULL;
-
-    if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
-        return NULL;
-    }
-    while ((mentry = getmntent(fp)) != NULL) {
-        if (strcmp(dir, mentry->mnt_dir) == 0) {
-            device = strdup(mentry->mnt_fsname);
-            break;
-        }
-    }
-    endmntent(fp);
-    return device;
-}
-
-static int hasVendorPartition()
-{
-    struct stat info;
-    if (!lstat("/vendor", &info))
-        if ((info.st_mode & S_IFMT) == S_IFDIR)
-          return true;
-    return false;
-}
-
-int make_block_device_writable(const char* dev)
-{
-    int fd = -1;
-    int OFF = 0;
-    int rc = -1;
-
-    if (!dev)
-        goto errout;
-
-    fd = unix_open(dev, O_RDONLY | O_CLOEXEC);
-    if (fd < 0)
-        goto errout;
-
-    if (ioctl(fd, BLKROSET, &OFF)) {
-        goto errout;
-    }
-
-    rc = 0;
-
-errout:
-    if (fd >= 0) {
-        adb_close(fd);
-    }
-    return rc;
-}
-
-/* Init mounts /system as read only, remount to enable writes. */
-static int remount(const char* dir, int* dir_ro)
-{
-    char *dev = 0;
-    int rc = -1;
-
-    dev = find_mount(dir);
-
-    if (!dev || make_block_device_writable(dev)) {
-        goto errout;
-    }
-
-    rc = mount(dev, dir, "none", MS_REMOUNT, NULL);
-    *dir_ro = rc;
-
-errout:
-    free(dev);
-    return rc;
-}
-
-static void write_string(int fd, const char* str)
-{
-    writex(fd, str, strlen(str));
-}
-
-void remount_service(int fd, void *cookie)
-{
-    char buffer[200];
-    char prop_buf[PROPERTY_VALUE_MAX];
-
-    bool system_verified = false, vendor_verified = false;
-    property_get("partition.system.verified", prop_buf, "0");
-    if (!strcmp(prop_buf, "1")) {
-        system_verified = true;
-    }
-
-    property_get("partition.vendor.verified", prop_buf, "0");
-    if (!strcmp(prop_buf, "1")) {
-        vendor_verified = true;
-    }
-
-    if (system_verified || vendor_verified) {
-        // Allow remount but warn of likely bad effects
-        bool both = system_verified && vendor_verified;
-        snprintf(buffer, sizeof(buffer),
-                 "dm_verity is enabled on the %s%s%s partition%s.\n",
-                 system_verified ? "system" : "",
-                 both ? " and " : "",
-                 vendor_verified ? "vendor" : "",
-                 both ? "s" : "");
-        write_string(fd, buffer);
-        snprintf(buffer, sizeof(buffer),
-                 "Use \"adb disable-verity\" to disable verity.\n"
-                 "If you do not, remount may succeed, however, you will still "
-                 "not be able to write to these volumes.\n");
-        write_string(fd, buffer);
-    }
-
-    if (remount("/system", &system_ro)) {
-        snprintf(buffer, sizeof(buffer), "remount of system failed: %s\n",strerror(errno));
-        write_string(fd, buffer);
-    }
-
-    if (hasVendorPartition()) {
-        if (remount("/vendor", &vendor_ro)) {
-            snprintf(buffer, sizeof(buffer), "remount of vendor failed: %s\n",strerror(errno));
-            write_string(fd, buffer);
-        }
-    }
-
-    if (!system_ro && (!vendor_ro || !hasVendorPartition()))
-        write_string(fd, "remount succeeded\n");
-    else {
-        write_string(fd, "remount failed\n");
-    }
-
-    adb_close(fd);
-}
diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp
new file mode 100644
index 0000000..483ca3d
--- /dev/null
+++ b/adb/remount_service.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2008 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 TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "adb.h"
+#include "adb_io.h"
+#include "cutils/properties.h"
+
+static int system_ro = 1;
+static int vendor_ro = 1;
+static int oem_ro = 1;
+
+/* Returns the device used to mount a directory in /proc/mounts */
+static std::string find_mount(const char *dir) {
+    FILE* fp;
+    struct mntent* mentry;
+    char* device = NULL;
+
+    if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
+        return NULL;
+    }
+    while ((mentry = getmntent(fp)) != NULL) {
+        if (strcmp(dir, mentry->mnt_dir) == 0) {
+            device = mentry->mnt_fsname;
+            break;
+        }
+    }
+    endmntent(fp);
+    return device;
+}
+
+static bool has_partition(const char* path) {
+    struct stat sb;
+    return (lstat(path, &sb) == 0 && S_ISDIR(sb.st_mode));
+}
+
+int make_block_device_writable(const std::string& dev) {
+    int fd = unix_open(dev.c_str(), O_RDONLY | O_CLOEXEC);
+    if (fd == -1) {
+        return -1;
+    }
+
+    int result = -1;
+    int OFF = 0;
+    if (!ioctl(fd, BLKROSET, &OFF)) {
+        result = 0;
+    }
+    adb_close(fd);
+
+    return result;
+}
+
+// Init mounts /system as read only, remount to enable writes.
+static int remount(const char* dir, int* dir_ro) {
+    std::string dev(find_mount(dir));
+    if (dev.empty() || make_block_device_writable(dev)) {
+        return -1;
+    }
+
+    int rc = mount(dev.c_str(), dir, "none", MS_REMOUNT, NULL);
+    *dir_ro = rc;
+    return rc;
+}
+
+static bool remount_partition(int fd, const char* partition, int* ro) {
+  if (!has_partition(partition)) {
+    return true;
+  }
+  if (remount(partition, ro)) {
+    char buf[200];
+    snprintf(buf, sizeof(buf), "remount of %s failed: %s\n", partition, strerror(errno));
+    WriteStringFully(fd, buf);
+    return false;
+  }
+  return true;
+}
+
+void remount_service(int fd, void* cookie) {
+    char prop_buf[PROPERTY_VALUE_MAX];
+
+    if (getuid() != 0) {
+        WriteStringFully(fd, "Not running as root. Try \"adb root\" first.\n");
+        adb_close(fd);
+        return;
+    }
+
+    bool system_verified = false, vendor_verified = false;
+    property_get("partition.system.verified", prop_buf, "0");
+    if (!strcmp(prop_buf, "1")) {
+        system_verified = true;
+    }
+
+    property_get("partition.vendor.verified", prop_buf, "0");
+    if (!strcmp(prop_buf, "1")) {
+        vendor_verified = true;
+    }
+
+    if (system_verified || vendor_verified) {
+        // Allow remount but warn of likely bad effects
+        bool both = system_verified && vendor_verified;
+        char buffer[200];
+        snprintf(buffer, sizeof(buffer),
+                 "dm_verity is enabled on the %s%s%s partition%s.\n",
+                 system_verified ? "system" : "",
+                 both ? " and " : "",
+                 vendor_verified ? "vendor" : "",
+                 both ? "s" : "");
+        WriteStringFully(fd, buffer);
+        snprintf(buffer, sizeof(buffer),
+                 "Use \"adb disable-verity\" to disable verity.\n"
+                 "If you do not, remount may succeed, however, you will still "
+                 "not be able to write to these volumes.\n");
+        WriteStringFully(fd, buffer);
+    }
+
+    bool success = true;
+    success &= remount_partition(fd, "/system", &system_ro);
+    success &= remount_partition(fd, "/vendor", &vendor_ro);
+    success &= remount_partition(fd, "/oem", &oem_ro);
+
+    WriteStringFully(fd, success ? "remount succeeded\n" : "remount failed\n");
+
+    adb_close(fd);
+}
diff --git a/adb/remount_service.h b/adb/remount_service.h
new file mode 100644
index 0000000..e1763cf
--- /dev/null
+++ b/adb/remount_service.h
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+#ifndef _REMOUNT_SERVICE_H_
+#define _REMOUNT_SERVICE_H_
+
+#include <string>
+
+int make_block_device_writable(const std::string&);
+void remount_service(int, void*);
+
+#endif
diff --git a/adb/services.c b/adb/services.cpp
similarity index 84%
rename from adb/services.c
rename to adb/services.cpp
index bd210a8..12eb406 100644
--- a/adb/services.c
+++ b/adb/services.cpp
@@ -14,30 +14,35 @@
  * limitations under the License.
  */
 
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
+#define TRACE_TAG TRACE_SERVICES
 
 #include "sysdeps.h"
 
-#define  TRACE_TAG  TRACE_SERVICES
-#include "adb.h"
-#include "file_sync_service.h"
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
-#if ADB_HOST
-#  ifndef HAVE_WINSOCK
-#    include <netinet/in.h>
-#    include <netdb.h>
-#    include <sys/ioctl.h>
-#  endif
-#else
-#  include <cutils/android_reboot.h>
-#  include <cutils/properties.h>
+#ifndef _WIN32
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
 #endif
 
+#if !ADB_HOST
+#include "base/file.h"
+#include "cutils/android_reboot.h"
+#include "cutils/properties.h"
+#endif
+
+#include "adb.h"
+#include "adb_io.h"
+#include "file_sync_service.h"
+#include "remount_service.h"
+#include "transport.h"
+
 typedef struct stinfo stinfo;
 
 struct stinfo {
@@ -49,7 +54,7 @@
 
 void *service_bootstrap_func(void *x)
 {
-    stinfo *sti = x;
+    stinfo* sti = reinterpret_cast<stinfo*>(x);
     sti->func(sti->fd, sti->cookie);
     free(sti);
     return 0;
@@ -64,20 +69,20 @@
 
     if (getuid() == 0) {
         snprintf(buf, sizeof(buf), "adbd is already running as root\n");
-        writex(fd, buf, strlen(buf));
+        WriteFdExactly(fd, buf, strlen(buf));
         adb_close(fd);
     } else {
         property_get("ro.debuggable", value, "");
         if (strcmp(value, "1") != 0) {
             snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n");
-            writex(fd, buf, strlen(buf));
+            WriteFdExactly(fd, buf, strlen(buf));
             adb_close(fd);
             return;
         }
 
         property_set("service.adb.root", "1");
         snprintf(buf, sizeof(buf), "restarting adbd as root\n");
-        writex(fd, buf, strlen(buf));
+        WriteFdExactly(fd, buf, strlen(buf));
         adb_close(fd);
     }
 }
@@ -88,12 +93,12 @@
 
     if (getuid() != 0) {
         snprintf(buf, sizeof(buf), "adbd not running as root\n");
-        writex(fd, buf, strlen(buf));
+        WriteFdExactly(fd, buf, strlen(buf));
         adb_close(fd);
     } else {
         property_set("service.adb.root", "0");
         snprintf(buf, sizeof(buf), "restarting adbd as non root\n");
-        writex(fd, buf, strlen(buf));
+        WriteFdExactly(fd, buf, strlen(buf));
         adb_close(fd);
     }
 }
@@ -106,7 +111,7 @@
 
     if (port <= 0) {
         snprintf(buf, sizeof(buf), "invalid port\n");
-        writex(fd, buf, strlen(buf));
+        WriteFdExactly(fd, buf, strlen(buf));
         adb_close(fd);
         return;
     }
@@ -114,7 +119,7 @@
     snprintf(value, sizeof(value), "%d", port);
     property_set("service.adb.tcp.port", value);
     snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
-    writex(fd, buf, strlen(buf));
+    WriteFdExactly(fd, buf, strlen(buf));
     adb_close(fd);
 }
 
@@ -124,42 +129,83 @@
 
     property_set("service.adb.tcp.port", "0");
     snprintf(buf, sizeof(buf), "restarting in USB mode\n");
-    writex(fd, buf, strlen(buf));
+    WriteFdExactly(fd, buf, strlen(buf));
     adb_close(fd);
 }
 
-void reboot_service(int fd, void *arg)
-{
+static bool reboot_service_impl(int fd, const char* arg) {
+    const char* reboot_arg = arg;
+    bool auto_reboot = false;
+
+    if (strcmp(reboot_arg, "sideload-auto-reboot") == 0) {
+        auto_reboot = true;
+        reboot_arg = "sideload";
+    }
+
     char buf[100];
-    char property_val[PROPERTY_VALUE_MAX];
-    int ret;
+    // It reboots into sideload mode by setting "--sideload" or "--sideload_auto_reboot"
+    // in the command file.
+    if (strcmp(reboot_arg, "sideload") == 0) {
+        if (getuid() != 0) {
+            snprintf(buf, sizeof(buf), "'adb root' is required for 'adb reboot sideload'.\n");
+            WriteStringFully(fd, buf);
+            return false;
+        }
+
+        const char* const recovery_dir = "/cache/recovery";
+        const char* const command_file = "/cache/recovery/command";
+        // Ensure /cache/recovery exists.
+        if (adb_mkdir(recovery_dir, 0770) == -1 && errno != EEXIST) {
+            D("Failed to create directory '%s': %s\n", recovery_dir, strerror(errno));
+            return false;
+        }
+
+        bool write_status = android::base::WriteStringToFile(
+                auto_reboot ? "--sideload_auto_reboot" : "--sideload", command_file);
+        if (!write_status) {
+            return false;
+        }
+
+        reboot_arg = "recovery";
+    }
 
     sync();
 
-    ret = snprintf(property_val, sizeof(property_val), "reboot,%s", (char *) arg);
-    if (ret >= (int) sizeof(property_val)) {
+    char property_val[PROPERTY_VALUE_MAX];
+    int ret = snprintf(property_val, sizeof(property_val), "reboot,%s", reboot_arg);
+    if (ret >= static_cast<int>(sizeof(property_val))) {
         snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret);
-        writex(fd, buf, strlen(buf));
-        goto cleanup;
+        WriteStringFully(fd, buf);
+        return false;
     }
 
     ret = property_set(ANDROID_RB_PROPERTY, property_val);
     if (ret < 0) {
         snprintf(buf, sizeof(buf), "reboot failed: %d\n", ret);
-        writex(fd, buf, strlen(buf));
-        goto cleanup;
+        WriteStringFully(fd, buf);
+        return false;
     }
-    // Don't return early. Give the reboot command time to take effect
-    // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
-    while(1) { pause(); }
-cleanup:
+
+    return true;
+}
+
+void reboot_service(int fd, void* arg)
+{
+    if (reboot_service_impl(fd, static_cast<const char*>(arg))) {
+        // Don't return early. Give the reboot command time to take effect
+        // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
+        while (1) {
+            pause();
+        }
+    }
+
     free(arg);
     adb_close(fd);
 }
 
 void reverse_service(int fd, void* arg)
 {
-    const char* command = arg;
+    const char* command = reinterpret_cast<const char*>(arg);
 
     if (handle_forward_request(command, kTransportAny, NULL, fd) < 0) {
         sendfailmsg(fd, "not a reverse forwarding command");
@@ -172,23 +218,23 @@
 
 static int create_service_thread(void (*func)(int, void *), void *cookie)
 {
-    stinfo *sti;
-    adb_thread_t t;
     int s[2];
-
-    if(adb_socketpair(s)) {
+    if (adb_socketpair(s)) {
         printf("cannot create service socket pair\n");
         return -1;
     }
     D("socketpair: (%d,%d)", s[0], s[1]);
 
-    sti = malloc(sizeof(stinfo));
-    if(sti == 0) fatal("cannot allocate stinfo");
+    stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
+    if (sti == nullptr) {
+        fatal("cannot allocate stinfo");
+    }
     sti->func = func;
     sti->cookie = cookie;
     sti->fd = s[1];
 
-    if(adb_thread_create( &t, service_bootstrap_func, sti)){
+    adb_thread_t t;
+    if (adb_thread_create(&t, service_bootstrap_func, sti)) {
         free(sti);
         adb_close(s[0]);
         adb_close(s[1]);
@@ -349,7 +395,7 @@
     D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
     if (SHELL_EXIT_NOTIFY_FD >=0) {
       int res;
-      res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd));
+      res = WriteFdExactly(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd)) ? 0 : -1;
       D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
         SHELL_EXIT_NOTIFY_FD, pid, res, errno);
     }
@@ -357,7 +403,6 @@
 
 static int create_subproc_thread(const char *name, const subproc_mode mode)
 {
-    stinfo *sti;
     adb_thread_t t;
     int ret_fd;
     pid_t pid = -1;
@@ -382,7 +427,7 @@
     }
     D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid);
 
-    sti = malloc(sizeof(stinfo));
+    stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
     if(sti == 0) fatal("cannot allocate stinfo");
     sti->func = subproc_waiter_service;
     sti->cookie = (void*) (uintptr_t) pid;
@@ -510,14 +555,14 @@
 
 static void wait_for_state(int fd, void* cookie)
 {
-    struct state_info* sinfo = cookie;
-    char* err = "unknown error";
+    state_info* sinfo = reinterpret_cast<state_info*>(cookie);
 
     D("wait_for_state %d\n", sinfo->state);
 
+    const char* err = "unknown error";
     atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
     if(t != 0) {
-        writex(fd, "OKAY", 4);
+        WriteFdExactly(fd, "OKAY", 4);
     } else {
         sendfailmsg(fd, err);
     }
@@ -633,7 +678,7 @@
 {
     char buf[4096];
     char resp[4096];
-    char *host = cookie;
+    char *host = reinterpret_cast<char*>(cookie);
 
     if (!strncmp(host, "emu:", 4)) {
         connect_emulator(host + 4, buf, sizeof(buf));
@@ -643,7 +688,7 @@
 
     // Send response for emulator and device
     snprintf(resp, sizeof(resp), "%04x%s",(unsigned)strlen(buf), buf);
-    writex(fd, resp, strlen(resp));
+    WriteFdExactly(fd, resp, strlen(resp));
     adb_close(fd);
 }
 #endif
@@ -654,7 +699,7 @@
     if (!strcmp(name,"track-devices")) {
         return create_device_tracker();
     } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
-        struct state_info* sinfo = malloc(sizeof(struct state_info));
+        auto sinfo = reinterpret_cast<state_info*>(malloc(sizeof(state_info)));
 
         if (serial)
             sinfo->serial = strdup(serial);
diff --git a/adb/set_verity_enable_state_service.c b/adb/set_verity_enable_state_service.cpp
similarity index 97%
rename from adb/set_verity_enable_state_service.c
rename to adb/set_verity_enable_state_service.cpp
index 184674d..b75ed4c 100644
--- a/adb/set_verity_enable_state_service.c
+++ b/adb/set_verity_enable_state_service.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
+
 #include <fcntl.h>
 #include <inttypes.h>
 #include <stdarg.h>
@@ -21,12 +25,12 @@
 #include <stdio.h>
 #include <sys/stat.h>
 
-#define  TRACE_TAG  TRACE_ADB
-#include "adb.h"
 #include "cutils/properties.h"
+
+#include "adb.h"
 #include "ext4_sb.h"
 #include "fs_mgr.h"
-#include "sysdeps.h"
+#include "remount_service.h"
 
 #define FSTAB_PREFIX "/fstab."
 struct fstab *fstab;
@@ -90,7 +94,7 @@
     uint32_t magic_number;
     const uint32_t new_magic = enable ? VERITY_METADATA_MAGIC_NUMBER
                                       : VERITY_METADATA_MAGIC_DISABLE;
-    uint64_t device_length;
+    uint64_t device_length = 0;
     int device = -1;
     int retval = -1;
 
@@ -140,7 +144,7 @@
     if (magic_number != VERITY_METADATA_MAGIC_NUMBER
             && magic_number != VERITY_METADATA_MAGIC_DISABLE) {
         write_console(fd,
-                      "Couldn't find verity metadata at offset %"PRIu64"!\n",
+                      "Couldn't find verity metadata at offset %" PRIu64 "!\n",
                       device_length);
         goto errout;
     }
diff --git a/adb/sockets.c b/adb/sockets.cpp
similarity index 91%
rename from adb/sockets.c
rename to adb/sockets.cpp
index 6cdde97..48d02d6 100644
--- a/adb/sockets.c
+++ b/adb/sockets.cpp
@@ -14,21 +14,24 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <ctype.h>
+#define TRACE_TAG TRACE_SOCKETS
 
 #include "sysdeps.h"
 
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
 #if !ADB_HOST
-#include <cutils/properties.h>
+#include "cutils/properties.h"
 #endif
 
-#define  TRACE_TAG  TRACE_SOCKETS
 #include "adb.h"
+#include "adb_io.h"
+#include "transport.h"
 
 ADB_MUTEX_DEFINE( socket_list_lock );
 
@@ -39,13 +42,17 @@
     char buf[9];
     int len;
     len = strlen(reason);
-    if(len > 0xffff) len = 0xffff;
-    snprintf(buf, sizeof buf, "FAIL%04x", len);
-    if(writex(fd, buf, 8)) return -1;
-    return writex(fd, reason, len);
-}
+    if (len > 0xffff) {
+        len = 0xffff;
+    }
 
-//extern int online;
+    snprintf(buf, sizeof buf, "FAIL%04x", len);
+    if (!WriteFdExactly(fd, buf, 8)) {
+        return -1;
+    }
+
+    return WriteFdExactly(fd, reason, len) ? 0 : -1;
+}
 
 static unsigned local_socket_next_id = 1;
 
@@ -196,10 +203,9 @@
 
 static void local_socket_ready(asocket *s)
 {
-        /* far side is ready for data, pay attention to
-           readable events */
+    /* far side is ready for data, pay attention to
+       readable events */
     fdevent_add(&s->fde, FDE_READ);
-//    D("LS(%d): ready()\n", s->id);
 }
 
 static void local_socket_close(asocket *s)
@@ -240,7 +246,7 @@
 
 static void local_socket_close_locked(asocket *s)
 {
-    D("entered. LS(%d) fd=%d\n", s->id, s->fd);
+    D("entered local_socket_close_locked. LS(%d) fd=%d\n", s->id, s->fd);
     if(s->peer) {
         D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n",
           s->id, s->peer->id, s->peer->fd);
@@ -280,98 +286,101 @@
     insert_local_socket(s, &local_socket_closing_list);
 }
 
-static void local_socket_event_func(int fd, unsigned ev, void *_s)
+static void local_socket_event_func(int fd, unsigned ev, void* _s)
 {
-    asocket *s = _s;
-
+    asocket* s = reinterpret_cast<asocket*>(_s);
     D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev);
 
     /* put the FDE_WRITE processing before the FDE_READ
     ** in order to simplify the code.
     */
-    if(ev & FDE_WRITE){
-        apacket *p;
-
-        while((p = s->pkt_first) != 0) {
-            while(p->len > 0) {
+    if (ev & FDE_WRITE) {
+        apacket* p;
+        while ((p = s->pkt_first) != nullptr) {
+            while (p->len > 0) {
                 int r = adb_write(fd, p->ptr, p->len);
-                if(r > 0) {
+                if (r == -1) {
+                    /* returning here is ok because FDE_READ will
+                    ** be processed in the next iteration loop
+                    */
+                    if (errno == EAGAIN) {
+                        return;
+                    }
+                } else if (r > 0) {
                     p->ptr += r;
                     p->len -= r;
                     continue;
                 }
-                if(r < 0) {
-                    /* returning here is ok because FDE_READ will
-                    ** be processed in the next iteration loop
-                    */
-                    if(errno == EAGAIN) return;
-                    if(errno == EINTR) continue;
-                }
+
                 D(" closing after write because r=%d and errno is %d\n", r, errno);
                 s->close(s);
                 return;
             }
 
-            if(p->len == 0) {
+            if (p->len == 0) {
                 s->pkt_first = p->next;
-                if(s->pkt_first == 0) s->pkt_last = 0;
+                if (s->pkt_first == 0) {
+                    s->pkt_last = 0;
+                }
                 put_apacket(p);
             }
         }
 
-            /* if we sent the last packet of a closing socket,
-            ** we can now destroy it.
-            */
+        /* if we sent the last packet of a closing socket,
+        ** we can now destroy it.
+        */
         if (s->closing) {
             D(" closing because 'closing' is set after write\n");
             s->close(s);
             return;
         }
 
-            /* no more packets queued, so we can ignore
-            ** writable events again and tell our peer
-            ** to resume writing
-            */
+        /* no more packets queued, so we can ignore
+        ** writable events again and tell our peer
+        ** to resume writing
+        */
         fdevent_del(&s->fde, FDE_WRITE);
         s->peer->ready(s->peer);
     }
 
 
-    if(ev & FDE_READ){
+    if (ev & FDE_READ) {
         apacket *p = get_apacket();
         unsigned char *x = p->data;
         size_t avail = MAX_PAYLOAD;
         int r;
         int is_eof = 0;
 
-        while(avail > 0) {
+        while (avail > 0) {
             r = adb_read(fd, x, avail);
-            D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu\n", s->id, s->fd, r, r<0?errno:0, avail);
-            if(r > 0) {
+            D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu\n",
+              s->id, s->fd, r, r < 0 ? errno : 0, avail);
+            if (r == -1) {
+                if (errno == EAGAIN) {
+                    break;
+                }
+            } else if (r > 0) {
                 avail -= r;
                 x += r;
                 continue;
             }
-            if(r < 0) {
-                if(errno == EAGAIN) break;
-                if(errno == EINTR) continue;
-            }
 
-                /* r = 0 or unhandled error */
+            /* r = 0 or unhandled error */
             is_eof = 1;
             break;
         }
         D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n",
           s->id, s->fd, r, is_eof, s->fde.force_eof);
-        if((avail == MAX_PAYLOAD) || (s->peer == 0)) {
+        if ((avail == MAX_PAYLOAD) || (s->peer == 0)) {
             put_apacket(p);
         } else {
             p->len = MAX_PAYLOAD - avail;
 
             r = s->peer->enqueue(s->peer, p);
-            D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r);
+            D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd,
+              r);
 
-            if(r < 0) {
+            if (r < 0) {
                     /* error return means they closed us as a side-effect
                     ** and we must return immediately.
                     **
@@ -383,7 +392,7 @@
                 return;
             }
 
-            if(r > 0) {
+            if (r > 0) {
                     /* if the remote cannot accept further events,
                     ** we disable notification of READs.  They'll
                     ** be enabled again when we get a call to ready()
@@ -392,18 +401,18 @@
             }
         }
         /* Don't allow a forced eof if data is still there */
-        if((s->fde.force_eof && !r) || is_eof) {
-            D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof);
+        if ((s->fde.force_eof && !r) || is_eof) {
+            D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n",
+              is_eof, r, s->fde.force_eof);
             s->close(s);
         }
     }
 
-    if(ev & FDE_ERROR){
+    if (ev & FDE_ERROR){
             /* this should be caught be the next read or write
             ** catching it here means we may skip the last few
             ** bytes of readable data.
             */
-//        s->close(s);
         D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd);
 
         return;
@@ -412,7 +421,7 @@
 
 asocket *create_local_socket(int fd)
 {
-    asocket *s = calloc(1, sizeof(asocket));
+    asocket *s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
     if (s == NULL) fatal("cannot allocate socket");
     s->fd = fd;
     s->enqueue = local_socket_enqueue;
@@ -422,8 +431,6 @@
     install_local_socket(s);
 
     fdevent_install(&s->fde, fd, local_socket_event_func, s);
-/*    fdevent_add(&s->fde, FDE_ERROR); */
-    //fprintf(stderr, "Created local socket in create_local_socket \n");
     D("LS(%d): created (fd=%d)\n", s->id, s->fd);
     return s;
 }
@@ -538,8 +545,8 @@
 
 static void remote_socket_disconnect(void*  _s, atransport*  t)
 {
-    asocket*  s    = _s;
-    asocket*  peer = s->peer;
+    asocket* s = reinterpret_cast<asocket*>(_s);
+    asocket* peer = s->peer;
 
     D("remote_socket_disconnect RS(%d)\n", s->id);
     if (peer) {
@@ -556,12 +563,9 @@
    Returns a new non-NULL asocket handle. */
 asocket *create_remote_socket(unsigned id, atransport *t)
 {
-    asocket* s;
-    adisconnect* dis;
-
     if (id == 0) fatal("invalid remote socket id (0)");
-    s = calloc(1, sizeof(aremotesocket));
-    dis = &((aremotesocket*)s)->disconnect;
+    asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(aremotesocket)));
+    adisconnect* dis = &reinterpret_cast<aremotesocket*>(s)->disconnect;
 
     if (s == NULL) fatal("cannot allocate socket");
     s->id = id;
@@ -823,7 +827,7 @@
     }
 #else /* !ADB_HOST */
     if (s->transport == NULL) {
-        char* error_string = "unknown failure";
+        const char* error_string = "unknown failure";
         s->transport = acquire_one_transport (CS_ANY,
                 kTransportAny, NULL, &error_string);
 
@@ -891,7 +895,7 @@
 static asocket *create_smart_socket(void)
 {
     D("Creating smart socket \n");
-    asocket *s = calloc(1, sizeof(asocket));
+    asocket *s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
     if (s == NULL) fatal("cannot allocate socket");
     s->enqueue = smart_socket_enqueue;
     s->ready = smart_socket_ready;
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index ec847b5..2ad28fa 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -24,6 +24,21 @@
 #  undef _WIN32
 #endif
 
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
+
 #ifdef _WIN32
 
 #include <ctype.h>
@@ -135,10 +150,8 @@
 #undef   close
 #define  close   ____xxx_close
 
-static __inline__  int  unix_read(int  fd, void*  buf, size_t  len)
-{
-    return read(fd, buf, len);
-}
+extern int  unix_read(int  fd, void*  buf, size_t  len);
+
 #undef   read
 #define  read  ___xxx_read
 
@@ -264,10 +277,6 @@
 
 extern char*  adb_strtok_r(char *str, const char *delim, char **saveptr);
 
-#ifdef __cplusplus
-}
-#endif
-
 #else /* !_WIN32 a.k.a. Unix */
 
 #include "fdevent.h"
@@ -291,21 +300,6 @@
 extern "C" {
 #endif
 
-/*
- * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
- * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
- * not already defined, then define it here.
- */
-#ifndef TEMP_FAILURE_RETRY
-/* Used to retry syscalls that can return EINTR. */
-#define TEMP_FAILURE_RETRY(exp) ({         \
-    typeof (exp) _rc;                      \
-    do {                                   \
-        _rc = (exp);                       \
-    } while (_rc == -1 && errno == EINTR); \
-    _rc; })
-#endif
-
 #define OS_PATH_SEPARATOR '/'
 #define OS_PATH_SEPARATOR_STR "/"
 #define ENV_PATH_SEPARATOR_STR ":"
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index f132b8c..c2742f1 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -1,10 +1,31 @@
+/*
+ * 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.
+ */
+
+#define TRACE_TAG TRACE_SYSDEPS
+
 #include "sysdeps.h"
-#include <winsock2.h>
+
+#include <winsock2.h> /* winsock.h *must* be included before windows.h. */
 #include <windows.h>
+
+#include <errno.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <errno.h>
-#define  TRACE_TAG  TRACE_SYSDEPS
+
 #include "adb.h"
 
 extern void fatal(const char *fmt, ...);
@@ -2230,3 +2251,905 @@
 	}
 	/* NOTREACHED */
 }
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****      Console Window Terminal Emulation                         *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+// This reads input from a Win32 console window and translates it into Unix
+// terminal-style sequences. This emulates mostly Gnome Terminal (in Normal
+// mode, not Application mode), which itself emulates xterm. Gnome Terminal
+// is emulated instead of xterm because it is probably more popular than xterm:
+// Ubuntu's default Ctrl-Alt-T shortcut opens Gnome Terminal, Gnome Terminal
+// supports modern fonts, etc. It seems best to emulate the terminal that most
+// Android developers use because they'll fix apps (the shell, etc.) to keep
+// working with that terminal's emulation.
+//
+// The point of this emulation is not to be perfect or to solve all issues with
+// console windows on Windows, but to be better than the original code which
+// just called read() (which called ReadFile(), which called ReadConsoleA())
+// which did not support Ctrl-C, tab completion, shell input line editing
+// keys, server echo, and more.
+//
+// This implementation reconfigures the console with SetConsoleMode(), then
+// calls ReadConsoleInput() to get raw input which it remaps to Unix
+// terminal-style sequences which is returned via unix_read() which is used
+// by the 'adb shell' command.
+//
+// Code organization:
+//
+// * stdin_raw_init() and stdin_raw_restore() reconfigure the console.
+// * unix_read() detects console windows (as opposed to pipes, files, etc.).
+// * _console_read() is the main code of the emulation.
+
+
+// Read an input record from the console; one that should be processed.
+static bool _get_interesting_input_record_uncached(const HANDLE console,
+    INPUT_RECORD* const input_record) {
+    for (;;) {
+        DWORD read_count = 0;
+        memset(input_record, 0, sizeof(*input_record));
+        if (!ReadConsoleInputA(console, input_record, 1, &read_count)) {
+            D("_get_interesting_input_record_uncached: ReadConsoleInputA() "
+              "failure, error %ld\n", GetLastError());
+            errno = EIO;
+            return false;
+        }
+
+        if (read_count == 0) {   // should be impossible
+            fatal("ReadConsoleInputA returned 0");
+        }
+
+        if (read_count != 1) {   // should be impossible
+            fatal("ReadConsoleInputA did not return one input record");
+        }
+
+        if ((input_record->EventType == KEY_EVENT) &&
+            (input_record->Event.KeyEvent.bKeyDown)) {
+            if (input_record->Event.KeyEvent.wRepeatCount == 0) {
+                fatal("ReadConsoleInputA returned a key event with zero repeat"
+                      " count");
+            }
+
+            // Got an interesting INPUT_RECORD, so return
+            return true;
+        }
+    }
+}
+
+// Cached input record (in case _console_read() is passed a buffer that doesn't
+// have enough space to fit wRepeatCount number of key sequences). A non-zero
+// wRepeatCount indicates that a record is cached.
+static INPUT_RECORD _win32_input_record;
+
+// Get the next KEY_EVENT_RECORD that should be processed.
+static KEY_EVENT_RECORD* _get_key_event_record(const HANDLE console) {
+    // If nothing cached, read directly from the console until we get an
+    // interesting record.
+    if (_win32_input_record.Event.KeyEvent.wRepeatCount == 0) {
+        if (!_get_interesting_input_record_uncached(console,
+            &_win32_input_record)) {
+            // There was an error, so make sure wRepeatCount is zero because
+            // that signifies no cached input record.
+            _win32_input_record.Event.KeyEvent.wRepeatCount = 0;
+            return NULL;
+        }
+    }
+
+    return &_win32_input_record.Event.KeyEvent;
+}
+
+static __inline__ bool _is_shift_pressed(const DWORD control_key_state) {
+    return (control_key_state & SHIFT_PRESSED) != 0;
+}
+
+static __inline__ bool _is_ctrl_pressed(const DWORD control_key_state) {
+    return (control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0;
+}
+
+static __inline__ bool _is_alt_pressed(const DWORD control_key_state) {
+    return (control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) != 0;
+}
+
+static __inline__ bool _is_numlock_on(const DWORD control_key_state) {
+    return (control_key_state & NUMLOCK_ON) != 0;
+}
+
+static __inline__ bool _is_capslock_on(const DWORD control_key_state) {
+    return (control_key_state & CAPSLOCK_ON) != 0;
+}
+
+static __inline__ bool _is_enhanced_key(const DWORD control_key_state) {
+    return (control_key_state & ENHANCED_KEY) != 0;
+}
+
+// Constants from MSDN for ToAscii().
+static const BYTE TOASCII_KEY_OFF = 0x00;
+static const BYTE TOASCII_KEY_DOWN = 0x80;
+static const BYTE TOASCII_KEY_TOGGLED_ON = 0x01;   // for CapsLock
+
+// Given a key event, ignore a modifier key and return the character that was
+// entered without the modifier. Writes to *ch and returns the number of bytes
+// written.
+static size_t _get_char_ignoring_modifier(char* const ch,
+    const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state,
+    const WORD modifier) {
+    // If there is no character from Windows, try ignoring the specified
+    // modifier and look for a character. Note that if AltGr is being used,
+    // there will be a character from Windows.
+    if (key_event->uChar.AsciiChar == '\0') {
+        // Note that we read the control key state from the passed in argument
+        // instead of from key_event since the argument has been normalized.
+        if (((modifier == VK_SHIFT)   &&
+            _is_shift_pressed(control_key_state)) ||
+            ((modifier == VK_CONTROL) &&
+            _is_ctrl_pressed(control_key_state)) ||
+            ((modifier == VK_MENU)    && _is_alt_pressed(control_key_state))) {
+
+            BYTE key_state[256]   = {0};
+            key_state[VK_SHIFT]   = _is_shift_pressed(control_key_state) ?
+                TOASCII_KEY_DOWN : TOASCII_KEY_OFF;
+            key_state[VK_CONTROL] = _is_ctrl_pressed(control_key_state)  ?
+                TOASCII_KEY_DOWN : TOASCII_KEY_OFF;
+            key_state[VK_MENU]    = _is_alt_pressed(control_key_state)   ?
+                TOASCII_KEY_DOWN : TOASCII_KEY_OFF;
+            key_state[VK_CAPITAL] = _is_capslock_on(control_key_state)   ?
+                TOASCII_KEY_TOGGLED_ON : TOASCII_KEY_OFF;
+
+            // cause this modifier to be ignored
+            key_state[modifier]   = TOASCII_KEY_OFF;
+
+            WORD translated = 0;
+            if (ToAscii(key_event->wVirtualKeyCode,
+                key_event->wVirtualScanCode, key_state, &translated, 0) == 1) {
+                // Ignoring the modifier, we found a character.
+                *ch = (CHAR)translated;
+                return 1;
+            }
+        }
+    }
+
+    // Just use whatever Windows told us originally.
+    *ch = key_event->uChar.AsciiChar;
+
+    // If the character from Windows is NULL, return a size of zero.
+    return (*ch == '\0') ? 0 : 1;
+}
+
+// If a Ctrl key is pressed, lookup the character, ignoring the Ctrl key,
+// but taking into account the shift key. This is because for a sequence like
+// Ctrl-Alt-0, we want to find the character '0' and for Ctrl-Alt-Shift-0,
+// we want to find the character ')'.
+//
+// Note that Windows doesn't seem to pass bKeyDown for Ctrl-Shift-NoAlt-0
+// because it is the default key-sequence to switch the input language.
+// This is configurable in the Region and Language control panel.
+static __inline__ size_t _get_non_control_char(char* const ch,
+    const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) {
+    return _get_char_ignoring_modifier(ch, key_event, control_key_state,
+        VK_CONTROL);
+}
+
+// Get without Alt.
+static __inline__ size_t _get_non_alt_char(char* const ch,
+    const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) {
+    return _get_char_ignoring_modifier(ch, key_event, control_key_state,
+        VK_MENU);
+}
+
+// Ignore the control key, find the character from Windows, and apply any
+// Control key mappings (for example, Ctrl-2 is a NULL character). Writes to
+// *pch and returns number of bytes written.
+static size_t _get_control_character(char* const pch,
+    const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) {
+    const size_t len = _get_non_control_char(pch, key_event,
+        control_key_state);
+
+    if ((len == 1) && _is_ctrl_pressed(control_key_state)) {
+        char ch = *pch;
+        switch (ch) {
+        case '2':
+        case '@':
+        case '`':
+            ch = '\0';
+            break;
+        case '3':
+        case '[':
+        case '{':
+            ch = '\x1b';
+            break;
+        case '4':
+        case '\\':
+        case '|':
+            ch = '\x1c';
+            break;
+        case '5':
+        case ']':
+        case '}':
+            ch = '\x1d';
+            break;
+        case '6':
+        case '^':
+        case '~':
+            ch = '\x1e';
+            break;
+        case '7':
+        case '-':
+        case '_':
+            ch = '\x1f';
+            break;
+        case '8':
+            ch = '\x7f';
+            break;
+        case '/':
+            if (!_is_alt_pressed(control_key_state)) {
+                ch = '\x1f';
+            }
+            break;
+        case '?':
+            if (!_is_alt_pressed(control_key_state)) {
+                ch = '\x7f';
+            }
+            break;
+        }
+        *pch = ch;
+    }
+
+    return len;
+}
+
+static DWORD _normalize_altgr_control_key_state(
+    const KEY_EVENT_RECORD* const key_event) {
+    DWORD control_key_state = key_event->dwControlKeyState;
+
+    // If we're in an AltGr situation where the AltGr key is down (depending on
+    // the keyboard layout, that might be the physical right alt key which
+    // produces a control_key_state where Right-Alt and Left-Ctrl are down) or
+    // AltGr-equivalent keys are down (any Ctrl key + any Alt key), and we have
+    // a character (which indicates that there was an AltGr mapping), then act
+    // as if alt and control are not really down for the purposes of modifiers.
+    // This makes it so that if the user with, say, a German keyboard layout
+    // presses AltGr-] (which we see as Right-Alt + Left-Ctrl + key), we just
+    // output the key and we don't see the Alt and Ctrl keys.
+    if (_is_ctrl_pressed(control_key_state) &&
+        _is_alt_pressed(control_key_state)
+        && (key_event->uChar.AsciiChar != '\0')) {
+        // Try to remove as few bits as possible to improve our chances of
+        // detecting combinations like Left-Alt + AltGr, Right-Ctrl + AltGr, or
+        // Left-Alt + Right-Ctrl + AltGr.
+        if ((control_key_state & RIGHT_ALT_PRESSED) != 0) {
+            // Remove Right-Alt.
+            control_key_state &= ~RIGHT_ALT_PRESSED;
+            // If uChar is set, a Ctrl key is pressed, and Right-Alt is
+            // pressed, Left-Ctrl is almost always set, except if the user
+            // presses Right-Ctrl, then AltGr (in that specific order) for
+            // whatever reason. At any rate, make sure the bit is not set.
+            control_key_state &= ~LEFT_CTRL_PRESSED;
+        } else if ((control_key_state & LEFT_ALT_PRESSED) != 0) {
+            // Remove Left-Alt.
+            control_key_state &= ~LEFT_ALT_PRESSED;
+            // Whichever Ctrl key is down, remove it from the state. We only
+            // remove one key, to improve our chances of detecting the
+            // corner-case of Left-Ctrl + Left-Alt + Right-Ctrl.
+            if ((control_key_state & LEFT_CTRL_PRESSED) != 0) {
+                // Remove Left-Ctrl.
+                control_key_state &= ~LEFT_CTRL_PRESSED;
+            } else if ((control_key_state & RIGHT_CTRL_PRESSED) != 0) {
+                // Remove Right-Ctrl.
+                control_key_state &= ~RIGHT_CTRL_PRESSED;
+            }
+        }
+
+        // Note that this logic isn't 100% perfect because Windows doesn't
+        // allow us to detect all combinations because a physical AltGr key
+        // press shows up as two bits, plus some combinations are ambiguous
+        // about what is actually physically pressed.
+    }
+
+    return control_key_state;
+}
+
+// If NumLock is on and Shift is pressed, SHIFT_PRESSED is not set in
+// dwControlKeyState for the following keypad keys: period, 0-9. If we detect
+// this scenario, set the SHIFT_PRESSED bit so we can add modifiers
+// appropriately.
+static DWORD _normalize_keypad_control_key_state(const WORD vk,
+    const DWORD control_key_state) {
+    if (!_is_numlock_on(control_key_state)) {
+        return control_key_state;
+    }
+    if (!_is_enhanced_key(control_key_state)) {
+        switch (vk) {
+            case VK_INSERT: // 0
+            case VK_DELETE: // .
+            case VK_END:    // 1
+            case VK_DOWN:   // 2
+            case VK_NEXT:   // 3
+            case VK_LEFT:   // 4
+            case VK_CLEAR:  // 5
+            case VK_RIGHT:  // 6
+            case VK_HOME:   // 7
+            case VK_UP:     // 8
+            case VK_PRIOR:  // 9
+                return control_key_state | SHIFT_PRESSED;
+        }
+    }
+
+    return control_key_state;
+}
+
+static const char* _get_keypad_sequence(const DWORD control_key_state,
+    const char* const normal, const char* const shifted) {
+    if (_is_shift_pressed(control_key_state)) {
+        // Shift is pressed and NumLock is off
+        return shifted;
+    } else {
+        // Shift is not pressed and NumLock is off, or,
+        // Shift is pressed and NumLock is on, in which case we want the
+        // NumLock and Shift to neutralize each other, thus, we want the normal
+        // sequence.
+        return normal;
+    }
+    // If Shift is not pressed and NumLock is on, a different virtual key code
+    // is returned by Windows, which can be taken care of by a different case
+    // statement in _console_read().
+}
+
+// Write sequence to buf and return the number of bytes written.
+static size_t _get_modifier_sequence(char* const buf, const WORD vk,
+    DWORD control_key_state, const char* const normal) {
+    // Copy the base sequence into buf.
+    const size_t len = strlen(normal);
+    memcpy(buf, normal, len);
+
+    int code = 0;
+
+    control_key_state = _normalize_keypad_control_key_state(vk,
+        control_key_state);
+
+    if (_is_shift_pressed(control_key_state)) {
+        code |= 0x1;
+    }
+    if (_is_alt_pressed(control_key_state)) {   // any alt key pressed
+        code |= 0x2;
+    }
+    if (_is_ctrl_pressed(control_key_state)) {  // any control key pressed
+        code |= 0x4;
+    }
+    // If some modifier was held down, then we need to insert the modifier code
+    if (code != 0) {
+        if (len == 0) {
+            // Should be impossible because caller should pass a string of
+            // non-zero length.
+            return 0;
+        }
+        size_t index = len - 1;
+        const char lastChar = buf[index];
+        if (lastChar != '~') {
+            buf[index++] = '1';
+        }
+        buf[index++] = ';';         // modifier separator
+        // 2 = shift, 3 = alt, 4 = shift & alt, 5 = control,
+        // 6 = shift & control, 7 = alt & control, 8 = shift & alt & control
+        buf[index++] = '1' + code;
+        buf[index++] = lastChar;    // move ~ (or other last char) to the end
+        return index;
+    }
+    return len;
+}
+
+// Write sequence to buf and return the number of bytes written.
+static size_t _get_modifier_keypad_sequence(char* const buf, const WORD vk,
+    const DWORD control_key_state, const char* const normal,
+    const char shifted) {
+    if (_is_shift_pressed(control_key_state)) {
+        // Shift is pressed and NumLock is off
+        if (shifted != '\0') {
+            buf[0] = shifted;
+            return sizeof(buf[0]);
+        } else {
+            return 0;
+        }
+    } else {
+        // Shift is not pressed and NumLock is off, or,
+        // Shift is pressed and NumLock is on, in which case we want the
+        // NumLock and Shift to neutralize each other, thus, we want the normal
+        // sequence.
+        return _get_modifier_sequence(buf, vk, control_key_state, normal);
+    }
+    // If Shift is not pressed and NumLock is on, a different virtual key code
+    // is returned by Windows, which can be taken care of by a different case
+    // statement in _console_read().
+}
+
+// The decimal key on the keypad produces a '.' for U.S. English and a ',' for
+// Standard German. Figure this out at runtime so we know what to output for
+// Shift-VK_DELETE.
+static char _get_decimal_char() {
+    return (char)MapVirtualKeyA(VK_DECIMAL, MAPVK_VK_TO_CHAR);
+}
+
+// Prefix the len bytes in buf with the escape character, and then return the
+// new buffer length.
+size_t _escape_prefix(char* const buf, const size_t len) {
+    // If nothing to prefix, don't do anything. We might be called with
+    // len == 0, if alt was held down with a dead key which produced nothing.
+    if (len == 0) {
+        return 0;
+    }
+
+    memmove(&buf[1], buf, len);
+    buf[0] = '\x1b';
+    return len + 1;
+}
+
+// Writes to buffer buf (of length len), returning number of bytes written or
+// -1 on error. Never returns zero because Win32 consoles are never 'closed'
+// (as far as I can tell).
+static int _console_read(const HANDLE console, void* buf, size_t len) {
+    for (;;) {
+        KEY_EVENT_RECORD* const key_event = _get_key_event_record(console);
+        if (key_event == NULL) {
+            return -1;
+        }
+
+        const WORD vk = key_event->wVirtualKeyCode;
+        const CHAR ch = key_event->uChar.AsciiChar;
+        const DWORD control_key_state = _normalize_altgr_control_key_state(
+            key_event);
+
+        // The following emulation code should write the output sequence to
+        // either seqstr or to seqbuf and seqbuflen.
+        const char* seqstr = NULL;  // NULL terminated C-string
+        // Enough space for max sequence string below, plus modifiers and/or
+        // escape prefix.
+        char seqbuf[16];
+        size_t seqbuflen = 0;       // Space used in seqbuf.
+
+#define MATCH(vk, normal) \
+            case (vk): \
+            { \
+                seqstr = (normal); \
+            } \
+            break;
+
+        // Modifier keys should affect the output sequence.
+#define MATCH_MODIFIER(vk, normal) \
+            case (vk): \
+            { \
+                seqbuflen = _get_modifier_sequence(seqbuf, (vk), \
+                    control_key_state, (normal)); \
+            } \
+            break;
+
+        // The shift key should affect the output sequence.
+#define MATCH_KEYPAD(vk, normal, shifted) \
+            case (vk): \
+            { \
+                seqstr = _get_keypad_sequence(control_key_state, (normal), \
+                    (shifted)); \
+            } \
+            break;
+
+        // The shift key and other modifier keys should affect the output
+        // sequence.
+#define MATCH_MODIFIER_KEYPAD(vk, normal, shifted) \
+            case (vk): \
+            { \
+                seqbuflen = _get_modifier_keypad_sequence(seqbuf, (vk), \
+                    control_key_state, (normal), (shifted)); \
+            } \
+            break;
+
+#define ESC "\x1b"
+#define CSI ESC "["
+#define SS3 ESC "O"
+
+        // Only support normal mode, not application mode.
+
+        // Enhanced keys:
+        // * 6-pack: insert, delete, home, end, page up, page down
+        // * cursor keys: up, down, right, left
+        // * keypad: divide, enter
+        // * Undocumented: VK_PAUSE (Ctrl-NumLock), VK_SNAPSHOT,
+        //   VK_CANCEL (Ctrl-Pause/Break), VK_NUMLOCK
+        if (_is_enhanced_key(control_key_state)) {
+            switch (vk) {
+                case VK_RETURN: // Enter key on keypad
+                    if (_is_ctrl_pressed(control_key_state)) {
+                        seqstr = "\n";
+                    } else {
+                        seqstr = "\r";
+                    }
+                    break;
+
+                MATCH_MODIFIER(VK_PRIOR, CSI "5~"); // Page Up
+                MATCH_MODIFIER(VK_NEXT,  CSI "6~"); // Page Down
+
+                // gnome-terminal currently sends SS3 "F" and SS3 "H", but that
+                // will be fixed soon to match xterm which sends CSI "F" and
+                // CSI "H". https://bugzilla.redhat.com/show_bug.cgi?id=1119764
+                MATCH(VK_END,  CSI "F");
+                MATCH(VK_HOME, CSI "H");
+
+                MATCH_MODIFIER(VK_LEFT,  CSI "D");
+                MATCH_MODIFIER(VK_UP,    CSI "A");
+                MATCH_MODIFIER(VK_RIGHT, CSI "C");
+                MATCH_MODIFIER(VK_DOWN,  CSI "B");
+
+                MATCH_MODIFIER(VK_INSERT, CSI "2~");
+                MATCH_MODIFIER(VK_DELETE, CSI "3~");
+
+                MATCH(VK_DIVIDE, "/");
+            }
+        } else {    // Non-enhanced keys:
+            switch (vk) {
+                case VK_BACK:   // backspace
+                    if (_is_alt_pressed(control_key_state)) {
+                        seqstr = ESC "\x7f";
+                    } else {
+                        seqstr = "\x7f";
+                    }
+                    break;
+
+                case VK_TAB:
+                    if (_is_shift_pressed(control_key_state)) {
+                        seqstr = CSI "Z";
+                    } else {
+                        seqstr = "\t";
+                    }
+                    break;
+
+                // Number 5 key in keypad when NumLock is off, or if NumLock is
+                // on and Shift is down.
+                MATCH_KEYPAD(VK_CLEAR, CSI "E", "5");
+
+                case VK_RETURN:     // Enter key on main keyboard
+                    if (_is_alt_pressed(control_key_state)) {
+                        seqstr = ESC "\n";
+                    } else if (_is_ctrl_pressed(control_key_state)) {
+                        seqstr = "\n";
+                    } else {
+                        seqstr = "\r";
+                    }
+                    break;
+
+                // VK_ESCAPE: Don't do any special handling. The OS uses many
+                // of the sequences with Escape and many of the remaining
+                // sequences don't produce bKeyDown messages, only !bKeyDown
+                // for whatever reason.
+
+                case VK_SPACE:
+                    if (_is_alt_pressed(control_key_state)) {
+                        seqstr = ESC " ";
+                    } else if (_is_ctrl_pressed(control_key_state)) {
+                        seqbuf[0] = '\0';   // NULL char
+                        seqbuflen = 1;
+                    } else {
+                        seqstr = " ";
+                    }
+                    break;
+
+                MATCH_MODIFIER_KEYPAD(VK_PRIOR, CSI "5~", '9'); // Page Up
+                MATCH_MODIFIER_KEYPAD(VK_NEXT,  CSI "6~", '3'); // Page Down
+
+                MATCH_KEYPAD(VK_END,  CSI "4~", "1");
+                MATCH_KEYPAD(VK_HOME, CSI "1~", "7");
+
+                MATCH_MODIFIER_KEYPAD(VK_LEFT,  CSI "D", '4');
+                MATCH_MODIFIER_KEYPAD(VK_UP,    CSI "A", '8');
+                MATCH_MODIFIER_KEYPAD(VK_RIGHT, CSI "C", '6');
+                MATCH_MODIFIER_KEYPAD(VK_DOWN,  CSI "B", '2');
+
+                MATCH_MODIFIER_KEYPAD(VK_INSERT, CSI "2~", '0');
+                MATCH_MODIFIER_KEYPAD(VK_DELETE, CSI "3~",
+                    _get_decimal_char());
+
+                case 0x30:          // 0
+                case 0x31:          // 1
+                case 0x39:          // 9
+                case VK_OEM_1:      // ;:
+                case VK_OEM_PLUS:   // =+
+                case VK_OEM_COMMA:  // ,<
+                case VK_OEM_PERIOD: // .>
+                case VK_OEM_7:      // '"
+                case VK_OEM_102:    // depends on keyboard, could be <> or \|
+                case VK_OEM_2:      // /?
+                case VK_OEM_3:      // `~
+                case VK_OEM_4:      // [{
+                case VK_OEM_5:      // \|
+                case VK_OEM_6:      // ]}
+                {
+                    seqbuflen = _get_control_character(seqbuf, key_event,
+                        control_key_state);
+
+                    if (_is_alt_pressed(control_key_state)) {
+                        seqbuflen = _escape_prefix(seqbuf, seqbuflen);
+                    }
+                }
+                break;
+
+                case 0x32:          // 2
+                case 0x36:          // 6
+                case VK_OEM_MINUS:  // -_
+                {
+                    seqbuflen = _get_control_character(seqbuf, key_event,
+                        control_key_state);
+
+                    // If Alt is pressed and it isn't Ctrl-Alt-ShiftUp, then
+                    // prefix with escape.
+                    if (_is_alt_pressed(control_key_state) &&
+                        !(_is_ctrl_pressed(control_key_state) &&
+                        !_is_shift_pressed(control_key_state))) {
+                        seqbuflen = _escape_prefix(seqbuf, seqbuflen);
+                    }
+                }
+                break;
+
+                case 0x33:  // 3
+                case 0x34:  // 4
+                case 0x35:  // 5
+                case 0x37:  // 7
+                case 0x38:  // 8
+                {
+                    seqbuflen = _get_control_character(seqbuf, key_event,
+                        control_key_state);
+
+                    // If Alt is pressed and it isn't Ctrl-Alt-ShiftUp, then
+                    // prefix with escape.
+                    if (_is_alt_pressed(control_key_state) &&
+                        !(_is_ctrl_pressed(control_key_state) &&
+                        !_is_shift_pressed(control_key_state))) {
+                        seqbuflen = _escape_prefix(seqbuf, seqbuflen);
+                    }
+                }
+                break;
+
+                case 0x41:  // a
+                case 0x42:  // b
+                case 0x43:  // c
+                case 0x44:  // d
+                case 0x45:  // e
+                case 0x46:  // f
+                case 0x47:  // g
+                case 0x48:  // h
+                case 0x49:  // i
+                case 0x4a:  // j
+                case 0x4b:  // k
+                case 0x4c:  // l
+                case 0x4d:  // m
+                case 0x4e:  // n
+                case 0x4f:  // o
+                case 0x50:  // p
+                case 0x51:  // q
+                case 0x52:  // r
+                case 0x53:  // s
+                case 0x54:  // t
+                case 0x55:  // u
+                case 0x56:  // v
+                case 0x57:  // w
+                case 0x58:  // x
+                case 0x59:  // y
+                case 0x5a:  // z
+                {
+                    seqbuflen = _get_non_alt_char(seqbuf, key_event,
+                        control_key_state);
+
+                    // If Alt is pressed, then prefix with escape.
+                    if (_is_alt_pressed(control_key_state)) {
+                        seqbuflen = _escape_prefix(seqbuf, seqbuflen);
+                    }
+                }
+                break;
+
+                // These virtual key codes are generated by the keys on the
+                // keypad *when NumLock is on* and *Shift is up*.
+                MATCH(VK_NUMPAD0, "0");
+                MATCH(VK_NUMPAD1, "1");
+                MATCH(VK_NUMPAD2, "2");
+                MATCH(VK_NUMPAD3, "3");
+                MATCH(VK_NUMPAD4, "4");
+                MATCH(VK_NUMPAD5, "5");
+                MATCH(VK_NUMPAD6, "6");
+                MATCH(VK_NUMPAD7, "7");
+                MATCH(VK_NUMPAD8, "8");
+                MATCH(VK_NUMPAD9, "9");
+
+                MATCH(VK_MULTIPLY, "*");
+                MATCH(VK_ADD,      "+");
+                MATCH(VK_SUBTRACT, "-");
+                // VK_DECIMAL is generated by the . key on the keypad *when
+                // NumLock is on* and *Shift is up* and the sequence is not
+                // Ctrl-Alt-NoShift-. (which causes Ctrl-Alt-Del and the
+                // Windows Security screen to come up).
+                case VK_DECIMAL:
+                    // U.S. English uses '.', Germany German uses ','.
+                    seqbuflen = _get_non_control_char(seqbuf, key_event,
+                        control_key_state);
+                    break;
+
+                MATCH_MODIFIER(VK_F1,  SS3 "P");
+                MATCH_MODIFIER(VK_F2,  SS3 "Q");
+                MATCH_MODIFIER(VK_F3,  SS3 "R");
+                MATCH_MODIFIER(VK_F4,  SS3 "S");
+                MATCH_MODIFIER(VK_F5,  CSI "15~");
+                MATCH_MODIFIER(VK_F6,  CSI "17~");
+                MATCH_MODIFIER(VK_F7,  CSI "18~");
+                MATCH_MODIFIER(VK_F8,  CSI "19~");
+                MATCH_MODIFIER(VK_F9,  CSI "20~");
+                MATCH_MODIFIER(VK_F10, CSI "21~");
+                MATCH_MODIFIER(VK_F11, CSI "23~");
+                MATCH_MODIFIER(VK_F12, CSI "24~");
+
+                MATCH_MODIFIER(VK_F13, CSI "25~");
+                MATCH_MODIFIER(VK_F14, CSI "26~");
+                MATCH_MODIFIER(VK_F15, CSI "28~");
+                MATCH_MODIFIER(VK_F16, CSI "29~");
+                MATCH_MODIFIER(VK_F17, CSI "31~");
+                MATCH_MODIFIER(VK_F18, CSI "32~");
+                MATCH_MODIFIER(VK_F19, CSI "33~");
+                MATCH_MODIFIER(VK_F20, CSI "34~");
+
+                // MATCH_MODIFIER(VK_F21, ???);
+                // MATCH_MODIFIER(VK_F22, ???);
+                // MATCH_MODIFIER(VK_F23, ???);
+                // MATCH_MODIFIER(VK_F24, ???);
+            }
+        }
+
+#undef MATCH
+#undef MATCH_MODIFIER
+#undef MATCH_KEYPAD
+#undef MATCH_MODIFIER_KEYPAD
+#undef ESC
+#undef CSI
+#undef SS3
+
+        const char* out;
+        size_t outlen;
+
+        // Check for output in any of:
+        // * seqstr is set (and strlen can be used to determine the length).
+        // * seqbuf and seqbuflen are set
+        // Fallback to ch from Windows.
+        if (seqstr != NULL) {
+            out = seqstr;
+            outlen = strlen(seqstr);
+        } else if (seqbuflen > 0) {
+            out = seqbuf;
+            outlen = seqbuflen;
+        } else if (ch != '\0') {
+            // Use whatever Windows told us it is.
+            seqbuf[0] = ch;
+            seqbuflen = 1;
+            out = seqbuf;
+            outlen = seqbuflen;
+        } else {
+            // No special handling for the virtual key code and Windows isn't
+            // telling us a character code, then we don't know how to translate
+            // the key press.
+            //
+            // Consume the input and 'continue' to cause us to get a new key
+            // event.
+            D("_console_read: unknown virtual key code: %d, enhanced: %s\n",
+                vk, _is_enhanced_key(control_key_state) ? "true" : "false");
+            key_event->wRepeatCount = 0;
+            continue;
+        }
+
+        int bytesRead = 0;
+
+        // put output wRepeatCount times into buf/len
+        while (key_event->wRepeatCount > 0) {
+            if (len >= outlen) {
+                // Write to buf/len
+                memcpy(buf, out, outlen);
+                buf = (void*)((char*)buf + outlen);
+                len -= outlen;
+                bytesRead += outlen;
+
+                // consume the input
+                --key_event->wRepeatCount;
+            } else {
+                // Not enough space, so just leave it in _win32_input_record
+                // for a subsequent retrieval.
+                if (bytesRead == 0) {
+                    // We didn't write anything because there wasn't enough
+                    // space to even write one sequence. This should never
+                    // happen if the caller uses sensible buffer sizes
+                    // (i.e. >= maximum sequence length which is probably a
+                    // few bytes long).
+                    D("_console_read: no buffer space to write one sequence; "
+                        "buffer: %ld, sequence: %ld\n", (long)len,
+                        (long)outlen);
+                    errno = ENOMEM;
+                    return -1;
+                } else {
+                    // Stop trying to write to buf/len, just return whatever
+                    // we wrote so far.
+                    break;
+                }
+            }
+        }
+
+        return bytesRead;
+    }
+}
+
+static DWORD _old_console_mode; // previous GetConsoleMode() result
+static HANDLE _console_handle;  // when set, console mode should be restored
+
+void stdin_raw_init(const int fd) {
+    if (STDIN_FILENO == fd) {
+        const HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
+        if ((in == INVALID_HANDLE_VALUE) || (in == NULL)) {
+            return;
+        }
+
+        if (GetFileType(in) != FILE_TYPE_CHAR) {
+            // stdin might be a file or pipe.
+            return;
+        }
+
+        if (!GetConsoleMode(in, &_old_console_mode)) {
+            // If GetConsoleMode() fails, stdin is probably is not a console.
+            return;
+        }
+
+        // Disable ENABLE_PROCESSED_INPUT so that Ctrl-C is read instead of
+        // calling the process Ctrl-C routine (configured by
+        // SetConsoleCtrlHandler()).
+        // Disable ENABLE_LINE_INPUT so that input is immediately sent.
+        // Disable ENABLE_ECHO_INPUT to disable local echo. Disabling this
+        // flag also seems necessary to have proper line-ending processing.
+        if (!SetConsoleMode(in, _old_console_mode & ~(ENABLE_PROCESSED_INPUT |
+            ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT))) {
+            // This really should not fail.
+            D("stdin_raw_init: SetConsoleMode() failure, error %ld\n",
+                GetLastError());
+        }
+
+        // Once this is set, it means that stdin has been configured for
+        // reading from and that the old console mode should be restored later.
+        _console_handle = in;
+
+        // Note that we don't need to configure C Runtime line-ending
+        // translation because _console_read() does not call the C Runtime to
+        // read from the console.
+    }
+}
+
+void stdin_raw_restore(const int fd) {
+    if (STDIN_FILENO == fd) {
+        if (_console_handle != NULL) {
+            const HANDLE in = _console_handle;
+            _console_handle = NULL;  // clear state
+
+            if (!SetConsoleMode(in, _old_console_mode)) {
+                // This really should not fail.
+                D("stdin_raw_restore: SetConsoleMode() failure, error %ld\n",
+                    GetLastError());
+            }
+        }
+    }
+}
+
+// Called by 'adb shell' command to read from stdin.
+int unix_read(int fd, void* buf, size_t len) {
+    if ((fd == STDIN_FILENO) && (_console_handle != NULL)) {
+        // If it is a request to read from stdin, and stdin_raw_init() has been
+        // called, and it successfully configured the console, then read from
+        // the console using Win32 console APIs and partially emulate a unix
+        // terminal.
+        return _console_read(_console_handle, buf, len);
+    } else {
+        // Just call into C Runtime which can read from pipes/files and which
+        // can do LF/CR translation.
+#undef read
+        return read(fd, buf, len);
+    }
+}
diff --git a/adb/test_track_devices.c b/adb/test_track_devices.cpp
similarity index 100%
rename from adb/test_track_devices.c
rename to adb/test_track_devices.cpp
diff --git a/adb/test_track_jdwp.c b/adb/test_track_jdwp.cpp
similarity index 100%
rename from adb/test_track_jdwp.c
rename to adb/test_track_jdwp.cpp
diff --git a/adb/tests/test_adb.py b/adb/tests/test_adb.py
index 4b3baf3..f111b043 100755
--- a/adb/tests/test_adb.py
+++ b/adb/tests/test_adb.py
@@ -215,15 +215,13 @@
 
 
 class AdbBasic(unittest.TestCase):
-    def test_devices(self):
-        """Get uptime for each device plugged in from /proc/uptime."""
-        dev_list = get_device_list()
-        for device in dev_list:
-            out = call_checked(
-                "adb -s {} shell cat /proc/uptime".format(device))
-            self.assertEqual(len(out.split()), 2)
-            self.assertGreater(float(out.split()[0]), 0.0)
-            self.assertGreater(float(out.split()[1]), 0.0)
+    def test_shell(self):
+        """Check that we can at least cat a file."""
+        adb = AdbWrapper()
+        out = adb.shell("cat /proc/uptime")
+        self.assertEqual(len(out.split()), 2)
+        self.assertGreater(float(out.split()[0]), 0.0)
+        self.assertGreater(float(out.split()[1]), 0.0)
 
     def test_help(self):
         """Make sure we get _something_ out of help."""
@@ -239,16 +237,35 @@
                 version_num = True
         self.assertTrue(version_num)
 
+    def _test_root(self):
+        adb = AdbWrapper()
+        adb.root()
+        adb.wait()
+        self.assertEqual("root", adb.shell("id -un").strip())
+
+    def _test_unroot(self):
+        adb = AdbWrapper()
+        adb.unroot()
+        adb.wait()
+        self.assertEqual("shell", adb.shell("id -un").strip())
+
     def test_root_unroot(self):
         """Make sure that adb root and adb unroot work, using id(1)."""
-        for device in get_device_list():
-            adb = AdbWrapper(device)
-            adb.root()
+        adb = AdbWrapper()
+        original_user = adb.shell("id -un").strip()
+        try:
+            if original_user == "root":
+                self._test_unroot()
+                self._test_root()
+            elif original_user == "shell":
+                self._test_root()
+                self._test_unroot()
+        finally:
+            if original_user == "root":
+                adb.root()
+            else:
+                adb.unroot()
             adb.wait()
-            self.assertEqual("root", adb.shell("id -un").strip())
-            adb.unroot()
-            adb.wait()
-            self.assertEqual("shell", adb.shell("id -un").strip())
 
 
 class AdbFile(unittest.TestCase):
@@ -257,15 +274,9 @@
     DEVICE_TEMP_DIR = SCRATCH_DIR + "/adb_test_dir"
 
     def test_push(self):
-        """Push a file to all attached devices."""
-        dev_list = get_device_list()
-        for device in dev_list:
-            self.push_with_device(device)
-
-    def push_with_device(self, device):
         """Push a randomly generated file to specified device."""
         kbytes = 512
-        adb = AdbWrapper(device)
+        adb = AdbWrapper()
         with tempfile.NamedTemporaryFile(mode="w") as tmp:
             rand_str = os.urandom(1024 * kbytes)
             tmp.write(rand_str)
@@ -284,15 +295,9 @@
     # TODO: write push directory test.
 
     def test_pull(self):
-        """Pull a file from all attached devices."""
-        dev_list = get_device_list()
-        for device in dev_list:
-            self.pull_with_device(device)
-
-    def pull_with_device(self, device):
         """Pull a randomly generated file from specified device."""
         kbytes = 512
-        adb = AdbWrapper(device)
+        adb = AdbWrapper()
         adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_FILE))
         try:
             adb.shell("dd if=/dev/urandom of={} bs=1024 count={}".format(
@@ -310,14 +315,8 @@
             adb.shell_nocheck("rm {}".format(AdbFile.DEVICE_TEMP_FILE))
 
     def test_pull_dir(self):
-        """Pull a directory from all attached devices."""
-        dev_list = get_device_list()
-        for device in dev_list:
-            self.pull_dir_with_device(device)
-
-    def pull_dir_with_device(self, device):
         """Pull a randomly generated directory of files from the device."""
-        adb = AdbWrapper(device)
+        adb = AdbWrapper()
         temp_files = {}
         host_dir = None
         try:
@@ -350,15 +349,9 @@
                 os.removedirs(host_dir)
 
     def test_sync(self):
-        """Sync a directory with all attached devices."""
-        dev_list = get_device_list()
-        for device in dev_list:
-            self.sync_dir_with_device(device)
-
-    def sync_dir_with_device(self, device):
         """Sync a randomly generated directory of files to specified device."""
         try:
-            adb = AdbWrapper(device)
+            adb = AdbWrapper()
             temp_files = {}
 
             # create temporary host directory
@@ -373,7 +366,7 @@
                                                 num_files=32)
 
             # clean up any trash on the device
-            adb = AdbWrapper(device, out_dir=base_dir)
+            adb = AdbWrapper(out_dir=base_dir)
             adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_DIR))
 
             # issue the sync
diff --git a/adb/transport.c b/adb/transport.cpp
similarity index 89%
rename from adb/transport.c
rename to adb/transport.cpp
index ffe59da..4b9eeeb 100644
--- a/adb/transport.c
+++ b/adb/transport.cpp
@@ -14,15 +14,18 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
+#define TRACE_TAG TRACE_TRANSPORT
 
 #include "sysdeps.h"
+#include "transport.h"
 
-#define   TRACE_TAG  TRACE_TRANSPORT
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
 #include "adb.h"
 
 static void transport_unref(atransport *t);
@@ -41,7 +44,7 @@
 
 #if ADB_TRACE
 #define MAX_DUMP_HEX_LEN 16
-static void  dump_hex( const unsigned char*  ptr, size_t  len )
+void dump_hex(const unsigned char* ptr, size_t  len)
 {
     int  nn, len2 = len;
     // Build a string instead of logging each character.
@@ -67,8 +70,7 @@
 }
 #endif
 
-void
-kick_transport(atransport*  t)
+void kick_transport(atransport* t)
 {
     if (t && !t->kicked)
     {
@@ -85,8 +87,25 @@
     }
 }
 
-void
-run_transport_disconnects(atransport*  t)
+// Each atransport contains a list of adisconnects (t->disconnects).
+// An adisconnect contains a link to the next/prev adisconnect, a function
+// pointer to a disconnect callback which takes a void* piece of user data and
+// the atransport, and some user data for the callback (helpfully named
+// "opaque").
+//
+// The list is circular. New items are added to the entry member of the list
+// (t->disconnects) by add_transport_disconnect.
+//
+// run_transport_disconnects invokes each function in the list.
+//
+// Gotchas:
+//   * run_transport_disconnects assumes that t->disconnects is non-null, so
+//     this can't be run on a zeroed atransport.
+//   * The callbacks in this list are not removed when called, and this function
+//     is not guarded against running more than once. As such, ensure that this
+//     function is not called multiple times on the same atransport.
+//     TODO(danalbert): Just fix this so that it is guarded once you have tests.
+void run_transport_disconnects(atransport* t)
 {
     adisconnect*  dis = t->disconnects.next;
 
@@ -202,7 +221,7 @@
 
 static void transport_socket_events(int fd, unsigned events, void *_t)
 {
-    atransport *t = _t;
+    atransport *t = reinterpret_cast<atransport*>(_t);
     D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events);
     if(events & FDE_READ){
         apacket *p = 0;
@@ -259,7 +278,7 @@
 
 static void *output_thread(void *_t)
 {
-    atransport *t = _t;
+    atransport *t = reinterpret_cast<atransport*>(_t);
     apacket *p;
 
     D("%s: starting transport output thread on fd %d, SYNC online (%d)\n",
@@ -314,7 +333,7 @@
 
 static void *input_thread(void *_t)
 {
-    atransport *t = _t;
+    atransport *t = reinterpret_cast<atransport*>(_t);
     apacket *p;
     int active = 0;
 
@@ -475,7 +494,8 @@
 asocket*
 create_device_tracker(void)
 {
-    device_tracker*  tracker = calloc(1,sizeof(*tracker));
+    device_tracker* tracker = reinterpret_cast<device_tracker*>(
+        calloc(1, sizeof(*tracker)));
 
     if(tracker == 0) fatal("cannot allocate device tracker");
 
@@ -494,8 +514,7 @@
 
 
 /* call this function each time the transport list has changed */
-void  update_transports(void)
-{
+void update_transports(void) {
     char             buffer[1024];
     int              len;
     device_tracker*  tracker;
@@ -752,19 +771,8 @@
     dis->next = dis->prev = dis;
 }
 
-static int qual_char_is_invalid(char ch)
-{
-    if ('A' <= ch && ch <= 'Z')
-        return 0;
-    if ('a' <= ch && ch <= 'z')
-        return 0;
-    if ('0' <= ch && ch <= '9')
-        return 0;
-    return 1;
-}
-
 static int qual_match(const char *to_test,
-                      const char *prefix, const char *qual, int sanitize_qual)
+                      const char *prefix, const char *qual, bool sanitize_qual)
 {
     if (!to_test || !*to_test)
         /* Return true if both the qual and to_test are null strings. */
@@ -782,7 +790,7 @@
 
     while (*qual) {
         char ch = *qual++;
-        if (sanitize_qual && qual_char_is_invalid(ch))
+        if (sanitize_qual && !isalnum(ch))
             ch = '_';
         if (ch != *to_test++)
             return 0;
@@ -792,7 +800,8 @@
     return !*to_test;
 }
 
-atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out)
+atransport *acquire_one_transport(int state, transport_type ttype,
+                                  const char* serial, const char** error_out)
 {
     atransport *t;
     atransport *result = NULL;
@@ -814,9 +823,9 @@
         if (serial) {
             if ((t->serial && !strcmp(serial, t->serial)) ||
                 (t->devpath && !strcmp(serial, t->devpath)) ||
-                qual_match(serial, "product:", t->product, 0) ||
-                qual_match(serial, "model:", t->model, 1) ||
-                qual_match(serial, "device:", t->device, 0)) {
+                qual_match(serial, "product:", t->product, false) ||
+                qual_match(serial, "model:", t->model, true) ||
+                qual_match(serial, "device:", t->device, false)) {
                 if (result) {
                     if (error_out)
                         *error_out = "more than one device";
@@ -909,20 +918,17 @@
 }
 
 static void add_qual(char **buf, size_t *buf_size,
-                     const char *prefix, const char *qual, int sanitize_qual)
+                     const char *prefix, const char *qual, bool sanitize_qual)
 {
-    size_t len;
-    int prefix_len;
-
     if (!buf || !*buf || !buf_size || !*buf_size || !qual || !*qual)
         return;
 
-    len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual);
+    int prefix_len;
+    size_t len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual);
 
     if (sanitize_qual) {
-        char *cp;
-        for (cp = *buf + prefix_len; cp < *buf + len; cp++) {
-            if (qual_char_is_invalid(*cp))
+        for (char* cp = *buf + prefix_len; cp < *buf + len; cp++) {
+            if (!isalnum(*cp))
                 *cp = '_';
         }
     }
@@ -947,10 +953,10 @@
         remaining -= len;
         buf += len;
 
-        add_qual(&buf, &remaining, " ", t->devpath, 0);
-        add_qual(&buf, &remaining, " product:", t->product, 0);
-        add_qual(&buf, &remaining, " model:", t->model, 1);
-        add_qual(&buf, &remaining, " device:", t->device, 0);
+        add_qual(&buf, &remaining, " ", t->devpath, false);
+        add_qual(&buf, &remaining, " product:", t->product, false);
+        add_qual(&buf, &remaining, " model:", t->model, true);
+        add_qual(&buf, &remaining, " device:", t->device, false);
 
         len = snprintf(buf, remaining, "\n");
         remaining -= len;
@@ -1000,7 +1006,8 @@
 
 int register_socket_transport(int s, const char *serial, int port, int local)
 {
-    atransport *t = calloc(1, sizeof(atransport));
+    atransport *t = reinterpret_cast<atransport*>(
+        calloc(1, sizeof(atransport)));
     atransport *n;
     char buff[32];
 
@@ -1099,7 +1106,8 @@
 
 void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable)
 {
-    atransport *t = calloc(1, sizeof(atransport));
+    atransport *t = reinterpret_cast<atransport*>(
+        calloc(1, sizeof(atransport)));
     D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
       serial ? serial : "");
     init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
@@ -1138,74 +1146,6 @@
 #undef TRACE_TAG
 #define TRACE_TAG  TRACE_RWX
 
-int readx(int fd, void *ptr, size_t len)
-{
-    char *p = ptr;
-    int r;
-#if ADB_TRACE
-    size_t len0 = len;
-#endif
-    D("readx: fd=%d wanted=%zu\n", fd, len);
-    while(len > 0) {
-        r = adb_read(fd, p, len);
-        if(r > 0) {
-            len -= r;
-            p += r;
-        } else {
-            if (r < 0) {
-                D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno));
-                if (errno == EINTR)
-                    continue;
-            } else {
-                D("readx: fd=%d disconnected\n", fd);
-            }
-            return -1;
-        }
-    }
-
-#if ADB_TRACE
-    D("readx: fd=%d wanted=%zu got=%zu\n", fd, len0, len0 - len);
-    if (ADB_TRACING) {
-        dump_hex( ptr, len0 );
-    }
-#endif
-    return 0;
-}
-
-int writex(int fd, const void *ptr, size_t len)
-{
-    char *p = (char*) ptr;
-    int r;
-
-#if ADB_TRACE
-    D("writex: fd=%d len=%d: ", fd, (int)len);
-    if (ADB_TRACING) {
-        dump_hex( ptr, len );
-    }
-#endif
-    while(len > 0) {
-        r = adb_write(fd, p, len);
-        if(r > 0) {
-            len -= r;
-            p += r;
-        } else {
-            if (r < 0) {
-                D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno));
-                if (errno == EINTR)
-                    continue;
-                if (errno == EAGAIN) {
-                    adb_sleep_ms(1); // just yield some cpu time
-                    continue;
-                }
-            } else {
-                D("writex: fd=%d disconnected\n", fd);
-            }
-            return -1;
-        }
-    }
-    return 0;
-}
-
 int check_header(apacket *p)
 {
     if(p->msg.magic != (p->msg.command ^ 0xffffffff)) {
diff --git a/adb/transport.h b/adb/transport.h
index d95ad32..36a0e40 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -17,18 +17,62 @@
 #ifndef __TRANSPORT_H
 #define __TRANSPORT_H
 
+#include <stdbool.h>
 #include <sys/types.h>
 
+#include "adb.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/* convenience wrappers around read/write that will retry on
-** EINTR and/or short read/write.  Returns 0 on success, -1
-** on error or EOF.
+#if ADB_TRACE
+void dump_hex(const unsigned char* ptr, size_t  len);
+#endif
+
+/*
+ * Obtain a transport from the available transports.
+ * If state is != CS_ANY, only transports in that state are considered.
+ * If serial is non-NULL then only the device with that serial will be chosen.
+ * If no suitable transport is found, error is set.
+ */
+atransport* acquire_one_transport(int state, transport_type ttype,
+                                  const char* serial, const char** error_out);
+void add_transport_disconnect(atransport* t, adisconnect* dis);
+void remove_transport_disconnect(atransport* t, adisconnect* dis);
+void kick_transport(atransport* t);
+void run_transport_disconnects(atransport* t);
+void update_transports(void);
+
+/* transports are ref-counted
+** get_device_transport does an acquire on your behalf before returning
 */
-int readx(int fd, void *ptr, size_t len);
-int writex(int fd, const void *ptr, size_t len);
+void init_transport_registration(void);
+int list_transports(char* buf, size_t bufsize, int long_listing);
+atransport* find_transport(const char* serial);
+
+void register_usb_transport(usb_handle* h, const char* serial,
+                            const char* devpath, unsigned writeable);
+
+/* cause new transports to be init'd and added to the list */
+int register_socket_transport(int s, const char* serial, int port, int local);
+
+/* this should only be used for transports with connection_state == CS_NOPERM */
+void unregister_usb_transport(usb_handle* usb);
+
+/* these should only be used for the "adb disconnect" command */
+void unregister_transport(atransport* t);
+void unregister_all_tcp_transports();
+
+int check_header(apacket* p);
+int check_data(apacket* p);
+
+/* for MacOS X cleanup */
+void close_usb_devices();
+
+void send_packet(apacket* p, atransport* t);
+
+asocket* create_device_tracker(void);
 
 #ifdef __cplusplus
 }
diff --git a/adb/transport_local.c b/adb/transport_local.cpp
similarity index 97%
rename from adb/transport_local.c
rename to adb/transport_local.cpp
index 6c4e220..fe3c87f 100644
--- a/adb/transport_local.c
+++ b/adb/transport_local.cpp
@@ -14,19 +14,23 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_TRANSPORT
+
+#include "sysdeps.h"
+#include "transport.h"
+
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <errno.h>
-
-#include "sysdeps.h"
 #include <sys/types.h>
+
 #if !ADB_HOST
-#include <cutils/properties.h>
+#include "cutils/properties.h"
 #endif
 
-#define  TRACE_TAG  TRACE_TRANSPORT
 #include "adb.h"
+#include "adb_io.h"
 
 #if ADB_HOST
 /* we keep a list of opened transports. The atransport struct knows to which
@@ -42,7 +46,7 @@
 
 static int remote_read(apacket *p, atransport *t)
 {
-    if(readx(t->sfd, &p->msg, sizeof(amessage))){
+    if(!ReadFdExactly(t->sfd, &p->msg, sizeof(amessage))){
         D("remote local: read terminated (message)\n");
         return -1;
     }
@@ -52,7 +56,7 @@
         return -1;
     }
 
-    if(readx(t->sfd, p->data, p->msg.data_length)){
+    if(!ReadFdExactly(t->sfd, p->data, p->msg.data_length)){
         D("remote local: terminated (data)\n");
         return -1;
     }
@@ -69,7 +73,7 @@
 {
     int   length = p->msg.data_length;
 
-    if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) {
+    if(!WriteFdExactly(t->sfd, &p->msg, sizeof(amessage) + length)) {
         D("remote local: write terminated\n");
         return -1;
     }
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
new file mode 100644
index 0000000..2b3fe3c
--- /dev/null
+++ b/adb/transport_test.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#include "transport.h"
+
+#include <gtest/gtest.h>
+
+#include "adb.h"
+
+TEST(transport, kick_transport) {
+  atransport t = {};
+  // Mutate some member so we can test that the function is run.
+  t.kick = [](atransport* trans) { trans->fd = 42; };
+  atransport expected = t;
+  expected.fd = 42;
+  expected.kicked = 1;
+  kick_transport(&t);
+  ASSERT_EQ(42, t.fd);
+  ASSERT_EQ(1, t.kicked);
+  ASSERT_EQ(0, memcmp(&expected, &t, sizeof(atransport)));
+}
+
+TEST(transport, kick_transport_already_kicked) {
+  // Ensure that the transport is not modified if the transport has already been
+  // kicked.
+  atransport t = {};
+  t.kicked = 1;
+  t.kick = [](atransport*) { FAIL() << "Kick should not have been called"; };
+  atransport expected = t;
+  kick_transport(&t);
+  ASSERT_EQ(0, memcmp(&expected, &t, sizeof(atransport)));
+}
+
+// Disabled because the function currently segfaults for a zeroed atransport. I
+// want to make sure I understand how this is working at all before I try fixing
+// that.
+TEST(transport, DISABLED_run_transport_disconnects_zeroed_atransport) {
+  atransport t = {};
+  run_transport_disconnects(&t);
+}
diff --git a/adb/transport_usb.c b/adb/transport_usb.cpp
similarity index 96%
rename from adb/transport_usb.c
rename to adb/transport_usb.cpp
index 1138ddd..cdabffe 100644
--- a/adb/transport_usb.c
+++ b/adb/transport_usb.cpp
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_TRANSPORT
+
+#include "sysdeps.h"
+#include "transport.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include <sysdeps.h>
-
-#define  TRACE_TAG  TRACE_TRANSPORT
 #include "adb.h"
 
 static int remote_read(apacket *p, atransport *t)
diff --git a/adb/usb_linux.c b/adb/usb_linux.cpp
similarity index 97%
rename from adb/usb_linux.c
rename to adb/usb_linux.cpp
index 7d13a5d..6fd2b40 100644
--- a/adb/usb_linux.c
+++ b/adb/usb_linux.cpp
@@ -14,33 +14,31 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
+#define TRACE_TAG TRACE_USB
 
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <errno.h>
+#include "sysdeps.h"
+
 #include <ctype.h>
-
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/version.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
 #include <linux/usb/ch9.h>
 #else
 #include <linux/usb_ch9.h>
 #endif
-#include <asm/byteorder.h>
 
-#include "sysdeps.h"
-
-#define   TRACE_TAG  TRACE_USB
 #include "adb.h"
-
+#include "transport.h"
 
 /* usb scan debugging is waaaay too verbose */
 #define DBGX(x...)
@@ -379,6 +377,7 @@
     struct usbdevfs_urb *out = NULL;
     int res;
 
+    D("++ usb_bulk_read ++\n");
     memset(urb, 0, sizeof(*urb));
     urb->type = USBDEVFS_URB_TYPE_BULK;
     urb->endpoint = h->ep_in;
@@ -441,6 +440,7 @@
     }
 fail:
     adb_mutex_unlock(&h->lock);
+    D("-- usb_bulk_read --\n");
     return res;
 }
 
@@ -451,6 +451,7 @@
     int n;
     int need_zero = 0;
 
+    D("++ usb_write ++\n");
     if(h->zero_mask) {
             /* if we need 0-markers and our transfer
             ** is an even multiple of the packet size,
@@ -480,6 +481,7 @@
         return n;
     }
 
+    D("-- usb_write --\n");
     return 0;
 }
 
@@ -554,7 +556,7 @@
 
 int usb_close(usb_handle *h)
 {
-    D("[ usb close ... ]\n");
+    D("++ usb close ++\n");
     adb_mutex_lock(&usb_lock);
     h->next->prev = h->prev;
     h->prev->next = h->next;
@@ -562,7 +564,7 @@
     h->next = 0;
 
     adb_close(h->desc);
-    D("[ usb closed %p (fd = %d) ]\n", h, h->desc);
+    D("-- usb closed %p (fd = %d) --\n", h, h->desc);
     adb_mutex_unlock(&usb_lock);
 
     free(h);
@@ -573,7 +575,6 @@
                             unsigned char ep_in, unsigned char ep_out,
                             int interface, int serial_index, unsigned zero_mask)
 {
-    usb_handle* usb = 0;
     int n = 0;
     char serial[256];
 
@@ -586,8 +587,9 @@
         ** name, we have no further work to do.
         */
     adb_mutex_lock(&usb_lock);
-    for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
-        if(!strcmp(usb->fname, dev_name)) {
+    for (usb_handle* usb = handle_list.next; usb != &handle_list;
+         usb = usb->next) {
+        if (!strcmp(usb->fname, dev_name)) {
             adb_mutex_unlock(&usb_lock);
             return;
         }
@@ -596,7 +598,8 @@
 
     D("[ usb located new device %s (%d/%d/%d) ]\n",
         dev_name, ep_in, ep_out, interface);
-    usb = calloc(1, sizeof(usb_handle));
+    usb_handle* usb = reinterpret_cast<usb_handle*>(
+        calloc(1, sizeof(usb_handle)));
     strcpy(usb->fname, dev_name);
     usb->ep_in = ep_in;
     usb->ep_out = ep_out;
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c
index ee6b37c..434451c 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.c
@@ -14,22 +14,23 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-#include <linux/usb/ch9.h>
-#include <linux/usb/functionfs.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <errno.h>
+#define TRACE_TAG TRACE_USB
 
 #include "sysdeps.h"
 
-#define   TRACE_TAG  TRACE_USB
+#include <dirent.h>
+#include <errno.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/functionfs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
 #include "adb.h"
+#include "transport.h"
 
 #define MAX_PACKET_SIZE_FS	64
 #define MAX_PACKET_SIZE_HS	512
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index ba157f1..94c8cfe 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_USB
+
+#include "sysdeps.h"
+
 #include <CoreFoundation/CoreFoundation.h>
 
 #include <IOKit/IOKitLib.h>
@@ -22,12 +26,10 @@
 #include <IOKit/IOMessage.h>
 #include <mach/mach_port.h>
 
-#include "sysdeps.h"
-
 #include <stdio.h>
 
-#define TRACE_TAG   TRACE_USB
 #include "adb.h"
+#include "transport.h"
 
 #define  DBG   D
 
diff --git a/adb/usb_windows.c b/adb/usb_windows.cpp
similarity index 98%
rename from adb/usb_windows.c
rename to adb/usb_windows.cpp
index a2d7226..d2bd58c 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.cpp
@@ -14,19 +14,21 @@
  * limitations under the License.
  */
 
-#include <winsock2.h>
-#include <windows.h>
-#include <winerror.h>
-#include <errno.h>
-#include <usb100.h>
-#include <adb_api.h>
-#include <stdio.h>
-#include <stdlib.h>
+#define TRACE_TAG TRACE_USB
 
 #include "sysdeps.h"
 
-#define   TRACE_TAG  TRACE_USB
+#include <winsock2.h>  // winsock.h *must* be included before windows.h.
+#include <adb_api.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <usb100.h>
+#include <windows.h>
+#include <winerror.h>
+
 #include "adb.h"
+#include "transport.h"
 
 /** Structure usb_handle describes our connection to the usb device via
   AdbWinApi.dll. This structure is returned from usb_open() routine and
diff --git a/adf/libadf/Android.mk b/adf/libadf/Android.mk
index 908aa6c..7df354b 100644
--- a/adf/libadf/Android.mk
+++ b/adf/libadf/Android.mk
@@ -18,6 +18,7 @@
 LOCAL_SRC_FILES := adf.c
 LOCAL_MODULE := libadf
 LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS += -Werror
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
 include $(BUILD_STATIC_LIBRARY)
diff --git a/adf/libadf/tests/Android.mk b/adf/libadf/tests/Android.mk
index 93efafa..68e5817 100644
--- a/adf/libadf/tests/Android.mk
+++ b/adf/libadf/tests/Android.mk
@@ -19,4 +19,5 @@
 LOCAL_SRC_FILES := adf_test.cpp
 LOCAL_MODULE := adf-unit-tests
 LOCAL_STATIC_LIBRARIES := libadf
+LOCAL_CFLAGS += -Werror
 include $(BUILD_NATIVE_TEST)
diff --git a/adf/libadf/tests/adf_test.cpp b/adf/libadf/tests/adf_test.cpp
index d95330d..01b2785 100644
--- a/adf/libadf/tests/adf_test.cpp
+++ b/adf/libadf/tests/adf_test.cpp
@@ -182,9 +182,9 @@
     ASSERT_GE(err, 0) << "getting ADF device data failed: " << strerror(-err);
 
     EXPECT_LT(data.n_attachments, ADF_MAX_ATTACHMENTS);
-    EXPECT_GT(data.n_allowed_attachments, 0);
+    EXPECT_GT(data.n_allowed_attachments, 0U);
     EXPECT_LT(data.n_allowed_attachments, ADF_MAX_ATTACHMENTS);
-    EXPECT_LT(data.custom_data_size, ADF_MAX_CUSTOM_DATA_SIZE);
+    EXPECT_LT(data.custom_data_size, (size_t)ADF_MAX_CUSTOM_DATA_SIZE);
     adf_free_device_data(&data);
 }
 
@@ -195,8 +195,8 @@
     EXPECT_LT(data.type, ADF_INTF_TYPE_MAX);
     EXPECT_LE(data.dpms_state, DRM_MODE_DPMS_OFF);
     EXPECT_EQ(1, data.hotplug_detect);
-    EXPECT_GT(data.n_available_modes, 0);
-    EXPECT_LT(data.custom_data_size, ADF_MAX_CUSTOM_DATA_SIZE);
+    EXPECT_GT(data.n_available_modes, 0U);
+    EXPECT_LT(data.custom_data_size, (size_t)ADF_MAX_CUSTOM_DATA_SIZE);
     adf_free_interface_data(&data);
 }
 
@@ -206,9 +206,9 @@
     ASSERT_GE(err, 0) << "getting ADF overlay engine failed: " <<
             strerror(-err);
 
-    EXPECT_GT(data.n_supported_formats, 0);
+    EXPECT_GT(data.n_supported_formats, 0U);
     EXPECT_LT(data.n_supported_formats, ADF_MAX_SUPPORTED_FORMATS);
-    EXPECT_LT(data.custom_data_size, ADF_MAX_CUSTOM_DATA_SIZE);
+    EXPECT_LT(data.custom_data_size, (size_t)ADF_MAX_CUSTOM_DATA_SIZE);
     adf_free_overlay_engine_data(&data);
 }
 
diff --git a/adf/libadfhwc/Android.mk b/adf/libadfhwc/Android.mk
index acea322..898f9c9 100644
--- a/adf/libadfhwc/Android.mk
+++ b/adf/libadfhwc/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE := libadfhwc
 LOCAL_MODULE_TAGS := optional
 LOCAL_STATIC_LIBRARIES := libadf liblog libutils
-LOCAL_CFLAGS += -DLOG_TAG=\"adfhwc\"
+LOCAL_CFLAGS += -DLOG_TAG=\"adfhwc\" -Werror
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
 include $(BUILD_STATIC_LIBRARY)
diff --git a/base/.clang-format b/base/.clang-format
new file mode 100644
index 0000000..2b83a1f
--- /dev/null
+++ b/base/.clang-format
@@ -0,0 +1,11 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 2
+PointerAlignment: Left
+TabWidth: 2
+UseTab: Never
+PenaltyExcessCharacter: 32
diff --git a/base/Android.mk b/base/Android.mk
new file mode 100644
index 0000000..ad85c6b
--- /dev/null
+++ b/base/Android.mk
@@ -0,0 +1,109 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+libbase_src_files := \
+    file.cpp \
+    stringprintf.cpp \
+    strings.cpp \
+
+libbase_test_src_files := \
+    file_test.cpp \
+    stringprintf_test.cpp \
+    strings_test.cpp \
+    test_main.cpp \
+    test_utils.cpp \
+
+libbase_cppflags := \
+    -Wall \
+    -Wextra \
+    -Werror \
+
+# Device
+# ------------------------------------------------------------------------------
+include $(CLEAR_VARS)
+LOCAL_MODULE := libbase
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := $(libbase_src_files) logging.cpp
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CPPFLAGS := $(libbase_cppflags)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libcutils
+LOCAL_MULTILIB := both
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libbase
+LOCAL_CLANG := true
+LOCAL_WHOLE_STATIC_LIBRARIES := libbase
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_MULTILIB := both
+include $(BUILD_SHARED_LIBRARY)
+
+# Host
+# ------------------------------------------------------------------------------
+include $(CLEAR_VARS)
+LOCAL_MODULE := libbase
+LOCAL_SRC_FILES := $(libbase_src_files)
+ifneq ($(HOST_OS),windows)
+    LOCAL_SRC_FILES += logging.cpp
+endif
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CPPFLAGS := $(libbase_cppflags)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libcutils
+LOCAL_MULTILIB := both
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libbase
+LOCAL_WHOLE_STATIC_LIBRARIES := libbase
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libcutils
+LOCAL_MULTILIB := both
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+# Tests
+# ------------------------------------------------------------------------------
+include $(CLEAR_VARS)
+LOCAL_MODULE := libbase_test
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := $(libbase_test_src_files) logging_test.cpp
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+LOCAL_CPPFLAGS := $(libbase_cppflags)
+LOCAL_SHARED_LIBRARIES := libbase
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libbase_test
+LOCAL_SRC_FILES := $(libbase_test_src_files)
+ifneq ($(HOST_OS),windows)
+    LOCAL_SRC_FILES += logging_test.cpp
+endif
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+LOCAL_CPPFLAGS := $(libbase_cppflags)
+LOCAL_SHARED_LIBRARIES := libbase
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_HOST_NATIVE_TEST)
diff --git a/base/CPPLINT.cfg b/base/CPPLINT.cfg
new file mode 100644
index 0000000..d94a89c
--- /dev/null
+++ b/base/CPPLINT.cfg
@@ -0,0 +1,2 @@
+set noparent
+filter=-build/header_guard,-build/include,-build/c++11,-whitespace/operators
diff --git a/libutils/file.cpp b/base/file.cpp
similarity index 68%
rename from libutils/file.cpp
rename to base/file.cpp
index 0690bc2..a51c5ff 100644
--- a/libutils/file.cpp
+++ b/base/file.cpp
@@ -14,19 +14,24 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "utils.file"
-#include <cutils/log.h>
-
-#include "utils/file.h"
+#include "base/file.h"
 
 #include <errno.h>
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#include <utils/Compat.h> // For TEMP_FAILURE_RETRY on Darwin.
+#include <string>
 
-bool android::ReadFdToString(int fd, std::string* content) {
+#include "base/macros.h"  // For TEMP_FAILURE_RETRY on Darwin.
+#define LOG_TAG "base.file"
+#include "cutils/log.h"
+#include "utils/Compat.h"
+
+namespace android {
+namespace base {
+
+bool ReadFdToString(int fd, std::string* content) {
   content->clear();
 
   char buf[BUFSIZ];
@@ -37,10 +42,11 @@
   return (n == 0) ? true : false;
 }
 
-bool android::ReadFileToString(const std::string& path, std::string* content) {
+bool ReadFileToString(const std::string& path, std::string* content) {
   content->clear();
 
-  int fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
+  int fd =
+      TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
   if (fd == -1) {
     return false;
   }
@@ -49,7 +55,7 @@
   return result;
 }
 
-bool android::WriteStringToFd(const std::string& content, int fd) {
+bool WriteStringToFd(const std::string& content, int fd) {
   const char* p = content.data();
   size_t left = content.size();
   while (left > 0) {
@@ -72,18 +78,18 @@
 }
 
 #if !defined(_WIN32)
-bool android::WriteStringToFile(const std::string& content, const std::string& path,
-                                mode_t mode, uid_t owner, gid_t group) {
-  int fd = TEMP_FAILURE_RETRY(open(path.c_str(),
-                                   O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
-                                   mode));
+bool WriteStringToFile(const std::string& content, const std::string& path,
+                       mode_t mode, uid_t owner, gid_t group) {
+  int fd = TEMP_FAILURE_RETRY(
+      open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+           mode));
   if (fd == -1) {
     ALOGE("android::WriteStringToFile open failed: %s", strerror(errno));
     return false;
   }
 
-  // We do an explicit fchmod here because we assume that the caller really meant what they
-  // said and doesn't want the umask-influenced mode.
+  // We do an explicit fchmod here because we assume that the caller really
+  // meant what they said and doesn't want the umask-influenced mode.
   if (fchmod(fd, mode) == -1) {
     ALOGE("android::WriteStringToFile fchmod failed: %s", strerror(errno));
     return CleanUpAfterFailedWrite(path);
@@ -101,10 +107,10 @@
 }
 #endif
 
-bool android::WriteStringToFile(const std::string& content, const std::string& path) {
-  int fd = TEMP_FAILURE_RETRY(open(path.c_str(),
-                                   O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
-                                   DEFFILEMODE));
+bool WriteStringToFile(const std::string& content, const std::string& path) {
+  int fd = TEMP_FAILURE_RETRY(
+      open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+           DEFFILEMODE));
   if (fd == -1) {
     return false;
   }
@@ -113,3 +119,6 @@
   TEMP_FAILURE_RETRY(close(fd));
   return result || CleanUpAfterFailedWrite(path);
 }
+
+}  // namespace base
+}  // namespace android
diff --git a/libutils/tests/file_test.cpp b/base/file_test.cpp
similarity index 61%
rename from libutils/tests/file_test.cpp
rename to base/file_test.cpp
index cea18b6..fc48b32 100644
--- a/libutils/tests/file_test.cpp
+++ b/base/file_test.cpp
@@ -14,48 +14,29 @@
  * limitations under the License.
  */
 
-#include "utils/file.h"
+#include "base/file.h"
+
+#include <gtest/gtest.h>
 
 #include <errno.h>
 #include <fcntl.h>
 #include <unistd.h>
-#include <gtest/gtest.h>
 
-class TemporaryFile {
- public:
-  TemporaryFile() {
-    init("/data/local/tmp");
-    if (fd == -1) {
-      init("/tmp");
-    }
-  }
+#include <string>
 
-  ~TemporaryFile() {
-    close(fd);
-    unlink(filename);
-  }
-
-  int fd;
-  char filename[1024];
-
- private:
-  void init(const char* tmp_dir) {
-    snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir);
-    fd = mkstemp(filename);
-  }
-};
+#include "test_utils.h"
 
 TEST(file, ReadFileToString_ENOENT) {
   std::string s("hello");
   errno = 0;
-  ASSERT_FALSE(android::ReadFileToString("/proc/does-not-exist", &s));
+  ASSERT_FALSE(android::base::ReadFileToString("/proc/does-not-exist", &s));
   EXPECT_EQ(ENOENT, errno);
-  EXPECT_EQ("", s); // s was cleared.
+  EXPECT_EQ("", s);  // s was cleared.
 }
 
 TEST(file, ReadFileToString_success) {
   std::string s("hello");
-  ASSERT_TRUE(android::ReadFileToString("/proc/version", &s)) << errno;
+  ASSERT_TRUE(android::base::ReadFileToString("/proc/version", &s)) << errno;
   EXPECT_GT(s.length(), 6U);
   EXPECT_EQ('\n', s[s.length() - 1]);
   s[5] = 0;
@@ -65,34 +46,36 @@
 TEST(file, WriteStringToFile) {
   TemporaryFile tf;
   ASSERT_TRUE(tf.fd != -1);
-  ASSERT_TRUE(android::WriteStringToFile("abc", tf.filename)) << errno;
+  ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.filename)) << errno;
   std::string s;
-  ASSERT_TRUE(android::ReadFileToString(tf.filename, &s)) << errno;
+  ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s)) << errno;
   EXPECT_EQ("abc", s);
 }
 
 TEST(file, WriteStringToFile2) {
   TemporaryFile tf;
   ASSERT_TRUE(tf.fd != -1);
-  ASSERT_TRUE(android::WriteStringToFile("abc", tf.filename, 0660, getuid(), getgid())) << errno;
+  ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.filename, 0660,
+                                               getuid(), getgid()))
+      << errno;
   struct stat sb;
   ASSERT_EQ(0, stat(tf.filename, &sb));
   ASSERT_EQ(0660U, (sb.st_mode & ~S_IFMT));
   ASSERT_EQ(getuid(), sb.st_uid);
   ASSERT_EQ(getgid(), sb.st_gid);
   std::string s;
-  ASSERT_TRUE(android::ReadFileToString(tf.filename, &s)) << errno;
+  ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s)) << errno;
   EXPECT_EQ("abc", s);
 }
 
 TEST(file, WriteStringToFd) {
   TemporaryFile tf;
   ASSERT_TRUE(tf.fd != -1);
-  ASSERT_TRUE(android::WriteStringToFd("abc", tf.fd));
+  ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
 
   ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << errno;
 
   std::string s;
-  ASSERT_TRUE(android::ReadFdToString(tf.fd, &s)) << errno;
+  ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << errno;
   EXPECT_EQ("abc", s);
 }
diff --git a/include/utils/file.h b/base/include/base/file.h
similarity index 89%
rename from include/utils/file.h
rename to base/include/base/file.h
index a80afb1..ef97742 100644
--- a/include/utils/file.h
+++ b/base/include/base/file.h
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-#ifndef UTILS_FILE_H
-#define UTILS_FILE_H
+#ifndef BASE_FILE_H
+#define BASE_FILE_H
 
-#include <string>
 #include <sys/stat.h>
+#include <string>
 
 namespace android {
+namespace base {
 
 bool ReadFdToString(int fd, std::string* content);
 bool ReadFileToString(const std::string& path, std::string* content);
@@ -33,6 +34,7 @@
                        mode_t mode, uid_t owner, gid_t group);
 #endif
 
-} // namespace android
+}  // namespace base
+}  // namespace android
 
-#endif
+#endif  // BASE_FILE_H
diff --git a/base/include/base/logging.h b/base/include/base/logging.h
new file mode 100644
index 0000000..19c1b64
--- /dev/null
+++ b/base/include/base/logging.h
@@ -0,0 +1,309 @@
+/*
+ * 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.
+ */
+
+#ifndef BASE_LOGGING_H
+#define BASE_LOGGING_H
+
+#include <functional>
+#include <memory>
+#include <ostream>
+
+#include "base/macros.h"
+
+namespace android {
+namespace base {
+
+enum LogSeverity {
+  VERBOSE,
+  DEBUG,
+  INFO,
+  WARNING,
+  ERROR,
+  FATAL,
+};
+
+enum LogId {
+  DEFAULT,
+  MAIN,
+  SYSTEM,
+};
+
+typedef std::function<void(LogId, LogSeverity, const char*, const char*,
+                           unsigned int, const char*)> LogFunction;
+
+extern void StderrLogger(LogId, LogSeverity, const char*, const char*,
+                         unsigned int, const char*);
+
+#ifdef __ANDROID__
+// We expose this even though it is the default because a user that wants to
+// override the default log buffer will have to construct this themselves.
+class LogdLogger {
+ public:
+  explicit LogdLogger(LogId default_log_id = android::base::MAIN);
+
+  void operator()(LogId, LogSeverity, const char* tag, const char* file,
+                  unsigned int line, const char* message);
+
+ private:
+  LogId default_log_id_;
+};
+#endif
+
+// Configure logging based on ANDROID_LOG_TAGS environment variable.
+// We need to parse a string that looks like
+//
+//      *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i
+//
+// The tag (or '*' for the global level) comes first, followed by a colon and a
+// letter indicating the minimum priority level we're expected to log.  This can
+// be used to reveal or conceal logs with specific tags.
+extern void InitLogging(char* argv[], LogFunction&& logger);
+
+// Configures logging using the default logger (logd for the device, stderr for
+// the host).
+extern void InitLogging(char* argv[]);
+
+// Replace the current logger.
+extern void SetLogger(LogFunction&& logger);
+
+// Returns the command line used to invoke the current tool or nullptr if
+// InitLogging hasn't been performed.
+extern const char* GetCmdLine();
+
+// The command used to start the program, such as "/system/bin/dalvikvm". If
+// InitLogging hasn't been performed then just returns "unknown"
+extern const char* ProgramInvocationName();
+
+// A short version of the command used to start the program, such as "dalvikvm".
+// If InitLogging hasn't been performed then just returns "unknown"
+extern const char* ProgramInvocationShortName();
+
+// Logs a message to logcat on Android otherwise to stderr. If the severity is
+// FATAL it also causes an abort. For example:
+//
+//     LOG(FATAL) << "We didn't expect to reach here";
+#define LOG(severity)                                                       \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
+                              ::android::base::severity, -1).stream()
+
+// Logs a message to logcat with the specified log ID on Android otherwise to
+// stderr. If the severity is FATAL it also causes an abort.
+#define LOG_TO(dest, severity)                                           \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::dest, \
+                              ::android::base::severity, -1).stream()
+
+// A variant of LOG that also logs the current errno value. To be used when
+// library calls fail.
+#define PLOG(severity)                                                      \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
+                              ::android::base::severity, errno).stream()
+
+// Behaves like PLOG, but logs to the specified log ID.
+#define PLOG_TO(dest, severity)                                          \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::dest, \
+                              ::android::base::severity, errno).stream()
+
+// Marker that code is yet to be implemented.
+#define UNIMPLEMENTED(level) \
+  LOG(level) << __PRETTY_FUNCTION__ << " unimplemented "
+
+// Check whether condition x holds and LOG(FATAL) if not. The value of the
+// expression x is only evaluated once. Extra logging can be appended using <<
+// after. For example:
+//
+//     CHECK(false == true) results in a log message of
+//       "Check failed: false == true".
+#define CHECK(x)                                                            \
+  if (UNLIKELY(!(x)))                                                       \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
+                              ::android::base::FATAL, -1).stream()          \
+      << "Check failed: " #x << " "
+
+// Helper for CHECK_xx(x,y) macros.
+#define CHECK_OP(LHS, RHS, OP)                                              \
+  for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS);        \
+       UNLIKELY(!(_values.lhs OP _values.rhs));                             \
+       /* empty */)                                                         \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
+                              ::android::base::FATAL, -1).stream()          \
+      << "Check failed: " << #LHS << " " << #OP << " " << #RHS              \
+      << " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") "
+
+// Check whether a condition holds between x and y, LOG(FATAL) if not. The value
+// of the expressions x and y is evaluated once. Extra logging can be appended
+// using << after. For example:
+//
+//     CHECK_NE(0 == 1, false) results in
+//       "Check failed: false != false (0==1=false, false=false) ".
+#define CHECK_EQ(x, y) CHECK_OP(x, y, == )
+#define CHECK_NE(x, y) CHECK_OP(x, y, != )
+#define CHECK_LE(x, y) CHECK_OP(x, y, <= )
+#define CHECK_LT(x, y) CHECK_OP(x, y, < )
+#define CHECK_GE(x, y) CHECK_OP(x, y, >= )
+#define CHECK_GT(x, y) CHECK_OP(x, y, > )
+
+// Helper for CHECK_STRxx(s1,s2) macros.
+#define CHECK_STROP(s1, s2, sense)                                         \
+  if (UNLIKELY((strcmp(s1, s2) == 0) != sense))                            \
+    LOG(FATAL) << "Check failed: "                                         \
+               << "\"" << s1 << "\""                                       \
+               << (sense ? " == " : " != ") << "\"" << s2 << "\""
+
+// Check for string (const char*) equality between s1 and s2, LOG(FATAL) if not.
+#define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true)
+#define CHECK_STRNE(s1, s2) CHECK_STROP(s1, s2, false)
+
+// Perform the pthread function call(args), LOG(FATAL) on error.
+#define CHECK_PTHREAD_CALL(call, args, what)                           \
+  do {                                                                 \
+    int rc = call args;                                                \
+    if (rc != 0) {                                                     \
+      errno = rc;                                                      \
+      PLOG(FATAL) << #call << " failed for " << what; \
+    }                                                                  \
+  } while (false)
+
+// CHECK that can be used in a constexpr function. For example:
+//
+//    constexpr int half(int n) {
+//      return
+//          DCHECK_CONSTEXPR(n >= 0, , 0)
+//          CHECK_CONSTEXPR((n & 1) == 0),
+//              << "Extra debugging output: n = " << n, 0)
+//          n / 2;
+//    }
+#define CHECK_CONSTEXPR(x, out, dummy)                                     \
+  (UNLIKELY(!(x)))                                                         \
+      ? (LOG(FATAL) << "Check failed: " << #x out, dummy) \
+      :
+
+// DCHECKs are debug variants of CHECKs only enabled in debug builds. Generally
+// CHECK should be used unless profiling identifies a CHECK as being in
+// performance critical code.
+#if defined(NDEBUG)
+static constexpr bool kEnableDChecks = false;
+#else
+static constexpr bool kEnableDChecks = true;
+#endif
+
+#define DCHECK(x) \
+  if (::android::base::kEnableDChecks) CHECK(x)
+#define DCHECK_EQ(x, y) \
+  if (::android::base::kEnableDChecks) CHECK_EQ(x, y)
+#define DCHECK_NE(x, y) \
+  if (::android::base::kEnableDChecks) CHECK_NE(x, y)
+#define DCHECK_LE(x, y) \
+  if (::android::base::kEnableDChecks) CHECK_LE(x, y)
+#define DCHECK_LT(x, y) \
+  if (::android::base::kEnableDChecks) CHECK_LT(x, y)
+#define DCHECK_GE(x, y) \
+  if (::android::base::kEnableDChecks) CHECK_GE(x, y)
+#define DCHECK_GT(x, y) \
+  if (::android::base::kEnableDChecks) CHECK_GT(x, y)
+#define DCHECK_STREQ(s1, s2) \
+  if (::android::base::kEnableDChecks) CHECK_STREQ(s1, s2)
+#define DCHECK_STRNE(s1, s2) \
+  if (::android::base::kEnableDChecks) CHECK_STRNE(s1, s2)
+#if defined(NDEBUG)
+#define DCHECK_CONSTEXPR(x, out, dummy)
+#else
+#define DCHECK_CONSTEXPR(x, out, dummy) CHECK_CONSTEXPR(x, out, dummy)
+#endif
+
+// Temporary class created to evaluate the LHS and RHS, used with
+// MakeEagerEvaluator to infer the types of LHS and RHS.
+template <typename LHS, typename RHS>
+struct EagerEvaluator {
+  EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) {
+  }
+  LHS lhs;
+  RHS rhs;
+};
+
+// Helper function for CHECK_xx.
+template <typename LHS, typename RHS>
+static inline EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
+  return EagerEvaluator<LHS, RHS>(lhs, rhs);
+}
+
+// Explicitly instantiate EagerEvalue for pointers so that char*s aren't treated
+// as strings. To compare strings use CHECK_STREQ and CHECK_STRNE. We rely on
+// signed/unsigned warnings to protect you against combinations not explicitly
+// listed below.
+#define EAGER_PTR_EVALUATOR(T1, T2)               \
+  template <>                                     \
+  struct EagerEvaluator<T1, T2> {                 \
+    EagerEvaluator(T1 l, T2 r)                    \
+        : lhs(reinterpret_cast<const void*>(l)),  \
+          rhs(reinterpret_cast<const void*>(r)) { \
+    }                                             \
+    const void* lhs;                              \
+    const void* rhs;                              \
+  }
+EAGER_PTR_EVALUATOR(const char*, const char*);
+EAGER_PTR_EVALUATOR(const char*, char*);
+EAGER_PTR_EVALUATOR(char*, const char*);
+EAGER_PTR_EVALUATOR(char*, char*);
+EAGER_PTR_EVALUATOR(const unsigned char*, const unsigned char*);
+EAGER_PTR_EVALUATOR(const unsigned char*, unsigned char*);
+EAGER_PTR_EVALUATOR(unsigned char*, const unsigned char*);
+EAGER_PTR_EVALUATOR(unsigned char*, unsigned char*);
+EAGER_PTR_EVALUATOR(const signed char*, const signed char*);
+EAGER_PTR_EVALUATOR(const signed char*, signed char*);
+EAGER_PTR_EVALUATOR(signed char*, const signed char*);
+EAGER_PTR_EVALUATOR(signed char*, signed char*);
+
+// Data for the log message, not stored in LogMessage to avoid increasing the
+// stack size.
+class LogMessageData;
+
+// A LogMessage is a temporarily scoped object used by LOG and the unlikely part
+// of a CHECK. The destructor will abort if the severity is FATAL.
+class LogMessage {
+ public:
+  LogMessage(const char* file, unsigned int line, LogId id,
+             LogSeverity severity, int error);
+
+  ~LogMessage();
+
+  // Returns the stream associated with the message, the LogMessage performs
+  // output when it goes out of scope.
+  std::ostream& stream();
+
+  // The routine that performs the actual logging.
+  static void LogLine(const char* file, unsigned int line, LogId id,
+                      LogSeverity severity, const char* msg);
+
+ private:
+  const std::unique_ptr<LogMessageData> data_;
+
+  DISALLOW_COPY_AND_ASSIGN(LogMessage);
+};
+
+// Allows to temporarily change the minimum severity level for logging.
+class ScopedLogSeverity {
+ public:
+  explicit ScopedLogSeverity(LogSeverity level);
+  ~ScopedLogSeverity();
+
+ private:
+  LogSeverity old_;
+};
+
+}  // namespace base
+}  // namespace android
+
+#endif  // BASE_LOGGING_H
diff --git a/base/include/base/macros.h b/base/include/base/macros.h
new file mode 100644
index 0000000..b1ce7c6
--- /dev/null
+++ b/base/include/base/macros.h
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ */
+
+#ifndef UTILS_MACROS_H
+#define UTILS_MACROS_H
+
+#include <stddef.h>  // for size_t
+#include <unistd.h>  // for TEMP_FAILURE_RETRY
+
+// bionic and glibc both have TEMP_FAILURE_RETRY, but eg Mac OS' libc doesn't.
+#ifndef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(exp)            \
+  ({                                       \
+    decltype(exp) _rc;                     \
+    do {                                   \
+      _rc = (exp);                         \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc;                                   \
+  })
+#endif
+
+// A macro to disallow the copy constructor and operator= functions
+// This must be placed in the private: declarations for a class.
+//
+// For disallowing only assign or copy, delete the relevant operator or
+// constructor, for example:
+// void operator=(const TypeName&) = delete;
+// Note, that most uses of DISALLOW_ASSIGN and DISALLOW_COPY are broken
+// semantically, one should either use disallow both or neither. Try to
+// avoid these in new code.
+//
+// When building with C++11 toolchains, just use the language support
+// for explicitly deleted methods.
+#if __cplusplus >= 201103L
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&) = delete;      \
+  void operator=(const TypeName&) = delete
+#else
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&);               \
+  void operator=(const TypeName&)
+#endif
+
+// A macro to disallow all the implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+//
+// This should be used in the private: declarations for a class
+// that wants to prevent anyone from instantiating it. This is
+// especially useful for classes containing only static methods.
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+  TypeName();                                    \
+  DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+// The arraysize(arr) macro returns the # of elements in an array arr.
+// The expression is a compile-time constant, and therefore can be
+// used in defining new arrays, for example.  If you use arraysize on
+// a pointer by mistake, you will get a compile-time error.
+//
+// One caveat is that arraysize() doesn't accept any array of an
+// anonymous type or a type defined inside a function.  In these rare
+// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below.  This is
+// due to a limitation in C++'s template system.  The limitation might
+// eventually be removed, but it hasn't happened yet.
+
+// This template function declaration is used in defining arraysize.
+// Note that the function doesn't need an implementation, as we only
+// use its type.
+template <typename T, size_t N>
+char(&ArraySizeHelper(T(&array)[N]))[N];  // NOLINT(readability/casting)
+
+#define arraysize(array) (sizeof(ArraySizeHelper(array)))
+
+// ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize,
+// but can be used on anonymous types or types defined inside
+// functions.  It's less safe than arraysize as it accepts some
+// (although not all) pointers.  Therefore, you should use arraysize
+// whenever possible.
+//
+// The expression ARRAYSIZE_UNSAFE(a) is a compile-time constant of type
+// size_t.
+//
+// ARRAYSIZE_UNSAFE catches a few type errors.  If you see a compiler error
+//
+//   "warning: division by zero in ..."
+//
+// when using ARRAYSIZE_UNSAFE, you are (wrongfully) giving it a pointer.
+// You should only use ARRAYSIZE_UNSAFE on statically allocated arrays.
+//
+// The following comments are on the implementation details, and can
+// be ignored by the users.
+//
+// ARRAYSIZE_UNSAFE(arr) works by inspecting sizeof(arr) (the # of bytes in
+// the array) and sizeof(*(arr)) (the # of bytes in one array
+// element).  If the former is divisible by the latter, perhaps arr is
+// indeed an array, in which case the division result is the # of
+// elements in the array.  Otherwise, arr cannot possibly be an array,
+// and we generate a compiler error to prevent the code from
+// compiling.
+//
+// Since the size of bool is implementation-defined, we need to cast
+// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
+// result has type size_t.
+//
+// This macro is not perfect as it wrongfully accepts certain
+// pointers, namely where the pointer size is divisible by the pointee
+// size.  Since all our code has to go through a 32-bit compiler,
+// where a pointer is 4 bytes, this means all pointers to a type whose
+// size is 3 or greater than 4 will be (righteously) rejected.
+#define ARRAYSIZE_UNSAFE(a)     \
+  ((sizeof(a) / sizeof(*(a))) / \
+    static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+
+#define LIKELY(x) __builtin_expect((x), true)
+#define UNLIKELY(x) __builtin_expect((x), false)
+
+#define WARN_UNUSED __attribute__((warn_unused_result))
+
+// A deprecated function to call to create a false use of the parameter, for
+// example:
+//   int foo(int x) { UNUSED(x); return 10; }
+// to avoid compiler warnings. Going forward we prefer ATTRIBUTE_UNUSED.
+template <typename... T>
+void UNUSED(const T&...) {
+}
+
+// An attribute to place on a parameter to a function, for example:
+//   int foo(int x ATTRIBUTE_UNUSED) { return 10; }
+// to avoid compiler warnings.
+#define ATTRIBUTE_UNUSED __attribute__((__unused__))
+
+// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through
+// between switch labels:
+//  switch (x) {
+//    case 40:
+//    case 41:
+//      if (truth_is_out_there) {
+//        ++x;
+//        FALLTHROUGH_INTENDED;  // Use instead of/along with annotations in
+//                               // comments.
+//      } else {
+//        return x;
+//      }
+//    case 42:
+//      ...
+//
+//  As shown in the example above, the FALLTHROUGH_INTENDED macro should be
+//  followed by a semicolon. It is designed to mimic control-flow statements
+//  like 'break;', so it can be placed in most places where 'break;' can, but
+//  only if there are no statements on the execution path between it and the
+//  next switch label.
+//
+//  When compiled with clang in C++11 mode, the FALLTHROUGH_INTENDED macro is
+//  expanded to [[clang::fallthrough]] attribute, which is analysed when
+//  performing switch labels fall-through diagnostic ('-Wimplicit-fallthrough').
+//  See clang documentation on language extensions for details:
+//  http://clang.llvm.org/docs/LanguageExtensions.html#clang__fallthrough
+//
+//  When used with unsupported compilers, the FALLTHROUGH_INTENDED macro has no
+//  effect on diagnostics.
+//
+//  In either case this macro has no effect on runtime behavior and performance
+//  of code.
+#if defined(__clang__) && __cplusplus >= 201103L && defined(__has_warning)
+#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
+#define FALLTHROUGH_INTENDED [[clang::fallthrough]]  // NOLINT
+#endif
+#endif
+
+#ifndef FALLTHROUGH_INTENDED
+#define FALLTHROUGH_INTENDED \
+  do {                       \
+  } while (0)
+#endif
+
+#endif  // UTILS_MACROS_H
diff --git a/include/utils/stringprintf.h b/base/include/base/stringprintf.h
similarity index 82%
rename from include/utils/stringprintf.h
rename to base/include/base/stringprintf.h
index e7dbac7..195c1de 100644
--- a/include/utils/stringprintf.h
+++ b/base/include/base/stringprintf.h
@@ -14,25 +14,27 @@
  * limitations under the License.
  */
 
-#ifndef UTILS_STRINGPRINTF_H_
-#define UTILS_STRINGPRINTF_H_
+#ifndef BASE_STRINGPRINTF_H
+#define BASE_STRINGPRINTF_H
 
 #include <stdarg.h>
 #include <string>
 
 namespace android {
+namespace base {
 
 // Returns a string corresponding to printf-like formatting of the arguments.
 std::string StringPrintf(const char* fmt, ...)
-        __attribute__((__format__(__printf__, 1, 2)));
+    __attribute__((__format__(__printf__, 1, 2)));
 
 // Appends a printf-like formatting of the arguments to 'dst'.
 void StringAppendF(std::string* dst, const char* fmt, ...)
-        __attribute__((__format__(__printf__, 2, 3)));
+    __attribute__((__format__(__printf__, 2, 3)));
 
 // Appends a printf-like formatting of the arguments to 'dst'.
 void StringAppendV(std::string* dst, const char* format, va_list ap);
 
+}  // namespace base
 }  // namespace android
 
-#endif
+#endif  // BASE_STRINGPRINTF_H
diff --git a/base/include/base/strings.h b/base/include/base/strings.h
new file mode 100644
index 0000000..ab56aad
--- /dev/null
+++ b/base/include/base/strings.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef BASE_STRINGS_H
+#define BASE_STRINGS_H
+
+#include <string>
+#include <vector>
+
+namespace android {
+namespace base {
+
+// Splits a string into a vector of strings.
+//
+// The string is split at each occurence of a character in delimiters.
+//
+// Empty splits will be omitted. I.e. Split("a,,b", ",") -> {"a", "b"}
+//
+// The empty string is not a valid delimiter list.
+std::vector<std::string> Split(const std::string& s,
+                               const std::string& delimiters);
+
+// Trims whitespace off both ends of the given string.
+std::string Trim(const std::string& s);
+
+// Joins a vector of strings into a single string, using the given separator.
+template <typename StringT>
+std::string Join(const std::vector<StringT>& strings, char separator);
+
+// Tests whether 's' starts with 'prefix'.
+bool StartsWith(const std::string& s, const char* prefix);
+
+// Tests whether 's' ends with 'suffix'.
+bool EndsWith(const std::string& s, const char* suffix);
+
+}  // namespace base
+}  // namespace android
+
+#endif  // BASE_STRINGS_H
diff --git a/base/logging.cpp b/base/logging.cpp
new file mode 100644
index 0000000..a36ac5f
--- /dev/null
+++ b/base/logging.cpp
@@ -0,0 +1,306 @@
+/*
+ * 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.
+ */
+
+#include "base/logging.h"
+
+#include <iostream>
+#include <limits>
+#include <mutex>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/strings.h"
+#include "cutils/threads.h"
+
+// Headers for LogMessage::LogLine.
+#ifdef __ANDROID__
+#include <android/set_abort_message.h>
+#include "cutils/log.h"
+#else
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+namespace android {
+namespace base {
+
+static std::mutex logging_lock;
+
+#ifdef __ANDROID__
+static LogFunction gLogger = LogdLogger();
+#else
+static LogFunction gLogger = StderrLogger;
+#endif
+
+static LogSeverity gMinimumLogSeverity = INFO;
+static std::unique_ptr<std::string> gCmdLine;
+static std::unique_ptr<std::string> gProgramInvocationName;
+static std::unique_ptr<std::string> gProgramInvocationShortName;
+
+const char* GetCmdLine() {
+  return (gCmdLine.get() != nullptr) ? gCmdLine->c_str() : nullptr;
+}
+
+const char* ProgramInvocationName() {
+  return (gProgramInvocationName.get() != nullptr)
+             ? gProgramInvocationName->c_str()
+             : "unknown";
+}
+
+const char* ProgramInvocationShortName() {
+  return (gProgramInvocationShortName.get() != nullptr)
+             ? gProgramInvocationShortName->c_str()
+             : "unknown";
+}
+
+void StderrLogger(LogId, LogSeverity severity, const char*, const char* file,
+                  unsigned int line, const char* message) {
+  static const char* log_characters = "VDIWEF";
+  CHECK_EQ(strlen(log_characters), FATAL + 1U);
+  char severity_char = log_characters[severity];
+  fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationShortName(),
+          severity_char, getpid(), gettid(), file, line, message);
+}
+
+
+#ifdef __ANDROID__
+LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) {
+}
+
+static const android_LogPriority kLogSeverityToAndroidLogPriority[] = {
+    ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
+    ANDROID_LOG_WARN,    ANDROID_LOG_ERROR, ANDROID_LOG_FATAL,
+};
+static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
+              "Mismatch in size of kLogSeverityToAndroidLogPriority and values "
+              "in LogSeverity");
+
+static const log_id kLogIdToAndroidLogId[] = {
+    LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM,
+};
+static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1,
+              "Mismatch in size of kLogIdToAndroidLogId and values in LogId");
+
+void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag,
+                            const char* file, unsigned int line,
+                            const char* message) {
+  int priority = kLogSeverityToAndroidLogPriority[severity];
+  if (id == DEFAULT) {
+    id = default_log_id_;
+  }
+
+  log_id lg_id = kLogIdToAndroidLogId[id];
+
+  if (priority == ANDROID_LOG_FATAL) {
+    __android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line,
+                            message);
+  } else {
+    __android_log_buf_print(lg_id, priority, tag, "%s", message);
+  }
+}
+#endif
+
+void InitLogging(char* argv[], LogFunction&& logger) {
+  SetLogger(std::forward<LogFunction>(logger));
+  InitLogging(argv);
+}
+
+void InitLogging(char* argv[]) {
+  if (gCmdLine.get() != nullptr) {
+    return;
+  }
+
+  // Stash the command line for later use. We can use /proc/self/cmdline on
+  // Linux to recover this, but we don't have that luxury on the Mac, and there
+  // are a couple of argv[0] variants that are commonly used.
+  if (argv != nullptr) {
+    gCmdLine.reset(new std::string(argv[0]));
+    for (size_t i = 1; argv[i] != nullptr; ++i) {
+      gCmdLine->append(" ");
+      gCmdLine->append(argv[i]);
+    }
+    gProgramInvocationName.reset(new std::string(argv[0]));
+    const char* last_slash = strrchr(argv[0], '/');
+    gProgramInvocationShortName.reset(
+        new std::string((last_slash != nullptr) ? last_slash + 1 : argv[0]));
+  } else {
+    // TODO: fall back to /proc/self/cmdline when argv is NULL on Linux.
+    gCmdLine.reset(new std::string("<unset>"));
+  }
+  const char* tags = getenv("ANDROID_LOG_TAGS");
+  if (tags == nullptr) {
+    return;
+  }
+
+  std::vector<std::string> specs = Split(tags, " ");
+  for (size_t i = 0; i < specs.size(); ++i) {
+    // "tag-pattern:[vdiwefs]"
+    std::string spec(specs[i]);
+    if (spec.size() == 3 && StartsWith(spec, "*:")) {
+      switch (spec[2]) {
+        case 'v':
+          gMinimumLogSeverity = VERBOSE;
+          continue;
+        case 'd':
+          gMinimumLogSeverity = DEBUG;
+          continue;
+        case 'i':
+          gMinimumLogSeverity = INFO;
+          continue;
+        case 'w':
+          gMinimumLogSeverity = WARNING;
+          continue;
+        case 'e':
+          gMinimumLogSeverity = ERROR;
+          continue;
+        case 'f':
+          gMinimumLogSeverity = FATAL;
+          continue;
+        // liblog will even suppress FATAL if you say 's' for silent, but that's
+        // crazy!
+        case 's':
+          gMinimumLogSeverity = FATAL;
+          continue;
+      }
+    }
+    LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags
+               << ")";
+  }
+}
+
+void SetLogger(LogFunction&& logger) {
+  std::lock_guard<std::mutex> lock(logging_lock);
+  gLogger = std::move(logger);
+}
+
+// This indirection greatly reduces the stack impact of having lots of
+// checks/logging in a function.
+class LogMessageData {
+ public:
+  LogMessageData(const char* file, unsigned int line, LogId id,
+                 LogSeverity severity, int error)
+      : file_(file),
+        line_number_(line),
+        id_(id),
+        severity_(severity),
+        error_(error) {
+    const char* last_slash = strrchr(file, '/');
+    file = (last_slash == nullptr) ? file : last_slash + 1;
+  }
+
+  const char* GetFile() const {
+    return file_;
+  }
+
+  unsigned int GetLineNumber() const {
+    return line_number_;
+  }
+
+  LogSeverity GetSeverity() const {
+    return severity_;
+  }
+
+  LogId GetId() const {
+    return id_;
+  }
+
+  int GetError() const {
+    return error_;
+  }
+
+  std::ostream& GetBuffer() {
+    return buffer_;
+  }
+
+  std::string ToString() const {
+    return buffer_.str();
+  }
+
+ private:
+  std::ostringstream buffer_;
+  const char* const file_;
+  const unsigned int line_number_;
+  const LogId id_;
+  const LogSeverity severity_;
+  const int error_;
+
+  DISALLOW_COPY_AND_ASSIGN(LogMessageData);
+};
+
+LogMessage::LogMessage(const char* file, unsigned int line, LogId id,
+                       LogSeverity severity, int error)
+    : data_(new LogMessageData(file, line, id, severity, error)) {
+}
+
+LogMessage::~LogMessage() {
+  if (data_->GetSeverity() < gMinimumLogSeverity) {
+    return;  // No need to format something we're not going to output.
+  }
+
+  // Finish constructing the message.
+  if (data_->GetError() != -1) {
+    data_->GetBuffer() << ": " << strerror(data_->GetError());
+  }
+  std::string msg(data_->ToString());
+
+  if (msg.find('\n') == std::string::npos) {
+    LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
+            data_->GetSeverity(), msg.c_str());
+  } else {
+    msg += '\n';
+    size_t i = 0;
+    while (i < msg.size()) {
+      size_t nl = msg.find('\n', i);
+      msg[nl] = '\0';
+      LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
+              data_->GetSeverity(), &msg[i]);
+      i = nl + 1;
+    }
+  }
+
+  // Abort if necessary.
+  if (data_->GetSeverity() == FATAL) {
+#ifdef __ANDROID__
+    android_set_abort_message(msg.c_str());
+#endif
+    abort();
+  }
+}
+
+std::ostream& LogMessage::stream() {
+  return data_->GetBuffer();
+}
+
+void LogMessage::LogLine(const char* file, unsigned int line, LogId id,
+                         LogSeverity severity, const char* message) {
+  const char* tag = ProgramInvocationShortName();
+  std::lock_guard<std::mutex> lock(logging_lock);
+  gLogger(id, severity, tag, file, line, message);
+}
+
+ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) {
+  old_ = gMinimumLogSeverity;
+  gMinimumLogSeverity = level;
+}
+
+ScopedLogSeverity::~ScopedLogSeverity() {
+  gMinimumLogSeverity = old_;
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
new file mode 100644
index 0000000..d947c1d
--- /dev/null
+++ b/base/logging_test.cpp
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+#include "base/logging.h"
+
+#include <regex>
+#include <string>
+
+#include "base/file.h"
+#include "base/stringprintf.h"
+#include "test_utils.h"
+
+#include <gtest/gtest.h>
+
+#ifdef __ANDROID__
+#define HOST_TEST(suite, name) TEST(suite, DISABLED_ ## name)
+#else
+#define HOST_TEST(suite, name) TEST(suite, name)
+#endif
+
+class CapturedStderr {
+ public:
+  CapturedStderr() : old_stderr_(-1) {
+    init();
+  }
+
+  ~CapturedStderr() {
+    reset();
+  }
+
+  int fd() const {
+    return temp_file_.fd;
+  }
+
+ private:
+  void init() {
+    old_stderr_ = dup(STDERR_FILENO);
+    ASSERT_NE(-1, old_stderr_);
+    ASSERT_NE(-1, dup2(fd(), STDERR_FILENO));
+  }
+
+  void reset() {
+    ASSERT_NE(-1, dup2(old_stderr_, STDERR_FILENO));
+    ASSERT_EQ(0, close(old_stderr_));
+  }
+
+  TemporaryFile temp_file_;
+  int old_stderr_;
+};
+
+TEST(logging, CHECK) {
+  ASSERT_DEATH(CHECK(false), "Check failed: false ");
+  CHECK(true);
+
+  ASSERT_DEATH(CHECK_EQ(0, 1), "Check failed: 0 == 1 ");
+  CHECK_EQ(0, 0);
+
+  ASSERT_DEATH(CHECK_STREQ("foo", "bar"), R"(Check failed: "foo" == "bar")");
+  CHECK_STREQ("foo", "foo");
+}
+
+std::string make_log_pattern(android::base::LogSeverity severity,
+                             const char* message) {
+  static const char* log_characters = "VDIWEF";
+  char log_char = log_characters[severity];
+  return android::base::StringPrintf(
+      "%c[[:space:]]+[[:digit:]]+[[:space:]]+[[:digit:]]+ " __FILE__
+      ":[[:digit:]]+] %s",
+      log_char, message);
+}
+
+TEST(logging, LOG) {
+  ASSERT_DEATH(LOG(FATAL) << "foobar", "foobar");
+
+  {
+    CapturedStderr cap;
+    LOG(WARNING) << "foobar";
+    ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+    std::string output;
+    android::base::ReadFdToString(cap.fd(), &output);
+
+    std::regex message_regex(
+        make_log_pattern(android::base::WARNING, "foobar"));
+    ASSERT_TRUE(std::regex_search(output, message_regex));
+  }
+
+  {
+    CapturedStderr cap;
+    LOG(INFO) << "foobar";
+    ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+    std::string output;
+    android::base::ReadFdToString(cap.fd(), &output);
+
+    std::regex message_regex(
+        make_log_pattern(android::base::INFO, "foobar"));
+    ASSERT_TRUE(std::regex_search(output, message_regex));
+  }
+
+  {
+    CapturedStderr cap;
+    LOG(DEBUG) << "foobar";
+    ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+    std::string output;
+    android::base::ReadFdToString(cap.fd(), &output);
+    ASSERT_TRUE(output.empty());
+  }
+
+  {
+    android::base::ScopedLogSeverity severity(android::base::DEBUG);
+    CapturedStderr cap;
+    LOG(DEBUG) << "foobar";
+    ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+    std::string output;
+    android::base::ReadFdToString(cap.fd(), &output);
+
+    std::regex message_regex(
+        make_log_pattern(android::base::DEBUG, "foobar"));
+    ASSERT_TRUE(std::regex_search(output, message_regex));
+  }
+}
+
+TEST(logging, PLOG) {
+  {
+    CapturedStderr cap;
+    errno = ENOENT;
+    PLOG(INFO) << "foobar";
+    ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+    std::string output;
+    android::base::ReadFdToString(cap.fd(), &output);
+
+    std::regex message_regex(make_log_pattern(
+        android::base::INFO, "foobar: No such file or directory"));
+    ASSERT_TRUE(std::regex_search(output, message_regex));
+  }
+}
+
+TEST(logging, UNIMPLEMENTED) {
+  {
+    CapturedStderr cap;
+    errno = ENOENT;
+    UNIMPLEMENTED(ERROR);
+    ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+    std::string output;
+    android::base::ReadFdToString(cap.fd(), &output);
+
+    std::string expected_message =
+        android::base::StringPrintf("%s unimplemented ", __PRETTY_FUNCTION__);
+    std::regex message_regex(
+        make_log_pattern(android::base::ERROR, expected_message.c_str()));
+    ASSERT_TRUE(std::regex_search(output, message_regex));
+  }
+}
diff --git a/libutils/stringprintf.cpp b/base/stringprintf.cpp
similarity index 84%
rename from libutils/stringprintf.cpp
rename to base/stringprintf.cpp
index 5eaa293..d55ff52 100644
--- a/libutils/stringprintf.cpp
+++ b/base/stringprintf.cpp
@@ -14,11 +14,16 @@
  * limitations under the License.
  */
 
-#include <utils/stringprintf.h>
+#include "base/stringprintf.h"
 
 #include <stdio.h>
 
-void android::StringAppendV(std::string* dst, const char* format, va_list ap) {
+#include <string>
+
+namespace android {
+namespace base {
+
+void StringAppendV(std::string* dst, const char* format, va_list ap) {
   // First try with a small fixed size buffer
   char space[1024];
 
@@ -45,7 +50,7 @@
 
   // Increase the buffer size to the size requested by vsnprintf,
   // plus one for the closing \0.
-  int length = result+1;
+  int length = result + 1;
   char* buf = new char[length];
 
   // Restore the va_list before we use it again
@@ -60,7 +65,7 @@
   delete[] buf;
 }
 
-std::string android::StringPrintf(const char* fmt, ...) {
+std::string StringPrintf(const char* fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
   std::string result;
@@ -69,9 +74,12 @@
   return result;
 }
 
-void android::StringAppendF(std::string* dst, const char* format, ...) {
+void StringAppendF(std::string* dst, const char* format, ...) {
   va_list ap;
   va_start(ap, format);
   StringAppendV(dst, format, ap);
   va_end(ap);
 }
+
+}  // namespace base
+}  // namespace android
diff --git a/libutils/tests/stringprintf_test.cpp b/base/stringprintf_test.cpp
similarity index 76%
rename from libutils/tests/stringprintf_test.cpp
rename to base/stringprintf_test.cpp
index f995452..5cc2086 100644
--- a/libutils/tests/stringprintf_test.cpp
+++ b/base/stringprintf_test.cpp
@@ -14,25 +14,27 @@
  * limitations under the License.
  */
 
-#include <utils/stringprintf.h>
+#include "base/stringprintf.h"
 
 #include <gtest/gtest.h>
 
+#include <string>
+
 TEST(StringPrintfTest, HexSizeT) {
   size_t size = 0x00107e59;
-  EXPECT_EQ("00107e59", android::StringPrintf("%08zx", size));
-  EXPECT_EQ("0x00107e59", android::StringPrintf("0x%08zx", size));
+  EXPECT_EQ("00107e59", android::base::StringPrintf("%08zx", size));
+  EXPECT_EQ("0x00107e59", android::base::StringPrintf("0x%08zx", size));
 }
 
 TEST(StringPrintfTest, StringAppendF) {
   std::string s("a");
-  android::StringAppendF(&s, "b");
+  android::base::StringAppendF(&s, "b");
   EXPECT_EQ("ab", s);
 }
 
 TEST(StringPrintfTest, Errno) {
   errno = 123;
-  android::StringPrintf("hello %s", "world");
+  android::base::StringPrintf("hello %s", "world");
   EXPECT_EQ(123, errno);
 }
 
@@ -40,7 +42,7 @@
   char* buf = new char[n + 1];
   memset(buf, 'x', n);
   buf[n] = '\0';
-  std::string s(android::StringPrintf("%s", buf));
+  std::string s(android::base::StringPrintf("%s", buf));
   EXPECT_EQ(buf, s);
   delete[] buf;
 }
diff --git a/base/strings.cpp b/base/strings.cpp
new file mode 100644
index 0000000..6f698d9
--- /dev/null
+++ b/base/strings.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+#include "base/strings.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <string>
+#include <vector>
+
+namespace android {
+namespace base {
+
+#define CHECK_NE(a, b) \
+  if ((a) == (b)) abort();
+
+std::vector<std::string> Split(const std::string& s,
+                               const std::string& delimiters) {
+  CHECK_NE(delimiters.size(), 0U);
+
+  std::vector<std::string> split;
+  if (s.size() == 0) {
+    // Split("", d) returns {} rather than {""}.
+    return split;
+  }
+
+  size_t base = 0;
+  size_t found;
+  do {
+    found = s.find_first_of(delimiters, base);
+    if (found != base) {
+      split.push_back(s.substr(base, found - base));
+    }
+
+    base = found + 1;
+  } while (found != s.npos);
+
+  return split;
+}
+
+std::string Trim(const std::string& s) {
+  std::string result;
+
+  if (s.size() == 0) {
+    return result;
+  }
+
+  size_t start_index = 0;
+  size_t end_index = s.size() - 1;
+
+  // Skip initial whitespace.
+  while (start_index < s.size()) {
+    if (!isspace(s[start_index])) {
+      break;
+    }
+    start_index++;
+  }
+
+  // Skip terminating whitespace.
+  while (end_index >= start_index) {
+    if (!isspace(s[end_index])) {
+      break;
+    }
+    end_index--;
+  }
+
+  // All spaces, no beef.
+  if (end_index < start_index) {
+    return "";
+  }
+  // Start_index is the first non-space, end_index is the last one.
+  return s.substr(start_index, end_index - start_index + 1);
+}
+
+template <typename StringT>
+std::string Join(const std::vector<StringT>& strings, char separator) {
+  if (strings.empty()) {
+    return "";
+  }
+
+  std::string result(strings[0]);
+  for (size_t i = 1; i < strings.size(); ++i) {
+    result += separator;
+    result += strings[i];
+  }
+  return result;
+}
+
+// Explicit instantiations.
+template std::string Join<std::string>(const std::vector<std::string>& strings,
+                                       char separator);
+template std::string Join<const char*>(const std::vector<const char*>& strings,
+                                       char separator);
+
+bool StartsWith(const std::string& s, const char* prefix) {
+  return s.compare(0, strlen(prefix), prefix) == 0;
+}
+
+bool EndsWith(const std::string& s, const char* suffix) {
+  size_t suffix_length = strlen(suffix);
+  size_t string_length = s.size();
+  if (suffix_length > string_length) {
+    return false;
+  }
+  size_t offset = string_length - suffix_length;
+  return s.compare(offset, suffix_length, suffix) == 0;
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
new file mode 100644
index 0000000..1bf07a1
--- /dev/null
+++ b/base/strings_test.cpp
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+
+#include "base/strings.h"
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <vector>
+
+TEST(strings, split_empty) {
+  std::vector<std::string> parts = android::base::Split("", ",");
+  ASSERT_EQ(0U, parts.size());
+}
+
+TEST(strings, split_single) {
+  std::vector<std::string> parts = android::base::Split("foo", ",");
+  ASSERT_EQ(1U, parts.size());
+  ASSERT_EQ("foo", parts[0]);
+}
+
+TEST(strings, split_simple) {
+  std::vector<std::string> parts = android::base::Split("foo,bar,baz", ",");
+  ASSERT_EQ(3U, parts.size());
+  ASSERT_EQ("foo", parts[0]);
+  ASSERT_EQ("bar", parts[1]);
+  ASSERT_EQ("baz", parts[2]);
+}
+
+TEST(strings, split_with_empty_part) {
+  std::vector<std::string> parts = android::base::Split("foo,,bar", ",");
+  ASSERT_EQ(2U, parts.size());
+  ASSERT_EQ("foo", parts[0]);
+  ASSERT_EQ("bar", parts[1]);
+}
+
+TEST(strings, split_null_char) {
+  std::vector<std::string> parts =
+      android::base::Split(std::string("foo\0bar", 7), std::string("\0", 1));
+  ASSERT_EQ(2U, parts.size());
+  ASSERT_EQ("foo", parts[0]);
+  ASSERT_EQ("bar", parts[1]);
+}
+
+TEST(strings, split_any) {
+  std::vector<std::string> parts = android::base::Split("foo:bar,baz", ",:");
+  ASSERT_EQ(3U, parts.size());
+  ASSERT_EQ("foo", parts[0]);
+  ASSERT_EQ("bar", parts[1]);
+  ASSERT_EQ("baz", parts[2]);
+}
+
+TEST(strings, split_any_with_empty_part) {
+  std::vector<std::string> parts = android::base::Split("foo:,bar", ",:");
+  ASSERT_EQ(2U, parts.size());
+  ASSERT_EQ("foo", parts[0]);
+  ASSERT_EQ("bar", parts[1]);
+}
+
+TEST(strings, trim_empty) {
+  ASSERT_EQ("", android::base::Trim(""));
+}
+
+TEST(strings, trim_already_trimmed) {
+  ASSERT_EQ("foo", android::base::Trim("foo"));
+}
+
+TEST(strings, trim_left) {
+  ASSERT_EQ("foo", android::base::Trim(" foo"));
+}
+
+TEST(strings, trim_right) {
+  ASSERT_EQ("foo", android::base::Trim("foo "));
+}
+
+TEST(strings, trim_both) {
+  ASSERT_EQ("foo", android::base::Trim(" foo "));
+}
+
+TEST(strings, trim_no_trim_middle) {
+  ASSERT_EQ("foo bar", android::base::Trim("foo bar"));
+}
+
+TEST(strings, trim_other_whitespace) {
+  ASSERT_EQ("foo", android::base::Trim("\v\tfoo\n\f"));
+}
+
+TEST(strings, join_nothing) {
+  std::vector<std::string> list = {};
+  ASSERT_EQ("", android::base::Join(list, ','));
+}
+
+TEST(strings, join_single) {
+  std::vector<std::string> list = {"foo"};
+  ASSERT_EQ("foo", android::base::Join(list, ','));
+}
+
+TEST(strings, join_simple) {
+  std::vector<std::string> list = {"foo", "bar", "baz"};
+  ASSERT_EQ("foo,bar,baz", android::base::Join(list, ','));
+}
+
+TEST(strings, join_separator_in_vector) {
+  std::vector<std::string> list = {",", ","};
+  ASSERT_EQ(",,,", android::base::Join(list, ','));
+}
+
+TEST(strings, startswith_empty) {
+  ASSERT_FALSE(android::base::StartsWith("", "foo"));
+  ASSERT_TRUE(android::base::StartsWith("", ""));
+}
+
+TEST(strings, startswith_simple) {
+  ASSERT_TRUE(android::base::StartsWith("foo", ""));
+  ASSERT_TRUE(android::base::StartsWith("foo", "f"));
+  ASSERT_TRUE(android::base::StartsWith("foo", "fo"));
+  ASSERT_TRUE(android::base::StartsWith("foo", "foo"));
+}
+
+TEST(strings, startswith_prefix_too_long) {
+  ASSERT_FALSE(android::base::StartsWith("foo", "foobar"));
+}
+
+TEST(strings, startswith_contains_prefix) {
+  ASSERT_FALSE(android::base::StartsWith("foobar", "oba"));
+  ASSERT_FALSE(android::base::StartsWith("foobar", "bar"));
+}
+
+TEST(strings, endswith_empty) {
+  ASSERT_FALSE(android::base::EndsWith("", "foo"));
+  ASSERT_TRUE(android::base::EndsWith("", ""));
+}
+
+TEST(strings, endswith_simple) {
+  ASSERT_TRUE(android::base::EndsWith("foo", ""));
+  ASSERT_TRUE(android::base::EndsWith("foo", "o"));
+  ASSERT_TRUE(android::base::EndsWith("foo", "oo"));
+  ASSERT_TRUE(android::base::EndsWith("foo", "foo"));
+}
+
+TEST(strings, endswith_prefix_too_long) {
+  ASSERT_FALSE(android::base::EndsWith("foo", "foobar"));
+}
+
+TEST(strings, endswith_contains_prefix) {
+  ASSERT_FALSE(android::base::EndsWith("foobar", "oba"));
+  ASSERT_FALSE(android::base::EndsWith("foobar", "foo"));
+}
diff --git a/base/test_main.cpp b/base/test_main.cpp
new file mode 100644
index 0000000..546923d
--- /dev/null
+++ b/base/test_main.cpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "base/logging.h"
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  android::base::InitLogging(argv, android::base::StderrLogger);
+  return RUN_ALL_TESTS();
+}
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
new file mode 100644
index 0000000..1f6d3cf
--- /dev/null
+++ b/base/test_utils.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#include "test_utils.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+TemporaryFile::TemporaryFile() {
+  init("/data/local/tmp");
+  if (fd == -1) {
+    init("/tmp");
+  }
+}
+
+TemporaryFile::~TemporaryFile() {
+  close(fd);
+  unlink(filename);
+}
+
+void TemporaryFile::init(const char* tmp_dir) {
+  snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir);
+  fd = mkstemp(filename);
+}
diff --git a/base/test_utils.h b/base/test_utils.h
new file mode 100644
index 0000000..132d3a7
--- /dev/null
+++ b/base/test_utils.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef TEST_UTILS_H
+#define TEST_UTILS_H
+
+class TemporaryFile {
+ public:
+  TemporaryFile();
+  ~TemporaryFile();
+
+  int fd;
+  char filename[1024];
+
+ private:
+  void init(const char* tmp_dir);
+};
+
+#endif // TEST_UTILS_H
diff --git a/cpio/Android.mk b/cpio/Android.mk
index 575beb2..b9d18ba 100644
--- a/cpio/Android.mk
+++ b/cpio/Android.mk
@@ -10,6 +10,8 @@
 
 LOCAL_CFLAGS := -Werror
 
+LOCAL_STATIC_LIBRARIES := libcutils
+
 include $(BUILD_HOST_EXECUTABLE)
 
 $(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE))
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index fbaac39..dd53296 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -5,6 +5,7 @@
 LOCAL_SRC_FILES:= \
     backtrace.cpp \
     debuggerd.cpp \
+    elf_utils.cpp \
     getevent.cpp \
     tombstone.cpp \
     utility.cpp \
@@ -12,7 +13,7 @@
 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 := 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
 
@@ -28,6 +29,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
     libbacktrace \
+    libbase \
     libcutils \
     liblog \
     libselinux \
@@ -38,7 +40,6 @@
 LOCAL_MODULE_STEM_32 := debuggerd
 LOCAL_MODULE_STEM_64 := debuggerd64
 LOCAL_MULTILIB := both
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 
 include $(BUILD_EXECUTABLE)
 
@@ -49,7 +50,7 @@
 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 := 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)
diff --git a/debuggerd/elf_utils.cpp b/debuggerd/elf_utils.cpp
new file mode 100644
index 0000000..764b9db
--- /dev/null
+++ b/debuggerd/elf_utils.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "DEBUG"
+
+#include <elf.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <string>
+
+#include <backtrace/Backtrace.h>
+#include <base/stringprintf.h>
+#include <log/log.h>
+
+#include "elf_utils.h"
+
+template <typename HdrType, typename PhdrType, typename NhdrType>
+static bool get_build_id(
+    Backtrace* backtrace, uintptr_t base_addr, uint8_t* e_ident, std::string* build_id) {
+  HdrType hdr;
+
+  memcpy(&hdr.e_ident[0], e_ident, EI_NIDENT);
+
+  // First read the rest of the header.
+  if (backtrace->Read(base_addr + EI_NIDENT, reinterpret_cast<uint8_t*>(&hdr) + EI_NIDENT,
+                      sizeof(HdrType) - EI_NIDENT) != sizeof(HdrType) - EI_NIDENT) {
+    return false;
+  }
+
+  for (size_t i = 0; i < hdr.e_phnum; i++) {
+    PhdrType phdr;
+    if (backtrace->Read(base_addr + hdr.e_phoff + i * hdr.e_phentsize,
+                        reinterpret_cast<uint8_t*>(&phdr), sizeof(phdr)) != sizeof(phdr)) {
+      return false;
+    }
+    // Looking for the .note.gnu.build-id note.
+    if (phdr.p_type == PT_NOTE) {
+      size_t hdr_size = phdr.p_filesz;
+      uintptr_t addr = base_addr + phdr.p_offset;
+      while (hdr_size >= sizeof(NhdrType)) {
+        NhdrType nhdr;
+        if (backtrace->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) {
+          return false;
+        }
+        addr += sizeof(nhdr);
+        if (nhdr.n_type == NT_GNU_BUILD_ID) {
+          // Skip the name (which is the owner and should be "GNU").
+          addr += nhdr.n_namesz;
+          uint8_t build_id_data[128];
+          if (nhdr.n_namesz > sizeof(build_id_data)) {
+            ALOGE("Possible corrupted note, name size value is too large: %u",
+                  nhdr.n_namesz);
+            return false;
+          }
+          if (backtrace->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) {
+            return false;
+          }
+
+          build_id->clear();
+          for (size_t bytes = 0; bytes < nhdr.n_descsz; bytes++) {
+            *build_id += android::base::StringPrintf("%02x", build_id_data[bytes]);
+          }
+
+          return true;
+        } else {
+          // Move past the extra note data.
+          hdr_size -= sizeof(nhdr);
+          size_t skip_bytes = nhdr.n_namesz + nhdr.n_descsz;
+          addr += skip_bytes;
+          if (hdr_size < skip_bytes) {
+            break;
+          }
+          hdr_size -= skip_bytes;
+        }
+      }
+    }
+  }
+  return false;
+}
+
+bool elf_get_build_id(Backtrace* backtrace, uintptr_t addr, std::string* build_id) {
+  // Read and verify the elf magic number first.
+  uint8_t e_ident[EI_NIDENT];
+  if (backtrace->Read(addr, e_ident, SELFMAG) != SELFMAG) {
+    return false;
+  }
+
+  if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
+    return false;
+  }
+
+  // Read the rest of EI_NIDENT.
+  if (backtrace->Read(addr + SELFMAG, e_ident + SELFMAG, EI_NIDENT - SELFMAG) != EI_NIDENT - SELFMAG) {
+    return false;
+  }
+
+  if (e_ident[EI_CLASS] == ELFCLASS32) {
+    return get_build_id<Elf32_Ehdr, Elf32_Phdr, Elf32_Nhdr>(backtrace, addr, e_ident, build_id);
+  } else if (e_ident[EI_CLASS] == ELFCLASS64) {
+    return get_build_id<Elf64_Ehdr, Elf64_Phdr, Elf64_Nhdr>(backtrace, addr, e_ident, build_id);
+  }
+
+  return false;
+}
diff --git a/debuggerd/elf_utils.h b/debuggerd/elf_utils.h
new file mode 100644
index 0000000..11d0a43
--- /dev/null
+++ b/debuggerd/elf_utils.h
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+#ifndef _DEBUGGERD_ELF_UTILS_H
+#define _DEBUGGERD_ELF_UTILS_H
+
+#include <stdint.h>
+#include <string>
+
+class Backtrace;
+
+bool elf_get_build_id(Backtrace*, uintptr_t, std::string*);
+
+#endif // _DEBUGGERD_ELF_UTILS_H
diff --git a/debuggerd/mips64/crashglue.S b/debuggerd/mips64/crashglue.S
new file mode 100644
index 0000000..70a6641
--- /dev/null
+++ b/debuggerd/mips64/crashglue.S
@@ -0,0 +1,48 @@
+	.set	noat
+
+	.globl crash1
+	.globl crashnostack
+
+crash1:
+	li	$0,0xdead0000+0
+	li	$1,0xdead0000+1
+	li	$2,0xdead0000+2
+	li	$3,0xdead0000+3
+	li	$4,0xdead0000+4
+	li	$5,0xdead0000+5
+	li	$6,0xdead0000+6
+	li	$7,0xdead0000+7
+	li	$8,0xdead0000+8
+	li	$9,0xdead0000+9
+	li	$10,0xdead0000+10
+	li	$11,0xdead0000+11
+	li	$12,0xdead0000+12
+	li	$13,0xdead0000+13
+	li	$14,0xdead0000+14
+	li	$15,0xdead0000+15
+	li	$16,0xdead0000+16
+	li	$17,0xdead0000+17
+	li	$18,0xdead0000+18
+	li	$19,0xdead0000+19
+	li	$20,0xdead0000+20
+	li	$21,0xdead0000+21
+	li	$22,0xdead0000+22
+	li	$23,0xdead0000+23
+	li	$24,0xdead0000+24
+	li	$25,0xdead0000+25
+	li	$26,0xdead0000+26
+	li	$27,0xdead0000+27
+	li	$28,0xdead0000+28
+	# don't trash the stack otherwise the signal handler won't run
+	#li	$29,0xdead0000+29
+	li	$30,0xdead0000+30
+	li	$31,0xdead0000+31
+
+	lw	$zero,($0)
+	b .
+
+
+crashnostack:
+	li	$sp, 0
+	lw	$zero,($0)
+	b .
diff --git a/debuggerd/mips64/machine.cpp b/debuggerd/mips64/machine.cpp
new file mode 100644
index 0000000..ef9092f
--- /dev/null
+++ b/debuggerd/mips64/machine.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright 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 <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+
+#include <sys/user.h>
+
+#include "../utility.h"
+#include "../machine.h"
+
+#define R(x) (static_cast<unsigned long>(x))
+
+// If configured to do so, dump memory around *all* registers
+// for the crashing thread.
+void dump_memory_and_code(log_t* log, pid_t tid) {
+  pt_regs r;
+  if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
+    return;
+  }
+
+  static const char REG_NAMES[] = "$0atv0v1a0a1a2a3a4a5a6a7t0t1t2t3s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
+
+  for (int reg = 0; reg < 32; reg++) {
+    // skip uninteresting registers
+    if (reg == 0 // $0
+        || reg == 26 // $k0
+        || reg == 27 // $k1
+        || reg == 31 // $ra (done below)
+       )
+      continue;
+
+    uintptr_t addr = R(r.regs[reg]);
+
+    // Don't bother if it looks like a small int or ~= null, or if
+    // it's in the kernel area.
+    if (addr < 4096 || addr >= 0x4000000000000000) {
+      continue;
+    }
+
+    _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
+    dump_memory(log, tid, addr);
+  }
+
+  unsigned long pc = R(r.cp0_epc);
+  unsigned long ra = R(r.regs[31]);
+
+  _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
+  dump_memory(log, tid, (uintptr_t)pc);
+
+  if (pc != ra) {
+    _LOG(log, logtype::MEMORY, "\ncode around ra:\n");
+    dump_memory(log, tid, (uintptr_t)ra);
+  }
+}
+
+void dump_registers(log_t* log, pid_t tid) {
+  pt_regs r;
+  if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
+    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+    return;
+  }
+
+  _LOG(log, logtype::REGISTERS, " zr %016lx  at %016lx  v0 %016lx  v1 %016lx\n",
+       R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
+  _LOG(log, logtype::REGISTERS, " a0 %016lx  a1 %016lx  a2 %016lx  a3 %016lx\n",
+       R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
+  _LOG(log, logtype::REGISTERS, " a4 %016lx  a5 %016lx  a6 %016lx  a7 %016lx\n",
+       R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
+  _LOG(log, logtype::REGISTERS, " t0 %016lx  t1 %016lx  t2 %016lx  t3 %016lx\n",
+       R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
+  _LOG(log, logtype::REGISTERS, " s0 %016lx  s1 %016lx  s2 %016lx  s3 %016lx\n",
+       R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
+  _LOG(log, logtype::REGISTERS, " s4 %016lx  s5 %016lx  s6 %016lx  s7 %016lx\n",
+       R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
+  _LOG(log, logtype::REGISTERS, " t8 %016lx  t9 %016lx  k0 %016lx  k1 %016lx\n",
+       R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
+  _LOG(log, logtype::REGISTERS, " gp %016lx  sp %016lx  s8 %016lx  ra %016lx\n",
+       R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
+  _LOG(log, logtype::REGISTERS, " hi %016lx  lo %016lx bva %016lx epc %016lx\n",
+       R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
+}
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 4233d46..094ab48 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -34,6 +34,7 @@
 
 #include <private/android_filesystem_config.h>
 
+#include <base/stringprintf.h>
 #include <cutils/properties.h>
 #include <log/log.h>
 #include <log/logger.h>
@@ -46,9 +47,12 @@
 
 #include <UniquePtr.h>
 
+#include <string>
+
+#include "backtrace.h"
+#include "elf_utils.h"
 #include "machine.h"
 #include "tombstone.h"
-#include "backtrace.h"
 
 #define STACK_WORDS 16
 
@@ -234,47 +238,36 @@
 
 static void dump_stack_segment(
     Backtrace* backtrace, log_t* log, uintptr_t* sp, size_t words, int label) {
+  // Read the data all at once.
+  word_t stack_data[words];
+  size_t bytes_read = backtrace->Read(*sp, reinterpret_cast<uint8_t*>(&stack_data[0]), sizeof(word_t) * words);
+  words = bytes_read / sizeof(word_t);
+  std::string line;
   for (size_t i = 0; i < words; i++) {
-    word_t stack_content;
-    if (!backtrace->ReadWord(*sp, &stack_content)) {
-      break;
+    line = "    ";
+    if (i == 0 && label >= 0) {
+      // Print the label once.
+      line += android::base::StringPrintf("#%02d  ", label);
+    } else {
+      line += "     ";
     }
+    line += android::base::StringPrintf("%" PRIPTR "  %" PRIPTR, *sp, stack_data[i]);
 
     backtrace_map_t map;
-    backtrace->FillInMap(stack_content, &map);
-    std::string map_name;
-    if (BacktraceMap::IsValid(map) && map.name.length() > 0) {
-      map_name = "  " + map.name;
-    }
-    uintptr_t offset = 0;
-    std::string func_name(backtrace->GetFunctionName(stack_content, &offset));
-    if (!func_name.empty()) {
-      if (!i && label >= 0) {
+    backtrace->FillInMap(stack_data[i], &map);
+    if (BacktraceMap::IsValid(map) && !map.name.empty()) {
+      line += "  " + map.name;
+      uintptr_t offset = 0;
+      std::string func_name(backtrace->GetFunctionName(stack_data[i], &offset));
+      if (!func_name.empty()) {
+        line += " (" + func_name;
         if (offset) {
-          _LOG(log, logtype::STACK, "    #%02d  %" PRIPTR "  %" PRIPTR "%s (%s+%" PRIuPTR ")\n",
-               label, *sp, stack_content, map_name.c_str(), func_name.c_str(), offset);
-        } else {
-          _LOG(log, logtype::STACK, "    #%02d  %" PRIPTR "  %" PRIPTR "%s (%s)\n",
-               label, *sp, stack_content, map_name.c_str(), func_name.c_str());
+          line += android::base::StringPrintf("+%" PRIuPTR, offset);
         }
-      } else {
-        if (offset) {
-          _LOG(log, logtype::STACK, "         %" PRIPTR "  %" PRIPTR "%s (%s+%" PRIuPTR ")\n",
-               *sp, stack_content, map_name.c_str(), func_name.c_str(), offset);
-        } else {
-          _LOG(log, logtype::STACK, "         %" PRIPTR "  %" PRIPTR "%s (%s)\n",
-               *sp, stack_content, map_name.c_str(), func_name.c_str());
-        }
-      }
-    } else {
-      if (!i && label >= 0) {
-        _LOG(log, logtype::STACK, "    #%02d  %" PRIPTR "  %" PRIPTR "%s\n",
-             label, *sp, stack_content, map_name.c_str());
-      } else {
-        _LOG(log, logtype::STACK, "         %" PRIPTR "  %" PRIPTR "%s\n",
-             *sp, stack_content, map_name.c_str());
+        line += ')';
       }
     }
+    _LOG(log, logtype::STACK, "%s\n", line.c_str());
 
     *sp += sizeof(word_t);
   }
@@ -325,44 +318,72 @@
   }
 }
 
-static void dump_map(log_t* log, const backtrace_map_t* map, bool fault_addr) {
-  _LOG(log, logtype::MAPS, "%s%" PRIPTR "-%" PRIPTR " %c%c%c  %7" PRIdPTR "%s\n",
-         (fault_addr? "--->" : "    "), map->start, map->end - 1,
-         (map->flags & PROT_READ) ? 'r' : '-', (map->flags & PROT_WRITE) ? 'w' : '-',
-         (map->flags & PROT_EXEC) ? 'x' : '-',
-         (map->end - map->start),
-         (map->name.length() > 0) ? ("  " + map->name).c_str() : "");
-}
-
-static void dump_all_maps(BacktraceMap* map, log_t* log, pid_t tid) {
-  bool has_fault_address = false;
+static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, pid_t tid) {
+  bool print_fault_address_marker = false;
   uintptr_t addr = 0;
   siginfo_t si;
   memset(&si, 0, sizeof(si));
   if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) {
-    _LOG(log, logtype::MAPS, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
+    _LOG(log, logtype::ERROR, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
   } else {
-    has_fault_address = signal_has_si_addr(si.si_signo);
+    print_fault_address_marker = signal_has_si_addr(si.si_signo);
     addr = reinterpret_cast<uintptr_t>(si.si_addr);
   }
 
-  _LOG(log, logtype::MAPS, "\nmemory map:%s\n", has_fault_address ? " (fault address prefixed with --->)" : "");
-
-  if (has_fault_address && (addr < map->begin()->start)) {
-    _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " before any mapped regions\n", addr);
-  }
-
-  BacktraceMap::const_iterator prev = map->begin();
-  for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
-    if (addr >= (*prev).end && addr < (*it).start) {
-      _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " between mapped regions\n", addr);
+  _LOG(log, logtype::MAPS, "\n");
+  if (!print_fault_address_marker) {
+    _LOG(log, logtype::MAPS, "memory map:\n");
+  } else {
+    _LOG(log, logtype::MAPS, "memory map: (fault address prefixed with --->)\n");
+    if (map->begin() != map->end() && addr < map->begin()->start) {
+      _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " before any mapped regions\n",
+           addr);
+      print_fault_address_marker = false;
     }
-    prev = it;
-    bool in_map = has_fault_address && (addr >= (*it).start) && (addr < (*it).end);
-    dump_map(log, &*it, in_map);
   }
-  if (has_fault_address && (addr >= (*prev).end)) {
-    _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " after any mapped regions\n", addr);
+
+  std::string line;
+  for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
+    line = "    ";
+    if (print_fault_address_marker) {
+      if (addr < it->start) {
+        _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " between mapped regions\n",
+             addr);
+        print_fault_address_marker = false;
+      } else if (addr >= it->start && addr < it->end) {
+        line = "--->";
+        print_fault_address_marker = false;
+      }
+    }
+    line += android::base::StringPrintf("%" PRIPTR "-%" PRIPTR " ", it->start, it->end - 1);
+    if (it->flags & PROT_READ) {
+      line += 'r';
+    } else {
+      line += '-';
+    }
+    if (it->flags & PROT_WRITE) {
+      line += 'w';
+    } else {
+      line += '-';
+    }
+    if (it->flags & PROT_EXEC) {
+      line += 'x';
+    } else {
+      line += '-';
+    }
+    line += android::base::StringPrintf("  %8" PRIxPTR, it->end - it->start);
+    if (it->name.length() > 0) {
+      line += "  " + it->name;
+      std::string build_id;
+      if ((it->flags & PROT_READ) && elf_get_build_id(backtrace, it->start, &build_id)) {
+        line += " (BuildId: " + build_id + ")";
+      }
+    }
+    _LOG(log, logtype::MAPS, "%s\n", line.c_str());
+  }
+  if (print_fault_address_marker) {
+    _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " after any mapped regions\n",
+        addr);
   }
 }
 
@@ -453,7 +474,7 @@
   }
 
   logger_list = android_logger_list_open(
-      android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid);
+      android_name_to_log_id(filename), ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, tail, pid);
 
   if (!logger_list) {
     ALOGE("Unable to open %s: %s\n", filename, strerror(errno));
@@ -627,7 +648,7 @@
     dump_backtrace_and_stack(backtrace.get(), log);
   }
   dump_memory_and_code(log, tid);
-  dump_all_maps(map.get(), log, tid);
+  dump_all_maps(backtrace.get(), map.get(), log, tid);
 
   if (want_logs) {
     dump_logs(log, pid, 5);
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 58a882c..49b46e8 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -26,8 +26,10 @@
 #define ABI_STRING "arm"
 #elif defined(__aarch64__)
 #define ABI_STRING "arm64"
-#elif defined(__mips__)
+#elif defined(__mips__) && !defined(__LP64__)
 #define ABI_STRING "mips"
+#elif defined(__mips__) && defined(__LP64__)
+#define ABI_STRING "mips64"
 #elif defined(__i386__)
 #define ABI_STRING "x86"
 #elif defined(__x86_64__)
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index aa5b14a..b9e957f 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -19,10 +19,11 @@
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
   $(LOCAL_PATH)/../../extras/ext4_utils \
   $(LOCAL_PATH)/../../extras/f2fs_utils
-LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c fs.c
+LOCAL_SRC_FILES := protocol.c engine.c bootimg_utils.cpp fastboot.cpp util.c fs.c
 LOCAL_MODULE := fastboot
 LOCAL_MODULE_TAGS := debug
-LOCAL_CFLAGS += -std=gnu99 -Werror
+LOCAL_CONLYFLAGS += -std=gnu99
+LOCAL_CFLAGS += -Wall -Wextra -Werror
 
 ifeq ($(HOST_OS),linux)
   LOCAL_SRC_FILES += usb_linux.c util_linux.c
@@ -52,9 +53,11 @@
 
 LOCAL_STATIC_LIBRARIES := \
     $(EXTRA_STATIC_LIBS) \
-    libzipfile \
+    libziparchive-host \
     libext4_utils_host \
     libsparse_host \
+    libutils \
+    liblog \
     libz
 
 ifneq ($(HOST_OS),windows)
diff --git a/fastboot/bootimg.c b/fastboot/bootimg_utils.cpp
similarity index 95%
rename from fastboot/bootimg.c
rename to fastboot/bootimg_utils.cpp
index 240784f..d8905a6 100644
--- a/fastboot/bootimg.c
+++ b/fastboot/bootimg_utils.cpp
@@ -26,12 +26,12 @@
  * SUCH DAMAGE.
  */
 
+#include "bootimg_utils.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include <bootimg.h>
-
 void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline)
 {
     strcpy((char*) h->cmdline, cmdline);
@@ -47,7 +47,6 @@
     unsigned ramdisk_actual;
     unsigned second_actual;
     unsigned page_mask;
-    boot_img_hdr *hdr;
 
     page_mask = page_size - 1;
 
@@ -57,9 +56,8 @@
 
     *bootimg_size = page_size + kernel_actual + ramdisk_actual + second_actual;
 
-    hdr = calloc(*bootimg_size, 1);
-
-    if(hdr == 0) {
+    boot_img_hdr* hdr = reinterpret_cast<boot_img_hdr*>(calloc(*bootimg_size, 1));
+    if (hdr == 0) {
         return hdr;
     }
 
diff --git a/fastboot/bootimg_utils.h b/fastboot/bootimg_utils.h
new file mode 100644
index 0000000..b1a86cd
--- /dev/null
+++ b/fastboot/bootimg_utils.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef _FASTBOOT_BOOTIMG_UTILS_H_
+#define _FASTBOOT_BOOTIMG_UTILS_H_
+
+#include <bootimg.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
+boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset,
+                        void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset,
+                        void *second, unsigned second_size, unsigned second_offset,
+                        unsigned page_size, unsigned base, unsigned tags_offset,
+                        unsigned *bootimg_size);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.cpp
similarity index 90%
rename from fastboot/fastboot.c
rename to fastboot/fastboot.cpp
index 959d3ad..e139bcd 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.cpp
@@ -44,10 +44,10 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <bootimg.h>
 #include <sparse/sparse.h>
-#include <zipfile/zipfile.h>
+#include <ziparchive/zip_archive.h>
 
+#include "bootimg_utils.h"
 #include "fastboot.h"
 #include "fs.h"
 
@@ -59,14 +59,6 @@
 
 char cur_product[FB_RESPONSE_SZ + 1];
 
-void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
-
-boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset,
-                        void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset,
-                        void *second, unsigned second_size, unsigned second_offset,
-                        unsigned page_size, unsigned base, unsigned tags_offset,
-                        unsigned *bootimg_size);
-
 static usb_handle *usb = 0;
 static const char *serial = 0;
 static const char *product = 0;
@@ -106,12 +98,10 @@
     {"vendor.img", "vendor.sig", "vendor", true},
 };
 
-void get_my_path(char *path);
-
 char *find_item(const char *item, const char *product)
 {
     char *dir;
-    char *fn;
+    const char *fn;
     char path[PATH_MAX + 128];
 
     if(!strcmp(item,"boot")) {
@@ -234,7 +224,7 @@
 int list_devices_callback(usb_ifc_info *info)
 {
     if (match_fastboot_with_serial(info, NULL) == 0) {
-        char* serial = info->serial_number;
+        const char* serial = info->serial_number;
         if (!info->writable) {
             serial = "no permissions"; // like "adb devices"
         }
@@ -300,7 +290,7 @@
             "                                           flash it\n"
             "  devices                                  list all connected devices\n"
             "  continue                                 continue with autoboot\n"
-            "  reboot                                   reboot device normally\n"
+            "  reboot [bootloader]                      reboot device, optionally into bootloader\n"
             "  reboot-bootloader                        reboot device into bootloader\n"
             "  help                                     show this help message\n"
             "\n"
@@ -389,30 +379,26 @@
     return bdata;
 }
 
-void *unzip_file(zipfile_t zip, const char *name, unsigned *sz)
+static void* unzip_file(ZipArchiveHandle zip, const char* entry_name, unsigned* sz)
 {
-    void *data;
-    zipentry_t entry;
-    unsigned datasz;
-
-    entry = lookup_zipentry(zip, name);
-    if (entry == NULL) {
-        fprintf(stderr, "archive does not contain '%s'\n", name);
+    ZipEntryName zip_entry_name(entry_name);
+    ZipEntry zip_entry;
+    if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
+        fprintf(stderr, "archive does not contain '%s'\n", entry_name);
         return 0;
     }
 
-    *sz = get_zipentry_size(entry);
+    *sz = zip_entry.uncompressed_length;
 
-    datasz = *sz * 1.001;
-    data = malloc(datasz);
-
-    if(data == 0) {
-        fprintf(stderr, "failed to allocate %d bytes\n", *sz);
+    uint8_t* data = reinterpret_cast<uint8_t*>(malloc(zip_entry.uncompressed_length));
+    if (data == NULL) {
+        fprintf(stderr, "failed to allocate %u bytes for '%s'\n", *sz, entry_name);
         return 0;
     }
 
-    if (decompress_zipentry(entry, data, datasz)) {
-        fprintf(stderr, "failed to unzip '%s' from archive\n", name);
+    int error = ExtractToMemory(zip, &zip_entry, data, zip_entry.uncompressed_length);
+    if (error != 0) {
+        fprintf(stderr, "failed to extract '%s': %s\n", entry_name, ErrorCodeString(error));
         free(data);
         return 0;
     }
@@ -420,27 +406,28 @@
     return data;
 }
 
-static int unzip_to_file(zipfile_t zip, char *name)
-{
-    int fd;
-    char *data;
-    unsigned sz;
-
-    fd = fileno(tmpfile());
-    if (fd < 0) {
+static int unzip_to_file(ZipArchiveHandle zip, char* entry_name) {
+    FILE* fp = tmpfile();
+    if (fp == NULL) {
+        fprintf(stderr, "failed to create temporary file for '%s': %s\n",
+                entry_name, strerror(errno));
         return -1;
     }
 
-    data = unzip_file(zip, name, &sz);
-    if (data == 0) {
+    ZipEntryName zip_entry_name(entry_name);
+    ZipEntry zip_entry;
+    if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
+        fprintf(stderr, "archive does not contain '%s'\n", entry_name);
         return -1;
     }
 
-    if (write(fd, data, sz) != (ssize_t)sz) {
-        fd = -1;
+    int fd = fileno(fp);
+    int error = ExtractEntryToFile(zip, &zip_entry, fd);
+    if (error != 0) {
+        fprintf(stderr, "failed to extract '%s': %s\n", entry_name, ErrorCodeString(error));
+        return -1;
     }
 
-    free(data);
     lseek(fd, 0, SEEK_SET);
     return fd;
 }
@@ -461,7 +448,6 @@
 static int setup_requirement_line(char *name)
 {
     char *val[MAX_OPTIONS];
-    const char **out;
     char *prod = NULL;
     unsigned n, count;
     char *x;
@@ -501,10 +487,11 @@
     name = strip(name);
     if (name == 0) return -1;
 
-        /* work around an unfortunate name mismatch */
-    if (!strcmp(name,"board")) name = "product";
+    const char* var = name;
+    // Work around an unfortunate name mismatch.
+    if (!strcmp(name,"board")) var = "product";
 
-    out = malloc(sizeof(char*) * count);
+    const char** out = reinterpret_cast<const char**>(malloc(sizeof(char*) * count));
     if (out == 0) return -1;
 
     for(n = 0; n < count; n++) {
@@ -518,7 +505,7 @@
         }
     }
 
-    fb_queue_require(prod, name, invert, n, out);
+    fb_queue_require(prod, var, invert, n, out);
     return 0;
 }
 
@@ -551,21 +538,17 @@
 
 static struct sparse_file **load_sparse_files(int fd, int max_size)
 {
-    struct sparse_file *s;
-    int files;
-    struct sparse_file **out_s;
-
-    s = sparse_file_import_auto(fd, false);
+    struct sparse_file* s = sparse_file_import_auto(fd, false, true);
     if (!s) {
         die("cannot sparse read file\n");
     }
 
-    files = sparse_file_resparse(s, max_size, NULL, 0);
+    int files = sparse_file_resparse(s, max_size, NULL, 0);
     if (files < 0) {
         die("Failed to resparse\n");
     }
 
-    out_s = calloc(sizeof(struct sparse_file *), files + 1);
+    sparse_file** out_s = reinterpret_cast<sparse_file**>(calloc(sizeof(struct sparse_file *), files + 1));
     if (!out_s) {
         die("Failed to allocate sparse file array\n");
     }
@@ -682,11 +665,11 @@
 
 static void flash_buf(const char *pname, struct fastboot_buffer *buf)
 {
-    struct sparse_file **s;
+    sparse_file** s;
 
     switch (buf->type) {
         case FB_BUFFER_SPARSE:
-            s = buf->data;
+            s = reinterpret_cast<sparse_file**>(buf->data);
             while (*s) {
                 int64_t sz64 = sparse_file_len(*s, true, false);
                 fb_queue_flash_sparse(pname, *s++, sz64);
@@ -710,63 +693,44 @@
     flash_buf(pname, &buf);
 }
 
-void do_update_signature(zipfile_t zip, char *fn)
+void do_update_signature(ZipArchiveHandle zip, char *fn)
 {
-    void *data;
     unsigned sz;
-    data = unzip_file(zip, fn, &sz);
+    void* data = unzip_file(zip, fn, &sz);
     if (data == 0) return;
     fb_queue_download("signature", data, sz);
     fb_queue_command("signature", "installing signature");
 }
 
-void do_update(usb_handle *usb, char *fn, int erase_first)
+void do_update(usb_handle *usb, const char *filename, int erase_first)
 {
-    void *zdata;
-    unsigned zsize;
-    void *data;
-    unsigned sz;
-    zipfile_t zip;
-    int fd;
-    int rc;
-    struct fastboot_buffer buf;
-    size_t i;
-
     queue_info_dump();
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
 
-    zdata = load_file(fn, &zsize);
-    if (zdata == 0) die("failed to load '%s': %s", fn, strerror(errno));
-
-    zip = init_zipfile(zdata, zsize);
-    if(zip == 0) die("failed to access zipdata in '%s'");
-
-    data = unzip_file(zip, "android-info.txt", &sz);
-    if (data == 0) {
-        char *tmp;
-            /* fallback for older zipfiles */
-        data = unzip_file(zip, "android-product.txt", &sz);
-        if ((data == 0) || (sz < 1)) {
-            die("update package has no android-info.txt or android-product.txt");
-        }
-        tmp = malloc(sz + 128);
-        if (tmp == 0) die("out of memory");
-        sprintf(tmp,"board=%sversion-baseband=0.66.04.19\n",(char*)data);
-        data = tmp;
-        sz = strlen(tmp);
+    ZipArchiveHandle zip;
+    int error = OpenArchive(filename, &zip);
+    if (error != 0) {
+        die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
     }
 
-    setup_requirements(data, sz);
+    unsigned sz;
+    void* data = unzip_file(zip, "android-info.txt", &sz);
+    if (data == 0) {
+        die("update package '%s' has no android-info.txt", filename);
+    }
 
-    for (i = 0; i < ARRAY_SIZE(images); i++) {
-        fd = unzip_to_file(zip, images[i].img_name);
+    setup_requirements(reinterpret_cast<char*>(data), sz);
+
+    for (size_t i = 0; i < ARRAY_SIZE(images); i++) {
+        int fd = unzip_to_file(zip, images[i].img_name);
         if (fd < 0) {
             if (images[i].is_optional)
                 continue;
             die("update package missing %s", images[i].img_name);
         }
-        rc = load_buf_fd(usb, fd, &buf);
+        fastboot_buffer buf;
+        int rc = load_buf_fd(usb, fd, &buf);
         if (rc) die("cannot load %s from flash", images[i].img_name);
         do_update_signature(zip, images[i].sig_name);
         if (erase_first && needs_erase(images[i].part_name)) {
@@ -778,6 +742,8 @@
          * program exits.
          */
     }
+
+    CloseArchive(zip);
 }
 
 void do_send_signature(char *fn)
@@ -800,24 +766,22 @@
 
 void do_flashall(usb_handle *usb, int erase_first)
 {
-    char *fname;
-    void *data;
-    unsigned sz;
-    struct fastboot_buffer buf;
-    size_t i;
-
     queue_info_dump();
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
 
-    fname = find_item("info", product);
+    char* fname = find_item("info", product);
     if (fname == 0) die("cannot find android-info.txt");
-    data = load_file(fname, &sz);
-    if (data == 0) die("could not load android-info.txt: %s", strerror(errno));
-    setup_requirements(data, sz);
 
-    for (i = 0; i < ARRAY_SIZE(images); i++) {
+    unsigned sz;
+    void* data = load_file(fname, &sz);
+    if (data == 0) die("could not load android-info.txt: %s", strerror(errno));
+
+    setup_requirements(reinterpret_cast<char*>(data), sz);
+
+    for (size_t i = 0; i < ARRAY_SIZE(images); i++) {
         fname = find_item(images[i].part_name, product);
+        fastboot_buffer buf;
         if (load_buf(usb, fname, &buf)) {
             if (images[i].is_optional)
                 continue;
@@ -1153,6 +1117,14 @@
         } else if(!strcmp(*argv, "reboot")) {
             wants_reboot = 1;
             skip(1);
+            if (argc > 0) {
+                if (!strcmp(*argv, "bootloader")) {
+                    wants_reboot = 0;
+                    wants_reboot_bootloader = 1;
+                    skip(1);
+                }
+            }
+            require(0);
         } else if(!strcmp(*argv, "reboot-bootloader")) {
             wants_reboot_bootloader = 1;
             skip(1);
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index fc5d4f4..1786e49 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -31,6 +31,10 @@
 
 #include "usb.h"
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 struct sparse_file;
 
 /* protocol.c - fastboot protocol */
@@ -67,7 +71,13 @@
 char *mkmsg(const char *fmt, ...);
 void die(const char *fmt, ...);
 
+void get_my_path(char *path);
+
 /* Current product */
 extern char cur_product[FB_RESPONSE_SZ + 1];
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif
diff --git a/fastboot/fs.h b/fastboot/fs.h
index 8444081..307772b 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -3,10 +3,18 @@
 
 #include <stdint.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 struct fs_generator;
 
 const struct fs_generator* fs_get_generator(const char *fs_type);
 int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif
 
diff --git a/fastboot/protocol.c b/fastboot/protocol.c
index 10a84c1..5b97600 100644
--- a/fastboot/protocol.c
+++ b/fastboot/protocol.c
@@ -305,7 +305,10 @@
         return -1;
     }
 
-    fb_download_data_sparse_flush(usb);
+    r = fb_download_data_sparse_flush(usb);
+    if (r < 0) {
+        return -1;
+    }
 
     return _command_end(usb);
 }
diff --git a/fastboot/usb.h b/fastboot/usb.h
index 17cf0a9..c7b748e 100644
--- a/fastboot/usb.h
+++ b/fastboot/usb.h
@@ -29,6 +29,10 @@
 #ifndef _USB_H_
 #define _USB_H_
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 typedef struct usb_handle usb_handle;
 
 typedef struct usb_ifc_info usb_ifc_info;
@@ -64,4 +68,8 @@
 int usb_write(usb_handle *h, const void *_data, int len);
 int usb_wait_for_disconnect(usb_handle *h);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 61bf1ee..1179eaa 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -35,6 +35,7 @@
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
 
 LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static
+LOCAL_CXX_STL := libc++_static
 
 LOCAL_CFLAGS := -Werror
 
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index a1391e0..273a2ec 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -31,6 +31,7 @@
 #include <dirent.h>
 #include <ext4.h>
 #include <ext4_sb.h>
+#include <ext4_crypt.h>
 
 #include <linux/loop.h>
 #include <private/android_filesystem_config.h>
@@ -154,9 +155,10 @@
     } else if (!strcmp(fs_type, "f2fs")) {
             char *f2fs_fsck_argv[] = {
                     F2FS_FSCK_BIN,
+                    "-f",
                     blk_device
             };
-        INFO("Running %s on %s\n", F2FS_FSCK_BIN, blk_device);
+        INFO("Running %s -f %s\n", F2FS_FSCK_BIN, blk_device);
 
         ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv,
                                       &status, true, LOG_KLOG | LOG_FILE,
@@ -185,19 +187,22 @@
  * Mark the given block device as read-only, using the BLKROSET ioctl.
  * Return 0 on success, and -1 on error.
  */
-static void fs_set_blk_ro(const char *blockdev)
+int fs_mgr_set_blk_ro(const char *blockdev)
 {
     int fd;
+    int rc = -1;
     int ON = 1;
 
-    fd = open(blockdev, O_RDONLY);
+    fd = TEMP_FAILURE_RETRY(open(blockdev, O_RDONLY | O_CLOEXEC));
     if (fd < 0) {
         // should never happen
-        return;
+        return rc;
     }
 
-    ioctl(fd, BLKROSET, &ON);
-    close(fd);
+    rc = ioctl(fd, BLKROSET, &ON);
+    TEMP_FAILURE_RETRY(close(fd));
+
+    return rc;
 }
 
 /*
@@ -223,7 +228,7 @@
     save_errno = errno;
     INFO("%s(source=%s,target=%s,type=%s)=%d\n", __func__, source, target, rec->fs_type, ret);
     if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
-        fs_set_blk_ro(source);
+        fs_mgr_set_blk_ro(source);
     }
     errno = save_errno;
     return ret;
@@ -424,6 +429,73 @@
     return ret;
 }
 
+// Check to see if a mountable volume has encryption requirements
+static int handle_encryptable(struct fstab *fstab, const struct fstab_rec* rec)
+{
+    /* If this is block encryptable, need to trigger encryption */
+    if (   (rec->fs_mgr_flags & MF_FORCECRYPT)
+        || (device_is_force_encrypted() && fs_mgr_is_encryptable(rec))) {
+        if (umount(rec->mount_point) == 0) {
+            return FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION;
+        } else {
+            WARNING("Could not umount %s (%s) - allow continue unencrypted\n",
+                    rec->mount_point, strerror(errno));
+            return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
+        }
+    }
+
+    // Deal with file level encryption
+    if (rec->fs_mgr_flags & MF_FILEENCRYPTION) {
+        // Default or not yet initialized encryption requires no more work here
+        if (!e4crypt_non_default_key(rec->mount_point)) {
+            INFO("%s is default file encrypted\n", rec->mount_point);
+            return FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED;
+        }
+
+        INFO("%s is non-default file encrypted\n", rec->mount_point);
+
+        // Uses non-default key, so must unmount and set up temp file system
+        if (umount(rec->mount_point)) {
+            ERROR("Failed to umount %s - rebooting\n", rec->mount_point);
+            return FS_MGR_MNTALL_FAIL;
+        }
+
+        if (fs_mgr_do_tmpfs_mount(rec->mount_point) != 0) {
+            ERROR("Failed to mount a tmpfs at %s\n", rec->mount_point);
+            return FS_MGR_MNTALL_FAIL;
+        }
+
+        // Mount data temporarily so we can access unencrypted dir
+        char tmp_mnt[PATH_MAX];
+        strlcpy(tmp_mnt, rec->mount_point, sizeof(tmp_mnt));
+        strlcat(tmp_mnt, "/tmp_mnt", sizeof(tmp_mnt));
+        if (mkdir(tmp_mnt, 0700)) {
+            ERROR("Failed to create temp mount point\n");
+            return FS_MGR_MNTALL_FAIL;
+        }
+
+        if (fs_mgr_do_mount(fstab, rec->mount_point,
+                            rec->blk_device, tmp_mnt)) {
+            ERROR("Error temp mounting encrypted file system\n");
+            return FS_MGR_MNTALL_FAIL;
+        }
+
+        // Link it to the normal place so ext4_crypt functions work normally
+        strlcat(tmp_mnt, "/unencrypted", sizeof(tmp_mnt));
+        char link_path[PATH_MAX];
+        strlcpy(link_path, rec->mount_point, sizeof(link_path));
+        strlcat(link_path, "/unencrypted", sizeof(link_path));
+        if (symlink(tmp_mnt, link_path)) {
+            ERROR("Error creating symlink to unencrypted directory\n");
+            return FS_MGR_MNTALL_FAIL;
+        }
+
+        return FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED;
+    }
+
+    return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
+}
+
 /* 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.
@@ -486,23 +558,21 @@
 
         /* Deal with encryptability. */
         if (!mret) {
-            /* If this is encryptable, need to trigger encryption */
-          if (fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) {
-                if (umount(fstab->recs[attempted_idx].mount_point) == 0) {
-                    if (encryptable == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
-                        ERROR("Will try to encrypt %s %s\n", fstab->recs[attempted_idx].mount_point,
-                              fstab->recs[attempted_idx].fs_type);
-                        encryptable = FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION;
-                    } else {
-                        ERROR("Only one encryptable/encrypted partition supported\n");
-                        encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
-                    }
-                } else {
-                    WARNING("Could not umount %s (%s) - allow continue unencrypted\n",
-                            fstab->recs[attempted_idx].mount_point, strerror(errno));
-                    continue;
-                }
+            int status = handle_encryptable(fstab, &fstab->recs[attempted_idx]);
+
+            if (status == FS_MGR_MNTALL_FAIL) {
+                /* Fatal error - no point continuing */
+                return status;
             }
+
+            if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
+                if (encryptable != FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
+                    // Log and continue
+                    ERROR("Only one encryptable/encrypted partition supported\n");
+                }
+                encryptable = status;
+            }
+
             /* Success!  Go get the next one */
             continue;
         }
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 9d536bd..8b0f714 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -24,6 +24,7 @@
 
 struct fs_mgr_flag_values {
     char *key_loc;
+    char *verity_loc;
     long long part_length;
     char *label;
     int partnum;
@@ -60,6 +61,7 @@
     { "check",       MF_CHECK },
     { "encryptable=",MF_CRYPT },
     { "forceencrypt=",MF_FORCECRYPT },
+    { "fileencryption",MF_FILEENCRYPTION },
     { "nonremovable",MF_NONREMOVABLE },
     { "voldmanaged=",MF_VOLDMANAGED},
     { "length=",     MF_LENGTH },
@@ -107,6 +109,14 @@
                      * location of the keys.  Get it and return it.
                      */
                     flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+                } else if ((fl[i].flag == MF_VERIFY) && flag_vals) {
+                    /* If the verify flag is followed by an = and the
+                     * location for the verity state,  get it and return it.
+                     */
+                    char *start = strchr(p, '=');
+                    if (start) {
+                        flag_vals->verity_loc = strdup(start + 1);
+                    }
                 } else if ((fl[i].flag == MF_FORCECRYPT) && flag_vals) {
                     /* The forceencrypt flag is followed by an = and the
                      * location of the keys.  Get it and return it.
@@ -291,6 +301,7 @@
         fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
                                                     &flag_vals, NULL, 0);
         fstab->recs[cnt].key_loc = flag_vals.key_loc;
+        fstab->recs[cnt].verity_loc = flag_vals.verity_loc;
         fstab->recs[cnt].length = flag_vals.part_length;
         fstab->recs[cnt].label = flag_vals.label;
         fstab->recs[cnt].partnum = flag_vals.partnum;
@@ -408,32 +419,32 @@
     return fs_mgr_get_entry_for_mount_point_after(NULL, fstab, path);
 }
 
-int fs_mgr_is_voldmanaged(struct fstab_rec *fstab)
+int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & MF_VOLDMANAGED;
 }
 
-int fs_mgr_is_nonremovable(struct fstab_rec *fstab)
+int fs_mgr_is_nonremovable(const struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & MF_NONREMOVABLE;
 }
 
-int fs_mgr_is_verified(struct fstab_rec *fstab)
+int fs_mgr_is_verified(const struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & MF_VERIFY;
 }
 
-int fs_mgr_is_encryptable(struct fstab_rec *fstab)
+int fs_mgr_is_encryptable(const struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT);
 }
 
-int fs_mgr_is_force_encrypted(struct fstab_rec *fstab)
+int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab)
 {
-    return fstab->fs_mgr_flags & MF_FORCECRYPT;
+    return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
 }
 
-int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)
+int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
 }
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 4ba6f92..d56111a 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -76,8 +76,11 @@
 #define MF_FORCECRYPT   0x400
 #define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only
                                  external storage */
+#define MF_FILEENCRYPTION 0x2000
 
 #define DM_BUF_SIZE 4096
 
+int fs_mgr_set_blk_ro(const char *blockdev);
+
 #endif /* __CORE_FS_MGR_PRIV_H */
 
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index 4683acb..acdc5a3 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -42,9 +42,31 @@
 #include "fs_mgr_priv.h"
 #include "fs_mgr_priv_verity.h"
 
+#define FSTAB_PREFIX "/fstab."
+
 #define VERITY_METADATA_SIZE 32768
 #define VERITY_TABLE_RSA_KEY "/verity_key"
 
+#define METADATA_MAGIC 0x01564c54
+#define METADATA_TAG_MAX_LENGTH 63
+#define METADATA_EOD "eod"
+
+#define VERITY_STATE_TAG "verity_state"
+#define VERITY_STATE_HEADER 0x83c0ae9d
+#define VERITY_STATE_VERSION 1
+
+#define VERITY_KMSG_RESTART "dm-verity device corrupted"
+#define VERITY_KMSG_BUFSIZE 1024
+
+#define __STRINGIFY(x) #x
+#define STRINGIFY(x) __STRINGIFY(x)
+
+struct verity_state {
+    uint32_t header;
+    uint32_t version;
+    int32_t mode;
+};
+
 extern struct fs_info info;
 
 static RSAPublicKey *load_key(char *path)
@@ -86,11 +108,11 @@
 static int verify_table(char *signature, char *table, int table_length)
 {
     RSAPublicKey *key;
-    uint8_t hash_buf[SHA_DIGEST_SIZE];
+    uint8_t hash_buf[SHA256_DIGEST_SIZE];
     int retval = -1;
 
     // Hash the table
-    SHA_hash((uint8_t*)table, table_length, hash_buf);
+    SHA256_hash((uint8_t*)table, table_length, hash_buf);
 
     // Now get the public key from the keyfile
     key = load_key(VERITY_TABLE_RSA_KEY);
@@ -104,7 +126,7 @@
                     (uint8_t*) signature,
                     RSANUMBYTES,
                     (uint8_t*) hash_buf,
-                    SHA_DIGEST_SIZE)) {
+                    SHA256_DIGEST_SIZE)) {
         ERROR("Couldn't verify table.");
         goto out;
     }
@@ -294,10 +316,12 @@
     return 0;
 }
 
-static int load_verity_table(struct dm_ioctl *io, char *name, char *blockdev, int fd, char *table)
+static int load_verity_table(struct dm_ioctl *io, char *name, char *blockdev, int fd, char *table,
+        int mode)
 {
     char *verity_params;
     char *buffer = (char*) io;
+    size_t bufsize;
     uint64_t device_size = 0;
 
     if (get_target_device_size(blockdev, &device_size) < 0) {
@@ -317,7 +341,17 @@
 
     // build the verity params here
     verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
-    strcpy(verity_params, table);
+    bufsize = DM_BUF_SIZE - (verity_params - buffer);
+
+    if (mode == VERITY_MODE_EIO) {
+        // allow operation with older dm-verity drivers that are unaware
+        // of the mode parameter by omitting it; this also means that we
+        // cannot use logging mode with these drivers, they always cause
+        // an I/O error for corrupted blocks
+        strcpy(verity_params, table);
+    } else if (snprintf(verity_params, bufsize, "%s %d", table, mode) < 0) {
+        return -1;
+    }
 
     // set next target boundary
     verity_params += strlen(verity_params) + 1;
@@ -354,36 +388,418 @@
     return -1;
 }
 
-static int set_verified_property(char *name) {
-    int ret;
-    char *key;
-    ret = asprintf(&key, "partition.%s.verified", name);
-    if (ret < 0) {
-        ERROR("Error formatting verified property");
-        return ret;
+static int check_verity_restart(const char *fname)
+{
+    char buffer[VERITY_KMSG_BUFSIZE + 1];
+    int fd;
+    int rc = 0;
+    ssize_t size;
+    struct stat s;
+
+    fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
+
+    if (fd == -1) {
+        if (errno != ENOENT) {
+            ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
+        }
+        goto out;
     }
-    ret = PROP_NAME_MAX - strlen(key);
-    if (ret < 0) {
-        ERROR("Verified property name is too long");
+
+    if (fstat(fd, &s) == -1) {
+        ERROR("Failed to fstat %s (%s)\n", fname, strerror(errno));
+        goto out;
+    }
+
+    size = VERITY_KMSG_BUFSIZE;
+
+    if (size > s.st_size) {
+        size = s.st_size;
+    }
+
+    if (lseek(fd, s.st_size - size, SEEK_SET) == -1) {
+        ERROR("Failed to lseek %jd %s (%s)\n", (intmax_t)(s.st_size - size), fname,
+            strerror(errno));
+        goto out;
+    }
+
+    if (TEMP_FAILURE_RETRY(read(fd, buffer, size)) != size) {
+        ERROR("Failed to read %zd bytes from %s (%s)\n", size, fname,
+            strerror(errno));
+        goto out;
+    }
+
+    buffer[size] = '\0';
+
+    if (strstr(buffer, VERITY_KMSG_RESTART) != NULL) {
+        rc = 1;
+    }
+
+out:
+    if (fd != -1) {
+        TEMP_FAILURE_RETRY(close(fd));
+    }
+
+    return rc;
+}
+
+static int was_verity_restart()
+{
+    static const char *files[] = {
+        "/sys/fs/pstore/console-ramoops",
+        "/proc/last_kmsg",
+        NULL
+    };
+    int i;
+
+    for (i = 0; files[i]; ++i) {
+        if (check_verity_restart(files[i])) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static int metadata_add(FILE *fp, long start, const char *tag,
+        unsigned int length, off64_t *offset)
+{
+    if (fseek(fp, start, SEEK_SET) < 0 ||
+        fprintf(fp, "%s %u\n", tag, length) < 0) {
         return -1;
     }
-    ret = property_set(key, "1");
-    if (ret < 0)
-        ERROR("Error setting verified property %s: %d", key, ret);
-    free(key);
-    return ret;
+
+    *offset = ftell(fp);
+
+    if (fseek(fp, length, SEEK_CUR) < 0 ||
+        fprintf(fp, METADATA_EOD " 0\n") < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static int metadata_find(const char *fname, const char *stag,
+        unsigned int slength, off64_t *offset)
+{
+    FILE *fp = NULL;
+    char tag[METADATA_TAG_MAX_LENGTH + 1];
+    int rc = -1;
+    int n;
+    long start = 0x4000; /* skip cryptfs metadata area */
+    uint32_t magic;
+    unsigned int length = 0;
+
+    if (!fname) {
+        return -1;
+    }
+
+    fp = fopen(fname, "r+");
+
+    if (!fp) {
+        ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
+        goto out;
+    }
+
+    /* check magic */
+    if (fseek(fp, start, SEEK_SET) < 0 ||
+        fread(&magic, sizeof(magic), 1, fp) != 1) {
+        ERROR("Failed to read magic from %s (%s)\n", fname, strerror(errno));
+        goto out;
+    }
+
+    if (magic != METADATA_MAGIC) {
+        magic = METADATA_MAGIC;
+
+        if (fseek(fp, start, SEEK_SET) < 0 ||
+            fwrite(&magic, sizeof(magic), 1, fp) != 1) {
+            ERROR("Failed to write magic to %s (%s)\n", fname, strerror(errno));
+            goto out;
+        }
+
+        rc = metadata_add(fp, start + sizeof(magic), stag, slength, offset);
+        if (rc < 0) {
+            ERROR("Failed to add metadata to %s: %s\n", fname, strerror(errno));
+        }
+
+        goto out;
+    }
+
+    start += sizeof(magic);
+
+    while (1) {
+        n = fscanf(fp, "%" STRINGIFY(METADATA_TAG_MAX_LENGTH) "s %u\n",
+                tag, &length);
+
+        if (n == 2 && strcmp(tag, METADATA_EOD)) {
+            /* found a tag */
+            start = ftell(fp);
+
+            if (!strcmp(tag, stag) && length == slength) {
+                *offset = start;
+                rc = 0;
+                goto out;
+            }
+
+            start += length;
+
+            if (fseek(fp, length, SEEK_CUR) < 0) {
+                ERROR("Failed to seek %s (%s)\n", fname, strerror(errno));
+                goto out;
+            }
+        } else {
+            rc = metadata_add(fp, start, stag, slength, offset);
+            if (rc < 0) {
+                ERROR("Failed to write metadata to %s: %s\n", fname,
+                    strerror(errno));
+            }
+            goto out;
+        }
+   }
+
+out:
+    if (fp) {
+        fflush(fp);
+        fclose(fp);
+    }
+
+    return rc;
+}
+
+static int write_verity_state(const char *fname, off64_t offset, int32_t mode)
+{
+    int fd;
+    int rc = -1;
+    struct verity_state s = { VERITY_STATE_HEADER, VERITY_STATE_VERSION, mode };
+
+    fd = TEMP_FAILURE_RETRY(open(fname, O_WRONLY | O_SYNC | O_CLOEXEC));
+
+    if (fd == -1) {
+        ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
+        goto out;
+    }
+
+    if (TEMP_FAILURE_RETRY(pwrite64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
+        ERROR("Failed to write %zu bytes to %s to offset %" PRIu64 " (%s)\n",
+            sizeof(s), fname, offset, strerror(errno));
+        goto out;
+    }
+
+    rc = 0;
+
+out:
+    if (fd != -1) {
+        TEMP_FAILURE_RETRY(close(fd));
+    }
+
+    return rc;
+}
+
+static int load_verity_state(struct fstab_rec *fstab, int *mode)
+{
+    int fd = -1;
+    int rc = -1;
+    off64_t offset = 0;
+    struct verity_state s;
+
+    if (metadata_find(fstab->verity_loc, VERITY_STATE_TAG, sizeof(s),
+            &offset) < 0) {
+        /* fall back to stateless behavior */
+        *mode = VERITY_MODE_EIO;
+        rc = 0;
+        goto out;
+    }
+
+    if (was_verity_restart()) {
+        /* device was restarted after dm-verity detected a corrupted
+         * block, so switch to logging mode */
+        *mode = VERITY_MODE_LOGGING;
+        rc = write_verity_state(fstab->verity_loc, offset, *mode);
+        goto out;
+    }
+
+    fd = TEMP_FAILURE_RETRY(open(fstab->verity_loc, O_RDONLY | O_CLOEXEC));
+
+    if (fd == -1) {
+        ERROR("Failed to open %s (%s)\n", fstab->verity_loc, strerror(errno));
+        goto out;
+    }
+
+    if (TEMP_FAILURE_RETRY(pread64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
+        ERROR("Failed to read %zu bytes from %s offset %" PRIu64 " (%s)\n",
+            sizeof(s), fstab->verity_loc, offset, strerror(errno));
+        goto out;
+    }
+
+    if (s.header != VERITY_STATE_HEADER) {
+        /* space allocated, but no state written. write default state */
+        *mode = VERITY_MODE_DEFAULT;
+        rc = write_verity_state(fstab->verity_loc, offset, *mode);
+        goto out;
+    }
+
+    if (s.version != VERITY_STATE_VERSION) {
+        ERROR("Unsupported verity state version (%u)\n", s.version);
+        goto out;
+    }
+
+    if (s.mode < VERITY_MODE_EIO ||
+        s.mode > VERITY_MODE_LAST) {
+        ERROR("Unsupported verity mode (%u)\n", s.mode);
+        goto out;
+    }
+
+    *mode = s.mode;
+    rc = 0;
+
+out:
+    if (fd != -1) {
+        TEMP_FAILURE_RETRY(close(fd));
+    }
+
+    return rc;
+}
+
+int fs_mgr_load_verity_state(int *mode)
+{
+    char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+    char propbuf[PROPERTY_VALUE_MAX];
+    int rc = -1;
+    int i;
+    struct fstab *fstab = NULL;
+
+    *mode = VERITY_MODE_DEFAULT;
+
+    property_get("ro.hardware", propbuf, "");
+    snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
+
+    fstab = fs_mgr_read_fstab(fstab_filename);
+
+    if (!fstab) {
+        ERROR("Failed to read %s\n", fstab_filename);
+        goto out;
+    }
+
+    for (i = 0; i < fstab->num_entries; i++) {
+        if (!fs_mgr_is_verified(&fstab->recs[i])) {
+            continue;
+        }
+
+        rc = load_verity_state(&fstab->recs[i], mode);
+        if (rc < 0) {
+            continue;
+        }
+
+        /* if any of the verified partitions are in logging mode, return */
+        if (*mode == VERITY_MODE_LOGGING) {
+            rc = 0;
+            goto out;
+        }
+    }
+
+    /* if there were multiple partitions, all in non-logging mode, return the
+     * state of the last one */
+    rc = 0;
+
+out:
+    if (fstab) {
+        fs_mgr_free_fstab(fstab);
+    }
+
+    return rc;
+}
+
+int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback)
+{
+    _Alignas(struct dm_ioctl) char buffer[DM_BUF_SIZE];
+    char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+    char *mount_point;
+    char propbuf[PROPERTY_VALUE_MAX];
+    char *status;
+    int fd = -1;
+    int i;
+    int rc = -1;
+    off64_t offset = 0;
+    struct dm_ioctl *io = (struct dm_ioctl *) buffer;
+    struct fstab *fstab = NULL;
+
+    fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
+
+    if (fd == -1) {
+        ERROR("Error opening device mapper (%s)\n", strerror(errno));
+        goto out;
+    }
+
+    property_get("ro.hardware", propbuf, "");
+    snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
+
+    fstab = fs_mgr_read_fstab(fstab_filename);
+
+    if (!fstab) {
+        ERROR("Failed to read %s\n", fstab_filename);
+        goto out;
+    }
+
+    for (i = 0; i < fstab->num_entries; i++) {
+        if (!fs_mgr_is_verified(&fstab->recs[i])) {
+            continue;
+        }
+
+        if (metadata_find(fstab->recs[i].verity_loc, VERITY_STATE_TAG,
+                sizeof(struct verity_state), &offset) < 0) {
+            continue;
+        }
+
+        mount_point = basename(fstab->recs[i].mount_point);
+        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));
+            goto out;
+        }
+
+        status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
+
+        if (*status == 'C') {
+            rc = write_verity_state(fstab->recs[i].verity_loc, offset,
+                    VERITY_MODE_LOGGING);
+
+            if (rc == -1) {
+                goto out;
+            }
+        }
+
+        if (callback) {
+            callback(&fstab->recs[i], mount_point, *status);
+        }
+    }
+
+    /* Don't overwrite possible previous state if there's no corruption. */
+    rc = 0;
+
+out:
+    if (fstab) {
+        fs_mgr_free_fstab(fstab);
+    }
+
+    if (fd) {
+        TEMP_FAILURE_RETRY(close(fd));
+    }
+
+    return rc;
 }
 
 int fs_mgr_setup_verity(struct fstab_rec *fstab) {
 
-    int retval = -1;
+    int retval = FS_MGR_SETUP_VERITY_FAIL;
     int fd = -1;
+    int mode;
 
     char *verity_blk_name = 0;
     char *verity_table = 0;
     char *verity_table_signature = 0;
 
-    char buffer[DM_BUF_SIZE];
+    _Alignas(struct dm_ioctl) char buffer[DM_BUF_SIZE];
     struct dm_ioctl *io = (struct dm_ioctl *) buffer;
     char *mount_point = basename(fstab->mount_point);
 
@@ -407,6 +823,8 @@
         goto out;
     }
 
+    retval = FS_MGR_SETUP_VERITY_FAIL;
+
     // get the device mapper fd
     if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
         ERROR("Error opening device mapper (%s)", strerror(errno));
@@ -432,8 +850,19 @@
         goto out;
     }
 
+    if (load_verity_state(fstab, &mode) < 0) {
+        /* if accessing or updating the state failed, switch to the default
+         * safe mode. This makes sure the device won't end up in an endless
+         * restart loop, and no corrupted data will be exposed to userspace
+         * without a warning. */
+        mode = VERITY_MODE_EIO;
+    }
+
+    INFO("Enabling dm-verity for %s (mode %d)\n",  mount_point, mode);
+
     // load the verity mapping table
-    if (load_verity_table(io, mount_point, fstab->blk_device, fd, verity_table) < 0) {
+    if (load_verity_table(io, mount_point, fstab->blk_device, fd, verity_table,
+            mode) < 0) {
         goto out;
     }
 
@@ -442,6 +871,9 @@
         goto out;
     }
 
+    // mark the underlying block device as read-only
+    fs_mgr_set_blk_ro(fstab->blk_device);
+
     // assign the new verity block device as the block device
     free(fstab->blk_device);
     fstab->blk_device = verity_blk_name;
@@ -452,8 +884,7 @@
         goto out;
     }
 
-    // set the property indicating that the partition is verified
-    retval = set_verified_property(mount_point);
+    retval = FS_MGR_SETUP_VERITY_SUCCESS;
 
 out:
     if (fd != -1) {
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 5ec3b99..b5e02f9 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -31,6 +31,15 @@
 extern "C" {
 #endif
 
+// Verity modes
+enum verity_mode {
+    VERITY_MODE_EIO = 0,
+    VERITY_MODE_LOGGING = 1,
+    VERITY_MODE_RESTART = 2,
+    VERITY_MODE_LAST = VERITY_MODE_RESTART,
+    VERITY_MODE_DEFAULT = VERITY_MODE_RESTART
+};
+
 /*
  * The entries must be kept in the same order as they were seen in the fstab.
  * Unless explicitly requested, a lookup on mount point should always
@@ -58,13 +67,20 @@
     unsigned int zram_size;
 };
 
+// Callback function for verity status
+typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab,
+        const char *mount_point, int status);
+
 struct fstab *fs_mgr_read_fstab(const char *fstab_path);
 void fs_mgr_free_fstab(struct fstab *fstab);
 
+#define FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED 5
+#define FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED 4
 #define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 3
 #define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 2
 #define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 1
 #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 0
+#define FS_MGR_MNTALL_FAIL -1
 int fs_mgr_mount_all(struct fstab *fstab);
 
 #define FS_MGR_DOMNT_FAILED -1
@@ -75,16 +91,18 @@
 int fs_mgr_unmount_all(struct fstab *fstab);
 int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc,
                           char *real_blk_device, int size);
+int fs_mgr_load_verity_state(int *mode);
+int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
 int fs_mgr_add_entry(struct fstab *fstab,
                      const char *mount_point, const char *fs_type,
                      const char *blk_device);
 struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path);
-int fs_mgr_is_voldmanaged(struct fstab_rec *fstab);
-int fs_mgr_is_nonremovable(struct fstab_rec *fstab);
-int fs_mgr_is_verified(struct fstab_rec *fstab);
-int fs_mgr_is_encryptable(struct fstab_rec *fstab);
-int fs_mgr_is_force_encrypted(struct fstab_rec *fstab);
-int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab);
+int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab);
+int fs_mgr_is_nonremovable(const struct fstab_rec *fstab);
+int fs_mgr_is_verified(const struct fstab_rec *fstab);
+int fs_mgr_is_encryptable(const struct fstab_rec *fstab);
+int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab);
+int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
 int fs_mgr_swapon_all(struct fstab *fstab);
 #ifdef __cplusplus
 }
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 06497c2..7ea8250 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -265,10 +265,10 @@
                  "battery none");
         }
 
-        KLOG_INFO(LOG_TAG, "%s chg=%s%s%s\n", dmesgline,
-                  props.chargerAcOnline ? "a" : "",
-                  props.chargerUsbOnline ? "u" : "",
-                  props.chargerWirelessOnline ? "w" : "");
+        KLOG_WARNING(LOG_TAG, "%s chg=%s%s%s\n", dmesgline,
+                     props.chargerAcOnline ? "a" : "",
+                     props.chargerUsbOnline ? "u" : "",
+                     props.chargerWirelessOnline ? "w" : "");
     }
 
     healthd_mode_ops->battery_update(&props);
@@ -511,7 +511,7 @@
     if (!mChargerNames.size())
         KLOG_ERROR(LOG_TAG, "No charger supplies found\n");
     if (!mBatteryDevicePresent) {
-        KLOG_INFO(LOG_TAG, "No battery devices found\n");
+        KLOG_WARNING(LOG_TAG, "No battery devices found\n");
         hc->periodic_chores_interval_fast = -1;
         hc->periodic_chores_interval_slow = -1;
     } else {
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index b34583d..1fee855 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -53,6 +53,7 @@
     .batteryCurrentAvgPath = String8(String8::kEmptyString),
     .batteryChargeCounterPath = String8(String8::kEmptyString),
     .energyCounter = NULL,
+    .screen_on = NULL,
 };
 
 static int eventct;
@@ -313,8 +314,8 @@
         return -1;
     }
 
-    healthd_mode_ops->init(&healthd_config);
     healthd_board_init(&healthd_config);
+    healthd_mode_ops->init(&healthd_config);
     wakealarm_init();
     uevent_init();
     gBatteryMonitor = new BatteryMonitor();
diff --git a/healthd/healthd.h b/healthd/healthd.h
index 972e728..4704f0b 100644
--- a/healthd/healthd.h
+++ b/healthd/healthd.h
@@ -67,6 +67,7 @@
     android::String8 batteryChargeCounterPath;
 
     int (*energyCounter)(int64_t *);
+    bool (*screen_on)(android::BatteryProperties *props);
 };
 
 // Global helper functions
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 291cb6c..9ed5944 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -68,14 +68,13 @@
 #define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
 
 #define BATTERY_FULL_THRESH     95
-#define SCREEN_ON_BATTERY_THRESH 0
 
 #define LAST_KMSG_PATH          "/proc/last_kmsg"
 #define LAST_KMSG_PSTORE_PATH   "/sys/fs/pstore/console-ramoops"
 #define LAST_KMSG_MAX_SZ        (32 * 1024)
 
 #define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0)
-#define LOGI(x...) do { KLOG_INFO("charger", x); } while (0)
+#define LOGW(x...) do { KLOG_WARNING("charger", x); } while (0)
 #define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
 
 struct key_state {
@@ -109,7 +108,6 @@
 struct charger {
     bool have_battery_state;
     bool charger_connected;
-    int capacity;
     int64_t next_screen_transition;
     int64_t next_key_check;
     int64_t next_pwr_check;
@@ -170,7 +168,8 @@
 };
 
 static struct charger charger_state;
-
+static struct healthd_config *healthd_config;
+static struct android::BatteryProperties *batt_prop;
 static int char_width;
 static int char_height;
 static bool minui_inited;
@@ -198,15 +197,15 @@
     unsigned sz = 0;
     int len;
 
-    LOGI("\n");
-    LOGI("*************** LAST KMSG ***************\n");
-    LOGI("\n");
+    LOGW("\n");
+    LOGW("*************** LAST KMSG ***************\n");
+    LOGW("\n");
     buf = (char *)load_file(LAST_KMSG_PSTORE_PATH, &sz);
 
     if (!buf || !sz) {
         buf = (char *)load_file(LAST_KMSG_PATH, &sz);
         if (!buf || !sz) {
-            LOGI("last_kmsg not found. Cold reset?\n");
+            LOGW("last_kmsg not found. Cold reset?\n");
             goto out;
         }
     }
@@ -225,7 +224,7 @@
 
         yoink = ptr[cnt];
         ptr[cnt] = '\0';
-        klog_write(6, "<6>%s", ptr);
+        klog_write(6, "<4>%s", ptr);
         ptr[cnt] = yoink;
 
         len -= cnt;
@@ -235,14 +234,9 @@
     free(buf);
 
 out:
-    LOGI("\n");
-    LOGI("************* END LAST KMSG *************\n");
-    LOGI("\n");
-}
-
-static int get_battery_capacity()
-{
-    return charger_state.capacity;
+    LOGW("\n");
+    LOGW("************* END LAST KMSG *************\n");
+    LOGW("\n");
 }
 
 #ifdef CHARGER_ENABLE_SUSPEND
@@ -356,15 +350,16 @@
         return;
 
     if (!minui_inited) {
-        int batt_cap = get_battery_capacity();
 
-        if (batt_cap < SCREEN_ON_BATTERY_THRESH) {
-            LOGV("[%" PRId64 "] level %d, leave screen off\n", now, batt_cap);
-            batt_anim->run = false;
-            charger->next_screen_transition = -1;
-            if (charger->charger_connected)
-                request_suspend(true);
-            return;
+        if (healthd_config && healthd_config->screen_on) {
+            if (!healthd_config->screen_on(batt_prop)) {
+                LOGV("[%" PRId64 "] leave screen off\n", now);
+                batt_anim->run = false;
+                charger->next_screen_transition = -1;
+                if (charger->charger_connected)
+                    request_suspend(true);
+                return;
+            }
         }
 
         gr_init();
@@ -391,16 +386,14 @@
 
     /* animation starting, set up the animation */
     if (batt_anim->cur_frame == 0) {
-        int batt_cap;
 
         LOGV("[%" PRId64 "] animation starting\n", now);
-        batt_cap = get_battery_capacity();
-        if (batt_cap >= 0 && batt_anim->num_frames != 0) {
+        if (batt_prop && batt_prop->batteryLevel >= 0 && batt_anim->num_frames != 0) {
             int i;
 
             /* find first frame given current capacity */
             for (i = 1; i < batt_anim->num_frames; i++) {
-                if (batt_cap < batt_anim->frames[i].min_capacity)
+                if (batt_prop->batteryLevel < batt_anim->frames[i].min_capacity)
                     break;
             }
             batt_anim->cur_frame = i - 1;
@@ -408,8 +401,8 @@
             /* show the first frame for twice as long */
             disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2;
         }
-
-        batt_anim->capacity = batt_cap;
+        if (batt_prop)
+            batt_anim->capacity = batt_prop->batteryLevel;
     }
 
     /* unblank the screen  on first cycle */
@@ -524,10 +517,10 @@
                    all devices. Check the property and continue booting or reboot
                    accordingly. */
                 if (property_get_bool("ro.enable_boot_charger_mode", false)) {
-                    LOGI("[%" PRId64 "] booting from charger mode\n", now);
+                    LOGW("[%" PRId64 "] booting from charger mode\n", now);
                     property_set("sys.boot_from_charger_mode", "1");
                 } else {
-                    LOGI("[%" PRId64 "] rebooting\n", now);
+                    LOGW("[%" PRId64 "] rebooting\n", now);
                     android_reboot(ANDROID_RB_RESTART, 0, 0);
                 }
             } else {
@@ -565,10 +558,10 @@
         request_suspend(false);
         if (charger->next_pwr_check == -1) {
             charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
-            LOGI("[%" PRId64 "] device unplugged: shutting down in %" PRId64 " (@ %" PRId64 ")\n",
+            LOGW("[%" PRId64 "] device unplugged: shutting down in %" PRId64 " (@ %" PRId64 ")\n",
                  now, (int64_t)UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
         } else if (now >= charger->next_pwr_check) {
-            LOGI("[%" PRId64 "] shutting down\n", now);
+            LOGW("[%" PRId64 "] shutting down\n", now);
             android_reboot(ANDROID_RB_POWEROFF, 0, 0);
         } else {
             /* otherwise we already have a shutdown timer scheduled */
@@ -576,7 +569,7 @@
     } else {
         /* online supply present, reset shutdown timer if set */
         if (charger->next_pwr_check != -1) {
-            LOGI("[%" PRId64 "] device plugged in: shutdown cancelled\n", now);
+            LOGW("[%" PRId64 "] device plugged in: shutdown cancelled\n", now);
             kick_animation(charger->batt_anim);
         }
         charger->next_pwr_check = -1;
@@ -605,7 +598,6 @@
     charger->charger_connected =
         props->chargerAcOnline || props->chargerUsbOnline ||
         props->chargerWirelessOnline;
-    charger->capacity = props->batteryLevel;
 
     if (!charger->have_battery_state) {
         charger->have_battery_state = true;
@@ -613,6 +605,7 @@
         reset_animation(charger->batt_anim);
         kick_animation(charger->batt_anim);
     }
+    batt_prop = props;
 }
 
 int healthd_mode_charger_preparetowait(void)
@@ -663,7 +656,7 @@
         ev_dispatch();
 }
 
-void healthd_mode_charger_init(struct healthd_config* /*config*/)
+void healthd_mode_charger_init(struct healthd_config* config)
 {
     int ret;
     struct charger *charger = &charger_state;
@@ -672,7 +665,7 @@
 
     dump_last_kmsg();
 
-    LOGI("--------------- STARTING CHARGER MODE ---------------\n");
+    LOGW("--------------- STARTING CHARGER MODE ---------------\n");
 
     ret = ev_init(input_callback, charger);
     if (!ret) {
@@ -711,4 +704,5 @@
     charger->next_screen_transition = -1;
     charger->next_key_check = -1;
     charger->next_pwr_check = -1;
+    healthd_config = config;
 }
diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h
index e2d718b..290682a 100644
--- a/include/backtrace/Backtrace.h
+++ b/include/backtrace/Backtrace.h
@@ -44,9 +44,6 @@
   uintptr_t func_offset;  // pc relative to the start of the function, only valid if func_name is not NULL.
 };
 
-// Forward declarations.
-class BacktraceImpl;
-
 #if defined(__APPLE__)
 struct __darwin_ucontext;
 typedef __darwin_ucontext ucontext_t;
@@ -72,7 +69,7 @@
   virtual ~Backtrace();
 
   // Get the current stack trace and store in the backtrace_ structure.
-  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL);
+  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL) = 0;
 
   // Get the function name and offset into the function given the pc.
   // If the string is empty, then no valid function name was found.
@@ -84,14 +81,20 @@
   // Read the data at a specific address.
   virtual bool ReadWord(uintptr_t ptr, word_t* out_value) = 0;
 
+  // Read arbitrary data from a specific address. If a read request would
+  // span from one map to another, this call only reads up until the end
+  // of the current map.
+  // Returns the total number of bytes actually read.
+  virtual size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) = 0;
+
   // Create a string representing the formatted line of backtrace information
   // for a single frame.
   virtual std::string FormatFrameData(size_t frame_num);
   virtual std::string FormatFrameData(const backtrace_frame_data_t* frame);
 
-  pid_t Pid() { return pid_; }
-  pid_t Tid() { return tid_; }
-  size_t NumFrames() { return frames_.size(); }
+  pid_t Pid() const { return pid_; }
+  pid_t Tid() const { return tid_; }
+  size_t NumFrames() const { return frames_.size(); }
 
   const backtrace_frame_data_t* GetFrame(size_t frame_num) {
     if (frame_num >= frames_.size()) {
@@ -111,7 +114,11 @@
   BacktraceMap* GetMap() { return map_; }
 
 protected:
-  Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map);
+  Backtrace(pid_t pid, pid_t tid, BacktraceMap* map);
+
+  // The name returned is not demangled, GetFunctionName() takes care of
+  // demangling the name.
+  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) = 0;
 
   virtual bool VerifyReadWordArgs(uintptr_t ptr, word_t* out_value);
 
@@ -124,10 +131,6 @@
   bool map_shared_;
 
   std::vector<backtrace_frame_data_t> frames_;
-
-  BacktraceImpl* impl_;
-
-  friend class BacktraceImpl;
 };
 
 #endif // _BACKTRACE_BACKTRACE_H
diff --git a/include/ctest/ctest.h b/include/ctest/ctest.h
deleted file mode 100644
index 1a83b20..0000000
--- a/include/ctest/ctest.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-/**
- * Very simple unit testing framework. 
- */
-
-#ifndef __CUTILS_TEST_H
-#define __CUTILS_TEST_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Adds a test to the test suite.
- */
-#define addTest(test) addNamedTest(#test, &test)
-   
-/**
- * Asserts that a condition is true. The test fails if it isn't.
- */
-#define assertTrue(value, message) assertTrueWithSource(value, __FILE__, __LINE__, message);
-
-/**
- * Asserts that a condition is false. The test fails if the value is true.
- */
-#define assertFalse(value, message) assertTrueWithSource(!value, __FILE__, __LINE__, message);
-
-/** Fails a test with the given message. */
-#define fail(message) assertTrueWithSource(0, __FILE__, __LINE__, message);
-
-/**
- * Asserts that two values are ==.
- */
-#define assertSame(a, b) assertTrueWithSource(a == b, __FILE__, __LINE__, "Expected same value.");
-    
-/**
- * Asserts that two values are !=.
- */
-#define assertNotSame(a, b) assertTrueWithSource(a != b, __FILE__, __LINE__,\
-        "Expected different values");
-    
-/**
- * Runs a test suite.
- */
-void runTests(void);
-
-// Do not call these functions directly. Use macros above instead.
-void addNamedTest(const char* name, void (*test)(void));
-void assertTrueWithSource(int value, const char* file, int line, char* message);
-    
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __CUTILS_TEST_H */ 
diff --git a/include/cutils/klog.h b/include/cutils/klog.h
index d5ae6d7..295d62b 100644
--- a/include/cutils/klog.h
+++ b/include/cutils/klog.h
@@ -18,6 +18,7 @@
 #define _CUTILS_KLOG_H_
 
 #include <sys/cdefs.h>
+#include <sys/uio.h>
 #include <stdarg.h>
 
 __BEGIN_DECLS
@@ -26,9 +27,10 @@
 int  klog_get_level(void);
 void klog_set_level(int level);
 /* TODO: void klog_close(void); - and make klog_fd users thread safe. */
+
 void klog_write(int level, const char *fmt, ...)
     __attribute__ ((format(printf, 2, 3)));
-void klog_vwrite(int level, const char *fmt, va_list ap);
+void klog_writev(int level, const struct iovec* iov, int iov_count);
 
 __END_DECLS
 
diff --git a/include/cutils/memory.h b/include/cutils/memory.h
index e725cdd..4d26882 100644
--- a/include/cutils/memory.h
+++ b/include/cutils/memory.h
@@ -30,7 +30,7 @@
 /* size is given in bytes and must be multiple of 4 */
 void android_memset32(uint32_t* dst, uint32_t value, size_t size);
 
-#if !HAVE_STRLCPY
+#if defined(__GLIBC__) || defined(_WIN32)
 /* Declaration of strlcpy() for platforms that don't already have it. */
 size_t strlcpy(char *dst, const char *src, size_t size);
 #endif
diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h
index c47588c..f8076ca 100644
--- a/include/cutils/sockets.h
+++ b/include/cutils/sockets.h
@@ -18,6 +18,7 @@
 #define __CUTILS_SOCKETS_H
 
 #include <errno.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdbool.h>
@@ -46,30 +47,19 @@
  */
 static inline int android_get_control_socket(const char *name)
 {
-	char key[64] = ANDROID_SOCKET_ENV_PREFIX;
-	const char *val;
-	int fd;
+	char key[64];
+	snprintf(key, sizeof(key), ANDROID_SOCKET_ENV_PREFIX "%s", name);
 
-	/* build our environment variable, counting cycles like a wolf ... */
-#if HAVE_STRLCPY
-	strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
-		name,
-		sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
-#else	/* for the host, which may lack the almightly strncpy ... */
-	strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
-		name,
-		sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
-	key[sizeof(key)-1] = '\0';
-#endif
-
-	val = getenv(key);
-	if (!val)
+	const char* val = getenv(key);
+	if (!val) {
 		return -1;
+	}
 
 	errno = 0;
-	fd = strtol(val, NULL, 10);
-	if (errno)
+	int fd = strtol(val, NULL, 10);
+	if (errno) {
 		return -1;
+	}
 
 	return fd;
 }
diff --git a/include/cutils/str_parms.h b/include/cutils/str_parms.h
index 66f3637..aa1435a 100644
--- a/include/cutils/str_parms.h
+++ b/include/cutils/str_parms.h
@@ -18,6 +18,9 @@
 #define __CUTILS_STR_PARMS_H
 
 #include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
 
 struct str_parms;
 
@@ -52,4 +55,6 @@
 /* debug */
 void str_parms_dump(struct str_parms *str_parms);
 
+__END_DECLS
+
 #endif /* __CUTILS_STR_PARMS_H */
diff --git a/include/cutils/threads.h b/include/cutils/threads.h
index ade9a0c..3133cdb 100644
--- a/include/cutils/threads.h
+++ b/include/cutils/threads.h
@@ -32,14 +32,16 @@
 #if !defined(_WIN32)
 
 #include  <pthread.h>
+#include  <sys/types.h>
 
 typedef struct {
     pthread_mutex_t   lock;
     int               has_tls;
     pthread_key_t     tls;
-
 } thread_store_t;
 
+extern pid_t gettid();
+
 #define  THREAD_STORE_INITIALIZER  { PTHREAD_MUTEX_INITIALIZER, 0, 0 }
 
 #else // !defined(_WIN32)
@@ -51,7 +53,6 @@
     int               has_tls;
     DWORD             tls;
     CRITICAL_SECTION  lock;
-
 } thread_store_t;
 
 #define  THREAD_STORE_INITIALIZER  { 0, 0, 0, {0, 0, 0, 0, 0, 0} }
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index 59ff6c1..9d039e6 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -80,7 +80,6 @@
 #error ATRACE_TAG must be defined to be one of the tags defined in cutils/trace.h
 #endif
 
-#ifdef HAVE_ANDROID_OS
 /**
  * Opens the trace file for writing and reads the property for initial tags.
  * The atrace.tags.enableflags property sets the tags to trace.
@@ -248,19 +247,6 @@
     }
 }
 
-#else // not HAVE_ANDROID_OS
-
-#define ATRACE_INIT()
-#define ATRACE_GET_ENABLED_TAGS()
-#define ATRACE_ENABLED() 0
-#define ATRACE_BEGIN(name)
-#define ATRACE_END()
-#define ATRACE_ASYNC_BEGIN(name, cookie)
-#define ATRACE_ASYNC_END(name, cookie)
-#define ATRACE_INT(name, value)
-
-#endif // not HAVE_ANDROID_OS
-
 __END_DECLS
 
 #endif // _LIBS_CUTILS_TRACE_H
diff --git a/include/log/logger.h b/include/log/logger.h
index 53be1d3..f030dab 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -154,6 +154,13 @@
 int android_logger_set_prune_list(struct logger_list *logger_list,
                                   char *buf, size_t len);
 
+#define ANDROID_LOG_RDONLY   O_RDONLY
+#define ANDROID_LOG_WRONLY   O_WRONLY
+#define ANDROID_LOG_RDWR     O_RDWR
+#define ANDROID_LOG_ACCMODE  O_ACCMODE
+#define ANDROID_LOG_NONBLOCK O_NONBLOCK
+#define ANDROID_LOG_PSTORE   0x80000000
+
 struct logger_list *android_logger_list_alloc(int mode,
                                               unsigned int tail,
                                               pid_t pid);
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 5efe2e1..a3d11a7 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -230,21 +230,14 @@
 static const struct fs_path_config android_files[] = {
     { 00440, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.rc" },
     { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.sh" },
-    { 00440, AID_ROOT,      AID_SHELL,     0, "system/etc/init.trout.rc" },
     { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.ril" },
     { 00550, AID_DHCP,      AID_SHELL,     0, "system/etc/dhcpcd/dhcpcd-run-hooks" },
-    { 00444, AID_RADIO,     AID_AUDIO,     0, "system/etc/AudioPara4.csv" },
     { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/ppp/*" },
     { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/rc.*" },
     { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app/*" },
     { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  0, "data/media/*" },
     { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-private/*" },
     { 00644, AID_APP,       AID_APP,       0, "data/data/*" },
-    { 00755, AID_ROOT,      AID_ROOT,      0, "system/bin/ping" },
-
-    /* the following file is INTENTIONALLY set-gid and not set-uid.
-     * Do not change. */
-    { 02750, AID_ROOT,      AID_INET,      0, "system/bin/netcfg" },
 
     /* the following five files are INTENTIONALLY set-uid, but they
      * are NOT included on user builds. */
@@ -252,7 +245,6 @@
     { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/librank" },
     { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procrank" },
     { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procmem" },
-    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/tcpdump" },
     { 04770, AID_ROOT,      AID_RADIO,     0, "system/bin/pppd-ril" },
 
     /* the following files have enhanced capabilities and ARE included in user builds. */
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
index cc7ba30..724ca51 100644
--- a/include/private/android_logger.h
+++ b/include/private/android_logger.h
@@ -41,4 +41,46 @@
     log_time realtime;
 } android_log_header_t;
 
+/* Event Header Structure to logd */
+typedef struct __attribute__((__packed__)) {
+    int32_t tag;  // Little Endian Order
+} android_event_header_t;
+
+/* Event payload EVENT_TYPE_INT */
+typedef struct __attribute__((__packed__)) {
+    int8_t type;  // EVENT_TYPE_INT
+    int32_t data; // Little Endian Order
+} android_event_int_t;
+
+/* Event with single EVENT_TYPE_INT */
+typedef struct __attribute__((__packed__)) {
+    android_event_header_t header;
+    android_event_int_t payload;
+} android_log_event_int_t;
+
+/* Event payload EVENT_TYPE_LONG */
+typedef struct __attribute__((__packed__)) {
+    int8_t type;  // EVENT_TYPE_LONG
+    int64_t data; // Little Endian Order
+} android_event_long_t;
+
+/* Event with single EVENT_TYPE_LONG */
+typedef struct __attribute__((__packed__)) {
+    android_event_header_t header;
+    android_event_long_t payload;
+} android_log_event_long_t;
+
+/* Event payload EVENT_TYPE_STRING */
+typedef struct __attribute__((__packed__)) {
+    int8_t type;    // EVENT_TYPE_STRING;
+    int32_t length; // Little Endian Order
+    char data[];
+} android_event_string_t;
+
+/* Event with single EVENT_TYPE_STRING */
+typedef struct __attribute__((__packed__)) {
+    android_event_header_t header;
+    android_event_string_t payload;
+} android_log_event_string_t;
+
 #endif
diff --git a/include/system/audio.h b/include/system/audio.h
index 9a25cfb..181a171 100644
--- a/include/system/audio.h
+++ b/include/system/audio.h
@@ -57,10 +57,14 @@
                                         * and must be routed to speaker
                                         */
     AUDIO_STREAM_DTMF             = 8,
-    AUDIO_STREAM_TTS              = 9,
-
-    AUDIO_STREAM_CNT,
-    AUDIO_STREAM_MAX              = AUDIO_STREAM_CNT - 1,
+    AUDIO_STREAM_TTS              = 9,  /* Transmitted Through Speaker.
+                                         * Plays over speaker only, silent on other devices.
+                                         */
+    AUDIO_STREAM_ACCESSIBILITY    = 10, /* For accessibility talk back prompts */
+    AUDIO_STREAM_REROUTING        = 11, /* For dynamic policy output mixes */
+    AUDIO_STREAM_PATCH            = 12, /* For internal audio flinger tracks. Fixed volume */
+    AUDIO_STREAM_PUBLIC_CNT       = AUDIO_STREAM_TTS + 1,
+    AUDIO_STREAM_CNT              = AUDIO_STREAM_PATCH + 1,
 } audio_stream_type_t;
 
 /* Do not change these values without updating their counterparts
@@ -96,6 +100,7 @@
     AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE     = 12,
     AUDIO_USAGE_ASSISTANCE_SONIFICATION            = 13,
     AUDIO_USAGE_GAME                               = 14,
+    AUDIO_USAGE_VIRTUAL_SOURCE                     = 15,
 
     AUDIO_USAGE_CNT,
     AUDIO_USAGE_MAX                                = AUDIO_USAGE_CNT - 1,
@@ -135,6 +140,7 @@
                                           /*  play the mix captured by this audio source.      */
     AUDIO_SOURCE_CNT,
     AUDIO_SOURCE_MAX                 = AUDIO_SOURCE_CNT - 1,
+    AUDIO_SOURCE_FM_TUNER            = 1998,
     AUDIO_SOURCE_HOTWORD             = 1999, /* A low-priority, preemptible audio source for
                                                 for background software hotword detection.
                                                 Same tuning as AUDIO_SOURCE_VOICE_RECOGNITION.
diff --git a/include/system/graphics.h b/include/system/graphics.h
index c3fca97..efd48cb 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -45,9 +45,12 @@
     /*
      * "linear" color pixel formats:
      *
-     * The pixel formats below contain sRGB data but are otherwise treated
-     * as linear formats, i.e.: no special operation is performed when
-     * reading or writing into a buffer in one of these formats
+     * When used with ANativeWindow, the dataSpace field describes the color
+     * space of the buffer.
+     *
+     * The color space determines, for example, if the formats are linear or
+     * gamma-corrected; or whether any special operations are performed when
+     * reading or writing into a buffer in one of these formats.
      */
     HAL_PIXEL_FORMAT_RGBA_8888          = 1,
     HAL_PIXEL_FORMAT_RGBX_8888          = 2,
@@ -55,25 +58,8 @@
     HAL_PIXEL_FORMAT_RGB_565            = 4,
     HAL_PIXEL_FORMAT_BGRA_8888          = 5,
 
-    /*
-     * sRGB color pixel formats:
-     *
-     * The red, green and blue components are stored in sRGB space, and converted
-     * to linear space when read, using the standard sRGB to linear equation:
-     *
-     * Clinear = Csrgb / 12.92                  for Csrgb <= 0.04045
-     *         = (Csrgb + 0.055 / 1.055)^2.4    for Csrgb >  0.04045
-     *
-     * When written the inverse transformation is performed:
-     *
-     * Csrgb = 12.92 * Clinear                  for Clinear <= 0.0031308
-     *       = 1.055 * Clinear^(1/2.4) - 0.055  for Clinear >  0.0031308
-     *
-     *
-     *  The alpha component, if present, is always stored in linear space and
-     *  is left unmodified when read or written.
-     *
-     */
+    // Deprecated sRGB formats for source code compatibility
+    // Not for use in new code
     HAL_PIXEL_FORMAT_sRGB_A_8888        = 0xC,
     HAL_PIXEL_FORMAT_sRGB_X_8888        = 0xD,
 
@@ -111,6 +97,8 @@
      *   cr_offset = y_size
      *   cb_offset = y_size + c_size
      *
+     * When used with ANativeWindow, the dataSpace field describes the color
+     * space of the buffer.
      */
     HAL_PIXEL_FORMAT_YV12   = 0x32315659, // YCrCb 4:2:0 Planar
 
@@ -135,6 +123,8 @@
      *
      *   size = stride * height
      *
+     * When used with ANativeWindow, the dataSpace field describes the color
+     * space of the buffer.
      */
     HAL_PIXEL_FORMAT_Y8     = 0x20203859,
 
@@ -159,6 +149,10 @@
      *
      *   size = stride * height * 2
      *
+     * When used with ANativeWindow, the dataSpace field describes the color
+     * space of the buffer, except that dataSpace field
+     * HAL_DATASPACE_DEPTH indicates that this buffer contains a depth
+     * image where each sample is a distance value measured by a depth camera.
      */
     HAL_PIXEL_FORMAT_Y16    = 0x20363159,
 
@@ -167,7 +161,7 @@
      *
      * This format is exposed outside of the camera HAL to applications.
      *
-     * RAW_SENSOR is a single-channel, 16-bit, little endian  format, typically
+     * RAW16 is a single-channel, 16-bit, little endian format, typically
      * representing raw Bayer-pattern images from an image sensor, with minimal
      * processing.
      *
@@ -193,9 +187,15 @@
      *    - GRALLOC_USAGE_HW_CAMERA_*
      *    - GRALLOC_USAGE_SW_*
      *    - GRALLOC_USAGE_RENDERSCRIPT
+     *
+     * When used with ANativeWindow, the dataSpace should be
+     * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
+     * extra metadata to define.
      */
     HAL_PIXEL_FORMAT_RAW16 = 0x20,
-    HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20, // TODO(rubenbrunk): Remove RAW_SENSOR.
+
+    // Temporary alias for source code compatibility; do not use in new code
+    HAL_PIXEL_FORMAT_RAW_SENSOR = HAL_PIXEL_FORMAT_RAW16,
 
     /*
      * Android RAW10 format:
@@ -244,6 +244,10 @@
      *    - GRALLOC_USAGE_HW_CAMERA_*
      *    - GRALLOC_USAGE_SW_*
      *    - GRALLOC_USAGE_RENDERSCRIPT
+     *
+     * When used with ANativeWindow, the dataSpace field should be
+     * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
+     * extra metadata to define.
      */
     HAL_PIXEL_FORMAT_RAW10 = 0x25,
 
@@ -261,6 +265,10 @@
      *    - GRALLOC_USAGE_HW_CAMERA_*
      *    - GRALLOC_USAGE_SW_*
      *    - GRALLOC_USAGE_RENDERSCRIPT
+     *
+     * When used with ANativeWindow, the dataSpace field should be
+     * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
+     * extra metadata to define.
      */
     HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24,
 
@@ -276,6 +284,16 @@
      *
      * Buffers of this format must have a height of 1, and width equal to their
      * size in bytes.
+     *
+     * When used with ANativeWindow, the mapping of the dataSpace field to
+     * buffer contents for BLOB is as follows:
+     *
+     *  dataSpace value               | Buffer contents
+     * -------------------------------+-----------------------------------------
+     *  HAL_DATASPACE_JFIF            | An encoded JPEG image
+     *  HAL_DATASPACE_DEPTH           | An android_depth_points buffer
+     *  Other                         | Unsupported
+     *
      */
     HAL_PIXEL_FORMAT_BLOB = 0x21,
 
@@ -292,6 +310,8 @@
      * framework will assume that sampling the texture will always return an
      * alpha value of 1.0 (i.e. the buffer contains only opaque pixel values).
      *
+     * When used with ANativeWindow, the dataSpace field describes the color
+     * space of the buffer.
      */
     HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22,
 
@@ -311,6 +331,9 @@
      *
      * This format is locked for use by gralloc's (*lock_ycbcr) method, and
      * locking with the (*lock) method will return an error.
+     *
+     * When used with ANativeWindow, the dataSpace field describes the color
+     * space of the buffer.
      */
     HAL_PIXEL_FORMAT_YCbCr_420_888 = 0x23,
 
@@ -355,6 +378,42 @@
 };
 
 /**
+ * Structure used to define depth point clouds for format HAL_PIXEL_FORMAT_BLOB
+ * with dataSpace value of HAL_DATASPACE_DEPTH.
+ * When locking a native buffer of the above format and dataSpace value,
+ * the vaddr pointer can be cast to this structure.
+ *
+ * A variable-length list of (x,y,z) 3D points, as floats.
+ *
+ * @num_points is the number of points in the list
+ *
+ * @xyz_points is the flexible array of floating-point values.
+ *   It contains (num_points) * 3 floats.
+ *
+ *   For example:
+ *     android_depth_points d = get_depth_buffer();
+ *     struct {
+ *       float x; float y; float z;
+ *     } firstPoint, lastPoint;
+ *
+ *     firstPoint.x = d.xyz_points[0];
+ *     firstPoint.y = d.xyz_points[1];
+ *     firstPoint.z = d.xyz_points[2];
+ *     lastPoint.x = d.xyz_points[(d.num_points - 1) * 3 + 0];
+ *     lastPoint.y = d.xyz_points[(d.num_points - 1) * 3 + 1];
+ *     lastPoint.z = d.xyz_points[(d.num_points - 1) * 3 + 2];
+ */
+
+struct android_depth_points {
+    uint32_t num_points;
+
+    /** reserved for future use, set to 0 by gralloc's (*lock)() */
+    uint32_t reserved[8];
+
+    float xyz_points[];
+};
+
+/**
  * Transformation definitions
  *
  * IMPORTANT NOTE:
@@ -378,19 +437,33 @@
 };
 
 /**
- * Colorspace Definitions
+ * Dataspace Definitions
  * ======================
  *
- * Colorspace is the definition of how pixel values should be interpreted.
- * It includes primaries (including white point) and the transfer
- * characteristic function, which describes both gamma curve and numeric
- * range (within the bit depth).
+ * Dataspace is the definition of how pixel values should be interpreted.
+ *
+ * For many formats, this is the colorspace of the image data, which includes
+ * primaries (including white point) and the transfer characteristic function,
+ * which describes both gamma curve and numeric range (within the bit depth).
+ *
+ * Other dataspaces include depth measurement data from a depth camera.
  */
 
-enum {
+typedef enum android_dataspace {
     /*
-     * Arbitrary colorspace with manually defined characteristics.
-     * Colorspace definition must be communicated separately.
+     * Default-assumption data space, when not explicitly specified.
+     *
+     * It is safest to assume the buffer is an image with sRGB primaries and
+     * encoding ranges, but the consumer and/or the producer of the data may
+     * simply be using defaults. No automatic gamma transform should be
+     * expected, except for a possible display gamma transform when drawn to a
+     * screen.
+     */
+    HAL_DATASPACE_UNKNOWN = 0x0,
+
+    /*
+     * Arbitrary dataspace with manually defined characteristics.  Definition
+     * for colorspaces or other meaning must be communicated separately.
      *
      * This is used when specifying primaries, transfer characteristics,
      * etc. separately.
@@ -399,7 +472,57 @@
      * where a colorspace can have separately defined primaries, transfer
      * characteristics, etc.
      */
-    HAL_COLORSPACE_ARBITRARY = 0x1,
+    HAL_DATASPACE_ARBITRARY = 0x1,
+
+    /*
+     * RGB Colorspaces
+     * -----------------
+     *
+     * Primaries are given using (x,y) coordinates in the CIE 1931 definition
+     * of x and y specified by ISO 11664-1.
+     *
+     * Transfer characteristics are the opto-electronic transfer characteristic
+     * at the source as a function of linear optical intensity (luminance).
+     */
+
+    /*
+     * sRGB linear encoding:
+     *
+     * The red, green, and blue components are stored in sRGB space, but
+     * are linear, not gamma-encoded.
+     * The RGB primaries and the white point are the same as BT.709.
+     *
+     * The values are encoded using the full range ([0,255] for 8-bit) for all
+     * components.
+     */
+    HAL_DATASPACE_SRGB_LINEAR = 0x200,
+
+    /*
+     * sRGB gamma encoding:
+     *
+     * The red, green and blue components are stored in sRGB space, and
+     * converted to linear space when read, using the standard sRGB to linear
+     * equation:
+     *
+     * Clinear = Csrgb / 12.92                  for Csrgb <= 0.04045
+     *         = (Csrgb + 0.055 / 1.055)^2.4    for Csrgb >  0.04045
+     *
+     * When written the inverse transformation is performed:
+     *
+     * Csrgb = 12.92 * Clinear                  for Clinear <= 0.0031308
+     *       = 1.055 * Clinear^(1/2.4) - 0.055  for Clinear >  0.0031308
+     *
+     *
+     * The alpha component, if present, is always stored in linear space and
+     * is left unmodified when read or written.
+     *
+     * The RGB primaries and the white point are the same as BT.709.
+     *
+     * The values are encoded using the full range ([0,255] for 8-bit) for all
+     * components.
+     *
+     */
+    HAL_DATASPACE_SRGB = 0x201,
 
     /*
      * YCbCr Colorspaces
@@ -429,7 +552,7 @@
      *  red             0.640   0.330
      *  white (D65)     0.3127  0.3290
      */
-    HAL_COLORSPACE_JFIF = 0x101,
+    HAL_DATASPACE_JFIF = 0x101,
 
     /*
      * ITU-R Recommendation 601 (BT.601) - 625-line
@@ -456,7 +579,7 @@
      *  red             0.640   0.330
      *  white (D65)     0.3127  0.3290
      */
-    HAL_COLORSPACE_BT601_625 = 0x102,
+    HAL_DATASPACE_BT601_625 = 0x102,
 
     /*
      * ITU-R Recommendation 601 (BT.601) - 525-line
@@ -483,7 +606,7 @@
      *  red             0.630   0.340
      *  white (D65)     0.3127  0.3290
      */
-    HAL_COLORSPACE_BT601_525 = 0x103,
+    HAL_DATASPACE_BT601_525 = 0x103,
 
     /*
      * ITU-R Recommendation 709 (BT.709)
@@ -504,8 +627,20 @@
      *  red             0.640   0.330
      *  white (D65)     0.3127  0.3290
      */
-    HAL_COLORSPACE_BT709 = 0x104,
-};
+    HAL_DATASPACE_BT709 = 0x104,
+
+    /*
+     * The buffer contains depth ranging measurements from a depth camera.
+     * This value is valid with formats:
+     *    HAL_PIXEL_FORMAT_Y16: 16-bit single channel depth image.
+     *    HAL_PIXEL_FORMAT_BLOB: A depth point cloud, as
+     *       a variable-length float (x,y,z) coordinate point list.
+     *       The point cloud will be represented with the android_depth_points
+     *       structure.
+     */
+    HAL_DATASPACE_DEPTH = 0x1000
+
+} android_dataspace_t;
 
 #ifdef __cplusplus
 }
diff --git a/include/system/window.h b/include/system/window.h
index bf93b79..af0418b 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -262,6 +262,12 @@
      * the aspect ratio of the buffers produced.
      */
     NATIVE_WINDOW_STICKY_TRANSFORM = 11,
+
+    /**
+     * The default data space for the buffers as set by the consumer.
+     * The values are defined in graphics.h.
+     */
+    NATIVE_WINDOW_DEFAULT_DATASPACE = 12
 };
 
 /* Valid operations for the (*perform)() hook.
@@ -294,6 +300,7 @@
     NATIVE_WINDOW_SET_POST_TRANSFORM_CROP   = 16,   /* private */
     NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */
     NATIVE_WINDOW_SET_SIDEBAND_STREAM       = 18,
+    NATIVE_WINDOW_SET_BUFFERS_DATASPACE     = 19
 };
 
 /* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
@@ -498,6 +505,7 @@
      *     NATIVE_WINDOW_SET_BUFFERS_GEOMETRY  (deprecated)
      *     NATIVE_WINDOW_SET_BUFFERS_TRANSFORM
      *     NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
+     *     NATIVE_WINDOW_SET_BUFFERS_DATASPACE
      *     NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS
      *     NATIVE_WINDOW_SET_BUFFERS_FORMAT
      *     NATIVE_WINDOW_SET_SCALING_MODE       (private)
@@ -799,6 +807,26 @@
 }
 
 /*
+ * native_window_set_buffers_data_space(..., int dataSpace)
+ * All buffers queued after this call will be associated with the dataSpace
+ * parameter specified.
+ *
+ * dataSpace specifies additional information about the buffer that's dependent
+ * on the buffer format and the endpoints. For example, it can be used to convey
+ * the color space of the image data in the buffer, or it can be used to
+ * indicate that the buffers contain depth measurement data instead of color
+ * images.  The default dataSpace is 0, HAL_DATASPACE_UNKNOWN, unless it has been
+ * overridden by the consumer.
+ */
+static inline int native_window_set_buffers_data_space(
+        struct ANativeWindow* window,
+        android_dataspace_t dataSpace)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_DATASPACE,
+            dataSpace);
+}
+
+/*
  * native_window_set_buffers_transform(..., int transform)
  * All buffers queued after this call will be displayed transformed according
  * to the transform parameter specified.
diff --git a/include/utils/Compat.h b/include/utils/Compat.h
index a238afe..7d96310 100644
--- a/include/utils/Compat.h
+++ b/include/utils/Compat.h
@@ -36,17 +36,17 @@
 #endif /* __APPLE__ */
 
 #if defined(_WIN32)
-#define O_CLOEXEC 0
+#define O_CLOEXEC O_NOINHERIT
 #define O_NOFOLLOW 0
 #define DEFFILEMODE 0666
 #endif /* _WIN32 */
 
-#if HAVE_PRINTF_ZD
-#  define ZD "%zd"
-#  define ZD_TYPE ssize_t
+#if defined(_WIN32)
+#define ZD "%ld"
+#define ZD_TYPE long
 #else
-#  define ZD "%ld"
-#  define ZD_TYPE long
+#define ZD "%zd"
+#define ZD_TYPE ssize_t
 #endif
 
 /*
diff --git a/include/utils/FileMap.h b/include/utils/FileMap.h
index 6c0aa52..f70fc92 100644
--- a/include/utils/FileMap.h
+++ b/include/utils/FileMap.h
@@ -63,6 +63,8 @@
     bool create(const char* origFileName, int fd,
                 off64_t offset, size_t length, bool readOnly);
 
+    ~FileMap(void);
+
     /*
      * Return the name of the file this map came from, if known.
      */
@@ -84,19 +86,6 @@
     off64_t getDataOffset(void) const { return mDataOffset; }
 
     /*
-     * Get a "copy" of the object.
-     */
-    FileMap* acquire(void) { mRefCount++; return this; }
-
-    /*
-     * Call this when mapping is no longer needed.
-     */
-    void release(void) {
-        if (--mRefCount <= 0)
-            delete this;
-    }
-
-    /*
      * This maps directly to madvise() values, but allows us to avoid
      * including <sys/mman.h> everywhere.
      */
@@ -112,15 +101,12 @@
     int advise(MapAdvice advice);
 
 protected:
-    // don't delete objects; call release()
-    ~FileMap(void);
 
 private:
     // these are not implemented
     FileMap(const FileMap& src);
     const FileMap& operator=(const FileMap& src);
 
-    int         mRefCount;      // reference count
     char*       mFileName;      // original file name, if known
     void*       mBasePtr;       // base of mmap area; page aligned
     size_t      mBaseLength;    // length, measured from "mBasePtr"
diff --git a/include/zipfile/zipfile.h b/include/zipfile/zipfile.h
deleted file mode 100644
index 0ae4ee4..0000000
--- a/include/zipfile/zipfile.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2008 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 _ZIPFILE_ZIPFILE_H
-#define _ZIPFILE_ZIPFILE_H
-
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef void* zipfile_t;
-typedef void* zipentry_t;
-
-// Provide a buffer.  Returns NULL on failure.
-zipfile_t init_zipfile(const void* data, size_t size);
-
-// Release the zipfile resources.
-void release_zipfile(zipfile_t file);
-
-// Get a named entry object.  Returns NULL if it doesn't exist
-// or if we won't be able to decompress it.  The zipentry_t is
-// freed by release_zipfile()
-zipentry_t lookup_zipentry(zipfile_t file, const char* entryName);
-
-// Return the size of the entry.
-size_t get_zipentry_size(zipentry_t entry);
-
-// return the filename of this entry, you own the memory returned
-char* get_zipentry_name(zipentry_t entry);
-
-// The buffer must be 1.001 times the buffer size returned
-// by get_zipentry_size.  Returns nonzero on failure.
-int decompress_zipentry(zipentry_t entry, void* buf, int bufsize);
-
-// iterate through the entries in the zip file.  pass a pointer to
-// a void* initialized to NULL to start.  Returns NULL when done
-zipentry_t iterate_zipfile(zipfile_t file, void** cookie);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // _ZIPFILE_ZIPFILE_H
diff --git a/init/Android.mk b/init/Android.mk
index a3b01e1..9d91a3f 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -18,16 +18,21 @@
     -Wno-unused-parameter \
     -Werror \
 
+init_clang := true
+
 # --
 
 include $(CLEAR_VARS)
 LOCAL_CPPFLAGS := $(init_cflags)
 LOCAL_SRC_FILES:= \
     init_parser.cpp \
+    log.cpp \
     parser.cpp \
     util.cpp \
 
+LOCAL_STATIC_LIBRARIES := libbase
 LOCAL_MODULE := libinit
+LOCAL_CLANG := $(init_clang)
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -45,7 +50,7 @@
     watchdogd.cpp \
 
 LOCAL_MODULE:= init
-
+LOCAL_C_INCLUDES += system/extras/ext4_utils
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
@@ -55,18 +60,22 @@
     libfs_mgr \
     liblogwrap \
     libcutils \
+    libbase \
+    libext4_utils_static \
     libutils \
     liblog \
     libc \
     libselinux \
     libmincrypt \
-    libext4_utils_static
+    libc++_static \
+    libdl
 
 # Create symlinks
 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
     ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
     ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd
 
+LOCAL_CLANG := $(init_clang)
 include $(BUILD_EXECUTABLE)
 
 
@@ -75,11 +84,13 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := init_tests
 LOCAL_SRC_FILES := \
+    init_parser_test.cpp \
     util_test.cpp \
 
 LOCAL_SHARED_LIBRARIES += \
     libcutils \
-    libutils \
+    libbase \
 
 LOCAL_STATIC_LIBRARIES := libinit
+LOCAL_CLANG := $(init_clang)
 include $(BUILD_NATIVE_TEST)
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index cc31920..95687cb 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -30,9 +30,10 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <memory>
 #include <string>
 
-#include <utils/file.h>
+#include <base/file.h>
 
 #define LOG_ROOT        "/data/bootchart"
 #define LOG_STAT        LOG_ROOT"/proc_stat.log"
@@ -59,7 +60,7 @@
 
 static long long get_uptime_jiffies() {
     std::string uptime;
-    if (!android::ReadFileToString("/proc/uptime", &uptime)) {
+    if (!android::base::ReadFileToString("/proc/uptime", &uptime)) {
         return 0;
     }
     return 100LL * strtod(uptime.c_str(), NULL);
@@ -82,7 +83,7 @@
     }
 
     std::string kernel_cmdline;
-    android::ReadFileToString("/proc/cmdline", &kernel_cmdline);
+    android::base::ReadFileToString("/proc/cmdline", &kernel_cmdline);
 
     FILE* out = fopen(LOG_HEADER, "we");
     if (out == NULL) {
@@ -106,7 +107,7 @@
     do_log_uptime(log);
 
     std::string content;
-    if (android::ReadFileToString(procfile, &content)) {
+    if (android::base::ReadFileToString(procfile, &content)) {
         fprintf(log, "%s\n", content.c_str());
     }
 }
@@ -114,9 +115,9 @@
 static void do_log_procs(FILE* log) {
     do_log_uptime(log);
 
-    DIR* dir = opendir("/proc");
+    std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir("/proc"), closedir);
     struct dirent* entry;
-    while ((entry = readdir(dir)) != NULL) {
+    while ((entry = readdir(dir.get())) != NULL) {
         // Only match numeric values.
         char* end;
         int pid = strtol(entry->d_name, &end, 10);
@@ -127,13 +128,13 @@
             // name from /proc/<pid>/cmdline.
             snprintf(filename, sizeof(filename), "/proc/%d/cmdline", pid);
             std::string cmdline;
-            android::ReadFileToString(filename, &cmdline);
+            android::base::ReadFileToString(filename, &cmdline);
             const char* full_name = cmdline.c_str(); // So we stop at the first NUL.
 
             // Read process stat line.
             snprintf(filename, sizeof(filename), "/proc/%d/stat", pid);
             std::string stat;
-            if (android::ReadFileToString(filename, &stat)) {
+            if (android::base::ReadFileToString(filename, &stat)) {
                 if (!cmdline.empty()) {
                     // Substitute the process name with its real name.
                     size_t open = stat.find('(');
@@ -146,7 +147,6 @@
             }
         }
     }
-    closedir(dir);
 
     fputc('\n', log);
 }
@@ -155,7 +155,7 @@
     int timeout = 0;
 
     std::string start;
-    android::ReadFileToString(LOG_STARTFILE, &start);
+    android::base::ReadFileToString(LOG_STARTFILE, &start);
     if (!start.empty()) {
         timeout = atoi(start.c_str());
     } else {
@@ -164,7 +164,7 @@
         // timeout. this is useful when using -wipe-data since the /data
         // partition is fresh.
         std::string cmdline;
-        android::ReadFileToString("/proc/cmdline", &cmdline);
+        android::base::ReadFileToString("/proc/cmdline", &cmdline);
 #define KERNEL_OPTION  "androidboot.bootchart="
         if (strstr(cmdline.c_str(), KERNEL_OPTION) != NULL) {
             timeout = atoi(cmdline.c_str() + sizeof(KERNEL_OPTION) - 1);
@@ -195,13 +195,8 @@
     }
 
     // Create kernel process accounting file.
-    {
-        int  fd = open( LOG_ACCT, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC,0644);
-        if (fd >= 0) {
-            close(fd);
-            acct( LOG_ACCT );
-        }
-    }
+    close(open(LOG_ACCT, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644));
+    acct(LOG_ACCT);
 
     log_header();
     return count;
@@ -210,11 +205,12 @@
 int do_bootchart_init(int nargs, char** args) {
     g_remaining_samples = bootchart_init();
     if (g_remaining_samples < 0) {
-        ERROR("bootcharting init failure: %s\n", strerror(errno));
+        ERROR("Bootcharting init failure: %s\n", strerror(errno));
     } else if (g_remaining_samples > 0) {
-        NOTICE("bootcharting started (will run for %d ms)\n", g_remaining_samples*BOOTCHART_POLLING_MS);
+        NOTICE("Bootcharting started (will run for %d s).\n",
+               (g_remaining_samples * BOOTCHART_POLLING_MS) / 1000);
     } else {
-        NOTICE("bootcharting ignored\n");
+        NOTICE("Not bootcharting.\n");
     }
     return 0;
 }
@@ -226,7 +222,7 @@
 
     // Stop if /data/bootchart/stop contains 1.
     std::string stop;
-    if (android::ReadFileToString(LOG_STOPFILE, &stop) && stop == "1") {
+    if (android::base::ReadFileToString(LOG_STOPFILE, &stop) && stop == "1") {
         return -1;
     }
 
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 9f3dcc1..9d5b8a8 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -14,31 +14,32 @@
  * limitations under the License.
  */
 
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-#include <linux/kd.h>
 #include <errno.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <linux/if.h>
-#include <arpa/inet.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
 #include <sys/mount.h>
 #include <sys/resource.h>
 #include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <sys/wait.h>
+#include <unistd.h>
 #include <linux/loop.h>
-#include <cutils/partition_utils.h>
-#include <cutils/android_reboot.h>
-#include <fs_mgr.h>
+#include <ext4_crypt.h>
 
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 
+#include <fs_mgr.h>
+#include <base/stringprintf.h>
+#include <cutils/partition_utils.h>
+#include <cutils/android_reboot.h>
+#include <private/android_filesystem_config.h>
+
 #include "init.h"
 #include "keywords.h"
 #include "property_service.h"
@@ -47,8 +48,6 @@
 #include "util.h"
 #include "log.h"
 
-#include <private/android_filesystem_config.h>
-
 #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
 
 int add_environment(const char *name, const char *value);
@@ -67,20 +66,6 @@
     return init_module(&module[0], module.size(), options);
 }
 
-static int setkey(struct kbentry *kbe)
-{
-    int fd, ret;
-
-    fd = open("/dev/tty0", O_RDWR | O_SYNC | O_CLOEXEC);
-    if (fd < 0)
-        return -1;
-
-    ret = ioctl(fd, KDSKBENT, kbe);
-
-    close(fd);
-    return ret;
-}
-
 static int __ifupdown(const char *interface, int up)
 {
     struct ifreq ifr;
@@ -118,18 +103,6 @@
     }
 }
 
-int do_chdir(int nargs, char **args)
-{
-    chdir(args[1]);
-    return 0;
-}
-
-int do_chroot(int nargs, char **args)
-{
-    chroot(args[1]);
-    return 0;
-}
-
 int do_class_start(int nargs, char **args)
 {
         /* Starting a class does not start services
@@ -172,11 +145,16 @@
     return 0;
 }
 
-int do_exec(int nargs, char **args)
-{
-    return -1;
+int do_exec(int nargs, char** args) {
+    service* svc = make_exec_oneshot_service(nargs, args);
+    if (svc == NULL) {
+        return -1;
+    }
+    service_start(svc, NULL);
+    return 0;
 }
 
+// TODO: remove execonce when exec is available.
 int do_execonce(int nargs, char **args)
 {
     pid_t child;
@@ -325,7 +303,7 @@
         }
     }
 
-    return 0;
+    return e4crypt_set_directory_policy(args[1]);
 }
 
 static struct {
@@ -469,6 +447,17 @@
     while (1) { pause(); }  // never reached
 }
 
+/*
+ * Callback to make a directory from the ext4 code
+ */
+static int do_mount_alls_make_dir(const char* dir)
+{
+    if (make_dir(dir, 0700) && errno != EEXIST) {
+        return -1;
+    }
+
+    return 0;
+}
 
 /*
  * This function might request a reboot, in which case it will
@@ -498,7 +487,7 @@
         int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
         if (wp_ret < 0) {
             /* Unexpected error code. We will continue anyway. */
-            NOTICE("waitpid failed rc=%d, errno=%d\n", wp_ret, errno);
+            NOTICE("waitpid failed rc=%d: %s\n", wp_ret, strerror(errno));
         }
 
         if (WIFEXITED(status)) {
@@ -537,6 +526,37 @@
         ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
         ret = wipe_data_via_recovery();
         /* If reboot worked, there is no return. */
+    } else if (ret == FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED) {
+        // We have to create the key files here. Only init can call make_dir,
+        // and we can't do it from fs_mgr as then fs_mgr would depend on
+        // make_dir creating a circular dependency.
+        fstab = fs_mgr_read_fstab(args[1]);
+        for (int i = 0; i < fstab->num_entries; ++i) {
+            if (fs_mgr_is_file_encrypted(&fstab->recs[i])) {
+              if (e4crypt_create_device_key(fstab->recs[i].mount_point,
+                                            do_mount_alls_make_dir)) {
+                    ERROR("Could not create device key on %s"
+                          " - continue unencrypted\n",
+                          fstab->recs[i].mount_point);
+                }
+            }
+        }
+        fs_mgr_free_fstab(fstab);
+
+        if (e4crypt_install_keyring()) {
+            return -1;
+        }
+        property_set("ro.crypto.state", "encrypted");
+
+        // Although encrypted, we have device key, so we do not need to
+        // do anything different from the nonencrypted case.
+        action_for_each_trigger("nonencrypted", action_add_queue_tail);
+    } else if (ret == FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED) {
+        if (e4crypt_install_keyring()) {
+            return -1;
+        }
+        property_set("ro.crypto.state", "encrypted");
+        property_set("vold.decrypt", "trigger_restart_min_framework");
     } else if (ret > 0) {
         ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
     }
@@ -566,24 +586,6 @@
     return 0;
 }
 
-int do_setenforce(int nargs, char **args) {
-    if (is_selinux_enabled() <= 0)
-        return 0;
-    if (security_setenforce(atoi(args[1])) < 0) {
-        return -errno;
-    }
-    return 0;
-}
-
-int do_setkey(int nargs, char **args)
-{
-    struct kbentry kbe;
-    kbe.kb_table = strtoul(args[1], 0, 0);
-    kbe.kb_index = strtoul(args[2], 0, 0);
-    kbe.kb_value = strtoul(args[3], 0, 0);
-    return setkey(&kbe);
-}
-
 int do_setprop(int nargs, char **args)
 {
     const char *name = args[1];
@@ -712,6 +714,23 @@
     return 0;
 }
 
+int do_verity_load_state(int nargs, char **args) {
+    int mode = -1;
+    int rc = fs_mgr_load_verity_state(&mode);
+    if (rc == 0 && mode == VERITY_MODE_LOGGING) {
+        action_for_each_trigger("verity-logging", action_add_queue_tail);
+    }
+    return rc;
+}
+
+static void verity_update_property(fstab_rec *fstab, const char *mount_point, int status) {
+    property_set(android::base::StringPrintf("partition.%s.verified", mount_point).c_str(), "1");
+}
+
+int do_verity_update_state(int nargs, char** args) {
+    return fs_mgr_update_verity_state(verity_update_property);
+}
+
 int do_write(int nargs, char **args)
 {
     const char *path = args[1];
@@ -844,34 +863,6 @@
     return ret;
 }
 
-int do_setsebool(int nargs, char **args) {
-    const char *name = args[1];
-    const char *value = args[2];
-    SELboolean b;
-    int ret;
-
-    if (is_selinux_enabled() <= 0)
-        return 0;
-
-    b.name = name;
-    if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on"))
-        b.value = 1;
-    else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off"))
-        b.value = 0;
-    else {
-        ERROR("setsebool: invalid value %s\n", value);
-        return -EINVAL;
-    }
-
-    if (security_set_boolean_list(1, &b, 0) < 0) {
-        ret = -errno;
-        ERROR("setsebool: could not set %s to %s\n", name, value);
-        return ret;
-    }
-
-    return 0;
-}
-
 int do_loglevel(int nargs, char **args) {
     int log_level;
     char log_level_str[PROP_VALUE_MAX] = "";
@@ -918,3 +909,12 @@
     } else
         return -1;
 }
+
+int do_installkey(int nargs, char **args)
+{
+    if (nargs == 2) {
+        return e4crypt_install_key(args[1]);
+    }
+
+    return -1;
+}
diff --git a/init/devices.cpp b/init/devices.cpp
index 3a9b753..96b1696 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -49,9 +49,9 @@
 #include "log.h"
 
 #define SYSFS_PREFIX    "/sys"
-#define FIRMWARE_DIR1   "/etc/firmware"
-#define FIRMWARE_DIR2   "/vendor/firmware"
-#define FIRMWARE_DIR3   "/firmware/image"
+static const char *firmware_dirs[] = { "/etc/firmware",
+                                       "/vendor/firmware",
+                                       "/firmware/image" };
 
 extern struct selabel_handle *sehandle;
 
@@ -364,13 +364,6 @@
     return 0;
 }
 
-static inline suseconds_t get_usecs(void)
-{
-    struct timeval tv;
-    gettimeofday(&tv, 0);
-    return tv.tv_sec * (suseconds_t) 1000000 + tv.tv_usec;
-}
-
 static void parse_event(const char *msg, struct uevent *uevent)
 {
     uevent->action = "";
@@ -818,8 +811,9 @@
 
 static void process_firmware_event(struct uevent *uevent)
 {
-    char *root, *loading, *data, *file1 = NULL, *file2 = NULL, *file3 = NULL;
+    char *root, *loading, *data;
     int l, loading_fd, data_fd, fw_fd;
+    size_t i;
     int booting = is_booting();
 
     INFO("firmware: loading '%s' for '%s'\n",
@@ -837,62 +831,49 @@
     if (l == -1)
         goto loading_free_out;
 
-    l = asprintf(&file1, FIRMWARE_DIR1"/%s", uevent->firmware);
-    if (l == -1)
-        goto data_free_out;
-
-    l = asprintf(&file2, FIRMWARE_DIR2"/%s", uevent->firmware);
-    if (l == -1)
-        goto data_free_out;
-
-    l = asprintf(&file3, FIRMWARE_DIR3"/%s", uevent->firmware);
-    if (l == -1)
-        goto data_free_out;
-
     loading_fd = open(loading, O_WRONLY|O_CLOEXEC);
     if(loading_fd < 0)
-        goto file_free_out;
+        goto data_free_out;
 
     data_fd = open(data, O_WRONLY|O_CLOEXEC);
     if(data_fd < 0)
         goto loading_close_out;
 
 try_loading_again:
-    fw_fd = open(file1, O_RDONLY|O_CLOEXEC);
-    if(fw_fd < 0) {
-        fw_fd = open(file2, O_RDONLY|O_CLOEXEC);
-        if (fw_fd < 0) {
-            fw_fd = open(file3, O_RDONLY|O_CLOEXEC);
-            if (fw_fd < 0) {
-                if (booting) {
-                        /* If we're not fully booted, we may be missing
-                         * filesystems needed for firmware, wait and retry.
-                         */
-                    usleep(100000);
-                    booting = is_booting();
-                    goto try_loading_again;
-                }
-                INFO("firmware: could not open '%s' %d\n", uevent->firmware, errno);
-                write(loading_fd, "-1", 2);
-                goto data_close_out;
-            }
+    for (i = 0; i < ARRAY_SIZE(firmware_dirs); i++) {
+        char *file = NULL;
+        l = asprintf(&file, "%s/%s", firmware_dirs[i], uevent->firmware);
+        if (l == -1)
+            goto data_free_out;
+        fw_fd = open(file, O_RDONLY|O_CLOEXEC);
+        free(file);
+        if (fw_fd >= 0) {
+            if(!load_firmware(fw_fd, loading_fd, data_fd))
+                INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware);
+            else
+                INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware);
+            break;
         }
     }
-
-    if(!load_firmware(fw_fd, loading_fd, data_fd))
-        INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware);
-    else
-        INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware);
+    if (fw_fd < 0) {
+        if (booting) {
+            /* If we're not fully booted, we may be missing
+             * filesystems needed for firmware, wait and retry.
+             */
+            usleep(100000);
+            booting = is_booting();
+            goto try_loading_again;
+        }
+        INFO("firmware: could not open '%s': %s\n", uevent->firmware, strerror(errno));
+        write(loading_fd, "-1", 2);
+        goto data_close_out;
+    }
 
     close(fw_fd);
 data_close_out:
     close(data_fd);
 loading_close_out:
     close(loading_fd);
-file_free_out:
-    free(file1);
-    free(file2);
-    free(file3);
 data_free_out:
     free(data);
 loading_free_out:
@@ -1002,12 +983,7 @@
     }
 }
 
-void device_init(void)
-{
-    suseconds_t t0, t1;
-    struct stat info;
-    int fd;
-
+void device_init() {
     sehandle = NULL;
     if (is_selinux_enabled() > 0) {
         sehandle = selinux_android_file_context_handle();
@@ -1016,26 +992,22 @@
 
     /* is 256K enough? udev uses 16MB! */
     device_fd = uevent_open_socket(256*1024, true);
-    if(device_fd < 0)
+    if (device_fd == -1) {
         return;
-
-    fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+    }
     fcntl(device_fd, F_SETFL, O_NONBLOCK);
 
-    if (stat(COLDBOOT_DONE, &info) < 0) {
-        t0 = get_usecs();
-        coldboot("/sys/class");
-        coldboot("/sys/block");
-        coldboot("/sys/devices");
-        t1 = get_usecs();
-        fd = open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000);
-        close(fd);
-        if (LOG_UEVENTS) {
-            INFO("coldboot %ld uS\n", ((long) (t1 - t0)));
-        }
-    } else if (LOG_UEVENTS) {
-        INFO("skipping coldboot, already done\n");
+    if (access(COLDBOOT_DONE, F_OK) == 0) {
+        NOTICE("Skipping coldboot, already done!\n");
+        return;
     }
+
+    Timer t;
+    coldboot("/sys/class");
+    coldboot("/sys/block");
+    coldboot("/sys/devices");
+    close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
+    NOTICE("Coldboot took %.2fs.\n", t.duration());
 }
 
 int get_device_fd()
diff --git a/init/grab-bootchart.sh b/init/grab-bootchart.sh
index 7fe8904..d6082aa 100755
--- a/init/grab-bootchart.sh
+++ b/init/grab-bootchart.sh
@@ -1,10 +1,9 @@
 #!/bin/sh
 #
-# this script is used to retrieve the bootchart log generated
-# by init when compiled with INIT_BOOTCHART=true.
-#
-# for all details, see //device/system/init/README.BOOTCHART
-#
+# This script is used to retrieve a bootchart log generated by init.
+# All options are passed to adb, for better or for worse.
+# See the readme in this directory for more on bootcharting.
+
 TMPDIR=/tmp/android-bootchart
 rm -rf $TMPDIR
 mkdir -p $TMPDIR
@@ -15,8 +14,9 @@
 FILES="header proc_stat.log proc_ps.log proc_diskstats.log kernel_pacct"
 
 for f in $FILES; do
-    adb pull $LOGROOT/$f $TMPDIR/$f 2>&1 > /dev/null
+    adb "${@}" pull $LOGROOT/$f $TMPDIR/$f 2>&1 > /dev/null
 done
 (cd $TMPDIR && tar -czf $TARBALL $FILES)
-cp -f $TMPDIR/$TARBALL ./$TARBALL
-echo "look at $TARBALL"
+bootchart ${TMPDIR}/${TARBALL}
+gnome-open ${TARBALL%.tgz}.png
+echo "Clean up ${TMPDIR}/ and ./${TARBALL%.tgz}.png when done"
diff --git a/init/init.cpp b/init/init.cpp
index 41ceb0a..b1d65db 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -14,37 +14,43 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <signal.h>
-#include <sys/wait.h>
 #include <sys/mount.h>
-#include <sys/stat.h>
 #include <sys/poll.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <mtd/mtd-user.h>
-#include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <sys/un.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <mtd/mtd-user.h>
 
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 #include <selinux/android.h>
 
-#include <libgen.h>
-
-#include <cutils/list.h>
+#include <base/file.h>
+#include <base/stringprintf.h>
 #include <cutils/android_reboot.h>
-#include <cutils/sockets.h>
-#include <cutils/iosched_policy.h>
 #include <cutils/fs.h>
+#include <cutils/iosched_policy.h>
+#include <cutils/list.h>
+#include <cutils/sockets.h>
 #include <private/android_filesystem_config.h>
-#include <termios.h>
+
+#include <memory>
 
 #include "devices.h"
 #include "init.h"
@@ -63,31 +69,40 @@
 
 static int property_triggers_enabled = 0;
 
-static char console[32];
-static char bootmode[32];
-static char hardware[32];
-static unsigned revision = 0;
 static char qemu[32];
 
 static struct action *cur_action = NULL;
 static struct command *cur_command = NULL;
 
-void notify_service_state(const char *name, const char *state)
-{
-    char pname[PROP_NAME_MAX];
-    int len = strlen(name);
-    if ((len + 10) > PROP_NAME_MAX)
-        return;
-    snprintf(pname, sizeof(pname), "init.svc.%s", name);
-    property_set(pname, state);
-}
-
 static int have_console;
 static char console_name[PROP_VALUE_MAX] = "/dev/console";
 static time_t process_needs_restart;
 
 static const char *ENV[32];
 
+bool waiting_for_exec = false;
+
+void service::NotifyStateChange(const char* new_state) {
+    if (!properties_initialized()) {
+        // If properties aren't available yet, we can't set them.
+        return;
+    }
+
+    if ((flags & SVC_EXEC) != 0) {
+        // 'exec' commands don't have properties tracking their state.
+        return;
+    }
+
+    char prop_name[PROP_NAME_MAX];
+    if (snprintf(prop_name, sizeof(prop_name), "init.svc.%s", name) >= PROP_NAME_MAX) {
+        // If the property name would be too long, we can't set it.
+        ERROR("Property name \"init.svc.%s\" too long; not setting to %s\n", name, new_state);
+        return;
+    }
+
+    property_set(prop_name, new_state);
+}
+
 /* add_environment - add "key=value" to the current environment */
 int add_environment(const char *key, const char *val)
 {
@@ -160,35 +175,26 @@
 
 void service_start(struct service *svc, const char *dynamic_args)
 {
-    struct stat s;
-    pid_t pid;
-    int needs_console;
-    char *scon = NULL;
-    int rc;
-
-        /* starting a service removes it from the disabled or reset
-         * state and immediately takes it out of the restarting
-         * state if it was in there
-         */
+    // Starting a service removes it from the disabled or reset state and
+    // immediately takes it out of the restarting state if it was in there.
     svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
     svc->time_started = 0;
 
-        /* running processes require no additional work -- if
-         * they're in the process of exiting, we've ensured
-         * that they will immediately restart on exit, unless
-         * they are ONESHOT
-         */
+    // Running processes require no additional work --- if they're in the
+    // process of exiting, we've ensured that they will immediately restart
+    // on exit, unless they are ONESHOT.
     if (svc->flags & SVC_RUNNING) {
         return;
     }
 
-    needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;
-    if (needs_console && (!have_console)) {
+    bool needs_console = (svc->flags & SVC_CONSOLE);
+    if (needs_console && !have_console) {
         ERROR("service '%s' requires console\n", svc->name);
         svc->flags |= SVC_DISABLED;
         return;
     }
 
+    struct stat s;
     if (stat(svc->args[0], &s) != 0) {
         ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);
         svc->flags |= SVC_DISABLED;
@@ -202,6 +208,7 @@
         return;
     }
 
+    char* scon = NULL;
     if (is_selinux_enabled() > 0) {
         if (svc->seclabel) {
             scon = strdup(svc->seclabel);
@@ -213,7 +220,7 @@
             char *mycon = NULL, *fcon = NULL;
 
             INFO("computing context for service '%s'\n", svc->args[0]);
-            rc = getcon(&mycon);
+            int rc = getcon(&mycon);
             if (rc < 0) {
                 ERROR("could not get context while starting '%s'\n", svc->name);
                 return;
@@ -239,10 +246,9 @@
         }
     }
 
-    NOTICE("starting '%s'\n", svc->name);
+    NOTICE("Starting service '%s'...\n", svc->name);
 
-    pid = fork();
-
+    pid_t pid = fork();
     if (pid == 0) {
         struct socketinfo *si;
         struct svcenvinfo *ei;
@@ -250,7 +256,7 @@
         int fd, sz;
 
         umask(077);
-        if (properties_inited()) {
+        if (properties_initialized()) {
             get_property_workspace(&fd, &sz);
             snprintf(tmp, sizeof(tmp), "%d,%d", dup(fd), sz);
             add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
@@ -298,7 +304,7 @@
 
         setpgid(0, getpid());
 
-    /* as requested, set our gid, supplemental gids, and uid */
+        // As requested, set our gid, supplemental gids, and uid.
         if (svc->gid) {
             if (setgid(svc->gid) != 0) {
                 ERROR("setgid failed: %s\n", strerror(errno));
@@ -361,8 +367,13 @@
     svc->pid = pid;
     svc->flags |= SVC_RUNNING;
 
-    if (properties_inited())
-        notify_service_state(svc->name, "running");
+    if ((svc->flags & SVC_EXEC) != 0) {
+        INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n",
+             svc->pid, svc->uid, svc->gid, svc->nr_supp_gids, svc->seclabel);
+        waiting_for_exec = true;
+    }
+
+    svc->NotifyStateChange("running");
 }
 
 /* The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART */
@@ -386,11 +397,11 @@
     }
 
     if (svc->pid) {
-        NOTICE("service '%s' is being killed\n", svc->name);
+        NOTICE("Service '%s' is being killed...\n", svc->name);
         kill(-svc->pid, SIGKILL);
-        notify_service_state(svc->name, "stopping");
+        svc->NotifyStateChange("stopping");
     } else {
-        notify_service_state(svc->name, "stopped");
+        svc->NotifyStateChange("stopped");
     }
 }
 
@@ -548,17 +559,18 @@
     }
 }
 
-void execute_one_command(void)
-{
-    int ret, i;
+void execute_one_command() {
+    Timer t;
+
     char cmd_str[256] = "";
     char name_str[256] = "";
 
     if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
         cur_action = action_remove_queue_head();
         cur_command = NULL;
-        if (!cur_action)
+        if (!cur_action) {
             return;
+        }
 
         build_triggers_string(name_str, sizeof(name_str), cur_action);
 
@@ -568,20 +580,26 @@
         cur_command = get_next_command(cur_action, cur_command);
     }
 
-    if (!cur_command)
+    if (!cur_command) {
         return;
+    }
 
-    ret = cur_command->func(cur_command->nargs, cur_command->args);
+    int result = cur_command->func(cur_command->nargs, cur_command->args);
     if (klog_get_level() >= KLOG_INFO_LEVEL) {
-        for (i = 0; i < cur_command->nargs; i++) {
+        for (int i = 0; i < cur_command->nargs; i++) {
             strlcat(cmd_str, cur_command->args[i], sizeof(cmd_str));
             if (i < cur_command->nargs - 1) {
                 strlcat(cmd_str, " ", sizeof(cmd_str));
             }
         }
-        INFO("command '%s' action=%s status=%d (%s:%d)\n",
-             cmd_str, cur_action ? name_str : "", ret, cur_command->filename,
-             cur_command->line);
+        char source[256];
+        if (cur_command->filename) {
+            snprintf(source, sizeof(source), " (%s:%d)", cur_command->filename, cur_command->line);
+        } else {
+            *source = '\0';
+        }
+        INFO("Command '%s' action=%s%s returned %d took %.2fs\n",
+             cmd_str, cur_action ? name_str : "", source, result, t.duration());
     }
 }
 
@@ -669,7 +687,6 @@
     if (urandom_fd != -1) {
         close(urandom_fd);
     }
-    memset(buf, 0, sizeof(buf));
     return result;
 }
 
@@ -681,13 +698,12 @@
 
 static int console_init_action(int nargs, char **args)
 {
-    int fd;
-
-    if (console[0]) {
+    char console[PROP_VALUE_MAX];
+    if (property_get("ro.boot.console", console) > 0) {
         snprintf(console_name, sizeof(console_name), "/dev/%s", console);
     }
 
-    fd = open(console_name, O_RDWR | O_CLOEXEC);
+    int fd = open(console_name, O_RDWR | O_CLOEXEC);
     if (fd >= 0)
         have_console = 1;
     close(fd);
@@ -750,55 +766,56 @@
     }
 }
 
-static void export_kernel_boot_props(void)
-{
-    char tmp[PROP_VALUE_MAX];
-    int ret;
-    unsigned i;
+static void export_kernel_boot_props() {
     struct {
         const char *src_prop;
-        const char *dest_prop;
-        const char *def_val;
+        const char *dst_prop;
+        const char *default_value;
     } prop_map[] = {
-        { "ro.boot.serialno", "ro.serialno", "", },
-        { "ro.boot.mode", "ro.bootmode", "unknown", },
-        { "ro.boot.baseband", "ro.baseband", "unknown", },
+        { "ro.boot.serialno",   "ro.serialno",   "", },
+        { "ro.boot.mode",       "ro.bootmode",   "unknown", },
+        { "ro.boot.baseband",   "ro.baseband",   "unknown", },
         { "ro.boot.bootloader", "ro.bootloader", "unknown", },
+        { "ro.boot.hardware",   "ro.hardware",   "unknown", },
+        { "ro.boot.revision",   "ro.revision",   "0", },
     };
+    for (size_t i = 0; i < ARRAY_SIZE(prop_map); i++) {
+        char value[PROP_VALUE_MAX];
+        int rc = property_get(prop_map[i].src_prop, value);
+        property_set(prop_map[i].dst_prop, (rc > 0) ? value : prop_map[i].default_value);
+    }
+}
 
-    for (i = 0; i < ARRAY_SIZE(prop_map); i++) {
-        ret = property_get(prop_map[i].src_prop, tmp);
-        if (ret > 0)
-            property_set(prop_map[i].dest_prop, tmp);
-        else
-            property_set(prop_map[i].dest_prop, prop_map[i].def_val);
+static void process_kernel_dt(void)
+{
+    static const char android_dir[] = "/proc/device-tree/firmware/android";
+
+    std::string file_name = android::base::StringPrintf("%s/compatible", android_dir);
+
+    std::string dt_file;
+    android::base::ReadFileToString(file_name, &dt_file);
+    if (!dt_file.compare("android,firmware")) {
+        ERROR("firmware/android is not compatible with 'android,firmware'\n");
+        return;
     }
 
-    ret = property_get("ro.boot.console", tmp);
-    if (ret)
-        strlcpy(console, tmp, sizeof(console));
+    std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dir), closedir);
+    if (!dir)
+        return;
 
-    /* save a copy for init's usage during boot */
-    property_get("ro.bootmode", tmp);
-    strlcpy(bootmode, tmp, sizeof(bootmode));
+    struct dirent *dp;
+    while ((dp = readdir(dir.get())) != NULL) {
+        if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible"))
+            continue;
 
-    /* if this was given on kernel command line, override what we read
-     * before (e.g. from /proc/cpuinfo), if anything */
-    ret = property_get("ro.boot.hardware", tmp);
-    if (ret)
-        strlcpy(hardware, tmp, sizeof(hardware));
-    property_set("ro.hardware", hardware);
+        file_name = android::base::StringPrintf("%s/%s", android_dir, dp->d_name);
 
-    snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
-    property_set("ro.revision", tmp);
+        android::base::ReadFileToString(file_name, &dt_file);
+        std::replace(dt_file.begin(), dt_file.end(), ',', '.');
 
-    /* TODO: these are obsolete. We should delete them */
-    if (!strcmp(bootmode,"factory"))
-        property_set("ro.factorytest", "1");
-    else if (!strcmp(bootmode,"factory2"))
-        property_set("ro.factorytest", "2");
-    else
-        property_set("ro.factorytest", "0");
+        std::string property_name = android::base::StringPrintf("ro.boot.%s", dp->d_name);
+        property_set(property_name.c_str(), dt_file.c_str());
+    }
 }
 
 static void process_kernel_cmdline(void)
@@ -813,11 +830,6 @@
     import_kernel_cmdline(0, import_kernel_nv);
     if (qemu[0])
         import_kernel_cmdline(1, import_kernel_nv);
-
-    /* now propogate the info given on command line to internal variables
-     * used by init as well as the current required properties
-     */
-    export_kernel_boot_props();
 }
 
 static int property_service_init_action(int nargs, char **args)
@@ -923,40 +935,25 @@
     return 0;
 }
 
-static int audit_callback(void *data, security_class_t /*cls*/, char *buf, size_t len)
-{
+static int audit_callback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
     snprintf(buf, len, "property=%s", !data ? "NULL" : (char *)data);
     return 0;
 }
 
-int log_callback(int type, const char *fmt, ...)
-{
-    int level;
-    va_list ap;
-    switch (type) {
-    case SELINUX_WARNING:
-        level = KLOG_WARNING_LEVEL;
-        break;
-    case SELINUX_INFO:
-        level = KLOG_INFO_LEVEL;
-        break;
-    default:
-        level = KLOG_ERROR_LEVEL;
-        break;
-    }
-    va_start(ap, fmt);
-    klog_vwrite(level, fmt, ap);
-    va_end(ap);
-    return 0;
-}
+static void selinux_initialize() {
+    Timer t;
 
-static void selinux_initialize(void)
-{
+    selinux_callback cb;
+    cb.func_log = selinux_klog_callback;
+    selinux_set_callback(SELINUX_CB_LOG, cb);
+    cb.func_audit = audit_callback;
+    selinux_set_callback(SELINUX_CB_AUDIT, cb);
+
     if (selinux_is_disabled()) {
         return;
     }
 
-    INFO("loading selinux policy\n");
+    INFO("Loading SELinux policy...\n");
     if (selinux_android_load_policy() < 0) {
         ERROR("SELinux: Failed to load policy; rebooting into recovery mode\n");
         android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
@@ -967,30 +964,26 @@
     bool is_enforcing = selinux_is_enforcing();
     INFO("SELinux: security_setenforce(%d)\n", is_enforcing);
     security_setenforce(is_enforcing);
+
+    NOTICE("(Initializing SELinux took %.2fs.)\n", t.duration());
 }
 
-int main(int argc, char **argv)
-{
-    size_t fd_count = 0;
-    struct pollfd ufds[4];
-    int property_set_fd_init = 0;
-    int signal_fd_init = 0;
-    int keychord_fd_init = 0;
-    bool is_charger = false;
-
-    if (!strcmp(basename(argv[0]), "ueventd"))
+int main(int argc, char** argv) {
+    if (!strcmp(basename(argv[0]), "ueventd")) {
         return ueventd_main(argc, argv);
+    }
 
-    if (!strcmp(basename(argv[0]), "watchdogd"))
+    if (!strcmp(basename(argv[0]), "watchdogd")) {
         return watchdogd_main(argc, argv);
+    }
 
-    /* clear the umask */
+    // Clear the umask.
     umask(0);
 
-        /* Get the basic filesystem setup we need put
-         * together in the initramdisk on / and then we'll
-         * let the rc file figure out the rest.
-         */
+    add_environment("PATH", _PATH_DEFPATH);
+
+    // Get the basic filesystem setup we need put together in the initramdisk
+    // on / and then we'll let the rc file figure out the rest.
     mkdir("/dev", 0755);
     mkdir("/proc", 0755);
     mkdir("/sys", 0755);
@@ -1002,43 +995,41 @@
     mount("proc", "/proc", "proc", 0, NULL);
     mount("sysfs", "/sys", "sysfs", 0, NULL);
 
-        /* indicate that booting is in progress to background fw loaders, etc */
+    // Indicate that booting is in progress to background fw loaders, etc.
     close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
 
-        /* We must have some place other than / to create the
-         * device nodes for kmsg and null, otherwise we won't
-         * be able to remount / read-only later on.
-         * Now that tmpfs is mounted on /dev, we can actually
-         * talk to the outside world.
-         */
+    // We must have some place other than / to create the device nodes for
+    // kmsg and null, otherwise we won't be able to remount / read-only
+    // later on. Now that tmpfs is mounted on /dev, we can actually talk
+    // to the outside world.
     open_devnull_stdio();
     klog_init();
+    klog_set_level(KLOG_NOTICE_LEVEL);
+
+    NOTICE("init started!\n");
+
     property_init();
 
-    get_hardware_name(hardware, &revision);
-
+    // If arguments are passed both on the command line and in DT,
+    // properties set in DT always have priority over the command-line ones.
+    process_kernel_dt();
     process_kernel_cmdline();
 
-    union selinux_callback cb;
-    cb.func_log = log_callback;
-    selinux_set_callback(SELINUX_CB_LOG, cb);
-
-    cb.func_audit = audit_callback;
-    selinux_set_callback(SELINUX_CB_AUDIT, cb);
+    // Propogate the kernel variables to internal variables
+    // used by init as well as the current required properties.
+    export_kernel_boot_props();
 
     selinux_initialize();
-    /* These directories were necessarily created before initial policy load
-     * and therefore need their security context restored to the proper value.
-     * This must happen before /dev is populated by ueventd.
-     */
+
+    // These directories were necessarily created before initial policy load
+    // and therefore need their security context restored to the proper value.
+    // This must happen before /dev is populated by ueventd.
+    INFO("Running restorecon...\n");
     restorecon("/dev");
     restorecon("/dev/socket");
     restorecon("/dev/__properties__");
     restorecon_recursive("/sys");
 
-    is_charger = !strcmp(bootmode, "charger");
-
-    INFO("property init\n");
     property_load_boot_defaults();
 
     init_parse_config_file("/init.rc");
@@ -1050,50 +1041,59 @@
     queue_builtin_action(keychord_init_action, "keychord_init");
     queue_builtin_action(console_init_action, "console_init");
 
-    /* execute all the boot actions to get us started */
+    // Trigger all the boot actions to get us started.
     action_for_each_trigger("init", action_add_queue_tail);
 
-    /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
-     * wasn't ready immediately after wait_for_coldboot_done
-     */
+    // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
+    // wasn't ready immediately after wait_for_coldboot_done
     queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
     queue_builtin_action(property_service_init_action, "property_service_init");
     queue_builtin_action(signal_init_action, "signal_init");
 
-    /* Don't mount filesystems or start core system services if in charger mode. */
-    if (is_charger) {
+    // Don't mount filesystems or start core system services in charger mode.
+    char bootmode[PROP_VALUE_MAX];
+    if (property_get("ro.bootmode", bootmode) > 0 && strcmp(bootmode, "charger") == 0) {
         action_for_each_trigger("charger", action_add_queue_tail);
     } else {
         action_for_each_trigger("late-init", action_add_queue_tail);
     }
 
-    /* run all property triggers based on current state of the properties */
+    // Run all property triggers based on current state of the properties.
     queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
 
+    // TODO: why do we only initialize ufds after execute_one_command and restart_processes?
+    size_t fd_count = 0;
+    struct pollfd ufds[3];
+    bool property_set_fd_init = false;
+    bool signal_fd_init = false;
+    bool keychord_fd_init = false;
+
     for (;;) {
-        execute_one_command();
-        restart_processes();
+        if (!waiting_for_exec) {
+            execute_one_command();
+            restart_processes();
+        }
 
         if (!property_set_fd_init && get_property_set_fd() > 0) {
             ufds[fd_count].fd = get_property_set_fd();
             ufds[fd_count].events = POLLIN;
             ufds[fd_count].revents = 0;
             fd_count++;
-            property_set_fd_init = 1;
+            property_set_fd_init = true;
         }
         if (!signal_fd_init && get_signal_fd() > 0) {
             ufds[fd_count].fd = get_signal_fd();
             ufds[fd_count].events = POLLIN;
             ufds[fd_count].revents = 0;
             fd_count++;
-            signal_fd_init = 1;
+            signal_fd_init = true;
         }
         if (!keychord_fd_init && get_keychord_fd() > 0) {
             ufds[fd_count].fd = get_keychord_fd();
             ufds[fd_count].events = POLLIN;
             ufds[fd_count].revents = 0;
             fd_count++;
-            keychord_fd_init = 1;
+            keychord_fd_init = true;
         }
 
         int timeout = -1;
diff --git a/init/init.h b/init/init.h
index eedec27..a104af6 100644
--- a/init/init.h
+++ b/init/init.h
@@ -17,13 +17,11 @@
 #ifndef _INIT_INIT_H
 #define _INIT_INIT_H
 
+#include <sys/types.h>
+
 #include <cutils/list.h>
 #include <cutils/iosched_policy.h>
 
-#include <sys/stat.h>
-
-void handle_control_message(const char *msg, const char *arg);
-
 struct command
 {
         /* list of commands in an action */
@@ -59,8 +57,6 @@
     struct command *current;
 };
 
-void build_triggers_string(char *name_str, int length, struct action *cur_action);
-
 struct socketinfo {
     struct socketinfo *next;
     const char *name;
@@ -77,27 +73,29 @@
     const char *value;
 };
 
-#define SVC_DISABLED    0x01  /* do not autostart with class */
-#define SVC_ONESHOT     0x02  /* do not restart on exit */
-#define SVC_RUNNING     0x04  /* currently active */
-#define SVC_RESTARTING  0x08  /* waiting to restart */
-#define SVC_CONSOLE     0x10  /* requires console */
-#define SVC_CRITICAL    0x20  /* will reboot into recovery if keeps crashing */
-#define SVC_RESET       0x40  /* Use when stopping a process, but not disabling
-                                 so it can be restarted with its class */
-#define SVC_RC_DISABLED 0x80  /* Remember if the disabled flag was set in the rc script */
-#define SVC_RESTART     0x100 /* Use to safely restart (stop, wait, start) a service */
-#define SVC_DISABLED_START 0x200 /* a start was requested but it was disabled at the time */
+#define SVC_DISABLED       0x001  // do not autostart with class
+#define SVC_ONESHOT        0x002  // do not restart on exit
+#define SVC_RUNNING        0x004  // currently active
+#define SVC_RESTARTING     0x008  // waiting to restart
+#define SVC_CONSOLE        0x010  // requires console
+#define SVC_CRITICAL       0x020  // will reboot into recovery if keeps crashing
+#define SVC_RESET          0x040  // Use when stopping a process, but not disabling so it can be restarted with its class.
+#define SVC_RC_DISABLED    0x080  // Remember if the disabled flag was set in the rc script.
+#define SVC_RESTART        0x100  // Use to safely restart (stop, wait, start) a service.
+#define SVC_DISABLED_START 0x200  // A start was requested but it was disabled at the time.
+#define SVC_EXEC           0x400  // This synthetic service corresponds to an 'exec'.
 
 #define NR_SVC_SUPP_GIDS 12    /* twelve supplementary groups */
 
 #define COMMAND_RETRY_TIMEOUT 5
 
 struct service {
+    void NotifyStateChange(const char* new_state);
+
         /* list of all services */
     struct listnode slist;
 
-    const char *name;
+    char *name;
     const char *classname;
 
     unsigned flags;
@@ -105,19 +103,19 @@
     time_t time_started;    /* time of last start */
     time_t time_crashed;    /* first crash within inspection window */
     int nr_crashed;         /* number of times crashed within window */
-    
+
     uid_t uid;
     gid_t gid;
     gid_t supp_gids[NR_SVC_SUPP_GIDS];
     size_t nr_supp_gids;
 
-    char *seclabel;
+    const char* seclabel;
 
     struct socketinfo *sockets;
     struct svcenvinfo *envvars;
 
     struct action onrestart;  /* Actions to execute on restart. */
-    
+
     /* keycodes for triggering this service via /dev/keychord */
     int *keycodes;
     int nkeycodes;
@@ -131,7 +129,13 @@
     char *args[1];
 }; /*     ^-------'args' MUST be at the end of this struct! */
 
-void notify_service_state(const char *name, const char *state);
+extern bool waiting_for_exec;
+extern struct selabel_handle *sehandle;
+extern struct selabel_handle *sehandle_prop;
+
+void build_triggers_string(char *name_str, int length, struct action *cur_action);
+
+void handle_control_message(const char *msg, const char *arg);
 
 struct service *service_find_by_name(const char *name);
 struct service *service_find_by_pid(pid_t pid);
@@ -147,9 +151,8 @@
 void service_start(struct service *svc, const char *dynamic_args);
 void property_changed(const char *name, const char *value);
 
-extern struct selabel_handle *sehandle;
-extern struct selabel_handle *sehandle_prop;
-extern int selinux_reload_policy(void);
+int selinux_reload_policy(void);
+
 void zap_stdio(void);
 
 #endif	/* _INIT_INIT_H */
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 61a5e0a..593f0c5 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -14,14 +14,16 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdarg.h>
 #include <string.h>
-#include <stddef.h>
-#include <ctype.h>
+#include <unistd.h>
 
 #include "init.h"
 #include "parser.h"
@@ -117,11 +119,9 @@
     switch (*s++) {
     case 'b':
         if (!strcmp(s, "ootchart_init")) return K_bootchart_init;
+        break;
     case 'c':
         if (!strcmp(s, "opy")) return K_copy;
-        if (!strcmp(s, "apability")) return K_capability;
-        if (!strcmp(s, "hdir")) return K_chdir;
-        if (!strcmp(s, "hroot")) return K_chroot;
         if (!strcmp(s, "lass")) return K_class;
         if (!strcmp(s, "lass_start")) return K_class_start;
         if (!strcmp(s, "lass_stop")) return K_class_stop;
@@ -152,6 +152,7 @@
         if (!strcmp(s, "fup")) return K_ifup;
         if (!strcmp(s, "nsmod")) return K_insmod;
         if (!strcmp(s, "mport")) return K_import;
+        if (!strcmp(s, "nstallkey")) return K_installkey;
         break;
     case 'k':
         if (!strcmp(s, "eycodes")) return K_keycodes;
@@ -185,12 +186,9 @@
         if (!strcmp(s, "eclabel")) return K_seclabel;
         if (!strcmp(s, "ervice")) return K_service;
         if (!strcmp(s, "etcon")) return K_setcon;
-        if (!strcmp(s, "etenforce")) return K_setenforce;
         if (!strcmp(s, "etenv")) return K_setenv;
-        if (!strcmp(s, "etkey")) return K_setkey;
         if (!strcmp(s, "etprop")) return K_setprop;
         if (!strcmp(s, "etrlimit")) return K_setrlimit;
-        if (!strcmp(s, "etsebool")) return K_setsebool;
         if (!strcmp(s, "ocket")) return K_socket;
         if (!strcmp(s, "tart")) return K_start;
         if (!strcmp(s, "top")) return K_stop;
@@ -204,6 +202,10 @@
     case 'u':
         if (!strcmp(s, "ser")) return K_user;
         break;
+    case 'v':
+        if (!strcmp(s, "erity_load_state")) return K_verity_load_state;
+        if (!strcmp(s, "erity_update_state")) return K_verity_update_state;
+        break;
     case 'w':
         if (!strcmp(s, "rite")) return K_write;
         if (!strcmp(s, "ait")) return K_wait;
@@ -350,7 +352,7 @@
     struct import* import = (struct import*) calloc(1, sizeof(struct import));
     import->filename = strdup(conf_file);
     list_add_tail(import_list, &import->list);
-    INFO("found import '%s', adding to import list", import->filename);
+    INFO("Added '%s' to import list\n", import->filename);
 }
 
 static void parse_new_section(struct parse_state *state, int kw,
@@ -437,7 +439,8 @@
 }
 
 int init_parse_config_file(const char* path) {
-    INFO("Parsing %s...", path);
+    INFO("Parsing %s...\n", path);
+    Timer t;
     std::string data;
     if (!read_file(path, &data)) {
         return -1;
@@ -445,6 +448,8 @@
 
     parse_config(path, data);
     dump_parser_state();
+
+    NOTICE("(Parsing %s took %.2fs.)\n", path, t.duration());
     return 0;
 }
 
@@ -660,6 +665,65 @@
     return list_empty(&action_queue);
 }
 
+service* make_exec_oneshot_service(int nargs, char** args) {
+    // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
+    int command_arg = 1;
+    for (int i = 1; i < nargs; ++i) {
+        if (strcmp(args[i], "--") == 0) {
+            command_arg = i + 1;
+            break;
+        }
+    }
+    if (command_arg > 4 + NR_SVC_SUPP_GIDS) {
+        ERROR("exec called with too many supplementary group ids\n");
+        return NULL;
+    }
+
+    int argc = nargs - command_arg;
+    char** argv = (args + command_arg);
+    if (argc < 1) {
+        ERROR("exec called without command\n");
+        return NULL;
+    }
+
+    service* svc = (service*) calloc(1, sizeof(*svc) + sizeof(char*) * argc);
+    if (svc == NULL) {
+        ERROR("Couldn't allocate service for exec of '%s': %s", argv[0], strerror(errno));
+        return NULL;
+    }
+
+    if (command_arg > 2) {
+        svc->seclabel = args[1];
+    }
+    if (command_arg > 3) {
+        svc->uid = decode_uid(args[2]);
+    }
+    if (command_arg > 4) {
+        svc->gid = decode_uid(args[3]);
+        svc->nr_supp_gids = command_arg - 1 /* -- */ - 4 /* exec SECLABEL UID GID */;
+        for (size_t i = 0; i < svc->nr_supp_gids; ++i) {
+            svc->supp_gids[i] = decode_uid(args[4 + i]);
+        }
+    }
+
+    static int exec_count; // Every service needs a unique name.
+    char* name = NULL;
+    asprintf(&name, "exec %d (%s)", exec_count++, argv[0]);
+    if (name == NULL) {
+        ERROR("Couldn't allocate name for exec service '%s'\n", argv[0]);
+        free(svc);
+        return NULL;
+    }
+    svc->name = name;
+    svc->classname = "default";
+    svc->flags = SVC_EXEC | SVC_ONESHOT;
+    svc->nargs = argc;
+    memcpy(svc->args, argv, sizeof(char*) * svc->nargs);
+    svc->args[argc] = NULL;
+    list_add_tail(&service_list, &svc->slist);
+    return svc;
+}
+
 static void *parse_service(struct parse_state *state, int nargs, char **args)
 {
     if (nargs < 3) {
@@ -683,7 +747,7 @@
         parse_error(state, "out of memory\n");
         return 0;
     }
-    svc->name = args[1];
+    svc->name = strdup(args[1]);
     svc->classname = "default";
     memcpy(svc->args, args + 2, sizeof(char*) * nargs);
     trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
@@ -711,8 +775,6 @@
 
     kw = lookup_keyword(args[0]);
     switch (kw) {
-    case K_capability:
-        break;
     case K_class:
         if (nargs != 2) {
             parse_error(state, "class option requires a classname\n");
diff --git a/init/init_parser.h b/init/init_parser.h
index 0047da7..6348607 100644
--- a/init/init_parser.h
+++ b/init/init_parser.h
@@ -20,6 +20,7 @@
 #define INIT_PARSER_MAXARGS 64
 
 struct action;
+struct service;
 
 struct action *action_remove_queue_head(void);
 void action_add_queue_tail(struct action *act);
@@ -33,4 +34,6 @@
 int init_parse_config_file(const char *fn);
 int expand_props(char *dst, const char *src, int len);
 
+service* make_exec_oneshot_service(int argc, char** argv);
+
 #endif
diff --git a/init/init_parser_test.cpp b/init/init_parser_test.cpp
new file mode 100644
index 0000000..170a73a
--- /dev/null
+++ b/init/init_parser_test.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#include "init_parser.h"
+
+#include "init.h"
+#include "util.h"
+
+#include <errno.h>
+#include <gtest/gtest.h>
+
+TEST(init_parser, make_exec_oneshot_service_invalid_syntax) {
+    char* argv[10];
+    memset(argv, 0, sizeof(argv));
+
+    // Nothing.
+    ASSERT_EQ(nullptr, make_exec_oneshot_service(0, argv));
+
+    // No arguments to 'exec'.
+    argv[0] = const_cast<char*>("exec");
+    ASSERT_EQ(nullptr, make_exec_oneshot_service(1, argv));
+
+    // No command in "exec --".
+    argv[1] = const_cast<char*>("--");
+    ASSERT_EQ(nullptr, make_exec_oneshot_service(2, argv));
+}
+
+TEST(init_parser, make_exec_oneshot_service_too_many_supplementary_gids) {
+    int argc = 0;
+    char* argv[4 + NR_SVC_SUPP_GIDS + 3];
+    argv[argc++] = const_cast<char*>("exec");
+    argv[argc++] = const_cast<char*>("seclabel");
+    argv[argc++] = const_cast<char*>("root"); // uid.
+    argv[argc++] = const_cast<char*>("root"); // gid.
+    for (int i = 0; i < NR_SVC_SUPP_GIDS; ++i) {
+        argv[argc++] = const_cast<char*>("root"); // Supplementary gid.
+    }
+    argv[argc++] = const_cast<char*>("--");
+    argv[argc++] = const_cast<char*>("/system/bin/id");
+    argv[argc] = nullptr;
+    ASSERT_EQ(nullptr, make_exec_oneshot_service(argc, argv));
+}
+
+static void Test_make_exec_oneshot_service(bool dash_dash, bool seclabel, bool uid, bool gid, bool supplementary_gids) {
+    int argc = 0;
+    char* argv[10];
+    argv[argc++] = const_cast<char*>("exec");
+    if (seclabel) {
+        argv[argc++] = const_cast<char*>("u:r:su:s0"); // seclabel
+        if (uid) {
+            argv[argc++] = const_cast<char*>("log");      // uid
+            if (gid) {
+                argv[argc++] = const_cast<char*>("shell");     // gid
+                if (supplementary_gids) {
+                    argv[argc++] = const_cast<char*>("system");    // supplementary gid 0
+                    argv[argc++] = const_cast<char*>("adb");       // supplementary gid 1
+                }
+            }
+        }
+    }
+    if (dash_dash) {
+        argv[argc++] = const_cast<char*>("--");
+    }
+    argv[argc++] = const_cast<char*>("/system/bin/toybox");
+    argv[argc++] = const_cast<char*>("id");
+    argv[argc] = nullptr;
+    service* svc = make_exec_oneshot_service(argc, argv);
+    ASSERT_NE(nullptr, svc);
+
+    if (seclabel) {
+        ASSERT_STREQ("u:r:su:s0", svc->seclabel);
+    } else {
+        ASSERT_EQ(nullptr, svc->seclabel);
+    }
+    if (uid) {
+        ASSERT_EQ(decode_uid("log"), svc->uid);
+    } else {
+        ASSERT_EQ(0U, svc->uid);
+    }
+    if (gid) {
+        ASSERT_EQ(decode_uid("shell"), svc->gid);
+    } else {
+        ASSERT_EQ(0U, svc->gid);
+    }
+    if (supplementary_gids) {
+        ASSERT_EQ(2U, svc->nr_supp_gids);
+        ASSERT_EQ(decode_uid("system"), svc->supp_gids[0]);
+        ASSERT_EQ(decode_uid("adb"), svc->supp_gids[1]);
+    } else {
+        ASSERT_EQ(0U, svc->nr_supp_gids);
+    }
+
+    ASSERT_EQ(2, svc->nargs);
+    ASSERT_EQ("/system/bin/toybox", svc->args[0]);
+    ASSERT_EQ("id", svc->args[1]);
+    ASSERT_EQ(nullptr, svc->args[2]);
+}
+
+TEST(init_parser, make_exec_oneshot_service_with_everything) {
+    Test_make_exec_oneshot_service(true, true, true, true, true);
+}
+
+TEST(init_parser, make_exec_oneshot_service_with_seclabel_uid_gid) {
+    Test_make_exec_oneshot_service(true, true, true, true, false);
+}
+
+TEST(init_parser, make_exec_oneshot_service_with_seclabel_uid) {
+    Test_make_exec_oneshot_service(true, true, true, false, false);
+}
+
+TEST(init_parser, make_exec_oneshot_service_with_seclabel) {
+    Test_make_exec_oneshot_service(true, true, false, false, false);
+}
+
+TEST(init_parser, make_exec_oneshot_service_with_just_command) {
+    Test_make_exec_oneshot_service(true, false, false, false, false);
+}
+
+TEST(init_parser, make_exec_oneshot_service_with_just_command_no_dash) {
+    Test_make_exec_oneshot_service(false, false, false, false, false);
+}
diff --git a/init/keychords.cpp b/init/keychords.cpp
index d6464bd..27894a2 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -80,7 +80,7 @@
 
     ret = write(fd, keychords, keychords_length);
     if (ret != keychords_length) {
-        ERROR("could not configure /dev/keychord %d (%d)\n", ret, errno);
+        ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno));
         close(fd);
         fd = -1;
     }
@@ -109,7 +109,7 @@
     if (!strcmp(adb_enabled, "running")) {
         svc = service_find_by_keychord(id);
         if (svc) {
-            INFO("starting service %s from keychord\n", svc->name);
+            INFO("Starting service %s from keychord\n", svc->name);
             service_start(svc, NULL);
         } else {
             ERROR("service for keychord %d not found\n", id);
diff --git a/init/keywords.h b/init/keywords.h
index a8f29d1..4bd0ba6 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -1,7 +1,5 @@
 #ifndef KEYWORD
 int do_bootchart_init(int nargs, char **args);
-int do_chroot(int nargs, char **args);
-int do_chdir(int nargs, char **args);
 int do_class_start(int nargs, char **args);
 int do_class_stop(int nargs, char **args);
 int do_class_reset(int nargs, char **args);
@@ -13,6 +11,7 @@
 int do_hostname(int nargs, char **args);
 int do_ifup(int nargs, char **args);
 int do_insmod(int nargs, char **args);
+int do_installkey(int nargs, char **args);
 int do_mkdir(int nargs, char **args);
 int do_mount_all(int nargs, char **args);
 int do_mount(int nargs, char **args);
@@ -23,11 +22,8 @@
 int do_rm(int nargs, char **args);
 int do_rmdir(int nargs, char **args);
 int do_setcon(int nargs, char **args);
-int do_setenforce(int nargs, char **args);
-int do_setkey(int nargs, char **args);
 int do_setprop(int nargs, char **args);
 int do_setrlimit(int nargs, char **args);
-int do_setsebool(int nargs, char **args);
 int do_start(int nargs, char **args);
 int do_stop(int nargs, char **args);
 int do_swapon_all(int nargs, char **args);
@@ -41,15 +37,14 @@
 int do_loglevel(int nargs, char **args);
 int do_load_persist_props(int nargs, char **args);
 int do_load_all_props(int nargs, char **args);
+int do_verity_load_state(int nargs, char **args);
+int do_verity_update_state(int nargs, char **args);
 int do_wait(int nargs, char **args);
 #define __MAKE_KEYWORD_ENUM__
 #define KEYWORD(symbol, flags, nargs, func) K_##symbol,
 enum {
     K_UNKNOWN,
 #endif
-    KEYWORD(capability,  OPTION,  0, 0)
-    KEYWORD(chdir,       COMMAND, 1, do_chdir)
-    KEYWORD(chroot,      COMMAND, 1, do_chroot)
     KEYWORD(class,       OPTION,  0, 0)
     KEYWORD(class_start, COMMAND, 1, do_class_start)
     KEYWORD(class_stop,  COMMAND, 1, do_class_stop)
@@ -66,6 +61,7 @@
     KEYWORD(hostname,    COMMAND, 1, do_hostname)
     KEYWORD(ifup,        COMMAND, 1, do_ifup)
     KEYWORD(insmod,      COMMAND, 1, do_insmod)
+    KEYWORD(installkey,  COMMAND, 1, do_installkey)
     KEYWORD(import,      SECTION, 1, 0)
     KEYWORD(keycodes,    OPTION,  0, 0)
     KEYWORD(mkdir,       COMMAND, 1, do_mkdir)
@@ -83,12 +79,9 @@
     KEYWORD(seclabel,    OPTION,  0, 0)
     KEYWORD(service,     SECTION, 0, 0)
     KEYWORD(setcon,      COMMAND, 1, do_setcon)
-    KEYWORD(setenforce,  COMMAND, 1, do_setenforce)
     KEYWORD(setenv,      OPTION,  2, 0)
-    KEYWORD(setkey,      COMMAND, 0, do_setkey)
     KEYWORD(setprop,     COMMAND, 2, do_setprop)
     KEYWORD(setrlimit,   COMMAND, 3, do_setrlimit)
-    KEYWORD(setsebool,   COMMAND, 2, do_setsebool)
     KEYWORD(socket,      OPTION,  0, 0)
     KEYWORD(start,       COMMAND, 1, do_start)
     KEYWORD(stop,        COMMAND, 1, do_stop)
@@ -97,6 +90,8 @@
     KEYWORD(symlink,     COMMAND, 1, do_symlink)
     KEYWORD(sysclktz,    COMMAND, 1, do_sysclktz)
     KEYWORD(user,        OPTION,  0, 0)
+    KEYWORD(verity_load_state,      COMMAND, 0, do_verity_load_state)
+    KEYWORD(verity_update_state,    COMMAND, 0, do_verity_update_state)
     KEYWORD(wait,        COMMAND, 1, do_wait)
     KEYWORD(write,       COMMAND, 2, do_write)
     KEYWORD(copy,        COMMAND, 2, do_copy)
diff --git a/init/log.cpp b/init/log.cpp
new file mode 100644
index 0000000..d32f2da
--- /dev/null
+++ b/init/log.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+
+#include <selinux/selinux.h>
+
+#include "log.h"
+
+static void init_klog_vwrite(int level, const char* fmt, va_list ap) {
+    static const char* tag = basename(getprogname());
+
+    char prefix[64];
+    snprintf(prefix, sizeof(prefix), "<%d>%s: ", level, tag);
+
+    char msg[512];
+    vsnprintf(msg, sizeof(msg), fmt, ap);
+
+    iovec iov[2];
+    iov[0].iov_base = prefix;
+    iov[0].iov_len = strlen(prefix);
+    iov[1].iov_base = msg;
+    iov[1].iov_len = strlen(msg);
+
+    klog_writev(level, iov, 2);
+}
+
+void init_klog_write(int level, const char* fmt, ...) {
+    va_list ap;
+    va_start(ap, fmt);
+    init_klog_vwrite(level, fmt, ap);
+    va_end(ap);
+}
+
+int selinux_klog_callback(int type, const char *fmt, ...) {
+    int level = KLOG_ERROR_LEVEL;
+    if (type == SELINUX_WARNING) {
+        level = KLOG_WARNING_LEVEL;
+    } else if (type == SELINUX_INFO) {
+        level = KLOG_INFO_LEVEL;
+    }
+    va_list ap;
+    va_start(ap, fmt);
+    init_klog_vwrite(level, fmt, ap);
+    va_end(ap);
+    return 0;
+}
diff --git a/init/log.h b/init/log.h
index e9cb65a..b804d1f 100644
--- a/init/log.h
+++ b/init/log.h
@@ -19,10 +19,11 @@
 
 #include <cutils/klog.h>
 
-#define ERROR(x...)   KLOG_ERROR("init", x)
-#define NOTICE(x...)  KLOG_NOTICE("init", x)
-#define INFO(x...)    KLOG_INFO("init", x)
+#define ERROR(x...)   init_klog_write(KLOG_ERROR_LEVEL, x)
+#define NOTICE(x...)  init_klog_write(KLOG_NOTICE_LEVEL, x)
+#define INFO(x...)    init_klog_write(KLOG_INFO_LEVEL, x)
 
-extern int log_callback(int type, const char *fmt, ...);
+void init_klog_write(int level, const char* fmt, ...) __printflike(2, 3);
+int selinux_klog_callback(int level, const char* fmt, ...) __printflike(2, 3);
 
 #endif
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 05c03d6..2fa81d4 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -26,12 +26,12 @@
 #include <errno.h>
 #include <sys/poll.h>
 
+#include <memory>
+
 #include <cutils/misc.h>
 #include <cutils/sockets.h>
 #include <cutils/multiuser.h>
 
-#include <utils/file.h>
-
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
 
@@ -54,7 +54,7 @@
 #define PERSISTENT_PROPERTY_DIR  "/data/property"
 
 static int persistent_properties_loaded = 0;
-static int property_area_inited = 0;
+static bool property_area_initialized = false;
 
 static int property_set_fd = -1;
 
@@ -63,34 +63,25 @@
     int fd;
 };
 
-static int init_workspace(workspace *w, size_t size)
-{
-    int fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW);
-    if (fd < 0)
-        return -1;
-
-    w->size = size;
-    w->fd = fd;
-    return 0;
-}
-
 static workspace pa_workspace;
 
-static int init_property_area(void)
-{
-    if (property_area_inited)
-        return -1;
+void property_init() {
+    if (property_area_initialized) {
+        return;
+    }
 
-    if(__system_property_area_init())
-        return -1;
+    property_area_initialized = true;
 
-    if(init_workspace(&pa_workspace, 0))
-        return -1;
+    if (__system_property_area_init()) {
+        return;
+    }
 
-    fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);
-
-    property_area_inited = 1;
-    return 0;
+    pa_workspace.size = 0;
+    pa_workspace.fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
+    if (pa_workspace.fd == -1) {
+        ERROR("Failed to open %s: %s\n", PROP_FILENAME, strerror(errno));
+        return;
+    }
 }
 
 static int check_mac_perms(const char *name, char *sctx)
@@ -161,7 +152,7 @@
     snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR);
     fd = mkstemp(tempPath);
     if (fd < 0) {
-        ERROR("Unable to write persistent property to temp file %s errno: %d\n", tempPath, errno);
+        ERROR("Unable to write persistent property to temp file %s: %s\n", tempPath, strerror(errno));
         return;
     }
     write(fd, value, strlen(value));
@@ -201,18 +192,14 @@
     return true;
 }
 
-int property_set(const char *name, const char *value)
-{
-    prop_info *pi;
-    int ret;
-
+static int property_set_impl(const char* name, const char* value) {
     size_t namelen = strlen(name);
     size_t valuelen = strlen(value);
 
     if (!is_legal_property_name(name, namelen)) return -1;
     if (valuelen >= PROP_VALUE_MAX) return -1;
 
-    pi = (prop_info*) __system_property_find(name);
+    prop_info* pi = (prop_info*) __system_property_find(name);
 
     if(pi != 0) {
         /* ro.* properties may NEVER be modified once set */
@@ -220,10 +207,9 @@
 
         __system_property_update(pi, value, valuelen);
     } else {
-        ret = __system_property_add(name, namelen, value, valuelen);
-        if (ret < 0) {
-            ERROR("Failed to set '%s'='%s'\n", name, value);
-            return ret;
+        int rc = __system_property_add(name, namelen, value, valuelen);
+        if (rc < 0) {
+            return rc;
         }
     }
     /* If name starts with "net." treat as a DNS property. */
@@ -252,6 +238,14 @@
     return 0;
 }
 
+int property_set(const char* name, const char* value) {
+    int rc = property_set_impl(name, value);
+    if (rc == -1) {
+        ERROR("property_set(\"%s\", \"%s\") failed\n", name, value);
+    }
+    return rc;
+}
+
 void handle_property_set_fd()
 {
     prop_msg msg;
@@ -286,15 +280,15 @@
         close(s);
         return;
     } else if (nr < 0) {
-        ERROR("sys_prop: error waiting for uid=%d to send property message. err=%d %s\n", cr.uid, errno, strerror(errno));
+        ERROR("sys_prop: error waiting for uid=%d to send property message: %s\n", cr.uid, strerror(errno));
         close(s);
         return;
     }
 
     r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));
     if(r != sizeof(prop_msg)) {
-        ERROR("sys_prop: mis-match msg size received: %d expected: %zu errno: %d\n",
-              r, sizeof(prop_msg), errno);
+        ERROR("sys_prop: mis-match msg size received: %d expected: %zu: %s\n",
+              r, sizeof(prop_msg), strerror(errno));
         close(s);
         return;
     }
@@ -416,87 +410,79 @@
  * Filter is used to decide which properties to load: NULL loads all keys,
  * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
  */
-static void load_properties_from_file(const char *fn, const char *filter)
-{
+static void load_properties_from_file(const char* filename, const char* filter) {
+    Timer t;
     std::string data;
-    if (read_file(fn, &data)) {
+    if (read_file(filename, &data)) {
         load_properties(&data[0], filter);
     }
+    NOTICE("(Loading properties from %s took %.2fs.)\n", filename, t.duration());
 }
 
-static void load_persistent_properties()
-{
-    DIR* dir = opendir(PERSISTENT_PROPERTY_DIR);
-    int dir_fd;
-    struct dirent*  entry;
-    char value[PROP_VALUE_MAX];
-    int fd, length;
-    struct stat sb;
+static void load_persistent_properties() {
+    persistent_properties_loaded = 1;
 
-    if (dir) {
-        dir_fd = dirfd(dir);
-        while ((entry = readdir(dir)) != NULL) {
-            if (strncmp("persist.", entry->d_name, strlen("persist.")))
-                continue;
-            if (entry->d_type != DT_REG)
-                continue;
-            /* open the file and read the property value */
-            fd = openat(dir_fd, entry->d_name, O_RDONLY | O_NOFOLLOW);
-            if (fd < 0) {
-                ERROR("Unable to open persistent property file \"%s\" errno: %d\n",
-                      entry->d_name, errno);
-                continue;
-            }
-            if (fstat(fd, &sb) < 0) {
-                ERROR("fstat on property file \"%s\" failed errno: %d\n", entry->d_name, errno);
-                close(fd);
-                continue;
-            }
-
-            // File must not be accessible to others, be owned by root/root, and
-            // not be a hard link to any other file.
-            if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0)
-                    || (sb.st_uid != 0)
-                    || (sb.st_gid != 0)
-                    || (sb.st_nlink != 1)) {
-                ERROR("skipping insecure property file %s (uid=%u gid=%u nlink=%u mode=%o)\n",
-                      entry->d_name, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid,
-                      (unsigned int)sb.st_nlink, sb.st_mode);
-                close(fd);
-                continue;
-            }
-
-            length = read(fd, value, sizeof(value) - 1);
-            if (length >= 0) {
-                value[length] = 0;
-                property_set(entry->d_name, value);
-            } else {
-                ERROR("Unable to read persistent property file %s errno: %d\n",
-                      entry->d_name, errno);
-            }
-            close(fd);
-        }
-        closedir(dir);
-    } else {
-        ERROR("Unable to open persistent property directory %s errno: %d\n", PERSISTENT_PROPERTY_DIR, errno);
+    std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(PERSISTENT_PROPERTY_DIR), closedir);
+    if (!dir) {
+        ERROR("Unable to open persistent property directory \"%s\": %s\n",
+              PERSISTENT_PROPERTY_DIR, strerror(errno));
+        return;
     }
 
-    persistent_properties_loaded = 1;
+    struct dirent* entry;
+    while ((entry = readdir(dir.get())) != NULL) {
+        if (strncmp("persist.", entry->d_name, strlen("persist."))) {
+            continue;
+        }
+        if (entry->d_type != DT_REG) {
+            continue;
+        }
+
+        // Open the file and read the property value.
+        int fd = openat(dirfd(dir.get()), entry->d_name, O_RDONLY | O_NOFOLLOW);
+        if (fd == -1) {
+            ERROR("Unable to open persistent property file \"%s\": %s\n",
+                  entry->d_name, strerror(errno));
+            continue;
+        }
+
+        struct stat sb;
+        if (fstat(fd, &sb) == -1) {
+            ERROR("fstat on property file \"%s\" failed: %s\n", entry->d_name, strerror(errno));
+            close(fd);
+            continue;
+        }
+
+        // File must not be accessible to others, be owned by root/root, and
+        // not be a hard link to any other file.
+        if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) || (sb.st_uid != 0) || (sb.st_gid != 0) ||
+                (sb.st_nlink != 1)) {
+            ERROR("skipping insecure property file %s (uid=%u gid=%u nlink=%u mode=%o)\n",
+                  entry->d_name, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid,
+                  (unsigned int)sb.st_nlink, sb.st_mode);
+            close(fd);
+            continue;
+        }
+
+        char value[PROP_VALUE_MAX];
+        int length = read(fd, value, sizeof(value) - 1);
+        if (length >= 0) {
+            value[length] = 0;
+            property_set(entry->d_name, value);
+        } else {
+            ERROR("Unable to read persistent property file %s: %s\n",
+                  entry->d_name, strerror(errno));
+        }
+        close(fd);
+    }
 }
 
-void property_init(void)
-{
-    init_property_area();
-}
-
-void property_load_boot_defaults(void)
-{
+void property_load_boot_defaults() {
     load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL);
 }
 
-int properties_inited(void)
-{
-    return property_area_inited;
+bool properties_initialized() {
+    return property_area_initialized;
 }
 
 static void load_override_properties() {
@@ -509,21 +495,18 @@
     }
 }
 
-
 /* When booting an encrypted system, /data is not mounted when the
  * property service is started, so any properties stored there are
  * not loaded.  Vold triggers init to load these properties once it
  * has mounted /data.
  */
-void load_persist_props(void)
-{
+void load_persist_props(void) {
     load_override_properties();
     /* Read persistent properties after all default values have been loaded. */
     load_persistent_properties();
 }
 
-void load_all_props(void)
-{
+void load_all_props() {
     load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
     load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL);
     load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);
@@ -536,12 +519,10 @@
     load_persistent_properties();
 }
 
-void start_property_service(void)
-{
-    int fd;
+void start_property_service() {
+    int fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL);
+    if (fd == -1) return;
 
-    fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL);
-    if(fd < 0) return;
     fcntl(fd, F_SETFD, FD_CLOEXEC);
     fcntl(fd, F_SETFL, O_NONBLOCK);
 
@@ -549,7 +530,6 @@
     property_set_fd = fd;
 }
 
-int get_property_set_fd()
-{
+int get_property_set_fd() {
     return property_set_fd;
 }
diff --git a/init/property_service.h b/init/property_service.h
index 6e7fc00..825a7dd 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -29,7 +29,7 @@
 void get_property_workspace(int *fd, int *sz);
 extern int __property_get(const char *name, char *value);
 extern int property_set(const char *name, const char *value);
-extern int properties_inited();
+extern bool properties_initialized();
 int get_property_set_fd(void);
 
 #ifndef __clang__
diff --git a/init/readme.txt b/init/readme.txt
index 32eb4ab..630dd03 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -70,11 +70,11 @@
 setenv <name> <value>
    Set the environment variable <name> to <value> in the launched process.
 
-socket <name> <type> <perm> [ <user> [ <group> [ <context> ] ] ]
+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.
-   Context is the SELinux security context for the socket.
+   '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.
 
@@ -91,8 +91,8 @@
    supplemental groups of the process (via setgroups()).
    Currently defaults to root.  (??? probably should default to nobody)
 
-seclabel <securitycontext>
-  Change to securitycontext before exec'ing this service.
+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.
@@ -137,32 +137,9 @@
 Commands
 --------
 
-exec <path> [ <argument> ]*
-   This command is not implemented.
-
-execonce <path> [ <argument> ]*
-   Fork and execute a program (<path>).  This will block until
-   the program completes execution.  This command can be run at most
-   once during init's lifetime. Subsequent invocations are ignored.
-   It is best to avoid exec as unlike the builtin commands, it runs
-   the risk of getting init "stuck".
-
-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)
-
-ifup <interface>
-   Bring the network interface <interface> online.
-
-import <filename>
-   Parse an init config file, extending the current configuration.
-
-hostname <name>
-   Set the host name.
-
-chdir <directory>
-   Change working directory.
+bootchart_init
+   Start bootcharting if configured (see below).
+   This is included in the default init.rc.
 
 chmod <octal-mode> <path>
    Change file access permissions.
@@ -170,17 +147,23 @@
 chown <owner> <group> <path>
    Change file owner and group.
 
-chroot <directory>
-  Change process root directory.
-
 class_start <serviceclass>
    Start all services of the specified class if they are
    not already running.
 
 class_stop <serviceclass>
-   Stop all services of the specified class if they are
+   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.
 
@@ -193,22 +176,67 @@
      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.
+
+execonce <path> [ <argument> ]*
+   Use exec instead. This command will be removed after existing callers have
+   moved to exec.
+
+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.
+
+import <filename>
+   Parse an init config file, extending the current configuration.
+
 insmod <path>
    Install the module at <path>
 
+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.
+   owned by the root user and root group. If provided, the mode, owner and group
+   will be updated if the directory exists already.
 
-mount <type> <device> <dir> [ <mountoption> ]*
+mount_all <fstab>
+   Calls fs_mgr_mount_all on the given fs_mgr-format fstab.
+
+mount <type> <device> <dir> [ <flag> ]* [<options>]
    Attempt to mount the named device at the directory <dir>
    <device> may be of the form mtd@name to specify a mtd block
    device by name.
-   <mountoption>s include "ro", "rw", "remount", "noatime", ...
+   <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
@@ -220,18 +248,19 @@
    Recursively restore the directory tree named by <path> to the
    security contexts specified in the file_contexts configuration.
 
-setcon <securitycontext>
+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.
+
+setcon <seclabel>
    Set the current process security context to the specified string.
    This is typically only used from early-init to set the init context
    before any other process is started.
 
-setenforce 0|1
-   Set the SELinux system-wide enforcing status.
-   0 is permissive (i.e. log but do not deny), 1 is enforcing.
-
-setkey
-   TBD
-
 setprop <name> <value>
    Set system property <name> to <value>. Properties are expanded
    within <value>.
@@ -239,16 +268,15 @@
 setrlimit <resource> <cur> <max>
    Set the rlimit for a resource.
 
-setsebool <name> <value>
-   Set SELinux boolean <name> to <value>.
-   <value> may be 1|true|on or 0|false|off
-
 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>
 
@@ -259,10 +287,18 @@
    Trigger an event.  Used to queue an action from another
    action.
 
+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.
+   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).
@@ -275,7 +311,7 @@
 Init updates some system properties to provide some insight into
 what it's doing:
 
-init.action 
+init.action
    Equal to the name of the action currently being executed or "" if none
 
 init.command
@@ -287,12 +323,11 @@
 
 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 new -bootchart <timeout> option to boot with
-bootcharting activated for <timeout> seconds.
+On the emulator, use the -bootchart <timeout> option to boot with bootcharting
+activated for <timeout> seconds.
 
 On a device, create /data/bootchart/start with a command like the following:
 
@@ -313,9 +348,12 @@
 bootchart command-line utility:
 
   sudo apt-get install pybootchartgui
+  # grab-bootchart.sh uses $ANDROID_SERIAL.
   $ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
-  bootchart ./bootchart.tgz
-  gnome-open bootchart.png
+
+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.
 
 
 Debugging init
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index c0898fb..8be4af5 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -14,90 +14,107 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
 #include <errno.h>
-#include <signal.h>
-#include <unistd.h>
 #include <fcntl.h>
-#include <sys/types.h>
+#include <signal.h>
+#include <stdio.h>
 #include <sys/socket.h>
+#include <sys/types.h>
 #include <sys/wait.h>
-#include <cutils/sockets.h>
+#include <unistd.h>
+
+#include <base/stringprintf.h>
 #include <cutils/android_reboot.h>
 #include <cutils/list.h>
+#include <cutils/sockets.h>
 
 #include "init.h"
-#include "util.h"
 #include "log.h"
+#include "util.h"
+
+#define CRITICAL_CRASH_THRESHOLD    4       /* if we crash >4 times ... */
+#define CRITICAL_CRASH_WINDOW       (4*60)  /* ... in 4 minutes, goto recovery */
 
 static int signal_fd = -1;
 static int signal_recv_fd = -1;
 
-static void sigchld_handler(int s)
-{
+static void sigchld_handler(int s) {
     write(signal_fd, &s, 1);
 }
 
-#define CRITICAL_CRASH_THRESHOLD    4       /* if we crash >4 times ... */
-#define CRITICAL_CRASH_WINDOW       (4*60)  /* ... in 4 minutes, goto recovery*/
+std::string DescribeStatus(int status) {
+    if (WIFEXITED(status)) {
+        return android::base::StringPrintf("exited with status %d", WEXITSTATUS(status));
+    } else if (WIFSIGNALED(status)) {
+        return android::base::StringPrintf("killed by signal %d", WTERMSIG(status));
+    } else if (WIFSTOPPED(status)) {
+        return android::base::StringPrintf("stopped by signal %d", WSTOPSIG(status));
+    } else {
+        return "state changed";
+    }
+}
 
-static int wait_for_one_process(int block)
-{
+static int wait_for_one_process() {
     int status;
-    struct service *svc;
-    struct socketinfo *si;
-    time_t now;
-    struct listnode *node;
-    struct command *cmd;
+    pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
+    if (pid <= 0) {
+        return -1;
+    }
 
-    pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, block ? 0 : WNOHANG));
-    if (pid <= 0) return -1;
-    INFO("waitpid returned pid %d, status = %08x\n", pid, status);
+    service* svc = service_find_by_pid(pid);
 
-    svc = service_find_by_pid(pid);
+    std::string name;
+    if (svc) {
+        name = android::base::StringPrintf("Service '%s' (pid %d)", svc->name, pid);
+    } else {
+        name = android::base::StringPrintf("Untracked pid %d", pid);
+    }
+
+    NOTICE("%s %s\n", name.c_str(), DescribeStatus(status).c_str());
+
     if (!svc) {
-        if (WIFEXITED(status)) {
-            ERROR("untracked pid %d exited with status %d\n", pid, WEXITSTATUS(status));
-        } else if (WIFSIGNALED(status)) {
-            ERROR("untracked pid %d killed by signal %d\n", pid, WTERMSIG(status));
-        } else if (WIFSTOPPED(status)) {
-            ERROR("untracked pid %d stopped by signal %d\n", pid, WSTOPSIG(status));
-        } else {
-            ERROR("untracked pid %d state changed\n", pid);
-        }
         return 0;
     }
 
-    NOTICE("process '%s', pid %d exited\n", svc->name, pid);
+    // TODO: all the code from here down should be a member function on service.
 
     if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {
+        NOTICE("Service '%s' (pid %d) killing any children in process group\n", svc->name, pid);
         kill(-pid, SIGKILL);
-        NOTICE("process '%s' killing any children in process group\n", svc->name);
     }
 
-    /* remove any sockets we may have created */
-    for (si = svc->sockets; si; si = si->next) {
+    // Remove any sockets we may have created.
+    for (socketinfo* si = svc->sockets; si; si = si->next) {
         char tmp[128];
         snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
         unlink(tmp);
     }
 
+    if (svc->flags & SVC_EXEC) {
+        INFO("SVC_EXEC pid %d finished...\n", svc->pid);
+        waiting_for_exec = false;
+        list_remove(&svc->slist);
+        free(svc->name);
+        free(svc);
+        return 0;
+    }
+
     svc->pid = 0;
     svc->flags &= (~SVC_RUNNING);
 
-        /* oneshot processes go into the disabled state on exit,
-         * except when manually restarted. */
+    // Oneshot processes go into the disabled state on exit,
+    // except when manually restarted.
     if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {
         svc->flags |= SVC_DISABLED;
     }
 
-        /* disabled and reset processes do not get restarted automatically */
-    if (svc->flags & (SVC_DISABLED | SVC_RESET) )  {
-        notify_service_state(svc->name, "stopped");
+    // Disabled and reset processes do not get restarted automatically.
+    if (svc->flags & (SVC_DISABLED | SVC_RESET))  {
+        svc->NotifyStateChange("stopped");
         return 0;
     }
 
-    now = gettime();
+    time_t now = gettime();
     if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) {
         if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
             if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
@@ -116,36 +133,33 @@
     svc->flags &= (~SVC_RESTART);
     svc->flags |= SVC_RESTARTING;
 
-    /* Execute all onrestart commands for this service. */
+    // Execute all onrestart commands for this service.
+    struct listnode* node;
     list_for_each(node, &svc->onrestart.commands) {
-        cmd = node_to_item(node, struct command, clist);
+        command* cmd = node_to_item(node, struct command, clist);
         cmd->func(cmd->nargs, cmd->args);
     }
-    notify_service_state(svc->name, "restarting");
+    svc->NotifyStateChange("restarting");
     return 0;
 }
 
-void handle_signal(void)
-{
+void handle_signal() {
+    // We got a SIGCHLD - reap and restart as needed.
     char tmp[32];
-
-    /* we got a SIGCHLD - reap and restart as needed */
     read(signal_recv_fd, tmp, sizeof(tmp));
-    while (!wait_for_one_process(0))
-        ;
+    while (!wait_for_one_process()) {
+    }
 }
 
-void signal_init(void)
-{
-    int s[2];
-
+void signal_init() {
     struct sigaction act;
     memset(&act, 0, sizeof(act));
     act.sa_handler = sigchld_handler;
     act.sa_flags = SA_NOCLDSTOP;
     sigaction(SIGCHLD, &act, 0);
 
-    /* create a signalling mechanism for the sigchld handler */
+    // Create a signalling mechanism for the sigchld handler.
+    int s[2];
     if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == 0) {
         signal_fd = s[0];
         signal_recv_fd = s[1];
@@ -154,7 +168,6 @@
     handle_signal();
 }
 
-int get_signal_fd()
-{
+int get_signal_fd() {
     return signal_recv_fd;
 }
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index d56b91a..c63fdaa 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -14,46 +14,27 @@
  * limitations under the License.
  */
 
-#include <poll.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
 #include <ctype.h>
+#include <fcntl.h>
+#include <poll.h>
 #include <signal.h>
-#include <selinux/selinux.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
+#include <base/stringprintf.h>
 #include <private/android_filesystem_config.h>
+#include <selinux/selinux.h>
 
 #include "ueventd.h"
 #include "log.h"
 #include "util.h"
 #include "devices.h"
 #include "ueventd_parser.h"
-
-static char hardware[32];
-static unsigned revision = 0;
-
-static void import_kernel_nv(char *name, int in_qemu)
-{
-    if (*name != '\0') {
-        char *value = strchr(name, '=');
-        if (value != NULL) {
-            *value++ = 0;
-            if (!strcmp(name,"androidboot.hardware"))
-            {
-                strlcpy(hardware, value, sizeof(hardware));
-            }
-        }
-    }
-}
+#include "property_service.h"
 
 int ueventd_main(int argc, char **argv)
 {
-    struct pollfd ufd;
-    int nr;
-    char tmp[32];
-
     /*
      * init sets the umask to 077 for forked processes. We need to
      * create files with exact permissions, without modification by
@@ -70,43 +51,35 @@
 
     open_devnull_stdio();
     klog_init();
-    if (LOG_UEVENTS) {
-        /* Ensure we're at a logging level that will show the events */
-        if (klog_get_level() < KLOG_INFO_LEVEL) {
-            klog_set_level(KLOG_INFO_LEVEL);
-        }
-    }
+    klog_set_level(KLOG_NOTICE_LEVEL);
 
-    union selinux_callback cb;
-    cb.func_log = log_callback;
+    NOTICE("ueventd started!\n");
+
+    selinux_callback cb;
+    cb.func_log = selinux_klog_callback;
     selinux_set_callback(SELINUX_CB_LOG, cb);
 
-    INFO("starting ueventd\n");
-
-    /* Respect hardware passed in through the kernel cmd line. Here we will look
-     * for androidboot.hardware param in kernel cmdline, and save its value in
-     * hardware[]. */
-    import_kernel_cmdline(0, import_kernel_nv);
-
-    get_hardware_name(hardware, &revision);
+    char hardware[PROP_VALUE_MAX];
+    property_get("ro.hardware", hardware);
 
     ueventd_parse_config_file("/ueventd.rc");
-
-    snprintf(tmp, sizeof(tmp), "/ueventd.%s.rc", hardware);
-    ueventd_parse_config_file(tmp);
+    ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware).c_str());
 
     device_init();
 
+    pollfd ufd;
     ufd.events = POLLIN;
     ufd.fd = get_device_fd();
 
-    while(1) {
+    while (true) {
         ufd.revents = 0;
-        nr = poll(&ufd, 1, -1);
-        if (nr <= 0)
+        int nr = poll(&ufd, 1, -1);
+        if (nr <= 0) {
             continue;
-        if (ufd.revents & POLLIN)
-               handle_device_fd();
+        }
+        if (ufd.revents & POLLIN) {
+            handle_device_fd();
+        }
     }
 
     return 0;
diff --git a/init/util.cpp b/init/util.cpp
index 3dddb15..3b49b30 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -32,11 +32,11 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
+#include <base/file.h>
+
 /* for ANDROID_SOCKET_* */
 #include <cutils/sockets.h>
 
-#include <utils/file.h>
-
 #include <private/android_filesystem_config.h>
 
 #include "init.h"
@@ -168,7 +168,7 @@
         return false;
     }
 
-    bool okay = android::ReadFdToString(fd, content);
+    bool okay = android::base::ReadFdToString(fd, content);
     TEMP_FAILURE_RETRY(close(fd));
     if (okay) {
         content->append("\n", 1);
@@ -181,7 +181,7 @@
     if (fd == -1) {
         return -errno;
     }
-    int result = android::WriteStringToFd(content, fd) ? 0 : -errno;
+    int result = android::base::WriteStringToFd(content, fd) ? 0 : -errno;
     TEMP_FAILURE_RETRY(close(fd));
     return result;
 }
@@ -258,22 +258,16 @@
     return -1;
 }
 
-/*
- * gettime() - returns the time in seconds of the system's monotonic clock or
- * zero on error.
- */
-time_t gettime(void)
-{
-    struct timespec ts;
-    int ret;
+time_t gettime() {
+    timespec now;
+    clock_gettime(CLOCK_MONOTONIC, &now);
+    return now.tv_sec;
+}
 
-    ret = clock_gettime(CLOCK_MONOTONIC, &ts);
-    if (ret < 0) {
-        ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
-        return 0;
-    }
-
-    return ts.tv_sec;
+uint64_t gettime_ns() {
+    timespec now;
+    clock_gettime(CLOCK_MONOTONIC, &now);
+    return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec;
 }
 
 int mkdir_recursive(const char *pathname, mode_t mode)
@@ -400,39 +394,6 @@
     exit(1);
 }
 
-void get_hardware_name(char *hardware, unsigned int *revision) {
-  // Hardware string was provided on kernel command line.
-  if (hardware[0]) {
-    return;
-  }
-
-  FILE* fp = fopen("/proc/cpuinfo", "re");
-  if (fp == NULL) {
-    return;
-  }
-  char buf[1024];
-  while (fgets(buf, sizeof(buf), fp) != NULL) {
-    if (strncmp(buf, "Hardware", 8) == 0) {
-      const char* hw = strstr(buf, ": ");
-      if (hw) {
-        hw += 2;
-        size_t n = 0;
-        while (*hw) {
-          if (!isspace(*hw)) {
-            hardware[n++] = tolower(*hw);
-          }
-          hw++;
-          if (n == 31) break;
-        }
-        hardware[n] = 0;
-      }
-    } else if (strncmp(buf, "Revision", 8) == 0) {
-      sscanf(buf, "Revision : %ux", revision);
-    }
-  }
-  fclose(fp);
-}
-
 void import_kernel_cmdline(int in_qemu,
                            void (*import_kernel_nv)(char *name, int in_qemu))
 {
diff --git a/init/util.h b/init/util.h
index 77da3ac..8fec7a8 100644
--- a/init/util.h
+++ b/init/util.h
@@ -33,7 +33,22 @@
 bool read_file(const char* path, std::string* content);
 int write_file(const char* path, const char* content);
 
-time_t gettime(void);
+time_t gettime();
+uint64_t gettime_ns();
+
+class Timer {
+ public:
+  Timer() : t0(gettime_ns()) {
+  }
+
+  double duration() {
+    return static_cast<double>(gettime_ns() - t0) / 1000000000.0;
+  }
+
+ private:
+  uint64_t t0;
+};
+
 unsigned int decode_uid(const char *s);
 
 int mkdir_recursive(const char *pathname, mode_t mode);
@@ -42,7 +57,6 @@
 void remove_link(const char *oldpath, const char *newpath);
 int wait_for_file(const char *filename, int timeout);
 void open_devnull_stdio(void);
-void get_hardware_name(char *hardware, unsigned int *revision);
 void import_kernel_cmdline(int in_qemu, void (*import_kernel_nv)(char *name, int in_qemu));
 int make_dir(const char *path, mode_t mode);
 int restorecon(const char *pathname);
diff --git a/init/util_test.cpp b/init/util_test.cpp
index e9a1581..5b3ab50 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -35,3 +35,9 @@
   s[5] = 0;
   EXPECT_STREQ("Linux", s.c_str());
 }
+
+TEST(util, decode_uid) {
+  EXPECT_EQ(0U, decode_uid("root"));
+  EXPECT_EQ(-1U, decode_uid("toot"));
+  EXPECT_EQ(123U, decode_uid("123"));
+}
diff --git a/init/watchdogd.cpp b/init/watchdogd.cpp
index 0790811..881a4df 100644
--- a/init/watchdogd.cpp
+++ b/init/watchdogd.cpp
@@ -27,52 +27,45 @@
 
 #define DEV_NAME "/dev/watchdog"
 
-int watchdogd_main(int argc, char **argv)
-{
-    int fd;
-    int ret;
-    int interval = 10;
-    int margin = 10;
-    int timeout;
-
+int watchdogd_main(int argc, char **argv) {
     open_devnull_stdio();
     klog_init();
+    klog_set_level(KLOG_NOTICE_LEVEL);
 
-    INFO("Starting watchdogd\n");
+    int interval = 10;
+    if (argc >= 2) interval = atoi(argv[1]);
 
-    if (argc >= 2)
-        interval = atoi(argv[1]);
+    int margin = 10;
+    if (argc >= 3) margin = atoi(argv[2]);
 
-    if (argc >= 3)
-        margin = atoi(argv[2]);
+    NOTICE("watchdogd started (interval %d, margin %d)!\n", interval, margin);
 
-    timeout = interval + margin;
-
-    fd = open(DEV_NAME, O_RDWR|O_CLOEXEC);
-    if (fd < 0) {
+    int fd = open(DEV_NAME, O_RDWR|O_CLOEXEC);
+    if (fd == -1) {
         ERROR("watchdogd: Failed to open %s: %s\n", DEV_NAME, strerror(errno));
         return 1;
     }
 
-    ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
+    int timeout = interval + margin;
+    int ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
     if (ret) {
         ERROR("watchdogd: Failed to set timeout to %d: %s\n", timeout, strerror(errno));
         ret = ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
         if (ret) {
             ERROR("watchdogd: Failed to get timeout: %s\n", strerror(errno));
         } else {
-            if (timeout > margin)
+            if (timeout > margin) {
                 interval = timeout - margin;
-            else
+            } else {
                 interval = 1;
+            }
             ERROR("watchdogd: Adjusted interval to timeout returned by driver: timeout %d, interval %d, margin %d\n",
                   timeout, interval, margin);
         }
     }
 
-    while(1) {
+    while (true) {
         write(fd, "", 1);
         sleep(interval);
     }
 }
-
diff --git a/libbacktrace/Android.build.mk b/libbacktrace/Android.build.mk
index 7e1cd53..35fed6d 100644
--- a/libbacktrace/Android.build.mk
+++ b/libbacktrace/Android.build.mk
@@ -19,28 +19,37 @@
 LOCAL_MODULE := $(module)
 LOCAL_MODULE_TAGS := $(module_tag)
 LOCAL_MULTILIB := $($(module)_multilib)
+ifeq ($(LOCAL_MULTILIB),both)
+ifneq ($(build_target),$(filter $(build_target),SHARED_LIBRARY STATIC_LIBRRARY))
+  LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+  LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+endif
+endif
 
 LOCAL_ADDITIONAL_DEPENDENCIES := \
     $(LOCAL_PATH)/Android.mk \
     $(LOCAL_PATH)/Android.build.mk \
 
 LOCAL_CFLAGS := \
-    $(common_cflags) \
+    $(libbacktrace_common_cflags) \
     $($(module)_cflags) \
     $($(module)_cflags_$(build_type)) \
 
+LOCAL_CLANG_CFLAGS += \
+    $(libbacktrace_common_clang_cflags) \
+
 LOCAL_CONLYFLAGS += \
-    $(common_conlyflags) \
+    $(libbacktrace_common_conlyflags) \
     $($(module)_conlyflags) \
     $($(module)_conlyflags_$(build_type)) \
 
 LOCAL_CPPFLAGS += \
-    $(common_cppflags) \
+    $(libbacktrace_common_cppflags) \
     $($(module)_cppflags) \
     $($(module)_cppflags_$(build_type)) \
 
 LOCAL_C_INCLUDES := \
-    $(common_c_includes) \
+    $(libbacktrace_common_c_includes) \
     $($(module)_c_includes) \
     $($(module)_c_includes_$(build_type)) \
 
@@ -67,10 +76,7 @@
 ifeq ($(build_type),host)
   # Only build if host builds are supported.
   ifeq ($(build_host),true)
-    LOCAL_CFLAGS += -Wno-extern-c-compat
-    ifneq ($($(module)_libc++),)
-      include external/libcxx/libcxx.mk
-    endif
+    LOCAL_CFLAGS += -Wno-extern-c-compat -fno-omit-frame-pointer
     include $(BUILD_HOST_$(build_target))
   endif
 endif
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
old mode 100755
new mode 100644
index f3b28dd..b875efd
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -16,16 +16,20 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-common_cflags := \
+libbacktrace_common_cflags := \
 	-Wall \
 	-Werror \
 
-common_conlyflags := \
+libbacktrace_common_conlyflags := \
 	-std=gnu99 \
 
-common_cppflags := \
+libbacktrace_common_cppflags := \
 	-std=gnu++11 \
 
+# The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
+libbacktrace_common_clang_cflags += \
+    -Wno-inline-asm
+
 build_host := false
 ifeq ($(HOST_OS),linux)
 ifeq ($(HOST_ARCH),$(filter $(HOST_ARCH),x86 x86_64))
@@ -37,20 +41,21 @@
 # The libbacktrace library.
 #-------------------------------------------------------------------------
 libbacktrace_src_files := \
-	BacktraceImpl.cpp \
+	Backtrace.cpp \
+	BacktraceCurrent.cpp \
 	BacktraceMap.cpp \
-	BacktraceThread.cpp \
+	BacktracePtrace.cpp \
 	thread_utils.c \
-
-libbacktrace_shared_libraries_target := \
-	libcutils \
-
-libbacktrace_src_files += \
+	ThreadEntry.cpp \
 	UnwindCurrent.cpp \
 	UnwindMap.cpp \
 	UnwindPtrace.cpp \
 
+libbacktrace_shared_libraries_target := \
+	libcutils \
+
 libbacktrace_shared_libraries := \
+	libbase \
 	libunwind \
 	libunwind-ptrace \
 
@@ -86,6 +91,7 @@
 module_tag := debug
 build_type := target
 build_target := SHARED_LIBRARY
+libbacktrace_test_multilib := both
 include $(LOCAL_PATH)/Android.build.mk
 build_type := host
 include $(LOCAL_PATH)/Android.build.mk
@@ -124,6 +130,7 @@
 module_tag := debug
 build_type := target
 build_target := NATIVE_TEST
+backtrace_test_multilib := both
 include $(LOCAL_PATH)/Android.build.mk
 build_type := host
 include $(LOCAL_PATH)/Android.build.mk
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
new file mode 100644
index 0000000..91ca8b7
--- /dev/null
+++ b/libbacktrace/Backtrace.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2013 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 <inttypes.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <ucontext.h>
+
+#include <string>
+
+#include <base/stringprintf.h>
+
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+#include "BacktraceLog.h"
+#include "thread_utils.h"
+#include "UnwindCurrent.h"
+#include "UnwindPtrace.h"
+
+using android::base::StringPrintf;
+
+//-------------------------------------------------------------------------
+// Backtrace functions.
+//-------------------------------------------------------------------------
+Backtrace::Backtrace(pid_t pid, pid_t tid, BacktraceMap* map)
+    : pid_(pid), tid_(tid), map_(map), map_shared_(true) {
+  if (map_ == nullptr) {
+    map_ = BacktraceMap::Create(pid);
+    map_shared_ = false;
+  }
+}
+
+Backtrace::~Backtrace() {
+  if (map_ && !map_shared_) {
+    delete map_;
+    map_ = nullptr;
+  }
+}
+
+extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len,
+                                int* status);
+
+std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
+  std::string func_name = GetFunctionNameRaw(pc, offset);
+  if (!func_name.empty()) {
+#if defined(__APPLE__)
+    // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
+    if (func_name[0] != '_') {
+      return func_name;
+    }
+#endif
+    char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0);
+    if (name) {
+      func_name = name;
+      free(name);
+    }
+  }
+  return func_name;
+}
+
+bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) {
+  if (ptr & (sizeof(word_t)-1)) {
+    BACK_LOGW("invalid pointer %p", reinterpret_cast<void*>(ptr));
+    *out_value = static_cast<word_t>(-1);
+    return false;
+  }
+  return true;
+}
+
+std::string Backtrace::FormatFrameData(size_t frame_num) {
+  if (frame_num >= frames_.size()) {
+    return "";
+  }
+  return FormatFrameData(&frames_[frame_num]);
+}
+
+std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) {
+  const char* map_name;
+  if (BacktraceMap::IsValid(frame->map) && !frame->map.name.empty()) {
+    map_name = frame->map.name.c_str();
+  } else {
+    map_name = "<unknown>";
+  }
+
+  uintptr_t relative_pc;
+  if (BacktraceMap::IsValid(frame->map)) {
+    relative_pc = frame->pc - frame->map.start;
+  } else {
+    relative_pc = frame->pc;
+  }
+
+  std::string line(StringPrintf("#%02zu pc %" PRIPTR "  %s", frame->num, relative_pc, map_name));
+  if (!frame->func_name.empty()) {
+    line += " (" + frame->func_name;
+    if (frame->func_offset) {
+      line += StringPrintf("+%" PRIuPTR, frame->func_offset);
+    }
+    line += ')';
+  }
+
+  return line;
+}
+
+void Backtrace::FillInMap(uintptr_t pc, backtrace_map_t* map) {
+  map_->FillIn(pc, map);
+}
+
+Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) {
+  if (pid == BACKTRACE_CURRENT_PROCESS) {
+    pid = getpid();
+    if (tid == BACKTRACE_CURRENT_THREAD) {
+      tid = gettid();
+    }
+  } else if (tid == BACKTRACE_CURRENT_THREAD) {
+    tid = pid;
+  }
+
+  if (pid == getpid()) {
+    return new UnwindCurrent(pid, tid, map);
+  } else {
+    return new UnwindPtrace(pid, tid, map);
+  }
+}
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
new file mode 100644
index 0000000..fd1f4da
--- /dev/null
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2013 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 _GNU_SOURCE 1
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+#include "BacktraceCurrent.h"
+#include "BacktraceLog.h"
+#include "ThreadEntry.h"
+#include "thread_utils.h"
+
+bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) {
+  if (!VerifyReadWordArgs(ptr, out_value)) {
+    return false;
+  }
+
+  backtrace_map_t map;
+  FillInMap(ptr, &map);
+  if (BacktraceMap::IsValid(map) && map.flags & PROT_READ) {
+    *out_value = *reinterpret_cast<word_t*>(ptr);
+    return true;
+  } else {
+    BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
+    *out_value = static_cast<word_t>(-1);
+    return false;
+  }
+}
+
+size_t BacktraceCurrent::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+  backtrace_map_t map;
+  FillInMap(addr, &map);
+  if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
+    return 0;
+  }
+  bytes = MIN(map.end - addr, bytes);
+  memcpy(buffer, reinterpret_cast<uint8_t*>(addr), bytes);
+  return bytes;
+}
+
+bool BacktraceCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+  if (ucontext) {
+    return UnwindFromContext(num_ignore_frames, ucontext);
+  }
+
+  if (Tid() != gettid()) {
+    return UnwindThread(num_ignore_frames);
+  }
+
+  return UnwindFromContext(num_ignore_frames, nullptr);
+}
+
+bool BacktraceCurrent::DiscardFrame(const backtrace_frame_data_t& frame) {
+  if (BacktraceMap::IsValid(frame.map)) {
+    const std::string library = basename(frame.map.name.c_str());
+    if (library == "libunwind.so" || library == "libbacktrace.so") {
+      return true;
+    }
+  }
+  return false;
+}
+
+static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void SignalHandler(int, siginfo_t*, void* sigcontext) {
+  ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false);
+  if (!entry) {
+    BACK_LOGW("Unable to find pid %d tid %d information", getpid(), gettid());
+    return;
+  }
+
+  entry->CopyUcontextFromSigcontext(sigcontext);
+
+  // Indicate the ucontext is now valid.
+  entry->Wake();
+
+  // Pause the thread until the unwind is complete. This avoids having
+  // the thread run ahead causing problems.
+  // The number indicates that we are waiting for the second Wake() call
+  // overall which is made by the thread requesting an unwind.
+  entry->Wait(2);
+
+  ThreadEntry::Remove(entry);
+}
+
+bool BacktraceCurrent::UnwindThread(size_t num_ignore_frames) {
+  // Prevent multiple threads trying to set the trigger action on different
+  // threads at the same time.
+  pthread_mutex_lock(&g_sigaction_mutex);
+
+  ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid());
+  entry->Lock();
+
+  struct sigaction act, oldact;
+  memset(&act, 0, sizeof(act));
+  act.sa_sigaction = SignalHandler;
+  act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+  sigemptyset(&act.sa_mask);
+  if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) {
+    BACK_LOGW("sigaction failed %s", strerror(errno));
+    entry->Unlock();
+    ThreadEntry::Remove(entry);
+    pthread_mutex_unlock(&g_sigaction_mutex);
+    return false;
+  }
+
+  if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) {
+    BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno));
+    sigaction(THREAD_SIGNAL, &oldact, nullptr);
+    entry->Unlock();
+    ThreadEntry::Remove(entry);
+    pthread_mutex_unlock(&g_sigaction_mutex);
+    return false;
+  }
+
+  // Wait for the thread to get the ucontext. The number indicates
+  // that we are waiting for the first Wake() call made by the thread.
+  entry->Wait(1);
+
+  // After the thread has received the signal, allow other unwinders to
+  // continue.
+  sigaction(THREAD_SIGNAL, &oldact, nullptr);
+  pthread_mutex_unlock(&g_sigaction_mutex);
+
+  bool unwind_done = UnwindFromContext(num_ignore_frames, entry->GetUcontext());
+
+  // Tell the signal handler to exit and release the entry.
+  entry->Wake();
+
+  return unwind_done;
+}
diff --git a/libbacktrace/BacktraceCurrent.h b/libbacktrace/BacktraceCurrent.h
new file mode 100644
index 0000000..8aad36d
--- /dev/null
+++ b/libbacktrace/BacktraceCurrent.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 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 _LIBBACKTRACE_BACKTRACE_CURRENT_H
+#define _LIBBACKTRACE_BACKTRACE_CURRENT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <ucontext.h>
+
+#include <backtrace/Backtrace.h>
+
+// The signal used to cause a thread to dump the stack.
+#if defined(__GLIBC__)
+// In order to run the backtrace_tests on the host, we can't use
+// the internal real time signals used by GLIBC. To avoid this,
+// use SIGRTMIN for the signal to dump the stack.
+#define THREAD_SIGNAL SIGRTMIN
+#else
+#define THREAD_SIGNAL (__SIGRTMIN+1)
+#endif
+
+class BacktraceMap;
+
+class BacktraceCurrent : public Backtrace {
+public:
+  BacktraceCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
+  virtual ~BacktraceCurrent() {}
+
+  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
+
+  bool ReadWord(uintptr_t ptr, word_t* out_value) override;
+
+  bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override;
+
+protected:
+  bool DiscardFrame(const backtrace_frame_data_t& frame);
+
+private:
+  bool UnwindThread(size_t num_ignore_frames);
+
+  virtual bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) = 0;
+};
+
+#endif // _LIBBACKTRACE_BACKTRACE_CURRENT_H
diff --git a/libbacktrace/BacktraceImpl.cpp b/libbacktrace/BacktraceImpl.cpp
deleted file mode 100644
index fb8a725..0000000
--- a/libbacktrace/BacktraceImpl.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2013 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 <stdlib.h>
-#include <string.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <ucontext.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include "BacktraceImpl.h"
-#include "BacktraceLog.h"
-#include "thread_utils.h"
-
-//-------------------------------------------------------------------------
-// Backtrace functions.
-//-------------------------------------------------------------------------
-Backtrace::Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map)
-    : pid_(pid), tid_(-1), map_(map), map_shared_(true), impl_(impl) {
-  impl_->SetParent(this);
-
-  if (map_ == NULL) {
-    map_ = BacktraceMap::Create(pid);
-    map_shared_ = false;
-  }
-}
-
-Backtrace::~Backtrace() {
-  if (impl_) {
-    delete impl_;
-    impl_ = NULL;
-  }
-
-  if (map_ && !map_shared_) {
-    delete map_;
-    map_ = NULL;
-  }
-}
-
-bool Backtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
-  return impl_->Unwind(num_ignore_frames, ucontext);
-}
-
-extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len,
-                                int* status);
-
-std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
-  std::string func_name = impl_->GetFunctionNameRaw(pc, offset);
-  if (!func_name.empty()) {
-#if defined(__APPLE__)
-    // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
-    if (func_name[0] != '_') {
-      return func_name;
-    }
-#endif
-    char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0);
-    if (name) {
-      func_name = name;
-      free(name);
-    }
-  }
-  return func_name;
-}
-
-bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) {
-  if (ptr & (sizeof(word_t)-1)) {
-    BACK_LOGW("invalid pointer %p", (void*)ptr);
-    *out_value = (word_t)-1;
-    return false;
-  }
-  return true;
-}
-
-std::string Backtrace::FormatFrameData(size_t frame_num) {
-  if (frame_num >= frames_.size()) {
-    return "";
-  }
-  return FormatFrameData(&frames_[frame_num]);
-}
-
-std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) {
-  const char* map_name;
-  if (BacktraceMap::IsValid(frame->map) && !frame->map.name.empty()) {
-    map_name = frame->map.name.c_str();
-  } else {
-    map_name = "<unknown>";
-  }
-
-  uintptr_t relative_pc;
-  if (BacktraceMap::IsValid(frame->map)) {
-    relative_pc = frame->pc - frame->map.start;
-  } else {
-    relative_pc = frame->pc;
-  }
-
-  char buf[512];
-  if (!frame->func_name.empty() && frame->func_offset) {
-    snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR "  %s (%s+%" PRIuPTR ")",
-             frame->num, (int)sizeof(uintptr_t)*2, relative_pc, map_name,
-             frame->func_name.c_str(), frame->func_offset);
-  } else if (!frame->func_name.empty()) {
-    snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR "  %s (%s)", frame->num,
-             (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->func_name.c_str());
-  } else {
-    snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR "  %s", frame->num,
-             (int)sizeof(uintptr_t)*2, relative_pc, map_name);
-  }
-
-  return buf;
-}
-
-void Backtrace::FillInMap(uintptr_t pc, backtrace_map_t* map) {
-  map_->FillIn(pc, map);
-}
-
-//-------------------------------------------------------------------------
-// BacktraceCurrent functions.
-//-------------------------------------------------------------------------
-BacktraceCurrent::BacktraceCurrent(
-    BacktraceImpl* impl, BacktraceMap* map) : Backtrace(impl, getpid(), map) {
-}
-
-BacktraceCurrent::~BacktraceCurrent() {
-}
-
-bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) {
-  if (!VerifyReadWordArgs(ptr, out_value)) {
-    return false;
-  }
-
-  backtrace_map_t map;
-  FillInMap(ptr, &map);
-  if (BacktraceMap::IsValid(map) && map.flags & PROT_READ) {
-    *out_value = *reinterpret_cast<word_t*>(ptr);
-    return true;
-  } else {
-    BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
-    *out_value = static_cast<word_t>(-1);
-    return false;
-  }
-}
-
-//-------------------------------------------------------------------------
-// BacktracePtrace functions.
-//-------------------------------------------------------------------------
-BacktracePtrace::BacktracePtrace(
-    BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map)
-    : Backtrace(impl, pid, map) {
-  tid_ = tid;
-}
-
-BacktracePtrace::~BacktracePtrace() {
-}
-
-bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
-  if (!VerifyReadWordArgs(ptr, out_value)) {
-    return false;
-  }
-
-#if defined(__APPLE__)
-  BACK_LOGW("MacOS does not support reading from another pid.");
-  return false;
-#else
-  // ptrace() returns -1 and sets errno when the operation fails.
-  // To disambiguate -1 from a valid result, we clear errno beforehand.
-  errno = 0;
-  *out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL);
-  if (*out_value == static_cast<word_t>(-1) && errno) {
-    BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
-              reinterpret_cast<void*>(ptr), Tid(), strerror(errno));
-    return false;
-  }
-  return true;
-#endif
-}
-
-Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) {
-  if (pid == BACKTRACE_CURRENT_PROCESS || pid == getpid()) {
-    if (tid == BACKTRACE_CURRENT_THREAD || tid == gettid()) {
-      return CreateCurrentObj(map);
-    } else {
-      return CreateThreadObj(tid, map);
-    }
-  } else if (tid == BACKTRACE_CURRENT_THREAD) {
-    return CreatePtraceObj(pid, pid, map);
-  } else {
-    return CreatePtraceObj(pid, tid, map);
-  }
-}
diff --git a/libbacktrace/BacktraceImpl.h b/libbacktrace/BacktraceImpl.h
deleted file mode 100755
index cd61bdf..0000000
--- a/libbacktrace/BacktraceImpl.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2013 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 _LIBBACKTRACE_BACKTRACE_IMPL_H
-#define _LIBBACKTRACE_BACKTRACE_IMPL_H
-
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include <sys/types.h>
-
-class BacktraceImpl {
-public:
-  virtual ~BacktraceImpl() { }
-
-  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) = 0;
-
-  // The name returned is not demangled, Backtrace::GetFunctionName()
-  // takes care of demangling the name.
-  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) = 0;
-
-  void SetParent(Backtrace* backtrace) { backtrace_obj_ = backtrace; }
-
-  inline pid_t Pid() { return backtrace_obj_->Pid(); }
-  inline pid_t Tid() { return backtrace_obj_->Tid(); }
-
-  inline void FillInMap(uintptr_t addr, backtrace_map_t* map) {
-    backtrace_obj_->FillInMap(addr, map);
-  }
-  inline std::string GetFunctionName(uintptr_t pc, uintptr_t* offset) {
-    return backtrace_obj_->GetFunctionName(pc, offset);
-  }
-  inline BacktraceMap* GetMap() { return backtrace_obj_->GetMap(); }
-
-protected:
-  inline std::vector<backtrace_frame_data_t>* GetFrames() { return &backtrace_obj_->frames_; }
-
-  Backtrace* backtrace_obj_;
-};
-
-class BacktraceCurrent : public Backtrace {
-public:
-  BacktraceCurrent(BacktraceImpl* impl, BacktraceMap* map);
-  virtual ~BacktraceCurrent();
-
-  bool ReadWord(uintptr_t ptr, word_t* out_value);
-};
-
-class BacktracePtrace : public Backtrace {
-public:
-  BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map);
-  virtual ~BacktracePtrace();
-
-  bool ReadWord(uintptr_t ptr, word_t* out_value);
-};
-
-Backtrace* CreateCurrentObj(BacktraceMap* map);
-Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map);
-Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map);
-
-#endif // _LIBBACKTRACE_BACKTRACE_IMPL_H
diff --git a/libbacktrace/BacktraceLog.h b/libbacktrace/BacktraceLog.h
old mode 100755
new mode 100644
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 82a4085..b0ada46 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -15,18 +15,15 @@
  */
 
 #include <ctype.h>
+#include <stdint.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <string>
-#include <vector>
-
 #include <backtrace/backtrace_constants.h>
 #include <backtrace/BacktraceMap.h>
 #include <log/log.h>
 
 #include "thread_utils.h"
-#include "BacktraceImpl.h"
 
 BacktraceMap::BacktraceMap(pid_t pid) : pid_(pid) {
   if (pid_ < 0) {
@@ -116,7 +113,7 @@
   snprintf(path, sizeof(path), "/proc/%d/maps", pid_);
   FILE* fp = fopen(path, "r");
 #endif
-  if (fp == NULL) {
+  if (fp == nullptr) {
     return false;
   }
 
@@ -142,7 +139,7 @@
   BacktraceMap* map = new BacktraceMap(pid);
   if (!map->Build()) {
     delete map;
-    return NULL;
+    return nullptr;
   }
   return map;
 }
diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp
new file mode 100644
index 0000000..6134438
--- /dev/null
+++ b/libbacktrace/BacktracePtrace.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2013 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 <stdint.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+#include "BacktraceLog.h"
+#include "BacktracePtrace.h"
+#include "thread_utils.h"
+
+#if !defined(__APPLE__)
+static bool PtraceRead(pid_t tid, uintptr_t addr, word_t* out_value) {
+  // ptrace() returns -1 and sets errno when the operation fails.
+  // To disambiguate -1 from a valid result, we clear errno beforehand.
+  errno = 0;
+  *out_value = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(addr), nullptr);
+  if (*out_value == static_cast<word_t>(-1) && errno) {
+    BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
+              reinterpret_cast<void*>(addr), tid, strerror(errno));
+    return false;
+  }
+  return true;
+}
+#endif
+
+bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
+#if defined(__APPLE__)
+  BACK_LOGW("MacOS does not support reading from another pid.");
+  return false;
+#else
+  if (!VerifyReadWordArgs(ptr, out_value)) {
+    return false;
+  }
+
+  backtrace_map_t map;
+  FillInMap(ptr, &map);
+  if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
+    return false;
+  }
+
+  return PtraceRead(Tid(), ptr, out_value);
+#endif
+}
+
+size_t BacktracePtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+#if defined(__APPLE__)
+  BACK_LOGW("MacOS does not support reading from another pid.");
+  return 0;
+#else
+  backtrace_map_t map;
+  FillInMap(addr, &map);
+  if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
+    return 0;
+  }
+
+  bytes = MIN(map.end - addr, bytes);
+  size_t bytes_read = 0;
+  word_t data_word;
+  size_t align_bytes = addr & (sizeof(word_t) - 1);
+  if (align_bytes != 0) {
+    if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) {
+      return 0;
+    }
+    align_bytes = sizeof(word_t) - align_bytes;
+    memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + sizeof(word_t) - align_bytes,
+           align_bytes);
+    addr += align_bytes;
+    buffer += align_bytes;
+    bytes -= align_bytes;
+    bytes_read += align_bytes;
+  }
+
+  size_t num_words = bytes / sizeof(word_t);
+  for (size_t i = 0; i < num_words; i++) {
+    if (!PtraceRead(Tid(), addr, &data_word)) {
+      return bytes_read;
+    }
+    memcpy(buffer, &data_word, sizeof(word_t));
+    buffer += sizeof(word_t);
+    addr += sizeof(word_t);
+    bytes_read += sizeof(word_t);
+  }
+
+  size_t left_over = bytes & (sizeof(word_t) - 1);
+  if (left_over) {
+    if (!PtraceRead(Tid(), addr, &data_word)) {
+      return bytes_read;
+    }
+    memcpy(buffer, &data_word, left_over);
+    bytes_read += left_over;
+  }
+  return bytes_read;
+#endif
+}
diff --git a/libbacktrace/BacktracePtrace.h b/libbacktrace/BacktracePtrace.h
new file mode 100644
index 0000000..1d49811
--- /dev/null
+++ b/libbacktrace/BacktracePtrace.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 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 _LIBBACKTRACE_BACKTRACE_PTRACE_H
+#define _LIBBACKTRACE_BACKTRACE_PTRACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <backtrace/Backtrace.h>
+
+class BacktraceMap;
+
+class BacktracePtrace : public Backtrace {
+public:
+  BacktracePtrace(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
+  virtual ~BacktracePtrace() {}
+
+  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes);
+
+  bool ReadWord(uintptr_t ptr, word_t* out_value);
+};
+
+#endif // _LIBBACKTRACE_BACKTRACE_PTRACE_H
diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp
deleted file mode 100644
index 439cc3b..0000000
--- a/libbacktrace/BacktraceThread.cpp
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (C) 2013 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 <inttypes.h>
-#include <limits.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/syscall.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <ucontext.h>
-#include <unistd.h>
-
-#include <cutils/atomic.h>
-
-#include "BacktraceLog.h"
-#include "BacktraceThread.h"
-#include "thread_utils.h"
-
-//-------------------------------------------------------------------------
-// ThreadEntry implementation.
-//-------------------------------------------------------------------------
-ThreadEntry* ThreadEntry::list_ = NULL;
-pthread_mutex_t ThreadEntry::list_mutex_ = PTHREAD_MUTEX_INITIALIZER;
-
-// Assumes that ThreadEntry::list_mutex_ has already been locked before
-// creating a ThreadEntry object.
-ThreadEntry::ThreadEntry(pid_t pid, pid_t tid)
-    : pid_(pid), tid_(tid), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER),
-      wait_mutex_(PTHREAD_MUTEX_INITIALIZER), wait_value_(0),
-      next_(ThreadEntry::list_), prev_(NULL) {
-  pthread_condattr_t attr;
-  pthread_condattr_init(&attr);
-  pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
-  pthread_cond_init(&wait_cond_, &attr);
-
-  // Add ourselves to the list.
-  if (ThreadEntry::list_) {
-    ThreadEntry::list_->prev_ = this;
-  }
-  ThreadEntry::list_ = this;
-}
-
-ThreadEntry* ThreadEntry::Get(pid_t pid, pid_t tid, bool create) {
-  pthread_mutex_lock(&ThreadEntry::list_mutex_);
-  ThreadEntry* entry = list_;
-  while (entry != NULL) {
-    if (entry->Match(pid, tid)) {
-      break;
-    }
-    entry = entry->next_;
-  }
-
-  if (!entry) {
-    if (create) {
-      entry = new ThreadEntry(pid, tid);
-    }
-  } else {
-    entry->ref_count_++;
-  }
-  pthread_mutex_unlock(&ThreadEntry::list_mutex_);
-
-  return entry;
-}
-
-void ThreadEntry::Remove(ThreadEntry* entry) {
-  pthread_mutex_unlock(&entry->mutex_);
-
-  pthread_mutex_lock(&ThreadEntry::list_mutex_);
-  if (--entry->ref_count_ == 0) {
-    delete entry;
-  }
-  pthread_mutex_unlock(&ThreadEntry::list_mutex_);
-}
-
-// Assumes that ThreadEntry::list_mutex_ has already been locked before
-// deleting a ThreadEntry object.
-ThreadEntry::~ThreadEntry() {
-  if (list_ == this) {
-    list_ = next_;
-  } else {
-    if (next_) {
-      next_->prev_ = prev_;
-    }
-    prev_->next_ = next_;
-  }
-
-  next_ = NULL;
-  prev_ = NULL;
-
-  pthread_cond_destroy(&wait_cond_);
-}
-
-void ThreadEntry::Wait(int value) {
-  timespec ts;
-  if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
-    BACK_LOGW("clock_gettime failed: %s", strerror(errno));
-    abort();
-  }
-  ts.tv_sec += 10;
-
-  pthread_mutex_lock(&wait_mutex_);
-  while (wait_value_ != value) {
-    int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts);
-    if (ret != 0) {
-      BACK_LOGW("pthread_cond_timedwait failed: %s", strerror(ret));
-      break;
-    }
-  }
-  pthread_mutex_unlock(&wait_mutex_);
-}
-
-void ThreadEntry::Wake() {
-  pthread_mutex_lock(&wait_mutex_);
-  wait_value_++;
-  pthread_mutex_unlock(&wait_mutex_);
-
-  pthread_cond_signal(&wait_cond_);
-}
-
-void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) {
-  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(sigcontext);
-  // The only thing the unwinder cares about is the mcontext data.
-  memcpy(&ucontext_.uc_mcontext, &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext));
-}
-
-//-------------------------------------------------------------------------
-// BacktraceThread functions.
-//-------------------------------------------------------------------------
-static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void SignalHandler(int, siginfo_t*, void* sigcontext) {
-  ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false);
-  if (!entry) {
-    BACK_LOGW("Unable to find pid %d tid %d information", getpid(), gettid());
-    return;
-  }
-
-  entry->CopyUcontextFromSigcontext(sigcontext);
-
-  // Indicate the ucontext is now valid.
-  entry->Wake();
-
-  // Pause the thread until the unwind is complete. This avoids having
-  // the thread run ahead causing problems.
-  entry->Wait(2);
-
-  ThreadEntry::Remove(entry);
-}
-
-BacktraceThread::BacktraceThread(BacktraceImpl* impl, pid_t tid, BacktraceMap* map)
-    : BacktraceCurrent(impl, map) {
-  tid_ = tid;
-}
-
-BacktraceThread::~BacktraceThread() {
-}
-
-bool BacktraceThread::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
-  if (ucontext) {
-    // Unwind using an already existing ucontext.
-    return impl_->Unwind(num_ignore_frames, ucontext);
-  }
-
-  // Prevent multiple threads trying to set the trigger action on different
-  // threads at the same time.
-  if (pthread_mutex_lock(&g_sigaction_mutex) < 0) {
-    BACK_LOGW("sigaction failed: %s", strerror(errno));
-    return false;
-  }
-
-  ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid());
-  entry->Lock();
-
-  struct sigaction act, oldact;
-  memset(&act, 0, sizeof(act));
-  act.sa_sigaction = SignalHandler;
-  act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
-  sigemptyset(&act.sa_mask);
-  if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) {
-    BACK_LOGW("sigaction failed %s", strerror(errno));
-    entry->Unlock();
-    ThreadEntry::Remove(entry);
-    pthread_mutex_unlock(&g_sigaction_mutex);
-    return false;
-  }
-
-  if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) {
-    BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno));
-    sigaction(THREAD_SIGNAL, &oldact, NULL);
-    entry->Unlock();
-    ThreadEntry::Remove(entry);
-    pthread_mutex_unlock(&g_sigaction_mutex);
-    return false;
-  }
-
-  // Wait for the thread to get the ucontext.
-  entry->Wait(1);
-
-  // After the thread has received the signal, allow other unwinders to
-  // continue.
-  sigaction(THREAD_SIGNAL, &oldact, NULL);
-  pthread_mutex_unlock(&g_sigaction_mutex);
-
-  bool unwind_done = impl_->Unwind(num_ignore_frames, entry->GetUcontext());
-
-  // Tell the signal handler to exit and release the entry.
-  entry->Wake();
-
-  return unwind_done;
-}
diff --git a/libbacktrace/GetPss.cpp b/libbacktrace/GetPss.cpp
index 442383b..09a721d 100644
--- a/libbacktrace/GetPss.cpp
+++ b/libbacktrace/GetPss.cpp
@@ -14,11 +14,10 @@
  * limitations under the License.
  */
 
-#include <assert.h>
 #include <inttypes.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdint.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -46,13 +45,22 @@
 
 size_t GetPssBytes() {
   FILE* maps = fopen("/proc/self/maps", "r");
-  assert(maps != NULL);
+  if (maps == nullptr) {
+    return 0;
+  }
 
   int pagecount_fd = open("/proc/kpagecount", O_RDONLY);
-  assert(pagecount_fd >= 0);
+  if (pagecount_fd == -1) {
+    fclose(maps);
+    return 0;
+  }
 
   int pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
-  assert(pagemap_fd >= 0);
+  if (pagemap_fd == -1) {
+    fclose(maps);
+    close(pagecount_fd);
+    return 0;
+  }
 
   char line[4096];
   size_t total_pss = 0;
diff --git a/libbacktrace/ThreadEntry.cpp b/libbacktrace/ThreadEntry.cpp
new file mode 100644
index 0000000..e8b60c8
--- /dev/null
+++ b/libbacktrace/ThreadEntry.cpp
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+#include <pthread.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#include <ucontext.h>
+
+#include "BacktraceLog.h"
+#include "ThreadEntry.h"
+
+// Initialize static member variables.
+ThreadEntry* ThreadEntry::list_ = nullptr;
+pthread_mutex_t ThreadEntry::list_mutex_ = PTHREAD_MUTEX_INITIALIZER;
+
+// Assumes that ThreadEntry::list_mutex_ has already been locked before
+// creating a ThreadEntry object.
+ThreadEntry::ThreadEntry(pid_t pid, pid_t tid)
+    : pid_(pid), tid_(tid), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER),
+      wait_mutex_(PTHREAD_MUTEX_INITIALIZER), wait_value_(0),
+      next_(ThreadEntry::list_), prev_(nullptr) {
+  pthread_condattr_t attr;
+  pthread_condattr_init(&attr);
+  pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+  pthread_cond_init(&wait_cond_, &attr);
+
+  // Add ourselves to the list.
+  if (ThreadEntry::list_) {
+    ThreadEntry::list_->prev_ = this;
+  }
+  ThreadEntry::list_ = this;
+}
+
+ThreadEntry* ThreadEntry::Get(pid_t pid, pid_t tid, bool create) {
+  pthread_mutex_lock(&ThreadEntry::list_mutex_);
+  ThreadEntry* entry = list_;
+  while (entry != nullptr) {
+    if (entry->Match(pid, tid)) {
+      break;
+    }
+    entry = entry->next_;
+  }
+
+  if (!entry) {
+    if (create) {
+      entry = new ThreadEntry(pid, tid);
+    }
+  } else {
+    entry->ref_count_++;
+  }
+  pthread_mutex_unlock(&ThreadEntry::list_mutex_);
+
+  return entry;
+}
+
+void ThreadEntry::Remove(ThreadEntry* entry) {
+  pthread_mutex_unlock(&entry->mutex_);
+
+  pthread_mutex_lock(&ThreadEntry::list_mutex_);
+  if (--entry->ref_count_ == 0) {
+    delete entry;
+  }
+  pthread_mutex_unlock(&ThreadEntry::list_mutex_);
+}
+
+// Assumes that ThreadEntry::list_mutex_ has already been locked before
+// deleting a ThreadEntry object.
+ThreadEntry::~ThreadEntry() {
+  if (list_ == this) {
+    list_ = next_;
+  } else {
+    if (next_) {
+      next_->prev_ = prev_;
+    }
+    prev_->next_ = next_;
+  }
+
+  next_ = nullptr;
+  prev_ = nullptr;
+
+  pthread_cond_destroy(&wait_cond_);
+}
+
+void ThreadEntry::Wait(int value) {
+  timespec ts;
+  clock_gettime(CLOCK_MONOTONIC, &ts);
+  ts.tv_sec += 10;
+
+  pthread_mutex_lock(&wait_mutex_);
+  while (wait_value_ != value) {
+    int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts);
+    if (ret != 0) {
+      BACK_LOGW("pthread_cond_timedwait failed: %s", strerror(ret));
+      break;
+    }
+  }
+  pthread_mutex_unlock(&wait_mutex_);
+}
+
+void ThreadEntry::Wake() {
+  pthread_mutex_lock(&wait_mutex_);
+  wait_value_++;
+  pthread_mutex_unlock(&wait_mutex_);
+
+  pthread_cond_signal(&wait_cond_);
+}
+
+void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) {
+  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(sigcontext);
+  // The only thing the unwinder cares about is the mcontext data.
+  memcpy(&ucontext_.uc_mcontext, &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext));
+}
diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/ThreadEntry.h
similarity index 70%
rename from libbacktrace/BacktraceThread.h
rename to libbacktrace/ThreadEntry.h
index 99a8638..94becf2 100644
--- a/libbacktrace/BacktraceThread.h
+++ b/libbacktrace/ThreadEntry.h
@@ -14,26 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef _LIBBACKTRACE_BACKTRACE_THREAD_H
-#define _LIBBACKTRACE_BACKTRACE_THREAD_H
+#ifndef _LIBBACKTRACE_THREAD_ENTRY_H
+#define _LIBBACKTRACE_THREAD_ENTRY_H
 
-#include <inttypes.h>
 #include <pthread.h>
-#include <signal.h>
-#include <string.h>
 #include <sys/types.h>
 #include <ucontext.h>
 
-#include "BacktraceImpl.h"
-
-// The signal used to cause a thread to dump the stack.
-#if defined(__GLIBC__)
-// GLIBC reserves __SIGRTMIN signals, so use SIGRTMIN to avoid errors.
-#define THREAD_SIGNAL SIGRTMIN
-#else
-#define THREAD_SIGNAL (__SIGRTMIN+1)
-#endif
-
 class ThreadEntry {
 public:
   static ThreadEntry* Get(pid_t pid, pid_t tid, bool create = true);
@@ -81,12 +68,4 @@
   static pthread_mutex_t list_mutex_;
 };
 
-class BacktraceThread : public BacktraceCurrent {
-public:
-  BacktraceThread(BacktraceImpl* impl, pid_t tid, BacktraceMap* map);
-  virtual ~BacktraceThread();
-
-  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext);
-};
-
-#endif // _LIBBACKTRACE_BACKTRACE_THREAD_H
+#endif // _LIBBACKTRACE_THREAD_ENTRY_H
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
old mode 100755
new mode 100644
index 372555b..67e583f
--- a/libbacktrace/UnwindCurrent.cpp
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -14,41 +14,30 @@
  * limitations under the License.
  */
 
-#include <sys/types.h>
+#include <stdint.h>
 #include <ucontext.h>
 
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
+#include <memory>
+#include <string>
 
 #define UNW_LOCAL_ONLY
 #include <libunwind.h>
 
+#include <backtrace/Backtrace.h>
+
 #include "BacktraceLog.h"
-#include "BacktraceThread.h"
 #include "UnwindCurrent.h"
-#include "UnwindMap.h"
 
-//-------------------------------------------------------------------------
-// UnwindCurrent functions.
-//-------------------------------------------------------------------------
-UnwindCurrent::UnwindCurrent() {
-}
-
-UnwindCurrent::~UnwindCurrent() {
-}
-
-bool UnwindCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
-  if (!ucontext) {
-    int ret = unw_getcontext(&context_);
-    if (ret < 0) {
-      BACK_LOGW("unw_getcontext failed %d", ret);
-      return false;
-    }
+std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+  *offset = 0;
+  char buf[512];
+  unw_word_t value;
+  if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf),
+                              &value, &context_) >= 0 && buf[0] != '\0') {
+    *offset = static_cast<uintptr_t>(value);
+    return buf;
   }
-  else {
-    GetUnwContextFromUcontext(ucontext);
-  }
-  return UnwindFromContext(num_ignore_frames, false);
+  return "";
 }
 
 void UnwindCurrent::GetUnwContextFromUcontext(const ucontext_t* ucontext) {
@@ -76,89 +65,67 @@
 #endif
 }
 
-std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
-  *offset = 0;
-  char buf[512];
-  unw_word_t value;
-  if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf),
-                              &value, &context_) >= 0 && buf[0] != '\0') {
-    *offset = static_cast<uintptr_t>(value);
-    return buf;
-  }
-  return "";
-}
-
-bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool within_handler) {
-  // The cursor structure is pretty large, do not put it on the stack.
-  unw_cursor_t* cursor = new unw_cursor_t;
-  int ret = unw_init_local(cursor, &context_);
-  if (ret < 0) {
-    if (!within_handler) {
-      BACK_LOGW("unw_init_local failed %d", ret);
+bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
+  if (ucontext == nullptr) {
+    int ret = unw_getcontext(&context_);
+    if (ret < 0) {
+      BACK_LOGW("unw_getcontext failed %d", ret);
+      return false;
     }
-    delete cursor;
+  } else {
+    GetUnwContextFromUcontext(ucontext);
+  }
+
+  // The cursor structure is pretty large, do not put it on the stack.
+  std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t);
+  int ret = unw_init_local(cursor.get(), &context_);
+  if (ret < 0) {
+    BACK_LOGW("unw_init_local failed %d", ret);
     return false;
   }
 
-  std::vector<backtrace_frame_data_t>* frames = GetFrames();
-  frames->reserve(MAX_BACKTRACE_FRAMES);
   size_t num_frames = 0;
   do {
     unw_word_t pc;
-    ret = unw_get_reg(cursor, UNW_REG_IP, &pc);
+    ret = unw_get_reg(cursor.get(), UNW_REG_IP, &pc);
     if (ret < 0) {
-      if (!within_handler) {
-        BACK_LOGW("Failed to read IP %d", ret);
-      }
+      BACK_LOGW("Failed to read IP %d", ret);
       break;
     }
     unw_word_t sp;
-    ret = unw_get_reg(cursor, UNW_REG_SP, &sp);
+    ret = unw_get_reg(cursor.get(), UNW_REG_SP, &sp);
     if (ret < 0) {
-      if (!within_handler) {
-        BACK_LOGW("Failed to read SP %d", ret);
-      }
+      BACK_LOGW("Failed to read SP %d", ret);
       break;
     }
 
-    if (num_ignore_frames == 0) {
-      frames->resize(num_frames+1);
-      backtrace_frame_data_t* frame = &frames->at(num_frames);
-      frame->num = num_frames;
-      frame->pc = static_cast<uintptr_t>(pc);
-      frame->sp = static_cast<uintptr_t>(sp);
-      frame->stack_size = 0;
+    frames_.resize(num_frames+1);
+    backtrace_frame_data_t* frame = &frames_.at(num_frames);
+    frame->num = num_frames;
+    frame->pc = static_cast<uintptr_t>(pc);
+    frame->sp = static_cast<uintptr_t>(sp);
+    frame->stack_size = 0;
 
-      if (num_frames > 0) {
-        // Set the stack size for the previous frame.
-        backtrace_frame_data_t* prev = &frames->at(num_frames-1);
-        prev->stack_size = frame->sp - prev->sp;
-      }
-
-      if (!within_handler) {
+    FillInMap(frame->pc, &frame->map);
+    // Check to see if we should skip this frame because it's coming
+    // from within the library, and we are doing a local unwind.
+    if (ucontext != nullptr || num_frames != 0 || !DiscardFrame(*frame)) {
+      if (num_ignore_frames == 0) {
+        // GetFunctionName is an expensive call, only do it if we are
+        // keeping the frame.
         frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
-        FillInMap(frame->pc, &frame->map);
+        if (num_frames > 0) {
+          // Set the stack size for the previous frame.
+          backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
+          prev->stack_size = frame->sp - prev->sp;
+        }
+        num_frames++;
       } else {
-        frame->func_offset = 0;
+        num_ignore_frames--;
       }
-      num_frames++;
-    } else {
-      num_ignore_frames--;
     }
-    ret = unw_step (cursor);
+    ret = unw_step (cursor.get());
   } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
 
-  delete cursor;
   return true;
 }
-
-//-------------------------------------------------------------------------
-// C++ object creation function.
-//-------------------------------------------------------------------------
-Backtrace* CreateCurrentObj(BacktraceMap* map) {
-  return new BacktraceCurrent(new UnwindCurrent(), map);
-}
-
-Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) {
-  return new BacktraceThread(new UnwindCurrent(), tid, map);
-}
diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h
index 2375e6e..3023996 100644
--- a/libbacktrace/UnwindCurrent.h
+++ b/libbacktrace/UnwindCurrent.h
@@ -17,27 +17,32 @@
 #ifndef _LIBBACKTRACE_UNWIND_CURRENT_H
 #define _LIBBACKTRACE_UNWIND_CURRENT_H
 
+#include <stdint.h>
+#include <sys/types.h>
+#include <ucontext.h>
+
 #include <string>
 
-#include "BacktraceImpl.h"
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+#include "BacktraceCurrent.h"
 
 #define UNW_LOCAL_ONLY
 #include <libunwind.h>
 
-class UnwindCurrent : public BacktraceImpl {
+class UnwindCurrent : public BacktraceCurrent {
 public:
-  UnwindCurrent();
-  virtual ~UnwindCurrent();
+  UnwindCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : BacktraceCurrent(pid, tid, map) {}
+  virtual ~UnwindCurrent() {}
 
-  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext);
+  std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
 
-  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+private:
+  void GetUnwContextFromUcontext(const ucontext_t* ucontext);
 
-  bool UnwindFromContext(size_t num_ignore_frames, bool within_handler);
+  bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;
 
-  void GetUnwContextFromUcontext(const ucontext_t* context);
-
-protected:
   unw_context_t context_;
 };
 
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index 284a561..fa59d07 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <pthread.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -142,7 +142,7 @@
   }
   if (!map->Build()) {
     delete map;
-    return NULL;
+    return nullptr;
   }
   return map;
 }
diff --git a/libbacktrace/UnwindMap.h b/libbacktrace/UnwindMap.h
index be8855e..e292016 100644
--- a/libbacktrace/UnwindMap.h
+++ b/libbacktrace/UnwindMap.h
@@ -17,6 +17,9 @@
 #ifndef _LIBBACKTRACE_UNWIND_MAP_H
 #define _LIBBACKTRACE_UNWIND_MAP_H
 
+#include <stdint.h>
+#include <sys/types.h>
+
 #include <backtrace/BacktraceMap.h>
 
 // The unw_map_cursor_t structure is different depending on whether it is
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
index efe758b..a7c3de5 100644
--- a/libbacktrace/UnwindPtrace.cpp
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -14,35 +14,36 @@
  * limitations under the License.
  */
 
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
+#include <stdint.h>
 #include <sys/types.h>
-#include <string.h>
 #include <ucontext.h>
 
 #include <libunwind.h>
 #include <libunwind-ptrace.h>
 
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
 #include "BacktraceLog.h"
 #include "UnwindMap.h"
 #include "UnwindPtrace.h"
 
-UnwindPtrace::UnwindPtrace() : addr_space_(NULL), upt_info_(NULL) {
+UnwindPtrace::UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
+    : BacktracePtrace(pid, tid, map), addr_space_(nullptr), upt_info_(nullptr) {
 }
 
 UnwindPtrace::~UnwindPtrace() {
   if (upt_info_) {
     _UPT_destroy(upt_info_);
-    upt_info_ = NULL;
+    upt_info_ = nullptr;
   }
   if (addr_space_) {
     // Remove the map from the address space before destroying it.
     // It will be freed in the UnwindMap destructor.
-    unw_map_set(addr_space_, NULL);
+    unw_map_set(addr_space_, nullptr);
 
     unw_destroy_addr_space(addr_space_);
-    addr_space_ = NULL;
+    addr_space_ = nullptr;
   }
 }
 
@@ -74,8 +75,6 @@
     return false;
   }
 
-  std::vector<backtrace_frame_data_t>* frames = GetFrames();
-  frames->reserve(MAX_BACKTRACE_FRAMES);
   size_t num_frames = 0;
   do {
     unw_word_t pc;
@@ -92,15 +91,15 @@
     }
 
     if (num_ignore_frames == 0) {
-      frames->resize(num_frames+1);
-      backtrace_frame_data_t* frame = &frames->at(num_frames);
+      frames_.resize(num_frames+1);
+      backtrace_frame_data_t* frame = &frames_.at(num_frames);
       frame->num = num_frames;
       frame->pc = static_cast<uintptr_t>(pc);
       frame->sp = static_cast<uintptr_t>(sp);
       frame->stack_size = 0;
 
       if (num_frames > 0) {
-        backtrace_frame_data_t* prev = &frames->at(num_frames-1);
+        backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
         prev->stack_size = frame->sp - prev->sp;
       }
 
@@ -129,10 +128,3 @@
   }
   return "";
 }
-
-//-------------------------------------------------------------------------
-// C++ object creation function.
-//-------------------------------------------------------------------------
-Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map) {
-  return new BacktracePtrace(new UnwindPtrace(), pid, tid, map);
-}
diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h
index 2fb7967..ab04abf 100644
--- a/libbacktrace/UnwindPtrace.h
+++ b/libbacktrace/UnwindPtrace.h
@@ -17,20 +17,26 @@
 #ifndef _LIBBACKTRACE_UNWIND_PTRACE_H
 #define _LIBBACKTRACE_UNWIND_PTRACE_H
 
+#include <stdint.h>
+#include <sys/types.h>
+
 #include <string>
 
-#include "BacktraceImpl.h"
-
+#ifdef UNW_LOCAL_ONLY
+#undef UNW_LOCAL_ONLY
+#endif
 #include <libunwind.h>
 
-class UnwindPtrace : public BacktraceImpl {
+#include "BacktracePtrace.h"
+
+class UnwindPtrace : public BacktracePtrace {
 public:
-  UnwindPtrace();
+  UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map);
   virtual ~UnwindPtrace();
 
-  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext);
+  bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override;
 
-  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+  std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
 
 private:
   unw_addr_space_t addr_space_;
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 76aabd1..4af6592 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#define _GNU_SOURCE 1
 #include <dirent.h>
 #include <errno.h>
 #include <inttypes.h>
@@ -31,15 +32,16 @@
 
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
-#include <UniquePtr.h>
 
 // For the THREAD_SIGNAL definition.
-#include "BacktraceThread.h"
+#include "BacktraceCurrent.h"
 
 #include <cutils/atomic.h>
 #include <gtest/gtest.h>
 
 #include <algorithm>
+#include <memory>
+#include <string>
 #include <vector>
 
 #include "thread_utils.h"
@@ -60,6 +62,7 @@
   pid_t tid;
   int32_t state;
   pthread_t threadId;
+  void* data;
 };
 
 struct dump_thread_t {
@@ -82,15 +85,16 @@
   return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec);
 }
 
-void DumpFrames(Backtrace* backtrace) {
+std::string DumpFrames(Backtrace* backtrace) {
   if (backtrace->NumFrames() == 0) {
-    printf("    No frames to dump\n");
-    return;
+    return "   No frames to dump.\n";
   }
 
+  std::string frame;
   for (size_t i = 0; i < backtrace->NumFrames(); i++) {
-    printf("    %s\n", backtrace->FormatFrameData(i).c_str());
+    frame += "   " + backtrace->FormatFrameData(i) + '\n';
   }
+  return frame;
 }
 
 void WaitForStop(pid_t pid) {
@@ -120,8 +124,10 @@
 }
 
 void VerifyLevelDump(Backtrace* backtrace) {
-  ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0));
-  ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES));
+  ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0))
+    << DumpFrames(backtrace);
+  ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
+    << DumpFrames(backtrace);
 
   // Look through the frames starting at the highest to find the
   // frame we want.
@@ -132,19 +138,23 @@
       break;
     }
   }
-  ASSERT_LT(static_cast<size_t>(0), frame_num);
-  ASSERT_LE(static_cast<size_t>(3), frame_num);
+  ASSERT_LT(static_cast<size_t>(0), frame_num) << DumpFrames(backtrace);
+  ASSERT_LE(static_cast<size_t>(3), frame_num) << DumpFrames(backtrace);
 
-  ASSERT_EQ(backtrace->GetFrame(frame_num)->func_name, "test_level_one");
-  ASSERT_EQ(backtrace->GetFrame(frame_num-1)->func_name, "test_level_two");
-  ASSERT_EQ(backtrace->GetFrame(frame_num-2)->func_name, "test_level_three");
-  ASSERT_EQ(backtrace->GetFrame(frame_num-3)->func_name, "test_level_four");
+  ASSERT_EQ(backtrace->GetFrame(frame_num)->func_name, "test_level_one")
+    << DumpFrames(backtrace);
+  ASSERT_EQ(backtrace->GetFrame(frame_num-1)->func_name, "test_level_two")
+    << DumpFrames(backtrace);
+  ASSERT_EQ(backtrace->GetFrame(frame_num-2)->func_name, "test_level_three")
+    << DumpFrames(backtrace);
+  ASSERT_EQ(backtrace->GetFrame(frame_num-3)->func_name, "test_level_four")
+    << DumpFrames(backtrace);
 }
 
 void VerifyLevelBacktrace(void*) {
-  UniquePtr<Backtrace> backtrace(
+  std::unique_ptr<Backtrace> backtrace(
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
-  ASSERT_TRUE(backtrace.get() != NULL);
+  ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
 
   VerifyLevelDump(backtrace.get());
@@ -155,16 +165,17 @@
 }
 
 void VerifyMaxDump(Backtrace* backtrace) {
-  ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES));
+  ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
+    << DumpFrames(backtrace);
   // Verify that the last frame is our recursive call.
-  ASSERT_EQ(backtrace->GetFrame(MAX_BACKTRACE_FRAMES-1)->func_name,
-            "test_recursive_call");
+  ASSERT_EQ(backtrace->GetFrame(MAX_BACKTRACE_FRAMES-1)->func_name, "test_recursive_call")
+    << DumpFrames(backtrace);
 }
 
 void VerifyMaxBacktrace(void*) {
-  UniquePtr<Backtrace> backtrace(
+  std::unique_ptr<Backtrace> backtrace(
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
-  ASSERT_TRUE(backtrace.get() != NULL);
+  ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
 
   VerifyMaxDump(backtrace.get());
@@ -180,8 +191,8 @@
 }
 
 void VerifyThreadTest(pid_t tid, void (*VerifyFunc)(Backtrace*)) {
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), tid));
-  ASSERT_TRUE(backtrace.get() != NULL);
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), tid));
+  ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
 
   VerifyFunc(backtrace.get());
@@ -197,18 +208,38 @@
   return false;
 }
 
+TEST(libbacktrace, local_no_unwind_frames) {
+  // Verify that a local unwind does not include any frames within
+  // libunwind or libbacktrace.
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid()));
+  ASSERT_TRUE(backtrace.get() != nullptr);
+  ASSERT_TRUE(backtrace->Unwind(0));
+
+  ASSERT_TRUE(backtrace->NumFrames() != 0);
+  for (const auto& frame : *backtrace ) {
+    if (BacktraceMap::IsValid(frame.map)) {
+      const std::string name = basename(frame.map.name.c_str());
+      ASSERT_TRUE(name != "libunwind.so" && name != "libbacktrace.so")
+        << DumpFrames(backtrace.get());
+    }
+    break;
+  }
+}
+
 TEST(libbacktrace, local_trace) {
-  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, NULL), 0);
+  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0);
 }
 
 void VerifyIgnoreFrames(
     Backtrace* bt_all, Backtrace* bt_ign1,
     Backtrace* bt_ign2, const char* cur_proc) {
-  EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1);
-  EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2);
+  EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1)
+    << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 1 backtrace:\n" << DumpFrames(bt_ign1);
+  EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2)
+    << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 2 backtrace:\n" << DumpFrames(bt_ign2);
 
   // Check all of the frames are the same > the current frame.
-  bool check = (cur_proc == NULL);
+  bool check = (cur_proc == nullptr);
   for (size_t i = 0; i < bt_ign2->NumFrames(); i++) {
     if (check) {
       EXPECT_EQ(bt_ign2->GetFrame(i)->pc, bt_ign1->GetFrame(i+1)->pc);
@@ -226,30 +257,30 @@
 }
 
 void VerifyLevelIgnoreFrames(void*) {
-  UniquePtr<Backtrace> all(
+  std::unique_ptr<Backtrace> all(
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
-  ASSERT_TRUE(all.get() != NULL);
+  ASSERT_TRUE(all.get() != nullptr);
   ASSERT_TRUE(all->Unwind(0));
 
-  UniquePtr<Backtrace> ign1(
+  std::unique_ptr<Backtrace> ign1(
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
-  ASSERT_TRUE(ign1.get() != NULL);
+  ASSERT_TRUE(ign1.get() != nullptr);
   ASSERT_TRUE(ign1->Unwind(1));
 
-  UniquePtr<Backtrace> ign2(
+  std::unique_ptr<Backtrace> ign2(
       Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
-  ASSERT_TRUE(ign2.get() != NULL);
+  ASSERT_TRUE(ign2.get() != nullptr);
   ASSERT_TRUE(ign2->Unwind(2));
 
   VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), "VerifyLevelIgnoreFrames");
 }
 
 TEST(libbacktrace, local_trace_ignore_frames) {
-  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelIgnoreFrames, NULL), 0);
+  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelIgnoreFrames, nullptr), 0);
 }
 
 TEST(libbacktrace, local_max_trace) {
-  ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, NULL), 0);
+  ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, nullptr), 0);
 }
 
 void VerifyProcTest(pid_t pid, pid_t tid, bool share_map,
@@ -263,35 +294,38 @@
   }
   uint64_t start = NanoTime();
   bool verified = false;
+  std::string last_dump;
   do {
     usleep(US_PER_MSEC);
     if (ptrace(PTRACE_ATTACH, ptrace_tid, 0, 0) == 0) {
       // Wait for the process to get to a stopping point.
       WaitForStop(ptrace_tid);
 
-      UniquePtr<BacktraceMap> map;
+      std::unique_ptr<BacktraceMap> map;
       if (share_map) {
         map.reset(BacktraceMap::Create(pid));
       }
-      UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
+      std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
+      ASSERT_TRUE(backtrace.get() != nullptr);
       ASSERT_TRUE(backtrace->Unwind(0));
-      ASSERT_TRUE(backtrace.get() != NULL);
       if (ReadyFunc(backtrace.get())) {
         VerifyFunc(backtrace.get());
         verified = true;
+      } else {
+        last_dump = DumpFrames(backtrace.get());
       }
 
       ASSERT_TRUE(ptrace(PTRACE_DETACH, ptrace_tid, 0, 0) == 0);
     }
     // If 5 seconds have passed, then we are done.
   } while (!verified && (NanoTime() - start) <= 5 * NS_PER_SEC);
-  ASSERT_TRUE(verified);
+  ASSERT_TRUE(verified) << "Last backtrace:\n" << last_dump;
 }
 
 TEST(libbacktrace, ptrace_trace) {
   pid_t pid;
   if ((pid = fork()) == 0) {
-    ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+    ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
     _exit(1);
   }
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyLevelDump);
@@ -304,7 +338,7 @@
 TEST(libbacktrace, ptrace_trace_shared_map) {
   pid_t pid;
   if ((pid = fork()) == 0) {
-    ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+    ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
     _exit(1);
   }
 
@@ -318,7 +352,7 @@
 TEST(libbacktrace, ptrace_max_trace) {
   pid_t pid;
   if ((pid = fork()) == 0) {
-    ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, NULL, NULL), 0);
+    ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, nullptr, nullptr), 0);
     _exit(1);
   }
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyMaxBacktrace, VerifyMaxDump);
@@ -329,21 +363,21 @@
 }
 
 void VerifyProcessIgnoreFrames(Backtrace* bt_all) {
-  UniquePtr<Backtrace> ign1(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD));
-  ASSERT_TRUE(ign1.get() != NULL);
+  std::unique_ptr<Backtrace> ign1(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD));
+  ASSERT_TRUE(ign1.get() != nullptr);
   ASSERT_TRUE(ign1->Unwind(1));
 
-  UniquePtr<Backtrace> ign2(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD));
-  ASSERT_TRUE(ign2.get() != NULL);
+  std::unique_ptr<Backtrace> ign2(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD));
+  ASSERT_TRUE(ign2.get() != nullptr);
   ASSERT_TRUE(ign2->Unwind(2));
 
-  VerifyIgnoreFrames(bt_all, ign1.get(), ign2.get(), NULL);
+  VerifyIgnoreFrames(bt_all, ign1.get(), ign2.get(), nullptr);
 }
 
 TEST(libbacktrace, ptrace_ignore_frames) {
   pid_t pid;
   if ((pid = fork()) == 0) {
-    ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+    ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
     _exit(1);
   }
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyProcessIgnoreFrames);
@@ -355,8 +389,8 @@
 
 // Create a process with multiple threads and dump all of the threads.
 void* PtraceThreadLevelRun(void*) {
-  EXPECT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
-  return NULL;
+  EXPECT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
+  return nullptr;
 }
 
 void GetThreads(pid_t pid, std::vector<pid_t>* threads) {
@@ -365,9 +399,9 @@
   snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
 
   DIR* tasks_dir = opendir(task_path);
-  ASSERT_TRUE(tasks_dir != NULL);
+  ASSERT_TRUE(tasks_dir != nullptr);
   struct dirent* entry;
-  while ((entry = readdir(tasks_dir)) != NULL) {
+  while ((entry = readdir(tasks_dir)) != nullptr) {
     char* end;
     pid_t tid = strtoul(entry->d_name, &end, 10);
     if (*end == '\0') {
@@ -386,9 +420,9 @@
       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
       pthread_t thread;
-      ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, NULL) == 0);
+      ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, nullptr) == 0);
     }
-    ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+    ASSERT_NE(test_level_one(1, 2, 3, 4, nullptr, nullptr), 0);
     _exit(1);
   }
 
@@ -420,27 +454,27 @@
 }
 
 void VerifyLevelThread(void*) {
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
-  ASSERT_TRUE(backtrace.get() != NULL);
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
+  ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
 
   VerifyLevelDump(backtrace.get());
 }
 
 TEST(libbacktrace, thread_current_level) {
-  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, NULL), 0);
+  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, nullptr), 0);
 }
 
 void VerifyMaxThread(void*) {
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
-  ASSERT_TRUE(backtrace.get() != NULL);
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
+  ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
 
   VerifyMaxDump(backtrace.get());
 }
 
 TEST(libbacktrace, thread_current_max) {
-  ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, NULL), 0);
+  ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, nullptr), 0);
 }
 
 void* ThreadLevelRun(void* data) {
@@ -448,7 +482,7 @@
 
   thread->tid = gettid();
   EXPECT_NE(test_level_one(1, 2, 3, 4, ThreadSetState, data), 0);
-  return NULL;
+  return nullptr;
 }
 
 TEST(libbacktrace, thread_level_trace) {
@@ -456,7 +490,7 @@
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
-  thread_t thread_data = { 0, 0, 0 };
+  thread_t thread_data = { 0, 0, 0, nullptr };
   pthread_t thread;
   ASSERT_TRUE(pthread_create(&thread, &attr, ThreadLevelRun, &thread_data) == 0);
 
@@ -471,10 +505,10 @@
 
   // Save the current signal action and make sure it is restored afterwards.
   struct sigaction cur_action;
-  ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &cur_action) == 0);
+  ASSERT_TRUE(sigaction(THREAD_SIGNAL, nullptr, &cur_action) == 0);
 
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
-  ASSERT_TRUE(backtrace.get() != NULL);
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
+  ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
 
   VerifyLevelDump(backtrace.get());
@@ -484,14 +518,18 @@
 
   // Verify that the old action was restored.
   struct sigaction new_action;
-  ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &new_action) == 0);
+  ASSERT_TRUE(sigaction(THREAD_SIGNAL, nullptr, &new_action) == 0);
   EXPECT_EQ(cur_action.sa_sigaction, new_action.sa_sigaction);
   // The SA_RESTORER flag gets set behind our back, so a direct comparison
   // doesn't work unless we mask the value off. Mips doesn't have this
   // flag, so skip this on that platform.
-#ifdef SA_RESTORER
+#if defined(SA_RESTORER)
   cur_action.sa_flags &= ~SA_RESTORER;
   new_action.sa_flags &= ~SA_RESTORER;
+#elif defined(__GLIBC__)
+  // Our host compiler doesn't appear to define this flag for some reason.
+  cur_action.sa_flags &= ~0x04000000;
+  new_action.sa_flags &= ~0x04000000;
 #endif
   EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags);
 }
@@ -501,26 +539,26 @@
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
-  thread_t thread_data = { 0, 0, 0 };
+  thread_t thread_data = { 0, 0, 0, nullptr };
   pthread_t thread;
   ASSERT_TRUE(pthread_create(&thread, &attr, ThreadLevelRun, &thread_data) == 0);
 
   // Wait up to 2 seconds for the tid to be set.
   ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
 
-  UniquePtr<Backtrace> all(Backtrace::Create(getpid(), thread_data.tid));
-  ASSERT_TRUE(all.get() != NULL);
+  std::unique_ptr<Backtrace> all(Backtrace::Create(getpid(), thread_data.tid));
+  ASSERT_TRUE(all.get() != nullptr);
   ASSERT_TRUE(all->Unwind(0));
 
-  UniquePtr<Backtrace> ign1(Backtrace::Create(getpid(), thread_data.tid));
-  ASSERT_TRUE(ign1.get() != NULL);
+  std::unique_ptr<Backtrace> ign1(Backtrace::Create(getpid(), thread_data.tid));
+  ASSERT_TRUE(ign1.get() != nullptr);
   ASSERT_TRUE(ign1->Unwind(1));
 
-  UniquePtr<Backtrace> ign2(Backtrace::Create(getpid(), thread_data.tid));
-  ASSERT_TRUE(ign2.get() != NULL);
+  std::unique_ptr<Backtrace> ign2(Backtrace::Create(getpid(), thread_data.tid));
+  ASSERT_TRUE(ign2.get() != nullptr);
   ASSERT_TRUE(ign2->Unwind(2));
 
-  VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), NULL);
+  VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), nullptr);
 
   // Tell the thread to exit its infinite loop.
   android_atomic_acquire_store(0, &thread_data.state);
@@ -531,7 +569,7 @@
 
   thread->tid = gettid();
   EXPECT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, ThreadSetState, data), 0);
-  return NULL;
+  return nullptr;
 }
 
 TEST(libbacktrace, thread_max_trace) {
@@ -539,15 +577,15 @@
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
-  thread_t thread_data = { 0, 0, 0 };
+  thread_t thread_data = { 0, 0, 0, nullptr };
   pthread_t thread;
   ASSERT_TRUE(pthread_create(&thread, &attr, ThreadMaxRun, &thread_data) == 0);
 
   // Wait for the tid to be set.
   ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
 
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
-  ASSERT_TRUE(backtrace.get() != NULL);
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
+  ASSERT_TRUE(backtrace.get() != nullptr);
   ASSERT_TRUE(backtrace->Unwind(0));
 
   VerifyMaxDump(backtrace.get());
@@ -570,7 +608,7 @@
 
   android_atomic_acquire_store(1, &dump->done);
 
-  return NULL;
+  return nullptr;
 }
 
 TEST(libbacktrace, thread_multiple_dump) {
@@ -614,11 +652,11 @@
     // Tell the runner thread to exit its infinite loop.
     android_atomic_acquire_store(0, &runners[i].state);
 
-    ASSERT_TRUE(dumpers[i].backtrace != NULL);
+    ASSERT_TRUE(dumpers[i].backtrace != nullptr);
     VerifyMaxDump(dumpers[i].backtrace);
 
     delete dumpers[i].backtrace;
-    dumpers[i].backtrace = NULL;
+    dumpers[i].backtrace = nullptr;
   }
 }
 
@@ -654,11 +692,11 @@
   for (size_t i = 0; i < NUM_THREADS; i++) {
     ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 30));
 
-    ASSERT_TRUE(dumpers[i].backtrace != NULL);
+    ASSERT_TRUE(dumpers[i].backtrace != nullptr);
     VerifyMaxDump(dumpers[i].backtrace);
 
     delete dumpers[i].backtrace;
-    dumpers[i].backtrace = NULL;
+    dumpers[i].backtrace = nullptr;
   }
 
   // Tell the runner thread to exit its infinite loop.
@@ -673,16 +711,19 @@
   BacktraceMap* map3 = BacktraceMap::Create(getpid());
 
   Backtrace* back1 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map1);
+  ASSERT_TRUE(back1 != nullptr);
   EXPECT_TRUE(back1->Unwind(0));
   delete back1;
   delete map1;
 
   Backtrace* back2 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map2);
+  ASSERT_TRUE(back2 != nullptr);
   EXPECT_TRUE(back2->Unwind(0));
   delete back2;
   delete map2;
 
   Backtrace* back3 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map3);
+  ASSERT_TRUE(back3 != nullptr);
   EXPECT_TRUE(back3->Unwind(0));
   delete back3;
   delete map3;
@@ -708,8 +749,8 @@
 }
 
 TEST(libbacktrace, format_test) {
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD));
-  ASSERT_TRUE(backtrace.get() != NULL);
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD));
+  ASSERT_TRUE(backtrace.get() != nullptr);
 
   backtrace_frame_data_t frame;
   frame.num = 1;
@@ -778,12 +819,12 @@
   return i.start < j.start;
 }
 
-static void VerifyMap(pid_t pid) {
+void VerifyMap(pid_t pid) {
   char buffer[4096];
   snprintf(buffer, sizeof(buffer), "/proc/%d/maps", pid);
 
   FILE* map_file = fopen(buffer, "r");
-  ASSERT_TRUE(map_file != NULL);
+  ASSERT_TRUE(map_file != nullptr);
   std::vector<map_test_t> test_maps;
   while (fgets(buffer, sizeof(buffer), map_file)) {
     map_test_t map;
@@ -793,7 +834,7 @@
   fclose(map_file);
   std::sort(test_maps.begin(), test_maps.end(), map_sort);
 
-  UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid));
+  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
 
   // Basic test that verifies that the map is in the expected order.
   std::vector<map_test_t>::const_iterator test_it = test_maps.begin();
@@ -827,7 +868,173 @@
   ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
 
   kill(pid, SIGKILL);
-  ASSERT_EQ(waitpid(pid, NULL, 0), pid);
+  ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
+}
+
+void* ThreadReadTest(void* data) {
+  thread_t* thread_data = reinterpret_cast<thread_t*>(data);
+
+  thread_data->tid = gettid();
+
+  // Create two map pages.
+  // Mark the second page as not-readable.
+  size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
+  uint8_t* memory;
+  if (posix_memalign(reinterpret_cast<void**>(&memory), pagesize, 2 * pagesize) != 0) {
+    return reinterpret_cast<void*>(-1);
+  }
+
+  if (mprotect(&memory[pagesize], pagesize, PROT_NONE) != 0) {
+    return reinterpret_cast<void*>(-1);
+  }
+
+  // Set up a simple pattern in memory.
+  for (size_t i = 0; i < pagesize; i++) {
+    memory[i] = i;
+  }
+
+  thread_data->data = memory;
+
+  // Tell the caller it's okay to start reading memory.
+  android_atomic_acquire_store(1, &thread_data->state);
+
+  // Loop waiting for the caller to finish reading the memory.
+  while (thread_data->state) {
+  }
+
+  // Re-enable read-write on the page so that we don't crash if we try
+  // and access data on this page when freeing the memory.
+  if (mprotect(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) != 0) {
+    return reinterpret_cast<void*>(-1);
+  }
+  free(memory);
+
+  android_atomic_acquire_store(1, &thread_data->state);
+
+  return nullptr;
+}
+
+void RunReadTest(Backtrace* backtrace, uintptr_t read_addr) {
+  size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
+
+  // Create a page of data to use to do quick compares.
+  uint8_t* expected = new uint8_t[pagesize];
+  for (size_t i = 0; i < pagesize; i++) {
+    expected[i] = i;
+  }
+  uint8_t* data = new uint8_t[2*pagesize];
+  // Verify that we can only read one page worth of data.
+  size_t bytes_read = backtrace->Read(read_addr, data, 2 * pagesize);
+  ASSERT_EQ(pagesize, bytes_read);
+  ASSERT_TRUE(memcmp(data, expected, pagesize) == 0);
+
+  // Verify unaligned reads.
+  for (size_t i = 1; i < sizeof(word_t); i++) {
+    bytes_read = backtrace->Read(read_addr + i, data, 2 * sizeof(word_t));
+    ASSERT_EQ(2 * sizeof(word_t), bytes_read);
+    ASSERT_TRUE(memcmp(data, &expected[i], 2 * sizeof(word_t)) == 0)
+        << "Offset at " << i << " failed";
+  }
+  delete data;
+  delete expected;
+}
+
+TEST(libbacktrace, thread_read) {
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+  pthread_t thread;
+  thread_t thread_data = { 0, 0, 0, nullptr };
+  ASSERT_TRUE(pthread_create(&thread, &attr, ThreadReadTest, &thread_data) == 0);
+
+  ASSERT_TRUE(WaitForNonZero(&thread_data.state, 10));
+
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
+  ASSERT_TRUE(backtrace.get() != nullptr);
+
+  RunReadTest(backtrace.get(), reinterpret_cast<uintptr_t>(thread_data.data));
+
+  android_atomic_acquire_store(0, &thread_data.state);
+
+  ASSERT_TRUE(WaitForNonZero(&thread_data.state, 10));
+}
+
+volatile uintptr_t g_ready = 0;
+volatile uintptr_t g_addr = 0;
+
+void ForkedReadTest() {
+  // Create two map pages.
+  size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
+  uint8_t* memory;
+  if (posix_memalign(reinterpret_cast<void**>(&memory), pagesize, 2 * pagesize) != 0) {
+    perror("Failed to allocate memory\n");
+    exit(1);
+  }
+
+  // Mark the second page as not-readable.
+  if (mprotect(&memory[pagesize], pagesize, PROT_NONE) != 0) {
+    perror("Failed to mprotect memory\n");
+    exit(1);
+  }
+
+  // Set up a simple pattern in memory.
+  for (size_t i = 0; i < pagesize; i++) {
+    memory[i] = i;
+  }
+
+  g_addr = reinterpret_cast<uintptr_t>(memory);
+  g_ready = 1;
+
+  while (1) {
+    usleep(US_PER_MSEC);
+  }
+}
+
+TEST(libbacktrace, process_read) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    ForkedReadTest();
+    exit(0);
+  }
+  ASSERT_NE(-1, pid);
+
+  bool test_executed = false;
+  uint64_t start = NanoTime();
+  while (1) {
+    if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) {
+      WaitForStop(pid);
+
+      std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
+      ASSERT_TRUE(backtrace.get() != nullptr);
+
+      uintptr_t read_addr;
+      size_t bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(&g_ready),
+                                          reinterpret_cast<uint8_t*>(&read_addr),
+                                          sizeof(uintptr_t));
+      ASSERT_EQ(sizeof(uintptr_t), bytes_read);
+      if (read_addr) {
+        // The forked process is ready to be read.
+        bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(&g_addr),
+                                     reinterpret_cast<uint8_t*>(&read_addr),
+                                     sizeof(uintptr_t));
+        ASSERT_EQ(sizeof(uintptr_t), bytes_read);
+
+        RunReadTest(backtrace.get(), read_addr);
+
+        test_executed = true;
+        break;
+      }
+      ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+    }
+    if ((NanoTime() - start) > 5 * NS_PER_SEC) {
+      break;
+    }
+    usleep(US_PER_MSEC);
+  }
+  kill(pid, SIGKILL);
+  ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
+
+  ASSERT_TRUE(test_executed);
 }
 
 #if defined(ENABLE_PSS_TESTS)
@@ -835,24 +1042,26 @@
 
 #define MAX_LEAK_BYTES 32*1024UL
 
-static void CheckForLeak(pid_t pid, pid_t tid) {
+void CheckForLeak(pid_t pid, pid_t tid) {
   // Do a few runs to get the PSS stable.
   for (size_t i = 0; i < 100; i++) {
     Backtrace* backtrace = Backtrace::Create(pid, tid);
-    ASSERT_TRUE(backtrace != NULL);
+    ASSERT_TRUE(backtrace != nullptr);
     ASSERT_TRUE(backtrace->Unwind(0));
     delete backtrace;
   }
   size_t stable_pss = GetPssBytes();
+  ASSERT_TRUE(stable_pss != 0);
 
   // Loop enough that even a small leak should be detectable.
   for (size_t i = 0; i < 4096; i++) {
     Backtrace* backtrace = Backtrace::Create(pid, tid);
-    ASSERT_TRUE(backtrace != NULL);
+    ASSERT_TRUE(backtrace != nullptr);
     ASSERT_TRUE(backtrace->Unwind(0));
     delete backtrace;
   }
   size_t new_pss = GetPssBytes();
+  ASSERT_TRUE(new_pss != 0);
   size_t abs_diff = (new_pss > stable_pss) ? new_pss - stable_pss : stable_pss - new_pss;
   // As long as the new pss is within a certain amount, consider everything okay.
   ASSERT_LE(abs_diff, MAX_LEAK_BYTES);
@@ -863,9 +1072,9 @@
 }
 
 TEST(libbacktrace, check_for_leak_local_thread) {
-  thread_t thread_data = { 0, 0, 0 };
+  thread_t thread_data = { 0, 0, 0, nullptr };
   pthread_t thread;
-  ASSERT_TRUE(pthread_create(&thread, NULL, ThreadLevelRun, &thread_data) == 0);
+  ASSERT_TRUE(pthread_create(&thread, nullptr, ThreadLevelRun, &thread_data) == 0);
 
   // Wait up to 2 seconds for the tid to be set.
   ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
@@ -875,7 +1084,7 @@
   // Tell the thread to exit its infinite loop.
   android_atomic_acquire_store(0, &thread_data.state);
 
-  ASSERT_TRUE(pthread_join(thread, NULL) == 0);
+  ASSERT_TRUE(pthread_join(thread, nullptr) == 0);
 }
 
 TEST(libbacktrace, check_for_leak_remote) {
@@ -898,6 +1107,6 @@
   ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
 
   kill(pid, SIGKILL);
-  ASSERT_EQ(waitpid(pid, NULL, 0), pid);
+  ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
 }
 #endif
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 2c5e351..d4450c6 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -22,6 +22,7 @@
 	native_handle.c \
 	config_utils.c \
 	load_file.c \
+	strlcpy.c \
 	open_memstream.c \
 	strdup16to8.c \
 	strdup8to16.c \
@@ -59,12 +60,13 @@
         sockets.c \
 
     commonHostSources += \
-        ashmem-host.c
+        ashmem-host.c \
+        trace-host.c
 
 endif
 
 
-# Static library for host
+# Shared and static library for host
 # ========================================================
 LOCAL_MODULE := libcutils
 LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c
@@ -73,23 +75,18 @@
 LOCAL_CFLAGS += -Werror
 endif
 LOCAL_MULTILIB := both
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_STATIC_LIBRARY)
 
-
-# Tests for host
-# ========================================================
 include $(CLEAR_VARS)
-LOCAL_MODULE := tst_str_parms
-LOCAL_CFLAGS += -DTEST_STR_PARMS
+LOCAL_MODULE := libcutils
+LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c
+LOCAL_SHARED_LIBRARIES := liblog
 ifneq ($(HOST_OS),windows)
 LOCAL_CFLAGS += -Werror
 endif
-LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(BUILD_HOST_EXECUTABLE)
+LOCAL_MULTILIB := both
+include $(BUILD_HOST_SHARED_LIBRARY)
+
 
 
 # Shared and static library for target
@@ -102,32 +99,19 @@
         ashmem-dev.c \
         debugger.c \
         klog.c \
-        memory.c \
         partition_utils.c \
         properties.c \
         qtaguid.c \
-        trace.c \
+        trace-dev.c \
         uevent.c \
 
-LOCAL_SRC_FILES_arm += \
-        arch-arm/memset32.S \
-
 # arch-arm/memset32.S does not compile with Clang.
 LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
 
-LOCAL_SRC_FILES_arm64 += \
-        arch-arm64/android_memset.S \
-
-ifndef ARCH_MIPS_REV6
-LOCAL_SRC_FILES_mips += \
-        arch-mips/android_memset.c \
-
-LOCAL_CFLAGS_mips += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-endif
-
-# TODO: switch mips64 back to using arch-mips/android_memset.c
-LOCAL_SRC_FILES_mips64 += \
-#       arch-mips/android_memset.c \
+LOCAL_SRC_FILES_arm += arch-arm/memset32.S
+LOCAL_SRC_FILES_arm64 += arch-arm64/android_memset.S
+LOCAL_SRC_FILES_mips += arch-mips/android_memset.S
+LOCAL_SRC_FILES_mips64 += arch-mips/android_memset.S
 
 LOCAL_SRC_FILES_x86 += \
         arch-x86/android_memset16.S \
@@ -137,16 +121,9 @@
         arch-x86_64/android_memset16.S \
         arch-x86_64/android_memset32.S \
 
-LOCAL_CFLAGS_arm += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-LOCAL_CFLAGS_arm64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-#LOCAL_CFLAGS_mips64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-LOCAL_CFLAGS_x86 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-LOCAL_CFLAGS_x86_64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-
 LOCAL_C_INCLUDES := $(libcutils_c_includes)
 LOCAL_STATIC_LIBRARIES := liblog
 LOCAL_CFLAGS += -Werror -std=gnu90
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -157,16 +134,6 @@
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_CFLAGS += -Werror
 LOCAL_C_INCLUDES := $(libcutils_c_includes)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_SHARED_LIBRARY)
 
-include $(CLEAR_VARS)
-LOCAL_MODULE := tst_str_parms
-LOCAL_CFLAGS += -DTEST_STR_PARMS -Werror
-LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(BUILD_EXECUTABLE)
-
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libcutils/arch-mips/android_memset.S b/libcutils/arch-mips/android_memset.S
new file mode 100644
index 0000000..6811de0
--- /dev/null
+++ b/libcutils/arch-mips/android_memset.S
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2009
+ *      MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``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 MIPS TECHNOLOGIES, INC. 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.
+ */
+
+/************************************************************************
+ *
+ *  memset.S, version "64h" with 1 cache line horizon for "pref 30" and 14 nops
+ *  Version: "043009"
+ *
+ ************************************************************************/
+
+
+/************************************************************************
+ *  Include files
+ ************************************************************************/
+
+#include <machine/asm.h>
+#define END(f) .cfi_endproc; .size f, .-f; .end f
+
+/*
+ * This routine could be optimized for MIPS64. The current code only
+ * uses MIPS32 instructions.
+ */
+
+#if defined(__MIPSEB__)
+#  define SWHI	swl		/* high part is left in big-endian	*/
+#  define SWLO	swr		/* low part is right in big-endian	*/
+#endif
+
+#if defined(__MIPSEL__)
+#  define SWHI	swr		/* high part is right in little-endian	*/
+#  define SWLO	swl		/* low part is left in little-endian	*/
+#endif
+
+#if !(defined(XGPROF) || defined(XPROF))
+#undef SETUP_GP
+#define SETUP_GP
+#endif
+
+#ifdef NDEBUG
+#define DBG #
+#else
+#define DBG
+#endif
+
+/*
+ * void android_memset16(uint16_t* dst, uint16_t value, size_t size);
+ */
+
+LEAF(android_memset16,0)
+	.set noreorder
+DBG	/* Check parameters */
+DBG	andi	t0,a0,1			# a0 must be halfword aligned
+DBG	tne	t0,zero
+DBG	andi	t2,a2,1			# a2 must be even
+DBG	tne	t2,zero
+
+#ifdef FIXARGS
+	# ensure count is even
+#if (__mips==32) && (__mips_isa_rev>=2)
+	ins	a2,zero,0,1
+#else
+	ori	a2,1
+	xori	a2,1
+#endif
+#endif
+
+#if (__mips==32) && (__mips_isa_rev>=2)
+	ins	a1,a1,16,16
+#else
+	andi	a1,0xffff
+	sll	t3,a1,16
+	or	a1,t3
+#endif
+
+	beqz	a2,.Ldone
+	 andi	t1,a0,2
+	beqz	t1,.Lalignok
+	 addu	t0,a0,a2		# t0 is the "past the end" address
+	sh	a1,0(a0)		# store one halfword to get aligned
+	addu	a0,2
+	subu	a2,2
+.Lalignok:
+	slti	t1,a2,4			# .Laligned for 4 or more bytes
+	beqz	t1,.Laligned
+	 sne	t1,a2,2			# one more halfword?
+	bnez	t1,.Ldone
+	 nop
+	sh	a1,0(a0)
+.Ldone:
+	j	ra
+	 nop
+	.set reorder
+END(android_memset16)
+
+/*
+ * void android_memset32(uint32_t* dst, uint32_t value, size_t size);
+ */
+
+LEAF(android_memset32,0)
+	.set noreorder
+DBG	/* Check parameters */
+DBG	andi	t0,a0,3			# a0 must be word aligned
+DBG	tne	t0,zero
+DBG	andi	t2,a2,3			# a2 must be a multiple of 4 bytes
+DBG	tne	t2,zero
+
+#ifdef FIXARGS
+	# ensure count is a multiple of 4
+#if (__mips==32) && (__mips_isa_rev>=2)
+	ins	$a2,$0,0,2
+#else
+	ori	a2,3
+	xori	a2,3
+#endif
+#endif
+
+	bnez	a2,.Laligned		# any work to do?
+	 addu	t0,a0,a2		# t0 is the "past the end" address
+
+	j	ra
+	 nop
+	.set reorder
+END(android_memset32)
+
+LEAF(memset,0)
+
+	.set	noreorder
+	.set	noat
+
+	addu	t0,a0,a2		# t0 is the "past the end" address
+	slti	AT,a2,4			# is a2 less than 4?
+	bne	AT,zero,.Llast4		# if yes, go to last4
+	 move	v0,a0			# memset returns the dst pointer
+
+	beq	a1,zero,.Lset0
+	 subu	v1,zero,a0
+
+	# smear byte into 32 bit word
+#if (__mips==32) && (__mips_isa_rev>=2)
+	ins     a1, a1, 8, 8        # Replicate fill byte into half-word.
+	ins     a1, a1, 16, 16      # Replicate fill byte into word.
+#else
+	and	a1,0xff
+	sll	AT,a1,8
+	or	a1,AT
+	sll	AT,a1,16
+	or	a1,AT
+#endif
+
+.Lset0:
+	andi	v1,v1,0x3		# word-unaligned address?
+	beq	v1,zero,.Laligned	# v1 is the unalignment count
+	 subu	a2,a2,v1
+	SWHI	a1,0(a0)
+	addu	a0,a0,v1
+
+# Here we have the "word-aligned" a0 (until the "last4")
+.Laligned:
+	andi	t8,a2,0x3f	# any 64-byte chunks?
+				# t8 is the byte count past 64-byte chunks
+	beq	a2,t8,.Lchk8w	# when a2==t8, no 64-byte chunks
+				# There will be at most 1 32-byte chunk then
+	 subu	a3,a2,t8	# subtract from a2 the reminder
+				# Here a3 counts bytes in 16w chunks
+	addu	a3,a0,a3	# Now a3 is the final dst after 64-byte chunks
+
+# Find out, if there are any 64-byte chunks after which will be still at least
+# 96 bytes left. The value "96" is calculated as needed buffer for
+# "pref 30,64(a0)" prefetch, which can be used as "pref 30,0(a0)" after
+# incrementing "a0" by 64.
+# For "a2" below 160 there will be no such "pref 30 safe" 64-byte chunk.
+#
+	sltiu	v1,a2,160
+	bgtz	v1,.Lloop16w_nopref30	# skip "pref 30,0(a0)"
+	 subu	t7,a2,96	# subtract "pref 30 unsafe" region
+		# below we have at least 1 64-byte chunk which is "pref 30 safe"
+	andi	t6,t7,0x3f	# t6 is past "64-byte safe chunks" reminder
+	subu	t5,t7,t6	# subtract from t7 the reminder
+				# Here t5 counts bytes in 16w "safe" chunks
+	addu	t4,a0,t5	# Now t4 is the dst after 64-byte "safe" chunks
+
+# Don't use "pref 30,0(a0)" for a0 in a "middle" of a cache line
+#	pref	30,0(a0)
+# Here we are in the region, where it is safe to use "pref 30,64(a0)"
+.Lloop16w:
+	addiu	a0,a0,64
+	pref	30,-32(a0)	# continue setting up the dest, addr 64-32
+	sw	a1,-64(a0)
+	sw	a1,-60(a0)
+	sw	a1,-56(a0)
+	sw	a1,-52(a0)
+	sw	a1,-48(a0)
+	sw	a1,-44(a0)
+	sw	a1,-40(a0)
+	sw	a1,-36(a0)
+	nop
+	nop			# the extra nop instructions help to balance
+	nop			# cycles needed for "store" + "fill" + "evict"
+	nop			# For 64byte store there are needed 8 fill
+	nop			# and 8 evict cycles, i.e. at least 32 instr.
+	nop
+	nop
+	pref	30,0(a0)	# continue setting up the dest, addr 64-0
+	sw	a1,-32(a0)
+	sw	a1,-28(a0)
+	sw	a1,-24(a0)
+	sw	a1,-20(a0)
+	sw	a1,-16(a0)
+	sw	a1,-12(a0)
+	sw	a1,-8(a0)
+	sw	a1,-4(a0)
+	nop
+	nop
+	nop
+	nop			# NOTE: adding 14 nop-s instead of 12 nop-s
+	nop			# gives better results for "fast" memory
+	nop
+	bne	a0,t4,.Lloop16w
+	 nop
+
+	beq	a0,a3,.Lchk8w	# maybe no more 64-byte chunks?
+	 nop			# this "delayed slot" is useless ...
+
+.Lloop16w_nopref30:	# there could be up to 3 "64-byte nopref30" chunks
+	addiu	a0,a0,64
+	sw	a1,-64(a0)
+	sw	a1,-60(a0)
+	sw	a1,-56(a0)
+	sw	a1,-52(a0)
+	sw	a1,-48(a0)
+	sw	a1,-44(a0)
+	sw	a1,-40(a0)
+	sw	a1,-36(a0)
+	sw	a1,-32(a0)
+	sw	a1,-28(a0)
+	sw	a1,-24(a0)
+	sw	a1,-20(a0)
+	sw	a1,-16(a0)
+	sw	a1,-12(a0)
+	sw	a1,-8(a0)
+	bne	a0,a3,.Lloop16w_nopref30
+	 sw	a1,-4(a0)
+
+.Lchk8w:		# t8 here is the byte count past 64-byte chunks
+
+	andi	t7,t8,0x1f	# is there a 32-byte chunk?
+				# the t7 is the reminder count past 32-bytes
+	beq	t8,t7,.Lchk1w	# when t8==t7, no 32-byte chunk
+	 move	a2,t7
+
+	sw	a1,0(a0)
+	sw	a1,4(a0)
+	sw	a1,8(a0)
+	sw	a1,12(a0)
+	sw	a1,16(a0)
+	sw	a1,20(a0)
+	sw	a1,24(a0)
+	sw	a1,28(a0)
+	addiu	a0,a0,32
+
+.Lchk1w:
+	andi	t8,a2,0x3	# now t8 is the reminder past 1w chunks
+	beq	a2,t8,.Llast4aligned
+	 subu	a3,a2,t8	# a3 is the count of bytes in 1w chunks
+	addu	a3,a0,a3	# now a3 is the dst address past the 1w chunks
+
+# copying in words (4-byte chunks)
+.LwordCopy_loop:
+	addiu	a0,a0,4
+	bne	a0,a3,.LwordCopy_loop
+	 sw	a1,-4(a0)
+
+# store last 0-3 bytes
+# this will repeat the last store if the memset finishes on a word boundary
+.Llast4aligned:
+	j	ra
+	 SWLO	a1,-1(t0)
+
+.Llast4:
+	beq	a0,t0,.Llast4e
+.Llast4l:
+	 addiu	a0,a0,1
+	bne	a0,t0,.Llast4l
+	 sb	a1,-1(a0)
+.Llast4e:
+	j	ra
+	 nop
+
+	.set	at
+	.set	reorder
+
+END(memset)
+
+
+/************************************************************************
+ *  Implementation : Static functions
+ ************************************************************************/
diff --git a/libcutils/arch-mips/android_memset.c b/libcutils/arch-mips/android_memset.c
deleted file mode 100644
index bbc99fe..0000000
--- a/libcutils/arch-mips/android_memset.c
+++ /dev/null
@@ -1,31 +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.
- */
-
-#include <cutils/memory.h>
-
-/* Use mips-assembler versions supplied by bionic/libc/arch-mips/string/memset.S: */
-void _memset16(uint16_t* dst, uint16_t value, size_t size);
-void _memset32(uint32_t* dst, uint32_t value, size_t size);
-
-void android_memset16(uint16_t* dst, uint16_t value, size_t size)
-{
-    _memset16(dst, value, size);
-}
-
-void android_memset32(uint32_t* dst, uint32_t value, size_t size)
-{
-    _memset32(dst, value, size);
-}
diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c
index a6da9ca..8946d3c 100644
--- a/libcutils/iosched_policy.c
+++ b/libcutils/iosched_policy.c
@@ -1,5 +1,5 @@
 /*
-** Copyright 2007-2014, The Android Open Source Project
+** Copyright 2007, 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. 
diff --git a/libcutils/klog.c b/libcutils/klog.c
index fbb7b72..f574f08 100644
--- a/libcutils/klog.c
+++ b/libcutils/klog.c
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-#include <sys/stat.h>
-#include <sys/types.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include <cutils/klog.h>
@@ -36,41 +37,36 @@
     klog_level = level;
 }
 
-void klog_init(void)
-{
-    static const char *name = "/dev/__kmsg__";
-
+void klog_init(void) {
     if (klog_fd >= 0) return; /* Already initialized */
 
+    static const char* name = "/dev/__kmsg__";
     if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {
-        klog_fd = open(name, O_WRONLY);
-        if (klog_fd < 0)
-                return;
-        fcntl(klog_fd, F_SETFD, FD_CLOEXEC);
+        klog_fd = open(name, O_WRONLY | O_CLOEXEC);
         unlink(name);
     }
 }
 
 #define LOG_BUF_MAX 512
 
-void klog_vwrite(int level, const char *fmt, va_list ap)
-{
-    char buf[LOG_BUF_MAX];
-
+void klog_writev(int level, const struct iovec* iov, int iov_count) {
     if (level > klog_level) return;
     if (klog_fd < 0) klog_init();
     if (klog_fd < 0) return;
-
-    vsnprintf(buf, LOG_BUF_MAX, fmt, ap);
-    buf[LOG_BUF_MAX - 1] = 0;
-
-    write(klog_fd, buf, strlen(buf));
+    TEMP_FAILURE_RETRY(writev(klog_fd, iov, iov_count));
 }
 
-void klog_write(int level, const char *fmt, ...)
-{
+void klog_write(int level, const char* fmt, ...) {
+    char buf[LOG_BUF_MAX];
     va_list ap;
     va_start(ap, fmt);
-    klog_vwrite(level, fmt, ap);
+    vsnprintf(buf, sizeof(buf), fmt, ap);
     va_end(ap);
+
+    buf[LOG_BUF_MAX - 1] = 0;
+
+    struct iovec iov[1];
+    iov[0].iov_base = buf;
+    iov[0].iov_len = strlen(buf);
+    klog_writev(level, iov, 1);
 }
diff --git a/libcutils/loghack.h b/libcutils/loghack.h
deleted file mode 100644
index 750cab0..0000000
--- a/libcutils/loghack.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-/**
- * This is a temporary hack to enable logging from cutils.
- */
-
-#ifndef _CUTILS_LOGHACK_H
-#define _CUTILS_LOGHACK_H
-
-#ifdef HAVE_ANDROID_OS
-#include <cutils/log.h>
-#else
-#include <stdio.h>
-#define ALOG(level, ...) \
-        ((void)printf("cutils:" level "/" LOG_TAG ": " __VA_ARGS__))
-#define ALOGV(...)   ALOG("V", __VA_ARGS__)
-#define ALOGD(...)   ALOG("D", __VA_ARGS__)
-#define ALOGI(...)   ALOG("I", __VA_ARGS__)
-#define ALOGW(...)   ALOG("W", __VA_ARGS__)
-#define ALOGE(...)   ALOG("E", __VA_ARGS__)
-#define LOG_ALWAYS_FATAL(...)   do { ALOGE(__VA_ARGS__); exit(1); } while (0)
-#endif
-
-#endif // _CUTILS_LOGHACK_H
diff --git a/libcutils/native_handle.c b/libcutils/native_handle.c
index 4089968..9a4a5bb 100644
--- a/libcutils/native_handle.c
+++ b/libcutils/native_handle.c
@@ -30,9 +30,11 @@
     native_handle_t* h = malloc(
             sizeof(native_handle_t) + sizeof(int)*(numFds+numInts));
 
-    h->version = sizeof(native_handle_t);
-    h->numFds = numFds;
-    h->numInts = numInts;
+    if (h) {
+        h->version = sizeof(native_handle_t);
+        h->numFds = numFds;
+        h->numInts = numInts;
+    }
     return h;
 }
 
diff --git a/libcutils/properties.c b/libcutils/properties.c
index 1190ab7..4e46e02 100644
--- a/libcutils/properties.c
+++ b/libcutils/properties.c
@@ -28,7 +28,7 @@
 #include <cutils/properties.h>
 #include <stdbool.h>
 #include <inttypes.h>
-#include "loghack.h"
+#include <log/log.h>
 
 int8_t property_get_bool(const char *key, int8_t default_value) {
     if (!key) {
@@ -104,8 +104,6 @@
     return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value);
 }
 
-#ifdef __BIONIC__
-
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
 
@@ -156,83 +154,3 @@
     struct property_list_callback_data data = { propfn, cookie };
     return __system_property_foreach(property_list_callback, &data);
 }
-
-#else
-
-/* SUPER-cheesy place-holder implementation for glibc/Mac OS/Windows. */
-
-#include <cutils/threads.h>
-
-static mutex_t  env_lock = MUTEX_INITIALIZER;
-
-int property_get(const char *key, char *value, const char *default_value)
-{
-    char ename[PROPERTY_KEY_MAX + 6];
-    char *p;
-    int len;
-    
-    len = strlen(key);
-    if(len >= PROPERTY_KEY_MAX) return -1;
-    memcpy(ename, "PROP_", 5);
-    memcpy(ename + 5, key, len + 1);
-    
-    mutex_lock(&env_lock);
-
-    p = getenv(ename);
-    if(p == 0) p = "";
-    len = strlen(p);
-    if(len >= PROPERTY_VALUE_MAX) {
-        len = PROPERTY_VALUE_MAX - 1;
-    }
-    
-    if((len == 0) && default_value) {
-        len = strlen(default_value);
-        memcpy(value, default_value, len + 1);
-    } else {
-        memcpy(value, p, len);
-        value[len] = 0;
-    }
-
-    mutex_unlock(&env_lock);
-    
-    return len;
-}
-
-
-int property_set(const char *key, const char *value)
-{
-    char ename[PROPERTY_KEY_MAX + 6];
-    char *p;
-    int len;
-    int r;
-
-    if(strlen(value) >= PROPERTY_VALUE_MAX) return -1;
-    
-    len = strlen(key);
-    if(len >= PROPERTY_KEY_MAX) return -1;
-    memcpy(ename, "PROP_", 5);
-    memcpy(ename + 5, key, len + 1);
-
-    mutex_lock(&env_lock);
-#ifdef HAVE_MS_C_RUNTIME
-    {
-        char  temp[256];
-        snprintf( temp, sizeof(temp), "%s=%s", ename, value);
-        putenv(temp);
-        r = 0;
-    }
-#else    
-    r = setenv(ename, value, 1);
-#endif    
-    mutex_unlock(&env_lock);
-    
-    return r;
-}
-
-int property_list(void (*propfn)(const char *key, const char *value, void *cookie), 
-                  void *cookie)
-{
-    return 0;
-}
-
-#endif
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 2a9d96b..dfc8777 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -45,8 +45,6 @@
 
 #define POLICY_DEBUG 0
 
-#define CAN_SET_SP_SYSTEM 0 // non-zero means to implement set_sched_policy(tid, SP_SYSTEM)
-
 // This prctl is only available in Android kernels.
 #define PR_SET_TIMERSLACK_PID 41
 
@@ -60,9 +58,6 @@
 // File descriptors open to /dev/cpuctl/../tasks, setup by initialize, or -1 on error.
 static int bg_cgroup_fd = -1;
 static int fg_cgroup_fd = -1;
-#if CAN_SET_SP_SYSTEM
-static int system_cgroup_fd = -1;
-#endif
 
 /* Add tid to the scheduling group defined by the policy */
 static int add_tid_to_cgroup(int tid, SchedPolicy policy)
@@ -78,11 +73,6 @@
     case SP_AUDIO_SYS:
         fd = fg_cgroup_fd;
         break;
-#if CAN_SET_SP_SYSTEM
-    case SP_SYSTEM:
-        fd = system_cgroup_fd;
-        break;
-#endif
     default:
         fd = -1;
         break;
@@ -123,21 +113,13 @@
     if (!access("/dev/cpuctl/tasks", F_OK)) {
         __sys_supports_schedgroups = 1;
 
-#if CAN_SET_SP_SYSTEM
         filename = "/dev/cpuctl/tasks";
-        system_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
-        if (system_cgroup_fd < 0) {
-            SLOGV("open of %s failed: %s\n", filename, strerror(errno));
-        }
-#endif
-
-        filename = "/dev/cpuctl/apps/tasks";
         fg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
         if (fg_cgroup_fd < 0) {
             SLOGE("open of %s failed: %s\n", filename, strerror(errno));
         }
 
-        filename = "/dev/cpuctl/apps/bg_non_interactive/tasks";
+        filename = "/dev/cpuctl/bg_non_interactive/tasks";
         bg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
         if (bg_cgroup_fd < 0) {
             SLOGE("open of %s failed: %s\n", filename, strerror(errno));
@@ -231,11 +213,9 @@
         if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0)
             return -1;
         if (grpBuf[0] == '\0') {
-            *policy = SP_SYSTEM;
-        } else if (!strcmp(grpBuf, "apps/bg_non_interactive")) {
-            *policy = SP_BACKGROUND;
-        } else if (!strcmp(grpBuf, "apps")) {
             *policy = SP_FOREGROUND;
+        } else if (!strcmp(grpBuf, "bg_non_interactive")) {
+            *policy = SP_BACKGROUND;
         } else {
             errno = ERANGE;
             return -1;
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
index dfe8c4b..924289a 100644
--- a/libcutils/str_parms.c
+++ b/libcutils/str_parms.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2013 The Android Open Source Project
+ * 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.
@@ -357,51 +357,3 @@
 {
     hashmapForEach(str_parms->map, dump_entry, str_parms);
 }
-
-#ifdef TEST_STR_PARMS
-static void test_str_parms_str(const char *str)
-{
-    struct str_parms *str_parms;
-    char *out_str;
-
-    str_parms = str_parms_create_str(str);
-    str_parms_add_str(str_parms, "dude", "woah");
-    str_parms_add_str(str_parms, "dude", "woah");
-    str_parms_del(str_parms, "dude");
-    str_parms_dump(str_parms);
-    out_str = str_parms_to_str(str_parms);
-    str_parms_destroy(str_parms);
-    ALOGI("%s: '%s' stringified is '%s'", __func__, str, out_str);
-    free(out_str);
-}
-
-int main(void)
-{
-    test_str_parms_str("");
-    test_str_parms_str(";");
-    test_str_parms_str("=");
-    test_str_parms_str("=;");
-    test_str_parms_str("=bar");
-    test_str_parms_str("=bar;");
-    test_str_parms_str("foo=");
-    test_str_parms_str("foo=;");
-    test_str_parms_str("foo=bar");
-    test_str_parms_str("foo=bar;");
-    test_str_parms_str("foo=bar;baz");
-    test_str_parms_str("foo=bar;baz=");
-    test_str_parms_str("foo=bar;baz=bat");
-    test_str_parms_str("foo=bar;baz=bat;");
-    test_str_parms_str("foo=bar;baz=bat;foo=bar");
-
-    // hashmapPut reports errors by setting errno to ENOMEM.
-    // Test that we're not confused by running in an environment where this is already true.
-    errno = ENOMEM;
-    test_str_parms_str("foo=bar;baz=");
-    if (errno != ENOMEM) {
-        abort();
-    }
-    test_str_parms_str("foo=bar;baz=");
-
-    return 0;
-}
-#endif
diff --git a/libcutils/memory.c b/libcutils/strlcpy.c
similarity index 62%
rename from libcutils/memory.c
rename to libcutils/strlcpy.c
index 6486b45..c66246c 100644
--- a/libcutils/memory.c
+++ b/libcutils/strlcpy.c
@@ -1,43 +1,4 @@
 /*
- * Copyright (C) 2007 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 <cutils/memory.h>
-
-#if !HAVE_MEMSET16
-void android_memset16(uint16_t* dst, uint16_t value, size_t size)
-{
-    size >>= 1;
-    while (size--) {
-        *dst++ = value;
-    }
-}
-#endif
-
-#if !HAVE_MEMSET32
-void android_memset32(uint32_t* dst, uint32_t value, size_t size)
-{
-    size >>= 2;
-    while (size--) {
-        *dst++ = value;
-    }
-}
-#endif
-
-#if !HAVE_STRLCPY
-/*
  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -54,8 +15,13 @@
  */
 
 #include <sys/types.h>
+
+#if defined(__GLIBC__) || defined(_WIN32)
+
 #include <string.h>
 
+#include <cutils/memory.h>
+
 /* Implementation of strlcpy() for platforms that don't already have it. */
 
 /*
@@ -88,4 +54,5 @@
 
 	return(s - src - 1);	/* count does not include NUL */
 }
+
 #endif
diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk
index 5a54698..cf70345 100644
--- a/libcutils/tests/Android.mk
+++ b/libcutils/tests/Android.mk
@@ -15,38 +15,59 @@
 LOCAL_PATH := $(call my-dir)
 
 test_src_files := \
+    test_str_parms.cpp \
+
+test_target_only_src_files := \
     MemsetTest.cpp \
     PropertiesTest.cpp \
 
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_MODULE := libcutils_test
-LOCAL_SRC_FILES := $(test_src_files)
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    liblog \
-    libutils \
+test_libraries := libcutils liblog
 
+
+#
+# Target.
+#
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcutils_test
+LOCAL_SRC_FILES := $(test_src_files) $(test_target_only_src_files)
+LOCAL_SHARED_LIBRARIES := $(test_libraries)
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 include $(BUILD_NATIVE_TEST)
 
-# The static libcutils tests cannot be built when using libc++ because there are
-# multiple symbol definition errors between libc++ and libgcc. b/18389856
-#include $(CLEAR_VARS)
-#LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-#LOCAL_MODULE := libcutils_test_static
-#LOCAL_FORCE_STATIC_EXECUTABLE := true
-#LOCAL_SRC_FILES := $(test_src_files)
-#LOCAL_STATIC_LIBRARIES := \
-#    libc \
-#    libcutils \
-#    liblog \
-#    libutils \
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcutils_test_static
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_SRC_FILES := $(test_src_files) $(test_target_only_src_files)
+LOCAL_STATIC_LIBRARIES := libc $(test_libraries)
+LOCAL_CXX_STL := libc++_static
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_NATIVE_TEST)
 
-#LOCAL_CXX_STL := stlport_static
-#LOCAL_MULTILIB := both
-#LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-#LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-#include $(BUILD_NATIVE_TEST)
+
+#
+# Host.
+#
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcutils_test
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_SHARED_LIBRARIES := $(test_libraries)
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_HOST_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcutils_test_static
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_STATIC_LIBRARIES := $(test_libraries)
+LOCAL_CXX_STL := libc++_static
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libcutils/tests/test_str_parms.cpp b/libcutils/tests/test_str_parms.cpp
new file mode 100644
index 0000000..d8f639b
--- /dev/null
+++ b/libcutils/tests/test_str_parms.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#include <cutils/str_parms.h>
+#include <gtest/gtest.h>
+
+static void test_str_parms_str(const char* str, const char* expected) {
+    str_parms* str_parms = str_parms_create_str(str);
+    str_parms_add_str(str_parms, "dude", "woah");
+    str_parms_add_str(str_parms, "dude", "woah");
+    str_parms_del(str_parms, "dude");
+    str_parms_dump(str_parms);
+    char* out_str = str_parms_to_str(str_parms);
+    str_parms_destroy(str_parms);
+    ASSERT_STREQ(expected, out_str) << str;
+    free(out_str);
+}
+
+TEST(str_parms, smoke) {
+    test_str_parms_str("", "");
+    test_str_parms_str(";", "");
+    test_str_parms_str("=", "");
+    test_str_parms_str("=;", "");
+    test_str_parms_str("=bar", "");
+    test_str_parms_str("=bar;", "");
+    test_str_parms_str("foo=", "foo=");
+    test_str_parms_str("foo=;", "foo=");
+    test_str_parms_str("foo=bar", "foo=bar");
+    test_str_parms_str("foo=bar;", "foo=bar");
+    test_str_parms_str("foo=bar;baz", "foo=bar;baz=");
+    test_str_parms_str("foo=bar;baz=", "foo=bar;baz=");
+    test_str_parms_str("foo=bar;baz=bat", "foo=bar;baz=bat");
+    test_str_parms_str("foo=bar;baz=bat;", "foo=bar;baz=bat");
+    test_str_parms_str("foo=bar1;baz=bat;foo=bar2", "foo=bar2;baz=bat");
+}
+
+TEST(str_parms, put_ENOMEM) {
+    // hashmapPut reports errors by setting errno to ENOMEM.
+    // Test that we're not confused by running in an environment where this is already true.
+    errno = ENOMEM;
+    test_str_parms_str("foo=bar;baz=", "foo=bar;baz=");
+    ASSERT_EQ(ENOMEM, errno);
+    test_str_parms_str("foo=bar;baz=", "foo=bar;baz=");
+}
diff --git a/libcutils/threads.c b/libcutils/threads.c
index ca600b3..5f5577b 100644
--- a/libcutils/threads.c
+++ b/libcutils/threads.c
@@ -14,9 +14,25 @@
 ** limitations under the License.
 */
 
-#include <cutils/threads.h>
+#include "cutils/threads.h"
 
 #if !defined(_WIN32)
+
+// For gettid.
+#if defined(__APPLE__)
+#include "AvailabilityMacros.h"  // For MAC_OS_X_VERSION_MAX_ALLOWED
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <unistd.h>
+#elif defined(__linux__) && !defined(__ANDROID__)
+#include <syscall.h>
+#include <unistd.h>
+#elif defined(_WIN32)
+#include <Windows.h>
+#endif
+
 void*  thread_store_get( thread_store_t*  store )
 {
     if (!store->has_tls)
@@ -42,6 +58,24 @@
     pthread_setspecific( store->tls, value );
 }
 
+// No definition needed for Android because we'll just pick up bionic's copy.
+#ifndef __ANDROID__
+pid_t gettid() {
+#if defined(__APPLE__)
+  uint64_t owner;
+  int rc = pthread_threadid_np(NULL, &owner);
+  if (rc != 0) {
+    abort();
+  }
+  return owner;
+#elif defined(__linux__)
+  return syscall(__NR_gettid);
+#elif defined(_WIN32)
+  return (pid_t)GetCurrentThreadId();
+#endif
+}
+#endif  // __ANDROID__
+
 #else /* !defined(_WIN32) */
 void*  thread_store_get( thread_store_t*  store )
 {
diff --git a/libcutils/trace.c b/libcutils/trace-dev.c
similarity index 100%
rename from libcutils/trace.c
rename to libcutils/trace-dev.c
diff --git a/libcutils/trace-host.c b/libcutils/trace-host.c
new file mode 100644
index 0000000..b87e543
--- /dev/null
+++ b/libcutils/trace-host.c
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#include <cutils/trace.h>
+
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+
+volatile int32_t        atrace_is_ready      = 1;
+int                     atrace_marker_fd     = -1;
+uint64_t                atrace_enabled_tags  = 0;
+
+void atrace_set_debuggable(bool debuggable __unused) { }
+void atrace_set_tracing_enabled(bool enabled __unused) { }
+void atrace_update_tags() { }
+void atrace_setup() { }
+void atrace_begin_body(const char* name __unused) { }
+void atrace_async_begin_body(const char* name __unused, int32_t cookie __unused) { }
+void atrace_async_end_body(const char* name __unused, int32_t cookie __unused) { }
+void atrace_int_body(const char* name __unused, int32_t value __unused) { }
+void atrace_int64_body(const char* name __unused, int64_t value __unused) { }
diff --git a/libcutils/uevent.c b/libcutils/uevent.c
index 827170a..de5d227 100644
--- a/libcutils/uevent.c
+++ b/libcutils/uevent.c
@@ -112,7 +112,7 @@
     addr.nl_pid = getpid();
     addr.nl_groups = 0xffffffff;
 
-    s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+    s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
     if(s < 0)
         return -1;
 
diff --git a/libion/tests/Android.mk b/libion/tests/Android.mk
index abf527a..894f90e 100644
--- a/libion/tests/Android.mk
+++ b/libion/tests/Android.mk
@@ -18,7 +18,6 @@
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := ion-unit-tests
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
 LOCAL_SHARED_LIBRARIES += libion
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../kernel-headers
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 5756c54..70aff83 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -16,6 +16,14 @@
 LOCAL_PATH := $(my-dir)
 include $(CLEAR_VARS)
 
+# This is what we want to do:
+#  liblog_cflags := $(shell \
+#   sed -n \
+#       's/^\([0-9]*\)[ \t]*liblog[ \t].*/-DLIBLOG_LOG_TAG=\1/p' \
+#       $(LOCAL_PATH)/event.logtags)
+# so make sure we do not regret hard-coding it as follows:
+liblog_cflags := -DLIBLOG_LOG_TAG=1005
+
 ifneq ($(TARGET_USES_LOGD),false)
 liblog_sources := logd_write.c
 else
@@ -25,28 +33,20 @@
 # some files must not be compiled when building against Mingw
 # they correspond to features not used by our host development tools
 # which are also hard or even impossible to port to native Win32
-WITH_MINGW :=
-ifeq ($(HOST_OS),windows)
-    ifeq ($(strip $(USE_CYGWIN)),)
-        WITH_MINGW := true
-    endif
-endif
-# USE_MINGW is defined when we build against Mingw on Linux
-ifneq ($(strip $(USE_MINGW)),)
-    WITH_MINGW := true
-endif
 
-ifndef WITH_MINGW
+ifeq ($(strip $(USE_MINGW)),)
     liblog_sources += \
-        logprint.c \
         event_tag_map.c
 else
     liblog_sources += \
         uio.c
 endif
 
-liblog_host_sources := $(liblog_sources) fake_log_device.c
+liblog_host_sources := $(liblog_sources) fake_log_device.c event.logtags
 liblog_target_sources := $(liblog_sources) log_time.cpp log_is_loggable.c
+ifeq ($(strip $(USE_MINGW)),)
+liblog_target_sources += logprint.c
+endif
 ifneq ($(TARGET_USES_LOGD),false)
 liblog_target_sources += log_read.c
 else
@@ -57,7 +57,7 @@
 # ========================================================
 LOCAL_MODULE := liblog
 LOCAL_SRC_FILES := $(liblog_host_sources)
-LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror
+LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror $(liblog_cflags)
 LOCAL_MULTILIB := both
 include $(BUILD_HOST_STATIC_LIBRARY)
 
@@ -76,13 +76,17 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := liblog
 LOCAL_SRC_FILES := $(liblog_target_sources)
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror $(liblog_cflags)
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := liblog
 LOCAL_WHOLE_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror $(liblog_cflags)
+
+# TODO: This is to work around b/19059885. Remove after root cause is fixed
+LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv
+
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/liblog/README b/liblog/README
index d7472e4..f29ac04 100644
--- a/liblog/README
+++ b/liblog/README
@@ -111,24 +111,56 @@
        ger_list_alloc,  calling  in  turn the android_logger_open for each log
        id.  Each entry can be retrieved  with  android_logger_list_read.   The
        log(s) can be closed with android_logger_list_free.  The logs should be
-       opened with an O_RDONLY mode.  O_NDELAY mode will report when  the  log
-       reading  is  done  with  an  EAGAIN  error  return  code, otherwise the
-       android_logger_list_read call will block for new entries.
+       opened  with an  ANDROID_LOG_RDONLY  mode.   ANDROID_LOG_NONBLOCK  mode
+       will report when the  log reading is done with an  EAGAIN  error return
+       code,  otherwise the  android_logger_list_read  call will block for new
+       entries.
+
+       The  ANDROID_LOG_PSTORE mode flag to the android_logger_open is used to
+       switch from the active logs to the persistent logs from before the last
+       reboot.
 
        The value returned by android_logger_open can be used as a parameter to
        the  android_logger_clear  function to empty the sub-log.  It is recom‐
-       mended to only open log O_WRONLY.
+       mended to only open log ANDROID_LOG_WRONLY in that case.
 
        The value returned by android_logger_open can be used as a parameter to
        the android_logger_get_log_(size|readable_size|version) to retrieve the
        sub-log maximum size, readable size and log buffer format protocol ver‐
        sion  respectively.  android_logger_get_id returns the id that was used
-       when opening the sub-log.  It is recommended to open the  log  O_RDONLY
-       in these cases.
+       when  opening  the  sub-log.    It  is  recommended  to  open  the  log
+       ANDROID_LOG_RDONLY in these cases.
+
+ERRORS
+       If messages fail, a negative error code will be returned to the caller.
+
+       The -ENOTCONN return code indicates that the logger daemon is stopped.
+
+       The  -EBADF return code indicates that the log access point can not be
+       opened, or the log buffer id is out of range.
+
+       For the  -EAGAIN  return code,  this means that the logging message was
+       temporarily backed-up either because of Denial Of Service (DOS) logging
+       pressure from some chatty application or service in the Android system,
+       or if too small of a value is set in /proc/sys/net/unix/max_dgram_qlen.
+       To aid in diagnosing the occurence of this,  a binary event from liblog
+       will be sent to the  log  daemon  once a  new  message  can get through
+       indicating how many  messages were  dropped  as a result.   Please take
+       action to resolve the structural problems at the source.
+
+       It is generally not advised for the caller to retry the  -EAGAIN return
+       code as  this  will  only  make the  problem(s)  worse  and  cause your
+       application to temporarily drop to the  logger daemon  priority,  BATCH
+       scheduling policy and background task cgroup. If you require a group of
+       messages to be passed atomically,  merge  them  into  one  message with
+       embedded newlines to the maximum length LOGGER_ENTRY_MAX_PAYLOAD.
+
+       Other return codes  from  writing operation can be returned.  Since the
+       library retries on EINTR, -EINTR should never be returned.
 
 SEE ALSO
        syslogd(8)
 
 
 
-                                  17 Dec 2013                        LIBLOG(3)
+                                  24 Jan 2014                        LIBLOG(3)
diff --git a/liblog/event.logtags b/liblog/event.logtags
new file mode 100644
index 0000000..72ecab1
--- /dev/null
+++ b/liblog/event.logtags
@@ -0,0 +1,36 @@
+# The entries in this file map a sparse set of log tag numbers to tag names.
+# This is installed on the device, in /system/etc, and parsed by logcat.
+#
+# Tag numbers are decimal integers, from 0 to 2^31.  (Let's leave the
+# negative values alone for now.)
+#
+# Tag names are one or more ASCII letters and numbers or underscores, i.e.
+# "[A-Z][a-z][0-9]_".  Do not include spaces or punctuation (the former
+# impacts log readability, the latter makes regex searches more annoying).
+#
+# Tag numbers and names are separated by whitespace.  Blank lines and lines
+# starting with '#' are ignored.
+#
+# Optionally, after the tag names can be put a description for the value(s)
+# of the tag. Description are in the format
+#    (<name>|data type[|data unit])
+# Multiple values are separated by commas.
+#
+# The data type is a number from the following values:
+# 1: int
+# 2: long
+# 3: string
+# 4: list
+#
+# The data unit is a number taken from the following list:
+# 1: Number of objects
+# 2: Number of bytes
+# 3: Number of milliseconds
+# 4: Number of allocations
+# 5: Id
+# 6: Percent
+# Default value for data of type int/long is 2 (bytes).
+#
+# TODO: generate ".java" and ".h" files with integer constants from this file.
+
+1005  liblog (dropped|1)
diff --git a/liblog/log_read.c b/liblog/log_read.c
index dbed886..5364e4f 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -19,6 +19,7 @@
 #include <inttypes.h>
 #include <poll.h>
 #include <signal.h>
+#include <stdbool.h>
 #include <stddef.h>
 #define NOMINMAX /* for windows to suppress definition of min in stdlib.h */
 #include <stdlib.h>
@@ -30,6 +31,8 @@
 #include <cutils/sockets.h>
 #include <log/log.h>
 #include <log/logger.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
 
 /* branchless on many architectures. */
 #define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
@@ -357,10 +360,64 @@
     return 0;
 }
 
+/* Determine the credentials of the caller */
+static bool uid_has_log_permission(uid_t uid)
+{
+    return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT);
+}
+
+static uid_t get_best_effective_uid()
+{
+    uid_t euid;
+    uid_t uid;
+    gid_t gid;
+    ssize_t i;
+    static uid_t last_uid = (uid_t) -1;
+
+    if (last_uid != (uid_t) -1) {
+        return last_uid;
+    }
+    uid = getuid();
+    if (uid_has_log_permission(uid)) {
+        return last_uid = uid;
+    }
+    euid = geteuid();
+    if (uid_has_log_permission(euid)) {
+        return last_uid = euid;
+    }
+    gid = getgid();
+    if (uid_has_log_permission(gid)) {
+        return last_uid = gid;
+    }
+    gid = getegid();
+    if (uid_has_log_permission(gid)) {
+        return last_uid = gid;
+    }
+    i = getgroups((size_t) 0, NULL);
+    if (i > 0) {
+        gid_t list[i];
+
+        getgroups(i, list);
+        while (--i >= 0) {
+            if (uid_has_log_permission(list[i])) {
+                return last_uid = list[i];
+            }
+        }
+    }
+    return last_uid = uid;
+}
+
 int android_logger_clear(struct logger *logger)
 {
     char buf[512];
 
+    if (logger->top->mode & ANDROID_LOG_PSTORE) {
+        if (uid_has_log_permission(get_best_effective_uid())) {
+            return unlink("/sys/fs/pstore/pmsg-ramoops-0");
+        }
+        errno = EPERM;
+        return -1;
+    }
     return check_log_success(buf,
         send_log_msg(logger, "clear %d", buf, sizeof(buf)));
 }
@@ -564,6 +621,116 @@
     return logger_list;
 }
 
+static int android_logger_list_read_pstore(struct logger_list *logger_list,
+                                           struct log_msg *log_msg)
+{
+    ssize_t ret;
+    off_t current, next;
+    uid_t uid;
+    struct logger *logger;
+    struct __attribute__((__packed__)) {
+        android_pmsg_log_header_t p;
+        android_log_header_t l;
+    } buf;
+    static uint8_t preread_count;
+
+    memset(log_msg, 0, sizeof(*log_msg));
+
+    if (logger_list->sock < 0) {
+        int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
+
+        if (fd < 0) {
+            return -errno;
+        }
+        logger_list->sock = fd;
+        preread_count = 0;
+    }
+
+    ret = 0;
+    while(1) {
+        if (preread_count < sizeof(buf)) {
+            ret = TEMP_FAILURE_RETRY(read(logger_list->sock,
+                                          &buf.p.magic + preread_count,
+                                          sizeof(buf) - preread_count));
+            if (ret < 0) {
+                return -errno;
+            }
+            preread_count += ret;
+        }
+        if (preread_count != sizeof(buf)) {
+            return preread_count ? -EIO : -EAGAIN;
+        }
+        if ((buf.p.magic != LOGGER_MAGIC)
+         || (buf.p.len <= sizeof(buf))
+         || (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD))
+         || (buf.l.id >= LOG_ID_MAX)
+         || (buf.l.realtime.tv_nsec >= NS_PER_SEC)) {
+            do {
+                memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
+            } while (preread_count && (buf.p.magic != LOGGER_MAGIC));
+            continue;
+        }
+        preread_count = 0;
+
+        logger_for_each(logger, logger_list) {
+            if (buf.l.id != logger->id) {
+                continue;
+            }
+
+            if ((logger_list->start.tv_sec || logger_list->start.tv_nsec)
+             && ((logger_list->start.tv_sec > buf.l.realtime.tv_sec)
+              || ((logger_list->start.tv_sec == buf.l.realtime.tv_sec)
+               && (logger_list->start.tv_nsec > buf.l.realtime.tv_nsec)))) {
+                break;
+            }
+
+            if (logger_list->pid && (logger_list->pid != buf.p.pid)) {
+                break;
+            }
+
+            uid = get_best_effective_uid();
+            if (!uid_has_log_permission(uid) && (uid != buf.p.uid)) {
+                break;
+            }
+
+            ret = TEMP_FAILURE_RETRY(read(logger_list->sock,
+                                          log_msg->entry_v3.msg,
+                                          buf.p.len - sizeof(buf)));
+            if (ret < 0) {
+                return -errno;
+            }
+            if (ret != (ssize_t)(buf.p.len - sizeof(buf))) {
+                return -EIO;
+            }
+
+            log_msg->entry_v3.len = buf.p.len - sizeof(buf);
+            log_msg->entry_v3.hdr_size = sizeof(log_msg->entry_v3);
+            log_msg->entry_v3.pid = buf.p.pid;
+            log_msg->entry_v3.tid = buf.l.tid;
+            log_msg->entry_v3.sec = buf.l.realtime.tv_sec;
+            log_msg->entry_v3.nsec = buf.l.realtime.tv_nsec;
+            log_msg->entry_v3.lid = buf.l.id;
+
+            return ret;
+        }
+
+        current = TEMP_FAILURE_RETRY(lseek(logger_list->sock,
+                                           (off_t)0, SEEK_CUR));
+        if (current < 0) {
+            return -errno;
+        }
+        next = TEMP_FAILURE_RETRY(lseek(logger_list->sock,
+                                        (off_t)(buf.p.len - sizeof(buf)),
+                                        SEEK_CUR));
+        if (next < 0) {
+            return -errno;
+        }
+        if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) {
+            return -EIO;
+        }
+    }
+}
+
 static void caught_signal(int signum __unused)
 {
 }
@@ -582,7 +749,11 @@
         return -EINVAL;
     }
 
-    if (logger_list->mode & O_NONBLOCK) {
+    if (logger_list->mode & ANDROID_LOG_PSTORE) {
+        return android_logger_list_read_pstore(logger_list, log_msg);
+    }
+
+    if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
         memset(&ignore, 0, sizeof(ignore));
         ignore.sa_handler = caught_signal;
         sigemptyset(&ignore.sa_mask);
@@ -602,7 +773,7 @@
         }
 
         strcpy(buffer,
-               (logger_list->mode & O_NONBLOCK) ? "dumpAndClose" : "stream");
+               (logger_list->mode & ANDROID_LOG_NONBLOCK) ? "dumpAndClose" : "stream");
         cp = buffer + strlen(buffer);
 
         strcpy(cp, " lids");
@@ -640,14 +811,14 @@
             cp += ret;
         }
 
-        if (logger_list->mode & O_NONBLOCK) {
+        if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
             /* Deal with an unresponsive logd */
             sigaction(SIGALRM, &ignore, &old_sigaction);
             old_alarm = alarm(30);
         }
         ret = write(sock, buffer, cp - buffer);
         e = errno;
-        if (logger_list->mode & O_NONBLOCK) {
+        if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
             if (e == EINTR) {
                 e = ETIMEDOUT;
             }
@@ -673,7 +844,7 @@
     while(1) {
         memset(log_msg, 0, sizeof(*log_msg));
 
-        if (logger_list->mode & O_NONBLOCK) {
+        if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
             /* particularily useful if tombstone is reporting for logd */
             sigaction(SIGALRM, &ignore, &old_sigaction);
             old_alarm = alarm(30);
@@ -681,7 +852,7 @@
         /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
         ret = recv(logger_list->sock, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
         e = errno;
-        if (logger_list->mode & O_NONBLOCK) {
+        if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
             if ((ret == 0) || (e == EINTR)) {
                 e = EAGAIN;
                 ret = -1;
diff --git a/liblog/log_read_kern.c b/liblog/log_read_kern.c
index 41b8a51..bdc7b18 100644
--- a/liblog/log_read_kern.c
+++ b/liblog/log_read_kern.c
@@ -75,10 +75,10 @@
 
 static int accessmode(int mode)
 {
-    if ((mode & O_ACCMODE) == O_WRONLY) {
+    if ((mode & ANDROID_LOG_ACCMODE) == ANDROID_LOG_WRONLY) {
         return W_OK;
     }
-    if ((mode & O_ACCMODE) == O_RDWR) {
+    if ((mode & ANDROID_LOG_ACCMODE) == ANDROID_LOG_RDWR) {
         return R_OK | W_OK;
     }
     return R_OK;
@@ -117,7 +117,7 @@
         ++b;
     }
 
-    ret = check_allocate_accessible(&n, b, O_RDONLY);
+    ret = check_allocate_accessible(&n, b, ANDROID_LOG_RDONLY);
     free(n);
     if (ret) {
         return ret;
@@ -201,8 +201,8 @@
         return -EFAULT;
     }
 
-    if (((mode & O_ACCMODE) == O_RDWR)
-            || (((mode ^ logger->top->mode) & O_ACCMODE) == 0)) {
+    if (((mode & ANDROID_LOG_ACCMODE) == ANDROID_LOG_RDWR)
+            || (((mode ^ logger->top->mode) & ANDROID_LOG_ACCMODE) == 0)) {
         return ioctl(logger->fd, cmd);
     }
 
@@ -227,13 +227,13 @@
 
 int android_logger_clear(struct logger *logger)
 {
-    return logger_ioctl(logger, LOGGER_FLUSH_LOG, O_WRONLY);
+    return logger_ioctl(logger, LOGGER_FLUSH_LOG, ANDROID_LOG_WRONLY);
 }
 
 /* returns the total size of the log's ring buffer */
 long android_logger_get_log_size(struct logger *logger)
 {
-    return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR);
+    return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, ANDROID_LOG_RDWR);
 }
 
 int android_logger_set_log_size(struct logger *logger __unused,
@@ -248,7 +248,7 @@
  */
 long android_logger_get_log_readable_size(struct logger *logger)
 {
-    return logger_ioctl(logger, LOGGER_GET_LOG_LEN, O_RDONLY);
+    return logger_ioctl(logger, LOGGER_GET_LOG_LEN, ANDROID_LOG_RDONLY);
 }
 
 /*
@@ -256,7 +256,7 @@
  */
 int android_logger_get_log_version(struct logger *logger)
 {
-    int ret = logger_ioctl(logger, LOGGER_GET_VERSION, O_RDWR);
+    int ret = logger_ioctl(logger, LOGGER_GET_VERSION, ANDROID_LOG_RDWR);
     return (ret < 0) ? 1 : ret;
 }
 
@@ -342,7 +342,7 @@
         goto err_name;
     }
 
-    logger->fd = open(n, logger_list->mode);
+    logger->fd = open(n, logger_list->mode & (ANDROID_LOG_ACCMODE | ANDROID_LOG_NONBLOCK));
     if (logger->fd < 0) {
         goto err_name;
     }
@@ -565,7 +565,7 @@
         if (result <= 0) {
             if (result) {
                 error = errno;
-            } else if (logger_list->mode & O_NDELAY) {
+            } else if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
                 error = EAGAIN;
             } else {
                 logger_list->timeout_ms = LOG_TIMEOUT_NEVER;
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 0208c73..c62a246 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -13,12 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#if (FAKE_LOG_DEVICE == 0)
+#include <endian.h>
+#endif
 #include <errno.h>
 #include <fcntl.h>
 #if !defined(_WIN32)
 #include <pthread.h>
 #endif
 #include <stdarg.h>
+#include <stdatomic.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -86,15 +90,6 @@
     return (g_log_status == kLogAvailable);
 }
 
-#if !FAKE_LOG_DEVICE
-/* give up, resources too limited */
-static int __write_to_log_null(log_id_t log_fd __unused, struct iovec *vec __unused,
-                               size_t nr __unused)
-{
-    return -1;
-}
-#endif
-
 /* log_init_lock assumed */
 static int __write_to_log_initialize()
 {
@@ -107,40 +102,32 @@
         log_fds[i] = fakeLogOpen(buf, O_WRONLY);
     }
 #else
-    if (logd_fd >= 0) {
-        i = logd_fd;
-        logd_fd = -1;
-        close(i);
+    if (pstore_fd < 0) {
+        pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
     }
-    if (pstore_fd >= 0) {
-        i = pstore_fd;
-        pstore_fd = -1;
-        close(i);
-    }
-    pstore_fd = open("/dev/pmsg0", O_WRONLY);
 
-    i = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-    if (i < 0) {
-        ret = -errno;
-        write_to_log = __write_to_log_null;
-    } else if (fcntl(i, F_SETFL, O_NONBLOCK) < 0) {
-        ret = -errno;
-        close(i);
-        i = -1;
-        write_to_log = __write_to_log_null;
-    } else {
-        struct sockaddr_un un;
-        memset(&un, 0, sizeof(struct sockaddr_un));
-        un.sun_family = AF_UNIX;
-        strcpy(un.sun_path, "/dev/socket/logdw");
-
-        if (connect(i, (struct sockaddr *)&un, sizeof(struct sockaddr_un)) < 0) {
+    if (logd_fd < 0) {
+        i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+        if (i < 0) {
+            ret = -errno;
+        } else if (TEMP_FAILURE_RETRY(fcntl(i, F_SETFL, O_NONBLOCK)) < 0) {
             ret = -errno;
             close(i);
-            i = -1;
+        } else {
+            struct sockaddr_un un;
+            memset(&un, 0, sizeof(struct sockaddr_un));
+            un.sun_family = AF_UNIX;
+            strcpy(un.sun_path, "/dev/socket/logdw");
+
+            if (TEMP_FAILURE_RETRY(connect(i, (struct sockaddr *)&un,
+                                           sizeof(struct sockaddr_un))) < 0) {
+                ret = -errno;
+                close(i);
+            } else {
+                logd_fd = i;
+            }
         }
     }
-    logd_fd = i;
 #endif
 
     return ret;
@@ -172,6 +159,11 @@
     size_t i, payload_size;
     static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
     static pid_t last_pid = (pid_t) -1;
+    static atomic_int_fast32_t dropped;
+
+    if (!nr) {
+        return -EINVAL;
+    }
 
     if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */
         last_uid = getuid();
@@ -206,7 +198,6 @@
     pmsg_header.uid = last_uid;
     pmsg_header.pid = last_pid;
 
-    header.id = log_id;
     header.tid = gettid();
     header.realtime.tv_sec = ts.tv_sec;
     header.realtime.tv_nsec = ts.tv_nsec;
@@ -216,6 +207,28 @@
     newVec[1].iov_base   = (unsigned char *) &header;
     newVec[1].iov_len    = sizeof(header);
 
+    if (logd_fd > 0) {
+        int32_t snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
+        if (snapshot) {
+            android_log_event_int_t buffer;
+
+            header.id = LOG_ID_EVENTS;
+            buffer.header.tag = htole32(LIBLOG_LOG_TAG);
+            buffer.payload.type = EVENT_TYPE_INT;
+            buffer.payload.data = htole32(snapshot);
+
+            newVec[2].iov_base = &buffer;
+            newVec[2].iov_len  = sizeof(buffer);
+
+            ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
+            if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+                atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
+            }
+        }
+    }
+
+    header.id = log_id;
+
     for (payload_size = 0, i = header_length; i < nr + header_length; i++) {
         newVec[i].iov_base = vec[i - header_length].iov_base;
         payload_size += newVec[i].iov_len = vec[i - header_length].iov_len;
@@ -263,6 +276,8 @@
 #if !defined(_WIN32)
             pthread_mutex_lock(&log_init_lock);
 #endif
+            close(logd_fd);
+            logd_fd = -1;
             ret = __write_to_log_initialize();
 #if !defined(_WIN32)
             pthread_mutex_unlock(&log_init_lock);
@@ -281,6 +296,8 @@
 
     if (ret > (ssize_t)sizeof(header)) {
         ret -= sizeof(header);
+    } else if (ret == -EAGAIN) {
+        atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
     }
 #endif
 
@@ -319,6 +336,11 @@
 #if !defined(_WIN32)
             pthread_mutex_unlock(&log_init_lock);
 #endif
+#if (FAKE_LOG_DEVICE == 0)
+            if (pstore_fd >= 0) {
+                __write_to_log_daemon(log_id, vec, nr);
+            }
+#endif
             return ret;
         }
 
@@ -334,43 +356,7 @@
 
 int __android_log_write(int prio, const char *tag, const char *msg)
 {
-    struct iovec vec[3];
-    log_id_t log_id = LOG_ID_MAIN;
-    char tmp_tag[32];
-
-    if (!tag)
-        tag = "";
-
-    /* XXX: This needs to go! */
-    if (!strcmp(tag, "HTC_RIL") ||
-        !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
-        !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
-        !strcmp(tag, "AT") ||
-        !strcmp(tag, "GSM") ||
-        !strcmp(tag, "STK") ||
-        !strcmp(tag, "CDMA") ||
-        !strcmp(tag, "PHONE") ||
-        !strcmp(tag, "SMS")) {
-            log_id = LOG_ID_RADIO;
-            /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
-            snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
-            tag = tmp_tag;
-    }
-
-#if __BIONIC__
-    if (prio == ANDROID_LOG_FATAL) {
-        android_set_abort_message(msg);
-    }
-#endif
-
-    vec[0].iov_base   = (unsigned char *) &prio;
-    vec[0].iov_len    = 1;
-    vec[1].iov_base   = (void *) tag;
-    vec[1].iov_len    = strlen(tag) + 1;
-    vec[2].iov_base   = (void *) msg;
-    vec[2].iov_len    = strlen(msg) + 1;
-
-    return write_to_log(log_id, vec, 3);
+    return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
 }
 
 int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
@@ -398,6 +384,12 @@
             tag = tmp_tag;
     }
 
+#if __BIONIC__
+    if (prio == ANDROID_LOG_FATAL) {
+        android_set_abort_message(msg);
+    }
+#endif
+
     vec[0].iov_base   = (unsigned char *) &prio;
     vec[0].iov_len    = 1;
     vec[1].iov_base   = (void *) tag;
@@ -463,7 +455,7 @@
     }
 
     __android_log_write(ANDROID_LOG_FATAL, tag, buf);
-    __builtin_trap(); /* trap so we have a chance to debug the situation */
+    abort(); /* abort so we have a chance to debug the situation */
     /* NOTREACHED */
 }
 
diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c
index 2ca3c94..8742b34 100644
--- a/liblog/logd_write_kern.c
+++ b/liblog/logd_write_kern.c
@@ -139,41 +139,7 @@
 
 int __android_log_write(int prio, const char *tag, const char *msg)
 {
-    struct iovec vec[3];
-    log_id_t log_id = LOG_ID_MAIN;
-    char tmp_tag[32];
-
-    if (!tag)
-        tag = "";
-
-    /* XXX: This needs to go! */
-    if (!strcmp(tag, "HTC_RIL") ||
-        !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
-        !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
-        !strcmp(tag, "AT") ||
-        !strcmp(tag, "GSM") ||
-        !strcmp(tag, "STK") ||
-        !strcmp(tag, "CDMA") ||
-        !strcmp(tag, "PHONE") ||
-        !strcmp(tag, "SMS")) {
-            log_id = LOG_ID_RADIO;
-            /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
-            snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
-            tag = tmp_tag;
-    }
-
-    if (prio == ANDROID_LOG_FATAL) {
-        android_set_abort_message(msg);
-    }
-
-    vec[0].iov_base   = (unsigned char *) &prio;
-    vec[0].iov_len    = 1;
-    vec[1].iov_base   = (void *) tag;
-    vec[1].iov_len    = strlen(tag) + 1;
-    vec[2].iov_base   = (void *) msg;
-    vec[2].iov_len    = strlen(msg) + 1;
-
-    return write_to_log(log_id, vec, 3);
+    return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
 }
 
 int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
@@ -201,6 +167,10 @@
             tag = tmp_tag;
     }
 
+    if (prio == ANDROID_LOG_FATAL) {
+        android_set_abort_message(msg);
+    }
+
     vec[0].iov_base   = (unsigned char *) &prio;
     vec[0].iov_len    = 1;
     vec[1].iov_base   = (void *) tag;
@@ -266,7 +236,7 @@
     }
 
     __android_log_write(ANDROID_LOG_FATAL, tag, buf);
-    __builtin_trap(); /* trap so we have a chance to debug the situation */
+    abort(); /* abort so we have a chance to debug the situation */
     /* NOTREACHED */
 }
 
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index 8137a75..d75bbc9 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -39,7 +39,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(test_module_prefix)benchmarks
 LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(benchmark_c_flags)
 LOCAL_SHARED_LIBRARIES += liblog libm
 LOCAL_SRC_FILES := $(benchmark_src_files)
@@ -77,7 +76,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(test_module_prefix)unit-tests
 LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(test_c_flags)
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_SRC_FILES := $(test_src_files)
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 9839729..29501be 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -39,7 +39,7 @@
     pid_t pid = getpid();
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, O_RDONLY | O_NDELAY, 1000, pid)));
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
     struct timespec ts;
     clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -99,7 +99,7 @@
     pid_t pid = getpid();
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        (log_id_t)LOG_ID_CRASH, O_RDONLY | O_NDELAY, 1000, pid)));
+        (log_id_t)LOG_ID_CRASH, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
     char b[80];
     struct timespec ts;
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 549d79e..979aded 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -130,7 +130,7 @@
     pid_t pid = getpid();
 
     struct logger_list * logger_list = android_logger_list_open(LOG_ID_EVENTS,
-        O_RDONLY, 0, pid);
+        ANDROID_LOG_RDONLY, 0, pid);
 
     if (!logger_list) {
         fprintf(stderr, "Unable to open events log: %s\n", strerror(errno));
@@ -208,7 +208,7 @@
     pid_t pid = getpid();
 
     struct logger_list * logger_list = android_logger_list_open(LOG_ID_EVENTS,
-        O_RDONLY, 0, pid);
+        ANDROID_LOG_RDONLY, 0, pid);
 
     if (!logger_list) {
         fprintf(stderr, "Unable to open events log: %s\n", strerror(errno));
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 393e2cd..33f6481 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -122,7 +122,7 @@
     pid_t pid = getpid();
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, O_RDONLY | O_NDELAY, 1000, pid)));
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
     log_time ts(CLOCK_MONOTONIC);
 
@@ -223,7 +223,7 @@
     v += pid & 0xFFFF;
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, O_RDONLY, 1000, pid)));
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 1000, pid)));
 
     int count = 0;
 
@@ -443,7 +443,7 @@
     struct logger_list *logger_list;
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_SYSTEM, O_RDONLY, 100, 0)));
+        LOG_ID_SYSTEM, ANDROID_LOG_RDONLY, 100, 0)));
 
     bool matches = false;
     ssize_t max_len = 0;
@@ -505,7 +505,7 @@
     struct logger_list *logger_list;
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_SYSTEM, O_RDONLY | O_NDELAY, 100, 0)));
+        LOG_ID_SYSTEM, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 100, 0)));
 
     ssize_t max_len = 0;
 
@@ -552,12 +552,12 @@
 
     // >25 messages due to liblog.__android_log_buf_print__concurrentXX above.
     ASSERT_TRUE(NULL != (logger_list1 = android_logger_list_open(
-        LOG_ID_MAIN, O_RDONLY | O_NDELAY, 25, 0)));
+        LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 25, 0)));
 
     struct logger_list *logger_list2;
 
     if (NULL == (logger_list2 = android_logger_list_open(
-            LOG_ID_MAIN, O_RDONLY | O_NDELAY, 15, 0))) {
+            LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 15, 0))) {
         android_logger_list_close(logger_list1);
         ASSERT_TRUE(NULL != logger_list2);
     }
@@ -595,7 +595,7 @@
 }
 
 TEST(liblog, android_logger_get_) {
-    struct logger_list * logger_list = android_logger_list_alloc(O_WRONLY, 0, 0);
+    struct logger_list * logger_list = android_logger_list_alloc(ANDROID_LOG_WRONLY, 0, 0);
 
     for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
         log_id_t id = static_cast<log_id_t>(i);
diff --git a/libnativebridge/tests/CompleteFlow_test.cpp b/libnativebridge/tests/CompleteFlow_test.cpp
index cf06d2c..b033792 100644
--- a/libnativebridge/tests/CompleteFlow_test.cpp
+++ b/libnativebridge/tests/CompleteFlow_test.cpp
@@ -36,6 +36,7 @@
 
     // Unload
     UnloadNativeBridge();
+
     ASSERT_FALSE(NativeBridgeAvailable());
     ASSERT_FALSE(NativeBridgeError());
 
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index 0f7c384..70e37c6 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -72,14 +72,16 @@
         maxnaps = 1;
     }
 
-    while (maxnaps-- > 0) {
-        usleep(NAP_TIME * 1000);
+    while (maxnaps-- >= 0) {
         if (property_get(name, value, NULL)) {
             if (desired_value == NULL || 
                     strcmp(value, desired_value) == 0) {
                 return 0;
             }
         }
+        if (maxnaps >= 0) {
+            usleep(NAP_TIME * 1000);
+        }
     }
     return -1; /* failure */
 }
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index bfe7121..7d2a5fb 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -123,7 +123,7 @@
 {
     int ret;
     if (ifc_ctl_sock == -1) {
-        ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
+        ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
         if (ifc_ctl_sock < 0) {
             printerr("socket() failed: %s\n", strerror(errno));
         }
@@ -137,7 +137,7 @@
 int ifc_init6(void)
 {
     if (ifc_ctl_sock6 == -1) {
-        ifc_ctl_sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
+        ifc_ctl_sock6 = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
         if (ifc_ctl_sock6 < 0) {
             printerr("socket() failed: %s\n", strerror(errno));
         }
@@ -316,7 +316,7 @@
     req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len) + RTA_LENGTH(addrlen);
     memcpy(RTA_DATA(rta), addr, addrlen);
 
-    s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+    s = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
     if (send(s, &req, req.n.nlmsg_len, 0) < 0) {
         close(s);
         return -errno;
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index acd18b0..697db25 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -62,6 +62,8 @@
 LOCAL_SRC_FILES_arm64 := $(PIXELFLINGER_SRC_FILES_arm64)
 LOCAL_SRC_FILES_mips := $(PIXELFLINGER_SRC_FILES_mips)
 LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
 LOCAL_SHARED_LIBRARIES := libcutils liblog
 
 # Really this should go away entirely or at least not depend on
@@ -74,22 +76,4 @@
 LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
 include $(BUILD_SHARED_LIBRARY)
 
-#
-# Static library version
-#
-
-include $(CLEAR_VARS)
-LOCAL_MODULE:= libpixelflinger_static
-LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES)
-LOCAL_SRC_FILES_arm := $(PIXELFLINGER_SRC_FILES_arm)
-LOCAL_SRC_FILES_arm64 := $(PIXELFLINGER_SRC_FILES_arm64)
-LOCAL_SRC_FILES_mips := $(PIXELFLINGER_SRC_FILES_mips)
-LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
-# t32cb16blend.S does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
-# arch-arm64/col32cb16blend.S does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
-include $(BUILD_STATIC_LIBRARY)
-
-
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/include/pixelflinger/format.h b/libpixelflinger/include/pixelflinger/format.h
similarity index 100%
rename from include/pixelflinger/format.h
rename to libpixelflinger/include/pixelflinger/format.h
diff --git a/include/pixelflinger/pixelflinger.h b/libpixelflinger/include/pixelflinger/pixelflinger.h
similarity index 100%
rename from include/pixelflinger/pixelflinger.h
rename to libpixelflinger/include/pixelflinger/pixelflinger.h
diff --git a/include/private/pixelflinger/ggl_context.h b/libpixelflinger/include/private/pixelflinger/ggl_context.h
similarity index 100%
rename from include/private/pixelflinger/ggl_context.h
rename to libpixelflinger/include/private/pixelflinger/ggl_context.h
diff --git a/include/private/pixelflinger/ggl_fixed.h b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
similarity index 100%
rename from include/private/pixelflinger/ggl_fixed.h
rename to libpixelflinger/include/private/pixelflinger/ggl_fixed.h
diff --git a/libpixelflinger/tests/arch-arm64/assembler/Android.mk b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
index 961f323..448d298 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
@@ -13,7 +13,7 @@
     libpixelflinger
 
 LOCAL_C_INCLUDES := \
-    system/core/libpixelflinger
+    $(LOCAL_PATH)/../../..
 
 LOCAL_MODULE:= test-pixelflinger-arm64-assembler-test
 
diff --git a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
index 8f62f09..d8f7e69 100644
--- a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
@@ -7,9 +7,6 @@
 
 LOCAL_SHARED_LIBRARIES :=
 
-LOCAL_C_INCLUDES := \
-    system/core/libpixelflinger/codeflinger
-
 LOCAL_MODULE:= test-pixelflinger-arm64-disassembler-test
 
 LOCAL_MODULE_TAGS := tests
diff --git a/libpixelflinger/tests/codegen/Android.mk b/libpixelflinger/tests/codegen/Android.mk
index bc07015..2f9ca2f 100644
--- a/libpixelflinger/tests/codegen/Android.mk
+++ b/libpixelflinger/tests/codegen/Android.mk
@@ -9,7 +9,7 @@
     libpixelflinger
 
 LOCAL_C_INCLUDES := \
-	system/core/libpixelflinger
+	$(LOCAL_PATH)/../..
 
 LOCAL_MODULE:= test-opengl-codegen
 
diff --git a/libpixelflinger/tests/gglmul/Android.mk b/libpixelflinger/tests/gglmul/Android.mk
index f479fa1..75bd39e 100644
--- a/libpixelflinger/tests/gglmul/Android.mk
+++ b/libpixelflinger/tests/gglmul/Android.mk
@@ -7,7 +7,7 @@
 LOCAL_SHARED_LIBRARIES :=
 
 LOCAL_C_INCLUDES := \
-	system/core/libpixelflinger
+	$(LOCAL_PATH)/../../include
 
 LOCAL_MODULE:= test-pixelflinger-gglmul
 
diff --git a/libprocessgroup/Android.mk b/libprocessgroup/Android.mk
index 051999a..ee6ba58 100644
--- a/libprocessgroup/Android.mk
+++ b/libprocessgroup/Android.mk
@@ -8,7 +8,6 @@
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_CFLAGS := -Wall -Werror
 LOCAL_REQUIRED_MODULE := processgroup_cleanup
-include external/libcxx/libcxx.mk
 include $(BUILD_SHARED_LIBRARY)
 
 include $(CLEAR_VARS)
diff --git a/libsparse/append2simg.c b/libsparse/append2simg.c
index 65e6cc2..1cf827c 100644
--- a/libsparse/append2simg.c
+++ b/libsparse/append2simg.c
@@ -82,7 +82,7 @@
         exit(-1);
     }
 
-    sparse_output = sparse_file_import_auto(output, true);
+    sparse_output = sparse_file_import_auto(output, true, true);
     if (!sparse_output) {
         fprintf(stderr, "Couldn't import output file\n");
         exit(-1);
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index 8b757d2..42d4adb 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -234,6 +234,7 @@
  *
  * @fd - file descriptor to read from
  * @crc - verify the crc of a file in the Android sparse file format
+ * @verbose - whether to use verbose logging
  *
  * Reads an existing sparse or normal file into a sparse file cookie.
  * Attempts to determine if the file is sparse or not by looking for the sparse
@@ -243,7 +244,7 @@
  *
  * Returns a new sparse file cookie on success, NULL on error.
  */
-struct sparse_file *sparse_file_import_auto(int fd, bool crc);
+struct sparse_file *sparse_file_import_auto(int fd, bool crc, bool verbose);
 
 /** sparse_file_resparse - rechunk an existing sparse file into smaller files
  *
diff --git a/libsparse/sparse.c b/libsparse/sparse.c
index baa30cd..65c09e0 100644
--- a/libsparse/sparse.c
+++ b/libsparse/sparse.c
@@ -101,26 +101,32 @@
 	return chunks;
 }
 
-static void sparse_file_write_block(struct output_file *out,
+static int sparse_file_write_block(struct output_file *out,
 		struct backed_block *bb)
 {
+	int ret = -EINVAL;
+
 	switch (backed_block_type(bb)) {
 	case BACKED_BLOCK_DATA:
-		write_data_chunk(out, backed_block_len(bb), backed_block_data(bb));
+		ret = write_data_chunk(out, backed_block_len(bb), backed_block_data(bb));
 		break;
 	case BACKED_BLOCK_FILE:
-		write_file_chunk(out, backed_block_len(bb),
-				backed_block_filename(bb), backed_block_file_offset(bb));
+		ret = write_file_chunk(out, backed_block_len(bb),
+				       backed_block_filename(bb),
+				       backed_block_file_offset(bb));
 		break;
 	case BACKED_BLOCK_FD:
-		write_fd_chunk(out, backed_block_len(bb),
-				backed_block_fd(bb), backed_block_file_offset(bb));
+		ret = write_fd_chunk(out, backed_block_len(bb),
+				     backed_block_fd(bb),
+				     backed_block_file_offset(bb));
 		break;
 	case BACKED_BLOCK_FILL:
-		write_fill_chunk(out, backed_block_len(bb),
-				backed_block_fill_val(bb));
+		ret = write_fill_chunk(out, backed_block_len(bb),
+				       backed_block_fill_val(bb));
 		break;
 	}
+
+	return ret;
 }
 
 static int write_all_blocks(struct sparse_file *s, struct output_file *out)
@@ -128,6 +134,7 @@
 	struct backed_block *bb;
 	unsigned int last_block = 0;
 	int64_t pad;
+	int ret = 0;
 
 	for (bb = backed_block_iter_new(s->backed_block_list); bb;
 			bb = backed_block_iter_next(bb)) {
@@ -135,7 +142,9 @@
 			unsigned int blocks = backed_block_block(bb) - last_block;
 			write_skip_chunk(out, (int64_t)blocks * s->block_size);
 		}
-		sparse_file_write_block(out, bb);
+		ret = sparse_file_write_block(out, bb);
+		if (ret)
+			return ret;
 		last_block = backed_block_block(bb) +
 				DIV_ROUND_UP(backed_block_len(bb), s->block_size);
 	}
@@ -230,6 +239,7 @@
 	struct backed_block *bb;
 	struct backed_block *start;
 	int64_t file_len = 0;
+	int ret;
 
 	/*
 	 * overhead is sparse file header, initial skip chunk, split chunk, end
@@ -249,7 +259,11 @@
 	for (bb = start; bb; bb = backed_block_iter_next(bb)) {
 		count = 0;
 		/* will call out_counter_write to update count */
-		sparse_file_write_block(out_counter, bb);
+		ret = sparse_file_write_block(out_counter, bb);
+		if (ret) {
+			bb = NULL;
+			goto out;
+		}
 		if (file_len + count > len) {
 			/*
 			 * If the remaining available size is more than 1/8th of the
@@ -260,16 +274,17 @@
 				backed_block_split(from->backed_block_list, bb, len - file_len);
 				last_bb = bb;
 			}
-			goto out;
+			goto move;
 		}
 		file_len += count;
 		last_bb = bb;
 	}
 
-out:
+move:
 	backed_block_list_move(from->backed_block_list,
 		to->backed_block_list, start, last_bb);
 
+out:
 	output_file_close(out_counter);
 
 	return bb;
diff --git a/libsparse/sparse_read.c b/libsparse/sparse_read.c
index 8e188e9..9b10293 100644
--- a/libsparse/sparse_read.c
+++ b/libsparse/sparse_read.c
@@ -472,13 +472,13 @@
 	return s;
 }
 
-struct sparse_file *sparse_file_import_auto(int fd, bool crc)
+struct sparse_file *sparse_file_import_auto(int fd, bool crc, bool verbose)
 {
 	struct sparse_file *s;
 	int64_t len;
 	int ret;
 
-	s = sparse_file_import(fd, true, crc);
+	s = sparse_file_import(fd, verbose, crc);
 	if (s) {
 		return s;
 	}
diff --git a/libsync/tests/Android.mk b/libsync/tests/Android.mk
index ad20e50..8137c7a 100644
--- a/libsync/tests/Android.mk
+++ b/libsync/tests/Android.mk
@@ -17,10 +17,8 @@
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
-include external/libcxx/libcxx.mk
 LOCAL_CLANG := true
 LOCAL_MODULE := sync-unit-tests
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers -Wno-sign-compare
 LOCAL_SHARED_LIBRARIES += libsync
 LOCAL_STATIC_LIBRARIES += libgtest_main
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 7bff14e..e9c5f89 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -39,9 +39,7 @@
 	Tokenizer.cpp \
 	Unicode.cpp \
 	VectorImpl.cpp \
-	file.cpp \
 	misc.cpp \
-	stringprintf.cpp \
 
 host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) -Werror
 
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 0af066f..91e45d8 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -48,7 +48,7 @@
 
 // Constructor.  Create an empty object.
 FileMap::FileMap(void)
-    : mRefCount(1), mFileName(NULL), mBasePtr(NULL), mBaseLength(0),
+    : mFileName(NULL), mBasePtr(NULL), mBaseLength(0),
       mDataPtr(NULL), mDataLength(0)
 {
 }
@@ -56,11 +56,6 @@
 // Destructor.
 FileMap::~FileMap(void)
 {
-    assert(mRefCount == 0);
-
-    //printf("+++ removing FileMap %p %zu\n", mDataPtr, mDataLength);
-
-    mRefCount = -100;       // help catch double-free
     if (mFileName != NULL) {
         free(mFileName);
     }
@@ -134,7 +129,6 @@
 
     void* ptr;
 
-    assert(mRefCount == 1);
     assert(fd >= 0);
     assert(offset >= 0);
     assert(length > 0);
diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp
index 7067533..610002f 100644
--- a/libutils/Tokenizer.cpp
+++ b/libutils/Tokenizer.cpp
@@ -43,9 +43,7 @@
 }
 
 Tokenizer::~Tokenizer() {
-    if (mFileMap) {
-        mFileMap->release();
-    }
+    delete mFileMap;
     if (mOwnBuffer) {
         delete[] mBuffer;
     }
@@ -74,7 +72,7 @@
                 fileMap->advise(FileMap::SEQUENTIAL);
                 buffer = static_cast<char*>(fileMap->getDataPtr());
             } else {
-                fileMap->release();
+                delete fileMap;
                 fileMap = NULL;
 
                 // Fall back to reading into a buffer since we can't mmap files in sysfs.
diff --git a/libutils/tests/Android.mk b/libutils/tests/Android.mk
index ce288ca..7cfad89 100644
--- a/libutils/tests/Android.mk
+++ b/libutils/tests/Android.mk
@@ -18,7 +18,6 @@
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_MODULE := libutils_tests
 
@@ -26,11 +25,9 @@
     BasicHashtable_test.cpp \
     BlobCache_test.cpp \
     BitSet_test.cpp \
-    file_test.cpp \
     Looper_test.cpp \
     LruCache_test.cpp \
     String8_test.cpp \
-    stringprintf_test.cpp \
     Unicode_test.cpp \
     Vector_test.cpp \
 
diff --git a/libziparchive/Android.mk b/libziparchive/Android.mk
index ba7b74d..0d31001 100644
--- a/libziparchive/Android.mk
+++ b/libziparchive/Android.mk
@@ -18,17 +18,16 @@
 source_files := zip_archive.cc
 
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_SRC_FILES := ${source_files}
 LOCAL_STATIC_LIBRARIES := libz
 LOCAL_SHARED_LIBRARIES := libutils
 LOCAL_MODULE:= libziparchive
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror -Wall
+LOCAL_CPPFLAGS := -Wold-style-cast
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_SRC_FILES := ${source_files}
 LOCAL_STATIC_LIBRARIES := libz libutils
@@ -41,7 +40,6 @@
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_SRC_FILES := ${source_files}
 LOCAL_STATIC_LIBRARIES := libz libutils
@@ -53,7 +51,6 @@
 
 # Tests.
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_MODULE := ziparchive-tests
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_CFLAGS := -Werror
@@ -63,7 +60,6 @@
 include $(BUILD_NATIVE_TEST)
 
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_MODULE := ziparchive-tests-host
 LOCAL_CPP_EXTENSION := .cc
 LOCAL_CFLAGS += \
diff --git a/libziparchive/testdata/declaredlength.zip b/libziparchive/testdata/declaredlength.zip
new file mode 100644
index 0000000..773380c
--- /dev/null
+++ b/libziparchive/testdata/declaredlength.zip
Binary files differ
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index afc122d..58285f1 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -18,6 +18,9 @@
  * Read-only access to Zip archives, with minimal heap allocation.
  */
 
+#include <memory>
+#include <vector>
+
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -293,7 +296,7 @@
 
   /* mapped central directory area */
   off64_t directory_offset;
-  android::FileMap* directory_map;
+  android::FileMap directory_map;
 
   /* number of entries in the Zip archive */
   uint16_t num_entries;
@@ -311,7 +314,6 @@
       fd(fd),
       close_file(assume_ownership),
       directory_offset(0),
-      directory_map(NULL),
       num_entries(0),
       hash_table_size(0),
       hash_table(NULL) {}
@@ -321,27 +323,10 @@
       close(fd);
     }
 
-    if (directory_map != NULL) {
-      directory_map->release();
-    }
     free(hash_table);
   }
 };
 
-// Returns 0 on success and negative values on failure.
-static android::FileMap* MapFileSegment(const int fd, const off64_t start,
-                                        const size_t length, const bool read_only,
-                                        const char* debug_file_name) {
-  android::FileMap* file_map = new android::FileMap;
-  const bool success = file_map->create(debug_file_name, fd, start, length, read_only);
-  if (!success) {
-    file_map->release();
-    return NULL;
-  }
-
-  return file_map;
-}
-
 static int32_t CopyFileToFile(int fd, uint8_t* begin, const uint32_t length, uint64_t *crc_out) {
   static const uint32_t kBufSize = 32768;
   uint8_t buf[kBufSize];
@@ -523,16 +508,12 @@
    * It all looks good.  Create a mapping for the CD, and set the fields
    * in archive.
    */
-  android::FileMap* map = MapFileSegment(fd,
-      static_cast<off64_t>(eocd->cd_start_offset),
-      static_cast<size_t>(eocd->cd_size),
-      true /* read only */, debug_file_name);
-  if (map == NULL) {
-    archive->directory_map = NULL;
+  if (!archive->directory_map.create(debug_file_name, fd,
+          static_cast<off64_t>(eocd->cd_start_offset),
+          static_cast<size_t>(eocd->cd_size), true /* read only */) ) {
     return kMmapFailed;
   }
 
-  archive->directory_map = map;
   archive->num_entries = eocd->num_records;
   archive->directory_offset = eocd->cd_start_offset;
 
@@ -559,7 +540,7 @@
     return kInvalidFile;
   }
 
-  if (file_length > (off64_t) 0xffffffff) {
+  if (file_length > static_cast<off64_t>(0xffffffff)) {
     ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length));
     return kInvalidFile;
   }
@@ -601,9 +582,9 @@
  * Returns 0 on success.
  */
 static int32_t ParseZipArchive(ZipArchive* archive) {
-  int32_t result = -1;
-  const uint8_t* const cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr();
-  const size_t cd_length = archive->directory_map->getDataLength();
+  const uint8_t* const cd_ptr =
+      reinterpret_cast<const uint8_t*>(archive->directory_map.getDataPtr());
+  const size_t cd_length = archive->directory_map.getDataLength();
   const uint16_t num_entries = archive->num_entries;
 
   /*
@@ -612,8 +593,8 @@
    * least one unused entry to avoid an infinite loop during creation.
    */
   archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
-  archive->hash_table = (ZipEntryName*) calloc(archive->hash_table_size,
-      sizeof(ZipEntryName));
+  archive->hash_table = reinterpret_cast<ZipEntryName*>(calloc(archive->hash_table_size,
+      sizeof(ZipEntryName)));
 
   /*
    * Walk through the central directory, adding entries to the hash
@@ -626,18 +607,19 @@
         reinterpret_cast<const CentralDirectoryRecord*>(ptr);
     if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
       ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
-      goto bail;
+      return -1;
     }
 
     if (ptr + sizeof(CentralDirectoryRecord) > cd_end) {
       ALOGW("Zip: ran off the end (at %" PRIu16 ")", i);
-      goto bail;
+      return -1;
     }
 
     const off64_t local_header_offset = cdr->local_file_header_offset;
     if (local_header_offset >= archive->directory_offset) {
-      ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16, (int64_t)local_header_offset, i);
-      goto bail;
+      ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16,
+          static_cast<int64_t>(local_header_offset), i);
+      return -1;
     }
 
     const uint16_t file_name_length = cdr->file_name_length;
@@ -647,7 +629,7 @@
 
     /* check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters */
     if (!IsValidEntryName(file_name, file_name_length)) {
-      goto bail;
+      return -1;
     }
 
     /* add the CDE filename to the hash table */
@@ -656,25 +638,21 @@
     entry_name.name_length = file_name_length;
     const int add_result = AddToHash(archive->hash_table,
         archive->hash_table_size, entry_name);
-    if (add_result) {
+    if (add_result != 0) {
       ALOGW("Zip: Error adding entry to hash table %d", add_result);
-      result = add_result;
-      goto bail;
+      return add_result;
     }
 
     ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length;
     if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) {
       ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16,
           ptr - cd_ptr, cd_length, i);
-      goto bail;
+      return -1;
     }
   }
   ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries);
 
-  result = 0;
-
-bail:
-  return result;
+  return 0;
 }
 
 static int32_t OpenArchiveInternal(ZipArchive* archive,
@@ -715,7 +693,7 @@
  * Close a ZipArchive, closing the file and freeing the contents.
  */
 void CloseArchive(ZipArchiveHandle handle) {
-  ZipArchive* archive = (ZipArchive*) handle;
+  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
   ALOGV("Closing archive %p", archive);
   delete archive;
 }
@@ -776,8 +754,8 @@
   // the name that's in the hash table is a pointer to a location within
   // this mapped region.
   const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>(
-    archive->directory_map->getDataPtr());
-  if (ptr < base_ptr || ptr > base_ptr + archive->directory_map->getDataLength()) {
+    archive->directory_map.getDataPtr());
+  if (ptr < base_ptr || ptr > base_ptr + archive->directory_map.getDataLength()) {
     ALOGW("Zip: Invalid entry pointer");
     return kInvalidOffset;
   }
@@ -812,7 +790,8 @@
   ssize_t actual = ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf),
                                  local_header_offset);
   if (actual != sizeof(lfh_buf)) {
-    ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)local_header_offset);
+    ALOGW("Zip: failed reading lfh name from offset %" PRId64,
+        static_cast<int64_t>(local_header_offset));
     return kIoError;
   }
 
@@ -845,17 +824,17 @@
   // name in the central directory.
   if (lfh->file_name_length == nameLen) {
     const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader);
-    if (name_offset + lfh->file_name_length >= cd_offset) {
+    if (name_offset + lfh->file_name_length > cd_offset) {
       ALOGW("Zip: Invalid declared length");
       return kInvalidOffset;
     }
 
-    uint8_t* name_buf = (uint8_t*) malloc(nameLen);
+    uint8_t* name_buf = reinterpret_cast<uint8_t*>(malloc(nameLen));
     ssize_t actual = ReadAtOffset(archive->fd, name_buf, nameLen,
                                   name_offset);
 
     if (actual != nameLen) {
-      ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)name_offset);
+      ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
       free(name_buf);
       return kIoError;
     }
@@ -874,20 +853,21 @@
   const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader)
       + lfh->file_name_length + lfh->extra_field_length;
   if (data_offset > cd_offset) {
-    ALOGW("Zip: bad data offset %" PRId64 " in zip", (int64_t)data_offset);
+    ALOGW("Zip: bad data offset %" PRId64 " in zip", static_cast<int64_t>(data_offset));
     return kInvalidOffset;
   }
 
-  if ((off64_t)(data_offset + data->compressed_length) > cd_offset) {
+  if (static_cast<off64_t>(data_offset + data->compressed_length) > cd_offset) {
     ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
-      (int64_t)data_offset, data->compressed_length, (int64_t)cd_offset);
+      static_cast<int64_t>(data_offset), data->compressed_length, static_cast<int64_t>(cd_offset));
     return kInvalidOffset;
   }
 
   if (data->method == kCompressStored &&
-    (off64_t)(data_offset + data->uncompressed_length) > cd_offset) {
+    static_cast<off64_t>(data_offset + data->uncompressed_length) > cd_offset) {
      ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
-       (int64_t)data_offset, data->uncompressed_length, (int64_t)cd_offset);
+       static_cast<int64_t>(data_offset), data->uncompressed_length,
+       static_cast<int64_t>(cd_offset));
      return kInvalidOffset;
   }
 
@@ -919,7 +899,7 @@
 
 int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr,
                        const ZipEntryName* optional_prefix) {
-  ZipArchive* archive = (ZipArchive *) handle;
+  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
 
   if (archive == NULL || archive->hash_table == NULL) {
     ALOGW("Zip: Invalid ZipArchiveHandle");
@@ -941,7 +921,7 @@
 
 int32_t FindEntry(const ZipArchiveHandle handle, const ZipEntryName& entryName,
                   ZipEntry* data) {
-  const ZipArchive* archive = (ZipArchive*) handle;
+  const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
   if (entryName.name_length == 0) {
     ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name);
     return kInvalidEntryName;
@@ -959,7 +939,7 @@
 }
 
 int32_t Next(void* cookie, ZipEntry* data, ZipEntryName* name) {
-  IterationHandle* handle = (IterationHandle *) cookie;
+  IterationHandle* handle = reinterpret_cast<IterationHandle*>(cookie);
   if (handle == NULL) {
     return kInvalidHandle;
   }
@@ -993,13 +973,20 @@
   return kIterationEnd;
 }
 
+// This method is using libz macros with old-style-casts
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+static inline int zlib_inflateInit2(z_stream* stream, int window_bits) {
+  return inflateInit2(stream, window_bits);
+}
+#pragma GCC diagnostic pop
+
 static int32_t InflateToFile(int fd, const ZipEntry* entry,
                              uint8_t* begin, uint32_t length,
                              uint64_t* crc_out) {
-  int32_t result = -1;
-  const uint32_t kBufSize = 32768;
-  uint8_t read_buf[kBufSize];
-  uint8_t write_buf[kBufSize];
+  const size_t kBufSize = 32768;
+  std::vector<uint8_t> read_buf(kBufSize);
+  std::vector<uint8_t> write_buf(kBufSize);
   z_stream zstream;
   int zerr;
 
@@ -1012,7 +999,7 @@
   zstream.opaque = Z_NULL;
   zstream.next_in = NULL;
   zstream.avail_in = 0;
-  zstream.next_out = (Bytef*) write_buf;
+  zstream.next_out = &write_buf[0];
   zstream.avail_out = kBufSize;
   zstream.data_type = Z_UNKNOWN;
 
@@ -1020,7 +1007,7 @@
    * Use the undocumented "negative window bits" feature to tell zlib
    * that there's no zlib header waiting for it.
    */
-  zerr = inflateInit2(&zstream, -MAX_WBITS);
+  zerr = zlib_inflateInit2(&zstream, -MAX_WBITS);
   if (zerr != Z_OK) {
     if (zerr == Z_VERSION_ERROR) {
       ALOGE("Installed zlib is not compatible with linked version (%s)",
@@ -1032,6 +1019,12 @@
     return kZlibError;
   }
 
+  auto zstream_deleter = [](z_stream* stream) {
+    inflateEnd(stream);  /* free up any allocated structures */
+  };
+
+  std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter);
+
   const uint32_t uncompressed_length = entry->uncompressed_length;
 
   uint32_t compressed_length = entry->compressed_length;
@@ -1040,16 +1033,15 @@
     /* read as much as we can */
     if (zstream.avail_in == 0) {
       const ZD_TYPE getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
-      const ZD_TYPE actual = TEMP_FAILURE_RETRY(read(fd, read_buf, getSize));
+      const ZD_TYPE actual = TEMP_FAILURE_RETRY(read(fd, &read_buf[0], getSize));
       if (actual != getSize) {
         ALOGW("Zip: inflate read failed (" ZD " vs " ZD ")", actual, getSize);
-        result = kIoError;
-        goto z_bail;
+        return kIoError;
       }
 
       compressed_length -= getSize;
 
-      zstream.next_in = read_buf;
+      zstream.next_in = &read_buf[0];
       zstream.avail_in = getSize;
     }
 
@@ -1059,22 +1051,21 @@
       ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
           zerr, zstream.next_in, zstream.avail_in,
           zstream.next_out, zstream.avail_out);
-      result = kZlibError;
-      goto z_bail;
+      return kZlibError;
     }
 
     /* write when we're full or when we're done */
     if (zstream.avail_out == 0 ||
       (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
-      const size_t write_size = zstream.next_out - write_buf;
+      const size_t write_size = zstream.next_out - &write_buf[0];
       // The file might have declared a bogus length.
       if (write_size + write_count > length) {
-        goto z_bail;
+        return -1;
       }
-      memcpy(begin + write_count, write_buf, write_size);
+      memcpy(begin + write_count, &write_buf[0], write_size);
       write_count += write_size;
 
-      zstream.next_out = write_buf;
+      zstream.next_out = &write_buf[0];
       zstream.avail_out = kBufSize;
     }
   } while (zerr == Z_OK);
@@ -1087,26 +1078,20 @@
   if (zstream.total_out != uncompressed_length || compressed_length != 0) {
     ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")",
         zstream.total_out, uncompressed_length);
-    result = kInconsistentInformation;
-    goto z_bail;
+    return kInconsistentInformation;
   }
 
-  result = 0;
-
-z_bail:
-  inflateEnd(&zstream);    /* free up any allocated structures */
-
-  return result;
+  return 0;
 }
 
 int32_t ExtractToMemory(ZipArchiveHandle handle,
                         ZipEntry* entry, uint8_t* begin, uint32_t size) {
-  ZipArchive* archive = (ZipArchive*) handle;
+  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
   const uint16_t method = entry->method;
   off64_t data_offset = entry->offset;
 
   if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
-    ALOGW("Zip: lseek to data at %" PRId64 " failed", (int64_t)data_offset);
+    ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset));
     return kIoError;
   }
 
@@ -1138,7 +1123,7 @@
 
 int32_t ExtractEntryToFile(ZipArchiveHandle handle,
                            ZipEntry* entry, int fd) {
-  const int32_t declared_length = entry->uncompressed_length;
+  const uint32_t declared_length = entry->uncompressed_length;
 
   const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
   if (current_offset == -1) {
@@ -1150,7 +1135,7 @@
   int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
   if (result == -1) {
     ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
-          (int64_t)(declared_length + current_offset), strerror(errno));
+          static_cast<int64_t>(declared_length + current_offset), strerror(errno));
     return kIoError;
   }
 
@@ -1161,16 +1146,14 @@
       return 0;
   }
 
-  android::FileMap* map  = MapFileSegment(fd, current_offset, declared_length,
-                                          false, kTempMappingFileName);
-  if (map == NULL) {
+  android::FileMap map;
+  if (!map.create(kTempMappingFileName, fd, current_offset, declared_length, false)) {
     return kMmapFailed;
   }
 
   const int32_t error = ExtractToMemory(handle, entry,
-                                        reinterpret_cast<uint8_t*>(map->getDataPtr()),
-                                        map->getDataLength());
-  map->release();
+                                        reinterpret_cast<uint8_t*>(map.getDataPtr()),
+                                        map.getDataLength());
   return error;
 }
 
@@ -1183,6 +1166,6 @@
 }
 
 int GetFileDescriptor(const ZipArchiveHandle handle) {
-  return ((ZipArchive*) handle)->fd;
+  return reinterpret_cast<ZipArchive*>(handle)->fd;
 }
 
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index c8dafa9..64faa6d 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -171,6 +171,22 @@
   CloseArchive(handle);
 }
 
+TEST(ziparchive, TestInvalidDeclaredLength) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle));
+
+  void* iteration_cookie;
+  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL));
+
+  ZipEntryName name;
+  ZipEntry data;
+
+  ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
+  ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
+
+  CloseArchive(handle);
+}
+
 TEST(ziparchive, ExtractToMemory) {
   ZipArchiveHandle handle;
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
diff --git a/libzipfile/Android.mk b/libzipfile/Android.mk
deleted file mode 100644
index f054e15..0000000
--- a/libzipfile/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# build host static library
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	centraldir.c \
-	zipfile.c
-
-LOCAL_STATIC_LIBRARIES := libz
-
-LOCAL_MODULE:= libzipfile
-
-LOCAL_CFLAGS := -Werror
-
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-# build device static library
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	centraldir.c \
-	zipfile.c
-
-LOCAL_STATIC_LIBRARIES := libz
-
-LOCAL_MODULE:= libzipfile
-
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_STATIC_LIBRARY)
-
-
-# build test_zipfile
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	test_zipfile.c
-
-LOCAL_STATIC_LIBRARIES := libzipfile libz
-
-LOCAL_MODULE := test_zipfile
-
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/libzipfile/MODULE_LICENSE_APACHE2 b/libzipfile/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/libzipfile/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/libzipfile/NOTICE b/libzipfile/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/libzipfile/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
-   Copyright (c) 2005-2008, 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.
-
-   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.
-
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
diff --git a/libzipfile/centraldir.c b/libzipfile/centraldir.c
deleted file mode 100644
index 69cf47a..0000000
--- a/libzipfile/centraldir.c
+++ /dev/null
@@ -1,222 +0,0 @@
-#include "private.h"

-#include <stdio.h>

-#include <string.h>

-#include <stdlib.h>

-

-#include <utils/Compat.h>

-

-enum {

-    // finding the directory

-    CD_SIGNATURE = 0x06054b50,

-    EOCD_LEN     = 22,        // EndOfCentralDir len, excl. comment

-    MAX_COMMENT_LEN = 65535,

-    MAX_EOCD_SEARCH = MAX_COMMENT_LEN + EOCD_LEN,

-

-    // central directory entries

-    ENTRY_SIGNATURE = 0x02014b50,

-    ENTRY_LEN = 46,          // CentralDirEnt len, excl. var fields

-

-    // local file header

-    LFH_SIZE = 30,

-};

-

-unsigned int

-read_le_int(const unsigned char* buf)

-{

-    return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);

-}

-

-unsigned int

-read_le_short(const unsigned char* buf)

-{

-    return buf[0] | (buf[1] << 8);

-}

-

-static int

-read_central_dir_values(Zipfile* file, const unsigned char* buf, int len)

-{

-    if (len < EOCD_LEN) {

-        // looks like ZIP file got truncated

-        fprintf(stderr, " Zip EOCD: expected >= %d bytes, found %d\n",

-                EOCD_LEN, len);

-        return -1;

-    }

-

-    file->disknum = read_le_short(&buf[0x04]);

-    file->diskWithCentralDir = read_le_short(&buf[0x06]);

-    file->entryCount = read_le_short(&buf[0x08]);

-    file->totalEntryCount = read_le_short(&buf[0x0a]);

-    file->centralDirSize = read_le_int(&buf[0x0c]);

-    file->centralDirOffest = read_le_int(&buf[0x10]);

-    file->commentLen = read_le_short(&buf[0x14]);

-

-    if (file->commentLen > 0) {

-        if (EOCD_LEN + file->commentLen > len) {

-            fprintf(stderr, "EOCD(%d) + comment(%d) exceeds len (%d)\n",

-                    EOCD_LEN, file->commentLen, len);

-            return -1;

-        }

-        file->comment = buf + EOCD_LEN;

-    }

-

-    return 0;

-}

-

-static int

-read_central_directory_entry(Zipfile* file, Zipentry* entry,

-                const unsigned char** buf, ssize_t* len)

-{

-    const unsigned char* p;

-

-    unsigned short  extraFieldLength;

-    unsigned short  fileCommentLength;

-    unsigned long   localHeaderRelOffset;

-    unsigned int dataOffset;

-

-    p = *buf;

-

-    if (*len < ENTRY_LEN) {

-        fprintf(stderr, "cde entry not large enough\n");

-        return -1;

-    }

-

-    if (read_le_int(&p[0x00]) != ENTRY_SIGNATURE) {

-        fprintf(stderr, "Whoops: didn't find expected signature\n");

-        return -1;

-    }

-

-    entry->compressionMethod = read_le_short(&p[0x0a]);

-    entry->compressedSize = read_le_int(&p[0x14]);

-    entry->uncompressedSize = read_le_int(&p[0x18]);

-    entry->fileNameLength = read_le_short(&p[0x1c]);

-    extraFieldLength = read_le_short(&p[0x1e]);

-    fileCommentLength = read_le_short(&p[0x20]);

-    localHeaderRelOffset = read_le_int(&p[0x2a]);

-

-    p += ENTRY_LEN;

-

-    // filename

-    if (entry->fileNameLength != 0) {

-        entry->fileName = p;

-    } else {

-        entry->fileName = NULL;

-    }

-    p += entry->fileNameLength;

-

-    // extra field

-    p += extraFieldLength;

-

-    // comment, if any

-    p += fileCommentLength;

-

-    *buf = p;

-

-    // the size of the extraField in the central dir is how much data there is,

-    // but the one in the local file header also contains some padding.

-    p = file->buf + localHeaderRelOffset;

-    extraFieldLength = read_le_short(&p[0x1c]);

-

-    dataOffset = localHeaderRelOffset + LFH_SIZE

-        + entry->fileNameLength + extraFieldLength;

-    entry->data = file->buf + dataOffset;

-#if 0

-    printf("file->buf=%p entry->data=%p dataOffset=%x localHeaderRelOffset=%d "

-           "entry->fileNameLength=%d extraFieldLength=%d\n",

-           file->buf, entry->data, dataOffset, localHeaderRelOffset,

-           entry->fileNameLength, extraFieldLength);

-#endif

-    return 0;

-}

-

-/*

- * Find the central directory and read the contents.

- *

- * The fun thing about ZIP archives is that they may or may not be

- * readable from start to end.  In some cases, notably for archives

- * that were written to stdout, the only length information is in the

- * central directory at the end of the file.

- *

- * Of course, the central directory can be followed by a variable-length

- * comment field, so we have to scan through it backwards.  The comment

- * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff

- * itself, plus apparently sometimes people throw random junk on the end

- * just for the fun of it.

- *

- * This is all a little wobbly.  If the wrong value ends up in the EOCD

- * area, we're hosed.  This appears to be the way that everbody handles

- * it though, so we're in pretty good company if this fails.

- */

-int

-read_central_dir(Zipfile *file)

-{

-    int err;

-

-    const unsigned char* buf = file->buf;

-    ZD_TYPE bufsize = file->bufsize;

-    const unsigned char* eocd;

-    const unsigned char* p;

-    const unsigned char* start;

-    ssize_t len;

-    int i;

-

-    // too small to be a ZIP archive?

-    if (bufsize < EOCD_LEN) {

-        fprintf(stderr, "Length is " ZD " -- too small\n", bufsize);

-        goto bail;

-    }

-

-    // find the end-of-central-dir magic

-    if (bufsize > MAX_EOCD_SEARCH) {

-        start = buf + bufsize - MAX_EOCD_SEARCH;

-    } else {

-        start = buf;

-    }

-    p = buf + bufsize - 4;

-    while (p >= start) {

-        if (*p == 0x50 && read_le_int(p) == CD_SIGNATURE) {

-            eocd = p;

-            break;

-        }

-        p--;

-    }

-    if (p < start) {

-        fprintf(stderr, "EOCD not found, not Zip\n");

-        goto bail;

-    }

-

-    // extract eocd values

-    err = read_central_dir_values(file, eocd, (buf+bufsize)-eocd);

-    if (err != 0) {

-        goto bail;

-    }

-

-    if (file->disknum != 0

-          || file->diskWithCentralDir != 0

-          || file->entryCount != file->totalEntryCount) {

-        fprintf(stderr, "Archive spanning not supported\n");

-        goto bail;

-    }

-

-    // Loop through and read the central dir entries.

-    p = buf + file->centralDirOffest;

-    len = (buf+bufsize)-p;

-    for (i=0; i < file->totalEntryCount; i++) {

-        Zipentry* entry = malloc(sizeof(Zipentry));

-        memset(entry, 0, sizeof(Zipentry));

-

-        err = read_central_directory_entry(file, entry, &p, &len);

-        if (err != 0) {

-            fprintf(stderr, "read_central_directory_entry failed\n");

-            free(entry);

-            goto bail;

-        }

-

-        // add it to our list

-        entry->next = file->entries;

-        file->entries = entry;

-    }

-

-    return 0;

-bail:

-    return -1;

-}

diff --git a/libzipfile/private.h b/libzipfile/private.h
deleted file mode 100644
index 06f788d..0000000
--- a/libzipfile/private.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef PRIVATE_H

-#define PRIVATE_H

-

-#include <stddef.h>

-#include <stdint.h>

-#include <stdio.h>

-#include <string.h>

-#include <stdlib.h>

-

-typedef struct Zipentry {

-    unsigned long fileNameLength;

-    const unsigned char* fileName;

-    unsigned short compressionMethod;

-    unsigned int uncompressedSize;

-    unsigned int compressedSize;

-    const unsigned char* data;

-    

-    struct Zipentry* next;

-} Zipentry;

-

-typedef struct Zipfile

-{

-    const unsigned char *buf;

-    ssize_t bufsize;

-

-    // Central directory

-    unsigned short  disknum;            //mDiskNumber;

-    unsigned short  diskWithCentralDir; //mDiskWithCentralDir;

-    unsigned short  entryCount;         //mNumEntries;

-    unsigned short  totalEntryCount;    //mTotalNumEntries;

-    unsigned int    centralDirSize;     //mCentralDirSize;

-    unsigned int    centralDirOffest;  // offset from first disk  //mCentralDirOffset;

-    unsigned short  commentLen;         //mCommentLen;

-    const unsigned char*  comment;            //mComment;

-

-    Zipentry* entries;

-} Zipfile;

-

-int read_central_dir(Zipfile* file);

-

-unsigned int read_le_int(const unsigned char* buf);

-unsigned int read_le_short(const unsigned char* buf);

-

-#endif // PRIVATE_H

-

diff --git a/libzipfile/test_zipfile.c b/libzipfile/test_zipfile.c
deleted file mode 100644
index 1aaa913..0000000
--- a/libzipfile/test_zipfile.c
+++ /dev/null
@@ -1,94 +0,0 @@
-#include <zipfile/zipfile.h>

-#include <string.h>

-#include <stdio.h>

-#include <stdlib.h>

-

-void dump_zipfile(FILE* to, zipfile_t file);

-

-int

-main(int argc, char** argv)

-{

-    FILE* f;

-    size_t size, unsize;

-    void* buf;

-    void* scratch;

-    zipfile_t zip;

-    zipentry_t entry;

-    int err;

-    enum { HUH, LIST, UNZIP } what = HUH;

-

-    if (strcmp(argv[2], "-l") == 0 && argc == 3) {

-        what = LIST;

-    }

-    else if (strcmp(argv[2], "-u") == 0 && argc == 5) {

-        what = UNZIP;

-    }

-    else {

-        fprintf(stderr, "usage: test_zipfile ZIPFILE -l\n"

-                        "          lists the files in the zipfile\n"

-                        "       test_zipfile ZIPFILE -u FILENAME SAVETO\n"

-                        "          saves FILENAME from the zip file into SAVETO\n");

-        return 1;

-    }

-    

-    f = fopen(argv[1], "r");

-    if (f == NULL) {

-        fprintf(stderr, "couldn't open %s\n", argv[1]);

-        return 1;

-    }

-

-    fseek(f, 0, SEEK_END);

-    size = ftell(f);

-    rewind(f);

-    

-    buf = malloc(size);

-    fread(buf, 1, size, f);

-

-    zip = init_zipfile(buf, size);

-    if (zip == NULL) {

-        fprintf(stderr, "inti_zipfile failed\n");

-        return 1;

-    }

-

-    fclose(f);

-

-

-    switch (what)

-    {

-        case HUH:

-            break;

-        case LIST:

-            dump_zipfile(stdout, zip);

-            break;

-        case UNZIP:

-            entry = lookup_zipentry(zip, argv[3]);

-            if (entry == NULL) {

-                fprintf(stderr, "zip file '%s' does not contain file '%s'\n",

-                                argv[1], argv[1]);

-                return 1;

-            }

-            f = fopen(argv[4], "w");

-            if (f == NULL) {

-                fprintf(stderr, "can't open file for writing '%s'\n", argv[4]);

-                return 1;

-            }

-            unsize = get_zipentry_size(entry);

-            size = unsize * 1.001;

-            scratch = malloc(size);

-            printf("scratch=%p\n", scratch);

-            err = decompress_zipentry(entry, scratch, size);

-            if (err != 0) {

-                fprintf(stderr, "error decompressing file\n");

-                return 1;

-            }

-            fwrite(scratch, unsize, 1, f);

-            free(scratch);

-            fclose(f);

-            break;

-    }

-    

-    free(buf);

-

-    return 0;

-}

-

diff --git a/libzipfile/zipfile.c b/libzipfile/zipfile.c
deleted file mode 100644
index b903fcf..0000000
--- a/libzipfile/zipfile.c
+++ /dev/null
@@ -1,159 +0,0 @@
-#include <zipfile/zipfile.h>
-
-#include "private.h"
-#include <stdlib.h>
-#include <string.h>
-#include <zlib.h>
-#define DEF_MEM_LEVEL 8                // normally in zutil.h?
-
-zipfile_t
-init_zipfile(const void* data, size_t size)
-{
-    int err;
-
-    Zipfile *file = malloc(sizeof(Zipfile));
-    if (file == NULL) return NULL;
-    memset(file, 0, sizeof(Zipfile));
-    file->buf = data;
-    file->bufsize = size;
-
-    err = read_central_dir(file);
-    if (err != 0) goto fail;
-
-    return file;
-fail:
-    free(file);
-    return NULL;
-}
-
-void
-release_zipfile(zipfile_t f)
-{
-    Zipfile* file = (Zipfile*)f;
-    Zipentry* entry = file->entries;
-    while (entry) {
-        Zipentry* next = entry->next;
-        free(entry);
-        entry = next;
-    }
-    free(file);
-}
-
-zipentry_t
-lookup_zipentry(zipfile_t f, const char* entryName)
-{
-    Zipfile* file = (Zipfile*)f;
-    Zipentry* entry = file->entries;
-    while (entry) {
-        if (0 == memcmp(entryName, entry->fileName, entry->fileNameLength)) {
-            return entry;
-        }
-        entry = entry->next;
-    }
-    return NULL;
-}
-
-size_t
-get_zipentry_size(zipentry_t entry)
-{
-    return ((Zipentry*)entry)->uncompressedSize;
-}
-
-char*
-get_zipentry_name(zipentry_t entry)
-{
-    Zipentry* e = (Zipentry*)entry;
-    int l = e->fileNameLength;
-    char* s = malloc(l+1);
-    memcpy(s, e->fileName, l);
-    s[l] = '\0';
-    return s;
-}
-
-enum {
-    STORED = 0,
-    DEFLATED = 8
-};
-
-static int
-uninflate(unsigned char* out, int unlen, const unsigned char* in, int clen)
-{
-    z_stream zstream;
-    int err = 0;
-    int zerr;
-
-    memset(&zstream, 0, sizeof(zstream));
-    zstream.zalloc = Z_NULL;
-    zstream.zfree = Z_NULL;
-    zstream.opaque = Z_NULL;
-    zstream.next_in = (void*)in;
-    zstream.avail_in = clen;
-    zstream.next_out = (Bytef*) out;
-    zstream.avail_out = unlen;
-    zstream.data_type = Z_UNKNOWN;
-
-    // Use the undocumented "negative window bits" feature to tell zlib
-    // that there's no zlib header waiting for it.
-    zerr = inflateInit2(&zstream, -MAX_WBITS);
-    if (zerr != Z_OK) {
-        return -1;
-    }
-
-    // uncompress the data
-    zerr = inflate(&zstream, Z_FINISH);
-    if (zerr != Z_STREAM_END) {
-        fprintf(stderr, "zerr=%d Z_STREAM_END=%d total_out=%lu\n", zerr, Z_STREAM_END,
-                    zstream.total_out);
-        err = -1;
-    }
-
-     inflateEnd(&zstream);
-    return err;
-}
-
-int
-decompress_zipentry(zipentry_t e, void* buf, int bufsize)
-{
-    Zipentry* entry = (Zipentry*)e;
-    switch (entry->compressionMethod)
-    {
-        case STORED:
-            memcpy(buf, entry->data, entry->uncompressedSize);
-            return 0;
-        case DEFLATED:
-            return uninflate(buf, bufsize, entry->data, entry->compressedSize);
-        default:
-            return -1;
-    }
-}
-
-void
-dump_zipfile(FILE* to, zipfile_t file)
-{
-    Zipfile* zip = (Zipfile*)file;
-    Zipentry* entry = zip->entries;
-    int i;
-
-    fprintf(to, "entryCount=%d\n", zip->entryCount);
-    for (i=0; i<zip->entryCount; i++) {
-        fprintf(to, "  file \"");
-        fwrite(entry->fileName, entry->fileNameLength, 1, to);
-        fprintf(to, "\"\n");
-        entry = entry->next;
-    }
-}
-
-zipentry_t
-iterate_zipfile(zipfile_t file, void** cookie)
-{
-    Zipentry* entry = (Zipentry*)*cookie;
-    if (entry == NULL) {
-        Zipfile* zip = (Zipfile*)file;
-        *cookie = zip->entries;
-        return *cookie;
-    } else {
-        entry = entry->next;
-        *cookie = entry;
-        return entry;
-    }
-}
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 79f2ebd..be96fc4 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1,4 +1,4 @@
-// Copyright 2006-2014 The Android Open Source Project
+// Copyright 2006-2015 The Android Open Source Project
 
 #include <assert.h>
 #include <ctype.h>
@@ -38,14 +38,12 @@
     struct logger *logger;
     struct logger_list *logger_list;
     bool printed;
-    char label;
 
     log_device_t* next;
 
-    log_device_t(const char* d, bool b, char l) {
+    log_device_t(const char* d, bool b) {
         device = d;
         binary = b;
-        label = l;
         next = NULL;
         printed = false;
     }
@@ -61,9 +59,7 @@
 static int g_outFD = -1;
 static off_t g_outByteCount = 0;
 static int g_printBinary = 0;
-static int g_devCount = 0;
-
-static EventTagMap* g_eventTagMap = NULL;
+static int g_devCount = 0;                              // >1 means multiple
 
 static int openLogFile (const char *pathname)
 {
@@ -133,8 +129,15 @@
     char binaryMsgBuf[1024];
 
     if (dev->binary) {
+        static bool hasOpenedEventTagMap = false;
+        static EventTagMap *eventTagMap = NULL;
+
+        if (!eventTagMap && !hasOpenedEventTagMap) {
+            eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+            hasOpenedEventTagMap = true;
+        }
         err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry,
-                                                 g_eventTagMap,
+                                                 eventTagMap,
                                                  binaryMsgBuf,
                                                  sizeof(binaryMsgBuf));
         //printf(">>> pri=%d len=%d msg='%s'\n",
@@ -147,16 +150,6 @@
     }
 
     if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority)) {
-        if (false && g_devCount > 1) {
-            binaryMsgBuf[0] = dev->label;
-            binaryMsgBuf[1] = ' ';
-            bytesWritten = write(g_outFD, binaryMsgBuf, 2);
-            if (bytesWritten < 0) {
-                perror("output error");
-                exit(-1);
-            }
-        }
-
         bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
 
         if (bytesWritten < 0) {
@@ -178,18 +171,19 @@
     return;
 }
 
-static void maybePrintStart(log_device_t* dev) {
-    if (!dev->printed) {
-        dev->printed = true;
+static void maybePrintStart(log_device_t* dev, bool printDividers) {
+    if (!dev->printed || printDividers) {
         if (g_devCount > 1 && !g_printBinary) {
             char buf[1024];
-            snprintf(buf, sizeof(buf), "--------- beginning of %s\n",
+            snprintf(buf, sizeof(buf), "--------- %s %s\n",
+                     dev->printed ? "switch to" : "beginning of",
                      dev->device);
             if (write(g_outFD, buf, strlen(buf)) < 0) {
                 perror("output error");
                 exit(-1);
             }
         }
+        dev->printed = true;
     }
 }
 
@@ -221,12 +215,13 @@
 
     fprintf(stderr, "options include:\n"
                     "  -s              Set default filter to silent.\n"
-                    "                  Like specifying filterspec '*:s'\n"
+                    "                  Like specifying filterspec '*:S'\n"
                     "  -f <filename>   Log to file. Default to stdout\n"
                     "  -r [<kbytes>]   Rotate log every kbytes. (16 if unspecified). Requires -f\n"
                     "  -n <count>      Sets max number of rotated logs to <count>, default 4\n"
                     "  -v <format>     Sets the log print format, where <format> is:\n\n"
                     "                  brief color long process raw tag thread threadtime time\n\n"
+                    "  -D              print dividers between each log buffer\n"
                     "  -c              clear (flush) the entire log and exit\n"
                     "  -d              dump the log and then exit (don't block)\n"
                     "  -t <count>      print only the most recent <count> lines (implies -d)\n"
@@ -235,6 +230,7 @@
                     "  -T '<time>'     print most recent lines since specified time (not imply -d)\n"
                     "                  count is pure numerical, time is 'MM-DD hh:mm:ss.mmm'\n"
                     "  -g              get the size of the log's ring buffer and exit\n"
+                    "  -L              dump logs from prior to last reboot\n"
                     "  -b <buffer>     Request alternate ring buffer, 'main', 'system', 'radio',\n"
                     "                  'events', 'crash' or 'all'. Multiple -b parameters are\n"
                     "                  allowed and results are interleaved. The default is\n"
@@ -254,21 +250,19 @@
     fprintf(stderr,"\nfilterspecs are a series of \n"
                    "  <tag>[:priority]\n\n"
                    "where <tag> is a log component tag (or * for all) and priority is:\n"
-                   "  V    Verbose\n"
-                   "  D    Debug\n"
+                   "  V    Verbose (default for <tag>)\n"
+                   "  D    Debug (default for '*')\n"
                    "  I    Info\n"
                    "  W    Warn\n"
                    "  E    Error\n"
                    "  F    Fatal\n"
-                   "  S    Silent (supress all output)\n"
-                   "\n'*' means '*:d' and <tag> by itself means <tag>:v\n"
-                   "\nIf not specified on the commandline, filterspec is set from ANDROID_LOG_TAGS.\n"
-                   "If no filterspec is found, filter defaults to '*:I'\n"
-                   "\nIf not specified with -v, format is set from ANDROID_PRINTF_LOG\n"
+                   "  S    Silent (suppress all output)\n"
+                   "\n'*' by itself means '*:D' and <tag> by itself means <tag>:V.\n"
+                   "If no '*' filterspec or -s on command line, all filter defaults to '*:V'.\n"
+                   "eg: '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.\n"
+                   "\nIf not specified on the command line, filterspec is set from ANDROID_LOG_TAGS.\n"
+                   "\nIf not specified with -v on command line, format is set from ANDROID_PRINTF_LOG\n"
                    "or defaults to \"threadtime\"\n\n");
-
-
-
 }
 
 
@@ -324,11 +318,11 @@
     int getPruneList = 0;
     char *setPruneList = NULL;
     int printStatistics = 0;
-    int mode = O_RDONLY;
+    int mode = ANDROID_LOG_RDONLY;
     const char *forceFilters = NULL;
     log_device_t* devices = NULL;
     log_device_t* dev;
-    bool needBinary = false;
+    bool printDividers = false;
     struct logger_list *logger_list;
     unsigned int tail_lines = 0;
     log_time tail_time(log_time::EPOCH);
@@ -345,7 +339,7 @@
     for (;;) {
         int ret;
 
-        ret = getopt(argc, argv, "cdt:T:gG:sQf:r:n:v:b:BSpP:");
+        ret = getopt(argc, argv, "cdDLt:T:gG:sQf:r:n:v:b:BSpP:");
 
         if (ret < 0) {
             break;
@@ -359,15 +353,19 @@
 
             case 'c':
                 clearLog = 1;
-                mode = O_WRONLY;
+                mode |= ANDROID_LOG_WRONLY;
+            break;
+
+            case 'L':
+                mode |= ANDROID_LOG_PSTORE;
             break;
 
             case 'd':
-                mode = O_RDONLY | O_NDELAY;
+                mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
             break;
 
             case 't':
-                mode = O_RDONLY | O_NDELAY;
+                mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
                 /* FALLTHRU */
             case 'T':
                 if (strspn(optarg, "0123456789") != strlen(optarg)) {
@@ -398,6 +396,10 @@
                 }
             break;
 
+            case 'D':
+                printDividers = true;
+            break;
+
             case 'g':
                 getLogSize = 1;
             break;
@@ -457,7 +459,6 @@
 
                     devices = dev = NULL;
                     android::g_devCount = 0;
-                    needBinary = false;
                     for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
                         const char *name = android_log_id_to_name((log_id_t)i);
                         log_id_t log_id = android_name_to_log_id(name);
@@ -467,7 +468,7 @@
                         }
 
                         bool binary = strcmp(name, "events") == 0;
-                        log_device_t* d = new log_device_t(name, binary, *name);
+                        log_device_t* d = new log_device_t(name, binary);
 
                         if (dev) {
                             dev->next = d;
@@ -476,26 +477,20 @@
                             devices = dev = d;
                         }
                         android::g_devCount++;
-                        if (binary) {
-                            needBinary = true;
-                        }
                     }
                     break;
                 }
 
                 bool binary = strcmp(optarg, "events") == 0;
-                if (binary) {
-                    needBinary = true;
-                }
 
                 if (devices) {
                     dev = devices;
                     while (dev->next) {
                         dev = dev->next;
                     }
-                    dev->next = new log_device_t(optarg, binary, optarg[0]);
+                    dev->next = new log_device_t(optarg, binary);
                 } else {
-                    devices = new log_device_t(optarg, binary, optarg[0]);
+                    devices = new log_device_t(optarg, binary);
                 }
                 android::g_devCount++;
             }
@@ -629,14 +624,14 @@
     }
 
     if (!devices) {
-        dev = devices = new log_device_t("main", false, 'm');
+        dev = devices = new log_device_t("main", false);
         android::g_devCount = 1;
         if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
-            dev = dev->next = new log_device_t("system", false, 's');
+            dev = dev->next = new log_device_t("system", false);
             android::g_devCount++;
         }
         if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
-            dev = dev->next = new log_device_t("crash", false, 'c');
+            dev = dev->next = new log_device_t("crash", false);
             android::g_devCount++;
         }
     }
@@ -836,15 +831,15 @@
     //LOG_EVENT_LONG(11, 0x1122334455667788LL);
     //LOG_EVENT_STRING(0, "whassup, doc?");
 
-    if (needBinary)
-        android::g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
-
+    dev = NULL;
+    log_device_t unexpected("unexpected", false);
     while (1) {
         struct log_msg log_msg;
+        log_device_t* d;
         int ret = android_logger_list_read(logger_list, &log_msg);
 
         if (ret == 0) {
-            fprintf(stderr, "read: Unexpected EOF!\n");
+            fprintf(stderr, "read: unexpected EOF!\n");
             exit(EXIT_FAILURE);
         }
 
@@ -854,7 +849,7 @@
             }
 
             if (ret == -EIO) {
-                fprintf(stderr, "read: Unexpected EOF!\n");
+                fprintf(stderr, "read: unexpected EOF!\n");
                 exit(EXIT_FAILURE);
             }
             if (ret == -EINVAL) {
@@ -865,17 +860,21 @@
             exit(EXIT_FAILURE);
         }
 
-        for(dev = devices; dev; dev = dev->next) {
-            if (android_name_to_log_id(dev->device) == log_msg.id()) {
+        for(d = devices; d; d = d->next) {
+            if (android_name_to_log_id(d->device) == log_msg.id()) {
                 break;
             }
         }
-        if (!dev) {
-            fprintf(stderr, "read: Unexpected log ID!\n");
-            exit(EXIT_FAILURE);
+        if (!d) {
+            android::g_devCount = 2; // set to Multiple
+            d = &unexpected;
+            d->binary = log_msg.id() == LOG_ID_EVENTS;
         }
 
-        android::maybePrintStart(dev);
+        if (dev != d) {
+            dev = d;
+            android::maybePrintStart(dev, printDividers);
+        }
         if (android::g_printBinary) {
             android::printBinary(&log_msg);
         } else {
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index 015a23d..a28664e 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -39,7 +39,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(test_module_prefix)benchmarks
 LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(test_c_flags)
 LOCAL_SRC_FILES := $(benchmark_src_files)
 include $(BUILD_NATIVE_TEST)
@@ -56,7 +55,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(test_module_prefix)unit-tests
 LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(test_c_flags)
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_SRC_FILES := $(test_src_files)
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index b358485..de2db67 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -505,12 +505,14 @@
             while (fgets(buffer, sizeof(buffer), fp)) {
                 static const char match_1[] = "4 log.txt";
                 static const char match_2[] = "8 log.txt";
-                static const char match_3[] = "16 log.txt";
+                static const char match_3[] = "12 log.txt";
+                static const char match_4[] = "16 log.txt";
                 static const char total[] = "total ";
 
                 if (!strncmp(buffer, match_1, sizeof(match_1) - 1)
                  || !strncmp(buffer, match_2, sizeof(match_2) - 1)
-                 || !strncmp(buffer, match_3, sizeof(match_3) - 1)) {
+                 || !strncmp(buffer, match_3, sizeof(match_3) - 1)
+                 || !strncmp(buffer, match_4, sizeof(match_4) - 1)) {
                     ++count;
                 } else if (strncmp(buffer, total, sizeof(total) - 1)) {
                     fprintf(stderr, "WARNING: Parse error: %s", buffer);
diff --git a/logd/Android.mk b/logd/Android.mk
index 188511f..127a66b 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -26,7 +26,16 @@
     libcutils \
     libutils
 
-LOCAL_CFLAGS := -Werror $(shell sed -n 's/^\([0-9]*\)[ \t]*auditd[ \t].*/-DAUDITD_LOG_TAG=\1/p' $(LOCAL_PATH)/event.logtags)
+# This is what we want to do:
+#  event_logtags = $(shell \
+#    sed -n \
+#        "s/^\([0-9]*\)[ \t]*$1[ \t].*/-D`echo $1 | tr a-z A-Z`_LOG_TAG=\1/p" \
+#        $(LOCAL_PATH)/$2/event.logtags)
+#  event_flag := $(call event_logtags,auditd)
+# so make sure we do not regret hard-coding it as follows:
+event_flag := -DAUDITD_LOG_TAG=1003
+
+LOCAL_CFLAGS := -Werror $(event_flag)
 
 include $(BUILD_EXECUTABLE)
 
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index d7088b4..561ea3e 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -44,6 +44,7 @@
     registerCmd(new GetStatisticsCmd(buf));
     registerCmd(new SetPruneListCmd(buf));
     registerCmd(new GetPruneListCmd(buf));
+    registerCmd(new ReinitCmd());
 }
 
 CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader,
@@ -296,6 +297,21 @@
     return 0;
 }
 
+CommandListener::ReinitCmd::ReinitCmd()
+        : LogCommand("reinit")
+{ }
+
+int CommandListener::ReinitCmd::runCommand(SocketClient *cli,
+                                         int /*argc*/, char ** /*argv*/) {
+    setname();
+
+    reinit_signal_handler(SIGHUP);
+
+    cli->sendMsg("success");
+
+    return 0;
+}
+
 int CommandListener::getLogSocket() {
     static const char socketName[] = "logd";
     int sock = android_get_control_socket(socketName);
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
index cd1c306..83e06b4 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -23,6 +23,9 @@
 #include "LogReader.h"
 #include "LogListener.h"
 
+// See main.cpp for implementation
+void reinit_signal_handler(int /*signal*/);
+
 class CommandListener : public FrameworkListener {
     LogBuffer &mBuf;
 
@@ -60,6 +63,14 @@
     LogBufferCmd(GetStatistics)
     LogBufferCmd(GetPruneList)
     LogBufferCmd(SetPruneList)
+
+    class ReinitCmd : public LogCommand {
+    public:
+        ReinitCmd();
+        virtual ~ReinitCmd() {}
+        int runCommand(SocketClient *c, int argc, char ** argv);
+    };
+
 };
 
 #endif
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index 3be07c0..26a1861 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -27,7 +27,7 @@
                            unsigned long tail,
                            unsigned int logMask,
                            pid_t pid,
-                           log_time start)
+                           uint64_t start)
         : mReader(reader)
         , mNonBlock(nonBlock)
         , mTail(tail)
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
index f34c06a..61c6858 100644
--- a/logd/FlushCommand.h
+++ b/logd/FlushCommand.h
@@ -31,7 +31,7 @@
     unsigned long mTail;
     unsigned int mLogMask;
     pid_t mPid;
-    log_time mStart;
+    uint64_t mStart;
 
 public:
     FlushCommand(LogReader &mReader,
@@ -39,7 +39,7 @@
                  unsigned long tail = -1,
                  unsigned int logMask = -1,
                  pid_t pid = 0,
-                 log_time start = LogTimeEntry::EPOCH);
+                 uint64_t start = 1);
     virtual void runSocketCommand(SocketClient *client);
 
     static bool hasReadLogs(SocketClient *client);
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index c7c0249..6b3e637 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <ctype.h>
+#include <endian.h>
 #include <errno.h>
 #include <limits.h>
 #include <stdarg.h>
@@ -23,13 +24,15 @@
 #include <sys/uio.h>
 #include <syslog.h>
 
+#include <private/android_logger.h>
+
 #include "libaudit.h"
 #include "LogAudit.h"
 
-#define KMSG_PRIORITY(PRI)         \
-    '<',                           \
-    '0' + (LOG_AUTH | (PRI)) / 10, \
-    '0' + (LOG_AUTH | (PRI)) % 10, \
+#define KMSG_PRIORITY(PRI)                          \
+    '<',                                            \
+    '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \
+    '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, \
     '>'
 
 LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg)
@@ -138,29 +141,23 @@
     // log to events
 
     size_t l = strlen(str);
-    size_t n = l + sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
+    size_t n = l + sizeof(android_log_event_string_t);
 
     bool notify = false;
 
-    char *newstr = reinterpret_cast<char *>(malloc(n));
-    if (!newstr) {
+    android_log_event_string_t *event = static_cast<android_log_event_string_t *>(malloc(n));
+    if (!event) {
         rc = -ENOMEM;
     } else {
-        cp = newstr;
-        *cp++ = AUDITD_LOG_TAG & 0xFF;
-        *cp++ = (AUDITD_LOG_TAG >> 8) & 0xFF;
-        *cp++ = (AUDITD_LOG_TAG >> 16) & 0xFF;
-        *cp++ = (AUDITD_LOG_TAG >> 24) & 0xFF;
-        *cp++ = EVENT_TYPE_STRING;
-        *cp++ = l & 0xFF;
-        *cp++ = (l >> 8) & 0xFF;
-        *cp++ = (l >> 16) & 0xFF;
-        *cp++ = (l >> 24) & 0xFF;
-        memcpy(cp, str, l);
+        event->header.tag = htole32(AUDITD_LOG_TAG);
+        event->payload.type = EVENT_TYPE_STRING;
+        event->payload.length = htole32(l);
+        memcpy(event->payload.data, str, l);
 
-        logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid, newstr,
+        logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid,
+                    reinterpret_cast<char *>(event),
                     (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
-        free(newstr);
+        free(event);
 
         notify = true;
     }
@@ -190,7 +187,7 @@
     }
     n = (estr - str) + strlen(ecomm) + l + 2;
 
-    newstr = reinterpret_cast<char *>(malloc(n));
+    char *newstr = static_cast<char *>(malloc(n));
     if (!newstr) {
         rc = -ENOMEM;
     } else {
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 3d0b38f..d11b129 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -27,8 +27,6 @@
 
 #include "LogBuffer.h"
 #include "LogReader.h"
-#include "LogStatistics.h"
-#include "LogWhiteBlackList.h"
 
 // Default
 #define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
@@ -92,11 +90,7 @@
     return value;
 }
 
-LogBuffer::LogBuffer(LastLogTimes *times)
-        : dgramQlenStatistics(false)
-        , mTimes(*times) {
-    pthread_mutex_init(&mLogElementsLock, NULL);
-
+void LogBuffer::init() {
     static const char global_tuneable[] = "persist.logd.size"; // Settings App
     static const char global_default[] = "ro.logd.size";       // BoardConfig.mk
 
@@ -132,6 +126,13 @@
     }
 }
 
+LogBuffer::LogBuffer(LastLogTimes *times)
+        : mTimes(*times) {
+    pthread_mutex_init(&mLogElementsLock, NULL);
+
+    init();
+}
+
 void LogBuffer::log(log_id_t log_id, log_time realtime,
                     uid_t uid, pid_t pid, pid_t tid,
                     const char *msg, unsigned short len) {
@@ -150,23 +151,6 @@
     while (last != mLogElements.begin()) {
         --it;
         if ((*it)->getRealTime() <= realtime) {
-            // halves the peak performance, use with caution
-            if (dgramQlenStatistics) {
-                LogBufferElementCollection::iterator ib = it;
-                unsigned short buckets, num = 1;
-                for (unsigned short i = 0; (buckets = stats.dgramQlen(i)); ++i) {
-                    buckets -= num;
-                    num += buckets;
-                    while (buckets && (--ib != mLogElements.begin())) {
-                        --buckets;
-                    }
-                    if (buckets) {
-                        break;
-                    }
-                    stats.recordDiff(
-                        elem->getRealTime() - (*ib)->getRealTime(), i);
-                }
-            }
             break;
         }
         last = it;
@@ -175,7 +159,7 @@
     if (last == mLogElements.end()) {
         mLogElements.push_back(elem);
     } else {
-        log_time end = log_time::EPOCH;
+        uint64_t end = 1;
         bool end_set = false;
         bool end_always = false;
 
@@ -198,7 +182,7 @@
         }
 
         if (end_always
-                || (end_set && (end >= (*last)->getMonotonicTime()))) {
+                || (end_set && (end >= (*last)->getSequence()))) {
             mLogElements.push_back(elem);
         } else {
             mLogElements.insert(last,elem);
@@ -207,7 +191,7 @@
         LogTimeEntry::unlock();
     }
 
-    stats.add(len, log_id, uid, pid);
+    stats.add(elem);
     maybePrune(log_id);
     pthread_mutex_unlock(&mLogElementsLock);
 }
@@ -230,6 +214,16 @@
     }
 }
 
+LogBufferElementCollection::iterator LogBuffer::erase(LogBufferElementCollection::iterator it) {
+    LogBufferElement *e = *it;
+
+    it = mLogElements.erase(it);
+    stats.subtract(e);
+    delete e;
+
+    return it;
+}
+
 // prune "pruneRows" of type "id" from the buffer.
 //
 // mLogElementsLock must be held when this function is called.
@@ -255,7 +249,7 @@
         for(it = mLogElements.begin(); it != mLogElements.end();) {
             LogBufferElement *e = *it;
 
-            if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+            if (oldest && (oldest->mStart <= e->getSequence())) {
                 break;
             }
 
@@ -264,12 +258,8 @@
                 continue;
             }
 
-            uid_t uid = e->getUid();
-
-            if (uid == caller_uid) {
-                it = mLogElements.erase(it);
-                stats.subtract(e->getMsgLen(), id, uid, e->getPid());
-                delete e;
+            if (e->getUid() == caller_uid) {
+                it = erase(it);
                 pruneRows--;
                 if (pruneRows == 0) {
                     break;
@@ -283,6 +273,7 @@
     }
 
     // prune by worst offender by uid
+    bool hasBlacklist = mPrune.naughty();
     while (pruneRows > 0) {
         // recalculate the worst offender on every batched pass
         uid_t worst = (uid_t) -1;
@@ -290,24 +281,28 @@
         size_t second_worst_sizes = 0;
 
         if ((id != LOG_ID_CRASH) && mPrune.worstUidEnabled()) {
-            LidStatistics &l = stats.id(id);
-            l.sort();
-            UidStatisticsCollection::iterator iu = l.begin();
-            if (iu != l.end()) {
-                UidStatistics *u = *iu;
-                worst = u->getUid();
-                worst_sizes = u->sizes();
-                if (++iu != l.end()) {
-                    second_worst_sizes = (*iu)->sizes();
+            const UidEntry **sorted = stats.sort(2, id);
+
+            if (sorted) {
+                if (sorted[0] && sorted[1]) {
+                    worst = sorted[0]->getKey();
+                    worst_sizes = sorted[0]->getSizes();
+                    second_worst_sizes = sorted[1]->getSizes();
                 }
+                delete [] sorted;
             }
         }
 
+        // skip if we have neither worst nor naughty filters
+        if ((worst == (uid_t) -1) && !hasBlacklist) {
+            break;
+        }
+
         bool kick = false;
         for(it = mLogElements.begin(); it != mLogElements.end();) {
             LogBufferElement *e = *it;
 
-            if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+            if (oldest && (oldest->mStart <= e->getSequence())) {
                 break;
             }
 
@@ -318,24 +313,28 @@
 
             uid_t uid = e->getUid();
 
-            if ((uid == worst) || mPrune.naughty(e)) { // Worst or BlackListed
-                it = mLogElements.erase(it);
-                unsigned short len = e->getMsgLen();
-                stats.subtract(len, id, uid, e->getPid());
-                delete e;
-                pruneRows--;
-                if (uid == worst) {
-                    kick = true;
-                    if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) {
-                        break;
-                    }
-                    worst_sizes -= len;
-                } else if (pruneRows == 0) {
-                    break;
-                }
-            } else {
+            // !Worst and !BlackListed?
+            if ((uid != worst) && (!hasBlacklist || !mPrune.naughty(e))) {
                 ++it;
+                continue;
             }
+
+            unsigned short len = e->getMsgLen();
+            it = erase(it);
+            pruneRows--;
+            if (pruneRows == 0) {
+                break;
+            }
+
+            if (uid != worst) {
+                continue;
+            }
+
+            kick = true;
+            if (worst_sizes < second_worst_sizes) {
+                break;
+            }
+            worst_sizes -= len;
         }
 
         if (!kick || !mPrune.worstUidEnabled()) {
@@ -344,58 +343,63 @@
     }
 
     bool whitelist = false;
+    bool hasWhitelist = mPrune.nice();
     it = mLogElements.begin();
     while((pruneRows > 0) && (it != mLogElements.end())) {
         LogBufferElement *e = *it;
-        if (e->getLogId() == id) {
-            if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
-                if (!whitelist) {
-                    if (stats.sizes(id) > (2 * log_buffer_size(id))) {
-                        // kick a misbehaving log reader client off the island
-                        oldest->release_Locked();
-                    } else {
-                        oldest->triggerSkip_Locked(id, pruneRows);
-                    }
-                }
+
+        if (e->getLogId() != id) {
+            it++;
+            continue;
+        }
+
+        if (oldest && (oldest->mStart <= e->getSequence())) {
+            if (whitelist) {
                 break;
             }
 
-            if (mPrune.nice(e)) { // WhiteListed
-                whitelist = true;
-                it++;
-                continue;
+            if (stats.sizes(id) > (2 * log_buffer_size(id))) {
+                // kick a misbehaving log reader client off the island
+                oldest->release_Locked();
+            } else {
+                oldest->triggerSkip_Locked(id, pruneRows);
             }
-
-            it = mLogElements.erase(it);
-            stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
-            delete e;
-            pruneRows--;
-        } else {
-            it++;
+            break;
         }
+
+        if (hasWhitelist && mPrune.nice(e)) { // WhiteListed
+            whitelist = true;
+            it++;
+            continue;
+        }
+
+        it = erase(it);
+        pruneRows--;
     }
 
+    // Do not save the whitelist if we are reader range limited
     if (whitelist && (pruneRows > 0)) {
         it = mLogElements.begin();
         while((it != mLogElements.end()) && (pruneRows > 0)) {
             LogBufferElement *e = *it;
-            if (e->getLogId() == id) {
-                if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
-                    if (stats.sizes(id) > (2 * log_buffer_size(id))) {
-                        // kick a misbehaving log reader client off the island
-                        oldest->release_Locked();
-                    } else {
-                        oldest->triggerSkip_Locked(id, pruneRows);
-                    }
-                    break;
-                }
-                it = mLogElements.erase(it);
-                stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
-                delete e;
-                pruneRows--;
-            } else {
-                it++;
+
+            if (e->getLogId() != id) {
+                ++it;
+                continue;
             }
+
+            if (oldest && (oldest->mStart <= e->getSequence())) {
+                if (stats.sizes(id) > (2 * log_buffer_size(id))) {
+                    // kick a misbehaving log reader client off the island
+                    oldest->release_Locked();
+                } else {
+                    oldest->triggerSkip_Locked(id, pruneRows);
+                }
+                break;
+            }
+
+            it = erase(it);
+            pruneRows--;
         }
     }
 
@@ -437,16 +441,16 @@
     return retval;
 }
 
-log_time LogBuffer::flushTo(
-        SocketClient *reader, const log_time start, bool privileged,
-        bool (*filter)(const LogBufferElement *element, void *arg), void *arg) {
+uint64_t LogBuffer::flushTo(
+        SocketClient *reader, const uint64_t start, bool privileged,
+        int (*filter)(const LogBufferElement *element, void *arg), void *arg) {
     LogBufferElementCollection::iterator it;
-    log_time max = start;
+    uint64_t max = start;
     uid_t uid = reader->getUid();
 
     pthread_mutex_lock(&mLogElementsLock);
 
-    if (start == LogTimeEntry::EPOCH) {
+    if (start <= 1) {
         // client wants to start from the beginning
         it = mLogElements.begin();
     } else {
@@ -455,7 +459,7 @@
         for (it = mLogElements.end(); it != mLogElements.begin(); /* do nothing */) {
             --it;
             LogBufferElement *element = *it;
-            if (element->getMonotonicTime() <= start) {
+            if (element->getSequence() <= start) {
                 it++;
                 break;
             }
@@ -469,13 +473,19 @@
             continue;
         }
 
-        if (element->getMonotonicTime() <= start) {
+        if (element->getSequence() <= start) {
             continue;
         }
 
         // NB: calling out to another object with mLogElementsLock held (safe)
-        if (filter && !(*filter)(element, arg)) {
-            continue;
+        if (filter) {
+            int ret = (*filter)(element, arg);
+            if (ret == false) {
+                continue;
+            }
+            if (ret != true) {
+                break;
+            }
         }
 
         pthread_mutex_unlock(&mLogElementsLock);
@@ -495,22 +505,9 @@
 }
 
 void LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) {
-    log_time oldest(CLOCK_MONOTONIC);
-
     pthread_mutex_lock(&mLogElementsLock);
 
-    // Find oldest element in the log(s)
-    LogBufferElementCollection::iterator it;
-    for (it = mLogElements.begin(); it != mLogElements.end(); ++it) {
-        LogBufferElement *element = *it;
-
-        if ((logMask & (1 << element->getLogId()))) {
-            oldest = element->getMonotonicTime();
-            break;
-        }
-    }
-
-    stats.format(strp, uid, logMask, oldest);
+    stats.format(strp, uid, logMask);
 
     pthread_mutex_unlock(&mLogElementsLock);
 }
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 879baea..a29e015 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -37,7 +37,6 @@
     pthread_mutex_t mLogElementsLock;
 
     LogStatistics stats;
-    bool dgramQlenStatistics;
 
     PruneList mPrune;
 
@@ -47,13 +46,14 @@
     LastLogTimes &mTimes;
 
     LogBuffer(LastLogTimes *times);
+    void init();
 
     void log(log_id_t log_id, log_time realtime,
              uid_t uid, pid_t pid, pid_t tid,
              const char *msg, unsigned short len);
-    log_time flushTo(SocketClient *writer, const log_time start,
+    uint64_t flushTo(SocketClient *writer, const uint64_t start,
                      bool privileged,
-                     bool (*filter)(const LogBufferElement *element, void *arg) = NULL,
+                     int (*filter)(const LogBufferElement *element, void *arg) = NULL,
                      void *arg = NULL);
 
     void clear(log_id_t id, uid_t uid = AID_ROOT);
@@ -63,11 +63,6 @@
     // *strp uses malloc, use free to release.
     void formatStatistics(char **strp, uid_t uid, unsigned int logMask);
 
-    void enableDgramQlenStatistics() {
-        stats.enableDgramQlenStatistics();
-        dgramQlenStatistics = true;
-    }
-
     void enableStatistics() {
         stats.enableStatistics();
     }
@@ -83,7 +78,7 @@
 private:
     void maybePrune(log_id_t id);
     void prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT);
-
+    LogBufferElementCollection::iterator erase(LogBufferElementCollection::iterator it);
 };
 
 #endif // _LOGD_LOG_BUFFER_H__
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index d959ceb..5e780b5 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -24,7 +24,8 @@
 #include "LogBufferElement.h"
 #include "LogReader.h"
 
-const log_time LogBufferElement::FLUSH_ERROR((uint32_t)0, (uint32_t)0);
+const uint64_t LogBufferElement::FLUSH_ERROR(0);
+atomic_int_fast64_t LogBufferElement::sequence;
 
 LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
                                    uid_t uid, pid_t pid, pid_t tid,
@@ -34,7 +35,7 @@
         , mPid(pid)
         , mTid(tid)
         , mMsgLen(len)
-        , mMonotonicTime(CLOCK_MONOTONIC)
+        , mSequence(sequence.fetch_add(1, memory_order_relaxed))
         , mRealTime(realtime) {
     mMsg = new char[len];
     memcpy(mMsg, msg, len);
@@ -44,7 +45,7 @@
     delete [] mMsg;
 }
 
-log_time LogBufferElement::flushTo(SocketClient *reader) {
+uint64_t LogBufferElement::flushTo(SocketClient *reader) {
     struct logger_entry_v3 entry;
     memset(&entry, 0, sizeof(struct logger_entry_v3));
     entry.hdr_size = sizeof(struct logger_entry_v3);
@@ -64,5 +65,5 @@
         return FLUSH_ERROR;
     }
 
-    return mMonotonicTime;
+    return mSequence;
 }
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index fdca973..0628d3e 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -17,7 +17,9 @@
 #ifndef _LOGD_LOG_BUFFER_ELEMENT_H__
 #define _LOGD_LOG_BUFFER_ELEMENT_H__
 
+#include <stdatomic.h>
 #include <sys/types.h>
+
 #include <sysutils/SocketClient.h>
 #include <log/log.h>
 #include <log/log_read.h>
@@ -29,8 +31,9 @@
     const pid_t mTid;
     char *mMsg;
     const unsigned short mMsgLen;
-    const log_time mMonotonicTime;
+    const uint64_t mSequence;
     const log_time mRealTime;
+    static atomic_int_fast64_t sequence;
 
 public:
     LogBufferElement(log_id_t log_id, log_time realtime,
@@ -43,11 +46,12 @@
     pid_t getPid(void) const { return mPid; }
     pid_t getTid(void) const { return mTid; }
     unsigned short getMsgLen() const { return mMsgLen; }
-    log_time getMonotonicTime(void) const { return mMonotonicTime; }
+    uint64_t getSequence(void) const { return mSequence; }
+    static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); }
     log_time getRealTime(void) const { return mRealTime; }
 
-    static const log_time FLUSH_ERROR;
-    log_time flushTo(SocketClient *writer);
+    static const uint64_t FLUSH_ERROR;
+    uint64_t flushTo(SocketClient *writer);
 };
 
 #endif
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
index e4c138e..b78c0e0 100644
--- a/logd/LogCommand.cpp
+++ b/logd/LogCommand.cpp
@@ -17,6 +17,7 @@
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include <private/android_filesystem_config.h>
 
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 26df087..f7df275 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -100,50 +100,51 @@
         nonBlock = true;
     }
 
-    // Convert realtime to monotonic time
-    if (start == log_time::EPOCH) {
-        start = LogTimeEntry::EPOCH;
-    } else {
+    uint64_t sequence = 1;
+    // Convert realtime to sequence number
+    if (start != log_time::EPOCH) {
         class LogFindStart {
             const pid_t mPid;
             const unsigned mLogMask;
             bool startTimeSet;
             log_time &start;
-            log_time last;
+            uint64_t &sequence;
+            uint64_t last;
 
         public:
-            LogFindStart(unsigned logMask, pid_t pid, log_time &start)
+            LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence)
                     : mPid(pid)
                     , mLogMask(logMask)
                     , startTimeSet(false)
                     , start(start)
-                    , last(LogTimeEntry::EPOCH)
+                    , sequence(sequence)
+                    , last(sequence)
             { }
 
-            static bool callback(const LogBufferElement *element, void *obj) {
+            static int callback(const LogBufferElement *element, void *obj) {
                 LogFindStart *me = reinterpret_cast<LogFindStart *>(obj);
-                if (!me->startTimeSet
-                        && (!me->mPid || (me->mPid == element->getPid()))
+                if ((!me->mPid || (me->mPid == element->getPid()))
                         && (me->mLogMask & (1 << element->getLogId()))) {
                     if (me->start == element->getRealTime()) {
-                        me->start = element->getMonotonicTime();
+                        me->sequence = element->getSequence();
                         me->startTimeSet = true;
+                        return -1;
                     } else {
                         if (me->start < element->getRealTime()) {
-                            me->start = me->last;
+                            me->sequence = me->last;
                             me->startTimeSet = true;
+                            return -1;
                         }
-                        me->last = element->getMonotonicTime();
+                        me->last = element->getSequence();
                     }
                 }
                 return false;
             }
 
             bool found() { return startTimeSet; }
-        } logFindStart(logMask, pid, start);
+        } logFindStart(logMask, pid, start, sequence);
 
-        logbuf().flushTo(cli, LogTimeEntry::EPOCH,
-                         FlushCommand::hasReadLogs(cli),
+        logbuf().flushTo(cli, sequence, FlushCommand::hasReadLogs(cli),
                          logFindStart.callback, &logFindStart);
 
         if (!logFindStart.found()) {
@@ -151,12 +152,11 @@
                 doSocketDelete(cli);
                 return false;
             }
-            log_time now(CLOCK_MONOTONIC);
-            start = now;
+            sequence = LogBufferElement::getCurrentSequence();
         }
     }
 
-    FlushCommand command(*this, nonBlock, tail, logMask, pid, start);
+    FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence);
     command.runSocketCommand(cli);
     return true;
 }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 53036e6..accd660 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
+#include <algorithm> // std::max
 #include <fcntl.h>
-#include <malloc.h>
-#include <stdarg.h>
-#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
 #include <log/logger.h>
 #include <private/android_filesystem_config.h>
@@ -25,80 +27,21 @@
 
 #include "LogStatistics.h"
 
-PidStatistics::PidStatistics(pid_t pid, char *name)
-        : pid(pid)
-        , mSizesTotal(0)
-        , mElementsTotal(0)
-        , mSizes(0)
-        , mElements(0)
-        , name(name)
-        , mGone(false)
-{ }
-
-#ifdef DO_NOT_ERROR_IF_PIDSTATISTICS_USES_A_COPY_CONSTRUCTOR
-PidStatistics::PidStatistics(const PidStatistics &copy)
-        : pid(copy->pid)
-        , name(copy->name ? strdup(copy->name) : NULL)
-        , mSizesTotal(copy->mSizesTotal)
-        , mElementsTotal(copy->mElementsTotal)
-        , mSizes(copy->mSizes)
-        , mElements(copy->mElements)
-        , mGone(copy->mGone)
-{ }
-#endif
-
-PidStatistics::~PidStatistics() {
-    free(name);
-}
-
-bool PidStatistics::pidGone() {
-    if (mGone || (pid == gone)) {
-        return true;
-    }
-    if (pid == 0) {
-        return false;
-    }
-    if (kill(pid, 0) && (errno != EPERM)) {
-        mGone = true;
-        return true;
-    }
-    return false;
-}
-
-void PidStatistics::setName(char *new_name) {
-    free(name);
-    name = new_name;
-}
-
-void PidStatistics::add(unsigned short size) {
-    mSizesTotal += size;
-    ++mElementsTotal;
-    mSizes += size;
-    ++mElements;
-}
-
-bool PidStatistics::subtract(unsigned short size) {
-    mSizes -= size;
-    --mElements;
-    return (mElements == 0) && pidGone();
-}
-
-void PidStatistics::addTotal(size_t size, size_t element) {
-    if (pid == gone) {
-        mSizesTotal += size;
-        mElementsTotal += element;
+LogStatistics::LogStatistics() {
+    log_id_for_each(id) {
+        mSizes[id] = 0;
+        mElements[id] = 0;
+        mSizesTotal[id] = 0;
+        mElementsTotal[id] = 0;
     }
 }
 
-// must call free to release return value
-//  If only we could sniff our own logs for:
-//   <time> <pid> <pid> E AndroidRuntime: Process: <name>, PID: <pid>
-//  which debuggerd prints as a process is crashing.
-char *PidStatistics::pidToName(pid_t pid) {
+// caller must own and free character string
+char *LogStatistics::pidToName(pid_t pid) {
     char *retval = NULL;
     if (pid == 0) { // special case from auditd for kernel
         retval = strdup("logd.auditd");
-    } else if (pid != gone) {
+    } else {
         char buffer[512];
         snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
         int fd = open(buffer, O_RDONLY);
@@ -117,418 +60,105 @@
     return retval;
 }
 
-UidStatistics::UidStatistics(uid_t uid)
-        : uid(uid)
-        , mSizes(0)
-        , mElements(0) {
-    Pids.clear();
-}
-
-UidStatistics::~UidStatistics() {
-    PidStatisticsCollection::iterator it;
-    for (it = begin(); it != end();) {
-        delete (*it);
-        it = erase(it);
-    }
-}
-
-void UidStatistics::add(unsigned short size, pid_t pid) {
-    mSizes += size;
-    ++mElements;
-
-    PidStatistics *p = NULL;
-    PidStatisticsCollection::iterator last;
-    PidStatisticsCollection::iterator it;
-    for (last = it = begin(); it != end(); last = it, ++it) {
-        p = *it;
-        if (pid == p->getPid()) {
-            p->add(size);
-            return;
-        }
-    }
-    // insert if the gone entry.
-    bool insert_before_last = (last != it) && p && (p->getPid() == p->gone);
-    p = new PidStatistics(pid, pidToName(pid));
-    if (insert_before_last) {
-        insert(last, p);
-    } else {
-        push_back(p);
-    }
-    p->add(size);
-}
-
-void UidStatistics::subtract(unsigned short size, pid_t pid) {
-    mSizes -= size;
-    --mElements;
-
-    PidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        PidStatistics *p = *it;
-        if (pid == p->getPid()) {
-            if (p->subtract(size)) {
-                size_t szsTotal = p->sizesTotal();
-                size_t elsTotal = p->elementsTotal();
-                delete p;
-                erase(it);
-                it = end();
-                --it;
-                if (it == end()) {
-                    p = new PidStatistics(p->gone);
-                    push_back(p);
-                } else {
-                    p = *it;
-                    if (p->getPid() != p->gone) {
-                        p = new PidStatistics(p->gone);
-                        push_back(p);
-                    }
-                }
-                p->addTotal(szsTotal, elsTotal);
-            }
-            return;
-        }
-    }
-}
-
-void UidStatistics::sort() {
-    for (bool pass = true; pass;) {
-        pass = false;
-        PidStatisticsCollection::iterator it = begin();
-        if (it != end()) {
-            PidStatisticsCollection::iterator lt = it;
-            PidStatistics *l = (*lt);
-            while (++it != end()) {
-                PidStatistics *n = (*it);
-                if ((n->getPid() != n->gone) && (n->sizes() > l->sizes())) {
-                    pass = true;
-                    erase(it);
-                    insert(lt, n);
-                    it = lt;
-                    n = l;
-                }
-                lt = it;
-                l = n;
-            }
-        }
-    }
-}
-
-size_t UidStatistics::sizes(pid_t pid) {
-    if (pid == pid_all) {
-        return sizes();
-    }
-
-    PidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        PidStatistics *p = *it;
-        if (pid == p->getPid()) {
-            return p->sizes();
-        }
-    }
-    return 0;
-}
-
-size_t UidStatistics::elements(pid_t pid) {
-    if (pid == pid_all) {
-        return elements();
-    }
-
-    PidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        PidStatistics *p = *it;
-        if (pid == p->getPid()) {
-            return p->elements();
-        }
-    }
-    return 0;
-}
-
-size_t UidStatistics::sizesTotal(pid_t pid) {
-    size_t sizes = 0;
-    PidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        PidStatistics *p = *it;
-        if ((pid == pid_all) || (pid == p->getPid())) {
-            sizes += p->sizesTotal();
-        }
-    }
-    return sizes;
-}
-
-size_t UidStatistics::elementsTotal(pid_t pid) {
-    size_t elements = 0;
-    PidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        PidStatistics *p = *it;
-        if ((pid == pid_all) || (pid == p->getPid())) {
-            elements += p->elementsTotal();
-        }
-    }
-    return elements;
-}
-
-LidStatistics::LidStatistics() {
-    Uids.clear();
-}
-
-LidStatistics::~LidStatistics() {
-    UidStatisticsCollection::iterator it;
-    for (it = begin(); it != end();) {
-        delete (*it);
-        it = Uids.erase(it);
-    }
-}
-
-void LidStatistics::add(unsigned short size, uid_t uid, pid_t pid) {
-    UidStatistics *u;
-    UidStatisticsCollection::iterator it;
-    UidStatisticsCollection::iterator last;
-
-    if (uid == (uid_t) -1) { // init
-        uid = (uid_t) AID_ROOT;
-    }
-
-    for (last = it = begin(); it != end(); last = it, ++it) {
-        u = *it;
-        if (uid == u->getUid()) {
-            u->add(size, pid);
-            if ((last != it) && ((*last)->sizesTotal() < u->sizesTotal())) {
-                Uids.erase(it);
-                Uids.insert(last, u);
-            }
-            return;
-        }
-    }
-    u = new UidStatistics(uid);
-    if ((last != it) && ((*last)->sizesTotal() < (size_t) size)) {
-        Uids.insert(last, u);
-    } else {
-        Uids.push_back(u);
-    }
-    u->add(size, pid);
-}
-
-void LidStatistics::subtract(unsigned short size, uid_t uid, pid_t pid) {
-    if (uid == (uid_t) -1) { // init
-        uid = (uid_t) AID_ROOT;
-    }
-
-    UidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        UidStatistics *u = *it;
-        if (uid == u->getUid()) {
-            u->subtract(size, pid);
-            return;
-        }
-    }
-}
-
-void LidStatistics::sort() {
-    for (bool pass = true; pass;) {
-        pass = false;
-        UidStatisticsCollection::iterator it = begin();
-        if (it != end()) {
-            UidStatisticsCollection::iterator lt = it;
-            UidStatistics *l = (*lt);
-            while (++it != end()) {
-                UidStatistics *n = (*it);
-                if (n->sizes() > l->sizes()) {
-                    pass = true;
-                    Uids.erase(it);
-                    Uids.insert(lt, n);
-                    it = lt;
-                    n = l;
-                }
-                lt = it;
-                l = n;
-            }
-        }
-    }
-}
-
-size_t LidStatistics::sizes(uid_t uid, pid_t pid) {
-    size_t sizes = 0;
-    UidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        UidStatistics *u = *it;
-        if ((uid == uid_all) || (uid == u->getUid())) {
-            sizes += u->sizes(pid);
-        }
-    }
-    return sizes;
-}
-
-size_t LidStatistics::elements(uid_t uid, pid_t pid) {
-    size_t elements = 0;
-    UidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        UidStatistics *u = *it;
-        if ((uid == uid_all) || (uid == u->getUid())) {
-            elements += u->elements(pid);
-        }
-    }
-    return elements;
-}
-
-size_t LidStatistics::sizesTotal(uid_t uid, pid_t pid) {
-    size_t sizes = 0;
-    UidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        UidStatistics *u = *it;
-        if ((uid == uid_all) || (uid == u->getUid())) {
-            sizes += u->sizesTotal(pid);
-        }
-    }
-    return sizes;
-}
-
-size_t LidStatistics::elementsTotal(uid_t uid, pid_t pid) {
-    size_t elements = 0;
-    UidStatisticsCollection::iterator it;
-    for (it = begin(); it != end(); ++it) {
-        UidStatistics *u = *it;
-        if ((uid == uid_all) || (uid == u->getUid())) {
-            elements += u->elementsTotal(pid);
-        }
-    }
-    return elements;
-}
-
-LogStatistics::LogStatistics()
-        : mStatistics(false)
-        , dgramQlenStatistics(false)
-        , start(CLOCK_MONOTONIC) {
-    log_id_for_each(i) {
-        mSizes[i] = 0;
-        mElements[i] = 0;
-    }
-
-    for(unsigned short bucket = 0; dgramQlen(bucket); ++bucket) {
-        mMinimum[bucket].tv_sec = mMinimum[bucket].tv_sec_max;
-        mMinimum[bucket].tv_nsec = mMinimum[bucket].tv_nsec_max;
-    }
-}
-
-//   Each bucket below represents a dgramQlen of log messages. By
-//   finding the minimum period of time from start to finish
-//   of each dgramQlen, we can get a performance expectation for
-//   the user space logger. The net result is that the period
-//   of time divided by the dgramQlen will give us the average time
-//   between log messages; at the point where the average time
-//   is greater than the throughput capability of the logger
-//   we will not longer require the benefits of the FIFO formed
-//   by max_dgram_qlen. We will also expect to see a very visible
-//   knee in the average time between log messages at this point,
-//   so we do not necessarily have to compare the rate against the
-//   measured performance (BM_log_maximum_retry) of the logger.
-//
-//   for example (reformatted):
-//
-//       Minimum time between log events per dgramQlen:
-//       1   2   3   5   10  20  30  50  100  200 300 400 500 600
-//       5u2 12u 13u 15u 16u 27u 30u 36u 407u 3m1 3m3 3m9 3m9 5m5
-//
-//   demonstrates a clear knee rising at 100, so this means that for this
-//   case max_dgram_qlen = 100 would be more than sufficient to handle the
-//   worst that the system could stuff into the logger. The
-//   BM_log_maximum_retry performance (derated by the log collection) on the
-//   same system was 33.2us so we would almost be fine with max_dgram_qlen = 50.
-//   BM_log_maxumum_retry with statistics off is roughly 20us, so
-//   max_dgram_qlen = 20 would work. We will be more than willing to have
-//   a large engineering margin so the rule of thumb that lead us to 100 is
-//   fine.
-//
-// bucket dgramQlen are tuned for /proc/sys/net/unix/max_dgram_qlen = 300
-const unsigned short LogStatistics::mBuckets[] = {
-    1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 400, 500, 600
-};
-
-unsigned short LogStatistics::dgramQlen(unsigned short bucket) {
-    if (bucket >= sizeof(mBuckets) / sizeof(mBuckets[0])) {
-        return 0;
-    }
-    return mBuckets[bucket];
-}
-
-unsigned long long LogStatistics::minimum(unsigned short bucket) {
-    if (mMinimum[bucket].tv_sec == mMinimum[bucket].tv_sec_max) {
-        return 0;
-    }
-    return mMinimum[bucket].nsec();
-}
-
-void LogStatistics::recordDiff(log_time diff, unsigned short bucket) {
-    if ((diff.tv_sec || diff.tv_nsec) && (mMinimum[bucket] > diff)) {
-        mMinimum[bucket] = diff;
-    }
-}
-
-void LogStatistics::add(unsigned short size,
-                        log_id_t log_id, uid_t uid, pid_t pid) {
+void LogStatistics::add(LogBufferElement *e) {
+    log_id_t log_id = e->getLogId();
+    unsigned short size = e->getMsgLen();
     mSizes[log_id] += size;
     ++mElements[log_id];
-    if (!mStatistics) {
-        return;
+
+    uid_t uid = e->getUid();
+    android::hash_t hash = android::hash_type(uid);
+    uidTable_t &table = uidTable[log_id];
+    ssize_t index = table.find(-1, hash, uid);
+    if (index == -1) {
+        UidEntry initEntry(uid);
+        initEntry.add(size);
+        table.add(hash, initEntry);
+    } else {
+        UidEntry &entry = table.editEntryAt(index);
+        entry.add(size);
     }
-    id(log_id).add(size, uid, pid);
+
+    mSizesTotal[log_id] += size;
+    ++mElementsTotal[log_id];
 }
 
-void LogStatistics::subtract(unsigned short size,
-                             log_id_t log_id, uid_t uid, pid_t pid) {
+void LogStatistics::subtract(LogBufferElement *e) {
+    log_id_t log_id = e->getLogId();
+    unsigned short size = e->getMsgLen();
     mSizes[log_id] -= size;
     --mElements[log_id];
-    if (!mStatistics) {
-        return;
+
+    uid_t uid = e->getUid();
+    android::hash_t hash = android::hash_type(uid);
+    uidTable_t &table = uidTable[log_id];
+    ssize_t index = table.find(-1, hash, uid);
+    if (index != -1) {
+        UidEntry &entry = table.editEntryAt(index);
+        if (entry.subtract(size)) {
+            table.removeAt(index);
+        }
     }
-    id(log_id).subtract(size, uid, pid);
 }
 
-size_t LogStatistics::sizes(log_id_t log_id, uid_t uid, pid_t pid) {
-    if (log_id != log_id_all) {
-        return id(log_id).sizes(uid, pid);
+// caller must own and delete UidEntry array
+const UidEntry **LogStatistics::sort(size_t n, log_id id) {
+    if (!n) {
+        return NULL;
     }
-    size_t sizes = 0;
-    log_id_for_each(i) {
-        sizes += id(i).sizes(uid, pid);
+
+    const UidEntry **retval = new const UidEntry* [n];
+    memset(retval, 0, sizeof(*retval) * n);
+
+    uidTable_t &table = uidTable[id];
+    ssize_t index = -1;
+    while ((index = table.next(index)) >= 0) {
+        const UidEntry &entry = table.entryAt(index);
+        size_t s = entry.getSizes();
+        ssize_t i = n - 1;
+        while ((!retval[i] || (s > retval[i]->getSizes())) && (--i >= 0));
+        if (++i < (ssize_t)n) {
+            size_t b = n - i - 1;
+            if (b) {
+                memmove(&retval[i+1], &retval[i], b * sizeof(retval[0]));
+            }
+            retval[i] = &entry;
+        }
     }
-    return sizes;
+    return retval;
 }
 
-size_t LogStatistics::elements(log_id_t log_id, uid_t uid, pid_t pid) {
-    if (log_id != log_id_all) {
-        return id(log_id).elements(uid, pid);
+// caller must own and free character string
+char *LogStatistics::uidToName(uid_t uid) {
+    // Local hard coded favourites
+    if (uid == AID_LOGD) {
+        return strdup("auditd");
     }
-    size_t elements = 0;
-    log_id_for_each(i) {
-        elements += id(i).elements(uid, pid);
+
+    // Android hard coded
+    const struct android_id_info *info = android_ids;
+
+    for (size_t i = 0; i < android_id_count; ++i) {
+        if (info->aid == uid) {
+            return strdup(info->name);
+        }
+        ++info;
     }
-    return elements;
+
+    // No one
+    return NULL;
 }
 
-size_t LogStatistics::sizesTotal(log_id_t log_id, uid_t uid, pid_t pid) {
-    if (log_id != log_id_all) {
-        return id(log_id).sizesTotal(uid, pid);
-    }
-    size_t sizes = 0;
-    log_id_for_each(i) {
-        sizes += id(i).sizesTotal(uid, pid);
-    }
-    return sizes;
+static void format_line(android::String8 &output,
+        android::String8 &name, android::String8 &size) {
+    static const size_t total_len = 70;
+
+    output.appendFormat("%s%*s\n", name.string(),
+        (int)std::max(total_len - name.length() - 1, size.length() + 1),
+        size.string());
 }
 
-size_t LogStatistics::elementsTotal(log_id_t log_id, uid_t uid, pid_t pid) {
-    if (log_id != log_id_all) {
-        return id(log_id).elementsTotal(uid, pid);
-    }
-    size_t elements = 0;
-    log_id_for_each(i) {
-        elements += id(i).elementsTotal(uid, pid);
-    }
-    return elements;
-}
-
-void LogStatistics::format(char **buf,
-                           uid_t uid, unsigned int logMask, log_time oldest) {
-    static const unsigned short spaces_current = 13;
+void LogStatistics::format(char **buf, uid_t uid, unsigned int logMask) {
     static const unsigned short spaces_total = 19;
 
     if (*buf) {
@@ -536,417 +166,142 @@
         *buf = NULL;
     }
 
-    android::String8 string("        span -> size/num");
-    size_t oldLength;
-    short spaces = 2;
+    // Report on total logging, current and for all time
 
-    log_id_for_each(i) {
-        if (!(logMask & (1 << i))) {
+    android::String8 output("size/num");
+    size_t oldLength;
+    short spaces = 1;
+
+    log_id_for_each(id) {
+        if (!(logMask & (1 << id))) {
             continue;
         }
-        oldLength = string.length();
+        oldLength = output.length();
         if (spaces < 0) {
             spaces = 0;
         }
-        string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i));
-        spaces += spaces_total + oldLength - string.length();
-
-        LidStatistics &l = id(i);
-        l.sort();
-
-        UidStatisticsCollection::iterator iu;
-        for (iu = l.begin(); iu != l.end(); ++iu) {
-            (*iu)->sort();
-        }
+        output.appendFormat("%*s%s", spaces, "", android_log_id_to_name(id));
+        spaces += spaces_total + oldLength - output.length();
     }
 
-    spaces = 1;
-    log_time t(CLOCK_MONOTONIC);
-    unsigned long long d;
-    if (mStatistics) {
-        d = t.nsec() - start.nsec();
-        string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu",
-                  d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
-                  (d / NS_PER_SEC) % 60, d % NS_PER_SEC);
+    spaces = 4;
+    output.appendFormat("\nTotal");
 
-        log_id_for_each(i) {
-            if (!(logMask & (1 << i))) {
-                continue;
-            }
-            oldLength = string.length();
-            if (spaces < 0) {
-                spaces = 0;
-            }
-            string.appendFormat("%*s%zu/%zu", spaces, "",
-                                sizesTotal(i), elementsTotal(i));
-            spaces += spaces_total + oldLength - string.length();
+    log_id_for_each(id) {
+        if (!(logMask & (1 << id))) {
+            continue;
         }
-        spaces = 1;
+        oldLength = output.length();
+        if (spaces < 0) {
+            spaces = 0;
+        }
+        output.appendFormat("%*s%zu/%zu", spaces, "",
+                            sizesTotal(id), elementsTotal(id));
+        spaces += spaces_total + oldLength - output.length();
     }
 
-    d = t.nsec() - oldest.nsec();
-    string.appendFormat("\nNow%6llu:%02llu:%02llu.%09llu",
-                  d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
-                  (d / NS_PER_SEC) % 60, d % NS_PER_SEC);
+    spaces = 6;
+    output.appendFormat("\nNow");
 
-    log_id_for_each(i) {
-        if (!(logMask & (1 << i))) {
+    log_id_for_each(id) {
+        if (!(logMask & (1 << id))) {
             continue;
         }
 
-        size_t els = elements(i);
+        size_t els = elements(id);
         if (els) {
-            oldLength = string.length();
+            oldLength = output.length();
             if (spaces < 0) {
                 spaces = 0;
             }
-            string.appendFormat("%*s%zu/%zu", spaces, "", sizes(i), els);
-            spaces -= string.length() - oldLength;
+            output.appendFormat("%*s%zu/%zu", spaces, "", sizes(id), els);
+            spaces -= output.length() - oldLength;
         }
         spaces += spaces_total;
     }
 
-    // Construct list of worst spammers by Pid
-    static const unsigned char num_spammers = 10;
-    bool header = false;
+    // Report on Chattiest
 
-    log_id_for_each(i) {
-        if (!(logMask & (1 << i))) {
+    // Chattiest by application (UID)
+    log_id_for_each(id) {
+        if (!(logMask & (1 << id))) {
             continue;
         }
 
-        PidStatisticsCollection pids;
-        pids.clear();
+        static const size_t maximum_sorted_entries = 32;
+        const UidEntry **sorted = sort(maximum_sorted_entries, id);
 
-        LidStatistics &l = id(i);
-        UidStatisticsCollection::iterator iu;
-        for (iu = l.begin(); iu != l.end(); ++iu) {
-            UidStatistics &u = *(*iu);
-            PidStatisticsCollection::iterator ip;
-            for (ip = u.begin(); ip != u.end(); ++ip) {
-                PidStatistics *p = (*ip);
-                if (p->getPid() == p->gone) {
-                    break;
-                }
-
-                size_t mySizes = p->sizes();
-
-                PidStatisticsCollection::iterator q;
-                unsigned char num = 0;
-                for (q = pids.begin(); q != pids.end(); ++q) {
-                    if (mySizes > (*q)->sizes()) {
-                        pids.insert(q, p);
-                        break;
-                    }
-                    // do we need to traverse deeper in the list?
-                    if (++num > num_spammers) {
-                        break;
-                    }
-                }
-                if (q == pids.end()) {
-                   pids.push_back(p);
-                }
-            }
+        if (!sorted) {
+            continue;
         }
 
-        size_t threshold = sizes(i);
-        if (threshold < 65536) {
-            threshold = 65536;
-        }
-        threshold /= 100;
+        bool print = false;
+        for(size_t index = 0; index < maximum_sorted_entries; ++index) {
+            const UidEntry *entry = sorted[index];
 
-        PidStatisticsCollection::iterator pt = pids.begin();
-
-        for(int line = 0;
-                (pt != pids.end()) && (line < num_spammers);
-                ++line, pt = pids.erase(pt)) {
-            PidStatistics *p = *pt;
-
-            size_t sizes = p->sizes();
-            if (sizes < threshold) {
+            if (!entry) {
                 break;
             }
 
-            char *name = p->getName();
-            pid_t pid = p->getPid();
-            if (!name || !*name) {
-                name = pidToName(pid);
-                if (name) {
-                    if (*name) {
-                        p->setName(name);
-                    } else {
-                        free(name);
-                        name = NULL;
-                    }
-                }
+            size_t sizes = entry->getSizes();
+            if (sizes < (65536/100)) {
+                break;
             }
 
-            if (!header) {
-                string.appendFormat("\n\nChattiest clients:\n"
-                                    "log id %-*s PID[?] name",
-                                    spaces_total, "size/total");
-                header = true;
+            uid_t u = entry->getKey();
+            if ((uid != AID_ROOT) && (u != uid)) {
+                continue;
             }
 
-            size_t sizesTotal = p->sizesTotal();
-
-            android::String8 sz("");
-            if (sizes == sizesTotal) {
-                sz.appendFormat("%zu", sizes);
-            } else {
-                sz.appendFormat("%zu/%zu", sizes, sizesTotal);
-            }
-
-            android::String8 pd("");
-            pd.appendFormat("%u%c", pid, p->pidGone() ? '?' : ' ');
-
-            string.appendFormat("\n%-7s%-*s %-7s%s",
-                                line ? "" : android_log_id_to_name(i),
-                                spaces_total, sz.string(), pd.string(),
-                                name ? name : "");
-        }
-
-        pids.clear();
-    }
-
-    if (dgramQlenStatistics) {
-        const unsigned short spaces_time = 6;
-        const unsigned long long max_seconds = 100000;
-        spaces = 0;
-        string.append("\n\nMinimum time between log events per max_dgram_qlen:\n");
-        for(unsigned short i = 0; dgramQlen(i); ++i) {
-            oldLength = string.length();
-            if (spaces < 0) {
-                spaces = 0;
-            }
-            string.appendFormat("%*s%u", spaces, "", dgramQlen(i));
-            spaces += spaces_time + oldLength - string.length();
-        }
-        string.append("\n");
-        spaces = 0;
-        unsigned short n;
-        for(unsigned short i = 0; (n = dgramQlen(i)); ++i) {
-            unsigned long long duration = minimum(i);
-            if (duration) {
-                duration /= n;
-                if (duration >= (NS_PER_SEC * max_seconds)) {
-                    duration = NS_PER_SEC * (max_seconds - 1);
-                }
-                oldLength = string.length();
-                if (spaces < 0) {
-                    spaces = 0;
-                }
-                string.appendFormat("%*s", spaces, "");
-                if (duration >= (NS_PER_SEC * 10)) {
-                    string.appendFormat("%llu",
-                        (duration + (NS_PER_SEC / 2))
-                            / NS_PER_SEC);
-                } else if (duration >= (NS_PER_SEC / (1000 / 10))) {
-                    string.appendFormat("%llum",
-                        (duration + (NS_PER_SEC / 2 / 1000))
-                            / (NS_PER_SEC / 1000));
-                } else if (duration >= (NS_PER_SEC / (1000000 / 10))) {
-                    string.appendFormat("%lluu",
-                        (duration + (NS_PER_SEC / 2 / 1000000))
-                            / (NS_PER_SEC / 1000000));
+            if (!print) {
+                if (uid == AID_ROOT) {
+                    output.appendFormat(
+                        "\n\nChattiest UIDs in %s:\n",
+                        android_log_id_to_name(id));
+                    android::String8 name("UID");
+                    android::String8 size("Size");
+                    format_line(output, name, size);
                 } else {
-                    string.appendFormat("%llun", duration);
+                    output.appendFormat(
+                        "\n\nLogging for your UID in %s:\n",
+                        android_log_id_to_name(id));
                 }
-                spaces -= string.length() - oldLength;
+                print = true;
             }
-            spaces += spaces_time;
+
+            android::String8 name("");
+            name.appendFormat("%u", u);
+            char *n = uidToName(u);
+            if (n) {
+                name.appendFormat("%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", n);
+                free(n);
+            }
+
+            android::String8 size("");
+            size.appendFormat("%zu", sizes);
+
+            format_line(output, name, size);
         }
+
+        delete [] sorted;
     }
 
-    log_id_for_each(i) {
-        if (!(logMask & (1 << i))) {
-            continue;
-        }
-
-        header = false;
-        bool first = true;
-
-        UidStatisticsCollection::iterator ut;
-        for(ut = id(i).begin(); ut != id(i).end(); ++ut) {
-            UidStatistics *up = *ut;
-            if ((uid != AID_ROOT) && (uid != up->getUid())) {
-                continue;
-            }
-
-            PidStatisticsCollection::iterator pt = up->begin();
-            if (pt == up->end()) {
-                continue;
-            }
-
-            android::String8 intermediate;
-
-            if (!header) {
-                // header below tuned to match spaces_total and spaces_current
-                spaces = 0;
-                intermediate = string.format("%s: UID/PID Total size/num",
-                                             android_log_id_to_name(i));
-                string.appendFormat("\n\n%-31sNow          "
-                                         "UID/PID[?]  Total              Now",
-                                    intermediate.string());
-                intermediate.clear();
-                header = true;
-            }
-
-            bool oneline = ++pt == up->end();
-            --pt;
-
-            if (!oneline) {
-                first = true;
-            } else if (!first && (spaces > 0)) {
-                string.appendFormat("%*s", spaces, "");
-            }
-            spaces = 0;
-
-            uid_t u = up->getUid();
-            PidStatistics *pp = *pt;
-            pid_t p = pp->getPid();
-
-            if (!oneline) {
-                intermediate = string.format("%d", u);
-            } else if (p == PidStatistics::gone) {
-                intermediate = string.format("%d/?", u);
-            } else if (pp->pidGone()) {
-                intermediate = string.format("%d/%d?", u, p);
-            } else {
-                intermediate = string.format("%d/%d", u, p);
-            }
-            string.appendFormat(first ? "\n%-12s" : "%-12s",
-                                intermediate.string());
-            intermediate.clear();
-
-            size_t elsTotal = up->elementsTotal();
-            oldLength = string.length();
-            string.appendFormat("%zu/%zu", up->sizesTotal(), elsTotal);
-            spaces += spaces_total + oldLength - string.length();
-
-            size_t els = up->elements();
-            if (els == elsTotal) {
-                if (spaces < 0) {
-                    spaces = 0;
-                }
-                string.appendFormat("%*s=", spaces, "");
-                spaces = -1;
-            } else if (els) {
-                oldLength = string.length();
-                if (spaces < 0) {
-                    spaces = 0;
-                }
-                string.appendFormat("%*s%zu/%zu", spaces, "", up->sizes(), els);
-                spaces -= string.length() - oldLength;
-            }
-            spaces += spaces_current;
-
-            first = !first;
-
-            if (oneline) {
-                continue;
-            }
-
-            size_t gone_szs = 0;
-            size_t gone_els = 0;
-
-            for(; pt != up->end(); ++pt) {
-                pp = *pt;
-                p = pp->getPid();
-
-                // If a PID no longer has any current logs, and is not
-                // active anymore, skip & report totals for gone.
-                elsTotal = pp->elementsTotal();
-                size_t szsTotal = pp->sizesTotal();
-                if (p == pp->gone) {
-                    gone_szs += szsTotal;
-                    gone_els += elsTotal;
-                    continue;
-                }
-                els = pp->elements();
-                bool gone = pp->pidGone();
-                if (gone && (els == 0)) {
-                    // ToDo: garbage collection: move this statistical bucket
-                    //       from its current UID/PID to UID/? (races and
-                    //       wrap around are our achilles heel). Below is
-                    //       merely lipservice to catch PIDs that were still
-                    //       around when the stats were pruned to zero.
-                    gone_szs += szsTotal;
-                    gone_els += elsTotal;
-                    continue;
-                }
-
-                if (!first && (spaces > 0)) {
-                    string.appendFormat("%*s", spaces, "");
-                }
-                spaces = 0;
-
-                intermediate = string.format(gone ? "%d/%d?" : "%d/%d", u, p);
-                string.appendFormat(first ? "\n%-12s" : "%-12s",
-                                    intermediate.string());
-                intermediate.clear();
-
-                oldLength = string.length();
-                string.appendFormat("%zu/%zu", szsTotal, elsTotal);
-                spaces += spaces_total + oldLength - string.length();
-
-                if (els == elsTotal) {
-                    if (spaces < 0) {
-                        spaces = 0;
-                    }
-                    string.appendFormat("%*s=", spaces, "");
-                    spaces = -1;
-                } else if (els) {
-                    oldLength = string.length();
-                    if (spaces < 0) {
-                        spaces = 0;
-                    }
-                    string.appendFormat("%*s%zu/%zu", spaces, "",
-                                        pp->sizes(), els);
-                    spaces -= string.length() - oldLength;
-                }
-                spaces += spaces_current;
-
-                first = !first;
-            }
-
-            if (gone_els) {
-                if (!first && (spaces > 0)) {
-                    string.appendFormat("%*s", spaces, "");
-                }
-
-                intermediate = string.format("%d/?", u);
-                string.appendFormat(first ? "\n%-12s" : "%-12s",
-                                    intermediate.string());
-                intermediate.clear();
-
-                spaces = spaces_total + spaces_current;
-
-                oldLength = string.length();
-                string.appendFormat("%zu/%zu", gone_szs, gone_els);
-                spaces -= string.length() - oldLength;
-
-                first = !first;
-            }
-        }
-    }
-
-    *buf = strdup(string.string());
+    *buf = strdup(output.string());
 }
 
 uid_t LogStatistics::pidToUid(pid_t pid) {
-    log_id_for_each(i) {
-        LidStatistics &l = id(i);
-        UidStatisticsCollection::iterator iu;
-        for (iu = l.begin(); iu != l.end(); ++iu) {
-            UidStatistics &u = *(*iu);
-            PidStatisticsCollection::iterator ip;
-            for (ip = u.begin(); ip != u.end(); ++ip) {
-                if ((*ip)->getPid() == pid) {
-                    return u.getUid();
-                }
+    char buffer[512];
+    snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
+    FILE *fp = fopen(buffer, "r");
+    if (fp) {
+        while (fgets(buffer, sizeof(buffer), fp)) {
+            int uid;
+            if (sscanf(buffer, "Groups: %d", &uid) == 1) {
+                fclose(fp);
+                return uid;
             }
         }
+        fclose(fp);
     }
     return getuid(); // associate this with the logger
 }
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index f6c4329..d5b8762 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -20,180 +20,60 @@
 #include <sys/types.h>
 
 #include <log/log.h>
-#include <log/log_read.h>
-#include <utils/List.h>
+#include <utils/BasicHashtable.h>
+
+#include "LogBufferElement.h"
 
 #define log_id_for_each(i) \
     for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1))
 
-class PidStatistics {
-    const pid_t pid;
-
-    // Total
-    size_t mSizesTotal;
-    size_t mElementsTotal;
-    // Current
-    size_t mSizes;
-    size_t mElements;
-
-    char *name;
-    bool mGone;
-
-public:
-    static const pid_t gone = (pid_t) -1;
-
-    PidStatistics(pid_t pid, char *name = NULL);
-    PidStatistics(const PidStatistics &copy);
-    ~PidStatistics();
-
-    pid_t getPid() const { return pid; }
-    bool pidGone();
-    char *getName() const { return name; }
-    void setName(char *name);
-
-    void add(unsigned short size);
-    bool subtract(unsigned short size); // returns true if stats and PID gone
-    void addTotal(size_t size, size_t element);
-
-    size_t sizes() const { return mSizes; }
-    size_t elements() const { return mElements; }
-
-    size_t sizesTotal() const { return mSizesTotal; }
-    size_t elementsTotal() const { return mElementsTotal; }
-
-    // helper
-    static char *pidToName(pid_t pid);
-};
-
-typedef android::List<PidStatistics *> PidStatisticsCollection;
-
-class UidStatistics {
+struct UidEntry {
     const uid_t uid;
+    size_t size;
 
-    PidStatisticsCollection Pids;
+    UidEntry(uid_t uid):uid(uid),size(0) { }
 
-    void insert(PidStatisticsCollection::iterator i, PidStatistics *p)
-        { Pids.insert(i, p); }
-    void push_back(PidStatistics *p) { Pids.push_back(p); }
-
-    size_t mSizes;
-    size_t mElements;
-
-public:
-    UidStatistics(uid_t uid);
-    ~UidStatistics();
-
-    PidStatisticsCollection::iterator begin() { return Pids.begin(); }
-    PidStatisticsCollection::iterator end() { return Pids.end(); }
-    PidStatisticsCollection::iterator erase(PidStatisticsCollection::iterator i)
-        { return Pids.erase(i); }
-
-    uid_t getUid() { return uid; }
-
-    void add(unsigned short size, pid_t pid);
-    void subtract(unsigned short size, pid_t pid);
-    void sort();
-
-    static const pid_t pid_all = (pid_t) -1;
-
-    // fast track current value
-    size_t sizes() const { return mSizes; };
-    size_t elements() const { return mElements; };
-
-    // statistical track
-    size_t sizes(pid_t pid);
-    size_t elements(pid_t pid);
-
-    size_t sizesTotal(pid_t pid = pid_all);
-    size_t elementsTotal(pid_t pid = pid_all);
-
-    // helper
-    static char *pidToName(pid_t pid) { return PidStatistics::pidToName(pid); }
-};
-
-typedef android::List<UidStatistics *> UidStatisticsCollection;
-
-class LidStatistics {
-    UidStatisticsCollection Uids;
-
-public:
-    LidStatistics();
-    ~LidStatistics();
-
-    UidStatisticsCollection::iterator begin() { return Uids.begin(); }
-    UidStatisticsCollection::iterator end() { return Uids.end(); }
-
-    void add(unsigned short size, uid_t uid, pid_t pid);
-    void subtract(unsigned short size, uid_t uid, pid_t pid);
-    void sort();
-
-    static const pid_t pid_all = (pid_t) -1;
-    static const uid_t uid_all = (uid_t) -1;
-
-    size_t sizes(uid_t uid = uid_all, pid_t pid = pid_all);
-    size_t elements(uid_t uid = uid_all, pid_t pid = pid_all);
-
-    size_t sizesTotal(uid_t uid = uid_all, pid_t pid = pid_all);
-    size_t elementsTotal(uid_t uid = uid_all, pid_t pid = pid_all);
+    inline const uid_t&getKey() const { return uid; }
+    size_t getSizes() const { return size; }
+    inline void add(size_t s) { size += s; }
+    inline bool subtract(size_t s) { size -= s; return !size; }
 };
 
 // Log Statistics
 class LogStatistics {
-    LidStatistics LogIds[LOG_ID_MAX];
-
     size_t mSizes[LOG_ID_MAX];
     size_t mElements[LOG_ID_MAX];
+    size_t mSizesTotal[LOG_ID_MAX];
+    size_t mElementsTotal[LOG_ID_MAX];
 
-    bool mStatistics;
-    bool dgramQlenStatistics;
-
-    static const unsigned short mBuckets[14];
-    log_time mMinimum[sizeof(mBuckets) / sizeof(mBuckets[0])];
+    // uid to size list
+    typedef android::BasicHashtable<uid_t, UidEntry> uidTable_t;
+    uidTable_t uidTable[LOG_ID_MAX];
 
 public:
-    const log_time start;
-
     LogStatistics();
 
-    LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; }
+    void enableStatistics() { }
 
-    void enableDgramQlenStatistics() { dgramQlenStatistics = true; }
-    void enableStatistics() { mStatistics = true; }
-    static unsigned short dgramQlen(unsigned short bucket);
-    unsigned long long minimum(unsigned short bucket);
-    void recordDiff(log_time diff, unsigned short bucket);
+    void add(LogBufferElement *entry);
+    void subtract(LogBufferElement *entry);
 
-    void add(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
-    void subtract(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
-    void sort();
+    // Caller must delete array
+    const UidEntry **sort(size_t n, log_id i);
 
     // fast track current value by id only
     size_t sizes(log_id_t id) const { return mSizes[id]; }
     size_t elements(log_id_t id) const { return mElements[id]; }
-
-    // statistical track
-    static const log_id_t log_id_all = (log_id_t) -1;
-    static const uid_t uid_all = (uid_t) -1;
-    static const pid_t pid_all = (pid_t) -1;
-
-    size_t sizes(log_id_t id, uid_t uid, pid_t pid = pid_all);
-    size_t elements(log_id_t id, uid_t uid, pid_t pid = pid_all);
-    size_t sizes() { return sizes(log_id_all, uid_all); }
-    size_t elements() { return elements(log_id_all, uid_all); }
-
-    size_t sizesTotal(log_id_t id = log_id_all,
-                      uid_t uid = uid_all,
-                      pid_t pid = pid_all);
-    size_t elementsTotal(log_id_t id = log_id_all,
-                         uid_t uid = uid_all,
-                         pid_t pid = pid_all);
+    size_t sizesTotal(log_id_t id) const { return mSizesTotal[id]; }
+    size_t elementsTotal(log_id_t id) const { return mElementsTotal[id]; }
 
     // *strp = malloc, balance with free
-    void format(char **strp, uid_t uid, unsigned int logMask, log_time oldest);
+    void format(char **strp, uid_t uid, unsigned int logMask);
 
     // helper
-    static char *pidToName(pid_t pid) { return PidStatistics::pidToName(pid); }
+    char *pidToName(pid_t pid);
     uid_t pidToUid(pid_t pid);
+    char *uidToName(uid_t uid);
 };
 
 #endif // _LOGD_LOG_STATISTICS_H__
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 5f9db8d..1b60b7e 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -23,12 +23,10 @@
 
 pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER;
 
-const struct timespec LogTimeEntry::EPOCH = { 0, 1 };
-
 LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client,
                            bool nonBlock, unsigned long tail,
                            unsigned int logMask, pid_t pid,
-                           log_time start)
+                           uint64_t start)
         : mRefCount(1)
         , mRelease(false)
         , mError(false)
@@ -42,7 +40,7 @@
         , mClient(client)
         , mStart(start)
         , mNonBlock(nonBlock)
-        , mEnd(CLOCK_MONOTONIC)
+        , mEnd(LogBufferElement::getCurrentSequence())
 {
         pthread_cond_init(&threadTriggeredCondition, NULL);
         cleanSkip_Locked();
@@ -129,7 +127,7 @@
     lock();
 
     while (me->threadRunning && !me->isError_Locked()) {
-        log_time start = me->mStart;
+        uint64_t start = me->mStart;
 
         unlock();
 
@@ -161,13 +159,13 @@
 }
 
 // A first pass to count the number of elements
-bool LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) {
+int LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) {
     LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
 
     LogTimeEntry::lock();
 
     if (me->mCount == 0) {
-        me->mStart = element->getMonotonicTime();
+        me->mStart = element->getSequence();
     }
 
     if ((!me->mPid || (me->mPid == element->getPid()))
@@ -181,12 +179,12 @@
 }
 
 // A second pass to send the selected elements
-bool LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) {
+int LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) {
     LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
 
     LogTimeEntry::lock();
 
-    me->mStart = element->getMonotonicTime();
+    me->mStart = element->getSequence();
 
     if (me->skipAhead[element->getLogId()]) {
         me->skipAhead[element->getLogId()]--;
@@ -195,7 +193,7 @@
 
     // Truncate to close race between first and second pass
     if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) {
-        goto skip;
+        goto stop;
     }
 
     if (!me->isWatching(element->getLogId())) {
@@ -207,7 +205,7 @@
     }
 
     if (me->isError_Locked()) {
-        goto skip;
+        goto stop;
     }
 
     if (!me->mTail) {
@@ -234,6 +232,10 @@
 skip:
     LogTimeEntry::unlock();
     return false;
+
+stop:
+    LogTimeEntry::unlock();
+    return -1;
 }
 
 void LogTimeEntry::cleanSkip_Locked(void) {
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index 81aedfb..ae2f92b 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -47,13 +47,12 @@
 public:
     LogTimeEntry(LogReader &reader, SocketClient *client, bool nonBlock,
                  unsigned long tail, unsigned int logMask, pid_t pid,
-                 log_time start);
+                 uint64_t start);
 
     SocketClient *mClient;
-    static const struct timespec EPOCH;
-    log_time mStart;
+    uint64_t mStart;
     const bool mNonBlock;
-    const log_time mEnd; // only relevant if mNonBlock
+    const uint64_t mEnd; // only relevant if mNonBlock
 
     // Protect List manipulations
     static void lock(void) { pthread_mutex_lock(&timesLock); }
@@ -103,8 +102,8 @@
     }
     bool isWatching(log_id_t id) { return (mLogMask & (1<<id)) != 0; }
     // flushTo filter callbacks
-    static bool FilterFirstPass(const LogBufferElement *element, void *me);
-    static bool FilterSecondPass(const LogBufferElement *element, void *me);
+    static int FilterFirstPass(const LogBufferElement *element, void *me);
+    static int FilterSecondPass(const LogBufferElement *element, void *me);
 };
 
 typedef android::List<LogTimeEntry *> LastLogTimes;
diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h
index 769d651..5f60801 100644
--- a/logd/LogWhiteBlackList.h
+++ b/logd/LogWhiteBlackList.h
@@ -61,7 +61,9 @@
     int init(char *str);
 
     bool naughty(LogBufferElement *element);
+    bool naughty(void) { return !mNaughty.empty(); }
     bool nice(LogBufferElement *element);
+    bool nice(void) { return !mNice.empty(); }
     bool worstUidEnabled() const { return mWorstUidEnabled; }
 
     // *strp is malloc'd, use free to release
diff --git a/logd/README.property b/logd/README.property
index b7fcece..60542b2 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -7,12 +7,6 @@
 logd.statistics             bool depends Enable logcat -S statistics.
 ro.config.low_ram           bool  false  if true, logd.statistics default false
 ro.build.type               string       if user, logd.statistics default false
-logd.statistics.dgram_qlen  bool  false  Record dgram_qlen statistics. This
-                                         represents a performance impact and
-                                         is used to determine the platform's
-                                         minimum domain socket network FIFO
-                                         size (see source for details) based
-                                         on typical load (logcat -S to view)
 persist.logd.size          number 256K   default size of the buffer for all
                                          log ids at initial startup, at runtime
                                          use: logcat -b all -G <value>
diff --git a/logd/libaudit.c b/logd/libaudit.c
index d00d579..cf76305 100644
--- a/logd/libaudit.c
+++ b/logd/libaudit.c
@@ -177,7 +177,7 @@
      */
     status.pid = pid;
     status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT;
-    status.rate_limit = 20; // audit entries per second
+    status.rate_limit = 5; // audit entries per second
 
     /* Let the kernel know this pid will be registering for audit events */
     rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
diff --git a/logd/main.cpp b/logd/main.cpp
index 7a1ae54..a61beff 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -17,7 +17,10 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <poll.h>
 #include <sched.h>
+#include <semaphore.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -26,10 +29,12 @@
 #include <sys/prctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <syslog.h>
 #include <unistd.h>
 
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
+#include <cutils/sockets.h>
 
 #include "private/android_filesystem_config.h"
 #include "CommandListener.h"
@@ -37,6 +42,12 @@
 #include "LogListener.h"
 #include "LogAudit.h"
 
+#define KMSG_PRIORITY(PRI)                            \
+    '<',                                              \
+    '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \
+    '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) % 10, \
+    '>'
+
 //
 //  The service is designed to be run by init, it does not respond well
 // to starting up manually. When starting up manually the sockets will
@@ -127,17 +138,107 @@
     return def;
 }
 
-// Foreground waits for exit of the three main persistent threads that
-// are started here.  The three threads are created to manage UNIX
-// domain client sockets for writing, reading and controlling the user
-// space logger.  Additional transitory per-client threads are created
-// for each reader once they register.
-int main() {
-    bool auditd = property_get_bool("logd.auditd", true);
+// Remove the static, and use this variable
+// globally for debugging if necessary. eg:
+//   write(fdDmesg, "I am here\n", 10);
+static int fdDmesg = -1;
 
-    int fdDmesg = -1;
-    if (auditd && property_get_bool("logd.auditd.dmesg", true)) {
-        fdDmesg = open("/dev/kmsg", O_WRONLY);
+static sem_t reinit;
+static bool reinit_running = false;
+static LogBuffer *logBuf = NULL;
+
+static void *reinit_thread_start(void * /*obj*/) {
+    prctl(PR_SET_NAME, "logd.daemon");
+    set_sched_policy(0, SP_BACKGROUND);
+
+    setgid(AID_LOGD);
+    setuid(AID_LOGD);
+
+    while (reinit_running && !sem_wait(&reinit) && reinit_running) {
+        if (fdDmesg >= 0) {
+            static const char reinit_message[] = { KMSG_PRIORITY(LOG_INFO),
+                'l', 'o', 'g', 'd', '.', 'd', 'a', 'e', 'm', 'o', 'n', ':',
+                ' ', 'r', 'e', 'i', 'n', 'i', 't', '\n' };
+            write(fdDmesg, reinit_message, sizeof(reinit_message));
+        }
+
+        // Anything that reads persist.<property>
+        if (logBuf) {
+            logBuf->init();
+        }
+    }
+
+    return NULL;
+}
+
+// Serves as a global method to trigger reinitialization
+// and as a function that can be provided to signal().
+void reinit_signal_handler(int /*signal*/) {
+    sem_post(&reinit);
+}
+
+// Foreground waits for exit of the main persistent threads
+// that are started here. The threads are created to manage
+// UNIX domain client sockets for writing, reading and
+// controlling the user space logger, and for any additional
+// logging plugins like auditd and restart control. Additional
+// transitory per-client threads are created for each reader.
+int main(int argc, char *argv[]) {
+    fdDmesg = open("/dev/kmsg", O_WRONLY);
+
+    // issue reinit command. KISS argument parsing.
+    if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
+        int sock = TEMP_FAILURE_RETRY(
+            socket_local_client("logd",
+                                ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                SOCK_STREAM));
+        if (sock < 0) {
+            return -errno;
+        }
+        static const char reinit[] = "reinit";
+        ssize_t ret = TEMP_FAILURE_RETRY(write(sock, reinit, sizeof(reinit)));
+        if (ret < 0) {
+            return -errno;
+        }
+        struct pollfd p;
+        memset(&p, 0, sizeof(p));
+        p.fd = sock;
+        p.events = POLLIN;
+        ret = TEMP_FAILURE_RETRY(poll(&p, 1, 100));
+        if (ret < 0) {
+            return -errno;
+        }
+        if ((ret == 0) || !(p.revents & POLLIN)) {
+            return -ETIME;
+        }
+        static const char success[] = "success";
+        char buffer[sizeof(success) - 1];
+        memset(buffer, 0, sizeof(buffer));
+        ret = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer)));
+        if (ret < 0) {
+            return -errno;
+        }
+        return strncmp(buffer, success, sizeof(success) - 1) != 0;
+    }
+
+    // Reinit Thread
+    sem_init(&reinit, 0, 0);
+    pthread_attr_t attr;
+    if (!pthread_attr_init(&attr)) {
+        struct sched_param param;
+
+        memset(&param, 0, sizeof(param));
+        pthread_attr_setschedparam(&attr, &param);
+        pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
+        if (!pthread_attr_setdetachstate(&attr,
+                                         PTHREAD_CREATE_DETACHED)) {
+            pthread_t thread;
+            reinit_running = true;
+            if (pthread_create(&thread, &attr, reinit_thread_start, NULL)) {
+                reinit_running = false;
+            }
+        }
+        pthread_attr_destroy(&attr);
     }
 
     if (drop_privs() != 0) {
@@ -153,11 +254,10 @@
     // LogBuffer is the object which is responsible for holding all
     // log entries.
 
-    LogBuffer *logBuf = new LogBuffer(times);
+    logBuf = new LogBuffer(times);
 
-    if (property_get_bool("logd.statistics.dgram_qlen", false)) {
-        logBuf->enableDgramQlenStatistics();
-    }
+    signal(SIGHUP, reinit_signal_handler);
+
     {
         char property[PROPERTY_VALUE_MAX];
         property_get("ro.build.type", property, "");
@@ -198,9 +298,13 @@
     // initiated log messages. New log entries are added to LogBuffer
     // and LogReader is notified to send updates to connected clients.
 
+    bool auditd = property_get_bool("logd.auditd", true);
+
     if (auditd) {
+        bool dmesg = property_get_bool("logd.auditd.dmesg", true);
+
         // failure is an option ... messages are in dmesg (required by standard)
-        LogAudit *al = new LogAudit(logBuf, reader, fdDmesg);
+        LogAudit *al = new LogAudit(logBuf, reader, dmesg ? fdDmesg : -1);
 
         int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
         if (len > 0) {
@@ -220,11 +324,10 @@
 
         if (al->startListener()) {
             delete al;
-            close(fdDmesg);
         }
     }
 
-    pause();
+    TEMP_FAILURE_RETRY(pause());
+
     exit(0);
 }
-
diff --git a/logd/tests/Android.mk b/logd/tests/Android.mk
index f851288..85ca4ac 100644
--- a/logd/tests/Android.mk
+++ b/logd/tests/Android.mk
@@ -46,7 +46,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(test_module_prefix)unit-tests
 LOCAL_MODULE_TAGS := $(test_tags)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_CFLAGS += $(test_c_flags)
 LOCAL_SHARED_LIBRARIES := libcutils
 LOCAL_SRC_FILES := $(test_src_files)
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 96877a9..46bd9c0 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -192,164 +192,6 @@
     EXPECT_TRUE(NULL != events_logs);
 #endif
 
-    // Parse timing stats
-
-    cp = strstr(cp, "Minimum time between log events per dgram_qlen:");
-
-    if (cp) {
-        while (*cp && (*cp != '\n')) {
-            ++cp;
-        }
-        if (*cp == '\n') {
-            ++cp;
-        }
-
-        char *list_of_spans = cp;
-        EXPECT_NE('\0', *list_of_spans);
-
-        unsigned short number_of_buckets = 0;
-        unsigned short *dgram_qlen = NULL;
-        unsigned short bucket = 0;
-        while (*cp && (*cp != '\n')) {
-            bucket = 0;
-            while (isdigit(*cp)) {
-                bucket = bucket * 10 + *cp - '0';
-                ++cp;
-            }
-            while (*cp == ' ') {
-                ++cp;
-            }
-            if (!bucket) {
-                break;
-            }
-            unsigned short *new_dgram_qlen = new unsigned short[number_of_buckets + 1];
-            EXPECT_TRUE(new_dgram_qlen != NULL);
-            if (dgram_qlen) {
-                memcpy(new_dgram_qlen, dgram_qlen, sizeof(*dgram_qlen) * number_of_buckets);
-                delete [] dgram_qlen;
-            }
-
-            dgram_qlen = new_dgram_qlen;
-            dgram_qlen[number_of_buckets++] = bucket;
-        }
-
-        char *end_of_spans = cp;
-        EXPECT_NE('\0', *end_of_spans);
-
-        EXPECT_LT(5, number_of_buckets);
-
-        unsigned long long *times = new unsigned long long [number_of_buckets];
-        ASSERT_TRUE(times != NULL);
-
-        memset(times, 0, sizeof(*times) * number_of_buckets);
-
-        while (*cp == '\n') {
-            ++cp;
-        }
-
-        unsigned short number_of_values = 0;
-        unsigned long long value;
-        while (*cp && (*cp != '\n')) {
-            EXPECT_GE(number_of_buckets, number_of_values);
-
-            value = 0;
-            while (isdigit(*cp)) {
-                value = value * 10ULL + *cp - '0';
-                ++cp;
-            }
-
-            switch(*cp) {
-            case ' ':
-            case '\n':
-                value *= 1000ULL;
-                /* FALLTHRU */
-            case 'm':
-                value *= 1000ULL;
-                /* FALLTHRU */
-            case 'u':
-                value *= 1000ULL;
-                /* FALLTHRU */
-            case 'n':
-            default:
-                break;
-            }
-            while (*++cp == ' ');
-
-            if (!value) {
-                break;
-            }
-
-            times[number_of_values] = value;
-            ++number_of_values;
-        }
-
-#ifdef TARGET_USES_LOGD
-        EXPECT_EQ(number_of_values, number_of_buckets);
-#endif
-
-        FILE *fp;
-        ASSERT_TRUE(NULL != (fp = fopen("/proc/sys/net/unix/max_dgram_qlen", "r")));
-
-        unsigned max_dgram_qlen = 0;
-        fscanf(fp, "%u", &max_dgram_qlen);
-
-        fclose(fp);
-
-        // Find launch point
-        unsigned short launch = 0;
-        unsigned long long total = 0;
-        do {
-            total += times[launch];
-        } while (((++launch < number_of_buckets)
-                && ((total / launch) >= (times[launch] / 8ULL)))
-            || (launch == 1)); // too soon
-
-        bool failure = number_of_buckets <= launch;
-        if (!failure) {
-            unsigned short l = launch;
-            if (l >= number_of_buckets) {
-                l = number_of_buckets - 1;
-            }
-            failure = max_dgram_qlen < dgram_qlen[l];
-        }
-
-        // We can get failure if at any time liblog_benchmarks has been run
-        // because designed to overload /proc/sys/net/unix/max_dgram_qlen even
-        // at excessive values like 20000. It does so to measure the raw processing
-        // performance of logd.
-        if (failure) {
-            cp = find_benchmark_spam(cp);
-        }
-
-        if (cp) {
-            // Fake a failure, but without the failure code
-            if (number_of_buckets <= launch) {
-                printf ("Expected: number_of_buckets > launch, actual: %u vs %u\n",
-                        number_of_buckets, launch);
-            }
-            if (launch >= number_of_buckets) {
-                launch = number_of_buckets - 1;
-            }
-            if (max_dgram_qlen < dgram_qlen[launch]) {
-                printf ("Expected: max_dgram_qlen >= dgram_qlen[%d],"
-                            " actual: %u vs %u\n",
-                        launch, max_dgram_qlen, dgram_qlen[launch]);
-            }
-        } else
-#ifndef TARGET_USES_LOGD
-        if (total)
-#endif
-        {
-            EXPECT_GT(number_of_buckets, launch);
-            if (launch >= number_of_buckets) {
-                launch = number_of_buckets - 1;
-            }
-            EXPECT_GE(max_dgram_qlen, dgram_qlen[launch]);
-        }
-
-        delete [] dgram_qlen;
-        delete [] times;
-    }
     delete [] buf;
 }
 
diff --git a/netcfg/Android.mk b/netcfg/Android.mk
deleted file mode 100644
index 4796c11..0000000
--- a/netcfg/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= netcfg.c
-LOCAL_MODULE:= netcfg
-LOCAL_SHARED_LIBRARIES := libnetutils
-LOCAL_CFLAGS := -Werror
-include $(BUILD_EXECUTABLE)
diff --git a/netcfg/MODULE_LICENSE_APACHE2 b/netcfg/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/netcfg/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/netcfg/NOTICE b/netcfg/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/netcfg/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
-   Copyright (c) 2005-2008, 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.
-
-   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.
-
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
diff --git a/netcfg/netcfg.c b/netcfg/netcfg.c
deleted file mode 100644
index eec1b2f..0000000
--- a/netcfg/netcfg.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
-** Copyright 2006, 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 <dirent.h>
-#include <netinet/ether.h>
-#include <netinet/if_ether.h>
-#include <netutils/dhcp.h>
-#include <netutils/ifc.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static const char *ipaddr(in_addr_t addr)
-{
-    struct in_addr in_addr;
-
-    in_addr.s_addr = addr;
-    return inet_ntoa(in_addr);
-}
-
-static void usage(void)
-{
-    fprintf(stderr,"usage: netcfg [<interface> dhcp]\n");
-    exit(1);
-}
-
-static int dump_interface(const char *name)
-{
-    unsigned addr, flags;
-    unsigned char hwbuf[ETH_ALEN];
-    int prefixLength;
-
-    if(ifc_get_info(name, &addr, &prefixLength, &flags)) {
-        return 0;
-    }
-
-    printf("%-8s %s  ", name, flags & 1 ? "UP  " : "DOWN");
-    printf("%40s", ipaddr(addr));
-    printf("/%-4d", prefixLength);
-    printf("0x%08x ", flags);
-    if (!ifc_get_hwaddr(name, hwbuf)) {
-        int i;
-        for(i=0; i < (ETH_ALEN-1); i++)
-            printf("%02x:", hwbuf[i]);
-        printf("%02x\n", hwbuf[i]);
-    } else {
-        printf("\n");
-    }
-    return 0;
-}
-
-static int dump_interfaces(void)
-{
-    DIR *d;
-    struct dirent *de;
-
-    d = opendir("/sys/class/net");
-    if(d == 0) return -1;
-
-    while((de = readdir(d))) {
-        if(de->d_name[0] == '.') continue;
-        dump_interface(de->d_name);
-    }
-    closedir(d);
-    return 0;
-}
-
-int main(int argc, char **argv)
-{
-    if(ifc_init()) {
-        perror("Cannot perform requested operation");
-        exit(1);
-    }
-
-    if(argc == 1) {
-        int result = dump_interfaces();
-        ifc_close();
-        return result;
-    }
-
-    if(argc != 3) usage();
-
-    char* iname = argv[1];
-    char* action = argv[2];
-    if(strlen(iname) > 16) usage();
-
-    if (!strcmp(action, "dhcp")) {
-        if (do_dhcp(iname)) {
-            fprintf(stderr, "dhcp failed: %s\n", strerror(errno));
-            ifc_close();
-            exit(1);
-        }
-    } else {
-        fprintf(stderr,"no such action '%s'\n", action);
-        usage();
-    }
-
-    ifc_close();
-    return 0;
-}
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 30bef46..0064790 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -1,6 +1,5 @@
 # set up the global environment
 on init
-    export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
     export ANDROID_BOOTLOGO 1
     export ANDROID_ROOT /system
     export ANDROID_ASSETS /system/app
diff --git a/rootdir/init.rc b/rootdir/init.rc
index bbb812b..cda79ce 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -32,8 +32,6 @@
 on init
     sysclktz 0
 
-    loglevel 3
-
     # Backward compatibility.
     symlink /system/etc /etc
     symlink /sys/kernel/debug /d
@@ -118,25 +116,18 @@
     mount cgroup none /dev/cpuctl cpu
     chown system system /dev/cpuctl
     chown system system /dev/cpuctl/tasks
-    chmod 0660 /dev/cpuctl/tasks
+    chmod 0666 /dev/cpuctl/tasks
     write /dev/cpuctl/cpu.shares 1024
-    write /dev/cpuctl/cpu.rt_runtime_us 950000
+    write /dev/cpuctl/cpu.rt_runtime_us 800000
     write /dev/cpuctl/cpu.rt_period_us 1000000
 
-    mkdir /dev/cpuctl/apps
-    chown system system /dev/cpuctl/apps/tasks
-    chmod 0666 /dev/cpuctl/apps/tasks
-    write /dev/cpuctl/apps/cpu.shares 1024
-    write /dev/cpuctl/apps/cpu.rt_runtime_us 800000
-    write /dev/cpuctl/apps/cpu.rt_period_us 1000000
-
-    mkdir /dev/cpuctl/apps/bg_non_interactive
-    chown system system /dev/cpuctl/apps/bg_non_interactive/tasks
-    chmod 0666 /dev/cpuctl/apps/bg_non_interactive/tasks
+    mkdir /dev/cpuctl/bg_non_interactive
+    chown system system /dev/cpuctl/bg_non_interactive/tasks
+    chmod 0666 /dev/cpuctl/bg_non_interactive/tasks
     # 5.0 %
-    write /dev/cpuctl/apps/bg_non_interactive/cpu.shares 52
-    write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_runtime_us 700000
-    write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_period_us 1000000
+    write /dev/cpuctl/bg_non_interactive/cpu.shares 52
+    write /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 700000
+    write /dev/cpuctl/bg_non_interactive/cpu.rt_period_us 1000000
 
     # qtaguid will limit access to specific data based on group memberships.
     #   net_bw_acct grants impersonation of socket owners.
@@ -171,6 +162,7 @@
 # Load properties from /system/ + /factory after fs mount.
 on load_all_props_action
     load_all_props
+    start logd-reinit
 
 # Indicate to fw loaders that the relevant mounts are up.
 on firmware_mounts_complete
@@ -233,6 +225,8 @@
     mkdir /cache/lost+found 0770 root root
 
 on post-fs-data
+    installkey /data
+
     # We chown/chmod /data again so because mount is run as root + defaults
     chown system system /data
     chmod 0771 /data
@@ -247,22 +241,6 @@
     # Avoid predictable entropy pool. Carry over entropy from previous boot.
     copy /data/system/entropy.dat /dev/urandom
 
-    # Create dump dir and collect dumps.
-    # Do this before we mount cache so eventually we can use cache for
-    # storing dumps on platforms which do not have a dedicated dump partition.
-    mkdir /data/dontpanic 0750 root log
-
-    # Collect apanic data, free resources and re-arm trigger
-    copy /proc/apanic_console /data/dontpanic/apanic_console
-    chown root log /data/dontpanic/apanic_console
-    chmod 0640 /data/dontpanic/apanic_console
-
-    copy /proc/apanic_threads /data/dontpanic/apanic_threads
-    chown root log /data/dontpanic/apanic_threads
-    chmod 0640 /data/dontpanic/apanic_threads
-
-    write /proc/apanic_console 1
-
     # create basic filesystem structure
     mkdir /data/misc 01771 system misc
     mkdir /data/misc/adb 02750 system shell
@@ -327,6 +305,14 @@
     # Separate location for storing security policy files on data
     mkdir /data/security 0711 system system
 
+    # Create all remaining /data root dirs so that they are made through init
+    # and get proper encryption policy installed
+    mkdir /data/backup 0700 system system
+    mkdir /data/media 0770 media_rw media_rw
+    mkdir /data/ss 0700 system system
+    mkdir /data/system 0775 system system
+    mkdir /data/user 0711 system system
+
     # Reload policy from /data/security if present.
     setprop selinux.reload_policy 1
 
@@ -453,6 +439,7 @@
 
 on property:vold.decrypt=trigger_load_persist_props
     load_persist_props
+    start logd-reinit
 
 on property:vold.decrypt=trigger_post_fs_data
     trigger post-fs-data
@@ -461,6 +448,7 @@
     class_start main
 
 on property:vold.decrypt=trigger_restart_framework
+    installkey /data
     class_start main
     class_start late_start
 
@@ -494,7 +482,10 @@
     socket logd stream 0666 logd logd
     socket logdr seqpacket 0666 logd logd
     socket logdw dgram 0222 logd logd
-    seclabel u:r:logd:s0
+
+service logd-reinit /system/bin/logd --reinit
+    oneshot
+    disabled
 
 service healthd /sbin/healthd
     class core
@@ -589,7 +580,7 @@
     # encryption) or trigger_restart_min_framework (other encryption)
 
 # One shot invocation to encrypt unencrypted volumes
-service encrypt /system/bin/vdc --wait cryptfs maybeenabledefaultcrypto
+service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace default
     disabled
     oneshot
     # vold will set vold.decrypt to trigger_restart_framework (default
@@ -608,7 +599,6 @@
 
 service flash_recovery /system/bin/install-recovery.sh
     class main
-    seclabel u:r:install_recovery:s0
     oneshot
 
 service racoon /system/bin/racoon
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 43d7bc9..9cf9ed9 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -89,6 +89,7 @@
 /dev/ppp                  0660   radio      vpn
 
 # sysfs properties
+/sys/devices/platform/trusty.*      trusty_version        0440  root   log
 /sys/devices/virtual/input/input*   enable      0660  root   input
 /sys/devices/virtual/input/input*   poll_delay  0660  root   input
 /sys/devices/virtual/usb_composite/*   enable      0664  root   system
diff --git a/run-as/package.c b/run-as/package.c
index 4f8f3a7..9e1f5bb 100644
--- a/run-as/package.c
+++ b/run-as/package.c
@@ -16,9 +16,11 @@
 */
 #include <errno.h>
 #include <fcntl.h>
-#include <unistd.h>
-#include <sys/stat.h>
+#include <string.h>
 #include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
 #include <private/android_filesystem_config.h>
 #include "package.h"
 
diff --git a/run-as/run-as.c b/run-as/run-as.c
index cc05e63..368b8f1 100644
--- a/run-as/run-as.c
+++ b/run-as/run-as.c
@@ -15,22 +15,25 @@
 ** limitations under the License.
 */
 
-#define PROGNAME  "run-as"
-#define LOG_TAG   PROGNAME
+#define PROGNAME "run-as"
+#define LOG_TAG  PROGNAME
 
+#include <dirent.h>
+#include <errno.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/types.h>
+#include <sys/capability.h>
+#include <sys/cdefs.h>
 #include <sys/stat.h>
-#include <dirent.h>
-#include <errno.h>
-#include <unistd.h>
+#include <sys/types.h>
 #include <time.h>
-#include <stdarg.h>
+#include <unistd.h>
 
-#include <selinux/android.h>
 #include <private/android_filesystem_config.h>
+#include <selinux/android.h>
+
 #include "package.h"
 
 /*
@@ -83,37 +86,37 @@
  *  - Run the 'gdbserver' binary executable to allow native debugging
  */
 
-static void
-usage(void)
-{
-    const char*  str = "Usage: " PROGNAME " <package-name> <command> [<args>]\n\n";
-    write(1, str, strlen(str));
-    exit(1);
-}
-
-
-static void
+__noreturn static void
 panic(const char* format, ...)
 {
     va_list args;
+    int e = errno;
 
     fprintf(stderr, "%s: ", PROGNAME);
     va_start(args, format);
     vfprintf(stderr, format, args);
     va_end(args);
-    exit(1);
+    exit(e ? -e : 1);
 }
 
+static void
+usage(void)
+{
+    panic("Usage:\n    " PROGNAME " <package-name> <command> [<args>]\n");
+}
 
 int main(int argc, char **argv)
 {
     const char* pkgname;
     int myuid, uid, gid;
     PackageInfo info;
+    struct __user_cap_header_struct capheader;
+    struct __user_cap_data_struct capdata[2];
 
     /* check arguments */
-    if (argc < 2)
+    if (argc < 2) {
         usage();
+    }
 
     /* check userid of caller - must be 'shell' or 'root' */
     myuid = getuid();
@@ -121,29 +124,37 @@
         panic("only 'shell' or 'root' users can run this program\n");
     }
 
-    /* retrieve package information from system */
+    memset(&capheader, 0, sizeof(capheader));
+    memset(&capdata, 0, sizeof(capdata));
+    capheader.version = _LINUX_CAPABILITY_VERSION_3;
+    capdata[CAP_TO_INDEX(CAP_SETUID)].effective |= CAP_TO_MASK(CAP_SETUID);
+    capdata[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID);
+    capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
+    capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
+
+    if (capset(&capheader, &capdata[0]) < 0) {
+        panic("Could not set capabilities: %s\n", strerror(errno));
+    }
+
+    /* retrieve package information from system (does setegid) */
     pkgname = argv[1];
     if (get_package_info(pkgname, &info) < 0) {
         panic("Package '%s' is unknown\n", pkgname);
-        return 1;
     }
 
     /* reject system packages */
     if (info.uid < AID_APP) {
         panic("Package '%s' is not an application\n", pkgname);
-        return 1;
     }
 
     /* reject any non-debuggable package */
     if (!info.isDebuggable) {
         panic("Package '%s' is not debuggable\n", pkgname);
-        return 1;
     }
 
     /* check that the data directory path is valid */
     if (check_data_path(info.dataDir, info.uid) < 0) {
         panic("Package '%s' has corrupt installation\n", pkgname);
-        return 1;
     }
 
     /* Ensure that we change all real/effective/saved IDs at the
@@ -152,38 +163,30 @@
     uid = gid = info.uid;
     if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) {
         panic("Permission denied\n");
-        return 1;
+    }
+
+    /* Required if caller has uid and gid all non-zero */
+    memset(&capdata, 0, sizeof(capdata));
+    if (capset(&capheader, &capdata[0]) < 0) {
+        panic("Could not clear all capabilities: %s\n", strerror(errno));
     }
 
     if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) {
-        panic("Could not set SELinux security context:  %s\n", strerror(errno));
-        return 1;
+        panic("Could not set SELinux security context: %s\n", strerror(errno));
     }
 
     /* cd into the data directory */
-    {
-        int ret;
-        do {
-            ret = chdir(info.dataDir);
-        } while (ret < 0 && errno == EINTR);
-
-        if (ret < 0) {
-            panic("Could not cd to package's data directory: %s\n", strerror(errno));
-            return 1;
-        }
+    if (TEMP_FAILURE_RETRY(chdir(info.dataDir)) < 0) {
+        panic("Could not cd to package's data directory: %s\n", strerror(errno));
     }
 
     /* User specified command for exec. */
-    if (argc >= 3 ) {
-        if (execvp(argv[2], argv+2) < 0) {
-            panic("exec failed for %s Error:%s\n", argv[2], strerror(errno));
-            return -errno;
-        }
+    if ((argc >= 3) && (execvp(argv[2], argv+2) < 0)) {
+        panic("exec failed for %s: %s\n", argv[2], strerror(errno));
     }
 
     /* Default exec shell. */
     execlp("/system/bin/sh", "sh", NULL);
 
-    panic("exec failed\n");
-    return 1;
+    panic("exec failed: %s\n", strerror(errno));
 }
diff --git a/sdcard/Android.mk b/sdcard/Android.mk
index 63b0f41..cb3a8fb 100644
--- a/sdcard/Android.mk
+++ b/sdcard/Android.mk
@@ -6,6 +6,6 @@
 LOCAL_MODULE := sdcard
 LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
 
-LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_SHARED_LIBRARIES := libcutils
 
 include $(BUILD_EXECUTABLE)
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 7ad14ab..041c37a 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -1887,7 +1887,8 @@
             "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
             fd, uid, gid);
 
-    res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC, opts);
+    res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC |
+            MS_NOATIME, opts);
     if (res < 0) {
         ERROR("cannot mount fuse filesystem: %s\n", strerror(errno));
         goto error;
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 05b83a2..186a89f 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -23,14 +23,12 @@
     upstream-netbsd/lib/libutil/raise_default_signal.c
 LOCAL_CFLAGS += $(common_cflags) -Dmain=dd_main -DNO_CONV
 LOCAL_MODULE := libtoolbox_dd
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := upstream-netbsd/usr.bin/du/du.c
 LOCAL_CFLAGS += $(common_cflags) -Dmain=du_main
 LOCAL_MODULE := libtoolbox_du
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 include $(BUILD_STATIC_LIBRARY)
 
 
@@ -44,11 +42,9 @@
     df \
     getevent \
     getprop \
-    getsebool \
     iftop \
     ioctl \
     ionice \
-    load_policy \
     log \
     ls \
     lsof \
@@ -56,22 +52,16 @@
     nandread \
     newfs_msdos \
     ps \
+    prlimit \
     renice \
     restorecon \
-    route \
-    runcon \
-    schedtop \
     sendevent \
     setprop \
-    setsebool \
-    smd \
     start \
     stop \
     top \
-    umount \
     uptime \
     watchprops \
-    wipe \
 
 ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS)
 
@@ -89,7 +79,6 @@
 LOCAL_WHOLE_STATIC_LIBRARIES := $(patsubst %,libtoolbox_%,$(BSD_TOOLS))
 
 LOCAL_MODULE := toolbox
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 
 # Install the symlinks.
 LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,$(ALL_TOOLS),ln -sf toolbox $(TARGET_OUT)/bin/$(t);)
@@ -107,6 +96,14 @@
 $(TOOLS_H):
 	$(transform-generated-source)
 
+$(LOCAL_PATH)/getevent.c: $(intermediates)/input.h-labels.h
+
+INPUT_H_LABELS_H := $(intermediates)/input.h-labels.h
+$(INPUT_H_LABELS_H): PRIVATE_LOCAL_PATH := $(LOCAL_PATH)
+$(INPUT_H_LABELS_H): PRIVATE_CUSTOM_TOOL = $(PRIVATE_LOCAL_PATH)/generate-input.h-labels.py > $@
+$(INPUT_H_LABELS_H): $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/generate-input.h-labels.py
+$(INPUT_H_LABELS_H):
+	$(transform-generated-source)
 
 # We only want 'r' on userdebug and eng builds.
 include $(CLEAR_VARS)
@@ -114,7 +111,6 @@
 LOCAL_CFLAGS += $(common_cflags)
 LOCAL_MODULE := r
 LOCAL_MODULE_TAGS := debug
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 include $(BUILD_EXECUTABLE)
 
 
diff --git a/toolbox/generate-input.h-labels.py b/toolbox/generate-input.h-labels.py
new file mode 100755
index 0000000..ebb9588
--- /dev/null
+++ b/toolbox/generate-input.h-labels.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+# pylint: disable=bad-indentation,bad-continuation
+
+import os
+import re
+
+input_prop_list = []
+ev_list = []
+syn_list = []
+key_list = []
+rel_list = []
+abs_list = []
+sw_list = []
+msc_list = []
+led_list = []
+rep_list = []
+snd_list = []
+mt_tool_list = []
+ff_status_list = []
+ff_list = []
+
+r = re.compile(r'#define\s+(\S+)\s+((?:0x)?\d+)')
+
+with open('bionic/libc/kernel/uapi/linux/input.h', 'r') as f:
+  for line in f:
+    m = r.match(line)
+    if m:
+      name = m.group(1)
+      if name.startswith("INPUT_PROP_"):
+        input_prop_list.append(name)
+      elif name.startswith("EV_"):
+        ev_list.append(name)
+      elif name.startswith("SYN_"):
+        syn_list.append(name)
+      elif name.startswith("KEY_") or name.startswith("BTN_"):
+        key_list.append(name)
+      elif name.startswith("REL_"):
+        rel_list.append(name)
+      elif name.startswith("ABS_"):
+        abs_list.append(name)
+      elif name.startswith("SW_"):
+        sw_list.append(name)
+      elif name.startswith("MSC_"):
+        msc_list.append(name)
+      elif name.startswith("LED_"):
+        led_list.append(name)
+      elif name.startswith("REP_"):
+        rep_list.append(name)
+      elif name.startswith("SND_"):
+        snd_list.append(name)
+      elif name.startswith("MT_TOOL_"):
+        mt_tool_list.append(name)
+      elif name.startswith("FF_STATUS_"):
+        ff_status_list.append(name)
+      elif name.startswith("FF_"):
+        ff_list.append(name)
+
+def Dump(struct_name, values):
+  print 'static struct label %s[] = {' % (struct_name)
+  for value in values:
+    print '    LABEL(%s),' % (value)
+  print '    LABEL_END,'
+  print '};'
+
+Dump("input_prop_labels", input_prop_list)
+Dump("ev_labels", ev_list)
+Dump("syn_labels", syn_list)
+Dump("key_labels", key_list)
+Dump("rel_labels", rel_list)
+Dump("abs_labels", abs_list)
+Dump("sw_labels", sw_list)
+Dump("msc_labels", msc_list)
+Dump("led_labels", led_list)
+Dump("rep_labels", rep_list)
+Dump("snd_labels", snd_list)
+Dump("mt_tool_labels", mt_tool_list)
+Dump("ff_status_labels", ff_status_list)
+Dump("ff_labels", ff_list)
diff --git a/toolbox/getevent.c b/toolbox/getevent.c
index c58eb5d..30053af 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -12,7 +12,25 @@
 #include <errno.h>
 #include <unistd.h>
 
-#include "getevent.h"
+struct label {
+    const char *name;
+    int value;
+};
+
+#define LABEL(constant) { #constant, constant }
+#define LABEL_END { NULL, -1 }
+
+static struct label key_value_labels[] = {
+        { "UP", 0 },
+        { "DOWN", 1 },
+        { "REPEAT", 2 },
+        LABEL_END,
+};
+
+#include "input.h-labels.h"
+
+#undef LABEL
+#undef LABEL_END
 
 static struct pollfd *ufds;
 static char **device_names;
diff --git a/toolbox/getevent.h b/toolbox/getevent.h
deleted file mode 100644
index 0482d04..0000000
--- a/toolbox/getevent.h
+++ /dev/null
@@ -1,727 +0,0 @@
-#include <linux/input.h>
-
-struct label {
-    const char *name;
-    int value;
-};
-
-#define LABEL(constant) { #constant, constant }
-#define LABEL_END { NULL, -1 }
-
-static struct label input_prop_labels[] = {
-        LABEL(INPUT_PROP_POINTER),
-        LABEL(INPUT_PROP_DIRECT),
-        LABEL(INPUT_PROP_BUTTONPAD),
-        LABEL(INPUT_PROP_SEMI_MT),
-        LABEL_END,
-};
-
-static struct label ev_labels[] = {
-        LABEL(EV_SYN),
-        LABEL(EV_KEY),
-        LABEL(EV_REL),
-        LABEL(EV_ABS),
-        LABEL(EV_MSC),
-        LABEL(EV_SW),
-        LABEL(EV_LED),
-        LABEL(EV_SND),
-        LABEL(EV_REP),
-        LABEL(EV_FF),
-        LABEL(EV_PWR),
-        LABEL(EV_FF_STATUS),
-        LABEL_END,
-};
-
-static struct label syn_labels[] = {
-        LABEL(SYN_REPORT),
-        LABEL(SYN_CONFIG),
-        LABEL(SYN_MT_REPORT),
-        LABEL(SYN_DROPPED),
-        LABEL_END,
-};
-
-static struct label key_labels[] = {
-        LABEL(KEY_RESERVED),
-        LABEL(KEY_ESC),
-        LABEL(KEY_1),
-        LABEL(KEY_2),
-        LABEL(KEY_3),
-        LABEL(KEY_4),
-        LABEL(KEY_5),
-        LABEL(KEY_6),
-        LABEL(KEY_7),
-        LABEL(KEY_8),
-        LABEL(KEY_9),
-        LABEL(KEY_0),
-        LABEL(KEY_MINUS),
-        LABEL(KEY_EQUAL),
-        LABEL(KEY_BACKSPACE),
-        LABEL(KEY_TAB),
-        LABEL(KEY_Q),
-        LABEL(KEY_W),
-        LABEL(KEY_E),
-        LABEL(KEY_R),
-        LABEL(KEY_T),
-        LABEL(KEY_Y),
-        LABEL(KEY_U),
-        LABEL(KEY_I),
-        LABEL(KEY_O),
-        LABEL(KEY_P),
-        LABEL(KEY_LEFTBRACE),
-        LABEL(KEY_RIGHTBRACE),
-        LABEL(KEY_ENTER),
-        LABEL(KEY_LEFTCTRL),
-        LABEL(KEY_A),
-        LABEL(KEY_S),
-        LABEL(KEY_D),
-        LABEL(KEY_F),
-        LABEL(KEY_G),
-        LABEL(KEY_H),
-        LABEL(KEY_J),
-        LABEL(KEY_K),
-        LABEL(KEY_L),
-        LABEL(KEY_SEMICOLON),
-        LABEL(KEY_APOSTROPHE),
-        LABEL(KEY_GRAVE),
-        LABEL(KEY_LEFTSHIFT),
-        LABEL(KEY_BACKSLASH),
-        LABEL(KEY_Z),
-        LABEL(KEY_X),
-        LABEL(KEY_C),
-        LABEL(KEY_V),
-        LABEL(KEY_B),
-        LABEL(KEY_N),
-        LABEL(KEY_M),
-        LABEL(KEY_COMMA),
-        LABEL(KEY_DOT),
-        LABEL(KEY_SLASH),
-        LABEL(KEY_RIGHTSHIFT),
-        LABEL(KEY_KPASTERISK),
-        LABEL(KEY_LEFTALT),
-        LABEL(KEY_SPACE),
-        LABEL(KEY_CAPSLOCK),
-        LABEL(KEY_F1),
-        LABEL(KEY_F2),
-        LABEL(KEY_F3),
-        LABEL(KEY_F4),
-        LABEL(KEY_F5),
-        LABEL(KEY_F6),
-        LABEL(KEY_F7),
-        LABEL(KEY_F8),
-        LABEL(KEY_F9),
-        LABEL(KEY_F10),
-        LABEL(KEY_NUMLOCK),
-        LABEL(KEY_SCROLLLOCK),
-        LABEL(KEY_KP7),
-        LABEL(KEY_KP8),
-        LABEL(KEY_KP9),
-        LABEL(KEY_KPMINUS),
-        LABEL(KEY_KP4),
-        LABEL(KEY_KP5),
-        LABEL(KEY_KP6),
-        LABEL(KEY_KPPLUS),
-        LABEL(KEY_KP1),
-        LABEL(KEY_KP2),
-        LABEL(KEY_KP3),
-        LABEL(KEY_KP0),
-        LABEL(KEY_KPDOT),
-        LABEL(KEY_ZENKAKUHANKAKU),
-        LABEL(KEY_102ND),
-        LABEL(KEY_F11),
-        LABEL(KEY_F12),
-        LABEL(KEY_RO),
-        LABEL(KEY_KATAKANA),
-        LABEL(KEY_HIRAGANA),
-        LABEL(KEY_HENKAN),
-        LABEL(KEY_KATAKANAHIRAGANA),
-        LABEL(KEY_MUHENKAN),
-        LABEL(KEY_KPJPCOMMA),
-        LABEL(KEY_KPENTER),
-        LABEL(KEY_RIGHTCTRL),
-        LABEL(KEY_KPSLASH),
-        LABEL(KEY_SYSRQ),
-        LABEL(KEY_RIGHTALT),
-        LABEL(KEY_LINEFEED),
-        LABEL(KEY_HOME),
-        LABEL(KEY_UP),
-        LABEL(KEY_PAGEUP),
-        LABEL(KEY_LEFT),
-        LABEL(KEY_RIGHT),
-        LABEL(KEY_END),
-        LABEL(KEY_DOWN),
-        LABEL(KEY_PAGEDOWN),
-        LABEL(KEY_INSERT),
-        LABEL(KEY_DELETE),
-        LABEL(KEY_MACRO),
-        LABEL(KEY_MUTE),
-        LABEL(KEY_VOLUMEDOWN),
-        LABEL(KEY_VOLUMEUP),
-        LABEL(KEY_POWER),
-        LABEL(KEY_KPEQUAL),
-        LABEL(KEY_KPPLUSMINUS),
-        LABEL(KEY_PAUSE),
-        LABEL(KEY_SCALE),
-        LABEL(KEY_KPCOMMA),
-        LABEL(KEY_HANGEUL),
-        LABEL(KEY_HANGUEL),
-        LABEL(KEY_HANJA),
-        LABEL(KEY_YEN),
-        LABEL(KEY_LEFTMETA),
-        LABEL(KEY_RIGHTMETA),
-        LABEL(KEY_COMPOSE),
-        LABEL(KEY_STOP),
-        LABEL(KEY_AGAIN),
-        LABEL(KEY_PROPS),
-        LABEL(KEY_UNDO),
-        LABEL(KEY_FRONT),
-        LABEL(KEY_COPY),
-        LABEL(KEY_OPEN),
-        LABEL(KEY_PASTE),
-        LABEL(KEY_FIND),
-        LABEL(KEY_CUT),
-        LABEL(KEY_HELP),
-        LABEL(KEY_MENU),
-        LABEL(KEY_CALC),
-        LABEL(KEY_SETUP),
-        LABEL(KEY_SLEEP),
-        LABEL(KEY_WAKEUP),
-        LABEL(KEY_FILE),
-        LABEL(KEY_SENDFILE),
-        LABEL(KEY_DELETEFILE),
-        LABEL(KEY_XFER),
-        LABEL(KEY_PROG1),
-        LABEL(KEY_PROG2),
-        LABEL(KEY_WWW),
-        LABEL(KEY_MSDOS),
-        LABEL(KEY_COFFEE),
-        LABEL(KEY_SCREENLOCK),
-        LABEL(KEY_DIRECTION),
-        LABEL(KEY_CYCLEWINDOWS),
-        LABEL(KEY_MAIL),
-        LABEL(KEY_BOOKMARKS),
-        LABEL(KEY_COMPUTER),
-        LABEL(KEY_BACK),
-        LABEL(KEY_FORWARD),
-        LABEL(KEY_CLOSECD),
-        LABEL(KEY_EJECTCD),
-        LABEL(KEY_EJECTCLOSECD),
-        LABEL(KEY_NEXTSONG),
-        LABEL(KEY_PLAYPAUSE),
-        LABEL(KEY_PREVIOUSSONG),
-        LABEL(KEY_STOPCD),
-        LABEL(KEY_RECORD),
-        LABEL(KEY_REWIND),
-        LABEL(KEY_PHONE),
-        LABEL(KEY_ISO),
-        LABEL(KEY_CONFIG),
-        LABEL(KEY_HOMEPAGE),
-        LABEL(KEY_REFRESH),
-        LABEL(KEY_EXIT),
-        LABEL(KEY_MOVE),
-        LABEL(KEY_EDIT),
-        LABEL(KEY_SCROLLUP),
-        LABEL(KEY_SCROLLDOWN),
-        LABEL(KEY_KPLEFTPAREN),
-        LABEL(KEY_KPRIGHTPAREN),
-        LABEL(KEY_NEW),
-        LABEL(KEY_REDO),
-        LABEL(KEY_F13),
-        LABEL(KEY_F14),
-        LABEL(KEY_F15),
-        LABEL(KEY_F16),
-        LABEL(KEY_F17),
-        LABEL(KEY_F18),
-        LABEL(KEY_F19),
-        LABEL(KEY_F20),
-        LABEL(KEY_F21),
-        LABEL(KEY_F22),
-        LABEL(KEY_F23),
-        LABEL(KEY_F24),
-        LABEL(KEY_PLAYCD),
-        LABEL(KEY_PAUSECD),
-        LABEL(KEY_PROG3),
-        LABEL(KEY_PROG4),
-        LABEL(KEY_DASHBOARD),
-        LABEL(KEY_SUSPEND),
-        LABEL(KEY_CLOSE),
-        LABEL(KEY_PLAY),
-        LABEL(KEY_FASTFORWARD),
-        LABEL(KEY_BASSBOOST),
-        LABEL(KEY_PRINT),
-        LABEL(KEY_HP),
-        LABEL(KEY_CAMERA),
-        LABEL(KEY_SOUND),
-        LABEL(KEY_QUESTION),
-        LABEL(KEY_EMAIL),
-        LABEL(KEY_CHAT),
-        LABEL(KEY_SEARCH),
-        LABEL(KEY_CONNECT),
-        LABEL(KEY_FINANCE),
-        LABEL(KEY_SPORT),
-        LABEL(KEY_SHOP),
-        LABEL(KEY_ALTERASE),
-        LABEL(KEY_CANCEL),
-        LABEL(KEY_BRIGHTNESSDOWN),
-        LABEL(KEY_BRIGHTNESSUP),
-        LABEL(KEY_MEDIA),
-        LABEL(KEY_SWITCHVIDEOMODE),
-        LABEL(KEY_KBDILLUMTOGGLE),
-        LABEL(KEY_KBDILLUMDOWN),
-        LABEL(KEY_KBDILLUMUP),
-        LABEL(KEY_SEND),
-        LABEL(KEY_REPLY),
-        LABEL(KEY_FORWARDMAIL),
-        LABEL(KEY_SAVE),
-        LABEL(KEY_DOCUMENTS),
-        LABEL(KEY_BATTERY),
-        LABEL(KEY_BLUETOOTH),
-        LABEL(KEY_WLAN),
-        LABEL(KEY_UWB),
-        LABEL(KEY_UNKNOWN),
-        LABEL(KEY_VIDEO_NEXT),
-        LABEL(KEY_VIDEO_PREV),
-        LABEL(KEY_BRIGHTNESS_CYCLE),
-        LABEL(KEY_BRIGHTNESS_ZERO),
-        LABEL(KEY_DISPLAY_OFF),
-        LABEL(KEY_WIMAX),
-        LABEL(KEY_RFKILL),
-        LABEL(BTN_0),
-        LABEL(BTN_1),
-        LABEL(BTN_2),
-        LABEL(BTN_3),
-        LABEL(BTN_4),
-        LABEL(BTN_5),
-        LABEL(BTN_6),
-        LABEL(BTN_7),
-        LABEL(BTN_8),
-        LABEL(BTN_9),
-        LABEL(BTN_LEFT),
-        LABEL(BTN_RIGHT),
-        LABEL(BTN_MIDDLE),
-        LABEL(BTN_SIDE),
-        LABEL(BTN_EXTRA),
-        LABEL(BTN_FORWARD),
-        LABEL(BTN_BACK),
-        LABEL(BTN_TASK),
-        LABEL(BTN_JOYSTICK),
-        LABEL(BTN_TRIGGER),
-        LABEL(BTN_THUMB),
-        LABEL(BTN_THUMB2),
-        LABEL(BTN_TOP),
-        LABEL(BTN_TOP2),
-        LABEL(BTN_PINKIE),
-        LABEL(BTN_BASE),
-        LABEL(BTN_BASE2),
-        LABEL(BTN_BASE3),
-        LABEL(BTN_BASE4),
-        LABEL(BTN_BASE5),
-        LABEL(BTN_BASE6),
-        LABEL(BTN_DEAD),
-        LABEL(BTN_A),
-        LABEL(BTN_B),
-        LABEL(BTN_C),
-        LABEL(BTN_X),
-        LABEL(BTN_Y),
-        LABEL(BTN_Z),
-        LABEL(BTN_TL),
-        LABEL(BTN_TR),
-        LABEL(BTN_TL2),
-        LABEL(BTN_TR2),
-        LABEL(BTN_SELECT),
-        LABEL(BTN_START),
-        LABEL(BTN_MODE),
-        LABEL(BTN_THUMBL),
-        LABEL(BTN_THUMBR),
-        LABEL(BTN_TOOL_PEN),
-        LABEL(BTN_TOOL_RUBBER),
-        LABEL(BTN_TOOL_BRUSH),
-        LABEL(BTN_TOOL_PENCIL),
-        LABEL(BTN_TOOL_AIRBRUSH),
-        LABEL(BTN_TOOL_FINGER),
-        LABEL(BTN_TOOL_MOUSE),
-        LABEL(BTN_TOOL_LENS),
-        LABEL(BTN_TOUCH),
-        LABEL(BTN_STYLUS),
-        LABEL(BTN_STYLUS2),
-        LABEL(BTN_TOOL_DOUBLETAP),
-        LABEL(BTN_TOOL_TRIPLETAP),
-        LABEL(BTN_TOOL_QUADTAP),
-        LABEL(BTN_GEAR_DOWN),
-        LABEL(BTN_GEAR_UP),
-        LABEL(KEY_OK),
-        LABEL(KEY_SELECT),
-        LABEL(KEY_GOTO),
-        LABEL(KEY_CLEAR),
-        LABEL(KEY_POWER2),
-        LABEL(KEY_OPTION),
-        LABEL(KEY_INFO),
-        LABEL(KEY_TIME),
-        LABEL(KEY_VENDOR),
-        LABEL(KEY_ARCHIVE),
-        LABEL(KEY_PROGRAM),
-        LABEL(KEY_CHANNEL),
-        LABEL(KEY_FAVORITES),
-        LABEL(KEY_EPG),
-        LABEL(KEY_PVR),
-        LABEL(KEY_MHP),
-        LABEL(KEY_LANGUAGE),
-        LABEL(KEY_TITLE),
-        LABEL(KEY_SUBTITLE),
-        LABEL(KEY_ANGLE),
-        LABEL(KEY_ZOOM),
-        LABEL(KEY_MODE),
-        LABEL(KEY_KEYBOARD),
-        LABEL(KEY_SCREEN),
-        LABEL(KEY_PC),
-        LABEL(KEY_TV),
-        LABEL(KEY_TV2),
-        LABEL(KEY_VCR),
-        LABEL(KEY_VCR2),
-        LABEL(KEY_SAT),
-        LABEL(KEY_SAT2),
-        LABEL(KEY_CD),
-        LABEL(KEY_TAPE),
-        LABEL(KEY_RADIO),
-        LABEL(KEY_TUNER),
-        LABEL(KEY_PLAYER),
-        LABEL(KEY_TEXT),
-        LABEL(KEY_DVD),
-        LABEL(KEY_AUX),
-        LABEL(KEY_MP3),
-        LABEL(KEY_AUDIO),
-        LABEL(KEY_VIDEO),
-        LABEL(KEY_DIRECTORY),
-        LABEL(KEY_LIST),
-        LABEL(KEY_MEMO),
-        LABEL(KEY_CALENDAR),
-        LABEL(KEY_RED),
-        LABEL(KEY_GREEN),
-        LABEL(KEY_YELLOW),
-        LABEL(KEY_BLUE),
-        LABEL(KEY_CHANNELUP),
-        LABEL(KEY_CHANNELDOWN),
-        LABEL(KEY_FIRST),
-        LABEL(KEY_LAST),
-        LABEL(KEY_AB),
-        LABEL(KEY_NEXT),
-        LABEL(KEY_RESTART),
-        LABEL(KEY_SLOW),
-        LABEL(KEY_SHUFFLE),
-        LABEL(KEY_BREAK),
-        LABEL(KEY_PREVIOUS),
-        LABEL(KEY_DIGITS),
-        LABEL(KEY_TEEN),
-        LABEL(KEY_TWEN),
-        LABEL(KEY_VIDEOPHONE),
-        LABEL(KEY_GAMES),
-        LABEL(KEY_ZOOMIN),
-        LABEL(KEY_ZOOMOUT),
-        LABEL(KEY_ZOOMRESET),
-        LABEL(KEY_WORDPROCESSOR),
-        LABEL(KEY_EDITOR),
-        LABEL(KEY_SPREADSHEET),
-        LABEL(KEY_GRAPHICSEDITOR),
-        LABEL(KEY_PRESENTATION),
-        LABEL(KEY_DATABASE),
-        LABEL(KEY_NEWS),
-        LABEL(KEY_VOICEMAIL),
-        LABEL(KEY_ADDRESSBOOK),
-        LABEL(KEY_MESSENGER),
-        LABEL(KEY_DISPLAYTOGGLE),
-        LABEL(KEY_SPELLCHECK),
-        LABEL(KEY_LOGOFF),
-        LABEL(KEY_DOLLAR),
-        LABEL(KEY_EURO),
-        LABEL(KEY_FRAMEBACK),
-        LABEL(KEY_FRAMEFORWARD),
-        LABEL(KEY_CONTEXT_MENU),
-        LABEL(KEY_MEDIA_REPEAT),
-        LABEL(KEY_10CHANNELSUP),
-        LABEL(KEY_10CHANNELSDOWN),
-        LABEL(KEY_IMAGES),
-        LABEL(KEY_DEL_EOL),
-        LABEL(KEY_DEL_EOS),
-        LABEL(KEY_INS_LINE),
-        LABEL(KEY_DEL_LINE),
-        LABEL(KEY_FN),
-        LABEL(KEY_FN_ESC),
-        LABEL(KEY_FN_F1),
-        LABEL(KEY_FN_F2),
-        LABEL(KEY_FN_F3),
-        LABEL(KEY_FN_F4),
-        LABEL(KEY_FN_F5),
-        LABEL(KEY_FN_F6),
-        LABEL(KEY_FN_F7),
-        LABEL(KEY_FN_F8),
-        LABEL(KEY_FN_F9),
-        LABEL(KEY_FN_F10),
-        LABEL(KEY_FN_F11),
-        LABEL(KEY_FN_F12),
-        LABEL(KEY_FN_1),
-        LABEL(KEY_FN_2),
-        LABEL(KEY_FN_D),
-        LABEL(KEY_FN_E),
-        LABEL(KEY_FN_F),
-        LABEL(KEY_FN_S),
-        LABEL(KEY_FN_B),
-        LABEL(KEY_BRL_DOT1),
-        LABEL(KEY_BRL_DOT2),
-        LABEL(KEY_BRL_DOT3),
-        LABEL(KEY_BRL_DOT4),
-        LABEL(KEY_BRL_DOT5),
-        LABEL(KEY_BRL_DOT6),
-        LABEL(KEY_BRL_DOT7),
-        LABEL(KEY_BRL_DOT8),
-        LABEL(KEY_BRL_DOT9),
-        LABEL(KEY_BRL_DOT10),
-        LABEL(KEY_NUMERIC_0),
-        LABEL(KEY_NUMERIC_1),
-        LABEL(KEY_NUMERIC_2),
-        LABEL(KEY_NUMERIC_3),
-        LABEL(KEY_NUMERIC_4),
-        LABEL(KEY_NUMERIC_5),
-        LABEL(KEY_NUMERIC_6),
-        LABEL(KEY_NUMERIC_7),
-        LABEL(KEY_NUMERIC_8),
-        LABEL(KEY_NUMERIC_9),
-        LABEL(KEY_NUMERIC_STAR),
-        LABEL(KEY_NUMERIC_POUND),
-        LABEL(KEY_CAMERA_FOCUS),
-        LABEL(KEY_WPS_BUTTON),
-        LABEL(KEY_TOUCHPAD_TOGGLE),
-        LABEL(KEY_TOUCHPAD_ON),
-        LABEL(KEY_TOUCHPAD_OFF),
-        LABEL(KEY_CAMERA_ZOOMIN),
-        LABEL(KEY_CAMERA_ZOOMOUT),
-        LABEL(KEY_CAMERA_UP),
-        LABEL(KEY_CAMERA_DOWN),
-        LABEL(KEY_CAMERA_LEFT),
-        LABEL(KEY_CAMERA_RIGHT),
-        LABEL(BTN_TRIGGER_HAPPY1),
-        LABEL(BTN_TRIGGER_HAPPY2),
-        LABEL(BTN_TRIGGER_HAPPY3),
-        LABEL(BTN_TRIGGER_HAPPY4),
-        LABEL(BTN_TRIGGER_HAPPY5),
-        LABEL(BTN_TRIGGER_HAPPY6),
-        LABEL(BTN_TRIGGER_HAPPY7),
-        LABEL(BTN_TRIGGER_HAPPY8),
-        LABEL(BTN_TRIGGER_HAPPY9),
-        LABEL(BTN_TRIGGER_HAPPY10),
-        LABEL(BTN_TRIGGER_HAPPY11),
-        LABEL(BTN_TRIGGER_HAPPY12),
-        LABEL(BTN_TRIGGER_HAPPY13),
-        LABEL(BTN_TRIGGER_HAPPY14),
-        LABEL(BTN_TRIGGER_HAPPY15),
-        LABEL(BTN_TRIGGER_HAPPY16),
-        LABEL(BTN_TRIGGER_HAPPY17),
-        LABEL(BTN_TRIGGER_HAPPY18),
-        LABEL(BTN_TRIGGER_HAPPY19),
-        LABEL(BTN_TRIGGER_HAPPY20),
-        LABEL(BTN_TRIGGER_HAPPY21),
-        LABEL(BTN_TRIGGER_HAPPY22),
-        LABEL(BTN_TRIGGER_HAPPY23),
-        LABEL(BTN_TRIGGER_HAPPY24),
-        LABEL(BTN_TRIGGER_HAPPY25),
-        LABEL(BTN_TRIGGER_HAPPY26),
-        LABEL(BTN_TRIGGER_HAPPY27),
-        LABEL(BTN_TRIGGER_HAPPY28),
-        LABEL(BTN_TRIGGER_HAPPY29),
-        LABEL(BTN_TRIGGER_HAPPY30),
-        LABEL(BTN_TRIGGER_HAPPY31),
-        LABEL(BTN_TRIGGER_HAPPY32),
-        LABEL(BTN_TRIGGER_HAPPY33),
-        LABEL(BTN_TRIGGER_HAPPY34),
-        LABEL(BTN_TRIGGER_HAPPY35),
-        LABEL(BTN_TRIGGER_HAPPY36),
-        LABEL(BTN_TRIGGER_HAPPY37),
-        LABEL(BTN_TRIGGER_HAPPY38),
-        LABEL(BTN_TRIGGER_HAPPY39),
-        LABEL(BTN_TRIGGER_HAPPY40),
-        LABEL_END,
-};
-
-static struct label rel_labels[] = {
-        LABEL(REL_X),
-        LABEL(REL_Y),
-        LABEL(REL_Z),
-        LABEL(REL_RX),
-        LABEL(REL_RY),
-        LABEL(REL_RZ),
-        LABEL(REL_HWHEEL),
-        LABEL(REL_DIAL),
-        LABEL(REL_WHEEL),
-        LABEL(REL_MISC),
-        LABEL_END,
-};
-
-static struct label abs_labels[] = {
-        LABEL(ABS_X),
-        LABEL(ABS_Y),
-        LABEL(ABS_Z),
-        LABEL(ABS_RX),
-        LABEL(ABS_RY),
-        LABEL(ABS_RZ),
-        LABEL(ABS_THROTTLE),
-        LABEL(ABS_RUDDER),
-        LABEL(ABS_WHEEL),
-        LABEL(ABS_GAS),
-        LABEL(ABS_BRAKE),
-        LABEL(ABS_HAT0X),
-        LABEL(ABS_HAT0Y),
-        LABEL(ABS_HAT1X),
-        LABEL(ABS_HAT1Y),
-        LABEL(ABS_HAT2X),
-        LABEL(ABS_HAT2Y),
-        LABEL(ABS_HAT3X),
-        LABEL(ABS_HAT3Y),
-        LABEL(ABS_PRESSURE),
-        LABEL(ABS_DISTANCE),
-        LABEL(ABS_TILT_X),
-        LABEL(ABS_TILT_Y),
-        LABEL(ABS_TOOL_WIDTH),
-        LABEL(ABS_VOLUME),
-        LABEL(ABS_MISC),
-        LABEL(ABS_MT_SLOT),
-        LABEL(ABS_MT_TOUCH_MAJOR),
-        LABEL(ABS_MT_TOUCH_MINOR),
-        LABEL(ABS_MT_WIDTH_MAJOR),
-        LABEL(ABS_MT_WIDTH_MINOR),
-        LABEL(ABS_MT_ORIENTATION),
-        LABEL(ABS_MT_POSITION_X),
-        LABEL(ABS_MT_POSITION_Y),
-        LABEL(ABS_MT_TOOL_TYPE),
-        LABEL(ABS_MT_BLOB_ID),
-        LABEL(ABS_MT_TRACKING_ID),
-        LABEL(ABS_MT_PRESSURE),
-        LABEL(ABS_MT_DISTANCE),
-        LABEL_END,
-};
-
-static struct label sw_labels[] = {
-        LABEL(SW_LID),
-        LABEL(SW_TABLET_MODE),
-        LABEL(SW_HEADPHONE_INSERT),
-        LABEL(SW_RFKILL_ALL),
-        LABEL(SW_RADIO),
-        LABEL(SW_MICROPHONE_INSERT),
-        LABEL(SW_DOCK),
-        LABEL(SW_LINEOUT_INSERT),
-        LABEL(SW_JACK_PHYSICAL_INSERT),
-        LABEL(SW_VIDEOOUT_INSERT),
-        LABEL(SW_CAMERA_LENS_COVER),
-        LABEL(SW_KEYPAD_SLIDE),
-        LABEL(SW_FRONT_PROXIMITY),
-        LABEL(SW_ROTATE_LOCK),
-        LABEL_END,
-};
-
-static struct label msc_labels[] = {
-        LABEL(MSC_SERIAL),
-        LABEL(MSC_PULSELED),
-        LABEL(MSC_GESTURE),
-        LABEL(MSC_RAW),
-        LABEL(MSC_SCAN),
-        LABEL_END,
-};
-
-static struct label led_labels[] = {
-        LABEL(LED_NUML),
-        LABEL(LED_CAPSL),
-        LABEL(LED_SCROLLL),
-        LABEL(LED_COMPOSE),
-        LABEL(LED_KANA),
-        LABEL(LED_SLEEP),
-        LABEL(LED_SUSPEND),
-        LABEL(LED_MUTE),
-        LABEL(LED_MISC),
-        LABEL(LED_MAIL),
-        LABEL(LED_CHARGING),
-        LABEL_END,
-};
-
-static struct label rep_labels[] = {
-        LABEL(REP_DELAY),
-        LABEL(REP_PERIOD),
-        LABEL_END,
-};
-
-static struct label snd_labels[] = {
-        LABEL(SND_CLICK),
-        LABEL(SND_BELL),
-        LABEL(SND_TONE),
-        LABEL_END,
-};
-
-#if 0
-static struct label id_labels[] = {
-        LABEL(ID_BUS),
-        LABEL(ID_VENDOR),
-        LABEL(ID_PRODUCT),
-        LABEL(ID_VERSION),
-        LABEL_END,
-};
-
-static struct label bus_labels[] = {
-        LABEL(BUS_PCI),
-        LABEL(BUS_ISAPNP),
-        LABEL(BUS_USB),
-        LABEL(BUS_HIL),
-        LABEL(BUS_BLUETOOTH),
-        LABEL(BUS_VIRTUAL),
-        LABEL(BUS_ISA),
-        LABEL(BUS_I8042),
-        LABEL(BUS_XTKBD),
-        LABEL(BUS_RS232),
-        LABEL(BUS_GAMEPORT),
-        LABEL(BUS_PARPORT),
-        LABEL(BUS_AMIGA),
-        LABEL(BUS_ADB),
-        LABEL(BUS_I2C),
-        LABEL(BUS_HOST),
-        LABEL(BUS_GSC),
-        LABEL(BUS_ATARI),
-        LABEL(BUS_SPI),
-        LABEL_END,
-};
-#endif
-
-static struct label mt_tool_labels[] = {
-        LABEL(MT_TOOL_FINGER),
-        LABEL(MT_TOOL_PEN),
-        LABEL(MT_TOOL_MAX),
-        LABEL_END,
-};
-
-static struct label ff_status_labels[] = {
-        LABEL(FF_STATUS_STOPPED),
-        LABEL(FF_STATUS_PLAYING),
-        LABEL(FF_STATUS_MAX),
-        LABEL_END,
-};
-
-static struct label ff_labels[] = {
-        LABEL(FF_RUMBLE),
-        LABEL(FF_PERIODIC),
-        LABEL(FF_CONSTANT),
-        LABEL(FF_SPRING),
-        LABEL(FF_FRICTION),
-        LABEL(FF_DAMPER),
-        LABEL(FF_INERTIA),
-        LABEL(FF_RAMP),
-        LABEL(FF_SQUARE),
-        LABEL(FF_TRIANGLE),
-        LABEL(FF_SINE),
-        LABEL(FF_SAW_UP),
-        LABEL(FF_SAW_DOWN),
-        LABEL(FF_CUSTOM),
-        LABEL(FF_GAIN),
-        LABEL(FF_AUTOCENTER),
-        LABEL_END,
-};
-
-static struct label key_value_labels[] = {
-        { "UP", 0 },
-        { "DOWN", 1 },
-        { "REPEAT", 2 },
-        LABEL_END,
-};
diff --git a/toolbox/getsebool.c b/toolbox/getsebool.c
deleted file mode 100644
index aab5200..0000000
--- a/toolbox/getsebool.c
+++ /dev/null
@@ -1,104 +0,0 @@
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <getopt.h>
-#include <errno.h>
-#include <string.h>
-#include <selinux/selinux.h>
-
-static void usage(const char *progname)
-{
-    fprintf(stderr, "usage:  %s -a or %s boolean...\n", progname, progname);
-    exit(1);
-}
-
-int getsebool_main(int argc, char **argv)
-{
-    int i, get_all = 0, rc = 0, active, pending, len = 0, opt;
-    char **names;
-
-    while ((opt = getopt(argc, argv, "a")) > 0) {
-        switch (opt) {
-        case 'a':
-            if (argc > 2)
-                usage(argv[0]);
-            if (is_selinux_enabled() <= 0) {
-                fprintf(stderr, "%s:  SELinux is disabled\n",
-                        argv[0]);
-                return 1;
-            }
-            errno = 0;
-            rc = security_get_boolean_names(&names, &len);
-            if (rc) {
-                fprintf(stderr,
-                        "%s:  Unable to get boolean names:  %s\n",
-                        argv[0], strerror(errno));
-                return 1;
-            }
-            if (!len) {
-                printf("No booleans\n");
-                return 0;
-            }
-            get_all = 1;
-            break;
-        default:
-            usage(argv[0]);
-        }
-    }
-
-    if (is_selinux_enabled() <= 0) {
-        fprintf(stderr, "%s:  SELinux is disabled\n", argv[0]);
-        return 1;
-    }
-    if (!len) {
-        if (argc < 2)
-            usage(argv[0]);
-        len = argc - 1;
-        names = malloc(sizeof(char *) * len);
-        if (!names) {
-            fprintf(stderr, "%s:  out of memory\n", argv[0]);
-            return 2;
-        }
-        for (i = 0; i < len; i++) {
-            names[i] = strdup(argv[i + 1]);
-            if (!names[i]) {
-                fprintf(stderr, "%s:  out of memory\n",
-                        argv[0]);
-                return 2;
-            }
-        }
-    }
-
-    for (i = 0; i < len; i++) {
-        active = security_get_boolean_active(names[i]);
-        if (active < 0) {
-            if (get_all && errno == EACCES)
-                continue;
-            fprintf(stderr, "Error getting active value for %s\n",
-                    names[i]);
-            rc = -1;
-            goto out;
-        }
-        pending = security_get_boolean_pending(names[i]);
-        if (pending < 0) {
-            fprintf(stderr, "Error getting pending value for %s\n",
-                    names[i]);
-            rc = -1;
-            goto out;
-        }
-        if (pending != active) {
-            printf("%s --> %s pending: %s\n", names[i],
-                   (active ? "on" : "off"),
-                   (pending ? "on" : "off"));
-        } else {
-            printf("%s --> %s\n", names[i],
-                   (active ? "on" : "off"));
-        }
-    }
-
-out:
-    for (i = 0; i < len; i++)
-        free(names[i]);
-    free(names);
-    return rc;
-}
diff --git a/toolbox/ioctl.c b/toolbox/ioctl.c
index d1cc14a..093e467 100644
--- a/toolbox/ioctl.c
+++ b/toolbox/ioctl.c
@@ -1,36 +1,81 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
+/*
+ * 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.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * 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 <errno.h>
+#include <error.h>
 #include <fcntl.h>
 #include <getopt.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
-#include <linux/kd.h>
-#include <linux/vt.h>
-#include <errno.h>
-#include <pthread.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
 
-int ioctl_main(int argc, char *argv[])
-{
-    int c;
-    int fd;
-    int res;
+static void usage() {
+    fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
+            "  -l <length>   Length of io buffer\n"
+            "  -a <argsize>  Size of each argument (1-8)\n"
+            "  -r            Open device in read only mode\n"
+            "  -d            Direct argument (no iobuffer)\n"
+            "  -h            Print help\n", getprogname());
+    exit(1);
+}
 
+static int xstrtoi(const char* s, const char* what) {
+    char* endp;
+    errno = 0;
+    long result = strtol(s, &endp, 0);
+    if (errno != 0 || *endp != '\0') {
+        error(1, errno, "couldn't parse %s '%s'", what, s);
+    }
+    if (result > INT_MAX || result < INT_MIN) {
+        error(1, errno, "%s '%s' out of range", what, s);
+    }
+    return result;
+}
+
+int ioctl_main(int argc, char* argv[]) {
     int read_only = 0;
     int length = -1;
     int arg_size = 4;
     int direct_arg = 0;
-    uint32_t ioctl_nr;
+
     void *ioctl_args = NULL;
     uint8_t *ioctl_argp;
     uint8_t *ioctl_argp_save = NULL;
     int rem;
 
-    do {
-        c = getopt(argc, argv, "rdl:a:h");
-        if (c == EOF)
-            break;
+    int c;
+    while ((c = getopt(argc, argv, "rdl:a:h")) != -1) {
         switch (c) {
         case 'r':
             read_only = 1;
@@ -39,43 +84,44 @@
             direct_arg = 1;
             break;
         case 'l':
-            length = strtol(optarg, NULL, 0);
+            length = xstrtoi(optarg, "length");
             break;
         case 'a':
-            arg_size = strtol(optarg, NULL, 0);
+            arg_size = xstrtoi(optarg, "argument size");
             break;
         case 'h':
-            fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
-                    "  -l <length>   Length of io buffer\n"
-                    "  -a <argsize>  Size of each argument (1-8)\n"
-                    "  -r            Open device in read only mode\n"
-                    "  -d            Direct argument (no iobuffer)\n"
-                    "  -h            Print help\n", argv[0]);
-            return -1;
-        case '?':
-            fprintf(stderr, "%s: invalid option -%c\n",
-                argv[0], optopt);
-            exit(1);
+            usage();
+            break;
+        default:
+            error(1, 0, "invalid option -%c", optopt);
         }
-    } while (1);
-
-    if(optind + 2 > argc) {
-        fprintf(stderr, "%s: too few arguments\n", argv[0]);
-        exit(1);
     }
 
-    if (!strcmp(argv[optind], "-")) {
+    if (optind + 2 > argc) {
+        usage();
+    }
+
+    const char* device = argv[optind];
+    int fd;
+    if (strcmp(device, "-") == 0) {
         fd = STDIN_FILENO;
     } else {
-        fd = open(argv[optind], read_only ? O_RDONLY : (O_RDWR | O_SYNC));
-        if (fd < 0) {
-            fprintf(stderr, "cannot open %s\n", argv[optind]);
-            return 1;
+        fd = open(device, read_only ? O_RDONLY : (O_RDWR | O_SYNC));
+        if (fd == -1) {
+            error(1, errno, "cannot open %s", argv[optind]);
         }
     }
     optind++;
-    
-    ioctl_nr = strtol(argv[optind], NULL, 0);
+
+    // IOCTL(2) wants second parameter as a signed int.
+    // Let's let the user specify either negative numbers or large positive
+    // numbers, for the case where ioctl number is larger than INT_MAX.
+    errno = 0;
+    char* endp;
+    int ioctl_nr = UINT_MAX & strtoll(argv[optind], &endp, 0);
+    if (errno != 0 || *endp != '\0') {
+        error(1, errno, "couldn't parse ioctl number '%s'", argv[optind]);
+    }
     optind++;
 
     if(direct_arg) {
@@ -91,11 +137,10 @@
 
         ioctl_argp_save = ioctl_argp = ioctl_args;
         rem = length;
-        while(optind < argc) {
+        while (optind < argc) {
             uint64_t tmp = strtoull(argv[optind], NULL, 0);
-            if(rem < arg_size) {
-                fprintf(stderr, "%s: too many arguments\n", argv[0]);
-                exit(1);
+            if (rem < arg_size) {
+                error(1, 0, "too many arguments");
             }
             memcpy(ioctl_argp, &tmp, arg_size);
             ioctl_argp += arg_size;
@@ -108,8 +153,9 @@
     while(rem--) {
         printf(" 0x%02x", *ioctl_argp_save++);
     }
-    printf("\n");
+    printf(" to %s\n", device);
 
+    int res;
     if(direct_arg)
         res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args);
     else if(length)
@@ -118,10 +164,10 @@
         res = ioctl(fd, ioctl_nr, 0);
     if (res < 0) {
         free(ioctl_args);
-        fprintf(stderr, "ioctl 0x%x failed, %d\n", ioctl_nr, res);
-        return 1;
+        error(1, errno, "ioctl 0x%x failed (returned %d)", ioctl_nr, res);
     }
-    if(length) {
+
+    if (length) {
         printf("return buf:");
         ioctl_argp = ioctl_args;
         rem = length;
@@ -131,5 +177,6 @@
         printf("\n");
     }
     free(ioctl_args);
+    close(fd);
     return 0;
 }
diff --git a/toolbox/load_policy.c b/toolbox/load_policy.c
deleted file mode 100644
index 90d48c4..0000000
--- a/toolbox/load_policy.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <selinux/selinux.h>
-
-int load_policy_main(int argc, char **argv)
-{
-    int fd, rc;
-    struct stat sb;
-    void *map;
-    const char *path;
-
-    if (argc != 2) {
-        fprintf(stderr, "usage:  %s policy-file\n", argv[0]);
-        exit(1);
-    }
-
-    path = argv[1];
-    fd = open(path, O_RDONLY);
-    if (fd < 0) {
-        fprintf(stderr, "Could not open %s:  %s\n", path, strerror(errno));
-        exit(2);
-    }
-
-    if (fstat(fd, &sb) < 0) {
-        fprintf(stderr, "Could not stat %s:  %s\n", path, strerror(errno));
-        exit(3);
-    }
-
-    map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-    if (map == MAP_FAILED) {
-        fprintf(stderr, "Could not mmap %s:  %s\n", path, strerror(errno));
-        exit(4);
-    }
-
-    rc = security_load_policy(map, sb.st_size);
-    if (rc < 0) {
-        fprintf(stderr, "Could not load %s:  %s\n", path, strerror(errno));
-        exit(5);
-    }
-    munmap(map, sb.st_size);
-    close(fd);
-    exit(0);
-}
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index 01517fd..5b98a01 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -798,6 +798,7 @@
                         __unused int oflag,struct bpb *bpb)
 {
     struct hd_geometry geom;
+    u_long block_size;
 
     if (ioctl(fd, BLKSSZGET, &bpb->bps)) {
         fprintf(stderr, "Error getting bytes / sector (%s)\n", strerror(errno));
@@ -806,11 +807,18 @@
 
     ckgeom(fname, bpb->bps, "bytes/sector");
 
-    if (ioctl(fd, BLKGETSIZE, &bpb->bsec)) {
+    if (ioctl(fd, BLKGETSIZE, &block_size)) {
         fprintf(stderr, "Error getting blocksize (%s)\n", strerror(errno));
         exit(1);
     }
 
+    if (block_size > UINT32_MAX) {
+        fprintf(stderr, "Error blocksize too large: %lu\n", block_size);
+        exit(1);
+    }
+
+    bpb->bsec = (u_int)block_size;
+
     if (ioctl(fd, HDIO_GETGEO, &geom)) {
         fprintf(stderr, "Error getting gemoetry (%s) - trying sane values\n", strerror(errno));
         geom.heads = 64;
diff --git a/toolbox/prlimit.c b/toolbox/prlimit.c
new file mode 100644
index 0000000..8cf202a
--- /dev/null
+++ b/toolbox/prlimit.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014, 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.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * 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 <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+static void
+usage(const char *s)
+{
+    fprintf(stderr, "usage: %s pid resource cur max\n", s);
+    exit(EXIT_FAILURE);
+}
+
+int prlimit_main(int argc, char *argv[])
+{
+    pid_t pid;
+    struct rlimit64 rl;
+    int resource;
+    int rc;
+
+    if (argc != 5)
+        usage(*argv);
+
+    if (sscanf(argv[1], "%d", &pid) != 1)
+        usage(*argv);
+
+    if (sscanf(argv[2], "%d", &resource) != 1)
+        usage(*argv);
+
+    if (sscanf(argv[3], "%llu", &rl.rlim_cur) != 1)
+        usage(*argv);
+
+    if (sscanf(argv[4], "%llu", &rl.rlim_max) != 1)
+        usage(*argv);
+
+    printf("setting resource %d of pid %d to [%llu,%llu]\n", resource, pid,
+            rl.rlim_cur, rl.rlim_max);
+    rc = prlimit64(pid, resource, &rl, NULL);
+    if (rc < 0) {
+        perror("prlimit");
+        exit(EXIT_FAILURE);
+    }
+
+    return 0;
+}
diff --git a/toolbox/ps.c b/toolbox/ps.c
index d0a8db3..cf3f05a 100644
--- a/toolbox/ps.c
+++ b/toolbox/ps.c
@@ -1,6 +1,7 @@
 #include <ctype.h>
 #include <dirent.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -29,6 +30,12 @@
 #define SHOW_NUMERIC_UID 32
 #define SHOW_ABI 64
 
+#if __LP64__
+#define PC_WIDTH 10 /* Realistically, the top bits will be 0, so don't waste space. */
+#else
+#define PC_WIDTH (2*sizeof(uintptr_t))
+#endif
+
 static int display_flags = 0;
 static int ppid_filter = 0;
 
@@ -44,7 +51,8 @@
     int fd, r;
     char *ptr, *name, *state;
     int ppid;
-    unsigned wchan, rss, vss, eip;
+    unsigned rss, vss;
+    uintptr_t eip;
     unsigned utime, stime;
     int prio, nice, rtprio, sched, psr;
     struct passwd *pw;
@@ -124,7 +132,7 @@
     nexttok(&ptr); // blocked
     nexttok(&ptr); // sigignore
     nexttok(&ptr); // sigcatch
-    wchan = strtoul(nexttok(&ptr), 0, 10); // wchan
+    nexttok(&ptr); // wchan
     nexttok(&ptr); // nswap
     nexttok(&ptr); // cnswap
     nexttok(&ptr); // exit signal
@@ -176,7 +184,16 @@
             else
                 printf(" %.2s ", get_sched_policy_name(p));
         }
-        printf(" %08x %08x %s ", wchan, eip, state);
+        char path[PATH_MAX];
+        snprintf(path, sizeof(path), "/proc/%d/wchan", pid);
+        char wchan[10];
+        int fd = open(path, O_RDONLY);
+        ssize_t wchan_len = read(fd, wchan, sizeof(wchan));
+        if (wchan_len == -1) {
+            wchan[wchan_len = 0] = '\0';
+        }
+        close(fd);
+        printf(" %10.*s %0*" PRIxPTR " %s ", (int) wchan_len, wchan, (int) PC_WIDTH, eip, state);
         if (display_flags & SHOW_ABI) {
             print_exe_abi(pid);
         }
@@ -285,12 +302,13 @@
     }
 
     if (display_flags & SHOW_MACLABEL) {
-        printf("LABEL                          USER     PID   PPID  NAME\n");
+        printf("LABEL                          USER      PID   PPID  NAME\n");
     } else {
-        printf("USER     PID   PPID  VSIZE  RSS   %s%s %s WCHAN    PC        %sNAME\n",
+        printf("USER      PID   PPID  VSIZE  RSS  %s%s %sWCHAN      %*s  %sNAME\n",
                (display_flags&SHOW_CPU)?"CPU ":"",
                (display_flags&SHOW_PRIO)?"PRIO  NICE  RTPRI SCHED ":"",
                (display_flags&SHOW_POLICY)?"PCY " : "",
+               (int) PC_WIDTH, "PC",
                (display_flags&SHOW_ABI)?"ABI " : "");
     }
     while((de = readdir(d)) != 0){
diff --git a/toolbox/route.c b/toolbox/route.c
deleted file mode 100644
index 3e10014..0000000
--- a/toolbox/route.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (c) 2009, 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.
- *  * Neither the name of Google, Inc. nor the names of its contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * 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 <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <linux/route.h>
-
-static inline int set_address(const char *address, struct sockaddr *sa) {
-    return inet_aton(address, &((struct sockaddr_in *)sa)->sin_addr);
-}
-
-/* current support the following routing entries */
-/* route add default dev wlan0 */
-/* route add default gw 192.168.1.1 dev wlan0 */
-/* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */
-
-int route_main(int argc, char *argv[])
-{
-    struct rtentry rt = {
-        .rt_dst     = {.sa_family = AF_INET},
-        .rt_genmask = {.sa_family = AF_INET},
-        .rt_gateway = {.sa_family = AF_INET},
-    };
-
-    errno = EINVAL;
-    if (argc > 2 && !strcmp(argv[1], "add")) {
-        if (!strcmp(argv[2], "default")) {
-            /* route add default dev wlan0 */
-            if (argc > 4 && !strcmp(argv[3], "dev")) {
-                rt.rt_flags = RTF_UP;
-                rt.rt_dev = argv[4];
-                errno = 0;
-                goto apply;
-            }
-
-            /* route add default gw 192.168.1.1 dev wlan0 */
-            if (argc > 6 && !strcmp(argv[3], "gw") && !strcmp(argv[5], "dev")) {
-                rt.rt_flags = RTF_UP | RTF_GATEWAY;
-                rt.rt_dev = argv[6];
-                if (set_address(argv[4], &rt.rt_gateway)) {
-                    errno = 0;
-                }
-                goto apply;
-            }
-        }
-
-        /* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */
-        if (argc > 7 && !strcmp(argv[2], "-net") &&
-                !strcmp(argv[4], "netmask")) {
-            if (!strcmp(argv[6], "gw")) {
-                rt.rt_flags = RTF_UP | RTF_GATEWAY;
-                if (set_address(argv[3], &rt.rt_dst) &&
-                    set_address(argv[5], &rt.rt_genmask) &&
-                    set_address(argv[7], &rt.rt_gateway)) {
-                    errno = 0;
-                }
-                goto apply;
-            } else if (!strcmp(argv[6], "dev")) {
-                rt.rt_flags = RTF_UP;
-                rt.rt_dev = argv[7];
-                if (set_address(argv[3], &rt.rt_dst) &&
-                    set_address(argv[5], &rt.rt_genmask)) {
-                    errno = 0;
-                }
-                goto apply;
-            }
-        }
-    }
-
-apply:
-    if (!errno) {
-        int s = socket(AF_INET, SOCK_DGRAM, 0);
-        if (s != -1 && (ioctl(s, SIOCADDRT, &rt) != -1 || errno == EEXIST)) {
-            return 0;
-        }
-    }
-    puts(strerror(errno));
-    return errno;
-}
diff --git a/toolbox/runcon.c b/toolbox/runcon.c
deleted file mode 100644
index 4a57bf3..0000000
--- a/toolbox/runcon.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <selinux/selinux.h>
-
-int runcon_main(int argc, char **argv)
-{
-    int rc;
-
-    if (argc < 3) {
-        fprintf(stderr, "usage:  %s context program args...\n", argv[0]);
-        exit(1);
-    }
-
-    rc = setexeccon(argv[1]);
-    if (rc < 0) {
-        fprintf(stderr, "Could not set context to %s:  %s\n", argv[1], strerror(errno));
-        exit(2);
-    }
-
-    argv += 2;
-    argc -= 2;
-    execvp(argv[0], argv);
-    fprintf(stderr, "Could not exec %s:  %s\n", argv[0], strerror(errno));
-    exit(3);
-}
diff --git a/toolbox/schedtop.c b/toolbox/schedtop.c
deleted file mode 100644
index 2fccd2e..0000000
--- a/toolbox/schedtop.c
+++ /dev/null
@@ -1,330 +0,0 @@
-#include <ctype.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-struct thread_info {
-    int pid;
-    int tid;
-    char name[64];
-    unsigned long long exec_time;
-    unsigned long long delay_time;
-    unsigned long long run_count;
-};
-
-struct thread_table {
-    size_t allocated;
-    size_t active;
-    struct thread_info *data;
-};
-
-enum {
-    FLAG_BATCH = 1U << 0,
-    FLAG_HIDE_IDLE = 1U << 1,
-    FLAG_SHOW_THREADS = 1U << 2,
-    FLAG_USE_ALTERNATE_SCREEN = 1U << 3,
-};
-
-static int time_dp = 9;
-static int time_div = 1;
-#define NS_TO_S_D(ns) \
-    (uint32_t)((ns) / 1000000000), time_dp, ((uint32_t)((ns) % 1000000000) / time_div)
-
-struct thread_table processes;
-struct thread_table last_processes;
-struct thread_table threads;
-struct thread_table last_threads;
-
-static void grow_table(struct thread_table *table)
-{
-    size_t size = table->allocated;
-    struct thread_info *new_table;
-    if (size < 128)
-        size = 128;
-    else
-        size *= 2;
-    
-    new_table = realloc(table->data, size * sizeof(*table->data));
-    if (new_table == NULL) {
-        fprintf(stderr, "out of memory\n");
-        exit(1);
-    }
-    table->data = new_table;
-    table->allocated = size;
-}
-
-static struct thread_info *get_item(struct thread_table *table)
-{
-    if (table->active >= table->allocated)
-        grow_table(table);
-    return table->data + table->active;
-}
-
-static void commit_item(struct thread_table *table)
-{
-    table->active++;
-}
-
-static int read_line(char *line, size_t line_size)
-{
-    int fd;
-    int len;
-    fd = open(line, O_RDONLY);
-    if(fd == 0)
-        return -1;
-    len = read(fd, line, line_size - 1);
-    close(fd);
-    if (len <= 0)
-        return -1;
-    line[len] = '\0';
-    return 0;
-}
-
-static void add_thread(int pid, int tid, struct thread_info *proc_info)
-{
-    char line[1024];
-    char *name, *name_end;
-    size_t name_len;
-    struct thread_info *info;
-    if(tid == 0)
-        info = get_item(&processes);
-    else
-        info = get_item(&threads);
-    info->pid = pid;
-    info->tid = tid;
-
-    if(tid)
-        sprintf(line, "/proc/%d/task/%d/schedstat", pid, tid);
-    else
-        sprintf(line, "/proc/%d/schedstat", pid);
-    if (read_line(line, sizeof(line)))
-        return;
-    if(sscanf(line, "%llu %llu %llu",
-              &info->exec_time, &info->delay_time, &info->run_count) != 3)
-        return;
-    if (proc_info) {
-        proc_info->exec_time += info->exec_time;
-        proc_info->delay_time += info->delay_time;
-        proc_info->run_count += info->run_count;
-    }
-
-    name = NULL;
-    if (!tid) {
-        sprintf(line, "/proc/%d/cmdline", pid);
-        if (read_line(line, sizeof(line)) == 0 && line[0]) {
-            name = line;
-            name_len = strlen(name);
-        }
-    }
-    if (!name) {
-        if (tid)
-            sprintf(line, "/proc/%d/task/%d/stat", pid, tid);
-        else
-            sprintf(line, "/proc/%d/stat", pid);
-        if (read_line(line, sizeof(line)))
-            return;
-        name = strchr(line, '(');
-        if (name == NULL)
-            return;
-        name_end = strchr(name, ')');
-        if (name_end == NULL)
-            return;
-        name++;
-        name_len = name_end - name;
-    }
-    if (name_len >= sizeof(info->name))
-        name_len = sizeof(info->name) - 1;
-    memcpy(info->name, name, name_len);
-    info->name[name_len] = '\0';
-    if(tid == 0)
-        commit_item(&processes);
-    else
-        commit_item(&threads);
-}
-
-static void add_threads(int pid, struct thread_info *proc_info)
-{
-    char path[1024];
-    DIR *d;
-    struct dirent *de;
-    sprintf(path, "/proc/%d/task", pid);
-    d = opendir(path);
-    if(d == 0) return;
-    while((de = readdir(d)) != 0){
-        if(isdigit(de->d_name[0])){
-            int tid = atoi(de->d_name);
-            add_thread(pid, tid, proc_info);
-        }
-    }
-    closedir(d);
-}
-
-static void print_threads(int pid, uint32_t flags)
-{
-    size_t i, j;
-    for (i = 0; i < last_threads.active; i++) {
-        int epid = last_threads.data[i].pid;
-        int tid = last_threads.data[i].tid;
-        if (epid != pid)
-            continue;
-        for (j = 0; j < threads.active; j++)
-            if (tid == threads.data[j].tid)
-                break;
-        if (j == threads.active)
-            printf(" %5u died\n", tid);
-        else if (!(flags & FLAG_HIDE_IDLE) || threads.data[j].run_count - last_threads.data[i].run_count)
-            printf(" %5u %2u.%0*u %2u.%0*u %5llu %5u.%0*u %5u.%0*u %7llu  %s\n", tid,
-                NS_TO_S_D(threads.data[j].exec_time - last_threads.data[i].exec_time),
-                NS_TO_S_D(threads.data[j].delay_time - last_threads.data[i].delay_time),
-                threads.data[j].run_count - last_threads.data[i].run_count,
-                NS_TO_S_D(threads.data[j].exec_time), NS_TO_S_D(threads.data[j].delay_time),
-                threads.data[j].run_count, threads.data[j].name);
-    }
-}
-
-static void update_table(DIR *d, uint32_t flags)
-{
-    size_t i, j;
-    struct dirent *de;
-    
-    rewinddir(d);
-    while((de = readdir(d)) != 0){
-        if(isdigit(de->d_name[0])){
-            int pid = atoi(de->d_name);
-            struct thread_info *proc_info;
-            add_thread(pid, 0, NULL);
-            proc_info = &processes.data[processes.active - 1];
-            proc_info->exec_time = 0;
-            proc_info->delay_time = 0;
-            proc_info->run_count = 0;
-            add_threads(pid, proc_info);
-        }
-    }
-    if (!(flags & FLAG_BATCH))
-        printf("\e[H\e[0J");
-    printf("Processes: %zu, Threads %zu\n", processes.active, threads.active);
-    switch (time_dp) {
-    case 3:
-        printf("   TID --- SINCE LAST ---- ---------- TOTAL ----------\n");
-        printf("  PID  EXEC_T  DELAY SCHED EXEC_TIME DELAY_TIM   SCHED NAME\n");
-        break;
-    case 6:
-        printf("   TID ------ SINCE LAST -------    ------------ TOTAL -----------\n");
-        printf("  PID  EXEC_TIME DELAY_TIM SCHED    EXEC_TIME   DELAY_TIME   SCHED NAME\n");
-        break;
-    default:
-        printf("   TID    -------- SINCE LAST --------       ------------- TOTAL -------------\n");
-        printf("  PID     EXEC_TIME   DELAY_TIME SCHED       EXEC_TIME      DELAY_TIME   SCHED NAME\n");
-        break;
-    }
-    for (i = 0; i < last_processes.active; i++) {
-        int pid = last_processes.data[i].pid;
-        for (j = 0; j < processes.active; j++)
-            if (pid == processes.data[j].pid)
-                break;
-        if (j == processes.active)
-            printf("%5u died\n", pid);
-        else if (!(flags & FLAG_HIDE_IDLE) || processes.data[j].run_count - last_processes.data[i].run_count) {
-            printf("%5u  %2u.%0*u %2u.%0*u %5llu %5u.%0*u %5u.%0*u %7llu %s\n", pid,
-                NS_TO_S_D(processes.data[j].exec_time - last_processes.data[i].exec_time),
-                NS_TO_S_D(processes.data[j].delay_time - last_processes.data[i].delay_time),
-                processes.data[j].run_count - last_processes.data[i].run_count,
-                NS_TO_S_D(processes.data[j].exec_time), NS_TO_S_D(processes.data[j].delay_time),
-                processes.data[j].run_count, processes.data[j].name);
-            if (flags & FLAG_SHOW_THREADS)
-                print_threads(pid, flags);
-        }
-    }
-
-    {
-        struct thread_table tmp;
-        tmp = last_processes;
-        last_processes = processes;
-        processes = tmp;
-        processes.active = 0;
-        tmp = last_threads;
-        last_threads = threads;
-        threads = tmp;
-        threads.active = 0;
-    }
-}
-
-void
-sig_abort(int signum)
-{
-    printf("\e[?47l");
-    exit(0);
-}
-
-
-int schedtop_main(int argc, char **argv)
-{
-    int c;
-    DIR *d;
-    uint32_t flags = 0;    
-    int delay = 3000000;
-    float delay_f;
-
-    while(1) {
-        c = getopt(argc, argv, "d:ibtamun");
-        if (c == EOF)
-            break;
-        switch (c) {
-        case 'd':
-            delay_f = atof(optarg);
-            delay = delay_f * 1000000;
-            break;
-        case 'b':
-            flags |= FLAG_BATCH;
-            break;
-        case 'i':
-            flags |= FLAG_HIDE_IDLE;
-            break;
-        case 't':
-            flags |= FLAG_SHOW_THREADS;
-            break;
-        case 'a':
-            flags |= FLAG_USE_ALTERNATE_SCREEN;
-            break;
-        case 'm':
-            time_dp = 3;
-            time_div = 1000000;
-            break;
-        case 'u':
-            time_dp = 6;
-            time_div = 1000;
-            break;
-        case 'n':
-            time_dp = 9;
-            time_div = 1;
-            break;
-        }
-    }
-
-    d = opendir("/proc");
-    if(d == 0) return -1;
-
-    if (!(flags & FLAG_BATCH)) {
-        if(flags & FLAG_USE_ALTERNATE_SCREEN) {
-            signal(SIGINT, sig_abort);
-            signal(SIGPIPE, sig_abort);
-            signal(SIGTERM, sig_abort);
-            printf("\e7\e[?47h");
-        }
-        printf("\e[2J");
-    }
-    while (1) {
-        update_table(d, flags);
-        usleep(delay);
-    }
-    closedir(d);
-    return 0;
-}
diff --git a/toolbox/setsebool.c b/toolbox/setsebool.c
deleted file mode 100644
index f79a612..0000000
--- a/toolbox/setsebool.c
+++ /dev/null
@@ -1,46 +0,0 @@
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <selinux/selinux.h>
-#include <errno.h>
-
-static int do_setsebool(int nargs, char **args) {
-    const char *name = args[1];
-    const char *value = args[2];
-    SELboolean b;
-
-    if (is_selinux_enabled() <= 0)
-        return 0;
-
-    b.name = name;
-    if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on"))
-        b.value = 1;
-    else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off"))
-        b.value = 0;
-    else {
-        fprintf(stderr, "setsebool: invalid value %s\n", value);
-        return -1;
-    }
-
-    if (security_set_boolean_list(1, &b, 0) < 0)
-    {
-        fprintf(stderr, "setsebool: could not set %s to %s:  %s", name, value, strerror(errno));
-        return -1;
-    }
-
-    return 0;
-}
-
-int setsebool_main(int argc, char **argv)
-{
-    if (argc != 3) {
-        fprintf(stderr, "Usage:  %s name value\n", argv[0]);
-        exit(1);
-    }
-
-    return do_setsebool(argc, argv);
-}
diff --git a/toolbox/smd.c b/toolbox/smd.c
deleted file mode 100644
index 343dea7..0000000
--- a/toolbox/smd.c
+++ /dev/null
@@ -1,42 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-
-int smd_main(int argc, char **argv)
-{
-    int fd, len, r, port = 0;
-    char devname[32];
-    argc--;
-    argv++;
-
-    if((argc > 0) && (argv[0][0] == '-')) {
-        port = atoi(argv[0] + 1);
-        argc--;
-        argv++;
-    }
-
-    sprintf(devname,"/dev/smd%d",port);
-    fd = open(devname, O_WRONLY);
-    if(fd < 0) {
-        fprintf(stderr,"failed to open smd0 - %s\n",
-            strerror(errno));
-        return -1;
-    }
-    while(argc > 0) {
-        len = strlen(argv[0]);
-        r = write(fd, argv[0], len);
-        if(r != len) {
-            fprintf(stderr,"failed to write smd0 (%d) %s\n",
-                r, strerror(errno));
-            return -1;
-        }
-        argc--;
-        argv++;
-        write(fd, argc ? " " : "\r", 1);
-    }
-    close(fd);
-    return 0;       
-}
diff --git a/toolbox/umount.c b/toolbox/umount.c
deleted file mode 100644
index 3e17396..0000000
--- a/toolbox/umount.c
+++ /dev/null
@@ -1,90 +0,0 @@
-
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <linux/loop.h>
-#include <errno.h>
-
-#define LOOPDEV_MAXLEN 64
-#define LOOP_MAJOR 7
-
-static int is_loop(char *dev)
-{
-    struct stat st;
-    int ret = 0;
-
-    if (stat(dev, &st) == 0) {
-        if (S_ISBLK(st.st_mode) && (major(st.st_rdev) == LOOP_MAJOR)) {
-            ret = 1;
-        }
-    }
-
-    return ret;
-}
-
-static int is_loop_mount(const char* path, char *loopdev)
-{
-    FILE* f;
-    int count;
-    char device[256];
-    char mount_path[256];
-    char rest[256];
-    int result = 0;
-    
-    f = fopen("/proc/mounts", "r");
-    if (!f) {
-        fprintf(stdout, "could not open /proc/mounts: %s\n", strerror(errno));
-        return -1;
-    }
-
-    do {
-        count = fscanf(f, "%255s %255s %255s\n", device, mount_path, rest);
-        if (count == 3) {
-            if (is_loop(device) && strcmp(path, mount_path) == 0) {
-                strlcpy(loopdev, device, LOOPDEV_MAXLEN);
-                result = 1;
-                break;
-            }
-        }
-    } while (count == 3);
-
-    fclose(f);
-    return result;
-}
-
-int umount_main(int argc, char *argv[])
-{
-    int loop, loop_fd;
-    char loopdev[LOOPDEV_MAXLEN];
-
-    if(argc != 2) {
-        fprintf(stderr,"umount <path>\n");
-        return 1;
-    }
-
-    loop = is_loop_mount(argv[1], loopdev);
-    if (umount(argv[1])) {
-        fprintf(stderr, "failed: %s\n", strerror(errno));
-        return 1;
-    }
-
-    if (loop) {
-        // free the loop device
-        loop_fd = open(loopdev, O_RDONLY);
-        if (loop_fd < 0) {
-            fprintf(stderr, "open loop device failed: %s\n", strerror(errno));
-            return 1;
-        }
-        if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
-            fprintf(stderr, "ioctl LOOP_CLR_FD failed: %s\n", strerror(errno));
-            return 1;
-        }
-
-        close(loop_fd);
-    }
-
-    return 0;
-}
diff --git a/toolbox/uptime.c b/toolbox/uptime.c
index 2dd8084..ebfb15e 100644
--- a/toolbox/uptime.c
+++ b/toolbox/uptime.c
@@ -29,71 +29,33 @@
  * SUCH DAMAGE.
  */
 
-#include <sys/time.h>
-#include <linux/ioctl.h>
-#include <linux/rtc.h>
-#include <linux/android_alarm.h>
-#include <fcntl.h>
+#include <errno.h>
 #include <stdio.h>
+#include <string.h>
 #include <time.h>
-#include <unistd.h>
 
 static void format_time(int time, char* buffer) {
-    int seconds, minutes, hours, days;
-
-    seconds = time % 60;
+    int seconds = time % 60;
     time /= 60;
-    minutes = time % 60;
+    int minutes = time % 60;
     time /= 60;
-    hours = time % 24;
-    days = time / 24;
+    int hours = time % 24;
+    int days = time / 24;
 
-    if (days > 0)
-        sprintf(buffer, "%d days, %02d:%02d:%02d", days, hours, minutes, seconds);
-    else
+    if (days > 0) {
+        sprintf(buffer, "%d day%s, %02d:%02d:%02d", days, (days == 1) ? "" : "s", hours, minutes, seconds);
+    } else {
         sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds);
+    }
 }
 
-static int elapsedRealtimeAlarm(struct timespec *ts)
-{
-    int fd, result;
-
-    fd = open("/dev/alarm", O_RDONLY);
-    if (fd < 0)
-        return fd;
-
-    result = ioctl(fd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), ts);
-    close(fd);
-
-    return result;
-}
-
-int64_t elapsedRealtime()
-{
-    struct timespec ts;
-
-    int result = elapsedRealtimeAlarm(&ts);
-    if (result < 0)
-        result = clock_gettime(CLOCK_BOOTTIME, &ts);
-
-    if (result == 0)
-        return ts.tv_sec;
-    return -1;
-}
-
-int uptime_main(int argc __attribute__((unused)),
-        char *argv[] __attribute__((unused)))
-{
-    float up_time, idle_time;
-    char up_string[100], idle_string[100], sleep_string[100];
-    int elapsed;
-    struct timespec up_timespec;
-
+int uptime_main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) {
     FILE* file = fopen("/proc/uptime", "r");
     if (!file) {
         fprintf(stderr, "Could not open /proc/uptime\n");
         return -1;
     }
+    float idle_time;
     if (fscanf(file, "%*f %f", &idle_time) != 1) {
         fprintf(stderr, "Could not parse /proc/uptime\n");
         fclose(file);
@@ -101,18 +63,21 @@
     }
     fclose(file);
 
-    if (clock_gettime(CLOCK_MONOTONIC, &up_timespec) < 0) {
-        fprintf(stderr, "Could not get monotonic time\n");
+    struct timespec up_timespec;
+    if (clock_gettime(CLOCK_MONOTONIC, &up_timespec) == -1) {
+        fprintf(stderr, "Could not get monotonic time: %s\n", strerror(errno));
 	return -1;
     }
-    up_time = up_timespec.tv_sec + up_timespec.tv_nsec / 1e9;
+    float up_time = up_timespec.tv_sec + up_timespec.tv_nsec / 1e9;
 
-    elapsed = elapsedRealtime();
-    if (elapsed < 0) {
-        fprintf(stderr, "elapsedRealtime failed\n");
+    struct timespec elapsed_timespec;
+    if (clock_gettime(CLOCK_BOOTTIME, &elapsed_timespec) == -1) {
+        fprintf(stderr, "Could not get boot time: %s\n", strerror(errno));
         return -1;
     }
+    int elapsed = elapsed_timespec.tv_sec;
 
+    char up_string[100], idle_string[100], sleep_string[100];
     format_time(elapsed, up_string);
     format_time((int)idle_time, idle_string);
     format_time((int)(elapsed - up_time), sleep_string);
diff --git a/toolbox/wipe.c b/toolbox/wipe.c
deleted file mode 100644
index 650a0d6..0000000
--- a/toolbox/wipe.c
+++ /dev/null
@@ -1,176 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <cutils/android_reboot.h>
-#include <sys/stat.h>
-
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
-
-
-/* Directories created by init defined in system/rootdir/init.rc */
-static char *INIT_DIRS[] = {
-    "/system/etc/ppp",
-    "/data/misc",
-    "/data/local",
-    "/data/local/tmp",
-    "/data/data",
-    "/data/app_private",
-    "/data/app",
-    NULL
-};
-
-static void wipe (const char *path);
-
-static int usage()
-{
-    fprintf(stderr, "wipe <system|data|all>\n\n"
-                    "system means '/system'\n"
-                    "data means '/data'\n");
-
-    return -1;
-}
-
-int wipe_main (int argc, char *argv[])
-{
-    char *whatToWipe;
-
-    if (argc != 2) return usage();
-
-    whatToWipe = argv[1];
-
-    if (0 == strcmp (whatToWipe, "system")) {
-        fprintf(stdout, "Wiping /system\n");
-        wipe ("/system");
-        fprintf(stdout, "Done wiping /android\n");
-    } else if (0 == strcmp (whatToWipe, "data")) {
-        fprintf(stdout, "Wiping /data\n");
-        wipe ("/data");
-        fprintf(stdout, "Done wiping /data\n");
-    } else if (0 == strcmp (whatToWipe, "all")) {
-        fprintf(stdout, "Wiping /system and /data\n");
-        wipe ("/system");
-        wipe ("/data");
-        fprintf(stdout, "Done wiping /system and /data\n");
-    } else if (0 == strcmp(whatToWipe, "nuke")) {
-		int ret;
-		fprintf(stdout, "Nuking the device...\n");
-		wipe ("/system");
-        wipe ("/data");
-		fprintf(stdout, "Device nuked! Rebooting...\n");
-		ret = android_reboot(ANDROID_RB_RESTART, 0, 0);
-	    if (ret < 0) {
-	        fprintf(stderr, "Reboot failed, %s\n", strerror(errno));
-	        return 1;
-	    }
-	} else {
-        return usage();
-    }
-
-    return 0;
-}
-
-static char nameBuffer[PATH_MAX];
-static struct stat statBuffer;
-
-static void wipe (const char *path) 
-{
-    DIR *dir;
-    struct dirent *de;
-    int ret;
-
-    dir = opendir(path);
-
-    if (dir == NULL) {
-        fprintf (stderr, "Error opendir'ing %s '%s'\n",
-                    path, strerror(errno));
-        return;
-    }
-
-    char *filenameOffset;
-
-    strcpy(nameBuffer, path);
-    strcat(nameBuffer, "/");
-
-    filenameOffset = nameBuffer + strlen(nameBuffer);
-
-    for (;;) {
-        de = readdir(dir);
-
-        if (de == NULL) {
-            break;
-        }
-
-        if (0 == strcmp(de->d_name, ".")
-                || 0 == strcmp(de->d_name, "..")
-                || 0 == strcmp(de->d_name, "lost+found")
-        ) {
-            continue;
-        }
-
-        strcpy(filenameOffset, de->d_name);
-
-        ret = lstat (nameBuffer, &statBuffer);
-
-        if (ret != 0) {
-            fprintf(stderr, "stat() error on '%s' '%s'\n", 
-                    nameBuffer, strerror(errno));
-        }
-
-        if(S_ISDIR(statBuffer.st_mode)) {
-            int i;
-            char *newpath;
-
-#if 0
-            closedir(dir);
-#endif
-
-            newpath = strdup(nameBuffer);
-            wipe(newpath);
-
-            /* Leave directories created by init, they have special permissions. */
-            for (i = 0; INIT_DIRS[i]; i++) {
-                if (strcmp(INIT_DIRS[i], newpath) == 0) {
-                    break;
-                }
-            }
-            if (INIT_DIRS[i] == NULL) {
-                ret = rmdir(newpath);
-                if (ret != 0) {
-                    fprintf(stderr, "rmdir() error on '%s' '%s'\n", 
-                        newpath, strerror(errno));
-                }
-            }
-
-            free(newpath);
-
-#if 0
-            dir = opendir(path);
-            if (dir == NULL) {
-                fprintf (stderr, "Error opendir'ing %s '%s'\n",
-                            path, strerror(errno));
-                return;
-            }
-#endif
-
-            strcpy(nameBuffer, path);
-            strcat(nameBuffer, "/");
-
-        } else {
-            ret = unlink(nameBuffer);
-
-            if (ret != 0) {
-                fprintf(stderr, "unlink() error on '%s' '%s'\n", 
-                    nameBuffer, strerror(errno));
-            }
-        }
-    }
-
-    closedir(dir);
-
-}