Merge "Add explicit cast to shut off clang warnings."
diff --git a/adb/Android.mk b/adb/Android.mk
index 903d1e1..c38cf93 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -17,10 +17,20 @@
     -Wvla \
     -DADB_REVISION='"$(adb_version)"' \
 
+ADB_COMMON_linux_CFLAGS := \
+    -std=c++14 \
+    -Wexit-time-destructors \
+
+ADB_COMMON_darwin_CFLAGS := \
+    -std=c++14 \
+    -Wexit-time-destructors \
+
 # Define windows.h and tchar.h Unicode preprocessor symbols so that
 # CreateFile(), _tfopen(), etc. map to versions that take wchar_t*, breaking the
 # build if you accidentally pass char*. Fix by calling like:
-# CreateFileW(widen(utf8).c_str()).
+#   std::wstring path_wide;
+#   if (!android::base::UTF8ToWide(path_utf8, &path_wide)) { /* error handling */ }
+#   CreateFileW(path_wide.c_str());
 ADB_COMMON_windows_CFLAGS := \
     -DUNICODE=1 -D_UNICODE=1 \
 
@@ -55,7 +65,10 @@
     -fvisibility=hidden \
 
 LIBADB_linux_CFLAGS := \
-    -std=c++14 \
+    $(ADB_COMMON_linux_CFLAGS) \
+
+LIBADB_darwin_CFLAGS := \
+    $(ADB_COMMON_darwin_CFLAGS) \
 
 LIBADB_windows_CFLAGS := \
     $(ADB_COMMON_windows_CFLAGS) \
@@ -110,6 +123,7 @@
 LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=1
 LOCAL_CFLAGS_windows := $(LIBADB_windows_CFLAGS)
 LOCAL_CFLAGS_linux := $(LIBADB_linux_CFLAGS)
+LOCAL_CFLAGS_darwin := $(LIBADB_darwin_CFLAGS)
 LOCAL_SRC_FILES := \
     $(LIBADB_SRC_FILES) \
     adb_auth_host.cpp \
@@ -155,6 +169,7 @@
 LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
 LOCAL_CFLAGS_windows := $(LIBADB_windows_CFLAGS)
 LOCAL_CFLAGS_linux := $(LIBADB_linux_CFLAGS)
+LOCAL_CFLAGS_darwin := $(LIBADB_darwin_CFLAGS)
 LOCAL_SRC_FILES := \
     $(LIBADB_TEST_SRCS) \
     services.cpp \
@@ -189,6 +204,7 @@
 LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
 LOCAL_CFLAGS_windows := $(LIBADB_windows_CFLAGS)
 LOCAL_CFLAGS_linux := $(LIBADB_linux_CFLAGS)
+LOCAL_CFLAGS_darwin := $(LIBADB_darwin_CFLAGS)
 LOCAL_SRC_FILES := test_track_devices.cpp
 LOCAL_SANITIZE := $(adb_host_sanitize)
 LOCAL_SHARED_LIBRARIES := libbase
@@ -204,7 +220,6 @@
 LOCAL_LDLIBS_linux := -lrt -ldl -lpthread
 
 LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
-LOCAL_CFLAGS_darwin := -Wno-sizeof-pointer-memaccess -Wno-unused-parameter
 
 # Use wmain instead of main
 LOCAL_LDFLAGS_windows := -municode
@@ -230,6 +245,13 @@
 LOCAL_CFLAGS_windows := \
     $(ADB_COMMON_windows_CFLAGS)
 
+LOCAL_CFLAGS_linux := \
+    $(ADB_COMMON_linux_CFLAGS) \
+
+LOCAL_CFLAGS_darwin := \
+    $(ADB_COMMON_darwin_CFLAGS) \
+    -Wno-sizeof-pointer-memaccess -Wno-unused-parameter \
+
 LOCAL_MODULE := adb
 LOCAL_MODULE_TAGS := debug
 LOCAL_MODULE_HOST_OS := darwin linux windows
@@ -239,9 +261,12 @@
     libadb \
     libbase \
     libcrypto_static \
-    libcutils \
     liblog \
 
+# Don't use libcutils on Windows.
+LOCAL_STATIC_LIBRARIES_darwin := libcutils
+LOCAL_STATIC_LIBRARIES_linux := libcutils
+
 LOCAL_CXX_STL := libc++_static
 
 # Don't add anything here, we don't want additional shared dependencies
@@ -273,6 +298,7 @@
 
 LOCAL_CFLAGS := \
     $(ADB_COMMON_CFLAGS) \
+    $(ADB_COMMON_linux_CFLAGS) \
     -DADB_HOST=0 \
     -D_GNU_SOURCE \
     -Wno-deprecated-declarations \
diff --git a/adb/adb.h b/adb/adb.h
index 491fff3..5187c81 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -151,7 +151,7 @@
 
 void get_my_path(char *s, size_t maxLen);
 int launch_server(int server_port);
-int adb_main(int is_daemon, int server_port, int ack_reply_fd);
+int adb_server_main(int is_daemon, int server_port, int ack_reply_fd);
 
 /* initialize a transport object's func pointers and state */
 #if ADB_HOST
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 5309519..e11bff0 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -311,7 +311,9 @@
               SystemErrorCodeToString(hr).c_str());
             return -1;
         }
-        home_str = narrow(path);
+        if (!android::base::WideToUTF8(path, &home_str)) {
+            return -1;
+        }
         home = home_str.c_str();
     }
     format = "%s\\%s";
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index a225a53..04b9882 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -58,7 +58,12 @@
               SystemErrorCodeToString(GetLastError()).c_str());
     }
 
-    return narrow(temp_path) + log_name;
+    std::string temp_path_utf8;
+    if (!android::base::WideToUTF8(temp_path, &temp_path_utf8)) {
+        fatal_errno("cannot convert temporary file path from UTF-16 to UTF-8");
+    }
+
+    return temp_path_utf8 + log_name;
 }
 #else
 static const char kNullFileName[] = "/dev/null";
@@ -81,8 +86,7 @@
 
 static void setup_daemon_logging(void) {
     const std::string log_file_path(GetLogFilePath());
-    int fd = unix_open(log_file_path.c_str(), O_WRONLY | O_CREAT | O_APPEND,
-                       0640);
+    int fd = unix_open(log_file_path.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0640);
     if (fd == -1) {
         fatal("cannot open '%s': %s", log_file_path.c_str(), strerror(errno));
     }
@@ -98,10 +102,10 @@
     LOG(INFO) << adb_version();
 }
 
-int adb_main(int is_daemon, int server_port, int ack_reply_fd) {
+int adb_server_main(int is_daemon, int server_port, int ack_reply_fd) {
 #if defined(_WIN32)
     // adb start-server starts us up with stdout and stderr hooked up to
-    // anonymous pipes to. When the C Runtime sees this, it makes stderr and
+    // anonymous pipes. When the C Runtime sees this, it makes stderr and
     // stdout buffered, but to improve the chance that error output is seen,
     // unbuffer stdout and stderr just like if we were run at the console.
     // This also keeps stderr unbuffered when it is redirected to adb.log.
@@ -115,8 +119,6 @@
     }
 
     SetConsoleCtrlHandler(ctrlc_handler, TRUE);
-#else
-    signal(SIGPIPE, SIG_IGN);
 #endif
 
     init_transport_registration();
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 6e4c4e8..bd3813e 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -62,7 +62,7 @@
 static int install_app_legacy(TransportType t, const char* serial, int argc, const char** argv);
 static int uninstall_app_legacy(TransportType t, const char* serial, int argc, const char** argv);
 
-static std::string gProductOutPath;
+static auto& gProductOutPath = *new std::string();
 extern int gListenAll;
 
 static std::string product_file(const char *extra) {
@@ -591,6 +591,11 @@
     std::vector<std::string> args;
     if (use_shell_protocol) {
         args.push_back(kShellServiceArgShellProtocol);
+
+        const char* terminal_type = getenv("TERM");
+        if (terminal_type != nullptr) {
+            args.push_back(std::string("TERM=") + terminal_type);
+        }
     }
     if (!type_arg.empty()) {
         args.push_back(type_arg);
@@ -1029,8 +1034,7 @@
         use_shell_protocol = CanUseFeature(features, kFeatureShell2);
     }
 
-    std::string service_string = ShellServiceString(use_shell_protocol, "",
-                                                    command);
+    std::string service_string = ShellServiceString(use_shell_protocol, "", command);
 
     int fd;
     while (true) {
@@ -1080,8 +1084,8 @@
     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();
+                fprintf(stderr, "adb: backup -f passed with no filename.\n");
+                return EXIT_FAILURE;
             }
             filename = argv[i+1];
             for (int j = i+2; j <= argc; ) {
@@ -1092,14 +1096,18 @@
         }
     }
 
-    /* bare "adb backup" or "adb backup -f filename" are not valid invocations */
-    if (argc < 2) return usage();
+    // Bare "adb backup" or "adb backup -f filename" are not valid invocations ---
+    // a list of packages is required.
+    if (argc < 2) {
+        fprintf(stderr, "adb: backup either needs a list of packages or -all/-shared.\n");
+        return EXIT_FAILURE;
+    }
 
     adb_unlink(filename);
     int outFd = adb_creat(filename, 0640);
     if (outFd < 0) {
-        fprintf(stderr, "adb: unable to open file %s\n", filename);
-        return -1;
+        fprintf(stderr, "adb: backup unable to create file '%s': %s\n", filename, strerror(errno));
+        return EXIT_FAILURE;
     }
 
     std::string cmd = "backup:";
@@ -1115,15 +1123,17 @@
     if (fd < 0) {
         fprintf(stderr, "adb: unable to connect for backup: %s\n", error.c_str());
         adb_close(outFd);
-        return -1;
+        return EXIT_FAILURE;
     }
 
-    printf("Now unlock your device and confirm the backup operation.\n");
+    printf("Now unlock your device and confirm the backup operation...\n");
+    fflush(stdout);
+
     copy_to_file(fd, outFd);
 
     adb_close(fd);
     adb_close(outFd);
-    return 0;
+    return EXIT_SUCCESS;
 }
 
 static int restore(int argc, const char** argv) {
@@ -1286,6 +1296,11 @@
     TransportType transport_type = kTransportAny;
     int ack_reply_fd = -1;
 
+#if !defined(_WIN32)
+    // We'd rather have EPIPE than SIGPIPE.
+    signal(SIGPIPE, SIG_IGN);
+#endif
+
     // 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
@@ -1417,7 +1432,7 @@
                 fprintf(stderr, "reply fd for adb server to client communication not specified.\n");
                 return usage();
             }
-            r = adb_main(is_daemon, server_port, ack_reply_fd);
+            r = adb_server_main(is_daemon, server_port, ack_reply_fd);
         } else {
             r = launch_server(server_port);
         }
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 06eb34d..46547b9 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -70,8 +70,8 @@
 
 // All operations to fdevent should happen only in the main thread.
 // That's why we don't need a lock for fdevent.
-static std::unordered_map<int, PollNode> g_poll_node_map;
-static std::list<fdevent*> g_pending_list;
+static auto& g_poll_node_map = *new std::unordered_map<int, PollNode>();
+static auto& g_pending_list = *new std::list<fdevent*>();
 static bool main_thread_valid;
 static pthread_t main_thread;
 
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 3322763..ad38369 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -403,9 +403,9 @@
     if (!sc.SendRequest(ID_RECV, rpath)) return false;
 
     adb_unlink(lpath);
