Merge "ANativeWindow: Add NATIVE_WINDOW_BUFFER_AGE query"
diff --git a/adb/Android.mk b/adb/Android.mk
index 3733ae3..9b6e147 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -5,7 +5,11 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-ADB_CLANG :=
+ifeq ($(HOST_OS),windows)
+  adb_host_clang := false  # libc++ for mingw not ready yet.
+else
+  adb_host_clang := true
+endif
 
 # libadb
 # =========================================================
@@ -21,11 +25,17 @@
     adb_auth.cpp \
     adb_io.cpp \
     adb_listeners.cpp \
+    adb_utils.cpp \
     sockets.cpp \
     transport.cpp \
     transport_local.cpp \
     transport_usb.cpp \
 
+LIBADB_TEST_SRCS := \
+    adb_io_test.cpp \
+    adb_utils_test.cpp \
+    transport_test.cpp \
+
 LIBADB_CFLAGS := \
     -Wall -Werror \
     -Wno-unused-parameter \
@@ -34,8 +44,8 @@
 
 LIBADB_darwin_SRC_FILES := \
     fdevent.cpp \
-    get_my_path_darwin.c \
-    usb_osx.c \
+    get_my_path_darwin.cpp \
+    usb_osx.cpp \
 
 LIBADB_linux_SRC_FILES := \
     fdevent.cpp \
@@ -44,11 +54,11 @@
 
 LIBADB_windows_SRC_FILES := \
     get_my_path_windows.cpp \
-    sysdeps_win32.c \
+    sysdeps_win32.cpp \
     usb_windows.cpp \
 
 include $(CLEAR_VARS)
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := true
 LOCAL_MODULE := libadbd
 LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
 LOCAL_SRC_FILES := \
@@ -57,12 +67,14 @@
     fdevent.cpp \
     jdwp_service.cpp \
     qemu_tracing.cpp \
-    usb_linux_client.c \
+    usb_linux_client.cpp \
+
+LOCAL_SHARED_LIBRARIES := libbase
 
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := $(adb_host_clang)
 LOCAL_MODULE := libadb
 LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=1
 LOCAL_SRC_FILES := \
@@ -70,6 +82,8 @@
     $(LIBADB_$(HOST_OS)_SRC_FILES) \
     adb_auth_host.cpp \
 
+LOCAL_SHARED_LIBRARIES := libbase
+
 # Even though we're building a static library (and thus there's no link step for
 # this to take effect), this adds the SSL includes to our path.
 LOCAL_STATIC_LIBRARIES := libcrypto_static
@@ -80,12 +94,8 @@
 
 include $(BUILD_HOST_STATIC_LIBRARY)
 
-LIBADB_TEST_SRCS := \
-    adb_io_test.cpp \
-    transport_test.cpp \
-
 include $(CLEAR_VARS)
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := true
 LOCAL_MODULE := adbd_test
 LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS)
 LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS)
@@ -94,7 +104,7 @@
 include $(BUILD_NATIVE_TEST)
 
 include $(CLEAR_VARS)
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := $(adb_host_clang)
 LOCAL_MODULE := adb_test
 LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
 LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS) services.cpp
@@ -108,6 +118,10 @@
   LOCAL_LDLIBS += -lrt -ldl -lpthread
 endif
 
+ifeq ($(HOST_OS),darwin)
+  LOCAL_LDLIBS += -framework CoreFoundation -framework IOKit
+endif
+
 include $(BUILD_HOST_NATIVE_TEST)
 
 # adb host tool
@@ -125,15 +139,11 @@
 endif
 
 ifeq ($(HOST_OS),windows)
+  LOCAL_LDLIBS += -lws2_32 -lgdi32
   EXTRA_STATIC_LIBS := AdbWinApi
-  ifneq ($(strip $(USE_MINGW)),)
-    # MinGW under Linux case
-    LOCAL_LDLIBS += -lws2_32 -lgdi32
-    USE_SYSDEPS_WIN32 := 1
-  endif
 endif
 
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := $(adb_host_clang)
 
 LOCAL_SRC_FILES := \
     adb_main.cpp \
@@ -154,13 +164,22 @@
 
 LOCAL_STATIC_LIBRARIES := \
     libadb \
+    libbase \
     libcrypto_static \
+    libcutils \
+    liblog \
     $(EXTRA_STATIC_LIBS) \
 
-ifeq ($(USE_SYSDEPS_WIN32),)
-    LOCAL_STATIC_LIBRARIES += libcutils
+# libc++ not available on windows yet
+ifneq ($(HOST_OS),windows)
+    LOCAL_CXX_STL := libc++_static
 endif
 
+# Don't add anything here, we don't want additional shared dependencies
+# on the host adb tool, and shared libraries that link against libc++
+# will violate ODR
+LOCAL_SHARED_LIBRARIES :=
+
 include $(BUILD_HOST_EXECUTABLE)
 
 $(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE))
@@ -177,7 +196,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := true
 
 LOCAL_SRC_FILES := \
     adb_main.cpp \
diff --git a/adb/adb.cpp b/adb/adb.cpp
index ad85184f..4c90dcc 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -32,6 +32,9 @@
 
 #include <string>
 
+#include <base/stringprintf.h>
+#include <base/strings.h>
+
 #include "adb_auth.h"
 #include "adb_io.h"
 #include "adb_listeners.h"
@@ -379,84 +382,60 @@
 }
 #endif // ADB_HOST
 
