More adb buffer fixes.

This patch factors out a lot of the basic protocol code: sending OKAY,
sending FAIL, and sending a length-prefixed string.

ADB_TRACE has been non-optional for a long time, so let's just remove
the #ifs.

Also actually build the device tracker test tool (and remove its duplicate).

Bug: http://b/20666660
Change-Id: I6c7d59f18707bdc62ca69dea45547617f9f31fc6
diff --git a/Android.mk b/Android.mk
index 9b6e147..dd1343b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -124,6 +124,21 @@
 
 include $(BUILD_HOST_NATIVE_TEST)
 
+# 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)
diff --git a/adb.cpp b/adb.cpp
index e526914..11c65da 100644
--- a/adb.cpp
+++ b/adb.cpp
@@ -48,9 +48,7 @@
 #include <sys/mount.h>
 #endif
 
-#if ADB_TRACE
 ADB_MUTEX_DEFINE( D_lock );
-#endif
 
 int HOST = 0;
 
@@ -322,28 +320,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 +332,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.
@@ -752,20 +702,11 @@
 {
     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 +714,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,19 +741,19 @@
         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;
             }
         }
@@ -820,7 +761,7 @@
         std::string error_msg;
         transport = acquire_one_transport(CS_ANY, ttype, serial, &error_msg);
         if (!transport) {
-            sendfailmsg(reply_fd, error_msg.c_str());
+            SendFail(reply_fd, error_msg);
             return 1;
         }
 
@@ -833,9 +774,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,7 +792,7 @@
             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;
@@ -862,7 +803,7 @@
     if(!strcmp(service, "kill")) {
         fprintf(stderr,"adb server killed by remote request\n");
         fflush(stdout);
-        adb_write(reply_fd, "OKAY", 4);
+        SendOkay(reply_fd);
         usb_cleanup();
         exit(0);
     }
@@ -892,25 +833,25 @@
 
         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
@@ -937,15 +878,15 @@
             }
         }
 
-        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;
     }
 
@@ -955,7 +896,8 @@
         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"))) {
@@ -964,7 +906,8 @@
         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
@@ -977,8 +920,8 @@
 
     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));
+        SendOkay(reply_fd);
+        SendProtocolString(reply_fd, transport->connection_state_name());
         return 0;
     }
 #endif // ADB_HOST
diff --git a/adb.h b/adb.h
index b8c6156..fd9d0e6 100644
--- a/adb.h
+++ b/adb.h
@@ -209,6 +209,8 @@
     unsigned char token[TOKEN_SIZE];
     fdevent auth_fde;
     unsigned failed_auth_attempts;
+
+    const char* connection_state_name() const;
 };
 
 
@@ -369,7 +371,6 @@
 #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);
 
 void handle_online(atransport *t);
diff --git a/adb_client.cpp b/adb_client.cpp
index 62f79fa..33eee82 100644
--- a/adb_client.cpp
+++ b/adb_client.cpp
@@ -56,7 +56,7 @@
     buf[4] = 0;
 
     unsigned long len = strtoul(buf, 0, 16);
-    s->resize(len + 1, '\0'); // Ensure NUL-termination.
+    s->resize(len, '\0');
     if (!ReadFdExactly(fd, &(*s)[0], len)) {
         *error = perror_str("protocol fault (couldn't read status message)");
         return false;
@@ -136,9 +136,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;
@@ -199,9 +197,7 @@
         return -1;
     }
 
-    char tmp[5];
-    snprintf(tmp, sizeof(tmp), "%04zx", service.size());
-    if(!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, &service[0], service.size())) {
+    if(!SendProtocolString(fd, service)) {
         *error = perror_str("write failure during connection");
         adb_close(fd);
         return -1;
diff --git a/adb_io.cpp b/adb_io.cpp
index d89f304..c34daf9 100644
--- a/adb_io.cpp
+++ b/adb_io.cpp
@@ -22,14 +22,31 @@
 #include <unistd.h>
 
 #include "adb_trace.h"
-#include "transport.h"
+#include "adb_utils.h"
+
+bool SendProtocolString(int fd, const std::string& s) {
+    int length = s.size();
+    if (length > 0xffff) {
+        length = 0xffff;
+    }
+
+    char buf[5];
+    snprintf(buf, sizeof(buf), "%04x", length);
+    return WriteFdExactly(fd, buf, 4) && 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,14 @@
     return true;
 }
 
+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 WriteStringFully(int fd, const char* str) {
     return WriteFdExactly(fd, str, strlen(str));
 }
diff --git a/adb_io.h b/adb_io.h
index 8d237ce..3b8b050 100644
--- a/adb_io.h
+++ b/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). */
+/* Same as above, but with an implicit len = strlen(buf). */
+bool WriteFdExactly(int fd, const char* s);
+bool WriteFdExactly(int fd, const std::string& s);
+
+// TODO: move minadb off this and remove it.
 bool WriteStringFully(int fd, const char* str);
 
 #endif /* ADB_IO_H */
diff --git a/adb_io_test.cpp b/adb_io_test.cpp
index da340b2..dd09919 100644
--- a/adb_io_test.cpp
+++ b/adb_io_test.cpp
@@ -139,13 +139,13 @@
     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;
diff --git a/adb_listeners.cpp b/adb_listeners.cpp
index a1a5ddb..71a9321 100644
--- a/adb_listeners.cpp
+++ b/adb_listeners.cpp
@@ -19,6 +19,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <base/stringprintf.h>
+
 #include "sysdeps.h"
 #include "transport.h"
 
@@ -143,49 +145,17 @@
     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;
 }
