Merge "Fix comment in audio definitions header"
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
index 2b83a1f..0395c8e 100644
--- a/adb/.clang-format
+++ b/adb/.clang-format
@@ -4,8 +4,8 @@
 
 CommentPragmas: NOLINT:.*
 DerivePointerAlignment: false
-IndentWidth: 2
+IndentWidth: 4
 PointerAlignment: Left
-TabWidth: 2
+TabWidth: 4
 UseTab: Never
 PenaltyExcessCharacter: 32
diff --git a/adb/Android.mk b/adb/Android.mk
index 8171611..8d38077 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -90,7 +90,7 @@
 LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS)
 LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS)
 LOCAL_STATIC_LIBRARIES := libadbd
-LOCAL_SHARED_LIBRARIES := liblog libcutils libutils
+LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
 include $(BUILD_NATIVE_TEST)
 
 include $(CLEAR_VARS)
@@ -98,12 +98,11 @@
 LOCAL_MODULE := adb_test
 LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
 LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS) services.cpp
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libbase
 LOCAL_STATIC_LIBRARIES := \
     libadb \
     libcrypto_static \
     libcutils \
-    libutils \
 
 ifeq ($(HOST_OS),linux)
   LOCAL_LDLIBS += -lrt -ldl -lpthread
@@ -200,7 +199,7 @@
 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
 
diff --git a/adb/adb.cpp b/adb/adb.cpp
index ffa93f4..ad85184f 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -14,21 +14,24 @@
  * 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"
@@ -74,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;
@@ -106,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;
@@ -138,6 +192,10 @@
         if (*p)
             p++;
     }
+
+#if !ADB_HOST
+    start_device_log();
+#endif
 }
 
 apacket* get_apacket(void)
diff --git a/adb/adb.h b/adb/adb.h
index 1aeac6b..749515c 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -298,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
 
diff --git a/adb/adb_auth.cpp b/adb/adb_auth.cpp
index c236b64..dc01825 100644
--- a/adb/adb_auth.cpp
+++ 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,9 +26,7 @@
 #include <unistd.h>
 
 #include "adb.h"
-#include "adb_auth.h"
 #include "transport.h"
-#include "sysdeps.h"
 
 int auth_enabled = 0;
 
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index 1487287..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,6 +41,7 @@
 
 #if ADB_HOST
 
+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);
@@ -58,6 +60,8 @@
 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(uint8_t* token, uint8_t* sig, int siglen);
 void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t);
diff --git a/adb/adb_auth_client.cpp b/adb/adb_auth_client.cpp
index deb0a5d..8e7d38b 100644
--- a/adb/adb_auth_client.cpp
+++ b/adb/adb_auth_client.cpp
@@ -14,24 +14,24 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_AUTH
+
+#include "sysdeps.h"
+#include "adb_auth.h"
+
 #include <resolv.h>
 #include <stdio.h>
 #include <string.h>
 
-#include "sysdeps.h"
-
-#include "adb.h"
-#include "adb_auth.h"
 #include "cutils/list.h"
 #include "cutils/sockets.h"
-#include "fdevent.h"
 #include "mincrypt/rsa.h"
 #include "mincrypt/sha.h"
+
+#include "adb.h"
+#include "fdevent.h"
 #include "transport.h"
 
-#define TRACE_TAG TRACE_AUTH
-
-
 struct adb_public_key {
     struct listnode node;
     RSAPublicKey key;
@@ -249,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.cpp b/adb/adb_auth_host.cpp
index aba23d4..7c2bcfb 100644
--- a/adb/adb_auth_host.cpp
+++ 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;
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index a485aa2..4751bff 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -14,6 +14,11 @@
  * 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>
@@ -23,10 +28,6 @@
 #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;
diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp
index 4dd9f4d..d89f304 100644
--- a/adb/adb_io.cpp
+++ b/adb/adb_io.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define TRACE_TAG  TRACE_RWX
+#define TRACE_TAG TRACE_RWX
 
 #include "sysdeps.h"
 #include "adb_io.h"
@@ -79,6 +79,8 @@
                 D("writex: fd=%d disconnected\n", fd);
                 errno = 0;
                 return false;
+            } else {
+                return false;
             }
         } else {
             len -= r;
diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp
index 330d9ce..da340b2 100644
--- a/adb/adb_io_test.cpp
+++ b/adb/adb_io_test.cpp
@@ -18,13 +18,16 @@
 
 #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 "utils/file.h"
+#include "base/file.h"
 
 class TemporaryFile {
  public:
@@ -55,7 +58,7 @@
   TemporaryFile tf;
   ASSERT_NE(-1, tf.fd);
 
-  ASSERT_TRUE(android::WriteStringToFd(expected, tf.fd)) << strerror(errno);
+  ASSERT_TRUE(android::base::WriteStringToFd(expected, tf.fd)) << strerror(errno);
   ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
 
   // Test reading the whole file.
@@ -69,7 +72,7 @@
   TemporaryFile tf;
   ASSERT_NE(-1, tf.fd);
 
-  ASSERT_TRUE(android::WriteStringToFd(expected, tf.fd)) << strerror(errno);
+  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.
@@ -83,7 +86,7 @@
   TemporaryFile tf;
   ASSERT_NE(-1, tf.fd);
 
-  ASSERT_TRUE(android::WriteStringToFd(input, tf.fd)) << strerror(errno);
+  ASSERT_TRUE(android::base::WriteStringToFd(input, tf.fd)) << strerror(errno);
   ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
 
   // Test reading a partial file.
@@ -106,7 +109,7 @@
   ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
 
   std::string s;
-  ASSERT_TRUE(android::ReadFdToString(tf.fd, &s));
+  ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s));
   EXPECT_STREQ(expected, s.c_str());
 }
 
@@ -123,10 +126,19 @@
   expected.pop_back();
 
   std::string s;
-  ASSERT_TRUE(android::ReadFdToString(tf.fd, &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;
@@ -137,6 +149,6 @@
   ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
 
   std::string s;
-  ASSERT_TRUE(android::ReadFdToString(tf.fd, &s));
+  ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s));
   EXPECT_STREQ(str, s.c_str());
 }
diff --git a/adb/adb_main.cpp b/adb/adb_main.cpp
index b0816ce..a03fcf1 100644
--- a/adb/adb_main.cpp
+++ b/adb/adb_main.cpp
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 
-#define  TRACE_TAG   TRACE_ADB
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
 
 #include <errno.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-#include "sysdeps.h"
-
 #include "adb.h"
 #include "adb_auth.h"
 #include "adb_listeners.h"
@@ -148,42 +148,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.
@@ -273,10 +237,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.
@@ -381,18 +349,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, 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[] = {
@@ -414,7 +398,6 @@
         }
     }
 
-    start_device_log();
     D("Handling main()\n");
     return adb_main(0, DEFAULT_ADB_PORT);
 #endif
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index ecaab83..c9b1eab 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
+
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
@@ -31,9 +35,6 @@
 #include <unistd.h>
 #endif
 
-#include "sysdeps.h"
-
-#define  TRACE_TAG  TRACE_ADB
 #include "adb.h"
 #include "adb_auth.h"
 #include "adb_client.h"
@@ -43,7 +44,8 @@
 static int do_cmd(transport_type ttype, const char* serial, const char *cmd, ...);
 
 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);
 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,
@@ -206,7 +208,7 @@
         "  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 remount                  - remounts the /system, /vendor (if present) and /oem (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 reboot-bootloader        - reboots the device into the bootloader\n"
         "  adb root                     - restarts the adbd daemon with root permissions\n"
@@ -222,9 +224,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"
@@ -1633,7 +1635,8 @@
     }
     else if (!strcmp(argv[0], "sync")) {
         const char* srcarg;
-        char *android_srcpath, *data_srcpath, *vendor_srcpath;
+        char *system_srcpath, *data_srcpath, *vendor_srcpath, *oem_srcpath;
+
         int listonly = 0;
 
         int ret;
@@ -1653,18 +1656,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;
     }