-/* qual_overwrite is used to overwrite a qualifier string.  dst is a
- * pointer to a char pointer.  It is assumed that if *dst is non-NULL, it
- * was malloc'ed and needs to freed.  *dst will be set to a dup of src.
- */
-static void qual_overwrite(char **dst, const char *src)
-{
-    if (!dst)
-        return;
-
+// qual_overwrite is used to overwrite a qualifier string.  dst is a
+// pointer to a char pointer.  It is assumed that if *dst is non-NULL, it
+// was malloc'ed and needs to freed.  *dst will be set to a dup of src.
+// TODO: switch to std::string for these atransport fields instead.
+static void qual_overwrite(char** dst, const std::string& src) {
     free(*dst);
-    *dst = NULL;
-
-    if (!src || !*src)
-        return;
-
-    *dst = strdup(src);
+    *dst = strdup(src.c_str());
 }
 
-void parse_banner(char *banner, atransport *t)
-{
-    static const char *prop_seps = ";";
-    static const char key_val_sep = '=';
-    char *cp;
-    char *type;
-
+void parse_banner(const char* banner, atransport* t) {
     D("parse_banner: %s\n", banner);
-    type = banner;
-    cp = strchr(type, ':');
-    if (cp) {
-        *cp++ = 0;
-        /* Nothing is done with second field. */
-        cp = strchr(cp, ':');
-        if (cp) {
-            char *save;
-            char *key;
-            key = adb_strtok_r(cp + 1, prop_seps, &save);
-            while (key) {
-                cp = strchr(key, key_val_sep);
-                if (cp) {
-                    *cp++ = '\0';
-                    if (!strcmp(key, "ro.product.name"))
-                        qual_overwrite(&t->product, cp);
-                    else if (!strcmp(key, "ro.product.model"))
-                        qual_overwrite(&t->model, cp);
-                    else if (!strcmp(key, "ro.product.device"))
-                        qual_overwrite(&t->device, cp);
-                }
-                key = adb_strtok_r(NULL, prop_seps, &save);
+
+    // The format is something like:
+    // "device::ro.product.name=x;ro.product.model=y;ro.product.device=z;".
+    std::vector<std::string> pieces = android::base::Split(banner, ":");
+
+    if (pieces.size() > 2) {
+        const std::string& props = pieces[2];
+        for (auto& prop : android::base::Split(props, ";")) {
+            // The list of properties was traditionally ;-terminated rather than ;-separated.
+            if (prop.empty()) continue;
+
+            std::vector<std::string> key_value = android::base::Split(prop, "=");
+            if (key_value.size() != 2) continue;
+
+            const std::string& key = key_value[0];
+            const std::string& value = key_value[1];
+            if (key == "ro.product.name") {
+                qual_overwrite(&t->product, value);
+            } else if (key == "ro.product.model") {
+                qual_overwrite(&t->model, value);
+            } else if (key == "ro.product.device") {
+                qual_overwrite(&t->device, value);
             }
         }
     }
 
-    if(!strcmp(type, "bootloader")){
+    const std::string& type = pieces[0];
+    if (type == "bootloader") {
         D("setting connection_state to CS_BOOTLOADER\n");
         t->connection_state = CS_BOOTLOADER;
         update_transports();
-        return;
-    }
-
-    if(!strcmp(type, "device")) {
+    } else if (type == "device") {
         D("setting connection_state to CS_DEVICE\n");
         t->connection_state = CS_DEVICE;
         update_transports();
-        return;
-    }
-
-    if(!strcmp(type, "recovery")) {
+    } else if (type == "recovery") {
         D("setting connection_state to CS_RECOVERY\n");
         t->connection_state = CS_RECOVERY;
         update_transports();
-        return;
-    }
-
-    if(!strcmp(type, "sideload")) {
+    } else if (type == "sideload") {
         D("setting connection_state to CS_SIDELOAD\n");
         t->connection_state = CS_SIDELOAD;
         update_transports();
-        return;
     }
 
     t->connection_state = CS_HOST;
@@ -491,7 +470,7 @@
             handle_offline(t);
         }
 
-        parse_banner((char*) p->data, t);
+        parse_banner(reinterpret_cast<const char*>(p->data), t);
 
         if (HOST || !auth_enabled) {
             handle_online(t);
@@ -802,7 +781,6 @@
     if (!strncmp(service, "forward:",8) ||
         !strncmp(service, "killforward:",12)) {
         char *local, *remote;
-        int r;
         atransport *transport;
 
         int createForward = strncmp(service, "kill", 4);
@@ -838,19 +816,20 @@
             }
         }
 
-        const char* err;
-        transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
+        std::string error_msg;
+        transport = acquire_one_transport(CS_ANY, ttype, serial, &error_msg);
         if (!transport) {
-            sendfailmsg(reply_fd, err);
+            sendfailmsg(reply_fd, error_msg.c_str());
             return 1;
         }
 
+        install_status_t r;
         if (createForward) {
             r = install_listener(local, remote, transport, no_rebind);
         } else {
             r = remove_listener(local, transport);
         }
-        if(r == 0) {
+        if (r == INSTALL_STATUS_OK) {
 #if ADB_HOST
             /* On the host: 1st OKAY is connect, 2nd OKAY is status */
             WriteFdExactly(reply_fd, "OKAY", 4);
@@ -859,22 +838,19 @@
             return 1;
         }
 
-        if (createForward) {
-            const char* message;
-            switch (r) {
-              case INSTALL_STATUS_CANNOT_BIND:
-                message = "cannot bind to socket";
-                break;
-              case INSTALL_STATUS_CANNOT_REBIND:
-                message = "cannot rebind existing socket";
-                break;
-              default:
-                message = "internal error";
-            }
-            sendfailmsg(reply_fd, message);
-        } else {
-            sendfailmsg(reply_fd, "cannot remove listener");
+        std::string message;
+        switch (r) {
+          case INSTALL_STATUS_OK: message = " "; break;
+          case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break;
+          case INSTALL_STATUS_CANNOT_BIND:
+            message = android::base::StringPrintf("cannot bind to socket: %s", strerror(errno));
+            break;
+          case INSTALL_STATUS_CANNOT_REBIND:
+            message = android::base::StringPrintf("cannot rebind existing socket: %s", strerror(errno));
+            break;
+          case INSTALL_STATUS_LISTENER_NOT_FOUND: message = "listener not found"; break;
         }
+        sendfailmsg(reply_fd, message.c_str());
         return 1;
     }
     return 0;
@@ -910,14 +886,14 @@
             serial = service;
         }
 
-        const char* error_string = "unknown failure";
-        transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
+        std::string error_msg = "unknown failure";
+        transport = acquire_one_transport(CS_ANY, type, serial, &error_msg);
 
         if (transport) {
             s->transport = transport;
             adb_write(reply_fd, "OKAY", 4);
         } else {
-            sendfailmsg(reply_fd, error_string);
+            sendfailmsg(reply_fd, error_msg.c_str());
         }
         return 1;
     }
@@ -975,7 +951,7 @@
     if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
         const char *out = "unknown";
         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
-       if (transport && transport->serial) {
+        if (transport && transport->serial) {
             out = transport->serial;
         }
         send_msg_with_okay(reply_fd, out, strlen(out));
@@ -984,7 +960,7 @@
     if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
         const char *out = "unknown";
         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
-       if (transport && transport->devpath) {
+        if (transport && transport->devpath) {
             out = transport->devpath;
         }
         send_msg_with_okay(reply_fd, out, strlen(out));
diff --git a/adb/adb.h b/adb/adb.h
index 749515c..cb2cf60 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -23,10 +23,6 @@
 #include "adb_trace.h"
 #include "fdevent.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #define MAX_PAYLOAD 4096
 
 #define A_SYNC 0x434e5953
@@ -47,14 +43,8 @@
 // Increment this when we want to force users to start a new adb server.
 #define ADB_SERVER_VERSION 32
 
-typedef struct amessage amessage;
-typedef struct apacket apacket;
-typedef struct asocket asocket;
-typedef struct alistener alistener;
-typedef struct aservice aservice;
-typedef struct atransport atransport;
-typedef struct adisconnect  adisconnect;
-typedef struct usb_handle usb_handle;
+struct atransport;
+struct usb_handle;
 
 struct amessage {
     unsigned command;       /* command identifier constant      */
@@ -171,12 +161,12 @@
 ** object, it's a special value used to indicate that a client wants to
 ** connect to a service implemented within the ADB server itself.
 */
-typedef enum transport_type {
+enum transport_type {
         kTransportUsb,
         kTransportLocal,
         kTransportAny,
         kTransportHost,
-} transport_type;
+};
 
 #define TOKEN_SIZE 20
 
@@ -363,10 +353,10 @@
 extern int HOST;
 extern int SHELL_EXIT_NOTIFY_FD;
 
-typedef enum {
+enum subproc_mode {
     SUBPROC_PTY = 0,
     SUBPROC_RAW = 1,
-} subproc_mode;
+} ;
 
 #define CHUNK_SIZE (64*1024)
 
@@ -389,8 +379,4 @@
 
 void send_connect(atransport *t);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index 635556e..1e1978d 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -19,10 +19,6 @@
 
 #include "adb.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern int auth_enabled;
 
 int adb_auth_keygen(const char* filename);
@@ -68,8 +64,4 @@
 
 #endif // ADB_HOST
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif // __ADB_AUTH_H
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 7c2bcfb..510dcc2 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -43,6 +43,7 @@
 #include "mincrypt/rsa.h"
 #undef RSA_verify
 
+#include <base/strings.h>
 #include <cutils/list.h>
 
 #include <openssl/evp.h>
@@ -172,7 +173,7 @@
         return 0;
     }
 
-    outfile = fopen(path, "w");
+    outfile = fopen(path, "we");
     if (!outfile) {
         D("Failed to open '%s'\n", path);
         return 0;
@@ -191,7 +192,7 @@
     encoded_length = 1 + ((sizeof(pkey) + 2) / 3 * 4);
 #endif
 
-    encoded = reinterpret_cast<uint8_t*>(malloc(encoded_length));
+    encoded = new uint8_t[encoded_length];
     if (encoded == nullptr) {
         D("Allocation failure");
         goto out;
@@ -212,9 +213,7 @@
     if (outfile != NULL) {
         fclose(outfile);
     }
-    if (encoded != NULL) {
-        free(encoded);
-    }
+    delete[] encoded;
     return ret;
 }
 
@@ -240,7 +239,7 @@
 
     old_mask = umask(077);
 
-    f = fopen(file, "w");
+    f = fopen(file, "we");
     if (!f) {
         D("Failed to open '%s'\n", file);
         umask(old_mask);
@@ -274,30 +273,24 @@
 {
     D("read_key '%s'\n", file);
 
-    FILE* f = fopen(file, "r");
-    if (!f) {
-        D("Failed to open '%s'\n", file);
+    FILE* fp = fopen(file, "re");
+    if (!fp) {
+        D("Failed to open '%s': %s\n", file, strerror(errno));
         return 0;
     }
 
-    adb_private_key* key = reinterpret_cast<adb_private_key*>(
-        malloc(sizeof(adb_private_key)));
-    if (!key) {
-        D("Failed to alloc key\n");
-        fclose(f);
-        return 0;
-    }
+    adb_private_key* key = new adb_private_key;
     key->rsa = RSA_new();
 
-    if (!PEM_read_RSAPrivateKey(f, &key->rsa, NULL, NULL)) {
+    if (!PEM_read_RSAPrivateKey(fp, &key->rsa, NULL, NULL)) {
         D("Failed to read key\n");
-        fclose(f);
+        fclose(fp);
         RSA_free(key->rsa);
-        free(key);
+        delete key;
         return 0;
     }
 
-    fclose(f);
+    fclose(fp);
     list_add_tail(list, &key->node);
     return 1;
 }
@@ -362,29 +355,16 @@
     return read_key(path, list);
 }
 
-static void get_vendor_keys(struct listnode *list)
-{
-    const char *adb_keys_path;
-    char keys_path[MAX_PAYLOAD];
-    char *path;
-    char *save;
-    struct stat buf;
-
-    adb_keys_path = getenv("ADB_VENDOR_KEYS");
-    if (!adb_keys_path)
+static void get_vendor_keys(struct listnode* key_list) {
+    const char* adb_keys_path = getenv("ADB_VENDOR_KEYS");
+    if (adb_keys_path == nullptr) {
         return;
-    strncpy(keys_path, adb_keys_path, sizeof(keys_path));
+    }
 
-    path = adb_strtok_r(keys_path, ENV_PATH_SEPARATOR_STR, &save);
-    while (path) {
-        D("Reading: '%s'\n", path);
-
-        if (stat(path, &buf))
-            D("Can't read '%s'\n", path);
-        else if (!read_key(path, list))
-            D("Failed to read '%s'\n", path);
-
-        path = adb_strtok_r(NULL, ENV_PATH_SEPARATOR_STR, &save);
+    for (auto& path : android::base::Split(adb_keys_path, ENV_PATH_SEPARATOR_STR)) {
+        if (!read_key(path.c_str(), key_list)) {
+            D("Failed to read '%s'\n", path.c_str());
+        }
     }
 }
 
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index 4751bff..0f64998 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -28,6 +28,8 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <string>
+
 #include "adb_io.h"
 
 static transport_type __adb_transport = kTransportAny;
@@ -108,44 +110,40 @@
 
 static int switch_socket_transport(int fd)
 {
-    char service[64];
-    char tmp[5];
-    int len;
-
-    if (__adb_serial)
-        snprintf(service, sizeof service, "host:transport:%s", __adb_serial);
-    else {
+    std::string service;
+    if (__adb_serial) {
+        service += "host:transport:";
+        service += __adb_serial;
+    } else {
         const char* transport_type = "???";
-
-         switch (__adb_transport) {
-            case kTransportUsb:
-                transport_type = "transport-usb";
-                break;
-            case kTransportLocal:
-                transport_type = "transport-local";
-                break;
-            case kTransportAny:
-                transport_type = "transport-any";
-                break;
-            case kTransportHost:
-                // no switch necessary
-                return 0;
-                break;
+        switch (__adb_transport) {
+          case kTransportUsb:
+            transport_type = "transport-usb";
+            break;
+          case kTransportLocal:
+            transport_type = "transport-local";
+            break;
+          case kTransportAny:
+            transport_type = "transport-any";
+            break;
+          case kTransportHost:
+            // no switch necessary
+            return 0;
         }
-
-        snprintf(service, sizeof service, "host:%s", transport_type);
+        service += "host:";
+        service += transport_type;
     }
-    len = strlen(service);
-    snprintf(tmp, sizeof tmp, "%04x", len);
 
-    if(!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, service, len)) {
+    char tmp[5];
+    snprintf(tmp, sizeof(tmp), "%04zx", service.size());
+    if (!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, service.c_str(), service.size())) {
         strcpy(__adb_error, "write failure during connection");
         adb_close(fd);
         return -1;
     }
     D("Switch transport in progress\n");
 
-    if(adb_status(fd)) {
+    if (adb_status(fd)) {
         adb_close(fd);
         D("Switch transport failed\n");
         return -1;
diff --git a/adb/adb_client.h b/adb/adb_client.h
index 9af176f..934362a 100644
--- a/adb/adb_client.h
+++ b/adb/adb_client.h
@@ -3,10 +3,6 @@
 
 #include "adb.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* connect to adb, connect to the named service, and return
 ** a valid fd for interacting with that service upon success
 ** or a negative number on failure
@@ -58,8 +54,4 @@
 */
 int adb_status(int fd);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/adb/adb_io.h b/adb/adb_io.h
index 7d09e7b..8d237ce 100644
--- a/adb/adb_io.h
+++ b/adb/adb_io.h
@@ -20,10 +20,6 @@
 #include <stdbool.h>
 #include <sys/types.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
  * Reads exactly len bytes from fd into buf.
  *
@@ -46,8 +42,4 @@
 /* Same as WriteFdExactly, but with an implicit len = strlen(buf). */
 bool WriteStringFully(int fd, const char* str);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* ADB_IO_H */
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index 84b9c64..a1a5ddb 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -190,17 +190,17 @@
     return result;
 }
 
-int remove_listener(const char *local_name, atransport* transport)
+install_status_t remove_listener(const char *local_name, atransport* transport)
 {
     alistener *l;
 
     for (l = listener_list.next; l != &listener_list; l = l->next) {
         if (!strcmp(local_name, l->local_name)) {
             listener_disconnect(l, l->transport);
-            return 0;
+            return INSTALL_STATUS_OK;
         }
     }
-    return -1;
+    return INSTALL_STATUS_LISTENER_NOT_FOUND;
 }
 
 void remove_all_listeners(void)
@@ -268,10 +268,10 @@
 
     listener->fd = local_name_to_fd(local_name);
     if (listener->fd < 0) {
+        printf("cannot bind '%s': %s\n", local_name, strerror(errno));
         free(listener->local_name);
         free(listener->connect_to);
         free(listener);
-        printf("cannot bind '%s'\n", local_name);
         return INSTALL_STATUS_CANNOT_BIND;
     }
 
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index 14fdcd6..f55fdee 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -19,17 +19,14 @@
 
 #include "adb.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 // error/status codes for install_listener.
-typedef enum {
+enum install_status_t {
   INSTALL_STATUS_OK = 0,
   INSTALL_STATUS_INTERNAL_ERROR = -1,
   INSTALL_STATUS_CANNOT_BIND = -2,
   INSTALL_STATUS_CANNOT_REBIND = -3,
-} install_status_t;
+  INSTALL_STATUS_LISTENER_NOT_FOUND = -4,
+};
 
 extern alistener listener_list;
 
@@ -44,11 +41,7 @@
 
 int format_listeners(char* buf, size_t buflen);
 
-int remove_listener(const char *local_name, atransport* transport);
+install_status_t remove_listener(const char* local_name, atransport* transport);
 void remove_all_listeners(void);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* __ADB_LISTENERS_H */
diff --git a/adb/adb_main.cpp b/adb/adb_main.cpp
index fb17e89..5acaf80 100644
--- a/adb/adb_main.cpp
+++ b/adb/adb_main.cpp
@@ -383,7 +383,7 @@
     /* 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 (true) {
         int c;
         int option_index = 0;
         static struct option opts[] = {
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index ef5dc24..32b6ae4 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -23,10 +23,6 @@
 #include <stdio.h>
 #endif
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
 #define  ADB_TRACE    1
 
@@ -34,7 +30,7 @@
  * forget to update the corresponding 'tags' table in
  * the adb_trace_init() function implemented in adb.c
  */
-typedef enum {
+enum AdbTrace {
     TRACE_ADB = 0,   /* 0x001 */
     TRACE_SOCKETS,
     TRACE_PACKETS,
@@ -47,7 +43,7 @@
     TRACE_SERVICES,
     TRACE_AUTH,
     TRACE_FDEVENT,
-} AdbTrace;
+} ;
 
 #if ADB_TRACE
 
@@ -148,8 +144,4 @@
 #  define  ADB_TRACING     0
 #endif /* ADB_TRACE */
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* __ADB_TRACE_H */
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
new file mode 100644
index 0000000..f10c143
--- /dev/null
+++ b/adb/adb_utils.cpp
@@ -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.
+ */
+
+#include "adb_utils.h"
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "sysdeps.h"
+
+bool getcwd(std::string* s) {
+  char* cwd = getcwd(nullptr, 0);
+  if (cwd != nullptr) *s = cwd;
+  free(cwd);
+  return (cwd != nullptr);
+}
+
+bool directory_exists(const std::string& path) {
+  struct stat sb;
+  return lstat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode);
+}
+
+std::string escape_arg(const std::string& s) {
+  std::string result = s;
+
+  // Insert a \ before any ' in the string.
+  for (auto it = result.begin(); it != result.end(); ++it) {
+      if (*it == '\'') {
+          it = result.insert(it, '\\') + 1;
+      }
+  }
+
+  // Prefix and suffix the whole string with '.
+  result.insert(result.begin(), '\'');
+  result.push_back('\'');
+  return result;
+}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
new file mode 100644
index 0000000..4b64afa
--- /dev/null
+++ b/adb/adb_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 _ADB_UTILS_H_
+#define _ADB_UTILS_H_
+
+#include <string>
+
+bool getcwd(std::string* cwd);
+bool directory_exists(const std::string& path);
+
+std::string escape_arg(const std::string& s);
+
+#endif
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
new file mode 100644
index 0000000..a395079
--- /dev/null
+++ b/adb/adb_utils_test.cpp
@@ -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.
+ */
+
+#include "adb_utils.h"
+
+#include <gtest/gtest.h>
+
+TEST(adb_utils, directory_exists) {
+  ASSERT_TRUE(directory_exists("/proc"));
+  ASSERT_FALSE(directory_exists("/proc/self")); // Symbolic link.
+  ASSERT_FALSE(directory_exists("/proc/does-not-exist"));
+}
+
+TEST(adb_utils, escape_arg) {
+  ASSERT_EQ(R"('')", escape_arg(""));
+
+  ASSERT_EQ(R"('abc')", escape_arg("abc"));
+
+  ASSERT_EQ(R"(' abc')", escape_arg(" abc"));
+  ASSERT_EQ(R"('\'abc')", escape_arg("'abc"));
+  ASSERT_EQ(R"('"abc')", escape_arg("\"abc"));
+  ASSERT_EQ(R"('\abc')", escape_arg("\\abc"));
+  ASSERT_EQ(R"('(abc')", escape_arg("(abc"));
+  ASSERT_EQ(R"(')abc')", escape_arg(")abc"));
+
+  ASSERT_EQ(R"('abc abc')", escape_arg("abc abc"));
+  ASSERT_EQ(R"('abc\'abc')", escape_arg("abc'abc"));
+  ASSERT_EQ(R"('abc"abc')", escape_arg("abc\"abc"));
+  ASSERT_EQ(R"('abc\abc')", escape_arg("abc\\abc"));
+  ASSERT_EQ(R"('abc(abc')", escape_arg("abc(abc"));
+  ASSERT_EQ(R"('abc)abc')", escape_arg("abc)abc"));
+
+  ASSERT_EQ(R"('abc ')", escape_arg("abc "));
+  ASSERT_EQ(R"('abc\'')", escape_arg("abc'"));
+  ASSERT_EQ(R"('abc"')", escape_arg("abc\""));
+  ASSERT_EQ(R"('abc\')", escape_arg("abc\\"));
+  ASSERT_EQ(R"('abc(')", escape_arg("abc("));
+  ASSERT_EQ(R"('abc)')", escape_arg("abc)"));
+}
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 34efefe..e59a96a 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -21,6 +21,7 @@
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <limits.h>
 #include <stdarg.h>
 #include <stdint.h>
@@ -30,6 +31,10 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <string>
+
+#include <base/stringprintf.h>
+
 #if !defined(_WIN32)
 #include <termios.h>
 #include <unistd.h>
@@ -39,49 +44,38 @@
 #include "adb_auth.h"
 #include "adb_client.h"
 #include "adb_io.h"
+#include "adb_utils.h"
 #include "file_sync_service.h"
 
 static int do_cmd(transport_type ttype, const char* serial, const char *cmd, ...);
 
-int find_sync_dirs(const char *srcarg,
-        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,
+static int install_app(transport_type transport, const char* serial, int argc,
+                       const char** argv);
+static int install_multiple_app(transport_type transport, const char* serial, int argc,
+                                const char** argv);
+static int uninstall_app(transport_type transport, const char* serial, int argc,
                          const char** argv);
-int uninstall_app(transport_type transport, const char* serial, int argc,
-                  const char** argv);
 
-static const char *gProductOutPath = NULL;
+static std::string gProductOutPath;
 extern int gListenAll;
 
-static char *product_file(const char *extra)
-{
-    if (gProductOutPath == NULL) {
+static std::string product_file(const char *extra) {
+    if (gProductOutPath.empty()) {
         fprintf(stderr, "adb: Product directory not specified; "
                 "use -p or define ANDROID_PRODUCT_OUT\n");
         exit(1);
     }
 
-    int n = strlen(gProductOutPath) + strlen(extra) + 2;
-    char* x = reinterpret_cast<char*>(malloc(n));
-    if (x == 0) {
-        fprintf(stderr, "adb: Out of memory (product_file())\n");
-        exit(1);
-    }
-
-    snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
-    return x;
+    return android::base::StringPrintf("%s%s%s",
+                                       gProductOutPath.c_str(), OS_PATH_SEPARATOR_STR, extra);
 }
 
-void version(FILE * out) {
+static void version(FILE* out) {
     fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
-         ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
+            ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
 }
 
-void help()
-{
+static void help() {
     version(stderr);
 
     fprintf(stderr,
@@ -241,19 +235,16 @@
         );
 }
 
-int usage()
-{
+static int usage() {
     help();
     return 1;
 }
 
 #if defined(_WIN32)
 
-// Implemented in sysdeps_win32.c.
-extern "C" {
+// Implemented in sysdeps_win32.cpp.
 void stdin_raw_init(int fd);
 void stdin_raw_restore(int fd);
-}
 
 #else
 static termios g_saved_terminal_state;
@@ -321,6 +312,7 @@
 static void copy_to_file(int inFd, int outFd) {
     const size_t BUFSIZE = 32 * 1024;
     char* buf = (char*) malloc(BUFSIZE);
+    if (buf == nullptr) fatal("couldn't allocate buffer for copy_to_file");
     int len;
     long total = 0;
 
@@ -330,7 +322,7 @@
         stdin_raw_init(STDIN_FILENO);
     }
 
-    for (;;) {
+    while (true) {
         if (inFd == STDIN_FILENO) {
             len = unix_read(inFd, buf, BUFSIZE);
         } else {
@@ -416,8 +408,7 @@
     return 0;
 }
 
-int interactive_shell(void)
-{
+static int interactive_shell() {
     adb_thread_t thr;
     int fdi, fd;
 
@@ -429,6 +420,11 @@
     fdi = 0; //dup(0);
 
     int* fds = reinterpret_cast<int*>(malloc(sizeof(int) * 2));
+    if (fds == nullptr) {
+        fprintf(stderr, "couldn't allocate fds array: %s\n", strerror(errno));
+        return 1;
+    }
+
     fds[0] = fd;
     fds[1] = fdi;
 
@@ -455,8 +451,8 @@
     }
 }
 
-int adb_download_buffer(const char *service, const char *fn, const void* data, int sz,
-                        unsigned progress)
+static int adb_download_buffer(const char *service, const char *fn, const void* data, int sz,
+                               unsigned progress)
 {
     char buf[4096];
     unsigned total;
@@ -514,23 +510,6 @@
     return 0;
 }
 
-
-int adb_download(const char *service, const char *fn, unsigned progress)
-{
-    void *data;
-    unsigned sz;
-
-    data = load_file(fn, &sz);
-    if(data == 0) {
-        fprintf(stderr,"* cannot read '%s' *\n", fn);
-        return -1;
-    }
-
-    int status = adb_download_buffer(service, fn, data, sz, progress);
-    free(data);
-    return status;
-}
-
 #define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE)
 
 /*
@@ -552,7 +531,7 @@
  * - When the other side sends "DONEDONE" instead of a block number,
  *   we hang up.
  */
-int adb_sideload_host(const char* fn) {
+static int adb_sideload_host(const char* fn) {
     unsigned sz;
     size_t xfer = 0;
     int status;
@@ -581,7 +560,7 @@
 
     opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
 
-    for (;;) {
+    while (true) {
         if (!ReadFdExactly(fd, buf, 8)) {
             fprintf(stderr, "* failed to read command: %s\n", adb_error());
             status = -1;
@@ -683,50 +662,6 @@
     }
 }
 
-static int should_escape(const char c)
-{
-    return (c == ' ' || c == '\'' || c == '"' || c == '\\' || c == '(' || c == ')');
-}
-
-/* Duplicate and escape given argument. */
-static char *escape_arg(const char *s)
-{
-    const char *ts;
-    size_t alloc_len;
-    char *ret;
-    char *dest;
-
-    alloc_len = 0;
-    for (ts = s; *ts != '\0'; ts++) {
-        alloc_len++;
-        if (should_escape(*ts)) {
-            alloc_len++;
-        }
-    }
-
-    if (alloc_len == 0) {
-        // Preserve empty arguments
-        ret = (char *) malloc(3);
-        ret[0] = '\"';
-        ret[1] = '\"';
-        ret[2] = '\0';
-        return ret;
-    }
-
-    ret = (char *) malloc(alloc_len + 1);
-    dest = ret;
-
-    for (ts = s; *ts != '\0'; ts++) {
-        if (should_escape(*ts)) {
-            *dest++ = '\\';
-        }
-        *dest++ = *ts;
-    }
-    *dest++ = '\0';
-
-    return ret;
-}
-
 /**
  * Run ppp in "notty" mode against a resource listed as the first parameter
  * eg:
@@ -734,8 +669,7 @@
  * ppp dev:/dev/omap_csmi_tty0 <ppp options>
  *
  */
-int ppp(int argc, const char **argv)
-{
+static int ppp(int argc, const char** argv) {
 #if defined(_WIN32)
     fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
     return -1;
@@ -800,14 +734,12 @@
 #endif /* !defined(_WIN32) */
 }
 
-static int send_shellcommand(transport_type transport, const char* serial,
-                             char* buf)
-{
-    int fd, ret;
-
-    for(;;) {
-        fd = adb_connect(buf);
-        if(fd >= 0)
+static int send_shell_command(transport_type transport, const char* serial,
+                              const std::string& command) {
+    int fd;
+    while (true) {
+        fd = adb_connect(command.c_str());
+        if (fd >= 0)
             break;
         fprintf(stderr,"- waiting for device -\n");
         adb_sleep_ms(1000);
@@ -815,42 +747,30 @@
     }
 
     read_and_dump(fd);
-    ret = adb_close(fd);
-    if (ret)
+    int rc = adb_close(fd);
+    if (rc) {
         perror("close");
-
-    return ret;
+    }
+    return rc;
 }
 
-static int logcat(transport_type transport, const char* serial, int argc,
-                  const char** argv)
-{
-    char buf[4096];
+static int logcat(transport_type transport, const char* serial, int argc, const char** argv) {
+    char* log_tags = getenv("ANDROID_LOG_TAGS");
+    std::string quoted = escape_arg(log_tags == nullptr ? "" : log_tags);
 
-    char *log_tags;
-    char *quoted;
-
-    log_tags = getenv("ANDROID_LOG_TAGS");
-    quoted = escape_arg(log_tags == NULL ? "" : log_tags);
-    snprintf(buf, sizeof(buf),
-            "shell:export ANDROID_LOG_TAGS=\"%s\"; exec logcat", quoted);
-    free(quoted);
+    std::string cmd = "shell:export ANDROID_LOG_TAGS=\"" + quoted + "\"; exec logcat";
 
     if (!strcmp(argv[0], "longcat")) {
-        strncat(buf, " -v long", sizeof(buf) - 1);
+        cmd += " -v long";
     }
 
-    argc -= 1;
-    argv += 1;
-    while(argc-- > 0) {
-        quoted = escape_arg(*argv++);
-        strncat(buf, " ", sizeof(buf) - 1);
-        strncat(buf, quoted, sizeof(buf) - 1);
-        free(quoted);
+    --argc;
+    ++argv;
+    while (argc-- > 0) {
+        cmd += " " + escape_arg(*argv++);
     }
 
-    send_shellcommand(transport, serial, buf);
-    return 0;
+    return send_shell_command(transport, serial, cmd);
 }
 
 static int mkdirs(const char *path)
@@ -873,21 +793,17 @@
 }
 
 static int backup(int argc, const char** argv) {
-    char buf[4096];
-    char default_name[32];
-    const char* filename = strcpy(default_name, "./backup.ab");
-    int fd, outFd;
-    int i, j;
+    const char* filename = "./backup.ab";
 
     /* find, extract, and use any -f argument */
-    for (i = 1; i < argc; i++) {
+    for (int i = 1; i < argc; i++) {
         if (!strcmp("-f", argv[i])) {
             if (i == argc-1) {
                 fprintf(stderr, "adb: -f passed with no filename\n");
                 return usage();
             }
             filename = argv[i+1];
-            for (j = i+2; j <= argc; ) {
+            for (int j = i+2; j <= argc; ) {
                 argv[i++] = argv[j++];
             }
             argc -= 2;
@@ -900,20 +816,21 @@
 
     adb_unlink(filename);
     mkdirs(filename);
-    outFd = adb_creat(filename, 0640);
+    int outFd = adb_creat(filename, 0640);
     if (outFd < 0) {
         fprintf(stderr, "adb: unable to open file %s\n", filename);
         return -1;
     }
 
-    snprintf(buf, sizeof(buf), "backup");
-    for (argc--, argv++; argc; argc--, argv++) {
-        strncat(buf, ":", sizeof(buf) - strlen(buf) - 1);
-        strncat(buf, argv[0], sizeof(buf) - strlen(buf) - 1);
+    std::string cmd = "backup:";
+    --argc;
+    ++argv;
+    while (argc-- > 0) {
+        cmd += " " + escape_arg(*argv++);
     }
 
-    D("backup. filename=%s buf=%s\n", filename, buf);
-    fd = adb_connect(buf);
+    D("backup. filename=%s cmd=%s\n", filename, cmd.c_str());
+    int fd = adb_connect(cmd.c_str());
     if (fd < 0) {
         fprintf(stderr, "adb: unable to connect for backup\n");
         adb_close(outFd);
@@ -956,81 +873,9 @@
     return 0;
 }
 
-#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
-static int top_works(const char *top)
-{
-    if (top != NULL && adb_is_absolute_host_path(top)) {
-        char path_buf[PATH_MAX];
-        snprintf(path_buf, sizeof(path_buf),
-                "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
-        return access(path_buf, F_OK) == 0;
-    }
-    return 0;
-}
-
-static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
-{
-    strcpy(path_buf, indir);
-    while (1) {
-        if (top_works(path_buf)) {
-            return path_buf;
-        }
-        char *s = adb_dirstop(path_buf);
-        if (s != NULL) {
-            *s = '\0';
-        } else {
-            path_buf[0] = '\0';
-            return NULL;
-        }
-    }
-}
-
-static char *find_top(char path_buf[PATH_MAX])
-{
-    char *top = getenv("ANDROID_BUILD_TOP");
-    if (top != NULL && top[0] != '\0') {
-        if (!top_works(top)) {
-            fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
-            return NULL;
-        }
-    } else {
-        top = getenv("TOP");
-        if (top != NULL && top[0] != '\0') {
-            if (!top_works(top)) {
-                fprintf(stderr, "adb: bad TOP value \"%s\"\n", top);
-                return NULL;
-            }
-        } else {
-            top = NULL;
-        }
-    }
-
-    if (top != NULL) {
-        /* The environment pointed to a top directory that works.
-         */
-        strcpy(path_buf, top);
-        return path_buf;
-    }
-
-    /* The environment didn't help.  Walk up the tree from the CWD
-     * to see if we can find the top.
-     */
-    char dir[PATH_MAX];
-    top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
-    if (top == NULL) {
-        /* If the CWD isn't under a good-looking top, see if the
-         * executable is.
-         */
-        get_my_path(dir, PATH_MAX);
-        top = find_top_from(dir, path_buf);
-    }
-    return top;
-}
-
 /* <hint> may be:
  * - A simple product name
  *   e.g., "sooner"
-TODO: debug?  sooner-debug, sooner:debug?
  * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
  *   e.g., "out/target/product/sooner"
  * - An absolute path to the PRODUCT_OUT dir
@@ -1039,62 +884,52 @@
  * Given <hint>, try to construct an absolute path to the
  * ANDROID_PRODUCT_OUT dir.
  */
-static const char *find_product_out_path(const char *hint)
-{
-    static char path_buf[PATH_MAX];
-
+static std::string find_product_out_path(const char* hint) {
     if (hint == NULL || hint[0] == '\0') {
-        return NULL;
+        return "";
     }
 
-    /* If it's already absolute, don't bother doing any work.
-     */
+    // If it's already absolute, don't bother doing any work.
     if (adb_is_absolute_host_path(hint)) {
-        strcpy(path_buf, hint);
-        return path_buf;
+        return hint;
     }
 
-    /* If there are any slashes in it, assume it's a relative path;
-     * make it absolute.
-     */
-    if (adb_dirstart(hint) != NULL) {
-        if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
-            fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
-            return NULL;
+    // If there are any slashes in it, assume it's a relative path;
+    // make it absolute.
+    if (adb_dirstart(hint) != nullptr) {
+        std::string cwd;
+        if (!getcwd(&cwd)) {
+            fprintf(stderr, "adb: getcwd failed: %s\n", strerror(errno));
+            return "";
         }
-        if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
-            fprintf(stderr, "adb: Couldn't assemble path\n");
-            return NULL;
-        }
-        strcat(path_buf, OS_PATH_SEPARATOR_STR);
-        strcat(path_buf, hint);
-        return path_buf;
+        return android::base::StringPrintf("%s%s%s", cwd.c_str(), OS_PATH_SEPARATOR_STR, hint);
     }
 
-    /* It's a string without any slashes.  Try to do something with it.
-     *
-     * Try to find the root of the build tree, and build a PRODUCT_OUT
-     * path from there.
-     */
-    char top_buf[PATH_MAX];
-    const char *top = find_top(top_buf);
-    if (top == NULL) {
-        fprintf(stderr, "adb: Couldn't find top of build tree\n");
-        return NULL;
+    // It's a string without any slashes.  Try to do something with it.
+    //
+    // Try to find the root of the build tree, and build a PRODUCT_OUT
+    // path from there.
+    char* top = getenv("ANDROID_BUILD_TOP");
+    if (top == nullptr) {
+        fprintf(stderr, "adb: ANDROID_BUILD_TOP not set!\n");
+        return "";
     }
-//TODO: if we have a way to indicate debug, look in out/debug/target/...
-    snprintf(path_buf, sizeof(path_buf),
-            "%s" OS_PATH_SEPARATOR_STR
-            "out" OS_PATH_SEPARATOR_STR
-            "target" OS_PATH_SEPARATOR_STR
-            "product" OS_PATH_SEPARATOR_STR
-            "%s", top_buf, hint);
-    if (access(path_buf, F_OK) < 0) {
-        fprintf(stderr, "adb: Couldn't find a product dir "
-                "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
-        return NULL;
+
+    std::string path = top;
+    path += OS_PATH_SEPARATOR_STR;
+    path += "out";
+    path += OS_PATH_SEPARATOR_STR;
+    path += "target";
+    path += OS_PATH_SEPARATOR_STR;
+    path += "product";
+    path += OS_PATH_SEPARATOR_STR;
+    path += hint;
+    if (!directory_exists(path)) {
+        fprintf(stderr, "adb: Couldn't find a product dir based on -p %s; "
+                        "\"%s\" doesn't exist\n", hint, path.c_str());
+        return "";
     }
-    return path_buf;
+    return path;
 }
 
 static void parse_push_pull_args(const char **arg, int narg, char const **path1,
@@ -1149,15 +984,14 @@
     const char* serial = NULL;
     const char* server_port_str = NULL;
 
-        /* If defined, this should be an absolute path to
-         * the directory containing all of the various system images
-         * for a particular product.  If not defined, and the adb
-         * command requires this information, then the user must
-         * specify the path using "-p".
-         */
-    gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
-    if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
-        gProductOutPath = NULL;
+    // If defined, this should be an absolute path to
+    // the directory containing all of the various system images
+    // for a particular product.  If not defined, and the adb
+    // command requires this information, then the user must
+    // specify the path using "-p".
+    char* ANDROID_PRODUCT_OUT = getenv("ANDROID_PRODUCT_OUT");
+    if (ANDROID_PRODUCT_OUT != nullptr) {
+        gProductOutPath = ANDROID_PRODUCT_OUT;
     }
     // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
 
@@ -1198,9 +1032,8 @@
                 product = argv[0] + 2;
             }
             gProductOutPath = find_product_out_path(product);
-            if (gProductOutPath == NULL) {
-                fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
-                        product);
+            if (gProductOutPath.empty()) {
+                fprintf(stderr, "adb: could not resolve \"-p %s\"\n", product);
                 return usage();
             }
         } else if (argv[0][0]=='-' && argv[0][1]=='s') {
@@ -1372,9 +1205,6 @@
         return adb_send_emulator_command(argc, argv);
     }
     else if (!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
-        int r;
-        int fd;
-
         char h = (argv[0][0] == 'h');
 
         if (h) {
@@ -1392,19 +1222,18 @@
             return r;
         }
 
-        snprintf(buf, sizeof(buf), "shell:%s", argv[1]);
+        std::string cmd = "shell:";
+        cmd += argv[1];
         argc -= 2;
         argv += 2;
         while (argc-- > 0) {
-            char *quoted = escape_arg(*argv++);
-            strncat(buf, " ", sizeof(buf) - 1);
-            strncat(buf, quoted, sizeof(buf) - 1);
-            free(quoted);
+            cmd += " " + escape_arg(*argv++);
         }
 
-        for(;;) {
-            D("interactive shell loop. buff=%s\n", buf);
-            fd = adb_connect(buf);
+        while (true) {
+            D("interactive shell loop. cmd=%s\n", cmd.c_str());
+            int fd = adb_connect(cmd.c_str());
+            int r;
             if (fd >= 0) {
                 D("about to read_and_dump(fd=%d)\n", fd);
                 read_and_dump(fd);
@@ -1432,19 +1261,16 @@
     }
     else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
         int exec_in = !strcmp(argv[0], "exec-in");
-        int fd;
 
-        snprintf(buf, sizeof buf, "exec:%s", argv[1]);
+        std::string cmd = "exec:";
+        cmd += argv[1];
         argc -= 2;
         argv += 2;
         while (argc-- > 0) {
-            char *quoted = escape_arg(*argv++);
-            strncat(buf, " ", sizeof(buf) - 1);
-            strncat(buf, quoted, sizeof(buf) - 1);
-            free(quoted);
+            cmd += " " + escape_arg(*argv++);
         }
 
-        fd = adb_connect(buf);
+        int fd = adb_connect(cmd.c_str());
         if (fd < 0) {
             fprintf(stderr, "error: %s\n", adb_error());
             return -1;
@@ -1636,46 +1462,49 @@
         return uninstall_app(ttype, serial, argc, argv);
     }
     else if (!strcmp(argv[0], "sync")) {
-        const char* srcarg;
-        char *system_srcpath, *data_srcpath, *vendor_srcpath, *oem_srcpath;
-
-        int listonly = 0;
-
-        int ret;
+        std::string src;
+        bool list_only = false;
         if (argc < 2) {
-            /* No local path was specified. */
-            srcarg = NULL;
+            // No local path was specified.
+            src = "";
         } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
-            listonly = 1;
+            list_only = true;
             if (argc == 3) {
-                srcarg = argv[2];
+                src = argv[2];
             } else {
-                srcarg = NULL;
+                src = "";
             }
         } else if (argc == 2) {
-            /* A local path or "android"/"data" arg was specified. */
-            srcarg = argv[1];
+            // A local path or "android"/"data" arg was specified.
+            src = argv[1];
         } else {
             return usage();
         }
-        ret = find_sync_dirs(srcarg, &system_srcpath, &data_srcpath, &vendor_srcpath,
-                &oem_srcpath);
-        if (ret != 0) return usage();
 
-        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);
+        if (src != "" &&
+            src != "system" && src != "data" && src != "vendor" && src != "oem") {
+            return usage();
+        }
 
-        free(system_srcpath);
-        free(vendor_srcpath);
-        free(oem_srcpath);
-        free(data_srcpath);
-        return ret;
+        std::string system_src_path = product_file("system");
+        std::string data_src_path = product_file("data");
+        std::string vendor_src_path = product_file("vendor");
+        std::string oem_src_path = product_file("oem");
+
+        int rc = 0;
+        if (rc == 0 && (src.empty() || src == "system")) {
+            rc = do_sync_sync(system_src_path, "/system", list_only);
+        }
+        if (rc == 0 && (src.empty() || src == "vendor") && directory_exists(vendor_src_path)) {
+            rc = do_sync_sync(vendor_src_path, "/vendor", list_only);
+        }
+        if (rc == 0 && (src.empty() || src == "oem") && directory_exists(oem_src_path)) {
+            rc = do_sync_sync(oem_src_path, "/oem", list_only);
+        }
+        if (rc == 0 && (src.empty() || src == "data")) {
+            rc = do_sync_sync(data_src_path, "/data", list_only);
+        }
+        return rc;
     }
     /* passthrough commands */
     else if (!strcmp(argv[0],"get-state") ||
@@ -1770,84 +1599,20 @@
     return adb_commandline(argc, argv);
 }
 
-int find_sync_dirs(const char *srcarg,
-        char **system_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out,
-        char **oem_srcdir_out)
-{
-    char *system_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL, *oem_srcdir = NULL;
-    struct stat st;
-
-    if(srcarg == NULL) {
-        system_srcdir = product_file("system");
-        data_srcdir = product_file("data");
-        vendor_srcdir = product_file("vendor");
-        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", "vendor", "oem" or NULL.
-        // If srcarg is NULL, then all partitions are synced.
-        if(strcmp(srcarg, "system") == 0) {
-            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", "data", "vendor", or "oem".
-            return 1;
-        }
-    }
-
-    if(system_srcdir_out != NULL)
-        *system_srcdir_out = system_srcdir;
-    else
-        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);
-
-    return 0;
-}
-
 static int pm_command(transport_type transport, const char* serial,
                       int argc, const char** argv)
 {
-    char buf[4096];
+    std::string cmd = "shell:pm";
 
-    snprintf(buf, sizeof(buf), "shell:pm");
-
-    while(argc-- > 0) {
-        char *quoted = escape_arg(*argv++);
-        strncat(buf, " ", sizeof(buf) - 1);
-        strncat(buf, quoted, sizeof(buf) - 1);
-        free(quoted);
+    while (argc-- > 0) {
+        cmd += " " + escape_arg(*argv++);
     }
 
-    send_shellcommand(transport, serial, buf);
-    return 0;
+    return send_shell_command(transport, serial, cmd);
 }
 
-int uninstall_app(transport_type transport, const char* serial, int argc,
-                  const char** argv)
+static int uninstall_app(transport_type transport, const char* serial, int argc,
+                         const char** argv)
 {
     /* if the user choose the -k option, we refuse to do it until devices are
        out with the option to uninstall the remaining data somehow (adb/ui) */
@@ -1867,16 +1632,8 @@
 
 static int delete_file(transport_type transport, const char* serial, char* filename)
 {
-    char buf[4096];
-    char* quoted;
-
-    snprintf(buf, sizeof(buf), "shell:rm -f ");
-    quoted = escape_arg(filename);
-    strncat(buf, quoted, sizeof(buf)-1);
-    free(quoted);
-
-    send_shellcommand(transport, serial, buf);
-    return 0;
+    std::string cmd = "shell:rm -f " + escape_arg(filename);
+    return send_shell_command(transport, serial, cmd);
 }
 
 static const char* get_basename(const char* filename)
@@ -1890,8 +1647,8 @@
     }
 }
 
-int install_app(transport_type transport, const char* serial, int argc,
-                const char** argv)
+static int install_app(transport_type transport, const char* serial, int argc,
+                       const char** argv)
 {
     static const char *const DATA_DEST = "/data/local/tmp/%s";
     static const char *const SD_DEST = "/sdcard/tmp/%s";
@@ -1937,20 +1694,19 @@
         argv[last_apk] = apk_dest; /* destination name, not source location */
     }
 
-    pm_command(transport, serial, argc, argv);
+    err = pm_command(transport, serial, argc, argv);
 
 cleanup_apk:
     delete_file(transport, serial, apk_dest);
     return err;
 }
 
-int install_multiple_app(transport_type transport, const char* serial, int argc,
-                         const char** argv)
+static int install_multiple_app(transport_type transport, const char* serial, int argc,
+                                const char** argv)
 {
-    char buf[1024];
     int i;
     struct stat sb;
-    unsigned long long total_size = 0;
+    uint64_t total_size = 0;
 
     // Find all APK arguments starting at end.
     // All other arguments passed through verbatim.
@@ -1976,20 +1732,22 @@
         return 1;
     }
 
-    snprintf(buf, sizeof(buf), "exec:pm install-create -S %lld", total_size);
+#if defined(_WIN32) // Remove when we're using clang for Win32.
+    std::string cmd = android::base::StringPrintf("exec:pm install-create -S %u", (unsigned) total_size);
+#else
+    std::string cmd = android::base::StringPrintf("exec:pm install-create -S %" PRIu64, total_size);
+#endif
     for (i = 1; i < first_apk; i++) {
-        char *quoted = escape_arg(argv[i]);
-        strncat(buf, " ", sizeof(buf) - 1);
-        strncat(buf, quoted, sizeof(buf) - 1);
-        free(quoted);
+        cmd += " " + escape_arg(argv[i]);
     }
 
     // Create install session
-    int fd = adb_connect(buf);
+    int fd = adb_connect(cmd.c_str());
     if (fd < 0) {
         fprintf(stderr, "Connect error for create: %s\n", adb_error());
         return -1;
     }
+    char buf[BUFSIZ];
     read_status_line(fd, buf, sizeof(buf));
     adb_close(fd);
 
@@ -2018,8 +1776,15 @@
             goto finalize_session;
         }
 
-        snprintf(buf, sizeof(buf), "exec:pm install-write -S %lld %d %d_%s -",
-                (long long int) sb.st_size, session_id, i, get_basename(file));
+#if defined(_WIN32) // Remove when we're using clang for Win32.
+        std::string cmd = android::base::StringPrintf(
+                "exec:pm install-write -S %u %d %d_%s -",
+                (unsigned) sb.st_size, session_id, i, get_basename(file));
+#else
+        std::string cmd = android::base::StringPrintf(
+                "exec:pm install-write -S %" PRIu64 " %d %d_%s -",
+                static_cast<uint64_t>(sb.st_size), session_id, i, get_basename(file));
+#endif
 
         int localFd = adb_open(file, O_RDONLY);
         if (localFd < 0) {
@@ -2028,7 +1793,7 @@
             goto finalize_session;
         }
 
-        int remoteFd = adb_connect(buf);
+        int remoteFd = adb_connect(cmd.c_str());
         if (remoteFd < 0) {
             fprintf(stderr, "Connect error for write: %s\n", adb_error());
             adb_close(localFd);
diff --git a/adb/fdevent.h b/adb/fdevent.h
index a8102ca..8d84b29 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -19,10 +19,6 @@
 
 #include <stdint.h>  /* for int64_t */
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* events that may be observed */
 #define FDE_READ              0x0001
 #define FDE_WRITE             0x0002
@@ -32,7 +28,7 @@
 /* features that may be set (via the events set/add/del interface) */
 #define FDE_DONT_CLOSE        0x0080
 
-typedef struct fdevent fdevent;
+struct fdevent;
 
 typedef void (*fd_func)(int fd, unsigned events, void *userdata);
 
@@ -82,8 +78,4 @@
     void *arg;
 };
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 4ba730b..49d8783 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -130,8 +130,6 @@
     return -1;
 }
 
-typedef struct syncsendbuf syncsendbuf;
-
 struct syncsendbuf {
     unsigned id;
     unsigned size;
@@ -557,8 +555,6 @@
     }
 }
 
-typedef struct copyinfo copyinfo;
-
 struct copyinfo
 {
     copyinfo *next;
@@ -804,12 +800,12 @@
 }
 
 
-typedef struct {
+struct sync_ls_build_list_cb_args {
     copyinfo **filelist;
     copyinfo **dirlist;
     const char *rpath;
     const char *lpath;
-} sync_ls_build_list_cb_args;
+};
 
 void
 sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
@@ -1031,18 +1027,18 @@
     }
 }
 
-int do_sync_sync(const char *lpath, const char *rpath, int listonly)
+int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only)
 {
-    fprintf(stderr,"syncing %s...\n",rpath);
+    fprintf(stderr, "syncing %s...\n", rpath.c_str());
 
     int fd = adb_connect("sync:");
-    if(fd < 0) {
-        fprintf(stderr,"error: %s\n", adb_error());
+    if (fd < 0) {
+        fprintf(stderr, "error: %s\n", adb_error());
         return 1;
     }
 
     BEGIN();
-    if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
+    if (copy_local_dir_remote(fd, lpath.c_str(), rpath.c_str(), 1, list_only)) {
         return 1;
     } else {
         END();
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 5b69a63..344eb98 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -17,9 +17,7 @@
 #ifndef _FILE_SYNC_SERVICE_H_
 #define _FILE_SYNC_SERVICE_H_
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include <string>
 
 #define htoll(x) (x)
 #define ltohl(x) (x)
@@ -38,7 +36,7 @@
 #define ID_FAIL MKID('F','A','I','L')
 #define ID_QUIT MKID('Q','U','I','T')
 
-typedef union {
+union syncmsg {
     unsigned id;
     struct {
         unsigned id;
@@ -65,19 +63,15 @@
         unsigned id;
         unsigned msglen;
     } status;
-} syncmsg;
+} ;
 
 
 void file_sync_service(int fd, void *cookie);
 int do_sync_ls(const char *path);
 int do_sync_push(const char *lpath, const char *rpath, int show_progress);
-int do_sync_sync(const char *lpath, const char *rpath, int listonly);
+int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only);
 int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime);
 
 #define SYNC_DATA_MAX (64*1024)
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/adb/get_my_path_darwin.c b/adb/get_my_path_darwin.cpp
similarity index 100%
rename from adb/get_my_path_darwin.c
rename to adb/get_my_path_darwin.cpp
diff --git a/adb/jdwp_service.cpp b/adb/jdwp_service.cpp
index 9cf084e..c0f7ec2 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/jdwp_service.cpp
@@ -121,7 +121,6 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
-typedef struct JdwpProcess  JdwpProcess;
 struct JdwpProcess {
     JdwpProcess*  next;
     JdwpProcess*  prev;
@@ -455,11 +454,10 @@
 #define  JDWP_CONTROL_NAME      "\0jdwp-control"
 #define  JDWP_CONTROL_NAME_LEN  (sizeof(JDWP_CONTROL_NAME)-1)
 
-typedef struct {
+struct JdwpControl {
     int       listen_socket;
     fdevent*  fde;
-
-} JdwpControl;
+};
 
 
 static void
@@ -570,10 +568,10 @@
  ** this simply returns the list of known JDWP process pids
  **/
 
-typedef struct {
+struct JdwpSocket {
     asocket  socket;
     int      pass;
-} JdwpSocket;
+};
 
 static void
 jdwp_socket_close( asocket*  s )
@@ -642,8 +640,6 @@
  ** to the client...
  **/
 
-typedef struct JdwpTracker  JdwpTracker;
-
 struct JdwpTracker {
     asocket       socket;
     JdwpTracker*  next;
@@ -754,4 +750,3 @@
 }
 
 #endif /* !ADB_HOST */
-
diff --git a/adb/qemu_tracing.h b/adb/qemu_tracing.h
index bf80457..ff42d4f 100644
--- a/adb/qemu_tracing.h
+++ b/adb/qemu_tracing.h
@@ -21,16 +21,8 @@
 #ifndef __QEMU_TRACING_H
 #define __QEMU_TRACING_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Initializes connection with the adb-debug qemud service in the emulator. */
 int adb_qemu_trace_init(void);
 void adb_qemu_trace(const char* fmt, ...);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* __QEMU_TRACING_H */
diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp
index b150274..1eaee73 100644
--- a/adb/remount_service.cpp
+++ b/adb/remount_service.cpp
@@ -31,6 +31,7 @@
 
 #include "adb.h"
 #include "adb_io.h"
+#include "adb_utils.h"
 #include "cutils/properties.h"
 
 static int system_ro = 1;
@@ -56,11 +57,6 @@
     return device;
 }
 
-static bool has_partition(const char* path) {
-    struct stat sb;
-    return (lstat(path, &sb) == 0 && S_ISDIR(sb.st_mode));
-}
-
 int make_block_device_writable(const std::string& dev) {
     int fd = unix_open(dev.c_str(), O_RDONLY | O_CLOEXEC);
     if (fd == -1) {
@@ -90,7 +86,7 @@
 }
 
 static bool remount_partition(int fd, const char* partition, int* ro) {
-  if (!has_partition(partition)) {
+  if (!directory_exists(partition)) {
     return true;
   }
   if (remount(partition, ro)) {
diff --git a/adb/services.cpp b/adb/services.cpp
index 12eb406..e6c84a4 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -31,6 +31,8 @@
 #include <unistd.h>
 #endif
 
+#include <base/stringprintf.h>
+
 #if !ADB_HOST
 #include "base/file.h"
 #include "cutils/android_reboot.h"
@@ -43,8 +45,6 @@
 #include "remount_service.h"
 #include "transport.h"
 
-typedef struct stinfo stinfo;
-
 struct stinfo {
     void (*func)(int fd, void *cookie);
     int fd;
@@ -194,7 +194,7 @@
     if (reboot_service_impl(fd, static_cast<const char*>(arg))) {
         // Don't return early. Give the reboot command time to take effect
         // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
-        while (1) {
+        while (true) {
             pause();
         }
     }
@@ -375,7 +375,7 @@
     pid_t pid = (pid_t) (uintptr_t) cookie;
 
     D("entered. fd=%d of pid=%d\n", fd, pid);
-    for (;;) {
+    while (true) {
         int status;
         pid_t p = waitpid(pid, &status, 0);
         if (p == pid) {
@@ -501,19 +501,8 @@
     } else if(!strncmp(name, "unroot:", 7)) {
         ret = create_service_thread(restart_unroot_service, NULL);
     } else if(!strncmp(name, "backup:", 7)) {
-        char* arg = strdup(name + 7);
-        if (arg == NULL) return -1;
-        char* c = arg;
-        for (; *c != '\0'; c++) {
-            if (*c == ':')
-                *c = ' ';
-        }
-        char* cmd;
-        if (asprintf(&cmd, "/system/bin/bu backup %s", arg) != -1) {
-            ret = create_subproc_thread(cmd, SUBPROC_RAW);
-            free(cmd);
-        }
-        free(arg);
+        ret = create_subproc_thread(android::base::StringPrintf("/system/bin/bu backup %s",
+                                                                (name + 7)).c_str(), SUBPROC_RAW);
     } else if(!strncmp(name, "restore:", 8)) {
         ret = create_subproc_thread("/system/bin/bu restore", SUBPROC_RAW);
     } else if(!strncmp(name, "tcpip:", 6)) {
@@ -559,12 +548,12 @@
 
     D("wait_for_state %d\n", sinfo->state);
 
-    const char* err = "unknown error";
-    atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
-    if(t != 0) {
+    std::string error_msg = "unknown error";
+    atransport* t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &error_msg);
+    if (t != 0) {
         WriteFdExactly(fd, "OKAY", 4);
     } else {
-        sendfailmsg(fd, err);
+        sendfailmsg(fd, error_msg.c_str());
     }
 
     if (sinfo->serial)
@@ -700,6 +689,10 @@
         return create_device_tracker();
     } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
         auto sinfo = reinterpret_cast<state_info*>(malloc(sizeof(state_info)));
+        if (sinfo == nullptr) {
+            fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno));
+            return NULL;
+        }
 
         if (serial)
             sinfo->serial = strdup(serial);
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 48d02d6..f468029 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -487,10 +487,10 @@
 /* a Remote socket is used to send/receive data to/from a given transport object
 ** it needs to be closed when the transport is forcibly destroyed by the user
 */
-typedef struct aremotesocket {
+struct aremotesocket {
     asocket      socket;
     adisconnect  disconnect;
-} aremotesocket;
+};
 
 static int remote_socket_enqueue(asocket *s, apacket *p)
 {
@@ -827,12 +827,11 @@
     }
 #else /* !ADB_HOST */
     if (s->transport == NULL) {
-        const char* error_string = "unknown failure";
-        s->transport = acquire_one_transport (CS_ANY,
-                kTransportAny, NULL, &error_string);
+        std::string error_msg = "unknown failure";
+        s->transport = acquire_one_transport(CS_ANY, kTransportAny, NULL, &error_msg);
 
         if (s->transport == NULL) {
-            sendfailmsg(s->peer->fd, error_string);
+            sendfailmsg(s->peer->fd, error_msg.c_str());
             goto fail;
         }
     }
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 2ad28fa..59e5b0b 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -54,10 +54,6 @@
 
 #include "fdevent.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #define OS_PATH_SEPARATOR '\\'
 #define OS_PATH_SEPARATOR_STR "\\"
 #define ENV_PATH_SEPARATOR_STR ";"
@@ -275,8 +271,6 @@
     return isalpha(path[0]) && path[1] == ':' && path[2] == '\\';
 }
 
-extern char*  adb_strtok_r(char *str, const char *delim, char **saveptr);
-
 #else /* !_WIN32 a.k.a. Unix */
 
 #include "fdevent.h"
@@ -296,10 +290,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #define OS_PATH_SEPARATOR '/'
 #define OS_PATH_SEPARATOR_STR "/"
 #define ENV_PATH_SEPARATOR_STR ":"
@@ -525,23 +515,11 @@
     return path[0] == '/';
 }
 
-static __inline__ char*  adb_strtok_r(char *str, const char *delim, char **saveptr)
-{
-    return strtok_r(str, delim, saveptr);
-}
-
 static __inline__ unsigned long adb_thread_id()
 {
     return (unsigned long)pthread_self();
 }
 
-#undef   strtok_r
-#define  strtok_r  ___xxx_strtok_r
-
 #endif /* !_WIN32 */
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* _ADB_SYSDEPS_H */
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.cpp
similarity index 94%
rename from adb/sysdeps_win32.c
rename to adb/sysdeps_win32.cpp
index c2742f1..633f6f5 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.cpp
@@ -30,6 +30,53 @@
 
 extern void fatal(const char *fmt, ...);
 
+/* forward declarations */
+
+typedef const struct FHClassRec_* FHClass;
+typedef struct FHRec_* FH;
+typedef struct EventHookRec_* EventHook;
+
+typedef struct FHClassRec_ {
+    void (*_fh_init)(FH);
+    int (*_fh_close)(FH);
+    int (*_fh_lseek)(FH, int, int);
+    int (*_fh_read)(FH, void*, int);
+    int (*_fh_write)(FH, const void*, int);
+    void (*_fh_hook)(FH, int, EventHook);
+} FHClassRec;
+
+static void _fh_file_init(FH);
+static int _fh_file_close(FH);
+static int _fh_file_lseek(FH, int, int);
+static int _fh_file_read(FH, void*, int);
+static int _fh_file_write(FH, const void*, int);
+static void _fh_file_hook(FH, int, EventHook);
+
+static const FHClassRec _fh_file_class = {
+    _fh_file_init,
+    _fh_file_close,
+    _fh_file_lseek,
+    _fh_file_read,
+    _fh_file_write,
+    _fh_file_hook
+};
+
+static void _fh_socket_init(FH);
+static int _fh_socket_close(FH);
+static int _fh_socket_lseek(FH, int, int);
+static int _fh_socket_read(FH, void*, int);
+static int _fh_socket_write(FH, const void*, int);
+static void _fh_socket_hook(FH, int, EventHook);
+
+static const FHClassRec _fh_socket_class = {
+    _fh_socket_init,
+    _fh_socket_close,
+    _fh_socket_lseek,
+    _fh_socket_read,
+    _fh_socket_write,
+    _fh_socket_hook
+};
+
 #define assert(cond)  do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0)
 
 /**************************************************************************/
@@ -92,23 +139,6 @@
 /**************************************************************************/
 /**************************************************************************/
 
-typedef const struct FHClassRec_*   FHClass;
-
-typedef struct FHRec_*          FH;
-
-typedef struct EventHookRec_*  EventHook;
-
-typedef struct FHClassRec_
-{
-    void (*_fh_init) ( FH  f );
-    int  (*_fh_close)( FH  f );
-    int  (*_fh_lseek)( FH  f, int  pos, int  origin );
-    int  (*_fh_read) ( FH  f, void*  buf, int  len );
-    int  (*_fh_write)( FH  f, const void*  buf, int  len );
-    void (*_fh_hook) ( FH  f, int  events, EventHook  hook );
-
-} FHClassRec;
-
 /* used to emulate unix-domain socket pairs */
 typedef struct SocketPairRec_*  SocketPair;
 
@@ -220,10 +250,6 @@
     return 0;
 }
 
-/* forward definitions */
-static const FHClassRec   _fh_file_class;
-static const FHClassRec   _fh_socket_class;
-
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
@@ -232,23 +258,17 @@
 /**************************************************************************/
 /**************************************************************************/
 
-static void
-_fh_file_init( FH  f )
-{
+static void _fh_file_init( FH  f ) {
     f->fh_handle = INVALID_HANDLE_VALUE;
 }
 
-static int
-_fh_file_close( FH  f )
-{
+static int _fh_file_close( FH  f ) {
     CloseHandle( f->fh_handle );
     f->fh_handle = INVALID_HANDLE_VALUE;
     return 0;
 }
 
-static int
-_fh_file_read( FH  f,  void*  buf, int   len )
-{
+static int _fh_file_read( FH  f,  void*  buf, int   len ) {
     DWORD  read_bytes;
 
     if ( !ReadFile( f->fh_handle, buf, (DWORD)len, &read_bytes, NULL ) ) {
@@ -261,9 +281,7 @@
     return (int)read_bytes;
 }
 
-static int
-_fh_file_write( FH  f,  const void*  buf, int   len )
-{
+static int _fh_file_write( FH  f,  const void*  buf, int   len ) {
     DWORD  wrote_bytes;
 
     if ( !WriteFile( f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL ) ) {
@@ -276,9 +294,7 @@
     return  (int)wrote_bytes;
 }
 
-static int
-_fh_file_lseek( FH  f, int  pos, int  origin )
-{
+static int _fh_file_lseek( FH  f, int  pos, int  origin ) {
     DWORD  method;
     DWORD  result;
 
@@ -302,17 +318,6 @@
     return (int)result;
 }
 
-static void  _fh_file_hook( FH  f, int  event, EventHook  eventhook );  /* forward */
-
-static const FHClassRec  _fh_file_class =
-{
-    _fh_file_init,
-    _fh_file_close,
-    _fh_file_lseek,
-    _fh_file_read,
-    _fh_file_write,
-    _fh_file_hook
-};
 
 /**************************************************************************/
 /**************************************************************************/
@@ -495,9 +500,7 @@
 
 #undef setsockopt
 
-static void
-_socket_set_errno( void )
-{
+static void _socket_set_errno( void ) {
     switch (WSAGetLastError()) {
     case 0:              errno = 0; break;
     case WSAEWOULDBLOCK: errno = EAGAIN; break;
@@ -508,17 +511,13 @@
     }
 }
 
-static void
-_fh_socket_init( FH  f )
-{
+static void _fh_socket_init( FH  f ) {
     f->fh_socket = INVALID_SOCKET;
     f->event     = WSACreateEvent();
     f->mask      = 0;
 }
 
-static int
-_fh_socket_close( FH  f )
-{
+static int _fh_socket_close( FH  f ) {
     /* gently tell any peer that we're closing the socket */
     shutdown( f->fh_socket, SD_BOTH );
     closesocket( f->fh_socket );
@@ -528,17 +527,13 @@
     return 0;
 }
 
-static int
-_fh_socket_lseek( FH  f, int pos, int origin )
-{
+static int _fh_socket_lseek( FH  f, int pos, int origin ) {
     errno = EPIPE;
     return -1;
 }
 
-static int
-_fh_socket_read( FH  f, void*  buf, int  len )
-{
-    int  result = recv( f->fh_socket, buf, len, 0 );
+static int _fh_socket_read(FH f, void* buf, int len) {
+    int  result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0);
     if (result == SOCKET_ERROR) {
         _socket_set_errno();
         result = -1;
@@ -546,10 +541,8 @@
     return  result;
 }
 
-static int
-_fh_socket_write( FH  f, const void*  buf, int  len )
-{
-    int  result = send( f->fh_socket, buf, len, 0 );
+static int _fh_socket_write(FH f, const void* buf, int len) {
+    int  result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0);
     if (result == SOCKET_ERROR) {
         _socket_set_errno();
         result = -1;
@@ -557,18 +550,6 @@
     return result;
 }
 
-static void  _fh_socket_hook( FH  f, int  event, EventHook  hook );  /* forward */
-
-static const FHClassRec  _fh_socket_class =
-{
-    _fh_socket_init,
-    _fh_socket_close,
-    _fh_socket_lseek,
-    _fh_socket_read,
-    _fh_socket_write,
-    _fh_socket_hook
-};
-
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
@@ -819,7 +800,7 @@
         return -1;
     }
 
-    return setsockopt( fh->fh_socket, level, optname, optval, optlen );
+    return setsockopt( fh->fh_socket, level, optname, reinterpret_cast<const char*>(optval), optlen );
 }
 
 /**************************************************************************/
@@ -1219,18 +1200,16 @@
 };
 
 
-int  adb_socketpair( int  sv[2] )
-{
-    FH          fa, fb;
-    SocketPair  pair;
+int  adb_socketpair(int sv[2]) {
+    SocketPair pair;
 
-    fa = _fh_alloc( &_fh_socketpair_class );
-    fb = _fh_alloc( &_fh_socketpair_class );
+    FH fa = _fh_alloc(&_fh_socketpair_class);
+    FH fb = _fh_alloc(&_fh_socketpair_class);
 
     if (!fa || !fb)
         goto Fail;
 
-    pair = malloc( sizeof(*pair) );
+    pair = reinterpret_cast<SocketPair>(malloc(sizeof(*pair)));
     if (pair == NULL) {
         D("adb_socketpair: not enough memory to allocate pipes\n" );
         goto Fail;
@@ -1328,13 +1307,12 @@
 static EventHook  _free_hooks;
 
 static EventHook
-event_hook_alloc( FH  fh )
-{
-    EventHook  hook = _free_hooks;
-    if (hook != NULL)
+event_hook_alloc(FH fh) {
+    EventHook hook = _free_hooks;
+    if (hook != NULL) {
         _free_hooks = hook->next;
-    else {
-        hook = malloc( sizeof(*hook) );
+    } else {
+        hook = reinterpret_cast<EventHook>(malloc(sizeof(*hook)));
         if (hook == NULL)
             fatal( "could not allocate event hook\n" );
     }
@@ -1796,7 +1774,7 @@
         while(fd_table_max <= fd) {
             fd_table_max *= 2;
         }
-        fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
+        fd_table = reinterpret_cast<fdevent**>(realloc(fd_table, sizeof(fdevent*) * fd_table_max));
         if(fd_table == 0) {
             FATAL("could not expand fd_table to %d entries\n", fd_table_max);
         }
@@ -2173,85 +2151,6 @@
     InitializeCriticalSection( &_win32_lock );
 }
 
-/* Windows doesn't have strtok_r.  Use the one from bionic. */
-
-/*
- * Copyright (c) 1988 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- */
-
-char *
-adb_strtok_r(char *s, const char *delim, char **last)
-{
-	char *spanp;
-	int c, sc;
-	char *tok;
-
-
-	if (s == NULL && (s = *last) == NULL)
-		return (NULL);
-
-	/*
-	 * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
-	 */
-cont:
-	c = *s++;
-	for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
-		if (c == sc)
-			goto cont;
-	}
-
-	if (c == 0) {		/* no non-delimiter characters */
-		*last = NULL;
-		return (NULL);
-	}
-	tok = s - 1;
-
-	/*
-	 * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
-	 * Note that delim must have one NUL; we stop if we see that, too.
-	 */
-	for (;;) {
-		c = *s++;
-		spanp = (char *)delim;
-		do {
-			if ((sc = *spanp++) == c) {
-				if (c == 0)
-					s = NULL;
-				else
-					s[-1] = 0;
-				*last = s;
-				return (tok);
-			}
-		} while (sc != 0);
-	}
-	/* NOTREACHED */
-}
-
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
diff --git a/adb/tests/test_adb.py b/adb/tests/test_adb.py
index f111b043..52d8056 100755
--- a/adb/tests/test_adb.py
+++ b/adb/tests/test_adb.py
@@ -267,6 +267,18 @@
                 adb.unroot()
             adb.wait()
 
+    def test_argument_escaping(self):
+        """Make sure that argument escaping is somewhat sane."""
+        adb = AdbWrapper()
+
+        # http://b/19734868
+        result = adb.shell("sh -c 'echo hello; echo world'").splitlines()
+        self.assertEqual(["hello", "world"], result)
+
+        # http://b/15479704
+        self.assertEqual('t', adb.shell("'true && echo t'").strip())
+        self.assertEqual('t', adb.shell("sh -c 'true && echo t'").strip())
+
 
 class AdbFile(unittest.TestCase):
     SCRATCH_DIR = "/data/local/tmp"
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 4b9eeeb..d395a80 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -406,7 +406,6 @@
  * number of client connections that want it through a single
  * live TCP connection
  */
-typedef struct device_tracker  device_tracker;
 struct device_tracker {
     asocket          socket;
     int              update_needed;
@@ -494,10 +493,8 @@
 asocket*
 create_device_tracker(void)
 {
-    device_tracker* tracker = reinterpret_cast<device_tracker*>(
-        calloc(1, sizeof(*tracker)));
-
-    if(tracker == 0) fatal("cannot allocate device tracker");
+    device_tracker* tracker = reinterpret_cast<device_tracker*>(calloc(1, sizeof(*tracker)));
+    if (tracker == nullptr) fatal("cannot allocate device tracker");
 
     D( "device tracker %p created\n", tracker);
 
@@ -536,7 +533,6 @@
 }
 #endif // ADB_HOST
 
-typedef struct tmsg tmsg;
 struct tmsg
 {
     atransport *transport;
@@ -800,22 +796,20 @@
     return !*to_test;
 }
 
-atransport *acquire_one_transport(int state, transport_type ttype,
-                                  const char* serial, const char** error_out)
+atransport* acquire_one_transport(int state, transport_type ttype,
+                                  const char* serial, std::string* error_out)
 {
     atransport *t;
     atransport *result = NULL;
     int ambiguous = 0;
 
 retry:
-    if (error_out)
-        *error_out = "device not found";
+    if (error_out) *error_out = "device not found";
 
     adb_mutex_lock(&transport_lock);
     for (t = transport_list.next; t != &transport_list; t = t->next) {
         if (t->connection_state == CS_NOPERM) {
-        if (error_out)
-            *error_out = "insufficient permissions for device";
+            if (error_out) *error_out = "insufficient permissions for device";
             continue;
         }
 
@@ -827,8 +821,7 @@
                 qual_match(serial, "model:", t->model, true) ||
                 qual_match(serial, "device:", t->device, false)) {
                 if (result) {
-                    if (error_out)
-                        *error_out = "more than one device";
+                    if (error_out) *error_out = "more than one device";
                     ambiguous = 1;
                     result = NULL;
                     break;
@@ -838,8 +831,7 @@
         } else {
             if (ttype == kTransportUsb && t->type == kTransportUsb) {
                 if (result) {
-                    if (error_out)
-                        *error_out = "more than one device";
+                    if (error_out) *error_out = "more than one device";
                     ambiguous = 1;
                     result = NULL;
                     break;
@@ -847,8 +839,7 @@
                 result = t;
             } else if (ttype == kTransportLocal && t->type == kTransportLocal) {
                 if (result) {
-                    if (error_out)
-                        *error_out = "more than one emulator";
+                    if (error_out) *error_out = "more than one emulator";
                     ambiguous = 1;
                     result = NULL;
                     break;
@@ -856,8 +847,7 @@
                 result = t;
             } else if (ttype == kTransportAny) {
                 if (result) {
-                    if (error_out)
-                        *error_out = "more than one device and emulator";
+                    if (error_out) *error_out = "more than one device and emulator";
                     ambiguous = 1;
                     result = NULL;
                     break;
@@ -870,29 +860,33 @@
 
     if (result) {
         if (result->connection_state == CS_UNAUTHORIZED) {
-            if (error_out)
-                *error_out = "device unauthorized. Please check the confirmation dialog on your device.";
+            if (error_out) {
+                *error_out = "device unauthorized.\n";
+                char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
+                *error_out += "This adbd's $ADB_VENDOR_KEYS is ";
+                *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
+                *error_out += "; try 'adb kill-server' if that seems wrong.\n";
+                *error_out += "Otherwise check for a confirmation dialog on your device.";
+            }
             result = NULL;
         }
 
-         /* offline devices are ignored -- they are either being born or dying */
+        /* offline devices are ignored -- they are either being born or dying */
         if (result && result->connection_state == CS_OFFLINE) {
-            if (error_out)
-                *error_out = "device offline";
+            if (error_out) *error_out = "device offline";
             result = NULL;
         }
-         /* check for required connection state */
+
+        /* check for required connection state */
         if (result && state != CS_ANY && result->connection_state != state) {
-            if (error_out)
-                *error_out = "invalid device state";
+            if (error_out) *error_out = "invalid device state";
             result = NULL;
         }
     }
 
     if (result) {
         /* found one that we can take */
-        if (error_out)
-            *error_out = NULL;
+        if (error_out) *error_out = "success";
     } else if (state != CS_ANY && (serial || !ambiguous)) {
         adb_sleep_ms(1000);
         goto retry;
@@ -1006,8 +1000,11 @@
 
 int register_socket_transport(int s, const char *serial, int port, int local)
 {
-    atransport *t = reinterpret_cast<atransport*>(
-        calloc(1, sizeof(atransport)));
+    atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport)));
+    if (t == nullptr) {
+        return -1;
+    }
+
     atransport *n;
     char buff[32];
 
@@ -1106,8 +1103,8 @@
 
 void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable)
 {
-    atransport *t = reinterpret_cast<atransport*>(
-        calloc(1, sizeof(atransport)));
+    atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport)));
+    if (t == nullptr) fatal("cannot allocate USB atransport");
     D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
       serial ? serial : "");
     init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
diff --git a/adb/transport.h b/adb/transport.h
index 36a0e40..a2077e8 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -17,14 +17,11 @@
 #ifndef __TRANSPORT_H
 #define __TRANSPORT_H
 
-#include <stdbool.h>
 #include <sys/types.h>
 
-#include "adb.h"
+#include <string>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "adb.h"
 
 #if ADB_TRACE
 void dump_hex(const unsigned char* ptr, size_t  len);
@@ -37,7 +34,7 @@
  * If no suitable transport is found, error is set.
  */
 atransport* acquire_one_transport(int state, transport_type ttype,
-                                  const char* serial, const char** error_out);
+                                  const char* serial, std::string* error_out);
 void add_transport_disconnect(atransport* t, adisconnect* dis);
 void remove_transport_disconnect(atransport* t, adisconnect* dis);
 void kick_transport(atransport* t);
@@ -74,8 +71,4 @@
 
 asocket* create_device_tracker(void);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif   /* __TRANSPORT_H */
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index fe3c87f..30e6bf5 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -144,7 +144,7 @@
         if(serverfd == -1) {
             serverfd = socket_inaddr_any_server(port, SOCK_STREAM);
             if(serverfd < 0) {
-                D("server: cannot bind socket yet\n");
+                D("server: cannot bind socket yet: %s\n", strerror(errno));
                 adb_sleep_ms(1000);
                 continue;
             }
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index 6fd2b40..999eb11 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -31,11 +31,11 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
 #include <linux/usb/ch9.h>
-#else
-#include <linux/usb_ch9.h>
-#endif
+
+#include <base/file.h>
+#include <base/stringprintf.h>
+#include <base/strings.h>
 
 #include "adb.h"
 #include "transport.h"
@@ -114,10 +114,6 @@
 
 }
 
-static void register_device(const char *dev_name, const char *devpath,
-                            unsigned char ep_in, unsigned char ep_out,
-                            int ifc, int serial_index, unsigned zero_mask);
-
 static inline int badname(const char *name)
 {
     while(*name) {
@@ -571,13 +567,10 @@
     return 0;
 }
 
-static void register_device(const char *dev_name, const char *devpath,
+static void register_device(const char* dev_name, const char* dev_path,
                             unsigned char ep_in, unsigned char ep_out,
                             int interface, int serial_index, unsigned zero_mask)
 {
-    int n = 0;
-    char serial[256];
-
         /* Since Linux will not reassign the device ID (and dev_name)
         ** as long as the device is open, we can add to the list here
         ** once we open it and remove from the list when we're finally
@@ -587,8 +580,7 @@
         ** name, we have no further work to do.
         */
     adb_mutex_lock(&usb_lock);
-    for (usb_handle* usb = handle_list.next; usb != &handle_list;
-         usb = usb->next) {
+    for (usb_handle* usb = handle_list.next; usb != &handle_list; usb = usb->next) {
         if (!strcmp(usb->fname, dev_name)) {
             adb_mutex_unlock(&usb_lock);
             return;
@@ -596,10 +588,9 @@
     }
     adb_mutex_unlock(&usb_lock);
 
-    D("[ usb located new device %s (%d/%d/%d) ]\n",
-        dev_name, ep_in, ep_out, interface);
-    usb_handle* usb = reinterpret_cast<usb_handle*>(
-        calloc(1, sizeof(usb_handle)));
+    D("[ usb located new device %s (%d/%d/%d) ]\n", dev_name, ep_in, ep_out, interface);
+    usb_handle* usb = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+    if (usb == nullptr) fatal("couldn't allocate usb_handle");
     strcpy(usb->fname, dev_name);
     usb->ep_in = ep_in;
     usb->ep_out = ep_out;
@@ -613,69 +604,40 @@
     usb->reaper_thread = 0;
 
     usb->desc = unix_open(usb->fname, O_RDWR | O_CLOEXEC);
-    if(usb->desc < 0) {
-        /* if we fail, see if have read-only access */
+    if (usb->desc == -1) {
+        // Opening RW failed, so see if we have RO access.
         usb->desc = unix_open(usb->fname, O_RDONLY | O_CLOEXEC);
-        if(usb->desc < 0) goto fail;
+        if (usb->desc == -1) {
+            D("[ usb open %s failed: %s]\n", usb->fname, strerror(errno));
+            free(usb);
+            return;
+        }
         usb->writeable = 0;
-        D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc);
-    } else {
-        D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
-        n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
-        if(n != 0) goto fail;
     }
 
-        /* read the device's serial number */
-    serial[0] = 0;
-    memset(serial, 0, sizeof(serial));
-    if (serial_index) {
-        struct usbdevfs_ctrltransfer  ctrl;
-        __u16 buffer[128];
-        __u16 languages[128];
-        int i, result;
-        int languageCount = 0;
+    D("[ usb opened %s%s, fd=%d]\n", usb->fname, (usb->writeable ? "" : " (read-only)"), usb->desc);
 
-        memset(languages, 0, sizeof(languages));
-        memset(&ctrl, 0, sizeof(ctrl));
-
-            // read list of supported languages
-        ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
-        ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
-        ctrl.wValue = (USB_DT_STRING << 8) | 0;
-        ctrl.wIndex = 0;
-        ctrl.wLength = sizeof(languages);
-        ctrl.data = languages;
-        ctrl.timeout = 1000;
-
-        result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
-        if (result > 0)
-            languageCount = (result - 2) / 2;
-
-        for (i = 1; i <= languageCount; i++) {
-            memset(buffer, 0, sizeof(buffer));
-            memset(&ctrl, 0, sizeof(ctrl));
-
-            ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
-            ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
-            ctrl.wValue = (USB_DT_STRING << 8) | serial_index;
-            ctrl.wIndex = __le16_to_cpu(languages[i]);
-            ctrl.wLength = sizeof(buffer);
-            ctrl.data = buffer;
-            ctrl.timeout = 1000;
-
-            result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
-            if (result > 0) {
-                int i;
-                // skip first word, and copy the rest to the serial string, changing shorts to bytes.
-                result /= 2;
-                for (i = 1; i < result; i++)
-                    serial[i - 1] = __le16_to_cpu(buffer[i]);
-                serial[i - 1] = 0;
-                break;
-            }
+    if (usb->writeable) {
+        if (ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface) != 0) {
+            D("[ usb ioctl(%d, USBDEVFS_CLAIMINTERFACE) failed: %s]\n", usb->desc, strerror(errno));
+            adb_close(usb->desc);
+            free(usb);
+            return;
         }
     }
 
+    // Read the device's serial number.
+    std::string serial_path =
+            android::base::StringPrintf("/sys/bus/usb/devices/%s/serial", dev_path + 4);
+    std::string serial;
+    if (!android::base::ReadFileToString(serial_path, &serial)) {
+        D("[ usb read %s failed: %s ]\n", serial_path.c_str(), strerror(errno));
+        adb_close(usb->desc);
+        free(usb);
+        return;
+    }
+    serial = android::base::Trim(serial);
+
         /* add to the end of the active handles */
     adb_mutex_lock(&usb_lock);
     usb->next = &handle_list;
@@ -684,19 +646,10 @@
     usb->next->prev = usb;
     adb_mutex_unlock(&usb_lock);
 
-    register_usb_transport(usb, serial, devpath, usb->writeable);
-    return;
-
-fail:
-    D("[ usb open %s error=%d, err_str = %s]\n",
-        usb->fname,  errno, strerror(errno));
-    if(usb->desc >= 0) {
-        adb_close(usb->desc);
-    }
-    free(usb);
+    register_usb_transport(usb, serial.c_str(), dev_path, usb->writeable);
 }
 
-void* device_poll_thread(void* unused)
+static void* device_poll_thread(void* unused)
 {
     D("Created device thread\n");
     for(;;) {
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.cpp
similarity index 91%
rename from adb/usb_linux_client.c
rename to adb/usb_linux_client.cpp
index 434451c..18289e2 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.cpp
@@ -18,6 +18,7 @@
 
 #include "sysdeps.h"
 
+#include <cutils/properties.h>
 #include <dirent.h>
 #include <errno.h>
 #include <linux/usb/ch9.h>
@@ -163,7 +164,7 @@
     struct usb_handle *usb = (struct usb_handle *)x;
     int fd;
 
-    while (1) {
+    while (true) {
         // wait until the USB device needs opening
         adb_mutex_lock(&usb->lock);
         while (usb->fd != -1)
@@ -239,11 +240,8 @@
 
 static void usb_adb_init()
 {
-    usb_handle *h;
-    adb_thread_t tid;
-    int fd;
-
-    h = calloc(1, sizeof(usb_handle));
+    usb_handle* h = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+    if (h == nullptr) fatal("couldn't allocate usb_handle");
 
     h->write = usb_adb_write;
     h->read = usb_adb_read;
@@ -253,12 +251,12 @@
     adb_cond_init(&h->notify, 0);
     adb_mutex_init(&h->lock, 0);
 
-    // Open the file /dev/android_adb_enable to trigger 
+    // Open the file /dev/android_adb_enable to trigger
     // the enabling of the adb USB function in the kernel.
     // We never touch this file again - just leave it open
     // indefinitely so the kernel will know when we are running
     // and when we are not.
-    fd = unix_open("/dev/android_adb_enable", O_RDWR);
+    int fd = unix_open("/dev/android_adb_enable", O_RDWR);
     if (fd < 0) {
        D("failed to open /dev/android_adb_enable\n");
     } else {
@@ -266,6 +264,7 @@
     }
 
     D("[ usb_init - starting thread ]\n");
+    adb_thread_t tid;
     if(adb_thread_create(&tid, usb_adb_open_thread, h)){
         fatal_errno("cannot create usb thread");
     }
@@ -351,14 +350,14 @@
 {
     struct usb_handle *usb = (struct usb_handle *)x;
 
-    while (1) {
+    while (true) {
         // wait until the USB device needs opening
         adb_mutex_lock(&usb->lock);
         while (usb->control != -1 && usb->bulk_in != -1 && usb->bulk_out != -1)
             adb_cond_wait(&usb->notify, &usb->lock);
         adb_mutex_unlock(&usb->lock);
 
-        while (1) {
+        while (true) {
             init_functionfs(usb);
 
             if (usb->control >= 0 && usb->bulk_in >= 0 && usb->bulk_out >= 0)
@@ -366,6 +365,7 @@
 
             adb_sleep_ms(1000);
         }
+        property_set("sys.usb.ffs.ready", "1");
 
         D("[ usb_thread - registering device ]\n");
         register_usb_transport(usb, 0, 0, 1);
@@ -375,7 +375,7 @@
     return 0;
 }
 
-static int bulk_write(int bulk_in, const char *buf, size_t length)
+static int bulk_write(int bulk_in, const uint8_t* buf, size_t length)
 {
     size_t count = 0;
     int ret;
@@ -394,22 +394,19 @@
     return count;
 }
 
-static int usb_ffs_write(usb_handle *h, const void *data, int len)
+static int usb_ffs_write(usb_handle* h, const void* data, int len)
 {
-    int n;
-
     D("about to write (fd=%d, len=%d)\n", h->bulk_in, len);
-    n = bulk_write(h->bulk_in, data, len);
+    int n = bulk_write(h->bulk_in, reinterpret_cast<const uint8_t*>(data), len);
     if (n != len) {
-        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
-            h->bulk_in, n, errno, strerror(errno));
+        D("ERROR: fd = %d, n = %d: %s\n", h->bulk_in, n, strerror(errno));
         return -1;
     }
     D("[ done fd=%d ]\n", h->bulk_in);
     return 0;
 }
 
-static int bulk_read(int bulk_out, char *buf, size_t length)
+static int bulk_read(int bulk_out, uint8_t* buf, size_t length)
 {
     size_t count = 0;
     int ret;
@@ -430,15 +427,12 @@
     return count;
 }
 
-static int usb_ffs_read(usb_handle *h, void *data, int len)
+static int usb_ffs_read(usb_handle* h, void* data, int len)
 {
-    int n;
-
     D("about to read (fd=%d, len=%d)\n", h->bulk_out, len);
-    n = bulk_read(h->bulk_out, data, len);
+    int n = bulk_read(h->bulk_out, reinterpret_cast<uint8_t*>(data), len);
     if (n != len) {
-        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
-            h->bulk_out, n, errno, strerror(errno));
+        D("ERROR: fd = %d, n = %d: %s\n", h->bulk_out, n, strerror(errno));
         return -1;
     }
     D("[ done fd=%d ]\n", h->bulk_out);
@@ -473,18 +467,15 @@
 
 static void usb_ffs_init()
 {
-    usb_handle *h;
-    adb_thread_t tid;
-
     D("[ usb_init - using FunctionFS ]\n");
 
-    h = calloc(1, sizeof(usb_handle));
+    usb_handle* h = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+    if (h == nullptr) fatal("couldn't allocate usb_handle");
 
     h->write = usb_ffs_write;
     h->read = usb_ffs_read;
     h->kick = usb_ffs_kick;
-
-    h->control  = -1;
+    h->control = -1;
     h->bulk_out = -1;
     h->bulk_out = -1;
 
@@ -492,6 +483,7 @@
     adb_mutex_init(&h->lock, 0);
 
     D("[ usb_init - starting thread ]\n");
+    adb_thread_t tid;
     if (adb_thread_create(&tid, usb_ffs_open_thread, h)){
         fatal_errno("[ cannot create usb thread ]\n");
     }
diff --git a/adb/usb_osx.c b/adb/usb_osx.cpp
similarity index 95%
rename from adb/usb_osx.c
rename to adb/usb_osx.cpp
index 94c8cfe..a795ce3 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.cpp
@@ -26,6 +26,7 @@
 #include <IOKit/IOMessage.h>
 #include <mach/mach_port.h>
 
+#include <inttypes.h>
 #include <stdio.h>
 
 #include "adb.h"
@@ -111,7 +112,7 @@
     HRESULT                  result;
     SInt32                   score;
     UInt32                   locationId;
-    UInt8                    class, subclass, protocol;
+    UInt8                    if_class, subclass, protocol;
     UInt16                   vendor;
     UInt16                   product;
     UInt8                    serialIndex;
@@ -132,9 +133,9 @@
         }
 
         //* This gets us the interface object
-        result = (*plugInInterface)->QueryInterface(plugInInterface,
-                CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)
-                &iface);
+        result = (*plugInInterface)->QueryInterface(
+            plugInInterface,
+            CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID*)&iface);
         //* We only needed the plugin to get the interface, so discard it
         (*plugInInterface)->Release(plugInInterface);
         if (result || !iface) {
@@ -142,12 +143,12 @@
             continue;
         }
 
-        kr = (*iface)->GetInterfaceClass(iface, &class);
+        kr = (*iface)->GetInterfaceClass(iface, &if_class);
         kr = (*iface)->GetInterfaceSubClass(iface, &subclass);
         kr = (*iface)->GetInterfaceProtocol(iface, &protocol);
-        if(class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) {
+        if(if_class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) {
             // Ignore non-ADB devices.
-            DBG("Ignoring interface with incorrect class/subclass/protocol - %d, %d, %d\n", class, subclass, protocol);
+            DBG("Ignoring interface with incorrect class/subclass/protocol - %d, %d, %d\n", if_class, subclass, protocol);
             (*iface)->Release(iface);
             continue;
         }
@@ -177,7 +178,7 @@
         }
 
         result = (*plugInInterface)->QueryInterface(plugInInterface,
-                CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev);
+            CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*)&dev);
         //* only needed this to query the plugin
         (*plugInInterface)->Release(plugInInterface);
         if (result || !dev) {
@@ -334,7 +335,8 @@
                 interfaceSubClass, interfaceProtocol))
         goto err_bad_adb_interface;
 
-    handle = calloc(1, sizeof(usb_handle));
+    handle = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+    if (handle == nullptr) goto err_bad_adb_interface;
 
     //* Iterate over the endpoints for this interface and find the first
     //* bulk in/out pipes available.  These will be our read/write pipes.
diff --git a/base/file.cpp b/base/file.cpp
index a51c5ff..6b19818 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -120,5 +120,29 @@
   return result || CleanUpAfterFailedWrite(path);
 }
 
+bool ReadFully(int fd, void* data, size_t byte_count) {
+  uint8_t* p = reinterpret_cast<uint8_t*>(data);
+  size_t remaining = byte_count;
+  while (remaining > 0) {
+    ssize_t n = TEMP_FAILURE_RETRY(read(fd, p, remaining));
+    if (n <= 0) return false;
+    p += n;
+    remaining -= n;
+  }
+  return true;
+}
+
+bool WriteFully(int fd, const void* data, size_t byte_count) {
+  const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
+  size_t remaining = byte_count;
+  while (remaining > 0) {
+    ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, remaining));
+    if (n == -1) return false;
+    p += n;
+    remaining -= n;
+  }
+  return true;
+}
+
 }  // namespace base
 }  // namespace android
diff --git a/base/file_test.cpp b/base/file_test.cpp
index fc48b32..e5cf696 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -79,3 +79,28 @@
   ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << errno;
   EXPECT_EQ("abc", s);
 }
+
+TEST(file, ReadFully) {
+  int fd = open("/proc/version", O_RDONLY);
+  ASSERT_NE(-1, fd) << strerror(errno);
+
+  char buf[1024];
+  memset(buf, 0, sizeof(buf));
+  ASSERT_TRUE(android::base::ReadFully(fd, buf, 5));
+  ASSERT_STREQ("Linux", buf);
+
+  ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
+
+  ASSERT_FALSE(android::base::ReadFully(fd, buf, sizeof(buf)));
+
+  close(fd);
+}
+
+TEST(file, WriteFully) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+  ASSERT_TRUE(android::base::WriteFully(tf.fd, "abc", 3));
+  std::string s;
+  ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s)) << errno;
+  EXPECT_EQ("abc", s);
+}
diff --git a/base/include/base/file.h b/base/include/base/file.h
index ef97742..acd29b3 100644
--- a/base/include/base/file.h
+++ b/base/include/base/file.h
@@ -34,6 +34,9 @@
                        mode_t mode, uid_t owner, gid_t group);
 #endif
 
+bool ReadFully(int fd, void* data, size_t byte_count);
+bool WriteFully(int fd, const void* data, size_t byte_count);
+
 }  // namespace base
 }  // namespace android
 
diff --git a/base/include/base/strings.h b/base/include/base/strings.h
index ab56aad..5dbc5fb 100644
--- a/base/include/base/strings.h
+++ b/base/include/base/strings.h
@@ -25,9 +25,7 @@
 
 // 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 string is split at each occurrence of a character in delimiters.
 //
 // The empty string is not a valid delimiter list.
 std::vector<std::string> Split(const std::string& s,
diff --git a/base/strings.cpp b/base/strings.cpp
index 6f698d9..d3375d9 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -32,24 +32,17 @@
                                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;
-  }
+  std::vector<std::string> result;
 
   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));
-    }
-
+    result.push_back(s.substr(base, found - base));
     base = found + 1;
   } while (found != s.npos);
 
-  return split;
+  return result;
 }
 
 std::string Trim(const std::string& s) {
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 1bf07a1..46a1ab5 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -23,7 +23,8 @@
 
 TEST(strings, split_empty) {
   std::vector<std::string> parts = android::base::Split("", ",");
-  ASSERT_EQ(0U, parts.size());
+  ASSERT_EQ(1U, parts.size());
+  ASSERT_EQ("", parts[0]);
 }
 
 TEST(strings, split_single) {
@@ -42,9 +43,10 @@
 
 TEST(strings, split_with_empty_part) {
   std::vector<std::string> parts = android::base::Split("foo,,bar", ",");
-  ASSERT_EQ(2U, parts.size());
+  ASSERT_EQ(3U, parts.size());
   ASSERT_EQ("foo", parts[0]);
-  ASSERT_EQ("bar", parts[1]);
+  ASSERT_EQ("", parts[1]);
+  ASSERT_EQ("bar", parts[2]);
 }
 
 TEST(strings, split_null_char) {
@@ -65,9 +67,10 @@
 
 TEST(strings, split_any_with_empty_part) {
   std::vector<std::string> parts = android::base::Split("foo:,bar", ",:");
-  ASSERT_EQ(2U, parts.size());
+  ASSERT_EQ(3U, parts.size());
   ASSERT_EQ("foo", parts[0]);
-  ASSERT_EQ("bar", parts[1]);
+  ASSERT_EQ("", parts[1]);
+  ASSERT_EQ("bar", parts[2]);
 }
 
 TEST(strings, trim_empty) {
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index e10feff..d6a6d2e 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -26,25 +26,12 @@
 #include <sys/wait.h>
 
 #include <backtrace/Backtrace.h>
+#include <base/file.h>
 #include <log/log.h>
 
 const int SLEEP_TIME_USEC = 50000;         // 0.05 seconds
 const int MAX_TOTAL_SLEEP_USEC = 10000000; // 10 seconds
 
-static int write_to_am(int fd, const char* buf, int len) {
-  int to_write = len;
-  while (to_write > 0) {
-    int written = TEMP_FAILURE_RETRY(write(fd, buf + len - to_write, to_write));
-    if (written < 0) {
-      // hard failure
-      ALOGE("AM write failure (%d / %s)\n", errno, strerror(errno));
-      return -1;
-    }
-    to_write -= written;
-  }
-  return len;
-}
-
 // Whitelist output desired in the logcat output.
 bool is_allowed_in_logcat(enum logtype ltype) {
   if ((ltype == ERROR)
@@ -82,9 +69,9 @@
   if (write_to_logcat) {
     __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, LOG_TAG, buf);
     if (write_to_activitymanager) {
-      int written = write_to_am(log->amfd, buf, len);
-      if (written <= 0) {
+      if (!android::base::WriteFully(log->amfd, buf, len)) {
         // timeout or other failure on write; stop informing the activity manager
+        ALOGE("AM write failed: %s", strerror(errno));
         log->amfd = -1;
       }
     }
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index b9e957f..dee471a 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -58,7 +58,8 @@
     libsparse_host \
     libutils \
     liblog \
-    libz
+    libz \
+    libbase
 
 ifneq ($(HOST_OS),windows)
 LOCAL_STATIC_LIBRARIES += libselinux
@@ -74,6 +75,16 @@
 LOCAL_STATIC_LIBRARIES += libf2fs_utils_host libf2fs_ioutils_host libf2fs_dlutils_host
 endif
 
+# libc++ not available on windows yet
+ifneq ($(HOST_OS),windows)
+    LOCAL_CXX_STL := libc++_static
+endif
+
+# Don't add anything here, we don't want additional shared dependencies
+# on the host fastboot tool, and shared libraries that link against libc++
+# will violate ODR
+LOCAL_SHARED_LIBRARIES :=
+
 include $(BUILD_HOST_EXECUTABLE)
 
 my_dist_files := $(LOCAL_BUILT_MODULE)
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 273a2ec..d5e94ac 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -31,7 +31,7 @@
 #include <dirent.h>
 #include <ext4.h>
 #include <ext4_sb.h>
-#include <ext4_crypt.h>
+#include <ext4_crypt_init_extensions.h>
 
 #include <linux/loop.h>
 #include <private/android_filesystem_config.h>
@@ -117,8 +117,10 @@
          * filesytsem due to an error, e2fsck is still run to do a full check
          * fix the filesystem.
          */
+        errno = 0;
         ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
-        INFO("%s(): mount(%s,%s,%s)=%d\n", __func__, blk_device, target, fs_type, ret);
+        INFO("%s(): mount(%s,%s,%s)=%d: %s\n",
+             __func__, blk_device, target, fs_type, ret, strerror(errno));
         if (!ret) {
             int i;
             for (i = 0; i < 5; i++) {
@@ -126,6 +128,7 @@
                 // Should we try rebooting if all attempts fail?
                 int result = umount(target);
                 if (result == 0) {
+                    INFO("%s(): unmount(%s) succeeded\n", __func__, target);
                     break;
                 }
                 ERROR("%s(): umount(%s)=%d: %s\n", __func__, target, result, strerror(errno));
@@ -480,16 +483,6 @@
             return FS_MGR_MNTALL_FAIL;
         }
 
-        // Link it to the normal place so ext4_crypt functions work normally
-        strlcat(tmp_mnt, "/unencrypted", sizeof(tmp_mnt));
-        char link_path[PATH_MAX];
-        strlcpy(link_path, rec->mount_point, sizeof(link_path));
-        strlcat(link_path, "/unencrypted", sizeof(link_path));
-        if (symlink(tmp_mnt, link_path)) {
-            ERROR("Error creating symlink to unencrypted directory\n");
-            return FS_MGR_MNTALL_FAIL;
-        }
-
         return FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED;
     }
 
diff --git a/include/cutils/dir_hash.h b/include/cutils/dir_hash.h
deleted file mode 100644
index fbb4d02..0000000
--- a/include/cutils/dir_hash.h
+++ /dev/null
@@ -1,26 +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.
- */
-
-typedef enum {
-    SHA_1,
-} HashAlgorithm;
-
-int get_file_hash(HashAlgorithm algorithm, const char *path,
-                  char *output_string, size_t max_output_string);
-
-int get_recursive_hash_manifest(HashAlgorithm algorithm,
-                                const char *directory_path,
-                                char **output_string);
diff --git a/include/cutils/partition_utils.h b/include/cutils/partition_utils.h
index 597df92..72ca80d 100644
--- a/include/cutils/partition_utils.h
+++ b/include/cutils/partition_utils.h
@@ -20,7 +20,6 @@
 __BEGIN_DECLS
 
 int partition_wiped(char *source);
-void erase_footer(const char *dev_path, long long size);
 
 __END_DECLS
 
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index 9d039e6..e4ed179 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -18,6 +18,7 @@
 #define _LIBS_CUTILS_TRACE_H
 
 #include <inttypes.h>
+#include <stdatomic.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -25,7 +26,6 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <cutils/atomic.h>
 #include <cutils/compiler.h>
 
 __BEGIN_DECLS
@@ -113,7 +113,7 @@
  * Nonzero indicates setup has completed.
  * Note: This does NOT indicate whether or not setup was successful.
  */
-extern volatile int32_t atrace_is_ready;
+extern atomic_bool atrace_is_ready;
 
 /**
  * Set of ATRACE_TAG flags to trace for, initialized to ATRACE_TAG_NOT_READY.
@@ -136,7 +136,7 @@
 #define ATRACE_INIT() atrace_init()
 static inline void atrace_init()
 {
-    if (CC_UNLIKELY(!android_atomic_acquire_load(&atrace_is_ready))) {
+    if (CC_UNLIKELY(!atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
         atrace_setup();
     }
 }
diff --git a/include/log/log.h b/include/log/log.h
index ce253e2..f9299b0 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -492,6 +492,7 @@
     EVENT_TYPE_LONG     = 1,
     EVENT_TYPE_STRING   = 2,
     EVENT_TYPE_LIST     = 3,
+    EVENT_TYPE_FLOAT    = 4,
 } AndroidEventLogType;
 #define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
 #define typeof_AndroidEventLogType unsigned char
@@ -510,6 +511,13 @@
             sizeof(longBuf));                                               \
     }
 #endif
+#ifndef LOG_EVENT_FLOAT
+#define LOG_EVENT_FLOAT(_tag, _value) {                                     \
+        float floatBuf = _value;                                            \
+        (void) android_btWriteLog(_tag, EVENT_TYPE_FLOAT, &floatBuf,        \
+            sizeof(floatBuf));                                              \
+    }
+#endif
 #ifndef LOG_EVENT_STRING
 #define LOG_EVENT_STRING(_tag, _value)                                      \
         (void) __android_log_bswrite(_tag, _value);
diff --git a/include/memtrack/memtrack.h b/include/memtrack/memtrack.h
index 0f1f85e..3917300 100644
--- a/include/memtrack/memtrack.h
+++ b/include/memtrack/memtrack.h
@@ -121,7 +121,7 @@
 ssize_t memtrack_proc_gl_pss(struct memtrack_proc *p);
 
 /**
- * memtrack_proc_gl_total
+ * memtrack_proc_other_total
  *
  * Same as memtrack_proc_graphics_total, but counts miscellaneous memory
  * not tracked by gl or graphics calls above.
@@ -131,7 +131,7 @@
 ssize_t memtrack_proc_other_total(struct memtrack_proc *p);
 
 /**
- * memtrack_proc_gl_pss
+ * memtrack_proc_other_pss
  *
  * Same as memtrack_proc_graphics_total, but counts miscellaneous memory
  * not tracked by gl or graphics calls above.
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index fed81f8..02fe2b5 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -215,6 +215,8 @@
 void fs_config(const char *path, int dir,
                unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities);
 
+ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc);
+
 __END_DECLS
 
 #endif
diff --git a/include/utils/Timers.h b/include/utils/Timers.h
index d015421..54ec474 100644
--- a/include/utils/Timers.h
+++ b/include/utils/Timers.h
@@ -24,6 +24,8 @@
 #include <sys/types.h>
 #include <sys/time.h>
 
+#include <utils/Compat.h>
+
 // ------------------------------------------------------------------
 // C API
 
@@ -33,46 +35,46 @@
 
 typedef int64_t nsecs_t;       // nano-seconds
 
-static inline nsecs_t seconds_to_nanoseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t seconds_to_nanoseconds(nsecs_t secs)
 {
     return secs*1000000000;
 }
 
-static inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs)
 {
     return secs*1000000;
 }
 
-static inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs)
 {
     return secs*1000;
 }
 
-static inline nsecs_t nanoseconds_to_seconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t nanoseconds_to_seconds(nsecs_t secs)
 {
     return secs/1000000000;
 }
 
-static inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs)
 {
     return secs/1000000;
 }
 
-static inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs)
 {
     return secs/1000;
 }
 
-static inline nsecs_t s2ns(nsecs_t v)  {return seconds_to_nanoseconds(v);}
-static inline nsecs_t ms2ns(nsecs_t v) {return milliseconds_to_nanoseconds(v);}
-static inline nsecs_t us2ns(nsecs_t v) {return microseconds_to_nanoseconds(v);}
-static inline nsecs_t ns2s(nsecs_t v)  {return nanoseconds_to_seconds(v);}
-static inline nsecs_t ns2ms(nsecs_t v) {return nanoseconds_to_milliseconds(v);}
-static inline nsecs_t ns2us(nsecs_t v) {return nanoseconds_to_microseconds(v);}
+static CONSTEXPR inline nsecs_t s2ns(nsecs_t v)  {return seconds_to_nanoseconds(v);}
+static CONSTEXPR inline nsecs_t ms2ns(nsecs_t v) {return milliseconds_to_nanoseconds(v);}
+static CONSTEXPR inline nsecs_t us2ns(nsecs_t v) {return microseconds_to_nanoseconds(v);}
+static CONSTEXPR inline nsecs_t ns2s(nsecs_t v)  {return nanoseconds_to_seconds(v);}
+static CONSTEXPR inline nsecs_t ns2ms(nsecs_t v) {return nanoseconds_to_milliseconds(v);}
+static CONSTEXPR inline nsecs_t ns2us(nsecs_t v) {return nanoseconds_to_microseconds(v);}
 
-static inline nsecs_t seconds(nsecs_t v)      { return s2ns(v); }
-static inline nsecs_t milliseconds(nsecs_t v) { return ms2ns(v); }
-static inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); }
+static CONSTEXPR inline nsecs_t seconds(nsecs_t v)      { return s2ns(v); }
+static CONSTEXPR inline nsecs_t milliseconds(nsecs_t v) { return ms2ns(v); }
+static CONSTEXPR inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); }
 
 enum {
     SYSTEM_TIME_REALTIME = 0,  // system-wide realtime clock
diff --git a/init/Android.mk b/init/Android.mk
index 4bd4f3d..0dc257d 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -5,9 +5,9 @@
 # --
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-init_options += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_DISABLE_SELINUX=1
+init_options += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_PERMISSIVE_SELINUX=1
 else
-init_options += -DALLOW_LOCAL_PROP_OVERRIDE=0 -DALLOW_DISABLE_SELINUX=0
+init_options += -DALLOW_LOCAL_PROP_OVERRIDE=0 -DALLOW_PERMISSIVE_SELINUX=0
 endif
 
 init_options += -DLOG_UEVENTS=0
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 3bbaf83..d772383 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -29,7 +29,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 #include <linux/loop.h>
-#include <ext4_crypt.h>
+#include <ext4_crypt_init_extensions.h>
 
 #include <selinux/selinux.h>
 #include <selinux/label.h>
@@ -386,18 +386,6 @@
 }
 
 /*
- * Callback to make a directory from the ext4 code
- */
-static int do_mount_alls_make_dir(const char* dir)
-{
-    if (make_dir(dir, 0700) && errno != EEXIST) {
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
  * This function might request a reboot, in which case it will
  * not return.
  */
@@ -452,6 +440,7 @@
         property_set("vold.decrypt", "trigger_encryption");
     } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
         property_set("ro.crypto.state", "encrypted");
+        property_set("ro.crypto.type", "block");
         property_set("vold.decrypt", "trigger_default_encryption");
     } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
         property_set("ro.crypto.state", "unencrypted");
@@ -465,26 +454,11 @@
         ret = wipe_data_via_recovery();
         /* If reboot worked, there is no return. */
     } else if (ret == FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED) {
-        // We have to create the key files here. Only init can call make_dir,
-        // and we can't do it from fs_mgr as then fs_mgr would depend on
-        // make_dir creating a circular dependency.
-        fstab = fs_mgr_read_fstab(args[1]);
-        for (int i = 0; i < fstab->num_entries; ++i) {
-            if (fs_mgr_is_file_encrypted(&fstab->recs[i])) {
-              if (e4crypt_create_device_key(fstab->recs[i].mount_point,
-                                            do_mount_alls_make_dir)) {
-                    ERROR("Could not create device key on %s"
-                          " - continue unencrypted\n",
-                          fstab->recs[i].mount_point);
-                }
-            }
-        }
-        fs_mgr_free_fstab(fstab);
-
         if (e4crypt_install_keyring()) {
             return -1;
         }
         property_set("ro.crypto.state", "encrypted");
+        property_set("ro.crypto.type", "file");
 
         // Although encrypted, we have device key, so we do not need to
         // do anything different from the nonencrypted case.
@@ -494,6 +468,7 @@
             return -1;
         }
         property_set("ro.crypto.state", "encrypted");
+        property_set("ro.crypto.type", "file");
         property_set("vold.decrypt", "trigger_restart_min_framework");
     } else if (ret > 0) {
         ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
@@ -515,15 +490,6 @@
     return ret;
 }
 
-int do_setcon(int nargs, char **args) {
-    if (is_selinux_enabled() <= 0)
-        return 0;
-    if (setcon(args[1]) < 0) {
-        return -errno;
-    }
-    return 0;
-}
-
 int do_setprop(int nargs, char **args)
 {
     const char *name = args[1];
@@ -849,11 +815,30 @@
         return -1;
 }
 
-int do_installkey(int nargs, char **args)
+/*
+ * Callback to make a directory from the ext4 code
+ */
+static int do_installkeys_ensure_dir_exists(const char* dir)
 {
-    if (nargs == 2) {
-        return e4crypt_install_key(args[1]);
+    if (make_dir(dir, 0700) && errno != EEXIST) {
+        return -1;
     }
 
-    return -1;
+    return 0;
+}
+
+int do_installkey(int nargs, char **args)
+{
+    if (nargs != 2) {
+        return -1;
+    }
+
+    char prop_value[PROP_VALUE_MAX] = {0};
+    property_get("ro.crypto.type", prop_value);
+    if (strcmp(prop_value, "file")) {
+        return 0;
+    }
+
+    return e4crypt_create_device_key(args[1],
+                                     do_installkeys_ensure_dir_exists);
 }
diff --git a/init/devices.cpp b/init/devices.cpp
index 96b1696..2c7f5a9 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -266,7 +266,6 @@
 static void add_platform_device(const char *path)
 {
     int path_len = strlen(path);
-    struct listnode *node;
     struct platform_node *bus;
     const char *name = path;
 
@@ -276,15 +275,6 @@
             name += 9;
     }
 
-    list_for_each_reverse(node, &platform_names) {
-        bus = node_to_item(node, struct platform_node, list);
-        if ((bus->path_len < path_len) &&
-                (path[bus->path_len] == '/') &&
-                !strncmp(path, bus->path, bus->path_len))
-            /* subdevice of an existing platform, ignore it */
-            return;
-    }
-
     INFO("adding platform device %s (%s)\n", name, path);
 
     bus = (platform_node*) calloc(1, sizeof(struct platform_node));
diff --git a/init/init.cpp b/init/init.cpp
index b1d65db..68c8b7f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -25,8 +25,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/epoll.h>
 #include <sys/mount.h>
-#include <sys/poll.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -82,6 +82,17 @@
 
 bool waiting_for_exec = false;
 
+static int epoll_fd = -1;
+
+void register_epoll_handler(int fd, void (*fn)()) {
+    epoll_event ev;
+    ev.events = EPOLLIN;
+    ev.data.ptr = reinterpret_cast<void*>(fn);
+    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+        ERROR("epoll_ctl failed: %s\n", strerror(errno));
+    }
+}
+
 void service::NotifyStateChange(const char* new_state) {
     if (!properties_initialized()) {
         // If properties aren't available yet, we can't set them.
@@ -603,14 +614,16 @@
     }
 }
 
-static int wait_for_coldboot_done_action(int nargs, char **args)
-{
-    int ret;
-    INFO("wait for %s\n", COLDBOOT_DONE);
-    ret = wait_for_file(COLDBOOT_DONE, COMMAND_RETRY_TIMEOUT);
-    if (ret)
+static int wait_for_coldboot_done_action(int nargs, char **args) {
+    Timer t;
+
+    NOTICE("Waiting for %s...\n", COLDBOOT_DONE);
+    if (wait_for_file(COLDBOOT_DONE, COMMAND_RETRY_TIMEOUT)) {
         ERROR("Timed out waiting for %s\n", COLDBOOT_DONE);
-    return ret;
+    }
+
+    NOTICE("Waiting for %s took %.2fs.\n", COLDBOOT_DONE, t.duration());
+    return 0;
 }
 
 /*
@@ -733,7 +746,7 @@
     return 0;
 }
 
-static void import_kernel_nv(char *name, int for_emulator)
+static void import_kernel_nv(char *name, bool for_emulator)
 {
     char *value = strchr(name, '=');
     int name_len = strlen(name);
@@ -827,35 +840,9 @@
      * second pass is only necessary for qemu to export all kernel params
      * as props.
      */
-    import_kernel_cmdline(0, import_kernel_nv);
+    import_kernel_cmdline(false, import_kernel_nv);
     if (qemu[0])
-        import_kernel_cmdline(1, import_kernel_nv);
-}
-
-static int property_service_init_action(int nargs, char **args)
-{
-    /* read any property files on system or data and
-     * fire up the property service.  This must happen
-     * after the ro.foo properties are set above so
-     * that /data/local.prop cannot interfere with them.
-     */
-    start_property_service();
-    if (get_property_set_fd() < 0) {
-        ERROR("start_property_service() failed\n");
-        exit(1);
-    }
-
-    return 0;
-}
-
-static int signal_init_action(int nargs, char **args)
-{
-    signal_init();
-    if (get_signal_fd() < 0) {
-        ERROR("signal_init() failed\n");
-        exit(1);
-    }
-    return 0;
+        import_kernel_cmdline(true, import_kernel_nv);
 }
 
 static int queue_property_triggers_action(int nargs, char **args)
@@ -866,59 +853,43 @@
     return 0;
 }
 
-void selinux_init_all_handles(void)
+static void selinux_init_all_handles(void)
 {
     sehandle = selinux_android_file_context_handle();
     selinux_android_set_sehandle(sehandle);
     sehandle_prop = selinux_android_prop_context_handle();
 }
 
-static bool selinux_is_disabled(void)
-{
-    if (ALLOW_DISABLE_SELINUX) {
-        if (access("/sys/fs/selinux", F_OK) != 0) {
-            // SELinux is not compiled into the kernel, or has been disabled
-            // via the kernel command line "selinux=0".
-            return true;
-        }
+enum selinux_enforcing_status { SELINUX_PERMISSIVE, SELINUX_ENFORCING };
 
-        char tmp[PROP_VALUE_MAX];
-        if ((property_get("ro.boot.selinux", tmp) != 0) && (strcmp(tmp, "disabled") == 0)) {
-            // SELinux is compiled into the kernel, but we've been told to disable it.
-            return true;
-        }
-    }
+static selinux_enforcing_status selinux_status_from_cmdline() {
+    selinux_enforcing_status status = SELINUX_ENFORCING;
 
-    return false;
+    std::function<void(char*,bool)> fn = [&](char* name, bool in_qemu) {
+        char *value = strchr(name, '=');
+        if (value == nullptr) { return; }
+        *value++ = '\0';
+        if (strcmp(name, "androidboot.selinux") == 0) {
+            if (strcmp(value, "permissive") == 0) {
+                status = SELINUX_PERMISSIVE;
+            }
+        }
+    };
+    import_kernel_cmdline(false, fn);
+
+    return status;
 }
 
 static bool selinux_is_enforcing(void)
 {
-    if (ALLOW_DISABLE_SELINUX) {
-        char tmp[PROP_VALUE_MAX];
-        if (property_get("ro.boot.selinux", tmp) == 0) {
-            // Property is not set.  Assume enforcing.
-            return true;
-        }
-
-        if (strcmp(tmp, "permissive") == 0) {
-            // SELinux is in the kernel, but we've been told to go into permissive mode.
-            return false;
-        }
-
-        if (strcmp(tmp, "enforcing") != 0) {
-            ERROR("SELinux: Unknown value of ro.boot.selinux. Got: \"%s\". Assuming enforcing.\n", tmp);
-        }
+    if (ALLOW_PERMISSIVE_SELINUX) {
+        return selinux_status_from_cmdline() == SELINUX_ENFORCING;
     }
     return true;
 }
 
 int selinux_reload_policy(void)
 {
-    if (selinux_is_disabled()) {
-        return -1;
-    }
-
     INFO("SELinux: Attempting to reload policy files\n");
 
     if (selinux_android_reload_policy() == -1) {
@@ -940,7 +911,13 @@
     return 0;
 }
 
-static void selinux_initialize() {
+static void security_failure() {
+    ERROR("Security failure; rebooting into recovery mode...\n");
+    android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+    while (true) { pause(); }  // never reached
+}
+
+static void selinux_initialize(bool in_kernel_domain) {
     Timer t;
 
     selinux_callback cb;
@@ -949,23 +926,32 @@
     cb.func_audit = audit_callback;
     selinux_set_callback(SELINUX_CB_AUDIT, cb);
 
-    if (selinux_is_disabled()) {
-        return;
+    if (in_kernel_domain) {
+        INFO("Loading SELinux policy...\n");
+        if (selinux_android_load_policy() < 0) {
+            ERROR("failed to load policy: %s\n", strerror(errno));
+            security_failure();
+        }
+
+        bool kernel_enforcing = (security_getenforce() == 1);
+        bool is_enforcing = selinux_is_enforcing();
+        if (kernel_enforcing != is_enforcing) {
+            if (security_setenforce(is_enforcing)) {
+                ERROR("security_setenforce(%s) failed: %s\n",
+                      is_enforcing ? "true" : "false", strerror(errno));
+                security_failure();
+            }
+        }
+
+        if (write_file("/sys/fs/selinux/checkreqprot", "0") == -1) {
+            security_failure();
+        }
+
+        NOTICE("(Initializing SELinux %s took %.2fs.)\n",
+               is_enforcing ? "enforcing" : "non-enforcing", t.duration());
+    } else {
+        selinux_init_all_handles();
     }
-
-    INFO("Loading SELinux policy...\n");
-    if (selinux_android_load_policy() < 0) {
-        ERROR("SELinux: Failed to load policy; rebooting into recovery mode\n");
-        android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
-        while (1) { pause(); }  // never reached
-    }
-
-    selinux_init_all_handles();
-    bool is_enforcing = selinux_is_enforcing();
-    INFO("SELinux: security_setenforce(%d)\n", is_enforcing);
-    security_setenforce(is_enforcing);
-
-    NOTICE("(Initializing SELinux took %.2fs.)\n", t.duration());
 }
 
 int main(int argc, char** argv) {
@@ -982,21 +968,18 @@
 
     add_environment("PATH", _PATH_DEFPATH);
 
+    bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);
+
     // Get the basic filesystem setup we need put together in the initramdisk
     // on / and then we'll let the rc file figure out the rest.
-    mkdir("/dev", 0755);
-    mkdir("/proc", 0755);
-    mkdir("/sys", 0755);
-
-    mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
-    mkdir("/dev/pts", 0755);
-    mkdir("/dev/socket", 0755);
-    mount("devpts", "/dev/pts", "devpts", 0, NULL);
-    mount("proc", "/proc", "proc", 0, NULL);
-    mount("sysfs", "/sys", "sysfs", 0, NULL);
-
-    // Indicate that booting is in progress to background fw loaders, etc.
-    close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
+    if (is_first_stage) {
+        mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
+        mkdir("/dev/pts", 0755);
+        mkdir("/dev/socket", 0755);
+        mount("devpts", "/dev/pts", "devpts", 0, NULL);
+        mount("proc", "/proc", "proc", 0, NULL);
+        mount("sysfs", "/sys", "sysfs", 0, NULL);
+    }
 
     // We must have some place other than / to create the device nodes for
     // kmsg and null, otherwise we won't be able to remount / read-only
@@ -1006,20 +989,41 @@
     klog_init();
     klog_set_level(KLOG_NOTICE_LEVEL);
 
-    NOTICE("init started!\n");
+    NOTICE("init%s started!\n", is_first_stage ? "" : " second stage");
 
-    property_init();
+    if (!is_first_stage) {
+        // Indicate that booting is in progress to background fw loaders, etc.
+        close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
 
-    // If arguments are passed both on the command line and in DT,
-    // properties set in DT always have priority over the command-line ones.
-    process_kernel_dt();
-    process_kernel_cmdline();
+        property_init();
 
-    // Propogate the kernel variables to internal variables
-    // used by init as well as the current required properties.
-    export_kernel_boot_props();
+        // If arguments are passed both on the command line and in DT,
+        // properties set in DT always have priority over the command-line ones.
+        process_kernel_dt();
+        process_kernel_cmdline();
 
-    selinux_initialize();
+        // Propogate the kernel variables to internal variables
+        // used by init as well as the current required properties.
+        export_kernel_boot_props();
+    }
+
+    // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
+    selinux_initialize(is_first_stage);
+
+    // If we're in the kernel domain, re-exec init to transition to the init domain now
+    // that the SELinux policy has been loaded.
+    if (is_first_stage) {
+        if (restorecon("/init") == -1) {
+            ERROR("restorecon failed: %s\n", strerror(errno));
+            security_failure();
+        }
+        char* path = argv[0];
+        char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
+        if (execv(path, args) == -1) {
+            ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));
+            security_failure();
+        }
+    }
 
     // These directories were necessarily created before initial policy load
     // and therefore need their security context restored to the proper value.
@@ -1030,13 +1034,24 @@
     restorecon("/dev/__properties__");
     restorecon_recursive("/sys");
 
+    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+    if (epoll_fd == -1) {
+        ERROR("epoll_create1 failed: %s\n", strerror(errno));
+        exit(1);
+    }
+
+    signal_handler_init();
+
     property_load_boot_defaults();
+    start_property_service();
 
     init_parse_config_file("/init.rc");
 
     action_for_each_trigger("early-init", action_add_queue_tail);
 
+    // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
     queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
+    // ... so that we can start queuing up actions that require stuff from /dev.
     queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
     queue_builtin_action(keychord_init_action, "keychord_init");
     queue_builtin_action(console_init_action, "console_init");
@@ -1047,8 +1062,6 @@
     // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
     // wasn't ready immediately after wait_for_coldboot_done
     queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
-    queue_builtin_action(property_service_init_action, "property_service_init");
-    queue_builtin_action(signal_init_action, "signal_init");
 
     // Don't mount filesystems or start core system services in charger mode.
     char bootmode[PROP_VALUE_MAX];
@@ -1061,41 +1074,12 @@
     // Run all property triggers based on current state of the properties.
     queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
 
-    // TODO: why do we only initialize ufds after execute_one_command and restart_processes?
-    size_t fd_count = 0;
-    struct pollfd ufds[3];
-    bool property_set_fd_init = false;
-    bool signal_fd_init = false;
-    bool keychord_fd_init = false;
-
-    for (;;) {
+    while (true) {
         if (!waiting_for_exec) {
             execute_one_command();
             restart_processes();
         }
 
-        if (!property_set_fd_init && get_property_set_fd() > 0) {
-            ufds[fd_count].fd = get_property_set_fd();
-            ufds[fd_count].events = POLLIN;
-            ufds[fd_count].revents = 0;
-            fd_count++;
-            property_set_fd_init = true;
-        }
-        if (!signal_fd_init && get_signal_fd() > 0) {
-            ufds[fd_count].fd = get_signal_fd();
-            ufds[fd_count].events = POLLIN;
-            ufds[fd_count].revents = 0;
-            fd_count++;
-            signal_fd_init = true;
-        }
-        if (!keychord_fd_init && get_keychord_fd() > 0) {
-            ufds[fd_count].fd = get_keychord_fd();
-            ufds[fd_count].events = POLLIN;
-            ufds[fd_count].revents = 0;
-            fd_count++;
-            keychord_fd_init = true;
-        }
-
         int timeout = -1;
         if (process_needs_restart) {
             timeout = (process_needs_restart - gettime()) * 1000;
@@ -1109,21 +1093,12 @@
 
         bootchart_sample(&timeout);
 
-        int nr = poll(ufds, fd_count, timeout);
-        if (nr <= 0) {
-            continue;
-        }
-
-        for (size_t i = 0; i < fd_count; i++) {
-            if (ufds[i].revents & POLLIN) {
-                if (ufds[i].fd == get_property_set_fd()) {
-                    handle_property_set_fd();
-                } else if (ufds[i].fd == get_keychord_fd()) {
-                    handle_keychord();
-                } else if (ufds[i].fd == get_signal_fd()) {
-                    handle_signal();
-                }
-            }
+        epoll_event ev;
+        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
+        if (nr == -1) {
+            ERROR("epoll_wait failed: %s\n", strerror(errno));
+        } else if (nr == 1) {
+            ((void (*)()) ev.data.ptr)();
         }
     }
 
diff --git a/init/init.h b/init/init.h
index a104af6..1cabb14 100644
--- a/init/init.h
+++ b/init/init.h
@@ -155,4 +155,6 @@
 
 void zap_stdio(void);
 
+void register_epoll_handler(int fd, void (*fn)());
+
 #endif	/* _INIT_INIT_H */
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index ff31093..b76b04e 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -184,7 +184,6 @@
     case 's':
         if (!strcmp(s, "eclabel")) return K_seclabel;
         if (!strcmp(s, "ervice")) return K_service;
-        if (!strcmp(s, "etcon")) return K_setcon;
         if (!strcmp(s, "etenv")) return K_setenv;
         if (!strcmp(s, "etprop")) return K_setprop;
         if (!strcmp(s, "etrlimit")) return K_setrlimit;
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 27894a2..10d9573 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -62,37 +62,7 @@
     }
 }
 
-void keychord_init()
-{
-    int fd, ret;
-
-    service_for_each(add_service_keycodes);
-
-    /* nothing to do if no services require keychords */
-    if (!keychords)
-        return;
-
-    fd = open("/dev/keychord", O_RDWR | O_CLOEXEC);
-    if (fd < 0) {
-        ERROR("could not open /dev/keychord\n");
-        return;
-    }
-
-    ret = write(fd, keychords, keychords_length);
-    if (ret != keychords_length) {
-        ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno));
-        close(fd);
-        fd = -1;
-    }
-
-    free(keychords);
-    keychords = 0;
-
-    keychord_fd = fd;
-}
-
-void handle_keychord()
-{
+static void handle_keychord() {
     struct service *svc;
     char adb_enabled[PROP_VALUE_MAX];
     int ret;
@@ -117,7 +87,28 @@
     }
 }
 
-int get_keychord_fd()
-{
-    return keychord_fd;
+void keychord_init() {
+    service_for_each(add_service_keycodes);
+
+    // Nothing to do if no services require keychords.
+    if (!keychords) {
+        return;
+    }
+
+    keychord_fd = TEMP_FAILURE_RETRY(open("/dev/keychord", O_RDWR | O_CLOEXEC));
+    if (keychord_fd == -1) {
+        ERROR("could not open /dev/keychord: %s\n", strerror(errno));
+        return;
+    }
+
+    int ret = write(keychord_fd, keychords, keychords_length);
+    if (ret != keychords_length) {
+        ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno));
+        close(keychord_fd);
+    }
+
+    free(keychords);
+    keychords = nullptr;
+
+    register_epoll_handler(keychord_fd, handle_keychord);
 }
diff --git a/init/keychords.h b/init/keychords.h
index 070b858..d2723b7 100644
--- a/init/keychords.h
+++ b/init/keychords.h
@@ -19,9 +19,7 @@
 
 struct service;
 
-void add_service_keycodes(struct service *svc);
-void keychord_init(void);
-void handle_keychord(void);
-int get_keychord_fd(void);
+void add_service_keycodes(service*);
+void keychord_init();
 
 #endif
diff --git a/init/keywords.h b/init/keywords.h
index 059dde1..37f01b8 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -20,7 +20,6 @@
 int do_restorecon_recursive(int nargs, char **args);
 int do_rm(int nargs, char **args);
 int do_rmdir(int nargs, char **args);
-int do_setcon(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);
@@ -76,7 +75,6 @@
     KEYWORD(rmdir,       COMMAND, 1, do_rmdir)
     KEYWORD(seclabel,    OPTION,  0, 0)
     KEYWORD(service,     SECTION, 0, 0)
-    KEYWORD(setcon,      COMMAND, 1, do_setcon)
     KEYWORD(setenv,      OPTION,  2, 0)
     KEYWORD(setprop,     COMMAND, 2, do_setprop)
     KEYWORD(setrlimit,   COMMAND, 3, do_setrlimit)
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 2fa81d4..930ef82 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -246,7 +246,7 @@
     return rc;
 }
 
-void handle_property_set_fd()
+static void handle_property_set_fd()
 {
     prop_msg msg;
     int s;
@@ -508,7 +508,6 @@
 
 void load_all_props() {
     load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
-    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL);
     load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);
     load_properties_from_file(PROP_PATH_BOOTIMAGE_BUILD, NULL);
     load_properties_from_file(PROP_PATH_FACTORY, "ro.*");
@@ -520,16 +519,14 @@
 }
 
 void start_property_service() {
-    int fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL);
-    if (fd == -1) return;
+    property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+                                    0666, 0, 0, NULL);
+    if (property_set_fd == -1) {
+        ERROR("start_property_service socket creation failed: %s\n", strerror(errno));
+        exit(1);
+    }
 
-    fcntl(fd, F_SETFD, FD_CLOEXEC);
-    fcntl(fd, F_SETFL, O_NONBLOCK);
+    listen(property_set_fd, 8);
 
-    listen(fd, 8);
-    property_set_fd = fd;
-}
-
-int get_property_set_fd() {
-    return property_set_fd;
+    register_epoll_handler(property_set_fd, handle_property_set_fd);
 }
diff --git a/init/property_service.h b/init/property_service.h
index 825a7dd..a27053d 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -20,7 +20,6 @@
 #include <stddef.h>
 #include <sys/system_properties.h>
 
-extern void handle_property_set_fd(void);
 extern void property_init(void);
 extern void property_load_boot_defaults(void);
 extern void load_persist_props(void);
@@ -30,7 +29,6 @@
 extern int __property_get(const char *name, char *value);
 extern int property_set(const char *name, const char *value);
 extern bool properties_initialized();
-int get_property_set_fd(void);
 
 #ifndef __clang__
 extern void __property_get_size_error()
diff --git a/init/readme.txt b/init/readme.txt
index 84afd11..6b9c42d 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -252,11 +252,6 @@
 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.
-
 setprop <name> <value>
    Set system property <name> to <value>. Properties are expanded
    within <value>.
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index 8be4af5..39a466d 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -35,14 +35,10 @@
 #define CRITICAL_CRASH_THRESHOLD    4       /* if we crash >4 times ... */
 #define CRITICAL_CRASH_WINDOW       (4*60)  /* ... in 4 minutes, goto recovery */
 
-static int signal_fd = -1;
-static int signal_recv_fd = -1;
+static int signal_write_fd = -1;
+static int signal_read_fd = -1;
 
-static void sigchld_handler(int s) {
-    write(signal_fd, &s, 1);
-}
-
-std::string DescribeStatus(int status) {
+static std::string DescribeStatus(int status) {
     if (WIFEXITED(status)) {
         return android::base::StringPrintf("exited with status %d", WEXITSTATUS(status));
     } else if (WIFSIGNALED(status)) {
@@ -54,11 +50,14 @@
     }
 }
 
-static int wait_for_one_process() {
+static bool wait_for_one_process() {
     int status;
     pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
-    if (pid <= 0) {
-        return -1;
+    if (pid == 0) {
+        return false;
+    } else if (pid == -1) {
+        ERROR("waitpid failed: %s\n", strerror(errno));
+        return false;
     }
 
     service* svc = service_find_by_pid(pid);
@@ -73,7 +72,7 @@
     NOTICE("%s %s\n", name.c_str(), DescribeStatus(status).c_str());
 
     if (!svc) {
-        return 0;
+        return true;
     }
 
     // TODO: all the code from here down should be a member function on service.
@@ -96,7 +95,7 @@
         list_remove(&svc->slist);
         free(svc->name);
         free(svc);
-        return 0;
+        return true;
     }
 
     svc->pid = 0;
@@ -111,7 +110,7 @@
     // Disabled and reset processes do not get restarted automatically.
     if (svc->flags & (SVC_DISABLED | SVC_RESET))  {
         svc->NotifyStateChange("stopped");
-        return 0;
+        return true;
     }
 
     time_t now = gettime();
@@ -122,7 +121,7 @@
                       "rebooting into recovery mode\n", svc->name,
                       CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
                 android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
-                return 0;
+                return true;
             }
         } else {
             svc->time_crashed = now;
@@ -140,34 +139,47 @@
         cmd->func(cmd->nargs, cmd->args);
     }
     svc->NotifyStateChange("restarting");
-    return 0;
+    return true;
 }
 
-void handle_signal() {
-    // We got a SIGCHLD - reap and restart as needed.
-    char tmp[32];
-    read(signal_recv_fd, tmp, sizeof(tmp));
-    while (!wait_for_one_process()) {
+static void reap_any_outstanding_children() {
+    while (wait_for_one_process()) {
     }
 }
 
-void signal_init() {
+static void handle_signal() {
+    // Clear outstanding requests.
+    char buf[32];
+    read(signal_read_fd, buf, sizeof(buf));
+
+    reap_any_outstanding_children();
+}
+
+static void SIGCHLD_handler(int) {
+    if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {
+        ERROR("write(signal_write_fd) failed: %s\n", strerror(errno));
+    }
+}
+
+void signal_handler_init() {
+    // Create a signalling mechanism for SIGCHLD.
+    int s[2];
+    if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
+        ERROR("socketpair failed: %s\n", strerror(errno));
+        exit(1);
+    }
+
+    signal_write_fd = s[0];
+    signal_read_fd = s[1];
+
+    // Write to signal_write_fd if we catch SIGCHLD.
     struct sigaction act;
     memset(&act, 0, sizeof(act));
-    act.sa_handler = sigchld_handler;
+    act.sa_handler = SIGCHLD_handler;
     act.sa_flags = SA_NOCLDSTOP;
     sigaction(SIGCHLD, &act, 0);
 
-    // Create a signalling mechanism for the sigchld handler.
-    int s[2];
-    if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == 0) {
-        signal_fd = s[0];
-        signal_recv_fd = s[1];
-    }
+    reap_any_outstanding_children();
 
-    handle_signal();
-}
-
-int get_signal_fd() {
-    return signal_recv_fd;
+    register_epoll_handler(signal_read_fd, handle_signal);
 }
diff --git a/init/signal_handler.h b/init/signal_handler.h
index b092ccb..449b4af 100644
--- a/init/signal_handler.h
+++ b/init/signal_handler.h
@@ -17,8 +17,6 @@
 #ifndef _INIT_SIGNAL_HANDLER_H_
 #define _INIT_SIGNAL_HANDLER_H_
 
-void signal_init(void);
-void handle_signal(void);
-int get_signal_fd(void);
+void signal_handler_init(void);
 
 #endif
diff --git a/init/util.cpp b/init/util.cpp
index 3b49b30..9343145 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -179,9 +179,13 @@
 int write_file(const char* path, const char* content) {
     int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0600));
     if (fd == -1) {
-        return -errno;
+        NOTICE("write_file: Unable to open '%s': %s\n", path, strerror(errno));
+        return -1;
     }
-    int result = android::base::WriteStringToFd(content, fd) ? 0 : -errno;
+    int result = android::base::WriteStringToFd(content, fd) ? 0 : -1;
+    if (result == -1) {
+        NOTICE("write_file: Unable to write to '%s': %s\n", path, strerror(errno));
+    }
     TEMP_FAILURE_RETRY(close(fd));
     return result;
 }
@@ -375,27 +379,31 @@
 
 void open_devnull_stdio(void)
 {
-    int fd;
-    static const char *name = "/dev/__null__";
-    if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
-        fd = open(name, O_RDWR);
-        unlink(name);
-        if (fd >= 0) {
-            dup2(fd, 0);
-            dup2(fd, 1);
-            dup2(fd, 2);
-            if (fd > 2) {
-                close(fd);
-            }
-            return;
+    // Try to avoid the mknod() call if we can. Since SELinux makes
+    // a /dev/null replacement available for free, let's use it.
+    int fd = open("/sys/fs/selinux/null", O_RDWR);
+    if (fd == -1) {
+        // OOPS, /sys/fs/selinux/null isn't available, likely because
+        // /sys/fs/selinux isn't mounted. Fall back to mknod.
+        static const char *name = "/dev/__null__";
+        if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
+            fd = open(name, O_RDWR);
+            unlink(name);
+        }
+        if (fd == -1) {
+            exit(1);
         }
     }
 
-    exit(1);
+    dup2(fd, 0);
+    dup2(fd, 1);
+    dup2(fd, 2);
+    if (fd > 2) {
+        close(fd);
+    }
 }
 
-void import_kernel_cmdline(int in_qemu,
-                           void (*import_kernel_nv)(char *name, int in_qemu))
+void import_kernel_cmdline(bool in_qemu, std::function<void(char*,bool)> import_kernel_nv)
 {
     char cmdline[2048];
     char *ptr;
diff --git a/init/util.h b/init/util.h
index 8fec7a8..6864acf 100644
--- a/init/util.h
+++ b/init/util.h
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 
 #include <string>
+#include <functional>
 
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
 
@@ -57,7 +58,7 @@
 void remove_link(const char *oldpath, const char *newpath);
 int wait_for_file(const char *filename, int timeout);
 void open_devnull_stdio(void);
-void import_kernel_cmdline(int in_qemu, void (*import_kernel_nv)(char *name, int in_qemu));
+void import_kernel_cmdline(bool in_qemu, std::function<void(char*,bool)>);
 int make_dir(const char *path, mode_t mode);
 int restorecon(const char *pathname);
 int restorecon_recursive(const char *pathname);
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index b875efd..54cace9 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -57,7 +57,6 @@
 libbacktrace_shared_libraries := \
 	libbase \
 	libunwind \
-	libunwind-ptrace \
 
 libbacktrace_shared_libraries_host := \
 	liblog \
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index c636196..9dc15d1 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -111,8 +111,9 @@
 
 LOCAL_SRC_FILES_arm += arch-arm/memset32.S
 LOCAL_SRC_FILES_arm64 += arch-arm64/android_memset.S
-LOCAL_SRC_FILES_mips += arch-mips/android_memset.S
-LOCAL_SRC_FILES_mips64 += arch-mips/android_memset.S
+
+LOCAL_SRC_FILES_mips += arch-mips/android_memset.c
+LOCAL_SRC_FILES_mips64 += arch-mips/android_memset.c
 
 LOCAL_SRC_FILES_x86 += \
         arch-x86/android_memset16.S \
diff --git a/libcutils/arch-mips/android_memset.S b/libcutils/arch-mips/android_memset.S
deleted file mode 100644
index 6811de0..0000000
--- a/libcutils/arch-mips/android_memset.S
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright (c) 2009
- *      MIPS Technologies, Inc., California.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/************************************************************************
- *
- *  memset.S, version "64h" with 1 cache line horizon for "pref 30" and 14 nops
- *  Version: "043009"
- *
- ************************************************************************/
-
-
-/************************************************************************
- *  Include files
- ************************************************************************/
-
-#include <machine/asm.h>
-#define END(f) .cfi_endproc; .size f, .-f; .end f
-
-/*
- * This routine could be optimized for MIPS64. The current code only
- * uses MIPS32 instructions.
- */
-
-#if defined(__MIPSEB__)
-#  define SWHI	swl		/* high part is left in big-endian	*/
-#  define SWLO	swr		/* low part is right in big-endian	*/
-#endif
-
-#if defined(__MIPSEL__)
-#  define SWHI	swr		/* high part is right in little-endian	*/
-#  define SWLO	swl		/* low part is left in little-endian	*/
-#endif
-
-#if !(defined(XGPROF) || defined(XPROF))
-#undef SETUP_GP
-#define SETUP_GP
-#endif
-
-#ifdef NDEBUG
-#define DBG #
-#else
-#define DBG
-#endif
-
-/*
- * void android_memset16(uint16_t* dst, uint16_t value, size_t size);
- */
-
-LEAF(android_memset16,0)
-	.set noreorder
-DBG	/* Check parameters */
-DBG	andi	t0,a0,1			# a0 must be halfword aligned
-DBG	tne	t0,zero
-DBG	andi	t2,a2,1			# a2 must be even
-DBG	tne	t2,zero
-
-#ifdef FIXARGS
-	# ensure count is even
-#if (__mips==32) && (__mips_isa_rev>=2)
-	ins	a2,zero,0,1
-#else
-	ori	a2,1
-	xori	a2,1
-#endif
-#endif
-
-#if (__mips==32) && (__mips_isa_rev>=2)
-	ins	a1,a1,16,16
-#else
-	andi	a1,0xffff
-	sll	t3,a1,16
-	or	a1,t3
-#endif
-
-	beqz	a2,.Ldone
-	 andi	t1,a0,2
-	beqz	t1,.Lalignok
-	 addu	t0,a0,a2		# t0 is the "past the end" address
-	sh	a1,0(a0)		# store one halfword to get aligned
-	addu	a0,2
-	subu	a2,2
-.Lalignok:
-	slti	t1,a2,4			# .Laligned for 4 or more bytes
-	beqz	t1,.Laligned
-	 sne	t1,a2,2			# one more halfword?
-	bnez	t1,.Ldone
-	 nop
-	sh	a1,0(a0)
-.Ldone:
-	j	ra
-	 nop
-	.set reorder
-END(android_memset16)
-
-/*
- * void android_memset32(uint32_t* dst, uint32_t value, size_t size);
- */
-
-LEAF(android_memset32,0)
-	.set noreorder
-DBG	/* Check parameters */
-DBG	andi	t0,a0,3			# a0 must be word aligned
-DBG	tne	t0,zero
-DBG	andi	t2,a2,3			# a2 must be a multiple of 4 bytes
-DBG	tne	t2,zero
-
-#ifdef FIXARGS
-	# ensure count is a multiple of 4
-#if (__mips==32) && (__mips_isa_rev>=2)
-	ins	$a2,$0,0,2
-#else
-	ori	a2,3
-	xori	a2,3
-#endif
-#endif
-
-	bnez	a2,.Laligned		# any work to do?
-	 addu	t0,a0,a2		# t0 is the "past the end" address
-
-	j	ra
-	 nop
-	.set reorder
-END(android_memset32)
-
-LEAF(memset,0)
-
-	.set	noreorder
-	.set	noat
-
-	addu	t0,a0,a2		# t0 is the "past the end" address
-	slti	AT,a2,4			# is a2 less than 4?
-	bne	AT,zero,.Llast4		# if yes, go to last4
-	 move	v0,a0			# memset returns the dst pointer
-
-	beq	a1,zero,.Lset0
-	 subu	v1,zero,a0
-
-	# smear byte into 32 bit word
-#if (__mips==32) && (__mips_isa_rev>=2)
-	ins     a1, a1, 8, 8        # Replicate fill byte into half-word.
-	ins     a1, a1, 16, 16      # Replicate fill byte into word.
-#else
-	and	a1,0xff
-	sll	AT,a1,8
-	or	a1,AT
-	sll	AT,a1,16
-	or	a1,AT
-#endif
-
-.Lset0:
-	andi	v1,v1,0x3		# word-unaligned address?
-	beq	v1,zero,.Laligned	# v1 is the unalignment count
-	 subu	a2,a2,v1
-	SWHI	a1,0(a0)
-	addu	a0,a0,v1
-
-# Here we have the "word-aligned" a0 (until the "last4")
-.Laligned:
-	andi	t8,a2,0x3f	# any 64-byte chunks?
-				# t8 is the byte count past 64-byte chunks
-	beq	a2,t8,.Lchk8w	# when a2==t8, no 64-byte chunks
-				# There will be at most 1 32-byte chunk then
-	 subu	a3,a2,t8	# subtract from a2 the reminder
-				# Here a3 counts bytes in 16w chunks
-	addu	a3,a0,a3	# Now a3 is the final dst after 64-byte chunks
-
-# Find out, if there are any 64-byte chunks after which will be still at least
-# 96 bytes left. The value "96" is calculated as needed buffer for
-# "pref 30,64(a0)" prefetch, which can be used as "pref 30,0(a0)" after
-# incrementing "a0" by 64.
-# For "a2" below 160 there will be no such "pref 30 safe" 64-byte chunk.
-#
-	sltiu	v1,a2,160
-	bgtz	v1,.Lloop16w_nopref30	# skip "pref 30,0(a0)"
-	 subu	t7,a2,96	# subtract "pref 30 unsafe" region
-		# below we have at least 1 64-byte chunk which is "pref 30 safe"
-	andi	t6,t7,0x3f	# t6 is past "64-byte safe chunks" reminder
-	subu	t5,t7,t6	# subtract from t7 the reminder
-				# Here t5 counts bytes in 16w "safe" chunks
-	addu	t4,a0,t5	# Now t4 is the dst after 64-byte "safe" chunks
-
-# Don't use "pref 30,0(a0)" for a0 in a "middle" of a cache line
-#	pref	30,0(a0)
-# Here we are in the region, where it is safe to use "pref 30,64(a0)"
-.Lloop16w:
-	addiu	a0,a0,64
-	pref	30,-32(a0)	# continue setting up the dest, addr 64-32
-	sw	a1,-64(a0)
-	sw	a1,-60(a0)
-	sw	a1,-56(a0)
-	sw	a1,-52(a0)
-	sw	a1,-48(a0)
-	sw	a1,-44(a0)
-	sw	a1,-40(a0)
-	sw	a1,-36(a0)
-	nop
-	nop			# the extra nop instructions help to balance
-	nop			# cycles needed for "store" + "fill" + "evict"
-	nop			# For 64byte store there are needed 8 fill
-	nop			# and 8 evict cycles, i.e. at least 32 instr.
-	nop
-	nop
-	pref	30,0(a0)	# continue setting up the dest, addr 64-0
-	sw	a1,-32(a0)
-	sw	a1,-28(a0)
-	sw	a1,-24(a0)
-	sw	a1,-20(a0)
-	sw	a1,-16(a0)
-	sw	a1,-12(a0)
-	sw	a1,-8(a0)
-	sw	a1,-4(a0)
-	nop
-	nop
-	nop
-	nop			# NOTE: adding 14 nop-s instead of 12 nop-s
-	nop			# gives better results for "fast" memory
-	nop
-	bne	a0,t4,.Lloop16w
-	 nop
-
-	beq	a0,a3,.Lchk8w	# maybe no more 64-byte chunks?
-	 nop			# this "delayed slot" is useless ...
-
-.Lloop16w_nopref30:	# there could be up to 3 "64-byte nopref30" chunks
-	addiu	a0,a0,64
-	sw	a1,-64(a0)
-	sw	a1,-60(a0)
-	sw	a1,-56(a0)
-	sw	a1,-52(a0)
-	sw	a1,-48(a0)
-	sw	a1,-44(a0)
-	sw	a1,-40(a0)
-	sw	a1,-36(a0)
-	sw	a1,-32(a0)
-	sw	a1,-28(a0)
-	sw	a1,-24(a0)
-	sw	a1,-20(a0)
-	sw	a1,-16(a0)
-	sw	a1,-12(a0)
-	sw	a1,-8(a0)
-	bne	a0,a3,.Lloop16w_nopref30
-	 sw	a1,-4(a0)
-
-.Lchk8w:		# t8 here is the byte count past 64-byte chunks
-
-	andi	t7,t8,0x1f	# is there a 32-byte chunk?
-				# the t7 is the reminder count past 32-bytes
-	beq	t8,t7,.Lchk1w	# when t8==t7, no 32-byte chunk
-	 move	a2,t7
-
-	sw	a1,0(a0)
-	sw	a1,4(a0)
-	sw	a1,8(a0)
-	sw	a1,12(a0)
-	sw	a1,16(a0)
-	sw	a1,20(a0)
-	sw	a1,24(a0)
-	sw	a1,28(a0)
-	addiu	a0,a0,32
-
-.Lchk1w:
-	andi	t8,a2,0x3	# now t8 is the reminder past 1w chunks
-	beq	a2,t8,.Llast4aligned
-	 subu	a3,a2,t8	# a3 is the count of bytes in 1w chunks
-	addu	a3,a0,a3	# now a3 is the dst address past the 1w chunks
-
-# copying in words (4-byte chunks)
-.LwordCopy_loop:
-	addiu	a0,a0,4
-	bne	a0,a3,.LwordCopy_loop
-	 sw	a1,-4(a0)
-
-# store last 0-3 bytes
-# this will repeat the last store if the memset finishes on a word boundary
-.Llast4aligned:
-	j	ra
-	 SWLO	a1,-1(t0)
-
-.Llast4:
-	beq	a0,t0,.Llast4e
-.Llast4l:
-	 addiu	a0,a0,1
-	bne	a0,t0,.Llast4l
-	 sb	a1,-1(a0)
-.Llast4e:
-	j	ra
-	 nop
-
-	.set	at
-	.set	reorder
-
-END(memset)
-
-
-/************************************************************************
- *  Implementation : Static functions
- ************************************************************************/
diff --git a/libcutils/arch-mips/android_memset.c b/libcutils/arch-mips/android_memset.c
new file mode 100644
index 0000000..a6b7496
--- /dev/null
+++ b/libcutils/arch-mips/android_memset.c
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+/* generic C version for any machine */
+
+#include <cutils/memory.h>
+
+void android_memset16(uint16_t* dst, uint16_t value, size_t size)
+{
+   /* optimized version of
+      size >>= 1;
+      while (size--)
+        *dst++ = value;
+   */
+
+   size >>= 1;
+   if (((uintptr_t)dst & 2) && size) {
+      /* fill unpaired first elem separately */
+      *dst++ = value;
+      size--;
+   }
+   /* dst is now 32-bit-aligned */
+   /* fill body with 32-bit pairs */
+   uint32_t value32 = (value << 16) | value;
+   android_memset32((uint32_t*) dst, value32, size<<1);
+   if (size & 1) {
+      dst[size-1] = value;  /* fill unpaired last elem */
+   }
+}
+
+
+void android_memset32(uint32_t* dst, uint32_t value, size_t size)
+{
+   /* optimized version of
+      size >>= 2;
+      while (size--)
+         *dst++ = value;
+   */
+
+   size >>= 2;
+   if (((uintptr_t)dst & 4) && size) {
+      /* fill unpaired first 32-bit elem separately */
+      *dst++ = value;
+      size--;
+   }
+   /* dst is now 64-bit aligned */
+   /* fill body with 64-bit pairs */
+   uint64_t value64 = (((uint64_t)value)<<32) | value;
+   uint64_t* dst64 = (uint64_t*)dst;
+
+   while (size >= 12) {
+      dst64[0] = value64;
+      dst64[1] = value64;
+      dst64[2] = value64;
+      dst64[3] = value64;
+      dst64[4] = value64;
+      dst64[5] = value64;
+      size  -= 12;
+      dst64 += 6;
+   }
+
+   /* fill remainder with original 32-bit single-elem loop */
+   dst = (uint32_t*) dst64;
+   while (size--) {
+      *dst++ = value;
+   }
+
+}
diff --git a/libcutils/dir_hash.c b/libcutils/dir_hash.c
deleted file mode 100644
index 098b5db..0000000
--- a/libcutils/dir_hash.c
+++ /dev/null
@@ -1,335 +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.
- */
-
-#include <dirent.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sha1.h>
-#include <unistd.h>
-#include <limits.h>
-
-#include <sys/stat.h>
-
-#include <netinet/in.h>
-#include <resolv.h>
-
-#include <cutils/dir_hash.h>
-
-/**
- * Copies, if it fits within max_output_string bytes, into output_string
- * a hash of the contents, size, permissions, uid, and gid of the file
- * specified by path, using the specified algorithm.  Returns the length
- * of the output string, or a negative number if the buffer is too short.
- */
-int get_file_hash(HashAlgorithm algorithm, const char *path,
-                  char *output_string, size_t max_output_string) {
-    SHA1_CTX context;
-    struct stat sb;
-    unsigned char md[SHA1_DIGEST_LENGTH];
-    int used;
-    size_t n;
-
-    if (algorithm != SHA_1) {
-        errno = EINVAL;
-        return -1;
-    }
-
-    if (stat(path, &sb) != 0) {
-        return -1;
-    }
-
-    if (S_ISLNK(sb.st_mode)) {
-        char buf[PATH_MAX];
-        int len;
-
-        len = readlink(path, buf, sizeof(buf));
-        if (len < 0) {
-            return -1;
-        }
-
-        SHA1Init(&context);
-        SHA1Update(&context, (unsigned char *) buf, len);
-        SHA1Final(md, &context);
-    } else if (S_ISREG(sb.st_mode)) {
-        char buf[10000];
-        FILE *f = fopen(path, "rb");
-        int len;
-
-        if (f == NULL) {
-            return -1;
-        }
-
-        SHA1Init(&context);
-
-        while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
-            SHA1Update(&context, (unsigned char *) buf, len);
-        }
-
-        if (ferror(f)) {
-            fclose(f);
-            return -1;
-        }
-
-        fclose(f);
-        SHA1Final(md, &context);
-    }
-
-    if (S_ISLNK(sb.st_mode) || S_ISREG(sb.st_mode)) {
-        used = b64_ntop(md, SHA1_DIGEST_LENGTH,
-                        output_string, max_output_string);
-        if (used < 0) {
-            errno = ENOSPC;
-            return -1;
-        }
-
-        n = snprintf(output_string + used, max_output_string - used,
-                     " %d 0%o %d %d", (int) sb.st_size, sb.st_mode,
-                     (int) sb.st_uid, (int) sb.st_gid);
-    } else {
-        n = snprintf(output_string, max_output_string,
-                     "- - 0%o %d %d", sb.st_mode,
-                     (int) sb.st_uid, (int) sb.st_gid);
-    }
-
-    if (n >= max_output_string - used) {
-        errno = ENOSPC;
-        return -(used + n);
-    }
-
-    return used + n;
-}
-
-struct list {
-    char *name;
-    struct list *next;
-};
-
-static int cmp(const void *a, const void *b) {
-    struct list *const *ra = a;
-    struct list *const *rb = b;
-
-    return strcmp((*ra)->name, (*rb)->name);
-}
-
-static int recurse(HashAlgorithm algorithm, const char *directory_path,
-                    struct list **out) {
-    struct list *list = NULL;
-    struct list *f;
-
-    struct dirent *de;
-    DIR *d = opendir(directory_path);
-
-    if (d == NULL) {
-        return -1;
-    }
-
-    while ((de = readdir(d)) != NULL) {
-        if (strcmp(de->d_name, ".") == 0) {
-            continue;
-        }
-        if (strcmp(de->d_name, "..") == 0) {
-            continue;
-        }
-
-        char *name = malloc(strlen(de->d_name) + 1);
-        struct list *node = malloc(sizeof(struct list));
-
-        if (name == NULL || node == NULL) {
-            struct list *next;
-            for (f = list; f != NULL; f = next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-
-            free(name);
-            free(node);
-            closedir(d);
-            return -1;
-        }
-
-        strcpy(name, de->d_name);
-
-        node->name = name;
-        node->next = list;
-        list = node;
-    }
-
-    closedir(d);
-
-    for (f = list; f != NULL; f = f->next) {
-        struct stat sb;
-        char *name;
-        char outstr[NAME_MAX + 100];
-        char *keep;
-        struct list *res;
-
-        name = malloc(strlen(f->name) + strlen(directory_path) + 2);
-        if (name == NULL) {
-            struct list *next;
-            for (f = list; f != NULL; f = f->next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-            for (f = *out; f != NULL; f = f->next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-            *out = NULL;
-            return -1;
-        }
-
-        sprintf(name, "%s/%s", directory_path, f->name);
-
-        int len = get_file_hash(algorithm, name,
-                                outstr, sizeof(outstr));
-        if (len < 0) {
-            // should not happen
-            return -1;
-        }
-
-        keep = malloc(len + strlen(name) + 3);
-        res = malloc(sizeof(struct list));
-
-        if (keep == NULL || res == NULL) {
-            struct list *next;
-            for (f = list; f != NULL; f = f->next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-            for (f = *out; f != NULL; f = f->next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-            *out = NULL;
-
-            free(keep);
-            free(res);
-            return -1;
-        }
-
-        sprintf(keep, "%s %s\n", name, outstr);
-
-        res->name = keep;
-        res->next = *out;
-        *out = res;
-
-        if ((stat(name, &sb) == 0) && S_ISDIR(sb.st_mode)) {
-            if (recurse(algorithm, name, out) < 0) {
-                struct list *next;
-                for (f = list; f != NULL; f = next) {
-                    next = f->next;
-                    free(f->name);
-                    free(f);
-                }
-
-                return -1;
-            }
-        }
-    }
-
-    struct list *next;
-    for (f = list; f != NULL; f = next) {
-        next = f->next;
-
-        free(f->name);
-        free(f);
-    }
-}
-
-/**
- * Allocates a string containing the names and hashes of all files recursively
- * reached under the specified directory_path, using the specified algorithm.
- * The string is returned as *output_string; the return value is the length
- * of the string, or a negative number if there was a failure.
- */
-int get_recursive_hash_manifest(HashAlgorithm algorithm,
-                                const char *directory_path,
-                                char **output_string) {
-    struct list *out = NULL;
-    struct list *r;
-    struct list **list;
-    int count = 0;
-    int len = 0;
-    int retlen = 0;
-    int i;
-    char *buf;
-    
-    if (recurse(algorithm, directory_path, &out) < 0) {
-        return -1;
-    }
-
-    for (r = out; r != NULL; r = r->next) {
-        count++;
-        len += strlen(r->name);
-    }
-
-    list = malloc(count * sizeof(struct list *));
-    if (list == NULL) {
-        struct list *next;
-        for (r = out; r != NULL; r = next) {
-            next = r->next;
-            free(r->name);
-            free(r);
-        }
-        return -1;
-    }
-
-    count = 0;
-    for (r = out; r != NULL; r = r->next) {
-        list[count++] = r;
-    }
-
-    qsort(list, count, sizeof(struct list *), cmp);
-
-    buf = malloc(len + 1);
-    if (buf == NULL) {
-        struct list *next;
-        for (r = out; r != NULL; r = next) {
-            next = r->next;
-            free(r->name);
-            free(r);
-        }
-        free(list);
-        return -1;
-    }
-
-    for (i = 0; i < count; i++) {
-        int n = strlen(list[i]->name);
-
-        strcpy(buf + retlen, list[i]->name);
-        retlen += n;
-    }
-
-    free(list);
-
-    struct list *next;
-    for (r = out; r != NULL; r = next) {
-        next = r->next;
-
-        free(r->name);
-        free(r);
-    }
-
-    *output_string = buf;
-    return retlen;
-}
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 659f614..9f8023e 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -19,11 +19,54 @@
 ** by the device side of adb.
 */
 
+#define LOG_TAG "fs_config"
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
 #include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 
+#include <log/log.h>
 #include <private/android_filesystem_config.h>
+#include <utils/Compat.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* The following structure is stored little endian */
+struct fs_path_config_from_file {
+    uint16_t len;
+    uint16_t mode;
+    uint16_t uid;
+    uint16_t gid;
+    uint64_t capabilities;
+    char prefix[];
+} __attribute__((__aligned__(sizeof(uint64_t))));
+
+/* My kingdom for <endian.h> */
+static inline uint16_t get2LE(const uint8_t* src)
+{
+    return src[0] | (src[1] << 8);
+}
+
+static inline uint64_t get8LE(const uint8_t* src)
+{
+    uint32_t low, high;
+
+    low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+    high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
+    return ((uint64_t) high << 32) | (uint64_t) low;
+}
+
+#define ALIGN(x, alignment) ( ((x) + ((alignment) - 1)) & ~((alignment) - 1) )
 
 /* Rules for directories.
 ** These rules are applied based on "first match", so they
@@ -61,6 +104,9 @@
 ** way up to the root. Prefixes ending in * denotes wildcard
 ** and will allow partial matches.
 */
+static const char conf_dir[] = "/system/etc/fs_config_dirs";
+static const char conf_file[] = "/system/etc/fs_config_files";
+
 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" },
@@ -68,6 +114,8 @@
     { 00550, AID_DHCP,      AID_SHELL,     0, "system/etc/dhcpcd/dhcpcd-run-hooks" },
     { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/ppp/*" },
     { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/rc.*" },
+    { 00444, AID_ROOT,      AID_ROOT,      0, conf_dir + 1 },
+    { 00444, AID_ROOT,      AID_ROOT,      0, conf_file + 1 },
     { 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/*" },
@@ -101,30 +149,102 @@
     { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
 };
 
+static int fs_config_open(int dir)
+{
+    int fd = -1;
+
+    const char *out = getenv("OUT");
+    if (out && *out) {
+        char *name = NULL;
+        asprintf(&name, "%s%s", out, dir ? conf_dir : conf_file);
+        if (name) {
+            fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_BINARY));
+            free(name);
+        }
+    }
+    if (fd < 0) {
+        fd = TEMP_FAILURE_RETRY(open(dir ? conf_dir : conf_file, O_RDONLY | O_BINARY));
+    }
+    return fd;
+}
+
+static bool fs_config_cmp(bool dir, const char *prefix, size_t len,
+                                    const char *path, size_t plen)
+{
+    if (dir) {
+        if (plen < len) {
+            return false;
+        }
+    } else {
+        /* If name ends in * then allow partial matches. */
+        if (prefix[len - 1] == '*') {
+            return !strncmp(prefix, path, len - 1);
+        }
+        if (plen != len) {
+            return false;
+        }
+    }
+    return !strncmp(prefix, path, len);
+}
+
 void fs_config(const char *path, int dir,
                unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities)
 {
     const struct fs_path_config *pc;
-    int plen;
+    int fd, plen;
 
     if (path[0] == '/') {
         path++;
     }
 
-    pc = dir ? android_dirs : android_files;
     plen = strlen(path);
-    for(; pc->prefix; pc++){
-        int len = strlen(pc->prefix);
-        if (dir) {
-            if(plen < len) continue;
-            if(!strncmp(pc->prefix, path, len)) break;
-            continue;
+
+    fd = fs_config_open(dir);
+    if (fd >= 0) {
+        struct fs_path_config_from_file header;
+
+        while (TEMP_FAILURE_RETRY(read(fd, &header, sizeof(header))) == sizeof(header)) {
+            char *prefix;
+            uint16_t host_len = get2LE((const uint8_t *)&header.len);
+            ssize_t len, remainder = host_len - sizeof(header);
+            if (remainder <= 0) {
+                ALOGE("%s len is corrupted", dir ? conf_dir : conf_file);
+                break;
+            }
+            prefix = calloc(1, remainder);
+            if (!prefix) {
+                ALOGE("%s out of memory", dir ? conf_dir : conf_file);
+                break;
+            }
+            if (TEMP_FAILURE_RETRY(read(fd, prefix, remainder)) != remainder) {
+                free(prefix);
+                ALOGE("%s prefix is truncated", dir ? conf_dir : conf_file);
+                break;
+            }
+            len = strnlen(prefix, remainder);
+            if (len >= remainder) { /* missing a terminating null */
+                free(prefix);
+                ALOGE("%s is corrupted", dir ? conf_dir : conf_file);
+                break;
+            }
+            if (fs_config_cmp(dir, prefix, len, path, plen)) {
+                free(prefix);
+                close(fd);
+                *uid = get2LE((const uint8_t *)&(header.uid));
+                *gid = get2LE((const uint8_t *)&(header.gid));
+                *mode = (*mode & (~07777)) | get2LE((const uint8_t *)&(header.mode));
+                *capabilities = get8LE((const uint8_t *)&(header.capabilities));
+                return;
+            }
+            free(prefix);
         }
-        /* If name ends in * then allow partial matches. */
-        if (pc->prefix[len -1] == '*') {
-            if(!strncmp(pc->prefix, path, len - 1)) break;
-        } else if (plen == len){
-            if(!strncmp(pc->prefix, path, len)) break;
+        close(fd);
+    }
+
+    pc = dir ? android_dirs : android_files;
+    for(; pc->prefix; pc++){
+        if (fs_config_cmp(dir, pc->prefix, strlen(pc->prefix), path, plen)) {
+            break;
         }
     }
     *uid = pc->uid;
@@ -132,3 +252,22 @@
     *mode = (*mode & (~07777)) | pc->mode;
     *capabilities = pc->capabilities;
 }
+
+ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc)
+{
+    struct fs_path_config_from_file *p = (struct fs_path_config_from_file *)buffer;
+    size_t len = ALIGN(sizeof(*p) + strlen(pc->prefix) + 1, sizeof(uint64_t));
+
+    if ((length < len) || (len > UINT16_MAX)) {
+        return -ENOSPC;
+    }
+    memset(p, 0, len);
+    uint16_t host_len = len;
+    p->len = get2LE((const uint8_t *)&host_len);
+    p->mode = get2LE((const uint8_t *)&(pc->mode));
+    p->uid = get2LE((const uint8_t *)&(pc->uid));
+    p->gid = get2LE((const uint8_t *)&(pc->gid));
+    p->capabilities = get8LE((const uint8_t *)&(pc->capabilities));
+    strcpy(p->prefix, pc->prefix);
+    return len;
+}
diff --git a/libcutils/trace-dev.c b/libcutils/trace-dev.c
index 4396625..a06987e 100644
--- a/libcutils/trace-dev.c
+++ b/libcutils/trace-dev.c
@@ -18,11 +18,11 @@
 #include <fcntl.h>
 #include <limits.h>
 #include <pthread.h>
+#include <stdatomic.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
-#include <cutils/atomic.h>
 #include <cutils/compiler.h>
 #include <cutils/properties.h>
 #include <cutils/trace.h>
@@ -37,11 +37,11 @@
  */
 #define ATRACE_MESSAGE_LENGTH 1024
 
-volatile int32_t        atrace_is_ready      = 0;
+atomic_bool             atrace_is_ready      = ATOMIC_VAR_INIT(false);
 int                     atrace_marker_fd     = -1;
 uint64_t                atrace_enabled_tags  = ATRACE_TAG_NOT_READY;
 static bool             atrace_is_debuggable = false;
-static volatile int32_t atrace_is_enabled    = 1;
+static atomic_bool      atrace_is_enabled    = ATOMIC_VAR_INIT(true);
 static pthread_once_t   atrace_once_control  = PTHREAD_ONCE_INIT;
 static pthread_mutex_t  atrace_tags_mutex    = PTHREAD_MUTEX_INITIALIZER;
 
@@ -58,7 +58,7 @@
 // the Zygote process from tracing.
 void atrace_set_tracing_enabled(bool enabled)
 {
-    android_atomic_release_store(enabled ? 1 : 0, &atrace_is_enabled);
+    atomic_store_explicit(&atrace_is_enabled, enabled, memory_order_release);
     atrace_update_tags();
 }
 
@@ -155,8 +155,8 @@
 void atrace_update_tags()
 {
     uint64_t tags;
-    if (CC_UNLIKELY(android_atomic_acquire_load(&atrace_is_ready))) {
-        if (android_atomic_acquire_load(&atrace_is_enabled)) {
+    if (CC_UNLIKELY(atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
+        if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
             tags = atrace_get_property();
             pthread_mutex_lock(&atrace_tags_mutex);
             atrace_enabled_tags = tags;
@@ -183,7 +183,7 @@
     atrace_enabled_tags = atrace_get_property();
 
 done:
-    android_atomic_release_store(1, &atrace_is_ready);
+    atomic_store_explicit(&atrace_is_ready, true, memory_order_release);
 }
 
 void atrace_setup()
diff --git a/libcutils/trace-host.c b/libcutils/trace-host.c
index b87e543..6478e3e 100644
--- a/libcutils/trace-host.c
+++ b/libcutils/trace-host.c
@@ -20,7 +20,7 @@
 #define __unused __attribute__((__unused__))
 #endif
 
-volatile int32_t        atrace_is_ready      = 1;
+atomic_bool             atrace_is_ready      = ATOMIC_VAR_INIT(true);
 int                     atrace_marker_fd     = -1;
 uint64_t                atrace_enabled_tags  = 0;
 
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index df67123..2e09192 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -28,7 +28,7 @@
         return def;
     }
     {
-        static const char log_namespace[] = "log.tag.";
+        static const char log_namespace[] = "persist.log.tag.";
         char key[sizeof(log_namespace) + strlen(tag)];
 
         strcpy(key, log_namespace);
@@ -37,6 +37,9 @@
         if (__system_property_get(key + 8, buf) <= 0) {
             buf[0] = '\0';
         }
+        if (!buf[0] && __system_property_get(key, buf) <= 0) {
+            buf[0] = '\0';
+        }
     }
     switch (toupper(buf[0])) {
         case 'V': return ANDROID_LOG_VERBOSE;
@@ -53,17 +56,6 @@
 
 int __android_log_is_loggable(int prio, const char *tag, int def)
 {
-    static char user;
-    int logLevel;
-
-    if (user == 0) {
-        char buf[PROP_VALUE_MAX];
-        if (__system_property_get("ro.build.type", buf) <= 0) {
-            buf[0] = '\0';
-        }
-        user = strcmp(buf, "user") ? -1 : 1;
-    }
-
-    logLevel = (user == 1) ? def : __android_log_level(tag, def);
+    int logLevel = __android_log_level(tag, def);
     return logLevel >= 0 && prio >= logLevel;
 }
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 7ba4c8e..0f01542 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -26,6 +26,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <inttypes.h>
 #include <sys/param.h>
 
 #include <log/logd.h>
@@ -432,7 +433,7 @@
 
     low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
     high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
-    return ((long long) high << 32) | (long long) low;
+    return ((uint64_t) high << 32) | (uint64_t) low;
 }
 
 
@@ -490,7 +491,7 @@
     case EVENT_TYPE_LONG:
         /* 64-bit signed long */
         {
-            long long lval;
+            uint64_t lval;
 
             if (eventDataLen < 8)
                 return -1;
@@ -498,7 +499,30 @@
             eventData += 8;
             eventDataLen -= 8;
 
-            outCount = snprintf(outBuf, outBufLen, "%lld", lval);
+            outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
+            if (outCount < outBufLen) {
+                outBuf += outCount;
+                outBufLen -= outCount;
+            } else {
+                /* halt output */
+                goto no_room;
+            }
+        }
+        break;
+    case EVENT_TYPE_FLOAT:
+        /* float */
+        {
+            uint32_t ival;
+            float fval;
+
+            if (eventDataLen < 4)
+                return -1;
+            ival = get4LE(eventData);
+            fval = *(float*)&ival;
+            eventData += 4;
+            eventDataLen -= 4;
+
+            outCount = snprintf(outBuf, outBufLen, "%f", fval);
             if (outCount < outBufLen) {
                 outBuf += outCount;
                 outBufLen -= outCount;
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 979aded..b594634 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -266,3 +266,17 @@
     android_logger_list_free(logger_list);
 }
 BENCHMARK(BM_log_delay);
+
+/*
+ *	Measure the time it takes for __android_log_is_loggable.
+ */
+static void BM_is_loggable(int iters) {
+    StartBenchmarkTiming();
+
+    for (int i = 0; i < iters; ++i) {
+        __android_log_is_loggable(ANDROID_LOG_WARN, "logd", ANDROID_LOG_VERBOSE);
+    }
+
+    StopBenchmarkTiming();
+}
+BENCHMARK(BM_is_loggable);
diff --git a/libnetutils/Android.mk b/libnetutils/Android.mk
index 1f61511..2060df4 100644
--- a/libnetutils/Android.mk
+++ b/libnetutils/Android.mk
@@ -17,3 +17,10 @@
 LOCAL_CFLAGS := -Werror
 
 include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := dhcptool.c
+LOCAL_SHARED_LIBRARIES := libnetutils
+LOCAL_MODULE := dhcptool
+LOCAL_MODULE_TAGS := debug
+include $(BUILD_EXECUTABLE)
diff --git a/libnetutils/dhcptool.c b/libnetutils/dhcptool.c
new file mode 100644
index 0000000..352ac5e
--- /dev/null
+++ b/libnetutils/dhcptool.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright 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 <errno.h>
+#include <error.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <netutils/dhcp.h>
+#include <netutils/ifc.h>
+
+int main(int argc, char* argv[]) {
+  if (argc != 2) {
+    error(EXIT_FAILURE, 0, "usage: %s INTERFACE", argv[0]);
+  }
+
+  char* interface = argv[1];
+  if (ifc_init()) {
+    error(EXIT_FAILURE, errno, "dhcptool %s: ifc_init failed", interface);
+  }
+
+  int rc = do_dhcp(interface);
+  if (rc) {
+    error(0, errno, "dhcptool %s: do_dhcp failed", interface);
+  }
+
+  ifc_close();
+
+  return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/libsparse/sparse.c b/libsparse/sparse.c
index 65c09e0..311678a 100644
--- a/libsparse/sparse.c
+++ b/libsparse/sparse.c
@@ -238,14 +238,15 @@
 	struct backed_block *last_bb = NULL;
 	struct backed_block *bb;
 	struct backed_block *start;
+	unsigned int last_block = 0;
 	int64_t file_len = 0;
 	int ret;
 
 	/*
-	 * overhead is sparse file header, initial skip chunk, split chunk, end
-	 * skip chunk, and crc chunk.
+	 * overhead is sparse file header, the potential end skip
+	 * chunk and crc chunk.
 	 */
-	int overhead = sizeof(sparse_header_t) + 4 * sizeof(chunk_header_t) +
+	int overhead = sizeof(sparse_header_t) + 2 * sizeof(chunk_header_t) +
 			sizeof(uint32_t);
 	len -= overhead;
 
@@ -258,6 +259,11 @@
 
 	for (bb = start; bb; bb = backed_block_iter_next(bb)) {
 		count = 0;
+		if (backed_block_block(bb) > last_block)
+			count += sizeof(chunk_header_t);
+		last_block = backed_block_block(bb) +
+				DIV_ROUND_UP(backed_block_len(bb), to->block_size);
+
 		/* will call out_counter_write to update count */
 		ret = sparse_file_write_block(out_counter, bb);
 		if (ret) {
@@ -270,6 +276,7 @@
 			 * requested size, split the chunk.  Results in sparse files that
 			 * are at least 7/8ths of the requested size
 			 */
+			file_len += sizeof(chunk_header_t);
 			if (!last_bb || (len - file_len > (len / 8))) {
 				backed_block_split(from->backed_block_list, bb, len - file_len);
 				last_bb = bb;
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 57c46a3..79c4c53 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -30,6 +30,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/file.h"
 #include "base/macros.h"  // TEMP_FAILURE_RETRY may or may not be in unistd
 #include "base/memory.h"
 #include "log/log.h"
@@ -85,7 +86,8 @@
   // Length of the central directory comment.
   uint16_t comment_length;
  private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(EocdRecord);
+  EocdRecord() = default;
+  DISALLOW_COPY_AND_ASSIGN(EocdRecord);
 } __attribute__((packed));
 
 // A structure representing the fixed length fields for a single
@@ -138,7 +140,8 @@
   // beginning of this archive.
   uint32_t local_file_header_offset;
  private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(CentralDirectoryRecord);
+  CentralDirectoryRecord() = default;
+  DISALLOW_COPY_AND_ASSIGN(CentralDirectoryRecord);
 } __attribute__((packed));
 
 // The local file header for a given entry. This duplicates information
@@ -175,7 +178,8 @@
   // will appear immediately after the entry file name.
   uint16_t extra_field_length;
  private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(LocalFileHeader);
+  LocalFileHeader() = default;
+  DISALLOW_COPY_AND_ASSIGN(LocalFileHeader);
 } __attribute__((packed));
 
 struct DataDescriptor {
@@ -189,10 +193,10 @@
   // Uncompressed size of the entry.
   uint32_t uncompressed_size;
  private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(DataDescriptor);
+  DataDescriptor() = default;
+  DISALLOW_COPY_AND_ASSIGN(DataDescriptor);
 } __attribute__((packed));
 
-#undef DISALLOW_IMPLICIT_CONSTRUCTORS
 
 static const uint32_t kGPBDDFlagMask = 0x0008;         // mask value that signifies that the entry has a DD
 
@@ -265,8 +269,6 @@
 
 static const int32_t kErrorMessageLowerBound = -13;
 
-static const char kTempMappingFileName[] = "zip: ExtractFileToFile";
-
 /*
  * A Read-only Zip archive.
  *
@@ -324,35 +326,6 @@
   }
 };
 
-static int32_t CopyFileToFile(int fd, uint8_t* begin, const uint32_t length, uint64_t *crc_out) {
-  static const uint32_t kBufSize = 32768;
-  uint8_t buf[kBufSize];
-
-  uint32_t count = 0;
-  uint64_t crc = 0;
-  while (count < length) {
-    uint32_t remaining = length - count;
-
-    // Safe conversion because kBufSize is narrow enough for a 32 bit signed
-    // value.
-    ssize_t get_size = (remaining > kBufSize) ? kBufSize : remaining;
-    ssize_t actual = TEMP_FAILURE_RETRY(read(fd, buf, get_size));
-
-    if (actual != get_size) {
-      ALOGW("CopyFileToFile: copy read failed (" ZD " vs " ZD ")", actual, get_size);
-      return kIoError;
-    }
-
-    memcpy(begin + count, buf, get_size);
-    crc = crc32(crc, buf, get_size);
-    count += get_size;
-  }
-
-  *crc_out = crc;
-
-  return 0;
-}
-
 /*
  * Round up to the next highest power of 2.
  *
@@ -972,6 +945,117 @@
   return kIterationEnd;
 }
 
+class Writer {
+ public:
+  virtual bool Append(uint8_t* buf, size_t buf_size) = 0;
+  virtual ~Writer() {}
+ protected:
+  Writer() = default;
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Writer);
+};
+
+// A Writer that writes data to a fixed size memory region.
+// The size of the memory region must be equal to the total size of
+// the data appended to it.
+class MemoryWriter : public Writer {
+ public:
+  MemoryWriter(uint8_t* buf, size_t size) : Writer(),
+      buf_(buf), size_(size), bytes_written_(0) {
+  }
+
+  virtual bool Append(uint8_t* buf, size_t buf_size) override {
+    if (bytes_written_ + buf_size > size_) {
+      ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)",
+            size_, bytes_written_ + buf_size);
+      return false;
+    }
+
+    memcpy(buf_ + bytes_written_, buf, buf_size);
+    bytes_written_ += buf_size;
+    return true;
+  }
+
+ private:
+  uint8_t* const buf_;
+  const size_t size_;
+  size_t bytes_written_;
+};
+
+// A Writer that appends data to a file |fd| at its current position.
+// The file will be truncated to the end of the written data.
+class FileWriter : public Writer {
+ public:
+
+  // Creates a FileWriter for |fd| and prepare to write |entry| to it,
+  // guaranteeing that the file descriptor is valid and that there's enough
+  // space on the volume to write out the entry completely and that the file
+  // is truncated to the correct length.
+  //
+  // Returns a valid FileWriter on success, |nullptr| if an error occurred.
+  static std::unique_ptr<FileWriter> Create(int fd, const ZipEntry* entry) {
+    const uint32_t declared_length = entry->uncompressed_length;
+    const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
+    if (current_offset == -1) {
+      ALOGW("Zip: unable to seek to current location on fd %d: %s", fd, strerror(errno));
+      return nullptr;
+    }
+
+    int result = 0;
+#if defined(__linux__)
+    if (declared_length > 0) {
+      // Make sure we have enough space on the volume to extract the compressed
+      // entry. Note that the call to ftruncate below will change the file size but
+      // will not allocate space on disk and this call to fallocate will not
+      // change the file size.
+      result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
+      if (result == -1) {
+        ALOGW("Zip: unable to allocate space for file to %" PRId64 ": %s",
+              static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+        return std::unique_ptr<FileWriter>(nullptr);
+      }
+    }
+#endif  // __linux__
+
+    result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
+    if (result == -1) {
+      ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
+            static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+      return std::unique_ptr<FileWriter>(nullptr);
+    }
+
+    return std::unique_ptr<FileWriter>(new FileWriter(fd, declared_length));
+  }
+
+  virtual bool Append(uint8_t* buf, size_t buf_size) override {
+    if (total_bytes_written_ + buf_size > declared_length_) {
+      ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)",
+            declared_length_, total_bytes_written_ + buf_size);
+      return false;
+    }
+
+    const bool result = android::base::WriteFully(fd_, buf, buf_size);
+    if (result) {
+      total_bytes_written_ += buf_size;
+    } else {
+      ALOGW("Zip: unable to write " ZD " bytes to file; %s", buf_size, strerror(errno));
+    }
+
+    return result;
+  }
+ private:
+  FileWriter(const int fd, const size_t declared_length) :
+      Writer(),
+      fd_(fd),
+      declared_length_(declared_length),
+      total_bytes_written_(0) {
+  }
+
+  const int fd_;
+  const size_t declared_length_;
+  size_t total_bytes_written_;
+};
+
 // This method is using libz macros with old-style-casts
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wold-style-cast"
@@ -980,9 +1064,8 @@
 }
 #pragma GCC diagnostic pop
 
-static int32_t InflateToFile(int fd, const ZipEntry* entry,
-                             uint8_t* begin, uint32_t length,
-                             uint64_t* crc_out) {
+static int32_t InflateEntryToWriter(int fd, const ZipEntry* entry,
+                                    Writer* writer, uint64_t* crc_out) {
   const size_t kBufSize = 32768;
   std::vector<uint8_t> read_buf(kBufSize);
   std::vector<uint8_t> write_buf(kBufSize);
@@ -1027,7 +1110,6 @@
   const uint32_t uncompressed_length = entry->uncompressed_length;
 
   uint32_t compressed_length = entry->compressed_length;
-  uint32_t write_count = 0;
   do {
     /* read as much as we can */
     if (zstream.avail_in == 0) {
@@ -1057,12 +1139,10 @@
     if (zstream.avail_out == 0 ||
       (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
       const size_t write_size = zstream.next_out - &write_buf[0];
-      // The file might have declared a bogus length.
-      if (write_size + write_count > length) {
-        return -1;
+      if (!writer->Append(&write_buf[0], write_size)) {
+        // The file might have declared a bogus length.
+        return kInconsistentInformation;
       }
-      memcpy(begin + write_count, &write_buf[0], write_size);
-      write_count += write_size;
 
       zstream.next_out = &write_buf[0];
       zstream.avail_out = kBufSize;
@@ -1083,8 +1163,41 @@
   return 0;
 }
 
-int32_t ExtractToMemory(ZipArchiveHandle handle,
-                        ZipEntry* entry, uint8_t* begin, uint32_t size) {
+static int32_t CopyEntryToWriter(int fd, const ZipEntry* entry, Writer* writer,
+                                 uint64_t *crc_out) {
+  static const uint32_t kBufSize = 32768;
+  std::vector<uint8_t> buf(kBufSize);
+
+  const uint32_t length = entry->uncompressed_length;
+  uint32_t count = 0;
+  uint64_t crc = 0;
+  while (count < length) {
+    uint32_t remaining = length - count;
+
+    // Safe conversion because kBufSize is narrow enough for a 32 bit signed
+    // value.
+    const ssize_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
+    const ssize_t actual = TEMP_FAILURE_RETRY(read(fd, &buf[0], block_size));
+
+    if (actual != block_size) {
+      ALOGW("CopyFileToFile: copy read failed (" ZD " vs " ZD ")", actual, block_size);
+      return kIoError;
+    }
+
+    if (!writer->Append(&buf[0], block_size)) {
+      return kIoError;
+    }
+    crc = crc32(crc, &buf[0], block_size);
+    count += block_size;
+  }
+
+  *crc_out = crc;
+
+  return 0;
+}
+
+int32_t ExtractToWriter(ZipArchiveHandle handle,
+                        ZipEntry* entry, Writer* writer) {
   ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
   const uint16_t method = entry->method;
   off64_t data_offset = entry->offset;
@@ -1098,9 +1211,9 @@
   int32_t return_value = -1;
   uint64_t crc = 0;
   if (method == kCompressStored) {
-    return_value = CopyFileToFile(archive->fd, begin, size, &crc);
+    return_value = CopyEntryToWriter(archive->fd, entry, writer, &crc);
   } else if (method == kCompressDeflated) {
-    return_value = InflateToFile(archive->fd, entry, begin, size, &crc);
+    return_value = InflateEntryToWriter(archive->fd, entry, writer, &crc);
   }
 
   if (!return_value && entry->has_data_descriptor) {
@@ -1120,40 +1233,20 @@
   return return_value;
 }
 
+int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry,
+                        uint8_t* begin, uint32_t size) {
+  std::unique_ptr<Writer> writer(new MemoryWriter(begin, size));
+  return ExtractToWriter(handle, entry, writer.get());
+}
+
 int32_t ExtractEntryToFile(ZipArchiveHandle handle,
                            ZipEntry* entry, int fd) {
-  const uint32_t declared_length = entry->uncompressed_length;
-
-  const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
-  if (current_offset == -1) {
-    ALOGW("Zip: unable to seek to current location on fd %d: %s", fd,
-          strerror(errno));
+  std::unique_ptr<Writer> writer(FileWriter::Create(fd, entry));
+  if (writer.get() == nullptr) {
     return kIoError;
   }
 
-  int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
-  if (result == -1) {
-    ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
-          static_cast<int64_t>(declared_length + current_offset), strerror(errno));
-    return kIoError;
-  }
-
-  // Don't attempt to map a region of length 0. We still need the
-  // ftruncate() though, since the API guarantees that we will truncate
-  // the file to the end of the uncompressed output.
-  if (declared_length == 0) {
-      return 0;
-  }
-
-  android::FileMap map;
-  if (!map.create(kTempMappingFileName, fd, current_offset, declared_length, false)) {
-    return kMmapFailed;
-  }
-
-  const int32_t error = ExtractToMemory(handle, entry,
-                                        reinterpret_cast<uint8_t*>(map.getDataPtr()),
-                                        map.getDataLength());
-  return error;
+  return ExtractToWriter(handle, entry, writer.get());
 }
 
 const char* ErrorCodeString(int32_t error_code) {
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 64faa6d..f8952ce 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -23,6 +23,7 @@
 #include <unistd.h>
 #include <vector>
 
+#include <base/file.h>
 #include <gtest/gtest.h>
 
 static std::string test_data_dir;
@@ -228,6 +229,44 @@
       0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
       0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
 
+// This is a zip file containing a single entry (ab.txt) that contains
+// 90072 repetitions of the string "ab\n" and has an uncompressed length
+// of 270216 bytes.
+static const uint16_t kAbZip[] = {
+  0x4b50, 0x0403, 0x0014, 0x0000, 0x0008, 0x51d2, 0x4698, 0xc4b0,
+  0x2cda, 0x011b, 0x0000, 0x1f88, 0x0004, 0x0006, 0x001c, 0x6261,
+  0x742e, 0x7478, 0x5455, 0x0009, 0x7c03, 0x3a09, 0x7c55, 0x3a09,
+  0x7555, 0x0b78, 0x0100, 0x8904, 0x0042, 0x0400, 0x1388, 0x0000,
+  0xc2ed, 0x0d31, 0x0000, 0x030c, 0x7fa0, 0x3b2e, 0x22ff, 0xa2aa,
+  0x841f, 0x45fc, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+  0x5555, 0x5555, 0x5555, 0x5555, 0xdd55, 0x502c, 0x014b, 0x1e02,
+  0x1403, 0x0000, 0x0800, 0xd200, 0x9851, 0xb046, 0xdac4, 0x1b2c,
+  0x0001, 0x8800, 0x041f, 0x0600, 0x1800, 0x0000, 0x0000, 0x0100,
+  0x0000, 0xa000, 0x0081, 0x0000, 0x6100, 0x2e62, 0x7874, 0x5574,
+  0x0554, 0x0300, 0x097c, 0x553a, 0x7875, 0x000b, 0x0401, 0x4289,
+  0x0000, 0x8804, 0x0013, 0x5000, 0x054b, 0x0006, 0x0000, 0x0100,
+  0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000
+};
+
+static const uint8_t kAbTxtName[] = { 'a', 'b', '.', 't', 'x', 't' };
+static const uint16_t kAbTxtNameLength = sizeof(kAbTxtName);
+static const size_t kAbUncompressedSize = 270216;
+
 static int make_temporary_file(const char* file_name_pattern) {
   char full_path[1024];
   // Account for differences between the host and the target.
@@ -275,6 +314,55 @@
   close(output_fd);
 }
 
+TEST(ziparchive, EntryLargerThan32K) {
+  char temp_file_pattern[] = "entry_larger_than_32k_test_XXXXXX";
+  int fd = make_temporary_file(temp_file_pattern);
+  ASSERT_NE(-1, fd);
+  ASSERT_TRUE(android::base::WriteFully(fd, reinterpret_cast<const uint8_t*>(kAbZip),
+                         sizeof(kAbZip) - 1));
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveFd(fd, "EntryLargerThan32KTest", &handle));
+
+  ZipEntry entry;
+  ZipEntryName ab_name;
+  ab_name.name = kAbTxtName;
+  ab_name.name_length = kAbTxtNameLength;
+  ASSERT_EQ(0, FindEntry(handle, ab_name, &entry));
+  ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
+
+  // Extract the entry to memory.
+  std::vector<uint8_t> buffer(kAbUncompressedSize);
+  ASSERT_EQ(0, ExtractToMemory(handle, &entry, &buffer[0], buffer.size()));
+
+  // Extract the entry to a file.
+  char output_file_pattern[] = "entry_larger_than_32k_test_output_XXXXXX";
+  int output_fd = make_temporary_file(output_file_pattern);
+  ASSERT_NE(-1, output_fd);
+  ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, output_fd));
+
+  // Make sure the extracted file size is as expected.
+  struct stat stat_buf;
+  ASSERT_EQ(0, fstat(output_fd, &stat_buf));
+  ASSERT_EQ(kAbUncompressedSize, static_cast<size_t>(stat_buf.st_size));
+
+  // Read the file back to a buffer and make sure the contents are
+  // the same as the memory buffer we extracted directly to.
+  std::vector<uint8_t> file_contents(kAbUncompressedSize);
+  ASSERT_EQ(0, lseek64(output_fd, 0, SEEK_SET));
+  ASSERT_TRUE(android::base::ReadFully(output_fd, &file_contents[0], file_contents.size()));
+  ASSERT_EQ(file_contents, buffer);
+
+  for (int i = 0; i < 90072; ++i) {
+    const uint8_t* line = &file_contents[0] + (3 * i);
+    ASSERT_EQ('a', line[0]);
+    ASSERT_EQ('b', line[1]);
+    ASSERT_EQ('\n', line[2]);
+  }
+
+  close(fd);
+  close(output_fd);
+}
+
 TEST(ziparchive, TrailerAfterEOCD) {
   char temp_file_pattern[] = "trailer_after_eocd_test_XXXXXX";
   int fd = make_temporary_file(temp_file_pattern);
diff --git a/logcat/event.logtags b/logcat/event.logtags
index 1b5c6f4..909f8e2 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -21,6 +21,7 @@
 # 2: long
 # 3: string
 # 4: list
+# 5: float
 #
 # The data unit is a number taken from the following list:
 # 1: Number of objects
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 90370e9..caae54b 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -155,12 +155,14 @@
         event->length = htole32(l);
         memcpy(event->data, str, l);
 
-        logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid,
-                    reinterpret_cast<char *>(event),
-                    (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+        rc = logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid,
+                         reinterpret_cast<char *>(event),
+                         (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
         free(event);
 
-        notify = true;
+        if (rc >= 0) {
+            notify = true;
+        }
     }
 
     // log to main
@@ -197,17 +199,22 @@
         strncpy(newstr + 1 + l, str, estr - str);
         strcpy(newstr + 1 + l + (estr - str), ecomm);
 
-        logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
-                    (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+        rc = logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
+                         (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
         free(newstr);
 
-        notify = true;
+        if (rc >= 0) {
+            notify = true;
+        }
     }
 
     free(str);
 
     if (notify) {
         reader->notifyNewLog();
+        if (rc < 0) {
+            rc = n;
+        }
     }
 
     return rc;
@@ -216,7 +223,7 @@
 int LogAudit::log(char *buf) {
     char *audit = strstr(buf, " audit(");
     if (!audit) {
-        return 0;
+        return -EXDEV;
     }
 
     *audit = '\0';
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 260e237..1dced11 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <ctype.h>
+#include <errno.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/user.h>
@@ -132,11 +133,11 @@
     init();
 }
 
-void LogBuffer::log(log_id_t log_id, log_time realtime,
-                    uid_t uid, pid_t pid, pid_t tid,
-                    const char *msg, unsigned short len) {
+int LogBuffer::log(log_id_t log_id, log_time realtime,
+                   uid_t uid, pid_t pid, pid_t tid,
+                   const char *msg, unsigned short len) {
     if ((log_id >= LOG_ID_MAX) || (log_id < 0)) {
-        return;
+        return -EINVAL;
     }
     LogBufferElement *elem = new LogBufferElement(log_id, realtime,
                                                   uid, pid, tid, msg, len);
@@ -193,6 +194,8 @@
     stats.add(elem);
     maybePrune(log_id);
     pthread_mutex_unlock(&mLogElementsLock);
+
+    return len;
 }
 
 // If we're using more than 256K of memory for log entries, prune
@@ -223,6 +226,84 @@
     return it;
 }
 
+// Define a temporary mechanism to report the last LogBufferElement pointer
+// for the specified uid, pid and tid. Used below to help merge-sort when
+// pruning for worst UID.
+class LogBufferElementKey {
+    const union {
+        struct {
+            uint16_t uid;
+            uint16_t pid;
+            uint16_t tid;
+            uint16_t padding;
+        } __packed;
+        uint64_t value;
+    } __packed;
+
+public:
+    LogBufferElementKey(uid_t u, pid_t p, pid_t t):uid(u),pid(p),tid(t),padding(0) { }
+    LogBufferElementKey(uint64_t k):value(k) { }
+
+    uint64_t getKey() { return value; }
+};
+
+class LogBufferElementEntry {
+    const uint64_t key;
+    LogBufferElement *last;
+
+public:
+    LogBufferElementEntry(const uint64_t &k, LogBufferElement *e):key(k),last(e) { }
+
+    const uint64_t&getKey() const { return key; }
+
+    LogBufferElement *getLast() { return last; }
+};
+
+class LogBufferElementLast : public android::BasicHashtable<uint64_t, LogBufferElementEntry> {
+
+public:
+    bool merge(LogBufferElement *e, unsigned short dropped) {
+        LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid());
+        android::hash_t hash = android::hash_type(key.getKey());
+        ssize_t index = find(-1, hash, key.getKey());
+        if (index != -1) {
+            LogBufferElementEntry &entry = editEntryAt(index);
+            LogBufferElement *l = entry.getLast();
+            unsigned short d = l->getDropped();
+            if ((dropped + d) > USHRT_MAX) {
+                removeAt(index);
+            } else {
+                l->setDropped(dropped + d);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    size_t add(LogBufferElement *e) {
+        LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid());
+        android::hash_t hash = android::hash_type(key.getKey());
+        return android::BasicHashtable<uint64_t, LogBufferElementEntry>::
+            add(hash, LogBufferElementEntry(key.getKey(), e));
+    }
+
+    inline void clear() {
+        android::BasicHashtable<uint64_t, LogBufferElementEntry>::clear();
+    }
+
+    void clear(LogBufferElement *e) {
+        uint64_t current = e->getRealTime().nsec() - NS_PER_SEC;
+        ssize_t index = -1;
+        while((index = next(index)) >= 0) {
+            if (current > editEntryAt(index).getLast()->getRealTime().nsec()) {
+                removeAt(index);
+                index = -1;
+            }
+        }
+    }
+
+};
+
 // prune "pruneRows" of type "id" from the buffer.
 //
 // mLogElementsLock must be held when this function is called.
@@ -284,9 +365,16 @@
 
             if (sorted.get()) {
                 if (sorted[0] && sorted[1]) {
-                    worst = sorted[0]->getKey();
                     worst_sizes = sorted[0]->getSizes();
-                    second_worst_sizes = sorted[1]->getSizes();
+                    // Calculate threshold as 12.5% of available storage
+                    size_t threshold = log_buffer_size(id) / 8;
+                    if (worst_sizes > threshold) {
+                        worst = sorted[0]->getKey();
+                        second_worst_sizes = sorted[1]->getSizes();
+                        if (second_worst_sizes < threshold) {
+                            second_worst_sizes = threshold;
+                        }
+                    }
                 }
             }
         }
@@ -298,7 +386,7 @@
 
         bool kick = false;
         bool leading = true;
-        LogBufferElement *last = NULL;
+        LogBufferElementLast last;
         for(it = mLogElements.begin(); it != mLogElements.end();) {
             LogBufferElement *e = *it;
 
@@ -319,24 +407,18 @@
                 continue;
             }
 
-            pid_t pid = e->getPid();
-
             // merge any drops
-            if (last && dropped
-             && ((dropped + last->getDropped()) < USHRT_MAX)
-             && (last->getPid() == pid)
-             && (last->getTid() == e->getTid())) {
+            if (dropped && last.merge(e, dropped)) {
                 it = mLogElements.erase(it);
                 stats.erase(e);
                 delete e;
-                last->setDropped(dropped + last->getDropped());
                 continue;
             }
 
             leading = false;
 
             if (hasBlacklist && mPrune.naughty(e)) {
-                last = NULL;
+                last.clear(e);
                 it = erase(it);
                 if (dropped) {
                     continue;
@@ -358,13 +440,13 @@
             }
 
             if (dropped) {
-                last = e;
+                last.add(e);
                 ++it;
                 continue;
             }
 
             if (e->getUid() != worst) {
-                last = NULL;
+                last.clear(e);
                 ++it;
                 continue;
             }
@@ -379,17 +461,12 @@
             unsigned short len = e->getMsgLen();
             stats.drop(e);
             e->setDropped(1);
-            // merge any drops
-            if (last
-             && (last->getDropped() < (USHRT_MAX - 1))
-             && (last->getPid() == pid)
-             && (last->getTid() == e->getTid())) {
+            if (last.merge(e, 1)) {
                 it = mLogElements.erase(it);
                 stats.erase(e);
                 delete e;
-                last->setDropped(last->getDropped() + 1);
             } else {
-                last = e;
+                last.add(e);
                 ++it;
             }
             if (worst_sizes < second_worst_sizes) {
@@ -397,6 +474,7 @@
             }
             worst_sizes -= len;
         }
+        last.clear();
 
         if (!kick || !mPrune.worstUidEnabled()) {
             break; // the following loop will ask bad clients to skip/drop
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index a29e015..9ee243d 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -48,9 +48,9 @@
     LogBuffer(LastLogTimes *times);
     void init();
 
-    void log(log_id_t log_id, log_time realtime,
-             uid_t uid, pid_t pid, pid_t tid,
-             const char *msg, unsigned short len);
+    int log(log_id_t log_id, log_time realtime,
+            uid_t uid, pid_t pid, pid_t tid,
+            const char *msg, unsigned short len);
     uint64_t flushTo(SocketClient *writer, const uint64_t start,
                      bool privileged,
                      int (*filter)(const LogBufferElement *element, void *arg) = NULL,
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 3b4ef88..05ced06 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -98,10 +98,11 @@
     // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
     // truncated message to the logs.
 
-    logbuf->log((log_id_t)header->id, header->realtime,
-        cred->uid, cred->pid, header->tid, msg,
-        ((size_t) n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
-    reader->notifyNewLog();
+    if (logbuf->log((log_id_t)header->id, header->realtime,
+            cred->uid, cred->pid, header->tid, msg,
+            ((size_t) n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX) >= 0) {
+        reader->notifyNewLog();
+    }
 
     return true;
 }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 0801fe8..eadc4dd 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -328,22 +328,32 @@
             }
 
             if (!headerPrinted) {
+                output.appendFormat("\n\n");
+                android::String8 name("");
                 if (uid == AID_ROOT) {
-                    output.appendFormat(
-                        "\n\nChattiest UIDs in %s:\n",
+                    name.appendFormat(
+                        "Chattiest UIDs in %s log buffer:",
                         android_log_id_to_name(id));
                 } else {
-                    output.appendFormat(
-                        "\n\nLogging for your UID in %s:\n",
+                    name.appendFormat(
+                        "Logging for your UID in %s log buffer:",
                         android_log_id_to_name(id));
                 }
-                android::String8 name("UID");
                 android::String8 size("Size");
                 android::String8 pruned("Pruned");
                 if (!worstUidEnabledForLogid(id)) {
                     pruned.setTo("");
                 }
                 format_line(output, name, size, pruned);
+
+                name.setTo("UID   PACKAGE");
+                size.setTo("BYTES");
+                pruned.setTo("LINES");
+                if (!worstUidEnabledForLogid(id)) {
+                    pruned.setTo("");
+                }
+                format_line(output, name, size, pruned);
+
                 headerPrinted = true;
             }
 
@@ -380,15 +390,22 @@
             }
 
             if (!headerPrinted) {
+                output.appendFormat("\n\n");
+                android::String8 name("");
                 if (uid == AID_ROOT) {
-                    output.appendFormat("\n\nChattiest PIDs:\n");
+                    name.appendFormat("Chattiest PIDs:");
                 } else {
-                    output.appendFormat("\n\nLogging for this PID:\n");
+                    name.appendFormat("Logging for this PID:");
                 }
-                android::String8 name("  PID/UID");
                 android::String8 size("Size");
                 android::String8 pruned("Pruned");
                 format_line(output, name, size, pruned);
+
+                name.setTo("  PID/UID   COMMAND LINE");
+                size.setTo("BYTES");
+                pruned.setTo("LINES");
+                format_line(output, name, size, pruned);
+
                 headerPrinted = true;
             }
 
diff --git a/logd/main.cpp b/logd/main.cpp
index 4aa38b3..eb29596 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -367,12 +367,12 @@
 
             int rc = klogctl(KLOG_READ_ALL, buf, len);
 
-            buf[len - 1] = '\0';
+            if (rc >= 0) {
+                buf[len - 1] = '\0';
 
-            for(char *ptr, *tok = buf;
-                    (rc >= 0) && ((tok = strtok_r(tok, "\r\n", &ptr)));
-                    tok = NULL) {
-                rc = al->log(tok);
+                for (char *ptr, *tok = buf; (tok = strtok_r(tok, "\r\n", &ptr)); tok = NULL) {
+                    al->log(tok);
+                }
             }
         }
 
diff --git a/rootdir/etc/mountd.conf b/rootdir/etc/mountd.conf
deleted file mode 100644
index 094a2c7..0000000
--- a/rootdir/etc/mountd.conf
+++ /dev/null
@@ -1,19 +0,0 @@
-## mountd configuration file
-
-## add a mount entry for each mount point to be managed by mountd
-mount {
-    ## root block device with partition map or raw FAT file system
-    block_device    /dev/block/mmcblk0
-        
-    ## mount point for block device
-    mount_point     /sdcard
-    
-    ## true if this mount point can be shared via USB mass storage
-    enable_ums      true
-    
-    ## path to the UMS driver file for specifying the block device path  
-    ## use this for the mass_storage function driver
-    driver_store_path   /sys/devices/platform/usb_mass_storage/lun0/file
-    ## use this for android_usb composite gadget driver
-    ##driver_store_path   /sys/devices/platform/msm_hsusb/gadget/lun0/file
-}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a2b8f59..3709b82 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -14,13 +14,6 @@
     # Set init and its forked children's oom_adj.
     write /proc/1/oom_score_adj -1000
 
-    # Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
-    write /sys/fs/selinux/checkreqprot 0
-
-    # Set the security context for the init process.
-    # This should occur before anything else (e.g. ueventd) is started.
-    setcon u:r:init:s0
-
     # Set the security context of /adb_keys if present.
     restorecon /adb_keys
 
@@ -162,6 +155,7 @@
 # Load properties from /system/ + /factory after fs mount.
 on load_all_props_action
     load_all_props
+    start logd
     start logd-reinit
 
 # Indicate to fw loaders that the relevant mounts are up.
@@ -226,14 +220,17 @@
     mkdir /cache/lost+found 0770 root root
 
 on post-fs-data
-    installkey /data
-
     # We chown/chmod /data again so because mount is run as root + defaults
     chown system system /data
     chmod 0771 /data
     # We restorecon /data in case the userdata partition has been reset.
     restorecon /data
 
+    # Make sure we have the device encryption key
+    start logd
+    start vold
+    installkey /data
+
     # Start bootcharting as soon as possible after the data partition is
     # mounted to collect more data.
     mkdir /data/bootchart 0755 shell shell
@@ -248,6 +245,7 @@
     mkdir /data/misc/bluedroid 0770 bluetooth net_bt_stack
     mkdir /data/misc/bluetooth 0770 system system
     mkdir /data/misc/keystore 0700 keystore keystore
+    mkdir /data/misc/gatekeeper 0700 system system
     mkdir /data/misc/keychain 0771 system system
     mkdir /data/misc/net 0750 root shell
     mkdir /data/misc/radio 0770 system radio
@@ -444,6 +442,7 @@
 
 on property:vold.decrypt=trigger_load_persist_props
     load_persist_props
+    start logd
     start logd-reinit
 
 on property:vold.decrypt=trigger_post_fs_data
@@ -453,7 +452,6 @@
     class_start main
 
 on property:vold.decrypt=trigger_restart_framework
-    installkey /data
     class_start main
     class_start late_start
 
@@ -489,7 +487,6 @@
     socket logdw dgram 0222 logd logd
 
 service logd-reinit /system/bin/logd --reinit
-    start logd
     oneshot
     disabled
 
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 041c37a..893c0dc 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -1875,7 +1875,7 @@
     struct fuse fuse;
 
     /* cleanup from previous instance, if necessary */
-    umount2(dest_path, 2);
+    umount2(dest_path, MNT_DETACH);
 
     fd = open("/dev/fuse", O_RDWR);
     if (fd < 0){
diff --git a/toolbox/toolbox.c b/toolbox/toolbox.c
index 0eac390..915da44 100644
--- a/toolbox/toolbox.c
+++ b/toolbox/toolbox.c
@@ -1,6 +1,8 @@
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 int main(int, char **);
 
@@ -31,11 +33,24 @@
     { 0, 0 },
 };
 
+static void SIGPIPE_handler(int signal) {
+    // Those desktop Linux tools that catch SIGPIPE seem to agree that it's
+    // a successful way to exit, not a failure. (Which makes sense --- we were
+    // told to stop by a reader, rather than failing to continue ourselves.)
+    _exit(0);
+}
+
 int main(int argc, char **argv)
 {
     int i;
     char *name = argv[0];
 
+    // Let's assume that none of this code handles broken pipes. At least ls,
+    // ps, and top were broken (though I'd previously added this fix locally
+    // to top). We exit rather than use SIG_IGN because tools like top will
+    // just keep on writing to nowhere forever if we don't stop them.
+    signal(SIGPIPE, SIGPIPE_handler);
+
     if((argc > 1) && (argv[1][0] == '@')) {
         name = argv[1] + 1;
         argc--;
diff --git a/toolbox/top.c b/toolbox/top.c
index b1a275c..1e99d4c 100644
--- a/toolbox/top.c
+++ b/toolbox/top.c
@@ -109,15 +109,9 @@
 static int numcmp(long long a, long long b);
 static void usage(char *cmd);
 
-static void exit_top(int signal) {
-  exit(EXIT_FAILURE);
-}
-
 int top_main(int argc, char *argv[]) {
     num_used_procs = num_free_procs = 0;
 
-    signal(SIGPIPE, exit_top);
-
     max_procs = 0;
     delay = 3;
     iterations = -1;