diff --git a/adb_listeners.h b/adb_listeners.h
index f55fdee..1d4f062 100644
--- a/adb_listeners.h
+++ b/adb_listeners.h
@@ -19,6 +19,8 @@
 
 #include "adb.h"
 
+#include <string>
+
 // error/status codes for install_listener.
 enum install_status_t {
   INSTALL_STATUS_OK = 0,
@@ -39,7 +41,7 @@
                                   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);
 void remove_all_listeners(void);
diff --git a/adb_trace.h b/adb_trace.h
index 32b6ae4..63d4151 100644
--- a/adb_trace.h
+++ b/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_utils.cpp b/adb_utils.cpp
index f10c143..0ce5ece 100644
--- a/adb_utils.cpp
+++ b/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) {
@@ -50,3 +57,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_utils.h b/adb_utils.h
index 4b64afa..84f7d0c 100644
--- a/adb_utils.h
+++ b/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/commandline.cpp b/commandline.cpp
index 4941689..7964cd3 100644
--- a/commandline.cpp
+++ b/commandline.cpp
@@ -490,17 +490,8 @@
         printf("\n");
     }
 
-    // TODO: should this be adb_status?
-    char buf[5];
-    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;
     }
 
diff --git a/remount_service.cpp b/remount_service.cpp
index 1eaee73..3fb2fcb 100644
--- a/remount_service.cpp
+++ b/remount_service.cpp
@@ -92,7 +92,7 @@
   if (remount(partition, ro)) {
     char buf[200];
     snprintf(buf, sizeof(buf), "remount of %s failed: %s\n", partition, strerror(errno));
-    WriteStringFully(fd, buf);
+    WriteFdExactly(fd, buf);
     return false;
   }
   return true;
@@ -102,7 +102,7 @@
     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;
     }
@@ -128,12 +128,11 @@
                  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);
+        WriteFdExactly(fd, buffer);
+        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;
@@ -141,7 +140,7 @@
     success &= remount_partition(fd, "/vendor", &vendor_ro);
     success &= remount_partition(fd, "/oem", &oem_ro);
 
-    WriteStringFully(fd, success ? "remount succeeded\n" : "remount failed\n");
+    WriteFdExactly(fd, success ? "remount succeeded\n" : "remount failed\n");
 
     adb_close(fd);
 }
diff --git a/services.cpp b/services.cpp
index e6c84a4..fa5a1a1 100644
--- a/services.cpp
+++ b/services.cpp
@@ -31,10 +31,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
@@ -147,8 +148,7 @@
     // 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;
         }
 
@@ -175,14 +175,14 @@
     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);
+        WriteFdExactly(fd, buf);
         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);
+        WriteFdExactly(fd, buf);
         return false;
     }
 
@@ -208,7 +208,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);
@@ -551,9 +551,9 @@
     std::string error_msg = "unknown error";
     atransport* t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &error_msg);
     if (t != 0) {
-        WriteFdExactly(fd, "OKAY", 4);
+        SendOkay(fd);
     } else {
-        sendfailmsg(fd, error_msg.c_str());
+        SendFail(fd, error_msg);
     }
 
     if (sinfo->serial)
@@ -563,35 +563,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 +595,74 @@
     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);
 
+    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);
     }
 
     // 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
diff --git a/set_verity_enable_state_service.cpp b/set_verity_enable_state_service.cpp
index b75ed4c..d856d57 100644
--- a/set_verity_enable_state_service.cpp
+++ b/set_verity_enable_state_service.cpp
@@ -21,7 +21,6 @@
 #include <fcntl.h>
 #include <inttypes.h>
 #include <stdarg.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <sys/stat.h>
 
diff --git a/sockets.cpp b/sockets.cpp
index f468029..32ca17d 100644
--- a/sockets.cpp
+++ b/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,6 +683,8 @@
     return serial_end;
 }
 
+#endif // ADB_HOST
+
 static int smart_socket_enqueue(asocket *s, apacket *p)
 {
     unsigned len;
@@ -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;
@@ -831,7 +818,7 @@
         s->transport = acquire_one_transport(CS_ANY, kTransportAny, NULL, &error_msg);
 
         if (s->transport == NULL) {
-            sendfailmsg(s->peer->fd, error_msg.c_str());
+            SendFail(s->peer->fd, error_msg);
             goto fail;
         }
     }
@@ -841,7 +828,7 @@
            /* 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/sysdeps_win32.cpp b/sysdeps_win32.cpp
index 633f6f5..a21272f 100644
--- a/sysdeps_win32.cpp
+++ b/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/test_track_devices.cpp b/test_track_devices.cpp
index 77b3ad9..3e823e9 100644
--- a/test_track_devices.cpp
+++ b/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,82 +17,49 @@
     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 );
diff --git a/test_track_jdwp.cpp b/test_track_jdwp.cpp
deleted file mode 100644
index 8ecc6b8..0000000
--- a/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/transport.cpp b/transport.cpp
index 45740a8..b7f30ea 100644
--- a/transport.cpp
+++ b/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
@@ -895,100 +839,71 @@
     return result;
 }
 
-#if ADB_HOST
-static const char *statename(atransport *t)
-{
-    switch(t->connection_state){
+const char* atransport::connection_state_name() const {
+    switch (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_SIDELOAD: return "sideload";
     case CS_UNAUTHORIZED: 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])
+    if (!serial || !serial[0]) {
         serial = "????????????";
+    }
 
     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);
diff --git a/transport.h b/transport.h
index a2077e8..5b6fdac 100644
--- a/transport.h
+++ b/transport.h
@@ -23,10 +23,6 @@
 
 #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.
@@ -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,