@@ -1770,49 +1777,60 @@
 }
 
 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;
 }
 
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 45d33db..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 "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
@@ -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_service.cpp b/adb/file_sync_service.cpp
index 2864b38..e8e9a0f 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -14,6 +14,11 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_SYNC
+
+#include "sysdeps.h"
+#include "file_sync_service.h"
+
 #include <dirent.h>
 #include <errno.h>
 #include <selinux/android.h>
@@ -25,23 +30,15 @@
 #include <unistd.h>
 #include <utime.h>
 
-#include "sysdeps.h"
-
-#define TRACE_TAG  TRACE_SYNC
 #include "adb.h"
 #include "adb_io.h"
-#include "file_sync_service.h"
 #include "private/android_filesystem_config.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);
-}
-
-static bool is_on_vendor(const char *name) {
-    const char *VENDOR = "/vendor/";
-    return (strncmp(VENDOR, name, strlen(VENDOR)) == 0);
+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);
@@ -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);
diff --git a/adb/jdwp_service.cpp b/adb/jdwp_service.cpp
index f0b4ba7..9cf084e 100644
--- a/adb/jdwp_service.cpp
+++ 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
diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp
index 414b316..483ca3d 100644
--- a/adb/remount_service.cpp
+++ b/adb/remount_service.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
+
 #include <errno.h>
 #include <fcntl.h>
 #include <mntent.h>
@@ -23,19 +27,18 @@
 #include <sys/mount.h>
 #include <unistd.h>
 
-#include "sysdeps.h"
+#include <string>
 
-#define  TRACE_TAG  TRACE_ADB
 #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 char *find_mount(const char *dir)
-{
+static std::string find_mount(const char *dir) {
     FILE* fp;
     struct mntent* mentry;
     char* device = NULL;
@@ -45,7 +48,7 @@
     }
     while ((mentry = getmntent(fp)) != NULL) {
         if (strcmp(dir, mentry->mnt_dir) == 0) {
-            device = strdup(mentry->mnt_fsname);
+            device = mentry->mnt_fsname;
             break;
         }
     }
@@ -53,64 +56,53 @@
     return device;
 }
 
-static int hasVendorPartition()
-{
-    struct stat info;
-    if (!lstat("/vendor", &info))
-        if ((info.st_mode & S_IFMT) == S_IFDIR)
-          return true;
-    return false;
+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 char* dev)
-{
-    int fd = -1;
+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;
-    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;
+    if (!ioctl(fd, BLKROSET, &OFF)) {
+        result = 0;
     }
+    adb_close(fd);
 
-    rc = 0;
-
-errout:
-    if (fd >= 0) {
-        adb_close(fd);
-    }
-    return rc;
+    return result;
 }
 
