Merge "Mark time conversion functions as constexpr"
diff --git a/adb/Android.mk b/adb/Android.mk
index 7d3978b..6951904 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -5,7 +5,11 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-ADB_CLANG :=
+ifeq ($(HOST_OS),windows)
+  adb_host_clang := false  # libc++ for mingw not ready yet.
+else
+  adb_host_clang := true
+endif
 
 # libadb
 # =========================================================
@@ -21,11 +25,17 @@
     adb_auth.cpp \
     adb_io.cpp \
     adb_listeners.cpp \
+    adb_utils.cpp \
     sockets.cpp \
     transport.cpp \
     transport_local.cpp \
     transport_usb.cpp \
 
+LIBADB_TEST_SRCS := \
+    adb_io_test.cpp \
+    adb_utils_test.cpp \
+    transport_test.cpp \
+
 LIBADB_CFLAGS := \
     -Wall -Werror \
     -Wno-unused-parameter \
@@ -59,10 +69,12 @@
     qemu_tracing.cpp \
     usb_linux_client.cpp \
 
+LOCAL_SHARED_LIBRARIES := libbase
+
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := $(adb_host_clang)
 LOCAL_MODULE := libadb
 LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=1
 LOCAL_SRC_FILES := \
@@ -70,6 +82,8 @@
     $(LIBADB_$(HOST_OS)_SRC_FILES) \
     adb_auth_host.cpp \
 
+LOCAL_SHARED_LIBRARIES := libbase
+
 # Even though we're building a static library (and thus there's no link step for
 # this to take effect), this adds the SSL includes to our path.
 LOCAL_STATIC_LIBRARIES := libcrypto_static
@@ -80,12 +94,8 @@
 
 include $(BUILD_HOST_STATIC_LIBRARY)
 
-LIBADB_TEST_SRCS := \
-    adb_io_test.cpp \
-    transport_test.cpp \
-
 include $(CLEAR_VARS)
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := true
 LOCAL_MODULE := adbd_test
 LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS)
 LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS)
@@ -94,7 +104,7 @@
 include $(BUILD_NATIVE_TEST)
 
 include $(CLEAR_VARS)
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := $(adb_host_clang)
 LOCAL_MODULE := adb_test
 LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
 LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS) services.cpp
@@ -129,15 +139,11 @@
 endif
 
 ifeq ($(HOST_OS),windows)
+  LOCAL_LDLIBS += -lws2_32 -lgdi32
   EXTRA_STATIC_LIBS := AdbWinApi
-  ifneq ($(strip $(USE_MINGW)),)
-    # MinGW under Linux case
-    LOCAL_LDLIBS += -lws2_32 -lgdi32
-    USE_SYSDEPS_WIN32 := 1
-  endif
 endif
 
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := $(adb_host_clang)
 
 LOCAL_SRC_FILES := \
     adb_main.cpp \
@@ -158,13 +164,21 @@
 
 LOCAL_STATIC_LIBRARIES := \
     libadb \
+    libbase \
     libcrypto_static \
+    libcutils \
     $(EXTRA_STATIC_LIBS) \
 
-ifeq ($(USE_SYSDEPS_WIN32),)
-    LOCAL_STATIC_LIBRARIES += libcutils
+# libc++ not available on windows yet
+ifneq ($(HOST_OS),windows)
+    LOCAL_CXX_STL := libc++_static
 endif
 
+# Don't add anything here, we don't want additional shared dependencies
+# on the host adb tool, and shared libraries that link against libc++
+# will violate ODR
+LOCAL_SHARED_LIBRARIES :=
+
 include $(BUILD_HOST_EXECUTABLE)
 
 $(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE))
@@ -181,7 +195,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := true
 
 LOCAL_SRC_FILES := \
     adb_main.cpp \
diff --git a/adb/adb.cpp b/adb/adb.cpp
index ad85184f..de82cd4 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -32,6 +32,8 @@
 
 #include <string>
 
+#include <base/stringprintf.h>
+
 #include "adb_auth.h"
 #include "adb_io.h"
 #include "adb_listeners.h"
@@ -802,7 +804,6 @@
     if (!strncmp(service, "forward:",8) ||
         !strncmp(service, "killforward:",12)) {
         char *local, *remote;
-        int r;
         atransport *transport;
 
         int createForward = strncmp(service, "kill", 4);
@@ -838,19 +839,20 @@
             }
         }
 
-        const char* err;
-        transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
+        std::string error_msg;
+        transport = acquire_one_transport(CS_ANY, ttype, serial, &error_msg);
         if (!transport) {
-            sendfailmsg(reply_fd, err);
+            sendfailmsg(reply_fd, error_msg.c_str());
             return 1;
         }
 
+        install_status_t r;
         if (createForward) {
             r = install_listener(local, remote, transport, no_rebind);
         } else {
             r = remove_listener(local, transport);
         }
-        if(r == 0) {
+        if (r == INSTALL_STATUS_OK) {
 #if ADB_HOST
             /* On the host: 1st OKAY is connect, 2nd OKAY is status */
             WriteFdExactly(reply_fd, "OKAY", 4);
@@ -859,22 +861,19 @@
             return 1;
         }
 
-        if (createForward) {
-            const char* message;
-            switch (r) {
-              case INSTALL_STATUS_CANNOT_BIND:
-                message = "cannot bind to socket";
-                break;
-              case INSTALL_STATUS_CANNOT_REBIND:
-                message = "cannot rebind existing socket";
-                break;
-              default:
-                message = "internal error";
-            }
-            sendfailmsg(reply_fd, message);
-        } else {
-            sendfailmsg(reply_fd, "cannot remove listener");
+        std::string message;
+        switch (r) {
+          case INSTALL_STATUS_OK: message = " "; break;
+          case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break;
+          case INSTALL_STATUS_CANNOT_BIND:
+            message = android::base::StringPrintf("cannot bind to socket: %s", strerror(errno));
+            break;
+          case INSTALL_STATUS_CANNOT_REBIND:
+            message = android::base::StringPrintf("cannot rebind existing socket: %s", strerror(errno));
+            break;
+          case INSTALL_STATUS_LISTENER_NOT_FOUND: message = "listener not found"; break;
         }
+        sendfailmsg(reply_fd, message.c_str());
         return 1;
     }
     return 0;
@@ -910,14 +909,14 @@
             serial = service;
         }
 
-        const char* error_string = "unknown failure";
-        transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
+        std::string error_msg = "unknown failure";
+        transport = acquire_one_transport(CS_ANY, type, serial, &error_msg);
 
         if (transport) {
             s->transport = transport;
             adb_write(reply_fd, "OKAY", 4);
         } else {
-            sendfailmsg(reply_fd, error_string);
+            sendfailmsg(reply_fd, error_msg.c_str());
         }
         return 1;
     }
@@ -975,7 +974,7 @@
     if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
         const char *out = "unknown";
         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