-    if (!mkdirs(adb_dirname(lpath))) {
-        sc.Error("failed to create parent directory '%s': %s",
-                 adb_dirname(lpath).c_str(), strerror(errno));
+    const std::string dirpath = adb_dirname(lpath);
+    if (!mkdirs(dirpath.c_str())) {
+        sc.Error("failed to create parent directory '%s': %s", dirpath.c_str(), strerror(errno));
         return false;
     }
 
@@ -478,32 +478,34 @@
 
 struct copyinfo
 {
-    std::string src;
-    std::string dst;
+    std::string lpath;
+    std::string rpath;
     unsigned int time;
     unsigned int mode;
     uint64_t size;
     bool skip;
 };
 
-static copyinfo mkcopyinfo(const std::string& spath, const std::string& dpath,
+static void ensure_trailing_separator(std::string& lpath, std::string& rpath) {
+    if (!adb_is_separator(lpath.back())) {
+        lpath.push_back(OS_PATH_SEPARATOR);
+    }
+    if (rpath.back() != '/') {
+        rpath.push_back('/');
+    }
+}
+
+static copyinfo mkcopyinfo(std::string lpath, std::string rpath,
                            const std::string& name, unsigned int mode) {
     copyinfo result;
-    result.src = spath;
-    result.dst = dpath;
-    if (result.src.back() != '/') {
-      result.src.push_back('/');
-    }
-    if (result.dst.back() != '/') {
-      result.dst.push_back('/');
-    }
-    result.src.append(name);
-    result.dst.append(name);
+    result.lpath = std::move(lpath);
+    result.rpath = std::move(rpath);
+    ensure_trailing_separator(result.lpath, result.rpath);
+    result.lpath.append(name);
+    result.rpath.append(name);
 
-    bool isdir = S_ISDIR(mode);
-    if (isdir) {
-        result.src.push_back('/');
-        result.dst.push_back('/');
+    if (S_ISDIR(mode)) {
+        ensure_trailing_separator(result.lpath, result.rpath);
     }
 
     result.time = 0;
@@ -538,22 +540,23 @@
         std::string stat_path = lpath + de->d_name;
 
         struct stat st;
-        if (!lstat(stat_path.c_str(), &st)) {
-            copyinfo ci = mkcopyinfo(lpath, rpath, de->d_name, st.st_mode);
-            if (S_ISDIR(st.st_mode)) {
-                dirlist.push_back(ci);
-            } else {
-                if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
-                    sc.Warning("skipping special file '%s'", lpath.c_str());
-                } else {
-                    ci.time = st.st_mtime;
-                    ci.size = st.st_size;
-                    filelist->push_back(ci);
-                }
-            }
-        } else {
+        if (lstat(stat_path.c_str(), &st) == -1) {
             sc.Error("cannot lstat '%s': %s", stat_path.c_str(),
                      strerror(errno));
+            continue;
+        }
+
+        copyinfo ci = mkcopyinfo(lpath, rpath, de->d_name, st.st_mode);
+        if (S_ISDIR(st.st_mode)) {
+            dirlist.push_back(ci);
+        } else {
+            if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
+                sc.Error("skipping special file '%s'", lpath.c_str());
+            } else {
+                ci.time = st.st_mtime;
+                ci.size = st.st_size;
+                filelist->push_back(ci);
+            }
         }
     }
 
@@ -574,7 +577,7 @@
     }
 
     for (const copyinfo& ci : dirlist) {
-        local_build_list(sc, filelist, ci.src.c_str(), ci.dst.c_str());
+        local_build_list(sc, filelist, ci.lpath, ci.rpath);
     }
 
     return true;
@@ -584,13 +587,8 @@
                                   std::string rpath, bool check_timestamps,
                                   bool list_only) {
     // Make sure that both directory paths end in a slash.
-    // Both paths are known to exist, so they cannot be empty.
-    if (lpath.back() != '/') {
-        lpath.push_back('/');
-    }
-    if (rpath.back() != '/') {
-        rpath.push_back('/');
-    }
+    // Both paths are known to be nonempty, so we don't need to check.
+    ensure_trailing_separator(lpath, rpath);
 
     // Recursively build the list of files to copy.
     std::vector<copyinfo> filelist;
@@ -602,7 +600,7 @@
 
     if (check_timestamps) {
         for (const copyinfo& ci : filelist) {
-            if (!sc.SendRequest(ID_STAT, ci.dst.c_str())) {
+            if (!sc.SendRequest(ID_STAT, ci.rpath.c_str())) {
                 return false;
             }
         }
@@ -624,10 +622,10 @@
     for (const copyinfo& ci : filelist) {
         if (!ci.skip) {
             if (list_only) {
-                sc.Error("would push: %s -> %s", ci.src.c_str(),
-                         ci.dst.c_str());
+                sc.Error("would push: %s -> %s", ci.lpath.c_str(),
+                         ci.rpath.c_str());
             } else {
-                if (!sync_send(sc, ci.src.c_str(), ci.dst.c_str(), ci.time,
+                if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time,
                                ci.mode)) {
                     return false;
                 }
@@ -649,9 +647,10 @@
     if (!sc.IsValid()) return false;
 
     bool success = true;
-    unsigned mode;
-    if (!sync_stat(sc, dst, nullptr, &mode, nullptr)) return false;
-    bool dst_isdir = mode != 0 && S_ISDIR(mode);
+    unsigned dst_mode;
+    if (!sync_stat(sc, dst, nullptr, &dst_mode, nullptr)) return false;
+    bool dst_exists = (dst_mode != 0);
+    bool dst_isdir = S_ISDIR(dst_mode);
 
     if (!dst_isdir) {
         if (srcs.size() > 1) {
@@ -659,7 +658,10 @@
             return false;
         } else {
             size_t dst_len = strlen(dst);
-            if (dst[dst_len - 1] == '/') {
+
+            // A path that ends with a slash doesn't have to be a directory if
+            // it doesn't exist yet.
+            if (dst[dst_len - 1] == '/' && dst_exists) {
                 sc.Error("failed to access '%s': Not a directory", dst);
                 return false;
             }
@@ -669,19 +671,37 @@
     for (const char* src_path : srcs) {
         const char* dst_path = dst;
         struct stat st;
-        if (stat(src_path, &st)) {
+        if (stat(src_path, &st) == -1) {
             sc.Error("cannot stat '%s': %s", src_path, strerror(errno));
             success = false;
             continue;
         }
 
         if (S_ISDIR(st.st_mode)) {
-            success &= copy_local_dir_remote(sc, src_path, dst, false, false);
+            std::string dst_dir = dst;
+
+            // If the destination path existed originally, the source directory
+            // should be copied as a child of the destination.
+            if (dst_exists) {
+                if (!dst_isdir) {
+                    sc.Error("target '%s' is not a directory", dst);
+                    return false;
+                }
+                // dst is a POSIX path, so we don't want to use the sysdeps
+                // helpers here.
+                if (dst_dir.back() != '/') {
+                    dst_dir.push_back('/');
+                }
+                dst_dir.append(adb_basename(src_path));
+            }
+
+            success &= copy_local_dir_remote(sc, src_path, dst_dir.c_str(),
+                                             false, false);
             continue;
         }
 
         std::string path_holder;
-        if (mode != 0 && S_ISDIR(mode)) {
+        if (dst_isdir) {
             // If we're copying a local file to a remote directory,
             // we really want to copy to remote_dir + "/" + local_filename.
             path_holder = android::base::StringPrintf(
@@ -712,7 +732,7 @@
         // We found a child that isn't '.' or '..'.
         empty_dir = false;
 
-        copyinfo ci = mkcopyinfo(rpath, lpath, name, mode);
+        copyinfo ci = mkcopyinfo(lpath, rpath, name, mode);
         if (S_ISDIR(mode)) {
             dirlist.push_back(ci);
         } else if (S_ISREG(mode) || S_ISLNK(mode)) {
@@ -731,11 +751,7 @@
     // Add the current directory to the list if it was empty, to ensure that
     // it gets created.
     if (empty_dir) {
-        auto rdname = adb_dirname(rpath);
-        auto ldname = adb_dirname(lpath);
-        auto rbasename = adb_basename(rpath);
-        auto lbasename = adb_basename(lpath);
-        filelist->push_back(mkcopyinfo(adb_dirname(rpath), adb_dirname(lpath),
+        filelist->push_back(mkcopyinfo(adb_dirname(lpath), adb_dirname(rpath),
                                        adb_basename(rpath), S_IFDIR));
         return true;
     }
@@ -744,8 +760,7 @@
     while (!dirlist.empty()) {
         copyinfo current = dirlist.back();
         dirlist.pop_back();
-        if (!remote_build_list(sc, filelist, current.src.c_str(),
-                               current.dst.c_str())) {
+        if (!remote_build_list(sc, filelist, current.rpath, current.lpath)) {
             return false;
         }
     }
@@ -753,15 +768,15 @@
     return true;
 }
 
-static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
-{
+static int set_time_and_mode(const std::string& lpath, time_t time,
+                             unsigned int mode) {
     struct utimbuf times = { time, time };
-    int r1 = utime(lpath, &times);
+    int r1 = utime(lpath.c_str(), &times);
 
     /* use umask for permissions */
     mode_t mask = umask(0000);
     umask(mask);
-    int r2 = chmod(lpath, mode & ~mask);
+    int r2 = chmod(lpath.c_str(), mode & ~mask);
 
     return r1 ? r1 : r2;
 }
@@ -769,13 +784,8 @@
 static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath,
                                   std::string lpath, bool copy_attrs) {
     // Make sure that both directory paths end in a slash.
-    // Both paths are known to exist, so they cannot be empty.
-    if (rpath.back() != '/') {
-        rpath.push_back('/');
-    }
-    if (lpath.back() != '/') {
-        lpath.push_back('/');
-    }
+    // Both paths are known to be nonempty, so we don't need to check.
+    ensure_trailing_separator(lpath, rpath);
 
     // Recursively build the list of files to copy.
     sc.Print("pull: building file list...");
@@ -788,26 +798,25 @@
     int skipped = 0;
     for (const copyinfo &ci : filelist) {
         if (!ci.skip) {
-            sc.Printf("pull: %s -> %s", ci.src.c_str(), ci.dst.c_str());
+            sc.Printf("pull: %s -> %s", ci.rpath.c_str(), ci.lpath.c_str());
 
             if (S_ISDIR(ci.mode)) {
                 // Entry is for an empty directory, create it and continue.
                 // TODO(b/25457350): We don't preserve permissions on directories.
-                if (!mkdirs(ci.dst))  {
+                if (!mkdirs(ci.lpath))  {
                     sc.Error("failed to create directory '%s': %s",
-                             ci.dst.c_str(), strerror(errno));
+                             ci.lpath.c_str(), strerror(errno));
                     return false;
                 }
                 pulled++;
                 continue;
             }
 
-            if (!sync_recv(sc, ci.src.c_str(), ci.dst.c_str())) {
+            if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str())) {
                 return false;
             }
 
-            if (copy_attrs &&
-                set_time_and_mode(ci.dst.c_str(), ci.time, ci.mode)) {
+            if (copy_attrs && set_time_and_mode(ci.lpath, ci.time, ci.mode)) {
                 return false;
             }
             pulled++;
@@ -828,25 +837,38 @@
     if (!sc.IsValid()) return false;
 
     bool success = true;
-    unsigned mode, time;
     struct stat st;
-    if (stat(dst, &st)) {
-        // If we're only pulling one file, the destination path might point to
+    bool dst_exists = true;
+
+    if (stat(dst, &st) == -1) {
+        dst_exists = false;
+
+        // If we're only pulling one path, the destination path might point to
         // a path that doesn't exist yet.
-        if (srcs.size() != 1 || errno != ENOENT) {
-            sc.Error("cannot stat '%s': %s", dst, strerror(errno));
+        if (srcs.size() == 1 && errno == ENOENT) {
+            // However, its parent must exist.
+            struct stat parent_st;
+            if (stat(adb_dirname(dst).c_str(), &parent_st) == -1) {
+                sc.Error("cannot create file/directory '%s': %s", dst, strerror(errno));
+                return false;
+            }
+        } else {
+            sc.Error("failed to access '%s': %s", dst, strerror(errno));
             return false;
         }
     }
 
-    bool dst_isdir = S_ISDIR(st.st_mode);
+    bool dst_isdir = dst_exists && S_ISDIR(st.st_mode);
     if (!dst_isdir) {
         if (srcs.size() > 1) {
             sc.Error("target '%s' is not a directory", dst);
             return false;
         } else {
             size_t dst_len = strlen(dst);
-            if (dst[dst_len - 1] == '/') {
+
+            // A path that ends with a slash doesn't have to be a directory if
+            // it doesn't exist yet.
+            if (adb_is_separator(dst[dst_len - 1]) && dst_exists) {
                 sc.Error("failed to access '%s': Not a directory", dst);
                 return false;
             }
@@ -855,38 +877,55 @@
 
     for (const char* src_path : srcs) {
         const char* dst_path = dst;
-        if (!sync_stat(sc, src_path, &time, &mode, nullptr)) return false;
-        if (mode == 0) {
+        unsigned src_mode, src_time;
+        if (!sync_stat(sc, src_path, &src_time, &src_mode, nullptr)) {
+            return false;
+        }
+        if (src_mode == 0) {
             sc.Error("remote object '%s' does not exist", src_path);
             success = false;
             continue;
         }
 
-        if (S_ISREG(mode) || S_ISLNK(mode)) {
-            // TODO(b/25601283): symlinks shouldn't be handled as files.
+        if (S_ISREG(src_mode)) {
             std::string path_holder;
-            struct stat st;
-            if (stat(dst_path, &st) == 0) {
-                if (S_ISDIR(st.st_mode)) {
-                    // If we're copying a remote file to a local directory,
-                    // we really want to copy to local_dir + "/" +
-                    // basename(remote).
-                    path_holder = android::base::StringPrintf(
-                        "%s/%s", dst_path, adb_basename(src_path).c_str());
-                    dst_path = path_holder.c_str();
-                }
+            if (dst_isdir) {
+                // If we're copying a remote file to a local directory, we
+                // really want to copy to local_dir + OS_PATH_SEPARATOR +
+                // basename(remote).
+                path_holder = android::base::StringPrintf(
+                    "%s%c%s", dst_path, OS_PATH_SEPARATOR,
+                    adb_basename(src_path).c_str());
+                dst_path = path_holder.c_str();
             }
             if (!sync_recv(sc, src_path, dst_path)) {
                 success = false;
                 continue;
             } else {
-                if (copy_attrs && set_time_and_mode(dst_path, time, mode)) {
+                if (copy_attrs &&
+                    set_time_and_mode(dst_path, src_time, src_mode) != 0) {
                     success = false;
                     continue;
                 }
             }
-        } else if (S_ISDIR(mode)) {
-            success &= copy_remote_dir_local(sc, src_path, dst_path, copy_attrs);
+        } else if (S_ISDIR(src_mode)) {
+            std::string dst_dir = dst;
+
+            // If the destination path existed originally, the source directory
+            // should be copied as a child of the destination.
+            if (dst_exists) {
+                if (!dst_isdir) {
+                    sc.Error("target '%s' is not a directory", dst);
+                    return false;
+                }
+                if (!adb_is_separator(dst_dir.back())) {
+                    dst_dir.push_back(OS_PATH_SEPARATOR);
+                }
+                dst_dir.append(adb_basename(src_path));
+            }
+
+            success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(),
+                                             copy_attrs);
             continue;
         } else {
             sc.Error("remote object '%s' not a file or directory", src_path);
diff --git a/adb/line_printer.cpp b/adb/line_printer.cpp
index aa332f7..4c57c7e 100644
--- a/adb/line_printer.cpp
+++ b/adb/line_printer.cpp
@@ -77,7 +77,7 @@
     CONSOLE_SCREEN_BUFFER_INFO csbi;
     GetConsoleScreenBufferInfo(console_, &csbi);
 
-    // TODO: const std::wstring to_print_wide = widen(to_print);
+    // TODO: std::wstring to_print_wide; if (!android::base::UTF8ToWide(to_print, &to_print_wide)...
     // TODO: wstring ElideMiddle.
     to_print = ElideMiddle(to_print, static_cast<size_t>(csbi.dwSize.X));
     // We don't want to have the cursor spamming back and forth, so instead of
diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp
index 35ba056..8f1c9b0 100644
--- a/adb/remount_service.cpp
+++ b/adb/remount_service.cpp
@@ -35,8 +35,6 @@
 #include "cutils/properties.h"
 #include "fs_mgr.h"
 
-const std::string kFstab_Prefix = "/fstab.";
-
 // Returns the device used to mount a directory in /proc/mounts.
 static std::string find_proc_mount(const char* dir) {
     std::unique_ptr<FILE, int(*)(FILE*)> fp(setmntent("/proc/mounts", "r"), endmntent);
@@ -58,7 +56,7 @@
     char propbuf[PROPERTY_VALUE_MAX];
 
     property_get("ro.hardware", propbuf, "");
-    std::string fstab_filename = kFstab_Prefix + propbuf;
+    std::string fstab_filename = std::string("/fstab.") + propbuf;
     struct fstab* fstab = fs_mgr_read_fstab(fstab_filename.c_str());
     struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, dir);
     std::string dev = rec ? std::string(rec->blk_device) : "";
diff --git a/adb/services.cpp b/adb/services.cpp
index 19a6726..41da4b8 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -213,9 +213,11 @@
     // Defaults:
     //   PTY for interactive, raw for non-interactive.
     //   No protocol.
+    //   $TERM set to "dumb".
     SubprocessType type(command.empty() ? SubprocessType::kPty
                                         : SubprocessType::kRaw);
     SubprocessProtocol protocol = SubprocessProtocol::kNone;
+    std::string terminal_type = "dumb";
 
     for (const std::string& arg : android::base::Split(service_args, ",")) {
         if (arg == kShellServiceArgRaw) {
@@ -224,14 +226,15 @@
             type = SubprocessType::kPty;
         } else if (arg == kShellServiceArgShellProtocol) {
             protocol = SubprocessProtocol::kShell;
-        }
-        else if (!arg.empty()) {
-            LOG(ERROR) << "Unsupported shell service arguments: " << args;
-            return -1;
+        } else if (android::base::StartsWith(arg, "TERM=")) {
+            terminal_type = arg.substr(5);
+        } else if (!arg.empty()) {
+            // This is not an error to allow for future expansion.
+            LOG(WARNING) << "Ignoring unknown shell service argument: " << arg;
         }
     }
 
-    return StartSubprocess(command.c_str(), type, protocol);
+    return StartSubprocess(command.c_str(), terminal_type.c_str(), type, protocol);
 }
 
 #endif  // !ADB_HOST
@@ -308,8 +311,7 @@
     } else if(!strncmp(name, "shell", 5)) {
         ret = ShellService(name + 5, transport);
     } else if(!strncmp(name, "exec:", 5)) {
-        ret = StartSubprocess(name + 5, SubprocessType::kRaw,
-                              SubprocessProtocol::kNone);
+        ret = StartSubprocess(name + 5, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);
     } else if(!strncmp(name, "sync:", 5)) {
         ret = create_service_thread(file_sync_service, NULL);
     } else if(!strncmp(name, "remount:", 8)) {
@@ -325,9 +327,9 @@
     } else if(!strncmp(name, "backup:", 7)) {
         ret = StartSubprocess(android::base::StringPrintf("/system/bin/bu backup %s",
                                                           (name + 7)).c_str(),
-                              SubprocessType::kRaw, SubprocessProtocol::kNone);
+                              nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);
     } else if(!strncmp(name, "restore:", 8)) {
-        ret = StartSubprocess("/system/bin/bu restore", SubprocessType::kRaw,
+        ret = StartSubprocess("/system/bin/bu restore", nullptr, SubprocessType::kRaw,
                               SubprocessProtocol::kNone);
     } else if(!strncmp(name, "tcpip:", 6)) {
         int port;
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index e3fde26..2e41fe6 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -175,8 +175,8 @@
 
 class Subprocess {
   public:
-    Subprocess(const std::string& command, SubprocessType type,
-               SubprocessProtocol protocol);
+    Subprocess(const std::string& command, const char* terminal_type,
+               SubprocessType type, SubprocessProtocol protocol);
     ~Subprocess();
 
     const std::string& command() const { return command_; }
@@ -207,6 +207,7 @@
     ScopedFd* PassOutput(ScopedFd* sfd, ShellProtocol::Id id);
 
     const std::string command_;
+    const std::string terminal_type_;
     SubprocessType type_;
     SubprocessProtocol protocol_;
     pid_t pid_ = -1;
@@ -220,9 +221,12 @@
     DISALLOW_COPY_AND_ASSIGN(Subprocess);
 };
 
-Subprocess::Subprocess(const std::string& command, SubprocessType type,
-                       SubprocessProtocol protocol)
-        : command_(command), type_(type), protocol_(protocol) {
+Subprocess::Subprocess(const std::string& command, const char* terminal_type,
+                       SubprocessType type, SubprocessProtocol protocol)
+    : command_(command),
+      terminal_type_(terminal_type ? terminal_type : ""),
+      type_(type),
+      protocol_(protocol) {
 }
 
 Subprocess::~Subprocess() {
@@ -290,6 +294,9 @@
             setenv("SHELL", pw->pw_shell, 1);
             setenv("USER", pw->pw_name, 1);
         }
+        if (!terminal_type_.empty()) {
+            setenv("TERM", terminal_type_.c_str(), 1);
+        }
 
         if (is_interactive()) {
             execl(_PATH_BSHELL, _PATH_BSHELL, "-", nullptr);
@@ -644,13 +651,14 @@
 
 }  // namespace
 
-int StartSubprocess(const char *name, SubprocessType type,
-                    SubprocessProtocol protocol) {
-    D("starting %s subprocess (protocol=%s): '%s'",
+int StartSubprocess(const char* name, const char* terminal_type,
+                    SubprocessType type, SubprocessProtocol protocol) {
+    D("starting %s subprocess (protocol=%s, TERM=%s): '%s'",
       type == SubprocessType::kRaw ? "raw" : "PTY",
-      protocol == SubprocessProtocol::kNone ? "none" : "shell", name);
+      protocol == SubprocessProtocol::kNone ? "none" : "shell",
+      terminal_type, name);
 
-    Subprocess* subprocess = new Subprocess(name, type, protocol);
+    Subprocess* subprocess = new Subprocess(name, terminal_type, type, protocol);
     if (!subprocess) {
         LOG(ERROR) << "failed to allocate new subprocess";
         return -1;
diff --git a/adb/shell_service.h b/adb/shell_service.h
index 63c00da..6f8ea9b 100644
--- a/adb/shell_service.h
+++ b/adb/shell_service.h
@@ -141,8 +141,8 @@
 // shell is started, otherwise |name| is executed non-interactively.
 //
 // Returns an open FD connected to the subprocess or -1 on failure.
-int StartSubprocess(const char* name, SubprocessType type,
-                    SubprocessProtocol protocol);
+int StartSubprocess(const char* name, const char* terminal_type,
+                    SubprocessType type, SubprocessProtocol protocol);
 
 #endif  // !ADB_HOST
 
diff --git a/adb/shell_service_test.cpp b/adb/shell_service_test.cpp
index e18f905..a012f3e 100644
--- a/adb/shell_service_test.cpp
+++ b/adb/shell_service_test.cpp
@@ -69,7 +69,7 @@
     SHELL_EXIT_NOTIFY_FD = fd[0];
     shell_exit_receiver_fd_ = fd[1];
 
-    subprocess_fd_ = StartSubprocess(command, type, protocol);
+    subprocess_fd_ = StartSubprocess(command, nullptr, type, protocol);
     ASSERT_TRUE(subprocess_fd_ >= 0);
 }
 
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 9f4012a..cba66fc 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -28,6 +28,9 @@
 
 #include <string>
 
+// Include this before open/unlink are defined as macros below.
+#include <base/utf8.h>
+
 /*
  * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
  * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
@@ -72,7 +75,7 @@
 #include <ws2tcpip.h>
 
 #include <memory>   // unique_ptr
-#include <string>   // Prototypes for narrow() and widen() use std::(w)string.
+#include <string>
 
 #include "fdevent.h"
 
@@ -81,6 +84,10 @@
 #define OS_PATH_SEPARATOR_STR "\\"
 #define ENV_PATH_SEPARATOR_STR ";"
 
+static __inline__ bool adb_is_separator(char c) {
+    return c == '\\' || c == '/';
+}
+
 typedef CRITICAL_SECTION          adb_mutex_t;
 
 #define  ADB_MUTEX_DEFINE(x)     adb_mutex_t   x
@@ -338,18 +345,6 @@
 char* adb_strerror(int err);
 #define strerror adb_strerror
 
-// Convert from UTF-8 to UTF-16, typically used to convert char strings into
-// wchar_t strings that can be passed to wchar_t-based OS and C Runtime APIs
-// on Windows.
-extern std::wstring widen(const std::string& utf8);
-extern std::wstring widen(const char* utf8);
-
-// Convert from UTF-16 to UTF-8, typically used to convert strings from OS and
-// C Runtime APIs that return wchar_t, to a format for our char-based data
-// structures.
-extern std::string narrow(const std::wstring& utf16);
-extern std::string narrow(const wchar_t* utf16);
-
 // Helper class to convert UTF-16 argv from wmain() to UTF-8 args that can be
 // passed to main().
 class NarrowArgs {
@@ -425,6 +420,10 @@
 #define OS_PATH_SEPARATOR_STR "/"
 #define ENV_PATH_SEPARATOR_STR ":"
 
+static __inline__ bool adb_is_separator(char c) {
+    return c == '/';
+}
+
 typedef  pthread_mutex_t          adb_mutex_t;
 
 #define  ADB_MUTEX_INITIALIZER    PTHREAD_MUTEX_INITIALIZER
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index e325889..81dcb41 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -35,6 +35,7 @@
 #include <base/logging.h>
 #include <base/stringprintf.h>
 #include <base/strings.h>
+#include <base/utf8.h>
 
 #include "adb.h"
 
@@ -102,7 +103,13 @@
   }
 
   // Convert UTF-16 to UTF-8.
-  std::string msg(narrow(msgbuf));
+  std::string msg;
+  if (!android::base::WideToUTF8(msgbuf, &msg)) {
+      return android::base::StringPrintf(
+          "Error (%d) converting from UTF-16 to UTF-8 while retrieving error. (%lu)", errno,
+          error_code);
+  }
+
   // Messages returned by the system end with line breaks.
   msg = android::base::Trim(msg);
   // There are many Windows error messages compared to POSIX, so include the
@@ -143,7 +150,11 @@
     char     *data;
     DWORD     file_size;
 
-    file = CreateFileW( widen(fn).c_str(),
+    std::wstring fn_wide;
+    if (!android::base::UTF8ToWide(fn, &fn_wide))
+        return NULL;
+
+    file = CreateFileW( fn_wide.c_str(),
                         GENERIC_READ,
                         FILE_SHARE_READ,
                         NULL,
@@ -433,7 +444,11 @@
         return -1;
     }
 
-    f->fh_handle = CreateFileW( widen(path).c_str(), desiredAccess, shareMode,
+    std::wstring path_wide;
+    if (!android::base::UTF8ToWide(path, &path_wide)) {
+        return -1;
+    }
+    f->fh_handle = CreateFileW( path_wide.c_str(), desiredAccess, shareMode,
                                 NULL, OPEN_EXISTING, 0, NULL );
 
     if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
@@ -474,7 +489,11 @@
         return -1;
     }
 
-    f->fh_handle = CreateFileW( widen(path).c_str(), GENERIC_WRITE,
+    std::wstring path_wide;
+    if (!android::base::UTF8ToWide(path, &path_wide)) {
+        return -1;
+    }
+    f->fh_handle = CreateFileW( path_wide.c_str(), GENERIC_WRITE,
                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
                                 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
                                 NULL );
@@ -980,7 +999,7 @@
 
 #if (NTDDI_VERSION >= NTDDI_WINXPSP2) || (_WIN32_WINNT >= _WIN32_WINNT_WS03)
     // TODO: When the Android SDK tools increases the Windows system
-    // requirements >= WinXP SP2, switch to GetAddrInfoW(widen(host).c_str()).
+    // requirements >= WinXP SP2, switch to android::base::UTF8ToWide() + GetAddrInfoW().
 #else
     // Otherwise, keep using getaddrinfo(), or do runtime API detection
     // with GetProcAddress("GetAddrInfoW").
@@ -2546,15 +2565,14 @@
     return _get_console_handle(fd) ? 1 : 0;
 }
 
-// Read an input record from the console; one that should be processed.
-static bool _get_interesting_input_record_uncached(const HANDLE console,
-    INPUT_RECORD* const input_record) {
+// Get the next KEY_EVENT_RECORD that should be processed.
+static bool _get_key_event_record(const HANDLE console, INPUT_RECORD* const input_record) {
     for (;;) {
         DWORD read_count = 0;
         memset(input_record, 0, sizeof(*input_record));
         if (!ReadConsoleInputA(console, input_record, 1, &read_count)) {
-            D("_get_interesting_input_record_uncached: ReadConsoleInputA() "
-              "failed: %s\n", SystemErrorCodeToString(GetLastError()).c_str());
+            D("_get_key_event_record: ReadConsoleInputA() failed: %s\n",
+              SystemErrorCodeToString(GetLastError()).c_str());
             errno = EIO;
             return false;
         }
@@ -2580,28 +2598,6 @@
     }
 }
 
-// Cached input record (in case _console_read() is passed a buffer that doesn't
-// have enough space to fit wRepeatCount number of key sequences). A non-zero
-// wRepeatCount indicates that a record is cached.
-static INPUT_RECORD _win32_input_record;
-
-// Get the next KEY_EVENT_RECORD that should be processed.
-static KEY_EVENT_RECORD* _get_key_event_record(const HANDLE console) {
-    // If nothing cached, read directly from the console until we get an
-    // interesting record.
-    if (_win32_input_record.Event.KeyEvent.wRepeatCount == 0) {
-        if (!_get_interesting_input_record_uncached(console,
-            &_win32_input_record)) {
-            // There was an error, so make sure wRepeatCount is zero because
-            // that signifies no cached input record.
-            _win32_input_record.Event.KeyEvent.wRepeatCount = 0;
-            return NULL;
-        }
-    }
-
-    return &_win32_input_record.Event.KeyEvent;
-}
-
 static __inline__ bool _is_shift_pressed(const DWORD control_key_state) {
     return (control_key_state & SHIFT_PRESSED) != 0;
 }
@@ -2946,16 +2942,34 @@
     return len + 1;
 }
 
-// Writes to buffer buf (of length len), returning number of bytes written or
-// -1 on error. Never returns zero because Win32 consoles are never 'closed'
-// (as far as I can tell).
+// Internal buffer to satisfy future _console_read() calls.
+static auto& g_console_input_buffer = *new std::vector<char>();
+
+// Writes to buffer buf (of length len), returning number of bytes written or -1 on error. Never
+// returns zero on console closure because Win32 consoles are never 'closed' (as far as I can tell).
 static int _console_read(const HANDLE console, void* buf, size_t len) {
     for (;;) {
-        KEY_EVENT_RECORD* const key_event = _get_key_event_record(console);
-        if (key_event == NULL) {
+        // Read of zero bytes should not block waiting for something from the console.
+        if (len == 0) {
+            return 0;
+        }
+
+        // Flush as much as possible from input buffer.
+        if (!g_console_input_buffer.empty()) {
+            const int bytes_read = std::min(len, g_console_input_buffer.size());
+            memcpy(buf, g_console_input_buffer.data(), bytes_read);
+            const auto begin = g_console_input_buffer.begin();
+            g_console_input_buffer.erase(begin, begin + bytes_read);
+            return bytes_read;
+        }
+
+        // Read from the actual console. This may block until input.
+        INPUT_RECORD input_record;
+        if (!_get_key_event_record(console, &input_record)) {
             return -1;
         }
 
+        KEY_EVENT_RECORD* const key_event = &input_record.Event.KeyEvent;
         const WORD vk = key_event->wVirtualKeyCode;
         const CHAR ch = key_event->uChar.AsciiChar;
         const DWORD control_key_state = _normalize_altgr_control_key_state(
@@ -3133,7 +3147,12 @@
                 break;
 
                 case 0x32:          // 2
+                case 0x33:          // 3
+                case 0x34:          // 4
+                case 0x35:          // 5
                 case 0x36:          // 6
+                case 0x37:          // 7
+                case 0x38:          // 8
                 case VK_OEM_MINUS:  // -_
                 {
                     seqbuflen = _get_control_character(seqbuf, key_event,
@@ -3149,25 +3168,6 @@
                 }
                 break;
 
-                case 0x33:  // 3
-                case 0x34:  // 4
-                case 0x35:  // 5
-                case 0x37:  // 7
-                case 0x38:  // 8
-                {
-                    seqbuflen = _get_control_character(seqbuf, key_event,
-                        control_key_state);
-
-                    // If Alt is pressed and it isn't Ctrl-Alt-ShiftUp, then
-                    // prefix with escape.
-                    if (_is_alt_pressed(control_key_state) &&
-                        !(_is_ctrl_pressed(control_key_state) &&
-                        !_is_shift_pressed(control_key_state))) {
-                        seqbuflen = _escape_prefix(seqbuf, seqbuflen);
-                    }
-                }
-                break;
-
                 case 0x41:  // a
                 case 0x42:  // b
                 case 0x43:  // c
@@ -3296,46 +3296,15 @@
             // event.
             D("_console_read: unknown virtual key code: %d, enhanced: %s",
                 vk, _is_enhanced_key(control_key_state) ? "true" : "false");
-            key_event->wRepeatCount = 0;
             continue;
         }
 
-        int bytesRead = 0;
-
-        // put output wRepeatCount times into buf/len
-        while (key_event->wRepeatCount > 0) {
-            if (len >= outlen) {
-                // Write to buf/len
-                memcpy(buf, out, outlen);
-                buf = (void*)((char*)buf + outlen);
-                len -= outlen;
-                bytesRead += outlen;
-
-                // consume the input
-                --key_event->wRepeatCount;
-            } else {
-                // Not enough space, so just leave it in _win32_input_record
-                // for a subsequent retrieval.
-                if (bytesRead == 0) {
-                    // We didn't write anything because there wasn't enough
-                    // space to even write one sequence. This should never
-                    // happen if the caller uses sensible buffer sizes
-                    // (i.e. >= maximum sequence length which is probably a
-                    // few bytes long).
-                    D("_console_read: no buffer space to write one sequence; "
-                        "buffer: %ld, sequence: %ld\n", (long)len,
-                        (long)outlen);
-                    errno = ENOMEM;
-                    return -1;
-                } else {
-                    // Stop trying to write to buf/len, just return whatever
-                    // we wrote so far.
-                    break;
-                }
-            }
+        // put output wRepeatCount times into g_console_input_buffer
+        while (key_event->wRepeatCount-- > 0) {
+            g_console_input_buffer.insert(g_console_input_buffer.end(), out, out + outlen);
         }
 
-        return bytesRead;
+        // Loop around and try to flush g_console_input_buffer
     }
 }
 
@@ -3454,11 +3423,11 @@
 // The Choice
 // ----------
 //
-// The code below chooses option 3, the UTF-8 everywhere strategy. It
-// introduces narrow() which converts UTF-16 to UTF-8. This is used by the
+// The code below chooses option 3, the UTF-8 everywhere strategy. It uses
+// android::base::WideToUTF8() which converts UTF-16 to UTF-8. This is used by the
 // NarrowArgs helper class that is used to convert wmain() args into UTF-8
-// args that are passed to main() at the beginning of program startup. We also
-// introduce widen() which converts from UTF-8 to UTF-16. This is used to
+// args that are passed to main() at the beginning of program startup. We also use
+// android::base::UTF8ToWide() which converts from UTF-8 to UTF-16. This is used to
 // implement wrappers below that call UTF-16 OS and C Runtime APIs.
 //
 // Unicode console output
@@ -3488,140 +3457,17 @@
 // to UTF-16 and then calls WriteConsoleW().
 
 
-// Function prototype because attributes cannot be placed on func definitions.
-static void _widen_fatal(const char *fmt, ...)
-    __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 1, 2)));
-
-// A version of fatal() that does not call adb_(v)fprintf(), so it can be
-// called from those functions.
-static void _widen_fatal(const char *fmt, ...) {
-    va_list ap;
-    va_start(ap, fmt);
-    // If (v)fprintf are macros that point to adb_(v)fprintf, when random adb
-    // code calls (v)fprintf, it may end up calling adb_(v)fprintf, which then
-    // calls _widen_fatal(). So then how does _widen_fatal() output a error?
-    // By directly calling real C Runtime APIs that don't properly output
-    // Unicode, but will be able to get a comprehendible message out. To do
-    // this, make sure we don't call (v)fprintf macros by undefining them.
-#pragma push_macro("fprintf")
-#pragma push_macro("vfprintf")
-#undef fprintf
-#undef vfprintf
-    fprintf(stderr, "error: ");
-    vfprintf(stderr, fmt, ap);
-    fprintf(stderr, "\n");
-#pragma pop_macro("vfprintf")
-#pragma pop_macro("fprintf")
-    va_end(ap);
-    exit(-1);
-}
-
-// TODO: Consider implementing widen() and narrow() out of std::wstring_convert
-// once libcxx is supported on Windows. Or, consider libutils/Unicode.cpp.
-
-// Convert from UTF-8 to UTF-16. A size of -1 specifies a NULL terminated
-// string. Any other size specifies the number of chars to convert, excluding
-// any NULL terminator (if you're passing an explicit size, you probably don't
-// have a NULL terminated string in the first place).
-std::wstring widen(const char* utf8, const int size) {
-    // Note: Do not call SystemErrorCodeToString() from widen() because
-    // SystemErrorCodeToString() calls narrow() which may call fatal() which
-    // calls adb_vfprintf() which calls widen(), potentially causing infinite
-    // recursion.
-    const int chars_to_convert = MultiByteToWideChar(CP_UTF8, 0, utf8, size,
-                                                     NULL, 0);
-    if (chars_to_convert <= 0) {
-        // UTF-8 to UTF-16 should be lossless, so we don't expect this to fail.
-        _widen_fatal("MultiByteToWideChar failed counting: %d, "
-                     "GetLastError: %lu", chars_to_convert, GetLastError());
-    }
-
-    std::wstring utf16;
-    size_t chars_to_allocate = chars_to_convert;
-    if (size == -1) {
-        // chars_to_convert includes a NULL terminator, so subtract space
-        // for that because resize() includes that itself.
-        --chars_to_allocate;
-    }
-    utf16.resize(chars_to_allocate);
-
-    // This uses &string[0] to get write-access to the entire string buffer
-    // which may be assuming that the chars are all contiguous, but it seems
-    // to work and saves us the hassle of using a temporary
-    // std::vector<wchar_t>.
-    const int result = MultiByteToWideChar(CP_UTF8, 0, utf8, size, &utf16[0],
-                                           chars_to_convert);
-    if (result != chars_to_convert) {
-        // UTF-8 to UTF-16 should be lossless, so we don't expect this to fail.
-        _widen_fatal("MultiByteToWideChar failed conversion: %d, "
-                     "GetLastError: %lu", result, GetLastError());
-    }
-
-    // If a size was passed in (size != -1), then the string is NULL terminated
-    // by a NULL char that was written by std::string::resize(). If size == -1,
-    // then MultiByteToWideChar() read a NULL terminator from the original
-    // string and converted it to a NULL UTF-16 char in the output.
-
-    return utf16;
-}
-
-// Convert a NULL terminated string from UTF-8 to UTF-16.
-std::wstring widen(const char* utf8) {
-    // Pass -1 to let widen() determine the string length.
-    return widen(utf8, -1);
-}
-
-// Convert from UTF-8 to UTF-16.
-std::wstring widen(const std::string& utf8) {
-    return widen(utf8.c_str(), utf8.length());
-}
-
-// Convert from UTF-16 to UTF-8.
-std::string narrow(const std::wstring& utf16) {
-    return narrow(utf16.c_str());
-}
-
-// Convert from UTF-16 to UTF-8.
-std::string narrow(const wchar_t* utf16) {
-    // Note: Do not call SystemErrorCodeToString() from narrow() because
-    // SystemErrorCodeToString() calls narrow() and we don't want potential
-    // infinite recursion.
-    const int chars_required = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL,
-                                                   0, NULL, NULL);
-    if (chars_required <= 0) {
-        // UTF-16 to UTF-8 should be lossless, so we don't expect this to fail.
-        fatal("WideCharToMultiByte failed counting: %d, GetLastError: %lu",
-              chars_required, GetLastError());
-    }
-
-    std::string utf8;
-    // Subtract space for the NULL terminator because resize() includes
-    // that itself. Note that this could potentially throw a std::bad_alloc
-    // exception.
-    utf8.resize(chars_required - 1);
-
-    // This uses &string[0] to get write-access to the entire string buffer
-    // which may be assuming that the chars are all contiguous, but it seems
-    // to work and saves us the hassle of using a temporary
-    // std::vector<char>.
-    const int result = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, &utf8[0],
-                                           chars_required, NULL, NULL);
-    if (result != chars_required) {
-        // UTF-16 to UTF-8 should be lossless, so we don't expect this to fail.
-        fatal("WideCharToMultiByte failed conversion: %d, GetLastError: %lu",
-              result, GetLastError());
-    }
-
-    return utf8;
-}
-
 // Constructor for helper class to convert wmain() UTF-16 args to UTF-8 to
 // be passed to main().
 NarrowArgs::NarrowArgs(const int argc, wchar_t** const argv) {
     narrow_args = new char*[argc + 1];
 
     for (int i = 0; i < argc; ++i) {
-        narrow_args[i] = strdup(narrow(argv[i]).c_str());
+        std::string arg_narrow;
+        if (!android::base::WideToUTF8(argv[i], &arg_narrow)) {
+            fatal_errno("cannot convert argument from UTF-16 to UTF-8");
+        }
+        narrow_args[i] = strdup(arg_narrow.c_str());
     }
     narrow_args[argc] = nullptr;   // terminate
 }
@@ -3637,20 +3483,24 @@
 }
 
 int unix_open(const char* path, int options, ...) {
+    std::wstring path_wide;
+    if (!android::base::UTF8ToWide(path, &path_wide)) {
+        return -1;
+    }
     if ((options & O_CREAT) == 0) {
-        return _wopen(widen(path).c_str(), options);
+        return _wopen(path_wide.c_str(), options);
     } else {
         int      mode;
         va_list  args;
         va_start(args, options);
         mode = va_arg(args, int);
         va_end(args);
-        return _wopen(widen(path).c_str(), options, mode);
+        return _wopen(path_wide.c_str(), options, mode);
     }
 }
 
 // Version of stat() that takes a UTF-8 path.
-int adb_stat(const char* f, struct adb_stat* s) {
+int adb_stat(const char* path, struct adb_stat* s) {
 #pragma push_macro("wstat")
 // This definition of wstat seems to be missing from <sys/stat.h>.
 #if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
@@ -3663,17 +3513,27 @@
 // <sys/stat.h> has a function prototype for wstat() that should be available.
 #endif
 
-    return wstat(widen(f).c_str(), s);
+    std::wstring path_wide;
+    if (!android::base::UTF8ToWide(path, &path_wide)) {
+        return -1;
+    }
+
+    return wstat(path_wide.c_str(), s);
 
 #pragma pop_macro("wstat")
 }
 
 // Version of opendir() that takes a UTF-8 path.
-DIR* adb_opendir(const char* name) {
+DIR* adb_opendir(const char* path) {
+    std::wstring path_wide;
+    if (!android::base::UTF8ToWide(path, &path_wide)) {
+        return nullptr;
+    }
+
     // Just cast _WDIR* to DIR*. This doesn't work if the caller reads any of
     // the fields, but right now all the callers treat the structure as
     // opaque.
-    return reinterpret_cast<DIR*>(_wopendir(widen(name).c_str()));
+    return reinterpret_cast<DIR*>(_wopendir(path_wide.c_str()));
 }
 
 // Version of readdir() that returns UTF-8 paths.
@@ -3683,8 +3543,12 @@
     if (went == nullptr) {
         return nullptr;
     }
+
     // Convert from UTF-16 to UTF-8.
-    const std::string name_utf8(narrow(went->d_name));
+    std::string name_utf8;
+    if (!android::base::WideToUTF8(went->d_name, &name_utf8)) {
+        return nullptr;
+    }
 
     // Cast the _wdirent* to dirent* and overwrite the d_name field (which has
     // space for UTF-16 wchar_t's) with UTF-8 char's.
@@ -3716,7 +3580,10 @@
 
 // Version of unlink() that takes a UTF-8 path.
 int adb_unlink(const char* path) {
-    const std::wstring wpath(widen(path));
+    std::wstring wpath;
+    if (!android::base::UTF8ToWide(path, &wpath)) {
+        return -1;
+    }
 
     int  rc = _wunlink(wpath.c_str());
 
@@ -3732,29 +3599,47 @@
 
 // Version of mkdir() that takes a UTF-8 path.
 int adb_mkdir(const std::string& path, int mode) {
-    return _wmkdir(widen(path.c_str()).c_str());
+    std::wstring path_wide;
+    if (!android::base::UTF8ToWide(path, &path_wide)) {
+        return -1;
+    }
+
+    return _wmkdir(path_wide.c_str());
 }
 
 // Version of utime() that takes a UTF-8 path.
 int adb_utime(const char* path, struct utimbuf* u) {
+    std::wstring path_wide;
+    if (!android::base::UTF8ToWide(path, &path_wide)) {
+        return -1;
+    }
+
     static_assert(sizeof(struct utimbuf) == sizeof(struct _utimbuf),
         "utimbuf and _utimbuf should be the same size because they both "
         "contain the same types, namely time_t");
-    return _wutime(widen(path).c_str(), reinterpret_cast<struct _utimbuf*>(u));
+    return _wutime(path_wide.c_str(), reinterpret_cast<struct _utimbuf*>(u));
 }
 
 // Version of chmod() that takes a UTF-8 path.
 int adb_chmod(const char* path, int mode) {
-    return _wchmod(widen(path).c_str(), mode);
+    std::wstring path_wide;
+    if (!android::base::UTF8ToWide(path, &path_wide)) {
+        return -1;
+    }
+
+    return _wchmod(path_wide.c_str(), mode);
 }
 
 // Internal helper function to write UTF-8 bytes to a console. Returns -1
 // on error.
 static int _console_write_utf8(const char* buf, size_t size, FILE* stream,
                                HANDLE console) {
-    // Convert from UTF-8 to UTF-16.
+    std::wstring output;
+
+    // Try to convert from data that might be UTF-8 to UTF-16, ignoring errors.
+    // Data might not be UTF-8 if the user cat's random data, runs dmesg, etc.
     // This could throw std::bad_alloc.
-    const std::wstring output(widen(buf, size));
+    (void)android::base::UTF8ToWide(buf, size, &output);
 
     // Note that this does not do \n => \r\n translation because that
     // doesn't seem necessary for the Windows console. For the Windows
@@ -3904,8 +3789,18 @@
 
 // Version of fopen() that takes a UTF-8 filename and can access a file with
 // a Unicode filename.
-FILE* adb_fopen(const char* f, const char* m) {
-    return _wfopen(widen(f).c_str(), widen(m).c_str());
+FILE* adb_fopen(const char* path, const char* mode) {
+    std::wstring path_wide;
+    if (!android::base::UTF8ToWide(path, &path_wide)) {
+        return nullptr;
+    }
+
+    std::wstring mode_wide;
+    if (!android::base::UTF8ToWide(mode, &mode_wide)) {
+        return nullptr;
+    }
+
+    return _wfopen(path_wide.c_str(), mode_wide.c_str());
 }
 
 // Return a lowercase version of the argument. Uses C Runtime tolower() on
@@ -3936,7 +3831,7 @@
 // currently updated if putenv, setenv, unsetenv are called. Note that no
 // thread synchronization is done, but we're called early enough in
 // single-threaded startup that things work ok.
-static std::unordered_map<std::string, char*> g_environ_utf8;
+static auto& g_environ_utf8 = *new std::unordered_map<std::string, char*>();
 
 // Make sure that shadow UTF-8 environment variables are setup.
 static void _ensure_env_setup() {
@@ -3965,15 +3860,27 @@
             continue;
         }
 
+        // If we encounter an error converting UTF-16, don't error-out on account of a single env
+        // var because the program might never even read this particular variable.
+        std::string name_utf8;
+        if (!android::base::WideToUTF8(*env, equal - *env, &name_utf8)) {
+            continue;
+        }
+
         // Store lowercase name so that we can do case-insensitive searches.
-        const std::string name_utf8(ToLower(narrow(
-                std::wstring(*env, equal - *env))));
-        char* const value_utf8 = strdup(narrow(equal + 1).c_str());
+        name_utf8 = ToLower(name_utf8);
+
+        std::string value_utf8;
+        if (!android::base::WideToUTF8(equal + 1, &value_utf8)) {
+            continue;
+        }
+
+        char* const value_dup = strdup(value_utf8.c_str());
 
         // Don't overwrite a previus env var with the same name. In reality,
         // the system probably won't let two env vars with the same name exist
         // in _wenviron.
-        g_environ_utf8.insert({name_utf8, value_utf8});
+        g_environ_utf8.insert({name_utf8, value_dup});
     }
 }
 
@@ -3999,10 +3906,15 @@
         return nullptr;
     }
 
-    const std::string buf_utf8(narrow(wbuf));
+    std::string buf_utf8;
+    const bool narrow_result = android::base::WideToUTF8(wbuf, &buf_utf8);
     free(wbuf);
     wbuf = nullptr;
 
+    if (!narrow_result) {
+        return nullptr;
+    }
+
     // If size was specified, make sure all the chars will fit.
     if (size != 0) {
         if (size < static_cast<int>(buf_utf8.length() + 1)) {
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 4066889..2f18f20 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -38,8 +38,8 @@
 
 static void transport_unref(atransport *t);
 
-static std::list<atransport*> transport_list;
-static std::list<atransport*> pending_list;
+static auto& transport_list = *new std::list<atransport*>();
+static auto& pending_list = *new std::list<atransport*>();
 
 ADB_MUTEX_DEFINE( transport_lock );
 
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index c633f7f..0358b62 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -81,8 +81,8 @@
     pthread_t reaper_thread = 0;
 };
 
-static std::mutex g_usb_handles_mutex;
-static std::list<usb_handle*> g_usb_handles;
+static auto& g_usb_handles_mutex = *new std::mutex();
+static auto& g_usb_handles = *new std::list<usb_handle*>();
 
 static int is_known_device(const char* dev_name) {
     std::lock_guard<std::mutex> lock(g_usb_handles_mutex);
diff --git a/adb/usb_windows.cpp b/adb/usb_windows.cpp
index d811b24..8d3501e 100644
--- a/adb/usb_windows.cpp
+++ b/adb/usb_windows.cpp
@@ -55,7 +55,7 @@
   ADBAPIHANDLE  adb_write_pipe;
 
   /// Interface name
-  char*         interface_name;
+  wchar_t*      interface_name;
 
   /// Mask for determining when to use zero length packets
   unsigned zero_mask;
@@ -74,11 +74,11 @@
 ADB_MUTEX_DEFINE( usb_lock );
 
 /// Checks if there is opened usb handle in handle_list for this device.
-int known_device(const char* dev_name);
+int known_device(const wchar_t* dev_name);
 
 /// Checks if there is opened usb handle in handle_list for this device.
 /// usb_lock mutex must be held before calling this routine.
-int known_device_locked(const char* dev_name);
+int known_device_locked(const wchar_t* dev_name);
 
 /// Registers opened usb handle (adds it to handle_list).
 int register_new_device(usb_handle* handle);
@@ -118,7 +118,7 @@
 /// Closes opened usb handle
 int usb_close(usb_handle* handle);
 
-int known_device_locked(const char* dev_name) {
+int known_device_locked(const wchar_t* dev_name) {
   usb_handle* usb;
 
   if (NULL != dev_name) {
@@ -126,7 +126,7 @@
     for(usb = handle_list.next; usb != &handle_list; usb = usb->next) {
       // In Windows names are not case sensetive!
       if((NULL != usb->interface_name) &&
-         (0 == stricmp(usb->interface_name, dev_name))) {
+         (0 == wcsicmp(usb->interface_name, dev_name))) {
         return 1;
       }
     }
@@ -135,7 +135,7 @@
   return 0;
 }
 
-int known_device(const char* dev_name) {
+int known_device(const wchar_t* dev_name) {
   int ret = 0;
 
   if (NULL != dev_name) {
@@ -316,17 +316,16 @@
   AdbGetInterfaceName(ret->adb_interface,
                       NULL,
                       &name_len,
-                      true);
+                      false);
   if (0 == name_len) {
     D("AdbGetInterfaceName returned name length of zero: %s",
       SystemErrorCodeToString(GetLastError()).c_str());
     goto fail;
   }
 
-  ret->interface_name = (char*)malloc(name_len);
+  ret->interface_name = (wchar_t*)malloc(name_len * sizeof(ret->interface_name[0]));
   if (NULL == ret->interface_name) {
-    D("Could not allocate %lu bytes for interface_name: %s", name_len,
-      strerror(errno));
+    D("Could not allocate %lu characters for interface_name: %s", name_len, strerror(errno));
     goto fail;
   }
 
@@ -334,7 +333,7 @@
   if (!AdbGetInterfaceName(ret->adb_interface,
                            ret->interface_name,
                            &name_len,
-                           true)) {
+                           false)) {
     D("AdbGetInterfaceName failed: %s",
       SystemErrorCodeToString(GetLastError()).c_str());
     goto fail;
@@ -581,12 +580,10 @@
 }
 
 void find_devices() {
-        usb_handle* handle = NULL;
+  usb_handle* handle = NULL;
   char entry_buffer[2048];
-  char interf_name[2048];
   AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
   unsigned long entry_buffer_size = sizeof(entry_buffer);
-  char* copy_name;
 
   // Enumerate all present and active interfaces.
   ADBAPIHANDLE enum_handle =
@@ -599,25 +596,21 @@
   }
 
   while (AdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) {
-    // TODO: FIXME - temp hack converting wchar_t into char.
-    // It would be better to change AdbNextInterface so it will return
-    // interface name as single char string.
-    const wchar_t* wchar_name = next_interface->device_name;
-    for(copy_name = interf_name;
-        L'\0' != *wchar_name;
-        wchar_name++, copy_name++) {
-      *copy_name = (char)(*wchar_name);
-    }
-    *copy_name = '\0';
-
     // Lets see if we already have this device in the list
-    if (!known_device(interf_name)) {
+    if (!known_device(next_interface->device_name)) {
       // This seems to be a new device. Open it!
-        handle = do_usb_open(next_interface->device_name);
-        if (NULL != handle) {
+      handle = do_usb_open(next_interface->device_name);
+      if (NULL != handle) {
         // Lets see if this interface (device) belongs to us
         if (recognized_device(handle)) {
-          D("adding a new device %s", interf_name);
+          D("adding a new device %ls", next_interface->device_name);
+
+          // We don't request a wchar_t string from AdbGetSerialNumber() because of a bug in
+          // adb_winusb_interface.cpp:CopyMemory(buffer, ser_num->bString, bytes_written) where the
+          // last parameter should be (str_len * sizeof(wchar_t)). The bug reads 2 bytes past the
+          // end of a stack buffer in the best case, and in the unlikely case of a long serial
+          // number, it will read 2 bytes past the end of a heap allocation. This doesn't affect the
+          // resulting string, but we should avoid the bad reads in the first place.
           char serial_number[512];
           unsigned long serial_number_len = sizeof(serial_number);
           if (AdbGetSerialNumber(handle->adb_interface,
@@ -628,7 +621,7 @@
             if (register_new_device(handle)) {
               register_usb_transport(handle, serial_number, NULL, 1);
             } else {
-              D("register_new_device failed for %s", interf_name);
+              D("register_new_device failed for %ls", next_interface->device_name);
               usb_cleanup_handle(handle);
               free(handle);
             }
diff --git a/base/Android.mk b/base/Android.mk
index 613636b..cba70d4 100644
--- a/base/Android.mk
+++ b/base/Android.mk
@@ -23,6 +23,9 @@
     strings.cpp \
     test_utils.cpp \
 
+libbase_windows_src_files := \
+    utf8.cpp \
+
 libbase_test_src_files := \
     file_test.cpp \
     logging_test.cpp \
@@ -31,19 +34,31 @@
     strings_test.cpp \
     test_main.cpp \
 
+libbase_test_windows_src_files := \
+    utf8_test.cpp \
+
 libbase_cppflags := \
     -Wall \
     -Wextra \
     -Werror \
 
+libbase_linux_cppflags := \
+    -Wexit-time-destructors \
+
+libbase_darwin_cppflags := \
+    -Wexit-time-destructors \
+
 # Device
 # ------------------------------------------------------------------------------
 include $(CLEAR_VARS)
 LOCAL_MODULE := libbase
 LOCAL_CLANG := true
 LOCAL_SRC_FILES := $(libbase_src_files)
+LOCAL_SRC_FILES_darwin := $(libbase_darwin_src_files)
+LOCAL_SRC_FILES_linux := $(libbase_linux_src_files)
+LOCAL_SRC_FILES_windows := $(libbase_windows_src_files)
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CPPFLAGS := $(libbase_cppflags)
+LOCAL_CPPFLAGS := $(libbase_cppflags) $(libbase_linux_cppflags)
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_STATIC_LIBRARIES := libcutils
 LOCAL_MULTILIB := both
@@ -64,8 +79,13 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := libbase
 LOCAL_SRC_FILES := $(libbase_src_files)
+LOCAL_SRC_FILES_darwin := $(libbase_darwin_src_files)
+LOCAL_SRC_FILES_linux := $(libbase_linux_src_files)
+LOCAL_SRC_FILES_windows := $(libbase_windows_src_files)
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_CPPFLAGS := $(libbase_cppflags)
+LOCAL_CPPFLAGS_darwin := $(libbase_darwin_cppflags)
+LOCAL_CPPFLAGS_linux := $(libbase_linux_cppflags)
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_STATIC_LIBRARIES := libcutils
 LOCAL_MULTILIB := both
@@ -88,6 +108,9 @@
 LOCAL_MODULE := libbase_test
 LOCAL_CLANG := true
 LOCAL_SRC_FILES := $(libbase_test_src_files)
+LOCAL_SRC_FILES_darwin := $(libbase_test_darwin_src_files)
+LOCAL_SRC_FILES_linux := $(libbase_test_linux_src_files)
+LOCAL_SRC_FILES_windows := $(libbase_test_windows_src_files)
 LOCAL_C_INCLUDES := $(LOCAL_PATH)
 LOCAL_CPPFLAGS := $(libbase_cppflags)
 LOCAL_SHARED_LIBRARIES := libbase
@@ -100,6 +123,9 @@
 LOCAL_MODULE := libbase_test
 LOCAL_MODULE_HOST_OS := darwin linux windows
 LOCAL_SRC_FILES := $(libbase_test_src_files)
+LOCAL_SRC_FILES_darwin := $(libbase_test_darwin_src_files)
+LOCAL_SRC_FILES_linux := $(libbase_test_linux_src_files)
+LOCAL_SRC_FILES_windows := $(libbase_test_windows_src_files)
 LOCAL_C_INCLUDES := $(LOCAL_PATH)
 LOCAL_CPPFLAGS := $(libbase_cppflags)
 LOCAL_SHARED_LIBRARIES := libbase
diff --git a/base/file.cpp b/base/file.cpp
index 3468dcf..7b5e7b1 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -24,6 +24,7 @@
 #include <string>
 
 #include "base/macros.h"  // For TEMP_FAILURE_RETRY on Darwin.
+#include "base/utf8.h"
 #define LOG_TAG "base.file"
 #include "cutils/log.h"
 #include "utils/Compat.h"
@@ -35,6 +36,9 @@
 namespace android {
 namespace base {
 
+// Versions of standard library APIs that support UTF-8 strings.
+using namespace android::base::utf8;
+
 bool ReadFdToString(int fd, std::string* content) {
   content->clear();
 
diff --git a/base/include/base/unique_fd.h b/base/include/base/unique_fd.h
new file mode 100644
index 0000000..4117775
--- /dev/null
+++ b/base/include/base/unique_fd.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_BASE_UNIQUE_FD_H
+#define ANDROID_BASE_UNIQUE_FD_H
+
+#include <unistd.h>
+
+#include <base/macros.h>
+
+/* Container for a file descriptor that automatically closes the descriptor as
+ * it goes out of scope.
+ *
+ *      unique_fd ufd(open("/some/path", "r"));
+ *
+ *      if (ufd.get() < 0) // invalid descriptor
+ *          return error;
+ *
+ *      // Do something useful
+ *
+ *      return 0; // descriptor is closed here
+ */
+namespace android {
+namespace base {
+
+class unique_fd final {
+ public:
+  unique_fd() : value_(-1) {}
+
+  explicit unique_fd(int value) : value_(value) {}
+  ~unique_fd() { clear(); }
+
+  unique_fd(unique_fd&& other) : value_(other.release()) {}
+  unique_fd& operator = (unique_fd&& s) {
+    reset(s.release());
+    return *this;
+  }
+
+  void reset(int new_value) {
+    if (value_ >= 0)
+      close(value_);
+    value_ = new_value;
+  }
+
+  void clear() {
+    reset(-1);
+  }
+
+  int get() const { return value_; }
+
+  int release() {
+    int ret = value_;
+    value_ = -1;
+    return ret;
+  }
+
+ private:
+  int value_;
+
+  DISALLOW_COPY_AND_ASSIGN(unique_fd);
+};
+
+}  // namespace base
+}  // namespace android
+
+#endif // ANDROID_BASE_UNIQUE_FD_H
diff --git a/base/include/base/utf8.h b/base/include/base/utf8.h
new file mode 100755
index 0000000..3b0ed0a
--- /dev/null
+++ b/base/include/base/utf8.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BASE_UTF8_H
+#define BASE_UTF8_H
+
+#ifdef _WIN32
+#include <string>
+#else
+// Bring in prototypes for standard APIs so that we can import them into the utf8 namespace.
+#include <fcntl.h>      // open
+#include <unistd.h>     // unlink
+#endif
+
+namespace android {
+namespace base {
+
+// Only available on Windows because this is only needed on Windows.
+#ifdef _WIN32
+// Convert size number of UTF-16 wchar_t's to UTF-8. Returns whether the
+// conversion was done successfully.
+bool WideToUTF8(const wchar_t* utf16, const size_t size, std::string* utf8);
+
+// Convert a NULL-terminated string of UTF-16 characters to UTF-8. Returns
+// whether the conversion was done successfully.
+bool WideToUTF8(const wchar_t* utf16, std::string* utf8);
+
+// Convert a UTF-16 std::wstring (including any embedded NULL characters) to
+// UTF-8. Returns whether the conversion was done successfully.
+bool WideToUTF8(const std::wstring& utf16, std::string* utf8);
+
+// Convert size number of UTF-8 char's to UTF-16. Returns whether the conversion
+// was done successfully.
+bool UTF8ToWide(const char* utf8, const size_t size, std::wstring* utf16);
+
+// Convert a NULL-terminated string of UTF-8 characters to UTF-16. Returns
+// whether the conversion was done successfully.
+bool UTF8ToWide(const char* utf8, std::wstring* utf16);
+
+// Convert a UTF-8 std::string (including any embedded NULL characters) to
+// UTF-16. Returns whether the conversion was done successfully.
+bool UTF8ToWide(const std::string& utf8, std::wstring* utf16);
+#endif
+
+// The functions in the utf8 namespace take UTF-8 strings. For Windows, these
+// are wrappers, for non-Windows these just expose existing APIs. To call these
+// functions, use:
+//
+// // anonymous namespace to avoid conflict with existing open(), unlink(), etc.
+// namespace {
+//   // Import functions into anonymous namespace.
+//   using namespace android::base::utf8;
+//
+//   void SomeFunction(const char* name) {
+//     int fd = open(name, ...);  // Calls android::base::utf8::open().
+//     ...
+//     unlink(name);              // Calls android::base::utf8::unlink().
+//   }
+// }
+namespace utf8 {
+
+#ifdef _WIN32
+int open(const char* name, int flags, ...);
+int unlink(const char* name);
+#else
+using ::open;
+using ::unlink;
+#endif
+
+}  // namespace utf8
+}  // namespace base
+}  // namespace android
+
+#endif  // BASE_UTF8_H
diff --git a/base/logging.cpp b/base/logging.cpp
index 248cd06..85f8b3f 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -53,6 +53,33 @@
 #include <unistd.h>
 #endif
 
+// For gettid.
+#if defined(__APPLE__)
+#include "AvailabilityMacros.h"  // For MAC_OS_X_VERSION_MAX_ALLOWED
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <unistd.h>
+#elif defined(__linux__) && !defined(__ANDROID__)
+#include <syscall.h>
+#include <unistd.h>
+#elif defined(_WIN32)
+#include <windows.h>
+#endif
+
+static pid_t GetThreadId() {
+#if defined(__BIONIC__)
+  return gettid();
+#elif defined(__APPLE__)
+  return syscall(SYS_thread_selfid);
+#elif defined(__linux__)
+  return syscall(__NR_gettid);
+#elif defined(_WIN32)
+  return GetCurrentThreadId();
+#endif
+}
+
 namespace {
 #ifndef _WIN32
 using std::mutex;
@@ -127,17 +154,17 @@
 namespace android {
 namespace base {
 
-static mutex logging_lock;
+static auto& logging_lock = *new mutex();
 
 #ifdef __ANDROID__
-static LogFunction gLogger = LogdLogger();
+static auto& gLogger = *new LogFunction(LogdLogger());
 #else
-static LogFunction gLogger = StderrLogger;
+static auto& gLogger = *new LogFunction(StderrLogger);
 #endif
 
 static bool gInitialized = false;
 static LogSeverity gMinimumLogSeverity = INFO;
-static std::unique_ptr<std::string> gProgramInvocationName;
+static auto& gProgramInvocationName = *new std::unique_ptr<std::string>();
 
 LogSeverity GetMinimumLogSeverity() {
   return gMinimumLogSeverity;
@@ -158,7 +185,7 @@
                 "Mismatch in size of log_characters and values in LogSeverity");
   char severity_char = log_characters[severity];
   fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationName(),
-          severity_char, getpid(), gettid(), file, line, message);
+          severity_char, getpid(), GetThreadId(), file, line, message);
 }
 
 
diff --git a/base/utf8.cpp b/base/utf8.cpp
new file mode 100755
index 0000000..99f0f54
--- /dev/null
+++ b/base/utf8.cpp
@@ -0,0 +1,187 @@
+/*
+ * 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 <windows.h>
+
+#include "base/utf8.h"
+
+#include <fcntl.h>
+
+#include <string>
+
+#include "base/logging.h"
+
+namespace android {
+namespace base {
+
+// Helper to set errno based on GetLastError() after WideCharToMultiByte()/MultiByteToWideChar().
+static void SetErrnoFromLastError() {
+  switch (GetLastError()) {
+    case ERROR_NO_UNICODE_TRANSLATION:
+      errno = EILSEQ;
+      break;
+    default:
+      errno = EINVAL;
+      break;
+  }
+}
+
+bool WideToUTF8(const wchar_t* utf16, const size_t size, std::string* utf8) {
+  utf8->clear();
+
+  if (size == 0) {
+    return true;
+  }
+
+  // TODO: Consider using std::wstring_convert once libcxx is supported on
+  // Windows.
+
+  // Only Vista or later has this flag that causes WideCharToMultiByte() to
+  // return an error on invalid characters.
+  const DWORD flags =
+#if (WINVER >= 0x0600)
+    WC_ERR_INVALID_CHARS;
+#else
+    0;
+#endif
+
+  const int chars_required = WideCharToMultiByte(CP_UTF8, flags, utf16, size,
+                                                 NULL, 0, NULL, NULL);
+  if (chars_required <= 0) {
+    SetErrnoFromLastError();
+    return false;
+  }
+
+  // This could potentially throw a std::bad_alloc exception.
+  utf8->resize(chars_required);
+
+  const int result = WideCharToMultiByte(CP_UTF8, flags, utf16, size,
+                                         &(*utf8)[0], chars_required, NULL,
+                                         NULL);
+  if (result != chars_required) {
+    SetErrnoFromLastError();
+    CHECK_LE(result, chars_required) << "WideCharToMultiByte wrote " << result
+        << " chars to buffer of " << chars_required << " chars";
+    utf8->clear();
+    return false;
+  }
+
+  return true;
+}
+
+bool WideToUTF8(const wchar_t* utf16, std::string* utf8) {
+  // Compute string length of NULL-terminated string with wcslen().
+  return WideToUTF8(utf16, wcslen(utf16), utf8);
+}
+
+bool WideToUTF8(const std::wstring& utf16, std::string* utf8) {
+  // Use the stored length of the string which allows embedded NULL characters
+  // to be converted.
+  return WideToUTF8(utf16.c_str(), utf16.length(), utf8);
+}
+
+// Internal helper function that takes MultiByteToWideChar() flags.
+static bool UTF8ToWideWithFlags(const char* utf8, const size_t size, std::wstring* utf16,
+                                const DWORD flags) {
+  utf16->clear();
+
+  if (size == 0) {
+    return true;
+  }
+
+  // TODO: Consider using std::wstring_convert once libcxx is supported on
+  // Windows.
+  const int chars_required = MultiByteToWideChar(CP_UTF8, flags, utf8, size,
+                                                 NULL, 0);
+  if (chars_required <= 0) {
+    SetErrnoFromLastError();
+    return false;
+  }
+
+  // This could potentially throw a std::bad_alloc exception.
+  utf16->resize(chars_required);
+
+  const int result = MultiByteToWideChar(CP_UTF8, flags, utf8, size,
+                                         &(*utf16)[0], chars_required);
+  if (result != chars_required) {
+    SetErrnoFromLastError();
+    CHECK_LE(result, chars_required) << "MultiByteToWideChar wrote " << result
+        << " chars to buffer of " << chars_required << " chars";
+    utf16->clear();
+    return false;
+  }
+
+  return true;
+}
+
+bool UTF8ToWide(const char* utf8, const size_t size, std::wstring* utf16) {
+  // If strictly interpreting as UTF-8 succeeds, return success.
+  if (UTF8ToWideWithFlags(utf8, size, utf16, MB_ERR_INVALID_CHARS)) {
+    return true;
+  }
+
+  const int saved_errno = errno;
+
+  // Fallback to non-strict interpretation, allowing invalid characters and
+  // converting as best as possible, and return false to signify a problem.
+  (void)UTF8ToWideWithFlags(utf8, size, utf16, 0);
+  errno = saved_errno;
+  return false;
+}
+
+bool UTF8ToWide(const char* utf8, std::wstring* utf16) {
+  // Compute string length of NULL-terminated string with strlen().
+  return UTF8ToWide(utf8, strlen(utf8), utf16);
+}
+
+bool UTF8ToWide(const std::string& utf8, std::wstring* utf16) {
+  // Use the stored length of the string which allows embedded NULL characters
+  // to be converted.
+  return UTF8ToWide(utf8.c_str(), utf8.length(), utf16);
+}
+
+// Versions of standard library APIs that support UTF-8 strings.
+namespace utf8 {
+
+int open(const char* name, int flags, ...) {
+  std::wstring name_utf16;
+  if (!UTF8ToWide(name, &name_utf16)) {
+    return -1;
+  }
+
+  int mode = 0;
+  if ((flags & O_CREAT) != 0) {
+    va_list args;
+    va_start(args, flags);
+    mode = va_arg(args, int);
+    va_end(args);
+  }
+
+  return _wopen(name_utf16.c_str(), flags, mode);
+}
+
+int unlink(const char* name) {
+  std::wstring name_utf16;
+  if (!UTF8ToWide(name, &name_utf16)) {
+    return -1;
+  }
+
+  return _wunlink(name_utf16.c_str());
+}
+
+}  // namespace utf8
+}  // namespace base
+}  // namespace android
diff --git a/base/utf8_test.cpp b/base/utf8_test.cpp
new file mode 100755
index 0000000..13f6431
--- /dev/null
+++ b/base/utf8_test.cpp
@@ -0,0 +1,412 @@
+/*
+* Copyright (C) 2015 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "base/utf8.h"
+
+#include <gtest/gtest.h>
+
+#include "base/macros.h"
+
+namespace android {
+namespace base {
+
+TEST(UTFStringConversionsTest, ConvertInvalidUTF8) {
+  std::wstring wide;
+
+  errno = 0;
+
+  // Standalone \xa2 is an invalid UTF-8 sequence, so this should return an
+  // error. Concatenate two C/C++ literal string constants to prevent the
+  // compiler from giving an error about "\xa2af" containing a "hex escape
+  // sequence out of range".
+  EXPECT_FALSE(android::base::UTF8ToWide("before\xa2" "after", &wide));
+
+  EXPECT_EQ(EILSEQ, errno);
+
+  // Even if an invalid character is encountered, UTF8ToWide() should still do
+  // its best to convert the rest of the string. sysdeps_win32.cpp:
+  // _console_write_utf8() depends on this behavior.
+  //
+  // Thus, we verify that the valid characters are converted, but we ignore the
+  // specific replacement character that UTF8ToWide() may replace the invalid
+  // UTF-8 characters with because we want to allow that to change if the
+  // implementation changes.
+  EXPECT_EQ(0, wide.find(L"before"));
+  const wchar_t after_wide[] = L"after";
+  EXPECT_EQ(wide.length() - (arraysize(after_wide) - 1), wide.find(after_wide));
+}
+
+// Below is adapted from https://chromium.googlesource.com/chromium/src/+/master/base/strings/utf_string_conversions_unittest.cc
+
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The tests below from utf_string_conversions_unittest.cc check for this
+// preprocessor symbol, so define it, as it is appropriate for Windows.
+#define WCHAR_T_IS_UTF16
+static_assert(sizeof(wchar_t) == 2, "wchar_t is not 2 bytes");
+
+// The tests below from utf_string_conversions_unittest.cc call versions of
+// UTF8ToWide() and WideToUTF8() that don't return success/failure, so these are
+// stub implementations with that signature. These are just for testing and
+// should not be moved to base because they assert/expect no errors which is
+// probably not a good idea (or at least it is something that should be left
+// up to the caller, not a base library).
+
+static std::wstring UTF8ToWide(const std::string& utf8) {
+  std::wstring utf16;
+  EXPECT_TRUE(UTF8ToWide(utf8, &utf16));
+  return utf16;
+}
+
+static std::string WideToUTF8(const std::wstring& utf16) {
+  std::string utf8;
+  EXPECT_TRUE(WideToUTF8(utf16, &utf8));
+  return utf8;
+}
+
+namespace {
+
+const wchar_t* const kConvertRoundtripCases[] = {
+  L"Google Video",
+  // "网页 图片 资讯更多 »"
+  L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb",
+  //  "Παγκόσμιος Ιστός"
+  L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+  L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2",
+  // "Поиск страниц на русском"
+  L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442"
+  L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430"
+  L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c",
+  // "전체서비스"
+  L"\xc804\xccb4\xc11c\xbe44\xc2a4",
+
+  // Test characters that take more than 16 bits. This will depend on whether
+  // wchar_t is 16 or 32 bits.
+#if defined(WCHAR_T_IS_UTF16)
+  L"\xd800\xdf00",
+  // ?????  (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
+  L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44",
+#elif defined(WCHAR_T_IS_UTF32)
+  L"\x10300",
+  // ?????  (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
+  L"\x11d40\x11d41\x11d42\x11d43\x11d44",
+#endif
+};
+
+}  // namespace
+
+TEST(UTFStringConversionsTest, ConvertUTF8AndWide) {
+  // we round-trip all the wide strings through UTF-8 to make sure everything
+  // agrees on the conversion. This uses the stream operators to test them
+  // simultaneously.
+  for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
+    std::ostringstream utf8;
+    utf8 << WideToUTF8(kConvertRoundtripCases[i]);
+    std::wostringstream wide;
+    wide << UTF8ToWide(utf8.str());
+
+    EXPECT_EQ(kConvertRoundtripCases[i], wide.str());
+  }
+}
+
+TEST(UTFStringConversionsTest, ConvertUTF8AndWideEmptyString) {
+  // An empty std::wstring should be converted to an empty std::string,
+  // and vice versa.
+  std::wstring wempty;
+  std::string empty;
+  EXPECT_EQ(empty, WideToUTF8(wempty));
+  EXPECT_EQ(wempty, UTF8ToWide(empty));
+}
+
+TEST(UTFStringConversionsTest, ConvertUTF8ToWide) {
+  struct UTF8ToWideCase {
+    const char* utf8;
+    const wchar_t* wide;
+    bool success;
+  } convert_cases[] = {
+    // Regular UTF-8 input.
+    {"\xe4\xbd\xa0\xe5\xa5\xbd", L"\x4f60\x597d", true},
+    // Non-character is passed through.
+    {"\xef\xbf\xbfHello", L"\xffffHello", true},
+    // Truncated UTF-8 sequence.
+    {"\xe4\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false},
+    // Truncated off the end.
+    {"\xe5\xa5\xbd\xe4\xa0", L"\x597d\xfffd", false},
+    // Non-shortest-form UTF-8.
+    {"\xf0\x84\xbd\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false},
+    // This UTF-8 character decodes to a UTF-16 surrogate, which is illegal.
+    // Note that for whatever reason, this test fails on Windows XP.
+    {"\xed\xb0\x80", L"\xfffd", false},
+    // Non-BMP characters. The second is a non-character regarded as valid.
+    // The result will either be in UTF-16 or UTF-32.
+#if defined(WCHAR_T_IS_UTF16)
+    {"A\xF0\x90\x8C\x80z", L"A\xd800\xdf00z", true},
+    {"A\xF4\x8F\xBF\xBEz", L"A\xdbff\xdffez", true},
+#elif defined(WCHAR_T_IS_UTF32)
+    {"A\xF0\x90\x8C\x80z", L"A\x10300z", true},
+    {"A\xF4\x8F\xBF\xBEz", L"A\x10fffez", true},
+#endif
+  };
+
+  for (size_t i = 0; i < arraysize(convert_cases); i++) {
+    std::wstring converted;
+    errno = 0;
+    const bool success = UTF8ToWide(convert_cases[i].utf8,
+                                    strlen(convert_cases[i].utf8),
+                                    &converted);
+    EXPECT_EQ(convert_cases[i].success, success);
+    // The original test always compared expected and converted, but don't do
+    // that because our implementation of UTF8ToWide() does not guarantee to
+    // produce the same output in error situations.
+    if (success) {
+      std::wstring expected(convert_cases[i].wide);
+      EXPECT_EQ(expected, converted);
+    } else {
+      EXPECT_EQ(EILSEQ, errno);
+    }
+  }
+
+  // Manually test an embedded NULL.
+  std::wstring converted;
+  EXPECT_TRUE(UTF8ToWide("\00Z\t", 3, &converted));
+  ASSERT_EQ(3U, converted.length());
+  EXPECT_EQ(static_cast<wchar_t>(0), converted[0]);
+  EXPECT_EQ('Z', converted[1]);
+  EXPECT_EQ('\t', converted[2]);
+
+  // Make sure that conversion replaces, not appends.
+  EXPECT_TRUE(UTF8ToWide("B", 1, &converted));
+  ASSERT_EQ(1U, converted.length());
+  EXPECT_EQ('B', converted[0]);
+}
+
+#if defined(WCHAR_T_IS_UTF16)
+// This test is only valid when wchar_t == UTF-16.
+TEST(UTFStringConversionsTest, ConvertUTF16ToUTF8) {
+  struct WideToUTF8Case {
+    const wchar_t* utf16;
+    const char* utf8;
+    bool success;
+  } convert_cases[] = {
+    // Regular UTF-16 input.
+    {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true},
+    // Test a non-BMP character.
+    {L"\xd800\xdf00", "\xF0\x90\x8C\x80", true},
+    // Non-characters are passed through.
+    {L"\xffffHello", "\xEF\xBF\xBFHello", true},
+    {L"\xdbff\xdffeHello", "\xF4\x8F\xBF\xBEHello", true},
+    // The first character is a truncated UTF-16 character.
+    // Note that for whatever reason, this test fails on Windows XP.
+    {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd",
+#if (WINVER >= 0x0600)
+    // Only Vista and later has a new API/flag that correctly returns false.
+    false
+#else
+    true
+#endif
+    },
+    // Truncated at the end.
+    // Note that for whatever reason, this test fails on Windows XP.
+    {L"\x597d\xd800", "\xe5\xa5\xbd\xef\xbf\xbd",
+#if (WINVER >= 0x0600)
+    // Only Vista and later has a new API/flag that correctly returns false.
+    false
+#else
+    true
+#endif
+    },
+  };
+
+  for (size_t i = 0; i < arraysize(convert_cases); i++) {
+    std::string converted;
+    errno = 0;
+    const bool success = WideToUTF8(convert_cases[i].utf16,
+                                    wcslen(convert_cases[i].utf16),
+                                    &converted);
+    EXPECT_EQ(convert_cases[i].success, success);
+    // The original test always compared expected and converted, but don't do
+    // that because our implementation of WideToUTF8() does not guarantee to
+    // produce the same output in error situations.
+    if (success) {
+      std::string expected(convert_cases[i].utf8);
+      EXPECT_EQ(expected, converted);
+    } else {
+      EXPECT_EQ(EILSEQ, errno);
+    }
+  }
+}
+
+#elif defined(WCHAR_T_IS_UTF32)
+// This test is only valid when wchar_t == UTF-32.
+TEST(UTFStringConversionsTest, ConvertUTF32ToUTF8) {
+  struct WideToUTF8Case {
+    const wchar_t* utf32;
+    const char* utf8;
+    bool success;
+  } convert_cases[] = {
+    // Regular 16-bit input.
+    {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true},
+    // Test a non-BMP character.
+    {L"A\x10300z", "A\xF0\x90\x8C\x80z", true},
+    // Non-characters are passed through.
+    {L"\xffffHello", "\xEF\xBF\xBFHello", true},
+    {L"\x10fffeHello", "\xF4\x8F\xBF\xBEHello", true},
+    // Invalid Unicode code points.
+    {L"\xfffffffHello", "\xEF\xBF\xBDHello", false},
+    // The first character is a truncated UTF-16 character.
+    {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", false},
+    {L"\xdc01Hello", "\xef\xbf\xbdHello", false},
+  };
+
+  for (size_t i = 0; i < arraysize(convert_cases); i++) {
+    std::string converted;
+    EXPECT_EQ(convert_cases[i].success,
+              WideToUTF8(convert_cases[i].utf32,
+                         wcslen(convert_cases[i].utf32),
+                         &converted));
+    std::string expected(convert_cases[i].utf8);
+    EXPECT_EQ(expected, converted);
+  }
+}
+#endif  // defined(WCHAR_T_IS_UTF32)
+
+// The test below uses these types and functions, so just do enough to get the
+// test running.
+typedef wchar_t char16;
+typedef std::wstring string16;
+
+template<typename T>
+static void* WriteInto(T* t, size_t size) {
+  // std::(w)string::resize() already includes space for a NULL terminator.
+  t->resize(size - 1);
+  return &(*t)[0];
+}
+
+// A stub implementation that calls a helper from above, just to get the test
+// below working. This is just for testing and should not be moved to base
+// because this ignores errors which is probably not a good idea, plus it takes
+// a string16 type which we don't really have.
+static std::string UTF16ToUTF8(const string16& utf16) {
+  return WideToUTF8(utf16);
+}
+
+TEST(UTFStringConversionsTest, ConvertMultiString) {
+  static char16 multi16[] = {
+    'f', 'o', 'o', '\0',
+    'b', 'a', 'r', '\0',
+    'b', 'a', 'z', '\0',
+    '\0'
+  };
+  static char multi[] = {
+    'f', 'o', 'o', '\0',
+    'b', 'a', 'r', '\0',
+    'b', 'a', 'z', '\0',
+    '\0'
+  };
+  string16 multistring16;
+  memcpy(WriteInto(&multistring16, arraysize(multi16)), multi16,
+                   sizeof(multi16));
+  EXPECT_EQ(arraysize(multi16) - 1, multistring16.length());
+  std::string expected;
+  memcpy(WriteInto(&expected, arraysize(multi)), multi, sizeof(multi));
+  EXPECT_EQ(arraysize(multi) - 1, expected.length());
+  const std::string& converted = UTF16ToUTF8(multistring16);
+  EXPECT_EQ(arraysize(multi) - 1, converted.length());
+  EXPECT_EQ(expected, converted);
+}
+
+// The tests below from sys_string_conversions_unittest.cc call SysWideToUTF8()
+// and SysUTF8ToWide(), so these are stub implementations that call the helpers
+// above. These are just for testing and should not be moved to base because
+// they ignore errors which is probably not a good idea.
+
+static std::string SysWideToUTF8(const std::wstring& utf16) {
+  return WideToUTF8(utf16);
+}
+
+static std::wstring SysUTF8ToWide(const std::string& utf8) {
+  return UTF8ToWide(utf8);
+}
+
+// Below is adapted from https://chromium.googlesource.com/chromium/src/+/master/base/strings/sys_string_conversions_unittest.cc
+
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifdef WCHAR_T_IS_UTF32
+static const std::wstring kSysWideOldItalicLetterA = L"\x10300";
+#else
+static const std::wstring kSysWideOldItalicLetterA = L"\xd800\xdf00";
+#endif
+
+TEST(SysStrings, SysWideToUTF8) {
+  EXPECT_EQ("Hello, world", SysWideToUTF8(L"Hello, world"));
+  EXPECT_EQ("\xe4\xbd\xa0\xe5\xa5\xbd", SysWideToUTF8(L"\x4f60\x597d"));
+
+  // >16 bits
+  EXPECT_EQ("\xF0\x90\x8C\x80", SysWideToUTF8(kSysWideOldItalicLetterA));
+
+  // Error case. When Windows finds a UTF-16 character going off the end of
+  // a string, it just converts that literal value to UTF-8, even though this
+  // is invalid.
+  //
+  // This is what XP does, but Vista has different behavior, so we don't bother
+  // verifying it:
+  // EXPECT_EQ("\xE4\xBD\xA0\xED\xA0\x80zyxw",
+  //           SysWideToUTF8(L"\x4f60\xd800zyxw"));
+
+  // Test embedded NULLs.
+  std::wstring wide_null(L"a");
+  wide_null.push_back(0);
+  wide_null.push_back('b');
+
+  std::string expected_null("a");
+  expected_null.push_back(0);
+  expected_null.push_back('b');
+
+  EXPECT_EQ(expected_null, SysWideToUTF8(wide_null));
+}
+
+TEST(SysStrings, SysUTF8ToWide) {
+  EXPECT_EQ(L"Hello, world", SysUTF8ToWide("Hello, world"));
+  EXPECT_EQ(L"\x4f60\x597d", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5\xbd"));
+  // >16 bits
+  EXPECT_EQ(kSysWideOldItalicLetterA, SysUTF8ToWide("\xF0\x90\x8C\x80"));
+
+  // Error case. When Windows finds an invalid UTF-8 character, it just skips
+  // it. This seems weird because it's inconsistent with the reverse conversion.
+  //
+  // This is what XP does, but Vista has different behavior, so we don't bother
+  // verifying it:
+  // EXPECT_EQ(L"\x4f60zyxw", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5zyxw"));
+
+  // Test embedded NULLs.
+  std::string utf8_null("a");
+  utf8_null.push_back(0);
+  utf8_null.push_back('b');
+
+  std::wstring expected_null(L"a");
+  expected_null.push_back(0);
+  expected_null.push_back('b');
+
+  EXPECT_EQ(expected_null, SysUTF8ToWide(utf8_null));
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/crash_reporter/user_collector.cc b/crash_reporter/user_collector.cc
index 56e7bb9..6714f52 100644
--- a/crash_reporter/user_collector.cc
+++ b/crash_reporter/user_collector.cc
@@ -90,9 +90,9 @@
   directory_failure_ = directory_failure;
   filter_in_ = filter_in;
 
-  gid_t groups[] = { AID_ROOT, AID_SYSTEM, AID_DBUS };
+  gid_t groups[] = { AID_ROOT, AID_SYSTEM, AID_DBUS, AID_READPROC };
   if (setgroups(arraysize(groups), groups) != 0) {
-    PLOG(FATAL) << "Unable to set groups to root, system, and dbus";
+    PLOG(FATAL) << "Unable to set groups to root, system, dbus, and readproc";
   }
 }
 
diff --git a/debuggerd/.clang-format b/debuggerd/.clang-format
new file mode 100644
index 0000000..9b7478c
--- /dev/null
+++ b/debuggerd/.clang-format
@@ -0,0 +1,15 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 2
+ContinuationIndentWidth: 2
+PointerAlignment: Left
+TabWidth: 2
+UseTab: Never
+PenaltyExcessCharacter: 32
+
+Cpp11BracedListStyle: false
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 1287fb9..884d4d5 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -34,9 +34,10 @@
 
 #include <log/logger.h>
 
-#include <cutils/sockets.h>
-#include <cutils/properties.h>
 #include <cutils/debugger.h>
+#include <cutils/properties.h>
+#include <cutils/sockets.h>
+#include <nativehelper/ScopedFd.h>
 
 #include <linux/input.h>
 
@@ -336,160 +337,146 @@
 static void handle_request(int fd) {
   ALOGV("handle_request(%d)\n", fd);
 
+  ScopedFd closer(fd);
   debugger_request_t request;
   memset(&request, 0, sizeof(request));
   int status = read_request(fd, &request);
-  if (!status) {
-    ALOGV("BOOM: pid=%d uid=%d gid=%d tid=%d\n",
-         request.pid, request.uid, request.gid, request.tid);
+  if (status != 0) {
+    return;
+  }
+
+  ALOGV("BOOM: pid=%d uid=%d gid=%d tid=%d\n", request.pid, request.uid, request.gid, request.tid);
 
 #if defined(__LP64__)
-    // On 64 bit systems, requests to dump 32 bit and 64 bit tids come
-    // to the 64 bit debuggerd. If the process is a 32 bit executable,
-    // redirect the request to the 32 bit debuggerd.
-    if (is32bit(request.tid)) {
-      // Only dump backtrace and dump tombstone requests can be redirected.
-      if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE
-          || request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
-        redirect_to_32(fd, &request);
-      } else {
-        ALOGE("debuggerd: Not allowed to redirect action %d to 32 bit debuggerd\n",
-              request.action);
-      }
-      close(fd);
-      return;
-    }
-#endif
-
-    // At this point, the thread that made the request is blocked in
-    // a read() call.  If the thread has crashed, then this gives us
-    // time to PTRACE_ATTACH to it before it has a chance to really fault.
-    //
-    // The PTRACE_ATTACH sends a SIGSTOP to the target process, but it
-    // won't necessarily have stopped by the time ptrace() returns.  (We
-    // currently assume it does.)  We write to the file descriptor to
-    // ensure that it can run as soon as we call PTRACE_CONT below.
-    // See details in bionic/libc/linker/debugger.c, in function
-    // debugger_signal_handler().
-    if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) {
-      ALOGE("ptrace attach failed: %s\n", strerror(errno));
+  // On 64 bit systems, requests to dump 32 bit and 64 bit tids come
+  // to the 64 bit debuggerd. If the process is a 32 bit executable,
+  // redirect the request to the 32 bit debuggerd.
+  if (is32bit(request.tid)) {
+    // Only dump backtrace and dump tombstone requests can be redirected.
+    if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE ||
+        request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
+      redirect_to_32(fd, &request);
     } else {
-      bool detach_failed = false;
-      bool tid_unresponsive = false;
-      bool attach_gdb = should_attach_gdb(&request);
-      if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
-        ALOGE("failed responding to client: %s\n", strerror(errno));
-      } else {
-        char* tombstone_path = NULL;
-
-        if (request.action == DEBUGGER_ACTION_CRASH) {
-          close(fd);
-          fd = -1;
-        }
-
-        int total_sleep_time_usec = 0;
-        for (;;) {
-          int signal = wait_for_sigstop(request.tid, &total_sleep_time_usec, &detach_failed);
-          if (signal == -1) {
-            tid_unresponsive = true;
-            break;
-          }
-
-          switch (signal) {
-            case SIGSTOP:
-              if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
-                ALOGV("stopped -- dumping to tombstone\n");
-                tombstone_path = engrave_tombstone(request.pid, request.tid,
-                                                   signal, request.original_si_code,
-                                                   request.abort_msg_address, true,
-                                                   &detach_failed, &total_sleep_time_usec);
-              } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
-                ALOGV("stopped -- dumping to fd\n");
-                dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed,
-                               &total_sleep_time_usec);
-              } else {
-                ALOGV("stopped -- continuing\n");
-                status = ptrace(PTRACE_CONT, request.tid, 0, 0);
-                if (status) {
-                  ALOGE("ptrace continue failed: %s\n", strerror(errno));
-                }
-                continue; // loop again
-              }
-              break;
-
-            case SIGABRT:
-            case SIGBUS:
-            case SIGFPE:
-            case SIGILL:
-            case SIGSEGV:
-#ifdef SIGSTKFLT
-            case SIGSTKFLT:
+      ALOGE("debuggerd: Not allowed to redirect action %d to 32 bit debuggerd\n", request.action);
+    }
+    return;
+  }
 #endif
-            case SIGTRAP:
-              ALOGV("stopped -- fatal signal\n");
-              // Send a SIGSTOP to the process to make all of
-              // the non-signaled threads stop moving.  Without
-              // this we get a lot of "ptrace detach failed:
-              // No such process".
-              kill(request.pid, SIGSTOP);
-              // don't dump sibling threads when attaching to GDB because it
-              // makes the process less reliable, apparently...
-              tombstone_path = engrave_tombstone(request.pid, request.tid,
-                                                 signal, request.original_si_code,
-                                                 request.abort_msg_address, !attach_gdb,
-                                                 &detach_failed, &total_sleep_time_usec);
-              break;
 
-            default:
-              ALOGE("process stopped due to unexpected signal %d\n", signal);
-              break;
-          }
-          break;
-        }
+  // At this point, the thread that made the request is blocked in
+  // a read() call.  If the thread has crashed, then this gives us
+  // time to PTRACE_ATTACH to it before it has a chance to really fault.
+  //
+  // The PTRACE_ATTACH sends a SIGSTOP to the target process, but it
+  // won't necessarily have stopped by the time ptrace() returns.  (We
+  // currently assume it does.)  We write to the file descriptor to
+  // ensure that it can run as soon as we call PTRACE_CONT below.
+  // See details in bionic/libc/linker/debugger.c, in function
+  // debugger_signal_handler().
+  if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) {
+    ALOGE("ptrace attach failed: %s\n", strerror(errno));
+    return;
+  }
 
-        if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
-          if (tombstone_path) {
-            write(fd, tombstone_path, strlen(tombstone_path));
-          }
-          close(fd);
-          fd = -1;
-        }
-        free(tombstone_path);
-      }
+  bool detach_failed = false;
+  bool tid_unresponsive = false;
+  bool attach_gdb = should_attach_gdb(&request);
+  if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
+    ALOGE("failed responding to client: %s\n", strerror(errno));
+    return;
+  }
 
-      if (!tid_unresponsive) {
-        ALOGV("detaching");
-        if (attach_gdb) {
-          // stop the process so we can debug
-          kill(request.pid, SIGSTOP);
-        }
-        if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
-          ALOGE("ptrace detach from %d failed: %s", request.tid, strerror(errno));
-          detach_failed = true;
-        } else if (attach_gdb) {
-          // if debug.db.uid is set, its value indicates if we should wait
-          // for user action for the crashing process.
-          // in this case, we log a message and turn the debug LED on
-          // waiting for a gdb connection (for instance)
-          wait_for_user_action(request);
-        }
-      }
-
-      // resume stopped process (so it can crash in peace).
-      kill(request.pid, SIGCONT);
-
-      // If we didn't successfully detach, we're still the parent, and the
-      // actual parent won't receive a death notification via wait(2).  At this point
-      // there's not much we can do about that.
-      if (detach_failed) {
-        ALOGE("debuggerd committing suicide to free the zombie!\n");
-        kill(getpid(), SIGKILL);
-      }
+  std::unique_ptr<char> tombstone_path;
+  int total_sleep_time_usec = 0;
+  while (true) {
+    int signal = wait_for_sigstop(request.tid, &total_sleep_time_usec, &detach_failed);
+    if (signal == -1) {
+      tid_unresponsive = true;
+      break;
     }
 
+    switch (signal) {
+      case SIGSTOP:
+        if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
+          ALOGV("stopped -- dumping to tombstone\n");
+          tombstone_path.reset(engrave_tombstone(
+            request.pid, request.tid, signal, request.original_si_code, request.abort_msg_address,
+            true, &detach_failed, &total_sleep_time_usec));
+        } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
+          ALOGV("stopped -- dumping to fd\n");
+          dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed, &total_sleep_time_usec);
+        } else {
+          ALOGV("stopped -- continuing\n");
+          status = ptrace(PTRACE_CONT, request.tid, 0, 0);
+          if (status) {
+            ALOGE("ptrace continue failed: %s\n", strerror(errno));
+          }
+          continue;  // loop again
+        }
+        break;
+
+      case SIGABRT:
+      case SIGBUS:
+      case SIGFPE:
+      case SIGILL:
+      case SIGSEGV:
+#ifdef SIGSTKFLT
+      case SIGSTKFLT:
+#endif
+      case SIGTRAP:
+        ALOGV("stopped -- fatal signal\n");
+        // Send a SIGSTOP to the process to make all of
+        // the non-signaled threads stop moving.  Without
+        // this we get a lot of "ptrace detach failed:
+        // No such process".
+        kill(request.pid, SIGSTOP);
+        // don't dump sibling threads when attaching to GDB because it
+        // makes the process less reliable, apparently...
+        tombstone_path.reset(engrave_tombstone(
+          request.pid, request.tid, signal, request.original_si_code, request.abort_msg_address,
+          !attach_gdb, &detach_failed, &total_sleep_time_usec));
+        break;
+
+      default:
+        ALOGE("process stopped due to unexpected signal %d\n", signal);
+        break;
+    }
+    break;
   }
-  if (fd >= 0) {
-    close(fd);
+
+  if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
+    if (tombstone_path) {
+      write(fd, tombstone_path.get(), strlen(tombstone_path.get()));
+    }
+  }
+
+  if (!tid_unresponsive) {
+    ALOGV("detaching");
+    if (attach_gdb) {
+      // stop the process so we can debug
+      kill(request.pid, SIGSTOP);
+    }
+    if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
+      ALOGE("ptrace detach from %d failed: %s", request.tid, strerror(errno));
+      detach_failed = true;
+    } else if (attach_gdb) {
+      // if debug.db.uid is set, its value indicates if we should wait
+      // for user action for the crashing process.
+      // in this case, we log a message and turn the debug LED on
+      // waiting for a gdb connection (for instance)
+      wait_for_user_action(request);
+    }
+  }
+
+  // resume stopped process (so it can crash in peace).
+  kill(request.pid, SIGCONT);
+
+  // If we didn't successfully detach, we're still the parent, and the
+  // actual parent won't receive a death notification via wait(2).  At this point
+  // there's not much we can do about that.
+  if (detach_failed) {
+    ALOGE("debuggerd committing suicide to free the zombie!\n");
+    kill(getpid(), SIGKILL);
   }
 }
 
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 3f201ec..5ca88cb 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -49,7 +49,7 @@
     libutils \
     liblog \
     libz \
-    libbase
+    libbase \
 
 LOCAL_STATIC_LIBRARIES_darwin := libselinux
 LOCAL_STATIC_LIBRARIES_linux := libselinux
@@ -83,5 +83,6 @@
 LOCAL_SRC_FILES := usbtest.cpp usb_linux.cpp util.cpp
 LOCAL_MODULE := usbtest
 LOCAL_CFLAGS := -Werror
+LOCAL_STATIC_LIBRARIES := libbase
 include $(BUILD_HOST_EXECUTABLE)
 endif
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index d4be63b..ac5a17a 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -75,13 +75,13 @@
 
 
 
-bool fb_getvar(usb_handle* usb, const std::string& key, std::string* value) {
+bool fb_getvar(Transport* transport, const std::string& key, std::string* value) {
     std::string cmd = "getvar:";
     cmd += key;
 
     char buf[FB_RESPONSE_SZ + 1];
     memset(buf, 0, sizeof(buf));
-    if (fb_command_response(usb, cmd.c_str(), buf)) {
+    if (fb_command_response(transport, cmd.c_str(), buf)) {
       return false;
     }
     *value = buf;
@@ -330,7 +330,7 @@
     queue_action(OP_WAIT_FOR_DISCONNECT, "");
 }
 
-int fb_execute_queue(usb_handle *usb)
+int fb_execute_queue(Transport* transport)
 {
     Action *a;
     char resp[FB_RESPONSE_SZ+1];
@@ -350,25 +350,25 @@
             fprintf(stderr,"%s...\n",a->msg);
         }
         if (a->op == OP_DOWNLOAD) {
-            status = fb_download_data(usb, a->data, a->size);
+            status = fb_download_data(transport, a->data, a->size);
             status = a->func(a, status, status ? fb_get_error() : "");
             if (status) break;
         } else if (a->op == OP_COMMAND) {
-            status = fb_command(usb, a->cmd);
+            status = fb_command(transport, a->cmd);
             status = a->func(a, status, status ? fb_get_error() : "");
             if (status) break;
         } else if (a->op == OP_QUERY) {
-            status = fb_command_response(usb, a->cmd, resp);
+            status = fb_command_response(transport, a->cmd, resp);
             status = a->func(a, status, status ? fb_get_error() : resp);
             if (status) break;
         } else if (a->op == OP_NOTICE) {
             fprintf(stderr,"%s\n",(char*)a->data);
         } else if (a->op == OP_DOWNLOAD_SPARSE) {
-            status = fb_download_data_sparse(usb, reinterpret_cast<sparse_file*>(a->data));
+            status = fb_download_data_sparse(transport, reinterpret_cast<sparse_file*>(a->data));
             status = a->func(a, status, status ? fb_get_error() : "");
             if (status) break;
         } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
-            usb_wait_for_disconnect(usb);
+            transport->WaitForDisconnect();
         } else {
             die("bogus action");
         }
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index be30d81..a16d7dd 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -55,6 +55,8 @@
 #include "bootimg_utils.h"
 #include "fastboot.h"
 #include "fs.h"
+#include "transport.h"
+#include "usb.h"
 
 #ifndef O_BINARY
 #define O_BINARY 0
@@ -222,16 +224,16 @@
     return -1;
 }
 
-static usb_handle* open_device() {
-    static usb_handle *usb = 0;
+static Transport* open_device() {
+    static Transport* transport = nullptr;
     int announce = 1;
 
-    if(usb) return usb;
+    if (transport) return transport;
 
-    for(;;) {
-        usb = usb_open(match_fastboot);
-        if(usb) return usb;
-        if(announce) {
+    for (;;) {
+        transport = usb_open(match_fastboot);
+        if (transport) return transport;
+        if (announce) {
             announce = 0;
             fprintf(stderr, "< waiting for %s >\n", serial ? serial : "any device");
         }
@@ -277,8 +279,6 @@
             "                                           override the fs type and/or size\n"
             "                                           the bootloader reports.\n"
             "  getvar <variable>                        Display a bootloader variable.\n"
-            "  set_active <suffix>                      Sets the active slot. If slots are\n"
-            "                                           not supported, this does nothing.\n"
             "  boot <kernel> [ <ramdisk> [ <second> ] ] Download and boot kernel.\n"
             "  flash:raw boot <kernel> [ <ramdisk> [ <second> ] ]\n"
             "                                           Create bootimage and flash it.\n"
@@ -299,9 +299,15 @@
             "  -p <product>                             Specify product name.\n"
             "  -c <cmdline>                             Override kernel commandline.\n"
             "  -i <vendor id>                           Specify a custom USB vendor id.\n"
-            "  -b <base_addr>                           Specify a custom kernel base\n"
+            "  -b, --base <base_addr>                   Specify a custom kernel base\n"
             "                                           address (default: 0x10000000).\n"
-            "  -n <page size>                           Specify the nand page size\n"
+            "  --kernel-offset                          Specify a custom kernel offset.\n"
+            "                                           (default: 0x00008000)\n"
+            "  --ramdisk-offset                         Specify a custom ramdisk offset.\n"
+            "                                           (default: 0x01000000)\n"
+            "  --tags-offset                            Specify a custom tags offset.\n"
+            "                                           (default: 0x00000100)\n"
+            "  -n, --page-size <page size>              Specify the nand page size\n"
             "                                           (default: 2048).\n"
             "  -S <size>[K|M|G]                         Automatically sparse files greater\n"
             "                                           than 'size'. 0 to disable.\n"
@@ -312,9 +318,15 @@
             "                                           to all slots. If this is not given,\n"
             "                                           slotted partitions will default to\n"
             "                                           the current active slot.\n"
+            "  -a, --set-active[=<suffix>]              Sets the active slot. If no suffix is\n"
+            "                                           provided, this will default to the value\n"
+            "                                           given by --slot. If slots are not\n"
+            "                                           supported, this does nothing.\n"
+            "  --unbuffered                             Do not buffer input or output.\n"
+            "  --version                                Display version.\n"
+            "  -h, --help                               show this message.\n"
         );
 }
-
 static void* load_bootable_image(const char* kernel, const char* ramdisk,
                                  const char* secondstage, int64_t* sz,
                                  const char* cmdline) {
@@ -587,9 +599,10 @@
     return out_s;
 }
 
-static int64_t get_target_sparse_limit(usb_handle* usb) {
+static int64_t get_target_sparse_limit(Transport* transport) {
     std::string max_download_size;
-    if (!fb_getvar(usb, "max-download-size", &max_download_size) || max_download_size.empty()) {
+    if (!fb_getvar(transport, "max-download-size", &max_download_size) ||
+            max_download_size.empty()) {
         fprintf(stderr, "target didn't report max-download-size\n");
         return 0;
     }
@@ -608,7 +621,7 @@
     return limit;
 }
 
-static int64_t get_sparse_limit(usb_handle* usb, int64_t size) {
+static int64_t get_sparse_limit(Transport* transport, int64_t size) {
     int64_t limit;
 
     if (sparse_limit == 0) {
@@ -617,7 +630,7 @@
         limit = sparse_limit;
     } else {
         if (target_sparse_limit == -1) {
-            target_sparse_limit = get_target_sparse_limit(usb);
+            target_sparse_limit = get_target_sparse_limit(transport);
         }
         if (target_sparse_limit > 0) {
             limit = target_sparse_limit;
@@ -636,22 +649,22 @@
 // Until we get lazy inode table init working in make_ext4fs, we need to
 // erase partitions of type ext4 before flashing a filesystem so no stale
 // inodes are left lying around.  Otherwise, e2fsck gets very upset.
-static bool needs_erase(usb_handle* usb, const char* partition) {
+static bool needs_erase(Transport* transport, const char* partition) {
     std::string partition_type;
-    if (!fb_getvar(usb, std::string("partition-type:") + partition, &partition_type)) {
+    if (!fb_getvar(transport, std::string("partition-type:") + partition, &partition_type)) {
         return false;
     }
     return partition_type == "ext4";
 }
 
-static int load_buf_fd(usb_handle* usb, int fd, struct fastboot_buffer* buf) {
+static int load_buf_fd(Transport* transport, int fd, struct fastboot_buffer* buf) {
     int64_t sz = get_file_size(fd);
     if (sz == -1) {
         return -1;
     }
 
     lseek64(fd, 0, SEEK_SET);
-    int64_t limit = get_sparse_limit(usb, sz);
+    int64_t limit = get_sparse_limit(transport, sz);
     if (limit) {
         sparse_file** s = load_sparse_files(fd, limit);
         if (s == nullptr) {
@@ -670,8 +683,7 @@
     return 0;
 }
 
-static int load_buf(usb_handle *usb, const char *fname,
-        struct fastboot_buffer *buf)
+static int load_buf(Transport* transport, const char *fname, struct fastboot_buffer *buf)
 {
     int fd;
 
@@ -680,7 +692,7 @@
         return -1;
     }
 
-    return load_buf_fd(usb, fd, buf);
+    return load_buf_fd(transport, fd, buf);
 }
 
 static void flash_buf(const char *pname, struct fastboot_buffer *buf)
@@ -703,84 +715,88 @@
     }
 }
 
-static std::vector<std::string> get_suffixes(usb_handle* usb) {
+static std::vector<std::string> get_suffixes(Transport* transport) {
     std::vector<std::string> suffixes;
     std::string suffix_list;
-    if (!fb_getvar(usb, "slot-suffixes", &suffix_list)) {
+    if (!fb_getvar(transport, "slot-suffixes", &suffix_list)) {
         die("Could not get suffixes.\n");
     }
     return android::base::Split(suffix_list, ",");
 }
 
-static std::string verify_slot(usb_handle* usb, const char *slot) {
+static std::string verify_slot(Transport* transport, const char *slot) {
     if (strcmp(slot, "all") == 0) {
         return "all";
     }
-    std::vector<std::string> suffixes = get_suffixes(usb);
+    std::vector<std::string> suffixes = get_suffixes(transport);
     for (const std::string &suffix : suffixes) {
         if (suffix == slot)
             return slot;
     }
-    fprintf(stderr, "Slot %s does not exist. supported slots are:", slot);
+    fprintf(stderr, "Slot %s does not exist. supported slots are:\n", slot);
     for (const std::string &suffix : suffixes) {
         fprintf(stderr, "%s\n", suffix.c_str());
     }
     exit(1);
 }
 
-static void do_for_partition(usb_handle* usb, const char *part, const char *slot, std::function<void(const std::string&)> func, bool force_slot) {
-    std::string partition_slot;
+static void do_for_partition(Transport* transport, const char *part, const char *slot,
+                             std::function<void(const std::string&)> func, bool force_slot) {
+    std::string has_slot;
     std::string current_slot;
 
-    if (!fb_getvar(usb, std::string("partition-slot:")+part, &partition_slot)) {
-        /* If partition-slot is not supported, the answer is no. */
-        partition_slot = "";
+    if (!fb_getvar(transport, std::string("has-slot:")+part, &has_slot)) {
+        /* If has-slot is not supported, the answer is no. */
+        has_slot = "no";
     }
-    if (partition_slot == "1") {
+    if (has_slot == "yes") {
         if (!slot || slot[0] == 0) {
-            if (!fb_getvar(usb, "current-slot", &current_slot)) {
+            if (!fb_getvar(transport, "current-slot", &current_slot)) {
                 die("Failed to identify current slot.\n");
             }
-            func(std::string(part) + '-' + current_slot);
+            func(std::string(part) + current_slot);
         } else {
-            func(std::string(part) + '-' + slot);
+            func(std::string(part) + slot);
         }
     } else {
         if (force_slot && slot && slot[0]) {
-             fprintf(stderr, "Warning: %s does not support slots, and slot %s was requested.\n", part, slot);
+             fprintf(stderr, "Warning: %s does not support slots, and slot %s was requested.\n",
+                     part, slot);
         }
         func(part);
     }
 }
 
-/* This function will find the real partition name given a base name, and a slot. If slot is NULL or empty,
- * it will use the current slot. If slot is "all", it will return a list of all possible partition names.
- * If force_slot is true, it will fail if a slot is specified, and the given partition does not support slots.
+/* This function will find the real partition name given a base name, and a slot. If slot is NULL or
+ * empty, it will use the current slot. If slot is "all", it will return a list of all possible
+ * partition names. If force_slot is true, it will fail if a slot is specified, and the given
+ * partition does not support slots.
  */
-static void do_for_partitions(usb_handle* usb, const char *part, const char *slot, std::function<void(const std::string&)> func, bool force_slot) {
-    std::string partition_slot;
+static void do_for_partitions(Transport* transport, const char *part, const char *slot,
+                              std::function<void(const std::string&)> func, bool force_slot) {
+    std::string has_slot;
 
     if (slot && strcmp(slot, "all") == 0) {
-        if (!fb_getvar(usb, std::string("partition-slot:") + part, &partition_slot)) {
+        if (!fb_getvar(transport, std::string("has-slot:") + part, &has_slot)) {
             die("Could not check if partition %s has slot.", part);
         }
-        if (partition_slot == "1") {
-            std::vector<std::string> suffixes = get_suffixes(usb);
+        if (has_slot == "yes") {
+            std::vector<std::string> suffixes = get_suffixes(transport);
             for (std::string &suffix : suffixes) {
-                do_for_partition(usb, part, suffix.c_str(), func, force_slot);
+                do_for_partition(transport, part, suffix.c_str(), func, force_slot);
             }
         } else {
-            do_for_partition(usb, part, "", func, force_slot);
+            do_for_partition(transport, part, "", func, force_slot);
         }
     } else {
-        do_for_partition(usb, part, slot, func, force_slot);
+        do_for_partition(transport, part, slot, func, force_slot);
     }
 }
 
-static void do_flash(usb_handle* usb, const char* pname, const char* fname) {
+static void do_flash(Transport* transport, const char* pname, const char* fname) {
     struct fastboot_buffer buf;
 
-    if (load_buf(usb, fname, &buf)) {
+    if (load_buf(transport, fname, &buf)) {
         die("cannot load '%s'", fname);
     }
     flash_buf(pname, &buf);
@@ -794,7 +810,7 @@
     fb_queue_command("signature", "installing signature");
 }
 
-static void do_update(usb_handle* usb, const char* filename, const char* slot_override, bool erase_first) {
+static void do_update(Transport* transport, const char* filename, const char* slot_override, bool erase_first) {
     queue_info_dump();
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
@@ -825,12 +841,12 @@
             exit(1); // unzip_to_file already explained why.
         }
         fastboot_buffer buf;
-        int rc = load_buf_fd(usb, fd, &buf);
+        int rc = load_buf_fd(transport, fd, &buf);
         if (rc) die("cannot load %s from flash", images[i].img_name);
 
         auto update = [&](const std::string &partition) {
             do_update_signature(zip, images[i].sig_name);
-            if (erase_first && needs_erase(usb, partition.c_str())) {
+            if (erase_first && needs_erase(transport, partition.c_str())) {
                 fb_queue_erase(partition.c_str());
             }
             flash_buf(partition.c_str(), &buf);
@@ -839,7 +855,7 @@
              * program exits.
              */
         };
-        do_for_partitions(usb, images[i].part_name, slot_override, update, false);
+        do_for_partitions(transport, images[i].part_name, slot_override, update, false);
     }
 
     CloseArchive(zip);
@@ -861,7 +877,7 @@
     fb_queue_command("signature", "installing signature");
 }
 
-static void do_flashall(usb_handle* usb, const char *slot_override, int erase_first) {
+static void do_flashall(Transport* transport, const char* slot_override, int erase_first) {
     queue_info_dump();
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
@@ -878,7 +894,7 @@
     for (size_t i = 0; i < ARRAY_SIZE(images); i++) {
         fname = find_item(images[i].part_name, product);
         fastboot_buffer buf;
-        if (load_buf(usb, fname, &buf)) {
+        if (load_buf(transport, fname, &buf)) {
             if (images[i].is_optional)
                 continue;
             die("could not load %s\n", images[i].img_name);
@@ -886,12 +902,12 @@
 
         auto flashall = [&](const std::string &partition) {
             do_send_signature(fname);
-            if (erase_first && needs_erase(usb, partition.c_str())) {
+            if (erase_first && needs_erase(transport, partition.c_str())) {
                 fb_queue_erase(partition.c_str());
             }
             flash_buf(partition.c_str(), &buf);
         };
-        do_for_partitions(usb, images[i].part_name, slot_override, flashall, false);
+        do_for_partitions(transport, images[i].part_name, slot_override, flashall, false);
     }
 }
 
@@ -976,7 +992,7 @@
     return num;
 }
 
-static void fb_perform_format(usb_handle* usb,
+static void fb_perform_format(Transport* transport,
                               const char* partition, int skip_if_not_supported,
                               const char* type_override, const char* size_override) {
     std::string partition_type, partition_size;
@@ -994,7 +1010,7 @@
         limit = sparse_limit;
     }
 
-    if (!fb_getvar(usb, std::string("partition-type:") + partition, &partition_type)) {
+    if (!fb_getvar(transport, std::string("partition-type:") + partition, &partition_type)) {
         errMsg = "Can't determine partition type.\n";
         goto failed;
     }
@@ -1006,7 +1022,7 @@
         partition_type = type_override;
     }
 
-    if (!fb_getvar(usb, std::string("partition-size:") + partition, &partition_size)) {
+    if (!fb_getvar(transport, std::string("partition-size:") + partition, &partition_size)) {
         errMsg = "Unable to get partition size\n";
         goto failed;
     }
@@ -1017,6 +1033,11 @@
         }
         partition_size = size_override;
     }
+    // Some bootloaders (angler, for example), send spurious leading whitespace.
+    partition_size = android::base::Trim(partition_size);
+    // Some bootloaders (hammerhead, for example) use implicit hex.
+    // This code used to use strtol with base 16.
+    if (!android::base::StartsWith(partition_size, "0x")) partition_size = "0x" + partition_size;
 
     gen = fs_get_generator(partition_type);
     if (!gen) {
@@ -1030,10 +1051,6 @@
         return;
     }
 
-    // Some bootloaders (hammerhead, for example) use implicit hex.
-    // This code used to use strtol with base 16.
-    if (!android::base::StartsWith(partition_size, "0x")) partition_size = "0x" + partition_size;
-
     int64_t size;
     if (!android::base::ParseInt(partition_size.c_str(), &size)) {
         fprintf(stderr, "Couldn't parse partition size '%s'.\n", partition_size.c_str());
@@ -1047,7 +1064,7 @@
         return;
     }
 
-    if (load_buf_fd(usb, fd, &buf)) {
+    if (load_buf_fd(transport, fd, &buf)) {
         fprintf(stderr, "Cannot read image: %s\n", strerror(errno));
         close(fd);
         return;
@@ -1065,37 +1082,50 @@
 
 int main(int argc, char **argv)
 {
-    int wants_wipe = 0;
-    int wants_reboot = 0;
-    int wants_reboot_bootloader = 0;
+    bool wants_wipe = false;
+    bool wants_reboot = false;
+    bool wants_reboot_bootloader = false;
+    bool wants_set_active = false;
     bool erase_first = true;
     void *data;
     int64_t sz;
     int longindex;
     std::string slot_override;
+    std::string next_active;
 
     const struct option longopts[] = {
         {"base", required_argument, 0, 'b'},
         {"kernel_offset", required_argument, 0, 'k'},
+        {"kernel-offset", required_argument, 0, 'k'},
         {"page_size", required_argument, 0, 'n'},
+        {"page-size", required_argument, 0, 'n'},
         {"ramdisk_offset", required_argument, 0, 'r'},
+        {"ramdisk-offset", required_argument, 0, 'r'},
         {"tags_offset", required_argument, 0, 't'},
+        {"tags-offset", required_argument, 0, 't'},
         {"help", no_argument, 0, 'h'},
         {"unbuffered", no_argument, 0, 0},
         {"version", no_argument, 0, 0},
         {"slot", required_argument, 0, 0},
+        {"set_active", optional_argument, 0, 'a'},
+        {"set-active", optional_argument, 0, 'a'},
         {0, 0, 0, 0}
     };
 
     serial = getenv("ANDROID_SERIAL");
 
     while (1) {
-        int c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lp:c:i:m:h", longopts, &longindex);
+        int c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lp:c:i:m:ha::", longopts, &longindex);
         if (c < 0) {
             break;
         }
         /* Alphabetical cases */
         switch (c) {
+        case 'a':
+            wants_set_active = true;
+            if (optarg)
+                next_active = optarg;
+            break;
         case 'b':
             base_addr = strtoul(optarg, 0, 16);
             break;
@@ -1147,7 +1177,7 @@
             erase_first = false;
             break;
         case 'w':
-            wants_wipe = 1;
+            wants_wipe = true;
             break;
         case '?':
             return 1;
@@ -1170,7 +1200,7 @@
     argc -= optind;
     argv += optind;
 
-    if (argc == 0 && !wants_wipe) {
+    if (argc == 0 && !wants_wipe && !wants_set_active) {
         usage();
         return 1;
     }
@@ -1186,9 +1216,21 @@
         return 0;
     }
 
-    usb_handle* usb = open_device();
+    Transport* transport = open_device();
     if (slot_override != "")
-        slot_override = verify_slot(usb, slot_override.c_str());
+        slot_override = verify_slot(transport, slot_override.c_str());
+    if (next_active != "")
+        next_active = verify_slot(transport, next_active.c_str());
+
+    if (wants_set_active) {
+        if (next_active == "") {
+            if (slot_override == "") {
+                wants_set_active = false;
+            } else {
+                next_active = slot_override;
+            }
+        }
+    }
 
     while (argc > 0) {
         if (!strcmp(*argv, "getvar")) {
@@ -1199,8 +1241,8 @@
             require(2);
 
             auto erase = [&](const std::string &partition) {
-            std::string partition_type;
-                if (fb_getvar(usb, std::string("partition-type:") + argv[1], &partition_type) &&
+                std::string partition_type;
+                if (fb_getvar(transport, std::string("partition-type:") + argv[1], &partition_type) &&
                     fs_get_generator(partition_type) != nullptr) {
                     fprintf(stderr, "******** Did you mean to fastboot format this %s partition?\n",
                             partition_type.c_str());
@@ -1208,7 +1250,7 @@
 
                 fb_queue_erase(partition.c_str());
             };
-            do_for_partitions(usb, argv[1], slot_override.c_str(), erase, true);
+            do_for_partitions(transport, argv[1], slot_override.c_str(), erase, true);
             skip(2);
         } else if(!strncmp(*argv, "format", strlen("format"))) {
             char *overrides;
@@ -1238,12 +1280,12 @@
             if (size_override && !size_override[0]) size_override = nullptr;
 
             auto format = [&](const std::string &partition) {
-                if (erase_first && needs_erase(usb, partition.c_str())) {
+                if (erase_first && needs_erase(transport, partition.c_str())) {
                     fb_queue_erase(partition.c_str());
                 }
-                fb_perform_format(usb, partition.c_str(), 0, type_override, size_override);
+                fb_perform_format(transport, partition.c_str(), 0, type_override, size_override);
             };
-            do_for_partitions(usb, argv[1], slot_override.c_str(), format, true);
+            do_for_partitions(transport, argv[1], slot_override.c_str(), format, true);
             skip(2);
         } else if(!strcmp(*argv, "signature")) {
             require(2);
@@ -1254,18 +1296,18 @@
             fb_queue_command("signature", "installing signature");
             skip(2);
         } else if(!strcmp(*argv, "reboot")) {
-            wants_reboot = 1;
+            wants_reboot = true;
             skip(1);
             if (argc > 0) {
                 if (!strcmp(*argv, "bootloader")) {
-                    wants_reboot = 0;
-                    wants_reboot_bootloader = 1;
+                    wants_reboot = false;
+                    wants_reboot_bootloader = true;
                     skip(1);
                 }
             }
             require(0);
         } else if(!strcmp(*argv, "reboot-bootloader")) {
-            wants_reboot_bootloader = 1;
+            wants_reboot_bootloader = true;
             skip(1);
         } else if (!strcmp(*argv, "continue")) {
             fb_queue_command("continue", "resuming boot");
@@ -1305,12 +1347,12 @@
             if (fname == 0) die("cannot determine image filename for '%s'", pname);
 
             auto flash = [&](const std::string &partition) {
-                if (erase_first && needs_erase(usb, partition.c_str())) {
+                if (erase_first && needs_erase(transport, partition.c_str())) {
                     fb_queue_erase(partition.c_str());
                 }
-                do_flash(usb, partition.c_str(), fname);
+                do_flash(transport, partition.c_str(), fname);
             };
-            do_for_partitions(usb, pname, slot_override.c_str(), flash, true);
+            do_for_partitions(transport, pname, slot_override.c_str(), flash, true);
         } else if(!strcmp(*argv, "flash:raw")) {
             char *kname = argv[2];
             char *rname = 0;
@@ -1330,24 +1372,20 @@
             auto flashraw = [&](const std::string &partition) {
                 fb_queue_flash(partition.c_str(), data, sz);
             };
-            do_for_partitions(usb, argv[1], slot_override.c_str(), flashraw, true);
+            do_for_partitions(transport, argv[1], slot_override.c_str(), flashraw, true);
         } else if(!strcmp(*argv, "flashall")) {
             skip(1);
-            do_flashall(usb, slot_override.c_str(), erase_first);
-            wants_reboot = 1;
+            do_flashall(transport, slot_override.c_str(), erase_first);
+            wants_reboot = true;
         } else if(!strcmp(*argv, "update")) {
             if (argc > 1) {
-                do_update(usb, argv[1], slot_override.c_str(), erase_first);
+                do_update(transport, argv[1], slot_override.c_str(), erase_first);
                 skip(2);
             } else {
-                do_update(usb, "update.zip", slot_override.c_str(), erase_first);
+                do_update(transport, "update.zip", slot_override.c_str(), erase_first);
                 skip(1);
             }
-            wants_reboot = 1;
-        } else if(!strcmp(*argv, "set_active")) {
-            require(2);
-            fb_set_active(argv[1]);
-            skip(2);
+            wants_reboot = true;
         } else if(!strcmp(*argv, "oem")) {
             argc = do_oem_command(argc, argv);
         } else if(!strcmp(*argv, "flashing")) {
@@ -1375,15 +1413,18 @@
     if (wants_wipe) {
         fprintf(stderr, "wiping userdata...\n");
         fb_queue_erase("userdata");
-        fb_perform_format(usb, "userdata", 1, nullptr, nullptr);
+        fb_perform_format(transport, "userdata", 1, nullptr, nullptr);
 
         std::string cache_type;
-        if (fb_getvar(usb, "partition-type:cache", &cache_type) && !cache_type.empty()) {
+        if (fb_getvar(transport, "partition-type:cache", &cache_type) && !cache_type.empty()) {
             fprintf(stderr, "wiping cache...\n");
             fb_queue_erase("cache");
-            fb_perform_format(usb, "cache", 1, nullptr, nullptr);
+            fb_perform_format(transport, "cache", 1, nullptr, nullptr);
         }
     }
+    if (wants_set_active) {
+        fb_set_active(next_active.c_str());
+    }
     if (wants_reboot) {
         fb_queue_reboot();
         fb_queue_wait_for_disconnect();
@@ -1392,5 +1433,5 @@
         fb_queue_wait_for_disconnect();
     }
 
-    return fb_execute_queue(usb) ? EXIT_FAILURE : EXIT_SUCCESS;
+    return fb_execute_queue(transport) ? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 784ec5c..acfbc13 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -34,22 +34,22 @@
 
 #include <string>
 
-#include "usb.h"
+#include "transport.h"
 
 struct sparse_file;
 
 /* protocol.c - fastboot protocol */
-int fb_command(usb_handle *usb, const char *cmd);
-int fb_command_response(usb_handle *usb, const char *cmd, char *response);
-int fb_download_data(usb_handle *usb, const void *data, uint32_t size);
-int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s);
+int fb_command(Transport* transport, const char* cmd);
+int fb_command_response(Transport* transport, const char* cmd, char* response);
+int fb_download_data(Transport* transport, const void* data, uint32_t size);
+int fb_download_data_sparse(Transport* transport, struct sparse_file* s);
 char *fb_get_error(void);
 
 #define FB_COMMAND_SZ 64
 #define FB_RESPONSE_SZ 64
 
 /* engine.c - high level command queue engine */
-bool fb_getvar(usb_handle* usb, const std::string& key, std::string* value);
+bool fb_getvar(Transport* transport, const std::string& key, std::string* value);
 void fb_queue_flash(const char *ptn, void *data, uint32_t sz);
 void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, uint32_t sz);
 void fb_queue_erase(const char *ptn);
@@ -63,7 +63,7 @@
 void fb_queue_download(const char *name, void *data, uint32_t size);
 void fb_queue_notice(const char *notice);
 void fb_queue_wait_for_disconnect(void);
-int fb_execute_queue(usb_handle *usb);
+int fb_execute_queue(Transport* transport);
 void fb_set_active(const char *slot);
 
 /* util stuff */
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
index cbd48e8..4850b4a 100644
--- a/fastboot/protocol.cpp
+++ b/fastboot/protocol.cpp
@@ -39,6 +39,7 @@
 #include <sparse/sparse.h>
 
 #include "fastboot.h"
+#include "transport.h"
 
 static char ERROR[128];
 
@@ -47,21 +48,21 @@
     return ERROR;
 }
 
-static int check_response(usb_handle* usb, uint32_t size, char* response) {
+static int check_response(Transport* transport, uint32_t size, char* response) {
     char status[65];
 
     while (true) {
-        int r = usb_read(usb, status, 64);
+        int r = transport->Read(status, 64);
         if (r < 0) {
             sprintf(ERROR, "status read failed (%s)", strerror(errno));
-            usb_close(usb);
+            transport->Close();
             return -1;
         }
         status[r] = 0;
 
         if (r < 4) {
             sprintf(ERROR, "status malformed (%d bytes)", r);
-            usb_close(usb);
+            transport->Close();
             return -1;
         }
 
@@ -90,21 +91,21 @@
             uint32_t dsize = strtol(status + 4, 0, 16);
             if (dsize > size) {
                 strcpy(ERROR, "data size too large");
-                usb_close(usb);
+                transport->Close();
                 return -1;
             }
             return dsize;
         }
 
         strcpy(ERROR,"unknown status code");
-        usb_close(usb);
+        transport->Close();
         break;
     }
 
     return -1;
 }
 
-static int _command_start(usb_handle* usb, const char* cmd, uint32_t size, char* response) {
+static int _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) {
     size_t cmdsize = strlen(cmd);
     if (cmdsize > 64) {
         sprintf(ERROR, "command too large");
@@ -115,51 +116,51 @@
         response[0] = 0;
     }
 
-    if (usb_write(usb, cmd, cmdsize) != static_cast<int>(cmdsize)) {
+    if (transport->Write(cmd, cmdsize) != static_cast<int>(cmdsize)) {
         sprintf(ERROR, "command write failed (%s)", strerror(errno));
-        usb_close(usb);
+        transport->Close();
         return -1;
     }
 
-    return check_response(usb, size, response);
+    return check_response(transport, size, response);
 }
 
-static int _command_data(usb_handle* usb, const void* data, uint32_t size) {
-    int r = usb_write(usb, data, size);
+static int _command_data(Transport* transport, const void* data, uint32_t size) {
+    int r = transport->Write(data, size);
     if (r < 0) {
         sprintf(ERROR, "data transfer failure (%s)", strerror(errno));
-        usb_close(usb);
+        transport->Close();
         return -1;
     }
     if (r != ((int) size)) {
         sprintf(ERROR, "data transfer failure (short transfer)");
-        usb_close(usb);
+        transport->Close();
         return -1;
     }
     return r;
 }
 
-static int _command_end(usb_handle* usb) {
-    return check_response(usb, 0, 0) < 0 ? -1 : 0;
+static int _command_end(Transport* transport) {
+    return check_response(transport, 0, 0) < 0 ? -1 : 0;
 }
 
-static int _command_send(usb_handle* usb, const char* cmd, const void* data, uint32_t size,
+static int _command_send(Transport* transport, const char* cmd, const void* data, uint32_t size,
                          char* response) {
     if (size == 0) {
         return -1;
     }
 
-    int r = _command_start(usb, cmd, size, response);
+    int r = _command_start(transport, cmd, size, response);
     if (r < 0) {
         return -1;
     }
 
-    r = _command_data(usb, data, size);
+    r = _command_data(transport, data, size);
     if (r < 0) {
         return -1;
     }
 
-    r = _command_end(usb);
+    r = _command_end(transport);
     if (r < 0) {
         return -1;
     }
@@ -167,59 +168,59 @@
     return size;
 }
 
-static int _command_send_no_data(usb_handle* usb, const char* cmd, char* response) {
-    return _command_start(usb, cmd, 0, response);
+static int _command_send_no_data(Transport* transport, const char* cmd, char* response) {
+    return _command_start(transport, cmd, 0, response);
 }
 
-int fb_command(usb_handle* usb, const char* cmd) {
-    return _command_send_no_data(usb, cmd, 0);
+int fb_command(Transport* transport, const char* cmd) {
+    return _command_send_no_data(transport, cmd, 0);
 }
 
-int fb_command_response(usb_handle* usb, const char* cmd, char* response) {
-    return _command_send_no_data(usb, cmd, response);
+int fb_command_response(Transport* transport, const char* cmd, char* response) {
+    return _command_send_no_data(transport, cmd, response);
 }
 
-int fb_download_data(usb_handle* usb, const void* data, uint32_t size) {
+int fb_download_data(Transport* transport, const void* data, uint32_t size) {
     char cmd[64];
     sprintf(cmd, "download:%08x", size);
-    return _command_send(usb, cmd, data, size, 0) < 0 ? -1 : 0;
+    return _command_send(transport, cmd, data, size, 0) < 0 ? -1 : 0;
 }
 
-#define USB_BUF_SIZE 1024
-static char usb_buf[USB_BUF_SIZE];
-static int usb_buf_len;
+#define TRANSPORT_BUF_SIZE 1024
+static char transport_buf[TRANSPORT_BUF_SIZE];
+static int transport_buf_len;
 
 static int fb_download_data_sparse_write(void *priv, const void *data, int len)
 {
     int r;
-    usb_handle* usb = reinterpret_cast<usb_handle*>(priv);
+    Transport* transport = reinterpret_cast<Transport*>(priv);
     int to_write;
     const char* ptr = reinterpret_cast<const char*>(data);
 
-    if (usb_buf_len) {
-        to_write = std::min(USB_BUF_SIZE - usb_buf_len, len);
+    if (transport_buf_len) {
+        to_write = std::min(TRANSPORT_BUF_SIZE - transport_buf_len, len);
 
-        memcpy(usb_buf + usb_buf_len, ptr, to_write);
-        usb_buf_len += to_write;
+        memcpy(transport_buf + transport_buf_len, ptr, to_write);
+        transport_buf_len += to_write;
         ptr += to_write;
         len -= to_write;
     }
 
-    if (usb_buf_len == USB_BUF_SIZE) {
-        r = _command_data(usb, usb_buf, USB_BUF_SIZE);
-        if (r != USB_BUF_SIZE) {
+    if (transport_buf_len == TRANSPORT_BUF_SIZE) {
+        r = _command_data(transport, transport_buf, TRANSPORT_BUF_SIZE);
+        if (r != TRANSPORT_BUF_SIZE) {
             return -1;
         }
-        usb_buf_len = 0;
+        transport_buf_len = 0;
     }
 
-    if (len > USB_BUF_SIZE) {
-        if (usb_buf_len > 0) {
-            sprintf(ERROR, "internal error: usb_buf not empty\n");
+    if (len > TRANSPORT_BUF_SIZE) {
+        if (transport_buf_len > 0) {
+            sprintf(ERROR, "internal error: transport_buf not empty\n");
             return -1;
         }
-        to_write = round_down(len, USB_BUF_SIZE);
-        r = _command_data(usb, ptr, to_write);
+        to_write = round_down(len, TRANSPORT_BUF_SIZE);
+        r = _command_data(transport, ptr, to_write);
         if (r != to_write) {
             return -1;
         }
@@ -228,28 +229,28 @@
     }
 
     if (len > 0) {
-        if (len > USB_BUF_SIZE) {
-            sprintf(ERROR, "internal error: too much left for usb_buf\n");
+        if (len > TRANSPORT_BUF_SIZE) {
+            sprintf(ERROR, "internal error: too much left for transport_buf\n");
             return -1;
         }
-        memcpy(usb_buf, ptr, len);
-        usb_buf_len = len;
+        memcpy(transport_buf, ptr, len);
+        transport_buf_len = len;
     }
 
     return 0;
 }
 
-static int fb_download_data_sparse_flush(usb_handle* usb) {
-    if (usb_buf_len > 0) {
-        if (_command_data(usb, usb_buf, usb_buf_len) != usb_buf_len) {
+static int fb_download_data_sparse_flush(Transport* transport) {
+    if (transport_buf_len > 0) {
+        if (_command_data(transport, transport_buf, transport_buf_len) != transport_buf_len) {
             return -1;
         }
-        usb_buf_len = 0;
+        transport_buf_len = 0;
     }
     return 0;
 }
 
-int fb_download_data_sparse(usb_handle* usb, struct sparse_file* s) {
+int fb_download_data_sparse(Transport* transport, struct sparse_file* s) {
     int size = sparse_file_len(s, true, false);
     if (size <= 0) {
         return -1;
@@ -257,20 +258,20 @@
 
     char cmd[64];
     sprintf(cmd, "download:%08x", size);
-    int r = _command_start(usb, cmd, size, 0);
+    int r = _command_start(transport, cmd, size, 0);
     if (r < 0) {
         return -1;
     }
 
-    r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, usb);
+    r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, transport);
     if (r < 0) {
         return -1;
     }
 
-    r = fb_download_data_sparse_flush(usb);
+    r = fb_download_data_sparse_flush(transport);
     if (r < 0) {
         return -1;
     }
 
-    return _command_end(usb);
+    return _command_end(transport);
 }
diff --git a/fastboot/transport.h b/fastboot/transport.h
new file mode 100644
index 0000000..55a5abb
--- /dev/null
+++ b/fastboot/transport.h
@@ -0,0 +1,48 @@
+/*
+ * 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 TRANSPORT_H_
+#define TRANSPORT_H_
+
+#include <base/macros.h>
+
+// General interface to allow the fastboot protocol to be used over different
+// types of transports.
+class Transport {
+  public:
+    Transport() = default;
+    virtual ~Transport() = default;
+
+    // Reads |len| bytes into |data|. Returns the number of bytes actually
+    // read or -1 on error.
+    virtual ssize_t Read(void* data, size_t len) = 0;
+
+    // Writes |len| bytes from |data|. Returns the number of bytes actually
+    // written or -1 on error.
+    virtual ssize_t Write(const void* data, size_t len) = 0;
+
+    // Closes the underlying transport. Returns 0 on success.
+    virtual int Close() = 0;
+
+    // Blocks until the transport disconnects. Transports that don't support
+    // this will return immediately. Returns 0 on success.
+    virtual int WaitForDisconnect() { return 0; }
+
+  private:
+    DISALLOW_COPY_AND_ASSIGN(Transport);
+};
+
+#endif  // TRANSPORT_H_
diff --git a/fastboot/usb.h b/fastboot/usb.h
index 0fda41a..4acf12d 100644
--- a/fastboot/usb.h
+++ b/fastboot/usb.h
@@ -29,7 +29,7 @@
 #ifndef _USB_H_
 #define _USB_H_
 
-struct usb_handle;
+#include "transport.h"
 
 struct usb_ifc_info {
         /* from device descriptor */
@@ -55,10 +55,6 @@
 
 typedef int (*ifc_match_func)(usb_ifc_info *ifc);
 
-usb_handle *usb_open(ifc_match_func callback);
-int usb_close(usb_handle *h);
-int usb_read(usb_handle *h, void *_data, int len);
-int usb_write(usb_handle *h, const void *_data, int len);
-int usb_wait_for_disconnect(usb_handle *h);
+Transport* usb_open(ifc_match_func callback);
 
 #endif
diff --git a/fastboot/usb_linux.cpp b/fastboot/usb_linux.cpp
index 7b87907..02ffcd9 100644
--- a/fastboot/usb_linux.cpp
+++ b/fastboot/usb_linux.cpp
@@ -43,6 +43,8 @@
 #include <linux/version.h>
 #include <linux/usb/ch9.h>
 
+#include <memory>
+
 #include "fastboot.h"
 #include "usb.h"
 
@@ -85,6 +87,22 @@
     unsigned char ep_out;
 };
 
+class LinuxUsbTransport : public Transport {
+  public:
+    LinuxUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
+    ~LinuxUsbTransport() override = default;
+
+    ssize_t Read(void* data, size_t len) override;
+    ssize_t Write(const void* data, size_t len) override;
+    int Close() override;
+    int WaitForDisconnect() override;
+
+  private:
+    std::unique_ptr<usb_handle> handle_;
+
+    DISALLOW_COPY_AND_ASSIGN(LinuxUsbTransport);
+};
+
 /* True if name isn't a valid name for a USB device in /sys/bus/usb/devices.
  * Device names are made up of numbers, dots, and dashes, e.g., '7-1.5'.
  * We reject interfaces (e.g., '7-1.5:1.0') and host controllers (e.g. 'usb1').
@@ -308,9 +326,9 @@
     return 0;
 }
 
-static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
+static std::unique_ptr<usb_handle> find_usb_device(const char* base, ifc_match_func callback)
 {
-    usb_handle *usb = 0;
+    std::unique_ptr<usb_handle> usb;
     char devname[64];
     char desc[1024];
     int n, in, out, ifc;
@@ -321,39 +339,37 @@
     int writable;
 
     busdir = opendir(base);
-    if(busdir == 0) return 0;
+    if (busdir == 0) return 0;
 
-    while((de = readdir(busdir)) && (usb == 0)) {
-        if(badname(de->d_name)) continue;
+    while ((de = readdir(busdir)) && (usb == nullptr)) {
+        if (badname(de->d_name)) continue;
 
-        if(!convert_to_devfs_name(de->d_name, devname, sizeof(devname))) {
+        if (!convert_to_devfs_name(de->d_name, devname, sizeof(devname))) {
 
 //            DBG("[ scanning %s ]\n", devname);
             writable = 1;
-            if((fd = open(devname, O_RDWR)) < 0) {
+            if ((fd = open(devname, O_RDWR)) < 0) {
                 // Check if we have read-only access, so we can give a helpful
                 // diagnostic like "adb devices" does.
                 writable = 0;
-                if((fd = open(devname, O_RDONLY)) < 0) {
+                if ((fd = open(devname, O_RDONLY)) < 0) {
                     continue;
                 }
             }
 
             n = read(fd, desc, sizeof(desc));
 
-            if(filter_usb_device(de->d_name, desc, n, writable, callback,
-                                 &in, &out, &ifc) == 0) {
-                usb = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+            if (filter_usb_device(de->d_name, desc, n, writable, callback, &in, &out, &ifc) == 0) {
+                usb.reset(new usb_handle());
                 strcpy(usb->fname, devname);
                 usb->ep_in = in;
                 usb->ep_out = out;
                 usb->desc = fd;
 
                 n = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &ifc);
-                if(n != 0) {
+                if (n != 0) {
                     close(fd);
-                    free(usb);
-                    usb = 0;
+                    usb.reset();
                     continue;
                 }
             } else {
@@ -366,14 +382,14 @@
     return usb;
 }
 
-int usb_write(usb_handle *h, const void *_data, int len)
+ssize_t LinuxUsbTransport::Write(const void* _data, size_t len)
 {
     unsigned char *data = (unsigned char*) _data;
     unsigned count = 0;
     struct usbdevfs_bulktransfer bulk;
     int n;
 
-    if(h->ep_out == 0 || h->desc == -1) {
+    if (handle_->ep_out == 0 || handle_->desc == -1) {
         return -1;
     }
 
@@ -381,12 +397,12 @@
         int xfer;
         xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
 
-        bulk.ep = h->ep_out;
+        bulk.ep = handle_->ep_out;
         bulk.len = xfer;
         bulk.data = data;
         bulk.timeout = 0;
 
-        n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
+        n = ioctl(handle_->desc, USBDEVFS_BULK, &bulk);
         if(n != xfer) {
             DBG("ERROR: n = %d, errno = %d (%s)\n",
                 n, errno, strerror(errno));
@@ -401,30 +417,30 @@
     return count;
 }
 
-int usb_read(usb_handle *h, void *_data, int len)
+ssize_t LinuxUsbTransport::Read(void* _data, size_t len)
 {
     unsigned char *data = (unsigned char*) _data;
     unsigned count = 0;
     struct usbdevfs_bulktransfer bulk;
     int n, retry;
 
-    if(h->ep_in == 0 || h->desc == -1) {
+    if (handle_->ep_in == 0 || handle_->desc == -1) {
         return -1;
     }
 
     while(len > 0) {
         int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
 
-        bulk.ep = h->ep_in;
+        bulk.ep = handle_->ep_in;
         bulk.len = xfer;
         bulk.data = data;
         bulk.timeout = 0;
         retry = 0;
 
         do{
-           DBG("[ usb read %d fd = %d], fname=%s\n", xfer, h->desc, h->fname);
-           n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
-           DBG("[ usb read %d ] = %d, fname=%s, Retry %d \n", xfer, n, h->fname, retry);
+           DBG("[ usb read %d fd = %d], fname=%s\n", xfer, handle_->desc, handle_->fname);
+           n = ioctl(handle_->desc, USBDEVFS_BULK, &bulk);
+           DBG("[ usb read %d ] = %d, fname=%s, Retry %d \n", xfer, n, handle_->fname, retry);
 
            if( n < 0 ) {
             DBG1("ERROR: n = %d, errno = %d (%s)\n",n, errno, strerror(errno));
@@ -446,24 +462,12 @@
     return count;
 }
 
-void usb_kick(usb_handle *h)
+int LinuxUsbTransport::Close()
 {
     int fd;
 
-    fd = h->desc;
-    h->desc = -1;
-    if(fd >= 0) {
-        close(fd);
-        DBG("[ usb closed %d ]\n", fd);
-    }
-}
-
-int usb_close(usb_handle *h)
-{
-    int fd;
-
-    fd = h->desc;
-    h->desc = -1;
+    fd = handle_->desc;
+    handle_->desc = -1;
     if(fd >= 0) {
         close(fd);
         DBG("[ usb closed %d ]\n", fd);
@@ -472,20 +476,21 @@
     return 0;
 }
 
-usb_handle *usb_open(ifc_match_func callback)
+Transport* usb_open(ifc_match_func callback)
 {
-    return find_usb_device("/sys/bus/usb/devices", callback);
+    std::unique_ptr<usb_handle> handle = find_usb_device("/sys/bus/usb/devices", callback);
+    return handle ? new LinuxUsbTransport(std::move(handle)) : nullptr;
 }
 
 /* Wait for the system to notice the device is gone, so that a subsequent
  * fastboot command won't try to access the device before it's rebooted.
  * Returns 0 for success, -1 for timeout.
  */
-int usb_wait_for_disconnect(usb_handle *usb)
+int LinuxUsbTransport::WaitForDisconnect()
 {
   double deadline = now() + WAIT_FOR_DISCONNECT_TIMEOUT;
   while (now() < deadline) {
-    if (access(usb->fname, F_OK))
+    if (access(handle_->fname, F_OK))
       return 0;
     usleep(50000);
   }
diff --git a/fastboot/usb_osx.cpp b/fastboot/usb_osx.cpp
index 45ae833..ee5d575 100644
--- a/fastboot/usb_osx.cpp
+++ b/fastboot/usb_osx.cpp
@@ -35,6 +35,8 @@
 #include <IOKit/IOMessage.h>
 #include <mach/mach_port.h>
 
+#include <memory>
+
 #include "usb.h"
 
 
@@ -63,6 +65,21 @@
     unsigned int zero_mask;
 };
 
+class OsxUsbTransport : public Transport {
+  public:
+    OsxUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
+    ~OsxUsbTransport() override = default;
+
+    ssize_t Read(void* data, size_t len) override;
+    ssize_t Write(const void* data, size_t len) override;
+    int Close() override;
+
+  private:
+    std::unique_ptr<usb_handle> handle_;
+
+    DISALLOW_COPY_AND_ASSIGN(OsxUsbTransport);
+};
+
 /** Try out all the interfaces and see if there's a match. Returns 0 on
  * success, -1 on failure. */
 static int try_interfaces(IOUSBDeviceInterface182 **dev, usb_handle *handle) {
@@ -390,7 +407,7 @@
 
 
 /** Initializes the USB system. Returns 0 on success, -1 on error. */
-static int init_usb(ifc_match_func callback, usb_handle **handle) {
+static int init_usb(ifc_match_func callback, std::unique_ptr<usb_handle>* handle) {
     int ret = -1;
     CFMutableDictionaryRef matchingDict;
     kern_return_t result;
@@ -443,8 +460,8 @@
         }
 
         if (h.success) {
-            *handle = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
-            memcpy(*handle, &h, sizeof(usb_handle));
+            handle->reset(new usb_handle);
+            memcpy(handle->get(), &h, sizeof(usb_handle));
             ret = 0;
             break;
         }
@@ -463,28 +480,23 @@
  * Definitions of this file's public functions.
  */
 
-usb_handle *usb_open(ifc_match_func callback) {
-    usb_handle *handle = NULL;
+Transport* usb_open(ifc_match_func callback) {
+    std::unique_ptr<usb_handle> handle;
 
     if (init_usb(callback, &handle) < 0) {
         /* Something went wrong initializing USB. */
-        return NULL;
+        return nullptr;
     }
 
-    return handle;
+    return new OsxUsbTransport(std::move(handle));
 }
 
-int usb_close(usb_handle *h) {
+int OsxUsbTransport::Close() {
     /* TODO: Something better here? */
     return 0;
 }
 
-int usb_wait_for_disconnect(usb_handle *usb) {
-    /* TODO: Punt for now */
-    return 0;
-}
-
-int usb_read(usb_handle *h, void *data, int len) {
+ssize_t OsxUsbTransport::Read(void* data, size_t len) {
     IOReturn result;
     UInt32 numBytes = len;
 
@@ -492,22 +504,21 @@
         return 0;
     }
 
-    if (h == NULL) {
+    if (handle_ == nullptr) {
         return -1;
     }
 
-    if (h->interface == NULL) {
+    if (handle_->interface == nullptr) {
         ERR("usb_read interface was null\n");
         return -1;
     }
 
-    if (h->bulkIn == 0) {
+    if (handle_->bulkIn == 0) {
         ERR("bulkIn endpoint not assigned\n");
         return -1;
     }
 
-    result = (*h->interface)->ReadPipe(
-            h->interface, h->bulkIn, data, &numBytes);
+    result = (*handle_->interface)->ReadPipe(handle_->interface, handle_->bulkIn, data, &numBytes);
 
     if (result == 0) {
         return (int) numBytes;
@@ -518,30 +529,30 @@
     return -1;
 }
 
-int usb_write(usb_handle *h, const void *data, int len) {
+ssize_t OsxUsbTransport::Write(const void* data, size_t len) {
     IOReturn result;
 
     if (len == 0) {
         return 0;
     }
 
-    if (h == NULL) {
+    if (handle_ == NULL) {
         return -1;
     }
 
-    if (h->interface == NULL) {
+    if (handle_->interface == NULL) {
         ERR("usb_write interface was null\n");
         return -1;
     }
 
-    if (h->bulkOut == 0) {
+    if (handle_->bulkOut == 0) {
         ERR("bulkOut endpoint not assigned\n");
         return -1;
     }
 
 #if 0
-    result = (*h->interface)->WritePipe(
-            h->interface, h->bulkOut, (void *)data, len);
+    result = (*handle_->interface)->WritePipe(
+            handle_->interface, handle_->bulkOut, (void *)data, len);
 #else
     /* Attempt to work around crashes in the USB driver that may be caused
      * by trying to write too much data at once.  The kernel IOCopyMapper
@@ -554,8 +565,8 @@
         int lenToSend = lenRemaining > maxLenToSend
             ? maxLenToSend : lenRemaining;
 
-        result = (*h->interface)->WritePipe(
-                h->interface, h->bulkOut, (void *)data, lenToSend);
+        result = (*handle_->interface)->WritePipe(
+                handle_->interface, handle_->bulkOut, (void *)data, lenToSend);
         if (result != 0) break;
 
         lenRemaining -= lenToSend;
@@ -564,11 +575,11 @@
 #endif
 
     #if 0
-    if ((result == 0) && (h->zero_mask)) {
+    if ((result == 0) && (handle_->zero_mask)) {
         /* we need 0-markers and our transfer */
-        if(!(len & h->zero_mask)) {
-            result = (*h->interface)->WritePipe(
-                    h->interface, h->bulkOut, (void *)data, 0);
+        if(!(len & handle_->zero_mask)) {
+            result = (*handle_->interface)->WritePipe(
+                    handle_->interface, handle_->bulkOut, (void *)data, 0);
         }
     }
     #endif
diff --git a/fastboot/usb_windows.cpp b/fastboot/usb_windows.cpp
index a09610f..1cdeb32 100644
--- a/fastboot/usb_windows.cpp
+++ b/fastboot/usb_windows.cpp
@@ -34,6 +34,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <memory>
+#include <string>
+
 #include "usb.h"
 
 //#define TRACE_USB 1
@@ -60,24 +63,32 @@
     ADBAPIHANDLE  adb_write_pipe;
 
     /// Interface name
-    char*         interface_name;
+    std::string interface_name;
+};
+
+class WindowsUsbTransport : public Transport {
+  public:
+    WindowsUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
+    ~WindowsUsbTransport() override = default;
+
+    ssize_t Read(void* data, size_t len) override;
+    ssize_t Write(const void* data, size_t len) override;
+    int Close() override;
+
+  private:
+    std::unique_ptr<usb_handle> handle_;
+
+    DISALLOW_COPY_AND_ASSIGN(WindowsUsbTransport);
 };
 
 /// Class ID assigned to the device by androidusb.sys
 static const GUID usb_class_id = ANDROID_USB_CLASS_ID;
 
-
 /// Checks if interface (device) matches certain criteria
 int recognized_device(usb_handle* handle, ifc_match_func callback);
 
 /// Opens usb interface (device) by interface (device) name.
-usb_handle* do_usb_open(const wchar_t* interface_name);
-
-/// Writes data to the opened usb handle
-int usb_write(usb_handle* handle, const void* data, int len);
-
-/// Reads data using the opened usb handle
-int usb_read(usb_handle *handle, void* data, int len);
+std::unique_ptr<usb_handle> do_usb_open(const wchar_t* interface_name);
 
 /// Cleans up opened usb handle
 void usb_cleanup_handle(usb_handle* handle);
@@ -85,23 +96,17 @@
 /// Cleans up (but don't close) opened usb handle
 void usb_kick(usb_handle* handle);
 
-/// Closes opened usb handle
-int usb_close(usb_handle* handle);
 
-
-usb_handle* do_usb_open(const wchar_t* interface_name) {
+std::unique_ptr<usb_handle> do_usb_open(const wchar_t* interface_name) {
     // Allocate our handle
-    usb_handle* ret = (usb_handle*)malloc(sizeof(usb_handle));
-    if (NULL == ret)
-        return NULL;
+    std::unique_ptr<usb_handle> ret(new usb_handle);
 
     // Create interface.
     ret->adb_interface = AdbCreateInterfaceByName(interface_name);
 
-    if (NULL == ret->adb_interface) {
-        free(ret);
+    if (nullptr == ret->adb_interface) {
         errno = GetLastError();
-        return NULL;
+        return nullptr;
     }
 
     // Open read pipe (endpoint)
@@ -109,35 +114,30 @@
         AdbOpenDefaultBulkReadEndpoint(ret->adb_interface,
                                    AdbOpenAccessTypeReadWrite,
                                    AdbOpenSharingModeReadWrite);
-    if (NULL != ret->adb_read_pipe) {
+    if (nullptr != ret->adb_read_pipe) {
         // Open write pipe (endpoint)
         ret->adb_write_pipe =
             AdbOpenDefaultBulkWriteEndpoint(ret->adb_interface,
                                       AdbOpenAccessTypeReadWrite,
                                       AdbOpenSharingModeReadWrite);
-        if (NULL != ret->adb_write_pipe) {
+        if (nullptr != ret->adb_write_pipe) {
             // Save interface name
             unsigned long name_len = 0;
 
             // First get expected name length
             AdbGetInterfaceName(ret->adb_interface,
-                          NULL,
+                          nullptr,
                           &name_len,
                           true);
             if (0 != name_len) {
-                ret->interface_name = (char*)malloc(name_len);
-
-                if (NULL != ret->interface_name) {
-                    // Now save the name
-                    if (AdbGetInterfaceName(ret->adb_interface,
-                                  ret->interface_name,
-                                  &name_len,
-                                  true)) {
-                        // We're done at this point
-                        return ret;
-                    }
-                } else {
-                    SetLastError(ERROR_OUTOFMEMORY);
+                // Now save the name
+                ret->interface_name.resize(name_len);
+                if (AdbGetInterfaceName(ret->adb_interface,
+                              &ret->interface_name[0],
+                              &name_len,
+                              true)) {
+                    // We're done at this point
+                    return ret;
                 }
             }
         }
@@ -145,35 +145,31 @@
 
     // Something went wrong.
     errno = GetLastError();
-    usb_cleanup_handle(ret);
-    free(ret);
+    usb_cleanup_handle(ret.get());
     SetLastError(errno);
 
-    return NULL;
+    return nullptr;
 }
 
-int usb_write(usb_handle* handle, const void* data, int len) {
+ssize_t WindowsUsbTransport::Write(const void* data, size_t len) {
     unsigned long time_out = 5000;
     unsigned long written = 0;
     unsigned count = 0;
     int ret;
 
     DBG("usb_write %d\n", len);
-    if (NULL != handle) {
+    if (nullptr != handle_) {
         // Perform write
         while(len > 0) {
             int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
-            ret = AdbWriteEndpointSync(handle->adb_write_pipe,
-                                   (void*)data,
-                                   (unsigned long)xfer,
-                                   &written,
-                                   time_out);
+            ret = AdbWriteEndpointSync(handle_->adb_write_pipe, const_cast<void*>(data), xfer,
+                                       &written, time_out);
             errno = GetLastError();
             DBG("AdbWriteEndpointSync returned %d, errno: %d\n", ret, errno);
             if (ret == 0) {
                 // assume ERROR_INVALID_HANDLE indicates we are disconnected
                 if (errno == ERROR_INVALID_HANDLE)
-                usb_kick(handle);
+                usb_kick(handle_.get());
                 return -1;
             }
 
@@ -194,21 +190,17 @@
     return -1;
 }
 
-int usb_read(usb_handle *handle, void* data, int len) {
+ssize_t WindowsUsbTransport::Read(void* data, size_t len) {
     unsigned long time_out = 0;
     unsigned long read = 0;
     int ret;
 
     DBG("usb_read %d\n", len);
-    if (NULL != handle) {
+    if (nullptr != handle_) {
         while (1) {
             int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
 
-	        ret = AdbReadEndpointSync(handle->adb_read_pipe,
-	                              (void*)data,
-	                              (unsigned long)xfer,
-	                              &read,
-	                              time_out);
+            ret = AdbReadEndpointSync(handle_->adb_read_pipe, data, xfer, &read, time_out);
             errno = GetLastError();
             DBG("usb_read got: %ld, expected: %d, errno: %d\n", read, xfer, errno);
             if (ret) {
@@ -216,7 +208,7 @@
             } else {
                 // assume ERROR_INVALID_HANDLE indicates we are disconnected
                 if (errno == ERROR_INVALID_HANDLE)
-                    usb_kick(handle);
+                    usb_kick(handle_.get());
                 break;
             }
             // else we timed out - try again
@@ -233,8 +225,6 @@
 
 void usb_cleanup_handle(usb_handle* handle) {
     if (NULL != handle) {
-        if (NULL != handle->interface_name)
-            free(handle->interface_name);
         if (NULL != handle->adb_write_pipe)
             AdbCloseHandle(handle->adb_write_pipe);
         if (NULL != handle->adb_read_pipe)
@@ -242,7 +232,7 @@
         if (NULL != handle->adb_interface)
             AdbCloseHandle(handle->adb_interface);
 
-        handle->interface_name = NULL;
+        handle->interface_name.clear();
         handle->adb_write_pipe = NULL;
         handle->adb_read_pipe = NULL;
         handle->adb_interface = NULL;
@@ -258,23 +248,18 @@
     }
 }
 
-int usb_close(usb_handle* handle) {
+int WindowsUsbTransport::Close() {
     DBG("usb_close\n");
 
-    if (NULL != handle) {
+    if (nullptr != handle_) {
         // Cleanup handle
-        usb_cleanup_handle(handle);
-        free(handle);
+        usb_cleanup_handle(handle_.get());
+        handle_.reset();
     }
 
     return 0;
 }
 
-int usb_wait_for_disconnect(usb_handle *usb) {
-    /* TODO: Punt for now */
-    return 0;
-}
-
 int recognized_device(usb_handle* handle, ifc_match_func callback) {
     struct usb_ifc_info info;
     USB_DEVICE_DESCRIPTOR device_desc;
@@ -326,8 +311,8 @@
     return 0;
 }
 
-static usb_handle *find_usb_device(ifc_match_func callback) {
-	usb_handle* handle = NULL;
+static std::unique_ptr<usb_handle> find_usb_device(ifc_match_func callback) {
+    std::unique_ptr<usb_handle> handle;
     char entry_buffer[2048];
     char interf_name[2048];
     AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
@@ -356,13 +341,12 @@
         handle = do_usb_open(next_interface->device_name);
         if (NULL != handle) {
             // Lets see if this interface (device) belongs to us
-            if (recognized_device(handle, callback)) {
+            if (recognized_device(handle.get(), callback)) {
                 // found it!
                 break;
             } else {
-                usb_cleanup_handle(handle);
-                free(handle);
-                handle = NULL;
+                usb_cleanup_handle(handle.get());
+                handle.reset();
             }
         }
 
@@ -373,9 +357,10 @@
     return handle;
 }
 
-usb_handle *usb_open(ifc_match_func callback)
+Transport* usb_open(ifc_match_func callback)
 {
-    return find_usb_device(callback);
+    std::unique_ptr<usb_handle> handle = find_usb_device(callback);
+    return handle ? new WindowsUsbTransport(std::move(handle)) : nullptr;
 }
 
 // called from fastboot.c
diff --git a/fastboot/usbtest.cpp b/fastboot/usbtest.cpp
index e6e2b37..9423c6d 100644
--- a/fastboot/usbtest.cpp
+++ b/fastboot/usbtest.cpp
@@ -86,7 +86,7 @@
     return 0;
 }
 
-int test_null(usb_handle *usb)
+int test_null(Transport* usb)
 {
     unsigned i;
     unsigned char buf[4096];
@@ -94,8 +94,8 @@
     long long t0, t1;
 
     t0 = NOW();
-    for(i = 0; i < arg_count; i++) {
-        if(usb_write(usb, buf, arg_size) != (int)arg_size) {
+    for (i = 0; i < arg_count; i++) {
+        if (usb->Write(buf, arg_size) != static_cast<int>(arg_size)) {
             fprintf(stderr,"write failed (%s)\n", strerror(errno));
             return -1;
         }
@@ -105,15 +105,15 @@
     return 0;
 }
 
-int test_zero(usb_handle *usb)
+int test_zero(Transport* usb)
 {
     unsigned i;
     unsigned char buf[4096];
     long long t0, t1;
 
     t0 = NOW();
-    for(i = 0; i < arg_count; i++) {
-        if(usb_read(usb, buf, arg_size) != (int)arg_size) {
+    for (i = 0; i < arg_count; i++) {
+        if (usb->Read(buf, arg_size) != static_cast<int>(arg_size)) {
             fprintf(stderr,"read failed (%s)\n", strerror(errno));
             return -1;
         }
@@ -127,7 +127,7 @@
 {
     const char *cmd;
     ifc_match_func match;
-    int (*test)(usb_handle *usb);
+    int (*test)(Transport* usb);
     const char *help;
 } tests[] = {
     { "list", printifc,   NULL,      "list interfaces" },
@@ -177,7 +177,7 @@
 
 int main(int argc, char **argv)
 {
-    usb_handle *usb;
+    Transport* usb;
     int i;
 
     if(argc < 2)
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index cb77a8e..63904b6 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -136,6 +136,9 @@
             { "USB_DCP", ANDROID_POWER_SUPPLY_TYPE_AC },
             { "USB_CDP", ANDROID_POWER_SUPPLY_TYPE_AC },
             { "USB_ACA", ANDROID_POWER_SUPPLY_TYPE_AC },
+            { "USB_C", ANDROID_POWER_SUPPLY_TYPE_AC },
+            { "USB_PD", ANDROID_POWER_SUPPLY_TYPE_AC },
+            { "USB_PD_DRP", ANDROID_POWER_SUPPLY_TYPE_USB },
             { "Wireless", ANDROID_POWER_SUPPLY_TYPE_WIRELESS },
             { NULL, 0 },
     };
diff --git a/include/log/log.h b/include/log/log.h
index 1cdf7bc..086d742 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -614,9 +614,11 @@
 
 /*
  * Use the per-tag properties "log.tag.<tagname>" to generate a runtime
- * result of non-zero to expose a log.
+ * result of non-zero to expose a log. prio is ANDROID_LOG_VERBOSE to
+ * ANDROID_LOG_FATAL. default_prio if no property. Undefined behavior if
+ * any other value.
  */
-int __android_log_is_loggable(int prio, const char *tag, int def);
+int __android_log_is_loggable(int prio, const char *tag, int default_prio);
 
 int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data,
                               uint32_t dataLen);
diff --git a/include/utils/LruCache.h b/include/utils/LruCache.h
index 1741fb2..ed96fe4 100644
--- a/include/utils/LruCache.h
+++ b/include/utils/LruCache.h
@@ -200,11 +200,11 @@
         return false;
     }
     Entry* entry = *find_result;
+    mSet->erase(entry);
     if (mListener) {
         (*mListener)(entry->key, entry->value);
     }
     detachFromCache(*entry);
-    mSet->erase(entry);
     delete entry;
     return true;
 }
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 2a178aa..f4454bb 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -88,6 +88,8 @@
     { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" },
     { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" },
     { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
+    { 00750, AID_ROOT,   AID_SHELL,  0, "data/nativetest" },
+    { 00750, AID_ROOT,   AID_SHELL,  0, "data/nativetest64" },
     { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
     { 00755, AID_ROOT,   AID_SYSTEM, 0, "mnt" },
     { 00755, AID_ROOT,   AID_ROOT,   0, "root" },
@@ -125,6 +127,8 @@
     { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  0, "data/media/*" },
     { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-private/*" },
     { 00644, AID_APP,       AID_APP,       0, "data/data/*" },
+    { 00640, AID_ROOT,      AID_SHELL,     0, "data/nativetest/tests.txt" },
+    { 00640, AID_ROOT,      AID_SHELL,     0, "data/nativetest64/tests.txt" },
     { 00750, AID_ROOT,      AID_SHELL,     0, "data/nativetest/*" },
     { 00750, AID_ROOT,      AID_SHELL,     0, "data/nativetest64/*" },
 
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index 8a8ece2..cb80ee6 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -99,6 +99,10 @@
 
 static void lock()
 {
+    /*
+     * If we trigger a signal handler in the middle of locked activity and the
+     * signal handler logs a message, we could get into a deadlock state.
+     */
     pthread_mutex_lock(&fakeLogDeviceLock);
 }
 
@@ -106,9 +110,12 @@
 {
     pthread_mutex_unlock(&fakeLogDeviceLock);
 }
+
 #else   // !defined(_WIN32)
+
 #define lock() ((void)0)
 #define unlock() ((void)0)
+
 #endif  // !defined(_WIN32)
 
 
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index 814d96d..e128edb 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -23,6 +23,22 @@
 
 #include <android/log.h>
 
+static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
+
+static void lock()
+{
+    /*
+     * If we trigger a signal handler in the middle of locked activity and the
+     * signal handler logs a message, we could get into a deadlock state.
+     */
+    pthread_mutex_lock(&lock_loggable);
+}
+
+static void unlock()
+{
+    pthread_mutex_unlock(&lock_loggable);
+}
+
 struct cache {
     const prop_info *pinfo;
     uint32_t serial;
@@ -49,9 +65,7 @@
     cache->c = buf[0];
 }
 
-static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
-
-static int __android_log_level(const char *tag, int def)
+static int __android_log_level(const char *tag, int default_prio)
 {
     /* sizeof() is used on this array below */
     static const char log_namespace[] = "persist.log.tag.";
@@ -86,7 +100,7 @@
 
     strcpy(key, log_namespace);
 
-    pthread_mutex_lock(&lock);
+    lock();
 
     current_global_serial = __system_property_area_serial();
 
@@ -156,7 +170,7 @@
 
     global_serial = current_global_serial;
 
-    pthread_mutex_unlock(&lock);
+    unlock();
 
     switch (toupper(c)) {
     case 'V': return ANDROID_LOG_VERBOSE;
@@ -168,36 +182,47 @@
     case 'A': return ANDROID_LOG_FATAL;
     case 'S': return -1; /* ANDROID_LOG_SUPPRESS */
     }
-    return def;
+    return default_prio;
 }
 
-int __android_log_is_loggable(int prio, const char *tag, int def)
+int __android_log_is_loggable(int prio, const char *tag, int default_prio)
 {
-    int logLevel = __android_log_level(tag, def);
+    int logLevel = __android_log_level(tag, default_prio);
     return logLevel >= 0 && prio >= logLevel;
 }
 
+/*
+ * Timestamp state generally remains constant, since a change is
+ * rare, we can accept a trylock failure gracefully. Use a separate
+ * lock from is_loggable to keep contention down b/25563384.
+ */
+static pthread_mutex_t lock_timestamp = PTHREAD_MUTEX_INITIALIZER;
+
 char android_log_timestamp()
 {
     static struct cache r_time_cache = { NULL, -1, 0 };
     static struct cache p_time_cache = { NULL, -1, 0 };
-    static uint32_t serial;
-    uint32_t current_serial;
     char retval;
 
-    pthread_mutex_lock(&lock);
+    if (pthread_mutex_trylock(&lock_timestamp)) {
+        /* We are willing to accept some race in this context */
+        if (!(retval = p_time_cache.c)) {
+            retval = r_time_cache.c;
+        }
+    } else {
+        static uint32_t serial;
+        uint32_t current_serial = __system_property_area_serial();
+        if (current_serial != serial) {
+            refresh_cache(&r_time_cache, "ro.logd.timestamp");
+            refresh_cache(&p_time_cache, "persist.logd.timestamp");
+            serial = current_serial;
+        }
+        if (!(retval = p_time_cache.c)) {
+            retval = r_time_cache.c;
+        }
 
-    current_serial = __system_property_area_serial();
-    if (current_serial != serial) {
-        refresh_cache(&r_time_cache, "ro.logd.timestamp");
-        refresh_cache(&p_time_cache, "persist.logd.timestamp");
-        serial = current_serial;
+        pthread_mutex_unlock(&lock_timestamp);
     }
-    if (!(retval = p_time_cache.c)) {
-        retval = r_time_cache.c;
-    }
-
-    pthread_mutex_unlock(&lock);
 
     return tolower(retval ?: 'r');
 }
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index a4310ae..83c6dc2 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -54,14 +54,35 @@
 
 static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
 static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
-#if !defined(_WIN32)
-static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
-#endif
 
 #ifndef __unused
 #define __unused  __attribute__((__unused__))
 #endif
 
+#if !defined(_WIN32)
+static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static void lock()
+{
+    /*
+     * If we trigger a signal handler in the middle of locked activity and the
+     * signal handler logs a message, we could get into a deadlock state.
+     */
+    pthread_mutex_lock(&log_init_lock);
+}
+
+static void unlock()
+{
+    pthread_mutex_unlock(&log_init_lock);
+}
+
+#else   /* !defined(_WIN32) */
+
+#define lock() ((void)0)
+#define unlock() ((void)0)
+
+#endif  /* !defined(_WIN32) */
+
 #if FAKE_LOG_DEVICE
 static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 };
 #else
@@ -277,15 +298,11 @@
     if (ret < 0) {
         ret = -errno;
         if (ret == -ENOTCONN) {
-#if !defined(_WIN32)
-            pthread_mutex_lock(&log_init_lock);
-#endif
+            lock();
             close(logd_fd);
             logd_fd = -1;
             ret = __write_to_log_initialize();
-#if !defined(_WIN32)
-            pthread_mutex_unlock(&log_init_lock);
-#endif
+            unlock();
 
             if (ret < 0) {
                 return ret;
@@ -329,18 +346,14 @@
 
 static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
 {
-#if !defined(_WIN32)
-    pthread_mutex_lock(&log_init_lock);
-#endif
+    lock();
 
     if (write_to_log == __write_to_log_init) {
         int ret;
 
         ret = __write_to_log_initialize();
         if (ret < 0) {
-#if !defined(_WIN32)
-            pthread_mutex_unlock(&log_init_lock);
-#endif
+            unlock();
 #if (FAKE_LOG_DEVICE == 0)
             if (pstore_fd >= 0) {
                 __write_to_log_daemon(log_id, vec, nr);
@@ -352,9 +365,7 @@
         write_to_log = __write_to_log_daemon;
     }
 
-#if !defined(_WIN32)
-    pthread_mutex_unlock(&log_init_lock);
-#endif
+    unlock();
 
     return write_to_log(log_id, vec, nr);
 }
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 9f12c96..ebf9786 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -908,7 +908,7 @@
                 } else if (*message == '\b') {
                     strcpy(buf, "\\b");
                 } else if (*message == '\t') {
-                    strcpy(buf, "\\t");
+                    strcpy(buf, "\t"); // Do not escape tabs
                 } else if (*message == '\v') {
                     strcpy(buf, "\\v");
                 } else if (*message == '\f') {
diff --git a/libutils/tests/LruCache_test.cpp b/libutils/tests/LruCache_test.cpp
index 580b980..dd95c57 100644
--- a/libutils/tests/LruCache_test.cpp
+++ b/libutils/tests/LruCache_test.cpp
@@ -73,6 +73,13 @@
 
 ssize_t ComplexValue::instanceCount = 0;
 
+struct KeyWithPointer {
+    int *ptr;
+    bool operator ==(const KeyWithPointer& other) const {
+        return *ptr == *other.ptr;
+    }
+};
+
 } // namespace
 
 
@@ -84,6 +91,10 @@
     return hash_type(value.k);
 }
 
+template<> inline android::hash_t hash_type(const KeyWithPointer& value) {
+    return hash_type(*value.ptr);
+}
+
 class EntryRemovedCallback : public OnEntryRemoved<SimpleKey, StringValue> {
 public:
     EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(NULL) { }
@@ -98,6 +109,14 @@
     StringValue lastValue;
 };
 
+class InvalidateKeyCallback : public OnEntryRemoved<KeyWithPointer, StringValue> {
+public:
+    void operator()(KeyWithPointer& k, StringValue&) {
+        delete k.ptr;
+        k.ptr = nullptr;
+    }
+};
+
 class LruCacheTest : public testing::Test {
 protected:
     virtual void SetUp() {
@@ -293,6 +312,25 @@
     EXPECT_EQ(3, callback.callbackCount);
 }
 
+TEST_F(LruCacheTest, CallbackRemovesKeyWorksOK) {
+    LruCache<KeyWithPointer, StringValue> cache(1);
+    InvalidateKeyCallback callback;
+    cache.setOnEntryRemovedListener(&callback);
+    KeyWithPointer key1;
+    key1.ptr = new int(1);
+    KeyWithPointer key2;
+    key2.ptr = new int(2);
+
+    cache.put(key1, "one");
+    // As the size of the cache is 1, the put will call the callback.
+    // Make sure everything goes smoothly even if the callback invalidates
+    // the key (b/24785286)
+    cache.put(key2, "two");
+    EXPECT_EQ(1U, cache.size());
+    EXPECT_STREQ("two", cache.get(key2));
+    cache.clear();
+}
+
 TEST_F(LruCacheTest, IteratorCheck) {
     LruCache<int, int> cache(100);
 
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index da5e78d..2a3f52f 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -582,7 +582,7 @@
     // Some may view the following as an ugly heuristic, the desire is to
     // beautify the kernel logs into an Android Logging format; the goal is
     // admirable but costly.
-    while ((isspace(*p) || !*p) && (p < &buf[len])) {
+    while ((p < &buf[len]) && (isspace(*p) || !*p)) {
         ++p;
     }
     if (p >= &buf[len]) { // timestamp, no content
@@ -596,7 +596,7 @@
         const char *bt, *et, *cp;
 
         bt = p;
-        if (!fast<strncmp>(p, "[INFO]", 6)) {
+        if ((taglen >= 6) && !fast<strncmp>(p, "[INFO]", 6)) {
             // <PRI>[<TIME>] "[INFO]"<tag> ":" message
             bt = p + 6;
             taglen -= 6;
@@ -620,7 +620,9 @@
             p = cp + 1;
         } else if (taglen) {
             size = et - bt;
-            if ((*bt == *cp) && fast<strncmp>(bt + 1, cp + 1, size - 1)) {
+            if ((taglen > size) &&   // enough space for match plus trailing :
+                    (*bt == *cp) &&  // ubber fast<strncmp> pair
+                    fast<strncmp>(bt + 1, cp + 1, size - 1)) {
                 // <PRI>[<TIME>] <tag>_host '<tag>.<num>' : message
                 if (!fast<strncmp>(bt + size - 5, "_host", 5)
                         && !fast<strncmp>(bt + 1, cp + 1, size - 6)) {
@@ -694,7 +696,7 @@
                     p = cp + 1;
                 }
             }
-        }
+        } /* else no tag */
         size = etag - tag;
         if ((size <= 1)
             // register names like x9
@@ -721,8 +723,12 @@
             taglen = mp - tag;
         }
     }
+    // Deal with sloppy and simplistic harmless p = cp + 1 etc above.
+    if (len < (size_t)(p - buf)) {
+        p = &buf[len];
+    }
     // skip leading space
-    while ((isspace(*p) || !*p) && (p < &buf[len])) {
+    while ((p < &buf[len]) && (isspace(*p) || !*p)) {
         ++p;
     }
     // truncate trailing space or nuls
@@ -735,16 +741,26 @@
         p = " ";
         b = 1;
     }
+    // paranoid sanity check, can not happen ...
     if (b > LOGGER_ENTRY_MAX_PAYLOAD) {
         b = LOGGER_ENTRY_MAX_PAYLOAD;
     }
+    if (taglen > LOGGER_ENTRY_MAX_PAYLOAD) {
+        taglen = LOGGER_ENTRY_MAX_PAYLOAD;
+    }
+    // calculate buffer copy requirements
     size_t n = 1 + taglen + 1 + b + 1;
-    int rc = n;
-    if ((taglen > n) || (b > n)) { // Can not happen ...
-        rc = -EINVAL;
-        return rc;
+    // paranoid sanity check, first two just can not happen ...
+    if ((taglen > n) || (b > n) || (n > USHRT_MAX)) {
+        return -EINVAL;
     }
 
+    // Careful.
+    // We are using the stack to house the log buffer for speed reasons.
+    // If we malloc'd this buffer, we could get away without n's USHRT_MAX
+    // test above, but we would then required a max(n, USHRT_MAX) as
+    // truncating length argument to logbuf->log() below. Gain is protection
+    // of stack sanity and speedup, loss is truncated long-line content.
     char newstr[n];
     char *np = newstr;
 
@@ -763,8 +779,8 @@
     np[b] = '\0';
 
     // Log message
-    rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr,
-                     (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+    int rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr,
+                         (unsigned short) n);
 
     // notify readers
     if (!rc) {
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
index 291c983..97c0d28 100644
--- a/metricsd/Android.mk
+++ b/metricsd/Android.mk
@@ -25,11 +25,14 @@
 metrics_client_sources := \
   metrics_client.cc
 
-metrics_daemon_common := \
+metrics_collector_common := \
   collectors/averaged_statistics_collector.cc \
   collectors/cpu_usage_collector.cc \
   collectors/disk_usage_collector.cc \
-  metrics_daemon.cc \
+  metrics_collector.cc \
+  persistent_integer.cc \
+
+metricsd_common := \
   persistent_integer.cc \
   serialization/metric_sample.cc \
   serialization/serialization_utils.cc \
@@ -40,14 +43,16 @@
   uploader/system_profile_cache.cc \
   uploader/upload_service.cc \
 
-metrics_tests_sources := \
+metrics_collector_tests_sources := \
   collectors/averaged_statistics_collector_test.cc \
   collectors/cpu_usage_collector_test.cc \
-  metrics_daemon_test.cc \
+  metrics_collector_test.cc \
   metrics_library_test.cc \
   persistent_integer_test.cc \
   serialization/serialization_utils_unittest.cc \
   timer_test.cc \
+
+metricsd_tests_sources := \
   uploader/metrics_hashes_unittest.cc \
   uploader/metrics_log_base_unittest.cc \
   uploader/mock/sender_mock.cc \
@@ -56,7 +61,6 @@
 metrics_CFLAGS := -Wall \
   -Wno-char-subscripts \
   -Wno-missing-field-initializers \
-  -Wno-unused-function \
   -Wno-unused-parameter \
   -Werror \
   -fvisibility=default
@@ -67,17 +71,22 @@
 metrics_includes := external/gtest/include \
   $(LOCAL_PATH)/include
 libmetrics_shared_libraries := libchrome libbrillo
-metrics_daemon_shared_libraries := $(libmetrics_shared_libraries) \
-  libbrillo-http \
+metrics_collector_shared_libraries := $(libmetrics_shared_libraries) \
   libbrillo-dbus \
+  libbrillo-http \
   libchrome-dbus \
   libdbus \
   libmetrics \
-  libprotobuf-cpp-lite \
   librootdev \
-  libupdate_engine_client \
   libweaved \
 
+metricsd_shared_libraries := \
+  libbrillo \
+  libbrillo-http \
+  libchrome \
+  libprotobuf-cpp-lite \
+  libupdate_engine_client \
+
 # Shared library for metrics.
 # ========================================================
 include $(CLEAR_VARS)
@@ -107,10 +116,10 @@
 LOCAL_SRC_FILES := $(metrics_client_sources)
 include $(BUILD_EXECUTABLE)
 
-# Protobuf library for metrics_daemon.
+# Protobuf library for metricsd.
 # ========================================================
 include $(CLEAR_VARS)
-LOCAL_MODULE := metrics_daemon_protos
+LOCAL_MODULE := metricsd_protos
 LOCAL_MODULE_CLASS := STATIC_LIBRARIES
 generated_sources_dir := $(call local-generated-sources-dir)
 LOCAL_EXPORT_C_INCLUDE_DIRS += \
@@ -118,40 +127,71 @@
 LOCAL_SRC_FILES :=  $(call all-proto-files-under,uploader/proto)
 include $(BUILD_STATIC_LIBRARY)
 
-# metrics daemon.
+# metrics_collector daemon.
 # ========================================================
 include $(CLEAR_VARS)
-LOCAL_MODULE := metrics_daemon
+LOCAL_MODULE := metrics_collector
 LOCAL_C_INCLUDES := $(metrics_includes)
 LOCAL_CFLAGS := $(metrics_CFLAGS)
+LOCAL_CLANG := true
 LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
 LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
-LOCAL_INIT_RC := metrics_daemon.rc
+LOCAL_INIT_RC := metrics_collector.rc
 LOCAL_REQUIRED_MODULES := \
   metrics.json \
-  metrics.schema.json \
-
+  metrics.schema.json
 LOCAL_RTTI_FLAG := -frtti
-LOCAL_SHARED_LIBRARIES := $(metrics_daemon_shared_libraries)
-LOCAL_CLANG := true
-LOCAL_SRC_FILES := $(metrics_daemon_common) \
-  metrics_daemon_main.cc
-LOCAL_STATIC_LIBRARIES := metrics_daemon_protos
+LOCAL_SHARED_LIBRARIES := $(metrics_collector_shared_libraries)
+LOCAL_SRC_FILES := $(metrics_collector_common) \
+  metrics_collector_main.cc
 include $(BUILD_EXECUTABLE)
 
-# Unit tests for metrics.
+# metricsd daemon.
 # ========================================================
 include $(CLEAR_VARS)
-LOCAL_MODULE := metrics_tests
-LOCAL_CLANG := true
+LOCAL_MODULE := metricsd
+LOCAL_C_INCLUDES := $(metrics_includes)
 LOCAL_CFLAGS := $(metrics_CFLAGS)
+LOCAL_CLANG := true
+LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
+LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
+LOCAL_INIT_RC := metricsd.rc
+LOCAL_REQUIRED_MODULES := \
+  metrics_collector
+LOCAL_RTTI_FLAG := -frtti
+LOCAL_SHARED_LIBRARIES := $(metricsd_shared_libraries)
+LOCAL_STATIC_LIBRARIES := metricsd_protos
+LOCAL_SRC_FILES := $(metricsd_common) \
+  metricsd_main.cc
+include $(BUILD_EXECUTABLE)
+
+# Unit tests for metricsd.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := metricsd_tests
+LOCAL_CFLAGS := $(metrics_CFLAGS)
+LOCAL_CLANG := true
 LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
 LOCAL_CPPFLAGS := $(metrics_CPPFLAGS) -Wno-sign-compare
 LOCAL_RTTI_FLAG := -frtti
-LOCAL_SHARED_LIBRARIES := $(metrics_daemon_shared_libraries)
-LOCAL_SRC_FILES := $(metrics_tests_sources) $(metrics_daemon_common)
-LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock metrics_daemon_protos
+LOCAL_SHARED_LIBRARIES := $(metricsd_shared_libraries) libmetrics
+LOCAL_SRC_FILES := $(metricsd_tests_sources) $(metricsd_common)
+LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock metricsd_protos
+include $(BUILD_NATIVE_TEST)
 
+# Unit tests for metrics_collector.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := metrics_collector_tests
+LOCAL_CFLAGS := $(metrics_CFLAGS)
+LOCAL_CLANG := true
+LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
+LOCAL_CPPFLAGS := $(metrics_CPPFLAGS) -Wno-sign-compare
+LOCAL_RTTI_FLAG := -frtti
+LOCAL_SHARED_LIBRARIES := $(metrics_collector_shared_libraries)
+LOCAL_SRC_FILES := $(metrics_collector_tests_sources) \
+  $(metrics_collector_common)
+LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock
 include $(BUILD_NATIVE_TEST)
 
 # Weave schema files
diff --git a/metricsd/collectors/averaged_statistics_collector.cc b/metricsd/collectors/averaged_statistics_collector.cc
index 0931e7b..bac2870 100644
--- a/metricsd/collectors/averaged_statistics_collector.cc
+++ b/metricsd/collectors/averaged_statistics_collector.cc
@@ -21,7 +21,7 @@
 #include <base/strings/string_number_conversions.h>
 #include <base/strings/string_split.h>
 
-#include "metrics_daemon.h"
+#include "metrics_collector.h"
 
 namespace {
 
@@ -90,7 +90,7 @@
 }
 
 void AveragedStatisticsCollector::ReadInitialValues() {
-  stats_start_time_ = MetricsDaemon::GetActiveTime();
+  stats_start_time_ = MetricsCollector::GetActiveTime();
   DiskStatsReadStats(&read_sectors_, &write_sectors_);
   VmStatsReadStats(&vmstats_);
 }
@@ -168,7 +168,7 @@
 void AveragedStatisticsCollector::Collect() {
   uint64_t read_sectors_now, write_sectors_now;
   struct VmstatRecord vmstats_now;
-  double time_now = MetricsDaemon::GetActiveTime();
+  double time_now = MetricsCollector::GetActiveTime();
   double delta_time = time_now - stats_start_time_;
   bool diskstats_success = DiskStatsReadStats(&read_sectors_now,
                                               &write_sectors_now);
diff --git a/metricsd/metrics_daemon.cc b/metricsd/metrics_collector.cc
similarity index 75%
rename from metricsd/metrics_daemon.cc
rename to metricsd/metrics_collector.cc
index b606fd0..28194a1 100644
--- a/metricsd/metrics_daemon.cc
+++ b/metricsd/metrics_collector.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "metrics_daemon.h"
+#include "metrics_collector.h"
 
 #include <sysexits.h>
 #include <time.h>
@@ -33,7 +33,6 @@
 #include <dbus/message.h>
 
 #include "constants.h"
-#include "uploader/upload_service.h"
 
 using base::FilePath;
 using base::StringPrintf;
@@ -74,18 +73,13 @@
 const char kMeminfoFileName[] = "/proc/meminfo";
 const char kVmStatFileName[] = "/proc/vmstat";
 
-// Thermal CPU throttling.
-
-const char kMetricScaledCpuFrequencyName[] =
-    "Platform.CpuFrequencyThermalScaling";
-
 }  // namespace
 
 // Zram sysfs entries.
 
-const char MetricsDaemon::kComprDataSizeName[] = "compr_data_size";
-const char MetricsDaemon::kOrigDataSizeName[] = "orig_data_size";
-const char MetricsDaemon::kZeroPagesName[] = "zero_pages";
+const char MetricsCollector::kComprDataSizeName[] = "compr_data_size";
+const char MetricsCollector::kOrigDataSizeName[] = "orig_data_size";
+const char MetricsCollector::kZeroPagesName[] = "zero_pages";
 
 // Memory use stats collection intervals.  We collect some memory use interval
 // at these intervals after boot, and we stop collecting after the last one,
@@ -99,15 +93,15 @@
   600 * kSecondsPerMinute,  // 12.5 hour mark
 };
 
-MetricsDaemon::MetricsDaemon()
+MetricsCollector::MetricsCollector()
     : memuse_final_time_(0),
       memuse_interval_index_(0) {}
 
-MetricsDaemon::~MetricsDaemon() {
+MetricsCollector::~MetricsCollector() {
 }
 
 // static
-double MetricsDaemon::GetActiveTime() {
+double MetricsCollector::GetActiveTime() {
   struct timespec ts;
   int r = clock_gettime(CLOCK_MONOTONIC, &ts);
   if (r < 0) {
@@ -118,7 +112,7 @@
   }
 }
 
-int MetricsDaemon::Run() {
+int MetricsCollector::Run() {
   if (CheckSystemCrash(kKernelCrashDetectedFile)) {
     ProcessKernelCrash();
   }
@@ -139,16 +133,7 @@
   return brillo::DBusDaemon::Run();
 }
 
-void MetricsDaemon::RunUploaderTest() {
-  upload_service_.reset(new UploadService(
-      new SystemProfileCache(true, metrics_directory_),
-      metrics_lib_,
-      server_));
-  upload_service_->Init(upload_interval_, metrics_directory_);
-  upload_service_->UploadEvent();
-}
-
-uint32_t MetricsDaemon::GetOsVersionHash() {
+uint32_t MetricsCollector::GetOsVersionHash() {
   brillo::OsReleaseReader reader;
   reader.Load();
   string version;
@@ -164,26 +149,15 @@
   return version_hash;
 }
 
-void MetricsDaemon::Init(bool testing,
-                         bool uploader_active,
-                         bool dbus_enabled,
+void MetricsCollector::Init(bool testing,
                          MetricsLibraryInterface* metrics_lib,
                          const string& diskstats_path,
-                         const string& scaling_max_freq_path,
-                         const string& cpuinfo_max_freq_path,
-                         const base::TimeDelta& upload_interval,
-                         const string& server,
                          const base::FilePath& metrics_directory) {
   CHECK(metrics_lib);
   testing_ = testing;
-  uploader_active_ = uploader_active;
-  dbus_enabled_ = dbus_enabled;
   metrics_directory_ = metrics_directory;
   metrics_lib_ = metrics_lib;
 
-  upload_interval_ = upload_interval;
-  server_ = server;
-
   daily_active_use_.reset(
       new PersistentInteger("Platform.UseTime.PerDay"));
   version_cumulative_active_use_.reset(
@@ -221,8 +195,6 @@
   weekly_cycle_.reset(new PersistentInteger("weekly.cycle"));
   version_cycle_.reset(new PersistentInteger("version.cycle"));
 
-  scaling_max_freq_path_ = scaling_max_freq_path;
-  cpuinfo_max_freq_path_ = cpuinfo_max_freq_path;
   disk_usage_collector_.reset(new DiskUsageCollector(metrics_lib_));
   averaged_stats_collector_.reset(
       new AveragedStatisticsCollector(metrics_lib_, diskstats_path,
@@ -230,9 +202,8 @@
   cpu_usage_collector_.reset(new CpuUsageCollector(metrics_lib_));
 }
 
-int MetricsDaemon::OnInit() {
-  int return_code = dbus_enabled_ ? brillo::DBusDaemon::OnInit() :
-      brillo::Daemon::OnInit();
+int MetricsCollector::OnInit() {
+  int return_code = brillo::DBusDaemon::OnInit();
   if (return_code != EX_OK)
     return return_code;
 
@@ -246,66 +217,58 @@
   if (testing_)
     return EX_OK;
 
-  if (dbus_enabled_) {
-    bus_->AssertOnDBusThread();
-    CHECK(bus_->SetUpAsyncOperations());
+  bus_->AssertOnDBusThread();
+  CHECK(bus_->SetUpAsyncOperations());
 
-    if (bus_->is_connected()) {
-      const std::string match_rule =
-          base::StringPrintf(kCrashReporterMatchRule,
-                             kCrashReporterInterface,
-                             kCrashReporterUserCrashSignal);
-
-      bus_->AddFilterFunction(&MetricsDaemon::MessageFilter, this);
-
-      DBusError error;
-      dbus_error_init(&error);
-      bus_->AddMatch(match_rule, &error);
-
-      if (dbus_error_is_set(&error)) {
-        LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
-            << error.name << ": " << error.message;
-        return EX_SOFTWARE;
-      }
-    } else {
-      LOG(ERROR) << "DBus isn't connected.";
-      return EX_UNAVAILABLE;
-    }
-
-    device_ = weaved::Device::CreateInstance(
-        bus_,
-        base::Bind(&MetricsDaemon::UpdateWeaveState, base::Unretained(this)));
-    device_->AddCommandHandler(
-        "_metrics._enableAnalyticsReporting",
-        base::Bind(&MetricsDaemon::OnEnableMetrics, base::Unretained(this)));
-    device_->AddCommandHandler(
-        "_metrics._disableAnalyticsReporting",
-        base::Bind(&MetricsDaemon::OnDisableMetrics, base::Unretained(this)));
-  }
-
-  latest_cpu_use_microseconds_ = cpu_usage_collector_->GetCumulativeCpuUse();
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::Bind(&MetricsDaemon::HandleUpdateStatsTimeout,
-                 base::Unretained(this)),
-      base::TimeDelta::FromMilliseconds(kUpdateStatsIntervalMs));
-
-  if (uploader_active_) {
-    upload_service_.reset(
-        new UploadService(new SystemProfileCache(), metrics_lib_, server_));
-    upload_service_->Init(upload_interval_, metrics_directory_);
-  }
-
-  return EX_OK;
-}
-
-void MetricsDaemon::OnShutdown(int* return_code) {
-  if (!testing_ && dbus_enabled_ && bus_->is_connected()) {
+  if (bus_->is_connected()) {
     const std::string match_rule =
         base::StringPrintf(kCrashReporterMatchRule,
                            kCrashReporterInterface,
                            kCrashReporterUserCrashSignal);
 
-    bus_->RemoveFilterFunction(&MetricsDaemon::MessageFilter, this);
+    bus_->AddFilterFunction(&MetricsCollector::MessageFilter, this);
+
+    DBusError error;
+    dbus_error_init(&error);
+    bus_->AddMatch(match_rule, &error);
+
+    if (dbus_error_is_set(&error)) {
+      LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
+          << error.name << ": " << error.message;
+      return EX_SOFTWARE;
+    }
+  } else {
+    LOG(ERROR) << "DBus isn't connected.";
+    return EX_UNAVAILABLE;
+  }
+
+  device_ = weaved::Device::CreateInstance(
+      bus_,
+      base::Bind(&MetricsCollector::UpdateWeaveState, base::Unretained(this)));
+  device_->AddCommandHandler(
+      "_metrics._enableAnalyticsReporting",
+      base::Bind(&MetricsCollector::OnEnableMetrics, base::Unretained(this)));
+  device_->AddCommandHandler(
+      "_metrics._disableAnalyticsReporting",
+      base::Bind(&MetricsCollector::OnDisableMetrics, base::Unretained(this)));
+
+  latest_cpu_use_microseconds_ = cpu_usage_collector_->GetCumulativeCpuUse();
+  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
+      base::Bind(&MetricsCollector::HandleUpdateStatsTimeout,
+                 base::Unretained(this)),
+      base::TimeDelta::FromMilliseconds(kUpdateStatsIntervalMs));
+
+  return EX_OK;
+}
+
+void MetricsCollector::OnShutdown(int* return_code) {
+  if (!testing_ && bus_->is_connected()) {
+    const std::string match_rule =
+        base::StringPrintf(kCrashReporterMatchRule,
+                           kCrashReporterInterface,
+                           kCrashReporterUserCrashSignal);
+
+    bus_->RemoveFilterFunction(&MetricsCollector::MessageFilter, this);
 
     DBusError error;
     dbus_error_init(&error);
@@ -319,7 +282,8 @@
   brillo::DBusDaemon::OnShutdown(return_code);
 }
 
-void MetricsDaemon::OnEnableMetrics(const std::weak_ptr<weaved::Command>& cmd) {
+void MetricsCollector::OnEnableMetrics(
+    const std::weak_ptr<weaved::Command>& cmd) {
   auto command = cmd.lock();
   if (!command)
     return;
@@ -336,7 +300,7 @@
   command->Complete({}, nullptr);
 }
 
-void MetricsDaemon::OnDisableMetrics(
+void MetricsCollector::OnDisableMetrics(
     const std::weak_ptr<weaved::Command>& cmd) {
   auto command = cmd.lock();
   if (!command)
@@ -354,7 +318,7 @@
   command->Complete({}, nullptr);
 }
 
-void MetricsDaemon::UpdateWeaveState() {
+void MetricsCollector::UpdateWeaveState() {
   if (!device_)
     return;
 
@@ -369,9 +333,9 @@
 }
 
 // static
-DBusHandlerResult MetricsDaemon::MessageFilter(DBusConnection* connection,
-                                               DBusMessage* message,
-                                               void* user_data) {
+DBusHandlerResult MetricsCollector::MessageFilter(DBusConnection* connection,
+                                                   DBusMessage* message,
+                                                   void* user_data) {
   int message_type = dbus_message_get_type(message);
   if (message_type != DBUS_MESSAGE_TYPE_SIGNAL) {
     DLOG(WARNING) << "unexpected message type " << message_type;
@@ -383,7 +347,7 @@
   const std::string member(dbus_message_get_member(message));
   DLOG(INFO) << "Got " << interface << "." << member << " D-Bus signal";
 
-  MetricsDaemon* daemon = static_cast<MetricsDaemon*>(user_data);
+  MetricsCollector* daemon = static_cast<MetricsCollector*>(user_data);
 
   DBusMessageIter iter;
   dbus_message_iter_init(message, &iter);
@@ -398,7 +362,7 @@
   return DBUS_HANDLER_RESULT_HANDLED;
 }
 
-void MetricsDaemon::ProcessUserCrash() {
+void MetricsCollector::ProcessUserCrash() {
   // Counts the active time up to now.
   UpdateStats(TimeTicks::Now(), Time::Now());
 
@@ -411,7 +375,7 @@
   user_crashes_weekly_count_->Add(1);
 }
 
-void MetricsDaemon::ProcessKernelCrash() {
+void MetricsCollector::ProcessKernelCrash() {
   // Counts the active time up to now.
   UpdateStats(TimeTicks::Now(), Time::Now());
 
@@ -426,7 +390,7 @@
   kernel_crashes_version_count_->Add(1);
 }
 
-void MetricsDaemon::ProcessUncleanShutdown() {
+void MetricsCollector::ProcessUncleanShutdown() {
   // Counts the active time up to now.
   UpdateStats(TimeTicks::Now(), Time::Now());
 
@@ -439,7 +403,7 @@
   any_crashes_weekly_count_->Add(1);
 }
 
-bool MetricsDaemon::CheckSystemCrash(const string& crash_file) {
+bool MetricsCollector::CheckSystemCrash(const string& crash_file) {
   FilePath crash_detected(crash_file);
   if (!base::PathExists(crash_detected))
     return false;
@@ -450,7 +414,7 @@
   return true;
 }
 
-void MetricsDaemon::StatsReporterInit() {
+void MetricsCollector::StatsReporterInit() {
   disk_usage_collector_->Schedule();
 
   cpu_usage_collector_->Init();
@@ -461,75 +425,18 @@
   averaged_stats_collector_->ScheduleWait();
 }
 
-
-bool MetricsDaemon::ReadFreqToInt(const string& sysfs_file_name, int* value) {
-  const FilePath sysfs_path(sysfs_file_name);
-  string value_string;
-  if (!base::ReadFileToString(sysfs_path, &value_string)) {
-    LOG(WARNING) << "cannot read " << sysfs_path.value().c_str();
-    return false;
-  }
-  if (!base::RemoveChars(value_string, "\n", &value_string)) {
-    LOG(WARNING) << "no newline in " << value_string;
-    // Continue even though the lack of newline is suspicious.
-  }
-  if (!base::StringToInt(value_string, value)) {
-    LOG(WARNING) << "cannot convert " << value_string << " to int";
-    return false;
-  }
-  return true;
-}
-
-void MetricsDaemon::SendCpuThrottleMetrics() {
-  // |max_freq| is 0 only the first time through.
-  static int max_freq = 0;
-  if (max_freq == -1)
-    // Give up, as sysfs did not report max_freq correctly.
-    return;
-  if (max_freq == 0 || testing_) {
-    // One-time initialization of max_freq.  (Every time when testing.)
-    if (!ReadFreqToInt(cpuinfo_max_freq_path_, &max_freq)) {
-      max_freq = -1;
-      return;
-    }
-    if (max_freq == 0) {
-      LOG(WARNING) << "sysfs reports 0 max CPU frequency\n";
-      max_freq = -1;
-      return;
-    }
-    if (max_freq % 10000 == 1000) {
-      // Special case: system has turbo mode, and max non-turbo frequency is
-      // max_freq - 1000.  This relies on "normal" (non-turbo) frequencies
-      // being multiples of (at least) 10 MHz.  Although there is no guarantee
-      // of this, it seems a fairly reasonable assumption.  Otherwise we should
-      // read scaling_available_frequencies, sort the frequencies, compare the
-      // two highest ones, and check if they differ by 1000 (kHz) (and that's a
-      // hack too, no telling when it will change).
-      max_freq -= 1000;
-    }
-  }
-  int scaled_freq = 0;
-  if (!ReadFreqToInt(scaling_max_freq_path_, &scaled_freq))
-    return;
-  // Frequencies are in kHz.  If scaled_freq > max_freq, turbo is on, but
-  // scaled_freq is not the actual turbo frequency.  We indicate this situation
-  // with a 101% value.
-  int percent = scaled_freq > max_freq ? 101 : scaled_freq / (max_freq / 100);
-  SendLinearSample(kMetricScaledCpuFrequencyName, percent, 101, 102);
-}
-
-void MetricsDaemon::ScheduleMeminfoCallback(int wait) {
+void MetricsCollector::ScheduleMeminfoCallback(int wait) {
   if (testing_) {
     return;
   }
   base::TimeDelta waitDelta = base::TimeDelta::FromSeconds(wait);
   base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::Bind(&MetricsDaemon::MeminfoCallback, base::Unretained(this),
+      base::Bind(&MetricsCollector::MeminfoCallback, base::Unretained(this),
                  waitDelta),
       waitDelta);
 }
 
-void MetricsDaemon::MeminfoCallback(base::TimeDelta wait) {
+void MetricsCollector::MeminfoCallback(base::TimeDelta wait) {
   string meminfo_raw;
   const FilePath meminfo_path(kMeminfoFileName);
   if (!base::ReadFileToString(meminfo_path, &meminfo_raw)) {
@@ -539,15 +446,15 @@
   // Make both calls even if the first one fails.
   if (ProcessMeminfo(meminfo_raw)) {
     base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-        base::Bind(&MetricsDaemon::MeminfoCallback, base::Unretained(this),
+        base::Bind(&MetricsCollector::MeminfoCallback, base::Unretained(this),
                    wait),
         wait);
   }
 }
 
 // static
-bool MetricsDaemon::ReadFileToUint64(const base::FilePath& path,
-                                     uint64_t* value) {
+bool MetricsCollector::ReadFileToUint64(const base::FilePath& path,
+                                         uint64_t* value) {
   std::string content;
   if (!base::ReadFileToString(path, &content)) {
     PLOG(WARNING) << "cannot read " << path.MaybeAsASCII();
@@ -562,7 +469,7 @@
   return true;
 }
 
-bool MetricsDaemon::ReportZram(const base::FilePath& zram_dir) {
+bool MetricsCollector::ReportZram(const base::FilePath& zram_dir) {
   // Data sizes are in bytes.  |zero_pages| is in number of pages.
   uint64_t compr_data_size, orig_data_size, zero_pages;
   const size_t page_size = 4096;
@@ -599,7 +506,7 @@
   return true;
 }
 
-bool MetricsDaemon::ProcessMeminfo(const string& meminfo_raw) {
+bool MetricsCollector::ProcessMeminfo(const string& meminfo_raw) {
   static const MeminfoRecord fields_array[] = {
     { "MemTotal", "MemTotal" },  // SPECIAL CASE: total system memory
     { "MemFree", "MemFree" },
@@ -670,8 +577,8 @@
   return true;
 }
 
-bool MetricsDaemon::FillMeminfo(const string& meminfo_raw,
-                                vector<MeminfoRecord>* fields) {
+bool MetricsCollector::FillMeminfo(const string& meminfo_raw,
+                                    vector<MeminfoRecord>* fields) {
   vector<string> lines;
   unsigned int nlines = Tokenize(meminfo_raw, "\n", &lines);
 
@@ -702,16 +609,16 @@
   return true;
 }
 
-void MetricsDaemon::ScheduleMemuseCallback(double interval) {
+void MetricsCollector::ScheduleMemuseCallback(double interval) {
   if (testing_) {
     return;
   }
   base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::Bind(&MetricsDaemon::MemuseCallback, base::Unretained(this)),
+      base::Bind(&MetricsCollector::MemuseCallback, base::Unretained(this)),
       base::TimeDelta::FromSeconds(interval));
 }
 
-void MetricsDaemon::MemuseCallback() {
+void MetricsCollector::MemuseCallback() {
   // Since we only care about active time (i.e. uptime minus sleep time) but
   // the callbacks are driven by real time (uptime), we check if we should
   // reschedule this callback due to intervening sleep periods.
@@ -732,7 +639,7 @@
   }
 }
 
-bool MetricsDaemon::MemuseCallbackWork() {
+bool MetricsCollector::MemuseCallbackWork() {
   string meminfo_raw;
   const FilePath meminfo_path(kMeminfoFileName);
   if (!base::ReadFileToString(meminfo_path, &meminfo_raw)) {
@@ -742,7 +649,7 @@
   return ProcessMemuse(meminfo_raw);
 }
 
-bool MetricsDaemon::ProcessMemuse(const string& meminfo_raw) {
+bool MetricsCollector::ProcessMemuse(const string& meminfo_raw) {
   static const MeminfoRecord fields_array[] = {
     { "MemTotal", "MemTotal" },  // SPECIAL CASE: total system memory
     { "ActiveAnon", "Active(anon)" },
@@ -768,12 +675,12 @@
   return true;
 }
 
-void MetricsDaemon::SendSample(const string& name, int sample,
-                               int min, int max, int nbuckets) {
+void MetricsCollector::SendSample(const string& name, int sample,
+                                   int min, int max, int nbuckets) {
   metrics_lib_->SendToUMA(name, sample, min, max, nbuckets);
 }
 
-void MetricsDaemon::SendKernelCrashesCumulativeCountStats() {
+void MetricsCollector::SendKernelCrashesCumulativeCountStats() {
   // Report the number of crashes for this OS version, but don't clear the
   // counter.  It is cleared elsewhere on version change.
   int64_t crashes_count = kernel_crashes_version_count_->Get();
@@ -818,7 +725,7 @@
   }
 }
 
-void MetricsDaemon::SendAndResetDailyUseSample(
+void MetricsCollector::SendAndResetDailyUseSample(
     const scoped_ptr<PersistentInteger>& use) {
   SendSample(use->Name(),
              use->GetAndClear(),
@@ -827,7 +734,7 @@
              50);                      // number of buckets
 }
 
-void MetricsDaemon::SendAndResetCrashIntervalSample(
+void MetricsCollector::SendAndResetCrashIntervalSample(
     const scoped_ptr<PersistentInteger>& interval) {
   SendSample(interval->Name(),
              interval->GetAndClear(),
@@ -836,7 +743,7 @@
              50);                      // number of buckets
 }
 
-void MetricsDaemon::SendAndResetCrashFrequencySample(
+void MetricsCollector::SendAndResetCrashFrequencySample(
     const scoped_ptr<PersistentInteger>& frequency) {
   SendSample(frequency->Name(),
              frequency->GetAndClear(),
@@ -845,16 +752,16 @@
              50);                      // number of buckets
 }
 
-void MetricsDaemon::SendLinearSample(const string& name, int sample,
-                                     int max, int nbuckets) {
+void MetricsCollector::SendLinearSample(const string& name, int sample,
+                                         int max, int nbuckets) {
   // TODO(semenzato): add a proper linear histogram to the Chrome external
   // metrics API.
   LOG_IF(FATAL, nbuckets != max + 1) << "unsupported histogram scale";
   metrics_lib_->SendEnumToUMA(name, sample, max);
 }
 
-void MetricsDaemon::UpdateStats(TimeTicks now_ticks,
-                                Time now_wall_time) {
+void MetricsCollector::UpdateStats(TimeTicks now_ticks,
+                                    Time now_wall_time) {
   const int elapsed_seconds = (now_ticks - last_update_stats_time_).InSeconds();
   daily_active_use_->Add(elapsed_seconds);
   version_cumulative_active_use_->Add(elapsed_seconds);
@@ -889,10 +796,10 @@
   }
 }
 
-void MetricsDaemon::HandleUpdateStatsTimeout() {
+void MetricsCollector::HandleUpdateStatsTimeout() {
   UpdateStats(TimeTicks::Now(), Time::Now());
   base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::Bind(&MetricsDaemon::HandleUpdateStatsTimeout,
+      base::Bind(&MetricsCollector::HandleUpdateStatsTimeout,
                  base::Unretained(this)),
       base::TimeDelta::FromMilliseconds(kUpdateStatsIntervalMs));
 }
diff --git a/metricsd/metrics_daemon.h b/metricsd/metrics_collector.h
similarity index 80%
rename from metricsd/metrics_daemon.h
rename to metricsd/metrics_collector.h
index f12b02e..e080ac0 100644
--- a/metricsd/metrics_daemon.h
+++ b/metricsd/metrics_collector.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef METRICS_METRICS_DAEMON_H_
-#define METRICS_METRICS_DAEMON_H_
+#ifndef METRICS_METRICS_COLLECTOR_H_
+#define METRICS_METRICS_COLLECTOR_H_
 
 #include <stdint.h>
 
@@ -36,25 +36,18 @@
 #include "collectors/disk_usage_collector.h"
 #include "metrics/metrics_library.h"
 #include "persistent_integer.h"
-#include "uploader/upload_service.h"
 
 using chromeos_metrics::PersistentInteger;
 
-class MetricsDaemon : public brillo::DBusDaemon {
+class MetricsCollector : public brillo::DBusDaemon {
  public:
-  MetricsDaemon();
-  ~MetricsDaemon();
+  MetricsCollector();
+  ~MetricsCollector();
 
   // Initializes metrics class variables.
   void Init(bool testing,
-            bool uploader_active,
-            bool dbus_enabled,
             MetricsLibraryInterface* metrics_lib,
             const std::string& diskstats_path,
-            const std::string& cpuinfo_max_freq_path,
-            const std::string& scaling_max_freq_path,
-            const base::TimeDelta& upload_interval,
-            const std::string& server,
             const base::FilePath& metrics_directory);
 
   // Initializes DBus and MessageLoop variables before running the MessageLoop.
@@ -66,9 +59,6 @@
   // Does all the work.
   int Run() override;
 
-  // Triggers an upload event and exit. (Used to test UploadService)
-  void RunUploaderTest();
-
   // Returns the active time since boot (uptime minus sleep time) in seconds.
   static double GetActiveTime();
 
@@ -79,26 +69,24 @@
   static const char kZeroPagesName[];
 
  private:
-  friend class MetricsDaemonTest;
-  FRIEND_TEST(MetricsDaemonTest, CheckSystemCrash);
-  FRIEND_TEST(MetricsDaemonTest, ComputeEpochNoCurrent);
-  FRIEND_TEST(MetricsDaemonTest, ComputeEpochNoLast);
-  FRIEND_TEST(MetricsDaemonTest, GetHistogramPath);
-  FRIEND_TEST(MetricsDaemonTest, IsNewEpoch);
-  FRIEND_TEST(MetricsDaemonTest, MessageFilter);
-  FRIEND_TEST(MetricsDaemonTest, ProcessKernelCrash);
-  FRIEND_TEST(MetricsDaemonTest, ProcessMeminfo);
-  FRIEND_TEST(MetricsDaemonTest, ProcessMeminfo2);
-  FRIEND_TEST(MetricsDaemonTest, ProcessUncleanShutdown);
-  FRIEND_TEST(MetricsDaemonTest, ProcessUserCrash);
-  FRIEND_TEST(MetricsDaemonTest, ReportCrashesDailyFrequency);
-  FRIEND_TEST(MetricsDaemonTest, ReadFreqToInt);
-  FRIEND_TEST(MetricsDaemonTest, ReportKernelCrashInterval);
-  FRIEND_TEST(MetricsDaemonTest, ReportUncleanShutdownInterval);
-  FRIEND_TEST(MetricsDaemonTest, ReportUserCrashInterval);
-  FRIEND_TEST(MetricsDaemonTest, SendSample);
-  FRIEND_TEST(MetricsDaemonTest, SendCpuThrottleMetrics);
-  FRIEND_TEST(MetricsDaemonTest, SendZramMetrics);
+  friend class MetricsCollectorTest;
+  FRIEND_TEST(MetricsCollectorTest, CheckSystemCrash);
+  FRIEND_TEST(MetricsCollectorTest, ComputeEpochNoCurrent);
+  FRIEND_TEST(MetricsCollectorTest, ComputeEpochNoLast);
+  FRIEND_TEST(MetricsCollectorTest, GetHistogramPath);
+  FRIEND_TEST(MetricsCollectorTest, IsNewEpoch);
+  FRIEND_TEST(MetricsCollectorTest, MessageFilter);
+  FRIEND_TEST(MetricsCollectorTest, ProcessKernelCrash);
+  FRIEND_TEST(MetricsCollectorTest, ProcessMeminfo);
+  FRIEND_TEST(MetricsCollectorTest, ProcessMeminfo2);
+  FRIEND_TEST(MetricsCollectorTest, ProcessUncleanShutdown);
+  FRIEND_TEST(MetricsCollectorTest, ProcessUserCrash);
+  FRIEND_TEST(MetricsCollectorTest, ReportCrashesDailyFrequency);
+  FRIEND_TEST(MetricsCollectorTest, ReportKernelCrashInterval);
+  FRIEND_TEST(MetricsCollectorTest, ReportUncleanShutdownInterval);
+  FRIEND_TEST(MetricsCollectorTest, ReportUserCrashInterval);
+  FRIEND_TEST(MetricsCollectorTest, SendSample);
+  FRIEND_TEST(MetricsCollectorTest, SendZramMetrics);
 
   // Type of scale to use for meminfo histograms.  For most of them we use
   // percent of total RAM, but for some we use absolute numbers, usually in
@@ -215,12 +203,6 @@
   // Parses meminfo data and sends it to UMA.
   bool ProcessMemuse(const std::string& meminfo_raw);
 
-  // Sends stats for thermal CPU throttling.
-  void SendCpuThrottleMetrics();
-
-  // Reads an integer CPU frequency value from sysfs.
-  bool ReadFreqToInt(const std::string& sysfs_file_name, int* value);
-
   // Reads the current OS version from /etc/lsb-release and hashes it
   // to a unsigned 32-bit int.
   uint32_t GetOsVersionHash();
@@ -243,13 +225,6 @@
   // Test mode.
   bool testing_;
 
-  // Whether the uploader is enabled or disabled.
-  bool uploader_active_;
-
-  // Whether or not dbus should be used.
-  // If disabled, we will not collect the frequency of crashes.
-  bool dbus_enabled_;
-
   // Root of the configuration files to use.
   base::FilePath metrics_directory_;
 
@@ -301,14 +276,7 @@
   scoped_ptr<DiskUsageCollector> disk_usage_collector_;
   scoped_ptr<AveragedStatisticsCollector> averaged_stats_collector_;
 
-  std::string scaling_max_freq_path_;
-  std::string cpuinfo_max_freq_path_;
-
-  base::TimeDelta upload_interval_;
-  std::string server_;
-
-  scoped_ptr<UploadService> upload_service_;
   std::unique_ptr<weaved::Device> device_;
 };
 
-#endif  // METRICS_METRICS_DAEMON_H_
+#endif  // METRICS_METRICS_COLLECTOR_H_
diff --git a/metricsd/metrics_collector.rc b/metricsd/metrics_collector.rc
new file mode 100644
index 0000000..2e7e0ae
--- /dev/null
+++ b/metricsd/metrics_collector.rc
@@ -0,0 +1,4 @@
+service metricscollector /system/bin/metrics_collector --foreground --logtosyslog
+    class late_start
+    user system
+    group system dbus
diff --git a/metricsd/metrics_collector_main.cc b/metricsd/metrics_collector_main.cc
new file mode 100644
index 0000000..117426e
--- /dev/null
+++ b/metricsd/metrics_collector_main.cc
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <base/at_exit.h>
+#include <base/command_line.h>
+#include <base/logging.h>
+#include <base/strings/string_util.h>
+#include <brillo/flag_helper.h>
+#include <brillo/syslog_logging.h>
+#include <rootdev.h>
+
+#include "constants.h"
+#include "metrics_collector.h"
+
+
+// Returns the path to the disk stats in the sysfs.  Returns the null string if
+// it cannot find the disk stats file.
+static
+const std::string MetricsMainDiskStatsPath() {
+  char dev_path_cstr[PATH_MAX];
+  std::string dev_prefix = "/dev/block/";
+  std::string dev_path;
+
+  int ret = rootdev(dev_path_cstr, sizeof(dev_path_cstr), true, true);
+  if (ret != 0) {
+    LOG(WARNING) << "error " << ret << " determining root device";
+    return "";
+  }
+  dev_path = dev_path_cstr;
+  // Check that rootdev begins with "/dev/block/".
+  if (!base::StartsWithASCII(dev_path, dev_prefix, false)) {
+    LOG(WARNING) << "unexpected root device " << dev_path;
+    return "";
+  }
+  return "/sys/class/block/" + dev_path.substr(dev_prefix.length()) + "/stat";
+}
+
+int main(int argc, char** argv) {
+  DEFINE_bool(foreground, false, "Don't daemonize");
+
+  DEFINE_string(metrics_directory,
+                metrics::kMetricsDirectory,
+                "Root of the configuration files (testing only)");
+
+  DEFINE_bool(logtostderr, false, "Log to standard error");
+  DEFINE_bool(logtosyslog, false, "Log to syslog");
+
+  brillo::FlagHelper::Init(argc, argv, "Chromium OS Metrics Daemon");
+
+  int logging_location = (FLAGS_foreground ? brillo::kLogToStderr
+                          : brillo::kLogToSyslog);
+  if (FLAGS_logtosyslog)
+    logging_location = brillo::kLogToSyslog;
+
+  if (FLAGS_logtostderr)
+    logging_location = brillo::kLogToStderr;
+
+  // Also log to stderr when not running as daemon.
+  brillo::InitLog(logging_location | brillo::kLogHeader);
+
+  if (FLAGS_logtostderr && FLAGS_logtosyslog) {
+    LOG(ERROR) << "only one of --logtosyslog and --logtostderr can be set";
+    return 1;
+  }
+
+  if (!FLAGS_foreground && daemon(0, 0) != 0) {
+    return errno;
+  }
+
+  MetricsLibrary metrics_lib;
+  metrics_lib.InitWithNoCaching();
+  MetricsCollector daemon;
+  daemon.Init(false,
+              &metrics_lib,
+              MetricsMainDiskStatsPath(),
+              base::FilePath(FLAGS_metrics_directory));
+
+  daemon.Run();
+}
diff --git a/metricsd/metrics_daemon_test.cc b/metricsd/metrics_collector_test.cc
similarity index 75%
rename from metricsd/metrics_daemon_test.cc
rename to metricsd/metrics_collector_test.cc
index d3c9a23..a0e7087 100644
--- a/metricsd/metrics_daemon_test.cc
+++ b/metricsd/metrics_collector_test.cc
@@ -24,7 +24,7 @@
 #include <gtest/gtest.h>
 
 #include "constants.h"
-#include "metrics_daemon.h"
+#include "metrics_collector.h"
 #include "metrics/metrics_library_mock.h"
 #include "persistent_integer_mock.h"
 
@@ -40,29 +40,15 @@
 using chromeos_metrics::PersistentIntegerMock;
 
 
-class MetricsDaemonTest : public testing::Test {
+class MetricsCollectorTest : public testing::Test {
  protected:
   virtual void SetUp() {
     brillo::FlagHelper::Init(0, nullptr, "");
     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
-    scaling_max_freq_path_ = temp_dir_.path().Append("scaling_max");
-    cpu_max_freq_path_ = temp_dir_.path().Append("cpu_freq_max");
-
-    CreateUint64ValueFile(cpu_max_freq_path_, 10000000);
-    CreateUint64ValueFile(scaling_max_freq_path_, 10000000);
 
     chromeos_metrics::PersistentInteger::SetMetricsDirectory(
         temp_dir_.path().value());
-    daemon_.Init(true,
-                 false,
-                 true,
-                 &metrics_lib_,
-                 "",
-                 scaling_max_freq_path_.value(),
-                 cpu_max_freq_path_.value(),
-                 base::TimeDelta::FromMinutes(30),
-                 metrics::kMetricsServer,
-                 temp_dir_.path());
+    daemon_.Init(true, &metrics_lib_, "", temp_dir_.path());
   }
 
   // Adds a metrics library mock expectation that the specified metric
@@ -114,28 +100,24 @@
                               value_string.length()));
   }
 
-  // The MetricsDaemon under test.
-  MetricsDaemon daemon_;
+  // The MetricsCollector under test.
+  MetricsCollector daemon_;
 
   // Temporary directory used for tests.
   base::ScopedTempDir temp_dir_;
 
-  // Path for the fake files.
-  base::FilePath scaling_max_freq_path_;
-  base::FilePath cpu_max_freq_path_;
-
   // Mocks. They are strict mock so that all unexpected
   // calls are marked as failures.
   StrictMock<MetricsLibraryMock> metrics_lib_;
 };
 
-TEST_F(MetricsDaemonTest, MessageFilter) {
+TEST_F(MetricsCollectorTest, MessageFilter) {
   // Ignore calls to SendToUMA.
   EXPECT_CALL(metrics_lib_, SendToUMA(_, _, _, _, _)).Times(AnyNumber());
 
   DBusMessage* msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL);
   DBusHandlerResult res =
-      MetricsDaemon::MessageFilter(/* connection */ nullptr, msg, &daemon_);
+      MetricsCollector::MessageFilter(/* connection */ nullptr, msg, &daemon_);
   EXPECT_EQ(DBUS_HANDLER_RESULT_NOT_YET_HANDLED, res);
   DeleteDBusMessage(msg);
 
@@ -144,7 +126,7 @@
                             "org.chromium.CrashReporter",
                             "UserCrash",
                             signal_args);
-  res = MetricsDaemon::MessageFilter(/* connection */ nullptr, msg, &daemon_);
+  res = MetricsCollector::MessageFilter(/* connection */ nullptr, msg, &daemon_);
   EXPECT_EQ(DBUS_HANDLER_RESULT_HANDLED, res);
   DeleteDBusMessage(msg);
 
@@ -155,18 +137,18 @@
                             "org.chromium.UnknownService.Manager",
                             "StateChanged",
                             signal_args);
-  res = MetricsDaemon::MessageFilter(/* connection */ nullptr, msg, &daemon_);
+  res = MetricsCollector::MessageFilter(/* connection */ nullptr, msg, &daemon_);
   EXPECT_EQ(DBUS_HANDLER_RESULT_NOT_YET_HANDLED, res);
   DeleteDBusMessage(msg);
 }
 
-TEST_F(MetricsDaemonTest, SendSample) {
+TEST_F(MetricsCollectorTest, SendSample) {
   ExpectSample("Dummy.Metric", 3);
   daemon_.SendSample("Dummy.Metric", /* sample */ 3,
                      /* min */ 1, /* max */ 100, /* buckets */ 50);
 }
 
-TEST_F(MetricsDaemonTest, ProcessMeminfo) {
+TEST_F(MetricsCollectorTest, ProcessMeminfo) {
   string meminfo =
       "MemTotal:        2000000 kB\nMemFree:          500000 kB\n"
       "Buffers:         1000000 kB\nCached:           213652 kB\n"
@@ -203,40 +185,13 @@
   EXPECT_TRUE(daemon_.ProcessMeminfo(meminfo));
 }
 
-TEST_F(MetricsDaemonTest, ProcessMeminfo2) {
+TEST_F(MetricsCollectorTest, ProcessMeminfo2) {
   string meminfo = "MemTotal:        2000000 kB\nMemFree:         1000000 kB\n";
   // Not enough fields.
   EXPECT_FALSE(daemon_.ProcessMeminfo(meminfo));
 }
 
-TEST_F(MetricsDaemonTest, ReadFreqToInt) {
-  const int fake_scaled_freq = 1666999;
-  const int fake_max_freq = 2000000;
-  int scaled_freq = 0;
-  int max_freq = 0;
-  CreateUint64ValueFile(scaling_max_freq_path_, fake_scaled_freq);
-  CreateUint64ValueFile(cpu_max_freq_path_, fake_max_freq);
-  EXPECT_TRUE(daemon_.testing_);
-  EXPECT_TRUE(daemon_.ReadFreqToInt(scaling_max_freq_path_.value(),
-                                    &scaled_freq));
-  EXPECT_TRUE(daemon_.ReadFreqToInt(cpu_max_freq_path_.value(), &max_freq));
-  EXPECT_EQ(fake_scaled_freq, scaled_freq);
-  EXPECT_EQ(fake_max_freq, max_freq);
-}
-
-TEST_F(MetricsDaemonTest, SendCpuThrottleMetrics) {
-  CreateUint64ValueFile(cpu_max_freq_path_, 2001000);
-  // Test the 101% and 100% cases.
-  CreateUint64ValueFile(scaling_max_freq_path_, 2001000);
-  EXPECT_TRUE(daemon_.testing_);
-  EXPECT_CALL(metrics_lib_, SendEnumToUMA(_, 101, 101));
-  daemon_.SendCpuThrottleMetrics();
-  CreateUint64ValueFile(scaling_max_freq_path_, 2000000);
-  EXPECT_CALL(metrics_lib_, SendEnumToUMA(_, 100, 101));
-  daemon_.SendCpuThrottleMetrics();
-}
-
-TEST_F(MetricsDaemonTest, SendZramMetrics) {
+TEST_F(MetricsCollectorTest, SendZramMetrics) {
   EXPECT_TRUE(daemon_.testing_);
 
   // |compr_data_size| is the size in bytes of compressed data.
@@ -248,13 +203,13 @@
   const uint64_t zero_pages = 10 * 1000 * 1000 / page_size;
 
   CreateUint64ValueFile(
-      temp_dir_.path().Append(MetricsDaemon::kComprDataSizeName),
+      temp_dir_.path().Append(MetricsCollector::kComprDataSizeName),
       compr_data_size);
   CreateUint64ValueFile(
-      temp_dir_.path().Append(MetricsDaemon::kOrigDataSizeName),
+      temp_dir_.path().Append(MetricsCollector::kOrigDataSizeName),
       orig_data_size);
   CreateUint64ValueFile(
-      temp_dir_.path().Append(MetricsDaemon::kZeroPagesName), zero_pages);
+      temp_dir_.path().Append(MetricsCollector::kZeroPagesName), zero_pages);
 
   const uint64_t real_orig_size = orig_data_size + zero_pages * page_size;
   const uint64_t zero_ratio_percent =
diff --git a/metricsd/metrics_daemon_main.cc b/metricsd/metrics_daemon_main.cc
deleted file mode 100644
index 50c279d..0000000
--- a/metricsd/metrics_daemon_main.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <base/at_exit.h>
-#include <base/command_line.h>
-#include <base/logging.h>
-#include <base/strings/string_util.h>
-#include <brillo/flag_helper.h>
-#include <brillo/syslog_logging.h>
-#include <rootdev.h>
-
-#include "constants.h"
-#include "metrics_daemon.h"
-
-const char kScalingMaxFreqPath[] =
-    "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq";
-const char kCpuinfoMaxFreqPath[] =
-    "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
-
-// Returns the path to the disk stats in the sysfs.  Returns the null string if
-// it cannot find the disk stats file.
-static
-const std::string MetricsMainDiskStatsPath() {
-  char dev_path_cstr[PATH_MAX];
-  std::string dev_prefix = "/dev/block/";
-  std::string dev_path;
-
-  int ret = rootdev(dev_path_cstr, sizeof(dev_path_cstr), true, true);
-  if (ret != 0) {
-    LOG(WARNING) << "error " << ret << " determining root device";
-    return "";
-  }
-  dev_path = dev_path_cstr;
-  // Check that rootdev begins with "/dev/block/".
-  if (!base::StartsWithASCII(dev_path, dev_prefix, false)) {
-    LOG(WARNING) << "unexpected root device " << dev_path;
-    return "";
-  }
-  return "/sys/class/block/" + dev_path.substr(dev_prefix.length()) + "/stat";
-}
-
-int main(int argc, char** argv) {
-  DEFINE_bool(daemon, true, "run as daemon (use -nodaemon for debugging)");
-
-  // The uploader is disabled by default on ChromeOS as Chrome is responsible
-  // for sending the metrics.
-  DEFINE_bool(uploader, false, "activate the uploader");
-
-  // Upload the metrics once and exit. (used for testing)
-  DEFINE_bool(uploader_test,
-              false,
-              "run the uploader once and exit");
-
-  // Enable dbus.
-  DEFINE_bool(withdbus, true, "Enable dbus");
-
-  // Upload Service flags.
-  DEFINE_int32(upload_interval_secs,
-               1800,
-               "Interval at which metrics_daemon sends the metrics. (needs "
-               "-uploader)");
-  DEFINE_string(server,
-                metrics::kMetricsServer,
-                "Server to upload the metrics to. (needs -uploader)");
-  DEFINE_string(metrics_directory,
-                metrics::kMetricsDirectory,
-                "Root of the configuration files (testing only)");
-
-  brillo::FlagHelper::Init(argc, argv, "Chromium OS Metrics Daemon");
-
-  // Also log to stderr when not running as daemon.
-  brillo::InitLog(brillo::kLogToSyslog | brillo::kLogHeader |
-                  (FLAGS_daemon ? 0 : brillo::kLogToStderr));
-
-  if (FLAGS_daemon && daemon(0, 0) != 0) {
-    return errno;
-  }
-
-  MetricsLibrary metrics_lib;
-  metrics_lib.InitWithNoCaching();
-  MetricsDaemon daemon;
-  daemon.Init(FLAGS_uploader_test,
-              FLAGS_uploader | FLAGS_uploader_test,
-              FLAGS_withdbus,
-              &metrics_lib,
-              MetricsMainDiskStatsPath(),
-              kScalingMaxFreqPath,
-              kCpuinfoMaxFreqPath,
-              base::TimeDelta::FromSeconds(FLAGS_upload_interval_secs),
-              FLAGS_server,
-              base::FilePath(FLAGS_metrics_directory));
-
-  if (FLAGS_uploader_test) {
-    daemon.RunUploaderTest();
-    return 0;
-  }
-
-  daemon.Run();
-}
diff --git a/metricsd/metrics_daemon.rc b/metricsd/metricsd.rc
similarity index 64%
rename from metricsd/metrics_daemon.rc
rename to metricsd/metricsd.rc
index 0ee577e..b5e7b82 100644
--- a/metricsd/metrics_daemon.rc
+++ b/metricsd/metricsd.rc
@@ -1,7 +1,7 @@
 on post-fs-data
     mkdir /data/misc/metrics 0770 system system
 
-service metrics_daemon /system/bin/metrics_daemon --uploader -nodaemon
+service metricsd /system/bin/metricsd --foreground --logtosyslog
     class late_start
     user system
     group system dbus inet
diff --git a/metricsd/metricsd_main.cc b/metricsd/metricsd_main.cc
new file mode 100644
index 0000000..ab71e6b
--- /dev/null
+++ b/metricsd/metricsd_main.cc
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <base/at_exit.h>
+#include <base/command_line.h>
+#include <base/files/file_path.h>
+#include <base/logging.h>
+#include <base/strings/string_util.h>
+#include <base/time/time.h>
+#include <brillo/flag_helper.h>
+#include <brillo/syslog_logging.h>
+
+#include "constants.h"
+#include "uploader/upload_service.h"
+
+
+int main(int argc, char** argv) {
+  DEFINE_bool(foreground, false, "Don't daemonize");
+
+  // Upload the metrics once and exit. (used for testing)
+  DEFINE_bool(uploader_test,
+              false,
+              "run the uploader once and exit");
+
+  // Upload Service flags.
+  DEFINE_int32(upload_interval_secs,
+               1800,
+               "Interval at which metrics_daemon sends the metrics. (needs "
+               "-uploader)");
+  DEFINE_string(server,
+                metrics::kMetricsServer,
+                "Server to upload the metrics to. (needs -uploader)");
+  DEFINE_string(metrics_directory,
+                metrics::kMetricsDirectory,
+                "Root of the configuration files (testing only)");
+
+  DEFINE_bool(logtostderr, false, "Log to standard error");
+  DEFINE_bool(logtosyslog, false, "Log to syslog");
+
+  brillo::FlagHelper::Init(argc, argv, "Brillo metrics daemon.");
+
+  int logging_location = (FLAGS_foreground ? brillo::kLogToStderr
+                          : brillo::kLogToSyslog);
+  if (FLAGS_logtosyslog)
+    logging_location = brillo::kLogToSyslog;
+
+  if (FLAGS_logtostderr)
+    logging_location = brillo::kLogToStderr;
+
+  // Also log to stderr when not running as daemon.
+  brillo::InitLog(logging_location | brillo::kLogHeader);
+
+  if (FLAGS_logtostderr && FLAGS_logtosyslog) {
+    LOG(ERROR) << "only one of --logtosyslog and --logtostderr can be set";
+    return 1;
+  }
+
+  if (!FLAGS_foreground && daemon(0, 0) != 0) {
+    return errno;
+  }
+
+  UploadService service(FLAGS_server,
+                        base::TimeDelta::FromSeconds(FLAGS_upload_interval_secs),
+                        base::FilePath(FLAGS_metrics_directory));
+
+  service.Run();
+}
diff --git a/metricsd/persistent_integer.cc b/metricsd/persistent_integer.cc
index e849f00..ddc4b50 100644
--- a/metricsd/persistent_integer.cc
+++ b/metricsd/persistent_integer.cc
@@ -22,7 +22,6 @@
 #include <base/posix/eintr_wrapper.h>
 
 #include "constants.h"
-#include "metrics/metrics_library.h"
 
 
 namespace chromeos_metrics {
diff --git a/metricsd/uploader/system_profile_cache.cc b/metricsd/uploader/system_profile_cache.cc
index f7060a2..8928a0d 100644
--- a/metricsd/uploader/system_profile_cache.cc
+++ b/metricsd/uploader/system_profile_cache.cc
@@ -84,10 +84,12 @@
     auto client = update_engine::UpdateEngineClient::CreateInstance();
     if (!client->GetChannel(&channel)) {
       LOG(ERROR) << "failed to read the current channel from update engine.";
+      return false;
     }
   }
 
-  if (!reader.GetString(metrics::kProductId, &profile_.product_id)) {
+  if (!reader.GetString(metrics::kProductId, &profile_.product_id)
+      || profile_.product_id.empty()) {
     LOG(ERROR) << "product_id is not set.";
     return false;
   }
@@ -179,13 +181,13 @@
 
 metrics::SystemProfileProto_Channel SystemProfileCache::ProtoChannelFromString(
     const std::string& channel) {
-  if (channel == "stable") {
+  if (channel == "stable-channel") {
     return metrics::SystemProfileProto::CHANNEL_STABLE;
-  } else if (channel == "dev") {
+  } else if (channel == "dev-channel") {
     return metrics::SystemProfileProto::CHANNEL_DEV;
-  } else if (channel == "beta") {
+  } else if (channel == "beta-channel") {
     return metrics::SystemProfileProto::CHANNEL_BETA;
-  } else if (channel == "canary") {
+  } else if (channel == "canary-channel") {
     return metrics::SystemProfileProto::CHANNEL_CANARY;
   }
 
diff --git a/metricsd/uploader/system_profile_cache.h b/metricsd/uploader/system_profile_cache.h
index ae54a2a..0a21ad4 100644
--- a/metricsd/uploader/system_profile_cache.h
+++ b/metricsd/uploader/system_profile_cache.h
@@ -69,6 +69,7 @@
   FRIEND_TEST(UploadServiceTest, ReadKeyValueFromFile);
   FRIEND_TEST(UploadServiceTest, SessionIdIncrementedAtInitialization);
   FRIEND_TEST(UploadServiceTest, ValuesInConfigFileAreSent);
+  FRIEND_TEST(UploadServiceTest, ProductIdMandatory);
 
   // Fetches all informations and populates |profile_|
   bool Initialize();
diff --git a/metricsd/uploader/upload_service.cc b/metricsd/uploader/upload_service.cc
index b630cec..ca5024e 100644
--- a/metricsd/uploader/upload_service.cc
+++ b/metricsd/uploader/upload_service.cc
@@ -16,6 +16,8 @@
 
 #include "uploader/upload_service.h"
 
+#include <sysexits.h>
+
 #include <string>
 
 #include <base/bind.h>
@@ -39,38 +41,34 @@
 
 const int UploadService::kMaxFailedUpload = 10;
 
-UploadService::UploadService(SystemProfileSetter* setter,
-                             MetricsLibraryInterface* metrics_lib,
-                             const std::string& server)
-    : system_profile_setter_(setter),
-      metrics_lib_(metrics_lib),
-      histogram_snapshot_manager_(this),
+UploadService::UploadService(const std::string& server,
+                             const base::TimeDelta& upload_interval,
+                             const base::FilePath& metrics_directory)
+    : histogram_snapshot_manager_(this),
       sender_(new HttpSender(server)),
       failed_upload_count_(metrics::kFailedUploadCountName),
-      testing_(false) {
-}
-
-UploadService::UploadService(SystemProfileSetter* setter,
-                             MetricsLibraryInterface* metrics_lib,
-                             const std::string& server,
-                             bool testing)
-    : UploadService(setter, metrics_lib, server) {
-  testing_ = testing;
-}
-
-void UploadService::Init(const base::TimeDelta& upload_interval,
-                         const base::FilePath& metrics_directory) {
-  base::StatisticsRecorder::Initialize();
+      upload_interval_(upload_interval) {
   metrics_file_ = metrics_directory.Append(metrics::kMetricsEventsFileName);
   staged_log_path_ = metrics_directory.Append(metrics::kStagedLogName);
+  consent_file_ = metrics_directory.Append(metrics::kConsentFileName);
+}
 
-  if (!testing_) {
-    base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-        base::Bind(&UploadService::UploadEventCallback,
-                   base::Unretained(this),
-                   upload_interval),
-        upload_interval);
-  }
+int UploadService::OnInit() {
+  base::StatisticsRecorder::Initialize();
+
+  system_profile_setter_.reset(new SystemProfileCache());
+
+  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
+      base::Bind(&UploadService::UploadEventCallback,
+                 base::Unretained(this),
+                 upload_interval_),
+      upload_interval_);
+  return EX_OK;
+}
+
+void UploadService::InitForTest(SystemProfileSetter* setter) {
+  base::StatisticsRecorder::Initialize();
+  system_profile_setter_.reset(setter);
 }
 
 void UploadService::StartNewLog() {
@@ -114,7 +112,7 @@
 
 void UploadService::SendStagedLog() {
   // If metrics are not enabled, discard the log and exit.
-  if (!metrics_lib_->AreMetricsEnabled()) {
+  if (!AreMetricsEnabled()) {
     LOG(INFO) << "Metrics disabled. Don't upload metrics samples.";
     base::DeleteFile(staged_log_path_, false);
     return;
@@ -263,3 +261,8 @@
     failed_upload_count_.Set(0);
   }
 }
+
+bool UploadService::AreMetricsEnabled() {
+  return base::PathExists(consent_file_);
+}
+
diff --git a/metricsd/uploader/upload_service.h b/metricsd/uploader/upload_service.h
index 77df74b..7faf357 100644
--- a/metricsd/uploader/upload_service.h
+++ b/metricsd/uploader/upload_service.h
@@ -19,11 +19,11 @@
 
 #include <string>
 
-#include "base/metrics/histogram_base.h"
-#include "base/metrics/histogram_flattener.h"
-#include "base/metrics/histogram_snapshot_manager.h"
+#include <base/metrics/histogram_base.h>
+#include <base/metrics/histogram_flattener.h>
+#include <base/metrics/histogram_snapshot_manager.h>
+#include <brillo/daemons/daemon.h>
 
-#include "metrics/metrics_library.h"
 #include "persistent_integer.h"
 #include "uploader/metrics_log.h"
 #include "uploader/sender.h"
@@ -67,14 +67,14 @@
 //    - if the upload fails, we keep the staged log in memory to retry
 //      uploading later.
 //
-class UploadService : public base::HistogramFlattener {
+class UploadService : public base::HistogramFlattener, public brillo::Daemon {
  public:
-  explicit UploadService(SystemProfileSetter* setter,
-                         MetricsLibraryInterface* metrics_lib,
-                         const std::string& server);
+  UploadService(const std::string& server,
+                const base::TimeDelta& upload_interval,
+                const base::FilePath& metrics_directory);
 
-  void Init(const base::TimeDelta& upload_interval,
-            const base::FilePath& metrics_directory);
+  // Initializes the upload service.
+  int OnInit();
 
   // Starts a new log. The log needs to be regenerated after each successful
   // launch as it is destroyed when staging the log.
@@ -114,11 +114,8 @@
   FRIEND_TEST(UploadServiceTest, UnknownCrashIgnored);
   FRIEND_TEST(UploadServiceTest, ValuesInConfigFileAreSent);
 
-  // Private constructor for use in unit testing.
-  UploadService(SystemProfileSetter* setter,
-                MetricsLibraryInterface* metrics_lib,
-                const std::string& server,
-                bool testing);
+  // Initializes the upload service for testing.
+  void InitForTest(SystemProfileSetter* setter);
 
   // If a staged log fails to upload more than kMaxFailedUpload times, it
   // will be discarded.
@@ -136,6 +133,9 @@
   // Adds a crash to the current log.
   void AddCrash(const std::string& crash_name);
 
+  // Returns true iff metrics reporting is enabled.
+  bool AreMetricsEnabled();
+
   // Aggregates all histogram available in memory and store them in the current
   // log.
   void GatherHistograms();
@@ -158,12 +158,14 @@
   MetricsLog* GetOrCreateCurrentLog();
 
   scoped_ptr<SystemProfileSetter> system_profile_setter_;
-  MetricsLibraryInterface* metrics_lib_;
   base::HistogramSnapshotManager histogram_snapshot_manager_;
   scoped_ptr<Sender> sender_;
   chromeos_metrics::PersistentInteger failed_upload_count_;
   scoped_ptr<MetricsLog> current_log_;
+  
+  base::TimeDelta upload_interval_;
 
+  base::FilePath consent_file_;
   base::FilePath metrics_file_;
   base::FilePath staged_log_path_;
 
diff --git a/metricsd/uploader/upload_service_test.cc b/metricsd/uploader/upload_service_test.cc
index 236376a..24e3127 100644
--- a/metricsd/uploader/upload_service_test.cc
+++ b/metricsd/uploader/upload_service_test.cc
@@ -44,11 +44,11 @@
     metrics_lib_.InitForTest(dir_.path());
     ASSERT_EQ(0, base::WriteFile(
         dir_.path().Append(metrics::kConsentFileName), "", 0));
-    upload_service_.reset(new UploadService(new MockSystemProfileSetter(),
-                                            &metrics_lib_, "", true));
+    upload_service_.reset(new UploadService("", base::TimeDelta(),
+                                            dir_.path()));
 
     upload_service_->sender_.reset(new SenderMock);
-    upload_service_->Init(base::TimeDelta::FromMinutes(30), dir_.path());
+    upload_service_->InitForTest(new MockSystemProfileSetter);
     upload_service_->GatherHistograms();
     upload_service_->Reset();
   }
@@ -58,7 +58,8 @@
   }
 
   void SetTestingProperty(const std::string& name, const std::string& value) {
-    base::FilePath filepath = dir_.path().Append("etc/os-release.d").Append(name);
+    base::FilePath filepath =
+        dir_.path().Append("etc/os-release.d").Append(name);
     ASSERT_TRUE(base::CreateDirectory(filepath.DirName()));
     ASSERT_EQ(
         value.size(),
@@ -159,8 +160,7 @@
 }
 
 TEST_F(UploadServiceTest, LogEmptyByDefault) {
-  UploadService upload_service(new MockSystemProfileSetter(), &metrics_lib_,
-                               "");
+  UploadService upload_service("", base::TimeDelta(), dir_.path());
 
   // current_log_ should be initialized later as it needs AtExitManager to exit
   // in order to gather system information from SysInfo.
@@ -214,10 +214,10 @@
       metrics::SystemProfileProto::CHANNEL_UNKNOWN);
 
   EXPECT_EQ(metrics::SystemProfileProto::CHANNEL_DEV,
-            SystemProfileCache::ProtoChannelFromString("dev"));
+            SystemProfileCache::ProtoChannelFromString("dev-channel"));
 
   EXPECT_EQ(metrics::SystemProfileProto::CHANNEL_STABLE,
-            SystemProfileCache::ProtoChannelFromString("stable"));
+            SystemProfileCache::ProtoChannelFromString("stable-channel"));
 
   EXPECT_EQ(metrics::SystemProfileProto::CHANNEL_UNKNOWN,
             SystemProfileCache::ProtoChannelFromString("this is a test"));
@@ -291,3 +291,14 @@
 
   EXPECT_EQ(1, sender->send_call_count());
 }
+
+// The product id must be set for metrics to be uploaded.
+// If it is not set, the system profile cache should fail to initialize.
+TEST_F(UploadServiceTest, ProductIdMandatory) {
+  SystemProfileCache cache(true, dir_.path());
+  ASSERT_FALSE(cache.Initialize());
+  SetTestingProperty(metrics::kProductId, "");
+  ASSERT_FALSE(cache.Initialize());
+  SetTestingProperty(metrics::kProductId, "hello");
+  ASSERT_TRUE(cache.Initialize());
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index b134f93..895a25d 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -48,6 +48,8 @@
     ln -sf /storage/self/primary $(TARGET_ROOT_OUT)/sdcard
 ifdef BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE
   LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/vendor
+else
+  LOCAL_POST_INSTALL_CMD += ; ln -sf /system/vendor $(TARGET_ROOT_OUT)/vendor
 endif
 ifdef BOARD_ROOT_EXTRA_SYMLINKS
 # BOARD_ROOT_EXTRA_SYMLINKS is a list of <target>:<link_name>.
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 7fa4b95..a0b1acf 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -342,7 +342,6 @@
 
     # create dalvik-cache, so as to enforce our permissions
     mkdir /data/dalvik-cache 0771 root root
-    mkdir /data/dalvik-cache/profiles 0711 system system
 
     # create resource-cache and double-check the perms
     mkdir /data/resource-cache 0771 system system
diff --git a/toolbox/top.c b/toolbox/top.c
index 1e99d4c..0ea5a5e 100644
--- a/toolbox/top.c
+++ b/toolbox/top.c
@@ -158,7 +158,7 @@
             fprintf(stderr, "Invalid argument \"%s\" for option -s.\n", argv[i]);
             exit(EXIT_FAILURE);
         }
-        if (!strcmp(argv[i], "-t")) { threads = 1; continue; }
+        if (!strcmp(argv[i], "-H") || !strcmp(argv[i], "-t")) { threads = 1; continue; }
         if (!strcmp(argv[i], "-h")) {
             usage(argv[0]);
             exit(EXIT_SUCCESS);
@@ -187,6 +187,7 @@
         read_procs();
         print_procs();
         free_old_procs();
+        fflush(stdout);
     }
 
     return 0;
@@ -566,7 +567,7 @@
                     "    -n num  Updates to show before exiting.\n"
                     "    -d num  Seconds to wait between updates.\n"
                     "    -s col  Column to sort by (cpu,vss,rss,thr).\n"
-                    "    -t      Show threads instead of processes.\n"
+                    "    -H      Show threads instead of processes.\n"
                     "    -h      Display this help screen.\n",
         cmd);
 }