-/* 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;
+// 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;
     }
 
-    rc = mount(dev, dir, "none", MS_REMOUNT, NULL);
+    int rc = mount(dev.c_str(), dir, "none", MS_REMOUNT, NULL);
     *dir_ro = rc;
-
-errout:
-    free(dev);
     return rc;
 }
 
-void remount_service(int fd, void *cookie)
-{
-    char buffer[200];
+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) {
@@ -133,6 +125,7 @@
     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" : "",
@@ -147,23 +140,12 @@
         WriteStringFully(fd, buffer);
     }
 
-    if (remount("/system", &system_ro)) {
-        snprintf(buffer, sizeof(buffer), "remount of system failed: %s\n",strerror(errno));
-        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);
 
-    if (hasVendorPartition()) {
-        if (remount("/vendor", &vendor_ro)) {
-            snprintf(buffer, sizeof(buffer), "remount of vendor failed: %s\n",strerror(errno));
-            WriteStringFully(fd, buffer);
-        }
-    }
-
-    if (!system_ro && (!vendor_ro || !hasVendorPartition()))
-        WriteStringFully(fd, "remount succeeded\n");
-    else {
-        WriteStringFully(fd, "remount failed\n");
-    }
+    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.cpp b/adb/services.cpp
index 600eb30..abf8ea5 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_SERVICES
+
+#include "sysdeps.h"
+
 #include <errno.h>
 #include <stddef.h>
 #include <stdio.h>
@@ -32,12 +36,10 @@
 #include "cutils/properties.h"
 #endif
 
-#include "sysdeps.h"
-
-#define  TRACE_TAG  TRACE_SERVICES
 #include "adb.h"
 #include "adb_io.h"
 #include "file_sync_service.h"
+#include "remount_service.h"
 #include "transport.h"
 
 typedef struct stinfo stinfo;
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/set_verity_enable_state_service.cpp
index 85637f2..b75ed4c 100644
--- a/adb/set_verity_enable_state_service.cpp
+++ 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;
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 12bc8d8..48d02d6 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_SOCKETS
+
+#include "sysdeps.h"
+
 #include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
@@ -21,14 +25,12 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "sysdeps.h"
-
-#define  TRACE_TAG  TRACE_SOCKETS
-#include "adb.h"
-#include "adb_io.h"
 #if !ADB_HOST
 #include "cutils/properties.h"
 #endif
+
+#include "adb.h"
+#include "adb_io.h"
 #include "transport.h"
 
 ADB_MUTEX_DEFINE( socket_list_lock );
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index f132b8c..c28e031 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -1,10 +1,30 @@
+/*
+ * 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 <stdio.h>
 #include <stdlib.h>
-#include <errno.h>
-#define  TRACE_TAG  TRACE_SYSDEPS
+
 #include "adb.h"
 
 extern void fatal(const char *fmt, ...);
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 1f8ac03..0a960ff 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-#include "sysdeps.h"
+#define TRACE_TAG TRACE_TRANSPORT
 
+#include "sysdeps.h"
 #include "transport.h"
 
 #include <ctype.h>
@@ -25,7 +26,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#define   TRACE_TAG  TRACE_TRANSPORT
 #include "adb.h"
 
 static void transport_unref(atransport *t);
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 440d4c5..fe3c87f 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -14,21 +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 <sys/types.h>
 
-#include "sysdeps.h"
-
-#define  TRACE_TAG  TRACE_TRANSPORT
-#include "adb.h"
-#include "adb_io.h"
 #if !ADB_HOST
 #include "cutils/properties.h"
 #endif
-#include "transport.h"
+
+#include "adb.h"
+#include "adb_io.h"
 
 #if ADB_HOST
 /* we keep a list of opened transports. The atransport struct knows to which
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 37a8219..cdabffe 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -14,15 +14,16 @@
  * 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"
-#include "transport.h"
 
 static int remote_read(apacket *p, atransport *t)
 {
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index c01ec8c..6fd2b40 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_USB
+
+#include "sysdeps.h"
+
 #include <ctype.h>
 #include <dirent.h>
 #include <errno.h>
@@ -33,9 +37,6 @@
 #include <linux/usb_ch9.h>
 #endif
 
-#include "sysdeps.h"
-
-#define   TRACE_TAG  TRACE_USB
 #include "adb.h"
 #include "transport.h"
 
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c
index c88b258..434451c 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.c
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_USB
+
+#include "sysdeps.h"
+
 #include <dirent.h>
 #include <errno.h>
 #include <linux/usb/ch9.h>
@@ -25,9 +29,6 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "sysdeps.h"
-
-#define   TRACE_TAG  TRACE_USB
 #include "adb.h"
 #include "transport.h"
 
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index aa7e1ea..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>
@@ -24,9 +28,6 @@
 
 #include <stdio.h>
 
-#include "sysdeps.h"
-
-#define TRACE_TAG   TRACE_USB
 #include "adb.h"
 #include "transport.h"
 
diff --git a/adb/usb_windows.cpp b/adb/usb_windows.cpp
index 3c5533b..d2bd58c 100644
--- a/adb/usb_windows.cpp
+++ b/adb/usb_windows.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_USB
+
+#include "sysdeps.h"
+
 #include <winsock2.h>  // winsock.h *must* be included before windows.h.
 #include <adb_api.h>
 #include <errno.h>
@@ -23,9 +27,6 @@
 #include <windows.h>
 #include <winerror.h>
 
-#include "sysdeps.h"
-
-#define   TRACE_TAG  TRACE_USB
 #include "adb.h"
 #include "transport.h"
 
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..7bd317b
--- /dev/null
+++ b/base/Android.mk
@@ -0,0 +1,105 @@
+#
+# 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 \
+    logging.cpp \
+    stringprintf.cpp \
+    strings.cpp \
+
+libbase_test_src_files := \
+    file_test.cpp \
+    logging_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)
+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)
+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)
+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)
+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..a61c08d
--- /dev/null
+++ b/base/CPPLINT.cfg
@@ -0,0 +1,2 @@
+set noparent
+filter=-build/header_guard,-build/include,-build/c++11
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..118071e 100644
--- a/libutils/file.cpp
+++ b/base/file.cpp
@@ -14,19 +14,23 @@
  * 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"
+
+namespace android {
+namespace base {
+
+bool ReadFdToString(int fd, std::string* content) {
   content->clear();
 
   char buf[BUFSIZ];
@@ -37,10 +41,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 +54,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 +77,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 +106,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 +118,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..5e115fe
--- /dev/null
+++ b/base/include/base/logging.h
@@ -0,0 +1,267 @@
+/*
+ * 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 <memory>
+#include <ostream>
+
+#include "base/macros.h"
+
+namespace android {
+namespace base {
+
+enum LogSeverity {
+  VERBOSE,
+  DEBUG,
+  INFO,
+  WARNING,
+  ERROR,
+  FATAL,
+};
+
+// 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[]);
+
+// 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::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::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::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::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, 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, LogSeverity severity,
+                      const char* msg);
+
+  // A variant of the above for use with little stack.
+  static void LogLineLowStack(const char* file, unsigned int line,
+                              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..8bfb204
--- /dev/null
+++ b/base/logging.cpp
@@ -0,0 +1,301 @@
+/*
+ * 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 <sstream>
+#include <string>
+#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;
+
+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 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
+               << ")";
+  }
+}
+
+// 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, LogSeverity severity,
+                 int error)
+      : file_(file), line_number_(line), 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_;
+  }
+
+  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 LogSeverity severity_;
+  const int error_;
+
+  DISALLOW_COPY_AND_ASSIGN(LogMessageData);
+};
+
+LogMessage::LogMessage(const char* file, unsigned int line,
+                       LogSeverity severity, int error)
+    : data_(new LogMessageData(file, line, 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());
+
+  // Do the actual logging with the lock held.
+  {
+    std::lock_guard<std::mutex> lock(logging_lock);
+    if (msg.find('\n') == std::string::npos) {
+      LogLine(data_->GetFile(), data_->GetLineNumber(), 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_->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();
+}
+
+#ifdef __ANDROID__
+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");
+#endif
+
+void LogMessage::LogLine(const char* file, unsigned int line,
+                         LogSeverity log_severity, const char* message) {
+#ifdef __ANDROID__
+  const char* tag = ProgramInvocationShortName();
+  int priority = kLogSeverityToAndroidLogPriority[log_severity];
+  if (priority == ANDROID_LOG_FATAL) {
+    LOG_PRI(priority, tag, "%s:%u] %s", file, line, message);
+  } else {
+    LOG_PRI(priority, tag, "%s", message);
+  }
+#else
+  static const char* log_characters = "VDIWEF";
+  CHECK_EQ(strlen(log_characters), FATAL + 1U);
+  char severity = log_characters[log_severity];
+  fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationShortName(),
+          severity, getpid(), gettid(), file, line, message);
+#endif
+}
+
+void LogMessage::LogLineLowStack(const char* file, unsigned int line,
+                                 LogSeverity log_severity, const char* message) {
+#ifdef __ANDROID__
+  // Use android_writeLog() to avoid stack-based buffers used by
+  // android_printLog().
+  const char* tag = ProgramInvocationShortName();
+  int priority = kLogSeverityToAndroidLogPriority[log_severity];
+  char* buf = nullptr;
+  size_t buf_size = 0u;
+  if (priority == ANDROID_LOG_FATAL) {
+    // Allocate buffer for snprintf(buf, buf_size, "%s:%u] %s", file, line,
+    // message) below.  If allocation fails, fall back to printing only the
+    // message.
+    buf_size = strlen(file) + 1 /* ':' */ +
+               std::numeric_limits<typeof(line)>::max_digits10 + 2 /* "] " */ +
+               strlen(message) + 1 /* terminating 0 */;
+    buf = reinterpret_cast<char*>(malloc(buf_size));
+  }
+  if (buf != nullptr) {
+    snprintf(buf, buf_size, "%s:%u] %s", file, line, message);
+    android_writeLog(priority, tag, buf);
+    free(buf);
+  } else {
+    android_writeLog(priority, tag, message);
+  }
+#else
+  static const char* log_characters = "VDIWEF";
+  CHECK_EQ(strlen(log_characters), FATAL + 1U);
+
+  const char* program_name = ProgramInvocationShortName();
+  write(STDERR_FILENO, program_name, strlen(program_name));
+  write(STDERR_FILENO, " ", 1);
+  write(STDERR_FILENO, &log_characters[log_severity], 1);
+  write(STDERR_FILENO, " ", 1);
+  // TODO: pid and tid.
+  write(STDERR_FILENO, file, strlen(file));
+  // TODO: line.
+  UNUSED(line);
+  write(STDERR_FILENO, "] ", 2);
+  write(STDERR_FILENO, message, strlen(message));
+  write(STDERR_FILENO, "\n", 1);
+#endif
+}
+
+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..0a03e38
--- /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_;
+};
+
+HOST_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);
+}
+
+HOST_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));
+  }
+}
+
+HOST_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));
+  }
+}
+
+HOST_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..5f7eccc
--- /dev/null
+++ b/base/strings.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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>
+#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..c49ca4b
--- /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);
+  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/debuggerd/Android.mk b/debuggerd/Android.mk
index 8cc4682..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 \
@@ -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)
 
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/tombstone.cpp b/debuggerd/tombstone.cpp
index e927ea3..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);
   }
 }
 
@@ -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/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 7279b04..a25d316 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"
         }
@@ -379,30 +369,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;
     }
@@ -410,27 +396,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;
 }
@@ -451,7 +438,6 @@
 static int setup_requirement_line(char *name)
 {
     char *val[MAX_OPTIONS];
-    const char **out;
     char *prod = NULL;
     unsigned n, count;
     char *x;
@@ -491,10 +477,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++) {
@@ -508,7 +495,7 @@
         }
     }
 
-    fb_queue_require(prod, name, invert, n, out);
+    fb_queue_require(prod, var, invert, n, out);
     return 0;
 }
 
@@ -541,21 +528,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);
     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");
     }
@@ -672,11 +655,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);
@@ -700,63 +683,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)) {
@@ -768,6 +732,8 @@
          * program exits.
          */
     }
+
+    CloseArchive(zip);
 }
 
 void do_send_signature(char *fn)
@@ -790,24 +756,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;
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/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index feb3c19..5c67333 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -591,7 +591,7 @@
     return rc;
 }
 
-int fs_mgr_update_verity_state()
+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)];
@@ -645,7 +645,14 @@
 
         if (*status == 'C') {
             rc = write_verity_state(state_loc, offset, VERITY_MODE_LOGGING);
-            goto out;
+
+            if (rc == -1) {
+                goto out;
+            }
+        }
+
+        if (callback) {
+            callback(&fstab->recs[i], mount_point, *status);
         }
     }
 
@@ -729,6 +736,8 @@
         mode = VERITY_MODE_RESTART; /* default dm-verity mode */
     }
 
+    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,
             mode) < 0) {
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index a7a0bdb..1af16c2 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -27,6 +27,10 @@
 // turn verity off in userdebug builds.
 #define VERITY_METADATA_MAGIC_DISABLE 0x46464f56 // "VOFF"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 // Verity modes
 enum verity_mode {
     VERITY_MODE_EIO = 0,
@@ -35,10 +39,6 @@
     VERITY_MODE_LAST = VERITY_MODE_RESTART
 };
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
  * 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
@@ -66,6 +66,10 @@
     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);
 
