Merge "LibNativeBridge: Version 2"
diff --git a/adb/Android.mk b/adb/Android.mk
index 9b6e147..f3a4822 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -6,11 +6,18 @@
 LOCAL_PATH:= $(call my-dir)
 
 ifeq ($(HOST_OS),windows)
-  adb_host_clang := false  # libc++ for mingw not ready yet.
+    adb_host_clang := false  # libc++ for mingw not ready yet.
 else
-  adb_host_clang := true
+    adb_host_clang := true
 endif
 
+adb_version := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/null)-android
+
+ADB_COMMON_CFLAGS := \
+    -Wall -Werror \
+    -Wno-unused-parameter \
+    -DADB_REVISION='"$(adb_version)"' \
+
 # libadb
 # =========================================================
 
@@ -37,8 +44,7 @@
     transport_test.cpp \
 
 LIBADB_CFLAGS := \
-    -Wall -Werror \
-    -Wno-unused-parameter \
+    $(ADB_COMMON_CFLAGS) \
     -Wno-missing-field-initializers \
     -fvisibility=hidden \
 
@@ -103,6 +109,7 @@
 LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
 include $(BUILD_NATIVE_TEST)
 
+ifneq ($(HOST_OS),windows)
 include $(CLEAR_VARS)
 LOCAL_CLANG := $(adb_host_clang)
 LOCAL_MODULE := adb_test
@@ -115,38 +122,54 @@
     libcutils \
 
 ifeq ($(HOST_OS),linux)
-  LOCAL_LDLIBS += -lrt -ldl -lpthread
+    LOCAL_LDLIBS += -lrt -ldl -lpthread
 endif
 
 ifeq ($(HOST_OS),darwin)
-  LOCAL_LDLIBS += -framework CoreFoundation -framework IOKit
+    LOCAL_LDLIBS += -framework CoreFoundation -framework IOKit
 endif
 
 include $(BUILD_HOST_NATIVE_TEST)
+endif
+
+# adb device tracker (used by ddms) test tool
+# =========================================================
+
+ifeq ($(HOST_OS),linux)
+include $(CLEAR_VARS)
+LOCAL_CLANG := $(adb_host_clang)
+LOCAL_MODULE := adb_device_tracker_test
+LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
+LOCAL_SRC_FILES := test_track_devices.cpp
+LOCAL_SHARED_LIBRARIES := liblog libbase
+LOCAL_STATIC_LIBRARIES := libadb libcrypto_static libcutils
+LOCAL_LDLIBS += -lrt -ldl -lpthread
+include $(BUILD_HOST_EXECUTABLE)
+endif
 
 # adb host tool
 # =========================================================
 include $(CLEAR_VARS)
 
 ifeq ($(HOST_OS),linux)
-  LOCAL_LDLIBS += -lrt -ldl -lpthread
-  LOCAL_CFLAGS += -DWORKAROUND_BUG6558362
+    LOCAL_LDLIBS += -lrt -ldl -lpthread
+    LOCAL_CFLAGS += -DWORKAROUND_BUG6558362
 endif
 
 ifeq ($(HOST_OS),darwin)
-  LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
-  LOCAL_CFLAGS += -Wno-sizeof-pointer-memaccess -Wno-unused-parameter
+    LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
+    LOCAL_CFLAGS += -Wno-sizeof-pointer-memaccess -Wno-unused-parameter
 endif
 
 ifeq ($(HOST_OS),windows)
-  LOCAL_LDLIBS += -lws2_32 -lgdi32
-  EXTRA_STATIC_LIBS := AdbWinApi
+    LOCAL_LDLIBS += -lws2_32 -lgdi32
+    EXTRA_STATIC_LIBS := AdbWinApi
 endif
 
 LOCAL_CLANG := $(adb_host_clang)
 
 LOCAL_SRC_FILES := \
-    adb_main.cpp \
+    client/main.cpp \
     console.cpp \
     commandline.cpp \
     adb_client.cpp \
@@ -154,8 +177,7 @@
     file_sync_client.cpp \
 
 LOCAL_CFLAGS += \
-    -Wall -Werror \
-    -Wno-unused-parameter \
+    $(ADB_COMMON_CFLAGS) \
     -D_GNU_SOURCE \
     -DADB_HOST=1 \
 
@@ -199,7 +221,7 @@
 LOCAL_CLANG := true
 
 LOCAL_SRC_FILES := \
-    adb_main.cpp \
+    daemon/main.cpp \
     services.cpp \
     file_sync_service.cpp \
     framebuffer_service.cpp \
@@ -207,10 +229,9 @@
     set_verity_enable_state_service.cpp \
 
 LOCAL_CFLAGS := \
+    $(ADB_COMMON_CFLAGS) \
     -DADB_HOST=0 \
     -D_GNU_SOURCE \
-    -Wall -Werror \
-    -Wno-unused-parameter \
     -Wno-deprecated-declarations \
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
diff --git a/adb/CPPLINT.cfg b/adb/CPPLINT.cfg
index 9b906e8..f496490 100644
--- a/adb/CPPLINT.cfg
+++ b/adb/CPPLINT.cfg
@@ -1,2 +1,2 @@
 set noparent
-filter=-build/header_guard,-build/include,-readability/function
+filter=-build/header_guard,-build/include,-readability/function,-whitespace/indent
diff --git a/adb/adb.cpp b/adb/adb.cpp
index e526914..3d1b7b4 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -48,9 +48,7 @@
 #include <sys/mount.h>
 #endif
 
-#if ADB_TRACE
 ADB_MUTEX_DEFINE( D_lock );
-#endif
 
 int HOST = 0;
 
@@ -91,10 +89,8 @@
     char timestamp[PATH_MAX];
     strftime(timestamp, sizeof(timestamp), "%Y-%m-%d-%H-%M-%S", &now);
 
-    char path[PATH_MAX];
-    snprintf(path, sizeof(path), "/data/adb/adb-%s-%d", timestamp, getpid());
-
-    int fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0640);
+    std::string path = android::base::StringPrintf("/data/adb/adb-%s-%d", timestamp, getpid());
+    int fd = unix_open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0640);
     if (fd == -1) {
         return;
     }
@@ -322,28 +318,6 @@
 #endif
 }
 
-#if !ADB_HOST
-static void send_msg_with_header(int fd, const char* msg, size_t msglen) {
-    char header[5];
-    if (msglen > 0xffff)
-        msglen = 0xffff;
-    snprintf(header, sizeof(header), "%04x", (unsigned)msglen);
-    WriteFdExactly(fd, header, 4);
-    WriteFdExactly(fd, msg, msglen);
-}
-#endif
-
-#if ADB_HOST
-static void send_msg_with_okay(int fd, const char* msg, size_t msglen) {
-    char header[9];
-    if (msglen > 0xffff)
-        msglen = 0xffff;
-    snprintf(header, sizeof(header), "OKAY%04x", (unsigned)msglen);
-    WriteFdExactly(fd, header, 8);
-    WriteFdExactly(fd, msg, msglen);
-}
-#endif // ADB_HOST
-
 void send_connect(atransport *t)
 {
     D("Calling send_connect \n");
@@ -356,32 +330,6 @@
     send_packet(cp, t);
 }
 
-#if ADB_HOST
-static const char* connection_state_name(atransport *t)
-{
-    if (t == NULL) {
-        return "unknown";
-    }
-
-    switch(t->connection_state) {
-    case CS_BOOTLOADER:
-        return "bootloader";
-    case CS_DEVICE:
-        return "device";
-    case CS_RECOVERY:
-        return "recovery";
-    case CS_SIDELOAD:
-        return "sideload";
-    case CS_OFFLINE:
-        return "offline";
-    case CS_UNAUTHORIZED:
-        return "unauthorized";
-    default:
-        return "unknown";
-    }
-}
-#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.
@@ -421,24 +369,24 @@
 
     const std::string& type = pieces[0];
     if (type == "bootloader") {
-        D("setting connection_state to CS_BOOTLOADER\n");
-        t->connection_state = CS_BOOTLOADER;
+        D("setting connection_state to kCsBootloader\n");
+        t->connection_state = kCsBootloader;
         update_transports();
     } else if (type == "device") {
-        D("setting connection_state to CS_DEVICE\n");
-        t->connection_state = CS_DEVICE;
+        D("setting connection_state to kCsDevice\n");
+        t->connection_state = kCsDevice;
         update_transports();
     } else if (type == "recovery") {
-        D("setting connection_state to CS_RECOVERY\n");
-        t->connection_state = CS_RECOVERY;
+        D("setting connection_state to kCsRecovery\n");
+        t->connection_state = kCsRecovery;
         update_transports();
     } else if (type == "sideload") {
-        D("setting connection_state to CS_SIDELOAD\n");
-        t->connection_state = CS_SIDELOAD;
+        D("setting connection_state to kCsSideload\n");
+        t->connection_state = kCsSideload;
         update_transports();
     } else {
-        D("setting connection_state to CS_HOST\n");
-        t->connection_state = CS_HOST;
+        D("setting connection_state to kCsHost\n");
+        t->connection_state = kCsHost;
     }
 }
 
@@ -458,7 +406,7 @@
             send_packet(p, t);
             if(HOST) send_connect(t);
         } else {
-            t->connection_state = CS_OFFLINE;
+            t->connection_state = kCsOffline;
             handle_offline(t);
             send_packet(p, t);
         }
@@ -466,8 +414,8 @@
 
     case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
             /* XXX verify version, etc */
-        if(t->connection_state != CS_OFFLINE) {
-            t->connection_state = CS_OFFLINE;
+        if(t->connection_state != kCsOffline) {
+            t->connection_state = kCsOffline;
             handle_offline(t);
         }
 
@@ -483,7 +431,7 @@
 
     case A_AUTH:
         if (p->msg.arg0 == ADB_AUTH_TOKEN) {
-            t->connection_state = CS_UNAUTHORIZED;
+            t->connection_state = kCsUnauthorized;
             t->key = adb_auth_nextkey(t->key);
             if (t->key) {
                 send_auth_response(p->data, p->msg.data_length, t);
@@ -748,24 +696,15 @@
 // Try to handle a network forwarding request.
 // This returns 1 on success, 0 on failure, and -1 to indicate this is not
 // a forwarding-related request.
-int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd)
+int handle_forward_request(const char* service, TransportType type, const char* serial, int reply_fd)
 {
     if (!strcmp(service, "list-forward")) {
         // Create the list of forward redirections.
-        int buffer_size = format_listeners(NULL, 0);
-        // Add one byte for the trailing zero.
-        char* buffer = reinterpret_cast<char*>(malloc(buffer_size + 1));
-        if (buffer == nullptr) {
-            sendfailmsg(reply_fd, "not enough memory");
-            return 1;
-        }
-        (void) format_listeners(buffer, buffer_size + 1);
+        std::string listeners = format_listeners();
 #if ADB_HOST
-        send_msg_with_okay(reply_fd, buffer, buffer_size);
-#else
-        send_msg_with_header(reply_fd, buffer, buffer_size);
+        SendOkay(reply_fd);
 #endif
-        free(buffer);
+        SendProtocolString(reply_fd, listeners);
         return 1;
     }
 
@@ -773,9 +712,9 @@
         remove_all_listeners();
 #if ADB_HOST
         /* On the host: 1st OKAY is connect, 2nd OKAY is status */
-        adb_write(reply_fd, "OKAY", 4);
+        SendOkay(reply_fd);
 #endif
-        adb_write(reply_fd, "OKAY", 4);
+        SendOkay(reply_fd);
         return 1;
     }
 
@@ -800,31 +739,31 @@
         if (createForward) {
             // Check forward: parameter format: '<local>;<remote>'
             if(remote == 0) {
-                sendfailmsg(reply_fd, "malformed forward spec");
+                SendFail(reply_fd, "malformed forward spec");
                 return 1;
             }
 
             *remote++ = 0;
             if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) {
-                sendfailmsg(reply_fd, "malformed forward spec");
+                SendFail(reply_fd, "malformed forward spec");
                 return 1;
             }
         } else {
             // Check killforward: parameter format: '<local>'
             if (local[0] == 0) {
-                sendfailmsg(reply_fd, "malformed forward spec");
+                SendFail(reply_fd, "malformed forward spec");
                 return 1;
             }
         }
 
         std::string error_msg;
-        transport = acquire_one_transport(CS_ANY, ttype, serial, &error_msg);
+        transport = acquire_one_transport(kCsAny, type, serial, &error_msg);
         if (!transport) {
-            sendfailmsg(reply_fd, error_msg.c_str());
+            SendFail(reply_fd, error_msg);
             return 1;
         }
 
-        install_status_t r;
+        InstallStatus r;
         if (createForward) {
             r = install_listener(local, remote, transport, no_rebind);
         } else {
@@ -833,9 +772,9 @@
         if (r == INSTALL_STATUS_OK) {
 #if ADB_HOST
             /* On the host: 1st OKAY is connect, 2nd OKAY is status */
-            WriteFdExactly(reply_fd, "OKAY", 4);
+            SendOkay(reply_fd);
 #endif
-            WriteFdExactly(reply_fd, "OKAY", 4);
+            SendOkay(reply_fd);
             return 1;
         }
 
@@ -851,19 +790,18 @@
             break;
           case INSTALL_STATUS_LISTENER_NOT_FOUND: message = "listener not found"; break;
         }
-        sendfailmsg(reply_fd, message.c_str());
+        SendFail(reply_fd, message);
         return 1;
     }
     return 0;
 }
 
-int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
-{
-    if(!strcmp(service, "kill")) {
-        fprintf(stderr,"adb server killed by remote request\n");
+int handle_host_request(const char* service, TransportType type,
+                        const char* serial, int reply_fd, asocket* s) {
+    if (strcmp(service, "kill") == 0) {
+        fprintf(stderr, "adb server killed by remote request\n");
         fflush(stdout);
-        adb_write(reply_fd, "OKAY", 4);
-        usb_cleanup();
+        SendOkay(reply_fd);
         exit(0);
     }
 
@@ -874,7 +812,7 @@
     // "transport-local:" is used for switching transport to the only local transport
     // "transport-any:" is used for switching transport to the only transport
     if (!strncmp(service, "transport", strlen("transport"))) {
-        transport_type type = kTransportAny;
+        TransportType type = kTransportAny;
 
         if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
             type = kTransportUsb;
@@ -888,36 +826,36 @@
         }
 
         std::string error_msg = "unknown failure";
-        transport = acquire_one_transport(CS_ANY, type, serial, &error_msg);
+        transport = acquire_one_transport(kCsAny, type, serial, &error_msg);
 
         if (transport) {
             s->transport = transport;
-            adb_write(reply_fd, "OKAY", 4);
+            SendOkay(reply_fd);
         } else {
-            sendfailmsg(reply_fd, error_msg.c_str());
+            SendFail(reply_fd, error_msg);
         }
         return 1;
     }
 
     // return a list of all connected devices
     if (!strncmp(service, "devices", 7)) {
-        char buffer[4096];
-        int use_long = !strcmp(service+7, "-l");
-        if (use_long || service[7] == 0) {
-            memset(buffer, 0, sizeof(buffer));
-            D("Getting device list \n");
-            list_transports(buffer, sizeof(buffer), use_long);
-            D("Wrote device list \n");
-            send_msg_with_okay(reply_fd, buffer, strlen(buffer));
+        bool long_listing = (strcmp(service+7, "-l") == 0);
+        if (long_listing || service[7] == 0) {
+            D("Getting device list...\n");
+            std::string device_list = list_transports(long_listing);
+            D("Sending device list...\n");
+            SendOkay(reply_fd);
+            SendProtocolString(reply_fd, device_list);
             return 0;
         }
+        return 1;
     }
 
     // remove TCP transport
     if (!strncmp(service, "disconnect:", 11)) {
         char buffer[4096];
         memset(buffer, 0, sizeof(buffer));
-        char* serial = service + 11;
+        const char* serial = service + 11;
         if (serial[0] == 0) {
             // disconnect from all TCP devices
             unregister_all_tcp_transports();
@@ -937,34 +875,36 @@
             }
         }
 
-        send_msg_with_okay(reply_fd, buffer, strlen(buffer));
+        SendOkay(reply_fd);
+        SendProtocolString(reply_fd, buffer);
         return 0;
     }
 
     // returns our value for ADB_SERVER_VERSION
     if (!strcmp(service, "version")) {
-        char version[12];
-        snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
-        send_msg_with_okay(reply_fd, version, strlen(version));
+        SendOkay(reply_fd);
+        SendProtocolString(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION));
         return 0;
     }
 
     if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
         const char *out = "unknown";
-        transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+        transport = acquire_one_transport(kCsAny, type, serial, NULL);
         if (transport && transport->serial) {
             out = transport->serial;
         }
-        send_msg_with_okay(reply_fd, out, strlen(out));
+        SendOkay(reply_fd);
+        SendProtocolString(reply_fd, out);
         return 0;
     }
     if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
         const char *out = "unknown";
-        transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+        transport = acquire_one_transport(kCsAny, type, serial, NULL);
         if (transport && transport->devpath) {
             out = transport->devpath;
         }
-        send_msg_with_okay(reply_fd, out, strlen(out));
+        SendOkay(reply_fd);
+        SendProtocolString(reply_fd, out);
         return 0;
     }
     // indicates a new emulator instance has started
@@ -976,14 +916,14 @@
     }
 
     if(!strncmp(service,"get-state",strlen("get-state"))) {
-        transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
-        const char *state = connection_state_name(transport);
-        send_msg_with_okay(reply_fd, state, strlen(state));
+        transport = acquire_one_transport(kCsAny, type, serial, NULL);
+        SendOkay(reply_fd);
+        SendProtocolString(reply_fd, transport->connection_state_name());
         return 0;
     }
 #endif // ADB_HOST
 
-    int ret = handle_forward_request(service, ttype, serial, reply_fd);
+    int ret = handle_forward_request(service, type, serial, reply_fd);
     if (ret >= 0)
       return ret - 1;
     return -1;
diff --git a/adb/adb.h b/adb/adb.h
index cb2cf60..e8960e3 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -161,7 +161,7 @@
 ** object, it's a special value used to indicate that a client wants to
 ** connect to a service implemented within the ADB server itself.
 */
-enum transport_type {
+enum TransportType {
         kTransportUsb,
         kTransportLocal,
         kTransportAny,
@@ -170,6 +170,18 @@
 
 #define TOKEN_SIZE 20
 
+enum ConnectionState {
+    kCsAny = -1,
+    kCsOffline = 0,
+    kCsBootloader,
+    kCsDevice,
+    kCsHost,
+    kCsRecovery,
+    kCsNoPerm,  // Insufficient permissions to communicate with the device.
+    kCsSideload,
+    kCsUnauthorized,
+};
+
 struct atransport
 {
     atransport *next;
@@ -187,7 +199,7 @@
     unsigned sync_token;
     int connection_state;
     int online;
-    transport_type type;
+    TransportType type;
 
         /* usb handle or socket fd as needed */
     usb_handle *usb;
@@ -209,6 +221,8 @@
     unsigned char token[TOKEN_SIZE];
     fdevent auth_fde;
     unsigned failed_auth_attempts;
+
+    const char* connection_state_name() const;
 };
 
 
@@ -243,8 +257,6 @@
 void remove_socket(asocket *s);
 void close_all_sockets(atransport *t);
 
-#define  LOCAL_CLIENT_PREFIX  "emulator-"
-
 asocket *create_local_socket(int fd);
 asocket *create_local_service_socket(const char *destination);
 
@@ -266,7 +278,7 @@
 int get_available_local_transport_index();
 #endif
 int  init_socket_transport(atransport *t, int s, int port, int local);
-void init_usb_transport(atransport *t, usb_handle *usb, int state);
+void init_usb_transport(atransport *t, usb_handle *usb, ConnectionState state);
 
 #if ADB_HOST
 atransport* find_emulator_transport_by_adb_port(int adb_port);
@@ -284,7 +296,7 @@
 int       create_jdwp_connection_fd(int  jdwp_pid);
 #endif
 
-int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd);
+int handle_forward_request(const char* service, TransportType type, const char* serial, int reply_fd);
 
 #if !ADB_HOST
 void framebuffer_service(int fd, void *cookie);
@@ -324,7 +336,6 @@
 
 /* usb host/client interface */
 void usb_init();
-void usb_cleanup();
 int usb_write(usb_handle *h, const void *data, int len);
 int usb_read(usb_handle *h, void *data, int len);
 int usb_close(usb_handle *h);
@@ -337,27 +348,12 @@
 
 int adb_commandline(int argc, const char **argv);
 
-int connection_state(atransport *t);
-
-#define CS_ANY       -1
-#define CS_OFFLINE    0
-#define CS_BOOTLOADER 1
-#define CS_DEVICE     2
-#define CS_HOST       3
-#define CS_RECOVERY   4
-#define CS_NOPERM     5 /* Insufficient permissions to communicate with the device */
-#define CS_SIDELOAD   6
-#define CS_UNAUTHORIZED 7
+ConnectionState connection_state(atransport *t);
 
 extern const char *adb_device_banner;
 extern int HOST;
 extern int SHELL_EXIT_NOTIFY_FD;
 
-enum subproc_mode {
-    SUBPROC_PTY = 0,
-    SUBPROC_RAW = 1,
-} ;
-
 #define CHUNK_SIZE (64*1024)
 
 #if !ADB_HOST
@@ -371,8 +367,7 @@
 #define USB_FFS_ADB_IN    USB_FFS_ADB_EP(ep2)
 #endif
 
-int sendfailmsg(int fd, const char *reason);
-int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s);
+int handle_host_request(const char* service, TransportType type, const char* serial, int reply_fd, asocket *s);
 
 void handle_online(atransport *t);
 void handle_offline(atransport *t);
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 510dcc2..61a3777 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -173,7 +173,7 @@
         return 0;
     }
 
-    outfile = fopen(path, "we");
+    outfile = fopen(path, "w");
     if (!outfile) {
         D("Failed to open '%s'\n", path);
         return 0;
@@ -239,7 +239,7 @@
 
     old_mask = umask(077);
 
-    f = fopen(file, "we");
+    f = fopen(file, "w");
     if (!f) {
         D("Failed to open '%s'\n", file);
         umask(old_mask);
@@ -273,7 +273,7 @@
 {
     D("read_key '%s'\n", file);
 
-    FILE* fp = fopen(file, "re");
+    FILE* fp = fopen(file, "r");
     if (!fp) {
         D("Failed to open '%s': %s\n", file, strerror(errno));
         return 0;
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index 0b2d038..c73d737 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -32,16 +32,39 @@
 #include <vector>
 
 #include <base/stringprintf.h>
+#include <base/strings.h>
 
 #include "adb_io.h"
 
-static transport_type __adb_transport = kTransportAny;
+static TransportType __adb_transport = kTransportAny;
 static const char* __adb_serial = NULL;
 
 static int __adb_server_port = DEFAULT_ADB_PORT;
 static const char* __adb_server_name = NULL;
 
-void adb_set_transport(transport_type type, const char* serial)
+static std::string perror_str(const char* msg) {
+    return android::base::StringPrintf("%s: %s", msg, strerror(errno));
+}
+
+static bool ReadProtocolString(int fd, std::string* s, std::string* error) {
+    char buf[5];
+    if (!ReadFdExactly(fd, buf, 4)) {
+        *error = perror_str("protocol fault (couldn't read status length)");
+        return false;
+    }
+    buf[4] = 0;
+
+    unsigned long len = strtoul(buf, 0, 16);
+    s->resize(len, '\0');
+    if (!ReadFdExactly(fd, &(*s)[0], len)) {
+        *error = perror_str("protocol fault (couldn't read status message)");
+        return false;
+    }
+
+    return true;
+}
+
+void adb_set_transport(TransportType type, const char* serial)
 {
     __adb_transport = type;
     __adb_serial = serial;
@@ -57,58 +80,6 @@
     __adb_server_name = hostname;
 }
 
-int  adb_get_emulator_console_port(void)
-{
-    const char*   serial = __adb_serial;
-    int           port;
-
-    if (serial == NULL) {
-        /* if no specific device was specified, we need to look at */
-        /* the list of connected devices, and extract an emulator  */
-        /* name from it. two emulators is an error                 */
-        std::string error;
-        char*  tmp = adb_query("host:devices", &error);
-        char*  p   = tmp;
-        if (!tmp) {
-            printf("no emulator connected: %s\n", error.c_str());
-            return -1;
-        }
-        while (*p) {
-            char*  q = strchr(p, '\n');
-            if (q != NULL)
-                *q++ = 0;
-            else
-                q = p + strlen(p);
-
-            if (!memcmp(p, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1)) {
-                if (serial != NULL) {  /* more than one emulator listed */
-                    free(tmp);
-                    return -2;
-                }
-                serial = p;
-            }
-
-            p = q;
-        }
-        free(tmp);
-
-        if (serial == NULL)
-            return -1;  /* no emulator found */
-    }
-    else {
-        if (memcmp(serial, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1) != 0)
-            return -1;  /* not an emulator */
-    }
-
-    serial += sizeof(LOCAL_CLIENT_PREFIX)-1;
-    port    = strtol(serial, NULL, 10);
-    return port;
-}
-
-std::string perror_str(const char* msg) {
-    return android::base::StringPrintf("%s: %s", msg, strerror(errno));
-}
-
 static int switch_socket_transport(int fd, std::string* error) {
     std::string service;
     if (__adb_serial) {
@@ -134,9 +105,7 @@
         service += transport_type;
     }
 
-    char tmp[5];
-    snprintf(tmp, sizeof(tmp), "%04zx", service.size());
-    if (!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, service.c_str(), service.size())) {
+    if (!SendProtocolString(fd, service)) {
         *error = perror_str("write failure during connection");
         adb_close(fd);
         return -1;
@@ -154,7 +123,6 @@
 
 bool adb_status(int fd, std::string* error) {
     char buf[5];
-
     if (!ReadFdExactly(fd, buf, 4)) {
         *error = perror_str("protocol fault (couldn't read status)");
         return false;
@@ -170,47 +138,34 @@
         return false;
     }
 
-    if (!ReadFdExactly(fd, buf, 4)) {
-        *error = perror_str("protocol fault (couldn't read status length)");
-        return false;
-    }
-    buf[4] = 0;
-
-    unsigned long len = strtoul(buf, 0, 16);
-    error->resize(len + 1, '\0'); // Ensure NUL-termination.
-    if (!ReadFdExactly(fd, &(*error)[0], len)) {
-        *error = perror_str("protocol fault (couldn't read status message)");
-    }
+    ReadProtocolString(fd, error, error);
     return false;
 }
 
-int _adb_connect(const char *service, std::string* error) {
-    char tmp[5];
-    int fd;
-
-    D("_adb_connect: %s\n", service);
-    size_t len = strlen(service);
-    if ((len < 1) || (len > 1024)) {
-        *error = android::base::StringPrintf("service name too long (%d)", static_cast<int>(len));
+int _adb_connect(const std::string& service, std::string* error) {
+    D("_adb_connect: %s\n", service.c_str());
+    if (service.empty() || service.size() > 1024) {
+        *error = android::base::StringPrintf("bad service name length (%zd)",
+                                             service.size());
         return -1;
     }
-    snprintf(tmp, sizeof tmp, "%04zx", len);
 
-    if (__adb_server_name)
+    int fd;
+    if (__adb_server_name) {
         fd = socket_network_client(__adb_server_name, __adb_server_port, SOCK_STREAM);
-    else
+    } else {
         fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
-
-    if(fd < 0) {
+    }
+    if (fd < 0) {
         *error = perror_str("cannot connect to daemon");
         return -2;
     }
 
-    if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd, error)) {
+    if (memcmp(&service[0],"host",4) != 0 && switch_socket_transport(fd, error)) {
         return -1;
     }
 
-    if(!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, service, len)) {
+    if(!SendProtocolString(fd, service)) {
         *error = perror_str("write failure during connection");
         adb_close(fd);
         return -1;
@@ -225,11 +180,11 @@
     return fd;
 }
 
-int adb_connect(const char* service, std::string* error) {
+int adb_connect(const std::string& service, std::string* error) {
     // first query the adb server's version
     int fd = _adb_connect("host:version", error);
 
-    D("adb_connect: service %s\n", service);
+    D("adb_connect: service %s\n", service.c_str());
     if (fd == -2 && __adb_server_name) {
         fprintf(stderr,"** Cannot start server on remote host\n");
         return fd;
@@ -248,21 +203,20 @@
         // fall through to _adb_connect
     } else {
         // if server was running, check its version to make sure it is not out of date
-        char buf[100];
-        size_t n;
         int version = ADB_SERVER_VERSION - 1;
 
         // if we have a file descriptor, then parse version result
         if (fd >= 0) {
-            if(!ReadFdExactly(fd, buf, 4)) goto error;
+            std::string version_string;
+            if (!ReadProtocolString(fd, &version_string, error)) {
+                goto error;
+            }
 
-            buf[4] = 0;
-            n = strtoul(buf, 0, 16);
-            if(n > sizeof(buf)) goto error;
-            if(!ReadFdExactly(fd, buf, n)) goto error;
             adb_close(fd);
 
-            if (sscanf(buf, "%04x", &version) != 1) goto error;
+            if (sscanf(&version_string[0], "%04x", &version) != 1) {
+                goto error;
+            }
         } else {
             // if fd is -1, then check for "unknown host service",
             // which would indicate a version of adb that does not support the version command
@@ -271,7 +225,7 @@
             }
         }
 
-        if(version != ADB_SERVER_VERSION) {
+        if (version != ADB_SERVER_VERSION) {
             printf("adb server is out of date.  killing...\n");
             fd = _adb_connect("host:kill", error);
             adb_close(fd);
@@ -283,7 +237,7 @@
     }
 
     // if the command is start-server, we are done.
-    if (!strcmp(service, "host:start-server")) {
+    if (service == "host:start-server") {
         return 0;
     }
 
@@ -302,7 +256,7 @@
 }
 
 
-int adb_command(const char* service, std::string* error) {
+int adb_command(const std::string& service, std::string* error) {
     int fd = adb_connect(service, error);
     if (fd < 0) {
         fprintf(stderr, "error: %s\n", error->c_str());
@@ -317,39 +271,18 @@
     return 0;
 }
 
-char* adb_query(const char* service, std::string* error) {
-    char buf[5];
-    unsigned long n;
-    char* tmp;
-
-    D("adb_query: %s\n", service);
+bool adb_query(const std::string& service, std::string* result, std::string* error) {
+    D("adb_query: %s\n", service.c_str());
     int fd = adb_connect(service, error);
     if (fd < 0) {
         fprintf(stderr,"error: %s\n", error->c_str());
         return 0;
     }
 
-    if (!ReadFdExactly(fd, buf, 4)) goto oops;
-
-    buf[4] = 0;
-    n = strtoul(buf, 0, 16);
-    // TODO: given that we just read a 4-byte hex length 0x????, why the test?
-    if (n >= 0xffff) {
-        *error = "reply is too long (>= 64KiB)";
-        goto oops;
-    }
-
-    tmp = reinterpret_cast<char*>(malloc(n + 1));
-    if(tmp == 0) goto oops;
-
-    if(!ReadFdExactly(fd, tmp, n) == 0) {
-        tmp[n] = 0;
+    result->clear();
+    if (!ReadProtocolString(fd, result, error)) {
         adb_close(fd);
-        return tmp;
+        return false;
     }
-    free(tmp);
-
-oops:
-    adb_close(fd);
-    return 0;
+    return true;
 }
diff --git a/adb/adb_client.h b/adb/adb_client.h
index 5ce7080..9895c49 100644
--- a/adb/adb_client.h
+++ b/adb/adb_client.h
@@ -1,3 +1,19 @@
+/*
+ * 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_CLIENT_H_
 #define _ADB_CLIENT_H_
 
@@ -5,51 +21,35 @@
 
 #include <string>
 
-/* 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
-*/
-int adb_connect(const char* service, std::string* error);
-int _adb_connect(const char* service, std::string* error);
+// 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.
+int adb_connect(const std::string& service, std::string* error);
+int _adb_connect(const std::string& service, std::string* error);
 
-/* connect to adb, connect to the named service, return 0 if
-** the connection succeeded AND the service returned OKAY
-*/
-int adb_command(const char* service, std::string* error);
+// Connect to adb, connect to the named service, return 0 if the connection
+// succeeded AND the service returned OKAY.
+int adb_command(const std::string& service, std::string* error);
 
-/* connect to adb, connect to the named service, return
-** a malloc'd string of its response upon success or NULL
-** on failure.
-*/
-char* adb_query(const char* service, std::string* error);
+// Connects to the named adb service and fills 'result' with the response.
+// Returns true on success; returns false and fills 'error' on failure.
+bool adb_query(const std::string& service, std::string* result, std::string* error);
 
-/* Set the preferred transport to connect to.
-*/
-void adb_set_transport(transport_type type, const char* serial);
+// Set the preferred transport to connect to.
+void adb_set_transport(TransportType type, const char* serial);
 
-/* Set TCP specifics of the transport to use
-*/
+// Set TCP specifics of the transport to use.
 void adb_set_tcp_specifics(int server_port);
 
-/* Set TCP Hostname of the transport to use
-*/
+// Set TCP Hostname of the transport to use.
 void adb_set_tcp_name(const char* hostname);
 
-/* Return the console port of the currently connected emulator (if any)
- * of -1 if there is no emulator, and -2 if there is more than one.
- * assumes adb_set_transport() was alled previously...
- */
-int  adb_get_emulator_console_port(void);
+// Send commands to the current emulator instance. Will fail if there is not
+// exactly one emulator connected (or if you use -s <serial> with a <serial>
+// that does not designate an emulator).
+int adb_send_emulator_command(int argc, const char** argv, const char* serial);
 
-/* send commands to the current emulator instance. will fail if there
- * is zero, or more than one emulator connected (or if you use -s <serial>
- * with a <serial> that does not designate an emulator)
- */
-int  adb_send_emulator_command(int  argc, const char**  argv);
-
-// Reads a standard adb status response (OKAY|FAIL) and
-// returns true in the event of OKAY, false in the event of FAIL
-// or protocol error.
+// Reads a standard adb status response (OKAY|FAIL) and returns true in the
+// event of OKAY, false in the event of FAIL or protocol error.
 bool adb_status(int fd, std::string* error);
 
 #endif
diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp
index d89f304..5ae6ec3 100644
--- a/adb/adb_io.cpp
+++ b/adb/adb_io.cpp
@@ -16,20 +16,37 @@
 
 #define TRACE_TAG TRACE_RWX
 
-#include "sysdeps.h"
 #include "adb_io.h"
 
 #include <unistd.h>
 
+#include <base/stringprintf.h>
+
 #include "adb_trace.h"
-#include "transport.h"
+#include "adb_utils.h"
+#include "sysdeps.h"
+
+bool SendProtocolString(int fd, const std::string& s) {
+    int length = s.size();
+    if (length > 0xffff) {
+        length = 0xffff;
+    }
+
+    return WriteFdFmt(fd, "%04x", length) && WriteFdExactly(fd, s);
+}
+
+bool SendOkay(int fd) {
+    return WriteFdExactly(fd, "OKAY", 4);
+}
+
+bool SendFail(int fd, const std::string& reason) {
+    return WriteFdExactly(fd, "FAIL", 4) && SendProtocolString(fd, reason);
+}
 
 bool ReadFdExactly(int fd, void* buf, size_t len) {
     char* p = reinterpret_cast<char*>(buf);
 
-#if ADB_TRACE
     size_t len0 = len;
-#endif
 
     D("readx: fd=%d wanted=%zu\n", fd, len);
     while (len > 0) {
@@ -47,12 +64,10 @@
         }
     }
 
-#if ADB_TRACE
     D("readx: fd=%d wanted=%zu got=%zu\n", fd, len0, len0 - len);
     if (ADB_TRACING) {
         dump_hex(reinterpret_cast<const unsigned char*>(buf), len0);
     }
-#endif
 
     return true;
 }
@@ -61,12 +76,10 @@
     const char* p = reinterpret_cast<const char*>(buf);
     int r;
 
-#if ADB_TRACE
     D("writex: fd=%d len=%d: ", fd, (int)len);
     if (ADB_TRACING) {
         dump_hex(reinterpret_cast<const unsigned char*>(buf), len);
     }
-#endif
 
     while (len > 0) {
         r = adb_write(fd, p, len);
@@ -90,6 +103,21 @@
     return true;
 }
 
-bool WriteStringFully(int fd, const char* str) {
+bool WriteFdExactly(int fd, const char* str) {
     return WriteFdExactly(fd, str, strlen(str));
 }
+
+bool WriteFdExactly(int fd, const std::string& str) {
+    return WriteFdExactly(fd, str.c_str(), str.size());
+}
+
+bool WriteFdFmt(int fd, const char* fmt, ...) {
+    std::string str;
+
+    va_list ap;
+    va_start(ap, fmt);
+    android::base::StringAppendV(&str, fmt, ap);
+    va_end(ap);
+
+    return WriteFdExactly(fd, str);
+}
diff --git a/adb/adb_io.h b/adb/adb_io.h
index 8d237ce..8d50a6d 100644
--- a/adb/adb_io.h
+++ b/adb/adb_io.h
@@ -17,9 +17,19 @@
 #ifndef ADB_IO_H
 #define ADB_IO_H
 
-#include <stdbool.h>
 #include <sys/types.h>
 
+#include <string>
+
+// Sends the protocol "OKAY" message.
+bool SendOkay(int fd);
+
+// Sends the protocol "FAIL" message, with the given failure reason.
+bool SendFail(int fd, const std::string& reason);
+
+// Writes a protocol-format string; a four hex digit length followed by the string data.
+bool SendProtocolString(int fd, const std::string& s);
+
 /*
  * Reads exactly len bytes from fd into buf.
  *
@@ -37,9 +47,13 @@
  * completed. If the other end of the fd (such as in a socket, pipe, or fifo),
  * is closed, errno will be set to 0.
  */
-bool WriteFdExactly(int fd, const void *buf, size_t len);
+bool WriteFdExactly(int fd, const void* buf, size_t len);
 
-/* Same as WriteFdExactly, but with an implicit len = strlen(buf). */
-bool WriteStringFully(int fd, const char* str);
+// Same as above, but for strings.
+bool WriteFdExactly(int fd, const char* s);
+bool WriteFdExactly(int fd, const std::string& s);
+
+// Same as above, but formats the string to send.
+bool WriteFdFmt(int fd, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3)));
 
 #endif /* ADB_IO_H */
diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp
index da340b2..8fd5cbf 100644
--- a/adb/adb_io_test.cpp
+++ b/adb/adb_io_test.cpp
@@ -139,16 +139,29 @@
     ASSERT_EQ(ENOSPC, errno);
 }
 
-TEST(io, WriteStringFully) {
+TEST(io, WriteFdExactly_string) {
   const char str[] = "Foobar";
   TemporaryFile tf;
   ASSERT_NE(-1, tf.fd);
 
   // Test writing a partial string to the file.
-  ASSERT_TRUE(WriteStringFully(tf.fd, str)) << strerror(errno);
+  ASSERT_TRUE(WriteFdExactly(tf.fd, str)) << strerror(errno);
   ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
 
   std::string s;
   ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s));
   EXPECT_STREQ(str, s.c_str());
 }
+
+TEST(io, WriteFdFmt) {
+    TemporaryFile tf;
+    ASSERT_NE(-1, tf.fd);
+
+    // Test writing a partial string to the file.
+    ASSERT_TRUE(WriteFdFmt(tf.fd, "Foo%s%d", "bar", 123)) << strerror(errno);
+    ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
+
+    std::string s;
+    ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s));
+    EXPECT_STREQ("Foobar123", s.c_str());
+}
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index a1a5ddb..cf193ab 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -19,6 +19,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <base/stringprintf.h>
+
 #include "sysdeps.h"
 #include "transport.h"
 
@@ -143,55 +145,22 @@
     return -1;
 }
 
-// Write a single line describing a listener to a user-provided buffer.
-// Appends a trailing zero, even in case of truncation, but the function
-// returns the full line length.
-// If |buffer| is NULL, does not write but returns required size.
-static int format_listener(alistener* l, char* buffer, size_t buffer_len) {
-    // Format is simply:
-    //
-    //  <device-serial> " " <local-name> " " <remote-name> "\n"
-    //
-    int local_len = strlen(l->local_name);
-    int connect_len = strlen(l->connect_to);
-    int serial_len = strlen(l->transport->serial);
-
-    if (buffer != NULL) {
-        snprintf(buffer, buffer_len, "%s %s %s\n",
-                l->transport->serial, l->local_name, l->connect_to);
-    }
-    // NOTE: snprintf() on Windows returns -1 in case of truncation, so
-    // return the computed line length instead.
-    return local_len + connect_len + serial_len + 3;
-}
-
-// Write the list of current listeners (network redirections) into a
-// user-provided buffer. Appends a trailing zero, even in case of
-// trunctaion, but return the full size in bytes.
-// If |buffer| is NULL, does not write but returns required size.
-int format_listeners(char* buf, size_t buflen)
-{
-    alistener* l;
-    int result = 0;
-    for (l = listener_list.next; l != &listener_list; l = l->next) {
+// Write the list of current listeners (network redirections) into a string.
+std::string format_listeners() {
+    std::string result;
+    for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
         // Ignore special listeners like those for *smartsocket*
-        if (l->connect_to[0] == '*')
-          continue;
-        int len = format_listener(l, buf, buflen);
-        // Ensure there is space for the trailing zero.
-        result += len;
-        if (buf != NULL) {
-          buf += len;
-          buflen -= len;
-          if (buflen <= 0)
-              break;
+        if (l->connect_to[0] == '*') {
+            continue;
         }
+        //  <device-serial> " " <local-name> " " <remote-name> "\n"
+        android::base::StringAppendF(&result, "%s %s %s\n",
+                                     l->transport->serial, l->local_name, l->connect_to);
     }
     return result;
 }
 
-install_status_t remove_listener(const char *local_name, atransport* transport)
-{
+InstallStatus remove_listener(const char *local_name, atransport* transport) {
     alistener *l;
 
     for (l = listener_list.next; l != &listener_list; l = l->next) {
@@ -215,13 +184,13 @@
     }
 }
 
-install_status_t install_listener(const char *local_name,
+InstallStatus install_listener(const std::string& local_name,
                                   const char *connect_to,
                                   atransport* transport,
                                   int no_rebind)
 {
     for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
-        if (strcmp(local_name, l->local_name) == 0) {
+        if (local_name == l->local_name) {
             char* cto;
 
             /* can't repurpose a smartsocket */
@@ -256,7 +225,7 @@
         goto nomem;
     }
 
-    listener->local_name = strdup(local_name);
+    listener->local_name = strdup(local_name.c_str());
     if (listener->local_name == nullptr) {
         goto nomem;
     }
@@ -266,9 +235,9 @@
         goto nomem;
     }
 
-    listener->fd = local_name_to_fd(local_name);
+    listener->fd = local_name_to_fd(listener->local_name);
     if (listener->fd < 0) {
-        printf("cannot bind '%s': %s\n", local_name, strerror(errno));
+        printf("cannot bind '%s': %s\n", listener->local_name, strerror(errno));
         free(listener->local_name);
         free(listener->connect_to);
         free(listener);
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index f55fdee..9a7ded1 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -19,8 +19,10 @@
 
 #include "adb.h"
 
+#include <string>
+
 // error/status codes for install_listener.
-enum install_status_t {
+enum InstallStatus {
   INSTALL_STATUS_OK = 0,
   INSTALL_STATUS_INTERNAL_ERROR = -1,
   INSTALL_STATUS_CANNOT_BIND = -2,
@@ -34,14 +36,14 @@
 void listener_event_func(int _fd, unsigned ev, void *_l);
 void ss_listener_event_func(int _fd, unsigned ev, void *_l);
 
-install_status_t install_listener(const char *local_name,
-                                  const char *connect_to,
-                                  atransport* transport,
-                                  int no_rebind);
+InstallStatus install_listener(const std::string& local_name,
+                               const char* connect_to,
+                               atransport* transport,
+                               int no_rebind);
 
-int format_listeners(char* buf, size_t buflen);
+std::string format_listeners();
 
-install_status_t remove_listener(const char* local_name, atransport* transport);
+InstallStatus remove_listener(const char* local_name, atransport* transport);
 void remove_all_listeners(void);
 
 #endif /* __ADB_LISTENERS_H */
diff --git a/adb/adb_main.cpp b/adb/adb_main.cpp
deleted file mode 100644
index 5acaf80..0000000
--- a/adb/adb_main.cpp
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define TRACE_TAG TRACE_ADB
-
-#include "sysdeps.h"
-
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "adb.h"
-#include "adb_auth.h"
-#include "adb_listeners.h"
-#include "transport.h"
-
-#if !ADB_HOST
-#include <getopt.h>
-#include <sys/prctl.h>
-
-#include "cutils/properties.h"
-#include "private/android_filesystem_config.h"
-#include "selinux/selinux.h"
-
-#include "qemu_tracing.h"
-#endif
-
-static void adb_cleanup(void)
-{
-    usb_cleanup();
-}
-
-#if defined(_WIN32)
-static BOOL WINAPI ctrlc_handler(DWORD type)
-{
-    exit(STATUS_CONTROL_C_EXIT);
-    return TRUE;
-}
-#endif
-
-#if ADB_HOST
-#ifdef WORKAROUND_BUG6558362
-#include <sched.h>
-#define AFFINITY_ENVVAR "ADB_CPU_AFFINITY_BUG6558362"
-void adb_set_affinity(void)
-{
-   cpu_set_t cpu_set;
-   const char* cpunum_str = getenv(AFFINITY_ENVVAR);
-   char* strtol_res;
-   int cpu_num;
-
-   if (!cpunum_str || !*cpunum_str)
-       return;
-   cpu_num = strtol(cpunum_str, &strtol_res, 0);
-   if (*strtol_res != '\0')
-     fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str, AFFINITY_ENVVAR);
-
-   sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
-   D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
-   CPU_ZERO(&cpu_set);
-   CPU_SET(cpu_num, &cpu_set);
-   sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
-   sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
-   D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
-}
-#endif
-#else /* ADB_HOST */
-static const char *root_seclabel = NULL;
-
-static void drop_capabilities_bounding_set_if_needed() {
-#ifdef ALLOW_ADBD_ROOT
-    char value[PROPERTY_VALUE_MAX];
-    property_get("ro.debuggable", value, "");
-    if (strcmp(value, "1") == 0) {
-        return;
-    }
-#endif
-    int i;
-    for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
-        if (i == CAP_SETUID || i == CAP_SETGID) {
-            // CAP_SETUID CAP_SETGID needed by /system/bin/run-as
-            continue;
-        }
-        int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
-
-        // Some kernels don't have file capabilities compiled in, and
-        // prctl(PR_CAPBSET_DROP) returns EINVAL. Don't automatically
-        // die when we see such misconfigured kernels.
-        if ((err < 0) && (errno != EINVAL)) {
-            exit(1);
-        }
-    }
-}
-
-static bool should_drop_privileges() {
-#if defined(ALLOW_ADBD_ROOT)
-    char value[PROPERTY_VALUE_MAX];
-
-    // The emulator is never secure, so don't drop privileges there.
-    // TODO: this seems like a bug --- shouldn't the emulator behave like a device?
-    property_get("ro.kernel.qemu", value, "");
-    if (strcmp(value, "1") == 0) {
-        return false;
-    }
-
-    // The properties that affect `adb root` and `adb unroot` are ro.secure and
-    // ro.debuggable. In this context the names don't make the expected behavior
-    // particularly obvious.
-    //
-    // ro.debuggable:
-    //   Allowed to become root, but not necessarily the default. Set to 1 on
-    //   eng and userdebug builds.
-    //
-    // ro.secure:
-    //   Drop privileges by default. Set to 1 on userdebug and user builds.
-    property_get("ro.secure", value, "1");
-    bool ro_secure = (strcmp(value, "1") == 0);
-
-    property_get("ro.debuggable", value, "");
-    bool ro_debuggable = (strcmp(value, "1") == 0);
-
-    // Drop privileges if ro.secure is set...
-    bool drop = ro_secure;
-
-    property_get("service.adb.root", value, "");
-    bool adb_root = (strcmp(value, "1") == 0);
-    bool adb_unroot = (strcmp(value, "0") == 0);
-
-    // ...except "adb root" lets you keep privileges in a debuggable build.
-    if (ro_debuggable && adb_root) {
-        drop = false;
-    }
-
-    // ...and "adb unroot" lets you explicitly drop privileges.
-    if (adb_unroot) {
-        drop = true;
-    }
-
-    return drop;
-#else
-    return true; // "adb root" not allowed, always drop privileges.
-#endif /* ALLOW_ADBD_ROOT */
-}
-#endif /* ADB_HOST */
-
-/* Constructs a local name of form tcp:port.
- * target_str points to the target string, it's content will be overwritten.
- * target_size is the capacity of the target string.
- * server_port is the port number to use for the local name.
- */
-void build_local_name(char* target_str, size_t target_size, int server_port)
-{
-  snprintf(target_str, target_size, "tcp:%d", server_port);
-}
-
-void start_logging(void)
-{
-#if defined(_WIN32)
-    char    temp[ MAX_PATH ];
-    FILE*   fnul;
-    FILE*   flog;
-
-    GetTempPath( sizeof(temp) - 8, temp );
-    strcat( temp, "adb.log" );
-
-    /* Win32 specific redirections */
-    fnul = fopen( "NUL", "rt" );
-    if (fnul != NULL)
-        stdin[0] = fnul[0];
-
-    flog = fopen( temp, "at" );
-    if (flog == NULL)
-        flog = fnul;
-
-    setvbuf( flog, NULL, _IONBF, 0 );
-
-    stdout[0] = flog[0];
-    stderr[0] = flog[0];
-    fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
-#else
-    int fd;
-
-    fd = unix_open("/dev/null", O_RDONLY);
-    dup2(fd, 0);
-    adb_close(fd);
-
-    fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
-    if(fd < 0) {
-        fd = unix_open("/dev/null", O_WRONLY);
-    }
-    dup2(fd, 1);
-    dup2(fd, 2);
-    adb_close(fd);
-    fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
-#endif
-}
-
-int adb_main(int is_daemon, int server_port)
-{
-#if !ADB_HOST
-    int port;
-    char value[PROPERTY_VALUE_MAX];
-
-    umask(000);
-#endif
-
-    atexit(adb_cleanup);
-#if defined(_WIN32)
-    SetConsoleCtrlHandler( ctrlc_handler, TRUE );
-#else
-    // No SIGCHLD. Let the service subproc handle its children.
-    signal(SIGPIPE, SIG_IGN);
-#endif
-
-    init_transport_registration();
-
-#if ADB_HOST
-    HOST = 1;
-
-#ifdef WORKAROUND_BUG6558362
-    if(is_daemon) adb_set_affinity();
-#endif
-    usb_init();
-    local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
-    adb_auth_init();
-
-    char local_name[30];
-    build_local_name(local_name, sizeof(local_name), server_port);
-    if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
-        exit(1);
-    }
-#else
-    // We need to call this even if auth isn't enabled because the file
-    // descriptor will always be open.
-    adbd_cloexec_auth_socket();
-
-    property_get("ro.adb.secure", value, "0");
-    auth_enabled = !strcmp(value, "1");
-    if (auth_enabled)
-        adbd_auth_init();
-
-    // Our external storage path may be different than apps, since
-    // we aren't able to bind mount after dropping root.
-    const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
-    if (NULL != adb_external_storage) {
-        setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
-    } else {
-        D("Warning: ADB_EXTERNAL_STORAGE is not set.  Leaving EXTERNAL_STORAGE"
-          " unchanged.\n");
-    }
-
-    /* add extra groups:
-    ** AID_ADB to access the USB driver
-    ** AID_LOG to read system logs (adb logcat)
-    ** AID_INPUT to diagnose input issues (getevent)
-    ** AID_INET to diagnose network issues (ping)
-    ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
-    ** AID_SDCARD_R to allow reading from the SD card
-    ** AID_SDCARD_RW to allow writing to the SD card
-    ** AID_NET_BW_STATS to read out qtaguid statistics
-    */
-    gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_NET_BT,
-                       AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
-                       AID_NET_BW_STATS };
-    if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
-        exit(1);
-    }
-
-    /* don't listen on a port (default 5037) if running in secure mode */
-    /* don't run as root if we are running in secure mode */
-    if (should_drop_privileges()) {
-        drop_capabilities_bounding_set_if_needed();
-
-        /* then switch user and group to "shell" */
-        if (setgid(AID_SHELL) != 0) {
-            exit(1);
-        }
-        if (setuid(AID_SHELL) != 0) {
-            exit(1);
-        }
-
-        D("Local port disabled\n");
-    } else {
-        char local_name[30];
-        if ((root_seclabel != NULL) && (is_selinux_enabled() > 0)) {
-            // b/12587913: fix setcon to allow const pointers
-            if (setcon((char *)root_seclabel) < 0) {
-                exit(1);
-            }
-        }
-        build_local_name(local_name, sizeof(local_name), server_port);
-        if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
-            exit(1);
-        }
-    }
-
-    int usb = 0;
-    if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) {
-        // listen on USB
-        usb_init();
-        usb = 1;
-    }
-
-    // If one of these properties is set, also listen on that port
-    // If one of the properties isn't set and we couldn't listen on usb,
-    // listen on the default port.
-    property_get("service.adb.tcp.port", value, "");
-    if (!value[0]) {
-        property_get("persist.adb.tcp.port", value, "");
-    }
-    if (sscanf(value, "%d", &port) == 1 && port > 0) {
-        printf("using port=%d\n", port);
-        // listen on TCP port specified by service.adb.tcp.port property
-        local_init(port);
-    } else if (!usb) {
-        // listen on default port
-        local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
-    }
-
-    D("adb_main(): pre init_jdwp()\n");
-    init_jdwp();
-    D("adb_main(): post init_jdwp()\n");
-#endif
-
-    if (is_daemon)
-    {
-        // inform our parent that we are up and running.
-#if defined(_WIN32)
-        DWORD  count;
-        WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL );
-#else
-        fprintf(stderr, "OK\n");
-#endif
-        start_logging();
-    }
-    D("Event loop starting\n");
-
-    fdevent_loop();
-
-    usb_cleanup();
-
-    return 0;
-}
-
-#if !ADB_HOST
-void close_stdin() {
-    int fd = unix_open("/dev/null", O_RDONLY);
-    if (fd == -1) {
-        perror("failed to open /dev/null, stdin will remain open");
-        return;
-    }
-    dup2(fd, 0);
-    adb_close(fd);
-}
-#endif
-
-int main(int argc, char **argv) {
-#if ADB_HOST
-    adb_sysdeps_init();
-#else
-    close_stdin();
-#endif
-    adb_trace_init();
-
-#if ADB_HOST
-    D("Handling commandline()\n");
-    return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
-#else
-    /* If adbd runs inside the emulator this will enable adb tracing via
-     * adb-debug qemud service in the emulator. */
-    adb_qemu_trace_init();
-    while (true) {
-        int c;
-        int option_index = 0;
-        static struct option opts[] = {
-            {"root_seclabel", required_argument, 0, 's' },
-            {"device_banner", required_argument, 0, 'b' }
-        };
-        c = getopt_long(argc, argv, "", opts, &option_index);
-        if (c == -1)
-            break;
-        switch (c) {
-        case 's':
-            root_seclabel = optarg;
-            break;
-        case 'b':
-            adb_device_banner = optarg;
-            break;
-        default:
-            break;
-        }
-    }
-
-    D("Handling main()\n");
-    return adb_main(0, DEFAULT_ADB_PORT);
-#endif
-}
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index 32b6ae4..63d4151 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -23,9 +23,6 @@
 #include <stdio.h>
 #endif
 
-/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
-#define  ADB_TRACE    1
-
 /* IMPORTANT: if you change the following list, don't
  * forget to update the corresponding 'tags' table in
  * the adb_trace_init() function implemented in adb.c
@@ -45,8 +42,6 @@
     TRACE_FDEVENT,
 } ;
 
-#if ADB_TRACE
-
 #if !ADB_HOST
 /*
  * When running inside the emulator, guest's adbd can connect to 'adb-debug'
@@ -97,19 +92,6 @@
                 errno = save_errno;                    \
            }                                           \
         } while (0)
-#  define  DD(...)                                     \
-        do {                                           \
-            int save_errno = errno;                    \
-            adb_mutex_lock(&D_lock);                   \
-            fprintf(stderr, "%16s: %5d:%5lu | ",       \
-                    __FUNCTION__,                      \
-                    getpid(), adb_thread_id());        \
-            errno = save_errno;                        \
-            fprintf(stderr, __VA_ARGS__ );             \
-            fflush(stderr);                            \
-            adb_mutex_unlock(&D_lock);                 \
-            errno = save_errno;                        \
-        } while (0)
 #else
 #  define  D(...)                                      \
         do {                                           \
@@ -129,19 +111,6 @@
                     __VA_ARGS__ );                     \
             }                                          \
         } while (0)
-#  define  DD(...)                                     \
-        do {                                           \
-          __android_log_print(                         \
-              ANDROID_LOG_INFO,                        \
-              __FUNCTION__,                            \
-              __VA_ARGS__ );                           \
-        } while (0)
 #endif /* ADB_HOST */
-#else
-#  define  D(...)          ((void)0)
-#  define  DR(...)         ((void)0)
-#  define  DD(...)         ((void)0)
-#  define  ADB_TRACING     0
-#endif /* ADB_TRACE */
 
 #endif /* __ADB_TRACE_H */
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index f10c143..604bd57 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define TRACE_TAG TRACE_ADB
+
 #include "adb_utils.h"
 
 #include <stdlib.h>
@@ -21,6 +23,11 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <algorithm>
+
+#include <base/stringprintf.h>
+
+#include "adb_trace.h"
 #include "sysdeps.h"
 
 bool getcwd(std::string* s) {
@@ -38,11 +45,16 @@
 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;
-      }
+  // Escape any ' in the string (before we single-quote the whole thing).
+  // The correct way to do this for the shell is to replace ' with '\'' --- that is,
+  // close the existing single-quoted string, escape a single single-quote, and start
+  // a new single-quoted string. Like the C preprocessor, the shell will concatenate
+  // these pieces into one string.
+  for (size_t i = 0; i < s.size(); ++i) {
+    if (s[i] == '\'') {
+      result.insert(i, "'\\'");
+      i += 2;
+    }
   }
 
   // Prefix and suffix the whole string with '.
@@ -50,3 +62,25 @@
   result.push_back('\'');
   return result;
 }
+
+void dump_hex(const void* data, size_t byte_count) {
+    byte_count = std::min(byte_count, size_t(16));
+
+    const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
+
+    std::string line;
+    for (size_t i = 0; i < byte_count; ++i) {
+        android::base::StringAppendF(&line, "%02x", p[i]);
+    }
+    line.push_back(' ');
+
+    for (size_t i = 0; i < byte_count; ++i) {
+        int c = p[i];
+        if (c < 32 || c > 127) {
+            c = '.';
+        }
+        line.push_back(c);
+    }
+
+    DR("%s\n", line.c_str());
+}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 4b64afa..84f7d0c 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -24,4 +24,6 @@
 
 std::string escape_arg(const std::string& s);
 
+void dump_hex(const void* ptr, size_t byte_count);
+
 #endif
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index a395079..052aea5 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -30,21 +30,21 @@
   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')", 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)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/client/main.cpp b/adb/client/main.cpp
new file mode 100644
index 0000000..f48182d
--- /dev/null
+++ b/adb/client/main.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// We only build the affinity WAR code for Linux.
+#if defined(__linux__)
+#include <sched.h>
+#endif
+
+#include "base/file.h"
+#include "base/logging.h"
+#include "base/stringprintf.h"
+
+#include "adb.h"
+#include "adb_auth.h"
+#include "adb_listeners.h"
+#include "transport.h"
+
+#if defined(WORKAROUND_BUG6558362) && defined(__linux__)
+static const bool kWorkaroundBug6558362 = true;
+#else
+static const bool kWorkaroundBug6558362 = false;
+#endif
+
+static void adb_workaround_affinity(void) {
+#if defined(__linux__)
+    const char affinity_env[] = "ADB_CPU_AFFINITY_BUG6558362";
+    const char* cpunum_str = getenv(affinity_env);
+    if (cpunum_str == nullptr || *cpunum_str == '\0') {
+        return;
+    }
+
+    char* strtol_res;
+    int cpu_num = strtol(cpunum_str, &strtol_res, 0);
+    if (*strtol_res != '\0') {
+        fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str,
+              affinity_env);
+    }
+
+    cpu_set_t cpu_set;
+    sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
+    D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
+
+    CPU_ZERO(&cpu_set);
+    CPU_SET(cpu_num, &cpu_set);
+    sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
+
+    sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
+    D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
+#else
+    // No workaround was ever implemented for the other platforms.
+#endif
+}
+
+#if defined(_WIN32)
+static const char kNullFileName[] = "NUL";
+
+static BOOL WINAPI ctrlc_handler(DWORD type) {
+    exit(STATUS_CONTROL_C_EXIT);
+    return TRUE;
+}
+
+static std::string GetLogFilePath() {
+    const char log_name[] = "adb.log";
+    char temp_path[MAX_PATH - sizeof(log_name) + 1];
+
+    // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992%28v=vs.85%29.aspx
+    DWORD nchars = GetTempPath(sizeof(temp_path), temp_path);
+    CHECK_LE(nchars, sizeof(temp_path));
+    if (nchars == 0) {
+        // TODO(danalbert): Log the error message from FormatError().
+        // Windows unfortunately has two errnos, errno and GetLastError(), so
+        // I'm not sure what to do about PLOG here. Probably better to just
+        // ignore it and add a simplified version of FormatError() for use in
+        // log messages.
+        LOG(ERROR) << "Error creating log file";
+    }
+
+    return std::string(temp_path) + log_name;
+}
+#else
+static const char kNullFileName[] = "/dev/null";
+
+static std::string GetLogFilePath() {
+    return std::string("/tmp/adb.log");
+}
+#endif
+
+static void close_stdin() {
+    int fd = unix_open(kNullFileName, O_RDONLY);
+    CHECK_NE(fd, -1);
+    dup2(fd, STDIN_FILENO);
+    adb_close(fd);
+}
+
+static void setup_daemon_logging(void) {
+    int fd = unix_open(GetLogFilePath().c_str(), O_WRONLY | O_CREAT | O_APPEND,
+                       0640);
+    if (fd == -1) {
+        fd = unix_open(kNullFileName, O_WRONLY);
+    }
+    dup2(fd, STDOUT_FILENO);
+    dup2(fd, STDERR_FILENO);
+    adb_close(fd);
+    fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid());
+}
+
+int adb_main(int is_daemon, int server_port) {
+    HOST = 1;
+
+#if defined(_WIN32)
+    SetConsoleCtrlHandler(ctrlc_handler, TRUE);
+#else
+    signal(SIGPIPE, SIG_IGN);
+#endif
+
+    init_transport_registration();
+
+    if (kWorkaroundBug6558362 && is_daemon) {
+        adb_workaround_affinity();
+    }
+
+    usb_init();
+    local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+    adb_auth_init();
+
+    std::string local_name = android::base::StringPrintf("tcp:%d", server_port);
+    if (install_listener(local_name, "*smartsocket*", nullptr, 0)) {
+        LOG(FATAL) << "Could not install *smartsocket* listener";
+    }
+
+    if (is_daemon) {
+        // Inform our parent that we are up and running.
+        // TODO(danalbert): Can't use SendOkay because we're sending "OK\n", not
+        // "OKAY".
+        // TODO(danalbert): Why do we use stdout for Windows?
+#if defined(_WIN32)
+        int reply_fd = STDOUT_FILENO;
+        // Change stdout mode to binary so \n => \r\n translation does not
+        // occur. In a moment stdout will be reopened to the daemon log file
+        // anyway.
+        _setmode(reply_fd, _O_BINARY);
+#else
+        int reply_fd = STDERR_FILENO;
+#endif
+        android::base::WriteStringToFd("OK\n", reply_fd);
+        close_stdin();
+        setup_daemon_logging();
+    }
+
+    D("Event loop starting\n");
+    fdevent_loop();
+
+    return 0;
+}
+
+int main(int argc, char** argv) {
+    adb_sysdeps_init();
+
+    android::base::InitLogging(argv);
+    adb_trace_init();
+    D("Handling commandline()\n");
+    return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
+}
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index b5015ea..d7bee91 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -47,14 +47,9 @@
 #include "adb_utils.h"
 #include "file_sync_service.h"
 
-static int do_cmd(transport_type ttype, const char* serial, const char *cmd, ...);
-
-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);
+static int install_app(TransportType t, const char* serial, int argc, const char** argv);
+static int install_multiple_app(TransportType t, const char* serial, int argc, const char** argv);
+static int uninstall_app(TransportType t, const char* serial, int argc, const char** argv);
 
 static std::string gProductOutPath;
 extern int gListenAll;
@@ -71,8 +66,8 @@
 }
 
 static void version(FILE* out) {
-    fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
-            ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
+    fprintf(out, "Android Debug Bridge version %d.%d.%d\nRevision %s\n",
+            ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION, ADB_REVISION);
 }
 
 static void help() {
@@ -201,7 +196,6 @@
         "  adb get-state                - prints: offline | bootloader | device\n"
         "  adb get-serialno             - prints: <serial-number>\n"
         "  adb get-devpath              - prints: <device-path>\n"
-        "  adb status-window            - continuously print device status for a specified device\n"
         "  adb remount                  - remounts the /system, /vendor (if present) and /oem (if present) partitions on the device read-write\n"
         "  adb reboot [bootloader|recovery]\n"
         "                               - reboots the device, optionally into the bootloader or recovery program.\n"
@@ -269,23 +263,16 @@
 }
 #endif
 
-static void read_and_dump(int fd)
-{
-    char buf[4096];
-    int len;
-
-    while(fd >= 0) {
+static void read_and_dump(int fd) {
+    while (fd >= 0) {
         D("read_and_dump(): pre adb_read(fd=%d)\n", fd);
-        len = adb_read(fd, buf, 4096);
+        char buf[BUFSIZ];
+        int len = adb_read(fd, buf, sizeof(buf));
         D("read_and_dump(): post adb_read(fd=%d): len=%d\n", fd, len);
-        if(len == 0) {
+        if (len <= 0) {
             break;
         }
 
-        if(len < 0) {
-            if(errno == EINTR) continue;
-            break;
-        }
         fwrite(buf, 1, len, stdout);
         fflush(stdout);
     }
@@ -409,7 +396,6 @@
 }
 
 static int interactive_shell() {
-    adb_thread_t thr;
     int fdi;
 
     std::string error;
@@ -430,38 +416,33 @@
     fds[1] = fdi;
 
     stdin_raw_init(fdi);
-    adb_thread_create(&thr, stdin_read_thread, fds);
+
+    adb_thread_create(stdin_read_thread, fds);
     read_and_dump(fd);
     stdin_raw_restore(fdi);
     return 0;
 }
 
 
-static void format_host_command(char* buffer, size_t  buflen, const char* command, transport_type ttype, const char* serial)
-{
+static std::string format_host_command(const char* command, TransportType type, const char* serial) {
     if (serial) {
-        snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
-    } else {
-        const char* prefix = "host";
-        if (ttype == kTransportUsb)
-            prefix = "host-usb";
-        else if (ttype == kTransportLocal)
-            prefix = "host-local";
-
-        snprintf(buffer, buflen, "%s:%s", prefix, command);
+        return android::base::StringPrintf("host-serial:%s:%s", serial, command);
     }
+
+    const char* prefix = "host";
+    if (type == kTransportUsb) {
+        prefix = "host-usb";
+    } else if (type == kTransportLocal) {
+        prefix = "host-local";
+    }
+    return android::base::StringPrintf("%s:%s", prefix, command);
 }
 
-static int adb_download_buffer(const char *service, const char *fn, const void* data, int sz,
+static int adb_download_buffer(const char *service, const char *fn, const void* data, unsigned sz,
                                bool show_progress)
 {
-    char buf[4096];
-    unsigned total;
-
-    sprintf(buf,"%s:%d", service, sz);
-
     std::string error;
-    int fd = adb_connect(buf, &error);
+    int fd = adb_connect(android::base::StringPrintf("%s:%d", service, sz), &error);
     if (fd < 0) {
         fprintf(stderr,"error: %s\n", error.c_str());
         return -1;
@@ -470,7 +451,7 @@
     int opt = CHUNK_SIZE;
     opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
 
-    total = sz;
+    unsigned total = sz;
     const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data);
 
     if (show_progress) {
@@ -478,7 +459,7 @@
         if(x) service = x + 1;
     }
 
-    while(sz > 0) {
+    while (sz > 0) {
         unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz;
         if (!WriteFdExactly(fd, ptr, xfer)) {
             std::string error;
@@ -497,15 +478,8 @@
         printf("\n");
     }
 
-    if(!ReadFdExactly(fd, buf, 4)){
-        fprintf(stderr,"* error reading response *\n");
-        adb_close(fd);
-        return -1;
-    }
-    if(memcmp(buf, "OKAY", 4)) {
-        buf[4] = 0;
-        fprintf(stderr,"* error response '%s' *\n", buf);
-        adb_close(fd);
+    if (!adb_status(fd, &error)) {
+        fprintf(stderr,"* error response '%s' *\n", error.c_str());
         return -1;
     }
 
@@ -550,10 +524,10 @@
         return -1;
     }
 
-    char buf[100];
-    sprintf(buf, "sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE);
+    std::string service =
+            android::base::StringPrintf("sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE);
     std::string error;
-    int fd = adb_connect(buf, &error);
+    int fd = adb_connect(service, &error);
     if (fd < 0) {
         // Try falling back to the older sideload method.  Maybe this
         // is an older device that doesn't support sideload-host.
@@ -565,18 +539,19 @@
     opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
 
     while (true) {
+        char buf[9];
         if (!ReadFdExactly(fd, buf, 8)) {
             fprintf(stderr, "* failed to read command: %s\n", strerror(errno));
             status = -1;
             goto done;
         }
+        buf[8] = '\0';
 
-        if (strncmp("DONEDONE", buf, 8) == 0) {
+        if (strcmp("DONEDONE", buf) == 0) {
             status = 0;
             break;
         }
 
-        buf[8] = '\0';
         int block = strtol(buf, NULL, 10);
 
         size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
@@ -622,51 +597,6 @@
     return status;
 }
 
-static void status_window(transport_type ttype, const char* serial)
-{
-    char command[4096];
-    char *state = 0;
-    char *laststate = 0;
-
-        /* silence stderr */
-#ifdef _WIN32
-    /* XXX: TODO */
-#else
-    int  fd;
-    fd = unix_open("/dev/null", O_WRONLY);
-    dup2(fd, 2);
-    adb_close(fd);
-#endif
-
-    format_host_command(command, sizeof command, "get-state", ttype, serial);
-
-    while (true) {
-        adb_sleep_ms(250);
-
-        if (state) {
-            free(state);
-            state = 0;
-        }
-
-        std::string error;
-        state = adb_query(command, &error);
-
-        if (state) {
-            if (laststate && !strcmp(state,laststate)){
-                continue;
-            } else {
-                if (laststate) free(laststate);
-                laststate = strdup(state);
-            }
-        }
-
-        printf("%c[2J%c[2H", 27, 27);
-        printf("Android Debug Bridge\n");
-        printf("State: %s\n", state ? state : "offline");
-        fflush(stdout);
-    }
-}
-
 /**
  * Run ppp in "notty" mode against a resource listed as the first parameter
  * eg:
@@ -736,18 +666,42 @@
 #endif /* !defined(_WIN32) */
 }
 
-static int send_shell_command(transport_type transport, const char* serial,
+static bool wait_for_device(const char* service, TransportType t, const char* serial) {
+    // Was the caller vague about what they'd like us to wait for?
+    // If so, check they weren't more specific in their choice of transport type.
+    if (strcmp(service, "wait-for-device") == 0) {
+        if (t == kTransportUsb) {
+            service = "wait-for-usb";
+        } else if (t == kTransportLocal) {
+            service = "wait-for-local";
+        } else {
+            service = "wait-for-any";
+        }
+    }
+
+    std::string cmd = format_host_command(service, t, serial);
+    std::string error;
+    if (adb_command(cmd, &error)) {
+        D("failure: %s *\n", error.c_str());
+        fprintf(stderr,"error: %s\n", error.c_str());
+        return false;
+    }
+
+    return true;
+}
+
+static int send_shell_command(TransportType transport_type, const char* serial,
                               const std::string& command) {
     int fd;
     while (true) {
         std::string error;
-        fd = adb_connect(command.c_str(), &error);
+        fd = adb_connect(command, &error);
         if (fd >= 0) {
             break;
         }
         fprintf(stderr,"- waiting for device -\n");
         adb_sleep_ms(1000);
-        do_cmd(transport, serial, "wait-for-device", 0);
+        wait_for_device("wait-for-device", transport_type, serial);
     }
 
     read_and_dump(fd);
@@ -758,7 +712,7 @@
     return rc;
 }
 
-static int logcat(transport_type transport, const char* serial, int argc, const char** argv) {
+static int logcat(TransportType 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);
 
@@ -835,7 +789,7 @@
 
     D("backup. filename=%s cmd=%s\n", filename, cmd.c_str());
     std::string error;
-    int fd = adb_connect(cmd.c_str(), &error);
+    int fd = adb_connect(cmd, &error);
     if (fd < 0) {
         fprintf(stderr, "adb: unable to connect for backup: %s\n", error.c_str());
         adb_close(outFd);
@@ -964,29 +918,35 @@
     }
 }
 
-static int adb_connect_command(const char* command) {
+static int adb_connect_command(const std::string& command) {
     std::string error;
     int fd = adb_connect(command, &error);
-    if (fd != -1) {
-        read_and_dump(fd);
-        adb_close(fd);
-        return 0;
+    if (fd < 0) {
+        fprintf(stderr, "error: %s\n", error.c_str());
+        return 1;
     }
-    fprintf(stderr, "Error: %s\n", error.c_str());
-    return 1;
+    read_and_dump(fd);
+    adb_close(fd);
+    return 0;
 }
 
-int adb_commandline(int argc, const char **argv)
-{
-    char buf[4096];
+static int adb_query_command(const std::string& command) {
+    std::string result;
+    std::string error;
+    if (!adb_query(command, &result, &error)) {
+        fprintf(stderr, "error: %s\n", error.c_str());
+        return 1;
+    }
+    printf("%s\n", result.c_str());
+    return 0;
+}
+
+int adb_commandline(int argc, const char **argv) {
     int no_daemon = 0;
     int is_daemon = 0;
     int is_server = 0;
-    int persist = 0;
     int r;
-    transport_type ttype = kTransportAny;
-    const char* serial = NULL;
-    const char* server_port_str = NULL;
+    TransportType transport_type = kTransportAny;
 
     // If defined, this should be an absolute path to
     // the directory containing all of the various system images
@@ -999,10 +959,10 @@
     }
     // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
 
-    serial = getenv("ANDROID_SERIAL");
+    const char* serial = getenv("ANDROID_SERIAL");
 
     /* Validate and assign the server port */
-    server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
+    const char* server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
     int server_port = DEFAULT_ADB_PORT;
     if (server_port_str && strlen(server_port_str) > 0) {
         server_port = (int) strtol(server_port_str, NULL, 0);
@@ -1023,8 +983,6 @@
         } else if (!strcmp(argv[0], "fork-server")) {
             /* this is a special flag used only when the ADB client launches the ADB Server */
             is_daemon = 1;
-        } else if (!strcmp(argv[0],"persist")) {
-            persist = 1;
         } else if (!strncmp(argv[0], "-p", 2)) {
             const char *product = NULL;
             if (argv[0][2] == '\0') {
@@ -1050,9 +1008,9 @@
                 argv++;
             }
         } else if (!strcmp(argv[0],"-d")) {
-            ttype = kTransportUsb;
+            transport_type = kTransportUsb;
         } else if (!strcmp(argv[0],"-e")) {
-            ttype = kTransportLocal;
+            transport_type = kTransportLocal;
         } else if (!strcmp(argv[0],"-a")) {
             gListenAll = 1;
         } else if (!strncmp(argv[0], "-H", 2)) {
@@ -1097,7 +1055,7 @@
         argv++;
     }
 
-    adb_set_transport(ttype, serial);
+    adb_set_transport(transport_type, serial);
     adb_set_tcp_specifics(server_port);
 
     if (is_server) {
@@ -1119,28 +1077,13 @@
     /* handle wait-for-* prefix */
     if (!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
         const char* service = argv[0];
-        if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
-            if (ttype == kTransportUsb) {
-                service = "wait-for-usb";
-            } else if (ttype == kTransportLocal) {
-                service = "wait-for-local";
-            } else {
-                service = "wait-for-any";
-            }
-        }
 
-        format_host_command(buf, sizeof buf, service, ttype, serial);
-
-        std::string error;
-        if (adb_command(buf, &error)) {
-            D("failure: %s *\n", error.c_str());
-            fprintf(stderr,"error: %s\n", error.c_str());
+        if (!wait_for_device(service, transport_type, serial)) {
             return 1;
         }
 
-        /* Allow a command to be run after wait-for-device,
-            * e.g. 'adb wait-for-device shell'.
-            */
+        // Allow a command to be run after wait-for-device,
+        // e.g. 'adb wait-for-device shell'.
         if (argc == 1) {
             return 0;
         }
@@ -1152,65 +1095,41 @@
 
     /* adb_connect() commands */
     if (!strcmp(argv[0], "devices")) {
-        char *tmp;
         const char *listopt;
-        if (argc < 2)
+        if (argc < 2) {
             listopt = "";
-        else if (argc == 2 && !strcmp(argv[1], "-l"))
+        } else if (argc == 2 && !strcmp(argv[1], "-l")) {
             listopt = argv[1];
-        else {
+        } else {
             fprintf(stderr, "Usage: adb devices [-l]\n");
             return 1;
         }
-        snprintf(buf, sizeof buf, "host:%s%s", argv[0], listopt);
-        std::string error;
-        tmp = adb_query(buf, &error);
-        if (tmp) {
-            printf("List of devices attached \n");
-            printf("%s\n", tmp);
-            return 0;
-        } else {
-            return 1;
-        }
+
+        std::string query = android::base::StringPrintf("host:%s%s", argv[0], listopt);
+        printf("List of devices attached\n");
+        return adb_query_command(query);
     }
     else if (!strcmp(argv[0], "connect")) {
-        char *tmp;
         if (argc != 2) {
             fprintf(stderr, "Usage: adb connect <host>[:<port>]\n");
             return 1;
         }
-        snprintf(buf, sizeof buf, "host:connect:%s", argv[1]);
-        std::string error;
-        tmp = adb_query(buf, &error);
-        if (tmp) {
-            printf("%s\n", tmp);
-            return 0;
-        } else {
-            return 1;
-        }
+
+        std::string query = android::base::StringPrintf("host:connect:%s", argv[1]);
+        return adb_query_command(query);
     }
     else if (!strcmp(argv[0], "disconnect")) {
-        char *tmp;
         if (argc > 2) {
             fprintf(stderr, "Usage: adb disconnect [<host>[:<port>]]\n");
             return 1;
         }
-        if (argc == 2) {
-            snprintf(buf, sizeof buf, "host:disconnect:%s", argv[1]);
-        } else {
-            snprintf(buf, sizeof buf, "host:disconnect:");
-        }
-        std::string error;
-        tmp = adb_query(buf, &error);
-        if (tmp) {
-            printf("%s\n", tmp);
-            return 0;
-        } else {
-            return 1;
-        }
+
+        std::string query = android::base::StringPrintf("host:disconnect:%s",
+                                                        (argc == 2) ? argv[1] : "");
+        return adb_query_command(query);
     }
     else if (!strcmp(argv[0], "emu")) {
-        return adb_send_emulator_command(argc, argv);
+        return adb_send_emulator_command(argc, argv, serial);
     }
     else if (!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
         char h = (argv[0][0] == 'h');
@@ -1231,17 +1150,18 @@
         }
 
         std::string cmd = "shell:";
-        cmd += argv[1];
-        argc -= 2;
-        argv += 2;
+        --argc;
+        ++argv;
         while (argc-- > 0) {
-            cmd += " " + escape_arg(*argv++);
+            // We don't escape here, just like ssh(1). http://b/20564385.
+            cmd += *argv++;
+            if (*argv) cmd += " ";
         }
 
         while (true) {
             D("interactive shell loop. cmd=%s\n", cmd.c_str());
             std::string error;
-            int fd = adb_connect(cmd.c_str(), &error);
+            int fd = adb_connect(cmd, &error);
             int r;
             if (fd >= 0) {
                 D("about to read_and_dump(fd=%d)\n", fd);
@@ -1254,18 +1174,12 @@
                 r = -1;
             }
 
-            if (persist) {
-                fprintf(stderr,"\n- waiting for device -\n");
-                adb_sleep_ms(1000);
-                do_cmd(ttype, serial, "wait-for-device", 0);
-            } else {
-                if (h) {
-                    printf("\x1b[0m");
-                    fflush(stdout);
-                }
-                D("interactive shell loop. return r=%d\n", r);
-                return r;
+            if (h) {
+                printf("\x1b[0m");
+                fflush(stdout);
             }
+            D("interactive shell loop. return r=%d\n", r);
+            return r;
         }
     }
     else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
@@ -1280,7 +1194,7 @@
         }
 
         std::string error;
-        int fd = adb_connect(cmd.c_str(), &error);
+        int fd = adb_connect(cmd, &error);
         if (fd < 0) {
             fprintf(stderr, "error: %s\n", error.c_str());
             return -1;
@@ -1321,23 +1235,23 @@
              !strcmp(argv[0], "unroot") ||
              !strcmp(argv[0], "disable-verity") ||
              !strcmp(argv[0], "enable-verity")) {
-        char command[100];
+        std::string command;
         if (!strcmp(argv[0], "reboot-bootloader")) {
-            snprintf(command, sizeof(command), "reboot:bootloader");
+            command = "reboot:bootloader";
         } else if (argc > 1) {
-            snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
+            command = android::base::StringPrintf("%s:%s", argv[0], argv[1]);
         } else {
-            snprintf(command, sizeof(command), "%s:", argv[0]);
+            command = android::base::StringPrintf("%s:", argv[0]);
         }
         return adb_connect_command(command);
     }
     else if (!strcmp(argv[0], "bugreport")) {
         if (argc != 1) return usage();
-        do_cmd(ttype, serial, "shell", "bugreport", 0);
-        return 0;
+        return send_shell_command(transport_type, serial, "shell:bugreport");
     }
     /* adb_command() wrapper commands */
     else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) {
+        std::string cmd;
         char host_prefix[64];
         char reverse = (char) !strcmp(argv[0], "reverse");
         char remove = 0;
@@ -1374,9 +1288,9 @@
             if (serial) {
                 snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
                         serial);
-            } else if (ttype == kTransportUsb) {
+            } else if (transport_type == kTransportUsb) {
                 snprintf(host_prefix, sizeof host_prefix, "host-usb");
-            } else if (ttype == kTransportLocal) {
+            } else if (transport_type == kTransportLocal) {
                 snprintf(host_prefix, sizeof host_prefix, "host-local");
             } else {
                 snprintf(host_prefix, sizeof host_prefix, "host");
@@ -1385,47 +1299,37 @@
 
         // Implement forward --list
         if (list) {
-            if (argc != 1)
+            if (argc != 1) {
                 return usage();
-            snprintf(buf, sizeof buf, "%s:list-forward", host_prefix);
-            std::string error;
-            char* forwards = adb_query(buf, &error);
-            if (forwards == NULL) {
-                fprintf(stderr, "error: %s\n", error.c_str());
-                return 1;
             }
-            printf("%s", forwards);
-            free(forwards);
-            return 0;
+
+            std::string query = android::base::StringPrintf("%s:list-forward", host_prefix);
+            return adb_query_command(query);
         }
 
         // Implement forward --remove-all
         else if (remove_all) {
-            if (argc != 1)
-                return usage();
-            snprintf(buf, sizeof buf, "%s:killforward-all", host_prefix);
+            if (argc != 1) return usage();
+            cmd = android::base::StringPrintf("%s:killforward-all", host_prefix);
         }
 
         // Implement forward --remove <local>
         else if (remove) {
-            if (argc != 2)
-                return usage();
-            snprintf(buf, sizeof buf, "%s:killforward:%s", host_prefix, argv[1]);
+            if (argc != 2) return usage();
+            cmd = android::base::StringPrintf("%s:killforward:%s", host_prefix, argv[1]);
         }
         // Or implement one of:
         //    forward <local> <remote>
         //    forward --no-rebind <local> <remote>
-        else
-        {
-          if (argc != 3)
-            return usage();
-          const char* command = no_rebind ? "forward:norebind" : "forward";
-          snprintf(buf, sizeof buf, "%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]);
+        else {
+            if (argc != 3) return usage();
+            const char* command = no_rebind ? "forward:norebind" : "forward";
+            cmd = android::base::StringPrintf("%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]);
         }
 
         std::string error;
-        if (adb_command(buf, &error)) {
-            fprintf(stderr,"error: %s\n", error.c_str());
+        if (adb_command(cmd, &error)) {
+            fprintf(stderr, "error: %s\n", error.c_str());
             return 1;
         }
         return 0;
@@ -1463,15 +1367,15 @@
     }
     else if (!strcmp(argv[0], "install")) {
         if (argc < 2) return usage();
-        return install_app(ttype, serial, argc, argv);
+        return install_app(transport_type, serial, argc, argv);
     }
     else if (!strcmp(argv[0], "install-multiple")) {
         if (argc < 2) return usage();
-        return install_multiple_app(ttype, serial, argc, argv);
+        return install_multiple_app(transport_type, serial, argc, argv);
     }
     else if (!strcmp(argv[0], "uninstall")) {
         if (argc < 2) return usage();
-        return uninstall_app(ttype, serial, argc, argv);
+        return uninstall_app(transport_type, serial, argc, argv);
     }
     else if (!strcmp(argv[0], "sync")) {
         std::string src;
@@ -1523,23 +1427,11 @@
         !strcmp(argv[0],"get-serialno") ||
         !strcmp(argv[0],"get-devpath"))
     {
-        format_host_command(buf, sizeof buf, argv[0], ttype, serial);
-        std::string error;
-        char* tmp = adb_query(buf, &error);
-        if (tmp) {
-            printf("%s\n", tmp);
-            return 0;
-        } else {
-            return 1;
-        }
+        return adb_query_command(format_host_command(argv[0], transport_type, serial));
     }
     /* other commands */
-    else if (!strcmp(argv[0],"status-window")) {
-        status_window(ttype, serial);
-        return 0;
-    }
     else if (!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) {
-        return logcat(ttype, serial, argc, argv);
+        return logcat(transport_type, serial, argc, argv);
     }
     else if (!strcmp(argv[0],"ppp")) {
         return ppp(argc, argv);
@@ -1575,45 +1467,7 @@
     return 1;
 }
 
-#define MAX_ARGV_LENGTH 16
-static int do_cmd(transport_type ttype, const char* serial, const char *cmd, ...)
-{
-    const char *argv[MAX_ARGV_LENGTH];
-    int argc;
-    va_list ap;
-
-    va_start(ap, cmd);
-    argc = 0;
-
-    if (serial) {
-        argv[argc++] = "-s";
-        argv[argc++] = serial;
-    } else if (ttype == kTransportUsb) {
-        argv[argc++] = "-d";
-    } else if (ttype == kTransportLocal) {
-        argv[argc++] = "-e";
-    }
-
-    argv[argc++] = cmd;
-    while(argc < MAX_ARGV_LENGTH &&
-        (argv[argc] = va_arg(ap, char*)) != 0) argc++;
-    assert(argc < MAX_ARGV_LENGTH);
-    va_end(ap);
-
-#if 0
-    int n;
-    fprintf(stderr,"argc = %d\n",argc);
-    for(n = 0; n < argc; n++) {
-        fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
-    }
-#endif
-
-    return adb_commandline(argc, argv);
-}
-
-static int pm_command(transport_type transport, const char* serial,
-                      int argc, const char** argv)
-{
+static int pm_command(TransportType transport, const char* serial, int argc, const char** argv) {
     std::string cmd = "shell:pm";
 
     while (argc-- > 0) {
@@ -1623,9 +1477,7 @@
     return send_shell_command(transport, serial, cmd);
 }
 
-static int uninstall_app(transport_type transport, const char* serial, int argc,
-                         const char** argv)
-{
+static int uninstall_app(TransportType 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) */
     if (argc == 3 && strcmp(argv[1], "-k") == 0)
@@ -1642,8 +1494,7 @@
     return pm_command(transport, serial, argc, argv);
 }
 
-static int delete_file(transport_type transport, const char* serial, char* filename)
-{
+static int delete_file(TransportType transport, const char* serial, char* filename) {
     std::string cmd = "shell:rm -f " + escape_arg(filename);
     return send_shell_command(transport, serial, cmd);
 }
@@ -1659,9 +1510,7 @@
     }
 }
 
-static int install_app(transport_type transport, const char* serial, int argc,
-                       const char** argv)
-{
+static int install_app(TransportType 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";
     const char* where = DATA_DEST;
@@ -1713,7 +1562,7 @@
     return err;
 }
 
-static int install_multiple_app(transport_type transport, const char* serial, int argc,
+static int install_multiple_app(TransportType transport, const char* serial, int argc,
                                 const char** argv)
 {
     int i;
@@ -1744,18 +1593,14 @@
         return 1;
     }
 
-#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++) {
         cmd += " " + escape_arg(argv[i]);
     }
 
     // Create install session
     std::string error;
-    int fd = adb_connect(cmd.c_str(), &error);
+    int fd = adb_connect(cmd, &error);
     if (fd < 0) {
         fprintf(stderr, "Connect error for create: %s\n", error.c_str());
         return -1;
@@ -1789,15 +1634,9 @@
             goto finalize_session;
         }
 
-#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) {
@@ -1807,7 +1646,7 @@
         }
 
         std::string error;
-        int remoteFd = adb_connect(cmd.c_str(), &error);
+        int remoteFd = adb_connect(cmd, &error);
         if (remoteFd < 0) {
             fprintf(stderr, "Connect error for write: %s\n", error.c_str());
             adb_close(localFd);
@@ -1831,13 +1670,10 @@
 
 finalize_session:
     // Commit session if we streamed everything okay; otherwise abandon
-    if (success) {
-        snprintf(buf, sizeof(buf), "exec:pm install-commit %d", session_id);
-    } else {
-        snprintf(buf, sizeof(buf), "exec:pm install-abandon %d", session_id);
-    }
-
-    fd = adb_connect(buf, &error);
+    std::string service =
+            android::base::StringPrintf("exec:pm install-%s %d",
+                                        success ? "commit" : "abandon", session_id);
+    fd = adb_connect(service, &error);
     if (fd < 0) {
         fprintf(stderr, "Connect error for finalize: %s\n", error.c_str());
         return -1;
diff --git a/adb/console.cpp b/adb/console.cpp
index 452ee41..0707960 100644
--- a/adb/console.cpp
+++ b/adb/console.cpp
@@ -1,44 +1,115 @@
+/*
+ * 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 "sysdeps.h"
-#include "adb.h"
-#include "adb_client.h"
+
 #include <stdio.h>
 
-static int  connect_to_console(void)
-{
-    int  fd, port;
+#include "base/file.h"
+#include "base/logging.h"
+#include "base/strings.h"
 
-    port = adb_get_emulator_console_port();
-    if (port < 0) {
-        if (port == -2)
-            fprintf(stderr, "error: more than one emulator detected. use -s option\n");
-        else
-            fprintf(stderr, "error: no emulator detected\n");
+#include "adb.h"
+#include "adb_client.h"
+
+// Return the console port of the currently connected emulator (if any) or -1 if
+// there is no emulator, and -2 if there is more than one.
+static int adb_get_emulator_console_port(const char* serial) {
+    if (serial) {
+        // The user specified a serial number; is it an emulator?
+        int port;
+        return (sscanf(serial, "emulator-%d", &port) == 1) ? port : -1;
+    }
+
+    // No specific device was given, so get the list of connected devices and
+    // search for emulators. If there's one, we'll take it. If there are more
+    // than one, that's an error.
+    std::string devices;
+    std::string error;
+    if (!adb_query("host:devices", &devices, &error)) {
+        fprintf(stderr, "error: no emulator connected: %s\n", error.c_str());
         return -1;
     }
-    fd = socket_loopback_client( port, SOCK_STREAM );
-    if (fd < 0) {
+
+    int port;
+    size_t emulator_count = 0;
+    for (const auto& device : android::base::Split(devices, "\n")) {
+        if (sscanf(device.c_str(), "emulator-%d", &port) == 1) {
+            if (++emulator_count > 1) {
+                fprintf(
+                    stderr, "error: more than one emulator detected; use -s\n");
+                return -1;
+            }
+        }
+    }
+
+    if (emulator_count == 0) {
+        fprintf(stderr, "error: no emulator detected\n");
+        return -1;
+    }
+
+    return port;
+}
+
+static int connect_to_console(const char* serial) {
+    int port = adb_get_emulator_console_port(serial);
+    if (port == -1) {
+        return -1;
+    }
+
+    int fd = socket_loopback_client(port, SOCK_STREAM);
+    if (fd == -1) {
         fprintf(stderr, "error: could not connect to TCP port %d\n", port);
         return -1;
     }
-    return  fd;
+    return fd;
 }
 
-
-int  adb_send_emulator_command(int  argc, const char**  argv)
-{
-    int   fd, nn;
-
-    fd = connect_to_console();
-    if (fd < 0)
+int adb_send_emulator_command(int argc, const char** argv, const char* serial) {
+    int fd = connect_to_console(serial);
+    if (fd == -1) {
         return 1;
-
-#define  QUIT  "quit\n"
-
-    for (nn = 1; nn < argc; nn++) {
-        adb_write( fd, argv[nn], strlen(argv[nn]) );
-        adb_write( fd, (nn == argc-1) ? "\n" : " ", 1 );
     }
-    adb_write( fd, QUIT, sizeof(QUIT)-1 );
+
+    for (int i = 1; i < argc; i++) {
+        adb_write(fd, argv[i], strlen(argv[i]));
+        adb_write(fd, i == argc - 1 ? "\n" : " ", 1);
+    }
+
+    const char disconnect_command[] = "quit\n";
+    if (adb_write(fd, disconnect_command, sizeof(disconnect_command) - 1) == -1) {
+        LOG(FATAL) << "Could not finalize emulator command";
+    }
+
+    // Drain output that the emulator console has sent us to prevent a problem
+    // on Windows where if adb closes the socket without reading all the data,
+    // the emulator's next call to recv() will have an ECONNABORTED error,
+    // preventing the emulator from reading the command that adb has sent.
+    // https://code.google.com/p/android/issues/detail?id=21021
+    int result;
+    do {
+        char buf[BUFSIZ];
+        result = adb_read(fd, buf, sizeof(buf));
+        // Keep reading until zero bytes (EOF) or an error. If 'adb emu kill'
+        // is executed, the emulator calls exit() which causes adb to get
+        // ECONNRESET. Any other emu command is followed by the quit command
+        // that we sent above, and that causes the emulator to close the socket
+        // which should cause zero bytes (EOF) to be returned.
+    } while (result > 0);
+
     adb_close(fd);
 
     return 0;
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
new file mode 100644
index 0000000..99ff539
--- /dev/null
+++ b/adb/daemon/main.cpp
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <sys/prctl.h>
+
+#include "base/logging.h"
+#include "base/stringprintf.h"
+#include "cutils/properties.h"
+#include "private/android_filesystem_config.h"
+#include "selinux/selinux.h"
+
+#include "adb.h"
+#include "adb_auth.h"
+#include "adb_listeners.h"
+#include "transport.h"
+#include "qemu_tracing.h"
+
+static const char* root_seclabel = nullptr;
+
+static void drop_capabilities_bounding_set_if_needed() {
+#ifdef ALLOW_ADBD_ROOT
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.debuggable", value, "");
+    if (strcmp(value, "1") == 0) {
+        return;
+    }
+#endif
+    for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
+        if (i == CAP_SETUID || i == CAP_SETGID) {
+            // CAP_SETUID CAP_SETGID needed by /system/bin/run-as
+            continue;
+        }
+
+        int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
+
+        // Some kernels don't have file capabilities compiled in, and
+        // prctl(PR_CAPBSET_DROP) returns EINVAL. Don't automatically
+        // die when we see such misconfigured kernels.
+        if ((err < 0) && (errno != EINVAL)) {
+            PLOG(FATAL) << "Could not drop capabilities";
+        }
+    }
+}
+
+static bool should_drop_privileges() {
+#if defined(ALLOW_ADBD_ROOT)
+    char value[PROPERTY_VALUE_MAX];
+
+    // The emulator is never secure, so don't drop privileges there.
+    // TODO: this seems like a bug --- shouldn't the emulator behave like a device?
+    property_get("ro.kernel.qemu", value, "");
+    if (strcmp(value, "1") == 0) {
+        return false;
+    }
+
+    // The properties that affect `adb root` and `adb unroot` are ro.secure and
+    // ro.debuggable. In this context the names don't make the expected behavior
+    // particularly obvious.
+    //
+    // ro.debuggable:
+    //   Allowed to become root, but not necessarily the default. Set to 1 on
+    //   eng and userdebug builds.
+    //
+    // ro.secure:
+    //   Drop privileges by default. Set to 1 on userdebug and user builds.
+    property_get("ro.secure", value, "1");
+    bool ro_secure = (strcmp(value, "1") == 0);
+
+    property_get("ro.debuggable", value, "");
+    bool ro_debuggable = (strcmp(value, "1") == 0);
+
+    // Drop privileges if ro.secure is set...
+    bool drop = ro_secure;
+
+    property_get("service.adb.root", value, "");
+    bool adb_root = (strcmp(value, "1") == 0);
+    bool adb_unroot = (strcmp(value, "0") == 0);
+
+    // ...except "adb root" lets you keep privileges in a debuggable build.
+    if (ro_debuggable && adb_root) {
+        drop = false;
+    }
+
+    // ...and "adb unroot" lets you explicitly drop privileges.
+    if (adb_unroot) {
+        drop = true;
+    }
+
+    return drop;
+#else
+    return true; // "adb root" not allowed, always drop privileges.
+#endif // ALLOW_ADBD_ROOT
+}
+
+int adbd_main(int server_port) {
+    umask(0);
+
+    signal(SIGPIPE, SIG_IGN);
+
+    init_transport_registration();
+
+    // We need to call this even if auth isn't enabled because the file
+    // descriptor will always be open.
+    adbd_cloexec_auth_socket();
+
+    auth_enabled = property_get_bool("ro.adb.secure", 0) != 0;
+    if (auth_enabled) {
+        adbd_auth_init();
+    }
+
+    // Our external storage path may be different than apps, since
+    // we aren't able to bind mount after dropping root.
+    const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
+    if (adb_external_storage != nullptr) {
+        setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
+    } else {
+        D("Warning: ADB_EXTERNAL_STORAGE is not set.  Leaving EXTERNAL_STORAGE"
+          " unchanged.\n");
+    }
+
+    // Add extra groups:
+    // AID_ADB to access the USB driver
+    // AID_LOG to read system logs (adb logcat)
+    // AID_INPUT to diagnose input issues (getevent)
+    // AID_INET to diagnose network issues (ping)
+    // AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
+    // AID_SDCARD_R to allow reading from the SD card
+    // AID_SDCARD_RW to allow writing to the SD card
+    // AID_NET_BW_STATS to read out qtaguid statistics
+    gid_t groups[] = {AID_ADB,      AID_LOG,       AID_INPUT,
+                      AID_INET,     AID_NET_BT,    AID_NET_BT_ADMIN,
+                      AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS};
+    if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) {
+        PLOG(FATAL) << "Could not set supplental groups";
+    }
+
+    /* don't listen on a port (default 5037) if running in secure mode */
+    /* don't run as root if we are running in secure mode */
+    if (should_drop_privileges()) {
+        drop_capabilities_bounding_set_if_needed();
+
+        /* then switch user and group to "shell" */
+        if (setgid(AID_SHELL) != 0) {
+            PLOG(FATAL) << "Could not setgid";
+        }
+        if (setuid(AID_SHELL) != 0) {
+            PLOG(FATAL) << "Could not setuid";
+        }
+
+        D("Local port disabled\n");
+    } else {
+        if ((root_seclabel != nullptr) && (is_selinux_enabled() > 0)) {
+            if (setcon(root_seclabel) < 0) {
+                LOG(FATAL) << "Could not set selinux context";
+            }
+        }
+        std::string local_name =
+            android::base::StringPrintf("tcp:%d", server_port);
+        if (install_listener(local_name, "*smartsocket*", nullptr, 0)) {
+            LOG(FATAL) << "Could not install *smartsocket* listener";
+        }
+    }
+
+    bool is_usb = false;
+    if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) {
+        // Listen on USB.
+        usb_init();
+        is_usb = true;
+    }
+
+    // If one of these properties is set, also listen on that port.
+    // If one of the properties isn't set and we couldn't listen on usb, listen
+    // on the default port.
+    char prop_port[PROPERTY_VALUE_MAX];
+    property_get("service.adb.tcp.port", prop_port, "");
+    if (prop_port[0] == '\0') {
+        property_get("persist.adb.tcp.port", prop_port, "");
+    }
+
+    int port;
+    if (sscanf(prop_port, "%d", &port) == 1 && port > 0) {
+        printf("using port=%d\n", port);
+        // Listen on TCP port specified by service.adb.tcp.port property.
+        local_init(port);
+    } else if (!is_usb) {
+        // Listen on default port.
+        local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+    }
+
+    D("adbd_main(): pre init_jdwp()\n");
+    init_jdwp();
+    D("adbd_main(): post init_jdwp()\n");
+
+    D("Event loop starting\n");
+    fdevent_loop();
+
+    return 0;
+}
+
+static void close_stdin() {
+    int fd = unix_open("/dev/null", O_RDONLY);
+    if (fd == -1) {
+        perror("failed to open /dev/null, stdin will remain open");
+        return;
+    }
+    dup2(fd, STDIN_FILENO);
+    adb_close(fd);
+}
+
+int main(int argc, char** argv) {
+    android::base::InitLogging(argv);
+
+    while (true) {
+        static struct option opts[] = {
+            {"root_seclabel", required_argument, nullptr, 's'},
+            {"device_banner", required_argument, nullptr, 'b'},
+            {"version", no_argument, nullptr, 'v'},
+        };
+
+        int option_index = 0;
+        int c = getopt_long(argc, argv, "", opts, &option_index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+        case 's':
+            root_seclabel = optarg;
+            break;
+        case 'b':
+            adb_device_banner = optarg;
+            break;
+        case 'v':
+            printf("Android Debug Bridge Daemon version %d.%d.%d %s\n",
+                   ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION,
+                   ADB_REVISION);
+            return 0;
+        default:
+            // getopt already prints "adbd: invalid option -- %c" for us.
+            return 1;
+        }
+    }
+
+    close_stdin();
+
+    adb_trace_init();
+
+    /* If adbd runs inside the emulator this will enable adb tracing via
+     * adb-debug qemud service in the emulator. */
+    adb_qemu_trace_init();
+
+    D("Handling main()\n");
+    return adbd_main(DEFAULT_ADB_PORT);
+}
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index aded301..1dc711ae 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -16,6 +16,7 @@
 
 #include <dirent.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -63,13 +64,12 @@
             total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
 }
 
-static const char* transfer_progress_format = "\rTransferring: %llu/%llu (%d%%)";
-
-static void print_transfer_progress(unsigned long long bytes_current,
-                                    unsigned long long bytes_total) {
+static void print_transfer_progress(uint64_t bytes_current,
+                                    uint64_t bytes_total) {
     if (bytes_total == 0) return;
 
-    fprintf(stderr, transfer_progress_format, bytes_current, bytes_total,
+    fprintf(stderr, "\rTransferring: %" PRIu64 "/%" PRIu64 " (%d%%)",
+            bytes_current, bytes_total,
             (int) (bytes_current * 100 / bytes_total));
 
     if (bytes_current == bytes_total) {
@@ -79,8 +79,7 @@
     fflush(stderr);
 }
 
-void sync_quit(int fd)
-{
+static void sync_quit(int fd) {
     syncmsg msg;
 
     msg.req.id = ID_QUIT;
@@ -91,8 +90,7 @@
 
 typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
 
-int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie)
-{
+static int sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
     syncmsg msg;
     char buf[257];
     int len;
@@ -138,9 +136,7 @@
 
 static syncsendbuf send_buffer;
 
-int sync_readtime(int fd, const char *path, unsigned int *timestamp,
-                  unsigned int *mode)
-{
+static int sync_readtime(int fd, const char* path, unsigned int* timestamp, unsigned int* mode) {
     syncmsg msg;
     int len = strlen(path);
 
@@ -199,8 +195,7 @@
     return 0;
 }
 
-int sync_readmode(int fd, const char *path, unsigned *mode)
-{
+static int sync_readmode(int fd, const char* path, unsigned* mode) {
     syncmsg msg;
     int len = strlen(path);
 
@@ -419,8 +414,7 @@
     return 0;
 }
 
-int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress)
-{
+static int sync_recv(int fd, const char* rpath, const char* lpath, int show_progress) {
     syncmsg msg;
     int len;
     int lfd = -1;
@@ -566,17 +560,14 @@
     int flag;
 };
 
-copyinfo *mkcopyinfo(const char *spath, const char *dpath,
-                     const char *name, int isdir)
-{
+static copyinfo* mkcopyinfo(const char* spath, const char* dpath, const char* name, int isdir) {
     int slen = strlen(spath);
     int dlen = strlen(dpath);
     int nlen = strlen(name);
     int ssize = slen + nlen + 2;
     int dsize = dlen + nlen + 2;
 
-    copyinfo *ci = reinterpret_cast<copyinfo*>(
-        malloc(sizeof(copyinfo) + ssize + dsize));
+    copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
     if(ci == 0) {
         fprintf(stderr,"out of memory\n");
         abort();
@@ -807,9 +798,8 @@
     const char *lpath;
 };
 
-void
-sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
-                      const char *name, void *cookie)
+static void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
+                                  const char* name, void* cookie)
 {
     sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
     copyinfo *ci;
diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp
index 1eaee73..7a3b89a 100644
--- a/adb/remount_service.cpp
+++ b/adb/remount_service.cpp
@@ -34,114 +34,89 @@
 #include "adb_utils.h"
 #include "cutils/properties.h"
 
-static int system_ro = 1;
-static int vendor_ro = 1;
-static int oem_ro = 1;
-
-/* Returns the device used to mount a directory in /proc/mounts */
-static std::string find_mount(const char *dir) {
-    FILE* fp;
-    struct mntent* mentry;
-    char* device = NULL;
-
-    if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
-        return NULL;
+// Returns the device used to mount a directory in /proc/mounts.
+static std::string find_mount(const char* dir) {
+    std::unique_ptr<FILE, int(*)(FILE*)> fp(setmntent("/proc/mounts", "r"), endmntent);
+    if (!fp) {
+        return "";
     }
-    while ((mentry = getmntent(fp)) != NULL) {
-        if (strcmp(dir, mentry->mnt_dir) == 0) {
-            device = mentry->mnt_fsname;
-            break;
+
+    mntent* e;
+    while ((e = getmntent(fp.get())) != nullptr) {
+        if (strcmp(dir, e->mnt_dir) == 0) {
+            return e->mnt_fsname;
         }
     }
-    endmntent(fp);
-    return device;
+    return "";
 }
 
-int make_block_device_writable(const std::string& dev) {
+bool make_block_device_writable(const std::string& dev) {
     int fd = unix_open(dev.c_str(), O_RDONLY | O_CLOEXEC);
     if (fd == -1) {
-        return -1;
+        return false;
     }
 
-    int result = -1;
     int OFF = 0;
-    if (!ioctl(fd, BLKROSET, &OFF)) {
-        result = 0;
-    }
+    bool result = (ioctl(fd, BLKROSET, &OFF) != -1);
     adb_close(fd);
-
     return result;
 }
 
-// Init mounts /system as read only, remount to enable writes.
-static int remount(const char* dir, int* dir_ro) {
-    std::string dev(find_mount(dir));
-    if (dev.empty() || make_block_device_writable(dev)) {
-        return -1;
+static bool remount_partition(int fd, const char* dir) {
+    if (!directory_exists(dir)) {
+        return true;
     }
-
-    int rc = mount(dev.c_str(), dir, "none", MS_REMOUNT, NULL);
-    *dir_ro = rc;
-    return rc;
-}
-
-static bool remount_partition(int fd, const char* partition, int* ro) {
-  if (!directory_exists(partition)) {
+    std::string dev = find_mount(dir);
+    if (dev.empty()) {
+        return true;
+    }
+    if (!make_block_device_writable(dev)) {
+        WriteFdFmt(fd, "remount of %s failed; couldn't make block device %s writable: %s\n",
+                   dir, dev.c_str(), strerror(errno));
+        return false;
+    }
+    if (mount(dev.c_str(), dir, "none", MS_REMOUNT, nullptr) == -1) {
+        WriteFdFmt(fd, "remount of %s failed: %s\n", dir, strerror(errno));
+        return false;
+    }
     return true;
-  }
-  if (remount(partition, ro)) {
-    char buf[200];
-    snprintf(buf, sizeof(buf), "remount of %s failed: %s\n", partition, strerror(errno));
-    WriteStringFully(fd, buf);
-    return false;
-  }
-  return true;
 }
 
 void remount_service(int fd, void* cookie) {
-    char prop_buf[PROPERTY_VALUE_MAX];
-
     if (getuid() != 0) {
-        WriteStringFully(fd, "Not running as root. Try \"adb root\" first.\n");
+        WriteFdExactly(fd, "Not running as root. Try \"adb root\" first.\n");
         adb_close(fd);
         return;
     }
 
-    bool system_verified = false, vendor_verified = false;
+    char prop_buf[PROPERTY_VALUE_MAX];
     property_get("partition.system.verified", prop_buf, "");
-    if (strlen(prop_buf) > 0) {
-        system_verified = true;
-    }
+    bool system_verified = (strlen(prop_buf) > 0);
 
     property_get("partition.vendor.verified", prop_buf, "");
-    if (strlen(prop_buf) > 0) {
-        vendor_verified = true;
-    }
+    bool vendor_verified = (strlen(prop_buf) > 0);
 
     if (system_verified || vendor_verified) {
         // Allow remount but warn of likely bad effects
         bool both = system_verified && vendor_verified;
-        char buffer[200];
-        snprintf(buffer, sizeof(buffer),
-                 "dm_verity is enabled on the %s%s%s partition%s.\n",
-                 system_verified ? "system" : "",
-                 both ? " and " : "",
-                 vendor_verified ? "vendor" : "",
-                 both ? "s" : "");
-        WriteStringFully(fd, buffer);
-        snprintf(buffer, sizeof(buffer),
-                 "Use \"adb disable-verity\" to disable verity.\n"
-                 "If you do not, remount may succeed, however, you will still "
-                 "not be able to write to these volumes.\n");
-        WriteStringFully(fd, buffer);
+        WriteFdFmt(fd,
+                   "dm_verity is enabled on the %s%s%s partition%s.\n",
+                   system_verified ? "system" : "",
+                   both ? " and " : "",
+                   vendor_verified ? "vendor" : "",
+                   both ? "s" : "");
+        WriteFdExactly(fd,
+                       "Use \"adb disable-verity\" to disable verity.\n"
+                       "If you do not, remount may succeed, however, you will still "
+                       "not be able to write to these volumes.\n");
     }
 
     bool success = true;
-    success &= remount_partition(fd, "/system", &system_ro);
-    success &= remount_partition(fd, "/vendor", &vendor_ro);
-    success &= remount_partition(fd, "/oem", &oem_ro);
+    success &= remount_partition(fd, "/system");
+    success &= remount_partition(fd, "/vendor");
+    success &= remount_partition(fd, "/oem");
 
-    WriteStringFully(fd, success ? "remount succeeded\n" : "remount failed\n");
+    WriteFdExactly(fd, success ? "remount succeeded\n" : "remount failed\n");
 
     adb_close(fd);
 }
diff --git a/adb/remount_service.h b/adb/remount_service.h
index e1763cf..7bda1be 100644
--- a/adb/remount_service.h
+++ b/adb/remount_service.h
@@ -19,7 +19,7 @@
 
 #include <string>
 
-int make_block_device_writable(const std::string&);
+bool make_block_device_writable(const std::string&);
 void remount_service(int, void*);
 
 #endif
diff --git a/adb/services.cpp b/adb/services.cpp
index e6c84a4..a9edbe5 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -24,6 +24,11 @@
 #include <stdlib.h>
 #include <string.h>
 
+#if !ADB_HOST
+#include <pty.h>
+#include <termios.h>
+#endif
+
 #ifndef _WIN32
 #include <netdb.h>
 #include <netinet/in.h>
@@ -31,10 +36,11 @@
 #include <unistd.h>
 #endif
 
+#include <base/file.h>
 #include <base/stringprintf.h>
+#include <base/strings.h>
 
 #if !ADB_HOST
-#include "base/file.h"
 #include "cutils/android_reboot.h"
 #include "cutils/properties.h"
 #endif
@@ -62,74 +68,54 @@
 
 #if !ADB_HOST
 
-void restart_root_service(int fd, void *cookie)
-{
-    char buf[100];
-    char value[PROPERTY_VALUE_MAX];
-
+void restart_root_service(int fd, void *cookie) {
     if (getuid() == 0) {
-        snprintf(buf, sizeof(buf), "adbd is already running as root\n");
-        WriteFdExactly(fd, buf, strlen(buf));
+        WriteFdExactly(fd, "adbd is already running as root\n");
         adb_close(fd);
     } else {
+        char value[PROPERTY_VALUE_MAX];
         property_get("ro.debuggable", value, "");
         if (strcmp(value, "1") != 0) {
-            snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n");
-            WriteFdExactly(fd, buf, strlen(buf));
+            WriteFdExactly(fd, "adbd cannot run as root in production builds\n");
             adb_close(fd);
             return;
         }
 
         property_set("service.adb.root", "1");
-        snprintf(buf, sizeof(buf), "restarting adbd as root\n");
-        WriteFdExactly(fd, buf, strlen(buf));
+        WriteFdExactly(fd, "restarting adbd as root\n");
         adb_close(fd);
     }
 }
 
-void restart_unroot_service(int fd, void *cookie)
-{
-    char buf[100];
-
+void restart_unroot_service(int fd, void *cookie) {
     if (getuid() != 0) {
-        snprintf(buf, sizeof(buf), "adbd not running as root\n");
-        WriteFdExactly(fd, buf, strlen(buf));
+        WriteFdExactly(fd, "adbd not running as root\n");
         adb_close(fd);
     } else {
         property_set("service.adb.root", "0");
-        snprintf(buf, sizeof(buf), "restarting adbd as non root\n");
-        WriteFdExactly(fd, buf, strlen(buf));
+        WriteFdExactly(fd, "restarting adbd as non root\n");
         adb_close(fd);
     }
 }
 
-void restart_tcp_service(int fd, void *cookie)
-{
-    char buf[100];
-    char value[PROPERTY_VALUE_MAX];
+void restart_tcp_service(int fd, void *cookie) {
     int port = (int) (uintptr_t) cookie;
-
     if (port <= 0) {
-        snprintf(buf, sizeof(buf), "invalid port\n");
-        WriteFdExactly(fd, buf, strlen(buf));
+        WriteFdFmt(fd, "invalid port %d\n", port);
         adb_close(fd);
         return;
     }
 
+    char value[PROPERTY_VALUE_MAX];
     snprintf(value, sizeof(value), "%d", port);
     property_set("service.adb.tcp.port", value);
-    snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
-    WriteFdExactly(fd, buf, strlen(buf));
+    WriteFdFmt(fd, "restarting in TCP mode port: %d\n", port);
     adb_close(fd);
 }
 
-void restart_usb_service(int fd, void *cookie)
-{
-    char buf[100];
-
+void restart_usb_service(int fd, void *cookie) {
     property_set("service.adb.tcp.port", "0");
-    snprintf(buf, sizeof(buf), "restarting in USB mode\n");
-    WriteFdExactly(fd, buf, strlen(buf));
+    WriteFdExactly(fd, "restarting in USB mode\n");
     adb_close(fd);
 }
 
@@ -142,13 +128,11 @@
         reboot_arg = "sideload";
     }
 
-    char buf[100];
     // It reboots into sideload mode by setting "--sideload" or "--sideload_auto_reboot"
     // in the command file.
     if (strcmp(reboot_arg, "sideload") == 0) {
         if (getuid() != 0) {
-            snprintf(buf, sizeof(buf), "'adb root' is required for 'adb reboot sideload'.\n");
-            WriteStringFully(fd, buf);
+            WriteFdExactly(fd, "'adb root' is required for 'adb reboot sideload'.\n");
             return false;
         }
 
@@ -174,15 +158,13 @@
     char property_val[PROPERTY_VALUE_MAX];
     int ret = snprintf(property_val, sizeof(property_val), "reboot,%s", reboot_arg);
     if (ret >= static_cast<int>(sizeof(property_val))) {
-        snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret);
-        WriteStringFully(fd, buf);
+        WriteFdFmt(fd, "reboot string too long: %d\n", ret);
         return false;
     }
 
     ret = property_set(ANDROID_RB_PROPERTY, property_val);
     if (ret < 0) {
-        snprintf(buf, sizeof(buf), "reboot failed: %d\n", ret);
-        WriteStringFully(fd, buf);
+        WriteFdFmt(fd, "reboot failed: %d\n", ret);
         return false;
     }
 
@@ -208,7 +190,7 @@
     const char* command = reinterpret_cast<const char*>(arg);
 
     if (handle_forward_request(command, kTransportAny, NULL, fd) < 0) {
-        sendfailmsg(fd, "not a reverse forwarding command");
+        SendFail(fd, "not a reverse forwarding command");
     }
     free(arg);
     adb_close(fd);
@@ -233,8 +215,7 @@
     sti->cookie = cookie;
     sti->fd = s[1];
 
-    adb_thread_t t;
-    if (adb_thread_create(&t, service_bootstrap_func, sti)) {
+    if (!adb_thread_create(service_bootstrap_func, sti)) {
         free(sti);
         adb_close(s[0]);
         adb_close(s[1]);
@@ -262,30 +243,14 @@
     }
 }
 
-static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
-{
+#if !ADB_HOST
+static int create_subproc_pty(const char* cmd, const char* arg0,
+                              const char* arg1, pid_t* pid) {
     D("create_subproc_pty(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
-#if defined(_WIN32)
-    fprintf(stderr, "error: create_subproc_pty not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
-    return -1;
-#else
+    char pts_name[PATH_MAX];
     int ptm;
-
-    ptm = unix_open("/dev/ptmx", O_RDWR | O_CLOEXEC); // | O_NOCTTY);
-    if(ptm < 0){
-        printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
-        return -1;
-    }
-
-    char devname[64];
-    if(grantpt(ptm) || unlockpt(ptm) || ptsname_r(ptm, devname, sizeof(devname)) != 0) {
-        printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
-        adb_close(ptm);
-        return -1;
-    }
-
-    *pid = fork();
-    if(*pid < 0) {
+    *pid = forkpty(&ptm, pts_name, nullptr, nullptr);
+    if (*pid == -1) {
         printf("- fork failed: %s -\n", strerror(errno));
         adb_close(ptm);
         return -1;
@@ -294,12 +259,33 @@
     if (*pid == 0) {
         init_subproc_child();
 
-        int pts = unix_open(devname, O_RDWR | O_CLOEXEC);
-        if (pts < 0) {
-            fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
+        int pts = unix_open(pts_name, O_RDWR | O_CLOEXEC);
+        if (pts == -1) {
+            fprintf(stderr, "child failed to open pseudo-term slave %s: %s\n",
+                    pts_name, strerror(errno));
+            adb_close(ptm);
             exit(-1);
         }
 
+        // arg0 is "-c" in batch mode and "-" in interactive mode.
+        if (strcmp(arg0, "-c") == 0) {
+            termios tattr;
+            if (tcgetattr(pts, &tattr) == -1) {
+                fprintf(stderr, "tcgetattr failed: %s\n", strerror(errno));
+                adb_close(pts);
+                adb_close(ptm);
+                exit(-1);
+            }
+
+            cfmakeraw(&tattr);
+            if (tcsetattr(pts, TCSADRAIN, &tattr) == -1) {
+                fprintf(stderr, "tcsetattr failed: %s\n", strerror(errno));
+                adb_close(pts);
+                adb_close(ptm);
+                exit(-1);
+            }
+        }
+
         dup2(pts, STDIN_FILENO);
         dup2(pts, STDOUT_FILENO);
         dup2(pts, STDERR_FILENO);
@@ -307,15 +293,15 @@
         adb_close(pts);
         adb_close(ptm);
 
-        execl(cmd, cmd, arg0, arg1, NULL);
+        execl(cmd, cmd, arg0, arg1, nullptr);
         fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
                 cmd, strerror(errno), errno);
         exit(-1);
     } else {
         return ptm;
     }
-#endif /* !defined(_WIN32) */
 }
+#endif // !ADB_HOST
 
 static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
 {
@@ -401,12 +387,7 @@
     }
 }
 
-static int create_subproc_thread(const char *name, const subproc_mode mode)
-{
-    adb_thread_t t;
-    int ret_fd;
-    pid_t pid = -1;
-
+static int create_subproc_thread(const char *name, bool pty = false) {
     const char *arg0, *arg1;
     if (name == 0 || *name == 0) {
         arg0 = "-"; arg1 = 0;
@@ -414,16 +395,12 @@
         arg0 = "-c"; arg1 = name;
     }
 
-    switch (mode) {
-    case SUBPROC_PTY:
+    pid_t pid = -1;
+    int ret_fd;
+    if (pty) {
         ret_fd = create_subproc_pty(SHELL_COMMAND, arg0, arg1, &pid);
-        break;
-    case SUBPROC_RAW:
+    } else {
         ret_fd = create_subproc_raw(SHELL_COMMAND, arg0, arg1, &pid);
-        break;
-    default:
-        fprintf(stderr, "invalid subproc_mode %d\n", mode);
-        return -1;
     }
     D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid);
 
@@ -433,7 +410,7 @@
     sti->cookie = (void*) (uintptr_t) pid;
     sti->fd = ret_fd;
 
-    if (adb_thread_create(&t, service_bootstrap_func, sti)) {
+    if (!adb_thread_create(service_bootstrap_func, sti)) {
         free(sti);
         adb_close(ret_fd);
         fprintf(stderr, "cannot create service thread\n");
@@ -485,9 +462,9 @@
     } else if (!strncmp(name, "jdwp:", 5)) {
         ret = create_jdwp_connection_fd(atoi(name+5));
     } else if(!HOST && !strncmp(name, "shell:", 6)) {
-        ret = create_subproc_thread(name + 6, SUBPROC_PTY);
+        ret = create_subproc_thread(name + 6, true);
     } else if(!HOST && !strncmp(name, "exec:", 5)) {
-        ret = create_subproc_thread(name + 5, SUBPROC_RAW);
+        ret = create_subproc_thread(name + 5);
     } else if(!strncmp(name, "sync:", 5)) {
         ret = create_service_thread(file_sync_service, NULL);
     } else if(!strncmp(name, "remount:", 8)) {
@@ -502,9 +479,9 @@
         ret = create_service_thread(restart_unroot_service, NULL);
     } else if(!strncmp(name, "backup:", 7)) {
         ret = create_subproc_thread(android::base::StringPrintf("/system/bin/bu backup %s",
-                                                                (name + 7)).c_str(), SUBPROC_RAW);
+                                                                (name + 7)).c_str());
     } else if(!strncmp(name, "restore:", 8)) {
-        ret = create_subproc_thread("/system/bin/bu restore", SUBPROC_RAW);
+        ret = create_subproc_thread("/system/bin/bu restore");
     } else if(!strncmp(name, "tcpip:", 6)) {
         int port;
         if (sscanf(name + 6, "%d", &port) != 1) {
@@ -537,9 +514,9 @@
 
 #if ADB_HOST
 struct state_info {
-    transport_type transport;
+    TransportType transport_type;
     char* serial;
-    int state;
+    ConnectionState state;
 };
 
 static void wait_for_state(int fd, void* cookie)
@@ -549,11 +526,12 @@
     D("wait_for_state %d\n", sinfo->state);
 
     std::string error_msg = "unknown error";
-    atransport* t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &error_msg);
+    atransport* t = acquire_one_transport(sinfo->state, sinfo->transport_type, sinfo->serial,
+                                          &error_msg);
     if (t != 0) {
-        WriteFdExactly(fd, "OKAY", 4);
+        SendOkay(fd);
     } else {
-        sendfailmsg(fd, error_msg.c_str());
+        SendFail(fd, error_msg);
     }
 
     if (sinfo->serial)
@@ -563,35 +541,31 @@
     D("wait_for_state is done\n");
 }
 
-static void connect_device(char* host, char* buffer, int buffer_size)
-{
-    int port, fd;
-    char* portstr = strchr(host, ':');
-    char hostbuf[100];
-    char serial[100];
-    int ret;
-
-    strncpy(hostbuf, host, sizeof(hostbuf) - 1);
-    if (portstr) {
-        if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) {
-            snprintf(buffer, buffer_size, "bad host name %s", host);
-            return;
-        }
-        // zero terminate the host at the point we found the colon
-        hostbuf[portstr - host] = 0;
-        if (sscanf(portstr + 1, "%d", &port) != 1) {
-            snprintf(buffer, buffer_size, "bad port number %s", portstr);
-            return;
-        }
-    } else {
-        port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
+static void connect_device(const std::string& host, std::string* response) {
+    if (host.empty()) {
+        *response = "empty host name";
+        return;
     }
 
-    snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
+    std::vector<std::string> pieces = android::base::Split(host, ":");
+    const std::string& hostname = pieces[0];
 
-    fd = socket_network_client_timeout(hostbuf, port, SOCK_STREAM, 10);
+    int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
+    if (pieces.size() > 1) {
+        if (sscanf(pieces[1].c_str(), "%d", &port) != 1) {
+            *response = android::base::StringPrintf("bad port number %s", pieces[1].c_str());
+            return;
+        }
+    }
+
+    // This may look like we're putting 'host' back together,
+    // but we're actually inserting the default port if necessary.
+    std::string serial = android::base::StringPrintf("%s:%d", hostname.c_str(), port);
+
+    int fd = socket_network_client_timeout(hostname.c_str(), port, SOCK_STREAM, 10);
     if (fd < 0) {
-        snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
+        *response = android::base::StringPrintf("unable to connect to %s:%d",
+                                                hostname.c_str(), port);
         return;
     }
 
@@ -599,85 +573,73 @@
     close_on_exec(fd);
     disable_tcp_nagle(fd);
 
-    ret = register_socket_transport(fd, serial, port, 0);
+    int ret = register_socket_transport(fd, serial.c_str(), port, 0);
     if (ret < 0) {
         adb_close(fd);
-        snprintf(buffer, buffer_size, "already connected to %s", serial);
+        *response = android::base::StringPrintf("already connected to %s", serial.c_str());
     } else {
-        snprintf(buffer, buffer_size, "connected to %s", serial);
+        *response = android::base::StringPrintf("connected to %s", serial.c_str());
     }
 }
 
-void connect_emulator(char* port_spec, char* buffer, int buffer_size)
-{
-    char* port_separator = strchr(port_spec, ',');
-    if (!port_separator) {
-        snprintf(buffer, buffer_size,
-                "unable to parse '%s' as <console port>,<adb port>",
-                port_spec);
+void connect_emulator(const std::string& port_spec, std::string* response) {
+    std::vector<std::string> pieces = android::base::Split(port_spec, ",");
+    if (pieces.size() != 2) {
+        *response = android::base::StringPrintf("unable to parse '%s' as <console port>,<adb port>",
+                                                port_spec.c_str());
         return;
     }
 
-    // Zero-terminate console port and make port_separator point to 2nd port.
-    *port_separator++ = 0;
-    int console_port = strtol(port_spec, NULL, 0);
-    int adb_port = strtol(port_separator, NULL, 0);
-    if (!(console_port > 0 && adb_port > 0)) {
-        *(port_separator - 1) = ',';
-        snprintf(buffer, buffer_size,
-                "Invalid port numbers: Expected positive numbers, got '%s'",
-                port_spec);
+    int console_port = strtol(pieces[0].c_str(), NULL, 0);
+    int adb_port = strtol(pieces[1].c_str(), NULL, 0);
+    if (console_port <= 0 || adb_port <= 0) {
+        *response = android::base::StringPrintf("Invalid port numbers: %s", port_spec.c_str());
         return;
     }
 
-    /* Check if the emulator is already known.
-     * Note: There's a small but harmless race condition here: An emulator not
-     * present just yet could be registered by another invocation right
-     * after doing this check here. However, local_connect protects
-     * against double-registration too. From here, a better error message
-     * can be produced. In the case of the race condition, the very specific
-     * error message won't be shown, but the data doesn't get corrupted. */
+    // Check if the emulator is already known.
+    // Note: There's a small but harmless race condition here: An emulator not
+    // present just yet could be registered by another invocation right
+    // after doing this check here. However, local_connect protects
+    // against double-registration too. From here, a better error message
+    // can be produced. In the case of the race condition, the very specific
+    // error message won't be shown, but the data doesn't get corrupted.
     atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port);
-    if (known_emulator != NULL) {
-        snprintf(buffer, buffer_size,
-                "Emulator on port %d already registered.", adb_port);
+    if (known_emulator != nullptr) {
+        *response = android::base::StringPrintf("Emulator already registered on port %d", adb_port);
         return;
     }
 
-    /* Check if more emulators can be registered. Similar unproblematic
-     * race condition as above. */
+    // Check if more emulators can be registered. Similar unproblematic
+    // race condition as above.
     int candidate_slot = get_available_local_transport_index();
     if (candidate_slot < 0) {
-        snprintf(buffer, buffer_size, "Cannot accept more emulators.");
+        *response = "Cannot accept more emulators";
         return;
     }
 
-    /* Preconditions met, try to connect to the emulator. */
+    // Preconditions met, try to connect to the emulator.
     if (!local_connect_arbitrary_ports(console_port, adb_port)) {
-        snprintf(buffer, buffer_size,
-                "Connected to emulator on ports %d,%d", console_port, adb_port);
+        *response = android::base::StringPrintf("Connected to emulator on ports %d,%d",
+                                                console_port, adb_port);
     } else {
-        snprintf(buffer, buffer_size,
-                "Could not connect to emulator on ports %d,%d",
-                console_port, adb_port);
+        *response = android::base::StringPrintf("Could not connect to emulator on ports %d,%d",
+                                                console_port, adb_port);
     }
 }
 
-static void connect_service(int fd, void* cookie)
-{
-    char buf[4096];
-    char resp[4096];
-    char *host = reinterpret_cast<char*>(cookie);
-
+static void connect_service(int fd, void* data) {
+    char* host = reinterpret_cast<char*>(data);
+    std::string response;
     if (!strncmp(host, "emu:", 4)) {
-        connect_emulator(host + 4, buf, sizeof(buf));
+        connect_emulator(host + 4, &response);
     } else {
-        connect_device(host, buf, sizeof(buf));
+        connect_device(host, &response);
     }
+    free(host);
 
     // Send response for emulator and device
-    snprintf(resp, sizeof(resp), "%04x%s",(unsigned)strlen(buf), buf);
-    WriteFdExactly(fd, resp, strlen(resp));
+    SendProtocolString(fd, response);
     adb_close(fd);
 }
 #endif
@@ -702,15 +664,18 @@
         name += strlen("wait-for-");
 
         if (!strncmp(name, "local", strlen("local"))) {
-            sinfo->transport = kTransportLocal;
-            sinfo->state = CS_DEVICE;
+            sinfo->transport_type = kTransportLocal;
+            sinfo->state = kCsDevice;
         } else if (!strncmp(name, "usb", strlen("usb"))) {
-            sinfo->transport = kTransportUsb;
-            sinfo->state = CS_DEVICE;
+            sinfo->transport_type = kTransportUsb;
+            sinfo->state = kCsDevice;
         } else if (!strncmp(name, "any", strlen("any"))) {
-            sinfo->transport = kTransportAny;
-            sinfo->state = CS_DEVICE;
+            sinfo->transport_type = kTransportAny;
+            sinfo->state = kCsDevice;
         } else {
+            if (sinfo->serial) {
+                free(sinfo->serial);
+            }
             free(sinfo);
             return NULL;
         }
@@ -718,8 +683,8 @@
         int fd = create_service_thread(wait_for_state, sinfo);
         return create_local_socket(fd);
     } else if (!strncmp(name, "connect:", 8)) {
-        const char *host = name + 8;
-        int fd = create_service_thread(connect_service, (void *)host);
+        char* host = strdup(name + 8);
+        int fd = create_service_thread(connect_service, host);
         return create_local_socket(fd);
     }
     return NULL;
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/set_verity_enable_state_service.cpp
index b75ed4c..bae38cf 100644
--- a/adb/set_verity_enable_state_service.cpp
+++ b/adb/set_verity_enable_state_service.cpp
@@ -21,13 +21,13 @@
 #include <fcntl.h>
 #include <inttypes.h>
 #include <stdarg.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <sys/stat.h>
 
 #include "cutils/properties.h"
 
 #include "adb.h"
+#include "adb_io.h"
 #include "ext4_sb.h"
 #include "fs_mgr.h"
 #include "remount_service.h"
@@ -41,18 +41,6 @@
 static const bool kAllowDisableVerity = false;
 #endif
 
-__attribute__((__format__(printf, 2, 3))) __nonnull((2))
-static void write_console(int fd, const char* format, ...)
-{
-    char buffer[256];
-    va_list args;
-    va_start (args, format);
-    vsnprintf (buffer, sizeof(buffer), format, args);
-    va_end (args);
-
-    adb_write(fd, buffer, strnlen(buffer, sizeof(buffer)));
-}
-
 static int get_target_device_size(int fd, const char *blk_device,
                                   uint64_t *device_size)
 {
@@ -64,18 +52,18 @@
 
     data_device = adb_open(blk_device, O_RDONLY | O_CLOEXEC);
     if (data_device < 0) {
-        write_console(fd, "Error opening block device (%s)\n", strerror(errno));
+        WriteFdFmt(fd, "Error opening block device (%s)\n", strerror(errno));
         return -1;
     }
 
     if (lseek64(data_device, 1024, SEEK_SET) < 0) {
-        write_console(fd, "Error seeking to superblock\n");
+        WriteFdFmt(fd, "Error seeking to superblock\n");
         adb_close(data_device);
         return -1;
     }
 
     if (adb_read(data_device, &sb, sizeof(sb)) != sizeof(sb)) {
-        write_console(fd, "Error reading superblock\n");
+        WriteFdFmt(fd, "Error reading superblock\n");
         adb_close(data_device);
         return -1;
     }
@@ -98,74 +86,65 @@
     int device = -1;
     int retval = -1;
 
-    if (make_block_device_writable(block_device)) {
-        write_console(fd, "Could not make block device %s writable (%s).\n",
-                      block_device, strerror(errno));
+    if (!make_block_device_writable(block_device)) {
+        WriteFdFmt(fd, "Could not make block device %s writable (%s).\n",
+                   block_device, strerror(errno));
         goto errout;
     }
 
     device = adb_open(block_device, O_RDWR | O_CLOEXEC);
     if (device == -1) {
-        write_console(fd, "Could not open block device %s (%s).\n",
-                      block_device, strerror(errno));
-        write_console(fd, "Maybe run adb remount?\n");
+        WriteFdFmt(fd, "Could not open block device %s (%s).\n", block_device, strerror(errno));
+        WriteFdFmt(fd, "Maybe run adb remount?\n");
         goto errout;
     }
 
     // find the start of the verity metadata
     if (get_target_device_size(fd, (char*)block_device, &device_length) < 0) {
-        write_console(fd, "Could not get target device size.\n");
+        WriteFdFmt(fd, "Could not get target device size.\n");
         goto errout;
     }
 
     if (lseek64(device, device_length, SEEK_SET) < 0) {
-        write_console(fd,
-                      "Could not seek to start of verity metadata block.\n");
+        WriteFdFmt(fd, "Could not seek to start of verity metadata block.\n");
         goto errout;
     }
 
     // check the magic number
-    if (adb_read(device, &magic_number, sizeof(magic_number))
-             != sizeof(magic_number)) {
-        write_console(fd, "Couldn't read magic number!\n");
+    if (adb_read(device, &magic_number, sizeof(magic_number)) != sizeof(magic_number)) {
+        WriteFdFmt(fd, "Couldn't read magic number!\n");
         goto errout;
     }
 
     if (!enable && magic_number == VERITY_METADATA_MAGIC_DISABLE) {
-        write_console(fd, "Verity already disabled on %s\n", mount_point);
+        WriteFdFmt(fd, "Verity already disabled on %s\n", mount_point);
         goto errout;
     }
 
     if (enable && magic_number == VERITY_METADATA_MAGIC_NUMBER) {
-        write_console(fd, "Verity already enabled on %s\n", mount_point);
+        WriteFdFmt(fd, "Verity already enabled on %s\n", mount_point);
         goto errout;
     }
 
     if (magic_number != VERITY_METADATA_MAGIC_NUMBER
             && magic_number != VERITY_METADATA_MAGIC_DISABLE) {
-        write_console(fd,
-                      "Couldn't find verity metadata at offset %" PRIu64 "!\n",
-                      device_length);
+        WriteFdFmt(fd, "Couldn't find verity metadata at offset %" PRIu64 "!\n", device_length);
         goto errout;
     }
 
     if (lseek64(device, device_length, SEEK_SET) < 0) {
-        write_console(fd,
-                      "Could not seek to start of verity metadata block.\n");
+        WriteFdFmt(fd, "Could not seek to start of verity metadata block.\n");
         goto errout;
     }
 
     if (adb_write(device, &new_magic, sizeof(new_magic)) != sizeof(new_magic)) {
-        write_console(
-            fd, "Could not set verity %s flag on device %s with error %s\n",
-            enable ? "enabled" : "disabled",
-            block_device, strerror(errno));
+        WriteFdFmt(fd, "Could not set verity %s flag on device %s with error %s\n",
+                   enable ? "enabled" : "disabled",
+                   block_device, strerror(errno));
         goto errout;
     }
 
-    write_console(fd, "Verity %s on %s\n",
-                  enable ? "enabled" : "disabled",
-                  mount_point);
+    WriteFdFmt(fd, "Verity %s on %s\n", enable ? "enabled" : "disabled", mount_point);
     retval = 0;
 errout:
     if (device != -1)
@@ -184,14 +163,13 @@
 
         property_get("ro.secure", propbuf, "0");
         if (strcmp(propbuf, "1")) {
-            write_console(fd, "verity not enabled - ENG build\n");
+            WriteFdFmt(fd, "verity not enabled - ENG build\n");
             goto errout;
         }
 
         property_get("ro.debuggable", propbuf, "0");
         if (strcmp(propbuf, "1")) {
-            write_console(
-                fd, "verity cannot be disabled/enabled - USER build\n");
+            WriteFdFmt(fd, "verity cannot be disabled/enabled - USER build\n");
             goto errout;
         }
 
@@ -201,8 +179,7 @@
 
         fstab = fs_mgr_read_fstab(fstab_filename);
         if (!fstab) {
-            write_console(fd, "Failed to open %s\nMaybe run adb root?\n",
-                          fstab_filename);
+            WriteFdFmt(fd, "Failed to open %s\nMaybe run adb root?\n", fstab_filename);
             goto errout;
         }
 
@@ -218,12 +195,11 @@
         }
 
         if (any_changed) {
-            write_console(
-                fd, "Now reboot your device for settings to take effect\n");
+            WriteFdFmt(fd, "Now reboot your device for settings to take effect\n");
         }
     } else {
-        write_console(fd, "%s-verity only works for userdebug builds\n",
-                      enable ? "enable" : "disable");
+        WriteFdFmt(fd, "%s-verity only works for userdebug builds\n",
+                   enable ? "enable" : "disable");
     }
 
 errout:
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index f468029..621944e 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -37,23 +37,6 @@
 
 static void local_socket_close_locked(asocket *s);
 
-int sendfailmsg(int fd, const char *reason)
-{
-    char buf[9];
-    int len;
-    len = strlen(reason);
-    if (len > 0xffff) {
-        len = 0xffff;
-    }
-
-    snprintf(buf, sizeof buf, "FAIL%04x", len);
-    if (!WriteFdExactly(fd, buf, 8)) {
-        return -1;
-    }
-
-    return WriteFdExactly(fd, reason, len) ? 0 : -1;
-}
-
 static unsigned local_socket_next_id = 1;
 
 static asocket local_socket_list = {
@@ -608,7 +591,7 @@
     s->ready = local_socket_ready;
     s->shutdown = NULL;
     s->close = local_socket_close;
-    adb_write(s->fd, "OKAY", 4);
+    SendOkay(s->fd);
     s->ready(s);
 }
 
@@ -620,11 +603,11 @@
     s->ready = local_socket_ready;
     s->shutdown = NULL;
     s->close = local_socket_close;
-    sendfailmsg(s->fd, "closed");
+    SendFail(s->fd, "closed");
     s->close(s);
 }
 
-unsigned unhex(unsigned char *s, int len)
+static unsigned unhex(unsigned char *s, int len)
 {
     unsigned n = 0, c;
 
@@ -654,6 +637,8 @@
     return n;
 }
 
+#if ADB_HOST
+
 #define PREFIX(str) { str, sizeof(str) - 1 }
 static const struct prefix_struct {
     const char *str;
@@ -670,7 +655,7 @@
    skipping over the 'serial' parameter in the ADB protocol,
    where parameter string may be a host:port string containing
    the protocol delimiter (colon). */
-char *skip_host_serial(char *service) {
+static char *skip_host_serial(char *service) {
     char *first_colon, *serial_end;
     int i;
 
@@ -698,13 +683,15 @@
     return serial_end;
 }
 
+#endif // ADB_HOST
+
 static int smart_socket_enqueue(asocket *s, apacket *p)
 {
     unsigned len;
 #if ADB_HOST
     char *service = NULL;
     char* serial = NULL;
-    transport_type ttype = kTransportAny;
+    TransportType type = kTransportAny;
 #endif
 
     D("SS(%d): enqueue %d\n", s->id, p->len);
@@ -761,13 +748,13 @@
             service = serial_end + 1;
         }
     } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) {
-        ttype = kTransportUsb;
+        type = kTransportUsb;
         service += strlen("host-usb:");
     } else if (!strncmp(service, "host-local:", strlen("host-local:"))) {
-        ttype = kTransportLocal;
+        type = kTransportLocal;
         service += strlen("host-local:");
     } else if (!strncmp(service, "host:", strlen("host:"))) {
-        ttype = kTransportAny;
+        type = kTransportAny;
         service += strlen("host:");
     } else {
         service = NULL;
@@ -781,7 +768,7 @@
             ** the OKAY or FAIL message and all we have to do
             ** is clean up.
             */
-        if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) {
+        if(handle_host_request(service, type, serial, s->peer->fd, s) == 0) {
                 /* XXX fail message? */
             D( "SS(%d): handled host service '%s'\n", s->id, service );
             goto fail;
@@ -799,7 +786,7 @@
         s2 = create_host_service_socket(service, serial);
         if(s2 == 0) {
             D( "SS(%d): couldn't create host service '%s'\n", s->id, service );
-            sendfailmsg(s->peer->fd, "unknown host service");
+            SendFail(s->peer->fd, "unknown host service");
             goto fail;
         }
 
@@ -810,7 +797,7 @@
             ** connection, and close this smart socket now
             ** that its work is done.
             */
-        adb_write(s->peer->fd, "OKAY", 4);
+        SendOkay(s->peer->fd);
 
         s->peer->ready = local_socket_ready;
         s->peer->shutdown = NULL;
@@ -828,20 +815,21 @@
 #else /* !ADB_HOST */
     if (s->transport == NULL) {
         std::string error_msg = "unknown failure";
-        s->transport = acquire_one_transport(CS_ANY, kTransportAny, NULL, &error_msg);
+        s->transport =
+            acquire_one_transport(kCsAny, kTransportAny, NULL, &error_msg);
 
         if (s->transport == NULL) {
-            sendfailmsg(s->peer->fd, error_msg.c_str());
+            SendFail(s->peer->fd, error_msg);
             goto fail;
         }
     }
 #endif
 
-    if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) {
+    if(!(s->transport) || (s->transport->connection_state == kCsOffline)) {
            /* if there's no remote we fail the connection
             ** right here and terminate it
             */
-        sendfailmsg(s->peer->fd, "device offline (x)");
+        SendFail(s->peer->fd, "device offline (x)");
         goto fail;
     }
 
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 59e5b0b..0aa1570 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -79,19 +79,13 @@
     LeaveCriticalSection( lock );
 }
 
-typedef struct { unsigned  tid; }  adb_thread_t;
-
 typedef  void*  (*adb_thread_func_t)(void*  arg);
 
 typedef  void (*win_thread_func_t)(void*  arg);
 
-static __inline__ int  adb_thread_create( adb_thread_t  *thread, adb_thread_func_t  func, void*  arg)
-{
-    thread->tid = _beginthread( (win_thread_func_t)func, 0, arg );
-    if (thread->tid == (unsigned)-1L) {
-        return -1;
-    }
-    return 0;
+static __inline__ bool adb_thread_create(adb_thread_func_t func, void* arg) {
+    uintptr_t tid = _beginthread((win_thread_func_t)func, 0, arg);
+    return (tid != static_cast<uintptr_t>(-1L));
 }
 
 static __inline__  unsigned long adb_thread_id()
@@ -429,18 +423,16 @@
 #define  unix_write  adb_write
 #define  unix_close  adb_close
 
-typedef  pthread_t                 adb_thread_t;
-
 typedef void*  (*adb_thread_func_t)( void*  arg );
 
-static __inline__ int  adb_thread_create( adb_thread_t  *pthread, adb_thread_func_t  start, void*  arg )
-{
-    pthread_attr_t   attr;
+static __inline__ bool adb_thread_create(adb_thread_func_t start, void* arg) {
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
-    pthread_attr_init (&attr);
-    pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
-
-    return pthread_create( pthread, &attr, start, arg );
+    pthread_t thread;
+    errno = pthread_create(&thread, &attr, start, arg);
+    return (errno == 0);
 }
 
 static __inline__  int  adb_socket_setbufsize( int   fd, int  bufsize )
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 633f6f5..a21272f 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -22,7 +22,6 @@
 #include <windows.h>
 
 #include <errno.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 
diff --git a/adb/test_track_devices.cpp b/adb/test_track_devices.cpp
index 77b3ad9..f78daeb 100644
--- a/adb/test_track_devices.cpp
+++ b/adb/test_track_devices.cpp
@@ -1,3 +1,5 @@
+// TODO: replace this with a shell/python script.
+
 /* a simple test program, connects to ADB server, and opens a track-devices session */
 #include <netdb.h>
 #include <sys/socket.h>
@@ -6,6 +8,8 @@
 #include <errno.h>
 #include <memory.h>
 
+#include <base/file.h>
+
 static void
 panic( const char*  msg )
 {
@@ -13,85 +17,52 @@
     exit(1);
 }
 
-static int
-unix_write( int  fd, const char*  buf, int  len )
-{
-    int  result = 0;
-    while (len > 0) {
-        int  len2 = write(fd, buf, len);
-        if (len2 < 0) {
-            if (errno == EINTR || errno == EAGAIN)
-                continue;
-            return -1;
-        }
-        result += len2;
-        len -= len2;
-        buf += len2;
+int main(int argc, char* argv[]) {
+    const char* request = "host:track-devices";
+
+    if (argv[1] && strcmp(argv[1], "--jdwp") == 0) {
+        request = "track-jdwp";
     }
-    return  result;
-}
 
-static int
-unix_read( int  fd, char*  buf, int  len )
-{
-    int  result = 0;
-    while (len > 0) {
-        int  len2 = read(fd, buf, len);
-        if (len2 < 0) {
-            if (errno == EINTR || errno == EAGAIN)
-                continue;
-            return -1;
-        }
-        result += len2;
-        len -= len2;
-        buf += len2;
-    }
-    return  result;
-}
-
-
-int  main( void )
-{
-    int                  ret, s;
+    int                  ret;
     struct sockaddr_in   server;
     char                 buffer[1024];
-    const char*          request = "host:track-devices";
-    int                  len;
 
     memset( &server, 0, sizeof(server) );
     server.sin_family      = AF_INET;
     server.sin_port        = htons(5037);
     server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 
-    s = socket( PF_INET, SOCK_STREAM, 0 );
+    int s = socket( PF_INET, SOCK_STREAM, 0 );
     ret = connect( s, (struct sockaddr*) &server, sizeof(server) );
     if (ret < 0) panic( "could not connect to server" );
 
     /* send the request */
-    len = snprintf( buffer, sizeof buffer, "%04x%s", strlen(request), request );
-    if (unix_write(s, buffer, len) < 0)
+    int len = snprintf(buffer, sizeof(buffer), "%04zx%s", strlen(request), request);
+    if (!android::base::WriteFully(s, buffer, len))
         panic( "could not send request" );
 
     /* read the OKAY answer */
-    if (unix_read(s, buffer, 4) != 4)
+    if (!android::base::ReadFully(s, buffer, 4))
         panic( "could not read request" );
 
     printf( "server answer: %.*s\n", 4, buffer );
 
     /* now loop */
-    for (;;) {
+    while (true) {
         char  head[5] = "0000";
 
-        if (unix_read(s, head, 4) < 0)
+        if (!android::base::ReadFully(s, head, 4))
             panic("could not read length");
 
-        if ( sscanf( head, "%04x", &len ) != 1 )
+        int len;
+        if (sscanf(head, "%04x", &len) != 1 )
             panic("could not decode length");
 
-        if (unix_read(s, buffer, len) != len)
+        if (!android::base::ReadFully(s, buffer, len))
             panic("could not read data");
 
-        printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer );
+        printf( "received header %.*s (%d bytes):\n%.*s----\n", 4, head, len, len, buffer );
     }
     close(s);
 }
diff --git a/adb/test_track_jdwp.cpp b/adb/test_track_jdwp.cpp
deleted file mode 100644
index 8ecc6b8..0000000
--- a/adb/test_track_jdwp.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/* a simple test program, connects to ADB server, and opens a track-devices session */
-#include <netdb.h>
-#include <sys/socket.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <memory.h>
-
-static void
-panic( const char*  msg )
-{
-    fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno));
-    exit(1);
-}
-
-static int
-unix_write( int  fd, const char*  buf, int  len )
-{
-    int  result = 0;
-    while (len > 0) {
-        int  len2 = write(fd, buf, len);
-        if (len2 < 0) {
-            if (errno == EINTR || errno == EAGAIN)
-                continue;
-            return -1;
-        }
-        result += len2;
-        len -= len2;
-        buf += len2;
-    }
-    return  result;
-}
-
-static int
-unix_read( int  fd, char*  buf, int  len )
-{
-    int  result = 0;
-    while (len > 0) {
-        int  len2 = read(fd, buf, len);
-        if (len2 < 0) {
-            if (errno == EINTR || errno == EAGAIN)
-                continue;
-            return -1;
-        }
-        result += len2;
-        len -= len2;
-        buf += len2;
-    }
-    return  result;
-}
-
-
-int  main( void )
-{
-    int                  ret, s;
-    struct sockaddr_in   server;
-    char                 buffer[1024];
-    const char*          request = "track-jdwp";
-    int                  len;
-
-    memset( &server, 0, sizeof(server) );
-    server.sin_family      = AF_INET;
-    server.sin_port        = htons(5037);
-    server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
-    s = socket( PF_INET, SOCK_STREAM, 0 );
-    ret = connect( s, (struct sockaddr*) &server, sizeof(server) );
-    if (ret < 0) panic( "could not connect to server" );
-
-    /* send the request */
-    len = snprintf( buffer, sizeof buffer, "%04x%s", strlen(request), request );
-    if (unix_write(s, buffer, len) < 0)
-        panic( "could not send request" );
-
-    /* read the OKAY answer */
-    if (unix_read(s, buffer, 4) != 4)
-        panic( "could not read request" );
-
-    printf( "server answer: %.*s\n", 4, buffer );
-
-    /* now loop */
-    for (;;) {
-        char  head[5] = "0000";
-
-        if (unix_read(s, head, 4) < 0)
-            panic("could not read length");
-
-        if ( sscanf( head, "%04x", &len ) != 1 )
-            panic("could not decode length");
-
-        if (unix_read(s, buffer, len) != len)
-            panic("could not read data");
-
-        printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer );
-    }
-    close(s);
-}
diff --git a/adb/tests/test_adb.py b/adb/tests/test_adb.py
index 52d8056..4eccc8c 100755
--- a/adb/tests/test_adb.py
+++ b/adb/tests/test_adb.py
@@ -6,6 +6,7 @@
 """
 import hashlib
 import os
+import pipes
 import random
 import re
 import shlex
@@ -162,6 +163,10 @@
     def shell_nocheck(self, cmd):
         return call_combined(self.adb_cmd + "shell " + cmd)
 
+    def install(self, filename):
+        return call_checked(
+            self.adb_cmd + "install {}".format(pipes.quote(filename)))
+
     def push(self, local, remote):
         return call_checked(self.adb_cmd + "push {} {}".format(local, remote))
 
@@ -272,13 +277,43 @@
         adb = AdbWrapper()
 
         # http://b/19734868
+        # Note that this actually matches ssh(1)'s behavior --- it's
+        # converted to "sh -c echo hello; echo world" which sh interprets
+        # as "sh -c echo" (with an argument to that shell of "hello"),
+        # and then "echo world" back in the first shell.
         result = adb.shell("sh -c 'echo hello; echo world'").splitlines()
+        self.assertEqual(["", "world"], result)
+        # If you really wanted "hello" and "world", here's what you'd do:
+        result = adb.shell(r"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())
 
+        # http://b/20564385
+        self.assertEqual('t', adb.shell("FOO=a BAR=b echo t").strip())
+        self.assertEqual('123Linux', adb.shell(r"echo -n 123\;uname").strip())
+
+    def test_install_argument_escaping(self):
+        """Make sure that install argument escaping works."""
+        adb = AdbWrapper()
+
+        # http://b/20323053
+        tf = tempfile.NamedTemporaryFile("w", suffix="-text;ls;1.apk")
+        self.assertIn("-text;ls;1.apk", adb.install(tf.name))
+
+        # http://b/3090932
+        tf = tempfile.NamedTemporaryFile("w", suffix="-Live Hold'em.apk")
+        self.assertIn("-Live Hold'em.apk", adb.install(tf.name))
+
+    def test_line_endings(self):
+        """Ensure that line ending translation is not happening in the pty.
+
+        Bug: http://b/19735063
+        """
+        self.assertFalse(AdbWrapper().shell("uname").endswith("\r\n"))
+
 
 class AdbFile(unittest.TestCase):
     SCRATCH_DIR = "/data/local/tmp"
diff --git a/adb/transport.cpp b/adb/transport.cpp
index d395a80..818ed97 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -26,7 +26,10 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <base/stringprintf.h>
+
 #include "adb.h"
+#include "adb_utils.h"
 
 static void transport_unref(atransport *t);
 
@@ -42,34 +45,6 @@
 
 ADB_MUTEX_DEFINE( transport_lock );
 
-#if ADB_TRACE
-#define MAX_DUMP_HEX_LEN 16
-void dump_hex(const unsigned char* ptr, size_t  len)
-{
-    int  nn, len2 = len;
-    // Build a string instead of logging each character.
-    // MAX chars in 2 digit hex, one space, MAX chars, one '\0'.
-    char buffer[MAX_DUMP_HEX_LEN *2 + 1 + MAX_DUMP_HEX_LEN + 1 ], *pb = buffer;
-
-    if (len2 > MAX_DUMP_HEX_LEN) len2 = MAX_DUMP_HEX_LEN;
-
-    for (nn = 0; nn < len2; nn++) {
-        sprintf(pb, "%02x", ptr[nn]);
-        pb += 2;
-    }
-    sprintf(pb++, " ");
-
-    for (nn = 0; nn < len2; nn++) {
-        int  c = ptr[nn];
-        if (c < 32 || c > 127)
-            c = '.';
-        *pb++ =  c;
-    }
-    *pb++ = '\0';
-    DR("%s\n", buffer);
-}
-#endif
-
 void kick_transport(atransport* t)
 {
     if (t && !t->kicked)
@@ -117,10 +92,7 @@
     }
 }
 
-#if ADB_TRACE
-static void
-dump_packet(const char* name, const char* func, apacket* p)
-{
+static void dump_packet(const char* name, const char* func, apacket* p) {
     unsigned  command = p->msg.command;
     int       len     = p->msg.data_length;
     char      cmd[9];
@@ -155,7 +127,6 @@
         name, func, cmd, arg0, arg1, len);
     dump_hex(p->data, len);
 }
-#endif /* ADB_TRACE */
 
 static int
 read_packet(int  fd, const char* name, apacket** ppacket)
@@ -180,11 +151,9 @@
         }
     }
 
-#if ADB_TRACE
     if (ADB_TRACING) {
         dump_packet(name, "from remote", *ppacket);
     }
-#endif
     return 0;
 }
 
@@ -199,11 +168,9 @@
         name = buff;
     }
 
-#if ADB_TRACE
     if (ADB_TRACING) {
         dump_packet(name, "to remote", *ppacket);
     }
-#endif
     len = sizeof(ppacket);
     while(len > 0) {
         r = adb_write(fd, p, len);
@@ -389,17 +356,6 @@
 
 
 #if ADB_HOST
-static int list_transports_msg(char*  buffer, size_t  bufferlen)
-{
-    char  head[5];
-    int   len;
-
-    len = list_transports(buffer+4, bufferlen-4, 0);
-    snprintf(head, sizeof(head), "%04x", len);
-    memcpy(buffer, head, 4);
-    len += 4;
-    return len;
-}
 
 /* this adds support required by the 'track-devices' service.
  * this is used to send the content of "list_transport" to any
@@ -457,39 +413,29 @@
     return -1;
 }
 
-static int
-device_tracker_send( device_tracker*  tracker,
-                     const char*      buffer,
-                     int              len )
-{
-    apacket*  p = get_apacket();
-    asocket*  peer = tracker->socket.peer;
+static int device_tracker_send(device_tracker* tracker, const std::string& string) {
+    apacket* p = get_apacket();
+    asocket* peer = tracker->socket.peer;
 
-    memcpy(p->data, buffer, len);
-    p->len = len;
-    return peer->enqueue( peer, p );
+    snprintf(reinterpret_cast<char*>(p->data), 5, "%04x", static_cast<int>(string.size()));
+    memcpy(&p->data[4], string.data(), string.size());
+    p->len = 4 + string.size();
+    return peer->enqueue(peer, p);
 }
 
+static void device_tracker_ready(asocket* socket) {
+    device_tracker* tracker = reinterpret_cast<device_tracker*>(socket);
 
-static void
-device_tracker_ready( asocket*  socket )
-{
-    device_tracker*  tracker = (device_tracker*) socket;
-
-    /* we want to send the device list when the tracker connects
-    * for the first time, even if no update occured */
+    // We want to send the device list when the tracker connects
+    // for the first time, even if no update occurred.
     if (tracker->update_needed > 0) {
-        char  buffer[1024];
-        int   len;
-
         tracker->update_needed = 0;
 
-        len = list_transports_msg(buffer, sizeof(buffer));
-        device_tracker_send(tracker, buffer, len);
+        std::string transports = list_transports(false);
+        device_tracker_send(tracker, transports);
     }
 }
 
-
 asocket*
 create_device_tracker(void)
 {
@@ -510,27 +456,25 @@
 }
 
 
-/* call this function each time the transport list has changed */
-void update_transports(void) {
-    char             buffer[1024];
-    int              len;
-    device_tracker*  tracker;
+// Call this function each time the transport list has changed.
+void update_transports() {
+    std::string transports = list_transports(false);
 
-    len = list_transports_msg(buffer, sizeof(buffer));
-
-    tracker = device_tracker_list;
-    while (tracker != NULL) {
-        device_tracker*  next = tracker->next;
-        /* note: this may destroy the tracker if the connection is closed */
-        device_tracker_send(tracker, buffer, len);
+    device_tracker* tracker = device_tracker_list;
+    while (tracker != nullptr) {
+        device_tracker* next = tracker->next;
+        // This may destroy the tracker if the connection is closed.
+        device_tracker_send(tracker, transports);
         tracker = next;
     }
 }
+
 #else
-void  update_transports(void)
-{
-    // nothing to do on the device side
+
+void update_transports() {
+    // Nothing to do on the device side.
 }
+
 #endif // ADB_HOST
 
 struct tmsg
@@ -586,8 +530,6 @@
 static void transport_registration_func(int _fd, unsigned ev, void *data)
 {
     tmsg m;
-    adb_thread_t output_thread_ptr;
-    adb_thread_t input_thread_ptr;
     int s[2];
     atransport *t;
 
@@ -636,7 +578,7 @@
     }
 
     /* don't create transport threads for inaccessible devices */
-    if (t->connection_state != CS_NOPERM) {
+    if (t->connection_state != kCsNoPerm) {
         /* initial references are the two threads */
         t->ref_count = 2;
 
@@ -656,11 +598,11 @@
 
         fdevent_set(&(t->transport_fde), FDE_READ);
 
-        if(adb_thread_create(&input_thread_ptr, input_thread, t)){
+        if (!adb_thread_create(input_thread, t)) {
             fatal_errno("cannot create input thread");
         }
 
-        if(adb_thread_create(&output_thread_ptr, output_thread, t)){
+        if (!adb_thread_create(output_thread, t)) {
             fatal_errno("cannot create output thread");
         }
     }
@@ -796,19 +738,18 @@
     return !*to_test;
 }
 
-atransport* acquire_one_transport(int state, transport_type ttype,
-                                  const char* serial, std::string* error_out)
-{
+atransport* acquire_one_transport(ConnectionState state, TransportType type,
+                                  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 = android::base::StringPrintf("device '%s' not found", serial);
 
     adb_mutex_lock(&transport_lock);
     for (t = transport_list.next; t != &transport_list; t = t->next) {
-        if (t->connection_state == CS_NOPERM) {
+        if (t->connection_state == kCsNoPerm) {
             if (error_out) *error_out = "insufficient permissions for device";
             continue;
         }
@@ -829,7 +770,7 @@
                 result = t;
             }
         } else {
-            if (ttype == kTransportUsb && t->type == kTransportUsb) {
+            if (type == kTransportUsb && t->type == kTransportUsb) {
                 if (result) {
                     if (error_out) *error_out = "more than one device";
                     ambiguous = 1;
@@ -837,7 +778,7 @@
                     break;
                 }
                 result = t;
-            } else if (ttype == kTransportLocal && t->type == kTransportLocal) {
+            } else if (type == kTransportLocal && t->type == kTransportLocal) {
                 if (result) {
                     if (error_out) *error_out = "more than one emulator";
                     ambiguous = 1;
@@ -845,9 +786,9 @@
                     break;
                 }
                 result = t;
-            } else if (ttype == kTransportAny) {
+            } else if (type == kTransportAny) {
                 if (result) {
-                    if (error_out) *error_out = "more than one device and emulator";
+                    if (error_out) *error_out = "more than one device/emulator";
                     ambiguous = 1;
                     result = NULL;
                     break;
@@ -859,7 +800,7 @@
     adb_mutex_unlock(&transport_lock);
 
     if (result) {
-        if (result->connection_state == CS_UNAUTHORIZED) {
+        if (result->connection_state == kCsUnauthorized) {
             if (error_out) {
                 *error_out = "device unauthorized.\n";
                 char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
@@ -872,13 +813,13 @@
         }
 
         /* offline devices are ignored -- they are either being born or dying */
-        if (result && result->connection_state == CS_OFFLINE) {
+        if (result && result->connection_state == kCsOffline) {
             if (error_out) *error_out = "device offline";
             result = NULL;
         }
 
         /* check for required connection state */
-        if (result && state != CS_ANY && result->connection_state != state) {
+        if (result && state != kCsAny && result->connection_state != state) {
             if (error_out) *error_out = "invalid device state";
             result = NULL;
         }
@@ -887,7 +828,7 @@
     if (result) {
         /* found one that we can take */
         if (error_out) *error_out = "success";
-    } else if (state != CS_ANY && (serial || !ambiguous)) {
+    } else if (state != kCsAny && (serial || !ambiguous)) {
         adb_sleep_ms(1000);
         goto retry;
     }
@@ -895,100 +836,72 @@
     return result;
 }
 
-#if ADB_HOST
-static const char *statename(atransport *t)
-{
-    switch(t->connection_state){
-    case CS_OFFLINE: return "offline";
-    case CS_BOOTLOADER: return "bootloader";
-    case CS_DEVICE: return "device";
-    case CS_HOST: return "host";
-    case CS_RECOVERY: return "recovery";
-    case CS_SIDELOAD: return "sideload";
-    case CS_NOPERM: return "no permissions";
-    case CS_UNAUTHORIZED: return "unauthorized";
+const char* atransport::connection_state_name() const {
+    switch (connection_state) {
+    case kCsOffline: return "offline";
+    case kCsBootloader: return "bootloader";
+    case kCsDevice: return "device";
+    case kCsHost: return "host";
+    case kCsRecovery: return "recovery";
+    case kCsNoPerm: return "no permissions";
+    case kCsSideload: return "sideload";
+    case kCsUnauthorized: return "unauthorized";
     default: return "unknown";
     }
 }
 
-static void add_qual(char **buf, size_t *buf_size,
-                     const char *prefix, const char *qual, bool sanitize_qual)
-{
-    if (!buf || !*buf || !buf_size || !*buf_size || !qual || !*qual)
+#if ADB_HOST
+
+static void append_transport_info(std::string* result, const char* key,
+                                  const char* value, bool sanitize) {
+    if (value == nullptr || *value == '\0') {
         return;
-
-    int prefix_len;
-    size_t len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual);
-
-    if (sanitize_qual) {
-        for (char* cp = *buf + prefix_len; cp < *buf + len; cp++) {
-            if (!isalnum(*cp))
-                *cp = '_';
-        }
     }
 
-    *buf_size -= len;
-    *buf += len;
+    *result += ' ';
+    *result += key;
+
+    for (const char* p = value; *p; ++p) {
+        result->push_back((!sanitize || isalnum(*p)) ? *p : '_');
+    }
 }
 
-static size_t format_transport(atransport *t, char *buf, size_t bufsize,
-                               int long_listing)
-{
+static void append_transport(atransport* t, std::string* result, bool long_listing) {
     const char* serial = t->serial;
-    if (!serial || !serial[0])
-        serial = "????????????";
+    if (!serial || !serial[0]) {
+        serial = "(no serial number)";
+    }
 
     if (!long_listing) {
-        return snprintf(buf, bufsize, "%s\t%s\n", serial, statename(t));
+        *result += serial;
+        *result += '\t';
+        *result += t->connection_state_name();
     } else {
-        size_t len, remaining = bufsize;
+        android::base::StringAppendF(result, "%-22s %s", serial, t->connection_state_name());
 
-        len = snprintf(buf, remaining, "%-22s %s", serial, statename(t));
-        remaining -= len;
-        buf += len;
-
-        add_qual(&buf, &remaining, " ", t->devpath, false);
-        add_qual(&buf, &remaining, " product:", t->product, false);
-        add_qual(&buf, &remaining, " model:", t->model, true);
-        add_qual(&buf, &remaining, " device:", t->device, false);
-
-        len = snprintf(buf, remaining, "\n");
-        remaining -= len;
-
-        return bufsize - remaining;
+        append_transport_info(result, "", t->devpath, false);
+        append_transport_info(result, "product:", t->product, false);
+        append_transport_info(result, "model:", t->model, true);
+        append_transport_info(result, "device:", t->device, false);
     }
+    *result += '\n';
 }
 
-int list_transports(char *buf, size_t  bufsize, int long_listing)
-{
-    char*       p   = buf;
-    char*       end = buf + bufsize;
-    int         len;
-    atransport *t;
-
-        /* XXX OVERRUN PROBLEMS XXX */
+std::string list_transports(bool long_listing) {
+    std::string result;
     adb_mutex_lock(&transport_lock);
-    for(t = transport_list.next; t != &transport_list; t = t->next) {
-        len = format_transport(t, p, end - p, long_listing);
-        if (p + len >= end) {
-            /* discard last line if buffer is too short */
-            break;
-        }
-        p += len;
+    for (atransport* t = transport_list.next; t != &transport_list; t = t->next) {
+        append_transport(t, &result, long_listing);
     }
-    p[0] = 0;
     adb_mutex_unlock(&transport_lock);
-    return p - buf;
+    return result;
 }
 
-
 /* hack for osx */
 void close_usb_devices()
 {
-    atransport *t;
-
     adb_mutex_lock(&transport_lock);
-    for(t = transport_list.next; t != &transport_list; t = t->next) {
+    for (atransport* t = transport_list.next; t != &transport_list; t = t->next) {
         if ( !t->kicked ) {
             t->kicked = 1;
             t->kick(t);
@@ -1107,7 +1020,7 @@
     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));
+    init_usb_transport(t, usb, (writeable ? kCsOffline : kCsNoPerm));
     if(serial) {
         t->serial = strdup(serial);
     }
@@ -1125,18 +1038,17 @@
     register_transport(t);
 }
 
-/* this should only be used for transports with connection_state == CS_NOPERM */
-void unregister_usb_transport(usb_handle *usb)
-{
-    atransport *t;
+// This should only be used for transports with connection_state == kCsNoPerm.
+void unregister_usb_transport(usb_handle* usb) {
     adb_mutex_lock(&transport_lock);
-    for(t = transport_list.next; t != &transport_list; t = t->next) {
-        if (t->usb == usb && t->connection_state == CS_NOPERM) {
+    for (atransport* t = transport_list.next; t != &transport_list;
+         t = t->next) {
+        if (t->usb == usb && t->connection_state == kCsNoPerm) {
             t->next->prev = t->prev;
             t->prev->next = t->next;
             break;
         }
-     }
+    }
     adb_mutex_unlock(&transport_lock);
 }
 
diff --git a/adb/transport.h b/adb/transport.h
index a2077e8..538f63e 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -23,17 +23,13 @@
 
 #include "adb.h"
 
-#if ADB_TRACE
-void dump_hex(const unsigned char* ptr, size_t  len);
-#endif
-
 /*
  * Obtain a transport from the available transports.
- * If state is != CS_ANY, only transports in that state are considered.
+ * If state is != kCsAny, only transports in that state are considered.
  * If serial is non-NULL then only the device with that serial will be chosen.
  * If no suitable transport is found, error is set.
  */
-atransport* acquire_one_transport(int state, transport_type ttype,
+atransport* acquire_one_transport(ConnectionState state, TransportType type,
                                   const char* serial, std::string* error_out);
 void add_transport_disconnect(atransport* t, adisconnect* dis);
 void remove_transport_disconnect(atransport* t, adisconnect* dis);
@@ -45,7 +41,7 @@
 ** get_device_transport does an acquire on your behalf before returning
 */
 void init_transport_registration(void);
-int list_transports(char* buf, size_t bufsize, int long_listing);
+std::string list_transports(bool long_listing);
 atransport* find_transport(const char* serial);
 
 void register_usb_transport(usb_handle* h, const char* serial,
@@ -54,7 +50,7 @@
 /* cause new transports to be init'd and added to the list */
 int register_socket_transport(int s, const char* serial, int port, int local);
 
-/* this should only be used for transports with connection_state == CS_NOPERM */
+// This should only be used for transports with connection_state == kCsNoPerm.
 void unregister_usb_transport(usb_handle* usb);
 
 /* these should only be used for the "adb disconnect" command */
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 30e6bf5..d3c4c30 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -25,6 +25,8 @@
 #include <string.h>
 #include <sys/types.h>
 
+#include <base/stringprintf.h>
+
 #if !ADB_HOST
 #include "cutils/properties.h"
 #endif
@@ -88,7 +90,6 @@
 
 int local_connect_arbitrary_ports(int console_port, int adb_port)
 {
-    char buf[64];
     int  fd = -1;
 
 #if ADB_HOST
@@ -105,8 +106,8 @@
         D("client: connected on remote on fd %d\n", fd);
         close_on_exec(fd);
         disable_tcp_nagle(fd);
-        snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, console_port);
-        register_socket_transport(fd, buf, adb_port, 1);
+        std::string serial = android::base::StringPrintf("emulator-%d", console_port);
+        register_socket_transport(fd, serial.c_str(), adb_port, 1);
         return 0;
     }
     return -1;
@@ -233,9 +234,8 @@
     if (fd < 0) {
         /* This could be an older version of the emulator, that doesn't
          * implement adb QEMUD service. Fall back to the old TCP way. */
-        adb_thread_t thr;
         D("adb service is not available. Falling back to TCP socket.\n");
-        adb_thread_create(&thr, server_socket_thread, arg);
+        adb_thread_create(server_socket_thread, arg);
         return 0;
     }
 
@@ -278,7 +278,6 @@
 
 void local_init(int port)
 {
-    adb_thread_t thr;
     void* (*func)(void *);
 
     if(HOST) {
@@ -303,9 +302,8 @@
 
     D("transport: local %s init\n", HOST ? "client" : "server");
 
-    if(adb_thread_create(&thr, func, (void *) (uintptr_t) port)) {
-        fatal_errno("cannot create local socket %s thread",
-                    HOST ? "client" : "server");
+    if (!adb_thread_create(func, (void *) (uintptr_t) port)) {
+        fatal_errno("cannot create local socket %s thread", HOST ? "client" : "server");
     }
 }
 
@@ -389,7 +387,7 @@
     t->write_to_remote = remote_write;
     t->sfd = s;
     t->sync_token = 1;
-    t->connection_state = CS_OFFLINE;
+    t->connection_state = kCsOffline;
     t->type = kTransportLocal;
     t->adb_port = 0;
 
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index cdabffe..eb3454d 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -80,7 +80,7 @@
     usb_kick(t->usb);
 }
 
-void init_usb_transport(atransport *t, usb_handle *h, int state)
+void init_usb_transport(atransport *t, usb_handle *h, ConnectionState state)
 {
     D("transport: usb\n");
     t->close = remote_close;
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index 999eb11..1e5d5c8 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -310,10 +310,6 @@
     closedir(busdir);
 }
 
-void usb_cleanup()
-{
-}
-
 static int usb_bulk_write(usb_handle *h, const void *data, int len)
 {
     struct usbdevfs_urb *urb = &h->urb_out;
@@ -569,16 +565,15 @@
 
 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)
-{
-        /* 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
-        ** closed and everything will work out fine.
-        **
-        ** If we have a usb_handle on the list 'o handles with a matching
-        ** name, we have no further work to do.
-        */
+                            int interface, int serial_index,
+                            unsigned zero_mask) {
+    // 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 closed and everything will work out
+    // fine.
+    //
+    // If we have a usb_handle on the list 'o handles with a matching 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) {
         if (!strcmp(usb->fname, dev_name)) {
@@ -599,7 +594,8 @@
 
     adb_cond_init(&usb->notify, 0);
     adb_mutex_init(&usb->lock, 0);
-    /* initialize mark to 1 so we don't get garbage collected after the device scan */
+    // Initialize mark to 1 so we don't get garbage collected after the device
+    // scan.
     usb->mark = 1;
     usb->reaper_thread = 0;
 
@@ -615,11 +611,13 @@
         usb->writeable = 0;
     }
 
-    D("[ usb opened %s%s, fd=%d]\n", usb->fname, (usb->writeable ? "" : " (read-only)"), usb->desc);
+    D("[ usb opened %s%s, fd=%d]\n", usb->fname,
+      (usb->writeable ? "" : " (read-only)"), usb->desc);
 
     if (usb->writeable) {
         if (ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface) != 0) {
-            D("[ usb ioctl(%d, USBDEVFS_CLAIMINTERFACE) failed: %s]\n", usb->desc, strerror(errno));
+            D("[ usb ioctl(%d, USBDEVFS_CLAIMINTERFACE) failed: %s]\n",
+              usb->desc, strerror(errno));
             adb_close(usb->desc);
             free(usb);
             return;
@@ -627,18 +625,19 @@
     }
 
     // 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_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;
+        // We don't actually want to treat an unknown serial as an error because
+        // devices aren't able to communicate a serial number in early bringup.
+        // http://b/20883914
+        serial = "";
     }
     serial = android::base::Trim(serial);
 
-        /* add to the end of the active handles */
+    // Add to the end of the active handles.
     adb_mutex_lock(&usb_lock);
     usb->next = &handle_list;
     usb->prev = handle_list.prev;
@@ -649,26 +648,23 @@
     register_usb_transport(usb, serial.c_str(), dev_path, usb->writeable);
 }
 
-static void* device_poll_thread(void* unused)
-{
+static void* device_poll_thread(void* unused) {
     D("Created device thread\n");
-    for(;;) {
-            /* XXX use inotify */
+    while (true) {
+        // TODO: Use inotify.
         find_usb_device("/dev/bus/usb", register_device);
         kick_disconnected_devices();
         sleep(1);
     }
-    return NULL;
+    return nullptr;
 }
 
-static void sigalrm_handler(int signo)
-{
+static void sigalrm_handler(int signo) {
     // don't need to do anything here
 }
 
 void usb_init()
 {
-    adb_thread_t tid;
     struct sigaction    actions;
 
     memset(&actions, 0, sizeof(actions));
@@ -677,7 +673,7 @@
     actions.sa_handler = sigalrm_handler;
     sigaction(SIGALRM,& actions, NULL);
 
-    if(adb_thread_create(&tid, device_poll_thread, NULL)){
+    if (!adb_thread_create(device_poll_thread, nullptr)) {
         fatal_errno("cannot create input thread");
     }
 }
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index 18289e2..63bb1c7 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -82,7 +82,7 @@
     struct func_desc fs_descs, hs_descs;
 } __attribute__((packed));
 
-struct func_desc fs_descriptors = {
+static struct func_desc fs_descriptors = {
     .intf = {
         .bLength = sizeof(fs_descriptors.intf),
         .bDescriptorType = USB_DT_INTERFACE,
@@ -109,7 +109,7 @@
     },
 };
 
-struct func_desc hs_descriptors = {
+static struct func_desc hs_descriptors = {
     .intf = {
         .bLength = sizeof(hs_descriptors.intf),
         .bDescriptorType = USB_DT_INTERFACE,
@@ -264,8 +264,7 @@
     }
 
     D("[ usb_init - starting thread ]\n");
-    adb_thread_t tid;
-    if(adb_thread_create(&tid, usb_adb_open_thread, h)){
+    if (!adb_thread_create(usb_adb_open_thread, h)) {
         fatal_errno("cannot create usb thread");
     }
 }
@@ -483,8 +482,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)){
+    if (!adb_thread_create(usb_ffs_open_thread, h)) {
         fatal_errno("[ cannot create usb thread ]\n");
     }
 }
@@ -497,10 +495,6 @@
         usb_adb_init();
 }
 
-void usb_cleanup()
-{
-}
-
 int usb_write(usb_handle *h, const void *data, int len)
 {
     return h->write(h, data, len);
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index a795ce3..af65130 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -398,22 +398,27 @@
     IONotificationPortDestroy(notificationPort);
 
     DBG("RunLoopThread done\n");
-    return NULL;    
+    return NULL;
 }
 
+static void usb_cleanup() {
+    DBG("usb_cleanup\n");
+    close_usb_devices();
+    if (currentRunLoop)
+        CFRunLoopStop(currentRunLoop);
+}
 
-static int initialized = 0;
-void usb_init()
-{
-    if (!initialized)
-    {
-        adb_thread_t    tid;
+void usb_init() {
+    static bool initialized = false;
+    if (!initialized) {
+        atexit(usb_cleanup);
 
         adb_mutex_init(&start_lock, NULL);
         adb_cond_init(&start_cond, NULL);
 
-        if(adb_thread_create(&tid, RunLoopThread, NULL))
+        if (!adb_thread_create(RunLoopThread, nullptr)) {
             fatal_errno("cannot create input thread");
+        }
 
         // Wait for initialization to finish
         adb_mutex_lock(&start_lock);
@@ -423,18 +428,10 @@
         adb_mutex_destroy(&start_lock);
         adb_cond_destroy(&start_cond);
 
-        initialized = 1;
+        initialized = true;
     }
 }
 
-void usb_cleanup()
-{
-    DBG("usb_cleanup\n");
-    close_usb_devices();
-    if (currentRunLoop)
-        CFRunLoopStop(currentRunLoop);
-}
-
 int usb_write(usb_handle *handle, const void *buf, int len)
 {
     IOReturn    result;
diff --git a/adb/usb_windows.cpp b/adb/usb_windows.cpp
index d2bd58c..25deb1b 100644
--- a/adb/usb_windows.cpp
+++ b/adb/usb_windows.cpp
@@ -93,9 +93,6 @@
 /// Initializes this module
 void usb_init();
 
-/// Cleans up this module
-void usb_cleanup();
-
 /// Opens usb interface (device) by interface (device) name.
 usb_handle* do_usb_open(const wchar_t* interface_name);
 
@@ -181,16 +178,11 @@
 }
 
 void usb_init() {
-  adb_thread_t tid;
-
-  if(adb_thread_create(&tid, device_poll_thread, NULL)) {
+  if (!adb_thread_create(device_poll_thread, nullptr)) {
     fatal_errno("cannot create input thread");
   }
 }
 
-void usb_cleanup() {
-}
-
 usb_handle* do_usb_open(const wchar_t* interface_name) {
   // Allocate our handle
   usb_handle* ret = (usb_handle*)malloc(sizeof(usb_handle));
diff --git a/base/file.cpp b/base/file.cpp
index 6b19818..9a340b7 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -51,7 +51,7 @@
     return false;
   }
   bool result = ReadFdToString(fd, content);
-  TEMP_FAILURE_RETRY(close(fd));
+  close(fd);
   return result;
 }
 
@@ -102,7 +102,7 @@
     ALOGE("android::WriteStringToFile write failed: %s", strerror(errno));
     return CleanUpAfterFailedWrite(path);
   }
-  TEMP_FAILURE_RETRY(close(fd));
+  close(fd);
   return true;
 }
 #endif
@@ -116,7 +116,7 @@
   }
 
   bool result = WriteStringToFd(content, fd);
-  TEMP_FAILURE_RETRY(close(fd));
+  close(fd);
   return result || CleanUpAfterFailedWrite(path);
 }
 
diff --git a/base/file_test.cpp b/base/file_test.cpp
index cbb2751..b138094 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -66,7 +66,7 @@
       << strerror(errno);
   struct stat sb;
   ASSERT_EQ(0, stat(tf.filename, &sb));
-  ASSERT_EQ(0660U, (sb.st_mode & ~S_IFMT));
+  ASSERT_EQ(0660U, static_cast<unsigned int>(sb.st_mode & ~S_IFMT));
   ASSERT_EQ(getuid(), sb.st_uid);
   ASSERT_EQ(getgid(), sb.st_gid);
   std::string s;
diff --git a/base/include/base/logging.h b/base/include/base/logging.h
index 230adb8..283a7bc 100644
--- a/base/include/base/logging.h
+++ b/base/include/base/logging.h
@@ -13,10 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 #ifndef BASE_LOGGING_H
 #define BASE_LOGGING_H
 
+// NOTE: For Windows, you must include logging.h after windows.h to allow the
+// following code to suppress the evil ERROR macro:
+#ifdef _WIN32
+// windows.h includes wingdi.h which defines an evil macro ERROR.
+#ifdef ERROR
+#undef ERROR
+#endif
+#endif
+
 #include <functional>
 #include <memory>
 #include <ostream>
diff --git a/base/include/base/stringprintf.h b/base/include/base/stringprintf.h
index 195c1de..d68af87 100644
--- a/base/include/base/stringprintf.h
+++ b/base/include/base/stringprintf.h
@@ -23,16 +23,32 @@
 namespace android {
 namespace base {
 
+// These printf-like functions are implemented in terms of vsnprintf, so they
+// use the same attribute for compile-time format string checking. On Windows,
+// if the mingw version of vsnprintf is used, use `gnu_printf' which allows z
+// in %zd and PRIu64 (and related) to be recognized by the compile-time
+// checking.
+#define FORMAT_ARCHETYPE __printf__
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+#undef FORMAT_ARCHETYPE
+#define FORMAT_ARCHETYPE gnu_printf
+#endif
+#endif
+
 // Returns a string corresponding to printf-like formatting of the arguments.
 std::string StringPrintf(const char* fmt, ...)
-    __attribute__((__format__(__printf__, 1, 2)));
+    __attribute__((__format__(FORMAT_ARCHETYPE, 1, 2)));
 
 // Appends a printf-like formatting of the arguments to 'dst'.
 void StringAppendF(std::string* dst, const char* fmt, ...)
-    __attribute__((__format__(__printf__, 2, 3)));
+    __attribute__((__format__(FORMAT_ARCHETYPE, 2, 3)));
 
 // Appends a printf-like formatting of the arguments to 'dst'.
-void StringAppendV(std::string* dst, const char* format, va_list ap);
+void StringAppendV(std::string* dst, const char* format, va_list ap)
+    __attribute__((__format__(FORMAT_ARCHETYPE, 2, 0)));
+
+#undef FORMAT_ARCHETYPE
 
 }  // namespace base
 }  // namespace android
diff --git a/base/logging.cpp b/base/logging.cpp
index 83957b3..34229a2 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
 #include "base/logging.h"
 
 #include <libgen.h>
@@ -34,9 +38,6 @@
 
 #ifndef _WIN32
 #include <mutex>
-#else
-#define NOGDI // Suppress the evil ERROR macro.
-#include <windows.h>
 #endif
 
 #include "base/macros.h"
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index c2a1dbc..b8084c5 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "DEBUG"
+
 #include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
@@ -26,8 +28,11 @@
 #include <sys/types.h>
 #include <sys/ptrace.h>
 
+#include <memory>
+
 #include <backtrace/Backtrace.h>
-#include <UniquePtr.h>
+
+#include <log/log.h>
 
 #include "backtrace.h"
 
@@ -92,9 +97,11 @@
     return;
   }
 
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
   if (backtrace->Unwind(0)) {
     dump_backtrace_to_log(backtrace.get(), log, "  ");
+  } else {
+    ALOGE("Unwind failed: tid = %d", tid);
   }
 
   if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 094ab48..ccdfe85 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -32,6 +32,9 @@
 #include <sys/stat.h>
 #include <sys/un.h>
 
+#include <memory>
+#include <string>
+
 #include <private/android_filesystem_config.h>
 
 #include <base/stringprintf.h>
@@ -45,10 +48,6 @@
 
 #include <selinux/android.h>
 
-#include <UniquePtr.h>
-
-#include <string>
-
 #include "backtrace.h"
 #include "elf_utils.h"
 #include "machine.h"
@@ -371,7 +370,8 @@
     } else {
       line += '-';
     }
-    line += android::base::StringPrintf("  %8" PRIxPTR, it->end - it->start);
+    line += android::base::StringPrintf("  %8" PRIxPTR "  %8" PRIxPTR,
+                                        it->offset, it->end - it->start);
     if (it->name.length() > 0) {
       line += "  " + it->name;
       std::string build_id;
@@ -379,6 +379,9 @@
         line += " (BuildId: " + build_id + ")";
       }
     }
+    if (it->load_base != 0) {
+      line += android::base::StringPrintf(" (load base 0x%" PRIxPTR ")", it->load_base);
+    }
     _LOG(log, logtype::MAPS, "%s\n", line.c_str());
   }
   if (print_fault_address_marker) {
@@ -441,9 +444,11 @@
     dump_thread_info(log, pid, new_tid);
 
     dump_registers(log, new_tid);
-    UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
+    std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
     if (backtrace->Unwind(0)) {
       dump_backtrace_and_stack(backtrace.get(), log);
+    } else {
+      ALOGE("Unwind of sibling failed: pid = %d, tid = %d", pid, new_tid);
     }
 
     log->current_tid = log->crashed_tid;
@@ -640,15 +645,19 @@
     dump_signal_info(log, tid, signal, si_code);
   }
 
-  UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid));
-  UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
+  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
   dump_abort_message(backtrace.get(), log, abort_msg_address);
   dump_registers(log, tid);
   if (backtrace->Unwind(0)) {
     dump_backtrace_and_stack(backtrace.get(), log);
+  } else {
+    ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
   }
   dump_memory_and_code(log, tid);
-  dump_all_maps(backtrace.get(), map.get(), log, tid);
+  if (map.get() != nullptr) {
+    dump_all_maps(backtrace.get(), map.get(), log, tid);
+  }
 
   if (want_logs) {
     dump_logs(log, pid, 5);
@@ -792,7 +801,7 @@
   *detach_failed = dump_crash(&log, pid, tid, signal, original_si_code, abort_msg_address,
                               dump_sibling_threads, total_sleep_time_usec);
 
-  ALOGI("\nTombstone written to: %s\n", path);
+  _LOG(&log, logtype::BACKTRACE, "\nTombstone written to: %s\n", path);
 
   // Either of these file descriptors can be -1, any error is ignored.
   close(amfd);
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index d6a6d2e..e722f82 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -67,7 +67,7 @@
   }
 
   if (write_to_logcat) {
-    __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, LOG_TAG, buf);
+    __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_FATAL, LOG_TAG, buf);
     if (write_to_activitymanager) {
       if (!android::base::WriteFully(log->amfd, buf, len)) {
         // timeout or other failure on write; stop informing the activity manager
diff --git a/fastboot/engineering_key.p12 b/fastboot/engineering_key.p12
deleted file mode 100644
index d8183b0..0000000
--- a/fastboot/engineering_key.p12
+++ /dev/null
Binary files differ
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e139bcd..7acfd6e 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -280,6 +280,17 @@
             "  flashall                                 flash boot, system, vendor and if found,\n"
             "                                           recovery\n"
             "  flash <partition> [ <filename> ]         write a file to a flash partition\n"
+            "  flashing lock                            locks the device. Prevents flashing"
+            "                                           partitions\n"
+            "  flashing unlock                          unlocks the device. Allows user to"
+            "                                           flash any partition except the ones"
+            "                                           that are related to bootloader\n"
+            "  flashing lock_critical                   Prevents flashing bootloader related"
+            "                                           partitions\n"
+            "  flashing unlock_critical                 Enables flashing bootloader related"
+            "                                           partitions\n"
+            "  flashing get_unlock_ability              Queries bootloader to see if the"
+            "                                           device is unlocked\n"
             "  erase <partition>                        erase a flash partition\n"
             "  format[:[<fs type>][:[<size>]] <partition> format a flash partition.\n"
             "                                           Can override the fs type and/or\n"
@@ -1201,6 +1212,16 @@
             wants_reboot = 1;
         } else if(!strcmp(*argv, "oem")) {
             argc = do_oem_command(argc, argv);
+        } else if(!strcmp(*argv, "flashing") && argc == 2) {
+            if(!strcmp(*(argv+1), "unlock") || !strcmp(*(argv+1), "lock")
+               || !strcmp(*(argv+1), "unlock_critical")
+               || !strcmp(*(argv+1), "lock_critical")
+               || !strcmp(*(argv+1), "get_unlock_ability")) {
+              argc = do_oem_command(argc, argv);
+            } else {
+              usage();
+              return 1;
+            }
         } else {
             usage();
             return 1;
diff --git a/fastboot/p12topem.sh b/fastboot/p12topem.sh
deleted file mode 100755
index f081eb5..0000000
--- a/fastboot/p12topem.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-
-if [ $# -ne 2 ]
-then
- echo "Usage: $0 alias passphrase"
- exit -1
-fi
-
-openssl pkcs12 -passin pass:"$2" -passout pass:"$2" -in $1.p12 -out $1.pem
diff --git a/fastboot/signfile.sh b/fastboot/signfile.sh
deleted file mode 100755
index 3188d2d..0000000
--- a/fastboot/signfile.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-
-if [ $# -ne 3 ]
-then
- echo "Usage: $0 alias filename passpharse"
- exit -1
-fi
-
-openssl dgst -passin pass:"$3" -binary -sha1 -sign $1.pem $2 > $2.sign
-
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index 6ef46ba..63b23b9 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -934,10 +934,6 @@
     struct dm_ioctl *io = (struct dm_ioctl *) buffer;
     char *mount_point = basename(fstab->mount_point);
 
-    // set the dm_ioctl flags
-    io->flags |= 1;
-    io->target_count = 1;
-
     // get verity filesystem size
     if (get_fs_size(fstab->fs_type, fstab->blk_device, &device_size) < 0) {
         return retval;
diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
index da96307..784bc03 100644
--- a/include/backtrace/BacktraceMap.h
+++ b/include/backtrace/BacktraceMap.h
@@ -37,6 +37,8 @@
 
   uintptr_t start;
   uintptr_t end;
+  uintptr_t offset;
+  uintptr_t load_base;
   int flags;
   std::string name;
 };
@@ -82,6 +84,14 @@
     return map.end > 0;
   }
 
+  static uintptr_t GetRelativePc(const backtrace_map_t& map, uintptr_t pc) {
+    if (IsValid(map)) {
+      return pc - map.start + map.load_base;
+    } else {
+      return pc;
+    }
+  }
+
 protected:
   BacktraceMap(pid_t pid);
 
diff --git a/include/log/log.h b/include/log/log.h
index f9299b0..0b17574 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -598,6 +598,7 @@
     LOG_ID_EVENTS = 2,
     LOG_ID_SYSTEM = 3,
     LOG_ID_CRASH = 4,
+    LOG_ID_KERNEL = 5,
 #endif
 
     LOG_ID_MAX
diff --git a/include/log/logprint.h b/include/log/logprint.h
index 1e42b47..96249e9 100644
--- a/include/log/logprint.h
+++ b/include/log/logprint.h
@@ -36,7 +36,9 @@
     FORMAT_TIME,
     FORMAT_THREADTIME,
     FORMAT_LONG,
-    FORMAT_COLOR,
+    /* The following two are modifiers to above formats */
+    FORMAT_MODIFIER_COLOR,     /* converts priority to color */
+    FORMAT_MODIFIER_TIME_USEC, /* switches from msec to usec time precision */
 } AndroidLogPrintFormat;
 
 typedef struct AndroidLogFormat_t AndroidLogFormat;
@@ -56,7 +58,8 @@
 
 void android_log_format_free(AndroidLogFormat *p_format);
 
-void android_log_setPrintFormat(AndroidLogFormat *p_format, 
+/* currently returns 0 if format is a modifier, 1 if not */
+int android_log_setPrintFormat(AndroidLogFormat *p_format,
         AndroidLogPrintFormat format);
 
 /**
@@ -64,7 +67,7 @@
  */
 AndroidLogPrintFormat android_log_formatFromString(const char *s);
 
-/** 
+/**
  * filterExpression: a single filter expression
  * eg "AT:d"
  *
@@ -74,12 +77,12 @@
  *
  */
 
-int android_log_addFilterRule(AndroidLogFormat *p_format, 
+int android_log_addFilterRule(AndroidLogFormat *p_format,
         const char *filterExpression);
 
 
-/** 
- * filterString: a whitespace-separated set of filter expressions 
+/**
+ * filterString: a whitespace-separated set of filter expressions
  * eg "AT:d *:i"
  *
  * returns 0 on success and -1 on invalid expression
@@ -92,7 +95,7 @@
         const char *filterString);
 
 
-/** 
+/**
  * returns 1 if this log line should be printed based on its priority
  * and tag, and 0 if it should not
  */
@@ -129,7 +132,7 @@
  * Returns NULL on malloc error
  */
 
-char *android_log_formatLogLine (    
+char *android_log_formatLogLine (
     AndroidLogFormat *p_format,
     char *defaultBuffer,
     size_t defaultBufferSize,
diff --git a/include/system/audio.h b/include/system/audio.h
index 181a171..8d9ec88 100644
--- a/include/system/audio.h
+++ b/include/system/audio.h
@@ -1102,8 +1102,10 @@
 
 static inline bool audio_is_remote_submix_device(audio_devices_t device)
 {
-    if ((device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) == AUDIO_DEVICE_OUT_REMOTE_SUBMIX
-            || (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) == AUDIO_DEVICE_IN_REMOTE_SUBMIX)
+    if ((audio_is_output_devices(device) &&
+         (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) == AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
+        || (!audio_is_output_devices(device) &&
+         (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) == AUDIO_DEVICE_IN_REMOTE_SUBMIX))
         return true;
     else
         return false;
diff --git a/init/Android.mk b/init/Android.mk
index 0dc257d..b14f9b5 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -50,7 +50,10 @@
     watchdogd.cpp \
 
 LOCAL_MODULE:= init
-LOCAL_C_INCLUDES += system/extras/ext4_utils
+LOCAL_C_INCLUDES += \
+    system/extras/ext4_utils \
+    system/core/mkbootimg
+
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
diff --git a/init/builtins.cpp b/init/builtins.cpp
index d772383..9e5f9ff 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -57,8 +57,14 @@
 
 static int insmod(const char *filename, char *options)
 {
+    char filename_val[PROP_VALUE_MAX];
+    if (expand_props(filename_val, filename, sizeof(filename_val)) == -1) {
+        ERROR("insmod: cannot expand '%s'\n", filename);
+        return -EINVAL;
+    }
+
     std::string module;
-    if (!read_file(filename, &module)) {
+    if (!read_file(filename_val, &module)) {
         return -1;
     }
 
diff --git a/init/init.cpp b/init/init.cpp
index 68c8b7f..60fcf64 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -43,6 +43,7 @@
 
 #include <base/file.h>
 #include <base/stringprintf.h>
+#include <base/strings.h>
 #include <cutils/android_reboot.h>
 #include <cutils/fs.h>
 #include <cutils/iosched_policy.h>
@@ -205,16 +206,15 @@
         return;
     }
 
-    struct stat s;
-    if (stat(svc->args[0], &s) != 0) {
-        ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);
+    struct stat sb;
+    if (stat(svc->args[0], &sb) == -1) {
+        ERROR("cannot find '%s' (%s), disabling '%s'\n", svc->args[0], strerror(errno), svc->name);
         svc->flags |= SVC_DISABLED;
         return;
     }
 
     if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {
-        ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
-               svc->args[0]);
+        ERROR("service '%s' must be one-shot to use dynamic args, disabling\n", svc->args[0]);
         svc->flags |= SVC_DISABLED;
         return;
     }
@@ -618,7 +618,10 @@
     Timer t;
 
     NOTICE("Waiting for %s...\n", COLDBOOT_DONE);
-    if (wait_for_file(COLDBOOT_DONE, COMMAND_RETRY_TIMEOUT)) {
+    // Any longer than 1s is an unreasonable length of time to delay booting.
+    // If you're hitting this timeout, check that you didn't make your
+    // sepolicy regular expressions too expensive (http://b/19899875).
+    if (wait_for_file(COLDBOOT_DONE, 1)) {
         ERROR("Timed out waiting for %s\n", COLDBOOT_DONE);
     }
 
@@ -746,36 +749,20 @@
     return 0;
 }
 
-static void import_kernel_nv(char *name, bool for_emulator)
-{
-    char *value = strchr(name, '=');
-    int name_len = strlen(name);
-
-    if (value == 0) return;
-    *value++ = 0;
-    if (name_len == 0) return;
+static void import_kernel_nv(const std::string& key, const std::string& value, bool for_emulator) {
+    if (key.empty()) return;
 
     if (for_emulator) {
-        /* in the emulator, export any kernel option with the
-         * ro.kernel. prefix */
-        char buff[PROP_NAME_MAX];
-        int len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name );
-
-        if (len < (int)sizeof(buff))
-            property_set( buff, value );
+        // In the emulator, export any kernel option with the "ro.kernel." prefix.
+        property_set(android::base::StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str());
         return;
     }
 
-    if (!strcmp(name,"qemu")) {
-        strlcpy(qemu, value, sizeof(qemu));
-    } else if (!strncmp(name, "androidboot.", 12) && name_len > 12) {
-        const char *boot_prop_name = name + 12;
-        char prop[PROP_NAME_MAX];
-        int cnt;
-
-        cnt = snprintf(prop, sizeof(prop), "ro.boot.%s", boot_prop_name);
-        if (cnt < PROP_NAME_MAX)
-            property_set(prop, value);
+    if (key == "qemu") {
+        strlcpy(qemu, value.c_str(), sizeof(qemu));
+    } else if (android::base::StartsWith(key, "androidboot.")) {
+        property_set(android::base::StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(),
+                     value.c_str());
     }
 }
 
@@ -799,8 +786,7 @@
     }
 }
 
-static void process_kernel_dt(void)
-{
+static void process_kernel_dt() {
     static const char android_dir[] = "/proc/device-tree/firmware/android";
 
     std::string file_name = android::base::StringPrintf("%s/compatible", android_dir);
@@ -813,13 +799,13 @@
     }
 
     std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dir), closedir);
-    if (!dir)
-        return;
+    if (!dir) return;
 
     struct dirent *dp;
     while ((dp = readdir(dir.get())) != NULL) {
-        if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible"))
+        if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible")) {
             continue;
+        }
 
         file_name = android::base::StringPrintf("%s/%s", android_dir, dp->d_name);
 
@@ -831,18 +817,15 @@
     }
 }
 
-static void process_kernel_cmdline(void)
-{
-    /* don't expose the raw commandline to nonpriv processes */
+static void process_kernel_cmdline() {
+    // Don't expose the raw commandline to unprivileged processes.
     chmod("/proc/cmdline", 0440);
 
-    /* first pass does the common stuff, and finds if we are in qemu.
-     * second pass is only necessary for qemu to export all kernel params
-     * as props.
-     */
+    // The first pass does the common stuff, and finds if we are in qemu.
+    // The second pass is only necessary for qemu to export all kernel params
+    // as properties.
     import_kernel_cmdline(false, import_kernel_nv);
-    if (qemu[0])
-        import_kernel_cmdline(true, import_kernel_nv);
+    if (qemu[0]) import_kernel_cmdline(true, import_kernel_nv);
 }
 
 static int queue_property_triggers_action(int nargs, char **args)
@@ -865,17 +848,11 @@
 static selinux_enforcing_status selinux_status_from_cmdline() {
     selinux_enforcing_status status = SELINUX_ENFORCING;
 
-    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, [&](const std::string& key, const std::string& value, bool in_qemu) {
+        if (key == "androidboot.selinux" && value == "permissive") {
+            status = SELINUX_PERMISSIVE;
         }
-    };
-    import_kernel_cmdline(false, fn);
+    });
 
     return status;
 }
@@ -989,7 +966,7 @@
     klog_init();
     klog_set_level(KLOG_NOTICE_LEVEL);
 
-    NOTICE("init%s started!\n", is_first_stage ? "" : " second stage");
+    NOTICE("init %s started!\n", is_first_stage ? "first stage" : "second stage");
 
     if (!is_first_stage) {
         // Indicate that booting is in progress to background fw loaders, etc.
@@ -1002,7 +979,7 @@
         process_kernel_dt();
         process_kernel_cmdline();
 
-        // Propogate the kernel variables to internal variables
+        // Propagate the kernel variables to internal variables
         // used by init as well as the current required properties.
         export_kernel_boot_props();
     }
@@ -1028,7 +1005,7 @@
     // These directories were necessarily created before initial policy load
     // and therefore need their security context restored to the proper value.
     // This must happen before /dev is populated by ueventd.
-    INFO("Running restorecon...\n");
+    NOTICE("Running restorecon...\n");
     restorecon("/dev");
     restorecon("/dev/socket");
     restorecon("/dev/__properties__");
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index b76b04e..df049ed 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -382,13 +382,13 @@
 
 static void parse_config(const char *fn, const std::string& data)
 {
-    struct parse_state state;
     struct listnode import_list;
     struct listnode *node;
     char *args[INIT_PARSER_MAXARGS];
-    int nargs;
 
-    nargs = 0;
+    int nargs = 0;
+
+    parse_state state;
     state.filename = fn;
     state.line = 0;
     state.ptr = strdup(data.c_str());  // TODO: fix this code!
@@ -426,29 +426,28 @@
 
 parser_done:
     list_for_each(node, &import_list) {
-         struct import *import = node_to_item(node, struct import, list);
-         int ret;
-
-         ret = init_parse_config_file(import->filename);
-         if (ret)
-             ERROR("could not import file '%s' from '%s'\n",
-                   import->filename, fn);
+         struct import* import = node_to_item(node, struct import, list);
+         if (!init_parse_config_file(import->filename)) {
+             ERROR("could not import file '%s' from '%s': %s\n",
+                   import->filename, fn, strerror(errno));
+         }
     }
 }
 
-int init_parse_config_file(const char* path) {
+bool init_parse_config_file(const char* path) {
     INFO("Parsing %s...\n", path);
     Timer t;
     std::string data;
     if (!read_file(path, &data)) {
-        return -1;
+        return false;
     }
 
+    data.push_back('\n'); // TODO: fix parse_config.
     parse_config(path, data);
     dump_parser_state();
 
     NOTICE("(Parsing %s took %.2fs.)\n", path, t.duration());
-    return 0;
+    return true;
 }
 
 static int valid_name(const char *name)
diff --git a/init/init_parser.h b/init/init_parser.h
index 6348607..90f880f 100644
--- a/init/init_parser.h
+++ b/init/init_parser.h
@@ -31,7 +31,7 @@
 void queue_all_property_triggers();
 void queue_builtin_action(int (*func)(int nargs, char **args), const char *name);
 
-int init_parse_config_file(const char *fn);
+bool init_parse_config_file(const char* path);
 int expand_props(char *dst, const char *src, int len);
 
 service* make_exec_oneshot_service(int argc, char** argv);
diff --git a/init/log.cpp b/init/log.cpp
index d32f2da..eb5ec42 100644
--- a/init/log.cpp
+++ b/init/log.cpp
@@ -14,30 +14,35 @@
  * limitations under the License.
  */
 
+#include "log.h"
+
 #include <stdlib.h>
 #include <string.h>
 #include <sys/uio.h>
 
 #include <selinux/selinux.h>
 
-#include "log.h"
+#include <base/stringprintf.h>
 
 static void init_klog_vwrite(int level, const char* fmt, va_list ap) {
     static const char* tag = basename(getprogname());
 
-    char prefix[64];
-    snprintf(prefix, sizeof(prefix), "<%d>%s: ", level, tag);
+    // The kernel's printk buffer is only 1024 bytes.
+    // TODO: should we automatically break up long lines into multiple lines?
+    // Or we could log but with something like "..." at the end?
+    char buf[1024];
+    size_t prefix_size = snprintf(buf, sizeof(buf), "<%d>%s: ", level, tag);
+    size_t msg_size = vsnprintf(buf + prefix_size, sizeof(buf) - prefix_size, fmt, ap);
+    if (msg_size >= sizeof(buf) - prefix_size) {
+        msg_size = snprintf(buf + prefix_size, sizeof(buf) - prefix_size,
+                            "(%zu-byte message too long for printk)\n", msg_size);
+    }
 
-    char msg[512];
-    vsnprintf(msg, sizeof(msg), fmt, ap);
+    iovec iov[1];
+    iov[0].iov_base = buf;
+    iov[0].iov_len = prefix_size + msg_size;
 
-    iovec iov[2];
-    iov[0].iov_base = prefix;
-    iov[0].iov_len = strlen(prefix);
-    iov[1].iov_base = msg;
-    iov[1].iov_len = strlen(msg);
-
-    klog_writev(level, iov, 2);
+    klog_writev(level, iov, 1);
 }
 
 void init_klog_write(int level, const char* fmt, ...) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 930ef82..0ee0351 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -46,12 +46,18 @@
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 
+#include <fs_mgr.h>
+#include <base/file.h>
+#include "bootimg.h"
+
 #include "property_service.h"
 #include "init.h"
 #include "util.h"
 #include "log.h"
 
 #define PERSISTENT_PROPERTY_DIR  "/data/property"
+#define FSTAB_PREFIX "/fstab."
+#define RECOVERY_MOUNT_POINT "/recovery"
 
 static int persistent_properties_loaded = 0;
 static bool property_area_initialized = false;
@@ -414,6 +420,7 @@
     Timer t;
     std::string data;
     if (read_file(filename, &data)) {
+        data.push_back('\n');
         load_properties(&data[0], filter);
     }
     NOTICE("(Loading properties from %s took %.2fs.)\n", filename, t.duration());
@@ -506,16 +513,57 @@
     load_persistent_properties();
 }
 
+void load_recovery_id_prop() {
+    char fstab_filename[PROP_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+    char propbuf[PROP_VALUE_MAX];
+    int ret = property_get("ro.hardware", propbuf);
+    if (!ret) {
+        ERROR("ro.hardware not set - unable to load recovery id\n");
+        return;
+    }
+    snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX "%s", propbuf);
+
+    std::unique_ptr<fstab, void(*)(fstab*)> tab(fs_mgr_read_fstab(fstab_filename),
+            fs_mgr_free_fstab);
+    if (!tab) {
+        ERROR("unable to read fstab %s: %s\n", fstab_filename, strerror(errno));
+        return;
+    }
+
+    fstab_rec* rec = fs_mgr_get_entry_for_mount_point(tab.get(), RECOVERY_MOUNT_POINT);
+    if (rec == NULL) {
+        ERROR("/recovery not specified in fstab\n");
+        return;
+    }
+
+    int fd = open(rec->blk_device, O_RDONLY);
+    if (fd == -1) {
+        ERROR("error opening block device %s: %s\n", rec->blk_device, strerror(errno));
+        return;
+    }
+
+    boot_img_hdr hdr;
+    if (android::base::ReadFully(fd, &hdr, sizeof(hdr))) {
+        std::string hex = bytes_to_hex(reinterpret_cast<uint8_t*>(hdr.id), sizeof(hdr.id));
+        property_set("ro.recovery_id", hex.c_str());
+    } else {
+        ERROR("error reading /recovery: %s\n", strerror(errno));
+    }
+
+    close(fd);
+}
+
 void load_all_props() {
     load_properties_from_file(PROP_PATH_SYSTEM_BUILD, 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.*");
 
     load_override_properties();
 
     /* Read persistent properties after all default values have been loaded. */
     load_persistent_properties();
+
+    load_recovery_id_prop();
 }
 
 void start_property_service() {
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 7a4841f..497c606 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -193,10 +193,10 @@
 
 static void parse_config(const char *fn, const std::string& data)
 {
-    struct parse_state state;
     char *args[UEVENTD_PARSER_MAXARGS];
-    int nargs;
-    nargs = 0;
+
+    int nargs = 0;
+    parse_state state;
     state.filename = fn;
     state.line = 1;
     state.ptr = strdup(data.c_str());  // TODO: fix this code!
@@ -231,6 +231,7 @@
         return -1;
     }
 
+    data.push_back('\n'); // TODO: fix parse_config.
     parse_config(fn, data);
     dump_parser_state();
     return 0;
diff --git a/init/util.cpp b/init/util.cpp
index 9343145..9c62f68 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -33,9 +33,11 @@
 #include <sys/un.h>
 
 #include <base/file.h>
+#include <base/strings.h>
 
 /* for ANDROID_SOCKET_* */
 #include <cutils/sockets.h>
+#include <base/stringprintf.h>
 
 #include <private/android_filesystem_config.h>
 
@@ -170,9 +172,6 @@
 
     bool okay = android::base::ReadFdToString(fd, content);
     TEMP_FAILURE_RETRY(close(fd));
-    if (okay) {
-        content->append("\n", 1);
-    }
     return okay;
 }
 
@@ -403,32 +402,16 @@
     }
 }
 
-void import_kernel_cmdline(bool in_qemu, std::function<void(char*,bool)> import_kernel_nv)
-{
-    char cmdline[2048];
-    char *ptr;
-    int fd;
+void import_kernel_cmdline(bool in_qemu,
+                           std::function<void(const std::string&, const std::string&, bool)> fn) {
+    std::string cmdline;
+    android::base::ReadFileToString("/proc/cmdline", &cmdline);
 
-    fd = open("/proc/cmdline", O_RDONLY | O_CLOEXEC);
-    if (fd >= 0) {
-        int n = read(fd, cmdline, sizeof(cmdline) - 1);
-        if (n < 0) n = 0;
-
-        /* get rid of trailing newline, it happens */
-        if (n > 0 && cmdline[n-1] == '\n') n--;
-
-        cmdline[n] = 0;
-        close(fd);
-    } else {
-        cmdline[0] = 0;
-    }
-
-    ptr = cmdline;
-    while (ptr && *ptr) {
-        char *x = strchr(ptr, ' ');
-        if (x != 0) *x++ = 0;
-        import_kernel_nv(ptr, in_qemu);
-        ptr = x;
+    for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
+        std::vector<std::string> pieces = android::base::Split(entry, "=");
+        if (pieces.size() == 2) {
+            fn(pieces[0], pieces[1], in_qemu);
+        }
     }
 }
 
@@ -464,3 +447,13 @@
 {
     return selinux_android_restorecon(pathname, SELINUX_ANDROID_RESTORECON_RECURSE);
 }
+
+/*
+ * Writes hex_len hex characters (1/2 byte) to hex from bytes.
+ */
+std::string bytes_to_hex(const uint8_t* bytes, size_t bytes_len) {
+    std::string hex("0x");
+    for (size_t i = 0; i < bytes_len; i++)
+        android::base::StringAppendF(&hex, "%02x", bytes[i]);
+    return hex;
+}
diff --git a/init/util.h b/init/util.h
index 6864acf..3aba599 100644
--- a/init/util.h
+++ b/init/util.h
@@ -58,8 +58,10 @@
 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(bool in_qemu, std::function<void(char*,bool)>);
+void import_kernel_cmdline(bool in_qemu,
+                           std::function<void(const std::string&, const std::string&, bool)>);
 int make_dir(const char *path, mode_t mode);
 int restorecon(const char *pathname);
 int restorecon_recursive(const char *pathname);
+std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len);
 #endif
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index 54cace9..be8b803 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -51,18 +51,10 @@
 	UnwindMap.cpp \
 	UnwindPtrace.cpp \
 
-libbacktrace_shared_libraries_target := \
-	libcutils \
-
 libbacktrace_shared_libraries := \
 	libbase \
-	libunwind \
-
-libbacktrace_shared_libraries_host := \
 	liblog \
-
-libbacktrace_static_libraries_host := \
-	libcutils \
+	libunwind \
 
 libbacktrace_ldlibs_host := \
 	-lpthread \
@@ -118,12 +110,14 @@
 backtrace_test_shared_libraries := \
 	libbacktrace_test \
 	libbacktrace \
-
-backtrace_test_shared_libraries_target := \
+	libbase \
 	libcutils \
 
-backtrace_test_static_libraries_host := \
-	libcutils \
+backtrace_test_shared_libraries_target += \
+	libdl \
+
+backtrace_test_ldlibs_host += \
+	-ldl \
 
 module := backtrace_test
 module_tag := debug
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 91ca8b7..128bb04 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -27,6 +27,8 @@
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
+#include <cutils/threads.h>
+
 #include "BacktraceLog.h"
 #include "thread_utils.h"
 #include "UnwindCurrent.h"
@@ -97,12 +99,7 @@
     map_name = "<unknown>";
   }
 
-  uintptr_t relative_pc;
-  if (BacktraceMap::IsValid(frame->map)) {
-    relative_pc = frame->pc - frame->map.start;
-  } else {
-    relative_pc = frame->pc;
-  }
+  uintptr_t relative_pc = BacktraceMap::GetRelativePc(frame->map, frame->pc);
 
   std::string line(StringPrintf("#%02zu pc %" PRIPTR "  %s", frame->num, relative_pc, map_name));
   if (!frame->func_name.empty()) {
@@ -117,7 +114,9 @@
 }
 
 void Backtrace::FillInMap(uintptr_t pc, backtrace_map_t* map) {
-  map_->FillIn(pc, map);
+  if (map_ != nullptr) {
+    map_->FillIn(pc, map);
+  }
 }
 
 Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) {
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index fd1f4da..95cd4d1 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -29,6 +29,8 @@
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
+#include <cutils/threads.h>
+
 #include "BacktraceCurrent.h"
 #include "BacktraceLog.h"
 #include "ThreadEntry.h"
@@ -63,6 +65,11 @@
 }
 
 bool BacktraceCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+  if (GetMap() == nullptr) {
+    // Without a map object, we can't do anything.
+    return false;
+  }
+
   if (ucontext) {
     return UnwindFromContext(num_ignore_frames, ucontext);
   }
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index b0ada46..ca47f67 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -135,7 +135,7 @@
 #if defined(__APPLE__)
 // Corkscrew and libunwind don't compile on the mac, so create a generic
 // map object.
-BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) {
+BacktraceMap* BacktraceMap::Create(pid_t pid, bool /*uncached*/) {
   BacktraceMap* map = new BacktraceMap(pid);
   if (!map->Build()) {
     delete map;
diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp
index 6134438..e10cce1 100644
--- a/libbacktrace/BacktracePtrace.cpp
+++ b/libbacktrace/BacktracePtrace.cpp
@@ -83,13 +83,12 @@
     if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) {
       return 0;
     }
-    align_bytes = sizeof(word_t) - align_bytes;
-    memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + sizeof(word_t) - align_bytes,
-           align_bytes);
-    addr += align_bytes;
-    buffer += align_bytes;
-    bytes -= align_bytes;
-    bytes_read += align_bytes;
+    size_t copy_bytes = MIN(sizeof(word_t) - align_bytes, bytes);
+    memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + align_bytes, copy_bytes);
+    addr += copy_bytes;
+    buffer += copy_bytes;
+    bytes -= copy_bytes;
+    bytes_read += copy_bytes;
   }
 
   size_t num_words = bytes / sizeof(word_t);
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index fa59d07..879fea5 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -51,6 +51,8 @@
 
     map.start = unw_map.start;
     map.end = unw_map.end;
+    map.offset = unw_map.offset;
+    map.load_base = unw_map.load_base;
     map.flags = unw_map.flags;
     map.name = unw_map.path;
 
@@ -91,6 +93,8 @@
 
       map.start = unw_map.start;
       map.end = unw_map.end;
+      map.offset = unw_map.offset;
+      map.load_base = unw_map.load_base;
       map.flags = unw_map.flags;
       map.name = unw_map.path;
 
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
index a7c3de5..07c2430 100644
--- a/libbacktrace/UnwindPtrace.cpp
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -48,6 +48,11 @@
 }
 
 bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+  if (GetMap() == nullptr) {
+    // Without a map object, we can't do anything.
+    return false;
+  }
+
   if (ucontext) {
     BACK_LOGW("Unwinding from a specified context not supported yet.");
     return false;
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 4af6592..760f5cc 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -16,7 +16,9 @@
 
 #define _GNU_SOURCE 1
 #include <dirent.h>
+#include <dlfcn.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <inttypes.h>
 #include <pthread.h>
 #include <signal.h>
@@ -25,25 +27,29 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/ptrace.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <time.h>
 #include <unistd.h>
 
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-// For the THREAD_SIGNAL definition.
-#include "BacktraceCurrent.h"
-
-#include <cutils/atomic.h>
-#include <gtest/gtest.h>
-
 #include <algorithm>
+#include <list>
 #include <memory>
 #include <string>
 #include <vector>
 
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+#include <base/stringprintf.h>
+#include <cutils/atomic.h>
+#include <cutils/threads.h>
+
+#include <gtest/gtest.h>
+
+// For the THREAD_SIGNAL definition.
+#include "BacktraceCurrent.h"
 #include "thread_utils.h"
 
 // Number of microseconds per milliseconds.
@@ -771,6 +777,7 @@
   // Check map name empty, but exists.
   frame.map.start = 1;
   frame.map.end = 1;
+  frame.map.load_base = 0;
 #if defined(__LP64__)
   EXPECT_EQ("#01 pc 0000000000000001  <unknown>",
 #else
@@ -808,6 +815,16 @@
   EXPECT_EQ("#01 pc 12345678  MapFake (ProcFake+645)",
 #endif
             backtrace->FormatFrameData(&frame));
+
+  // Check func_name is set, func offset is non-zero, and load_base is non-zero.
+  frame.func_offset = 645;
+  frame.map.load_base = 100;
+#if defined(__LP64__)
+  EXPECT_EQ("#01 pc 00000000123456dc  MapFake (ProcFake+645)",
+#else
+  EXPECT_EQ("#01 pc 123456dc  MapFake (ProcFake+645)",
+#endif
+            backtrace->FormatFrameData(&frame));
 }
 
 struct map_test_t {
@@ -871,6 +888,17 @@
   ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
 }
 
+void InitMemory(uint8_t* memory, size_t bytes) {
+  for (size_t i = 0; i < bytes; i++) {
+    memory[i] = i;
+    if (memory[i] == '\0') {
+      // Don't use '\0' in our data so we can verify that an overread doesn't
+      // occur by using a '\0' as the character after the read data.
+      memory[i] = 23;
+    }
+  }
+}
+
 void* ThreadReadTest(void* data) {
   thread_t* thread_data = reinterpret_cast<thread_t*>(data);
 
@@ -889,9 +917,7 @@
   }
 
   // Set up a simple pattern in memory.
-  for (size_t i = 0; i < pagesize; i++) {
-    memory[i] = i;
-  }
+  InitMemory(memory, pagesize);
 
   thread_data->data = memory;
 
@@ -919,9 +945,8 @@
 
   // Create a page of data to use to do quick compares.
   uint8_t* expected = new uint8_t[pagesize];
-  for (size_t i = 0; i < pagesize; i++) {
-    expected[i] = i;
-  }
+  InitMemory(expected, pagesize);
+
   uint8_t* data = new uint8_t[2*pagesize];
   // Verify that we can only read one page worth of data.
   size_t bytes_read = backtrace->Read(read_addr, data, 2 * pagesize);
@@ -935,6 +960,20 @@
     ASSERT_TRUE(memcmp(data, &expected[i], 2 * sizeof(word_t)) == 0)
         << "Offset at " << i << " failed";
   }
+
+  // Verify small unaligned reads.
+  for (size_t i = 1; i < sizeof(word_t); i++) {
+    for (size_t j = 1; j < sizeof(word_t); j++) {
+      // Set one byte past what we expect to read, to guarantee we don't overread.
+      data[j] = '\0';
+      bytes_read = backtrace->Read(read_addr + i, data, j);
+      ASSERT_EQ(j, bytes_read);
+      ASSERT_TRUE(memcmp(data, &expected[i], j) == 0)
+          << "Offset at " << i << " length " << j << " miscompared";
+      ASSERT_EQ('\0', data[j])
+          << "Offset at " << i << " length " << j << " wrote too much data";
+    }
+  }
   delete data;
   delete expected;
 }
@@ -978,9 +1017,7 @@
   }
 
   // Set up a simple pattern in memory.
-  for (size_t i = 0; i < pagesize; i++) {
-    memory[i] = i;
-  }
+  InitMemory(memory, pagesize);
 
   g_addr = reinterpret_cast<uintptr_t>(memory);
   g_ready = 1;
@@ -991,6 +1028,7 @@
 }
 
 TEST(libbacktrace, process_read) {
+  g_ready = 0;
   pid_t pid;
   if ((pid = fork()) == 0) {
     ForkedReadTest();
@@ -1037,6 +1075,297 @@
   ASSERT_TRUE(test_executed);
 }
 
+void VerifyFunctionsFound(const std::vector<std::string>& found_functions) {
+  // We expect to find these functions in libbacktrace_test. If we don't
+  // find them, that's a bug in the memory read handling code in libunwind.
+  std::list<std::string> expected_functions;
+  expected_functions.push_back("test_recursive_call");
+  expected_functions.push_back("test_level_one");
+  expected_functions.push_back("test_level_two");
+  expected_functions.push_back("test_level_three");
+  expected_functions.push_back("test_level_four");
+  for (const auto& found_function : found_functions) {
+    for (const auto& expected_function : expected_functions) {
+      if (found_function == expected_function) {
+        expected_functions.remove(found_function);
+        break;
+      }
+    }
+  }
+  ASSERT_TRUE(expected_functions.empty()) << "Not all functions found in shared library.";
+}
+
+const char* CopySharedLibrary() {
+#if defined(__LP64__)
+  const char* lib_name = "lib64";
+#else
+  const char* lib_name = "lib";
+#endif
+
+#if defined(__BIONIC__)
+  const char* tmp_so_name = "/data/local/tmp/libbacktrace_test.so";
+  std::string cp_cmd = android::base::StringPrintf("cp /system/%s/libbacktrace_test.so %s",
+                                                   lib_name, tmp_so_name);
+#else
+  const char* tmp_so_name = "/tmp/libbacktrace_test.so";
+  if (getenv("ANDROID_HOST_OUT") == NULL) {
+    fprintf(stderr, "ANDROID_HOST_OUT not set, make sure you run lunch.");
+    return nullptr;
+  }
+  std::string cp_cmd = android::base::StringPrintf("cp %s/%s/libbacktrace_test.so %s",
+                                                   getenv("ANDROID_HOST_OUT"), lib_name,
+                                                   tmp_so_name);
+#endif
+
+  // Copy the shared so to a tempory directory.
+  system(cp_cmd.c_str());
+
+  return tmp_so_name;
+}
+
+TEST(libbacktrace, check_unreadable_elf_local) {
+  const char* tmp_so_name = CopySharedLibrary();
+  ASSERT_TRUE(tmp_so_name != nullptr);
+
+  struct stat buf;
+  ASSERT_TRUE(stat(tmp_so_name, &buf) != -1);
+  uintptr_t map_size = buf.st_size;
+
+  int fd = open(tmp_so_name, O_RDONLY);
+  ASSERT_TRUE(fd != -1);
+
+  void* map = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
+  ASSERT_TRUE(map != MAP_FAILED);
+  close(fd);
+  ASSERT_TRUE(unlink(tmp_so_name) != -1);
+
+  std::vector<std::string> found_functions;
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
+                                                         BACKTRACE_CURRENT_THREAD));
+  ASSERT_TRUE(backtrace.get() != nullptr);
+
+  // Needed before GetFunctionName will work.
+  backtrace->Unwind(0);
+
+  // Loop through the entire map, and get every function we can find.
+  map_size += reinterpret_cast<uintptr_t>(map);
+  std::string last_func;
+  for (uintptr_t read_addr = reinterpret_cast<uintptr_t>(map);
+       read_addr < map_size; read_addr += 4) {
+    uintptr_t offset;
+    std::string func_name = backtrace->GetFunctionName(read_addr, &offset);
+    if (!func_name.empty() && last_func != func_name) {
+      found_functions.push_back(func_name);
+    }
+    last_func = func_name;
+  }
+
+  ASSERT_TRUE(munmap(map, map_size - reinterpret_cast<uintptr_t>(map)) == 0);
+
+  VerifyFunctionsFound(found_functions);
+}
+
+TEST(libbacktrace, check_unreadable_elf_remote) {
+  const char* tmp_so_name = CopySharedLibrary();
+  ASSERT_TRUE(tmp_so_name != nullptr);
+
+  g_ready = 0;
+
+  struct stat buf;
+  ASSERT_TRUE(stat(tmp_so_name, &buf) != -1);
+  uintptr_t map_size = buf.st_size;
+
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    int fd = open(tmp_so_name, O_RDONLY);
+    if (fd == -1) {
+      fprintf(stderr, "Failed to open file %s: %s\n", tmp_so_name, strerror(errno));
+      unlink(tmp_so_name);
+      exit(0);
+    }
+
+    void* map = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (map == MAP_FAILED) {
+      fprintf(stderr, "Failed to map in memory: %s\n", strerror(errno));
+      unlink(tmp_so_name);
+      exit(0);
+    }
+    close(fd);
+    if (unlink(tmp_so_name) == -1) {
+      fprintf(stderr, "Failed to unlink: %s\n", strerror(errno));
+      exit(0);
+    }
+
+    g_addr = reinterpret_cast<uintptr_t>(map);
+    g_ready = 1;
+    while (true) {
+      usleep(US_PER_MSEC);
+    }
+    exit(0);
+  }
+  ASSERT_TRUE(pid > 0);
+
+  std::vector<std::string> found_functions;
+  uint64_t start = NanoTime();
+  while (true) {
+    ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
+
+    // Wait for the process to get to a stopping point.
+    WaitForStop(pid);
+
+    std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
+    ASSERT_TRUE(backtrace.get() != nullptr);
+
+    uintptr_t read_addr;
+    ASSERT_EQ(sizeof(uintptr_t), backtrace->Read(reinterpret_cast<uintptr_t>(&g_ready), reinterpret_cast<uint8_t*>(&read_addr), sizeof(uintptr_t)));
+    if (read_addr) {
+      ASSERT_EQ(sizeof(uintptr_t), backtrace->Read(reinterpret_cast<uintptr_t>(&g_addr), reinterpret_cast<uint8_t*>(&read_addr), sizeof(uintptr_t)));
+
+      // Needed before GetFunctionName will work.
+      backtrace->Unwind(0);
+
+      // Loop through the entire map, and get every function we can find.
+      map_size += read_addr;
+      std::string last_func;
+      for (; read_addr < map_size; read_addr += 4) {
+        uintptr_t offset;
+        std::string func_name = backtrace->GetFunctionName(read_addr, &offset);
+        if (!func_name.empty() && last_func != func_name) {
+          found_functions.push_back(func_name);
+        }
+        last_func = func_name;
+      }
+      break;
+    }
+    ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+
+    if ((NanoTime() - start) > 5 * NS_PER_SEC) {
+      break;
+    }
+    usleep(US_PER_MSEC);
+  }
+
+  kill(pid, SIGKILL);
+  ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
+
+  VerifyFunctionsFound(found_functions);
+}
+
+bool FindFuncFrameInBacktrace(Backtrace* backtrace, uintptr_t test_func, size_t* frame_num) {
+  backtrace_map_t map;
+  backtrace->FillInMap(test_func, &map);
+  if (!BacktraceMap::IsValid(map)) {
+    return false;
+  }
+
+  // Loop through the frames, and find the one that is in the map.
+  *frame_num = 0;
+  for (Backtrace::const_iterator it = backtrace->begin(); it != backtrace->end(); ++it) {
+    if (BacktraceMap::IsValid(it->map) && map.start == it->map.start &&
+        it->pc >= test_func) {
+      *frame_num = it->num;
+      return true;
+    }
+  }
+  return false;
+}
+
+void VerifyUnreadableElfFrame(Backtrace* backtrace, uintptr_t test_func, size_t frame_num) {
+  ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
+    << DumpFrames(backtrace);
+
+  ASSERT_TRUE(frame_num != 0) << DumpFrames(backtrace);
+  // Make sure that there is at least one more frame above the test func call.
+  ASSERT_LT(frame_num, backtrace->NumFrames()) << DumpFrames(backtrace);
+
+  uintptr_t diff = backtrace->GetFrame(frame_num)->pc - test_func;
+  ASSERT_LT(diff, 200U) << DumpFrames(backtrace);
+}
+
+void VerifyUnreadableElfBacktrace(uintptr_t test_func) {
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
+                                                         BACKTRACE_CURRENT_THREAD));
+  ASSERT_TRUE(backtrace.get() != nullptr);
+  ASSERT_TRUE(backtrace->Unwind(0));
+
+  size_t frame_num;
+  ASSERT_TRUE(FindFuncFrameInBacktrace(backtrace.get(), test_func, &frame_num));
+
+  VerifyUnreadableElfFrame(backtrace.get(), test_func, frame_num);
+}
+
+typedef int (*test_func_t)(int, int, int, int, void (*)(uintptr_t), uintptr_t);
+
+TEST(libbacktrace, unwind_through_unreadable_elf_local) {
+  const char* tmp_so_name = CopySharedLibrary();
+  ASSERT_TRUE(tmp_so_name != nullptr);
+  void* lib_handle = dlopen(tmp_so_name, RTLD_NOW);
+  ASSERT_TRUE(lib_handle != nullptr);
+  ASSERT_TRUE(unlink(tmp_so_name) != -1);
+
+  test_func_t test_func;
+  test_func = reinterpret_cast<test_func_t>(dlsym(lib_handle, "test_level_one"));
+  ASSERT_TRUE(test_func != nullptr);
+
+  ASSERT_NE(test_func(1, 2, 3, 4, VerifyUnreadableElfBacktrace,
+                      reinterpret_cast<uintptr_t>(test_func)), 0);
+
+  ASSERT_TRUE(dlclose(lib_handle) == 0);
+}
+
+TEST(libbacktrace, unwind_through_unreadable_elf_remote) {
+  const char* tmp_so_name = CopySharedLibrary();
+  ASSERT_TRUE(tmp_so_name != nullptr);
+  void* lib_handle = dlopen(tmp_so_name, RTLD_NOW);
+  ASSERT_TRUE(lib_handle != nullptr);
+  ASSERT_TRUE(unlink(tmp_so_name) != -1);
+
+  test_func_t test_func;
+  test_func = reinterpret_cast<test_func_t>(dlsym(lib_handle, "test_level_one"));
+  ASSERT_TRUE(test_func != nullptr);
+
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    test_func(1, 2, 3, 4, 0, 0);
+    exit(0);
+  }
+  ASSERT_TRUE(pid > 0);
+  ASSERT_TRUE(dlclose(lib_handle) == 0);
+
+  uint64_t start = NanoTime();
+  bool done = false;
+  while (!done) {
+    ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
+
+    // Wait for the process to get to a stopping point.
+    WaitForStop(pid);
+
+    std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
+    ASSERT_TRUE(backtrace.get() != nullptr);
+    ASSERT_TRUE(backtrace->Unwind(0));
+
+    size_t frame_num;
+    if (FindFuncFrameInBacktrace(backtrace.get(),
+                                 reinterpret_cast<uintptr_t>(test_func), &frame_num)) {
+
+      VerifyUnreadableElfFrame(backtrace.get(), reinterpret_cast<uintptr_t>(test_func), frame_num);
+      done = true;
+    }
+
+    ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+
+    if ((NanoTime() - start) > 5 * NS_PER_SEC) {
+      break;
+    }
+    usleep(US_PER_MSEC);
+  }
+
+  kill(pid, SIGKILL);
+  ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
+
+  ASSERT_TRUE(done) << "Test function never found in unwind.";
+}
+
 #if defined(ENABLE_PSS_TESTS)
 #include "GetPss.h"
 
@@ -1110,3 +1439,4 @@
   ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
 }
 #endif
+
diff --git a/libbacktrace/thread_utils.c b/libbacktrace/thread_utils.c
index 6f4cd3c..e75f56e 100644
--- a/libbacktrace/thread_utils.c
+++ b/libbacktrace/thread_utils.c
@@ -16,25 +16,12 @@
 
 #include "thread_utils.h"
 
-#if defined(__APPLE__)
+#if !defined(__BIONIC__)
 
-#include <sys/syscall.h>
-
-// Mac OS >= 10.6 has a system call equivalent to Linux's gettid().
-pid_t gettid() {
-  return syscall(SYS_thread_selfid);
-}
-
-#elif !defined(__BIONIC__)
-
-// glibc doesn't implement or export either gettid or tgkill.
+// glibc doesn't implement or export tgkill.
 #include <unistd.h>
 #include <sys/syscall.h>
 
-pid_t gettid() {
-  return syscall(__NR_gettid);
-}
-
 int tgkill(int tgid, int tid, int sig) {
   return syscall(__NR_tgkill, tgid, tid, sig);
 }
diff --git a/libbacktrace/thread_utils.h b/libbacktrace/thread_utils.h
index ae4c929..df83581 100644
--- a/libbacktrace/thread_utils.h
+++ b/libbacktrace/thread_utils.h
@@ -23,8 +23,6 @@
 
 int tgkill(int tgid, int tid, int sig);
 
-pid_t gettid();
-
 __END_DECLS
 
 #endif /* _LIBBACKTRACE_THREAD_UTILS_H */
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 9dc15d1..d5a9050 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -106,9 +106,6 @@
         trace-dev.c \
         uevent.c \
 
-# arch-arm/memset32.S does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
-
 LOCAL_SRC_FILES_arm += arch-arm/memset32.S
 LOCAL_SRC_FILES_arm64 += arch-arm64/android_memset.S
 
diff --git a/libcutils/arch-arm/memset32.S b/libcutils/arch-arm/memset32.S
index 6efab9f..1e89636 100644
--- a/libcutils/arch-arm/memset32.S
+++ b/libcutils/arch-arm/memset32.S
@@ -18,6 +18,8 @@
  *
  */
 
+    .syntax unified
+
     .text
     .align
 
@@ -45,7 +47,7 @@
 
         /* align to 32 bits */
         tst         r0, #2
-        strneh      r1, [r0], #2
+        strhne      r1, [r0], #2
         subne       r2, r2, #2
         .fnend
 
@@ -68,27 +70,27 @@
 
         /* conditionally writes 0 to 7 words (length in r3) */
         movs        r3, r3, lsl #28
-        stmcsia     r0!, {r1, lr}
-        stmcsia     r0!, {r1, lr}
-        stmmiia     r0!, {r1, lr}
+        stmiacs     r0!, {r1, lr}
+        stmiacs     r0!, {r1, lr}
+        stmiami     r0!, {r1, lr}
         movs        r3, r3, lsl #2
         strcs       r1, [r0], #4
 
 .Laligned32:
         mov         r3, r1
 1:      subs        r2, r2, #32
-        stmhsia     r0!, {r1,r3,r12,lr}
-        stmhsia     r0!, {r1,r3,r12,lr}
+        stmiahs     r0!, {r1,r3,r12,lr}
+        stmiahs     r0!, {r1,r3,r12,lr}
         bhs         1b
         add         r2, r2, #32
 
         /* conditionally stores 0 to 30 bytes */
         movs        r2, r2, lsl #28
-        stmcsia     r0!, {r1,r3,r12,lr}
-        stmmiia     r0!, {r1,lr}
+        stmiacs     r0!, {r1,r3,r12,lr}
+        stmiami     r0!, {r1,lr}
         movs        r2, r2, lsl #2
         strcs       r1, [r0], #4
-        strmih      lr, [r0], #2
+        strhmi      lr, [r0], #2
 
         ldr         lr, [sp], #4
         .cfi_def_cfa_offset 0
diff --git a/libcutils/klog.c b/libcutils/klog.c
index f574f08..710dc66 100644
--- a/libcutils/klog.c
+++ b/libcutils/klog.c
@@ -40,6 +40,11 @@
 void klog_init(void) {
     if (klog_fd >= 0) return; /* Already initialized */
 
+    klog_fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
+    if (klog_fd >= 0) {
+        return;
+    }
+
     static const char* name = "/dev/__kmsg__";
     if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {
         klog_fd = open(name, O_WRONLY | O_CLOEXEC);
diff --git a/libcutils/threads.c b/libcutils/threads.c
index 3d8dd48..036f8c5 100644
--- a/libcutils/threads.c
+++ b/libcutils/threads.c
@@ -35,12 +35,7 @@
 #ifndef __ANDROID__
 pid_t gettid() {
 #if defined(__APPLE__)
-  uint64_t owner;
-  int rc = pthread_threadid_np(NULL, &owner);
-  if (rc != 0) {
-    abort();
-  }
-  return owner;
+  return syscall(SYS_thread_selfid);
 #elif defined(__linux__)
   return syscall(__NR_gettid);
 #elif defined(_WIN32)
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 70aff83..d7766f5 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -85,7 +85,7 @@
 LOCAL_CFLAGS := -Werror $(liblog_cflags)
 
 # TODO: This is to work around b/19059885. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv
+LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/liblog/log_read.c b/liblog/log_read.c
index 5364e4f..9c4af30 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -208,6 +208,7 @@
     [LOG_ID_EVENTS] = "events",
     [LOG_ID_SYSTEM] = "system",
     [LOG_ID_CRASH] = "crash",
+    [LOG_ID_KERNEL] = "kernel",
 };
 
 const char *android_log_id_to_name(log_id_t log_id)
diff --git a/liblog/log_read_kern.c b/liblog/log_read_kern.c
index bdc7b18..69b405c 100644
--- a/liblog/log_read_kern.c
+++ b/liblog/log_read_kern.c
@@ -62,7 +62,8 @@
     [LOG_ID_RADIO] = "radio",
     [LOG_ID_EVENTS] = "events",
     [LOG_ID_SYSTEM] = "system",
-    [LOG_ID_CRASH] = "crash"
+    [LOG_ID_CRASH] = "crash",
+    [LOG_ID_KERNEL] = "kernel",
 };
 
 const char *android_log_id_to_name(log_id_t log_id)
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index c62a246..bdee28f 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -310,7 +310,8 @@
     [LOG_ID_RADIO] = "radio",
     [LOG_ID_EVENTS] = "events",
     [LOG_ID_SYSTEM] = "system",
-    [LOG_ID_CRASH] = "crash"
+    [LOG_ID_CRASH] = "crash",
+    [LOG_ID_KERNEL] = "kernel",
 };
 
 const char *android_log_id_to_name(log_id_t log_id)
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 0f01542..a3f1d7e 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -43,6 +43,7 @@
     FilterInfo *filters;
     AndroidLogPrintFormat format;
     bool colored_output;
+    bool usec_time_output;
 };
 
 /*
@@ -185,6 +186,7 @@
     p_ret->global_pri = ANDROID_LOG_VERBOSE;
     p_ret->format = FORMAT_BRIEF;
     p_ret->colored_output = false;
+    p_ret->usec_time_output = false;
 
     return p_ret;
 }
@@ -207,13 +209,19 @@
 
 
 
-void android_log_setPrintFormat(AndroidLogFormat *p_format,
+int android_log_setPrintFormat(AndroidLogFormat *p_format,
         AndroidLogPrintFormat format)
 {
-    if (format == FORMAT_COLOR)
+    if (format == FORMAT_MODIFIER_COLOR) {
         p_format->colored_output = true;
-    else
-        p_format->format = format;
+        return 0;
+    }
+    if (format == FORMAT_MODIFIER_TIME_USEC) {
+        p_format->usec_time_output = true;
+        return 0;
+    }
+    p_format->format = format;
+    return 1;
 }
 
 /**
@@ -231,7 +239,8 @@
     else if (strcmp(formatString, "time") == 0) format = FORMAT_TIME;
     else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
     else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
-    else if (strcmp(formatString, "color") == 0) format = FORMAT_COLOR;
+    else if (strcmp(formatString, "color") == 0) format = FORMAT_MODIFIER_COLOR;
+    else if (strcmp(formatString, "usec") == 0) format = FORMAT_MODIFIER_TIME_USEC;
     else format = FORMAT_OFF;
 
     return format;
@@ -745,7 +754,7 @@
     struct tm tmBuf;
 #endif
     struct tm* ptm;
-    char timeBuf[32];
+    char timeBuf[32]; /* good margin, 23+nul for msec, 26+nul for usec */
     char prefixBuf[128], suffixBuf[128];
     char priChar;
     int prefixSuffixIsHeaderFooter = 0;
@@ -771,6 +780,14 @@
 #endif
     //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
     strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
+    len = strlen(timeBuf);
+    if (p_format->usec_time_output) {
+        snprintf(timeBuf + len, sizeof(timeBuf) - len,
+                 ".%06ld", entry->tv_nsec / 1000);
+    } else {
+        snprintf(timeBuf + len, sizeof(timeBuf) - len,
+                 ".%03ld", entry->tv_nsec / 1000000);
+    }
 
     /*
      * Construct a buffer containing the log header and log message.
@@ -811,23 +828,21 @@
             break;
         case FORMAT_TIME:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%s.%03ld %c/%-8s(%5d): ", timeBuf, entry->tv_nsec / 1000000,
-                priChar, entry->tag, entry->pid);
+                "%s %c/%-8s(%5d): ", timeBuf, priChar, entry->tag, entry->pid);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
         case FORMAT_THREADTIME:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000,
+                "%s %5d %5d %c %-8s: ", timeBuf,
                 entry->pid, entry->tid, priChar, entry->tag);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
         case FORMAT_LONG:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "[ %s.%03ld %5d:%5d %c/%-8s ]\n",
-                timeBuf, entry->tv_nsec / 1000000, entry->pid,
-                entry->tid, priChar, entry->tag);
+                "[ %s %5d:%5d %c/%-8s ]\n",
+                timeBuf, entry->pid, entry->tid, priChar, entry->tag);
             strcpy(suffixBuf + suffixLen, "\n\n");
             suffixLen += 2;
             prefixSuffixIsHeaderFooter = 1;
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 29501be..0e84f4e 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -136,3 +136,12 @@
 
     android_logger_list_close(logger_list);
 }
+
+TEST(libc, __pstore_append) {
+    FILE *fp;
+    ASSERT_TRUE(NULL != (fp = fopen("/dev/pmsg0", "a")));
+    static const char message[] = "libc.__pstore_append\n";
+    ASSERT_EQ((size_t)1, fwrite(message, sizeof(message), 1, fp));
+    ASSERT_EQ(0, fclose(fp));
+    fprintf(stderr, "Reboot, ensure string libc.__pstore_append is in /sys/fs/pstore/pmsg-ramoops-0\n");
+}
diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk
index 503bcb4..7906986 100644
--- a/libmincrypt/Android.mk
+++ b/libmincrypt/Android.mk
@@ -6,8 +6,6 @@
 LOCAL_MODULE := libmincrypt
 LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c
 LOCAL_CFLAGS := -Wall -Werror
-# Clang's slp-vectorize phase has segmentation fault when compiling p256_ec.c.
-LOCAL_CLANG_CFLAGS += -fno-slp-vectorize
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 2b19b93..2c2d785 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -235,7 +235,7 @@
                     "  -r <kbytes>     Rotate log every kbytes. Requires -f\n"
                     "  -n <count>      Sets max number of rotated logs to <count>, default 4\n"
                     "  -v <format>     Sets the log print format, where <format> is:\n\n"
-                    "                  brief color long process raw tag thread threadtime time\n\n"
+                    "                  brief color long process raw tag thread threadtime time usec\n\n"
                     "  -D              print dividers between each log buffer\n"
                     "  -c              clear (flush) the entire log and exit\n"
                     "  -d              dump the log and then exit (don't block)\n"
@@ -291,9 +291,7 @@
         return -1;
     }
 
-    android_log_setPrintFormat(g_logformat, format);
-
-    return 0;
+    return android_log_setPrintFormat(g_logformat, format);
 }
 
 static const char multipliers[][2] = {
@@ -569,10 +567,7 @@
                 if (err < 0) {
                     logcat_panic(true, "Invalid parameter %s to -v\n", optarg);
                 }
-
-                if (strcmp("color", optarg)) { // exception for modifiers
-                    hasSetLogFormat = 1;
-                }
+                hasSetLogFormat |= err;
             break;
 
             case 'Q':
diff --git a/logd/Android.mk b/logd/Android.mk
index e65e9ff..73da8dc 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -18,6 +18,7 @@
     LogWhiteBlackList.cpp \
     libaudit.c \
     LogAudit.cpp \
+    LogKlog.cpp \
     event.logtags
 
 LOCAL_SHARED_LIBRARIES := \
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index bdfed3b..5489cc9 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -33,9 +33,9 @@
 #include "LogCommand.h"
 
 CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
-                                 LogListener * /*swl*/)
-        : FrameworkListener(getLogSocket())
-        , mBuf(*buf) {
+                                 LogListener * /*swl*/) :
+        FrameworkListener(getLogSocket()),
+        mBuf(*buf) {
     // registerCmd(new ShutdownCmd(buf, writer, swl));
     registerCmd(new ClearCmd(buf));
     registerCmd(new GetBufSizeCmd(buf));
@@ -48,12 +48,12 @@
 }
 
 CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader,
-                                          LogListener *swl)
-        : LogCommand("shutdown")
-        , mBuf(*buf)
-        , mReader(*reader)
-        , mSwl(*swl)
-{ }
+                                          LogListener *swl) :
+        LogCommand("shutdown"),
+        mBuf(*buf),
+        mReader(*reader),
+        mSwl(*swl) {
+}
 
 int CommandListener::ShutdownCmd::runCommand(SocketClient * /*cli*/,
                                              int /*argc*/,
@@ -63,10 +63,10 @@
     exit(0);
 }
 
-CommandListener::ClearCmd::ClearCmd(LogBuffer *buf)
-        : LogCommand("clear")
-        , mBuf(*buf)
-{ }
+CommandListener::ClearCmd::ClearCmd(LogBuffer *buf) :
+        LogCommand("clear"),
+        mBuf(*buf) {
+}
 
 static void setname() {
     static bool name_set;
@@ -100,10 +100,10 @@
     return 0;
 }
 
-CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer *buf)
-        : LogCommand("getLogSize")
-        , mBuf(*buf)
-{ }
+CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer *buf) :
+        LogCommand("getLogSize"),
+        mBuf(*buf) {
+}
 
 int CommandListener::GetBufSizeCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
@@ -126,10 +126,10 @@
     return 0;
 }
 
-CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer *buf)
-        : LogCommand("setLogSize")
-        , mBuf(*buf)
-{ }
+CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer *buf) :
+        LogCommand("setLogSize"),
+        mBuf(*buf) {
+}
 
 int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
@@ -160,10 +160,10 @@
     return 0;
 }
 
-CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf)
-        : LogCommand("getLogSizeUsed")
-        , mBuf(*buf)
-{ }
+CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf) :
+        LogCommand("getLogSizeUsed"),
+        mBuf(*buf) {
+}
 
 int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
@@ -186,10 +186,10 @@
     return 0;
 }
 
-CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer *buf)
-        : LogCommand("getStatistics")
-        , mBuf(*buf)
-{ }
+CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer *buf) :
+        LogCommand("getStatistics"),
+        mBuf(*buf) {
+}
 
 static void package_string(char **strp) {
     const char *a = *strp;
@@ -243,10 +243,10 @@
     return 0;
 }
 
-CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf)
-        : LogCommand("getPruneList")
-        , mBuf(*buf)
-{ }
+CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf) :
+        LogCommand("getPruneList"),
+        mBuf(*buf) {
+}
 
 int CommandListener::GetPruneListCmd::runCommand(SocketClient *cli,
                                          int /*argc*/, char ** /*argv*/) {
@@ -263,10 +263,10 @@
     return 0;
 }
 
-CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer *buf)
-        : LogCommand("setPruneList")
-        , mBuf(*buf)
-{ }
+CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer *buf) :
+        LogCommand("setPruneList"),
+        mBuf(*buf) {
+}
 
 int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
@@ -301,9 +301,8 @@
     return 0;
 }
 
-CommandListener::ReinitCmd::ReinitCmd()
-        : LogCommand("reinit")
-{ }
+CommandListener::ReinitCmd::ReinitCmd() : LogCommand("reinit") {
+}
 
 int CommandListener::ReinitCmd::runCommand(SocketClient *cli,
                                          int /*argc*/, char ** /*argv*/) {
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index 26a1861..d584925 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -27,14 +27,14 @@
                            unsigned long tail,
                            unsigned int logMask,
                            pid_t pid,
-                           uint64_t start)
-        : mReader(reader)
-        , mNonBlock(nonBlock)
-        , mTail(tail)
-        , mLogMask(logMask)
-        , mPid(pid)
-        , mStart(start)
-{ }
+                           uint64_t start) :
+        mReader(reader),
+        mNonBlock(nonBlock),
+        mTail(tail),
+        mLogMask(logMask),
+        mPid(pid),
+        mStart(start) {
+}
 
 // runSocketCommand is called once for every open client on the
 // log reader socket. Here we manage and associated the reader
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index caae54b..4ec2e59 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -29,6 +29,7 @@
 
 #include "libaudit.h"
 #include "LogAudit.h"
+#include "LogKlog.h"
 
 #define KMSG_PRIORITY(PRI)                          \
     '<',                                            \
@@ -36,12 +37,12 @@
     '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, \
     '>'
 
-LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg)
-        : SocketListener(getLogSocket(), false)
-        , logbuf(buf)
-        , reader(reader)
-        , fdDmesg(fdDmesg)
-        , initialized(false) {
+LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg) :
+        SocketListener(getLogSocket(), false),
+        logbuf(buf),
+        reader(reader),
+        fdDmesg(fdDmesg),
+        initialized(false) {
     static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
         'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
         ' ', 's', 't', 'a', 'r', 't', '\n' };
@@ -121,6 +122,15 @@
             && (*cp == ':')) {
         memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
         memmove(timeptr + sizeof(audit_str) - 1 + 3, cp, strlen(cp) + 1);
+        //
+        // We are either in 1970ish (MONOTONIC) or 2015+ish (REALTIME) so to
+        // differentiate without prejudice, we use 1980 to delineate, earlier
+        // is monotonic, later is real.
+        //
+#       define EPOCH_PLUS_10_YEARS (10 * 1461 / 4 * 24 * 60 * 60)
+        if (now.tv_sec < EPOCH_PLUS_10_YEARS) {
+            LogKlog::convertMonotonicToReal(now);
+        }
     } else {
         now.strptime("", ""); // side effect of setting CLOCK_REALTIME
     }
@@ -223,7 +233,7 @@
 int LogAudit::log(char *buf) {
     char *audit = strstr(buf, " audit(");
     if (!audit) {
-        return -EXDEV;
+        return 0;
     }
 
     *audit = '\0';
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 1dced11..8c0a0be 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -126,8 +126,7 @@
     }
 }
 
-LogBuffer::LogBuffer(LastLogTimes *times)
-        : mTimes(*times) {
+LogBuffer::LogBuffer(LastLogTimes *times) : mTimes(*times) {
     pthread_mutex_init(&mLogElementsLock, NULL);
 
     init();
@@ -295,7 +294,9 @@
         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()) {
+            LogBufferElement *l = editEntryAt(index).getLast();
+            if ((l->getDropped() >= EXPIRE_THRESHOLD)
+                    && (current > l->getRealTime().nsec())) {
                 removeAt(index);
                 index = -1;
             }
@@ -387,6 +388,7 @@
         bool kick = false;
         bool leading = true;
         LogBufferElementLast last;
+        log_time start(log_time::EPOCH);
         for(it = mLogElements.begin(); it != mLogElements.end();) {
             LogBufferElement *e = *it;
 
@@ -446,11 +448,29 @@
             }
 
             if (e->getUid() != worst) {
+                if (start != log_time::EPOCH) {
+                    static const timespec too_old = {
+                        EXPIRE_HOUR_THRESHOLD * 60 * 60, 0
+                    };
+                    start = e->getRealTime() + too_old;
+                }
                 last.clear(e);
                 ++it;
                 continue;
             }
 
+            if ((start != log_time::EPOCH) && (e->getRealTime() > start)) {
+                // KISS. Really a heuristic rather than algorithmically strong,
+                // a crude mechanism, the following loops will move the oldest
+                // watermark possibly wiping out the extra EXPIRE_HOUR_THRESHOLD
+                // we just thought we were preserving. We count on the typical
+                // pruneRows of 10% of total not being a sledgehammer.
+                // A stronger algorithm would have us loop back to the top if
+                // we have worst-UID enabled and we start expiring messages
+                // below less than EXPIRE_HOUR_THRESHOLD old.
+                break;
+            }
+
             pruneRows--;
             if (pruneRows == 0) {
                 break;
@@ -630,7 +650,7 @@
         pthread_mutex_unlock(&mLogElementsLock);
 
         // range locking in LastLogTimes looks after us
-        max = element->flushTo(reader);
+        max = element->flushTo(reader, this);
 
         if (max == element->FLUSH_ERROR) {
             return max;
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 9ee243d..00b19b6 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -74,6 +74,7 @@
     // helper
     char *pidToName(pid_t pid) { return stats.pidToName(pid); }
     uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); }
+    char *uidToName(uid_t uid) { return stats.uidToName(uid); }
 
 private:
     void maybePrune(log_id_t id);
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index a173e63..3d7237e 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
 #include <endian.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
@@ -32,14 +34,14 @@
 
 LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
                                    uid_t uid, pid_t pid, pid_t tid,
-                                   const char *msg, unsigned short len)
-        : mLogId(log_id)
-        , mUid(uid)
-        , mPid(pid)
-        , mTid(tid)
-        , mMsgLen(len)
-        , mSequence(sequence.fetch_add(1, memory_order_relaxed))
-        , mRealTime(realtime) {
+                                   const char *msg, unsigned short len) :
+        mLogId(log_id),
+        mUid(uid),
+        mPid(pid),
+        mTid(tid),
+        mMsgLen(len),
+        mSequence(sequence.fetch_add(1, memory_order_relaxed)),
+        mRealTime(realtime) {
     mMsg = new char[len];
     memcpy(mMsg, msg, len);
 }
@@ -48,18 +50,95 @@
     delete [] mMsg;
 }
 
-// assumption: mMsg == NULL
-size_t LogBufferElement::populateDroppedMessage(char *&buffer, bool privileged) {
-    static const char format_uid[] = "uid=%u dropped=%u";
-    static const size_t unprivileged_offset = 7;
-    static const char tag[] = "logd";
-
-    size_t len;
-    if (privileged) {
-        len = snprintf(NULL, 0, format_uid, mUid, mDropped);
-    } else {
-        len = snprintf(NULL, 0, format_uid + unprivileged_offset, mDropped);
+uint32_t LogBufferElement::getTag() const {
+    if ((mLogId != LOG_ID_EVENTS) || !mMsg || (mMsgLen < sizeof(uint32_t))) {
+        return 0;
     }
+    return le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag);
+}
+
+// caller must own and free character string
+char *android::tidToName(pid_t tid) {
+    char *retval = NULL;
+    char buffer[256];
+    snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid);
+    int fd = open(buffer, O_RDONLY);
+    if (fd >= 0) {
+        ssize_t ret = read(fd, buffer, sizeof(buffer));
+        if (ret >= (ssize_t)sizeof(buffer)) {
+            ret = sizeof(buffer) - 1;
+        }
+        while ((ret > 0) && isspace(buffer[ret - 1])) {
+            --ret;
+        }
+        if (ret > 0) {
+            buffer[ret] = '\0';
+            retval = strdup(buffer);
+        }
+        close(fd);
+    }
+
+    // if nothing for comm, check out cmdline
+    char *name = android::pidToName(tid);
+    if (!retval) {
+        retval = name;
+        name = NULL;
+    }
+
+    // check if comm is truncated, see if cmdline has full representation
+    if (name) {
+        // impossible for retval to be NULL if name not NULL
+        size_t retval_len = strlen(retval);
+        size_t name_len = strlen(name);
+        // KISS: ToDo: Only checks prefix truncated, not suffix, or both
+        if ((retval_len < name_len) && !strcmp(retval, name + name_len - retval_len)) {
+            free(retval);
+            retval = name;
+        } else {
+            free(name);
+        }
+    }
+    return retval;
+}
+
+// assumption: mMsg == NULL
+size_t LogBufferElement::populateDroppedMessage(char *&buffer,
+        LogBuffer *parent) {
+    static const char tag[] = "logd";
+    static const char format_uid[] = "uid=%u%s too chatty%s, expire %u line%s";
+
+    char *name = parent->uidToName(mUid);
+    char *commName = android::tidToName(mTid);
+    if (!commName && (mTid != mPid)) {
+        commName = android::tidToName(mPid);
+    }
+    if (!commName) {
+        commName = parent->pidToName(mPid);
+    }
+    if (name && commName && !strcmp(name, commName)) {
+        free(commName);
+        commName = NULL;
+    }
+    if (name) {
+        char *p = NULL;
+        asprintf(&p, "(%s)", name);
+        if (p) {
+            free(name);
+            name = p;
+        }
+    }
+    if (commName) {
+        char *p = NULL;
+        asprintf(&p, " comm=%s", commName);
+        if (p) {
+            free(commName);
+            commName = p;
+        }
+    }
+    // identical to below to calculate the buffer size required
+    size_t len = snprintf(NULL, 0, format_uid, mUid, name ? name : "",
+                          commName ? commName : "",
+                          mDropped, (mDropped > 1) ? "s" : "");
 
     size_t hdrLen;
     if (mLogId == LOG_ID_EVENTS) {
@@ -70,6 +149,8 @@
 
     buffer = static_cast<char *>(calloc(1, hdrLen + len + 1));
     if (!buffer) {
+        free(name);
+        free(commName);
         return 0;
     }
 
@@ -86,16 +167,16 @@
         strcpy(buffer + 1, tag);
     }
 
-    if (privileged) {
-        snprintf(buffer + hdrLen, len + 1, format_uid, mUid, mDropped);
-    } else {
-        snprintf(buffer + hdrLen, len + 1, format_uid + unprivileged_offset, mDropped);
-    }
+    snprintf(buffer + hdrLen, len + 1, format_uid, mUid, name ? name : "",
+             commName ? commName : "",
+             mDropped, (mDropped > 1) ? "s" : "");
+    free(name);
+    free(commName);
 
     return retval;
 }
 
-uint64_t LogBufferElement::flushTo(SocketClient *reader) {
+uint64_t LogBufferElement::flushTo(SocketClient *reader, LogBuffer *parent) {
     struct logger_entry_v3 entry;
 
     memset(&entry, 0, sizeof(struct logger_entry_v3));
@@ -114,7 +195,7 @@
     char *buffer = NULL;
 
     if (!mMsg) {
-        entry.len = populateDroppedMessage(buffer, clientHasLogCredentials(reader));
+        entry.len = populateDroppedMessage(buffer, parent);
         if (!entry.len) {
             return mSequence;
         }
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 7b6456d..3dcf9d1 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -25,18 +25,34 @@
 #include <log/log.h>
 #include <log/log_read.h>
 
+// Hijack this header as a common include file used by most all sources
+// to report some utilities defined here and there.
+
 namespace android {
 
 // Furnished in main.cpp. Caller must own and free returned value
-// This function is designed for a single caller and is NOT thread-safe
 char *uidToName(uid_t uid);
 
+// Furnished in LogStatistics.cpp. Caller must own and free returned value
+char *pidToName(pid_t pid);
+char *tidToName(pid_t tid);
+
+// Furnished in main.cpp. Thread safe.
+const char *tagToName(uint32_t tag);
+
 }
 
 static inline bool worstUidEnabledForLogid(log_id_t id) {
-    return (id != LOG_ID_CRASH) && (id != LOG_ID_EVENTS);
+    return (id != LOG_ID_CRASH) && (id != LOG_ID_KERNEL) && (id != LOG_ID_EVENTS);
 }
 
+class LogBuffer;
+
+#define EXPIRE_HOUR_THRESHOLD 24 // Only expire chatty UID logs to preserve
+                                 // non-chatty UIDs less than this age in hours
+#define EXPIRE_THRESHOLD 4       // A smaller expire count is considered too
+                                 // chatty for the temporal expire messages
+
 class LogBufferElement {
     const log_id_t mLogId;
     const uid_t mUid;
@@ -52,7 +68,8 @@
     static atomic_int_fast64_t sequence;
 
     // assumption: mMsg == NULL
-    size_t populateDroppedMessage(char *&buffer, bool privileged);
+    size_t populateDroppedMessage(char *&buffer,
+                                  LogBuffer *parent);
 
 public:
     LogBufferElement(log_id_t log_id, log_time realtime,
@@ -77,8 +94,10 @@
     static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); }
     log_time getRealTime(void) const { return mRealTime; }
 
+    uint32_t getTag(void) const;
+
     static const uint64_t FLUSH_ERROR;
-    uint64_t flushTo(SocketClient *writer);
+    uint64_t flushTo(SocketClient *writer, LogBuffer *parent);
 };
 
 #endif
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
index b78c0e0..06d865c 100644
--- a/logd/LogCommand.cpp
+++ b/logd/LogCommand.cpp
@@ -23,8 +23,7 @@
 
 #include "LogCommand.h"
 
-LogCommand::LogCommand(const char *cmd)
-        : FrameworkCommand(cmd) {
+LogCommand::LogCommand(const char *cmd) : FrameworkCommand(cmd) {
 }
 
 // gets a list of supplementary group IDs associated with
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
new file mode 100644
index 0000000..8df0d0a
--- /dev/null
+++ b/logd/LogKlog.cpp
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <sys/uio.h>
+#include <syslog.h>
+
+#include <log/logger.h>
+
+#include "LogKlog.h"
+
+#define KMSG_PRIORITY(PRI)           \
+    '<',                             \
+    '0' + (LOG_SYSLOG | (PRI)) / 10, \
+    '0' + (LOG_SYSLOG | (PRI)) % 10, \
+    '>'
+
+static const char priority_message[] = { KMSG_PRIORITY(LOG_INFO), '\0' };
+
+log_time LogKlog::correction = log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC);
+
+LogKlog::LogKlog(LogBuffer *buf, LogReader *reader, int fdWrite, int fdRead, bool auditd) :
+        SocketListener(fdRead, false),
+        logbuf(buf),
+        reader(reader),
+        signature(CLOCK_MONOTONIC),
+        fdWrite(fdWrite),
+        fdRead(fdRead),
+        initialized(false),
+        enableLogging(true),
+        auditd(auditd) {
+    static const char klogd_message[] = "%slogd.klogd: %" PRIu64 "\n";
+    char buffer[sizeof(priority_message) + sizeof(klogd_message) + 20 - 4];
+    snprintf(buffer, sizeof(buffer), klogd_message, priority_message,
+        signature.nsec());
+    write(fdWrite, buffer, strlen(buffer));
+}
+
+bool LogKlog::onDataAvailable(SocketClient *cli) {
+    if (!initialized) {
+        prctl(PR_SET_NAME, "logd.klogd");
+        initialized = true;
+        enableLogging = false;
+    }
+
+    char buffer[LOGGER_ENTRY_MAX_PAYLOAD];
+    size_t len = 0;
+
+    for(;;) {
+        ssize_t retval = 0;
+        if ((sizeof(buffer) - 1 - len) > 0) {
+            retval = read(cli->getSocket(), buffer + len, sizeof(buffer) - 1 - len);
+        }
+        if ((retval == 0) && (len == 0)) {
+            break;
+        }
+        if (retval < 0) {
+            return false;
+        }
+        len += retval;
+        bool full = len == (sizeof(buffer) - 1);
+        char *ep = buffer + len;
+        *ep = '\0';
+        len = 0;
+        for(char *ptr, *tok = buffer;
+                ((tok = strtok_r(tok, "\r\n", &ptr)));
+                tok = NULL) {
+            if (((tok + strlen(tok)) == ep) && (retval != 0) && full) {
+                len = strlen(tok);
+                memmove(buffer, tok, len);
+                break;
+            }
+            if (*tok) {
+                log(tok);
+            }
+        }
+    }
+
+    return true;
+}
+
+
+void LogKlog::calculateCorrection(const log_time &monotonic,
+                                  const char *real_string) {
+    log_time real;
+    if (!real.strptime(real_string, "%Y-%m-%d %H:%M:%S.%09q UTC")) {
+        return;
+    }
+    // kernel report UTC, log_time::strptime is localtime from calendar.
+    // Bionic and liblog strptime does not support %z or %Z to pick up
+    // timezone so we are calculating our own correction.
+    time_t now = real.tv_sec;
+    struct tm tm;
+    memset(&tm, 0, sizeof(tm));
+    tm.tm_isdst = -1;
+    localtime_r(&now, &tm);
+    real.tv_sec += tm.tm_gmtoff;
+    correction = real - monotonic;
+}
+
+void LogKlog::sniffTime(log_time &now, const char **buf, bool reverse) {
+    const char *cp;
+    if ((cp = now.strptime(*buf, "[ %s.%q]"))) {
+        static const char suspend[] = "PM: suspend entry ";
+        static const char resume[] = "PM: suspend exit ";
+        static const char suspended[] = "Suspended for ";
+
+        if (isspace(*cp)) {
+            ++cp;
+        }
+        if (!strncmp(cp, suspend, sizeof(suspend) - 1)) {
+            calculateCorrection(now, cp + sizeof(suspend) - 1);
+        } else if (!strncmp(cp, resume, sizeof(resume) - 1)) {
+            calculateCorrection(now, cp + sizeof(resume) - 1);
+        } else if (!strncmp(cp, suspended, sizeof(suspended) - 1)) {
+            log_time real;
+            char *endp;
+            real.tv_sec = strtol(cp + sizeof(suspended) - 1, &endp, 10);
+            if (*endp == '.') {
+                real.tv_nsec = strtol(endp + 1, &endp, 10) * 1000000L;
+                if (reverse) {
+                    correction -= real;
+                } else {
+                    correction += real;
+                }
+            }
+        }
+
+        convertMonotonicToReal(now);
+        *buf = cp;
+    } else {
+        now = log_time(CLOCK_REALTIME);
+    }
+}
+
+// Passed the entire SYSLOG_ACTION_READ_ALL buffer and interpret a
+// compensated start time.
+void LogKlog::synchronize(const char *buf) {
+    const char *cp = strstr(buf, "] PM: suspend e");
+    if (!cp) {
+        return;
+    }
+
+    do {
+        --cp;
+    } while ((cp > buf) && (isdigit(*cp) || isspace(*cp) || (*cp == '.')));
+
+    log_time now;
+    sniffTime(now, &cp, true);
+
+    char *suspended = strstr(buf, "] Suspended for ");
+    if (!suspended || (suspended > cp)) {
+        return;
+    }
+    cp = suspended;
+
+    do {
+        --cp;
+    } while ((cp > buf) && (isdigit(*cp) || isspace(*cp) || (*cp == '.')));
+
+    sniffTime(now, &cp, true);
+}
+
+// kernel log prefix, convert to a kernel log priority number
+static int parseKernelPrio(const char **buf) {
+    int pri = LOG_USER | LOG_INFO;
+    const char *cp = *buf;
+    if (*cp == '<') {
+        pri = 0;
+        while(isdigit(*++cp)) {
+            pri = (pri * 10) + *cp - '0';
+        }
+        if (*cp == '>') {
+            ++cp;
+        } else {
+            cp = *buf;
+            pri = LOG_USER | LOG_INFO;
+        }
+        *buf = cp;
+    }
+    return pri;
+}
+
+// Convert kernel log priority number into an Android Logger priority number
+static int convertKernelPrioToAndroidPrio(int pri) {
+    switch(pri & LOG_PRIMASK) {
+    case LOG_EMERG:
+        // FALLTHRU
+    case LOG_ALERT:
+        // FALLTHRU
+    case LOG_CRIT:
+        return ANDROID_LOG_FATAL;
+
+    case LOG_ERR:
+        return ANDROID_LOG_ERROR;
+
+    case LOG_WARNING:
+        return ANDROID_LOG_WARN;
+
+    default:
+        // FALLTHRU
+    case LOG_NOTICE:
+        // FALLTHRU
+    case LOG_INFO:
+        break;
+
+    case LOG_DEBUG:
+        return ANDROID_LOG_DEBUG;
+    }
+
+    return ANDROID_LOG_INFO;
+}
+
+//
+// log a message into the kernel log buffer
+//
+// Filter rules to parse <PRI> <TIME> <tag> and <message> in order for
+// them to appear correct in the logcat output:
+//
+// LOG_KERN (0):
+// <PRI>[<TIME>] <tag> ":" <message>
+// <PRI>[<TIME>] <tag> <tag> ":" <message>
+// <PRI>[<TIME>] <tag> <tag>_work ":" <message>
+// <PRI>[<TIME>] <tag> '<tag>.<num>' ":" <message>
+// <PRI>[<TIME>] <tag> '<tag><num>' ":" <message>
+// <PRI>[<TIME>] <tag>_host '<tag>.<num>' ":" <message>
+// (unimplemented) <PRI>[<TIME>] <tag> '<num>.<tag>' ":" <message>
+// <PRI>[<TIME>] "[INFO]"<tag> : <message>
+// <PRI>[<TIME>] "------------[ cut here ]------------"   (?)
+// <PRI>[<TIME>] "---[ end trace 3225a3070ca3e4ac ]---"   (?)
+// LOG_USER, LOG_MAIL, LOG_DAEMON, LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS
+// LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_FTP:
+// <PRI+TAG>[<TIME>] (see sys/syslog.h)
+// Observe:
+//  Minimum tag length = 3   NB: drops things like r5:c00bbadf, but allow PM:
+//  Maximum tag words = 2
+//  Maximum tag length = 16  NB: we are thinking of how ugly logcat can get.
+//  Not a Tag if there is no message content.
+//  leading additional spaces means no tag, inherit last tag.
+//  Not a Tag if <tag>: is "ERROR:", "WARNING:", "INFO:" or "CPU:"
+// Drop:
+//  empty messages
+//  messages with ' audit(' in them if auditd is running
+//  logd.klogd:
+// return -1 if message logd.klogd: <signature>
+//
+int LogKlog::log(const char *buf) {
+    if (auditd && strstr(buf, " audit(")) {
+        return 0;
+    }
+
+    int pri = parseKernelPrio(&buf);
+
+    log_time now;
+    sniffTime(now, &buf, false);
+
+    // sniff for start marker
+    const char klogd_message[] = "logd.klogd: ";
+    if (!strncmp(buf, klogd_message, sizeof(klogd_message) - 1)) {
+        char *endp;
+        uint64_t sig = strtoll(buf + sizeof(klogd_message) - 1, &endp, 10);
+        if (sig == signature.nsec()) {
+            if (initialized) {
+                enableLogging = true;
+            } else {
+                enableLogging = false;
+            }
+            return -1;
+        }
+        return 0;
+    }
+
+    if (!enableLogging) {
+        return 0;
+    }
+
+    // Parse pid, tid and uid (not possible)
+    const pid_t pid = 0;
+    const pid_t tid = 0;
+    const uid_t uid = 0;
+
+    // Parse (rules at top) to pull out a tag from the incoming kernel message.
+    // Some may view the following as an ugly heuristic, the desire is to
+    // beautify the kernel logs into an Android Logging format; the goal is
+    // admirable but costly.
+    while (isspace(*buf)) {
+        ++buf;
+    }
+    if (!*buf) {
+        return 0;
+    }
+    const char *start = buf;
+    const char *tag = "";
+    const char *etag = tag;
+    if (!isspace(*buf)) {
+        const char *bt, *et, *cp;
+
+        bt = buf;
+        if (!strncmp(buf, "[INFO]", 6)) {
+            // <PRI>[<TIME>] "[INFO]"<tag> ":" message
+            bt = buf + 6;
+        }
+        for(et = bt; *et && (*et != ':') && !isspace(*et); ++et);
+        for(cp = et; isspace(*cp); ++cp);
+        size_t size;
+
+        if (*cp == ':') {
+            // One Word
+            tag = bt;
+            etag = et;
+            buf = cp + 1;
+        } else {
+            size = et - bt;
+            if (strncmp(bt, cp, size)) {
+                // <PRI>[<TIME>] <tag>_host '<tag>.<num>' : message
+                if (!strncmp(bt + size - 5, "_host", 5)
+                 && !strncmp(bt, cp, size - 5)) {
+                    const char *b = cp;
+                    cp += size - 5;
+                    if (*cp == '.') {
+                        while (!isspace(*++cp) && (*cp != ':'));
+                        const char *e;
+                        for(e = cp; isspace(*cp); ++cp);
+                        if (*cp == ':') {
+                            tag = b;
+                            etag = e;
+                            buf = cp + 1;
+                        }
+                    }
+                } else {
+                    while (!isspace(*++cp) && (*cp != ':'));
+                    const char *e;
+                    for(e = cp; isspace(*cp); ++cp);
+                    // Two words
+                    if (*cp == ':') {
+                        tag = bt;
+                        etag = e;
+                        buf = cp + 1;
+                    }
+                }
+            } else if (isspace(cp[size])) {
+                const char *b = cp;
+                cp += size;
+                while (isspace(*++cp));
+                // <PRI>[<TIME>] <tag> <tag> : message
+                if (*cp == ':') {
+                    tag = bt;
+                    etag = et;
+                    buf = cp + 1;
+                }
+            } else if (cp[size] == ':') {
+                // <PRI>[<TIME>] <tag> <tag> : message
+                tag = bt;
+                etag = et;
+                buf = cp + size + 1;
+            } else if ((cp[size] == '.') || isdigit(cp[size])) {
+                // <PRI>[<TIME>] <tag> '<tag>.<num>' : message
+                // <PRI>[<TIME>] <tag> '<tag><num>' : message
+                const char *b = cp;
+                cp += size;
+                while (!isspace(*++cp) && (*cp != ':'));
+                const char *e = cp;
+                while (isspace(*cp)) {
+                    ++cp;
+                }
+                if (*cp == ':') {
+                    tag = b;
+                    etag = e;
+                    buf = cp + 1;
+                }
+            } else {
+                while (!isspace(*++cp) && (*cp != ':'));
+                const char *e = cp;
+                while (isspace(*cp)) {
+                    ++cp;
+                }
+                // Two words
+                if (*cp == ':') {
+                    tag = bt;
+                    etag = e;
+                    buf = cp + 1;
+                }
+            }
+        }
+        size = etag - tag;
+        if ((size <= 1)
+         || ((size == 2) && (isdigit(tag[0]) || isdigit(tag[1])))
+         || ((size == 3) && !strncmp(tag, "CPU", 3))
+         || ((size == 7) && !strncmp(tag, "WARNING", 7))
+         || ((size == 5) && !strncmp(tag, "ERROR", 5))
+         || ((size == 4) && !strncmp(tag, "INFO", 4))) {
+            buf = start;
+            etag = tag = "";
+        }
+    }
+    size_t l = etag - tag;
+    while (isspace(*buf)) {
+        ++buf;
+    }
+    size_t n = 1 + l + 1 + strlen(buf) + 1;
+
+    // Allocate a buffer to hold the interpreted log message
+    int rc = n;
+    char *newstr = reinterpret_cast<char *>(malloc(n));
+    if (!newstr) {
+        rc = -ENOMEM;
+        return rc;
+    }
+    char *np = newstr;
+
+    // Convert priority into single-byte Android logger priority
+    *np = convertKernelPrioToAndroidPrio(pri);
+    ++np;
+
+    // Copy parsed tag following priority
+    strncpy(np, tag, l);
+    np += l;
+    *np = '\0';
+    ++np;
+
+    // Copy main message to the remainder
+    strcpy(np, buf);
+
+    // Log message
+    rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr,
+                     (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+    free(newstr);
+
+    // notify readers
+    if (!rc) {
+        reader->notifyNewLog();
+    }
+
+    return rc;
+}
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
new file mode 100644
index 0000000..8de9c87
--- /dev/null
+++ b/logd/LogKlog.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LOGD_LOG_KLOG_H__
+#define _LOGD_LOG_KLOG_H__
+
+#include <sysutils/SocketListener.h>
+#include <log/log_read.h>
+#include "LogReader.h"
+
+class LogKlog : public SocketListener {
+    LogBuffer *logbuf;
+    LogReader *reader;
+    const log_time signature;
+    const int fdWrite; // /dev/kmsg
+    const int fdRead;  // /proc/kmsg
+    // Set once thread is started, separates KLOG_ACTION_READ_ALL
+    // and KLOG_ACTION_READ phases.
+    bool initialized;
+    // Used during each of the above phases to control logging.
+    bool enableLogging;
+    // set if we are also running auditd, to filter out audit reports from
+    // our copy of the kernel log
+    bool auditd;
+
+    static log_time correction;
+
+public:
+    LogKlog(LogBuffer *buf, LogReader *reader, int fdWrite, int fdRead, bool auditd);
+    int log(const char *buf);
+    void synchronize(const char *buf);
+
+    static void convertMonotonicToReal(log_time &real) { real += correction; }
+
+protected:
+    void sniffTime(log_time &now, const char **buf, bool reverse);
+    void calculateCorrection(const log_time &monotonic, const char *real_string);
+    virtual bool onDataAvailable(SocketClient *cli);
+
+};
+
+#endif
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 05ced06..b29f5ab 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -28,11 +28,11 @@
 
 #include "LogListener.h"
 
-LogListener::LogListener(LogBuffer *buf, LogReader *reader)
-        : SocketListener(getLogSocket(), false)
-        , logbuf(buf)
-        , reader(reader)
-{  }
+LogListener::LogListener(LogBuffer *buf, LogReader *reader) :
+        SocketListener(getLogSocket(), false),
+        logbuf(buf),
+        reader(reader) {
+}
 
 bool LogListener::onDataAvailable(SocketClient *cli) {
     static bool name_set;
@@ -88,7 +88,7 @@
     }
 
     android_log_header_t *header = reinterpret_cast<android_log_header_t *>(buffer);
-    if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX) {
+    if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX || header->id == LOG_ID_KERNEL) {
         return false;
     }
 
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 745e847..c7deec0 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -24,10 +24,10 @@
 #include "LogReader.h"
 #include "FlushCommand.h"
 
-LogReader::LogReader(LogBuffer *logbuf)
-        : SocketListener(getLogSocket(), true)
-        , mLogbuf(*logbuf)
-{ }
+LogReader::LogReader(LogBuffer *logbuf) :
+        SocketListener(getLogSocket(), true),
+        mLogbuf(*logbuf) {
+}
 
 // When we are notified a new log entry is available, inform
 // all of our listening sockets.
@@ -116,14 +116,14 @@
             uint64_t last;
 
         public:
-            LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence)
-                    : mPid(pid)
-                    , mLogMask(logMask)
-                    , startTimeSet(false)
-                    , start(start)
-                    , sequence(sequence)
-                    , last(sequence)
-            { }
+            LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence) :
+                    mPid(pid),
+                    mLogMask(logMask),
+                    startTimeSet(false),
+                    start(start),
+                    sequence(sequence),
+                    last(sequence) {
+            }
 
             static int callback(const LogBufferElement *element, void *obj) {
                 LogFindStart *me = reinterpret_cast<LogFindStart *>(obj);
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index eadc4dd..90c49c0 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -26,8 +26,7 @@
 
 #include "LogStatistics.h"
 
-LogStatistics::LogStatistics()
-        : enable(false) {
+LogStatistics::LogStatistics() : enable(false) {
     log_id_for_each(id) {
         mSizes[id] = 0;
         mElements[id] = 0;
@@ -39,10 +38,10 @@
 namespace android {
 
 // caller must own and free character string
-static char *pidToName(pid_t pid) {
+char *pidToName(pid_t pid) {
     char *retval = NULL;
-    if (pid == 0) { // special case from auditd for kernel
-        retval = strdup("logd.auditd");
+    if (pid == 0) { // special case from auditd/klogd for kernel
+        retval = strdup("logd");
     } else {
         char buffer[512];
         snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
@@ -70,50 +69,25 @@
     mSizes[log_id] += size;
     ++mElements[log_id];
 
-    uid_t uid = e->getUid();
-    unsigned short dropped = e->getDropped();
-    android::hash_t hash = android::hash_type(uid);
-    uidTable_t &table = uidTable[log_id];
-    ssize_t index = table.find(-1, hash, uid);
-    if (index == -1) {
-        UidEntry initEntry(uid);
-        initEntry.add(size);
-        initEntry.add_dropped(dropped);
-        table.add(hash, initEntry);
-    } else {
-        UidEntry &entry = table.editEntryAt(index);
-        entry.add(size);
-        entry.add_dropped(dropped);
-    }
-
     mSizesTotal[log_id] += size;
     ++mElementsTotal[log_id];
 
+    if (log_id == LOG_ID_KERNEL) {
+        return;
+    }
+
+    uidTable[log_id].add(e->getUid(), e);
+
     if (!enable) {
         return;
     }
 
-    pid_t pid = e->getPid();
-    hash = android::hash_type(pid);
-    index = pidTable.find(-1, hash, pid);
-    if (index == -1) {
-        PidEntry initEntry(pid, uid, android::pidToName(pid));
-        initEntry.add(size);
-        initEntry.add_dropped(dropped);
-        pidTable.add(hash, initEntry);
-    } else {
-        PidEntry &entry = pidTable.editEntryAt(index);
-        if (entry.getUid() != uid) {
-            entry.setUid(uid);
-            entry.setName(android::pidToName(pid));
-        } else if (!entry.getName()) {
-            char *name = android::pidToName(pid);
-            if (name) {
-                entry.setName(name);
-            }
-        }
-        entry.add(size);
-        entry.add_dropped(dropped);
+    pidTable.add(e->getPid(), e);
+    tidTable.add(e->getTid(), e);
+
+    uint32_t tag = e->getTag();
+    if (tag) {
+        tagTable.add(tag, e);
     }
 }
 
@@ -123,30 +97,22 @@
     mSizes[log_id] -= size;
     --mElements[log_id];
 
-    uid_t uid = e->getUid();
-    unsigned short dropped = e->getDropped();
-    android::hash_t hash = android::hash_type(uid);
-    uidTable_t &table = uidTable[log_id];
-    ssize_t index = table.find(-1, hash, uid);
-    if (index != -1) {
-        UidEntry &entry = table.editEntryAt(index);
-        if (entry.subtract(size) || entry.subtract_dropped(dropped)) {
-            table.removeAt(index);
-        }
+    if (log_id == LOG_ID_KERNEL) {
+        return;
     }
 
+    uidTable[log_id].subtract(e->getUid(), e);
+
     if (!enable) {
         return;
     }
 
-    pid_t pid = e->getPid();
-    hash = android::hash_type(pid);
-    index = pidTable.find(-1, hash, pid);
-    if (index != -1) {
-        PidEntry &entry = pidTable.editEntryAt(index);
-        if (entry.subtract(size) || entry.subtract_dropped(dropped)) {
-            pidTable.removeAt(index);
-        }
+    pidTable.subtract(e->getPid(), e);
+    tidTable.subtract(e->getTid(), e);
+
+    uint32_t tag = e->getTag();
+    if (tag) {
+        tagTable.subtract(tag, e);
     }
 }
 
@@ -157,28 +123,14 @@
     unsigned short size = e->getMsgLen();
     mSizes[log_id] -= size;
 
-    uid_t uid = e->getUid();
-    android::hash_t hash = android::hash_type(uid);
-    typeof uidTable[0] &table = uidTable[log_id];
-    ssize_t index = table.find(-1, hash, uid);
-    if (index != -1) {
-        UidEntry &entry = table.editEntryAt(index);
-        entry.subtract(size);
-        entry.add_dropped(1);
-    }
+    uidTable[log_id].drop(e->getUid(), e);
 
     if (!enable) {
         return;
     }
 
-    pid_t pid = e->getPid();
-    hash = android::hash_type(pid);
-    index = pidTable.find(-1, hash, pid);
-    if (index != -1) {
-        PidEntry &entry = pidTable.editEntryAt(index);
-        entry.subtract(size);
-        entry.add_dropped(1);
-    }
+    pidTable.drop(e->getPid(), e);
+    tidTable.drop(e->getTid(), e);
 }
 
 // caller must own and free character string
@@ -199,7 +151,11 @@
     }
 
     // Parse /data/system/packages.list
-    char *name = android::uidToName(uid);
+    uid_t userId = uid % AID_USER;
+    char *name = android::uidToName(userId);
+    if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
+        name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
+    }
     if (name) {
         return name;
     }
@@ -217,7 +173,8 @@
                     name = strdup(n);
                 } else if (strcmp(name, n)) {
                     free(name);
-                    return NULL;
+                    name = NULL;
+                    break;
                 }
             }
         }
@@ -379,6 +336,7 @@
     }
 
     if (enable) {
+        // Pid table
         bool headerPrinted = false;
         std::unique_ptr<const PidEntry *[]> sorted = pidTable.sort(maximum_sorted_entries);
         ssize_t index = -1;
@@ -435,6 +393,108 @@
         }
     }
 
+    if (enable) {
+        // Tid table
+        bool headerPrinted = false;
+        // sort() returns list of references, unique_ptr makes sure self-delete
+        std::unique_ptr<const TidEntry *[]> sorted = tidTable.sort(maximum_sorted_entries);
+        ssize_t index = -1;
+        while ((index = tidTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
+            const TidEntry *entry = sorted[index];
+            uid_t u = entry->getUid();
+            if ((uid != AID_ROOT) && (u != uid)) {
+                continue;
+            }
+
+            if (!headerPrinted) { // Only print header if we have table to print
+                output.appendFormat("\n\n");
+                android::String8 name("Chattiest TIDs:");
+                android::String8 size("Size");
+                android::String8 pruned("Pruned");
+                format_line(output, name, size, pruned);
+
+                name.setTo("  TID/UID   COMM");
+                size.setTo("BYTES");
+                pruned.setTo("LINES");
+                format_line(output, name, size, pruned);
+
+                headerPrinted = true;
+            }
+
+            android::String8 name("");
+            name.appendFormat("%5u/%u", entry->getKey(), u);
+            const char *n = entry->getName();
+            if (n) {
+                name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", n);
+            } else {
+                // if we do not have a PID name, lets punt to try UID name?
+                char *un = uidToName(u);
+                if (un) {
+                    name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", un);
+                    free(un);
+                }
+                // We tried, better to not have a name at all, we still
+                // have TID/UID by number to report in any case.
+            }
+
+            android::String8 size("");
+            size.appendFormat("%zu", entry->getSizes());
+
+            android::String8 pruned("");
+            size_t dropped = entry->getDropped();
+            if (dropped) {
+                pruned.appendFormat("%zu", dropped);
+            }
+
+            format_line(output, name, size, pruned);
+        }
+    }
+
+    if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
+        // Tag table
+        bool headerPrinted = false;
+        std::unique_ptr<const TagEntry *[]> sorted = tagTable.sort(maximum_sorted_entries);
+        ssize_t index = -1;
+        while ((index = tagTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
+            const TagEntry *entry = sorted[index];
+            uid_t u = entry->getUid();
+            if ((uid != AID_ROOT) && (u != uid)) {
+                continue;
+            }
+
+            android::String8 pruned("");
+
+            if (!headerPrinted) {
+                output.appendFormat("\n\n");
+                android::String8 name("Chattiest events log buffer TAGs:");
+                android::String8 size("Size");
+                format_line(output, name, size, pruned);
+
+                name.setTo("    TAG/UID   TAGNAME");
+                size.setTo("BYTES");
+                format_line(output, name, size, pruned);
+
+                headerPrinted = true;
+            }
+
+            android::String8 name("");
+            if (u == (uid_t)-1) {
+                name.appendFormat("%7u", entry->getKey());
+            } else {
+                name.appendFormat("%7u/%u", entry->getKey(), u);
+            }
+            const char *n = entry->getName();
+            if (n) {
+                name.appendFormat("%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", n);
+            }
+
+            android::String8 size("");
+            size.appendFormat("%zu", entry->getSizes());
+
+            format_line(output, name, size, pruned);
+        }
+    }
+
     *buf = strdup(output.string());
 }
 
@@ -460,48 +520,14 @@
 }
 
 uid_t LogStatistics::pidToUid(pid_t pid) {
-    uid_t uid;
-    android::hash_t hash = android::hash_type(pid);
-    ssize_t index = pidTable.find(-1, hash, pid);
-    if (index == -1) {
-        uid = android::pidToUid(pid);
-        PidEntry initEntry(pid, uid, android::pidToName(pid));
-        pidTable.add(hash, initEntry);
-    } else {
-        PidEntry &entry = pidTable.editEntryAt(index);
-        if (!entry.getName()) {
-            char *name = android::pidToName(pid);
-            if (name) {
-                entry.setName(name);
-            }
-        }
-        uid = entry.getUid();
-    }
-    return uid;
+    return pidTable.entryAt(pidTable.add(pid)).getUid();
 }
 
 // caller must free character string
 char *LogStatistics::pidToName(pid_t pid) {
-    char *name;
-
-    android::hash_t hash = android::hash_type(pid);
-    ssize_t index = pidTable.find(-1, hash, pid);
-    if (index == -1) {
-        name = android::pidToName(pid);
-        PidEntry initEntry(pid, android::pidToUid(pid), name ? strdup(name) : NULL);
-        pidTable.add(hash, initEntry);
-    } else {
-        PidEntry &entry = pidTable.editEntryAt(index);
-        const char *n = entry.getName();
-        if (n) {
-            name = strdup(n);
-        } else {
-            name = android::pidToName(pid);
-            if (name) {
-                entry.setName(strdup(name));
-            }
-        }
+    const char *name = pidTable.entryAt(pidTable.add(pid)).getName();
+    if (!name) {
+        return NULL;
     }
-
-    return name;
+    return strdup(name);
 }
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index f3110d7..f60f3ed 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -73,52 +73,214 @@
     ssize_t next(ssize_t index) {
         return android::BasicHashtable<TKey, TEntry>::next(index);
     }
+
+    size_t add(TKey key, LogBufferElement *e) {
+        android::hash_t hash = android::hash_type(key);
+        ssize_t index = android::BasicHashtable<TKey, TEntry>::find(-1, hash, key);
+        if (index == -1) {
+            return android::BasicHashtable<TKey, TEntry>::add(hash, TEntry(e));
+        }
+        android::BasicHashtable<TKey, TEntry>::editEntryAt(index).add(e);
+        return index;
+    }
+
+    inline size_t add(TKey key) {
+        android::hash_t hash = android::hash_type(key);
+        ssize_t index = android::BasicHashtable<TKey, TEntry>::find(-1, hash, key);
+        if (index == -1) {
+            return android::BasicHashtable<TKey, TEntry>::add(hash, TEntry(key));
+        }
+        android::BasicHashtable<TKey, TEntry>::editEntryAt(index).add(key);
+        return index;
+    }
+
+    void subtract(TKey key, LogBufferElement *e) {
+        ssize_t index = android::BasicHashtable<TKey, TEntry>::find(-1, android::hash_type(key), key);
+        if ((index != -1)
+         && android::BasicHashtable<TKey, TEntry>::editEntryAt(index).subtract(e)) {
+            android::BasicHashtable<TKey, TEntry>::removeAt(index);
+        }
+    }
+
+    inline void drop(TKey key, LogBufferElement *e) {
+        ssize_t index = android::BasicHashtable<TKey, TEntry>::find(-1, android::hash_type(key), key);
+        if (index != -1) {
+            android::BasicHashtable<TKey, TEntry>::editEntryAt(index).drop(e);
+        }
+    }
+
 };
 
-struct UidEntry {
-    const uid_t uid;
+struct EntryBase {
     size_t size;
+
+    EntryBase():size(0) { }
+    EntryBase(LogBufferElement *e):size(e->getMsgLen()) { }
+
+    size_t getSizes() const { return size; }
+
+    inline void add(LogBufferElement *e) { size += e->getMsgLen(); }
+    inline bool subtract(LogBufferElement *e) { size -= e->getMsgLen(); return !size; }
+};
+
+struct EntryBaseDropped : public EntryBase {
     size_t dropped;
 
-    UidEntry(uid_t uid):uid(uid),size(0),dropped(0) { }
+    EntryBaseDropped():dropped(0) { }
+    EntryBaseDropped(LogBufferElement *e):EntryBase(e),dropped(e->getDropped()){ }
 
-    inline const uid_t&getKey() const { return uid; }
-    size_t getSizes() const { return size; }
     size_t getDropped() const { return dropped; }
 
-    inline void add(size_t s) { size += s; }
-    inline void add_dropped(size_t d) { dropped += d; }
-    inline bool subtract(size_t s) { size -= s; return !dropped && !size; }
-    inline bool subtract_dropped(size_t d) { dropped -= d; return !dropped && !size; }
+    inline void add(LogBufferElement *e) {
+        dropped += e->getDropped();
+        EntryBase::add(e);
+    }
+    inline bool subtract(LogBufferElement *e) {
+        dropped -= e->getDropped();
+        return EntryBase::subtract(e) && !dropped;
+    }
+    inline void drop(LogBufferElement *e) {
+        dropped += 1;
+        EntryBase::subtract(e);
+    }
 };
 
-struct PidEntry {
+struct UidEntry : public EntryBaseDropped {
+    const uid_t uid;
+
+    UidEntry(LogBufferElement *e):EntryBaseDropped(e),uid(e->getUid()) { }
+
+    inline const uid_t&getKey() const { return uid; }
+};
+
+namespace android {
+uid_t pidToUid(pid_t pid);
+}
+
+struct PidEntry : public EntryBaseDropped {
     const pid_t pid;
     uid_t uid;
     char *name;
-    size_t size;
-    size_t dropped;
 
-    PidEntry(pid_t p, uid_t u, char *n):pid(p),uid(u),name(n),size(0),dropped(0) { }
+    PidEntry(pid_t p):
+        EntryBaseDropped(),
+        pid(p),
+        uid(android::pidToUid(p)),
+        name(android::pidToName(pid)) { }
+    PidEntry(LogBufferElement *e):
+        EntryBaseDropped(e),
+        pid(e->getPid()),
+        uid(e->getUid()),
+        name(android::pidToName(e->getPid())) { }
     PidEntry(const PidEntry &c):
+        EntryBaseDropped(c),
         pid(c.pid),
         uid(c.uid),
-        name(c.name ? strdup(c.name) : NULL),
-        size(c.size),
-        dropped(c.dropped) { }
+        name(c.name ? strdup(c.name) : NULL) { }
     ~PidEntry() { free(name); }
 
     const pid_t&getKey() const { return pid; }
     const uid_t&getUid() const { return uid; }
-    uid_t&setUid(uid_t u) { return uid = u; }
     const char*getName() const { return name; }
-    char *setName(char *n) { free(name); return name = n; }
-    size_t getSizes() const { return size; }
-    size_t getDropped() const { return dropped; }
-    inline void add(size_t s) { size += s; }
-    inline void add_dropped(size_t d) { dropped += d; }
-    inline bool subtract(size_t s) { size -= s; return !dropped && !size; }
-    inline bool subtract_dropped(size_t d) { dropped -= d; return !dropped && !size; }
+
+    inline void add(pid_t p) {
+        if (name && !strncmp(name, "zygote", 6)) {
+            free(name);
+            name = NULL;
+        }
+        if (!name) {
+            char *n = android::pidToName(p);
+            if (n) {
+                name = n;
+            }
+        }
+    }
+
+    inline void add(LogBufferElement *e) {
+        uid_t u = e->getUid();
+        if (getUid() != u) {
+            uid = u;
+            free(name);
+            name = android::pidToName(e->getPid());
+        } else {
+            add(e->getPid());
+        }
+        EntryBaseDropped::add(e);
+    }
+};
+
+struct TidEntry : public EntryBaseDropped {
+    const pid_t tid;
+    uid_t uid;
+    char *name;
+
+    TidEntry(pid_t t):
+        EntryBaseDropped(),
+        tid(t),
+        uid(android::pidToUid(t)),
+        name(android::tidToName(tid)) { }
+    TidEntry(LogBufferElement *e):
+        EntryBaseDropped(e),
+        tid(e->getTid()),
+        uid(e->getUid()),
+        name(android::tidToName(e->getTid())) { }
+    TidEntry(const TidEntry &c):
+        EntryBaseDropped(c),
+        tid(c.tid),
+        uid(c.uid),
+        name(c.name ? strdup(c.name) : NULL) { }
+    ~TidEntry() { free(name); }
+
+    const pid_t&getKey() const { return tid; }
+    const uid_t&getUid() const { return uid; }
+    const char*getName() const { return name; }
+
+    inline void add(pid_t t) {
+        if (name && !strncmp(name, "zygote", 6)) {
+            free(name);
+            name = NULL;
+        }
+        if (!name) {
+            char *n = android::tidToName(t);
+            if (n) {
+                name = n;
+            }
+        }
+    }
+
+    inline void add(LogBufferElement *e) {
+        uid_t u = e->getUid();
+        if (getUid() != u) {
+            uid = u;
+            free(name);
+            name = android::tidToName(e->getTid());
+        } else {
+            add(e->getTid());
+        }
+        EntryBaseDropped::add(e);
+    }
+};
+
+struct TagEntry : public EntryBase {
+    const uint32_t tag;
+    uid_t uid;
+
+    TagEntry(LogBufferElement *e):
+        EntryBase(e),
+        tag(e->getTag()),
+        uid(e->getUid()) { }
+
+    const uint32_t&getKey() const { return tag; }
+    const uid_t&getUid() const { return uid; }
+    const char*getName() const { return android::tagToName(tag); }
+
+    inline void add(LogBufferElement *e) {
+        uid_t u = e->getUid();
+        if (uid != u) {
+            uid = -1;
+        }
+        EntryBase::add(e);
+    }
 };
 
 // Log Statistics
@@ -137,6 +299,14 @@
     typedef LogHashtable<pid_t, PidEntry> pidTable_t;
     pidTable_t pidTable;
 
+    // tid to uid list
+    typedef LogHashtable<pid_t, TidEntry> tidTable_t;
+    tidTable_t tidTable;
+
+    // tag list
+    typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
+    tagTable_t tagTable;
+
 public:
     LogStatistics();
 
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 1b60b7e..ec67c07 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -26,24 +26,23 @@
 LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client,
                            bool nonBlock, unsigned long tail,
                            unsigned int logMask, pid_t pid,
-                           uint64_t start)
-        : mRefCount(1)
-        , mRelease(false)
-        , mError(false)
-        , threadRunning(false)
-        , mReader(reader)
-        , mLogMask(logMask)
-        , mPid(pid)
-        , mCount(0)
-        , mTail(tail)
-        , mIndex(0)
-        , mClient(client)
-        , mStart(start)
-        , mNonBlock(nonBlock)
-        , mEnd(LogBufferElement::getCurrentSequence())
-{
-        pthread_cond_init(&threadTriggeredCondition, NULL);
-        cleanSkip_Locked();
+                           uint64_t start) :
+        mRefCount(1),
+        mRelease(false),
+        mError(false),
+        threadRunning(false),
+        mReader(reader),
+        mLogMask(logMask),
+        mPid(pid),
+        mCount(0),
+        mTail(tail),
+        mIndex(0),
+        mClient(client),
+        mStart(start),
+        mNonBlock(nonBlock),
+        mEnd(LogBufferElement::getCurrentSequence()) {
+    pthread_cond_init(&threadTriggeredCondition, NULL);
+    cleanSkip_Locked();
 }
 
 void LogTimeEntry::startReader_Locked(void) {
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index bee940d..277b3ca 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -22,10 +22,8 @@
 
 // White and Black list
 
-Prune::Prune(uid_t uid, pid_t pid)
-        : mUid(uid)
-        , mPid(pid)
-{ }
+Prune::Prune(uid_t uid, pid_t pid) : mUid(uid), mPid(pid) {
+}
 
 int Prune::cmp(uid_t uid, pid_t pid) const {
     if ((mUid == uid_all) || (mUid == uid)) {
@@ -51,8 +49,7 @@
     }
 }
 
-PruneList::PruneList()
-        : mWorstUidEnabled(true) {
+PruneList::PruneList() : mWorstUidEnabled(true) {
     mNaughty.clear();
     mNice.clear();
 }
diff --git a/logd/README.property b/logd/README.property
index 60542b2..ad7d0cd 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -4,9 +4,12 @@
 logd.auditd                 bool  true   Enable selinux audit daemon
 logd.auditd.dmesg           bool  true   selinux audit messages duplicated and
                                          sent on to dmesg log
+logd.klogd                  bool depends Enable klogd daemon
 logd.statistics             bool depends Enable logcat -S statistics.
-ro.config.low_ram           bool  false  if true, logd.statistics default false
-ro.build.type               string       if user, logd.statistics default false
+ro.config.low_ram           bool  false  if true, logd.statistics & logd.klogd
+                                         default false
+ro.build.type               string       if user, logd.statistics & logd.klogd
+                                         default false
 persist.logd.size          number 256K   default size of the buffer for all
                                          log ids at initial startup, at runtime
                                          use: logcat -b all -G <value>
diff --git a/logd/libaudit.c b/logd/libaudit.c
index cf76305..d00d579 100644
--- a/logd/libaudit.c
+++ b/logd/libaudit.c
@@ -177,7 +177,7 @@
      */
     status.pid = pid;
     status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT;
-    status.rate_limit = 5; // audit entries per second
+    status.rate_limit = 20; // audit entries per second
 
     /* Let the kernel know this pid will be registering for audit events */
     rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
diff --git a/logd/main.cpp b/logd/main.cpp
index eb29596..6db819e 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -35,12 +35,14 @@
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
+#include <log/event_tag_map.h>
 #include <private/android_filesystem_config.h>
 
 #include "CommandListener.h"
 #include "LogBuffer.h"
 #include "LogListener.h"
 #include "LogAudit.h"
+#include "LogKlog.h"
 
 #define KMSG_PRIORITY(PRI)                            \
     '<',                                              \
@@ -210,18 +212,26 @@
     return NULL;
 }
 
+static sem_t sem_name;
+
 char *android::uidToName(uid_t u) {
     if (!u || !reinit_running) {
         return NULL;
     }
 
-    // Not multi-thread safe, we know there is only one caller
+    sem_wait(&sem_name);
+
+    // Not multi-thread safe, we use sem_name to protect
     uid = u;
 
     name = NULL;
     sem_post(&reinit);
     sem_wait(&uidName);
-    return name;
+    char *ret = name;
+
+    sem_post(&sem_name);
+
+    return ret;
 }
 
 // Serves as a global method to trigger reinitialization
@@ -230,6 +240,34 @@
     sem_post(&reinit);
 }
 
+// tagToName converts an events tag into a name
+const char *android::tagToName(uint32_t tag) {
+    static const EventTagMap *map;
+
+    if (!map) {
+        sem_wait(&sem_name);
+        if (!map) {
+            map = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+        }
+        sem_post(&sem_name);
+        if (!map) {
+            return NULL;
+        }
+    }
+    return android_lookupEventTag(map, tag);
+}
+
+static bool property_get_bool_svelte(const char *key) {
+    bool not_user;
+    {
+        char property[PROPERTY_VALUE_MAX];
+        property_get("ro.build.type", property, "");
+        not_user = !!strcmp(property, "user");
+    }
+    return property_get_bool(key, not_user
+            && !property_get_bool("ro.config.low_ram", false));
+}
+
 // Foreground waits for exit of the main persistent threads
 // that are started here. The threads are created to manage
 // UNIX domain client sockets for writing, reading and
@@ -237,6 +275,11 @@
 // logging plugins like auditd and restart control. Additional
 // transitory per-client threads are created for each reader.
 int main(int argc, char *argv[]) {
+    int fdPmesg = -1;
+    bool klogd = property_get_bool_svelte("logd.klogd");
+    if (klogd) {
+        fdPmesg = open("/proc/kmsg", O_RDONLY | O_NDELAY);
+    }
     fdDmesg = open("/dev/kmsg", O_WRONLY);
 
     // issue reinit command. KISS argument parsing.
@@ -277,6 +320,7 @@
     // Reinit Thread
     sem_init(&reinit, 0, 0);
     sem_init(&uidName, 0, 0);
+    sem_init(&sem_name, 0, 1);
     pthread_attr_t attr;
     if (!pthread_attr_init(&attr)) {
         struct sched_param param;
@@ -312,14 +356,8 @@
 
     signal(SIGHUP, reinit_signal_handler);
 
-    {
-        char property[PROPERTY_VALUE_MAX];
-        property_get("ro.build.type", property, "");
-        if (property_get_bool("logd.statistics",
-                   !!strcmp(property, "user")
-                && !property_get_bool("ro.config.low_ram", false))) {
-            logBuf->enableStatistics();
-        }
+    if (property_get_bool_svelte("logd.statistics")) {
+        logBuf->enableStatistics();
     }
 
     // LogReader listens on /dev/socket/logdr. When a client
@@ -354,12 +392,18 @@
 
     bool auditd = property_get_bool("logd.auditd", true);
 
+    LogAudit *al = NULL;
     if (auditd) {
         bool dmesg = property_get_bool("logd.auditd.dmesg", true);
+        al = new LogAudit(logBuf, reader, dmesg ? fdDmesg : -1);
+    }
 
-        // failure is an option ... messages are in dmesg (required by standard)
-        LogAudit *al = new LogAudit(logBuf, reader, dmesg ? fdDmesg : -1);
+    LogKlog *kl = NULL;
+    if (klogd) {
+        kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != NULL);
+    }
 
+    if (al || kl) {
         int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
         if (len > 0) {
             len++;
@@ -367,16 +411,31 @@
 
             int rc = klogctl(KLOG_READ_ALL, buf, len);
 
-            if (rc >= 0) {
-                buf[len - 1] = '\0';
+            buf[len - 1] = '\0';
 
-                for (char *ptr, *tok = buf; (tok = strtok_r(tok, "\r\n", &ptr)); tok = NULL) {
-                    al->log(tok);
+            if ((rc >= 0) && kl) {
+                kl->synchronize(buf);
+            }
+
+            for (char *ptr, *tok = buf;
+                 (rc >= 0) && ((tok = strtok_r(tok, "\r\n", &ptr)));
+                 tok = NULL) {
+                if (al) {
+                    rc = al->log(tok);
+                }
+                if (kl) {
+                    rc = kl->log(tok);
                 }
             }
         }
 
-        if (al->startListener()) {
+        // failure is an option ... messages are in dmesg (required by standard)
+
+        if (kl && kl->startListener()) {
+            delete kl;
+        }
+
+        if (al && al->startListener()) {
             delete al;
         }
     }
diff --git a/mkbootimg/bootimg.h b/mkbootimg/bootimg.h
index 9171d85..5ab6195 100644
--- a/mkbootimg/bootimg.h
+++ b/mkbootimg/bootimg.h
@@ -15,6 +15,8 @@
 ** limitations under the License.
 */
 
+#include <stdint.h>
+
 #ifndef _BOOT_IMAGE_H_
 #define _BOOT_IMAGE_H_
 
@@ -28,31 +30,31 @@
 
 struct boot_img_hdr
 {
-    unsigned char magic[BOOT_MAGIC_SIZE];
+    uint8_t magic[BOOT_MAGIC_SIZE];
 
-    unsigned kernel_size;  /* size in bytes */
-    unsigned kernel_addr;  /* physical load addr */
+    uint32_t kernel_size;  /* size in bytes */
+    uint32_t kernel_addr;  /* physical load addr */
 
-    unsigned ramdisk_size; /* size in bytes */
-    unsigned ramdisk_addr; /* physical load addr */
+    uint32_t ramdisk_size; /* size in bytes */
+    uint32_t ramdisk_addr; /* physical load addr */
 
-    unsigned second_size;  /* size in bytes */
-    unsigned second_addr;  /* physical load addr */
+    uint32_t second_size;  /* size in bytes */
+    uint32_t second_addr;  /* physical load addr */
 
-    unsigned tags_addr;    /* physical addr for kernel tags */
-    unsigned page_size;    /* flash page size we assume */
-    unsigned unused[2];    /* future expansion: should be 0 */
+    uint32_t tags_addr;    /* physical addr for kernel tags */
+    uint32_t page_size;    /* flash page size we assume */
+    uint32_t unused[2];    /* future expansion: should be 0 */
 
-    unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
+    uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
 
-    unsigned char cmdline[BOOT_ARGS_SIZE];
+    uint8_t cmdline[BOOT_ARGS_SIZE];
 
-    unsigned id[8]; /* timestamp / checksum / sha1 / etc */
+    uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
 
     /* Supplemental command line data; kept here to maintain
      * binary compatibility with older versions of mkbootimg */
-    unsigned char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
-};
+    uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
+} __attribute__((packed));
 
 /*
 ** +-----------------+ 
diff --git a/mkbootimg/mkbootimg.c b/mkbootimg/mkbootimg.c
index fc92b4d..40e5261 100644
--- a/mkbootimg/mkbootimg.c
+++ b/mkbootimg/mkbootimg.c
@@ -21,6 +21,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <stdbool.h>
 
 #include "mincrypt/sha.h"
 #include "bootimg.h"
@@ -65,6 +66,7 @@
             "       [ --board <boardname> ]\n"
             "       [ --base <address> ]\n"
             "       [ --pagesize <pagesize> ]\n"
+            "       [ --id ]\n"
             "       -o|--output <filename>\n"
             );
     return 1;
@@ -74,6 +76,14 @@
 
 static unsigned char padding[16384] = { 0, };
 
+static void print_id(const uint8_t *id, size_t id_len) {
+    printf("0x");
+    for (unsigned i = 0; i < id_len; i++) {
+        printf("%02x", id[i]);
+    }
+    printf("\n");
+}
+
 int write_padding(int fd, unsigned pagesize, unsigned itemsize)
 {
     unsigned pagemask = pagesize - 1;
@@ -96,24 +106,24 @@
 {
     boot_img_hdr hdr;
 
-    char *kernel_fn = 0;
-    void *kernel_data = 0;
-    char *ramdisk_fn = 0;
-    void *ramdisk_data = 0;
-    char *second_fn = 0;
-    void *second_data = 0;
+    char *kernel_fn = NULL;
+    void *kernel_data = NULL;
+    char *ramdisk_fn = NULL;
+    void *ramdisk_data = NULL;
+    char *second_fn = NULL;
+    void *second_data = NULL;
     char *cmdline = "";
-    char *bootimg = 0;
+    char *bootimg = NULL;
     char *board = "";
-    unsigned pagesize = 2048;
+    uint32_t pagesize = 2048;
     int fd;
     SHA_CTX ctx;
     const uint8_t* sha;
-    unsigned base           = 0x10000000;
-    unsigned kernel_offset  = 0x00008000;
-    unsigned ramdisk_offset = 0x01000000;
-    unsigned second_offset  = 0x00f00000;
-    unsigned tags_offset    = 0x00000100;
+    uint32_t base           = 0x10000000U;
+    uint32_t kernel_offset  = 0x00008000U;
+    uint32_t ramdisk_offset = 0x01000000U;
+    uint32_t second_offset  = 0x00f00000U;
+    uint32_t tags_offset    = 0x00000100U;
     size_t cmdlen;
 
     argc--;
@@ -121,42 +131,48 @@
 
     memset(&hdr, 0, sizeof(hdr));
 
+    bool get_id = false;
     while(argc > 0){
         char *arg = argv[0];
-        char *val = argv[1];
-        if(argc < 2) {
-            return usage();
-        }
-        argc -= 2;
-        argv += 2;
-        if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) {
-            bootimg = val;
-        } else if(!strcmp(arg, "--kernel")) {
-            kernel_fn = val;
-        } else if(!strcmp(arg, "--ramdisk")) {
-            ramdisk_fn = val;
-        } else if(!strcmp(arg, "--second")) {
-            second_fn = val;
-        } else if(!strcmp(arg, "--cmdline")) {
-            cmdline = val;
-        } else if(!strcmp(arg, "--base")) {
-            base = strtoul(val, 0, 16);
-        } else if(!strcmp(arg, "--kernel_offset")) {
-            kernel_offset = strtoul(val, 0, 16);
-        } else if(!strcmp(arg, "--ramdisk_offset")) {
-            ramdisk_offset = strtoul(val, 0, 16);
-        } else if(!strcmp(arg, "--second_offset")) {
-            second_offset = strtoul(val, 0, 16);
-        } else if(!strcmp(arg, "--tags_offset")) {
-            tags_offset = strtoul(val, 0, 16);
-        } else if(!strcmp(arg, "--board")) {
-            board = val;
-        } else if(!strcmp(arg,"--pagesize")) {
-            pagesize = strtoul(val, 0, 10);
-            if ((pagesize != 2048) && (pagesize != 4096)
-                && (pagesize != 8192) && (pagesize != 16384)) {
-                fprintf(stderr,"error: unsupported page size %d\n", pagesize);
-                return -1;
+        if (!strcmp(arg, "--id")) {
+            get_id = true;
+            argc -= 1;
+            argv += 1;
+        } else if(argc >= 2) {
+            char *val = argv[1];
+            argc -= 2;
+            argv += 2;
+            if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) {
+                bootimg = val;
+            } else if(!strcmp(arg, "--kernel")) {
+                kernel_fn = val;
+            } else if(!strcmp(arg, "--ramdisk")) {
+                ramdisk_fn = val;
+            } else if(!strcmp(arg, "--second")) {
+                second_fn = val;
+            } else if(!strcmp(arg, "--cmdline")) {
+                cmdline = val;
+            } else if(!strcmp(arg, "--base")) {
+                base = strtoul(val, 0, 16);
+            } else if(!strcmp(arg, "--kernel_offset")) {
+                kernel_offset = strtoul(val, 0, 16);
+            } else if(!strcmp(arg, "--ramdisk_offset")) {
+                ramdisk_offset = strtoul(val, 0, 16);
+            } else if(!strcmp(arg, "--second_offset")) {
+                second_offset = strtoul(val, 0, 16);
+            } else if(!strcmp(arg, "--tags_offset")) {
+                tags_offset = strtoul(val, 0, 16);
+            } else if(!strcmp(arg, "--board")) {
+                board = val;
+            } else if(!strcmp(arg,"--pagesize")) {
+                pagesize = strtoul(val, 0, 10);
+                if ((pagesize != 2048) && (pagesize != 4096)
+                    && (pagesize != 8192) && (pagesize != 16384)) {
+                    fprintf(stderr,"error: unsupported page size %d\n", pagesize);
+                    return -1;
+                }
+            } else {
+                return usage();
             }
         } else {
             return usage();
@@ -266,6 +282,10 @@
         if(write_padding(fd, pagesize, hdr.second_size)) goto fail;
     }
 
+    if (get_id) {
+        print_id((uint8_t *) hdr.id, sizeof(hdr.id));
+    }
+
     return 0;
 
 fail:
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 3ecb1db..7ab76b8 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -26,7 +26,7 @@
 #
 # create some directories (some are mount points)
 LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
-    sbin dev proc sys system data)
+    sbin dev proc sys system data oem)
 
 include $(BUILD_SYSTEM)/base_rules.mk
 
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 3709b82..9fe1b4f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -260,6 +260,7 @@
     mkdir /data/misc/ethernet 0770 system system
     mkdir /data/misc/dhcp 0770 dhcp dhcp
     mkdir /data/misc/user 0771 root root
+    mkdir /data/misc/perfprofd 0775 root root
     # give system access to wpa_supplicant.conf for backup and restore
     chmod 0660 /data/misc/wifi/wpa_supplicant.conf
     mkdir /data/local 0751 root root
@@ -643,3 +644,11 @@
     class main
     disabled
     oneshot
+
+on property:ro.debuggable=1
+    start perfprofd
+
+service perfprofd /system/xbin/perfprofd
+    disabled
+    user root
+    oneshot