-       if (transport && transport->serial) {
+        if (transport && transport->serial) {
             out = transport->serial;
         }
         send_msg_with_okay(reply_fd, out, strlen(out));
@@ -984,7 +983,7 @@
     if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
         const char *out = "unknown";
         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
-       if (transport && transport->devpath) {
+        if (transport && transport->devpath) {
             out = transport->devpath;
         }
         send_msg_with_okay(reply_fd, out, strlen(out));
diff --git a/adb/adb.h b/adb/adb.h
index 749515c..cb2cf60 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -23,10 +23,6 @@
 #include "adb_trace.h"
 #include "fdevent.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #define MAX_PAYLOAD 4096
 
 #define A_SYNC 0x434e5953
@@ -47,14 +43,8 @@
 // Increment this when we want to force users to start a new adb server.
 #define ADB_SERVER_VERSION 32
 
-typedef struct amessage amessage;
-typedef struct apacket apacket;
-typedef struct asocket asocket;
-typedef struct alistener alistener;
-typedef struct aservice aservice;
-typedef struct atransport atransport;
-typedef struct adisconnect  adisconnect;
-typedef struct usb_handle usb_handle;
+struct atransport;
+struct usb_handle;
 
 struct amessage {
     unsigned command;       /* command identifier constant      */
@@ -171,12 +161,12 @@
 ** object, it's a special value used to indicate that a client wants to
 ** connect to a service implemented within the ADB server itself.
 */
-typedef enum transport_type {
+enum transport_type {
         kTransportUsb,
         kTransportLocal,
         kTransportAny,
         kTransportHost,
-} transport_type;
+};
 
 #define TOKEN_SIZE 20
 
@@ -363,10 +353,10 @@
 extern int HOST;
 extern int SHELL_EXIT_NOTIFY_FD;
 
-typedef enum {
+enum subproc_mode {
     SUBPROC_PTY = 0,
     SUBPROC_RAW = 1,
-} subproc_mode;
+} ;
 
 #define CHUNK_SIZE (64*1024)
 
@@ -389,8 +379,4 @@
 
 void send_connect(atransport *t);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index 635556e..1e1978d 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -19,10 +19,6 @@
 
 #include "adb.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern int auth_enabled;
 
 int adb_auth_keygen(const char* filename);
@@ -68,8 +64,4 @@
 
 #endif // ADB_HOST
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif // __ADB_AUTH_H
diff --git a/adb/adb_client.h b/adb/adb_client.h
index 9af176f..934362a 100644
--- a/adb/adb_client.h
+++ b/adb/adb_client.h
@@ -3,10 +3,6 @@
 
 #include "adb.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* connect to adb, connect to the named service, and return
 ** a valid fd for interacting with that service upon success
 ** or a negative number on failure
@@ -58,8 +54,4 @@
 */
 int adb_status(int fd);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/adb/adb_io.h b/adb/adb_io.h
index 7d09e7b..8d237ce 100644
--- a/adb/adb_io.h
+++ b/adb/adb_io.h
@@ -20,10 +20,6 @@
 #include <stdbool.h>
 #include <sys/types.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
  * Reads exactly len bytes from fd into buf.
  *
@@ -46,8 +42,4 @@
 /* Same as WriteFdExactly, but with an implicit len = strlen(buf). */
 bool WriteStringFully(int fd, const char* str);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* ADB_IO_H */
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index 84b9c64..a1a5ddb 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -190,17 +190,17 @@
     return result;
 }
 
-int remove_listener(const char *local_name, atransport* transport)
+install_status_t remove_listener(const char *local_name, atransport* transport)
 {
     alistener *l;
 
     for (l = listener_list.next; l != &listener_list; l = l->next) {
         if (!strcmp(local_name, l->local_name)) {
             listener_disconnect(l, l->transport);
-            return 0;
+            return INSTALL_STATUS_OK;
         }
     }
-    return -1;
+    return INSTALL_STATUS_LISTENER_NOT_FOUND;
 }
 
 void remove_all_listeners(void)
@@ -268,10 +268,10 @@
 
     listener->fd = local_name_to_fd(local_name);
     if (listener->fd < 0) {
+        printf("cannot bind '%s': %s\n", local_name, strerror(errno));
         free(listener->local_name);
         free(listener->connect_to);
         free(listener);
-        printf("cannot bind '%s'\n", local_name);
         return INSTALL_STATUS_CANNOT_BIND;
     }
 
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index 14fdcd6..f55fdee 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -19,17 +19,14 @@
 
 #include "adb.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 // error/status codes for install_listener.
-typedef enum {
+enum install_status_t {
   INSTALL_STATUS_OK = 0,
   INSTALL_STATUS_INTERNAL_ERROR = -1,
   INSTALL_STATUS_CANNOT_BIND = -2,
   INSTALL_STATUS_CANNOT_REBIND = -3,
-} install_status_t;
+  INSTALL_STATUS_LISTENER_NOT_FOUND = -4,
+};
 
 extern alistener listener_list;
 
@@ -44,11 +41,7 @@
 
 int format_listeners(char* buf, size_t buflen);
 
-int remove_listener(const char *local_name, atransport* transport);
+install_status_t remove_listener(const char* local_name, atransport* transport);
 void remove_all_listeners(void);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* __ADB_LISTENERS_H */
diff --git a/adb/adb_main.cpp b/adb/adb_main.cpp
index fb17e89..5acaf80 100644
--- a/adb/adb_main.cpp
+++ b/adb/adb_main.cpp
@@ -383,7 +383,7 @@
     /* If adbd runs inside the emulator this will enable adb tracing via
      * adb-debug qemud service in the emulator. */
     adb_qemu_trace_init();
-    while (1) {
+    while (true) {
         int c;
         int option_index = 0;
         static struct option opts[] = {
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index ef5dc24..32b6ae4 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -23,10 +23,6 @@
 #include <stdio.h>
 #endif
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
 #define  ADB_TRACE    1
 
@@ -34,7 +30,7 @@
  * forget to update the corresponding 'tags' table in
  * the adb_trace_init() function implemented in adb.c
  */
-typedef enum {
+enum AdbTrace {
     TRACE_ADB = 0,   /* 0x001 */
     TRACE_SOCKETS,
     TRACE_PACKETS,
@@ -47,7 +43,7 @@
     TRACE_SERVICES,
     TRACE_AUTH,
     TRACE_FDEVENT,
-} AdbTrace;
+} ;
 
 #if ADB_TRACE
 
@@ -148,8 +144,4 @@
 #  define  ADB_TRACING     0
 #endif /* ADB_TRACE */
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* __ADB_TRACE_H */
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
new file mode 100644
index 0000000..f10c143
--- /dev/null
+++ b/adb/adb_utils.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "adb_utils.h"
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "sysdeps.h"
+
+bool getcwd(std::string* s) {
+  char* cwd = getcwd(nullptr, 0);
+  if (cwd != nullptr) *s = cwd;
+  free(cwd);
+  return (cwd != nullptr);
+}
+
+bool directory_exists(const std::string& path) {
+  struct stat sb;
+  return lstat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode);
+}
+
+std::string escape_arg(const std::string& s) {
+  std::string result = s;
+
+  // Insert a \ before any ' in the string.
+  for (auto it = result.begin(); it != result.end(); ++it) {
+      if (*it == '\'') {
+          it = result.insert(it, '\\') + 1;
+      }
+  }
+
+  // Prefix and suffix the whole string with '.
+  result.insert(result.begin(), '\'');
+  result.push_back('\'');
+  return result;
+}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
new file mode 100644
index 0000000..4b64afa
--- /dev/null
+++ b/adb/adb_utils.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ADB_UTILS_H_
+#define _ADB_UTILS_H_
+
+#include <string>
+
+bool getcwd(std::string* cwd);
+bool directory_exists(const std::string& path);
+
+std::string escape_arg(const std::string& s);
+
+#endif
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
new file mode 100644
index 0000000..a395079
--- /dev/null
+++ b/adb/adb_utils_test.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "adb_utils.h"
+
+#include <gtest/gtest.h>
+
+TEST(adb_utils, directory_exists) {
+  ASSERT_TRUE(directory_exists("/proc"));
+  ASSERT_FALSE(directory_exists("/proc/self")); // Symbolic link.
+  ASSERT_FALSE(directory_exists("/proc/does-not-exist"));
+}
+
+TEST(adb_utils, escape_arg) {
+  ASSERT_EQ(R"('')", escape_arg(""));
+
+  ASSERT_EQ(R"('abc')", escape_arg("abc"));
+
+  ASSERT_EQ(R"(' abc')", escape_arg(" abc"));
+  ASSERT_EQ(R"('\'abc')", escape_arg("'abc"));
+  ASSERT_EQ(R"('"abc')", escape_arg("\"abc"));
+  ASSERT_EQ(R"('\abc')", escape_arg("\\abc"));
+  ASSERT_EQ(R"('(abc')", escape_arg("(abc"));
+  ASSERT_EQ(R"(')abc')", escape_arg(")abc"));
+
+  ASSERT_EQ(R"('abc abc')", escape_arg("abc abc"));
+  ASSERT_EQ(R"('abc\'abc')", escape_arg("abc'abc"));
+  ASSERT_EQ(R"('abc"abc')", escape_arg("abc\"abc"));
+  ASSERT_EQ(R"('abc\abc')", escape_arg("abc\\abc"));
+  ASSERT_EQ(R"('abc(abc')", escape_arg("abc(abc"));
+  ASSERT_EQ(R"('abc)abc')", escape_arg("abc)abc"));
+
+  ASSERT_EQ(R"('abc ')", escape_arg("abc "));
+  ASSERT_EQ(R"('abc\'')", escape_arg("abc'"));
+  ASSERT_EQ(R"('abc"')", escape_arg("abc\""));
+  ASSERT_EQ(R"('abc\')", escape_arg("abc\\"));
+  ASSERT_EQ(R"('abc(')", escape_arg("abc("));
+  ASSERT_EQ(R"('abc)')", escape_arg("abc)"));
+}
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 19a2fee..58e1ade 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -21,6 +21,7 @@
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <limits.h>
 #include <stdarg.h>
 #include <stdint.h>
@@ -30,6 +31,10 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <string>
+
+#include <base/stringprintf.h>
+
 #if !defined(_WIN32)
 #include <termios.h>
 #include <unistd.h>
@@ -39,49 +44,38 @@
 #include "adb_auth.h"
 #include "adb_client.h"
 #include "adb_io.h"
+#include "adb_utils.h"
 #include "file_sync_service.h"
 
 static int do_cmd(transport_type ttype, const char* serial, const char *cmd, ...);
 
-int find_sync_dirs(const char *srcarg,
-        char **system_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out,
-        char **oem_srcdir_out);
-int install_app(transport_type transport, const char* serial, int argc,
-                const char** argv);
-int install_multiple_app(transport_type transport, const char* serial, int argc,
+static int install_app(transport_type transport, const char* serial, int argc,
+                       const char** argv);
+static int install_multiple_app(transport_type transport, const char* serial, int argc,
+                                const char** argv);
+static int uninstall_app(transport_type transport, const char* serial, int argc,
                          const char** argv);
-int uninstall_app(transport_type transport, const char* serial, int argc,
-                  const char** argv);
 
-static const char *gProductOutPath = NULL;
+static std::string gProductOutPath;
 extern int gListenAll;
 
-static char *product_file(const char *extra)
-{
-    if (gProductOutPath == NULL) {
+static std::string product_file(const char *extra) {
+    if (gProductOutPath.empty()) {
         fprintf(stderr, "adb: Product directory not specified; "
                 "use -p or define ANDROID_PRODUCT_OUT\n");
         exit(1);
     }
 
-    int n = strlen(gProductOutPath) + strlen(extra) + 2;
-    char* x = reinterpret_cast<char*>(malloc(n));
-    if (x == 0) {
-        fprintf(stderr, "adb: Out of memory (product_file())\n");
-        exit(1);
-    }
-
-    snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
-    return x;
+    return android::base::StringPrintf("%s%s%s",
+                                       gProductOutPath.c_str(), OS_PATH_SEPARATOR_STR, extra);
 }
 
-void version(FILE * out) {
+static void version(FILE* out) {
     fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
-         ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
+            ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
 }
 
-void help()
-{
+static void help() {
     version(stderr);
 
     fprintf(stderr,
@@ -241,8 +235,7 @@
         );
 }
 
-int usage()
-{
+static int usage() {
     help();
     return 1;
 }
@@ -328,7 +321,7 @@
         stdin_raw_init(STDIN_FILENO);
     }
 
-    for (;;) {
+    while (true) {
         if (inFd == STDIN_FILENO) {
             len = unix_read(inFd, buf, BUFSIZE);
         } else {
@@ -414,8 +407,7 @@
     return 0;
 }
 
-int interactive_shell(void)
-{
+static int interactive_shell() {
     adb_thread_t thr;
     int fdi, fd;
 
@@ -453,8 +445,8 @@
     }
 }
 
-int adb_download_buffer(const char *service, const char *fn, const void* data, int sz,
-                        unsigned progress)
+static int adb_download_buffer(const char *service, const char *fn, const void* data, int sz,
+                               unsigned progress)
 {
     char buf[4096];
     unsigned total;
@@ -512,23 +504,6 @@
     return 0;
 }
 
-
-int adb_download(const char *service, const char *fn, unsigned progress)
-{
-    void *data;
-    unsigned sz;
-
-    data = load_file(fn, &sz);
-    if(data == 0) {
-        fprintf(stderr,"* cannot read '%s' *\n", fn);
-        return -1;
-    }
-
-    int status = adb_download_buffer(service, fn, data, sz, progress);
-    free(data);
-    return status;
-}
-
 #define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE)
 
 /*
@@ -550,7 +525,7 @@
  * - When the other side sends "DONEDONE" instead of a block number,
  *   we hang up.
  */
-int adb_sideload_host(const char* fn) {
+static int adb_sideload_host(const char* fn) {
     unsigned sz;
     size_t xfer = 0;
     int status;
@@ -579,7 +554,7 @@
 
     opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
 
-    for (;;) {
+    while (true) {
         if (!ReadFdExactly(fd, buf, 8)) {
             fprintf(stderr, "* failed to read command: %s\n", adb_error());
             status = -1;
@@ -681,50 +656,6 @@
     }
 }
 
-static int should_escape(const char c)
-{
-    return (c == ' ' || c == '\'' || c == '"' || c == '\\' || c == '(' || c == ')');
-}
-
-/* Duplicate and escape given argument. */
-static char *escape_arg(const char *s)
-{
-    const char *ts;
-    size_t alloc_len;
-    char *ret;
-    char *dest;
-
-    alloc_len = 0;
-    for (ts = s; *ts != '\0'; ts++) {
-        alloc_len++;
-        if (should_escape(*ts)) {
-            alloc_len++;
-        }
-    }
-
-    if (alloc_len == 0) {
-        // Preserve empty arguments
-        ret = (char *) malloc(3);
-        ret[0] = '\"';
-        ret[1] = '\"';
-        ret[2] = '\0';
-        return ret;
-    }
-
-    ret = (char *) malloc(alloc_len + 1);
-    dest = ret;
-
-    for (ts = s; *ts != '\0'; ts++) {
-        if (should_escape(*ts)) {
-            *dest++ = '\\';
-        }
-        *dest++ = *ts;
-    }
-    *dest++ = '\0';
-
-    return ret;
-}
-
 /**
  * Run ppp in "notty" mode against a resource listed as the first parameter
  * eg:
@@ -732,8 +663,7 @@
  * ppp dev:/dev/omap_csmi_tty0 <ppp options>
  *
  */
-int ppp(int argc, const char **argv)
-{
+static int ppp(int argc, const char** argv) {
 #if defined(_WIN32)
     fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
     return -1;
@@ -798,14 +728,12 @@
 #endif /* !defined(_WIN32) */
 }
 
-static int send_shellcommand(transport_type transport, const char* serial,
-                             char* buf)
-{
-    int fd, ret;
-
-    for(;;) {
-        fd = adb_connect(buf);
-        if(fd >= 0)
+static int send_shell_command(transport_type transport, const char* serial,
+                              const std::string& command) {
+    int fd;
+    while (true) {
+        fd = adb_connect(command.c_str());
+        if (fd >= 0)
             break;
         fprintf(stderr,"- waiting for device -\n");
         adb_sleep_ms(1000);
@@ -813,41 +741,30 @@
     }
 
     read_and_dump(fd);
-    ret = adb_close(fd);
-    if (ret)
+    int rc = adb_close(fd);
+    if (rc) {
         perror("close");
-
-    return ret;
+    }
+    return rc;
 }
 
-static int logcat(transport_type transport, const char* serial, int argc,
-                  const char** argv)
-{
-    char buf[4096];
+static int logcat(transport_type transport, const char* serial, int argc, const char** argv) {
+    char* log_tags = getenv("ANDROID_LOG_TAGS");
+    std::string quoted = escape_arg(log_tags == nullptr ? "" : log_tags);
 
-    char *log_tags;
-    char *quoted;
-
-    log_tags = getenv("ANDROID_LOG_TAGS");
-    quoted = escape_arg(log_tags == NULL ? "" : log_tags);
-    snprintf(buf, sizeof(buf),
-            "shell:export ANDROID_LOG_TAGS=\"%s\"; exec logcat", quoted);
-    free(quoted);
+    std::string cmd = "shell:export ANDROID_LOG_TAGS=\"" + quoted + "\"; exec logcat";
 
     if (!strcmp(argv[0], "longcat")) {
-        strncat(buf, " -v long", sizeof(buf) - 1);
+        cmd += " -v long";
     }
 
-    argc -= 1;
-    argv += 1;
-    while(argc-- > 0) {
-        quoted = escape_arg(*argv++);
-        strncat(buf, " ", sizeof(buf) - 1);
-        strncat(buf, quoted, sizeof(buf) - 1);
-        free(quoted);
+    --argc;
+    ++argv;
+    while (argc-- > 0) {
+        cmd += " " + escape_arg(*argv++);
     }
 
-    send_shellcommand(transport, serial, buf);
+    send_shell_command(transport, serial, cmd);
     return 0;
 }
 
@@ -871,21 +788,17 @@
 }
 
 static int backup(int argc, const char** argv) {
-    char buf[4096];
-    char default_name[32];
-    const char* filename = strcpy(default_name, "./backup.ab");
-    int fd, outFd;
-    int i, j;
+    const char* filename = "./backup.ab";
 
     /* find, extract, and use any -f argument */
-    for (i = 1; i < argc; i++) {
+    for (int i = 1; i < argc; i++) {
         if (!strcmp("-f", argv[i])) {
             if (i == argc-1) {
                 fprintf(stderr, "adb: -f passed with no filename\n");
                 return usage();
             }
             filename = argv[i+1];
-            for (j = i+2; j <= argc; ) {
+            for (int j = i+2; j <= argc; ) {
                 argv[i++] = argv[j++];
             }
             argc -= 2;
@@ -898,20 +811,21 @@
 
     adb_unlink(filename);
     mkdirs(filename);
-    outFd = adb_creat(filename, 0640);
+    int outFd = adb_creat(filename, 0640);
     if (outFd < 0) {
         fprintf(stderr, "adb: unable to open file %s\n", filename);
         return -1;
     }
 
-    snprintf(buf, sizeof(buf), "backup");
-    for (argc--, argv++; argc; argc--, argv++) {
-        strncat(buf, ":", sizeof(buf) - strlen(buf) - 1);
-        strncat(buf, argv[0], sizeof(buf) - strlen(buf) - 1);
+    std::string cmd = "backup:";
+    --argc;
+    ++argv;
+    while (argc-- > 0) {
+        cmd += " " + escape_arg(*argv++);
     }
 
-    D("backup. filename=%s buf=%s\n", filename, buf);
-    fd = adb_connect(buf);
+    D("backup. filename=%s cmd=%s\n", filename, cmd.c_str());
+    int fd = adb_connect(cmd.c_str());
     if (fd < 0) {
         fprintf(stderr, "adb: unable to connect for backup\n");
         adb_close(outFd);
@@ -954,81 +868,9 @@
     return 0;
 }
 
-#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
-static int top_works(const char *top)
-{
-    if (top != NULL && adb_is_absolute_host_path(top)) {
-        char path_buf[PATH_MAX];
-        snprintf(path_buf, sizeof(path_buf),
-                "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
-        return access(path_buf, F_OK) == 0;
-    }
-    return 0;
-}
-
-static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
-{
-    strcpy(path_buf, indir);
-    while (1) {
-        if (top_works(path_buf)) {
-            return path_buf;
-        }
-        char *s = adb_dirstop(path_buf);
-        if (s != NULL) {
-            *s = '\0';
-        } else {
-            path_buf[0] = '\0';
-            return NULL;
-        }
-    }
-}
-
-static char *find_top(char path_buf[PATH_MAX])
-{
-    char *top = getenv("ANDROID_BUILD_TOP");
-    if (top != NULL && top[0] != '\0') {
-        if (!top_works(top)) {
-            fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
-            return NULL;
-        }
-    } else {
-        top = getenv("TOP");
-        if (top != NULL && top[0] != '\0') {
-            if (!top_works(top)) {
-                fprintf(stderr, "adb: bad TOP value \"%s\"\n", top);
-                return NULL;
-            }
-        } else {
-            top = NULL;
-        }
-    }
-
-    if (top != NULL) {
-        /* The environment pointed to a top directory that works.
-         */
-        strcpy(path_buf, top);
-        return path_buf;
-    }
-
-    /* The environment didn't help.  Walk up the tree from the CWD
-     * to see if we can find the top.
-     */
-    char dir[PATH_MAX];
-    top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
-    if (top == NULL) {
-        /* If the CWD isn't under a good-looking top, see if the
-         * executable is.
-         */
-        get_my_path(dir, PATH_MAX);
-        top = find_top_from(dir, path_buf);
-    }
-    return top;
-}
-
 /* <hint> may be:
  * - A simple product name
  *   e.g., "sooner"
-TODO: debug?  sooner-debug, sooner:debug?
  * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
  *   e.g., "out/target/product/sooner"
  * - An absolute path to the PRODUCT_OUT dir
@@ -1037,62 +879,52 @@
  * Given <hint>, try to construct an absolute path to the
  * ANDROID_PRODUCT_OUT dir.
  */
-static const char *find_product_out_path(const char *hint)
-{
-    static char path_buf[PATH_MAX];
-
+static std::string find_product_out_path(const char* hint) {
     if (hint == NULL || hint[0] == '\0') {
-        return NULL;
+        return "";
     }
 
-    /* If it's already absolute, don't bother doing any work.
-     */
+    // If it's already absolute, don't bother doing any work.
     if (adb_is_absolute_host_path(hint)) {
-        strcpy(path_buf, hint);
-        return path_buf;
+        return hint;
     }
 
-    /* If there are any slashes in it, assume it's a relative path;
-     * make it absolute.
-     */
-    if (adb_dirstart(hint) != NULL) {
-        if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
-            fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
-            return NULL;
+    // If there are any slashes in it, assume it's a relative path;
+    // make it absolute.
+    if (adb_dirstart(hint) != nullptr) {
+        std::string cwd;
+        if (!getcwd(&cwd)) {
+            fprintf(stderr, "adb: getcwd failed: %s\n", strerror(errno));
+            return "";
         }
-        if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
-            fprintf(stderr, "adb: Couldn't assemble path\n");
-            return NULL;
-        }
-        strcat(path_buf, OS_PATH_SEPARATOR_STR);
-        strcat(path_buf, hint);
-        return path_buf;
+        return android::base::StringPrintf("%s%s%s", cwd.c_str(), OS_PATH_SEPARATOR_STR, hint);
     }
 
-    /* It's a string without any slashes.  Try to do something with it.
-     *
-     * Try to find the root of the build tree, and build a PRODUCT_OUT
-     * path from there.
-     */
-    char top_buf[PATH_MAX];
-    const char *top = find_top(top_buf);
-    if (top == NULL) {
-        fprintf(stderr, "adb: Couldn't find top of build tree\n");
-        return NULL;
+    // It's a string without any slashes.  Try to do something with it.
+    //
+    // Try to find the root of the build tree, and build a PRODUCT_OUT
+    // path from there.
+    char* top = getenv("ANDROID_BUILD_TOP");
+    if (top == nullptr) {
+        fprintf(stderr, "adb: ANDROID_BUILD_TOP not set!\n");
+        return "";
     }
-//TODO: if we have a way to indicate debug, look in out/debug/target/...
-    snprintf(path_buf, sizeof(path_buf),
-            "%s" OS_PATH_SEPARATOR_STR
-            "out" OS_PATH_SEPARATOR_STR
-            "target" OS_PATH_SEPARATOR_STR
-            "product" OS_PATH_SEPARATOR_STR
-            "%s", top_buf, hint);
-    if (access(path_buf, F_OK) < 0) {
-        fprintf(stderr, "adb: Couldn't find a product dir "
-                "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
-        return NULL;
+
+    std::string path = top;
+    path += OS_PATH_SEPARATOR_STR;
+    path += "out";
+    path += OS_PATH_SEPARATOR_STR;
+    path += "target";
+    path += OS_PATH_SEPARATOR_STR;
+    path += "product";
+    path += OS_PATH_SEPARATOR_STR;
+    path += hint;
+    if (!directory_exists(path)) {
+        fprintf(stderr, "adb: Couldn't find a product dir based on -p %s; "
+                        "\"%s\" doesn't exist\n", hint, path.c_str());
+        return "";
     }
-    return path_buf;
+    return path;
 }
 
 static void parse_push_pull_args(const char **arg, int narg, char const **path1,
@@ -1147,15 +979,14 @@
     const char* serial = NULL;
     const char* server_port_str = NULL;
 
-        /* If defined, this should be an absolute path to
-         * the directory containing all of the various system images
-         * for a particular product.  If not defined, and the adb
-         * command requires this information, then the user must
-         * specify the path using "-p".
-         */
-    gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
-    if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
-        gProductOutPath = NULL;
+    // If defined, this should be an absolute path to
+    // the directory containing all of the various system images
+    // for a particular product.  If not defined, and the adb
+    // command requires this information, then the user must
+    // specify the path using "-p".
+    char* ANDROID_PRODUCT_OUT = getenv("ANDROID_PRODUCT_OUT");
+    if (ANDROID_PRODUCT_OUT != nullptr) {
+        gProductOutPath = ANDROID_PRODUCT_OUT;
     }
     // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
 
@@ -1196,9 +1027,8 @@
                 product = argv[0] + 2;
             }
             gProductOutPath = find_product_out_path(product);
-            if (gProductOutPath == NULL) {
-                fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
-                        product);
+            if (gProductOutPath.empty()) {
+                fprintf(stderr, "adb: could not resolve \"-p %s\"\n", product);
                 return usage();
             }
         } else if (argv[0][0]=='-' && argv[0][1]=='s') {
@@ -1370,9 +1200,6 @@
         return adb_send_emulator_command(argc, argv);
     }
     else if (!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
-        int r;
-        int fd;
-
         char h = (argv[0][0] == 'h');
 
         if (h) {
@@ -1390,19 +1217,18 @@
             return r;
         }
 
-        snprintf(buf, sizeof(buf), "shell:%s", argv[1]);
+        std::string cmd = "shell:";
+        cmd += argv[1];
         argc -= 2;
         argv += 2;
         while (argc-- > 0) {
-            char *quoted = escape_arg(*argv++);
-            strncat(buf, " ", sizeof(buf) - 1);
-            strncat(buf, quoted, sizeof(buf) - 1);
-            free(quoted);
+            cmd += " " + escape_arg(*argv++);
         }
 
-        for(;;) {
-            D("interactive shell loop. buff=%s\n", buf);
-            fd = adb_connect(buf);
+        while (true) {
+            D("interactive shell loop. cmd=%s\n", cmd.c_str());
+            int fd = adb_connect(cmd.c_str());
+            int r;
             if (fd >= 0) {
                 D("about to read_and_dump(fd=%d)\n", fd);
                 read_and_dump(fd);
@@ -1430,19 +1256,16 @@
     }
     else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
         int exec_in = !strcmp(argv[0], "exec-in");
-        int fd;
 
-        snprintf(buf, sizeof buf, "exec:%s", argv[1]);
+        std::string cmd = "exec:";
+        cmd += argv[1];
         argc -= 2;
         argv += 2;
         while (argc-- > 0) {
-            char *quoted = escape_arg(*argv++);
-            strncat(buf, " ", sizeof(buf) - 1);
-            strncat(buf, quoted, sizeof(buf) - 1);
-            free(quoted);
+            cmd += " " + escape_arg(*argv++);
         }
 
-        fd = adb_connect(buf);
+        int fd = adb_connect(cmd.c_str());
         if (fd < 0) {
             fprintf(stderr, "error: %s\n", adb_error());
             return -1;
@@ -1634,46 +1457,49 @@
         return uninstall_app(ttype, serial, argc, argv);
     }
     else if (!strcmp(argv[0], "sync")) {
-        const char* srcarg;
-        char *system_srcpath, *data_srcpath, *vendor_srcpath, *oem_srcpath;
-
-        int listonly = 0;
-
-        int ret;
+        std::string src;
+        bool list_only = false;
         if (argc < 2) {
-            /* No local path was specified. */
-            srcarg = NULL;
+            // No local path was specified.
+            src = "";
         } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
-            listonly = 1;
+            list_only = true;
             if (argc == 3) {
-                srcarg = argv[2];
+                src = argv[2];
             } else {
-                srcarg = NULL;
+                src = "";
             }
         } else if (argc == 2) {
-            /* A local path or "android"/"data" arg was specified. */
-            srcarg = argv[1];
+            // A local path or "android"/"data" arg was specified.
+            src = argv[1];
         } else {
             return usage();
         }
-        ret = find_sync_dirs(srcarg, &system_srcpath, &data_srcpath, &vendor_srcpath,
-                &oem_srcpath);
-        if (ret != 0) return usage();
 
-        if (system_srcpath != NULL)
-            ret = do_sync_sync(system_srcpath, "/system", listonly);
-        if (ret == 0 && vendor_srcpath != NULL)
-            ret = do_sync_sync(vendor_srcpath, "/vendor", listonly);
-        if(ret == 0 && oem_srcpath != NULL)
-            ret = do_sync_sync(oem_srcpath, "/oem", listonly);
-        if (ret == 0 && data_srcpath != NULL)
-            ret = do_sync_sync(data_srcpath, "/data", listonly);
+        if (src != "" &&
+            src != "system" && src != "data" && src != "vendor" && src != "oem") {
+            return usage();
+        }
 
-        free(system_srcpath);
-        free(vendor_srcpath);
-        free(oem_srcpath);
-        free(data_srcpath);
-        return ret;
+        std::string system_src_path = product_file("system");
+        std::string data_src_path = product_file("data");
+        std::string vendor_src_path = product_file("vendor");
+        std::string oem_src_path = product_file("oem");
+
+        int rc = 0;
+        if (rc == 0 && (src.empty() || src == "system")) {
+            rc = do_sync_sync(system_src_path, "/system", list_only);
+        }
+        if (rc == 0 && (src.empty() || src == "vendor") && directory_exists(vendor_src_path)) {
+            rc = do_sync_sync(vendor_src_path, "/vendor", list_only);
+        }
+        if (rc == 0 && (src.empty() || src == "oem") && directory_exists(oem_src_path)) {
+            rc = do_sync_sync(oem_src_path, "/oem", list_only);
+        }
+        if (rc == 0 && (src.empty() || src == "data")) {
+            rc = do_sync_sync(data_src_path, "/data", list_only);
+        }
+        return rc;
     }
     /* passthrough commands */
     else if (!strcmp(argv[0],"get-state") ||
@@ -1768,84 +1594,21 @@
     return adb_commandline(argc, argv);
 }
 
-int find_sync_dirs(const char *srcarg,
-        char **system_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out,
-        char **oem_srcdir_out)
-{
-    char *system_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL, *oem_srcdir = NULL;
-    struct stat st;
-
-    if(srcarg == NULL) {
-        system_srcdir = product_file("system");
-        data_srcdir = product_file("data");
-        vendor_srcdir = product_file("vendor");
-        oem_srcdir = product_file("oem");
-        // Check if vendor partition exists.
-        if (lstat(vendor_srcdir, &st) || !S_ISDIR(st.st_mode))
-            vendor_srcdir = NULL;
-        // Check if oem partition exists.
-        if (lstat(oem_srcdir, &st) || !S_ISDIR(st.st_mode))
-            oem_srcdir = NULL;
-    } else {
-        // srcarg may be "data", "system", "vendor", "oem" or NULL.
-        // If srcarg is NULL, then all partitions are synced.
-        if(strcmp(srcarg, "system") == 0) {
-            system_srcdir = product_file("system");
-        } else if(strcmp(srcarg, "data") == 0) {
-            data_srcdir = product_file("data");
-        } else if(strcmp(srcarg, "vendor") == 0) {
-            vendor_srcdir = product_file("vendor");
-        } else if(strcmp(srcarg, "oem") == 0) {
-            oem_srcdir = product_file("oem");
-        } else {
-            // It's not "system", "data", "vendor", or "oem".
-            return 1;
-        }
-    }
-
-    if(system_srcdir_out != NULL)
-        *system_srcdir_out = system_srcdir;
-    else
-        free(system_srcdir);
-
-    if(vendor_srcdir_out != NULL)
-        *vendor_srcdir_out = vendor_srcdir;
-    else
-        free(vendor_srcdir);
-
-    if(oem_srcdir_out != NULL)
-        *oem_srcdir_out = oem_srcdir;
-    else
-        free(oem_srcdir);
-
-    if(data_srcdir_out != NULL)
-        *data_srcdir_out = data_srcdir;
-    else
-        free(data_srcdir);
-
-    return 0;
-}
-
 static int pm_command(transport_type transport, const char* serial,
                       int argc, const char** argv)
 {
-    char buf[4096];
+    std::string cmd = "shell:pm";
 
-    snprintf(buf, sizeof(buf), "shell:pm");
-
-    while(argc-- > 0) {
-        char *quoted = escape_arg(*argv++);
-        strncat(buf, " ", sizeof(buf) - 1);
-        strncat(buf, quoted, sizeof(buf) - 1);
-        free(quoted);
+    while (argc-- > 0) {
+        cmd += " " + escape_arg(*argv++);
     }
 
-    send_shellcommand(transport, serial, buf);
+    send_shell_command(transport, serial, cmd);
     return 0;
 }
 
-int uninstall_app(transport_type transport, const char* serial, int argc,
-                  const char** argv)
+static int uninstall_app(transport_type transport, const char* serial, int argc,
+                         const char** argv)
 {
     /* if the user choose the -k option, we refuse to do it until devices are
        out with the option to uninstall the remaining data somehow (adb/ui) */
@@ -1865,15 +1628,8 @@
 
 static int delete_file(transport_type transport, const char* serial, char* filename)
 {
-    char buf[4096];
-    char* quoted;
-
-    snprintf(buf, sizeof(buf), "shell:rm -f ");
-    quoted = escape_arg(filename);
-    strncat(buf, quoted, sizeof(buf)-1);
-    free(quoted);
-
-    send_shellcommand(transport, serial, buf);
+    std::string cmd = "shell:rm -f " + escape_arg(filename);
+    send_shell_command(transport, serial, cmd);
     return 0;
 }
 
@@ -1888,8 +1644,8 @@
     }
 }
 
-int install_app(transport_type transport, const char* serial, int argc,
-                const char** argv)
+static int install_app(transport_type transport, const char* serial, int argc,
+                       const char** argv)
 {
     static const char *const DATA_DEST = "/data/local/tmp/%s";
     static const char *const SD_DEST = "/sdcard/tmp/%s";
@@ -1942,13 +1698,12 @@
     return err;
 }
 
-int install_multiple_app(transport_type transport, const char* serial, int argc,
-                         const char** argv)
+static int install_multiple_app(transport_type transport, const char* serial, int argc,
+                                const char** argv)
 {
-    char buf[1024];
     int i;
     struct stat sb;
-    unsigned long long total_size = 0;
+    uint64_t total_size = 0;
 
     // Find all APK arguments starting at end.
     // All other arguments passed through verbatim.
@@ -1974,20 +1729,22 @@
         return 1;
     }
 
-    snprintf(buf, sizeof(buf), "exec:pm install-create -S %lld", total_size);
+#if defined(_WIN32) // Remove when we're using clang for Win32.
+    std::string cmd = android::base::StringPrintf("exec:pm install-create -S %u", (unsigned) total_size);
+#else
+    std::string cmd = android::base::StringPrintf("exec:pm install-create -S %" PRIu64, total_size);
+#endif
     for (i = 1; i < first_apk; i++) {
-        char *quoted = escape_arg(argv[i]);
-        strncat(buf, " ", sizeof(buf) - 1);
-        strncat(buf, quoted, sizeof(buf) - 1);
-        free(quoted);
+        cmd += " " + escape_arg(argv[i]);
     }
 
     // Create install session
-    int fd = adb_connect(buf);
+    int fd = adb_connect(cmd.c_str());
     if (fd < 0) {
         fprintf(stderr, "Connect error for create: %s\n", adb_error());
         return -1;
     }
+    char buf[BUFSIZ];
     read_status_line(fd, buf, sizeof(buf));
     adb_close(fd);
 
@@ -2016,8 +1773,15 @@
             goto finalize_session;
         }
 
-        snprintf(buf, sizeof(buf), "exec:pm install-write -S %lld %d %d_%s -",
-                (long long int) sb.st_size, session_id, i, get_basename(file));
+#if defined(_WIN32) // Remove when we're using clang for Win32.
+        std::string cmd = android::base::StringPrintf(
+                "exec:pm install-write -S %u %d %d_%s -",
+                (unsigned) sb.st_size, session_id, i, get_basename(file));
+#else
+        std::string cmd = android::base::StringPrintf(
+                "exec:pm install-write -S %" PRIu64 " %d %d_%s -",
+                static_cast<uint64_t>(sb.st_size), session_id, i, get_basename(file));
+#endif
 
         int localFd = adb_open(file, O_RDONLY);
         if (localFd < 0) {
@@ -2026,7 +1790,7 @@
             goto finalize_session;
         }
 
-        int remoteFd = adb_connect(buf);
+        int remoteFd = adb_connect(cmd.c_str());
         if (remoteFd < 0) {
             fprintf(stderr, "Connect error for write: %s\n", adb_error());
             adb_close(localFd);
diff --git a/adb/fdevent.h b/adb/fdevent.h
index a8102ca..8d84b29 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -19,10 +19,6 @@
 
 #include <stdint.h>  /* for int64_t */
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* events that may be observed */
 #define FDE_READ              0x0001
 #define FDE_WRITE             0x0002
@@ -32,7 +28,7 @@
 /* features that may be set (via the events set/add/del interface) */
 #define FDE_DONT_CLOSE        0x0080
 
-typedef struct fdevent fdevent;
+struct fdevent;
 
 typedef void (*fd_func)(int fd, unsigned events, void *userdata);
 
@@ -82,8 +78,4 @@
     void *arg;
 };
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 4ba730b..49d8783 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -130,8 +130,6 @@
     return -1;
 }
 
-typedef struct syncsendbuf syncsendbuf;
-
 struct syncsendbuf {
     unsigned id;
     unsigned size;
@@ -557,8 +555,6 @@
     }
 }
 
-typedef struct copyinfo copyinfo;
-
 struct copyinfo
 {
     copyinfo *next;
@@ -804,12 +800,12 @@
 }
 
 
-typedef struct {
+struct sync_ls_build_list_cb_args {
     copyinfo **filelist;
     copyinfo **dirlist;
     const char *rpath;
     const char *lpath;
-} sync_ls_build_list_cb_args;
+};
 
 void
 sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
@@ -1031,18 +1027,18 @@
     }
 }
 
-int do_sync_sync(const char *lpath, const char *rpath, int listonly)
+int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only)
 {
-    fprintf(stderr,"syncing %s...\n",rpath);
+    fprintf(stderr, "syncing %s...\n", rpath.c_str());
 
     int fd = adb_connect("sync:");
-    if(fd < 0) {
-        fprintf(stderr,"error: %s\n", adb_error());
+    if (fd < 0) {
+        fprintf(stderr, "error: %s\n", adb_error());
         return 1;
     }
 
     BEGIN();
-    if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
+    if (copy_local_dir_remote(fd, lpath.c_str(), rpath.c_str(), 1, list_only)) {
         return 1;
     } else {
         END();
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 5b69a63..344eb98 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -17,9 +17,7 @@
 #ifndef _FILE_SYNC_SERVICE_H_
 #define _FILE_SYNC_SERVICE_H_
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include <string>
 
 #define htoll(x) (x)
 #define ltohl(x) (x)
@@ -38,7 +36,7 @@
 #define ID_FAIL MKID('F','A','I','L')
 #define ID_QUIT MKID('Q','U','I','T')
 
-typedef union {
+union syncmsg {
     unsigned id;
     struct {
         unsigned id;
@@ -65,19 +63,15 @@
         unsigned id;
         unsigned msglen;
     } status;
-} syncmsg;
+} ;
 
 
 void file_sync_service(int fd, void *cookie);
 int do_sync_ls(const char *path);
 int do_sync_push(const char *lpath, const char *rpath, int show_progress);
-int do_sync_sync(const char *lpath, const char *rpath, int listonly);
+int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only);
 int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime);
 
 #define SYNC_DATA_MAX (64*1024)
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/adb/jdwp_service.cpp b/adb/jdwp_service.cpp
index 9cf084e..c0f7ec2 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/jdwp_service.cpp
@@ -121,7 +121,6 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
-typedef struct JdwpProcess  JdwpProcess;
 struct JdwpProcess {
     JdwpProcess*  next;
     JdwpProcess*  prev;
@@ -455,11 +454,10 @@
 #define  JDWP_CONTROL_NAME      "\0jdwp-control"
 #define  JDWP_CONTROL_NAME_LEN  (sizeof(JDWP_CONTROL_NAME)-1)
 
-typedef struct {
+struct JdwpControl {
     int       listen_socket;
     fdevent*  fde;
-
-} JdwpControl;
+};
 
 
 static void
@@ -570,10 +568,10 @@
  ** this simply returns the list of known JDWP process pids
  **/
 
-typedef struct {
+struct JdwpSocket {
     asocket  socket;
     int      pass;
-} JdwpSocket;
+};
 
 static void
 jdwp_socket_close( asocket*  s )
@@ -642,8 +640,6 @@
  ** to the client...
  **/
 
-typedef struct JdwpTracker  JdwpTracker;
-
 struct JdwpTracker {
     asocket       socket;
     JdwpTracker*  next;
@@ -754,4 +750,3 @@
 }
 
 #endif /* !ADB_HOST */
-
diff --git a/adb/qemu_tracing.h b/adb/qemu_tracing.h
index bf80457..ff42d4f 100644
--- a/adb/qemu_tracing.h
+++ b/adb/qemu_tracing.h
@@ -21,16 +21,8 @@
 #ifndef __QEMU_TRACING_H
 #define __QEMU_TRACING_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Initializes connection with the adb-debug qemud service in the emulator. */
 int adb_qemu_trace_init(void);
 void adb_qemu_trace(const char* fmt, ...);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* __QEMU_TRACING_H */
diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp
index b150274..1eaee73 100644
--- a/adb/remount_service.cpp
+++ b/adb/remount_service.cpp
@@ -31,6 +31,7 @@
 
 #include "adb.h"
 #include "adb_io.h"
+#include "adb_utils.h"
 #include "cutils/properties.h"
 
 static int system_ro = 1;
@@ -56,11 +57,6 @@
     return device;
 }
 
-static bool has_partition(const char* path) {
-    struct stat sb;
-    return (lstat(path, &sb) == 0 && S_ISDIR(sb.st_mode));
-}
-
 int make_block_device_writable(const std::string& dev) {
     int fd = unix_open(dev.c_str(), O_RDONLY | O_CLOEXEC);
     if (fd == -1) {
@@ -90,7 +86,7 @@
 }
 
 static bool remount_partition(int fd, const char* partition, int* ro) {
-  if (!has_partition(partition)) {
+  if (!directory_exists(partition)) {
     return true;
   }
   if (remount(partition, ro)) {
diff --git a/adb/services.cpp b/adb/services.cpp
index 12eb406..ff13722 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -31,6 +31,8 @@
 #include <unistd.h>
 #endif
 
+#include <base/stringprintf.h>
+
 #if !ADB_HOST
 #include "base/file.h"
 #include "cutils/android_reboot.h"
@@ -43,8 +45,6 @@
 #include "remount_service.h"
 #include "transport.h"
 
-typedef struct stinfo stinfo;
-
 struct stinfo {
     void (*func)(int fd, void *cookie);
     int fd;
@@ -194,7 +194,7 @@
     if (reboot_service_impl(fd, static_cast<const char*>(arg))) {
         // Don't return early. Give the reboot command time to take effect
         // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
-        while (1) {
+        while (true) {
             pause();
         }
     }
@@ -375,7 +375,7 @@
     pid_t pid = (pid_t) (uintptr_t) cookie;
 
     D("entered. fd=%d of pid=%d\n", fd, pid);
-    for (;;) {
+    while (true) {
         int status;
         pid_t p = waitpid(pid, &status, 0);
         if (p == pid) {
@@ -501,19 +501,8 @@
     } else if(!strncmp(name, "unroot:", 7)) {
         ret = create_service_thread(restart_unroot_service, NULL);
     } else if(!strncmp(name, "backup:", 7)) {
-        char* arg = strdup(name + 7);
-        if (arg == NULL) return -1;
-        char* c = arg;
-        for (; *c != '\0'; c++) {
-            if (*c == ':')
-                *c = ' ';
-        }
-        char* cmd;
-        if (asprintf(&cmd, "/system/bin/bu backup %s", arg) != -1) {
-            ret = create_subproc_thread(cmd, SUBPROC_RAW);
-            free(cmd);
-        }
-        free(arg);
+        ret = create_subproc_thread(android::base::StringPrintf("/system/bin/bu backup %s",
+                                                                (name + 7)).c_str(), SUBPROC_RAW);
     } else if(!strncmp(name, "restore:", 8)) {
         ret = create_subproc_thread("/system/bin/bu restore", SUBPROC_RAW);
     } else if(!strncmp(name, "tcpip:", 6)) {
@@ -559,12 +548,12 @@
 
     D("wait_for_state %d\n", sinfo->state);
 
-    const char* err = "unknown error";
-    atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
-    if(t != 0) {
+    std::string error_msg = "unknown error";
+    atransport* t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &error_msg);
+    if (t != 0) {
         WriteFdExactly(fd, "OKAY", 4);
     } else {
-        sendfailmsg(fd, err);
+        sendfailmsg(fd, error_msg.c_str());
     }
 
     if (sinfo->serial)
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 48d02d6..f468029 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -487,10 +487,10 @@
 /* a Remote socket is used to send/receive data to/from a given transport object
 ** it needs to be closed when the transport is forcibly destroyed by the user
 */
-typedef struct aremotesocket {
+struct aremotesocket {
     asocket      socket;
     adisconnect  disconnect;
-} aremotesocket;
+};
 
 static int remote_socket_enqueue(asocket *s, apacket *p)
 {
@@ -827,12 +827,11 @@
     }
 #else /* !ADB_HOST */
     if (s->transport == NULL) {
-        const char* error_string = "unknown failure";
-        s->transport = acquire_one_transport (CS_ANY,
-                kTransportAny, NULL, &error_string);
+        std::string error_msg = "unknown failure";
+        s->transport = acquire_one_transport(CS_ANY, kTransportAny, NULL, &error_msg);
 
         if (s->transport == NULL) {
-            sendfailmsg(s->peer->fd, error_string);
+            sendfailmsg(s->peer->fd, error_msg.c_str());
             goto fail;
         }
     }
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 2ad28fa..d9a1518 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -54,10 +54,6 @@
 
 #include "fdevent.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #define OS_PATH_SEPARATOR '\\'
 #define OS_PATH_SEPARATOR_STR "\\"
 #define ENV_PATH_SEPARATOR_STR ";"
@@ -296,10 +292,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #define OS_PATH_SEPARATOR '/'
 #define OS_PATH_SEPARATOR_STR "/"
 #define ENV_PATH_SEPARATOR_STR ":"
@@ -540,8 +532,4 @@
 
 #endif /* !_WIN32 */
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* _ADB_SYSDEPS_H */
diff --git a/adb/tests/test_adb.py b/adb/tests/test_adb.py
index f111b043..69dead2 100755
--- a/adb/tests/test_adb.py
+++ b/adb/tests/test_adb.py
@@ -267,6 +267,14 @@
                 adb.unroot()
             adb.wait()
 
+    def test_argument_escaping(self):
+        """Make sure that argument escaping is somewhat sane."""
+        adb = AdbWrapper()
+
+        # http://b/19734868
+        result = adb.shell("sh -c 'echo hello; echo world'").splitlines()
+        self.assertEqual(["hello", "world"], result)
+
 
 class AdbFile(unittest.TestCase):
     SCRATCH_DIR = "/data/local/tmp"
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 4b9eeeb..37f9d7b 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -406,7 +406,6 @@
  * number of client connections that want it through a single
  * live TCP connection
  */
-typedef struct device_tracker  device_tracker;
 struct device_tracker {
     asocket          socket;
     int              update_needed;
@@ -536,7 +535,6 @@
 }
 #endif // ADB_HOST
 
-typedef struct tmsg tmsg;
 struct tmsg
 {
     atransport *transport;
@@ -800,22 +798,20 @@
     return !*to_test;
 }
 
-atransport *acquire_one_transport(int state, transport_type ttype,
-                                  const char* serial, const char** error_out)
+atransport* acquire_one_transport(int state, transport_type ttype,
+                                  const char* serial, std::string* error_out)
 {
     atransport *t;
     atransport *result = NULL;
     int ambiguous = 0;
 
 retry:
-    if (error_out)
-        *error_out = "device not found";
+    if (error_out) *error_out = "device not found";
 
     adb_mutex_lock(&transport_lock);
     for (t = transport_list.next; t != &transport_list; t = t->next) {
         if (t->connection_state == CS_NOPERM) {
-        if (error_out)
-            *error_out = "insufficient permissions for device";
+            if (error_out) *error_out = "insufficient permissions for device";
             continue;
         }
 
@@ -827,8 +823,7 @@
                 qual_match(serial, "model:", t->model, true) ||
                 qual_match(serial, "device:", t->device, false)) {
                 if (result) {
-                    if (error_out)
-                        *error_out = "more than one device";
+                    if (error_out) *error_out = "more than one device";
                     ambiguous = 1;
                     result = NULL;
                     break;
@@ -838,8 +833,7 @@
         } else {
             if (ttype == kTransportUsb && t->type == kTransportUsb) {
                 if (result) {
-                    if (error_out)
-                        *error_out = "more than one device";
+                    if (error_out) *error_out = "more than one device";
                     ambiguous = 1;
                     result = NULL;
                     break;
@@ -847,8 +841,7 @@
                 result = t;
             } else if (ttype == kTransportLocal && t->type == kTransportLocal) {
                 if (result) {
-                    if (error_out)
-                        *error_out = "more than one emulator";
+                    if (error_out) *error_out = "more than one emulator";
                     ambiguous = 1;
                     result = NULL;
                     break;
@@ -856,8 +849,7 @@
                 result = t;
             } else if (ttype == kTransportAny) {
                 if (result) {
-                    if (error_out)
-                        *error_out = "more than one device and emulator";
+                    if (error_out) *error_out = "more than one device and emulator";
                     ambiguous = 1;
                     result = NULL;
                     break;
@@ -870,29 +862,33 @@
 
     if (result) {
         if (result->connection_state == CS_UNAUTHORIZED) {
-            if (error_out)
-                *error_out = "device unauthorized. Please check the confirmation dialog on your device.";
+            if (error_out) {
+                *error_out = "device unauthorized.\n";
+                char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
+                *error_out += "This adbd's $ADB_VENDOR_KEYS is ";
+                *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
+                *error_out += "; try 'adb kill-server' if that seems wrong.\n";
+                *error_out += "Otherwise check for a confirmation dialog on your device.";
+            }
             result = NULL;
         }
 
-         /* offline devices are ignored -- they are either being born or dying */
+        /* offline devices are ignored -- they are either being born or dying */
         if (result && result->connection_state == CS_OFFLINE) {
-            if (error_out)
-                *error_out = "device offline";
+            if (error_out) *error_out = "device offline";
             result = NULL;
         }
-         /* check for required connection state */
+
+        /* check for required connection state */
         if (result && state != CS_ANY && result->connection_state != state) {
-            if (error_out)
-                *error_out = "invalid device state";
+            if (error_out) *error_out = "invalid device state";
             result = NULL;
         }
     }
 
     if (result) {
         /* found one that we can take */
-        if (error_out)
-            *error_out = NULL;
+        if (error_out) *error_out = "success";
     } else if (state != CS_ANY && (serial || !ambiguous)) {
         adb_sleep_ms(1000);
         goto retry;
diff --git a/adb/transport.h b/adb/transport.h
index 36a0e40..a2077e8 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -17,14 +17,11 @@
 #ifndef __TRANSPORT_H
 #define __TRANSPORT_H
 
-#include <stdbool.h>
 #include <sys/types.h>
 
-#include "adb.h"
+#include <string>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "adb.h"
 
 #if ADB_TRACE
 void dump_hex(const unsigned char* ptr, size_t  len);
@@ -37,7 +34,7 @@
  * If no suitable transport is found, error is set.
  */
 atransport* acquire_one_transport(int state, transport_type ttype,
-                                  const char* serial, const char** error_out);
+                                  const char* serial, std::string* error_out);
 void add_transport_disconnect(atransport* t, adisconnect* dis);
 void remove_transport_disconnect(atransport* t, adisconnect* dis);
 void kick_transport(atransport* t);
@@ -74,8 +71,4 @@
 
 asocket* create_device_tracker(void);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif   /* __TRANSPORT_H */
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index fe3c87f..30e6bf5 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -144,7 +144,7 @@
         if(serverfd == -1) {
             serverfd = socket_inaddr_any_server(port, SOCK_STREAM);
             if(serverfd < 0) {
-                D("server: cannot bind socket yet\n");
+                D("server: cannot bind socket yet: %s\n", strerror(errno));
                 adb_sleep_ms(1000);
                 continue;
             }
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index 8d670f8..6d21104 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -18,6 +18,7 @@
 
 #include "sysdeps.h"
 
+#include <cutils/properties.h>
 #include <dirent.h>
 #include <errno.h>
 #include <linux/usb/ch9.h>
@@ -163,7 +164,7 @@
     struct usb_handle *usb = (struct usb_handle *)x;
     int fd;
 
-    while (1) {
+    while (true) {
         // wait until the USB device needs opening
         adb_mutex_lock(&usb->lock);
         while (usb->fd != -1)
@@ -347,14 +348,14 @@
 {
     struct usb_handle *usb = (struct usb_handle *)x;
 
-    while (1) {
+    while (true) {
         // wait until the USB device needs opening
         adb_mutex_lock(&usb->lock);
         while (usb->control != -1 && usb->bulk_in != -1 && usb->bulk_out != -1)
             adb_cond_wait(&usb->notify, &usb->lock);
         adb_mutex_unlock(&usb->lock);
 
-        while (1) {
+        while (true) {
             init_functionfs(usb);
 
             if (usb->control >= 0 && usb->bulk_in >= 0 && usb->bulk_out >= 0)
@@ -362,6 +363,7 @@
 
             adb_sleep_ms(1000);
         }
+        property_set("sys.usb.ffs.ready", "1");
 
         D("[ usb_thread - registering device ]\n");
         register_usb_transport(usb, 0, 0, 1);
diff --git a/base/include/base/strings.h b/base/include/base/strings.h
index ab56aad..3559342 100644
--- a/base/include/base/strings.h
+++ b/base/include/base/strings.h
@@ -25,7 +25,7 @@
 
 // Splits a string into a vector of strings.
 //
-// The string is split at each occurence of a character in delimiters.
+// The string is split at each occurrence of a character in delimiters.
 //
 // Empty splits will be omitted. I.e. Split("a,,b", ",") -> {"a", "b"}
 //
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index b9e957f..7b2975b 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -74,6 +74,16 @@
 LOCAL_STATIC_LIBRARIES += libf2fs_utils_host libf2fs_ioutils_host libf2fs_dlutils_host
 endif
 
+# libc++ not available on windows yet
+ifneq ($(HOST_OS),windows)
+    LOCAL_CXX_STL := libc++_static
+endif
+
+# Don't add anything here, we don't want additional shared dependencies
+# on the host fastboot tool, and shared libraries that link against libc++
+# will violate ODR
+LOCAL_SHARED_LIBRARIES :=
+
 include $(BUILD_HOST_EXECUTABLE)
 
 my_dist_files := $(LOCAL_BUILT_MODULE)
diff --git a/include/cutils/dir_hash.h b/include/cutils/dir_hash.h
deleted file mode 100644
index fbb4d02..0000000
--- a/include/cutils/dir_hash.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-typedef enum {
-    SHA_1,
-} HashAlgorithm;
-
-int get_file_hash(HashAlgorithm algorithm, const char *path,
-                  char *output_string, size_t max_output_string);
-
-int get_recursive_hash_manifest(HashAlgorithm algorithm,
-                                const char *directory_path,
-                                char **output_string);
diff --git a/include/cutils/partition_utils.h b/include/cutils/partition_utils.h
index 597df92..72ca80d 100644
--- a/include/cutils/partition_utils.h
+++ b/include/cutils/partition_utils.h
@@ -20,7 +20,6 @@
 __BEGIN_DECLS
 
 int partition_wiped(char *source);
-void erase_footer(const char *dev_path, long long size);
 
 __END_DECLS
 
diff --git a/libcutils/dir_hash.c b/libcutils/dir_hash.c
deleted file mode 100644
index 098b5db..0000000
--- a/libcutils/dir_hash.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <dirent.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sha1.h>
-#include <unistd.h>
-#include <limits.h>
-
-#include <sys/stat.h>
-
-#include <netinet/in.h>
-#include <resolv.h>
-
-#include <cutils/dir_hash.h>
-
-/**
- * Copies, if it fits within max_output_string bytes, into output_string
- * a hash of the contents, size, permissions, uid, and gid of the file
- * specified by path, using the specified algorithm.  Returns the length
- * of the output string, or a negative number if the buffer is too short.
- */
-int get_file_hash(HashAlgorithm algorithm, const char *path,
-                  char *output_string, size_t max_output_string) {
-    SHA1_CTX context;
-    struct stat sb;
-    unsigned char md[SHA1_DIGEST_LENGTH];
-    int used;
-    size_t n;
-
-    if (algorithm != SHA_1) {
-        errno = EINVAL;
-        return -1;
-    }
-
-    if (stat(path, &sb) != 0) {
-        return -1;
-    }
-
-    if (S_ISLNK(sb.st_mode)) {
-        char buf[PATH_MAX];
-        int len;
-
-        len = readlink(path, buf, sizeof(buf));
-        if (len < 0) {
-            return -1;
-        }
-
-        SHA1Init(&context);
-        SHA1Update(&context, (unsigned char *) buf, len);
-        SHA1Final(md, &context);
-    } else if (S_ISREG(sb.st_mode)) {
-        char buf[10000];
-        FILE *f = fopen(path, "rb");
-        int len;
-
-        if (f == NULL) {
-            return -1;
-        }
-
-        SHA1Init(&context);
-
-        while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
-            SHA1Update(&context, (unsigned char *) buf, len);
-        }
-
-        if (ferror(f)) {
-            fclose(f);
-            return -1;
-        }
-
-        fclose(f);
-        SHA1Final(md, &context);
-    }
-
-    if (S_ISLNK(sb.st_mode) || S_ISREG(sb.st_mode)) {
-        used = b64_ntop(md, SHA1_DIGEST_LENGTH,
-                        output_string, max_output_string);
-        if (used < 0) {
-            errno = ENOSPC;
-            return -1;
-        }
-
-        n = snprintf(output_string + used, max_output_string - used,
-                     " %d 0%o %d %d", (int) sb.st_size, sb.st_mode,
-                     (int) sb.st_uid, (int) sb.st_gid);
-    } else {
-        n = snprintf(output_string, max_output_string,
-                     "- - 0%o %d %d", sb.st_mode,
-                     (int) sb.st_uid, (int) sb.st_gid);
-    }
-
-    if (n >= max_output_string - used) {
-        errno = ENOSPC;
-        return -(used + n);
-    }
-
-    return used + n;
-}
-
-struct list {
-    char *name;
-    struct list *next;
-};
-
-static int cmp(const void *a, const void *b) {
-    struct list *const *ra = a;
-    struct list *const *rb = b;
-
-    return strcmp((*ra)->name, (*rb)->name);
-}
-
-static int recurse(HashAlgorithm algorithm, const char *directory_path,
-                    struct list **out) {
-    struct list *list = NULL;
-    struct list *f;
-
-    struct dirent *de;
-    DIR *d = opendir(directory_path);
-
-    if (d == NULL) {
-        return -1;
-    }
-
-    while ((de = readdir(d)) != NULL) {
-        if (strcmp(de->d_name, ".") == 0) {
-            continue;
-        }
-        if (strcmp(de->d_name, "..") == 0) {
-            continue;
-        }
-
-        char *name = malloc(strlen(de->d_name) + 1);
-        struct list *node = malloc(sizeof(struct list));
-
-        if (name == NULL || node == NULL) {
-            struct list *next;
-            for (f = list; f != NULL; f = next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-
-            free(name);
-            free(node);
-            closedir(d);
-            return -1;
-        }
-
-        strcpy(name, de->d_name);
-
-        node->name = name;
-        node->next = list;
-        list = node;
-    }
-
-    closedir(d);
-
-    for (f = list; f != NULL; f = f->next) {
-        struct stat sb;
-        char *name;
-        char outstr[NAME_MAX + 100];
-        char *keep;
-        struct list *res;
-
-        name = malloc(strlen(f->name) + strlen(directory_path) + 2);
-        if (name == NULL) {
-            struct list *next;
-            for (f = list; f != NULL; f = f->next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-            for (f = *out; f != NULL; f = f->next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-            *out = NULL;
-            return -1;
-        }
-
-        sprintf(name, "%s/%s", directory_path, f->name);
-
-        int len = get_file_hash(algorithm, name,
-                                outstr, sizeof(outstr));
-        if (len < 0) {
-            // should not happen
-            return -1;
-        }
-
-        keep = malloc(len + strlen(name) + 3);
-        res = malloc(sizeof(struct list));
-
-        if (keep == NULL || res == NULL) {
-            struct list *next;
-            for (f = list; f != NULL; f = f->next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-            for (f = *out; f != NULL; f = f->next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-            *out = NULL;
-
-            free(keep);
-            free(res);
-            return -1;
-        }
-
-        sprintf(keep, "%s %s\n", name, outstr);
-
-        res->name = keep;
-        res->next = *out;
-        *out = res;
-
-        if ((stat(name, &sb) == 0) && S_ISDIR(sb.st_mode)) {
-            if (recurse(algorithm, name, out) < 0) {
-                struct list *next;
-                for (f = list; f != NULL; f = next) {
-                    next = f->next;
-                    free(f->name);
-                    free(f);
-                }
-
-                return -1;
-            }
-        }
-    }
-
-    struct list *next;
-    for (f = list; f != NULL; f = next) {
-        next = f->next;
-
-        free(f->name);
-        free(f);
-    }
-}
-
-/**
- * Allocates a string containing the names and hashes of all files recursively
- * reached under the specified directory_path, using the specified algorithm.
- * The string is returned as *output_string; the return value is the length
- * of the string, or a negative number if there was a failure.
- */
-int get_recursive_hash_manifest(HashAlgorithm algorithm,
-                                const char *directory_path,
-                                char **output_string) {
-    struct list *out = NULL;
-    struct list *r;
-    struct list **list;
-    int count = 0;
-    int len = 0;
-    int retlen = 0;
-    int i;
-    char *buf;
-    
-    if (recurse(algorithm, directory_path, &out) < 0) {
-        return -1;
-    }
-
-    for (r = out; r != NULL; r = r->next) {
-        count++;
-        len += strlen(r->name);
-    }
-
-    list = malloc(count * sizeof(struct list *));
-    if (list == NULL) {
-        struct list *next;
-        for (r = out; r != NULL; r = next) {
-            next = r->next;
-            free(r->name);
-            free(r);
-        }
-        return -1;
-    }
-
-    count = 0;
-    for (r = out; r != NULL; r = r->next) {
-        list[count++] = r;
-    }
-
-    qsort(list, count, sizeof(struct list *), cmp);
-
-    buf = malloc(len + 1);
-    if (buf == NULL) {
-        struct list *next;
-        for (r = out; r != NULL; r = next) {
-            next = r->next;
-            free(r->name);
-            free(r);
-        }
-        free(list);
-        return -1;
-    }
-
-    for (i = 0; i < count; i++) {
-        int n = strlen(list[i]->name);
-
-        strcpy(buf + retlen, list[i]->name);
-        retlen += n;
-    }
-
-    free(list);
-
-    struct list *next;
-    for (r = out; r != NULL; r = next) {
-        next = r->next;
-
-        free(r->name);
-        free(r);
-    }
-
-    *output_string = buf;
-    return retlen;
-}
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 57c46a3..8582344 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -1131,7 +1131,22 @@
     return kIoError;
   }
 
-  int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
+  int result = 0;
+#if defined(__linux__)
+  // Make sure we have enough space on the volume to extract the compressed
+  // entry. Note that the call to ftruncate below will change the file size but
+  // will not allocate space on disk.
+  if (declared_length > 0) {
+    result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
+    if (result == -1) {
+      ALOGW("Zip: unable to allocate space for file to %" PRId64 ": %s",
+            static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+      return kIoError;
+    }
+  }
+#endif  // defined(__linux__)
+
+  result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
   if (result == -1) {
     ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
           static_cast<int64_t>(declared_length + current_offset), strerror(errno));
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index a0436ef..1859461 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -226,6 +226,68 @@
     return it;
 }
 
+// Define a temporary mechanism to report the last LogBufferElement pointer
+// for the specified uid, pid and tid. Used below to help merge-sort when
+// pruning for worst UID.
+class LogBufferElementKey {
+    const union {
+        struct {
+            uint16_t uid;
+            uint16_t pid;
+            uint16_t tid;
+            uint16_t padding;
+        } __packed;
+        uint64_t value;
+    } __packed;
+
+public:
+    LogBufferElementKey(uid_t u, pid_t p, pid_t t):uid(u),pid(p),tid(t),padding(0) { }
+    LogBufferElementKey(uint64_t k):value(k) { }
+
+    uint64_t getKey() { return value; }
+};
+
+struct LogBufferElementEntry {
+    const uint64_t key;
+    LogBufferElement *last;
+
+public:
+    LogBufferElementEntry(const uint64_t &k, LogBufferElement *e):key(k),last(e) { }
+
+    const uint64_t&getKey() const { return key; }
+
+    LogBufferElement *getLast() { return last; }
+};
+
+struct LogBufferElementLast : public android::BasicHashtable<uint64_t, LogBufferElementEntry> {
+
+    bool merge(LogBufferElement *e, unsigned short dropped) {
+        LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid());
+        android::hash_t hash = android::hash_type(key.getKey());
+        ssize_t index = find(-1, hash, key.getKey());
+        if (index != -1) {
+            LogBufferElementEntry &entry = editEntryAt(index);
+            LogBufferElement *l = entry.getLast();
+            unsigned short d = l->getDropped();
+            if ((dropped + d) > USHRT_MAX) {
+                removeAt(index);
+            } else {
+                l->setDropped(dropped + d);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    size_t add(LogBufferElement *e) {
+        LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid());
+        android::hash_t hash = android::hash_type(key.getKey());
+        return android::BasicHashtable<uint64_t, LogBufferElementEntry>::
+            add(hash, LogBufferElementEntry(key.getKey(), e));
+    }
+
+};
+
 // prune "pruneRows" of type "id" from the buffer.
 //
 // mLogElementsLock must be held when this function is called.
@@ -301,7 +363,7 @@
 
         bool kick = false;
         bool leading = true;
-        LogBufferElement *last = NULL;
+        LogBufferElementLast last;
         for(it = mLogElements.begin(); it != mLogElements.end();) {
             LogBufferElement *e = *it;
 
@@ -322,24 +384,18 @@
                 continue;
             }
 
-            pid_t pid = e->getPid();
-
             // merge any drops
-            if (last && dropped
-             && ((dropped + last->getDropped()) < USHRT_MAX)
-             && (last->getPid() == pid)
-             && (last->getTid() == e->getTid())) {
+            if (dropped && last.merge(e, dropped)) {
                 it = mLogElements.erase(it);
                 stats.erase(e);
                 delete e;
-                last->setDropped(dropped + last->getDropped());
                 continue;
             }
 
             leading = false;
 
             if (hasBlacklist && mPrune.naughty(e)) {
-                last = NULL;
+                last.clear();
                 it = erase(it);
                 if (dropped) {
                     continue;
@@ -361,13 +417,13 @@
             }
 
             if (dropped) {
-                last = e;
+                last.add(e);
                 ++it;
                 continue;
             }
 
             if (e->getUid() != worst) {
-                last = NULL;
+                last.clear();
                 ++it;
                 continue;
             }
@@ -382,17 +438,12 @@
             unsigned short len = e->getMsgLen();
             stats.drop(e);
             e->setDropped(1);
-            // merge any drops
-            if (last
-             && (last->getDropped() < (USHRT_MAX - 1))
-             && (last->getPid() == pid)
-             && (last->getTid() == e->getTid())) {
+            if (last.merge(e, 1)) {
                 it = mLogElements.erase(it);
                 stats.erase(e);
                 delete e;
-                last->setDropped(last->getDropped() + 1);
             } else {
-                last = e;
+                last.add(e);
                 ++it;
             }
             if (worst_sizes < second_worst_sizes) {
@@ -400,6 +451,7 @@
             }
             worst_sizes -= len;
         }
+        last.clear();
 
         if (!kick || !mPrune.worstUidEnabled()) {
             break; // the following loop will ask bad clients to skip/drop
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 0801fe8..eadc4dd 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -328,22 +328,32 @@
             }
 
             if (!headerPrinted) {
+                output.appendFormat("\n\n");
+                android::String8 name("");
                 if (uid == AID_ROOT) {
-                    output.appendFormat(
-                        "\n\nChattiest UIDs in %s:\n",
+                    name.appendFormat(
+                        "Chattiest UIDs in %s log buffer:",
                         android_log_id_to_name(id));
                 } else {
-                    output.appendFormat(
-                        "\n\nLogging for your UID in %s:\n",
+                    name.appendFormat(
+                        "Logging for your UID in %s log buffer:",
                         android_log_id_to_name(id));
                 }
-                android::String8 name("UID");
                 android::String8 size("Size");
                 android::String8 pruned("Pruned");
                 if (!worstUidEnabledForLogid(id)) {
                     pruned.setTo("");
                 }
                 format_line(output, name, size, pruned);
+
+                name.setTo("UID   PACKAGE");
+                size.setTo("BYTES");
+                pruned.setTo("LINES");
+                if (!worstUidEnabledForLogid(id)) {
+                    pruned.setTo("");
+                }
+                format_line(output, name, size, pruned);
+
                 headerPrinted = true;
             }
 
@@ -380,15 +390,22 @@
             }
 
             if (!headerPrinted) {
+                output.appendFormat("\n\n");
+                android::String8 name("");
                 if (uid == AID_ROOT) {
-                    output.appendFormat("\n\nChattiest PIDs:\n");
+                    name.appendFormat("Chattiest PIDs:");
                 } else {
-                    output.appendFormat("\n\nLogging for this PID:\n");
+                    name.appendFormat("Logging for this PID:");
                 }
-                android::String8 name("  PID/UID");
                 android::String8 size("Size");
                 android::String8 pruned("Pruned");
                 format_line(output, name, size, pruned);
+
+                name.setTo("  PID/UID   COMMAND LINE");
+                size.setTo("BYTES");
+                pruned.setTo("LINES");
+                format_line(output, name, size, pruned);
+
                 headerPrinted = true;
             }
 
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a2b8f59..a5ea60a 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -248,6 +248,7 @@
     mkdir /data/misc/bluedroid 0770 bluetooth net_bt_stack
     mkdir /data/misc/bluetooth 0770 system system
     mkdir /data/misc/keystore 0700 keystore keystore
+    mkdir /data/misc/gatekeeper 0700 system system
     mkdir /data/misc/keychain 0771 system system
     mkdir /data/misc/net 0750 root shell
     mkdir /data/misc/radio 0770 system radio