@@ -84,7 +88,7 @@
 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();
+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);
diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h
index e2d718b..8c39acb 100644
--- a/include/backtrace/Backtrace.h
+++ b/include/backtrace/Backtrace.h
@@ -84,6 +84,12 @@
   // 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);
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/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/netutils/dhcp.h b/include/netutils/dhcp.h
index de6bc82..008dbd8 100644
--- a/include/netutils/dhcp.h
+++ b/include/netutils/dhcp.h
@@ -23,26 +23,18 @@
 __BEGIN_DECLS
 
 extern int do_dhcp(char *iname);
-extern int dhcp_do_request(const char *ifname,
-                          char *ipaddr,
-                          char *gateway,
-                          uint32_t *prefixLength,
-                          char *dns[],
-                          char *server,
-                          uint32_t *lease,
-                          char *vendorInfo,
-                          char *domain,
-                          char *mtu);
-extern int dhcp_do_request_renew(const char *ifname,
-                                char *ipaddr,
-                                char *gateway,
-                                uint32_t *prefixLength,
-                                char *dns[],
-                                char *server,
-                                uint32_t *lease,
-                                char *vendorInfo,
-                                char *domain,
-                                char *mtu);
+extern int dhcp_start(const char *ifname);
+extern int dhcp_start_renew(const char *ifname);
+extern int dhcp_get_results(const char *ifname,
+                            char *ipaddr,
+                            char *gateway,
+                            uint32_t *prefixLength,
+                            char *dns[],
+                            char *server,
+                            uint32_t *lease,
+                            char *vendorInfo,
+                            char *domain,
+                            char *mtu);
 extern int dhcp_stop(const char *ifname);
 extern int dhcp_release_lease(const char *ifname);
 extern char *dhcp_get_errmsg();
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 101cacd..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. */
diff --git a/include/system/radio.h b/include/system/radio.h
new file mode 100644
index 0000000..a088526
--- /dev/null
+++ b/include/system/radio.h
@@ -0,0 +1,247 @@
+/*
+ * 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 ANDROID_RADIO_H
+#define ANDROID_RADIO_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+
+#define RADIO_NUM_BANDS_MAX     16
+#define RADIO_NUM_SPACINGS_MAX  16
+#define RADIO_STRING_LEN_MAX    128
+
+/*
+ * Radio hardware module class. A given radio hardware module HAL is of one class
+ * only. The platform can not have more than one hardware module of each class.
+ * Current version of the framework only supports RADIO_CLASS_AM_FM.
+ */
+typedef enum {
+    RADIO_CLASS_AM_FM = 0,  /* FM (including HD radio) and AM */
+    RADIO_CLASS_SAT   = 1,  /* Satellite Radio */
+    RADIO_CLASS_DT    = 2,  /* Digital Radio (DAB) */
+} radio_class_t;
+
+/* value for field "type" of radio band described in struct radio_hal_band_config */
+typedef enum {
+    RADIO_BAND_AM     = 0,  /* Amplitude Modulation band: LW, MW, SW */
+    RADIO_BAND_FM     = 1,  /* Frequency Modulation band: FM */
+    RADIO_BAND_FM_HD  = 2,  /* FM HD Radio / DRM (IBOC) */
+    RADIO_BAND_AM_HD  = 3,  /* AM HD Radio / DRM (IBOC) */
+} radio_band_t;
+
+/* RDS variant implemented. A struct radio_hal_fm_band_config can list none or several. */
+enum {
+    RADIO_RDS_NONE   = 0x0,
+    RADIO_RDS_WORLD  = 0x01,
+    RADIO_RDS_US     = 0x02,
+};
+typedef unsigned int radio_rds_t;
+
+/* FM deemphasis variant implemented. A struct radio_hal_fm_band_config can list one or more. */
+enum {
+    RADIO_DEEMPHASIS_50   = 0x1,
+    RADIO_DEEMPHASIS_75   = 0x2,
+};
+typedef unsigned int radio_deemphasis_t;
+
+/* Region a particular radio band configuration corresponds to. Not used at the HAL.
+ * Derived by the framework when converting the band descriptors retrieved from the HAL to
+ * individual band descriptors for each supported region. */
+typedef enum {
+    RADIO_REGION_NONE  = -1,
+    RADIO_REGION_ITU_1 = 0,
+    RADIO_REGION_ITU_2 = 1,
+    RADIO_REGION_OIRT  = 2,
+    RADIO_REGION_JAPAN = 3,
+    RADIO_REGION_KOREA = 4,
+} radio_region_t;
+
+/* scanning direction for scan() and step() tuner APIs */
+typedef enum {
+    RADIO_DIRECTION_UP,
+    RADIO_DIRECTION_DOWN
+} radio_direction_t;
+
+/* unique handle allocated to a radio module */
+typedef unsigned int radio_handle_t;
+
+/* Opaque meta data structure used by radio meta data API (see system/radio_metadata.h) */
+typedef struct radio_medtadata radio_metadata_t;
+
+
+/* Additional attributes for an FM band configuration */
+typedef struct radio_hal_fm_band_config {
+    radio_deemphasis_t  deemphasis; /* deemphasis variant */
+    bool                stereo;     /* stereo supported */
+    radio_rds_t         rds;        /* RDS variants supported */
+    bool                ta;         /* Traffic Announcement supported */
+    bool                af;         /* Alternate Frequency supported */
+} radio_hal_fm_band_config_t;
+
+/* Additional attributes for an AM band configuration */
+typedef struct radio_hal_am_band_config {
+    bool                stereo;     /* stereo supported */
+} radio_hal_am_band_config_t;
+
+/* Radio band configuration. Describes a given band supported by the radio module.
+ * The HAL can expose only one band per type with the the maximum range supported and all options.
+ * THe framework will derive the actual regions were this module can operate and expose separate
+ * band configurations for applications to chose from. */
+typedef struct radio_hal_band_config {
+    radio_band_t type;
+    bool         antenna_connected;
+    unsigned int lower_limit;
+    unsigned int upper_limit;
+    unsigned int num_spacings;
+    unsigned int spacings[RADIO_NUM_SPACINGS_MAX];
+    union {
+        radio_hal_fm_band_config_t fm;
+        radio_hal_am_band_config_t am;
+    };
+} radio_hal_band_config_t;
+
+/* Used internally by the framework to represent a band for s specific region */
+typedef struct radio_band_config {
+    radio_region_t  region;
+    radio_hal_band_config_t band;
+} radio_band_config_t;
+
+
+/* Exposes properties of a given hardware radio module.
+ * NOTE: current framework implementation supports only one audio source (num_audio_sources = 1).
+ * The source corresponds to AUDIO_DEVICE_IN_FM_TUNER.
+ * If more than one tuner is supported (num_tuners > 1), only one can be connected to the audio
+ * source. */
+typedef struct radio_hal_properties {
+    radio_class_t   class_id;   /* Class of this module. E.g RADIO_CLASS_AM_FM */
+    char            implementor[RADIO_STRING_LEN_MAX];  /* implementor name */
+    char            product[RADIO_STRING_LEN_MAX];  /* product name */
+    char            version[RADIO_STRING_LEN_MAX];  /* product version */
+    char            serial[RADIO_STRING_LEN_MAX];  /* serial number (for subscription services) */
+    unsigned int    num_tuners;     /* number of tuners controllable independently */
+    unsigned int    num_audio_sources; /* number of audio sources driven simultaneously */
+    bool            supports_capture; /* the hardware supports capture of audio source audio HAL */
+    unsigned int    num_bands;      /* number of band descriptors */
+    radio_hal_band_config_t bands[RADIO_NUM_BANDS_MAX]; /* band descriptors */
+} radio_hal_properties_t;
+
+/* Used internally by the framework. Same information as in struct radio_hal_properties plus a
+ * unique handle and one band configuration per region. */
+typedef struct radio_properties {
+    radio_handle_t      handle;
+    radio_class_t       class_id;
+    char                implementor[RADIO_STRING_LEN_MAX];
+    char                product[RADIO_STRING_LEN_MAX];
+    char                version[RADIO_STRING_LEN_MAX];
+    char                serial[RADIO_STRING_LEN_MAX];
+    unsigned int        num_tuners;
+    unsigned int        num_audio_sources;
+    bool                supports_capture;
+    unsigned int        num_bands;
+    radio_band_config_t bands[RADIO_NUM_BANDS_MAX];
+} radio_properties_t;
+
+/* Radio program information. Returned by the HAL with event RADIO_EVENT_TUNED.
+ * Contains information on currently tuned channel.
+ */
+typedef struct radio_program_info {
+    unsigned int     channel;   /* current channel. (e.g kHz for band type RADIO_BAND_FM) */
+    unsigned int     sub_channel; /* current sub channel. (used for RADIO_BAND_FM_HD) */
+    bool             tuned;     /* tuned to a program or not */
+    bool             stereo;    /* program is stereo or not */
+    bool             digital;   /* digital program or not (e.g HD Radio program) */
+    unsigned int     signal_strength; /* signal strength from 0 to 100 */
+    radio_metadata_t *metadata; /* non null if meta data are present (e.g PTY, song title ...) */
+} radio_program_info_t;
+
+
+/* Events sent to the framework via the HAL callback. An event can notify the completion of an
+ * asynchronous command (configuration, tune, scan ...) or a spontaneous change (antenna connection,
+ * failure, AF switching, meta data reception... */
+enum {
+    RADIO_EVENT_HW_FAILURE  = 0,  /* hardware module failure. Requires reopening the tuner */
+    RADIO_EVENT_CONFIG      = 1,  /* configuration change completed */
+    RADIO_EVENT_ANTENNA     = 2,  /* Antenna connected, disconnected */
+    RADIO_EVENT_TUNED       = 3,  /* tune, step, scan completed */
+    RADIO_EVENT_METADATA    = 4,  /* New meta data received */
+    RADIO_EVENT_TA          = 5,  /* Traffic announcement start or stop */
+    RADIO_EVENT_AF_SWITCH   = 6,  /* Switch to Alternate Frequency */
+    // begin framework only events
+    RADIO_EVENT_CONTROL     = 100, /* loss/gain of tuner control */
+    RADIO_EVENT_SERVER_DIED = 101, /* radio service died */
+};
+typedef unsigned int radio_event_type_t;
+
+/* Event passed to the framework by the HAL callback */
+typedef struct radio_hal_event {
+    radio_event_type_t  type;       /* event type */
+    int                 status;     /* used by RADIO_EVENT_CONFIG, RADIO_EVENT_TUNED */
+    union {
+        bool                    on;     /* RADIO_EVENT_ANTENNA, RADIO_EVENT_TA */
+        radio_hal_band_config_t config; /* RADIO_EVENT_CONFIG */
+        radio_program_info_t    info;   /* RADIO_EVENT_TUNED, RADIO_EVENT_AF_SWITCH */
+        radio_metadata_t        *metadata; /* RADIO_EVENT_METADATA */
+    };
+} radio_hal_event_t;
+
+/* Used internally by the framework. Same information as in struct radio_hal_event */
+typedef struct radio_event {
+    radio_event_type_t  type;
+    int                 status;
+    union {
+        bool                    on;
+        radio_band_config_t     config;
+        radio_program_info_t    info;
+        radio_metadata_t        *metadata; /* offset from start of struct when in shared memory */
+    };
+} radio_event_t;
+
+
+static radio_rds_t radio_rds_for_region(bool rds, radio_region_t region) {
+    if (!rds)
+        return RADIO_RDS_NONE;
+    switch(region) {
+        case RADIO_REGION_ITU_1:
+        case RADIO_REGION_OIRT:
+        case RADIO_REGION_JAPAN:
+        case RADIO_REGION_KOREA:
+            return RADIO_RDS_WORLD;
+        case RADIO_REGION_ITU_2:
+            return RADIO_RDS_US;
+        default:
+            return RADIO_REGION_NONE;
+    }
+}
+
+static radio_deemphasis_t radio_demephasis_for_region(radio_region_t region) {
+    switch(region) {
+        case RADIO_REGION_KOREA:
+        case RADIO_REGION_ITU_2:
+            return RADIO_DEEMPHASIS_75;
+        case RADIO_REGION_ITU_1:
+        case RADIO_REGION_OIRT:
+        case RADIO_REGION_JAPAN:
+        default:
+            return RADIO_DEEMPHASIS_50;
+    }
+}
+
+#endif  // ANDROID_RADIO_H
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 ec2861b..5b8094f 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -27,6 +27,7 @@
     parser.cpp \
     util.cpp \
 
+LOCAL_STATIC_LIBRARIES := libbase
 LOCAL_MODULE := libinit
 include $(BUILD_STATIC_LIBRARY)
 
@@ -55,7 +56,7 @@
     libfs_mgr \
     liblogwrap \
     libcutils \
-    libutils \
+    libbase \
     liblog \
     libc \
     libselinux \
@@ -80,7 +81,7 @@
 
 LOCAL_SHARED_LIBRARIES += \
     libcutils \
-    libutils \
+    libbase \
 
 LOCAL_STATIC_LIBRARIES := libinit
 include $(BUILD_NATIVE_TEST)
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index cc31920..03c8b30 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);
@@ -226,7 +226,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 3d2e552..6daea37 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -14,31 +14,31 @@
  * 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 <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 +47,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 +65,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 +102,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
@@ -503,7 +475,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)) {
@@ -571,15 +543,6 @@
     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];
@@ -709,17 +672,20 @@
 }
 
 int do_verity_load_state(int nargs, char **args) {
-    if (nargs == 1) {
-        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;
+    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 -1;
+    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)
diff --git a/init/devices.cpp b/init/devices.cpp
index 3a9b753..9bce39a 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;
 
@@ -818,8 +818,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 +838,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:
diff --git a/init/init.cpp b/init/init.cpp
index c1e9c01..1449bc6 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <libgen.h>
+#include <paths.h>
 #include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -34,22 +35,22 @@
 #include <termios.h>
 #include <unistd.h>
 
-#include <memory>
-
 #include <mtd/mtd-user.h>
 
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 #include <selinux/android.h>
 
+#include <base/file.h>
+#include <base/stringprintf.h>
 #include <cutils/android_reboot.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 <utils/file.h>
-#include <utils/stringprintf.h>
+
+#include <memory>
 
 #include "devices.h"
 #include "init.h"
@@ -68,8 +69,6 @@
 
 static int property_triggers_enabled = 0;
 
-static char console[32];
-static char bootmode[32];
 static char qemu[32];
 
 static struct action *cur_action = NULL;
@@ -681,7 +680,6 @@
     if (urandom_fd != -1) {
         close(urandom_fd);
     }
-    memset(buf, 0, sizeof(buf));
     return result;
 }
 
@@ -693,13 +691,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);
@@ -762,57 +759,34 @@
     }
 }
 
-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", },
+        { "ro.boot.hardware",   "ro.hardware",   "unknown", },
+        { "ro.boot.revision",   "ro.revision",   "0", },
     };
-
-    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);
+    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);
     }
-
-    ret = property_get("ro.boot.console", tmp);
-    if (ret)
-        strlcpy(console, tmp, sizeof(console));
-
-    /* save a copy for init's usage during boot */
-    property_get("ro.bootmode", tmp);
-    strlcpy(bootmode, tmp, sizeof(bootmode));
-
-    /* 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");
 }
 
 static void process_kernel_dt(void)
 {
     static const char android_dir[] = "/proc/device-tree/firmware/android";
 
-    std::string file_name = android::StringPrintf("%s/compatible", android_dir);
+    std::string file_name = android::base::StringPrintf("%s/compatible", android_dir);
 
     std::string dt_file;
-    android::ReadFileToString(file_name, &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;
@@ -827,15 +801,13 @@
         if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible"))
             continue;
 
-        file_name = android::StringPrintf("%s/%s", android_dir, dp->d_name);
+        file_name = android::base::StringPrintf("%s/%s", android_dir, dp->d_name);
 
-        android::ReadFileToString(file_name, &dt_file);
+        android::base::ReadFileToString(file_name, &dt_file);
         std::replace(dt_file.begin(), dt_file.end(), ',', '.');
 
-        std::string property_name = android::StringPrintf("ro.boot.%s", dp->d_name);
-        if (property_set(property_name.c_str(), dt_file.c_str())) {
-            ERROR("Could not set property %s to value %s", property_name.c_str(), dt_file.c_str());
-        }
+        std::string property_name = android::base::StringPrintf("ro.boot.%s", dp->d_name);
+        property_set(property_name.c_str(), dt_file.c_str());
     }
 }
 
@@ -1012,6 +984,8 @@
     // Clear the umask.
     umask(0);
 
+    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);
@@ -1085,7 +1059,8 @@
     queue_builtin_action(signal_init_action, "signal_init");
 
     // Don't mount filesystems or start core system services in charger mode.
-    if (strcmp(bootmode, "charger") == 0) {
+    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);
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 2ee4f86..57eb299 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -118,11 +118,10 @@
     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;
@@ -187,7 +186,6 @@
         if (!strcmp(s, "ervice")) return K_service;
         if (!strcmp(s, "etcon")) return K_setcon;
         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, "ocket")) return K_socket;
@@ -205,6 +203,7 @@
         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;
diff --git a/init/keychords.cpp b/init/keychords.cpp
index d6464bd..2e996ea 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;
     }
diff --git a/init/keywords.h b/init/keywords.h
index 486e536..09f645b 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);
@@ -23,7 +21,6 @@
 int do_rm(int nargs, char **args);
 int do_rmdir(int nargs, char **args);
 int do_setcon(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_start(int nargs, char **args);
@@ -40,6 +37,7 @@
 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,
@@ -47,8 +45,6 @@
     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)
@@ -83,7 +79,6 @@
     KEYWORD(service,     SECTION, 0, 0)
     KEYWORD(setcon,      COMMAND, 1, do_setcon)
     KEYWORD(setenv,      OPTION,  2, 0)
-    KEYWORD(setkey,      COMMAND, 0, do_setkey)
     KEYWORD(setprop,     COMMAND, 2, do_setprop)
     KEYWORD(setrlimit,   COMMAND, 3, do_setrlimit)
     KEYWORD(socket,      OPTION,  0, 0)
@@ -95,6 +90,7 @@
     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/property_service.cpp b/init/property_service.cpp
index 05c03d6..363b377 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>
 
@@ -161,7 +161,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 +201,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 +216,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 +247,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 +289,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;
     }
@@ -424,64 +427,62 @@
     }
 }
 
-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)
diff --git a/init/readme.txt b/init/readme.txt
index fdcc9eb..4c8d0d3 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -137,35 +137,9 @@
 Commands
 --------
 
-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> ]*
-   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 execonce 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.
@@ -173,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.
 
@@ -196,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
@@ -223,14 +248,19 @@
    Recursively restore the directory tree named by <path> to the
    security contexts specified in the file_contexts configuration.
 
+rm <path>
+   Calls unlink(2) on the given path. You might want to
+   use "exec -- rm ..." instead (provided the system partition is
+   already mounted).
+
+rmdir <path>
+   Calls rmdir(2) on the given path.
+
 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.
 
-setkey
-   TBD
-
 setprop <name> <value>
    Set system property <name> to <value>. Properties are expanded
    within <value>.
@@ -244,6 +274,9 @@
 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>
 
@@ -254,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).
diff --git a/init/util.cpp b/init/util.cpp
index 0726053..8b238d4 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;
 }
diff --git a/libbacktrace/BacktraceImpl.cpp b/libbacktrace/BacktraceImpl.cpp
index fb8a725..4650b6a 100644
--- a/libbacktrace/BacktraceImpl.cpp
+++ b/libbacktrace/BacktraceImpl.cpp
@@ -17,6 +17,7 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/param.h>
 #include <sys/ptrace.h>
 #include <sys/types.h>
 #include <ucontext.h>
@@ -159,6 +160,17 @@
   }
 }
 
+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;
+}
+
 //-------------------------------------------------------------------------
 // BacktracePtrace functions.
 //-------------------------------------------------------------------------
@@ -171,25 +183,88 @@
 BacktracePtrace::~BacktracePtrace() {
 }
 
-bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
-  if (!VerifyReadWordArgs(ptr, out_value)) {
+#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), 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*>(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
-  // 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));
+  if (!VerifyReadWordArgs(ptr, out_value)) {
     return false;
   }
-  return true;
+
+  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/BacktraceImpl.h b/libbacktrace/BacktraceImpl.h
index cd61bdf..18c3cb5 100755
--- a/libbacktrace/BacktraceImpl.h
+++ b/libbacktrace/BacktraceImpl.h
@@ -56,6 +56,8 @@
   BacktraceCurrent(BacktraceImpl* impl, BacktraceMap* map);
   virtual ~BacktraceCurrent();
 
+  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes);
+
   bool ReadWord(uintptr_t ptr, word_t* out_value);
 };
 
@@ -64,6 +66,8 @@
   BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map);
   virtual ~BacktracePtrace();
 
+  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes);
+
   bool ReadWord(uintptr_t ptr, word_t* out_value);
 };
 
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 76aabd1..b1e34bd 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -31,7 +31,6 @@
 
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
-#include <UniquePtr.h>
 
 // For the THREAD_SIGNAL definition.
 #include "BacktraceThread.h"
@@ -40,6 +39,7 @@
 #include <gtest/gtest.h>
 
 #include <algorithm>
+#include <memory>
 #include <vector>
 
 #include "thread_utils.h"
@@ -60,6 +60,7 @@
   pid_t tid;
   int32_t state;
   pthread_t threadId;
+  void* data;
 };
 
 struct dump_thread_t {
@@ -142,9 +143,9 @@
 }
 
 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());
@@ -162,9 +163,9 @@
 }
 
 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 +181,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());
@@ -198,7 +199,7 @@
 }
 
 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(
@@ -208,7 +209,7 @@
   EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2);
 
   // 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 +227,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,
@@ -269,13 +270,13 @@
       // 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->Unwind(0));
-      ASSERT_TRUE(backtrace.get() != NULL);
+      ASSERT_TRUE(backtrace.get() != nullptr);
       if (ReadyFunc(backtrace.get())) {
         VerifyFunc(backtrace.get());
         verified = true;
@@ -291,7 +292,7 @@
 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 +305,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 +319,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 +330,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 +356,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 +366,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 +387,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 +421,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 +449,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 +457,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 +472,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,7 +485,7 @@
 
   // 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
@@ -501,26 +502,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 +532,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 +540,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 +571,7 @@
 
   android_atomic_acquire_store(1, &dump->done);
 
-  return NULL;
+  return nullptr;
 }
 
 TEST(libbacktrace, thread_multiple_dump) {
@@ -614,11 +615,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 +655,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.
@@ -708,8 +709,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 +779,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 +794,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 +828,167 @@
   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 everything
+  while (thread_data->state) {
+  }
+
+  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));
+
+      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,11 +996,11 @@
 
 #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;
   }
@@ -848,7 +1009,7 @@
   // 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;
   }
@@ -863,9 +1024,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 +1036,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 +1059,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/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/liblog/logd_write.c b/liblog/logd_write.c
index a865093..dfe34d1 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -90,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()
 {
@@ -111,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;
@@ -178,6 +161,10 @@
     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();
     }
@@ -289,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);
@@ -347,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;
         }
 
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index 0f7c384..c6b9fe4 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -1,16 +1,16 @@
 /*
  * Copyright 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 
+ * 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 
+ *     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 
+ * 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.
  */
 
@@ -33,7 +33,7 @@
 static const int NAP_TIME = 200;   /* wait for 200ms at a time */
                                   /* when polling for property values */
 static const char DAEMON_NAME_RENEW[]  = "iprenew";
-static char errmsg[100];
+static char errmsg[100] = "\0";
 /* interface length for dhcpcd daemon start (dhcpcd_<interface> as defined in init.rc file)
  * or for filling up system properties dhcpcd.<interface>.ipaddress, dhcpcd.<interface>.dns1
  * and other properties on a successful bind
@@ -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 || 
+            if (desired_value == NULL ||
                     strcmp(value, desired_value) == 0) {
                 return 0;
             }
         }
+        if (maxnaps >= 0) {
+            usleep(NAP_TIME * 1000);
+        }
     }
     return -1; /* failure */
 }
@@ -167,6 +169,47 @@
 }
 
 /*
+ * Get any available DHCP results.
+ */
+int dhcp_get_results(const char *interface,
+                     char *ipaddr,
+                     char *gateway,
+                     uint32_t *prefixLength,
+                     char *dns[],
+                     char *server,
+                     uint32_t *lease,
+                     char *vendorInfo,
+                     char *domain,
+                     char *mtu)
+{
+    char result_prop_name[PROPERTY_KEY_MAX];
+    char prop_value[PROPERTY_VALUE_MAX];
+
+    /* Interface name after converting p2p0-p2p0-X to p2p to reuse system properties */
+    char p2p_interface[MAX_INTERFACE_LENGTH];
+    get_p2p_interface_replacement(interface, p2p_interface);
+    snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
+            DHCP_PROP_NAME_PREFIX,
+            p2p_interface);
+
+    memset(prop_value, '\0', PROPERTY_VALUE_MAX);
+    if (!property_get(result_prop_name, prop_value, NULL)) {
+        snprintf(errmsg, sizeof(errmsg), "%s", "DHCP result property was not set");
+        return -1;
+    }
+    if (strcmp(prop_value, "ok") == 0) {
+        if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
+                server, lease, vendorInfo, domain, mtu) == -1) {
+            return -1;
+        }
+        return 0;
+    } else {
+        snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value);
+        return -1;
+    }
+}
+
+/*
  * Start the dhcp client daemon, and wait for it to finish
  * configuring the interface.
  *
@@ -175,16 +218,7 @@
  * Example:
  * service dhcpcd_<interface> /system/bin/dhcpcd -ABKL -f dhcpcd.conf
  */
-int dhcp_do_request(const char *interface,
-                    char *ipaddr,
-                    char *gateway,
-                    uint32_t *prefixLength,
-                    char *dns[],
-                    char *server,
-                    uint32_t *lease,
-                    char *vendorInfo,
-                    char *domain,
-                    char *mtu)
+int dhcp_start(const char *interface)
 {
     char result_prop_name[PROPERTY_KEY_MAX];
     char daemon_prop_name[PROPERTY_KEY_MAX];
@@ -228,21 +262,7 @@
         return -1;
     }
 
-    if (!property_get(result_prop_name, prop_value, NULL)) {
-        /* shouldn't ever happen, given the success of wait_for_property() */
-        snprintf(errmsg, sizeof(errmsg), "%s", "DHCP result property was not set");
-        return -1;
-    }
-    if (strcmp(prop_value, "ok") == 0) {
-        if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
-                server, lease, vendorInfo, domain, mtu) == -1) {
-            return -1;
-        }
-        return 0;
-    } else {
-        snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value);
-        return -1;
-    }
+    return 0;
 }
 
 /**
@@ -318,16 +338,7 @@
  * service iprenew_<interface> /system/bin/dhcpcd -n
  *
  */
-int dhcp_do_request_renew(const char *interface,
-                    char *ipaddr,
-                    char *gateway,
-                    uint32_t *prefixLength,
-                    char *dns[],
-                    char *server,
-                    uint32_t *lease,
-                    char *vendorInfo,
-                    char *domain,
-                    char *mtu)
+int dhcp_start_renew(const char *interface)
 {
     char result_prop_name[PROPERTY_KEY_MAX];
     char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
@@ -357,16 +368,5 @@
         return -1;
     }
 
-    if (!property_get(result_prop_name, prop_value, NULL)) {
-        /* shouldn't ever happen, given the success of wait_for_property() */
-        snprintf(errmsg, sizeof(errmsg), "%s", "DHCP Renew result property was not set");
-        return -1;
-    }
-    if (strcmp(prop_value, "ok") == 0) {
-        return fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
-                server, lease, vendorInfo, domain, mtu);
-    } else {
-        snprintf(errmsg, sizeof(errmsg), "DHCP Renew result was %s", prop_value);
-        return -1;
-    }
+    return 0;
 }
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/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/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/tests/Android.mk b/libutils/tests/Android.mk
index ce288ca..634f44f 100644
--- a/libutils/tests/Android.mk
+++ b/libutils/tests/Android.mk
@@ -26,11 +26,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/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 e820f2a..58285f1 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -824,7 +824,7 @@
   // 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;
     }
@@ -1123,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) {
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/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/LogBuffer.cpp b/logd/LogBuffer.cpp
index 2b495ab..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?
@@ -161,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;
 
@@ -184,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);
@@ -193,7 +191,7 @@
         LogTimeEntry::unlock();
     }
 
-    stats.add(len, log_id, uid, pid);
+    stats.add(elem);
     maybePrune(log_id);
     pthread_mutex_unlock(&mLogElementsLock);
 }
@@ -216,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.
@@ -241,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;
             }
 
@@ -250,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;
@@ -269,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;
@@ -276,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;
             }
 
@@ -304,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()) {
@@ -330,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--;
         }
     }
 
@@ -423,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 {
@@ -441,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;
             }
@@ -455,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);
@@ -481,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 86a2a2a..a29e015 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -51,9 +51,9 @@
     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);
@@ -78,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/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 5a70689..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,358 +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)
-        , start(CLOCK_MONOTONIC) {
-    log_id_for_each(i) {
-        mSizes[i] = 0;
-        mElements[i] = 0;
-    }
-}
-
-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) {
@@ -476,368 +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;
+            }
+
+            uid_t u = entry->getKey();
+            if ((uid != AID_ROOT) && (u != uid)) {
+                continue;
+            }
+
+            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 {
+                    output.appendFormat(
+                        "\n\nLogging for your UID in %s:\n",
+                        android_log_id_to_name(id));
                 }
+                print = true;
             }
 
-            if (!header) {
-                string.appendFormat("\n\nChattiest clients:\n"
-                                    "log id %-*s PID[?] name",
-                                    spaces_total, "size/total");
-                header = true;
+            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);
             }
 
-            size_t sizesTotal = p->sizesTotal();
+            android::String8 size("");
+            size.appendFormat("%zu", sizes);
 
-            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 : "");
+            format_line(output, name, size);
         }
 
-        pids.clear();
+        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 f892cd0..d5b8762 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -20,175 +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;
-
-    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 enableStatistics() { mStatistics = true; }
+    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/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 9748fed..2ff0d04 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -336,9 +336,9 @@
     write /proc/sys/vm/overcommit_memory 1
     write /proc/sys/vm/min_free_order_shift 4
     chown root system /sys/module/lowmemorykiller/parameters/adj
-    chmod 0220 /sys/module/lowmemorykiller/parameters/adj
+    chmod 0664 /sys/module/lowmemorykiller/parameters/adj
     chown root system /sys/module/lowmemorykiller/parameters/minfree
-    chmod 0220 /sys/module/lowmemorykiller/parameters/minfree
+    chmod 0664 /sys/module/lowmemorykiller/parameters/minfree
 
     # Tweak background writeout
     write /proc/sys/vm/dirty_expire_centisecs 200
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 4d50bf0..599236f 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -146,8 +146,6 @@
     PERM_ANDROID_OBB,
     /* This node is "/Android/media" */
     PERM_ANDROID_MEDIA,
-    /* This node is "/Android/user" */
-    PERM_ANDROID_USER,
 } perm_t;
 
 /* Permissions structure to derive */
@@ -250,7 +248,7 @@
     __u32 inode_ctr;
 
     Hashmap* package_to_appid;
-    Hashmap* appid_with_rw;
+    Hashmap* uid_with_rw;
 };
 
 /* Private data used by a single fuse handler. */
@@ -472,6 +470,7 @@
         /* Legacy internal layout places users at top level */
         node->perm = PERM_ROOT;
         node->userid = strtoul(node->name, NULL, 10);
+        node->gid = multiuser_get_uid(node->userid, AID_SDCARD_R);
         break;
     case PERM_ROOT:
         /* Assume masked off by default. */
@@ -483,14 +482,14 @@
         } else if (fuse->split_perms) {
             if (!strcasecmp(node->name, "DCIM")
                     || !strcasecmp(node->name, "Pictures")) {
-                node->gid = AID_SDCARD_PICS;
+                node->gid = multiuser_get_uid(node->userid, AID_SDCARD_PICS);
             } else if (!strcasecmp(node->name, "Alarms")
                     || !strcasecmp(node->name, "Movies")
                     || !strcasecmp(node->name, "Music")
                     || !strcasecmp(node->name, "Notifications")
                     || !strcasecmp(node->name, "Podcasts")
                     || !strcasecmp(node->name, "Ringtones")) {
-                node->gid = AID_SDCARD_AV;
+                node->gid = multiuser_get_uid(node->userid, AID_SDCARD_AV);
             }
         }
         break;
@@ -510,13 +509,6 @@
             /* App-specific directories inside; let anyone traverse */
             node->perm = PERM_ANDROID_MEDIA;
             node->mode = 0771;
-        } else if (!strcasecmp(node->name, "user")) {
-            /* User directories must only be accessible to system, protected
-             * by sdcard_all. Zygote will bind mount the appropriate user-
-             * specific path. */
-            node->perm = PERM_ANDROID_USER;
-            node->gid = AID_SDCARD_ALL;
-            node->mode = 0770;
         }
         break;
     case PERM_ANDROID_DATA:
@@ -528,13 +520,6 @@
         }
         node->mode = 0770;
         break;
-    case PERM_ANDROID_USER:
-        /* Root of a secondary user */
-        node->perm = PERM_ROOT;
-        node->userid = strtoul(node->name, NULL, 10);
-        node->gid = AID_SDCARD_R;
-        node->mode = 0771;
-        break;
     }
 }
 
@@ -545,8 +530,7 @@
         return true;
     }
 
-    appid_t appid = multiuser_get_app_id(hdr->uid);
-    return hashmapContainsKey(fuse->appid_with_rw, (void*) (uintptr_t) appid);
+    return hashmapContainsKey(fuse->uid_with_rw, (void*) (uintptr_t) hdr->uid);
 }
 
 /* Kernel has already enforced everything we returned through
@@ -725,7 +709,7 @@
 }
 
 static void fuse_init(struct fuse *fuse, int fd, const char *source_path,
-        gid_t write_gid, derive_t derive, bool split_perms) {
+        gid_t write_gid, userid_t owner_user, derive_t derive, bool split_perms) {
     pthread_mutex_init(&fuse->lock, NULL);
 
     fuse->fd = fd;
@@ -760,7 +744,7 @@
         fuse->root.mode = 0771;
         fuse->root.gid = AID_SDCARD_R;
         fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
-        fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);
+        fuse->uid_with_rw = hashmapCreate(128, int_hash, int_equals);
         snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/obb", source_path);
         fs_prepare_dir(fuse->obbpath, 0775, getuid(), getgid());
         break;
@@ -769,9 +753,10 @@
          * /Android/user and shared OBB path under /Android/obb. */
         fuse->root.perm = PERM_ROOT;
         fuse->root.mode = 0771;
-        fuse->root.gid = AID_SDCARD_R;
+        fuse->root.userid = owner_user;
+        fuse->root.gid = multiuser_get_uid(owner_user, AID_SDCARD_R);
         fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
-        fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);
+        fuse->uid_with_rw = hashmapCreate(128, int_hash, int_equals);
         snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/Android/obb", source_path);
         break;
     }
@@ -1692,7 +1677,7 @@
     pthread_mutex_lock(&fuse->lock);
 
     hashmapForEach(fuse->package_to_appid, remove_str_to_int, fuse->package_to_appid);
-    hashmapForEach(fuse->appid_with_rw, remove_int_to_null, fuse->appid_with_rw);
+    hashmapForEach(fuse->uid_with_rw, remove_int_to_null, fuse->uid_with_rw);
 
     FILE* file = fopen(kPackagesListFile, "r");
     if (!file) {
@@ -1713,9 +1698,14 @@
 
             char* token = strtok(gids, ",");
             while (token != NULL) {
-                if (strtoul(token, NULL, 10) == fuse->write_gid) {
-                    hashmapPut(fuse->appid_with_rw, (void*) (uintptr_t) appid, (void*) (uintptr_t) 1);
-                    break;
+                // Current packages.list format is a bit funky; it blends per
+                // user GID membership into a single per-app line. Here we
+                // work backwards from the groups to build the per-user UIDs
+                // that have write permission.
+                gid_t gid = strtoul(token, NULL, 10);
+                if (multiuser_get_app_id(gid) == fuse->write_gid) {
+                    uid_t uid = multiuser_get_uid(multiuser_get_user_id(gid), appid);
+                    hashmapPut(fuse->uid_with_rw, (void*) (uintptr_t) uid, (void*) (uintptr_t) 1);
                 }
                 token = strtok(NULL, ",");
             }
@@ -1724,7 +1714,7 @@
 
     TRACE("read_package_list: found %zu packages, %zu with write_gid\n",
             hashmapSize(fuse->package_to_appid),
-            hashmapSize(fuse->appid_with_rw));
+            hashmapSize(fuse->uid_with_rw));
     fclose(file);
     pthread_mutex_unlock(&fuse->lock);
     return 0;
@@ -1849,7 +1839,7 @@
 }
 
 static int run(const char* source_path, const char* dest_path, uid_t uid,
-        gid_t gid, gid_t write_gid, int num_threads, derive_t derive,
+        gid_t gid, gid_t write_gid, userid_t owner_user, int num_threads, derive_t derive,
         bool split_perms) {
     int fd;
     char opts[256];
@@ -1893,7 +1883,7 @@
         goto error;
     }
 
-    fuse_init(&fuse, fd, source_path, write_gid, derive, split_perms);
+    fuse_init(&fuse, fd, source_path, write_gid, owner_user, derive, split_perms);
 
     umask(0);
     res = ignite_fuse(&fuse, num_threads);
@@ -1914,6 +1904,7 @@
     uid_t uid = 0;
     gid_t gid = 0;
     gid_t write_gid = AID_SDCARD_RW;
+    userid_t owner_user = 0;
     int num_threads = DEFAULT_NUM_THREADS;
     derive_t derive = DERIVE_NONE;
     bool split_perms = false;
@@ -1922,7 +1913,7 @@
     int fs_version;
 
     int opt;
-    while ((opt = getopt(argc, argv, "u:g:w:t:dls")) != -1) {
+    while ((opt = getopt(argc, argv, "u:g:w:o:t:dls")) != -1) {
         switch (opt) {
             case 'u':
                 uid = strtoul(optarg, NULL, 10);
@@ -1933,6 +1924,9 @@
             case 'w':
                 write_gid = strtoul(optarg, NULL, 10);
                 break;
+            case 'o':
+                owner_user = strtoul(optarg, NULL, 10);
+                break;
             case 't':
                 num_threads = strtoul(optarg, NULL, 10);
                 break;
@@ -1999,6 +1993,7 @@
         sleep(1);
     }
 
-    res = run(source_path, dest_path, uid, gid, write_gid, num_threads, derive, split_perms);
+    res = run(source_path, dest_path, uid, gid, write_gid, owner_user,
+            num_threads, derive, split_perms);
     return res < 0 ? 1 : 0;
 }
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 424ba23..9b57d59 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -59,11 +59,8 @@
     renice \
     restorecon \
     route \
-    runcon \
-    schedtop \
     sendevent \
     setprop \
-    smd \
     start \
     stop \
     top \
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/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/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);