Merge "libsparse: use strcmp and validate last_used pointer"
diff --git a/.gitignore b/.gitignore
index b25c15b..2f836aa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 *~
+*.pyc
diff --git a/adb/Android.mk b/adb/Android.mk
index 355bb7f..e2d0bb1 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -11,6 +11,9 @@
     adb_host_clang := true
 endif
 
+adb_host_sanitize :=
+adb_target_sanitize :=
+
 adb_version := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/null)-android
 
 ADB_COMMON_CFLAGS := \
@@ -19,6 +22,15 @@
     -Wno-missing-field-initializers \
     -DADB_REVISION='"$(adb_version)"' \
 
+# 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()).
+ADB_COMMON_windows_CFLAGS := \
+    -DUNICODE=1 -D_UNICODE=1 \
+
+ADB_COMMON_CFLAGS += $(ADB_COMMON_$(HOST_OS)_CFLAGS)
+
 # libadb
 # =========================================================
 
@@ -64,7 +76,6 @@
     usb_linux.cpp \
 
 LIBADB_windows_SRC_FILES := \
-    get_my_path_windows.cpp \
     sysdeps_win32.cpp \
     usb_windows.cpp \
 
@@ -80,6 +91,7 @@
     qemu_tracing.cpp \
     usb_linux_client.cpp \
 
+LOCAL_SANITIZE := $(adb_target_sanitize)
 LOCAL_SHARED_LIBRARIES := libbase
 
 # Even though we're building a static library (and thus there's no link step for
@@ -97,6 +109,7 @@
     $(LIBADB_$(HOST_OS)_SRC_FILES) \
     adb_auth_host.cpp \
 
+LOCAL_SANITIZE := $(adb_host_sanitize)
 LOCAL_SHARED_LIBRARIES := libbase
 
 # Even though we're building a static library (and thus there's no link step for
@@ -114,16 +127,20 @@
 LOCAL_MODULE := adbd_test
 LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS)
 LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS)
+LOCAL_SANITIZE := $(adb_target_sanitize)
 LOCAL_STATIC_LIBRARIES := libadbd
 LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
 include $(BUILD_NATIVE_TEST)
 
-ifneq ($(HOST_OS),windows)
+# adb_test
+# =========================================================
+
 include $(CLEAR_VARS)
 LOCAL_CLANG := $(adb_host_clang)
 LOCAL_MODULE := adb_test
 LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
 LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS) services.cpp
+LOCAL_SANITIZE := $(adb_host_sanitize)
 LOCAL_SHARED_LIBRARIES := liblog libbase
 LOCAL_STATIC_LIBRARIES := \
     libadb \
@@ -138,9 +155,13 @@
     LOCAL_LDLIBS += -framework CoreFoundation -framework IOKit
 endif
 
-include $(BUILD_HOST_NATIVE_TEST)
+ifeq ($(HOST_OS),windows)
+    LOCAL_LDLIBS += -lws2_32 -luserenv
+    LOCAL_STATIC_LIBRARIES += AdbWinApi
 endif
 
+include $(BUILD_HOST_NATIVE_TEST)
+
 # adb device tracker (used by ddms) test tool
 # =========================================================
 
@@ -150,6 +171,7 @@
 LOCAL_MODULE := adb_device_tracker_test
 LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
 LOCAL_SRC_FILES := test_track_devices.cpp
+LOCAL_SANITIZE := $(adb_host_sanitize)
 LOCAL_SHARED_LIBRARIES := liblog libbase
 LOCAL_STATIC_LIBRARIES := libadb libcrypto_static libcutils
 LOCAL_LDLIBS += -lrt -ldl -lpthread
@@ -171,6 +193,8 @@
 endif
 
 ifeq ($(HOST_OS),windows)
+    # Use wmain instead of main
+    LOCAL_LDFLAGS += -municode
     LOCAL_LDLIBS += -lws2_32 -lgdi32
     EXTRA_STATIC_LIBS := AdbWinApi
 endif
@@ -193,6 +217,7 @@
 LOCAL_MODULE := adb
 LOCAL_MODULE_TAGS := debug
 
+LOCAL_SANITIZE := $(adb_host_sanitize)
 LOCAL_STATIC_LIBRARIES := \
     libadb \
     libbase \
@@ -257,6 +282,7 @@
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
 LOCAL_C_INCLUDES += system/extras/ext4_utils
 
+LOCAL_SANITIZE := $(adb_target_sanitize)
 LOCAL_STATIC_LIBRARIES := \
     libadbd \
     libbase \
diff --git a/adb/adb.cpp b/adb/adb.cpp
index aa9ef55..29c9481 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -35,6 +35,7 @@
 #include <unordered_map>
 
 #include <base/logging.h>
+#include <base/macros.h>
 #include <base/stringprintf.h>
 #include <base/strings.h>
 
@@ -54,11 +55,11 @@
 
 ADB_MUTEX_DEFINE(D_lock);
 
-int HOST = 0;
-
 #if !ADB_HOST
 const char* adb_device_banner = "device";
 static android::base::LogdLogger gLogdLogger;
+#else
+const char* adb_device_banner = "host";
 #endif
 
 void AdbLogger(android::base::LogId id, android::base::LogSeverity severity,
@@ -70,6 +71,14 @@
 #endif
 }
 
+std::string adb_version() {
+    // Don't change the format of this --- it's parsed by ddmlib.
+    return android::base::StringPrintf("Android Debug Bridge version %d.%d.%d\n"
+                                       "Revision %s\n",
+                                       ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION,
+                                       ADB_REVISION);
+}
+
 void fatal(const char *fmt, ...) {
     va_list ap;
     va_start(ap, fmt);
@@ -191,21 +200,20 @@
 }
 
 void adb_trace_init(char** argv) {
+#if !ADB_HOST
     // Don't open log file if no tracing, since this will block
     // the crypto unmount of /data
-    const std::string trace_setting = get_trace_setting();
-    if (trace_setting.empty()) {
-        return;
-    }
-
-#if !ADB_HOST
-    if (isatty(STDOUT_FILENO) == 0) {
-        start_device_log();
+    if (!get_trace_setting().empty()) {
+        if (isatty(STDOUT_FILENO) == 0) {
+            start_device_log();
+        }
     }
 #endif
 
     setup_trace_mask();
     android::base::InitLogging(argv, AdbLogger);
+
+    D("%s", adb_version().c_str());
 }
 
 apacket* get_apacket(void)
@@ -299,45 +307,50 @@
     send_packet(p, t);
 }
 
-static size_t fill_connect_data(char *buf, size_t bufsize)
-{
-#if ADB_HOST
-    return snprintf(buf, bufsize, "host::") + 1;
-#else
-    static const char *cnxn_props[] = {
+std::string get_connection_string() {
+    std::vector<std::string> connection_properties;
+
+#if !ADB_HOST
+    static const char* cnxn_props[] = {
         "ro.product.name",
         "ro.product.model",
         "ro.product.device",
     };
-    static const int num_cnxn_props = ARRAY_SIZE(cnxn_props);
-    int i;
-    size_t remaining = bufsize;
-    size_t len;
 
-    len = snprintf(buf, remaining, "%s::", adb_device_banner);
-    remaining -= len;
-    buf += len;
-    for (i = 0; i < num_cnxn_props; i++) {
+    for (const auto& prop_name : cnxn_props) {
         char value[PROPERTY_VALUE_MAX];
-        property_get(cnxn_props[i], value, "");
-        len = snprintf(buf, remaining, "%s=%s;", cnxn_props[i], value);
-        remaining -= len;
-        buf += len;
+        property_get(prop_name, value, "");
+        connection_properties.push_back(
+            android::base::StringPrintf("%s=%s", prop_name, value));
     }
-
-    return bufsize - remaining + 1;
 #endif
+
+    connection_properties.push_back(android::base::StringPrintf(
+        "features=%s", android::base::Join(supported_features(), ',').c_str()));
+
+    return android::base::StringPrintf(
+        "%s::%s", adb_device_banner,
+        android::base::Join(connection_properties, ';').c_str());
 }
 
-void send_connect(atransport *t)
-{
+void send_connect(atransport* t) {
     D("Calling send_connect \n");
-    apacket *cp = get_apacket();
+    apacket* cp = get_apacket();
     cp->msg.command = A_CNXN;
     cp->msg.arg0 = t->get_protocol_version();
     cp->msg.arg1 = t->get_max_payload();
-    cp->msg.data_length = fill_connect_data((char *)cp->data,
-                                            MAX_PAYLOAD_V1);
+
+    std::string connection_str = get_connection_string();
+    // Connect and auth packets are limited to MAX_PAYLOAD_V1 because we don't
+    // yet know how much data the other size is willing to accept.
+    if (connection_str.length() > MAX_PAYLOAD_V1) {
+        LOG(FATAL) << "Connection banner is too long (length = "
+                   << connection_str.length() << ")";
+    }
+
+    memcpy(cp->data, connection_str.c_str(), connection_str.length());
+    cp->msg.data_length = connection_str.length();
+
     send_packet(cp, t);
 }
 
@@ -350,8 +363,8 @@
     *dst = strdup(src.c_str());
 }
 
-void parse_banner(const char* banner, atransport* t) {
-    D("parse_banner: %s\n", banner);
+void parse_banner(const std::string& banner, atransport* t) {
+    D("parse_banner: %s\n", banner.c_str());
 
     // The format is something like:
     // "device::ro.product.name=x;ro.product.model=y;ro.product.device=z;".
@@ -374,6 +387,10 @@
                 qual_overwrite(&t->model, value);
             } else if (key == "ro.product.device") {
                 qual_overwrite(&t->device, value);
+            } else if (key == "features") {
+                for (const auto& feature : android::base::Split(value, ",")) {
+                    t->add_feature(feature);
+                }
             }
         }
     }
@@ -401,6 +418,29 @@
     }
 }
 
+static void handle_new_connection(atransport* t, apacket* p) {
+    if (t->connection_state != kCsOffline) {
+        t->connection_state = kCsOffline;
+        handle_offline(t);
+    }
+
+    t->update_version(p->msg.arg0, p->msg.arg1);
+    std::string banner(reinterpret_cast<const char*>(p->data),
+                       p->msg.data_length);
+    parse_banner(banner, t);
+
+#if ADB_HOST
+    handle_online(t);
+#else
+    if (!auth_required) {
+        handle_online(t);
+        send_connect(t);
+    } else {
+        send_auth_request(t);
+    }
+#endif
+}
+
 void handle_packet(apacket *p, atransport *t)
 {
     asocket *s;
@@ -415,7 +455,9 @@
     case A_SYNC:
         if(p->msg.arg0){
             send_packet(p, t);
-            if(HOST) send_connect(t);
+#if ADB_HOST
+            send_connect(t);
+#endif
         } else {
             t->connection_state = kCsOffline;
             handle_offline(t);
@@ -423,21 +465,8 @@
         }
         return;
 
-    case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
-        if(t->connection_state != kCsOffline) {
-            t->connection_state = kCsOffline;
-            handle_offline(t);
-        }
-
-        t->update_version(p->msg.arg0, p->msg.arg1);
-        parse_banner(reinterpret_cast<const char*>(p->data), t);
-
-        if (HOST || !auth_required) {
-            handle_online(t);
-            if (!HOST) send_connect(t);
-        } else {
-            send_auth_request(t);
-        }
+    case A_CNXN:  // CONNECT(version, maxdata, "system-id-string")
+        handle_new_connection(t, p);
         break;
 
     case A_AUTH:
@@ -557,9 +586,9 @@
     HANDLE                pipe_read, pipe_write;
     HANDLE                stdout_handle, stderr_handle;
     SECURITY_ATTRIBUTES   sa;
-    STARTUPINFO           startup;
+    STARTUPINFOW          startup;
     PROCESS_INFORMATION   pinfo;
-    char                  program_path[ MAX_PATH ];
+    WCHAR                 program_path[ MAX_PATH ];
     int                   ret;
 
     sa.nLength = sizeof(sa);
@@ -579,8 +608,8 @@
                            FILE_SHARE_READ | FILE_SHARE_WRITE, &sa,
                            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
     if (nul_read == INVALID_HANDLE_VALUE) {
-        fprintf(stderr, "CreateFileW(nul, GENERIC_READ) failure, error %ld\n",
-                GetLastError());
+        fprintf(stderr, "CreateFileW(nul, GENERIC_READ) failed: %s\n",
+                SystemErrorCodeToString(GetLastError()).c_str());
         return -1;
     }
 
@@ -588,8 +617,8 @@
                             FILE_SHARE_READ | FILE_SHARE_WRITE, &sa,
                             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
     if (nul_write == INVALID_HANDLE_VALUE) {
-        fprintf(stderr, "CreateFileW(nul, GENERIC_WRITE) failure, error %ld\n",
-                GetLastError());
+        fprintf(stderr, "CreateFileW(nul, GENERIC_WRITE) failed: %s\n",
+                SystemErrorCodeToString(GetLastError()).c_str());
         CloseHandle(nul_read);
         return -1;
     }
@@ -597,7 +626,8 @@
     /* create pipe, and ensure its read handle isn't inheritable */
     ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
     if (!ret) {
-        fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
+        fprintf(stderr, "CreatePipe() failed: %s\n",
+                SystemErrorCodeToString(GetLastError()).c_str());
         CloseHandle(nul_read);
         CloseHandle(nul_write);
         return -1;
@@ -628,17 +658,39 @@
     ZeroMemory( &startup, sizeof(startup) );
     startup.cb = sizeof(startup);
     startup.hStdInput  = nul_read;
-    startup.hStdOutput = pipe_write;
+    startup.hStdOutput = nul_write;
     startup.hStdError  = nul_write;
     startup.dwFlags    = STARTF_USESTDHANDLES;
 
     ZeroMemory( &pinfo, sizeof(pinfo) );
 
     /* get path of current program */
-    GetModuleFileName( NULL, program_path, sizeof(program_path) );
-    char args[64];
-    snprintf(args, sizeof(args), "adb -P %d fork-server server",  server_port);
-    ret = CreateProcess(
+    DWORD module_result = GetModuleFileNameW(NULL, program_path,
+                                             arraysize(program_path));
+    if ((module_result == arraysize(program_path)) || (module_result == 0)) {
+        // String truncation or some other error.
+        fprintf(stderr, "GetModuleFileNameW() failed: %s\n",
+                SystemErrorCodeToString(GetLastError()).c_str());
+        return -1;
+    }
+
+    // Verify that the pipe_write handle value can be passed on the command line
+    // as %d and that the rest of adb code can pass it around in an int.
+    const int pipe_write_as_int = cast_handle_to_int(pipe_write);
+    if (cast_int_to_handle(pipe_write_as_int) != pipe_write) {
+        // If this fires, either handle values are larger than 32-bits or else
+        // there is a bug in our casting.
+        // https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203%28v=vs.85%29.aspx
+        fprintf(stderr, "CreatePipe handle value too large: 0x%p\n",
+                pipe_write);
+        return -1;
+    }
+
+    WCHAR args[64];
+    snwprintf(args, arraysize(args),
+              L"adb -P %d fork-server server --reply-fd %d", server_port,
+              pipe_write_as_int);
+    ret = CreateProcessW(
             program_path,                              /* program path  */
             args,
                                     /* the fork-server argument will set the
@@ -657,7 +709,8 @@
     CloseHandle( pipe_write );
 
     if (!ret) {
-        fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
+        fprintf(stderr, "CreateProcess failed: %s\n",
+                SystemErrorCodeToString(GetLastError()).c_str());
         CloseHandle( pipe_read );
         return -1;
     }
@@ -673,7 +726,8 @@
         ret = ReadFile( pipe_read, temp, 3, &count, NULL );
         CloseHandle( pipe_read );
         if ( !ret ) {
-            fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() );
+            fprintf(stderr, "could not read ok from ADB Server, error: %s\n",
+                    SystemErrorCodeToString(GetLastError()).c_str());
             return -1;
         }
         if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
@@ -686,7 +740,7 @@
     int     fd[2];
 
     // set up a pipe so the child can tell us when it is ready.
-    // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
+    // fd[0] will be parent's end, and the child will write on fd[1]
     if (pipe(fd)) {
         fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
         return -1;
@@ -698,16 +752,14 @@
     if (pid == 0) {
         // child side of the fork
 
-        // redirect stderr to the pipe
-        // we use stderr instead of stdout due to stdout's buffering behavior.
         adb_close(fd[0]);
-        dup2(fd[1], STDERR_FILENO);
-        adb_close(fd[1]);
 
         char str_port[30];
-        snprintf(str_port, sizeof(str_port), "%d",  server_port);
+        snprintf(str_port, sizeof(str_port), "%d", server_port);
+        char reply_fd[30];
+        snprintf(reply_fd, sizeof(reply_fd), "%d", fd[1]);
         // child process
-        int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL);
+        int result = execl(path, "adb", "-P", str_port, "fork-server", "server", "--reply-fd", reply_fd, NULL);
         // this should not return
         fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
     } else  {
@@ -801,11 +853,13 @@
             return 1;
         }
 
+        std::string error;
         InstallStatus r;
         if (kill_forward) {
             r = remove_listener(pieces[0].c_str(), transport);
         } else {
-            r = install_listener(pieces[0], pieces[1].c_str(), transport, no_rebind);
+            r = install_listener(pieces[0], pieces[1].c_str(), transport,
+                                 no_rebind, &error);
         }
         if (r == INSTALL_STATUS_OK) {
 #if ADB_HOST
@@ -821,7 +875,8 @@
           case INSTALL_STATUS_OK: message = "success (!)"; break;
           case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break;
           case INSTALL_STATUS_CANNOT_BIND:
-            message = android::base::StringPrintf("cannot bind to socket: %s", strerror(errno));
+            message = android::base::StringPrintf("cannot bind listener: %s",
+                                                  error.c_str());
             break;
           case INSTALL_STATUS_CANNOT_REBIND:
             message = android::base::StringPrintf("cannot rebind existing socket");
@@ -850,6 +905,12 @@
         fprintf(stderr, "adb server killed by remote request\n");
         fflush(stdout);
         SendOkay(reply_fd);
+
+        // At least on Windows, if we exit() without shutdown(SD_SEND) or
+        // closesocket(), the client's next recv() will error-out with
+        // WSAECONNRESET and they'll never read the OKAY.
+        adb_shutdown(reply_fd);
+
         exit(0);
     }
 
@@ -895,6 +956,13 @@
         return 1;
     }
 
+    if (!strcmp(service, "features")) {
+        SendOkay(reply_fd);
+        SendProtocolString(
+            reply_fd, android::base::Join(supported_features(), '\n'));
+        return 0;
+    }
+
     // remove TCP transport
     if (!strncmp(service, "disconnect:", 11)) {
         const std::string address(service + 11);
diff --git a/adb/adb.h b/adb/adb.h
index 309b0e9..6855f3b 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -20,10 +20,10 @@
 #include <limits.h>
 #include <sys/types.h>
 
-#include <base/macros.h>
-
 #include <string>
 
+#include <base/macros.h>
+
 #include "adb_trace.h"
 #include "fdevent.h"
 
@@ -46,6 +46,8 @@
 #define ADB_VERSION_MAJOR 1
 #define ADB_VERSION_MINOR 0
 
+std::string adb_version();
+
 // Increment this when we want to force users to start a new adb server.
 #define ADB_SERVER_VERSION 32
 
@@ -189,71 +191,6 @@
     kCsUnauthorized,
 };
 
-class atransport {
-public:
-    // TODO(danalbert): We expose waaaaaaay too much stuff because this was
-    // historically just a struct, but making the whole thing a more idiomatic
-    // class in one go is a very large change. Given how bad our testing is,
-    // it's better to do this piece by piece.
-
-    atransport() {
-        auth_fde = {};
-        transport_fde = {};
-        protocol_version = A_VERSION;
-        max_payload = MAX_PAYLOAD;
-    }
-
-    virtual ~atransport() {}
-
-    int (*read_from_remote)(apacket* p, atransport* t) = nullptr;
-    int (*write_to_remote)(apacket* p, atransport* t) = nullptr;
-    void (*close)(atransport* t) = nullptr;
-    void (*kick)(atransport* t) = nullptr;
-
-    int fd = -1;
-    int transport_socket = -1;
-    fdevent transport_fde;
-    int ref_count = 0;
-    uint32_t sync_token = 0;
-    ConnectionState connection_state = kCsOffline;
-    bool online = false;
-    TransportType type = kTransportAny;
-
-    // USB handle or socket fd as needed.
-    usb_handle* usb = nullptr;
-    int sfd = -1;
-
-    // Used to identify transports for clients.
-    char* serial = nullptr;
-    char* product = nullptr;
-    char* model = nullptr;
-    char* device = nullptr;
-    char* devpath = nullptr;
-    int adb_port = -1;  // Use for emulators (local transport)
-    bool kicked = false;
-
-    // A list of adisconnect callbacks called when the transport is kicked.
-    adisconnect disconnects = {};
-
-    void* key = nullptr;
-    unsigned char token[TOKEN_SIZE] = {};
-    fdevent auth_fde;
-    size_t failed_auth_attempts = 0;
-
-    const char* connection_state_name() const;
-
-    void update_version(int version, size_t payload);
-    int get_protocol_version() const;
-    size_t get_max_payload() const;
-
-private:
-    int protocol_version;
-    size_t max_payload;
-
-    DISALLOW_COPY_AND_ASSIGN(atransport);
-};
-
-
 /* A listener is an entity which binds to a local port
 ** and, upon receiving a connection on that port, creates
 ** an asocket to connect the new local connection to a
@@ -299,7 +236,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 adb_main(int is_daemon, int server_port, int ack_reply_fd);
 
 /* initialize a transport object's func pointers and state */
 #if ADB_HOST
@@ -378,8 +315,8 @@
 
 ConnectionState connection_state(atransport *t);
 
-extern const char *adb_device_banner;
-extern int HOST;
+extern const char* adb_device_banner;
+
 #if !ADB_HOST
 extern int SHELL_EXIT_NOTIFY_FD;
 #endif // !ADB_HOST
@@ -404,4 +341,6 @@
 
 void send_connect(atransport *t);
 
+void parse_banner(const std::string&, atransport* t);
+
 #endif
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index b6bb00c..e7f82a9 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -301,11 +301,18 @@
     char android_dir[PATH_MAX];
     struct stat buf;
 #ifdef _WIN32
-    char path[PATH_MAX];
+    std::string home_str;
     home = getenv("ANDROID_SDK_HOME");
     if (!home) {
-        SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, path);
-        home = path;
+        WCHAR path[MAX_PATH];
+        const HRESULT hr = SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path);
+        if (FAILED(hr)) {
+            D("SHGetFolderPathW failed: %s\n",
+              SystemErrorCodeToString(hr).c_str());
+            return -1;
+        }
+        home_str = narrow(path);
+        home = home_str.c_str();
     }
     format = "%s\\%s";
 #else
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index 418662c..4bf647c 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -153,8 +153,8 @@
     }
 
     int fd;
+    std::string reason;
     if (__adb_server_name) {
-        std::string reason;
         fd = network_connect(__adb_server_name, __adb_server_port, SOCK_STREAM, 0, &reason);
         if (fd == -1) {
             *error = android::base::StringPrintf("can't connect to %s:%d: %s",
@@ -163,9 +163,10 @@
             return -2;
         }
     } else {
-        fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
+        fd = network_loopback_client(__adb_server_port, SOCK_STREAM, &reason);
         if (fd == -1) {
-            *error = perror_str("cannot connect to daemon");
+            *error = android::base::StringPrintf("cannot connect to daemon: %s",
+                                                 reason.c_str());
             return -2;
         }
     }
@@ -196,6 +197,7 @@
     D("adb_connect: service %s\n", service.c_str());
     if (fd == -2 && __adb_server_name) {
         fprintf(stderr,"** Cannot start server on remote host\n");
+        // error is the original network connection error
         return fd;
     } else if (fd == -2) {
         fprintf(stdout,"* daemon not running. starting it now on port %d *\n",
@@ -203,6 +205,10 @@
     start_server:
         if (launch_server(__adb_server_port)) {
             fprintf(stderr,"* failed to start daemon *\n");
+            // launch_server() has already printed detailed error info, so just
+            // return a generic error string about the overall adb_connect()
+            // that the caller requested.
+            *error = "cannot connect to daemon";
             return -1;
         } else {
             fprintf(stdout,"* daemon started successfully *\n");
@@ -224,12 +230,16 @@
             adb_close(fd);
 
             if (sscanf(&version_string[0], "%04x", &version) != 1) {
-                goto error;
+                *error = android::base::StringPrintf(
+                        "cannot parse version string: %s",
+                        version_string.c_str());
+                return -1;
             }
         } else {
             // if fd is -1, then check for "unknown host service",
-            // which would indicate a version of adb that does not support the version command
-            if (*error == "unknown host service") {
+            // which would indicate a version of adb that does not support the
+            // version command, in which case we should fall-through to kill it.
+            if (*error != "unknown host service") {
                 return fd;
             }
         }
@@ -237,7 +247,13 @@
         if (version != ADB_SERVER_VERSION) {
             printf("adb server is out of date.  killing...\n");
             fd = _adb_connect("host:kill", error);
-            adb_close(fd);
+            if (fd >= 0) {
+                adb_close(fd);
+            } else {
+                // If we couldn't connect to the server or had some other error,
+                // report it, but still try to start the server.
+                fprintf(stderr, "error: %s\n", error->c_str());
+            }
 
             /* XXX can we better detect its death? */
             adb_sleep_ms(2000);
diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp
index 8fd5cbf..f637073 100644
--- a/adb/adb_io_test.cpp
+++ b/adb/adb_io_test.cpp
@@ -28,30 +28,13 @@
 #include <string>
 
 #include "base/file.h"
+#include "base/test_utils.h"
 
-class TemporaryFile {
- public:
-  TemporaryFile() {
-    init("/data/local/tmp");
-    if (fd == -1) {
-      init("/tmp");
-    }
-  }
-
-  ~TemporaryFile() {
-    close(fd);
-    unlink(filename);
-  }
-
-  int fd;
-  char filename[1024];
-
- private:
-  void init(const char* tmp_dir) {
-    snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir);
-    fd = mkstemp(filename);
-  }
-};
+// All of these tests fail on Windows because they use the C Runtime open(),
+// but the adb_io APIs expect file descriptors from adb_open(). Also, the
+// android::base file APIs use the C Runtime which uses CR/LF translation by
+// default (changeable with _setmode()), but the adb_io APIs use adb_read()
+// and adb_write() which do no translation.
 
 TEST(io, ReadFdExactly_whole) {
   const char expected[] = "Foobar";
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index bb45022..8fb2d19 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -110,27 +110,30 @@
     free_listener(reinterpret_cast<alistener*>(listener));
 }
 
-static int local_name_to_fd(const char* name) {
+static int local_name_to_fd(const char* name, std::string* error) {
     if (!strncmp("tcp:", name, 4)) {
         int port = atoi(name + 4);
         if (gListenAll > 0) {
-            return socket_inaddr_any_server(port, SOCK_STREAM);
+            return network_inaddr_any_server(port, SOCK_STREAM, error);
         } else {
-            return socket_loopback_server(port, SOCK_STREAM);
+            return network_loopback_server(port, SOCK_STREAM, error);
         }
     }
 #if !defined(_WIN32)  // No Unix-domain sockets on Windows.
     // It's nonsensical to support the "reserved" space on the adb host side
     if (!strncmp(name, "local:", 6)) {
-        return socket_local_server(name + 6, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+        return network_local_server(name + 6,
+                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM, error);
     } else if (!strncmp(name, "localabstract:", 14)) {
-        return socket_local_server(name + 14, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+        return network_local_server(name + 14,
+                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM, error);
     } else if (!strncmp(name, "localfilesystem:", 16)) {
-        return socket_local_server(name + 16, ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
+        return network_local_server(name + 16,
+                ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM, error);
     }
 
 #endif
-    printf("unknown local portname '%s'\n", name);
+    *error = android::base::StringPrintf("unknown local portname '%s'", name);
     return -1;
 }
 
@@ -178,7 +181,8 @@
 InstallStatus install_listener(const std::string& local_name,
                                   const char *connect_to,
                                   atransport* transport,
-                                  int no_rebind)
+                                  int no_rebind,
+                                  std::string* error)
 {
     for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
         if (local_name == l->local_name) {
@@ -186,16 +190,19 @@
 
             /* can't repurpose a smartsocket */
             if(l->connect_to[0] == '*') {
+                *error = "cannot repurpose smartsocket";
                 return INSTALL_STATUS_INTERNAL_ERROR;
             }
 
             /* can't repurpose a listener if 'no_rebind' is true */
             if (no_rebind) {
+                *error = "cannot rebind";
                 return INSTALL_STATUS_CANNOT_REBIND;
             }
 
             cto = strdup(connect_to);
             if(cto == 0) {
+                *error = "cannot duplicate string";
                 return INSTALL_STATUS_INTERNAL_ERROR;
             }
 
@@ -226,9 +233,8 @@
         goto nomem;
     }
 
-    listener->fd = local_name_to_fd(listener->local_name);
+    listener->fd = local_name_to_fd(listener->local_name, error);
     if (listener->fd < 0) {
-        printf("cannot bind '%s': %s\n", listener->local_name, strerror(errno));
         free(listener->local_name);
         free(listener->connect_to);
         free(listener);
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index 67deb21..fa98eed 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -33,7 +33,8 @@
 InstallStatus install_listener(const std::string& local_name,
                                const char* connect_to,
                                atransport* transport,
-                               int no_rebind);
+                               int no_rebind,
+                               std::string* error);
 
 std::string format_listeners();
 
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 6fa6c2e..ca843bd 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -18,6 +18,7 @@
 
 #include "adb_utils.h"
 
+#include <libgen.h>
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -28,16 +29,11 @@
 #include <base/logging.h>
 #include <base/stringprintf.h>
 #include <base/strings.h>
-#include <cutils/sockets.h>
 
 #include "adb_trace.h"
 #include "sysdeps.h"
 
-#if defined(_WIN32)
-#include <ws2tcpip.h>
-#else
-#include <netdb.h>
-#endif
+ADB_MUTEX_DEFINE(dirname_lock);
 
 bool getcwd(std::string* s) {
   char* cwd = getcwd(nullptr, 0);
@@ -72,24 +68,87 @@
   return result;
 }
 
-int mkdirs(const std::string& path) {
-    // TODO: rewrite this function and merge it with the *other* mkdirs in adb.
-    std::unique_ptr<char> path_rw(strdup(path.c_str()));
-    int ret;
-    char* x = path_rw.get() + 1;
+std::string adb_basename(const std::string& path) {
+  size_t base = path.find_last_of(OS_PATH_SEPARATORS);
+  return (base != std::string::npos) ? path.substr(base + 1) : path;
+}
 
-    for(;;) {
-        x = const_cast<char*>(adb_dirstart(x));
-        if(x == 0) return 0;
-        *x = 0;
-        ret = adb_mkdir(path_rw.get(), 0775);
-        *x = OS_PATH_SEPARATOR;
-        if((ret < 0) && (errno != EEXIST)) {
-            return ret;
-        }
-        x++;
+std::string adb_dirname(const std::string& path) {
+  // Copy path because dirname may modify the string passed in.
+  std::string parent_storage(path);
+
+  // Use lock because dirname() may write to a process global and return a
+  // pointer to that. Note that this locking strategy only works if all other
+  // callers to dirname in the process also grab this same lock.
+  adb_mutex_lock(&dirname_lock);
+
+  // Note that if std::string uses copy-on-write strings, &str[0] will cause
+  // the copy to be made, so there is no chance of us accidentally writing to
+  // the storage for 'path'.
+  char* parent = dirname(&parent_storage[0]);
+
+  // In case dirname returned a pointer to a process global, copy that string
+  // before leaving the lock.
+  const std::string result(parent);
+
+  adb_mutex_unlock(&dirname_lock);
+
+  return result;
+}
+
+// Given a relative or absolute filepath, create the parent directory hierarchy
+// as needed. Returns true if the hierarchy is/was setup.
+bool mkdirs(const std::string& path) {
+  // TODO: all the callers do unlink && mkdirs && adb_creat ---
+  // that's probably the operation we should expose.
+
+  // Implementation Notes:
+  //
+  // Pros:
+  // - Uses dirname, so does not need to deal with OS_PATH_SEPARATOR.
+  // - On Windows, uses mingw dirname which accepts '/' and '\\', drive letters
+  //   (C:\foo), UNC paths (\\server\share\dir\dir\file), and Unicode (when
+  //   combined with our adb_mkdir() which takes UTF-8).
+  // - Is optimistic wrt thinking that a deep directory hierarchy will exist.
+  //   So it does as few stat()s as possible before doing mkdir()s.
+  // Cons:
+  // - Recursive, so it uses stack space relative to number of directory
+  //   components.
+
+  const std::string parent(adb_dirname(path));
+
+  if (directory_exists(parent)) {
+    return true;
+  }
+
+  // If dirname returned the same path as what we passed in, don't go recursive.
+  // This can happen on Windows when walking up the directory hierarchy and not
+  // finding anything that already exists (unlike POSIX that will eventually
+  // find . or /).
+  if (parent == path) {
+    errno = ENOENT;
+    return false;
+  }
+
+  // Recursively make parent directories of 'parent'.
+  if (!mkdirs(parent)) {
+    return false;
+  }
+
+  // Now that the parent directory hierarchy of 'parent' has been ensured,
+  // create parent itself.
+  if (adb_mkdir(parent, 0775) == -1) {
+    // Can't just check for errno == EEXIST because it might be a file that
+    // exists.
+    const int saved_errno = errno;
+    if (directory_exists(parent)) {
+      return true;
     }
-    return 0;
+    errno = saved_errno;
+    return false;
+  }
+
+  return true;
 }
 
 void dump_hex(const void* data, size_t byte_count) {
@@ -166,18 +225,3 @@
                << " (" << *canonical_address << ")";
     return true;
 }
-
-int network_connect(const std::string& host, int port, int type, int timeout, std::string* error) {
-    int getaddrinfo_error = 0;
-    int fd = socket_network_client_timeout(host.c_str(), port, type, timeout, &getaddrinfo_error);
-    if (fd != -1) {
-        return fd;
-    }
-    if (getaddrinfo_error != 0) {
-        // TODO: gai_strerror is not thread safe on Win32.
-        *error = gai_strerror(getaddrinfo_error);
-    } else {
-        *error = strerror(errno);
-    }
-    return -1;
-}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 673aaac..739efcc 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -22,7 +22,12 @@
 bool getcwd(std::string* cwd);
 bool directory_exists(const std::string& path);
 
-int mkdirs(const std::string& path);
+// Like the regular basename and dirname, but thread-safe on all
+// platforms and capable of correctly handling exotic Windows paths.
+std::string adb_basename(const std::string& path);
+std::string adb_dirname(const std::string& path);
+
+bool mkdirs(const std::string& path);
 
 std::string escape_arg(const std::string& s);
 
@@ -39,6 +44,4 @@
                          std::string* host, int* port,
                          std::string* error);
 
-int network_connect(const std::string& host, int port, int type, int timeout, std::string* error);
-
 #endif
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index 7aa610a..17c8d0a 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -16,12 +16,60 @@
 
 #include "adb_utils.h"
 
+#ifdef _WIN32
+#include <windows.h>
+#include <userenv.h>
+#endif
+
+#include <string>
+
 #include <gtest/gtest.h>
 
+#include <stdlib.h>
+#include <string.h>
+
+#include "sysdeps.h"
+
+#include <base/macros.h>
+#include <base/test_utils.h>
+
+#ifdef _WIN32
+static std::string subdir(const char* parent, const char* child) {
+  std::string str(parent);
+  str += OS_PATH_SEPARATOR;
+  str += child;
+  return str;
+}
+#endif
+
 TEST(adb_utils, directory_exists) {
+#ifdef _WIN32
+  char profiles_dir[MAX_PATH];
+  DWORD cch = arraysize(profiles_dir);
+
+  // On typical Windows 7, returns C:\Users
+  ASSERT_TRUE(GetProfilesDirectoryA(profiles_dir, &cch));
+
+  ASSERT_TRUE(directory_exists(profiles_dir));
+
+  // On modern (English?) Windows, this is a directory symbolic link to
+  // C:\ProgramData. Symbolic links are rare on Windows and the user requires
+  // a special permission (by default granted to Administrative users) to
+  // create symbolic links.
+  ASSERT_FALSE(directory_exists(subdir(profiles_dir, "All Users")));
+
+  // On modern (English?) Windows, this is a directory junction to
+  // C:\Users\Default. Junctions are used throughout user profile directories
+  // for backwards compatibility and they don't require any special permissions
+  // to create.
+  ASSERT_FALSE(directory_exists(subdir(profiles_dir, "Default User")));
+
+  ASSERT_FALSE(directory_exists(subdir(profiles_dir, "does-not-exist")));
+#else
   ASSERT_TRUE(directory_exists("/proc"));
   ASSERT_FALSE(directory_exists("/proc/self")); // Symbolic link.
   ASSERT_FALSE(directory_exists("/proc/does-not-exist"));
+#endif
 }
 
 TEST(adb_utils, escape_arg) {
@@ -51,6 +99,11 @@
   ASSERT_EQ(R"('abc)')", escape_arg("abc)"));
 }
 
+TEST(adb_utils, adb_basename) {
+  EXPECT_EQ("sh", adb_basename("/system/bin/sh"));
+  EXPECT_EQ("sh", adb_basename("sh"));
+}
+
 TEST(adb_utils, parse_host_and_port) {
   std::string canonical_address;
   std::string host;
@@ -132,3 +185,20 @@
   EXPECT_FALSE(parse_host_and_port("1.2.3.4:0", &canonical_address, &host, &port, &error));
   EXPECT_FALSE(parse_host_and_port("1.2.3.4:65536", &canonical_address, &host, &port, &error));
 }
+
+void test_mkdirs(const std::string basepath) {
+  EXPECT_TRUE(mkdirs(basepath));
+  EXPECT_NE(-1, adb_creat(basepath.c_str(), 0600));
+  EXPECT_FALSE(mkdirs(basepath + "/subdir/"));
+}
+
+TEST(adb_utils, mkdirs) {
+  TemporaryDir td;
+
+  // Absolute paths.
+  test_mkdirs(std::string(td.path) + "/dir/subdir/file");
+
+  // Relative paths.
+  ASSERT_EQ(0, chdir(td.path)) << strerror(errno);
+  test_mkdirs(std::string("relative/subrel/file"));
+}
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index c018b8a..206442a 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -82,21 +82,17 @@
 
 static std::string GetLogFilePath() {
     const char log_name[] = "adb.log";
-    char temp_path[MAX_PATH - sizeof(log_name) + 1];
+    WCHAR temp_path[MAX_PATH];
 
     // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992%28v=vs.85%29.aspx
-    DWORD nchars = GetTempPath(sizeof(temp_path), temp_path);
-    CHECK_LE(nchars, sizeof(temp_path));
-    if (nchars == 0) {
-        // TODO(danalbert): Log the error message from FormatError().
-        // Windows unfortunately has two errnos, errno and GetLastError(), so
-        // I'm not sure what to do about PLOG here. Probably better to just
-        // ignore it and add a simplified version of FormatError() for use in
-        // log messages.
-        LOG(ERROR) << "Error creating log file";
+    DWORD nchars = GetTempPathW(arraysize(temp_path), temp_path);
+    if ((nchars >= arraysize(temp_path)) || (nchars == 0)) {
+        // If string truncation or some other error.
+        fatal("cannot retrieve temporary file path: %s\n",
+              SystemErrorCodeToString(GetLastError()).c_str());
     }
 
-    return std::string(temp_path) + log_name;
+    return narrow(temp_path) + log_name;
 }
 #else
 static const char kNullFileName[] = "/dev/null";
@@ -108,19 +104,28 @@
 
 static void close_stdin() {
     int fd = unix_open(kNullFileName, O_RDONLY);
-    CHECK_NE(fd, -1);
-    dup2(fd, STDIN_FILENO);
+    if (fd == -1) {
+        fatal("cannot open '%s': %s", kNullFileName, strerror(errno));
+    }
+    if (dup2(fd, STDIN_FILENO) == -1) {
+        fatal("cannot redirect stdin: %s", strerror(errno));
+    }
     unix_close(fd);
 }
 
 static void setup_daemon_logging(void) {
-    int fd = unix_open(GetLogFilePath().c_str(), O_WRONLY | O_CREAT | O_APPEND,
+    const std::string log_file_path(GetLogFilePath());
+    int fd = unix_open(log_file_path.c_str(), O_WRONLY | O_CREAT | O_APPEND,
                        0640);
     if (fd == -1) {
-        fd = unix_open(kNullFileName, O_WRONLY);
+        fatal("cannot open '%s': %s", log_file_path.c_str(), strerror(errno));
     }
-    dup2(fd, STDOUT_FILENO);
-    dup2(fd, STDERR_FILENO);
+    if (dup2(fd, STDOUT_FILENO) == -1) {
+        fatal("cannot redirect stdout: %s", strerror(errno));
+    }
+    if (dup2(fd, STDERR_FILENO) == -1) {
+        fatal("cannot redirect stderr: %s", strerror(errno));
+    }
     unix_close(fd);
 
 #ifdef _WIN32
@@ -131,9 +136,7 @@
     fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid());
 }
 
-int adb_main(int is_daemon, int server_port) {
-    HOST = 1;
-
+int adb_main(int is_daemon, int server_port, int ack_reply_fd) {
 #if defined(_WIN32)
     SetConsoleCtrlHandler(ctrlc_handler, TRUE);
 #else
@@ -150,34 +153,36 @@
     local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
     adb_auth_init();
 
+    std::string error;
     std::string local_name = android::base::StringPrintf("tcp:%d", server_port);
-    if (install_listener(local_name, "*smartsocket*", nullptr, 0)) {
-        LOG(FATAL) << "Could not install *smartsocket* listener";
+    if (install_listener(local_name, "*smartsocket*", nullptr, 0, &error)) {
+        fatal("could not install *smartsocket* listener: %s", error.c_str());
     }
 
+    // Inform our parent that we are up and running.
     if (is_daemon) {
-        // Inform our parent that we are up and running.
+#if defined(_WIN32)
+        const HANDLE ack_reply_handle = cast_int_to_handle(ack_reply_fd);
+        const CHAR ack[] = "OK\n";
+        const DWORD bytes_to_write = arraysize(ack) - 1;
+        DWORD written = 0;
+        if (!WriteFile(ack_reply_handle, ack, bytes_to_write, &written, NULL)) {
+            fatal("adb: cannot write ACK to handle 0x%p: %s", ack_reply_handle,
+                  SystemErrorCodeToString(GetLastError()).c_str());
+        }
+        if (written != bytes_to_write) {
+            fatal("adb: cannot write %lu bytes of ACK: only wrote %lu bytes",
+                  bytes_to_write, written);
+        }
+        CloseHandle(ack_reply_handle);
+#else
         // TODO(danalbert): Can't use SendOkay because we're sending "OK\n", not
         // "OKAY".
-        // TODO(danalbert): Why do we use stdout for Windows? There is a
-        // comment in launch_server() that suggests that non-Windows uses
-        // stderr because it is non-buffered. So perhaps the history is that
-        // stdout was preferred for all platforms, but it was discovered that
-        // non-Windows needed a non-buffered fd, so stderr was used there.
-        // Note that using stderr on unix means that if you do
-        // `ADB_TRACE=all adb start-server`, it will say "ADB server didn't ACK"
-        // and "* failed to start daemon *" because the adb server will write
-        // logging to stderr, obscuring the OK\n output that is sent to stderr.
-#if defined(_WIN32)
-        int reply_fd = STDOUT_FILENO;
-        // Change stdout mode to binary so \n => \r\n translation does not
-        // occur. In a moment stdout will be reopened to the daemon log file
-        // anyway.
-        _setmode(reply_fd, _O_BINARY);
-#else
-        int reply_fd = STDERR_FILENO;
+        if (!android::base::WriteStringToFd("OK\n", ack_reply_fd)) {
+            fatal_errno("error writing ACK to fd %d", ack_reply_fd);
+        }
+        unix_close(ack_reply_fd);
 #endif
-        android::base::WriteStringToFd("OK\n", reply_fd);
         close_stdin();
         setup_daemon_logging();
     }
@@ -188,9 +193,34 @@
     return 0;
 }
 
+#ifdef _WIN32
+static bool _argv_is_utf8 = false;
+#endif
+
 int main(int argc, char** argv) {
+#ifdef _WIN32
+    if (!_argv_is_utf8) {
+        fatal("_argv_is_utf8 is not set, suggesting that wmain was not "
+              "called. Did you forget to link with -municode?");
+    }
+#endif
+
     adb_sysdeps_init();
     adb_trace_init(argv);
-    D("Handling commandline()\n");
     return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
 }
+
+#ifdef _WIN32
+
+extern "C"
+int wmain(int argc, wchar_t **argv) {
+    // Set diagnostic flag to try to detect if the build system was not
+    // configured to call wmain.
+    _argv_is_utf8 = true;
+
+    // Convert args from UTF-16 to UTF-8 and pass that to main().
+    NarrowArgs narrow_args(argc, argv);
+    return main(argc, narrow_args.data());
+}
+
+#endif
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index d54faec..c7b7675 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -65,16 +65,9 @@
                                        gProductOutPath.c_str(), OS_PATH_SEPARATOR_STR, extra);
 }
 
-static void version(FILE* out) {
-    fprintf(out, "Android Debug Bridge version %d.%d.%d\nRevision %s\n",
-            ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION, ADB_REVISION);
-}
-
 static void help() {
-    version(stderr);
-
+    fprintf(stderr, "%s\n", adb_version().c_str());
     fprintf(stderr,
-        "\n"
         " -a                            - directs adb to listen on all interfaces for a connection\n"
         " -d                            - directs command to the only connected USB device\n"
         "                                 returns an error if more than one USB device is present.\n"
@@ -847,25 +840,25 @@
  * Given <hint>, try to construct an absolute path to the
  * ANDROID_PRODUCT_OUT dir.
  */
-static std::string find_product_out_path(const char* hint) {
-    if (hint == NULL || hint[0] == '\0') {
+static std::string find_product_out_path(const std::string& hint) {
+    if (hint.empty()) {
         return "";
     }
 
     // If it's already absolute, don't bother doing any work.
-    if (adb_is_absolute_host_path(hint)) {
+    if (adb_is_absolute_host_path(hint.c_str())) {
         return hint;
     }
 
     // If there are any slashes in it, assume it's a relative path;
     // make it absolute.
-    if (adb_dirstart(hint) != nullptr) {
+    if (hint.find_first_of(OS_PATH_SEPARATORS) != std::string::npos) {
         std::string cwd;
         if (!getcwd(&cwd)) {
             fprintf(stderr, "adb: getcwd failed: %s\n", strerror(errno));
             return "";
         }
-        return android::base::StringPrintf("%s%s%s", cwd.c_str(), OS_PATH_SEPARATOR_STR, hint);
+        return android::base::StringPrintf("%s%c%s", cwd.c_str(), OS_PATH_SEPARATOR, hint.c_str());
     }
 
     // It's a string without any slashes.  Try to do something with it.
@@ -889,7 +882,7 @@
     path += hint;
     if (!directory_exists(path)) {
         fprintf(stderr, "adb: Couldn't find a product dir based on -p %s; "
-                        "\"%s\" doesn't exist\n", hint, path.c_str());
+                        "\"%s\" doesn't exist\n", hint.c_str(), path.c_str());
         return "";
     }
     return path;
@@ -953,6 +946,7 @@
     int is_server = 0;
     int r;
     TransportType transport_type = kTransportAny;
+    int ack_reply_fd = -1;
 
     // If defined, this should be an absolute path to
     // the directory containing all of the various system images
@@ -971,10 +965,10 @@
     const char* server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
     int server_port = DEFAULT_ADB_PORT;
     if (server_port_str && strlen(server_port_str) > 0) {
-        server_port = (int) strtol(server_port_str, NULL, 0);
+        server_port = strtol(server_port_str, nullptr, 0);
         if (server_port <= 0 || server_port > 65535) {
             fprintf(stderr,
-                    "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number less than 65535. Got \"%s\"\n",
+                    "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number less than 65536. Got \"%s\"\n",
                     server_port_str);
             return usage();
         }
@@ -989,8 +983,25 @@
         } else if (!strcmp(argv[0], "fork-server")) {
             /* this is a special flag used only when the ADB client launches the ADB Server */
             is_daemon = 1;
+        } else if (!strcmp(argv[0], "--reply-fd")) {
+            if (argc < 2) return usage();
+            const char* reply_fd_str = argv[1];
+            argc--;
+            argv++;
+            ack_reply_fd = strtol(reply_fd_str, nullptr, 10);
+#ifdef _WIN32
+            const HANDLE ack_reply_handle = cast_int_to_handle(ack_reply_fd);
+            if ((GetStdHandle(STD_INPUT_HANDLE) == ack_reply_handle) ||
+                (GetStdHandle(STD_OUTPUT_HANDLE) == ack_reply_handle) ||
+                (GetStdHandle(STD_ERROR_HANDLE) == ack_reply_handle)) {
+#else
+            if (ack_reply_fd <= 2) { // Disallow stdin, stdout, and stderr.
+#endif
+                fprintf(stderr, "adb: invalid reply fd \"%s\"\n", reply_fd_str);
+                return usage();
+            }
         } else if (!strncmp(argv[0], "-p", 2)) {
-            const char *product = NULL;
+            const char* product = nullptr;
             if (argv[0][2] == '\0') {
                 if (argc < 2) return usage();
                 product = argv[1];
@@ -1066,7 +1077,11 @@
 
     if (is_server) {
         if (no_daemon || is_daemon) {
-            r = adb_main(is_daemon, server_port);
+            if (is_daemon && (ack_reply_fd == -1)) {
+                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);
         } else {
             r = launch_server(server_port);
         }
@@ -1218,11 +1233,22 @@
     else if (!strcmp(argv[0], "kill-server")) {
         std::string error;
         int fd = _adb_connect("host:kill", &error);
-        if (fd == -1) {
+        if (fd == -2) {
+            // Failed to make network connection to server. Don't output the
+            // network error since that is expected.
             fprintf(stderr,"* server not running *\n");
+            // Successful exit code because the server is already "killed".
+            return 0;
+        } else if (fd == -1) {
+            // Some other error.
+            fprintf(stderr, "error: %s\n", error.c_str());
             return 1;
+        } else {
+            // Successfully connected, kill command sent, okay status came back.
+            // Server should exit() in a moment, if not already.
+            adb_close(fd);
+            return 0;
         }
-        return 0;
     }
     else if (!strcmp(argv[0], "sideload")) {
         if (argc != 2) return usage();
@@ -1406,7 +1432,11 @@
     }
     else if (!strcmp(argv[0], "start-server")) {
         std::string error;
-        return adb_connect("host:start-server", &error);
+        const int result = adb_connect("host:start-server", &error);
+        if (result < 0) {
+            fprintf(stderr, "error: %s\n", error.c_str());
+        }
+        return result;
     }
     else if (!strcmp(argv[0], "backup")) {
         return backup(argc, argv);
@@ -1427,9 +1457,12 @@
         return 0;
     }
     else if (!strcmp(argv[0], "version")) {
-        version(stdout);
+        fprintf(stdout, "%s", adb_version().c_str());
         return 0;
     }
+    else if (!strcmp(argv[0], "features")) {
+        return adb_query_command("host:features");
+    }
 
     usage();
     return 1;
@@ -1462,22 +1495,11 @@
     return pm_command(transport, serial, argc, argv);
 }
 
-static int delete_file(TransportType transport, const char* serial, char* filename) {
+static int delete_file(TransportType transport, const char* serial, const std::string& filename) {
     std::string cmd = "shell:rm -f " + escape_arg(filename);
     return send_shell_command(transport, serial, cmd);
 }
 
-static const char* get_basename(const char* filename)
-{
-    const char* basename = adb_dirstop(filename);
-    if (basename) {
-        basename++;
-        return basename;
-    } else {
-        return filename;
-    }
-}
-
 static int install_app(TransportType transport, const char* serial, int argc, const char** argv) {
     static const char *const DATA_DEST = "/data/local/tmp/%s";
     static const char *const SD_DEST = "/sdcard/tmp/%s";
@@ -1514,13 +1536,12 @@
     }
 
     const char* apk_file = argv[last_apk];
-    char apk_dest[PATH_MAX];
-    snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
-    int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */);
+    std::string apk_dest = android::base::StringPrintf(where, adb_basename(apk_file).c_str());
+    int err = do_sync_push(apk_file, apk_dest.c_str(), 0 /* no show progress */);
     if (err) {
         goto cleanup_apk;
     } else {
-        argv[last_apk] = apk_dest; /* destination name, not source location */
+        argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
     }
 
     err = pm_command(transport, serial, argc, argv);
@@ -1604,7 +1625,7 @@
 
         std::string cmd = android::base::StringPrintf(
                 "exec:pm install-write -S %" PRIu64 " %d %d_%s -",
-                static_cast<uint64_t>(sb.st_size), session_id, i, get_basename(file));
+                static_cast<uint64_t>(sb.st_size), session_id, i, adb_basename(file).c_str());
 
         int localFd = adb_open(file, O_RDONLY);
         if (localFd < 0) {
diff --git a/adb/console.cpp b/adb/console.cpp
index b7f5345..ba5a72b 100644
--- a/adb/console.cpp
+++ b/adb/console.cpp
@@ -71,9 +71,11 @@
         return -1;
     }
 
-    int fd = socket_loopback_client(port, SOCK_STREAM);
+    std::string error;
+    int fd = network_loopback_client(port, SOCK_STREAM, &error);
     if (fd == -1) {
-        fprintf(stderr, "error: could not connect to TCP port %d\n", port);
+        fprintf(stderr, "error: could not connect to TCP port %d: %s\n", port,
+                error.c_str());
         return -1;
     }
     return fd;
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 157c97b..dc89639 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -68,13 +68,6 @@
 #if defined(ALLOW_ADBD_ROOT)
     char value[PROPERTY_VALUE_MAX];
 
-    // The emulator is never secure, so don't drop privileges there.
-    // TODO: this seems like a bug --- shouldn't the emulator behave like a device?
-    property_get("ro.kernel.qemu", value, "");
-    if (strcmp(value, "1") == 0) {
-        return false;
-    }
-
     // The properties that affect `adb root` and `adb unroot` are ro.secure and
     // ro.debuggable. In this context the names don't make the expected behavior
     // particularly obvious.
@@ -177,10 +170,13 @@
                 LOG(FATAL) << "Could not set selinux context";
             }
         }
+        std::string error;
         std::string local_name =
             android::base::StringPrintf("tcp:%d", server_port);
-        if (install_listener(local_name, "*smartsocket*", nullptr, 0)) {
-            LOG(FATAL) << "Could not install *smartsocket* listener";
+        if (install_listener(local_name, "*smartsocket*", nullptr, 0,
+                             &error)) {
+            LOG(FATAL) << "Could not install *smartsocket* listener: "
+                << error;
         }
     }
 
diff --git a/adb/device.py b/adb/device.py
index b6eaad6..5b33ff2 100644
--- a/adb/device.py
+++ b/adb/device.py
@@ -101,6 +101,20 @@
 
 
 class AndroidDevice(object):
+    # Delimiter string to indicate the start of the exit code.
+    _RETURN_CODE_DELIMITER = 'x'
+
+    # Follow any shell command with this string to get the exit
+    # status of a program since this isn't propagated by adb.
+    #
+    # The delimiter is needed because `printf 1; echo $?` would print
+    # "10", and we wouldn't be able to distinguish the exit code.
+    _RETURN_CODE_PROBE_STRING = 'echo "{0}$?"'.format(_RETURN_CODE_DELIMITER)
+
+    # Maximum search distance from the output end to find the delimiter.
+    # adb on Windows returns \r\n even if adbd returns \n.
+    _RETURN_CODE_SEARCH_LENGTH = len('{0}255\r\n'.format(_RETURN_CODE_DELIMITER))
+
     def __init__(self, serial, product=None):
         self.serial = serial
         self.product = product
@@ -110,40 +124,44 @@
         if self.product is not None:
             self.adb_cmd.extend(['-p', product])
         self._linesep = None
-        self._shell_result_pattern = None
 
     @property
     def linesep(self):
         if self._linesep is None:
-            self._linesep = subprocess.check_output(['adb', 'shell', 'echo'])
+            self._linesep = subprocess.check_output(self.adb_cmd +
+                                                    ['shell', 'echo'])
         return self._linesep
 
     def _make_shell_cmd(self, user_cmd):
-        # Follow any shell command with `; echo; echo $?` to get the exit
-        # status of a program since this isn't propagated by adb.
-        #
-        # The leading newline is needed because `printf 1; echo $?` would print
-        # "10", and we wouldn't be able to distinguish the exit code.
-        rc_probe = '; echo "\n$?"'
-        return self.adb_cmd + ['shell'] + user_cmd + [rc_probe]
+        return (self.adb_cmd + ['shell'] + user_cmd +
+                ['; ' + self._RETURN_CODE_PROBE_STRING])
 
-    def _parse_shell_output(self, out):  # pylint: disable=no-self-use
+    def _parse_shell_output(self, out):
+        """Finds the exit code string from shell output.
+
+        Args:
+            out: Shell output string.
+
+        Returns:
+            An (exit_code, output_string) tuple. The output string is
+            cleaned of any additional stuff we appended to find the
+            exit code.
+
+        Raises:
+            RuntimeError: Could not find the exit code in |out|.
+        """
         search_text = out
-        max_result_len = len('{0}255{0}'.format(self.linesep))
-        if len(search_text) > max_result_len:
-            # We don't want to regex match over massive amounts of data when we
-            # know the part we want is right at the end.
-            search_text = search_text[-max_result_len:]
-        if self._shell_result_pattern is None:
-            self._shell_result_pattern = re.compile(
-                r'({0}\d+{0})$'.format(self.linesep), re.MULTILINE)
-        m = self._shell_result_pattern.search(search_text)
-        if m is None:
+        if len(search_text) > self._RETURN_CODE_SEARCH_LENGTH:
+            # We don't want to search over massive amounts of data when we know
+            # the part we want is right at the end.
+            search_text = search_text[-self._RETURN_CODE_SEARCH_LENGTH:]
+        partition = search_text.rpartition(self._RETURN_CODE_DELIMITER)
+        if partition[1] == '':
             raise RuntimeError('Could not find exit status in shell output.')
-
-        result_text = m.group(1)
-        result = int(result_text.strip())
-        out = out[:-len(result_text)]  # Trim the result text from the output.
+        result = int(partition[2])
+        # partition[0] won't contain the full text if search_text was truncated,
+        # pull from the original string instead.
+        out = out[:-len(partition[1]) - len(partition[2])]
         return result, out
 
     def _simple_call(self, cmd):
@@ -170,8 +188,12 @@
         out, _ = p.communicate()
         return self._parse_shell_output(out)
 
-    def install(self, filename):
-        return self._simple_call(['install', filename])
+    def install(self, filename, replace=False):
+        cmd = ['install']
+        if replace:
+            cmd.append('-r')
+        cmd.append(filename)
+        return self._simple_call(cmd)
 
     def push(self, local, remote):
         return self._simple_call(['push', local, remote])
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 5cd4988..a8abade 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -234,7 +234,7 @@
 
 #else /* USE_SELECT */
 
-#ifdef HAVE_WINSOCK
+#if defined(_WIN32)
 #include <winsock2.h>
 #else
 #include <sys/select.h>
@@ -617,7 +617,7 @@
     fde->func = func;
     fde->arg = arg;
 
-#ifndef HAVE_WINSOCK
+#if !defined(_WIN32)
     fcntl(fd, F_SETFL, O_NONBLOCK);
 #endif
     fdevent_register(fde);
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 49d42a3..da80013 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -35,6 +35,8 @@
 #include "adb_utils.h"
 #include "file_sync_service.h"
 
+#include <base/stringprintf.h>
+
 static unsigned long long total_bytes;
 static long long start_time;
 
@@ -92,36 +94,30 @@
 typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
 
 static int sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
+    int len = strlen(path);
+    if (len > 1024) goto fail;
+
     syncmsg msg;
-    char buf[257];
-    int len;
-
-    len = strlen(path);
-    if(len > 1024) goto fail;
-
     msg.req.id = ID_LIST;
     msg.req.namelen = htoll(len);
 
-    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
-       !WriteFdExactly(fd, path, len)) {
+    if (!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || !WriteFdExactly(fd, path, len)) {
         goto fail;
     }
 
-    for(;;) {
-        if(!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break;
-        if(msg.dent.id == ID_DONE) return 0;
-        if(msg.dent.id != ID_DENT) break;
+    for (;;) {
+        if (!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break;
+        if (msg.dent.id == ID_DONE) return 0;
+        if (msg.dent.id != ID_DENT) break;
 
         len = ltohl(msg.dent.namelen);
-        if(len > 256) break;
+        if (len > 256) break;
 
-        if(!ReadFdExactly(fd, buf, len)) break;
+        char buf[257];
+        if (!ReadFdExactly(fd, buf, len)) break;
         buf[len] = 0;
 
-        func(ltohl(msg.dent.mode),
-             ltohl(msg.dent.size),
-             ltohl(msg.dent.time),
-             buf, cookie);
+        func(ltohl(msg.dent.mode), ltohl(msg.dent.size), ltohl(msg.dent.time), buf, cookie);
     }
 
 fail:
@@ -220,7 +216,7 @@
     return 0;
 }
 
-static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show_progress)
+static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, bool show_progress)
 {
     int lfd, err = 0;
     unsigned long long size = 0;
@@ -274,7 +270,7 @@
 }
 
 static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
-                             int show_progress)
+                             bool show_progress)
 {
     int err = 0;
     int total = 0;
@@ -308,10 +304,8 @@
 #else
 static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
 {
-    int len, ret;
-
-    len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
-    if(len < 0) {
+    int len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
+    if (len < 0) {
         fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
         return -1;
     }
@@ -320,9 +314,9 @@
     sbuf->size = htoll(len + 1);
     sbuf->id = ID_DATA;
 
-    ret = !WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
-    if(ret)
+    if (!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1)) {
         return -1;
+    }
 
     total_bytes += len + 1;
 
@@ -331,7 +325,7 @@
 #endif
 
 static int sync_send(int fd, const char *lpath, const char *rpath,
-                     unsigned mtime, mode_t mode, int show_progress)
+                     unsigned mtime, mode_t mode, bool show_progress)
 {
     syncmsg msg;
     int len, r;
@@ -396,7 +390,7 @@
     return -1;
 }
 
-static int sync_recv(int fd, const char* rpath, const char* lpath, int show_progress) {
+static int sync_recv(int fd, const char* rpath, const char* lpath, bool show_progress) {
     syncmsg msg;
     int len;
     int lfd = -1;
@@ -523,12 +517,12 @@
         return 1;
     }
 
-    if(sync_ls(fd, path, do_sync_ls_cb, 0)) {
+    if (sync_ls(fd, path, do_sync_ls_cb, 0)) {
         return 1;
-    } else {
-        sync_quit(fd);
-        return 0;
     }
+
+    sync_quit(fd);
+    return 0;
 }
 
 struct copyinfo
@@ -712,11 +706,7 @@
 }
 
 
-int do_sync_push(const char *lpath, const char *rpath, int show_progress)
-{
-    struct stat st;
-    unsigned mode;
-
+int do_sync_push(const char* lpath, const char* rpath, bool show_progress) {
     std::string error;
     int fd = adb_connect("sync:", &error);
     if (fd < 0) {
@@ -724,51 +714,38 @@
         return 1;
     }
 
-    if(stat(lpath, &st)) {
+    struct stat st;
+    if (stat(lpath, &st)) {
         fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
         sync_quit(fd);
         return 1;
     }
 
-    if(S_ISDIR(st.st_mode)) {
+    if (S_ISDIR(st.st_mode)) {
         BEGIN();
-        if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
+        if (copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
             return 1;
-        } else {
-            END();
-            sync_quit(fd);
         }
     } else {
-        if(sync_readmode(fd, rpath, &mode)) {
+        unsigned mode;
+        if (sync_readmode(fd, rpath, &mode)) {
             return 1;
         }
-        if((mode != 0) && S_ISDIR(mode)) {
-                /* if we're copying a local file to a remote directory,
-                ** we *really* want to copy to remotedir + "/" + localfilename
-                */
-            const char *name = adb_dirstop(lpath);
-            if(name == 0) {
-                name = lpath;
-            } else {
-                name++;
-            }
-            int  tmplen = strlen(name) + strlen(rpath) + 2;
-            char *tmp = reinterpret_cast<char*>(
-                malloc(strlen(name) + strlen(rpath) + 2));
-            if(tmp == 0) return 1;
-            snprintf(tmp, tmplen, "%s/%s", rpath, name);
-            rpath = tmp;
+        std::string path_holder;
+        if ((mode != 0) && S_ISDIR(mode)) {
+            // 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("%s/%s", rpath, adb_basename(lpath).c_str());
+            rpath = path_holder.c_str();
         }
         BEGIN();
-        if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
+        if (sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
             return 1;
-        } else {
-            END();
-            sync_quit(fd);
-            return 0;
         }
     }
 
+    END();
+    sync_quit(fd);
     return 0;
 }
 
@@ -934,11 +911,7 @@
     return ret;
 }
 
-int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs)
-{
-    unsigned mode, time;
-    struct stat st;
-
+int do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs) {
     std::string error;
     int fd = adb_connect("sync:", &error);
     if (fd < 0) {
@@ -946,56 +919,46 @@
         return 1;
     }
 
-    if(sync_readtime(fd, rpath, &time, &mode)) {
+    unsigned mode, time;
+    if (sync_readtime(fd, rpath, &time, &mode)) {
         return 1;
     }
-    if(mode == 0) {
+    if (mode == 0) {
         fprintf(stderr,"remote object '%s' does not exist\n", rpath);
         return 1;
     }
 
-    if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
-        if(stat(lpath, &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 localdir + "/" + remotefilename
-                    */
-                const char *name = adb_dirstop(rpath);
-                if(name == 0) {
-                    name = rpath;
-                } else {
-                    name++;
-                }
-                int  tmplen = strlen(name) + strlen(lpath) + 2;
-                char *tmp = reinterpret_cast<char*>(malloc(tmplen));
-                if(tmp == 0) return 1;
-                snprintf(tmp, tmplen, "%s/%s", lpath, name);
-                lpath = tmp;
+    if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
+        std::string path_holder;
+        struct stat st;
+        if (stat(lpath, &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", lpath, adb_basename(rpath).c_str());
+                lpath = path_holder.c_str();
             }
         }
         BEGIN();
         if (sync_recv(fd, rpath, lpath, show_progress)) {
             return 1;
         } else {
-            if (copy_attrs && set_time_and_mode(lpath, time, mode))
+            if (copy_attrs && set_time_and_mode(lpath, time, mode)) {
                 return 1;
-            END();
-            sync_quit(fd);
-            return 0;
+            }
         }
     } else if(S_ISDIR(mode)) {
         BEGIN();
         if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
             return 1;
-        } else {
-            END();
-            sync_quit(fd);
-            return 0;
         }
     } else {
         fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
         return 1;
     }
+    END();
+    sync_quit(fd);
+    return 0;
 }
 
 int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only)
@@ -1012,9 +975,8 @@
     BEGIN();
     if (copy_local_dir_remote(fd, lpath.c_str(), rpath.c_str(), 1, list_only)) {
         return 1;
-    } else {
-        END();
-        sync_quit(fd);
-        return 0;
     }
+    END();
+    sync_quit(fd);
+    return 0;
 }
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 2067836..ea019f4 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -34,47 +34,46 @@
 #include "adb_io.h"
 #include "private/android_filesystem_config.h"
 
-static bool should_use_fs_config(const char* path) {
+#include <base/strings.h>
+
+static bool should_use_fs_config(const std::string& path) {
     // TODO: use fs_config to configure permissions on /data.
-    return strncmp("/system/", path, strlen("/system/")) == 0 ||
-           strncmp("/vendor/", path, strlen("/vendor/")) == 0 ||
-           strncmp("/oem/", path, strlen("/oem/")) == 0;
+    return android::base::StartsWith(path, "/system/") ||
+           android::base::StartsWith(path, "/vendor/") ||
+           android::base::StartsWith(path, "/oem/");
 }
 
-static int mkdirs(char *name)
-{
-    int ret;
-    char *x = name + 1;
+static bool secure_mkdirs(const std::string& path) {
     uid_t uid = -1;
     gid_t gid = -1;
     unsigned int mode = 0775;
     uint64_t cap = 0;
 
-    if(name[0] != '/') return -1;
+    if (path[0] != '/') return false;
 
-    for(;;) {
-        x = const_cast<char*>(adb_dirstart(x));
-        if(x == 0) return 0;
-        *x = 0;
-        if (should_use_fs_config(name)) {
-            fs_config(name, 1, &uid, &gid, &mode, &cap);
+    std::vector<std::string> path_components = android::base::Split(path, "/");
+    path_components.pop_back(); // For "/system/bin/sh", only create "/system/bin".
+
+    std::string partial_path;
+    for (auto& path_component : path_components) {
+        if (partial_path.back() != OS_PATH_SEPARATOR) partial_path += OS_PATH_SEPARATOR;
+        partial_path += path_component;
+
+        if (should_use_fs_config(partial_path)) {
+            fs_config(partial_path.c_str(), 1, &uid, &gid, &mode, &cap);
         }
-        ret = adb_mkdir(name, mode);
-        if((ret < 0) && (errno != EEXIST)) {
-            D("mkdir(\"%s\") -> %s\n", name, strerror(errno));
-            *x = '/';
-            return ret;
-        } else if(ret == 0) {
-            ret = chown(name, uid, gid);
-            if (ret < 0) {
-                *x = '/';
-                return ret;
+        if (adb_mkdir(partial_path.c_str(), mode) == -1) {
+            if (errno != EEXIST) {
+                return false;
             }
-            selinux_android_restorecon(name, 0);
+        } else {
+            if (chown(partial_path.c_str(), uid, gid) == -1) {
+                return false;
+            }
+            selinux_android_restorecon(partial_path.c_str(), 0);
         }
-        *x++ = '/';
     }
-    return 0;
+    return true;
 }
 
 static int do_stat(int s, const char *path)
@@ -99,26 +98,24 @@
 
 static int do_list(int s, const char *path)
 {
-    DIR *d;
     struct dirent *de;
     struct stat st;
-    syncmsg msg;
-    int len;
 
     char tmp[1024 + 256 + 1];
     char *fname;
 
-    len = strlen(path);
+    size_t len = strlen(path);
     memcpy(tmp, path, len);
     tmp[len] = '/';
     fname = tmp + len + 1;
 
+    syncmsg msg;
     msg.dent.id = ID_DENT;
 
-    d = opendir(path);
-    if(d == 0) goto done;
+    std::unique_ptr<DIR, int(*)(DIR*)> d(opendir(path), closedir);
+    if (!d) goto done;
 
-    while((de = readdir(d))) {
+    while ((de = readdir(d.get()))) {
         int len = strlen(de->d_name);
 
             /* not supposed to be possible, but
@@ -134,14 +131,11 @@
 
             if(!WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ||
                !WriteFdExactly(s, de->d_name, len)) {
-                closedir(d);
                 return -1;
             }
         }
     }
 
-    closedir(d);
-
 done:
     msg.dent.id = ID_DONE;
     msg.dent.mode = 0;
@@ -182,7 +176,7 @@
 
     fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
     if(fd < 0 && errno == ENOENT) {
-        if(mkdirs(path) != 0) {
+        if (!secure_mkdirs(path)) {
             if(fail_errno(s))
                 return -1;
             fd = -1;
@@ -294,7 +288,7 @@
 
     ret = symlink(buffer, path);
     if(ret && errno == ENOENT) {
-        if(mkdirs(path) != 0) {
+        if (!secure_mkdirs(path)) {
             fail_errno(s);
             return -1;
         }
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 344eb98..1d3e3bd 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -68,9 +68,9 @@
 
 void file_sync_service(int fd, void *cookie);
 int do_sync_ls(const char *path);
-int do_sync_push(const char *lpath, const char *rpath, int show_progress);
+int do_sync_push(const char *lpath, const char *rpath, bool show_progress);
 int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only);
-int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime);
+int do_sync_pull(const char *rpath, const char *lpath, bool show_progress, int pullTime);
 
 #define SYNC_DATA_MAX (64*1024)
 
diff --git a/adb/get_my_path_windows.cpp b/adb/get_my_path_windows.cpp
deleted file mode 100644
index 9d23e1c..0000000
--- a/adb/get_my_path_windows.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <assert.h>
-#include <limits.h>
-#include <windows.h>
-
-#include "adb.h"
-
-void get_my_path(char *exe, size_t maxLen)
-{
-    char  *r;
-
-    /* XXX: should be GetModuleFileNameA */
-    if (GetModuleFileName(NULL, exe, maxLen) > 0) {
-        r = strrchr(exe, '\\');
-        if (r != NULL)
-            *r = '\0';
-    } else {
-        exe[0] = '\0';
-    }
-}
-
diff --git a/adb/mutex_list.h b/adb/mutex_list.h
index ff72751..9003361 100644
--- a/adb/mutex_list.h
+++ b/adb/mutex_list.h
@@ -6,6 +6,7 @@
 #ifndef ADB_MUTEX
 #error ADB_MUTEX not defined when including this file
 #endif
+ADB_MUTEX(dirname_lock)
 ADB_MUTEX(socket_list_lock)
 ADB_MUTEX(transport_lock)
 #if ADB_HOST
diff --git a/adb/services.cpp b/adb/services.cpp
index 82efb1c..255be09 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -59,6 +59,10 @@
     void *cookie;
 };
 
+enum class SubprocessType {
+    kPty,
+    kRaw,
+};
 
 void *service_bootstrap_func(void *x)
 {
@@ -389,17 +393,27 @@
     }
 }
 
-static int create_subproc_thread(const char *name, bool pty = false) {
+// Starts a subprocess and spawns a thread to wait for the subprocess to finish
+// and trigger the necessary cleanup.
+//
+// |name| is the command to execute in the subprocess; empty string will start
+//     an interactive session.
+// |type| selects between a PTY or raw subprocess.
+//
+// Returns an open file descriptor tied to the subprocess stdin/stdout/stderr.
+static int create_subproc_thread(const char *name, SubprocessType type) {
     const char *arg0, *arg1;
-    if (name == 0 || *name == 0) {
-        arg0 = "-"; arg1 = 0;
+    if (*name == '\0') {
+        arg0 = "-";
+        arg1 = nullptr;
     } else {
-        arg0 = "-c"; arg1 = name;
+        arg0 = "-c";
+        arg1 = name;
     }
 
     pid_t pid = -1;
     int ret_fd;
-    if (pty) {
+    if (type == SubprocessType::kPty) {
         ret_fd = create_subproc_pty(SHELL_COMMAND, arg0, arg1, &pid);
     } else {
         ret_fd = create_subproc_raw(SHELL_COMMAND, arg0, arg1, &pid);
@@ -432,7 +446,8 @@
         int port = atoi(name + 4);
         name = strchr(name + 4, ':');
         if(name == 0) {
-            ret = socket_loopback_client(port, SOCK_STREAM);
+            std::string error;
+            ret = network_loopback_client(port, SOCK_STREAM, &error);
             if (ret >= 0)
                 disable_tcp_nagle(ret);
         } else {
@@ -443,7 +458,7 @@
             return -1;
 #endif
         }
-#ifndef HAVE_WINSOCK   /* winsock doesn't implement unix domain sockets */
+#if !defined(_WIN32)   /* winsock doesn't implement unix domain sockets */
     } else if(!strncmp(name, "local:", 6)) {
         ret = socket_local_client(name + 6,
                 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
@@ -464,10 +479,17 @@
         ret = create_service_thread(framebuffer_service, 0);
     } else if (!strncmp(name, "jdwp:", 5)) {
         ret = create_jdwp_connection_fd(atoi(name+5));
-    } else if(!HOST && !strncmp(name, "shell:", 6)) {
-        ret = create_subproc_thread(name + 6, true);
-    } else if(!HOST && !strncmp(name, "exec:", 5)) {
-        ret = create_subproc_thread(name + 5);
+    } else if(!strncmp(name, "shell:", 6)) {
+        const char* args = name + 6;
+        if (*args) {
+            // Non-interactive session uses a raw subprocess.
+            ret = create_subproc_thread(args, SubprocessType::kRaw);
+        } else {
+            // Interactive session uses a PTY subprocess.
+            ret = create_subproc_thread(args, SubprocessType::kPty);
+        }
+    } else if(!strncmp(name, "exec:", 5)) {
+        ret = create_subproc_thread(name + 5, SubprocessType::kRaw);
     } else if(!strncmp(name, "sync:", 5)) {
         ret = create_service_thread(file_sync_service, NULL);
     } else if(!strncmp(name, "remount:", 8)) {
@@ -481,10 +503,13 @@
     } else if(!strncmp(name, "unroot:", 7)) {
         ret = create_service_thread(restart_unroot_service, NULL);
     } else if(!strncmp(name, "backup:", 7)) {
-        ret = create_subproc_thread(android::base::StringPrintf("/system/bin/bu backup %s",
-                                                                (name + 7)).c_str());
+        ret = create_subproc_thread(
+                android::base::StringPrintf("/system/bin/bu backup %s",
+                                            (name + 7)).c_str(),
+                SubprocessType::kRaw);
     } else if(!strncmp(name, "restore:", 8)) {
-        ret = create_subproc_thread("/system/bin/bu restore");
+        ret = create_subproc_thread("/system/bin/bu restore",
+                                    SubprocessType::kRaw);
     } else if(!strncmp(name, "tcpip:", 6)) {
         int port;
         if (sscanf(name + 6, "%d", &port) != 1) {
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 729bbcb..6f3c443 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -26,6 +26,8 @@
 
 #include <errno.h>
 
+#include <string>
+
 /*
  * 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
@@ -41,21 +43,39 @@
     _rc; })
 #endif
 
+// Some printf-like functions are implemented in terms of
+// android::base::StringAppendV, so they should use the same attribute for
+// compile-time format string checking. On Windows, if the mingw version of
+// vsnprintf is used in StringAppendV, use `gnu_printf' which allows z in %zd
+// and PRIu64 (and related) to be recognized by the compile-time checking.
+#define ADB_FORMAT_ARCHETYPE __printf__
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+#undef ADB_FORMAT_ARCHETYPE
+#define ADB_FORMAT_ARCHETYPE gnu_printf
+#endif
+#endif
+
 #ifdef _WIN32
 
 #include <ctype.h>
 #include <direct.h>
+#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <io.h>
 #include <process.h>
 #include <sys/stat.h>
+#include <utime.h>
 #include <winsock2.h>
 #include <windows.h>
 #include <ws2tcpip.h>
 
+#include <string>   // Prototypes for narrow() and widen() use std::(w)string.
+
 #include "fdevent.h"
 
+#define OS_PATH_SEPARATORS "\\/"
 #define OS_PATH_SEPARATOR '\\'
 #define OS_PATH_SEPARATOR_STR "\\"
 #define ENV_PATH_SEPARATOR_STR ";"
@@ -104,26 +124,11 @@
 
 #define  S_ISLNK(m)   0   /* no symlinks on Win32 */
 
-static __inline__  int    adb_unlink(const char*  path)
-{
-    int  rc = unlink(path);
-
-    if (rc == -1 && errno == EACCES) {
-        /* unlink returns EACCES when the file is read-only, so we first */
-        /* try to make it writable, then unlink again...                  */
-        rc = chmod(path, _S_IREAD|_S_IWRITE );
-        if (rc == 0)
-            rc = unlink(path);
-    }
-    return rc;
-}
+extern int  adb_unlink(const char*  path);
 #undef  unlink
 #define unlink  ___xxx_unlink
 
-static __inline__ int  adb_mkdir(const char*  path, int mode)
-{
-	return _mkdir(path);
-}
+extern int adb_mkdir(const std::string& path, int mode);
 #undef   mkdir
 #define  mkdir  ___xxx_mkdir
 
@@ -165,22 +170,7 @@
 }
 
 // See the comments for the !defined(_WIN32) version of unix_open().
-static __inline__ int  unix_open(const char*  path, int options,...)
-{
-    if ((options & O_CREAT) == 0)
-    {
-        return  open(path, options);
-    }
-    else
-    {
-        int      mode;
-        va_list  args;
-        va_start( args, options );
-        mode = va_arg( args, int );
-        va_end( args );
-        return open(path, options, mode);
-    }
-}
+extern int unix_open(const char* path, int options, ...);
 #define  open    ___xxx_unix_open
 
 
@@ -210,6 +200,12 @@
     Sleep( mseconds );
 }
 
+int network_loopback_client(int port, int type, std::string* error);
+int network_loopback_server(int port, int type, std::string* error);
+int network_inaddr_any_server(int port, int type, std::string* error);
+int network_connect(const std::string& host, int port, int type, int timeout,
+                    std::string* error);
+
 extern int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen);
 
 #undef   accept
@@ -234,41 +230,136 @@
 
 extern int  adb_socketpair( int  sv[2] );
 
-static __inline__  char*  adb_dirstart( const char*  path )
-{
-    char*  p  = strchr(path, '/');
-    char*  p2 = strchr(path, '\\');
-
-    if ( !p )
-        p = p2;
-    else if ( p2 && p2 > p )
-        p = p2;
-
-    return p;
-}
-
-static __inline__  const char*  adb_dirstop( const char*  path )
-{
-    const char*  p  = strrchr(path, '/');
-    const char*  p2 = strrchr(path, '\\');
-
-    if ( !p )
-        p = p2;
-    else if ( p2 && p2 > p )
-        p = p2;
-
-    return p;
-}
-
-static __inline__  int  adb_is_absolute_host_path( const char*  path )
-{
+static __inline__ int adb_is_absolute_host_path(const char* path) {
     return isalpha(path[0]) && path[1] == ':' && path[2] == '\\';
 }
 
+// Like strerror(), but for Win32 error codes.
+std::string SystemErrorCodeToString(DWORD error_code);
+
+// We later define a macro mapping 'stat' to 'adb_stat'. This causes:
+//   struct stat s;
+//   stat(filename, &s);
+// To turn into the following:
+//   struct adb_stat s;
+//   adb_stat(filename, &s);
+// To get this to work, we need to make 'struct adb_stat' the same as
+// 'struct stat'. Note that this definition of 'struct adb_stat' uses the
+// *current* macro definition of stat, so it may actually be inheriting from
+// struct _stat32i64 (or some other remapping).
+struct adb_stat : public stat {};
+
+static_assert(sizeof(struct adb_stat) == sizeof(struct stat),
+    "structures should be the same");
+
+extern int adb_stat(const char* f, struct adb_stat* s);
+
+// stat is already a macro, undefine it so we can redefine it.
+#undef stat
+#define stat adb_stat
+
+// UTF-8 versions of POSIX APIs.
+extern DIR* adb_opendir(const char* dirname);
+extern struct dirent* adb_readdir(DIR* dir);
+extern int adb_closedir(DIR* dir);
+
+extern int adb_utime(const char *, struct utimbuf *);
+extern int adb_chmod(const char *, int);
+
+extern int adb_vfprintf(FILE *stream, const char *format, va_list ap)
+    __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 0)));
+extern int adb_fprintf(FILE *stream, const char *format, ...)
+    __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3)));
+extern int adb_printf(const char *format, ...)
+    __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 1, 2)));
+
+extern int adb_fputs(const char* buf, FILE* stream);
+extern int adb_fputc(int ch, FILE* stream);
+extern size_t adb_fwrite(const void* ptr, size_t size, size_t nmemb,
+                         FILE* stream);
+
+extern FILE* adb_fopen(const char* f, const char* m);
+
+extern char* adb_getenv(const char* name);
+
+extern char* adb_getcwd(char* buf, int size);
+
+// Remap calls to POSIX APIs to our UTF-8 versions.
+#define opendir adb_opendir
+#define readdir adb_readdir
+#define closedir adb_closedir
+#define rewinddir rewinddir_utf8_not_yet_implemented
+#define telldir telldir_utf8_not_yet_implemented
+#define seekdir seekdir_utf8_not_yet_implemented
+
+#define utime adb_utime
+#define chmod adb_chmod
+
+#define vfprintf adb_vfprintf
+#define fprintf adb_fprintf
+#define printf adb_printf
+#define fputs adb_fputs
+#define fputc adb_fputc
+#define fwrite adb_fwrite
+
+#define fopen adb_fopen
+
+#define getenv adb_getenv
+#define putenv putenv_utf8_not_yet_implemented
+#define setenv setenv_utf8_not_yet_implemented
+#define unsetenv unsetenv_utf8_not_yet_implemented
+
+#define getcwd adb_getcwd
+
+// 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 {
+public:
+    NarrowArgs(int argc, wchar_t** argv);
+    ~NarrowArgs();
+
+    inline char** data() {
+        return narrow_args;
+    }
+
+private:
+    char** narrow_args;
+};
+
+// Windows HANDLE values only use 32-bits of the type, even on 64-bit machines,
+// so they can fit in an int. To convert back, we just need to sign-extend.
+// https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203%28v=vs.85%29.aspx
+// Note that this does not make a HANDLE value work with APIs like open(), nor
+// does this make a value from open() passable to APIs taking a HANDLE. This
+// just lets you take a HANDLE, pass it around as an int, and then use it again
+// as a HANDLE.
+inline int cast_handle_to_int(const HANDLE h) {
+    // truncate
+    return static_cast<int>(reinterpret_cast<INT_PTR>(h));
+}
+
+inline HANDLE cast_int_to_handle(const int fd) {
+    // sign-extend
+    return reinterpret_cast<HANDLE>(static_cast<INT_PTR>(fd));
+}
+
 #else /* !_WIN32 a.k.a. Unix */
 
 #include "fdevent.h"
 #include <cutils/misc.h>
+#include <cutils/sockets.h>
 #include <cutils/threads.h>
 #include <signal.h>
 #include <sys/wait.h>
@@ -279,11 +370,15 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <stdarg.h>
+#include <netdb.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <string.h>
 #include <unistd.h>
 
+#include <string>
+
+#define OS_PATH_SEPARATORS "/"
 #define OS_PATH_SEPARATOR '/'
 #define OS_PATH_SEPARATOR_STR "/"
 #define ENV_PATH_SEPARATOR_STR ":"
@@ -426,6 +521,48 @@
 #undef   creat
 #define  creat  ___xxx_creat
 
+// Helper for network_* functions.
+inline int _fd_set_error_str(int fd, std::string* error) {
+  if (fd == -1) {
+    *error = strerror(errno);
+  }
+  return fd;
+}
+
+inline int network_loopback_client(int port, int type, std::string* error) {
+  return _fd_set_error_str(socket_loopback_client(port, type), error);
+}
+
+inline int network_loopback_server(int port, int type, std::string* error) {
+  return _fd_set_error_str(socket_loopback_server(port, type), error);
+}
+
+inline int network_inaddr_any_server(int port, int type, std::string* error) {
+  return _fd_set_error_str(socket_inaddr_any_server(port, type), error);
+}
+
+inline int network_local_server(const char *name, int namespace_id, int type,
+                                std::string* error) {
+  return _fd_set_error_str(socket_local_server(name, namespace_id, type),
+                           error);
+}
+
+inline int network_connect(const std::string& host, int port, int type,
+                           int timeout, std::string* error) {
+  int getaddrinfo_error = 0;
+  int fd = socket_network_client_timeout(host.c_str(), port, type, timeout,
+                                         &getaddrinfo_error);
+  if (fd != -1) {
+    return fd;
+  }
+  if (getaddrinfo_error != 0) {
+    *error = gai_strerror(getaddrinfo_error);
+  } else {
+    *error = strerror(errno);
+  }
+  return -1;
+}
+
 static __inline__ int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen)
 {
     int fd;
@@ -510,10 +647,11 @@
     usleep( mseconds*1000 );
 }
 
-static __inline__ int  adb_mkdir(const char*  path, int mode)
+static __inline__ int  adb_mkdir(const std::string& path, int mode)
 {
-    return mkdir(path, mode);
+    return mkdir(path.c_str(), mode);
 }
+
 #undef   mkdir
 #define  mkdir  ___xxx_mkdir
 
@@ -521,18 +659,7 @@
 {
 }
 
-static __inline__ const char*  adb_dirstart(const char*  path)
-{
-    return strchr(path, '/');
-}
-
-static __inline__ const char*  adb_dirstop(const char*  path)
-{
-    return strrchr(path, '/');
-}
-
-static __inline__  int  adb_is_absolute_host_path( const char*  path )
-{
+static __inline__ int adb_is_absolute_host_path(const char* path) {
     return path[0] == '/';
 }
 
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index a274892..f534d61 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -25,8 +25,16 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <memory>
+#include <string>
+#include <unordered_map>
+
 #include <cutils/sockets.h>
 
+#include <base/logging.h>
+#include <base/stringprintf.h>
+#include <base/strings.h>
+
 #include "adb.h"
 
 extern void fatal(const char *fmt, ...);
@@ -80,6 +88,30 @@
 
 #define assert(cond)  do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0)
 
+std::string SystemErrorCodeToString(const DWORD error_code) {
+  const int kErrorMessageBufferSize = 256;
+  WCHAR msgbuf[kErrorMessageBufferSize];
+  DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
+  DWORD len = FormatMessageW(flags, nullptr, error_code, 0, msgbuf,
+                             arraysize(msgbuf), nullptr);
+  if (len == 0) {
+    return android::base::StringPrintf(
+        "Error (%lu) while retrieving error. (%lu)", GetLastError(),
+        error_code);
+  }
+
+  // Convert UTF-16 to UTF-8.
+  std::string msg(narrow(msgbuf));
+  // 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
+  // numeric error code for easier, quicker, accurate identification. Use
+  // decimal instead of hex because there are decimal ranges like 10000-11999
+  // for Winsock.
+  android::base::StringAppendF(&msg, " (%lu)", error_code);
+  return msg;
+}
+
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
@@ -94,13 +126,13 @@
     char     *data;
     DWORD     file_size;
 
-    file = CreateFile( fn,
-                       GENERIC_READ,
-                       FILE_SHARE_READ,
-                       NULL,
-                       OPEN_EXISTING,
-                       0,
-                       NULL );
+    file = CreateFileW( widen(fn).c_str(),
+                        GENERIC_READ,
+                        FILE_SHARE_READ,
+                        NULL,
+                        OPEN_EXISTING,
+                        0,
+                        NULL );
 
     if (file == INVALID_HANDLE_VALUE)
         return NULL;
@@ -171,7 +203,7 @@
 
 static adb_mutex_t   _win32_lock;
 static  FHRec        _win32_fhs[ WIN32_MAX_FHS ];
-static  int          _win32_fh_count;
+static  int          _win32_fh_next;  // where to start search for free FHRec
 
 static FH
 _fh_from_int( int   fd, const char*   func )
@@ -180,7 +212,7 @@
 
     fd -= WIN32_FH_BASE;
 
-    if (fd < 0 || fd >= _win32_fh_count) {
+    if (fd < 0 || fd >= WIN32_MAX_FHS) {
         D( "_fh_from_int: invalid fd %d passed to %s\n", fd + WIN32_FH_BASE,
            func );
         errno = EBADF;
@@ -212,28 +244,32 @@
 static FH
 _fh_alloc( FHClass  clazz )
 {
-    int  nn;
     FH   f = NULL;
 
     adb_mutex_lock( &_win32_lock );
 
-    if (_win32_fh_count < WIN32_MAX_FHS) {
-        f = &_win32_fhs[ _win32_fh_count++ ];
-        goto Exit;
-    }
-
-    for (nn = 0; nn < WIN32_MAX_FHS; nn++) {
-        if ( _win32_fhs[nn].clazz == NULL) {
-            f = &_win32_fhs[nn];
+    // Search entire array, starting from _win32_fh_next.
+    for (int nn = 0; nn < WIN32_MAX_FHS; nn++) {
+        // Keep incrementing _win32_fh_next to avoid giving out an index that
+        // was recently closed, to try to avoid use-after-free.
+        const int index = _win32_fh_next++;
+        // Handle wrap-around of _win32_fh_next.
+        if (_win32_fh_next == WIN32_MAX_FHS) {
+            _win32_fh_next = 0;
+        }
+        if (_win32_fhs[index].clazz == NULL) {
+            f = &_win32_fhs[index];
             goto Exit;
         }
     }
     D( "_fh_alloc: no more free file descriptors\n" );
+    errno = EMFILE;   // Too many open files
 Exit:
     if (f) {
-        f->clazz = clazz;
-        f->used  = 1;
-        f->eof   = 0;
+        f->clazz   = clazz;
+        f->used    = 1;
+        f->eof     = 0;
+        f->name[0] = '\0';
         clazz->_fh_init(f);
     }
     adb_mutex_unlock( &_win32_lock );
@@ -244,15 +280,37 @@
 static int
 _fh_close( FH   f )
 {
-    if ( f->used ) {
+    // Use lock so that closing only happens once and so that _fh_alloc can't
+    // allocate a FH that we're in the middle of closing.
+    adb_mutex_lock(&_win32_lock);
+    if (f->used) {
         f->clazz->_fh_close( f );
-        f->used = 0;
-        f->eof  = 0;
-        f->clazz = NULL;
+        f->name[0] = '\0';
+        f->eof     = 0;
+        f->used    = 0;
+        f->clazz   = NULL;
     }
+    adb_mutex_unlock(&_win32_lock);
     return 0;
 }
 
+// Deleter for unique_fh.
+class fh_deleter {
+ public:
+  void operator()(struct FHRec_* fh) {
+    // We're called from a destructor and destructors should not overwrite
+    // errno because callers may do:
+    //   errno = EBLAH;
+    //   return -1; // calls destructor, which should not overwrite errno
+    const int saved_errno = errno;
+    _fh_close(fh);
+    errno = saved_errno;
+  }
+};
+
+// Like std::unique_ptr, but calls _fh_close() instead of operator delete().
+typedef std::unique_ptr<struct FHRec_, fh_deleter> unique_fh;
+
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
@@ -355,12 +413,11 @@
 
     f = _fh_alloc( &_fh_file_class );
     if ( !f ) {
-        errno = ENOMEM;
         return -1;
     }
 
-    f->fh_handle = CreateFile( path, desiredAccess, shareMode, NULL, OPEN_EXISTING,
-                               0, NULL );
+    f->fh_handle = CreateFileW( widen(path).c_str(), desiredAccess, shareMode,
+                                NULL, OPEN_EXISTING, 0, NULL );
 
     if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
         const DWORD err = GetLastError();
@@ -378,7 +435,8 @@
                 return -1;
 
             default:
-                D( "unknown error: %ld\n", err );
+                D( "unknown error: %s\n",
+                   SystemErrorCodeToString( err ).c_str() );
                 errno = ENOENT;
                 return -1;
         }
@@ -396,13 +454,13 @@
 
     f = _fh_alloc( &_fh_file_class );
     if ( !f ) {
-        errno = ENOMEM;
         return -1;
     }
 
-    f->fh_handle = CreateFile( path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
-                               NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
-                               NULL );
+    f->fh_handle = CreateFileW( widen(path).c_str(), GENERIC_WRITE,
+                                FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+                                NULL );
 
     if ( f->fh_handle == INVALID_HANDLE_VALUE ) {
         const DWORD err = GetLastError();
@@ -420,7 +478,8 @@
                 return -1;
 
             default:
-                D( "unknown error: %ld\n", err );
+                D( "unknown error: %s\n",
+                   SystemErrorCodeToString( err ).c_str() );
                 errno = ENOENT;
                 return -1;
         }
@@ -467,21 +526,6 @@
 }
 
 
-int  adb_shutdown(int  fd)
-{
-    FH   f = _fh_from_int(fd, __func__);
-
-    if (!f || f->clazz != &_fh_socket_class) {
-        D("adb_shutdown: invalid fd %d\n", fd);
-        return -1;
-    }
-
-    D( "adb_shutdown: %s\n", f->name);
-    shutdown( f->fh_socket, SD_BOTH );
-    return 0;
-}
-
-
 int  adb_close(int  fd)
 {
     FH   f = _fh_from_int(fd, __func__);
@@ -505,29 +549,66 @@
 
 #undef setsockopt
 
-static void _socket_set_errno( void ) {
-    switch (WSAGetLastError()) {
+static void _socket_set_errno( const DWORD err ) {
+    // The Windows C Runtime (MSVCRT.DLL) strerror() does not support a lot of
+    // POSIX and socket error codes, so this can only meaningfully map so much.
+    switch ( err ) {
     case 0:              errno = 0; break;
+    // Mapping WSAEWOULDBLOCK to EAGAIN is absolutely critical because
+    // non-blocking sockets can cause an error code of WSAEWOULDBLOCK and
+    // callers check specifically for EAGAIN.
     case WSAEWOULDBLOCK: errno = EAGAIN; break;
     case WSAEINTR:       errno = EINTR; break;
+    case WSAEFAULT:      errno = EFAULT; break;
+    case WSAEINVAL:      errno = EINVAL; break;
+    case WSAEMFILE:      errno = EMFILE; break;
     default:
-        D( "_socket_set_errno: unhandled value %d\n", WSAGetLastError() );
         errno = EINVAL;
+        D( "_socket_set_errno: mapping Windows error code %lu to errno %d\n",
+           err, errno );
     }
 }
 
 static void _fh_socket_init( FH  f ) {
     f->fh_socket = INVALID_SOCKET;
     f->event     = WSACreateEvent();
+    if (f->event == WSA_INVALID_EVENT) {
+        D("WSACreateEvent failed: %s\n",
+          SystemErrorCodeToString(WSAGetLastError()).c_str());
+
+        // _event_socket_start assumes that this field is INVALID_HANDLE_VALUE
+        // on failure, instead of NULL which is what Windows really returns on
+        // error. It might be better to change all the other code to look for
+        // NULL, but that is a much riskier change.
+        f->event = INVALID_HANDLE_VALUE;
+    }
     f->mask      = 0;
 }
 
 static int _fh_socket_close( FH  f ) {
-    /* gently tell any peer that we're closing the socket */
-    shutdown( f->fh_socket, SD_BOTH );
-    closesocket( f->fh_socket );
-    f->fh_socket = INVALID_SOCKET;
-    CloseHandle( f->event );
+    if (f->fh_socket != INVALID_SOCKET) {
+        /* gently tell any peer that we're closing the socket */
+        if (shutdown(f->fh_socket, SD_BOTH) == SOCKET_ERROR) {
+            // If the socket is not connected, this returns an error. We want to
+            // minimize logging spam, so don't log these errors for now.
+#if 0
+            D("socket shutdown failed: %s\n",
+              SystemErrorCodeToString(WSAGetLastError()).c_str());
+#endif
+        }
+        if (closesocket(f->fh_socket) == SOCKET_ERROR) {
+            D("closesocket failed: %s\n",
+              SystemErrorCodeToString(WSAGetLastError()).c_str());
+        }
+        f->fh_socket = INVALID_SOCKET;
+    }
+    if (f->event != NULL) {
+        if (!CloseHandle(f->event)) {
+            D("CloseHandle failed: %s\n",
+              SystemErrorCodeToString(GetLastError()).c_str());
+        }
+        f->event = NULL;
+    }
     f->mask = 0;
     return 0;
 }
@@ -540,7 +621,14 @@
 static int _fh_socket_read(FH f, void* buf, int len) {
     int  result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0);
     if (result == SOCKET_ERROR) {
-        _socket_set_errno();
+        const DWORD err = WSAGetLastError();
+        // WSAEWOULDBLOCK is normal with a non-blocking socket, so don't trace
+        // that to reduce spam and confusion.
+        if (err != WSAEWOULDBLOCK) {
+            D("recv fd %d failed: %s\n", _fh_to_int(f),
+              SystemErrorCodeToString(err).c_str());
+        }
+        _socket_set_errno(err);
         result = -1;
     }
     return  result;
@@ -549,7 +637,10 @@
 static int _fh_socket_write(FH f, const void* buf, int len) {
     int  result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0);
     if (result == SOCKET_ERROR) {
-        _socket_set_errno();
+        const DWORD err = WSAGetLastError();
+        D("send fd %d failed: %s\n", _fh_to_int(f),
+          SystemErrorCodeToString(err).c_str());
+        _socket_set_errno(err);
         result = -1;
     }
     return result;
@@ -568,33 +659,44 @@
 static int  _winsock_init;
 
 static void
-_cleanup_winsock( void )
-{
-    WSACleanup();
-}
-
-static void
 _init_winsock( void )
 {
+    // TODO: Multiple threads calling this may potentially cause multiple calls
+    // to WSAStartup() which offers no real benefit.
     if (!_winsock_init) {
         WSADATA  wsaData;
         int      rc = WSAStartup( MAKEWORD(2,2), &wsaData);
         if (rc != 0) {
-            fatal( "adb: could not initialize Winsock\n" );
+            fatal( "adb: could not initialize Winsock: %s",
+                   SystemErrorCodeToString( rc ).c_str());
         }
-        atexit( _cleanup_winsock );
         _winsock_init = 1;
+
+        // Note that we do not call atexit() to register WSACleanup to be called
+        // at normal process termination because:
+        // 1) When exit() is called, there are still threads actively using
+        //    Winsock because we don't cleanly shutdown all threads, so it
+        //    doesn't make sense to call WSACleanup() and may cause problems
+        //    with those threads.
+        // 2) A deadlock can occur when exit() holds a C Runtime lock, then it
+        //    calls WSACleanup() which tries to unload a DLL, which tries to
+        //    grab the LoaderLock. This conflicts with the device_poll_thread
+        //    which holds the LoaderLock because AdbWinApi.dll calls
+        //    setupapi.dll which tries to load wintrust.dll which tries to load
+        //    crypt32.dll which calls atexit() which tries to acquire the C
+        //    Runtime lock that the other thread holds.
     }
 }
 
-int socket_loopback_client(int port, int type)
-{
-    FH  f = _fh_alloc( &_fh_socket_class );
+int network_loopback_client(int port, int type, std::string* error) {
     struct sockaddr_in addr;
     SOCKET  s;
 
-    if (!f)
+    unique_fh  f(_fh_alloc(&_fh_socket_class));
+    if (!f) {
+        *error = strerror(errno);
         return -1;
+    }
 
     if (!_winsock_init)
         _init_winsock();
@@ -606,32 +708,45 @@
 
     s = socket(AF_INET, type, 0);
     if(s == INVALID_SOCKET) {
-        D("socket_loopback_client: could not create socket\n" );
-        _fh_close(f);
+        *error = android::base::StringPrintf("cannot create socket: %s",
+                SystemErrorCodeToString(WSAGetLastError()).c_str());
+        D("%s\n", error->c_str());
+        return -1;
+    }
+    f->fh_socket = s;
+
+    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) {
+        // Save err just in case inet_ntoa() or ntohs() changes the last error.
+        const DWORD err = WSAGetLastError();
+        *error = android::base::StringPrintf("cannot connect to %s:%u: %s",
+                inet_ntoa(addr.sin_addr), ntohs(addr.sin_port),
+                SystemErrorCodeToString(err).c_str());
+        D("could not connect to %s:%d: %s\n",
+          type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str());
         return -1;
     }
 
-    f->fh_socket = s;
-    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        D("socket_loopback_client: could not connect to %s:%d\n", type != SOCK_STREAM ? "udp" : "tcp", port );
-        _fh_close(f);
-        return -1;
-    }
-    snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
-    D( "socket_loopback_client: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
-    return _fh_to_int(f);
+    const int fd = _fh_to_int(f.get());
+    snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", fd,
+              type != SOCK_STREAM ? "udp:" : "", port );
+    D( "port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp",
+       fd );
+    f.release();
+    return fd;
 }
 
 #define LISTEN_BACKLOG 4
 
-int socket_loopback_server(int port, int type)
-{
-    FH   f = _fh_alloc( &_fh_socket_class );
+// interface_address is INADDR_LOOPBACK or INADDR_ANY.
+static int _network_server(int port, int type, u_long interface_address,
+                           std::string* error) {
     struct sockaddr_in addr;
     SOCKET  s;
     int  n;
 
+    unique_fh   f(_fh_alloc(&_fh_socket_class));
     if (!f) {
+        *error = strerror(errno);
         return -1;
     }
 
@@ -641,149 +756,173 @@
     memset(&addr, 0, sizeof(addr));
     addr.sin_family = AF_INET;
     addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+    addr.sin_addr.s_addr = htonl(interface_address);
 
+    // TODO: Consider using dual-stack socket that can simultaneously listen on
+    // IPv4 and IPv6.
     s = socket(AF_INET, type, 0);
-    if(s == INVALID_SOCKET) return -1;
+    if (s == INVALID_SOCKET) {
+        *error = android::base::StringPrintf("cannot create socket: %s",
+                SystemErrorCodeToString(WSAGetLastError()).c_str());
+        D("%s\n", error->c_str());
+        return -1;
+    }
 
     f->fh_socket = s;
 
+    // Note: SO_REUSEADDR on Windows allows multiple processes to bind to the
+    // same port, so instead use SO_EXCLUSIVEADDRUSE.
     n = 1;
-    setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
+    if (setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n,
+                   sizeof(n)) == SOCKET_ERROR) {
+        *error = android::base::StringPrintf(
+                "cannot set socket option SO_EXCLUSIVEADDRUSE: %s",
+                SystemErrorCodeToString(WSAGetLastError()).c_str());
+        D("%s\n", error->c_str());
+        return -1;
+    }
 
-    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        _fh_close(f);
+    if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) {
+        // Save err just in case inet_ntoa() or ntohs() changes the last error.
+        const DWORD err = WSAGetLastError();
+        *error = android::base::StringPrintf("cannot bind to %s:%u: %s",
+                inet_ntoa(addr.sin_addr), ntohs(addr.sin_port),
+                SystemErrorCodeToString(err).c_str());
+        D("could not bind to %s:%d: %s\n",
+          type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str());
         return -1;
     }
     if (type == SOCK_STREAM) {
-        int ret;
-
-        ret = listen(s, LISTEN_BACKLOG);
-        if (ret < 0) {
-            _fh_close(f);
+        if (listen(s, LISTEN_BACKLOG) == SOCKET_ERROR) {
+            *error = android::base::StringPrintf("cannot listen on socket: %s",
+                    SystemErrorCodeToString(WSAGetLastError()).c_str());
+            D("could not listen on %s:%d: %s\n",
+              type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str());
             return -1;
         }
     }
-    snprintf( f->name, sizeof(f->name), "%d(lo-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
-    D( "socket_loopback_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
-    return _fh_to_int(f);
+    const int fd = _fh_to_int(f.get());
+    snprintf( f->name, sizeof(f->name), "%d(%s-server:%s%d)", fd,
+              interface_address == INADDR_LOOPBACK ? "lo" : "any",
+              type != SOCK_STREAM ? "udp:" : "", port );
+    D( "port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp",
+       fd );
+    f.release();
+    return fd;
 }
 
+int network_loopback_server(int port, int type, std::string* error) {
+    return _network_server(port, type, INADDR_LOOPBACK, error);
+}
 
-int socket_network_client_timeout(const char *host, int port, int type, int timeout,
-                                  int* getaddrinfo_error) {
-    FH  f = _fh_alloc( &_fh_socket_class );
-    if (!f) return -1;
+int network_inaddr_any_server(int port, int type, std::string* error) {
+    return _network_server(port, type, INADDR_ANY, error);
+}
+
+int network_connect(const std::string& host, int port, int type, int timeout, std::string* error) {
+    unique_fh f(_fh_alloc(&_fh_socket_class));
+    if (!f) {
+        *error = strerror(errno);
+        return -1;
+    }
 
     if (!_winsock_init) _init_winsock();
 
-    hostent* hp = gethostbyname(host);
-    if(hp == 0) {
-        _fh_close(f);
+    struct addrinfo hints;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = type;
+
+    char port_str[16];
+    snprintf(port_str, sizeof(port_str), "%d", port);
+
+    struct addrinfo* addrinfo_ptr = nullptr;
+
+#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()).
+#else
+    // Otherwise, keep using getaddrinfo(), or do runtime API detection
+    // with GetProcAddress("GetAddrInfoW").
+#endif
+    if (getaddrinfo(host.c_str(), port_str, &hints, &addrinfo_ptr) != 0) {
+        *error = android::base::StringPrintf(
+                "cannot resolve host '%s' and port %s: %s", host.c_str(),
+                port_str, SystemErrorCodeToString(WSAGetLastError()).c_str());
+        D("%s\n", error->c_str());
         return -1;
     }
+    std::unique_ptr<struct addrinfo, decltype(freeaddrinfo)*>
+        addrinfo(addrinfo_ptr, freeaddrinfo);
+    addrinfo_ptr = nullptr;
 
-    sockaddr_in addr;
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = hp->h_addrtype;
-    addr.sin_port = htons(port);
-    memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
-
-    SOCKET s = socket(hp->h_addrtype, type, 0);
+    // TODO: Try all the addresses if there's more than one? This just uses
+    // the first. Or, could call WSAConnectByName() (Windows Vista and newer)
+    // which tries all addresses, takes a timeout and more.
+    SOCKET s = socket(addrinfo->ai_family, addrinfo->ai_socktype,
+                      addrinfo->ai_protocol);
     if(s == INVALID_SOCKET) {
-        _fh_close(f);
+        *error = android::base::StringPrintf("cannot create socket: %s",
+                SystemErrorCodeToString(WSAGetLastError()).c_str());
+        D("%s\n", error->c_str());
         return -1;
     }
     f->fh_socket = s;
 
-    // TODO: implement timeouts for Windows.
-
-    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        _fh_close(f);
+    // TODO: Implement timeouts for Windows. Seems like the default in theory
+    // (according to http://serverfault.com/a/671453) and in practice is 21 sec.
+    if(connect(s, addrinfo->ai_addr, addrinfo->ai_addrlen) == SOCKET_ERROR) {
+        // TODO: Use WSAAddressToString or inet_ntop on address.
+        *error = android::base::StringPrintf("cannot connect to %s:%s: %s",
+                host.c_str(), port_str,
+                SystemErrorCodeToString(WSAGetLastError()).c_str());
+        D("could not connect to %s:%s:%s: %s\n",
+          type != SOCK_STREAM ? "udp" : "tcp", host.c_str(), port_str,
+          error->c_str());
         return -1;
     }
 
-    snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
-    D( "socket_network_client_timeout: host '%s' port %d type %s => fd %d\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
-    return _fh_to_int(f);
-}
-
-
-int socket_inaddr_any_server(int port, int type)
-{
-    FH  f = _fh_alloc( &_fh_socket_class );
-    struct sockaddr_in addr;
-    SOCKET  s;
-    int n;
-
-    if (!f)
-        return -1;
-
-    if (!_winsock_init)
-        _init_winsock();
-
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
-    s = socket(AF_INET, type, 0);
-    if(s == INVALID_SOCKET) {
-        _fh_close(f);
-        return -1;
-    }
-
-    f->fh_socket = s;
-    n = 1;
-    setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n));
-
-    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        _fh_close(f);
-        return -1;
-    }
-
-    if (type == SOCK_STREAM) {
-        int ret;
-
-        ret = listen(s, LISTEN_BACKLOG);
-        if (ret < 0) {
-            _fh_close(f);
-            return -1;
-        }
-    }
-    snprintf( f->name, sizeof(f->name), "%d(any-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port );
-    D( "socket_inaddr_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) );
-    return _fh_to_int(f);
+    const int fd = _fh_to_int(f.get());
+    snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", fd,
+              type != SOCK_STREAM ? "udp:" : "", port );
+    D( "host '%s' port %d type %s => fd %d\n", host.c_str(), port,
+       type != SOCK_STREAM ? "udp" : "tcp", fd );
+    f.release();
+    return fd;
 }
 
 #undef accept
 int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen)
 {
     FH   serverfh = _fh_from_int(serverfd, __func__);
-    FH   fh;
 
     if ( !serverfh || serverfh->clazz != &_fh_socket_class ) {
-        D( "adb_socket_accept: invalid fd %d\n", serverfd );
+        D("adb_socket_accept: invalid fd %d\n", serverfd);
+        errno = EBADF;
         return -1;
     }
 
-    fh = _fh_alloc( &_fh_socket_class );
+    unique_fh fh(_fh_alloc( &_fh_socket_class ));
     if (!fh) {
-        D( "adb_socket_accept: not enough memory to allocate accepted socket descriptor\n" );
+        PLOG(ERROR) << "adb_socket_accept: failed to allocate accepted socket "
+                       "descriptor";
         return -1;
     }
 
     fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen );
     if (fh->fh_socket == INVALID_SOCKET) {
         const DWORD err = WSAGetLastError();
-        _fh_close( fh );
-        D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, err );
+        LOG(ERROR) << "adb_socket_accept: accept on fd " << serverfd <<
+                      " failed: " + SystemErrorCodeToString(err);
+        _socket_set_errno( err );
         return -1;
     }
 
-    snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name );
-    D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh) );
-    return  _fh_to_int(fh);
+    const int fd = _fh_to_int(fh.get());
+    snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", fd, serverfh->name );
+    D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, fd );
+    fh.release();
+    return  fd;
 }
 
 
@@ -793,10 +932,42 @@
 
     if ( !fh || fh->clazz != &_fh_socket_class ) {
         D("adb_setsockopt: invalid fd %d\n", fd);
+        errno = EBADF;
+        return -1;
+    }
+    int result = setsockopt( fh->fh_socket, level, optname,
+                             reinterpret_cast<const char*>(optval), optlen );
+    if ( result == SOCKET_ERROR ) {
+        const DWORD err = WSAGetLastError();
+        D( "adb_setsockopt: setsockopt on fd %d level %d optname %d "
+           "failed: %s\n", fd, level, optname,
+           SystemErrorCodeToString(err).c_str() );
+        _socket_set_errno( err );
+        result = -1;
+    }
+    return result;
+}
+
+
+int  adb_shutdown(int  fd)
+{
+    FH   f = _fh_from_int(fd, __func__);
+
+    if (!f || f->clazz != &_fh_socket_class) {
+        D("adb_shutdown: invalid fd %d\n", fd);
+        errno = EBADF;
         return -1;
     }
 
-    return setsockopt( fh->fh_socket, level, optname, reinterpret_cast<const char*>(optval), optlen );
+    D( "adb_shutdown: %s\n", f->name);
+    if (shutdown(f->fh_socket, SD_BOTH) == SOCKET_ERROR) {
+        const DWORD err = WSAGetLastError();
+        D("socket shutdown fd %d failed: %s\n", fd,
+          SystemErrorCodeToString(err).c_str());
+        _socket_set_errno(err);
+        return -1;
+    }
+    return 0;
 }
 
 /**************************************************************************/
@@ -1199,16 +1370,19 @@
 int  adb_socketpair(int sv[2]) {
     SocketPair pair;
 
-    FH fa = _fh_alloc(&_fh_socketpair_class);
-    FH fb = _fh_alloc(&_fh_socketpair_class);
-
-    if (!fa || !fb)
-        goto Fail;
+    unique_fh fa(_fh_alloc(&_fh_socketpair_class));
+    if (!fa) {
+        return -1;
+    }
+    unique_fh fb(_fh_alloc(&_fh_socketpair_class));
+    if (!fb) {
+        return -1;
+    }
 
     pair = reinterpret_cast<SocketPair>(malloc(sizeof(*pair)));
     if (pair == NULL) {
         D("adb_socketpair: not enough memory to allocate pipes\n" );
-        goto Fail;
+        return -1;
     }
 
     bip_buffer_init( &pair->a2b_bip );
@@ -1217,10 +1391,10 @@
     fa->fh_pair = pair;
     fb->fh_pair = pair;
     pair->used  = 2;
-    pair->a_fd  = fa;
+    pair->a_fd  = fa.get();
 
-    sv[0] = _fh_to_int(fa);
-    sv[1] = _fh_to_int(fb);
+    sv[0] = _fh_to_int(fa.get());
+    sv[1] = _fh_to_int(fb.get());
 
     pair->a2b_bip.fdin  = sv[0];
     pair->a2b_bip.fdout = sv[1];
@@ -1230,12 +1404,9 @@
     snprintf( fa->name, sizeof(fa->name), "%d(pair:%d)", sv[0], sv[1] );
     snprintf( fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0] );
     D( "adb_socketpair: returns (%d, %d)\n", sv[0], sv[1] );
+    fa.release();
+    fb.release();
     return 0;
-
-Fail:
-    _fh_close(fb);
-    _fh_close(fa);
-    return -1;
 }
 
 /**************************************************************************/
@@ -2083,6 +2254,7 @@
     hook->check   = _event_socket_check;
     hook->peek    = _event_socket_peek;
 
+    // TODO: check return value?
     _event_socket_start( hook );
 }
 
@@ -2190,7 +2362,7 @@
         memset(input_record, 0, sizeof(*input_record));
         if (!ReadConsoleInputA(console, input_record, 1, &read_count)) {
             D("_get_interesting_input_record_uncached: ReadConsoleInputA() "
-              "failure, error %ld\n", GetLastError());
+              "failed: %s\n", SystemErrorCodeToString(GetLastError()).c_str());
             errno = EIO;
             return false;
         }
@@ -3004,8 +3176,8 @@
         if (!SetConsoleMode(in, _old_console_mode & ~(ENABLE_PROCESSED_INPUT |
             ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT))) {
             // This really should not fail.
-            D("stdin_raw_init: SetConsoleMode() failure, error %ld\n",
-                GetLastError());
+            D("stdin_raw_init: SetConsoleMode() failed: %s\n",
+              SystemErrorCodeToString(GetLastError()).c_str());
         }
 
         // Once this is set, it means that stdin has been configured for
@@ -3026,8 +3198,8 @@
 
             if (!SetConsoleMode(in, _old_console_mode)) {
                 // This really should not fail.
-                D("stdin_raw_restore: SetConsoleMode() failure, error %ld\n",
-                    GetLastError());
+                D("stdin_raw_restore: SetConsoleMode() failed: %s\n",
+                  SystemErrorCodeToString(GetLastError()).c_str());
             }
         }
     }
@@ -3052,3 +3224,624 @@
 #pragma pop_macro("read")
     }
 }
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****      Unicode support                                           *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+// This implements support for using files with Unicode filenames and for
+// outputting Unicode text to a Win32 console window. This is inspired from
+// http://utf8everywhere.org/.
+//
+// Background
+// ----------
+//
+// On POSIX systems, to deal with files with Unicode filenames, just pass UTF-8
+// filenames to APIs such as open(). This works because filenames are largely
+// opaque 'cookies' (perhaps excluding path separators).
+//
+// On Windows, the native file APIs such as CreateFileW() take 2-byte wchar_t
+// UTF-16 strings. There is an API, CreateFileA() that takes 1-byte char
+// strings, but the strings are in the ANSI codepage and not UTF-8. (The
+// CreateFile() API is really just a macro that adds the W/A based on whether
+// the UNICODE preprocessor symbol is defined).
+//
+// Options
+// -------
+//
+// Thus, to write a portable program, there are a few options:
+//
+// 1. Write the program with wchar_t filenames (wchar_t path[256];).
+//    For Windows, just call CreateFileW(). For POSIX, write a wrapper openW()
+//    that takes a wchar_t string, converts it to UTF-8 and then calls the real
+//    open() API.
+//
+// 2. Write the program with a TCHAR typedef that is 2 bytes on Windows and
+//    1 byte on POSIX. Make T-* wrappers for various OS APIs and call those,
+//    potentially touching a lot of code.
+//
+// 3. Write the program with a 1-byte char filenames (char path[256];) that are
+//    UTF-8. For POSIX, just call open(). For Windows, write a wrapper that
+//    takes a UTF-8 string, converts it to UTF-16 and then calls the real OS
+//    or C Runtime API.
+//
+// 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
+// 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
+// implement wrappers below that call UTF-16 OS and C Runtime APIs.
+//
+// Unicode console output
+// ----------------------
+//
+// The way to output Unicode to a Win32 console window is to call
+// WriteConsoleW() with UTF-16 text. (The user must also choose a proper font
+// such as Lucida Console or Consolas, and in the case of East Asian languages
+// (such as Chinese, Japanese, Korean), the user must go to the Control Panel
+// and change the "system locale" to Chinese, etc., which allows a Chinese, etc.
+// font to be used in console windows.)
+//
+// The problem is getting the C Runtime to make fprintf and related APIs call
+// WriteConsoleW() under the covers. The C Runtime API, _setmode() sounds
+// promising, but the various modes have issues:
+//
+// 1. _setmode(_O_TEXT) (the default) does not use WriteConsoleW() so UTF-8 and
+//    UTF-16 do not display properly.
+// 2. _setmode(_O_BINARY) does not use WriteConsoleW() and the text comes out
+//    totally wrong.
+// 3. _setmode(_O_U8TEXT) seems to cause the C Runtime _invalid_parameter
+//    handler to be called (upon a later I/O call), aborting the process.
+// 4. _setmode(_O_U16TEXT) and _setmode(_O_WTEXT) cause non-wide printf/fprintf
+//    to output nothing.
+//
+// So the only solution is to write our own adb_fprintf() that converts UTF-8
+// 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());
+    }
+    narrow_args[argc] = nullptr;   // terminate
+}
+
+NarrowArgs::~NarrowArgs() {
+    if (narrow_args != nullptr) {
+        for (char** argp = narrow_args; *argp != nullptr; ++argp) {
+            free(*argp);
+        }
+        delete[] narrow_args;
+        narrow_args = nullptr;
+    }
+}
+
+int unix_open(const char* path, int options, ...) {
+    if ((options & O_CREAT) == 0) {
+        return _wopen(widen(path).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);
+    }
+}
+
+// Version of stat() that takes a UTF-8 path.
+int adb_stat(const char* f, 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)
+#ifdef _USE_32BIT_TIME_T
+#define wstat _wstat32i64
+#else
+#define wstat _wstat64
+#endif
+#else
+// <sys/stat.h> has a function prototype for wstat() that should be available.
+#endif
+
+    return wstat(widen(f).c_str(), s);
+
+#pragma pop_macro("wstat")
+}
+
+// Version of opendir() that takes a UTF-8 path.
+DIR* adb_opendir(const char* name) {
+    // 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()));
+}
+
+// Version of readdir() that returns UTF-8 paths.
+struct dirent* adb_readdir(DIR* dir) {
+    _WDIR* const wdir = reinterpret_cast<_WDIR*>(dir);
+    struct _wdirent* const went = _wreaddir(wdir);
+    if (went == nullptr) {
+        return nullptr;
+    }
+    // Convert from UTF-16 to UTF-8.
+    const std::string name_utf8(narrow(went->d_name));
+
+    // 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.
+    struct dirent* ent = reinterpret_cast<struct dirent*>(went);
+
+    if (name_utf8.length() + 1 > sizeof(went->d_name)) {
+        // Name too big to fit in existing buffer.
+        errno = ENOMEM;
+        return nullptr;
+    }
+
+    // Note that sizeof(_wdirent::d_name) is bigger than sizeof(dirent::d_name)
+    // because _wdirent contains wchar_t instead of char. So even if name_utf8
+    // can fit in _wdirent::d_name, the resulting dirent::d_name field may be
+    // bigger than the caller expects because they expect a dirent structure
+    // which has a smaller d_name field. Ignore this since the caller should be
+    // resilient.
+
+    // Rewrite the UTF-16 d_name field to UTF-8.
+    strcpy(ent->d_name, name_utf8.c_str());
+
+    return ent;
+}
+
+// Version of closedir() to go with our version of adb_opendir().
+int adb_closedir(DIR* dir) {
+    return _wclosedir(reinterpret_cast<_WDIR*>(dir));
+}
+
+// Version of unlink() that takes a UTF-8 path.
+int adb_unlink(const char* path) {
+    const std::wstring wpath(widen(path));
+
+    int  rc = _wunlink(wpath.c_str());
+
+    if (rc == -1 && errno == EACCES) {
+        /* unlink returns EACCES when the file is read-only, so we first */
+        /* try to make it writable, then unlink again...                 */
+        rc = _wchmod(wpath.c_str(), _S_IREAD | _S_IWRITE);
+        if (rc == 0)
+            rc = _wunlink(wpath.c_str());
+    }
+    return rc;
+}
+
+// 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());
+}
+
+// Version of utime() that takes a UTF-8 path.
+int adb_utime(const char* path, struct utimbuf* u) {
+    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));
+}
+
+// Version of chmod() that takes a UTF-8 path.
+int adb_chmod(const char* path, int mode) {
+    return _wchmod(widen(path).c_str(), mode);
+}
+
+// Internal function to get a Win32 console HANDLE from a C Runtime FILE*.
+static HANDLE _get_console_handle(FILE* const stream) {
+    // Get a C Runtime file descriptor number from the FILE* structure.
+    const int fd = fileno(stream);
+    if (fd < 0) {
+        return NULL;
+    }
+
+    // If it is not a "character device", it is probably a file and not a
+    // console. Do this check early because it is probably cheap. Still do more
+    // checks after this since there are devices that pass this test, but are
+    // not a console, such as NUL, the Windows /dev/null equivalent (I think).
+    if (!isatty(fd)) {
+        return NULL;
+    }
+
+    // Given a C Runtime file descriptor number, get the underlying OS
+    // file handle.
+    const intptr_t osfh = _get_osfhandle(fd);
+    if (osfh == -1) {
+        return NULL;
+    }
+
+    const HANDLE h = reinterpret_cast<const HANDLE>(osfh);
+
+    DWORD old_mode = 0;
+    if (!GetConsoleMode(h, &old_mode)) {
+        return NULL;
+    }
+
+    // If GetConsoleMode() was successful, assume this is a console.
+    return h;
+}
+
+// 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.
+    // This could throw std::bad_alloc.
+    const std::wstring output(widen(buf, size));
+
+    // Note that this does not do \n => \r\n translation because that
+    // doesn't seem necessary for the Windows console. For the Windows
+    // console \r moves to the beginning of the line and \n moves to a new
+    // line.
+
+    // Flush any stream buffering so that our output is afterwards which
+    // makes sense because our call is afterwards.
+    (void)fflush(stream);
+
+    // Write UTF-16 to the console.
+    DWORD written = 0;
+    if (!WriteConsoleW(console, output.c_str(), output.length(), &written,
+                       NULL)) {
+        errno = EIO;
+        return -1;
+    }
+
+    // This is the number of UTF-16 chars written, which might be different
+    // than the number of UTF-8 chars passed in. It doesn't seem practical to
+    // get this count correct.
+    return written;
+}
+
+// Function prototype because attributes cannot be placed on func definitions.
+static int _console_vfprintf(const HANDLE console, FILE* stream,
+                             const char *format, va_list ap)
+    __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 3, 0)));
+
+// Internal function to format a UTF-8 string and write it to a Win32 console.
+// Returns -1 on error.
+static int _console_vfprintf(const HANDLE console, FILE* stream,
+                             const char *format, va_list ap) {
+    std::string output_utf8;
+
+    // Format the string.
+    // This could throw std::bad_alloc.
+    android::base::StringAppendV(&output_utf8, format, ap);
+
+    return _console_write_utf8(output_utf8.c_str(), output_utf8.length(),
+                               stream, console);
+}
+
+// Version of vfprintf() that takes UTF-8 and can write Unicode to a
+// Windows console.
+int adb_vfprintf(FILE *stream, const char *format, va_list ap) {
+    const HANDLE console = _get_console_handle(stream);
+
+    // If there is an associated Win32 console, write to it specially,
+    // otherwise defer to the regular C Runtime, passing it UTF-8.
+    if (console != NULL) {
+        return _console_vfprintf(console, stream, format, ap);
+    } else {
+        // If vfprintf is a macro, undefine it, so we can call the real
+        // C Runtime API.
+#pragma push_macro("vfprintf")
+#undef vfprintf
+        return vfprintf(stream, format, ap);
+#pragma pop_macro("vfprintf")
+    }
+}
+
+// Version of fprintf() that takes UTF-8 and can write Unicode to a
+// Windows console.
+int adb_fprintf(FILE *stream, const char *format, ...) {
+    va_list ap;
+    va_start(ap, format);
+    const int result = adb_vfprintf(stream, format, ap);
+    va_end(ap);
+
+    return result;
+}
+
+// Version of printf() that takes UTF-8 and can write Unicode to a
+// Windows console.
+int adb_printf(const char *format, ...) {
+    va_list ap;
+    va_start(ap, format);
+    const int result = adb_vfprintf(stdout, format, ap);
+    va_end(ap);
+
+    return result;
+}
+
+// Version of fputs() that takes UTF-8 and can write Unicode to a
+// Windows console.
+int adb_fputs(const char* buf, FILE* stream) {
+    // adb_fprintf returns -1 on error, which is conveniently the same as EOF
+    // which fputs (and hence adb_fputs) should return on error.
+    return adb_fprintf(stream, "%s", buf);
+}
+
+// Version of fputc() that takes UTF-8 and can write Unicode to a
+// Windows console.
+int adb_fputc(int ch, FILE* stream) {
+    const int result = adb_fprintf(stream, "%c", ch);
+    if (result <= 0) {
+        // If there was an error, or if nothing was printed (which should be an
+        // error), return an error, which fprintf signifies with EOF.
+        return EOF;
+    }
+    // For success, fputc returns the char, cast to unsigned char, then to int.
+    return static_cast<unsigned char>(ch);
+}
+
+// Internal function to write UTF-8 to a Win32 console. Returns the number of
+// items (of length size) written. On error, returns a short item count or 0.
+static size_t _console_fwrite(const void* ptr, size_t size, size_t nmemb,
+                              FILE* stream, HANDLE console) {
+    // TODO: Note that a Unicode character could be several UTF-8 bytes. But
+    // if we're passed only some of the bytes of a character (for example, from
+    // the network socket for adb shell), we won't be able to convert the char
+    // to a complete UTF-16 char (or surrogate pair), so the output won't look
+    // right.
+    //
+    // To fix this, see libutils/Unicode.cpp for hints on decoding UTF-8.
+    //
+    // For now we ignore this problem because the alternative is that we'd have
+    // to parse UTF-8 and buffer things up (doable). At least this is better
+    // than what we had before -- always incorrect multi-byte UTF-8 output.
+    int result = _console_write_utf8(reinterpret_cast<const char*>(ptr),
+                                     size * nmemb, stream, console);
+    if (result == -1) {
+        return 0;
+    }
+    return result / size;
+}
+
+// Version of fwrite() that takes UTF-8 and can write Unicode to a
+// Windows console.
+size_t adb_fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream) {
+    const HANDLE console = _get_console_handle(stream);
+
+    // If there is an associated Win32 console, write to it specially,
+    // otherwise defer to the regular C Runtime, passing it UTF-8.
+    if (console != NULL) {
+        return _console_fwrite(ptr, size, nmemb, stream, console);
+    } else {
+        // If fwrite is a macro, undefine it, so we can call the real
+        // C Runtime API.
+#pragma push_macro("fwrite")
+#undef fwrite
+        return fwrite(ptr, size, nmemb, stream);
+#pragma pop_macro("fwrite")
+    }
+}
+
+// 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());
+}
+
+// Shadow UTF-8 environment variable name/value pairs that are created from
+// _wenviron the first time that adb_getenv() is called. Note that this is not
+// 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;
+
+// Make sure that shadow UTF-8 environment variables are setup.
+static void _ensure_env_setup() {
+    // If some name/value pairs exist, then we've already done the setup below.
+    if (g_environ_utf8.size() != 0) {
+        return;
+    }
+
+    // Read name/value pairs from UTF-16 _wenviron and write new name/value
+    // pairs to UTF-8 g_environ_utf8. Note that it probably does not make sense
+    // to use the D() macro here because that tracing only works if the
+    // ADB_TRACE environment variable is setup, but that env var can't be read
+    // until this code completes.
+    for (wchar_t** env = _wenviron; *env != nullptr; ++env) {
+        wchar_t* const equal = wcschr(*env, L'=');
+        if (equal == nullptr) {
+            // Malformed environment variable with no equal sign. Shouldn't
+            // really happen, but we should be resilient to this.
+            continue;
+        }
+
+        const std::string name_utf8(narrow(std::wstring(*env, equal - *env)));
+        char* const value_utf8 = strdup(narrow(equal + 1).c_str());
+
+        // Overwrite any duplicate name, but there shouldn't be a dup in the
+        // first place.
+        g_environ_utf8[name_utf8] = value_utf8;
+    }
+}
+
+// Version of getenv() that takes a UTF-8 environment variable name and
+// retrieves a UTF-8 value.
+char* adb_getenv(const char* name) {
+    _ensure_env_setup();
+
+    const auto it = g_environ_utf8.find(std::string(name));
+    if (it == g_environ_utf8.end()) {
+        return nullptr;
+    }
+
+    return it->second;
+}
+
+// Version of getcwd() that returns the current working directory in UTF-8.
+char* adb_getcwd(char* buf, int size) {
+    wchar_t* wbuf = _wgetcwd(nullptr, 0);
+    if (wbuf == nullptr) {
+        return nullptr;
+    }
+
+    const std::string buf_utf8(narrow(wbuf));
+    free(wbuf);
+    wbuf = nullptr;
+
+    // If size was specified, make sure all the chars will fit.
+    if (size != 0) {
+        if (size < static_cast<int>(buf_utf8.length() + 1)) {
+            errno = ERANGE;
+            return nullptr;
+        }
+    }
+
+    // If buf was not specified, allocate storage.
+    if (buf == nullptr) {
+        if (size == 0) {
+            size = buf_utf8.length() + 1;
+        }
+        buf = reinterpret_cast<char*>(malloc(size));
+        if (buf == nullptr) {
+            return nullptr;
+        }
+    }
+
+    // Destination buffer was allocated with enough space, or we've already
+    // checked an existing buffer size for enough space.
+    strcpy(buf, buf_utf8.c_str());
+
+    return buf;
+}
diff --git a/adb/test_device.py b/adb/test_device.py
index 8003eaa..c893ad4 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -55,10 +55,15 @@
 class GetDeviceTest(unittest.TestCase):
     def setUp(self):
         self.android_serial = os.getenv('ANDROID_SERIAL')
-        del os.environ['ANDROID_SERIAL']
+        if 'ANDROID_SERIAL' in os.environ:
+            del os.environ['ANDROID_SERIAL']
 
     def tearDown(self):
-        os.environ['ANDROID_SERIAL'] = self.android_serial
+        if self.android_serial is not None:
+            os.environ['ANDROID_SERIAL'] = self.android_serial
+        else:
+            if 'ANDROID_SERIAL' in os.environ:
+                del os.environ['ANDROID_SERIAL']
 
     @mock.patch('adb.device.get_devices')
     def test_explicit(self, mock_get_devices):
@@ -150,6 +155,31 @@
         output = self.device.shell(['uname'])
         self.assertEqual(output, 'Linux' + self.device.linesep)
 
+    def test_pty_logic(self):
+        """Verify PTY logic for shells.
+
+        Interactive shells should use a PTY, non-interactive should not.
+
+        Bug: http://b/21215503
+        """
+        proc = subprocess.Popen(
+                self.device.adb_cmd + ['shell'], stdin=subprocess.PIPE,
+                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        # [ -t 0 ] is used (rather than `tty`) to provide portability. This
+        # gives an exit code of 0 iff stdin is connected to a terminal.
+        #
+        # Closing host-side stdin doesn't currently trigger the interactive
+        # shell to exit so we need to explicitly add an exit command to
+        # close the session from the device side, and append \n to complete
+        # the interactive command.
+        result = proc.communicate('[ -t 0 ]; echo x$?; exit 0\n')[0]
+        partition = result.rpartition('x')
+        self.assertEqual(partition[1], 'x')
+        self.assertEqual(int(partition[2]), 0)
+
+        exit_code = self.device.shell_nocheck(['[ -t 0 ]'])[0]
+        self.assertEqual(exit_code, 1)
+
 
 class ArgumentEscapingTest(DeviceTest):
     def test_shell_escaping(self):
@@ -311,7 +341,7 @@
         size = random.randrange(min_size, max_size, 1024)
 
         base_name = 'device_tmpfile' + str(file_num)
-        full_path = os.path.join(in_dir, base_name)
+        full_path = posixpath.join(in_dir, base_name)
 
         device.shell(['dd', 'if=/dev/urandom', 'of={}'.format(full_path),
                       'bs={}'.format(size), 'count=1'])
@@ -328,107 +358,96 @@
 
     def _test_push(self, local_file, checksum):
         self.device.shell(['rm', '-rf', self.DEVICE_TEMP_FILE])
-        try:
-            self.device.push(
-                local=local_file, remote=self.DEVICE_TEMP_FILE)
-            dev_md5, _ = self.device.shell(
-                [get_md5_prog(self.device), self.DEVICE_TEMP_FILE]).split()
-            self.assertEqual(checksum, dev_md5)
-        finally:
-            self.device.shell(['rm', '-f', self.DEVICE_TEMP_FILE])
+        self.device.push(local=local_file, remote=self.DEVICE_TEMP_FILE)
+        dev_md5, _ = self.device.shell([get_md5_prog(self.device),
+                                       self.DEVICE_TEMP_FILE]).split()
+        self.assertEqual(checksum, dev_md5)
+        self.device.shell(['rm', '-f', self.DEVICE_TEMP_FILE])
 
     def test_push(self):
         """Push a randomly generated file to specified device."""
         kbytes = 512
         tmp = tempfile.NamedTemporaryFile(mode='wb', delete=False)
-        try:
-            rand_str = os.urandom(1024 * kbytes)
-            tmp.write(rand_str)
-            tmp.close()
-            self._test_push(tmp.name, compute_md5(rand_str))
-        finally:
-            os.remove(tmp.name)
+        rand_str = os.urandom(1024 * kbytes)
+        tmp.write(rand_str)
+        tmp.close()
+        self._test_push(tmp.name, compute_md5(rand_str))
+        os.remove(tmp.name)
 
     # TODO: write push directory test.
 
     def _test_pull(self, remote_file, checksum):
         tmp_write = tempfile.NamedTemporaryFile(mode='wb', delete=False)
-        try:
-            tmp_write.close()
-            self.device.pull(remote=remote_file, local=tmp_write.name)
-            with open(tmp_write.name, 'rb') as tmp_read:
-                host_contents = tmp_read.read()
-                host_md5 = compute_md5(host_contents)
-            self.assertEqual(checksum, host_md5)
-        finally:
-            os.remove(tmp_write.name)
+        tmp_write.close()
+        self.device.pull(remote=remote_file, local=tmp_write.name)
+        with open(tmp_write.name, 'rb') as tmp_read:
+            host_contents = tmp_read.read()
+            host_md5 = compute_md5(host_contents)
+        self.assertEqual(checksum, host_md5)
+        os.remove(tmp_write.name)
 
     def test_pull(self):
         """Pull a randomly generated file from specified device."""
         kbytes = 512
         self.device.shell(['rm', '-rf', self.DEVICE_TEMP_FILE])
-        try:
-            cmd = ['dd', 'if=/dev/urandom',
-                   'of={}'.format(self.DEVICE_TEMP_FILE), 'bs=1024',
-                   'count={}'.format(kbytes)]
-            self.device.shell(cmd)
-            dev_md5, _ = self.device.shell(
-                [get_md5_prog(self.device), self.DEVICE_TEMP_FILE]).split()
-            self._test_pull(self.DEVICE_TEMP_FILE, dev_md5)
-        finally:
-            self.device.shell_nocheck(['rm', self.DEVICE_TEMP_FILE])
+        cmd = ['dd', 'if=/dev/urandom',
+               'of={}'.format(self.DEVICE_TEMP_FILE), 'bs=1024',
+               'count={}'.format(kbytes)]
+        self.device.shell(cmd)
+        dev_md5, _ = self.device.shell(
+            [get_md5_prog(self.device), self.DEVICE_TEMP_FILE]).split()
+        self._test_pull(self.DEVICE_TEMP_FILE, dev_md5)
+        self.device.shell_nocheck(['rm', self.DEVICE_TEMP_FILE])
 
     def test_pull_dir(self):
         """Pull a randomly generated directory of files from the device."""
         host_dir = tempfile.mkdtemp()
-        try:
-            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
-            self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR])
+        self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR])
 
-            # Populate device directory with random files.
-            temp_files = make_random_device_files(
-                self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32)
+        # Populate device directory with random files.
+        temp_files = make_random_device_files(
+            self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32)
 
-            self.device.pull(remote=self.DEVICE_TEMP_DIR, local=host_dir)
+        self.device.pull(remote=self.DEVICE_TEMP_DIR, local=host_dir)
 
-            for temp_file in temp_files:
-                host_path = os.path.join(host_dir, temp_file.base_name)
-                with open(host_path, 'rb') as host_file:
-                    host_md5 = compute_md5(host_file.read())
-                    self.assertEqual(host_md5, temp_file.checksum)
-        finally:
-            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
-            if host_dir is not None:
-                shutil.rmtree(host_dir)
+        for temp_file in temp_files:
+            host_path = os.path.join(host_dir, temp_file.base_name)
+            with open(host_path, 'rb') as host_file:
+                host_md5 = compute_md5(host_file.read())
+                self.assertEqual(host_md5, temp_file.checksum)
+
+        self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        if host_dir is not None:
+            shutil.rmtree(host_dir)
 
     def test_sync(self):
         """Sync a randomly generated directory of files to specified device."""
         base_dir = tempfile.mkdtemp()
-        try:
-            # Create mirror device directory hierarchy within base_dir.
-            full_dir_path = base_dir + self.DEVICE_TEMP_DIR
-            os.makedirs(full_dir_path)
 
-            # Create 32 random files within the host mirror.
-            temp_files = make_random_host_files(in_dir=full_dir_path,
-                                                num_files=32)
+        # Create mirror device directory hierarchy within base_dir.
+        full_dir_path = base_dir + self.DEVICE_TEMP_DIR
+        os.makedirs(full_dir_path)
 
-            # Clean up any trash on the device.
-            device = adb.get_device(product=base_dir)
-            device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        # Create 32 random files within the host mirror.
+        temp_files = make_random_host_files(in_dir=full_dir_path, num_files=32)
 
-            device.sync('data')
+        # Clean up any trash on the device.
+        device = adb.get_device(product=base_dir)
+        device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
 
-            # Confirm that every file on the device mirrors that on the host.
-            for temp_file in temp_files:
-                device_full_path = posixpath.join(
-                    self.DEVICE_TEMP_DIR, temp_file.base_name)
-                dev_md5, _ = device.shell(
-                    [get_md5_prog(self.device), device_full_path]).split()
-                self.assertEqual(temp_file.checksum, dev_md5)
-        finally:
-            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
-            shutil.rmtree(base_dir + self.DEVICE_TEMP_DIR)
+        device.sync('data')
+
+        # Confirm that every file on the device mirrors that on the host.
+        for temp_file in temp_files:
+            device_full_path = posixpath.join(self.DEVICE_TEMP_DIR,
+                                              temp_file.base_name)
+            dev_md5, _ = device.shell(
+                [get_md5_prog(self.device), device_full_path]).split()
+            self.assertEqual(temp_file.checksum, dev_md5)
+
+        self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        shutil.rmtree(base_dir + self.DEVICE_TEMP_DIR)
 
     def test_unicode_paths(self):
         """Ensure that we can support non-ASCII paths, even on Windows."""
diff --git a/adb/test_track_devices.cpp b/adb/test_track_devices.cpp
index f78daeb..6f658f6 100644
--- a/adb/test_track_devices.cpp
+++ b/adb/test_track_devices.cpp
@@ -1,12 +1,13 @@
 // TODO: replace this with a shell/python script.
 
 /* a simple test program, connects to ADB server, and opens a track-devices session */
-#include <netdb.h>
-#include <sys/socket.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <errno.h>
 #include <memory.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <unistd.h>
 
 #include <base/file.h>
 
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 87aff88..2ea4d44 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -29,6 +29,7 @@
 #include <list>
 
 #include <base/stringprintf.h>
+#include <base/strings.h>
 
 #include "adb.h"
 #include "adb_utils.h"
@@ -126,19 +127,18 @@
 static int
 read_packet(int  fd, const char* name, apacket** ppacket)
 {
-    char *p = (char*)ppacket;  /* really read a packet address */
-    int   r;
-    int   len = sizeof(*ppacket);
-    char  buff[8];
+    char buff[8];
     if (!name) {
         snprintf(buff, sizeof buff, "fd=%d", fd);
         name = buff;
     }
+    char* p = reinterpret_cast<char*>(ppacket);  /* really read a packet address */
+    int len = sizeof(apacket*);
     while(len > 0) {
-        r = adb_read(fd, p, len);
+        int r = adb_read(fd, p, len);
         if(r > 0) {
             len -= r;
-            p   += r;
+            p += r;
         } else {
             D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
             if((r < 0) && (errno == EINTR)) continue;
@@ -155,20 +155,18 @@
 static int
 write_packet(int  fd, const char* name, apacket** ppacket)
 {
-    char *p = (char*) ppacket;  /* we really write the packet address */
-    int r, len = sizeof(ppacket);
     char buff[8];
     if (!name) {
         snprintf(buff, sizeof buff, "fd=%d", fd);
         name = buff;
     }
-
     if (ADB_TRACING) {
         dump_packet(name, "to remote", *ppacket);
     }
-    len = sizeof(ppacket);
+    char* p = reinterpret_cast<char*>(ppacket);  /* we really write the packet address */
+    int len = sizeof(apacket*);
     while(len > 0) {
-        r = adb_write(fd, p, len);
+        int r = adb_write(fd, p, len);
         if(r > 0) {
             len -= r;
             p += r;
@@ -538,7 +536,7 @@
 
     t = m.transport;
 
-    if(m.action == 0){
+    if (m.action == 0) {
         D("transport: %s removing and free'ing %d\n", t->serial, t->transport_socket);
 
             /* IMPORTANT: the remove closes one half of the
@@ -848,6 +846,29 @@
     return max_payload;
 }
 
+// The list of features supported by the current system. Will be sent to the
+// other side of the connection in the banner.
+static const FeatureSet gSupportedFeatures = {
+    // None yet.
+};
+
+const FeatureSet& supported_features() {
+    return gSupportedFeatures;
+}
+
+bool atransport::has_feature(const std::string& feature) const {
+    return features_.count(feature) > 0;
+}
+
+void atransport::add_feature(const std::string& feature) {
+    features_.insert(feature);
+}
+
+bool atransport::CanUseFeature(const std::string& feature) const {
+    return has_feature(feature) &&
+           supported_features().count(feature) > 0;
+}
+
 #if ADB_HOST
 
 static void append_transport_info(std::string* result, const char* key,
@@ -882,6 +903,9 @@
         append_transport_info(result, "product:", t->product, false);
         append_transport_info(result, "model:", t->model, true);
         append_transport_info(result, "device:", t->device, false);
+        append_transport_info(result, "features:",
+                              android::base::Join(t->features(), ',').c_str(),
+                              false);
     }
     *result += '\n';
 }
diff --git a/adb/transport.h b/adb/transport.h
index edcc99d..e809407 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -20,9 +20,92 @@
 #include <sys/types.h>
 
 #include <string>
+#include <unordered_set>
 
 #include "adb.h"
 
+typedef std::unordered_set<std::string> FeatureSet;
+
+const FeatureSet& supported_features();
+
+class atransport {
+public:
+    // TODO(danalbert): We expose waaaaaaay too much stuff because this was
+    // historically just a struct, but making the whole thing a more idiomatic
+    // class in one go is a very large change. Given how bad our testing is,
+    // it's better to do this piece by piece.
+
+    atransport() {
+        auth_fde = {};
+        transport_fde = {};
+        protocol_version = A_VERSION;
+        max_payload = MAX_PAYLOAD;
+    }
+
+    virtual ~atransport() {}
+
+    int (*read_from_remote)(apacket* p, atransport* t) = nullptr;
+    int (*write_to_remote)(apacket* p, atransport* t) = nullptr;
+    void (*close)(atransport* t) = nullptr;
+    void (*kick)(atransport* t) = nullptr;
+
+    int fd = -1;
+    int transport_socket = -1;
+    fdevent transport_fde;
+    int ref_count = 0;
+    uint32_t sync_token = 0;
+    ConnectionState connection_state = kCsOffline;
+    bool online = false;
+    TransportType type = kTransportAny;
+
+    // USB handle or socket fd as needed.
+    usb_handle* usb = nullptr;
+    int sfd = -1;
+
+    // Used to identify transports for clients.
+    char* serial = nullptr;
+    char* product = nullptr;
+    char* model = nullptr;
+    char* device = nullptr;
+    char* devpath = nullptr;
+    int adb_port = -1;  // Use for emulators (local transport)
+    bool kicked = false;
+
+    // A list of adisconnect callbacks called when the transport is kicked.
+    adisconnect disconnects = {};
+
+    void* key = nullptr;
+    unsigned char token[TOKEN_SIZE] = {};
+    fdevent auth_fde;
+    size_t failed_auth_attempts = 0;
+
+    const char* connection_state_name() const;
+
+    void update_version(int version, size_t payload);
+    int get_protocol_version() const;
+    size_t get_max_payload() const;
+
+    inline const FeatureSet features() const {
+        return features_;
+    }
+
+    bool has_feature(const std::string& feature) const;
+    void add_feature(const std::string& feature);
+
+    // Returns true if both we and the other end of the transport support the
+    // feature.
+    bool CanUseFeature(const std::string& feature) const;
+
+private:
+    // A set of features transmitted in the banner with the initial connection.
+    // This is stored in the banner as 'features=feature0,feature1,etc'.
+    FeatureSet features_;
+    int protocol_version;
+    size_t max_payload;
+
+    DISALLOW_COPY_AND_ASSIGN(atransport);
+};
+
 /*
  * Obtain a transport from the available transports.
  * If state is != kCsAny, only transports in that state are considered.
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 0dc9581..6a17497 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -94,13 +94,17 @@
     int fd = -1;
 
 #if ADB_HOST
+    if (find_emulator_transport_by_adb_port(adb_port) != nullptr) {
+        return -1;
+    }
+
     const char *host = getenv("ADBHOST");
     if (host) {
         fd = network_connect(host, adb_port, SOCK_STREAM, 0, error);
     }
 #endif
     if (fd < 0) {
-        fd = socket_loopback_client(adb_port, SOCK_STREAM);
+        fd = network_loopback_client(adb_port, SOCK_STREAM, error);
     }
 
     if (fd >= 0) {
@@ -108,31 +112,33 @@
         close_on_exec(fd);
         disable_tcp_nagle(fd);
         std::string serial = android::base::StringPrintf("emulator-%d", console_port);
-        register_socket_transport(fd, serial.c_str(), adb_port, 1);
-        return 0;
+        if (register_socket_transport(fd, serial.c_str(), adb_port, 1) == 0) {
+            return 0;
+        }
+        adb_close(fd);
     }
     return -1;
 }
 
-
+#if ADB_HOST
 static void *client_socket_thread(void *x)
 {
-#if ADB_HOST
-    int  port  = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
-    int  count = ADB_LOCAL_TRANSPORT_MAX;
-
     D("transport: client_socket_thread() starting\n");
+    while (true) {
+        int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
+        int count = ADB_LOCAL_TRANSPORT_MAX;
 
-    /* try to connect to any number of running emulator instances     */
-    /* this is only done when ADB starts up. later, each new emulator */
-    /* will send a message to ADB to indicate that is is starting up  */
-    for ( ; count > 0; count--, port += 2 ) {
-        local_connect(port);
+        // Try to connect to any number of running emulator instances.
+        for ( ; count > 0; count--, port += 2 ) {
+            local_connect(port);
+        }
+        sleep(1);
     }
-#endif
     return 0;
 }
 
+#else // ADB_HOST
+
 static void *server_socket_thread(void * arg)
 {
     int serverfd, fd;
@@ -144,9 +150,10 @@
     serverfd = -1;
     for(;;) {
         if(serverfd == -1) {
-            serverfd = socket_inaddr_any_server(port, SOCK_STREAM);
+            std::string error;
+            serverfd = network_inaddr_any_server(port, SOCK_STREAM, &error);
             if(serverfd < 0) {
-                D("server: cannot bind socket yet: %s\n", strerror(errno));
+                D("server: cannot bind socket yet: %s\n", error.c_str());
                 adb_sleep_ms(1000);
                 continue;
             }
@@ -168,7 +175,6 @@
 }
 
 /* This is relevant only for ADB daemon running inside the emulator. */
-#if !ADB_HOST
 /*
  * Redefine open and write for qemu_pipe.h that contains inlined references
  * to those routines. We will redifine them back after qemu_pipe.h inclusion.
@@ -280,31 +286,29 @@
 void local_init(int port)
 {
     void* (*func)(void *);
+    const char* debug_name = "";
 
-    if(HOST) {
-        func = client_socket_thread;
-    } else {
 #if ADB_HOST
-        func = server_socket_thread;
+    func = client_socket_thread;
+    debug_name = "client";
 #else
-        /* For the adbd daemon in the system image we need to distinguish
-         * between the device, and the emulator. */
-        char is_qemu[PROPERTY_VALUE_MAX];
-        property_get("ro.kernel.qemu", is_qemu, "");
-        if (!strcmp(is_qemu, "1")) {
-            /* Running inside the emulator: use QEMUD pipe as the transport. */
-            func = qemu_socket_thread;
-        } else {
-            /* Running inside the device: use TCP socket as the transport. */
-            func = server_socket_thread;
-        }
-#endif // !ADB_HOST
+    /* For the adbd daemon in the system image we need to distinguish
+     * between the device, and the emulator. */
+    char is_qemu[PROPERTY_VALUE_MAX];
+    property_get("ro.kernel.qemu", is_qemu, "");
+    if (!strcmp(is_qemu, "1")) {
+        /* Running inside the emulator: use QEMUD pipe as the transport. */
+        func = qemu_socket_thread;
+    } else {
+        /* Running inside the device: use TCP socket as the transport. */
+        func = server_socket_thread;
     }
+    debug_name = "server";
+#endif // !ADB_HOST
 
-    D("transport: local %s init\n", HOST ? "client" : "server");
-
+    D("transport: local %s init\n", debug_name);
     if (!adb_thread_create(func, (void *) (uintptr_t) port)) {
-        fatal_errno("cannot create local socket %s thread", HOST ? "client" : "server");
+        fatal_errno("cannot create local socket %s thread", debug_name);
     }
 }
 
@@ -316,17 +320,15 @@
     adb_close(fd);
 
 #if ADB_HOST
-    if(HOST) {
-        int  nn;
-        adb_mutex_lock( &local_transports_lock );
-        for (nn = 0; nn < ADB_LOCAL_TRANSPORT_MAX; nn++) {
-            if (local_transports[nn] == t) {
-                local_transports[nn] = NULL;
-                break;
-            }
+    int  nn;
+    adb_mutex_lock( &local_transports_lock );
+    for (nn = 0; nn < ADB_LOCAL_TRANSPORT_MAX; nn++) {
+        if (local_transports[nn] == t) {
+            local_transports[nn] = NULL;
+            break;
         }
-        adb_mutex_unlock( &local_transports_lock );
     }
+    adb_mutex_unlock( &local_transports_lock );
 #endif
 }
 
@@ -397,7 +399,7 @@
     t->adb_port = 0;
 
 #if ADB_HOST
-    if (HOST && local) {
+    if (local) {
         adb_mutex_lock( &local_transports_lock );
         {
             t->adb_port = adb_port;
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 4b74adf..743d97d 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -59,10 +59,33 @@
         EXPECT_EQ(0, memcmp(&auth_fde, &rhs.auth_fde, sizeof(fdevent)));
         EXPECT_EQ(failed_auth_attempts, rhs.failed_auth_attempts);
 
+        EXPECT_EQ(features(), rhs.features());
+
         return true;
     }
 };
 
+class TransportSetup {
+public:
+  TransportSetup() {
+#ifdef _WIN32
+    // Use extern instead of including sysdeps.h which brings in various macros
+    // that conflict with APIs used in this file.
+    extern void adb_sysdeps_init(void);
+    adb_sysdeps_init();
+#else
+    // adb_sysdeps_init() is an inline function that we cannot link against.
+#endif
+  }
+};
+
+// Static initializer will call adb_sysdeps_init() before main() to initialize
+// the transport mutex before it is used in the tests. Alternatives would be to
+// use __attribute__((constructor)) here or to use that or a static initializer
+// for adb_sysdeps_init() itself in sysdeps_win32.cpp (caveats of unclear
+// init order), or to use a test fixture whose SetUp() could do the init once.
+static TransportSetup g_TransportSetup;
+
 TEST(transport, kick_transport) {
   TestTransport t;
 
@@ -99,6 +122,73 @@
 // want to make sure I understand how this is working at all before I try fixing
 // that.
 TEST(transport, DISABLED_run_transport_disconnects_zeroed_atransport) {
-  atransport t;
-  run_transport_disconnects(&t);
+    atransport t;
+    run_transport_disconnects(&t);
+}
+
+TEST(transport, add_feature) {
+    atransport t;
+    ASSERT_EQ(0U, t.features().size());
+
+    t.add_feature("foo");
+    ASSERT_EQ(1U, t.features().size());
+    ASSERT_TRUE(t.has_feature("foo"));
+
+    t.add_feature("bar");
+    ASSERT_EQ(2U, t.features().size());
+    ASSERT_TRUE(t.has_feature("foo"));
+    ASSERT_TRUE(t.has_feature("bar"));
+
+    t.add_feature("foo");
+    ASSERT_EQ(2U, t.features().size());
+    ASSERT_TRUE(t.has_feature("foo"));
+    ASSERT_TRUE(t.has_feature("bar"));
+}
+
+TEST(transport, parse_banner_no_features) {
+    atransport t;
+
+    parse_banner("host::", &t);
+
+    ASSERT_EQ(0U, t.features().size());
+    ASSERT_EQ(kCsHost, t.connection_state);
+
+    ASSERT_EQ(nullptr, t.product);
+    ASSERT_EQ(nullptr, t.model);
+    ASSERT_EQ(nullptr, t.device);
+}
+
+TEST(transport, parse_banner_product_features) {
+    atransport t;
+
+    const char banner[] =
+        "host::ro.product.name=foo;ro.product.model=bar;ro.product.device=baz;";
+    parse_banner(banner, &t);
+
+    ASSERT_EQ(kCsHost, t.connection_state);
+
+    ASSERT_EQ(0U, t.features().size());
+
+    ASSERT_EQ(std::string("foo"), t.product);
+    ASSERT_EQ(std::string("bar"), t.model);
+    ASSERT_EQ(std::string("baz"), t.device);
+}
+
+TEST(transport, parse_banner_features) {
+    atransport t;
+
+    const char banner[] =
+        "host::ro.product.name=foo;ro.product.model=bar;ro.product.device=baz;"
+        "features=woodly,doodly";
+    parse_banner(banner, &t);
+
+    ASSERT_EQ(kCsHost, t.connection_state);
+
+    ASSERT_EQ(2U, t.features().size());
+    ASSERT_TRUE(t.has_feature("woodly"));
+    ASSERT_TRUE(t.has_feature("doodly"));
+
+    ASSERT_EQ(std::string("foo"), t.product);
+    ASSERT_EQ(std::string("bar"), t.model);
+    ASSERT_EQ(std::string("baz"), t.device);
 }
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 2c975a9..96ccdad 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -91,12 +91,6 @@
     t->connection_state = state;
     t->type = kTransportUsb;
     t->usb = h;
-
-#if ADB_HOST
-    HOST = 1;
-#else
-    HOST = 0;
-#endif
 }
 
 #if ADB_HOST
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index af65130..afa08c1 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -34,16 +34,20 @@
 
 #define  DBG   D
 
+// There's no strerror equivalent for the errors returned by IOKit.
+// https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/AccessingHardware/AH_Handling_Errors/AH_Handling_Errors.html
+// Search the web for "IOReturn.h" to find a complete up to date list.
+
 static IONotificationPortRef    notificationPort = 0;
 static io_iterator_t            notificationIterator;
 
 struct usb_handle
 {
-    UInt8                     bulkIn;
-    UInt8                     bulkOut;
-    IOUSBInterfaceInterface   **interface;
-    io_object_t               usbNotification;
-    unsigned int              zero_mask;
+    UInt8 bulkIn;
+    UInt8 bulkOut;
+    IOUSBInterfaceInterface190** interface;
+    io_object_t usbNotification;
+    unsigned int zero_mask;
 };
 
 static CFRunLoopRef currentRunLoop = 0;
@@ -55,7 +59,7 @@
 static void AndroidInterfaceNotify(void *refCon, io_iterator_t iterator,
                                    natural_t messageType,
                                    void *messageArgument);
-static usb_handle* CheckInterface(IOUSBInterfaceInterface **iface,
+static usb_handle* CheckInterface(IOUSBInterfaceInterface190 **iface,
                                   UInt16 vendor, UInt16 product);
 
 static int
@@ -252,7 +256,7 @@
         DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product,
             serial);
 
-        usb_handle* handle = CheckInterface((IOUSBInterfaceInterface**)iface,
+        usb_handle* handle = CheckInterface((IOUSBInterfaceInterface190**)iface,
                                             vendor, product);
         if (handle == NULL) {
             DBG("ERR: Could not find device interface: %08x\n", kr);
@@ -295,16 +299,27 @@
     }
 }
 
+// Used to clear both the endpoints before starting.
+// When adb quits, we might clear the host endpoint but not the device.
+// So we make sure both sides are clear before starting up.
+static bool ClearPipeStallBothEnds(IOUSBInterfaceInterface190** interface, UInt8 bulkEp) {
+    IOReturn rc = (*interface)->ClearPipeStallBothEnds(interface, bulkEp);
+    if (rc != kIOReturnSuccess) {
+        DBG("ERR: Could not clear pipe: (%08x)\n",  rc);
+        return false;
+    }
+    return true;
+}
+
 //* TODO: simplify this further since we only register to get ADB interface
 //* subclass+protocol events
 static usb_handle*
-CheckInterface(IOUSBInterfaceInterface **interface, UInt16 vendor, UInt16 product)
+CheckInterface(IOUSBInterfaceInterface190 **interface, UInt16 vendor, UInt16 product)
 {
-    usb_handle*                 handle = NULL;
-    IOReturn                    kr;
-    UInt8  interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol;
-    UInt8  endpoint;
-
+    usb_handle* handle;
+    IOReturn kr;
+    UInt8 interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol;
+    UInt8 endpoint;
 
     //* Now open the interface.  This will cause the pipes associated with
     //* the endpoints in the interface descriptor to be instantiated
@@ -331,16 +346,16 @@
 
     //* check to make sure interface class, subclass and protocol match ADB
     //* avoid opening mass storage endpoints
-    if (!is_adb_interface(vendor, product, interfaceClass,
-                interfaceSubClass, interfaceProtocol))
+    if (!is_adb_interface(vendor, product, interfaceClass, interfaceSubClass, interfaceProtocol)) {
         goto err_bad_adb_interface;
+    }
 
     handle = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
     if (handle == nullptr) goto err_bad_adb_interface;
 
     //* Iterate over the endpoints for this interface and find the first
     //* bulk in/out pipes available.  These will be our read/write pipes.
-    for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) {
+    for (endpoint = 1; endpoint <= interfaceNumEndpoints; endpoint++) {
         UInt8   transferType;
         UInt16  maxPacketSize;
         UInt8   interval;
@@ -349,22 +364,24 @@
 
         kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
                 &number, &transferType, &maxPacketSize, &interval);
-
-        if (kIOReturnSuccess == kr) {
-            if (kUSBBulk != transferType)
-                continue;
-
-            if (kUSBIn == direction)
-                handle->bulkIn = endpoint;
-
-            if (kUSBOut == direction)
-                handle->bulkOut = endpoint;
-
-            handle->zero_mask = maxPacketSize - 1;
-        } else {
-            DBG("ERR: FindDeviceInterface - could not get pipe properties\n");
+        if (kr != kIOReturnSuccess) {
+            DBG("ERR: FindDeviceInterface - could not get pipe properties (%08x)\n", kr);
             goto err_get_pipe_props;
         }
+
+        if (kUSBBulk != transferType) continue;
+
+        if (kUSBIn == direction) {
+            handle->bulkIn = endpoint;
+            if (!ClearPipeStallBothEnds(interface, handle->bulkIn)) goto err_get_pipe_props;
+        }
+
+        if (kUSBOut == direction) {
+            handle->bulkOut = endpoint;
+            if (!ClearPipeStallBothEnds(interface, handle->bulkOut)) goto err_get_pipe_props;
+        }
+
+        handle->zero_mask = maxPacketSize - 1;
     }
 
     handle->interface = interface;
diff --git a/adb/usb_windows.cpp b/adb/usb_windows.cpp
index 4c9a152..b8cc5cf 100644
--- a/adb/usb_windows.cpp
+++ b/adb/usb_windows.cpp
@@ -33,6 +33,10 @@
 /** Structure usb_handle describes our connection to the usb device via
   AdbWinApi.dll. This structure is returned from usb_open() routine and
   is expected in each subsequent call that is accessing the device.
+
+  Most members are protected by usb_lock, except for adb_{read,write}_pipe which
+  rely on AdbWinApi.dll's handle validation and AdbCloseHandle(endpoint)'s
+  ability to break a thread out of pipe IO.
 */
 struct usb_handle {
   /// Previous entry in the list of opened usb handles
@@ -86,6 +90,9 @@
 /// registers usb transport for them.
 void find_devices();
 
+/// Kicks all USB devices
+static void kick_devices();
+
 /// Entry point for thread that polls (every second) for new usb interfaces.
 /// This routine calls find_devices in infinite loop.
 void* device_poll_thread(void* unused);
@@ -111,9 +118,6 @@
 /// Closes opened usb handle
 int usb_close(usb_handle* handle);
 
-/// Gets interface (device) name for an opened usb handle
-const char *usb_name(usb_handle* handle);
-
 int known_device_locked(const char* dev_name) {
   usb_handle* usb;
 
@@ -177,17 +181,99 @@
   return NULL;
 }
 
+static LRESULT CALLBACK _power_window_proc(HWND hwnd, UINT uMsg, WPARAM wParam,
+                                           LPARAM lParam) {
+  switch (uMsg) {
+  case WM_POWERBROADCAST:
+    switch (wParam) {
+    case PBT_APMRESUMEAUTOMATIC:
+      // Resuming from sleep or hibernation, so kick all existing USB devices
+      // and then allow the device_poll_thread to redetect USB devices from
+      // scratch. If we don't do this, existing USB devices will never respond
+      // to us because they'll be waiting for the connect/auth handshake.
+      D("Received (WM_POWERBROADCAST, PBT_APMRESUMEAUTOMATIC) notification, "
+        "so kicking all USB devices\n");
+      kick_devices();
+      return TRUE;
+    }
+  }
+  return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+}
+
+static void* _power_notification_thread(void* unused) {
+  // This uses a thread with its own window message pump to get power
+  // notifications. If adb runs from a non-interactive service account, this
+  // might not work (not sure). If that happens to not work, we could use
+  // heavyweight WMI APIs to get power notifications. But for the common case
+  // of a developer's interactive session, a window message pump is more
+  // appropriate.
+  D("Created power notification thread\n");
+
+  // Window class names are process specific.
+  static const WCHAR kPowerNotificationWindowClassName[] =
+    L"PowerNotificationWindow";
+
+  // Get the HINSTANCE corresponding to the module that _power_window_proc
+  // is in (the main module).
+  const HINSTANCE instance = GetModuleHandleW(NULL);
+  if (!instance) {
+    // This is such a common API call that this should never fail.
+    fatal("GetModuleHandleW failed: %s",
+          SystemErrorCodeToString(GetLastError()).c_str());
+  }
+
+  WNDCLASSEXW wndclass;
+  memset(&wndclass, 0, sizeof(wndclass));
+  wndclass.cbSize = sizeof(wndclass);
+  wndclass.lpfnWndProc = _power_window_proc;
+  wndclass.hInstance = instance;
+  wndclass.lpszClassName = kPowerNotificationWindowClassName;
+  if (!RegisterClassExW(&wndclass)) {
+    fatal("RegisterClassExW failed: %s",
+          SystemErrorCodeToString(GetLastError()).c_str());
+  }
+
+  if (!CreateWindowExW(WS_EX_NOACTIVATE, kPowerNotificationWindowClassName,
+                       L"ADB Power Notification Window", WS_POPUP, 0, 0, 0, 0,
+                       NULL, NULL, instance, NULL)) {
+    fatal("CreateWindowExW failed: %s",
+          SystemErrorCodeToString(GetLastError()).c_str());
+  }
+
+  MSG msg;
+  while (GetMessageW(&msg, NULL, 0, 0)) {
+    TranslateMessage(&msg);
+    DispatchMessageW(&msg);
+  }
+
+  // GetMessageW() will return false if a quit message is posted. We don't
+  // do that, but it might be possible for that to occur when logging off or
+  // shutting down. Not a big deal since the whole process will be going away
+  // soon anyway.
+  D("Power notification thread exiting\n");
+
+  return NULL;
+}
+
 void usb_init() {
   if (!adb_thread_create(device_poll_thread, nullptr)) {
-    fatal_errno("cannot create input thread");
+    fatal_errno("cannot create device poll thread");
+  }
+  if (!adb_thread_create(_power_notification_thread, nullptr)) {
+    fatal_errno("cannot create power notification thread");
   }
 }
 
 usb_handle* do_usb_open(const wchar_t* interface_name) {
+  unsigned long name_len = 0;
+
   // Allocate our handle
-  usb_handle* ret = (usb_handle*)malloc(sizeof(usb_handle));
-  if (NULL == ret)
-    return NULL;
+  usb_handle* ret = (usb_handle*)calloc(1, sizeof(usb_handle));
+  if (NULL == ret) {
+    D("Could not allocate %u bytes for usb_handle: %s\n", sizeof(usb_handle),
+      strerror(errno));
+    goto fail;
+  }
 
   // Set linkers back to the handle
   ret->next = ret;
@@ -195,11 +281,10 @@
 
   // Create interface.
   ret->adb_interface = AdbCreateInterfaceByName(interface_name);
-
   if (NULL == ret->adb_interface) {
-    free(ret);
-    errno = GetLastError();
-    return NULL;
+    D("AdbCreateInterfaceByName failed: %s\n",
+      SystemErrorCodeToString(GetLastError()).c_str());
+    goto fail;
   }
 
   // Open read pipe (endpoint)
@@ -207,45 +292,60 @@
     AdbOpenDefaultBulkReadEndpoint(ret->adb_interface,
                                    AdbOpenAccessTypeReadWrite,
                                    AdbOpenSharingModeReadWrite);
-  if (NULL != ret->adb_read_pipe) {
-    // Open write pipe (endpoint)
-    ret->adb_write_pipe =
-      AdbOpenDefaultBulkWriteEndpoint(ret->adb_interface,
-                                      AdbOpenAccessTypeReadWrite,
-                                      AdbOpenSharingModeReadWrite);
-    if (NULL != ret->adb_write_pipe) {
-      // Save interface name
-      unsigned long name_len = 0;
-
-      // First get expected name length
-      AdbGetInterfaceName(ret->adb_interface,
-                          NULL,
-                          &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);
-        }
-      }
-    }
+  if (NULL == ret->adb_read_pipe) {
+    D("AdbOpenDefaultBulkReadEndpoint failed: %s\n",
+      SystemErrorCodeToString(GetLastError()).c_str());
+    goto fail;
   }
 
-  // Something went wrong.
-  int saved_errno = GetLastError();
-  usb_cleanup_handle(ret);
-  free(ret);
-  SetLastError(saved_errno);
+  // Open write pipe (endpoint)
+  ret->adb_write_pipe =
+    AdbOpenDefaultBulkWriteEndpoint(ret->adb_interface,
+                                    AdbOpenAccessTypeReadWrite,
+                                    AdbOpenSharingModeReadWrite);
+  if (NULL == ret->adb_write_pipe) {
+    D("AdbOpenDefaultBulkWriteEndpoint failed: %s\n",
+      SystemErrorCodeToString(GetLastError()).c_str());
+    goto fail;
+  }
+
+  // Save interface name
+  // First get expected name length
+  AdbGetInterfaceName(ret->adb_interface,
+                      NULL,
+                      &name_len,
+                      true);
+  if (0 == name_len) {
+    D("AdbGetInterfaceName returned name length of zero: %s\n",
+      SystemErrorCodeToString(GetLastError()).c_str());
+    goto fail;
+  }
+
+  ret->interface_name = (char*)malloc(name_len);
+  if (NULL == ret->interface_name) {
+    D("Could not allocate %lu bytes for interface_name: %s\n", name_len,
+      strerror(errno));
+    goto fail;
+  }
+
+  // Now save the name
+  if (!AdbGetInterfaceName(ret->adb_interface,
+                           ret->interface_name,
+                           &name_len,
+                           true)) {
+    D("AdbGetInterfaceName failed: %s\n",
+      SystemErrorCodeToString(GetLastError()).c_str());
+    goto fail;
+  }
+
+  // We're done at this point
+  return ret;
+
+fail:
+  if (NULL != ret) {
+    usb_cleanup_handle(ret);
+    free(ret);
+  }
 
   return NULL;
 }
@@ -253,92 +353,130 @@
 int usb_write(usb_handle* handle, const void* data, int len) {
   unsigned long time_out = 5000;
   unsigned long written = 0;
-  int ret;
+  int err = 0;
 
   D("usb_write %d\n", len);
-  if (NULL != handle) {
-    // Perform write
-    ret = AdbWriteEndpointSync(handle->adb_write_pipe,
-                               (void*)data,
-                               (unsigned long)len,
-                               &written,
-                               time_out);
-    int saved_errno = GetLastError();
-
-    if (ret) {
-      // Make sure that we've written what we were asked to write
-      D("usb_write got: %ld, expected: %d\n", written, len);
-      if (written == (unsigned long)len) {
-        if(handle->zero_mask && (len & handle->zero_mask) == 0) {
-          // Send a zero length packet
-          AdbWriteEndpointSync(handle->adb_write_pipe,
-                               (void*)data,
-                               0,
-                               &written,
-                               time_out);
-        }
-        return 0;
-      }
-    } else {
-      // assume ERROR_INVALID_HANDLE indicates we are disconnected
-      if (saved_errno == ERROR_INVALID_HANDLE)
-        usb_kick(handle);
-    }
-    errno = saved_errno;
-  } else {
-    D("usb_write NULL handle\n");
-    SetLastError(ERROR_INVALID_HANDLE);
+  if (NULL == handle) {
+    D("usb_write was passed NULL handle\n");
+    err = EINVAL;
+    goto fail;
   }
 
-  D("usb_write failed: %d\n", errno);
+  // Perform write
+  if (!AdbWriteEndpointSync(handle->adb_write_pipe,
+                            (void*)data,
+                            (unsigned long)len,
+                            &written,
+                            time_out)) {
+    D("AdbWriteEndpointSync failed: %s\n",
+      SystemErrorCodeToString(GetLastError()).c_str());
+    err = EIO;
+    goto fail;
+  }
 
+  // Make sure that we've written what we were asked to write
+  D("usb_write got: %ld, expected: %d\n", written, len);
+  if (written != (unsigned long)len) {
+    // If this occurs, this code should be changed to repeatedly call
+    // AdbWriteEndpointSync() until all bytes are written.
+    D("AdbWriteEndpointSync was supposed to write %d, but only wrote %ld\n",
+      len, written);
+    err = EIO;
+    goto fail;
+  }
+
+  if (handle->zero_mask && (len & handle->zero_mask) == 0) {
+    // Send a zero length packet
+    if (!AdbWriteEndpointSync(handle->adb_write_pipe,
+                              (void*)data,
+                              0,
+                              &written,
+                              time_out)) {
+      D("AdbWriteEndpointSync of zero length packet failed: %s\n",
+        SystemErrorCodeToString(GetLastError()).c_str());
+      err = EIO;
+      goto fail;
+    }
+  }
+
+  return 0;
+
+fail:
+  // Any failure should cause us to kick the device instead of leaving it a
+  // zombie state with potential to hang.
+  if (NULL != handle) {
+    D("Kicking device due to error in usb_write\n");
+    usb_kick(handle);
+  }
+
+  D("usb_write failed\n");
+  errno = err;
   return -1;
 }
 
 int usb_read(usb_handle *handle, void* data, int len) {
   unsigned long time_out = 0;
   unsigned long read = 0;
+  int err = 0;
 
   D("usb_read %d\n", len);
-  if (handle != nullptr) {
-    while (len > 0) {
-      int ret = AdbReadEndpointSync(handle->adb_read_pipe, data, len, &read, time_out);
-      int saved_errno = GetLastError();
-      D("usb_write got: %ld, expected: %d, errno: %d\n", read, len, saved_errno);
-      if (ret) {
-        data = (char *)data + read;
-        len -= read;
-
-        if (len == 0)
-          return 0;
-      } else {
-        // assume ERROR_INVALID_HANDLE indicates we are disconnected
-        if (saved_errno == ERROR_INVALID_HANDLE)
-          usb_kick(handle);
-        break;
-      }
-      errno = saved_errno;
-    }
-  } else {
-    D("usb_read NULL handle\n");
-    SetLastError(ERROR_INVALID_HANDLE);
+  if (NULL == handle) {
+    D("usb_read was passed NULL handle\n");
+    err = EINVAL;
+    goto fail;
   }
 
-  D("usb_read failed: %d\n", errno);
+  while (len > 0) {
+    if (!AdbReadEndpointSync(handle->adb_read_pipe, data, len, &read,
+                             time_out)) {
+      D("AdbReadEndpointSync failed: %s\n",
+        SystemErrorCodeToString(GetLastError()).c_str());
+      err = EIO;
+      goto fail;
+    }
+    D("usb_read got: %ld, expected: %d\n", read, len);
 
+    data = (char *)data + read;
+    len -= read;
+  }
+
+  return 0;
+
+fail:
+  // Any failure should cause us to kick the device instead of leaving it a
+  // zombie state with potential to hang.
+  if (NULL != handle) {
+    D("Kicking device due to error in usb_read\n");
+    usb_kick(handle);
+  }
+
+  D("usb_read failed\n");
+  errno = err;
   return -1;
 }
 
+// Wrapper around AdbCloseHandle() that logs diagnostics.
+static void _adb_close_handle(ADBAPIHANDLE adb_handle) {
+  if (!AdbCloseHandle(adb_handle)) {
+    D("AdbCloseHandle(%p) failed: %s\n", adb_handle,
+      SystemErrorCodeToString(GetLastError()).c_str());
+  }
+}
+
 void usb_cleanup_handle(usb_handle* handle) {
+  D("usb_cleanup_handle\n");
   if (NULL != handle) {
     if (NULL != handle->interface_name)
       free(handle->interface_name);
+    // AdbCloseHandle(pipe) will break any threads out of pending IO calls and
+    // wait until the pipe no longer uses the interface. Then we can
+    // AdbCloseHandle() the interface.
     if (NULL != handle->adb_write_pipe)
-      AdbCloseHandle(handle->adb_write_pipe);
+      _adb_close_handle(handle->adb_write_pipe);
     if (NULL != handle->adb_read_pipe)
-      AdbCloseHandle(handle->adb_read_pipe);
+      _adb_close_handle(handle->adb_read_pipe);
     if (NULL != handle->adb_interface)
-      AdbCloseHandle(handle->adb_interface);
+      _adb_close_handle(handle->adb_interface);
 
     handle->interface_name = NULL;
     handle->adb_write_pipe = NULL;
@@ -347,16 +485,22 @@
   }
 }
 
+static void usb_kick_locked(usb_handle* handle) {
+  // The reason the lock must be acquired before calling this function is in
+  // case multiple threads are trying to kick the same device at the same time.
+  usb_cleanup_handle(handle);
+}
+
 void usb_kick(usb_handle* handle) {
+  D("usb_kick\n");
   if (NULL != handle) {
     adb_mutex_lock(&usb_lock);
 
-    usb_cleanup_handle(handle);
+    usb_kick_locked(handle);
 
     adb_mutex_unlock(&usb_lock);
   } else {
-    SetLastError(ERROR_INVALID_HANDLE);
-    errno = ERROR_INVALID_HANDLE;
+    errno = EINVAL;
   }
 }
 
@@ -384,16 +528,6 @@
   return 0;
 }
 
-const char *usb_name(usb_handle* handle) {
-  if (NULL == handle) {
-    SetLastError(ERROR_INVALID_HANDLE);
-    errno = ERROR_INVALID_HANDLE;
-    return NULL;
-  }
-
-  return (const char*)handle->interface_name;
-}
-
 int recognized_device(usb_handle* handle) {
   if (NULL == handle)
     return 0;
@@ -403,6 +537,8 @@
 
   if (!AdbGetUsbDeviceDescriptor(handle->adb_interface,
                                  &device_desc)) {
+    D("AdbGetUsbDeviceDescriptor failed: %s\n",
+      SystemErrorCodeToString(GetLastError()).c_str());
     return 0;
   }
 
@@ -411,6 +547,8 @@
 
   if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface,
                                     &interf_desc)) {
+    D("AdbGetUsbInterfaceDescriptor failed: %s\n",
+      SystemErrorCodeToString(GetLastError()).c_str());
     return 0;
   }
 
@@ -427,6 +565,10 @@
       // assuming zero is a valid bulk endpoint ID
       if (AdbGetEndpointInformation(handle->adb_interface, 0, &endpoint_info)) {
         handle->zero_mask = endpoint_info.max_packet_size - 1;
+        D("device zero_mask: 0x%x\n", handle->zero_mask);
+      } else {
+        D("AdbGetEndpointInformation failed: %s\n",
+          SystemErrorCodeToString(GetLastError()).c_str());
       }
     }
 
@@ -448,8 +590,11 @@
   ADBAPIHANDLE enum_handle =
     AdbEnumInterfaces(usb_class_id, true, true, true);
 
-  if (NULL == enum_handle)
+  if (NULL == enum_handle) {
+    D("AdbEnumInterfaces failed: %s\n",
+      SystemErrorCodeToString(GetLastError()).c_str());
     return;
+  }
 
   while (AdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) {
     // TODO: FIXME - temp hack converting wchar_t into char.
@@ -486,7 +631,8 @@
               free(handle);
             }
           } else {
-            D("cannot get serial number\n");
+            D("cannot get serial number: %s\n",
+              SystemErrorCodeToString(GetLastError()).c_str());
             usb_cleanup_handle(handle);
             free(handle);
           }
@@ -500,5 +646,21 @@
     entry_buffer_size = sizeof(entry_buffer);
   }
 
-  AdbCloseHandle(enum_handle);
+  if (GetLastError() != ERROR_NO_MORE_ITEMS) {
+    // Only ERROR_NO_MORE_ITEMS is expected at the end of enumeration.
+    D("AdbNextInterface failed: %s\n",
+      SystemErrorCodeToString(GetLastError()).c_str());
+  }
+
+  _adb_close_handle(enum_handle);
+}
+
+static void kick_devices() {
+  // Need to acquire lock to safely walk the list which might be modified
+  // by another thread.
+  adb_mutex_lock(&usb_lock);
+  for (usb_handle* usb = handle_list.next; usb != &handle_list; usb = usb->next) {
+    usb_kick_locked(usb);
+  }
+  adb_mutex_unlock(&usb_lock);
 }
diff --git a/base/Android.mk b/base/Android.mk
index 7bd317b..4e135f6 100644
--- a/base/Android.mk
+++ b/base/Android.mk
@@ -21,6 +21,7 @@
     logging.cpp \
     stringprintf.cpp \
     strings.cpp \
+    test_utils.cpp \
 
 libbase_test_src_files := \
     file_test.cpp \
@@ -28,7 +29,6 @@
     stringprintf_test.cpp \
     strings_test.cpp \
     test_main.cpp \
-    test_utils.cpp \
 
 libbase_cppflags := \
     -Wall \
diff --git a/base/file_test.cpp b/base/file_test.cpp
index b138094..77b9268 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -24,7 +24,7 @@
 
 #include <string>
 
-#include "test_utils.h"
+#include "base/test_utils.h"
 
 TEST(file, ReadFileToString_ENOENT) {
   std::string s("hello");
@@ -34,23 +34,13 @@
   EXPECT_EQ("", s);  // s was cleared.
 }
 
-TEST(file, ReadFileToString_success) {
-  std::string s("hello");
-  ASSERT_TRUE(android::base::ReadFileToString("/proc/version", &s))
-    << strerror(errno);
-  EXPECT_GT(s.length(), 6U);
-  EXPECT_EQ('\n', s[s.length() - 1]);
-  s[5] = 0;
-  EXPECT_STREQ("Linux", s.c_str());
-}
-
-TEST(file, WriteStringToFile) {
+TEST(file, ReadFileToString_WriteStringToFile) {
   TemporaryFile tf;
   ASSERT_TRUE(tf.fd != -1);
-  ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.filename))
+  ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path))
     << strerror(errno);
   std::string s;
-  ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s))
+  ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
     << strerror(errno);
   EXPECT_EQ("abc", s);
 }
@@ -61,16 +51,16 @@
 TEST(file, WriteStringToFile2) {
   TemporaryFile tf;
   ASSERT_TRUE(tf.fd != -1);
-  ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.filename, 0660,
+  ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path, 0660,
                                                getuid(), getgid()))
       << strerror(errno);
   struct stat sb;
-  ASSERT_EQ(0, stat(tf.filename, &sb));
+  ASSERT_EQ(0, stat(tf.path, &sb));
   ASSERT_EQ(0660U, static_cast<unsigned int>(sb.st_mode & ~S_IFMT));
   ASSERT_EQ(getuid(), sb.st_uid);
   ASSERT_EQ(getgid(), sb.st_gid);
   std::string s;
-  ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s))
+  ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
     << strerror(errno);
   EXPECT_EQ("abc", s);
 }
@@ -88,28 +78,21 @@
   EXPECT_EQ("abc", s);
 }
 
-TEST(file, ReadFully) {
-  int fd = open("/proc/version", O_RDONLY);
-  ASSERT_NE(-1, fd) << strerror(errno);
-
-  char buf[1024];
-  memset(buf, 0, sizeof(buf));
-  ASSERT_TRUE(android::base::ReadFully(fd, buf, 5));
-  ASSERT_STREQ("Linux", buf);
-
-  ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
-
-  ASSERT_FALSE(android::base::ReadFully(fd, buf, sizeof(buf)));
-
-  close(fd);
-}
-
 TEST(file, WriteFully) {
   TemporaryFile tf;
   ASSERT_TRUE(tf.fd != -1);
   ASSERT_TRUE(android::base::WriteFully(tf.fd, "abc", 3));
+
+  ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
+
   std::string s;
-  ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s))
+  s.resize(3);
+  ASSERT_TRUE(android::base::ReadFully(tf.fd, &s[0], s.size()))
     << strerror(errno);
   EXPECT_EQ("abc", s);
+
+  ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
+
+  s.resize(1024);
+  ASSERT_FALSE(android::base::ReadFully(tf.fd, &s[0], s.size()));
 }
diff --git a/base/test_utils.h b/base/include/base/test_utils.h
similarity index 69%
rename from base/test_utils.h
rename to base/include/base/test_utils.h
index 132d3a7..402e0a5 100644
--- a/base/test_utils.h
+++ b/base/include/base/test_utils.h
@@ -17,16 +17,35 @@
 #ifndef TEST_UTILS_H
 #define TEST_UTILS_H
 
+#include <string>
+
+#include <base/macros.h>
+
 class TemporaryFile {
  public:
   TemporaryFile();
   ~TemporaryFile();
 
   int fd;
-  char filename[1024];
+  char path[1024];
 
  private:
-  void init(const char* tmp_dir);
+  void init(const std::string& tmp_dir);
+
+  DISALLOW_COPY_AND_ASSIGN(TemporaryFile);
+};
+
+class TemporaryDir {
+ public:
+  TemporaryDir();
+  ~TemporaryDir();
+
+  char path[1024];
+
+ private:
+  bool init(const std::string& tmp_dir);
+
+  DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
 };
 
 #endif // TEST_UTILS_H
diff --git a/base/logging.cpp b/base/logging.cpp
index 34229a2..e9e06df 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -70,9 +70,14 @@
   static char progname[MAX_PATH] = {};
 
   if (first) {
-    // TODO(danalbert): This is a full path on Windows. Just get the basename.
-    DWORD nchars = GetModuleFileName(nullptr, progname, sizeof(progname));
-    DCHECK_GT(nchars, 0U);
+    CHAR longname[MAX_PATH];
+    DWORD nchars = GetModuleFileNameA(nullptr, longname, arraysize(longname));
+    if ((nchars >= arraysize(longname)) || (nchars == 0)) {
+      // String truncation or some other error.
+      strcpy(progname, "<unknown>");
+    } else {
+      strcpy(progname, basename(longname));
+    }
     first = false;
   }
 
@@ -82,25 +87,22 @@
 class mutex {
  public:
   mutex() {
-    semaphore_ = CreateSemaphore(nullptr, 1, 1, nullptr);
-    CHECK(semaphore_ != nullptr) << "Failed to create Mutex";
+    InitializeCriticalSection(&critical_section_);
   }
   ~mutex() {
-    CloseHandle(semaphore_);
+    DeleteCriticalSection(&critical_section_);
   }
 
   void lock() {
-    DWORD result = WaitForSingleObject(semaphore_, INFINITE);
-    CHECK_EQ(result, WAIT_OBJECT_0) << GetLastError();
+    EnterCriticalSection(&critical_section_);
   }
 
   void unlock() {
-    bool result = ReleaseSemaphore(semaphore_, 1, nullptr);
-    CHECK(result);
+    LeaveCriticalSection(&critical_section_);
   }
 
  private:
-  HANDLE semaphore_;
+  CRITICAL_SECTION critical_section_;
 };
 
 template <typename LockT>
@@ -147,8 +149,9 @@
 
 void StderrLogger(LogId, LogSeverity severity, const char*, const char* file,
                   unsigned int line, const char* message) {
-  static const char* log_characters = "VDIWEF";
-  CHECK_EQ(strlen(log_characters), FATAL + 1U);
+  static const char log_characters[] = "VDIWEF";
+  static_assert(arraysize(log_characters) - 1 == FATAL + 1,
+                "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);
@@ -197,6 +200,20 @@
   InitLogging(argv);
 }
 
+// TODO: make this public; it's independently useful.
+class ErrnoRestorer {
+ public:
+  ErrnoRestorer(int saved_errno) : saved_errno_(saved_errno) {
+  }
+
+  ~ErrnoRestorer() {
+    errno = saved_errno_;
+  }
+
+ private:
+  const int saved_errno_;
+};
+
 void InitLogging(char* argv[]) {
   if (gInitialized) {
     return;
@@ -257,19 +274,25 @@
   gLogger = std::move(logger);
 }
 
+// We can't use basename(3) because this code runs on the Mac, which doesn't
+// have a non-modifying basename.
+static const char* GetFileBasename(const char* file) {
+  const char* last_slash = strrchr(file, '/');
+  return (last_slash == nullptr) ? file : last_slash + 1;
+}
+
 // This indirection greatly reduces the stack impact of having lots of
 // checks/logging in a function.
 class LogMessageData {
  public:
   LogMessageData(const char* file, unsigned int line, LogId id,
-                 LogSeverity severity, int error)
-      : file_(file),
+                 LogSeverity severity, int error, int saved_errno)
+      : file_(GetFileBasename(file)),
         line_number_(line),
         id_(id),
         severity_(severity),
-        error_(error) {
-    const char* last_slash = strrchr(file, '/');
-    file = (last_slash == nullptr) ? file : last_slash + 1;
+        error_(error),
+        errno_restorer_(saved_errno) {
   }
 
   const char* GetFile() const {
@@ -307,13 +330,14 @@
   const LogId id_;
   const LogSeverity severity_;
   const int error_;
+  ErrnoRestorer errno_restorer_;
 
   DISALLOW_COPY_AND_ASSIGN(LogMessageData);
 };
 
 LogMessage::LogMessage(const char* file, unsigned int line, LogId id,
                        LogSeverity severity, int error)
-    : data_(new LogMessageData(file, line, id, severity, error)) {
+    : data_(new LogMessageData(file, line, id, severity, error, errno)) {
 }
 
 LogMessage::~LogMessage() {
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
index c91857a..c12dfa5 100644
--- a/base/logging_test.cpp
+++ b/base/logging_test.cpp
@@ -16,12 +16,14 @@
 
 #include "base/logging.h"
 
+#include <libgen.h>
+
 #include <regex>
 #include <string>
 
 #include "base/file.h"
 #include "base/stringprintf.h"
-#include "test_utils.h"
+#include "base/test_utils.h"
 
 #include <gtest/gtest.h>
 
@@ -76,10 +78,10 @@
                              const char* message) {
   static const char* log_characters = "VDIWEF";
   char log_char = log_characters[severity];
+  std::string holder(__FILE__);
   return android::base::StringPrintf(
-      "%c[[:space:]]+[[:digit:]]+[[:space:]]+[[:digit:]]+ " __FILE__
-      ":[[:digit:]]+] %s",
-      log_char, message);
+      "%c[[:space:]]+[[:digit:]]+[[:space:]]+[[:digit:]]+ %s:[[:digit:]]+] %s",
+      log_char, basename(&holder[0]), message);
 }
 
 TEST(logging, LOG) {
@@ -100,7 +102,7 @@
 #if !defined(_WIN32)
     std::regex message_regex(
         make_log_pattern(android::base::WARNING, "foobar"));
-    ASSERT_TRUE(std::regex_search(output, message_regex));
+    ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
 #endif
   }
 
@@ -116,7 +118,7 @@
 #if !defined(_WIN32)
     std::regex message_regex(
         make_log_pattern(android::base::INFO, "foobar"));
-    ASSERT_TRUE(std::regex_search(output, message_regex));
+    ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
 #endif
   }
 
@@ -143,7 +145,7 @@
 #if !defined(_WIN32)
     std::regex message_regex(
         make_log_pattern(android::base::DEBUG, "foobar"));
-    ASSERT_TRUE(std::regex_search(output, message_regex));
+    ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
 #endif
   }
 }
@@ -162,7 +164,7 @@
 #if !defined(_WIN32)
     std::regex message_regex(make_log_pattern(
         android::base::INFO, "foobar: No such file or directory"));
-    ASSERT_TRUE(std::regex_search(output, message_regex));
+    ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
 #endif
   }
 }
@@ -183,7 +185,7 @@
         android::base::StringPrintf("%s unimplemented ", __PRETTY_FUNCTION__);
     std::regex message_regex(
         make_log_pattern(android::base::ERROR, expected_message.c_str()));
-    ASSERT_TRUE(std::regex_search(output, message_regex));
+    ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
 #endif
   }
 }
diff --git a/base/stringprintf_test.cpp b/base/stringprintf_test.cpp
index 54b2b6c..5cc2086 100644
--- a/base/stringprintf_test.cpp
+++ b/base/stringprintf_test.cpp
@@ -20,14 +20,11 @@
 
 #include <string>
 
-// The z size sepcifier isn't supported on Windows, so this test isn't useful.
-#if !defined(_WIN32)
 TEST(StringPrintfTest, HexSizeT) {
   size_t size = 0x00107e59;
   EXPECT_EQ("00107e59", android::base::StringPrintf("%08zx", size));
   EXPECT_EQ("0x00107e59", android::base::StringPrintf("0x%08zx", size));
 }
-#endif
 
 TEST(StringPrintfTest, StringAppendF) {
   std::string s("a");
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 0517bc7..b0c5a12 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-#include "test_utils.h"
+#include "base/logging.h"
+#include "base/test_utils.h"
+#include "utils/Compat.h" // For OS_PATH_SEPARATOR.
 
 #include <fcntl.h>
 #include <stdio.h>
@@ -24,36 +26,77 @@
 
 #if defined(_WIN32)
 #include <windows.h>
+#include <direct.h>
 #endif
 
-TemporaryFile::TemporaryFile() {
-#if defined(__ANDROID__)
-  init("/data/local/tmp");
-#elif defined(_WIN32)
-  char wd[MAX_PATH] = {};
-  _getcwd(wd, sizeof(wd));
-  init(wd);
-#else
-  init("/tmp");
+#include <string>
+
+#ifdef _WIN32
+int mkstemp(char* template_name) {
+  if (_mktemp(template_name) == nullptr) {
+    return -1;
+  }
+  // Use open() to match the close() that TemporaryFile's destructor does.
+  // Note that on Windows, this does CR/LF translation and _setmode() should
+  // be used to change that if appropriate.
+  return open(template_name, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
+}
+
+char* mkdtemp(char* template_name) {
+  if (_mktemp(template_name) == nullptr) {
+    return nullptr;
+  }
+  if (_mkdir(template_name) == -1) {
+    return nullptr;
+  }
+  return template_name;
+}
 #endif
+
+static std::string GetSystemTempDir() {
+#if defined(__ANDROID__)
+  return "/data/local/tmp";
+#elif defined(_WIN32)
+  char tmp_dir[MAX_PATH];
+  DWORD result = GetTempPathA(sizeof(tmp_dir), tmp_dir);
+  CHECK_NE(result, 0ul) << "GetTempPathA failed, error: " << GetLastError();
+  CHECK_LT(result, sizeof(tmp_dir)) << "path truncated to: " << result;
+
+  // GetTempPath() returns a path with a trailing slash, but init()
+  // does not expect that, so remove it.
+  CHECK_EQ(tmp_dir[result - 1], '\\');
+  tmp_dir[result - 1] = '\0';
+  return tmp_dir;
+#else
+  return "/tmp";
+#endif
+}
+
+TemporaryFile::TemporaryFile() {
+  init(GetSystemTempDir());
 }
 
 TemporaryFile::~TemporaryFile() {
   close(fd);
-  unlink(filename);
+  unlink(path);
 }
 
-void TemporaryFile::init(const char* tmp_dir) {
-  snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir);
-#if !defined(_WIN32)
-  fd = mkstemp(filename);
-#else
-  // Windows doesn't have mkstemp, and tmpfile creates the file in the root
-  // directory, requiring root (?!) permissions. We have to settle for mktemp.
-  if (mktemp(filename) == nullptr) {
-    abort();
-  }
+void TemporaryFile::init(const std::string& tmp_dir) {
+  snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(),
+           OS_PATH_SEPARATOR);
+  fd = mkstemp(path);
+}
 
-  fd = open(filename, O_RDWR | O_NOINHERIT | O_CREAT, _S_IREAD | _S_IWRITE);
-#endif
+TemporaryDir::TemporaryDir() {
+  init(GetSystemTempDir());
+}
+
+TemporaryDir::~TemporaryDir() {
+  rmdir(path);
+}
+
+bool TemporaryDir::init(const std::string& tmp_dir) {
+  snprintf(path, sizeof(path), "%s%cTemporaryDir-XXXXXX", tmp_dir.c_str(),
+           OS_PATH_SEPARATOR);
+  return (mkdtemp(path) != nullptr);
 }
diff --git a/crash_reporter/chrome_collector.cc b/crash_reporter/chrome_collector.cc
deleted file mode 100644
index ec291c0..0000000
--- a/crash_reporter/chrome_collector.cc
+++ /dev/null
@@ -1,335 +0,0 @@
-// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "crash-reporter/chrome_collector.h"
-
-#include <pcrecpp.h>
-#include <stdint.h>
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include <base/files/file_util.h>
-#include <base/logging.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_util.h>
-#include <chromeos/data_encoding.h>
-#include <chromeos/dbus/service_constants.h>
-#include <chromeos/process.h>
-#include <chromeos/syslog_logging.h>
-
-using base::FilePath;
-using base::StringPrintf;
-
-namespace {
-
-const char kDefaultMinidumpName[] = "upload_file_minidump";
-
-// Path to the gzip binary.
-const char kGzipPath[] = "/bin/gzip";
-
-// Filenames for logs attached to crash reports. Also used as metadata keys.
-const char kChromeLogFilename[] = "chrome.txt";
-const char kGpuStateFilename[] = "i915_error_state.log.xz";
-
-// From //net/crash/collector/collector.h
-const int kDefaultMaxUploadBytes = 1024 * 1024;
-
-// Extract a string delimited by the given character, from the given offset
-// into a source string. Returns false if the string is zero-sized or no
-// delimiter was found.
-bool GetDelimitedString(const std::string &str, char ch, size_t offset,
-                        std::string *substr) {
-  size_t at = str.find_first_of(ch, offset);
-  if (at == std::string::npos || at == offset)
-    return false;
-  *substr = str.substr(offset, at - offset);
-  return true;
-}
-
-// Gets the GPU's error state from debugd and writes it to |error_state_path|.
-// Returns true on success.
-bool GetDriErrorState(const FilePath &error_state_path,
-                      org::chromium::debugdProxy *proxy) {
-  chromeos::ErrorPtr error;
-  std::string error_state_str;
-
-  proxy->GetLog("i915_error_state", &error_state_str, &error);
-
-  if (error) {
-    LOG(ERROR) << "Error calling D-Bus proxy call to interface "
-               << "'" << proxy->GetObjectPath().value() << "':"
-               << error->GetMessage();
-    return false;
-  }
-
-  if (error_state_str == "<empty>")
-    return false;
-
-  const char kBase64Header[] = "<base64>: ";
-  const size_t kBase64HeaderLength = sizeof(kBase64Header) - 1;
-  if (error_state_str.compare(0, kBase64HeaderLength, kBase64Header)) {
-    LOG(ERROR) << "i915_error_state is missing base64 header";
-    return false;
-  }
-
-  std::string decoded_error_state;
-
-  if (!chromeos::data_encoding::Base64Decode(
-      error_state_str.c_str() + kBase64HeaderLength,
-      &decoded_error_state)) {
-    LOG(ERROR) << "Could not decode i915_error_state";
-    return false;
-  }
-
-  int written = base::WriteFile(error_state_path,
-                                decoded_error_state.c_str(),
-                                decoded_error_state.length());
-  if (written < 0 ||
-      static_cast<size_t>(written) != decoded_error_state.length()) {
-    LOG(ERROR) << "Could not write file " << error_state_path.value()
-               << " Written: " << written << " Len: "
-               << decoded_error_state.length();
-    base::DeleteFile(error_state_path, false);
-    return false;
-  }
-
-  return true;
-}
-
-// Gzip-compresses |path|, removes the original file, and returns the path of
-// the new file. On failure, the original file is left alone and an empty path
-// is returned.
-FilePath GzipFile(const FilePath& path) {
-  chromeos::ProcessImpl proc;
-  proc.AddArg(kGzipPath);
-  proc.AddArg(path.value());
-  const int res = proc.Run();
-  if (res != 0) {
-    LOG(ERROR) << "Failed to gzip " << path.value();
-    return FilePath();
-  }
-  return path.AddExtension(".gz");
-}
-
-}  // namespace
-
-
-ChromeCollector::ChromeCollector() : output_file_ptr_(stdout) {}
-
-ChromeCollector::~ChromeCollector() {}
-
-bool ChromeCollector::HandleCrash(const FilePath &file_path,
-                                  const std::string &pid_string,
-                                  const std::string &uid_string,
-                                  const std::string &exe_name) {
-  if (!is_feedback_allowed_function_())
-    return true;
-
-  LOG(WARNING) << "Received crash notification for " << exe_name << "["
-               << pid_string << "] user " << uid_string << " (called directly)";
-
-  if (exe_name.find('/') != std::string::npos) {
-    LOG(ERROR) << "exe_name contains illegal characters: " << exe_name;
-    return false;
-  }
-
-  FilePath dir;
-  uid_t uid = atoi(uid_string.c_str());
-  pid_t pid = atoi(pid_string.c_str());
-  if (!GetCreatedCrashDirectoryByEuid(uid, &dir, nullptr)) {
-    LOG(ERROR) << "Can't create crash directory for uid " << uid;
-    return false;
-  }
-
-  std::string dump_basename = FormatDumpBasename(exe_name, time(nullptr), pid);
-  FilePath meta_path = GetCrashPath(dir, dump_basename, "meta");
-  FilePath minidump_path = GetCrashPath(dir, dump_basename, "dmp");
-
-  std::string data;
-  if (!base::ReadFileToString(file_path, &data)) {
-    LOG(ERROR) << "Can't read crash log: " << file_path.value();
-    return false;
-  }
-
-  if (!ParseCrashLog(data, dir, minidump_path, dump_basename)) {
-    LOG(ERROR) << "Failed to parse Chrome's crash log";
-    return false;
-  }
-
-
-  int64_t report_size = 0;
-  base::GetFileSize(minidump_path, &report_size);
-
-  // Keyed by crash metadata key name.
-  const std::map<std::string, base::FilePath> additional_logs =
-      GetAdditionalLogs(dir, dump_basename, exe_name);
-  for (auto it : additional_logs) {
-    int64_t file_size = 0;
-    if (!base::GetFileSize(it.second, &file_size)) {
-      PLOG(WARNING) << "Unable to get size of " << it.second.value();
-      continue;
-    }
-    if (report_size + file_size > kDefaultMaxUploadBytes) {
-      LOG(INFO) << "Skipping upload of " << it.second.value() << "("
-                << file_size << "B) because report size would exceed limit ("
-                << kDefaultMaxUploadBytes << "B)";
-      continue;
-    }
-    VLOG(1) << "Adding metadata: " << it.first << " -> " << it.second.value();
-    // Call AddCrashMetaUploadFile() rather than AddCrashMetaData() here. The
-    // former adds a prefix to the key name; without the prefix, only the key
-    // "logs" appears to be displayed on the crash server.
-    AddCrashMetaUploadFile(it.first, it.second.value());
-    report_size += file_size;
-  }
-
-  // We're done.
-  WriteCrashMetaData(meta_path, exe_name, minidump_path.value());
-
-  fprintf(output_file_ptr_, "%s", kSuccessMagic);
-  fflush(output_file_ptr_);
-
-  return true;
-}
-
-void ChromeCollector::SetUpDBus() {
-  CrashCollector::SetUpDBus();
-
-  debugd_proxy_.reset(
-      new org::chromium::debugdProxy(bus_, debugd::kDebugdServiceName));
-}
-
-bool ChromeCollector::ParseCrashLog(const std::string &data,
-                                    const FilePath &dir,
-                                    const FilePath &minidump,
-                                    const std::string &basename) {
-  size_t at = 0;
-  while (at < data.size()) {
-    // Look for a : followed by a decimal number, followed by another :
-    // followed by N bytes of data.
-    std::string name, size_string;
-    if (!GetDelimitedString(data, ':', at, &name)) {
-      LOG(ERROR) << "Can't find : after name @ offset " << at;
-      break;
-    }
-    at += name.size() + 1;  // Skip the name & : delimiter.
-
-    if (!GetDelimitedString(data, ':', at, &size_string)) {
-      LOG(ERROR) << "Can't find : after size @ offset " << at;
-      break;
-    }
-    at += size_string.size() + 1;  // Skip the size & : delimiter.
-
-    size_t size;
-    if (!base::StringToSizeT(size_string, &size)) {
-      LOG(ERROR) << "String not convertible to integer: " << size_string;
-      break;
-    }
-
-    // Data would run past the end, did we get a truncated file?
-    if (at + size > data.size()) {
-      LOG(ERROR) << "Overrun, expected " << size << " bytes of data, got "
-        << (data.size() - at);
-      break;
-    }
-
-    if (name.find("filename") != std::string::npos) {
-      // File.
-      // Name will be in a semi-MIME format of
-      // <descriptive name>"; filename="<name>"
-      // Descriptive name will be upload_file_minidump for the dump.
-      std::string desc, filename;
-      pcrecpp::RE re("(.*)\" *; *filename=\"(.*)\"");
-      if (!re.FullMatch(name.c_str(), &desc, &filename)) {
-        LOG(ERROR) << "Filename was not in expected format: " << name;
-        break;
-      }
-
-      if (desc.compare(kDefaultMinidumpName) == 0) {
-        // The minidump.
-        WriteNewFile(minidump, data.c_str() + at, size);
-      } else {
-        // Some other file.
-        FilePath path = GetCrashPath(dir, basename + "-" + filename, "other");
-        if (WriteNewFile(path, data.c_str() + at, size) >= 0) {
-          AddCrashMetaUploadFile(desc, path.value());
-        }
-      }
-    } else {
-      // Other attribute.
-      std::string value_str;
-      value_str.reserve(size);
-
-      // Since metadata is one line/value the values must be escaped properly.
-      for (size_t i = at; i < at + size; i++) {
-        switch (data[i]) {
-          case '"':
-          case '\\':
-            value_str.push_back('\\');
-            value_str.push_back(data[i]);
-            break;
-
-          case '\r':
-            value_str += "\\r";
-            break;
-
-          case '\n':
-            value_str += "\\n";
-           break;
-
-          case '\t':
-            value_str += "\\t";
-           break;
-
-          case '\0':
-            value_str += "\\0";
-           break;
-
-          default:
-           value_str.push_back(data[i]);
-           break;
-        }
-      }
-      AddCrashMetaUploadData(name, value_str);
-    }
-
-    at += size;
-  }
-
-  return at == data.size();
-}
-
-std::map<std::string, base::FilePath> ChromeCollector::GetAdditionalLogs(
-    const FilePath &dir,
-    const std::string &basename,
-    const std::string &exe_name) {
-  std::map<std::string, base::FilePath> logs;
-
-  // Run the command specified by the config file to gather logs.
-  const FilePath chrome_log_path =
-      GetCrashPath(dir, basename, kChromeLogFilename);
-  if (GetLogContents(log_config_path_, exe_name, chrome_log_path)) {
-    const FilePath compressed_path = GzipFile(chrome_log_path);
-    if (!compressed_path.empty())
-      logs[kChromeLogFilename] = compressed_path;
-    else
-      base::DeleteFile(chrome_log_path, false /* recursive */);
-  }
-
-  // For unit testing, debugd_proxy_ isn't initialized, so skip attempting to
-  // get the GPU error state from debugd.
-  if (debugd_proxy_) {
-    const FilePath dri_error_state_path =
-        GetCrashPath(dir, basename, kGpuStateFilename);
-    if (GetDriErrorState(dri_error_state_path, debugd_proxy_.get()))
-      logs[kGpuStateFilename] = dri_error_state_path;
-  }
-
-  return logs;
-}
-
-// static
-const char ChromeCollector::kSuccessMagic[] = "_sys_cr_finished";
diff --git a/crash_reporter/chrome_collector.h b/crash_reporter/chrome_collector.h
deleted file mode 100644
index 0b58c19..0000000
--- a/crash_reporter/chrome_collector.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CRASH_REPORTER_CHROME_COLLECTOR_H_
-#define CRASH_REPORTER_CHROME_COLLECTOR_H_
-
-#include <map>
-#include <string>
-
-#include <base/files/file_path.h>
-#include <base/macros.h>
-#include <gtest/gtest_prod.h>  // for FRIEND_TEST
-
-#include "crash-reporter/crash_collector.h"
-#include "debugd/dbus-proxies.h"
-
-class SystemLogging;
-
-// Chrome crash collector.
-class ChromeCollector : public CrashCollector {
- public:
-  ChromeCollector();
-  ~ChromeCollector() override;
-
-  // Magic string to let Chrome know the crash report succeeded.
-  static const char kSuccessMagic[];
-
-  // Handle a specific chrome crash.  Returns true on success.
-  bool HandleCrash(const base::FilePath &file_path,
-                   const std::string &pid_string,
-                   const std::string &uid_string,
-                   const std::string &exe_name);
-
- protected:
-  void SetUpDBus() override;
-
- private:
-  friend class ChromeCollectorTest;
-  FRIEND_TEST(ChromeCollectorTest, GoodValues);
-  FRIEND_TEST(ChromeCollectorTest, BadValues);
-  FRIEND_TEST(ChromeCollectorTest, Newlines);
-  FRIEND_TEST(ChromeCollectorTest, File);
-  FRIEND_TEST(ChromeCollectorTest, HandleCrash);
-
-  // Crashes are expected to be in a TLV-style format of:
-  // <name>:<length>:<value>
-  // Length is encoded as a decimal number. It can be zero, but must consist of
-  // at least one character
-  // For file values, name actually contains both a description and a filename,
-  // in a fixed format of: <description>"; filename="<filename>"
-  bool ParseCrashLog(const std::string &data, const base::FilePath &dir,
-                     const base::FilePath &minidump,
-                     const std::string &basename);
-
-  // Writes additional logs for |exe_name| to files based on |basename| within
-  // |dir|. Crash report metadata key names and the corresponding file paths are
-  // returned.
-  std::map<std::string, base::FilePath> GetAdditionalLogs(
-      const base::FilePath &dir,
-      const std::string &basename,
-      const std::string &exe_name);
-
-  FILE *output_file_ptr_;
-
-  // D-Bus proxy for debugd interface.  Unset in unit tests.
-  std::unique_ptr<org::chromium::debugdProxy> debugd_proxy_;
-
-  DISALLOW_COPY_AND_ASSIGN(ChromeCollector);
-};
-
-#endif  // CRASH_REPORTER_CHROME_COLLECTOR_H_
diff --git a/crash_reporter/chrome_collector_test.cc b/crash_reporter/chrome_collector_test.cc
deleted file mode 100644
index 0d6a7ce..0000000
--- a/crash_reporter/chrome_collector_test.cc
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "crash-reporter/chrome_collector.h"
-
-#include <stdio.h>
-
-#include <base/auto_reset.h>
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <chromeos/syslog_logging.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-using base::FilePath;
-
-namespace {
-
-const char kCrashFormatGood[] = "value1:10:abcdefghijvalue2:5:12345";
-const char kCrashFormatEmbeddedNewline[] =
-    "value1:10:abcd\r\nghijvalue2:5:12\n34";
-const char kCrashFormatBad1[] = "value1:10:abcdefghijvalue2:6=12345";
-const char kCrashFormatBad2[] = "value1:10:abcdefghijvalue2:512345";
-const char kCrashFormatBad3[] = "value1:10::abcdefghijvalue2:5=12345";
-const char kCrashFormatBad4[] = "value1:10:abcdefghijvalue2:4=12345";
-
-const char kCrashFormatWithFile[] =
-    "value1:10:abcdefghijvalue2:5:12345"
-    "some_file\"; filename=\"foo.txt\":15:12345\n789\n12345"
-    "value3:2:ok";
-
-void CountCrash() {
-}
-
-bool s_allow_crash = false;
-
-bool IsMetrics() {
-  return s_allow_crash;
-}
-
-}  // namespace
-
-class ChromeCollectorMock : public ChromeCollector {
- public:
-  MOCK_METHOD0(SetUpDBus, void());
-};
-
-class ChromeCollectorTest : public ::testing::Test {
- protected:
-  void ExpectFileEquals(const char *golden,
-                        const FilePath &file_path) {
-    std::string contents;
-    EXPECT_TRUE(base::ReadFileToString(file_path, &contents));
-    EXPECT_EQ(golden, contents);
-  }
-
-  ChromeCollectorMock collector_;
-
- private:
-  void SetUp() override {
-    EXPECT_CALL(collector_, SetUpDBus()).WillRepeatedly(testing::Return());
-
-    collector_.Initialize(CountCrash, IsMetrics);
-    chromeos::ClearLog();
-  }
-};
-
-TEST_F(ChromeCollectorTest, GoodValues) {
-  FilePath dir(".");
-  EXPECT_TRUE(collector_.ParseCrashLog(kCrashFormatGood,
-                                       dir, dir.Append("minidump.dmp"),
-                                       "base"));
-
-  // Check to see if the values made it in properly.
-  std::string meta = collector_.extra_metadata_;
-  EXPECT_TRUE(meta.find("value1=abcdefghij") != std::string::npos);
-  EXPECT_TRUE(meta.find("value2=12345") != std::string::npos);
-}
-
-TEST_F(ChromeCollectorTest, Newlines) {
-  FilePath dir(".");
-  EXPECT_TRUE(collector_.ParseCrashLog(kCrashFormatEmbeddedNewline,
-                                       dir, dir.Append("minidump.dmp"),
-                                       "base"));
-
-  // Check to see if the values were escaped.
-  std::string meta = collector_.extra_metadata_;
-  EXPECT_TRUE(meta.find("value1=abcd\\r\\nghij") != std::string::npos);
-  EXPECT_TRUE(meta.find("value2=12\\n34") != std::string::npos);
-}
-
-TEST_F(ChromeCollectorTest, BadValues) {
-  FilePath dir(".");
-  const struct {
-    const char *data;
-  } list[] = {
-    {kCrashFormatBad1, },
-    {kCrashFormatBad2, },
-    {kCrashFormatBad3, },
-    {kCrashFormatBad4, },
-  };
-
-  for (size_t i = 0; i < sizeof(list) / sizeof(list[0]); i++) {
-    chromeos::ClearLog();
-    EXPECT_FALSE(collector_.ParseCrashLog(list[i].data,
-                                          dir, dir.Append("minidump.dmp"),
-                                          "base"));
-  }
-}
-
-TEST_F(ChromeCollectorTest, File) {
-  base::ScopedTempDir scoped_temp_dir;
-  ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
-  const FilePath& dir = scoped_temp_dir.path();
-  EXPECT_TRUE(collector_.ParseCrashLog(kCrashFormatWithFile,
-                                       dir, dir.Append("minidump.dmp"),
-                                       "base"));
-
-  // Check to see if the values are still correct and that the file was
-  // written with the right data.
-  std::string meta = collector_.extra_metadata_;
-  EXPECT_TRUE(meta.find("value1=abcdefghij") != std::string::npos);
-  EXPECT_TRUE(meta.find("value2=12345") != std::string::npos);
-  EXPECT_TRUE(meta.find("value3=ok") != std::string::npos);
-  ExpectFileEquals("12345\n789\n12345", dir.Append("base-foo.txt.other"));
-}
-
-TEST_F(ChromeCollectorTest, HandleCrash) {
-  base::AutoReset<bool> auto_reset(&s_allow_crash, true);
-  base::ScopedTempDir scoped_temp_dir;
-  ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
-  const FilePath& dir = scoped_temp_dir.path();
-  FilePath dump_file = dir.Append("test.dmp");
-  ASSERT_EQ(strlen(kCrashFormatWithFile),
-            base::WriteFile(dump_file, kCrashFormatWithFile,
-                            strlen(kCrashFormatWithFile)));
-  collector_.ForceCrashDirectory(dir);
-
-  FilePath log_file;
-  {
-    base::ScopedFILE output(
-        base::CreateAndOpenTemporaryFileInDir(dir, &log_file));
-    ASSERT_TRUE(output.get());
-    base::AutoReset<FILE*> auto_reset_file_ptr(&collector_.output_file_ptr_,
-                                               output.get());
-    EXPECT_TRUE(collector_.HandleCrash(dump_file, "123", "456", "chrome_test"));
-  }
-  ExpectFileEquals(ChromeCollector::kSuccessMagic, log_file);
-}
diff --git a/crash_reporter/crash-reporter.gyp b/crash_reporter/crash-reporter.gyp
deleted file mode 100644
index a7f0e7e..0000000
--- a/crash_reporter/crash-reporter.gyp
+++ /dev/null
@@ -1,147 +0,0 @@
-{
-  # Shouldn't need this, but doesn't work otherwise.
-  # http://crbug.com/340086 and http://crbug.com/385186
-  # Note: the unused dependencies are optimized out by the compiler.
-  'target_defaults': {
-    'variables': {
-      'deps': [
-        'libchromeos-<(libbase_ver)',
-      ],
-    },
-  },
-  'targets': [
-    {
-      'target_name': 'libcrash',
-      'type': 'static_library',
-      'variables': {
-        'exported_deps': [
-          'libchrome-<(libbase_ver)',
-          'libpcrecpp',
-        ],
-        'deps': ['<@(exported_deps)'],
-      },
-      'all_dependent_settings': {
-        'variables': {
-          'deps': [
-            '<@(exported_deps)',
-          ],
-        },
-      },
-      'sources': [
-        'chrome_collector.cc',
-        'crash_collector.cc',
-        'kernel_collector.cc',
-        'kernel_warning_collector.cc',
-        'udev_collector.cc',
-        'unclean_shutdown_collector.cc',
-        'user_collector.cc',
-      ],
-      'actions': [
-        {
-          'action_name': 'generate-session-manager-proxies',
-          'variables': {
-            'proxy_output_file': 'include/session_manager/dbus-proxies.h'
-          },
-          'sources': [
-            '../login_manager/org.chromium.SessionManagerInterface.xml',
-          ],
-          'includes': ['../common-mk/generate-dbus-proxies.gypi'],
-        },
-        {
-          'action_name': 'generate-debugd-proxies',
-          'variables': {
-            'proxy_output_file': 'include/debugd/dbus-proxies.h'
-          },
-          'sources': [
-            '../debugd/share/org.chromium.debugd.xml',
-          ],
-          'includes': ['../common-mk/generate-dbus-proxies.gypi'],
-        },
-      ],
-    },
-    {
-      'target_name': 'crash_reporter',
-      'type': 'executable',
-      'variables': {
-        'deps': [
-          'dbus-1',
-          'libmetrics-<(libbase_ver)',
-        ],
-      },
-      'dependencies': [
-        'libcrash',
-      ],
-      'sources': [
-        'crash_reporter.cc',
-      ],
-    },
-    {
-      'target_name': 'list_proxies',
-      'type': 'executable',
-      'variables': {
-        'deps': [
-          'dbus-1',
-          'libchrome-<(libbase_ver)',
-        ],
-      },
-      'sources': [
-        'list_proxies.cc',
-      ],
-      'actions': [
-        {
-          'action_name': 'generate-lib-cros-service-proxies',
-          'variables': {
-            'proxy_output_file': 'include/libcrosservice/dbus-proxies.h'
-          },
-          'sources': [
-            './dbus_bindings/org.chromium.LibCrosService.xml',
-          ],
-          'includes': ['../common-mk/generate-dbus-proxies.gypi'],
-        },
-      ],
-    },
-    {
-      'target_name': 'warn_collector',
-      'type': 'executable',
-      'variables': {
-        'lexer_out_dir': 'crash-reporter',
-        'deps': [
-          'libmetrics-<(libbase_ver)',
-        ],
-      },
-      'link_settings': {
-        'libraries': [
-          '-lfl',
-        ],
-      },
-      'sources': [
-        'warn_collector.l',
-      ],
-      'includes': ['../common-mk/lex.gypi'],
-    },
-  ],
-  'conditions': [
-    ['USE_test == 1', {
-      'targets': [
-        {
-          'target_name': 'crash_reporter_test',
-          'type': 'executable',
-          'includes': ['../common-mk/common_test.gypi'],
-          'dependencies': ['libcrash'],
-          'sources': [
-            'chrome_collector_test.cc',
-            'crash_collector_test.cc',
-            'crash_collector_test.h',
-            'crash_reporter_logs_test.cc',
-            'kernel_collector_test.cc',
-            'kernel_collector_test.h',
-            'testrunner.cc',
-            'udev_collector_test.cc',
-            'unclean_shutdown_collector_test.cc',
-            'user_collector_test.cc',
-          ],
-        },
-      ],
-    }],
-  ],
-}
diff --git a/crash_reporter/crash_collector.cc b/crash_reporter/crash_collector.cc
index 04f3ba8..5406160 100644
--- a/crash_reporter/crash_collector.cc
+++ b/crash_reporter/crash_collector.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "crash-reporter/crash_collector.h"
+#include "crash_collector.h"
 
 #include <dirent.h>
 #include <fcntl.h>  // For file creation modes.
@@ -23,8 +23,6 @@
 #include <base/strings/string_split.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
-#include <chromeos/cryptohome.h>
-#include <chromeos/dbus/service_constants.h>
 #include <chromeos/key_value_store.h>
 #include <chromeos/process.h>
 
@@ -38,7 +36,7 @@
 const char kLeaveCoreFile[] = "/root/.leave_core";
 const char kLsbRelease[] = "/etc/lsb-release";
 const char kShellPath[] = "/bin/sh";
-const char kSystemCrashPath[] = "/var/spool/crash";
+const char kSystemCrashPath[] = "/data/misc/crash_reporter/crash";
 const char kUploadVarPrefix[] = "upload_var_";
 const char kUploadFilePrefix[] = "upload_file_";
 
@@ -87,8 +85,6 @@
 }
 
 CrashCollector::~CrashCollector() {
-  if (bus_)
-    bus_->ShutdownAndBlock();
 }
 
 void CrashCollector::Initialize(
@@ -99,21 +95,6 @@
 
   count_crash_function_ = count_crash_function;
   is_feedback_allowed_function_ = is_feedback_allowed_function;
-
-  SetUpDBus();
-}
-
-void CrashCollector::SetUpDBus() {
-  dbus::Bus::Options options;
-  options.bus_type = dbus::Bus::SYSTEM;
-
-  bus_ = new dbus::Bus(options);
-  CHECK(bus_->Connect());
-
-  session_manager_proxy_.reset(
-      new org::chromium::SessionManagerInterfaceProxy(
-          bus_,
-          login_manager::kSessionManagerServiceName));
 }
 
 int CrashCollector::WriteNewFile(const FilePath &filename,
@@ -166,62 +147,14 @@
                                              extension.c_str()));
 }
 
-bool CrashCollector::GetActiveUserSessions(
-    std::map<std::string, std::string> *sessions) {
-  chromeos::ErrorPtr error;
-  session_manager_proxy_->RetrieveActiveSessions(sessions, &error);
-
-  if (error) {
-    LOG(ERROR) << "Error calling D-Bus proxy call to interface "
-               << "'" << session_manager_proxy_->GetObjectPath().value() << "':"
-               << error->GetMessage();
-    return false;
-  }
-
-  return true;
-}
-
-FilePath CrashCollector::GetUserCrashPath() {
-  // In this multiprofile world, there is no one-specific user dir anymore.
-  // Ask the session manager for the active ones, then just run with the
-  // first result we get back.
-  FilePath user_path = FilePath(kFallbackUserCrashPath);
-  std::map<std::string, std::string> active_sessions;
-  if (!GetActiveUserSessions(&active_sessions) || active_sessions.empty()) {
-    LOG(ERROR) << "Could not get active user sessions, using default.";
-    return user_path;
-  }
-
-  user_path = chromeos::cryptohome::home::GetHashedUserPath(
-      active_sessions.begin()->second).Append("crash");
-
-  return user_path;
-}
-
 FilePath CrashCollector::GetCrashDirectoryInfo(
-    uid_t process_euid,
-    uid_t default_user_id,
-    gid_t default_user_group,
     mode_t *mode,
     uid_t *directory_owner,
     gid_t *directory_group) {
-  // TODO(mkrebs): This can go away once Chrome crashes are handled
-  // normally (see crosbug.com/5872).
-  // Check if the user crash directory should be used.  If we are
-  // collecting chrome crashes during autotesting, we want to put them in
-  // the system crash directory so they are outside the cryptohome -- in
-  // case we are being run during logout (see crosbug.com/18637).
-  if (process_euid == default_user_id && IsUserSpecificDirectoryEnabled()) {
-    *mode = kUserCrashPathMode;
-    *directory_owner = default_user_id;
-    *directory_group = default_user_group;
-    return GetUserCrashPath();
-  } else {
-    *mode = kSystemCrashPathMode;
-    *directory_owner = kRootOwner;
-    *directory_group = kRootGroup;
-    return FilePath(kSystemCrashPath);
-  }
+  *mode = kSystemCrashPathMode;
+  *directory_owner = kRootOwner;
+  *directory_group = kRootGroup;
+  return FilePath(kSystemCrashPath);
 }
 
 bool CrashCollector::GetUserInfoFromName(const std::string &name,
@@ -245,9 +178,6 @@
 bool CrashCollector::GetCreatedCrashDirectoryByEuid(uid_t euid,
                                                     FilePath *crash_directory,
                                                     bool *out_of_capacity) {
-  uid_t default_user_id;
-  gid_t default_user_group;
-
   if (out_of_capacity) *out_of_capacity = false;
 
   // For testing.
@@ -256,20 +186,11 @@
     return true;
   }
 
-  if (!GetUserInfoFromName(kDefaultUserName,
-                           &default_user_id,
-                           &default_user_group)) {
-    LOG(ERROR) << "Could not find default user info";
-    return false;
-  }
   mode_t directory_mode;
   uid_t directory_owner;
   gid_t directory_group;
   *crash_directory =
-      GetCrashDirectoryInfo(euid,
-                            default_user_id,
-                            default_user_group,
-                            &directory_mode,
+      GetCrashDirectoryInfo(&directory_mode,
                             &directory_owner,
                             &directory_group);
 
@@ -295,6 +216,8 @@
 
   if (!CheckHasCapacity(*crash_directory)) {
     if (out_of_capacity) *out_of_capacity = true;
+    LOG(ERROR) << "Directory " << crash_directory->value()
+               << " is out of capacity.";
     return false;
   }
 
@@ -366,6 +289,8 @@
 bool CrashCollector::CheckHasCapacity(const FilePath &crash_directory) {
   DIR* dir = opendir(crash_directory.value().c_str());
   if (!dir) {
+    LOG(WARNING) << "Unable to open crash directory "
+                 << crash_directory.value();
     return false;
   }
   struct dirent ent_buf;
@@ -491,22 +416,3 @@
     return false;
   return base::PathExists(FilePath(kLeaveCoreFile));
 }
-
-bool CrashCollector::ShouldHandleChromeCrashes() {
-  // If we're testing crash reporter itself, we don't want to allow an
-  // override for chrome crashes.  And, let's be conservative and only
-  // allow an override for developer images.
-  if (!IsCrashTestInProgress() && IsDeveloperImage()) {
-    // Check if there's an override to indicate we should indeed collect
-    // chrome crashes.  This allows the crashes to still be tracked when
-    // they occur in autotests.  See "crosbug.com/17987".
-    if (base::PathExists(FilePath(kCollectChromeFile)))
-      return true;
-  }
-  // We default to ignoring chrome crashes.
-  return false;
-}
-
-bool CrashCollector::IsUserSpecificDirectoryEnabled() {
-  return !ShouldHandleChromeCrashes();
-}
diff --git a/crash_reporter/crash_collector.h b/crash_reporter/crash_collector.h
index ef443d3..0c28048 100644
--- a/crash_reporter/crash_collector.h
+++ b/crash_reporter/crash_collector.h
@@ -12,11 +12,8 @@
 
 #include <base/files/file_path.h>
 #include <base/macros.h>
-#include <base/memory/scoped_ptr.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
-#include "session_manager/dbus-proxies.h"
-
 // User crash collector.
 class CrashCollector {
  public:
@@ -44,7 +41,6 @@
   FRIEND_TEST(CrashCollectorTest, ForkExecAndPipe);
   FRIEND_TEST(CrashCollectorTest, FormatDumpBasename);
   FRIEND_TEST(CrashCollectorTest, Initialize);
-  FRIEND_TEST(CrashCollectorTest, IsUserSpecificDirectoryEnabled);
   FRIEND_TEST(CrashCollectorTest, MetaData);
   FRIEND_TEST(CrashCollectorTest, Sanitize);
   FRIEND_TEST(CrashCollectorTest, WriteNewFile);
@@ -61,9 +57,6 @@
   // Set maximum enqueued crashes in a crash directory.
   static const int kMaxCrashDirectorySize;
 
-  // Set up D-Bus.
-  virtual void SetUpDBus();
-
   // Writes |data| of |size| to |filename|, which must be a new file.
   // If the file already exists or writing fails, return a negative value.
   // Otherwise returns the number of bytes written.
@@ -79,15 +72,9 @@
     forced_crash_directory_ = forced_directory;
   }
 
-  virtual bool GetActiveUserSessions(
-      std::map<std::string, std::string> *sessions);
-  base::FilePath GetUserCrashPath();
-  base::FilePath GetCrashDirectoryInfo(uid_t process_euid,
-                                 uid_t default_user_id,
-                                 gid_t default_user_group,
-                                 mode_t *mode,
-                                 uid_t *directory_owner,
-                                 gid_t *directory_group);
+  base::FilePath GetCrashDirectoryInfo(mode_t *mode,
+                                       uid_t *directory_owner,
+                                       gid_t *directory_group);
   bool GetUserInfoFromName(const std::string &name,
                            uid_t *uid,
                            gid_t *gid);
@@ -154,10 +141,6 @@
   // Returns true if we should consider ourselves to be running on a
   // developer image.
   bool IsDeveloperImage();
-  // Returns true if chrome crashes should be handled.
-  bool ShouldHandleChromeCrashes();
-  // Returns true if user crash directory may be used.
-  bool IsUserSpecificDirectoryEnabled();
 
   CountCrashFunction count_crash_function_;
   IsFeedbackAllowedFunction is_feedback_allowed_function_;
@@ -166,13 +149,7 @@
   std::string lsb_release_;
   base::FilePath log_config_path_;
 
-  scoped_refptr<dbus::Bus> bus_;
-
  private:
-  // D-Bus proxy for session manager interface.
-  std::unique_ptr<org::chromium::SessionManagerInterfaceProxy>
-      session_manager_proxy_;
-
   DISALLOW_COPY_AND_ASSIGN(CrashCollector);
 };
 
diff --git a/crash_reporter/crash_collector_test.cc b/crash_reporter/crash_collector_test.cc
index ce9af2b..28c4462 100644
--- a/crash_reporter/crash_collector_test.cc
+++ b/crash_reporter/crash_collector_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "crash-reporter/crash_collector_test.h"
+#include "crash_collector_test.h"
 
 #include <unistd.h>
 #include <utility>
@@ -13,7 +13,7 @@
 #include <chromeos/syslog_logging.h>
 #include <gtest/gtest.h>
 
-#include "crash-reporter/crash_collector.h"
+#include "crash_collector.h"
 
 using base::FilePath;
 using base::StringPrintf;
@@ -32,13 +32,6 @@
   return false;
 }
 
-bool GetActiveUserSessionsImpl(std::map<std::string, std::string> *sessions) {
-  char kUser[] = "chicken@butt.com";
-  char kHash[] = "hashcakes";
-  sessions->insert(std::pair<std::string, std::string>(kUser, kHash));
-  return true;
-}
-
 }  // namespace
 
 class CrashCollectorTest : public ::testing::Test {
@@ -90,59 +83,6 @@
   EXPECT_EQ("_", collector_.Sanitize(" "));
 }
 
-TEST_F(CrashCollectorTest, GetCrashDirectoryInfo) {
-  FilePath path;
-  const int kRootUid = 0;
-  const int kRootGid = 0;
-  const int kNtpUid = 5;
-  const int kChronosUid = 1000;
-  const int kChronosGid = 1001;
-  const mode_t kExpectedSystemMode = 01755;
-  const mode_t kExpectedUserMode = 0755;
-
-  mode_t directory_mode;
-  uid_t directory_owner;
-  gid_t directory_group;
-
-  path = collector_.GetCrashDirectoryInfo(kRootUid,
-                                          kChronosUid,
-                                          kChronosGid,
-                                          &directory_mode,
-                                          &directory_owner,
-                                          &directory_group);
-  EXPECT_EQ("/var/spool/crash", path.value());
-  EXPECT_EQ(kExpectedSystemMode, directory_mode);
-  EXPECT_EQ(kRootUid, directory_owner);
-  EXPECT_EQ(kRootGid, directory_group);
-
-  path = collector_.GetCrashDirectoryInfo(kNtpUid,
-                                          kChronosUid,
-                                          kChronosGid,
-                                          &directory_mode,
-                                          &directory_owner,
-                                          &directory_group);
-  EXPECT_EQ("/var/spool/crash", path.value());
-  EXPECT_EQ(kExpectedSystemMode, directory_mode);
-  EXPECT_EQ(kRootUid, directory_owner);
-  EXPECT_EQ(kRootGid, directory_group);
-
-  EXPECT_CALL(collector_, GetActiveUserSessions(testing::_))
-      .WillOnce(Invoke(&GetActiveUserSessionsImpl));
-
-  EXPECT_EQ(collector_.IsUserSpecificDirectoryEnabled(), true);
-
-  path = collector_.GetCrashDirectoryInfo(kChronosUid,
-                                          kChronosUid,
-                                          kChronosGid,
-                                          &directory_mode,
-                                          &directory_owner,
-                                          &directory_group);
-  EXPECT_EQ("/home/user/hashcakes/crash", path.value());
-  EXPECT_EQ(kExpectedUserMode, directory_mode);
-  EXPECT_EQ(kChronosUid, directory_owner);
-  EXPECT_EQ(kChronosGid, directory_group);
-}
-
 TEST_F(CrashCollectorTest, FormatDumpBasename) {
   struct tm tm = {0};
   tm.tm_sec = 15;
diff --git a/crash_reporter/crash_collector_test.h b/crash_reporter/crash_collector_test.h
index 8339fa0..c875d44 100644
--- a/crash_reporter/crash_collector_test.h
+++ b/crash_reporter/crash_collector_test.h
@@ -5,7 +5,7 @@
 #ifndef CRASH_REPORTER_CRASH_COLLECTOR_TEST_H_
 #define CRASH_REPORTER_CRASH_COLLECTOR_TEST_H_
 
-#include "crash-reporter/crash_collector.h"
+#include "crash_collector.h"
 
 #include <map>
 #include <string>
diff --git a/crash_reporter/crash_reporter.cc b/crash_reporter/crash_reporter.cc
index 1528b3f..0e45992 100644
--- a/crash_reporter/crash_reporter.cc
+++ b/crash_reporter/crash_reporter.cc
@@ -16,12 +16,11 @@
 #include <chromeos/syslog_logging.h>
 #include <metrics/metrics_library.h>
 
-#include "crash-reporter/chrome_collector.h"
-#include "crash-reporter/kernel_collector.h"
-#include "crash-reporter/kernel_warning_collector.h"
-#include "crash-reporter/udev_collector.h"
-#include "crash-reporter/unclean_shutdown_collector.h"
-#include "crash-reporter/user_collector.h"
+#include "kernel_collector.h"
+#include "kernel_warning_collector.h"
+#include "udev_collector.h"
+#include "unclean_shutdown_collector.h"
+#include "user_collector.h"
 
 static const char kCrashCounterHistogram[] = "Logging.CrashCounter";
 static const char kUserCrashSignal[] =
@@ -97,12 +96,6 @@
   LOG_IF(WARNING, status != 0) << "dbus-send running failed";
 }
 
-static void CountChromeCrash() {
-  // For now, consider chrome crashes the same as user crashes for reporting
-  // purposes.
-  CountUserCrash();
-}
-
 
 static int Initialize(KernelCollector *kernel_collector,
                       UserCollector *user_collector,
@@ -164,25 +157,6 @@
   return 0;
 }
 
-static int HandleChromeCrash(ChromeCollector *chrome_collector,
-                             const std::string& chrome_dump_file,
-                             const std::string& pid,
-                             const std::string& uid,
-                             const std::string& exe) {
-  CHECK(!chrome_dump_file.empty()) << "--chrome= must be set";
-  CHECK(!pid.empty()) << "--pid= must be set";
-  CHECK(!uid.empty()) << "--uid= must be set";
-  CHECK(!exe.empty()) << "--exe= must be set";
-
-  chromeos::LogToString(true);
-  bool handled = chrome_collector->HandleCrash(FilePath(chrome_dump_file),
-                                               pid, uid, exe);
-  chromeos::LogToString(false);
-  if (!handled)
-    return 1;
-  return 0;
-}
-
 static int HandleUdevCrash(UdevCollector *udev_collector,
                            const std::string& udev_event) {
   // Handle a crash indicated by a udev event.
@@ -258,7 +232,6 @@
   DEFINE_bool(unclean_check, true, "Check for unclean shutdown");
   DEFINE_string(udev, "", "Udev event description (type:device:subsystem)");
   DEFINE_bool(kernel_warning, false, "Report collected kernel warning");
-  DEFINE_string(chrome, "", "Chrome crash dump file");
   DEFINE_string(pid, "", "PID of crashing process");
   DEFINE_string(uid, "", "UID of crashing process");
   DEFINE_string(exe, "", "Executable name of crashing process");
@@ -289,8 +262,6 @@
                                         IsFeedbackAllowed);
   UdevCollector udev_collector;
   udev_collector.Initialize(CountUdevCrash, IsFeedbackAllowed);
-  ChromeCollector chrome_collector;
-  chrome_collector.Initialize(CountChromeCrash, IsFeedbackAllowed);
 
   KernelWarningCollector kernel_warning_collector;
   kernel_warning_collector.Initialize(CountUdevCrash, IsFeedbackAllowed);
@@ -322,13 +293,5 @@
     return HandleKernelWarning(&kernel_warning_collector);
   }
 
-  if (!FLAGS_chrome.empty()) {
-    return HandleChromeCrash(&chrome_collector,
-                             FLAGS_chrome,
-                             FLAGS_pid,
-                             FLAGS_uid,
-                             FLAGS_exe);
-  }
-
   return HandleUserCrash(&user_collector, FLAGS_user, FLAGS_crash_test);
 }
diff --git a/crash_reporter/init.crash_reporter.rc b/crash_reporter/init.crash_reporter.rc
new file mode 100644
index 0000000..f65371a
--- /dev/null
+++ b/crash_reporter/init.crash_reporter.rc
@@ -0,0 +1,19 @@
+on property:crash_reporter.coredump.enabled=1
+    write /proc/sys/kernel/core_pattern \
+          "|/system/bin/crash_reporter --user=%P:%s:%u:%e"
+
+on property:crash_reporter.coredump.enabled=0
+    write /proc/sys/kernel/core_pattern "core"
+
+on boot
+    # Allow catching multiple unrelated concurrent crashes, but use a finite
+    # number to prevent infinitely recursing on crash handling.
+    write /proc/sys/kernel/core_pipe_limit 4
+
+    # Create crash directories.
+    mkdir /data/misc/crash_reporter 0700 root root
+    mkdir /data/local/tmp/crash_reporter 0700 root root
+
+service crash_reporter /system/bin/crash_reporter --init
+    class late_start
+    oneshot
diff --git a/crash_reporter/kernel_collector.cc b/crash_reporter/kernel_collector.cc
index d86efbd..b3cbede 100644
--- a/crash_reporter/kernel_collector.cc
+++ b/crash_reporter/kernel_collector.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "crash-reporter/kernel_collector.h"
+#include "kernel_collector.h"
 
 #include <map>
 #include <sys/stat.h>
diff --git a/crash_reporter/kernel_collector.h b/crash_reporter/kernel_collector.h
index c8aedfe..5fc4ac2 100644
--- a/crash_reporter/kernel_collector.h
+++ b/crash_reporter/kernel_collector.h
@@ -13,7 +13,7 @@
 #include <base/macros.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
-#include "crash-reporter/crash_collector.h"
+#include "crash_collector.h"
 
 // Kernel crash collector.
 class KernelCollector : public CrashCollector {
diff --git a/crash_reporter/kernel_collector_test.cc b/crash_reporter/kernel_collector_test.cc
index 48d94ea..a534803 100644
--- a/crash_reporter/kernel_collector_test.cc
+++ b/crash_reporter/kernel_collector_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "crash-reporter/kernel_collector_test.h"
+#include "kernel_collector_test.h"
 
 #include <unistd.h>
 
diff --git a/crash_reporter/kernel_collector_test.h b/crash_reporter/kernel_collector_test.h
index 75ac01e..d450134 100644
--- a/crash_reporter/kernel_collector_test.h
+++ b/crash_reporter/kernel_collector_test.h
@@ -5,7 +5,7 @@
 #ifndef CRASH_REPORTER_KERNEL_COLLECTOR_TEST_H_
 #define CRASH_REPORTER_KERNEL_COLLECTOR_TEST_H_
 
-#include "crash-reporter/kernel_collector.h"
+#include "kernel_collector.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
diff --git a/crash_reporter/kernel_warning_collector.cc b/crash_reporter/kernel_warning_collector.cc
index 5dcd1f6..4cf7640 100644
--- a/crash_reporter/kernel_warning_collector.cc
+++ b/crash_reporter/kernel_warning_collector.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "crash-reporter/kernel_warning_collector.h"
+#include "kernel_warning_collector.h"
 
 #include <base/files/file_util.h>
 #include <base/logging.h>
diff --git a/crash_reporter/kernel_warning_collector.h b/crash_reporter/kernel_warning_collector.h
index f326b23..82c509c 100644
--- a/crash_reporter/kernel_warning_collector.h
+++ b/crash_reporter/kernel_warning_collector.h
@@ -10,7 +10,7 @@
 #include <base/macros.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
-#include "crash-reporter/crash_collector.h"
+#include "crash_collector.h"
 
 // Kernel warning collector.
 class KernelWarningCollector : public CrashCollector {
diff --git a/crash_reporter/udev_collector.cc b/crash_reporter/udev_collector.cc
index 908bbc9..85f40db 100644
--- a/crash_reporter/udev_collector.cc
+++ b/crash_reporter/udev_collector.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "crash-reporter/udev_collector.h"
+#include "udev_collector.h"
 
 #include <map>
 #include <utility>
diff --git a/crash_reporter/udev_collector.h b/crash_reporter/udev_collector.h
index 1689dd3..d9b37eb 100644
--- a/crash_reporter/udev_collector.h
+++ b/crash_reporter/udev_collector.h
@@ -11,7 +11,7 @@
 #include <base/macros.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
-#include "crash-reporter/crash_collector.h"
+#include "crash_collector.h"
 
 // Udev crash collector.
 class UdevCollector : public CrashCollector {
diff --git a/crash_reporter/udev_collector_test.cc b/crash_reporter/udev_collector_test.cc
index 08d9b2c..4897b91 100644
--- a/crash_reporter/udev_collector_test.cc
+++ b/crash_reporter/udev_collector_test.cc
@@ -10,7 +10,7 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
-#include "crash-reporter/udev_collector.h"
+#include "udev_collector.h"
 
 using base::FilePath;
 
diff --git a/crash_reporter/unclean_shutdown_collector.cc b/crash_reporter/unclean_shutdown_collector.cc
index e8273b5..a6da1bb 100644
--- a/crash_reporter/unclean_shutdown_collector.cc
+++ b/crash_reporter/unclean_shutdown_collector.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "crash-reporter/unclean_shutdown_collector.h"
+#include "unclean_shutdown_collector.h"
 
 #include <base/files/file_util.h>
 #include <base/logging.h>
diff --git a/crash_reporter/unclean_shutdown_collector.h b/crash_reporter/unclean_shutdown_collector.h
index d30a0b2..2ce0842 100644
--- a/crash_reporter/unclean_shutdown_collector.h
+++ b/crash_reporter/unclean_shutdown_collector.h
@@ -11,7 +11,7 @@
 #include <base/macros.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
-#include "crash-reporter/crash_collector.h"
+#include "crash_collector.h"
 
 // Unclean shutdown collector.
 class UncleanShutdownCollector : public CrashCollector {
diff --git a/crash_reporter/unclean_shutdown_collector_test.cc b/crash_reporter/unclean_shutdown_collector_test.cc
index f5e1b32..dc420fb 100644
--- a/crash_reporter/unclean_shutdown_collector_test.cc
+++ b/crash_reporter/unclean_shutdown_collector_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "crash-reporter/unclean_shutdown_collector.h"
+#include "unclean_shutdown_collector.h"
 
 #include <unistd.h>
 
diff --git a/crash_reporter/user_collector.cc b/crash_reporter/user_collector.cc
index 302b130..6bf9120 100644
--- a/crash_reporter/user_collector.cc
+++ b/crash_reporter/user_collector.cc
@@ -2,45 +2,39 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "crash-reporter/user_collector.h"
+#include "user_collector.h"
 
-#include <bits/wordsize.h>
 #include <elf.h>
 #include <fcntl.h>
 #include <grp.h>  // For struct group.
 #include <pcrecpp.h>
 #include <pwd.h>  // For struct passwd.
 #include <stdint.h>
+#include <sys/cdefs.h>  // For __WORDSIZE
 #include <sys/types.h>  // For getpwuid_r, getgrnam_r, WEXITSTATUS.
 
-#include <set>
 #include <string>
 #include <vector>
 
 #include <base/files/file_util.h>
 #include <base/logging.h>
 #include <base/posix/eintr_wrapper.h>
-#include <base/stl_util.h>
 #include <base/strings/string_split.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
 #include <chromeos/process.h>
 #include <chromeos/syslog_logging.h>
+#include <cutils/properties.h>
 
 static const char kCollectionErrorSignature[] =
     "crash_reporter-user-collection";
-// This procfs file is used to cause kernel core file writing to
-// instead pipe the core file into a user space process.  See
-// core(5) man page.
-static const char kCorePatternFile[] = "/proc/sys/kernel/core_pattern";
-static const char kCorePipeLimitFile[] = "/proc/sys/kernel/core_pipe_limit";
-// Set core_pipe_limit to 4 so that we can catch a few unrelated concurrent
-// crashes, but finite to avoid infinitely recursing on crash handling.
-static const char kCorePipeLimit[] = "4";
-static const char kCoreToMinidumpConverterPath[] = "/usr/bin/core2md";
+static const char kCorePatternProperty[] = "crash_reporter.coredump.enabled";
+static const char kCoreToMinidumpConverterPath[] = "/system/bin/core2md";
 
 static const char kStatePrefix[] = "State:\t";
 
+static const char kCoreTempFolder[] = "/data/local/tmp/crash_reporter";
+
 // Define an otherwise invalid value that represents an unknown UID.
 static const uid_t kUnknownUid = -1;
 
@@ -52,8 +46,6 @@
 
 UserCollector::UserCollector()
     : generate_diagnostics_(false),
-      core_pattern_file_(kCorePatternFile),
-      core_pipe_limit_file_(kCorePipeLimitFile),
       initialized_(false) {
 }
 
@@ -117,18 +109,8 @@
   CHECK(initialized_);
   LOG(INFO) << (enabled ? "Enabling" : "Disabling") << " user crash handling";
 
-  if (base::WriteFile(FilePath(core_pipe_limit_file_), kCorePipeLimit,
-                      strlen(kCorePipeLimit)) !=
-      static_cast<int>(strlen(kCorePipeLimit))) {
-    PLOG(ERROR) << "Unable to write " << core_pipe_limit_file_;
-    return false;
-  }
-  std::string pattern = GetPattern(enabled);
-  if (base::WriteFile(FilePath(core_pattern_file_), pattern.c_str(),
-                      pattern.length()) != static_cast<int>(pattern.length())) {
-    PLOG(ERROR) << "Unable to write " << core_pattern_file_;
-    return false;
-  }
+  property_set(kCorePatternProperty, enabled ? "1" : "0");
+
   return true;
 }
 
@@ -344,7 +326,7 @@
 
 bool UserCollector::CopyStdinToCoreFile(const FilePath &core_path) {
   // Copy off all stdin to a core file.
-  FilePath stdin_path("/dev/fd/0");
+  FilePath stdin_path("/proc/self/fd/0");
   if (base::CopyFile(stdin_path, core_path)) {
     return true;
   }
@@ -440,7 +422,7 @@
 
   // Directory like /tmp/crash_reporter/1234 which contains the
   // procfs entries and other temporary files used during conversion.
-  FilePath container_dir(StringPrintf("/tmp/crash_reporter/%d", pid));
+  FilePath container_dir(StringPrintf("%s/%d", kCoreTempFolder, pid));
   // Delete a pre-existing directory from crash reporter that may have
   // been left around for diagnostics from a failed conversion attempt.
   // If we don't, existing files can cause forking to fail.
@@ -495,101 +477,11 @@
       kernel_supplied_name);
 }
 
-// Returns true if the given executable name matches that of Chrome.  This
-// includes checks for threads that Chrome has renamed.
-static bool IsChromeExecName(const std::string &exec) {
-  static const char *kChromeNames[] = {
-    "chrome",
-    // These are additional thread names seen in http://crash/
-    "MediaPipeline",
-    // These come from the use of base::PlatformThread::SetName() directly
-    "CrBrowserMain", "CrRendererMain", "CrUtilityMain", "CrPPAPIMain",
-    "CrPPAPIBrokerMain", "CrPluginMain", "CrWorkerMain", "CrGpuMain",
-    "BrokerEvent", "CrVideoRenderer", "CrShutdownDetector",
-    "UsbEventHandler", "CrNaClMain", "CrServiceMain",
-    // These thread names come from the use of base::Thread
-    "Gamepad polling thread", "Chrome_InProcGpuThread",
-    "Chrome_DragDropThread", "Renderer::FILE", "VC manager",
-    "VideoCaptureModuleImpl", "JavaBridge", "VideoCaptureManagerThread",
-    "Geolocation", "Geolocation_wifi_provider",
-    "Device orientation polling thread", "Chrome_InProcRendererThread",
-    "NetworkChangeNotifier", "Watchdog", "inotify_reader",
-    "cf_iexplore_background_thread", "BrowserWatchdog",
-    "Chrome_HistoryThread", "Chrome_SyncThread", "Chrome_ShellDialogThread",
-    "Printing_Worker", "Chrome_SafeBrowsingThread", "SimpleDBThread",
-    "D-Bus thread", "AudioThread", "NullAudioThread", "V4L2Thread",
-    "ChromotingClientDecodeThread", "Profiling_Flush",
-    "worker_thread_ticker", "AudioMixerAlsa", "AudioMixerCras",
-    "FakeAudioRecordingThread", "CaptureThread",
-    "Chrome_WebSocketproxyThread", "ProcessWatcherThread",
-    "Chrome_CameraThread", "import_thread", "NaCl_IOThread",
-    "Chrome_CloudPrintJobPrintThread", "Chrome_CloudPrintProxyCoreThread",
-    "DaemonControllerFileIO", "ChromotingMainThread",
-    "ChromotingEncodeThread", "ChromotingDesktopThread",
-    "ChromotingIOThread", "ChromotingFileIOThread",
-    "Chrome_libJingle_WorkerThread", "Chrome_ChildIOThread",
-    "GLHelperThread", "RemotingHostPlugin",
-    // "PAC thread #%d",  // not easy to check because of "%d"
-    "Chrome_DBThread", "Chrome_WebKitThread", "Chrome_FileThread",
-    "Chrome_FileUserBlockingThread", "Chrome_ProcessLauncherThread",
-    "Chrome_CacheThread", "Chrome_IOThread", "Cache Thread", "File Thread",
-    "ServiceProcess_IO", "ServiceProcess_File",
-    "extension_crash_uploader", "gpu-process_crash_uploader",
-    "plugin_crash_uploader", "renderer_crash_uploader",
-    // These come from the use of webkit_glue::WebThreadImpl
-    "Compositor", "Browser Compositor",
-    // "WorkerPool/%d",  // not easy to check because of "%d"
-    // These come from the use of base::Watchdog
-    "Startup watchdog thread Watchdog", "Shutdown watchdog thread Watchdog",
-    // These come from the use of AudioDeviceThread::Start
-    "AudioDevice", "AudioInputDevice", "AudioOutputDevice",
-    // These come from the use of MessageLoopFactory::GetMessageLoop
-    "GpuVideoDecoder", "RtcVideoDecoderThread", "PipelineThread",
-    "AudioDecoderThread", "VideoDecoderThread",
-    // These come from the use of MessageLoopFactory::GetMessageLoopProxy
-    "CaptureVideoDecoderThread", "CaptureVideoDecoder",
-    // These come from the use of base::SimpleThread
-    "LocalInputMonitor/%d",  // "%d" gets lopped off for kernel-supplied
-    // These come from the use of base::DelegateSimpleThread
-    "ipc_channel_nacl reader thread/%d", "plugin_audio_input_thread/%d",
-    "plugin_audio_thread/%d",
-    // These come from the use of base::SequencedWorkerPool
-    "BrowserBlockingWorker%d/%d",  // "%d" gets lopped off for kernel-supplied
-  };
-  static std::set<std::string> chrome_names;
-
-  // Initialize a set of chrome names, for efficient lookup
-  if (chrome_names.empty()) {
-    for (size_t i = 0; i < arraysize(kChromeNames); i++) {
-      std::string check_name(kChromeNames[i]);
-      chrome_names.insert(check_name);
-      // When checking a kernel-supplied name, it should be truncated to 15
-      // chars.  See PR_SET_NAME in
-      // http://www.kernel.org/doc/man-pages/online/pages/man2/prctl.2.html,
-      // although that page misleads by saying "16 bytes".
-      chrome_names.insert("supplied_" + std::string(check_name, 0, 15));
-    }
-  }
-
-  return ContainsKey(chrome_names, exec);
-}
-
 bool UserCollector::ShouldDump(bool has_owner_consent,
                                bool is_developer,
-                               bool handle_chrome_crashes,
-                               const std::string &exec,
                                std::string *reason) {
   reason->clear();
 
-  // Treat Chrome crashes as if the user opted-out.  We stop counting Chrome
-  // crashes towards user crashes, so user crashes really mean non-Chrome
-  // user-space crashes.
-  if (!handle_chrome_crashes && IsChromeExecName(exec)) {
-    *reason = "ignoring call by kernel - chrome crash; "
-              "waiting for chrome to call us directly";
-    return false;
-  }
-
   // For developer builds, we always want to keep the crash reports unless
   // we're testing the crash facilities themselves.  This overrides
   // feedback.  Crash sending still obeys consent.
@@ -646,8 +538,6 @@
   std::string reason;
   bool dump = ShouldDump(is_feedback_allowed_function_(),
                          IsDeveloperImage(),
-                         ShouldHandleChromeCrashes(),
-                         exec,
                          &reason);
 
   LOG(WARNING) << "Received crash notification for " << exec << "[" << pid
diff --git a/crash_reporter/user_collector.h b/crash_reporter/user_collector.h
index aac94cb..dd42457 100644
--- a/crash_reporter/user_collector.h
+++ b/crash_reporter/user_collector.h
@@ -12,7 +12,7 @@
 #include <base/macros.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
-#include "crash-reporter/crash_collector.h"
+#include "crash_collector.h"
 
 class SystemLogging;
 
@@ -47,16 +47,6 @@
   bool HandleCrash(const std::string &crash_attributes,
                    const char *force_exec);
 
-  // Set (override the default) core file pattern.
-  void set_core_pattern_file(const std::string &pattern) {
-    core_pattern_file_ = pattern;
-  }
-
-  // Set (override the default) core pipe limit file.
-  void set_core_pipe_limit_file(const std::string &path) {
-    core_pipe_limit_file_ = path;
-  }
-
  private:
   friend class UserCollectorTest;
   FRIEND_TEST(UserCollectorTest, CopyOffProcFilesBadPath);
@@ -169,13 +159,9 @@
 
   bool ShouldDump(bool has_owner_consent,
                   bool is_developer,
-                  bool handle_chrome_crashes,
-                  const std::string &exec,
                   std::string *reason);
 
   bool generate_diagnostics_;
-  std::string core_pattern_file_;
-  std::string core_pipe_limit_file_;
   std::string our_path_;
   bool initialized_;
 
diff --git a/crash_reporter/user_collector_test.cc b/crash_reporter/user_collector_test.cc
index 823d8b4..3c59521 100644
--- a/crash_reporter/user_collector_test.cc
+++ b/crash_reporter/user_collector_test.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "crash-reporter/user_collector.h"
+#include "user_collector.h"
 
-#include <bits/wordsize.h>
 #include <elf.h>
+#include <sys/cdefs.h>  // For __WORDSIZE
 #include <unistd.h>
 
 #include <base/files/file_util.h>
@@ -60,8 +60,6 @@
                           "");
     base::DeleteFile(FilePath("test"), true);
     mkdir("test", 0777);
-    collector_.set_core_pattern_file("test/core_pattern");
-    collector_.set_core_pipe_limit_file("test/core_pipe_limit");
     pid_ = getpid();
     chromeos::ClearLog();
   }
@@ -84,49 +82,6 @@
   pid_t pid_;
 };
 
-TEST_F(UserCollectorTest, EnableOK) {
-  ASSERT_TRUE(collector_.Enable());
-  ExpectFileEquals("|/my/path --user=%P:%s:%u:%e",
-                   FilePath("test/core_pattern"));
-  ExpectFileEquals("4", FilePath("test/core_pipe_limit"));
-  ASSERT_EQ(s_crashes, 0);
-  EXPECT_TRUE(FindLog("Enabling user crash handling"));
-}
-
-TEST_F(UserCollectorTest, EnableNoPatternFileAccess) {
-  collector_.set_core_pattern_file("/does_not_exist");
-  ASSERT_FALSE(collector_.Enable());
-  ASSERT_EQ(s_crashes, 0);
-  EXPECT_TRUE(FindLog("Enabling user crash handling"));
-  EXPECT_TRUE(FindLog("Unable to write /does_not_exist"));
-}
-
-TEST_F(UserCollectorTest, EnableNoPipeLimitFileAccess) {
-  collector_.set_core_pipe_limit_file("/does_not_exist");
-  ASSERT_FALSE(collector_.Enable());
-  ASSERT_EQ(s_crashes, 0);
-  // Core pattern should not be written if we cannot access the pipe limit
-  // or otherwise we may set a pattern that results in infinite recursion.
-  ASSERT_FALSE(base::PathExists(FilePath("test/core_pattern")));
-  EXPECT_TRUE(FindLog("Enabling user crash handling"));
-  EXPECT_TRUE(FindLog("Unable to write /does_not_exist"));
-}
-
-TEST_F(UserCollectorTest, DisableOK) {
-  ASSERT_TRUE(collector_.Disable());
-  ExpectFileEquals("core", FilePath("test/core_pattern"));
-  ASSERT_EQ(s_crashes, 0);
-  EXPECT_TRUE(FindLog("Disabling user crash handling"));
-}
-
-TEST_F(UserCollectorTest, DisableNoFileAccess) {
-  collector_.set_core_pattern_file("/does_not_exist");
-  ASSERT_FALSE(collector_.Disable());
-  ASSERT_EQ(s_crashes, 0);
-  EXPECT_TRUE(FindLog("Disabling user crash handling"));
-  EXPECT_TRUE(FindLog("Unable to write /does_not_exist"));
-}
-
 TEST_F(UserCollectorTest, ParseCrashAttributes) {
   pid_t pid;
   int signal;
@@ -164,81 +119,20 @@
 
 TEST_F(UserCollectorTest, ShouldDumpDeveloperImageOverridesConsent) {
   std::string reason;
-  EXPECT_TRUE(collector_.ShouldDump(false, true, false,
-                                    "chrome-wm", &reason));
+  EXPECT_TRUE(collector_.ShouldDump(false, true, &reason));
   EXPECT_EQ("developer build - not testing - always dumping", reason);
 
   // When running a crash test, behave as normal.
-  EXPECT_FALSE(collector_.ShouldDump(false, false, false,
-                                    "chrome-wm", &reason));
+  EXPECT_FALSE(collector_.ShouldDump(false, false, &reason));
   EXPECT_EQ("ignoring - no consent", reason);
 }
 
-TEST_F(UserCollectorTest, ShouldDumpChromeOverridesDeveloperImage) {
-  std::string reason;
-  // When running a crash test, behave as normal.
-  EXPECT_FALSE(collector_.ShouldDump(false, false, false,
-                                     "chrome", &reason));
-  EXPECT_EQ(kChromeIgnoreMsg, reason);
-  EXPECT_FALSE(collector_.ShouldDump(false, false, false,
-                                     "supplied_Compositor", &reason));
-  EXPECT_EQ(kChromeIgnoreMsg, reason);
-  EXPECT_FALSE(collector_.ShouldDump(false, false, false,
-                                     "supplied_PipelineThread", &reason));
-  EXPECT_EQ(kChromeIgnoreMsg, reason);
-  EXPECT_FALSE(collector_.ShouldDump(false, false, false,
-                                     "Chrome_ChildIOThread", &reason));
-  EXPECT_EQ(kChromeIgnoreMsg, reason);
-  EXPECT_FALSE(collector_.ShouldDump(false, false, false,
-                                     "supplied_Chrome_ChildIOT", &reason));
-  EXPECT_EQ(kChromeIgnoreMsg, reason);
-  EXPECT_FALSE(collector_.ShouldDump(false, false, false,
-                                     "supplied_ChromotingClien", &reason));
-  EXPECT_EQ(kChromeIgnoreMsg, reason);
-  EXPECT_FALSE(collector_.ShouldDump(false, false, false,
-                                     "supplied_LocalInputMonit", &reason));
-  EXPECT_EQ(kChromeIgnoreMsg, reason);
-
-  // When running a developer image, test that chrome crashes are handled
-  // when the "handle_chrome_crashes" flag is set.
-  EXPECT_TRUE(collector_.ShouldDump(false, true, true,
-                                    "chrome", &reason));
-  EXPECT_EQ("developer build - not testing - always dumping",
-            reason);
-  EXPECT_TRUE(collector_.ShouldDump(false, true, true,
-                                    "supplied_Compositor", &reason));
-  EXPECT_EQ("developer build - not testing - always dumping",
-            reason);
-  EXPECT_TRUE(collector_.ShouldDump(false, true, true,
-                                    "supplied_PipelineThread", &reason));
-  EXPECT_EQ("developer build - not testing - always dumping",
-            reason);
-  EXPECT_TRUE(collector_.ShouldDump(false, true, true,
-                                    "Chrome_ChildIOThread", &reason));
-  EXPECT_EQ("developer build - not testing - always dumping",
-            reason);
-  EXPECT_TRUE(collector_.ShouldDump(false, true, true,
-                                    "supplied_Chrome_ChildIOT", &reason));
-  EXPECT_EQ("developer build - not testing - always dumping",
-            reason);
-  EXPECT_TRUE(collector_.ShouldDump(false, true, true,
-                                    "supplied_ChromotingClien", &reason));
-  EXPECT_EQ("developer build - not testing - always dumping",
-            reason);
-  EXPECT_TRUE(collector_.ShouldDump(false, true, true,
-                                    "supplied_LocalInputMonit", &reason));
-  EXPECT_EQ("developer build - not testing - always dumping",
-            reason);
-}
-
 TEST_F(UserCollectorTest, ShouldDumpUseConsentProductionImage) {
   std::string result;
-  EXPECT_FALSE(collector_.ShouldDump(false, false, false,
-                                     "chrome-wm", &result));
+  EXPECT_FALSE(collector_.ShouldDump(false, false, &result));
   EXPECT_EQ("ignoring - no consent", result);
 
-  EXPECT_TRUE(collector_.ShouldDump(true, false, false,
-                                    "chrome-wm", &result));
+  EXPECT_TRUE(collector_.ShouldDump(true, false, &result));
   EXPECT_EQ("handling", result);
 }
 
diff --git a/crash_reporter/warn_collector.l b/crash_reporter/warn_collector.l
index 691ef99..de746fe 100644
--- a/crash_reporter/warn_collector.l
+++ b/crash_reporter/warn_collector.l
@@ -11,6 +11,8 @@
  * shipment to the crash server.
  */
 
+%option noyywrap
+
 %{
 #include <fcntl.h>
 #include <inttypes.h>
@@ -122,6 +124,7 @@
   hash_bitmap[word_index] |= 1 << bit_index;
 }
 
+#pragma GCC diagnostic ignored "-Wwrite-strings"
 int WarnStart(void) {
   uint32_t hash;
   char *spacep;
@@ -140,7 +143,7 @@
   yyout = fopen(warn_dump_path, "w");
   if (yyout == NULL)
     Die("fopen %s failed: %s\n", warn_dump_path, strerror(errno));
-  spacep = index(yytext, ' ');
+  spacep = strchr(yytext, ' ');
   if (spacep == NULL || spacep[1] == '\0')
     spacep = "unknown-function";
   fprintf(yyout, "%08x-%s\n", hash, spacep + 1);
@@ -318,5 +321,4 @@
  */
 void UnusedFunctionWarningSuppressor(void) {
   yyunput(0, 0);
-  (void) input();
 }
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c
index af86fe9..b5064b4 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.c
@@ -157,12 +157,6 @@
     } else if (!strcmp(arg, "SIGFPE")) {
         raise(SIGFPE);
         return EXIT_SUCCESS;
-    } else if (!strcmp(arg, "SIGPIPE")) {
-        int pipe_fds[2];
-        pipe(pipe_fds);
-        close(pipe_fds[0]);
-        write(pipe_fds[1], "oops", 4);
-        return EXIT_SUCCESS;
     } else if (!strcmp(arg, "SIGTRAP")) {
         raise(SIGTRAP);
         return EXIT_SUCCESS;
@@ -189,7 +183,6 @@
     fprintf(stderr, "  LOG_ALWAYS_FATAL      call LOG_ALWAYS_FATAL\n");
     fprintf(stderr, "  LOG_ALWAYS_FATAL_IF   call LOG_ALWAYS_FATAL\n");
     fprintf(stderr, "  SIGFPE                cause a SIGFPE\n");
-    fprintf(stderr, "  SIGPIPE               cause a SIGPIPE\n");
     fprintf(stderr, "  SIGSEGV               cause a SIGSEGV at address 0x0 (synonym: crash)\n");
     fprintf(stderr, "  SIGSEGV-non-null      cause a SIGSEGV at a non-zero address\n");
     fprintf(stderr, "  SIGSEGV-unmapped      mmap/munmap a region of memory and then attempt to access it\n");
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 787b7aa..599995c 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -408,7 +408,6 @@
             case SIGBUS:
             case SIGFPE:
             case SIGILL:
-            case SIGPIPE:
             case SIGSEGV:
 #ifdef SIGSTKFLT
             case SIGSTKFLT:
diff --git a/debuggerd/test/tombstone_test.cpp b/debuggerd/test/tombstone_test.cpp
index a771a39..d945d27 100644
--- a/debuggerd/test/tombstone_test.cpp
+++ b/debuggerd/test/tombstone_test.cpp
@@ -76,7 +76,7 @@
     resetLogs();
     elf_set_fake_build_id("");
     siginfo_t si;
-    si.si_signo = SIGPIPE;
+    si.si_signo = SIGABRT;
     ptrace_set_fake_getsiginfo(si);
   }
 
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 114c7e4..e283923 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -81,7 +81,6 @@
     case SIGBUS: return "SIGBUS";
     case SIGFPE: return "SIGFPE";
     case SIGILL: return "SIGILL";
-    case SIGPIPE: return "SIGPIPE";
     case SIGSEGV: return "SIGSEGV";
 #if defined(SIGSTKFLT)
     case SIGSTKFLT: return "SIGSTKFLT";
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index b964a36..4dbf32f 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -189,25 +189,16 @@
     return load_fd(fd, _sz);
 }
 
-int match_fastboot_with_serial(usb_ifc_info *info, const char *local_serial)
-{
-    if(!(vendor_id && (info->dev_vendor == vendor_id)) &&
-       (info->dev_vendor != 0x18d1) &&  // Google
-       (info->dev_vendor != 0x8087) &&  // Intel
-       (info->dev_vendor != 0x0451) &&
-       (info->dev_vendor != 0x0502) &&
-       (info->dev_vendor != 0x0fce) &&  // Sony Ericsson
-       (info->dev_vendor != 0x05c6) &&  // Qualcomm
-       (info->dev_vendor != 0x22b8) &&  // Motorola
-       (info->dev_vendor != 0x0955) &&  // Nvidia
-       (info->dev_vendor != 0x413c) &&  // DELL
-       (info->dev_vendor != 0x2314) &&  // INQ Mobile
-       (info->dev_vendor != 0x0b05) &&  // Asus
-       (info->dev_vendor != 0x0bb4))    // HTC
-            return -1;
-    if(info->ifc_class != 0xff) return -1;
-    if(info->ifc_subclass != 0x42) return -1;
-    if(info->ifc_protocol != 0x03) return -1;
+int match_fastboot_with_serial(usb_ifc_info* info, const char* local_serial) {
+    // Require a matching vendor id if the user specified one with -i.
+    if (vendor_id != 0 && info->dev_vendor != vendor_id) {
+        return -1;
+    }
+
+    if (info->ifc_class != 0xff || info->ifc_subclass != 0x42 || info->ifc_protocol != 0x03) {
+        return -1;
+    }
+
     // require matching serial number or device path if requested
     // at the command line with the -s option.
     if (local_serial && (strcmp(local_serial, info->serial_number) != 0 &&
@@ -255,7 +246,7 @@
         if(usb) return usb;
         if(announce) {
             announce = 0;
-            fprintf(stderr,"< waiting for device >\n");
+            fprintf(stderr, "< waiting for %s >\n", serial ? serial : "any device");
         }
         usleep(1000);
     }
diff --git a/fastboot/usb_osx.cpp b/fastboot/usb_osx.cpp
index a959566..45ae833 100644
--- a/fastboot/usb_osx.cpp
+++ b/fastboot/usb_osx.cpp
@@ -75,7 +75,6 @@
     HRESULT result;
     SInt32 score;
     UInt8 interfaceNumEndpoints;
-    UInt8 endpoint;
     UInt8 configuration;
 
     // Placing the constant KIOUSBFindInterfaceDontCare into the following
@@ -182,7 +181,7 @@
 
         // Iterate over the endpoints for this interface and see if there
         // are any that do bulk in/out.
-        for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) {
+        for (UInt8 endpoint = 1; endpoint <= interfaceNumEndpoints; endpoint++) {
             UInt8   transferType;
             UInt16  maxPacketSize;
             UInt8   interval;
@@ -210,7 +209,7 @@
                     handle->zero_mask = maxPacketSize - 1;
                 }
             } else {
-                ERR("could not get pipe properties\n");
+                ERR("could not get pipe properties for endpoint %u (%08x)\n", endpoint, kr);
             }
 
             if (handle->info.has_bulk_in && handle->info.has_bulk_out) {
@@ -294,6 +293,13 @@
 
     // So, we have a device, finally. Grab its vitals.
 
+
+    kr = (*dev)->USBDeviceOpen(dev);
+    if (kr != 0) {
+        WARN("USBDeviceOpen");
+        goto out;
+    }
+
     kr = (*dev)->GetDeviceVendor(dev, &handle->info.dev_vendor);
     if (kr != 0) {
         ERR("GetDeviceVendor");
@@ -366,12 +372,16 @@
         goto error;
     }
 
+    out:
+
+    (*dev)->USBDeviceClose(dev);
     (*dev)->Release(dev);
     return 0;
 
     error:
 
     if (dev != NULL) {
+        (*dev)->USBDeviceClose(dev);
         (*dev)->Release(dev);
     }
 
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index f467f81..044c895 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -151,8 +151,8 @@
             INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
 
             ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
-                                        &status, true, LOG_KLOG | LOG_FILE,
-                                        true, FSCK_LOG_FILE);
+                                          &status, true, LOG_KLOG | LOG_FILE,
+                                          true, FSCK_LOG_FILE, NULL, 0);
 
             if (ret < 0) {
                 /* No need to check for error in fork, we can't really handle it now */
@@ -169,7 +169,7 @@
 
         ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv,
                                       &status, true, LOG_KLOG | LOG_FILE,
-                                      true, FSCK_LOG_FILE);
+                                      true, FSCK_LOG_FILE, NULL, 0);
         if (ret < 0) {
             /* No need to check for error in fork, we can't really handle it now */
             ERROR("Failed trying to run %s\n", F2FS_FSCK_BIN);
@@ -524,6 +524,14 @@
             continue;
         }
 
+        /* Skip mounting the root partition, as it will already have been mounted */
+        if (!strcmp(fstab->recs[i].mount_point, "/")) {
+            if ((fstab->recs[i].fs_mgr_flags & MS_RDONLY) != 0) {
+                fs_mgr_set_blk_ro(fstab->recs[i].blk_device);
+            }
+            continue;
+        }
+
         /* Translate LABEL= file system labels into block devices */
         if (!strcmp(fstab->recs[i].fs_type, "ext2") ||
             !strcmp(fstab->recs[i].fs_type, "ext3") ||
@@ -787,7 +795,8 @@
         /* Initialize the swap area */
         mkswap_argv[1] = fstab->recs[i].blk_device;
         err = android_fork_execvp_ext(ARRAY_SIZE(mkswap_argv), mkswap_argv,
-                                      &status, true, LOG_KLOG, false, NULL);
+                                      &status, true, LOG_KLOG, false, NULL,
+                                      NULL, 0);
         if (err) {
             ERROR("mkswap failed for %s\n", fstab->recs[i].blk_device);
             ret = -1;
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 7ea8250..ed773d0 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -24,11 +24,13 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/types.h>
 #include <unistd.h>
+
 #include <batteryservice/BatteryService.h>
 #include <cutils/klog.h>
 #include <cutils/properties.h>
-#include <sys/types.h>
+#include <log/log_read.h>
 #include <utils/Errors.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
@@ -265,10 +267,32 @@
                  "battery none");
         }
 
-        KLOG_WARNING(LOG_TAG, "%s chg=%s%s%s\n", dmesgline,
-                     props.chargerAcOnline ? "a" : "",
-                     props.chargerUsbOnline ? "u" : "",
-                     props.chargerWirelessOnline ? "w" : "");
+        size_t len = strlen(dmesgline);
+        snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
+                 props.chargerAcOnline ? "a" : "",
+                 props.chargerUsbOnline ? "u" : "",
+                 props.chargerWirelessOnline ? "w" : "");
+
+        log_time realtime(CLOCK_REALTIME);
+        time_t t = realtime.tv_sec;
+        struct tm *tmp = gmtime(&t);
+        if (tmp) {
+            static const char fmt[] = " %Y-%m-%d %H:%M:%S.XXXXXXXXX UTC";
+            len = strlen(dmesgline);
+            if ((len < (sizeof(dmesgline) - sizeof(fmt) - 8)) // margin
+                    && strftime(dmesgline + len, sizeof(dmesgline) - len,
+                                fmt, tmp)) {
+                char *usec = strchr(dmesgline + len, 'X');
+                if (usec) {
+                    len = usec - dmesgline;
+                    snprintf(dmesgline + len, sizeof(dmesgline) - len,
+                             "%09u", realtime.tv_nsec);
+                    usec[9] = ' ';
+                }
+            }
+        }
+
+        KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);
     }
 
     healthd_mode_ops->battery_update(&props);
diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h
index 07d1351..2d3c743 100644
--- a/include/cutils/sockets.h
+++ b/include/cutils/sockets.h
@@ -23,7 +23,7 @@
 #include <string.h>
 #include <stdbool.h>
 
-#ifdef HAVE_WINSOCK
+#if defined(_WIN32)
 #include <winsock2.h>
 typedef int  socklen_t;
 #else
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index e4ed179..6d9b3bc 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -67,7 +67,8 @@
 #define ATRACE_TAG_RS               (1<<15)
 #define ATRACE_TAG_BIONIC           (1<<16)
 #define ATRACE_TAG_POWER            (1<<17)
-#define ATRACE_TAG_LAST             ATRACE_TAG_POWER
+#define ATRACE_TAG_PACKAGE_MANAGER  (1<<18)
+#define ATRACE_TAG_LAST             ATRACE_TAG_PACKAGE_MANAGER
 
 // Reserved for initialization.
 #define ATRACE_TAG_NOT_READY        (1LL<<63)
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 0c071ca..7047e0f 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -26,7 +26,7 @@
 #include <sys/types.h>
 #include <stdint.h>
 
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
 #include <linux/capability.h>
 #else
 #include "android_filesystem_capability.h"
@@ -99,6 +99,10 @@
 #define AID_NET_BW_ACCT   3007  /* change bandwidth statistics accounting */
 #define AID_NET_BT_STACK  3008  /* bluetooth: access config files */
 
+/* The range 5000-5999 is also reserved for OEM, and must never be used here. */
+#define AID_OEM_RESERVED_2_START 5000
+#define AID_OEM_RESERVED_2_END   5999
+
 #define AID_EVERYBODY     9997  /* shared between all apps in the same profile */
 #define AID_MISC          9998  /* access to misc storage */
 #define AID_NOBODY        9999
diff --git a/include/utils/AndroidThreads.h b/include/utils/AndroidThreads.h
index aad1e82..4c2dd49 100644
--- a/include/utils/AndroidThreads.h
+++ b/include/utils/AndroidThreads.h
@@ -73,7 +73,7 @@
 // ------------------------------------------------------------------
 // Extra functions working with raw pids.
 
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
 // Change the priority AND scheduling group of a particular thread.  The priority
 // should be one of the ANDROID_PRIORITY constants.  Returns INVALID_OPERATION
 // if the priority set failed, else another value if just the group set failed;
diff --git a/include/utils/ByteOrder.h b/include/utils/ByteOrder.h
index baa3a83..44ea13d 100644
--- a/include/utils/ByteOrder.h
+++ b/include/utils/ByteOrder.h
@@ -21,7 +21,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
-#ifdef HAVE_WINSOCK
+#if defined(_WIN32)
 #include <winsock2.h>
 #else
 #include <netinet/in.h>
diff --git a/include/utils/Errors.h b/include/utils/Errors.h
index 46173db..08ddcd2 100644
--- a/include/utils/Errors.h
+++ b/include/utils/Errors.h
@@ -23,7 +23,7 @@
 namespace android {
 
 // use this type to return error codes
-#ifdef HAVE_MS_C_RUNTIME
+#ifdef _WIN32
 typedef int         status_t;
 #else
 typedef int32_t     status_t;
@@ -58,8 +58,7 @@
     ALREADY_EXISTS      = -EEXIST,
     DEAD_OBJECT         = -EPIPE,
     FAILED_TRANSACTION  = (UNKNOWN_ERROR + 2),
-    JPARKS_BROKE_IT     = -EPIPE,
-#if !defined(HAVE_MS_C_RUNTIME)
+#if !defined(_WIN32)
     BAD_INDEX           = -EOVERFLOW,
     NOT_ENOUGH_DATA     = -ENODATA,
     WOULD_BLOCK         = -EWOULDBLOCK, 
diff --git a/include/utils/FileMap.h b/include/utils/FileMap.h
index f70fc92..afd7bfd 100644
--- a/include/utils/FileMap.h
+++ b/include/utils/FileMap.h
@@ -26,7 +26,7 @@
 
 #if defined(__MINGW32__)
 // Ensure that we always pull in winsock2.h before windows.h
-#ifdef HAVE_WINSOCK
+#if defined(_WIN32)
 #include <winsock2.h>
 #endif
 #include <windows.h>
diff --git a/include/utils/Mutex.h b/include/utils/Mutex.h
index 757519b..f027c79 100644
--- a/include/utils/Mutex.h
+++ b/include/utils/Mutex.h
@@ -59,7 +59,7 @@
     // lock if possible; returns 0 on success, error otherwise
     status_t    tryLock();
 
-#if HAVE_ANDROID_OS
+#if defined(__ANDROID__)
     // lock the mutex, but don't wait longer than timeoutMilliseconds.
     // Returns 0 on success, TIMED_OUT for failure due to timeout expiration.
     //
@@ -128,7 +128,7 @@
 inline status_t Mutex::tryLock() {
     return -pthread_mutex_trylock(&mMutex);
 }
-#if HAVE_ANDROID_OS
+#if defined(__ANDROID__)
 inline status_t Mutex::timedLock(nsecs_t timeoutNs) {
     const struct timespec ts = {
         /* .tv_sec = */ static_cast<time_t>(timeoutNs / 1000000000),
diff --git a/include/utils/Thread.h b/include/utils/Thread.h
index 28839fd..1532b7e 100644
--- a/include/utils/Thread.h
+++ b/include/utils/Thread.h
@@ -70,7 +70,7 @@
     // Indicates whether this thread is running or not.
             bool        isRunning() const;
 
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
     // Return the thread's kernel ID, same as the thread itself calling gettid(),
     // or -1 if the thread is not running.
             pid_t       getTid() const;
@@ -101,7 +101,7 @@
     volatile bool           mExitPending;
     volatile bool           mRunning;
             sp<Thread>      mHoldSelf;
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
     // legacy for debugging, not used by getTid() as it is set by the child thread
     // and so is not initialized until the child reaches that point
             pid_t           mTid;
diff --git a/include/utils/Trace.h b/include/utils/Trace.h
index 6ee343d..6ba68f6 100644
--- a/include/utils/Trace.h
+++ b/include/utils/Trace.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_TRACE_H
 #define ANDROID_TRACE_H
 
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
 
 #include <fcntl.h>
 #include <stdint.h>
@@ -59,11 +59,11 @@
 
 }; // namespace android
 
-#else // HAVE_ANDROID_OS
+#else // !__ANDROID__
 
 #define ATRACE_NAME(...)
 #define ATRACE_CALL()
 
-#endif // HAVE_ANDROID_OS
+#endif // __ANDROID__
 
 #endif // ANDROID_TRACE_H
diff --git a/init/Android.mk b/init/Android.mk
index 45b002d..58bff58 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -20,16 +20,40 @@
 
 # --
 
+# If building on Linux, then build unit test for the host.
+ifeq ($(HOST_OS),linux)
 include $(CLEAR_VARS)
 LOCAL_CPPFLAGS := $(init_cflags)
 LOCAL_SRC_FILES:= \
+    parser/tokenizer.cpp \
+
+LOCAL_MODULE := libinit_parser
+LOCAL_CLANG := true
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := init_parser_tests
+LOCAL_SRC_FILES := \
+    parser/tokenizer_test.cpp \
+
+LOCAL_STATIC_LIBRARIES := libinit_parser
+LOCAL_CLANG := true
+include $(BUILD_HOST_NATIVE_TEST)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_CPPFLAGS := $(init_cflags)
+LOCAL_SRC_FILES:= \
+    action.cpp \
     init_parser.cpp \
     log.cpp \
     parser.cpp \
+    service.cpp \
     util.cpp \
 
 LOCAL_STATIC_LIBRARIES := libbase
 LOCAL_MODULE := libinit
+LOCAL_SANITIZE := integer
 LOCAL_CLANG := true
 include $(BUILD_STATIC_LIBRARY)
 
@@ -77,6 +101,7 @@
     ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
     ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd
 
+LOCAL_SANITIZE := integer
 LOCAL_CLANG := true
 include $(BUILD_EXECUTABLE)
 
@@ -94,5 +119,6 @@
     libbase \
 
 LOCAL_STATIC_LIBRARIES := libinit
+LOCAL_SANITIZE := integer
 LOCAL_CLANG := true
 include $(BUILD_NATIVE_TEST)
diff --git a/init/action.cpp b/init/action.cpp
new file mode 100644
index 0000000..2eb809e
--- /dev/null
+++ b/init/action.cpp
@@ -0,0 +1,378 @@
+/*
+ * 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 "action.h"
+
+#include <errno.h>
+
+#include <base/strings.h>
+#include <base/stringprintf.h>
+
+#include "error.h"
+#include "init_parser.h"
+#include "log.h"
+#include "property_service.h"
+#include "util.h"
+
+class Action::Command
+{
+public:
+    Command(int (*f)(const std::vector<std::string>& args),
+            const std::vector<std::string>& args,
+            const std::string& filename,
+            int line);
+
+    int InvokeFunc() const;
+    std::string BuildCommandString() const;
+    std::string BuildSourceString() const;
+
+private:
+    int (*func_)(const std::vector<std::string>& args);
+    const std::vector<std::string> args_;
+    const std::string filename_;
+    int line_;
+};
+
+Action::Command::Command(int (*f)(const std::vector<std::string>& args),
+                         const std::vector<std::string>& args,
+                         const std::string& filename,
+                         int line) :
+    func_(f), args_(args), filename_(filename), line_(line)
+{
+}
+
+int Action::Command::InvokeFunc() const
+{
+    std::vector<std::string> expanded_args;
+    expanded_args.resize(args_.size());
+    expanded_args[0] = args_[0];
+    for (std::size_t i = 1; i < args_.size(); ++i) {
+        if (expand_props(args_[i], &expanded_args[i]) == -1) {
+            ERROR("%s: cannot expand '%s'\n", args_[0].c_str(), args_[i].c_str());
+            return -EINVAL;
+        }
+    }
+
+    return func_(expanded_args);
+}
+
+std::string Action::Command::BuildCommandString() const
+{
+    return android::base::Join(args_, ' ');
+}
+
+std::string Action::Command::BuildSourceString() const
+{
+    if (!filename_.empty()) {
+        return android::base::StringPrintf(" (%s:%d)", filename_.c_str(), line_);
+    } else {
+        return std::string();
+    }
+}
+
+Action::Action()
+{
+}
+
+void Action::AddCommand(int (*f)(const std::vector<std::string>& args),
+                        const std::vector<std::string>& args,
+                        const std::string& filename, int line)
+{
+    Action::Command* cmd = new Action::Command(f, args, filename, line);
+    commands_.push_back(cmd);
+}
+
+std::size_t Action::NumCommands() const
+{
+    return commands_.size();
+}
+
+void Action::ExecuteOneCommand(std::size_t command) const
+{
+    ExecuteCommand(*commands_[command]);
+}
+
+void Action::ExecuteAllCommands() const
+{
+    for (const auto& c : commands_) {
+        ExecuteCommand(*c);
+    }
+}
+
+void Action::ExecuteCommand(const Command& command) const
+{
+    Timer t;
+    int result = command.InvokeFunc();
+
+    if (klog_get_level() >= KLOG_INFO_LEVEL) {
+        std::string trigger_name = BuildTriggersString();
+        std::string cmd_str = command.BuildCommandString();
+        std::string source = command.BuildSourceString();
+
+        INFO("Command '%s' action=%s%s returned %d took %.2fs\n",
+             cmd_str.c_str(), trigger_name.c_str(), source.c_str(),
+             result, t.duration());
+    }
+}
+
+bool Action::ParsePropertyTrigger(const std::string& trigger, std::string* err)
+{
+    const static std::string prop_str("property:");
+    std::string prop_name(trigger.substr(prop_str.length()));
+    size_t equal_pos = prop_name.find('=');
+    if (equal_pos == std::string::npos) {
+        *err = "property trigger found without matching '='";
+        return false;
+    }
+
+    std::string prop_value(prop_name.substr(equal_pos + 1));
+    prop_name.erase(equal_pos);
+
+    auto res = property_triggers_.emplace(prop_name, prop_value);
+    if (res.second == false) {
+        *err = "multiple property triggers found for same property";
+        return false;
+    }
+    return true;
+}
+
+bool Action::InitTriggers(const std::vector<std::string>& args, std::string* err)
+{
+    const static std::string prop_str("property:");
+    for (std::size_t i = 0; i < args.size(); ++i) {
+        if (i % 2) {
+            if (args[i].compare("&&")) {
+                *err = "&& is the only symbol allowed to concatenate actions";
+                return false;
+            } else {
+                continue;
+            }
+        }
+
+        if (!args[i].compare(0, prop_str.length(), prop_str)) {
+            if (!ParsePropertyTrigger(args[i], err)) {
+                return false;
+            }
+        } else {
+            if (!event_trigger_.empty()) {
+                *err = "multiple event triggers are not allowed";
+                return false;
+            }
+
+            event_trigger_ = args[i];
+        }
+    }
+
+    return true;
+}
+
+bool Action::InitSingleTrigger(const std::string& trigger)
+{
+    std::vector<std::string> name_vector{trigger};
+    std::string err;
+    return InitTriggers(name_vector, &err);
+}
+
+bool Action::CheckPropertyTriggers(const std::string& name,
+                                   const std::string& value) const
+{
+    bool found = !name.compare("");
+    if (property_triggers_.empty()) {
+        return true;
+    }
+
+    for (const auto& t : property_triggers_) {
+        if (!t.first.compare(name)) {
+            if (t.second.compare("*") &&
+                t.second.compare(value)) {
+                return false;
+            } else {
+                found = true;
+            }
+        } else {
+            std::string prop_val = property_get(t.first.c_str());
+            if (prop_val.empty() ||
+                (t.second.compare("*") &&
+                 t.second.compare(prop_val))) {
+                return false;
+            }
+        }
+    }
+    return found;
+}
+
+bool Action::CheckEventTrigger(const std::string& trigger) const
+{
+    return !event_trigger_.empty() &&
+        !trigger.compare(event_trigger_) &&
+        CheckPropertyTriggers();
+}
+
+bool Action::CheckPropertyTrigger(const std::string& name,
+                                  const std::string& value) const
+{
+    return event_trigger_.empty() && CheckPropertyTriggers(name, value);
+}
+
+bool Action::TriggersEqual(const class Action& other) const
+{
+    return property_triggers_.size() == other.property_triggers_.size() &&
+        std::equal(property_triggers_.begin(), property_triggers_.end(),
+                   other.property_triggers_.begin()) &&
+        !event_trigger_.compare(other.event_trigger_);
+}
+
+std::string Action::BuildTriggersString() const
+{
+    std::string result;
+
+    for (const auto& t : property_triggers_) {
+        result += t.first;
+        result += '=';
+        result += t.second;
+        result += ' ';
+    }
+    if (!event_trigger_.empty()) {
+        result += event_trigger_;
+        result += ' ';
+    }
+    result.pop_back();
+    return result;
+}
+
+void Action::DumpState() const
+{
+    INFO("on ");
+    std::string trigger_name = BuildTriggersString();
+    INFO("%s", trigger_name.c_str());
+    INFO("\n");
+
+    for (const auto& c : commands_) {
+        std::string cmd_str = c->BuildCommandString();
+        INFO(" %s", cmd_str.c_str());
+    }
+    INFO("\n");
+}
+
+ActionManager::ActionManager() : cur_command_(0)
+{
+}
+
+ActionManager& ActionManager::GetInstance() {
+    static ActionManager instance;
+    return instance;
+}
+
+void ActionManager::QueueEventTrigger(const std::string& trigger)
+{
+    for (const auto& a : action_list_) {
+        if (a->CheckEventTrigger(trigger)) {
+            action_queue_.push(a);
+        }
+    }
+}
+
+void ActionManager::QueuePropertyTrigger(const std::string& name,
+                                         const std::string& value)
+{
+    for (const auto& a : action_list_) {
+        if (a->CheckPropertyTrigger(name, value)) {
+            action_queue_.push(a);
+        }
+    }
+}
+
+void ActionManager::QueueAllPropertyTriggers()
+{
+    QueuePropertyTrigger("", "");
+}
+
+void ActionManager::QueueBuiltinAction(int (*func)(const std::vector<std::string>& args),
+                                       const std::string& name)
+{
+    Action* act = new Action();
+    std::vector<std::string> name_vector{name};
+
+    if (!act->InitSingleTrigger(name)) {
+        return;
+    }
+
+    act->AddCommand(func, name_vector);
+
+    action_queue_.push(act);
+}
+
+void ActionManager::ExecuteOneCommand() {
+    if (action_queue_.empty()) {
+        return;
+    }
+
+    Action* action = action_queue_.front();
+    if (!action->NumCommands()) {
+        action_queue_.pop();
+        return;
+    }
+
+    if (cur_command_ == 0) {
+        std::string trigger_name = action->BuildTriggersString();
+        INFO("processing action %p (%s)\n", action, trigger_name.c_str());
+    }
+
+    action->ExecuteOneCommand(cur_command_++);
+    if (cur_command_ == action->NumCommands()) {
+        cur_command_ = 0;
+        action_queue_.pop();
+    }
+}
+
+bool ActionManager::HasMoreCommands() const
+{
+    return !action_queue_.empty();
+}
+
+Action* ActionManager::AddNewAction(const std::vector<std::string>& triggers,
+                                    std::string* err)
+{
+    if (triggers.size() < 1) {
+        *err = "actions must have a trigger\n";
+        return nullptr;
+    }
+
+    Action* act = new Action();
+    if (!act->InitTriggers(triggers, err)) {
+        return nullptr;
+    }
+
+    auto old_act_it =
+        std::find_if(action_list_.begin(), action_list_.end(),
+                     [&act] (Action* a) { return act->TriggersEqual(*a); });
+
+    if (old_act_it != action_list_.end()) {
+        delete act;
+        return *old_act_it;
+    }
+
+    action_list_.push_back(act);
+    return act;
+}
+
+void ActionManager::DumpState() const
+{
+    for (const auto& a : action_list_) {
+        a->DumpState();
+    }
+    INFO("\n");
+}
diff --git a/init/action.h b/init/action.h
new file mode 100644
index 0000000..ae28fe1
--- /dev/null
+++ b/init/action.h
@@ -0,0 +1,82 @@
+/*
+ * 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 _INIT_ACTION_H
+#define _INIT_ACTION_H
+
+#include <map>
+#include <queue>
+#include <string>
+#include <vector>
+
+class Action {
+public:
+    Action();
+
+    void AddCommand(int (*f)(const std::vector<std::string>& args),
+                    const std::vector<std::string>& args,
+                    const std::string& filename = "", int line = 0);
+    bool InitTriggers(const std::vector<std::string>& args, std::string* err);
+    bool InitSingleTrigger(const std::string& trigger);
+    std::size_t NumCommands() const;
+    void ExecuteOneCommand(std::size_t command) const;
+    void ExecuteAllCommands() const;
+    bool CheckEventTrigger(const std::string& trigger) const;
+    bool CheckPropertyTrigger(const std::string& name,
+                              const std::string& value) const;
+    bool TriggersEqual(const class Action& other) const;
+    std::string BuildTriggersString() const;
+    void DumpState() const;
+
+private:
+    class Command;
+
+    void ExecuteCommand(const Command& command) const;
+    bool CheckPropertyTriggers(const std::string& name = "",
+                               const std::string& value = "") const;
+    bool ParsePropertyTrigger(const std::string& trigger, std::string* err);
+
+    std::map<std::string, std::string> property_triggers_;
+    std::string event_trigger_;
+    std::vector<Command*> commands_;
+};
+
+class ActionManager {
+public:
+    static ActionManager& GetInstance();
+    void QueueEventTrigger(const std::string& trigger);
+    void QueuePropertyTrigger(const std::string& name, const std::string& value);
+    void QueueAllPropertyTriggers();
+    void QueueBuiltinAction(int (*func)(const std::vector<std::string>& args),
+                            const std::string& name);
+    void ExecuteOneCommand();
+    bool HasMoreCommands() const;
+    Action* AddNewAction(const std::vector<std::string>& triggers,
+                         std::string* err);
+    void DumpState() const;
+
+private:
+    ActionManager();
+
+    ActionManager(ActionManager const&) = delete;
+    void operator=(ActionManager const&) = delete;
+
+    std::vector<Action*> action_list_;
+    std::queue<Action*> action_queue_;
+    std::size_t cur_command_;
+};
+
+#endif
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index e5b153a..efaee1c 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -203,7 +203,7 @@
     return count;
 }
 
-int do_bootchart_init(int nargs, char** args) {
+int do_bootchart_init(const std::vector<std::string>& args) {
     g_remaining_samples = bootchart_init();
     if (g_remaining_samples < 0) {
         ERROR("Bootcharting init failure: %s\n", strerror(errno));
diff --git a/init/builtins.cpp b/init/builtins.cpp
index d05f046..e663501 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -43,24 +43,24 @@
 #include <logwrap/logwrap.h>
 #include <private/android_filesystem_config.h>
 
-#include "init.h"
-#include "keywords.h"
-#include "property_service.h"
+#include "action.h"
 #include "devices.h"
+#include "init.h"
 #include "init_parser.h"
-#include "util.h"
+#include "keywords.h"
 #include "log.h"
+#include "property_service.h"
+#include "service.h"
+#include "util.h"
 
 #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
 #define UNMOUNT_CHECK_MS 5000
 #define UNMOUNT_CHECK_TIMES 10
 
-int add_environment(const char *name, const char *value);
-
 // System call provided by bionic but not in any header file.
 extern "C" int init_module(void *, unsigned long, const char *);
 
-static int insmod(const char *filename, char *options)
+static int insmod(const char *filename, const char *options)
 {
     std::string module;
     if (!read_file(filename, &module)) {
@@ -99,15 +99,6 @@
     return ret;
 }
 
-static void service_start_if_not_disabled(struct service *svc)
-{
-    if (!(svc->flags & SVC_DISABLED)) {
-        service_start(svc, NULL);
-    } else {
-        svc->flags |= SVC_DISABLED_START;
-    }
-}
-
 static void unmount_and_fsck(const struct mntent *entry)
 {
     if (strcmp(entry->mnt_type, "f2fs") && strcmp(entry->mnt_type, "ext4"))
@@ -130,7 +121,7 @@
      * automatically restart after kill(), but that is not really a problem
      * because |entry->mnt_dir| is no longer visible to such new processes.
      */
-    service_for_each(service_stop);
+    ServiceManager::GetInstance().ForEachService([] (Service* s) { s->Stop(); });
     TEMP_FAILURE_RETRY(kill(-1, SIGKILL));
 
     int count = 0;
@@ -159,155 +150,139 @@
             "/system/bin/fsck.f2fs", "-f", entry->mnt_fsname,
         };
         android_fork_execvp_ext(ARRAY_SIZE(f2fs_argv), (char **)f2fs_argv,
-                                &st, true, LOG_KLOG, true, NULL);
+                                &st, true, LOG_KLOG, true, NULL, NULL, 0);
     } else if (!strcmp(entry->mnt_type, "ext4")) {
         const char *ext4_argv[] = {
             "/system/bin/e2fsck", "-f", "-y", entry->mnt_fsname,
         };
         android_fork_execvp_ext(ARRAY_SIZE(ext4_argv), (char **)ext4_argv,
-                                &st, true, LOG_KLOG, true, NULL);
+                                &st, true, LOG_KLOG, true, NULL, NULL, 0);
     }
 }
 
-int do_class_start(int nargs, char **args)
+int do_class_start(const std::vector<std::string>& args)
 {
         /* Starting a class does not start services
          * which are explicitly disabled.  They must
          * be started individually.
          */
-    service_for_each_class(args[1], service_start_if_not_disabled);
+    ServiceManager::GetInstance().
+        ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
     return 0;
 }
 
-int do_class_stop(int nargs, char **args)
+int do_class_stop(const std::vector<std::string>& args)
 {
-    service_for_each_class(args[1], service_stop);
+    ServiceManager::GetInstance().
+        ForEachServiceInClass(args[1], [] (Service* s) { s->Stop(); });
     return 0;
 }
 
-int do_class_reset(int nargs, char **args)
+int do_class_reset(const std::vector<std::string>& args)
 {
-    service_for_each_class(args[1], service_reset);
+    ServiceManager::GetInstance().
+        ForEachServiceInClass(args[1], [] (Service* s) { s->Reset(); });
     return 0;
 }
 
-int do_domainname(int nargs, char **args)
+int do_domainname(const std::vector<std::string>& args)
 {
-    return write_file("/proc/sys/kernel/domainname", args[1]);
+    return write_file("/proc/sys/kernel/domainname", args[1].c_str());
 }
 
-int do_enable(int nargs, char **args)
+int do_enable(const std::vector<std::string>& args)
 {
-    struct service *svc;
-    svc = service_find_by_name(args[1]);
-    if (svc) {
-        svc->flags &= ~(SVC_DISABLED | SVC_RC_DISABLED);
-        if (svc->flags & SVC_DISABLED_START) {
-            service_start(svc, NULL);
-        }
-    } else {
+    Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
+    if (!svc) {
         return -1;
     }
-    return 0;
+    return svc->Enable();
 }
 
-int do_exec(int nargs, char** args) {
-    service* svc = make_exec_oneshot_service(nargs, args);
-    if (svc == NULL) {
+int do_exec(const std::vector<std::string>& args) {
+    Service* svc = ServiceManager::GetInstance().MakeExecOneshotService(args);
+    if (!svc) {
         return -1;
     }
-    service_start(svc, NULL);
+    if (!svc->Start()) {
+        return -1;
+    }
+    waiting_for_exec = true;
     return 0;
 }
 
-int do_export(int nargs, char **args)
+int do_export(const std::vector<std::string>& args)
 {
-    return add_environment(args[1], args[2]);
+    return add_environment(args[1].c_str(), args[2].c_str());
 }
 
-int do_hostname(int nargs, char **args)
+int do_hostname(const std::vector<std::string>& args)
 {
-    return write_file("/proc/sys/kernel/hostname", args[1]);
+    return write_file("/proc/sys/kernel/hostname", args[1].c_str());
 }
 
-int do_ifup(int nargs, char **args)
+int do_ifup(const std::vector<std::string>& args)
 {
-    return __ifupdown(args[1], 1);
+    return __ifupdown(args[1].c_str(), 1);
 }
 
-
-static int do_insmod_inner(int nargs, char **args, int opt_len)
+int do_insmod(const std::vector<std::string>& args)
 {
-    char options[opt_len + 1];
-    int i;
+    std::string options;
 
-    options[0] = '\0';
-    if (nargs > 2) {
-        strcpy(options, args[2]);
-        for (i = 3; i < nargs; ++i) {
-            strcat(options, " ");
-            strcat(options, args[i]);
+    if (args.size() > 2) {
+        options += args[2];
+        for (std::size_t i = 3; i < args.size(); ++i) {
+            options += ' ';
+            options += args[i];
         }
     }
 
-    return insmod(args[1], options);
+    return insmod(args[1].c_str(), options.c_str());
 }
 
-int do_insmod(int nargs, char **args)
-{
-    int i;
-    int size = 0;
-
-    if (nargs > 2) {
-        for (i = 2; i < nargs; ++i)
-            size += strlen(args[i]) + 1;
-    }
-
-    return do_insmod_inner(nargs, args, size);
-}
-
-int do_mkdir(int nargs, char **args)
+int do_mkdir(const std::vector<std::string>& args)
 {
     mode_t mode = 0755;
     int ret;
 
     /* mkdir <path> [mode] [owner] [group] */
 
-    if (nargs >= 3) {
-        mode = strtoul(args[2], 0, 8);
+    if (args.size() >= 3) {
+        mode = std::stoul(args[2], 0, 8);
     }
 
-    ret = make_dir(args[1], mode);
+    ret = make_dir(args[1].c_str(), mode);
     /* chmod in case the directory already exists */
     if (ret == -1 && errno == EEXIST) {
-        ret = fchmodat(AT_FDCWD, args[1], mode, AT_SYMLINK_NOFOLLOW);
+        ret = fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW);
     }
     if (ret == -1) {
         return -errno;
     }
 
-    if (nargs >= 4) {
-        uid_t uid = decode_uid(args[3]);
+    if (args.size() >= 4) {
+        uid_t uid = decode_uid(args[3].c_str());
         gid_t gid = -1;
 
-        if (nargs == 5) {
-            gid = decode_uid(args[4]);
+        if (args.size() == 5) {
+            gid = decode_uid(args[4].c_str());
         }
 
-        if (lchown(args[1], uid, gid) == -1) {
+        if (lchown(args[1].c_str(), uid, gid) == -1) {
             return -errno;
         }
 
         /* chown may have cleared S_ISUID and S_ISGID, chmod again */
         if (mode & (S_ISUID | S_ISGID)) {
-            ret = fchmodat(AT_FDCWD, args[1], mode, AT_SYMLINK_NOFOLLOW);
+            ret = fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW);
             if (ret == -1) {
                 return -errno;
             }
         }
     }
 
-    return e4crypt_set_directory_policy(args[1]);
+    return e4crypt_set_directory_policy(args[1].c_str());
 }
 
 static struct {
@@ -335,35 +310,36 @@
 #define DATA_MNT_POINT "/data"
 
 /* mount <type> <device> <path> <flags ...> <options> */
-int do_mount(int nargs, char **args)
+int do_mount(const std::vector<std::string>& args)
 {
     char tmp[64];
-    char *source, *target, *system;
-    char *options = NULL;
+    const char *source, *target, *system;
+    const char *options = NULL;
     unsigned flags = 0;
+    std::size_t na = 0;
     int n, i;
     int wait = 0;
 
-    for (n = 4; n < nargs; n++) {
+    for (na = 4; na < args.size(); na++) {
         for (i = 0; mount_flags[i].name; i++) {
-            if (!strcmp(args[n], mount_flags[i].name)) {
+            if (!args[na].compare(mount_flags[i].name)) {
                 flags |= mount_flags[i].flag;
                 break;
             }
         }
 
         if (!mount_flags[i].name) {
-            if (!strcmp(args[n], "wait"))
+            if (!args[na].compare("wait"))
                 wait = 1;
             /* if our last argument isn't a flag, wolf it up as an option string */
-            else if (n + 1 == nargs)
-                options = args[n];
+            else if (na + 1 == args.size())
+                options = args[na].c_str();
         }
     }
 
-    system = args[1];
-    source = args[2];
-    target = args[3];
+    system = args[1].c_str();
+    source = args[2].c_str();
+    target = args[3].c_str();
 
     if (!strncmp(source, "mtd@", 4)) {
         n = mtd_name_to_number(source + 4);
@@ -455,7 +431,7 @@
  * This function might request a reboot, in which case it will
  * not return.
  */
-int do_mount_all(int nargs, char **args)
+int do_mount_all(const std::vector<std::string>& args)
 {
     pid_t pid;
     int ret = -1;
@@ -463,10 +439,10 @@
     int status;
     struct fstab *fstab;
 
-    if (nargs != 2) {
+    if (args.size() != 2) {
         return -1;
     }
-    const char* fstabfile = args[1];
+    const char* fstabfile = args[1].c_str();
     /*
      * Call fs_mgr_mount_all() to mount all filesystems.  We fork(2) and
      * do the call in the child to provide protection to the main init
@@ -513,7 +489,7 @@
         /* If fs_mgr determined this is an unencrypted device, then trigger
          * that action.
          */
-        action_for_each_trigger("nonencrypted", action_add_queue_tail);
+        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
     } else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
         /* Setup a wipe via recovery, and reboot into recovery */
         ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
@@ -528,7 +504,7 @@
 
         // Although encrypted, we have device key, so we do not need to
         // do anything different from the nonencrypted case.
-        action_for_each_trigger("nonencrypted", action_add_queue_tail);
+        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
     } else if (ret == FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED) {
         if (e4crypt_install_keyring()) {
             return -1;
@@ -544,78 +520,81 @@
     return ret;
 }
 
-int do_swapon_all(int nargs, char **args)
+int do_swapon_all(const std::vector<std::string>& args)
 {
     struct fstab *fstab;
     int ret;
 
-    fstab = fs_mgr_read_fstab(args[1]);
+    fstab = fs_mgr_read_fstab(args[1].c_str());
     ret = fs_mgr_swapon_all(fstab);
     fs_mgr_free_fstab(fstab);
 
     return ret;
 }
 
-int do_setprop(int nargs, char **args)
+int do_setprop(const std::vector<std::string>& args)
 {
-    const char *name = args[1];
-    const char *value = args[2];
+    const char* name = args[1].c_str();
+    const char* value = args[2].c_str();
     property_set(name, value);
     return 0;
 }
 
-int do_setrlimit(int nargs, char **args)
+int do_setrlimit(const std::vector<std::string>& args)
 {
     struct rlimit limit;
     int resource;
-    resource = atoi(args[1]);
-    limit.rlim_cur = atoi(args[2]);
-    limit.rlim_max = atoi(args[3]);
+    resource = std::stoi(args[1]);
+    limit.rlim_cur = std::stoi(args[2]);
+    limit.rlim_max = std::stoi(args[3]);
     return setrlimit(resource, &limit);
 }
 
-int do_start(int nargs, char **args)
+int do_start(const std::vector<std::string>& args)
 {
-    struct service *svc;
-    svc = service_find_by_name(args[1]);
-    if (svc) {
-        service_start(svc, NULL);
+    Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
+    if (!svc) {
+        ERROR("do_start: Service %s not found\n", args[1].c_str());
+        return -1;
     }
+    if (!svc->Start())
+        return -1;
     return 0;
 }
 
-int do_stop(int nargs, char **args)
+int do_stop(const std::vector<std::string>& args)
 {
-    struct service *svc;
-    svc = service_find_by_name(args[1]);
-    if (svc) {
-        service_stop(svc);
+    Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
+    if (!svc) {
+        ERROR("do_stop: Service %s not found\n", args[1].c_str());
+        return -1;
     }
+    svc->Stop();
     return 0;
 }
 
-int do_restart(int nargs, char **args)
+int do_restart(const std::vector<std::string>& args)
 {
-    struct service *svc;
-    svc = service_find_by_name(args[1]);
-    if (svc) {
-        service_restart(svc);
+    Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
+    if (!svc) {
+        ERROR("do_restart: Service %s not found\n", args[1].c_str());
+        return -1;
     }
+    svc->Restart();
     return 0;
 }
 
-int do_powerctl(int nargs, char **args)
+int do_powerctl(const std::vector<std::string>& args)
 {
-    const char* command = args[1];
+    const char* command = args[1].c_str();
     int len = 0;
-    int cmd = 0;
-    const char *reboot_target;
+    unsigned int cmd = 0;
+    const char *reboot_target = "";
     void (*callback_on_ro_remount)(const struct mntent*) = NULL;
 
     if (strncmp(command, "shutdown", 8) == 0) {
         cmd = ANDROID_RB_POWEROFF;
         len = 8;
-        callback_on_ro_remount = unmount_and_fsck;
     } else if (strncmp(command, "reboot", 6) == 0) {
         cmd = ANDROID_RB_RESTART2;
         len = 6;
@@ -625,10 +604,15 @@
     }
 
     if (command[len] == ',') {
-        reboot_target = &command[len + 1];
-    } else if (command[len] == '\0') {
-        reboot_target = "";
-    } else {
+        if (cmd == ANDROID_RB_POWEROFF &&
+            !strcmp(&command[len + 1], "userrequested")) {
+            // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
+            // Run fsck once the file system is remounted in read-only mode.
+            callback_on_ro_remount = unmount_and_fsck;
+        } else if (cmd == ANDROID_RB_RESTART2) {
+            reboot_target = &command[len + 1];
+        }
+    } else if (command[len] != '\0') {
         ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);
         return -EINVAL;
     }
@@ -637,46 +621,46 @@
                                         callback_on_ro_remount);
 }
 
-int do_trigger(int nargs, char **args)
+int do_trigger(const std::vector<std::string>& args)
 {
-    action_for_each_trigger(args[1], action_add_queue_tail);
+    ActionManager::GetInstance().QueueEventTrigger(args[1]);
     return 0;
 }
 
-int do_symlink(int nargs, char **args)
+int do_symlink(const std::vector<std::string>& args)
 {
-    return symlink(args[1], args[2]);
+    return symlink(args[1].c_str(), args[2].c_str());
 }
 
-int do_rm(int nargs, char **args)
+int do_rm(const std::vector<std::string>& args)
 {
-    return unlink(args[1]);
+    return unlink(args[1].c_str());
 }
 
-int do_rmdir(int nargs, char **args)
+int do_rmdir(const std::vector<std::string>& args)
 {
-    return rmdir(args[1]);
+    return rmdir(args[1].c_str());
 }
 
-int do_sysclktz(int nargs, char **args)
+int do_sysclktz(const std::vector<std::string>& args)
 {
     struct timezone tz;
 
-    if (nargs != 2)
+    if (args.size() != 2)
         return -1;
 
     memset(&tz, 0, sizeof(tz));
-    tz.tz_minuteswest = atoi(args[1]);
+    tz.tz_minuteswest = std::stoi(args[1]);
     if (settimeofday(NULL, &tz))
         return -1;
     return 0;
 }
 
-int do_verity_load_state(int nargs, char **args) {
+int do_verity_load_state(const std::vector<std::string>& args) {
     int mode = -1;
     int rc = fs_mgr_load_verity_state(&mode);
     if (rc == 0 && mode == VERITY_MODE_LOGGING) {
-        action_for_each_trigger("verity-logging", action_add_queue_tail);
+        ActionManager::GetInstance().QueueEventTrigger("verity-logging");
     }
     return rc;
 }
@@ -686,18 +670,18 @@
                  android::base::StringPrintf("%d", mode).c_str());
 }
 
-int do_verity_update_state(int nargs, char** args) {
+int do_verity_update_state(const std::vector<std::string>& args) {
     return fs_mgr_update_verity_state(verity_update_property);
 }
 
-int do_write(int nargs, char **args)
+int do_write(const std::vector<std::string>& args)
 {
-    const char *path = args[1];
-    const char *value = args[2];
+    const char* path = args[1].c_str();
+    const char* value = args[2].c_str();
     return write_file(path, value);
 }
 
-int do_copy(int nargs, char **args)
+int do_copy(const std::vector<std::string>& args)
 {
     char *buffer = NULL;
     int rc = 0;
@@ -706,16 +690,16 @@
     int brtw, brtr;
     char *p;
 
-    if (nargs != 3)
+    if (args.size() != 3)
         return -1;
 
-    if (stat(args[1], &info) < 0)
+    if (stat(args[1].c_str(), &info) < 0)
         return -1;
 
-    if ((fd1 = open(args[1], O_RDONLY|O_CLOEXEC)) < 0)
+    if ((fd1 = open(args[1].c_str(), O_RDONLY|O_CLOEXEC)) < 0)
         goto out_err;
 
-    if ((fd2 = open(args[2], O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0660)) < 0)
+    if ((fd2 = open(args[2].c_str(), O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0660)) < 0)
         goto out_err;
 
     if (!(buffer = (char*) malloc(info.st_size)))
@@ -759,13 +743,14 @@
     return rc;
 }
 
-int do_chown(int nargs, char **args) {
+int do_chown(const std::vector<std::string>& args) {
     /* GID is optional. */
-    if (nargs == 3) {
-        if (lchown(args[2], decode_uid(args[1]), -1) == -1)
+    if (args.size() == 3) {
+        if (lchown(args[2].c_str(), decode_uid(args[1].c_str()), -1) == -1)
             return -errno;
-    } else if (nargs == 4) {
-        if (lchown(args[3], decode_uid(args[1]), decode_uid(args[2])) == -1)
+    } else if (args.size() == 4) {
+        if (lchown(args[3].c_str(), decode_uid(args[1].c_str()),
+                   decode_uid(args[2].c_str())) == -1)
             return -errno;
     } else {
         return -1;
@@ -786,43 +771,41 @@
     return mode;
 }
 
-int do_chmod(int nargs, char **args) {
-    mode_t mode = get_mode(args[1]);
-    if (fchmodat(AT_FDCWD, args[2], mode, AT_SYMLINK_NOFOLLOW) < 0) {
+int do_chmod(const std::vector<std::string>& args) {
+    mode_t mode = get_mode(args[1].c_str());
+    if (fchmodat(AT_FDCWD, args[2].c_str(), mode, AT_SYMLINK_NOFOLLOW) < 0) {
         return -errno;
     }
     return 0;
 }
 
-int do_restorecon(int nargs, char **args) {
-    int i;
+int do_restorecon(const std::vector<std::string>& args) {
     int ret = 0;
 
-    for (i = 1; i < nargs; i++) {
-        if (restorecon(args[i]) < 0)
+    for (auto it = std::next(args.begin()); it != args.end(); ++it) {
+        if (restorecon(it->c_str()) < 0)
             ret = -errno;
     }
     return ret;
 }
 
-int do_restorecon_recursive(int nargs, char **args) {
-    int i;
+int do_restorecon_recursive(const std::vector<std::string>& args) {
     int ret = 0;
 
-    for (i = 1; i < nargs; i++) {
-        if (restorecon_recursive(args[i]) < 0)
+    for (auto it = std::next(args.begin()); it != args.end(); ++it) {
+        if (restorecon_recursive(it->c_str()) < 0)
             ret = -errno;
     }
     return ret;
 }
 
-int do_loglevel(int nargs, char **args) {
-    if (nargs != 2) {
+int do_loglevel(const std::vector<std::string>& args) {
+    if (args.size() != 2) {
         ERROR("loglevel: missing argument\n");
         return -EINVAL;
     }
 
-    int log_level = atoi(args[1]);
+    int log_level = std::stoi(args[1]);
     if (log_level < KLOG_ERROR_LEVEL || log_level > KLOG_DEBUG_LEVEL) {
         ERROR("loglevel: invalid log level'%d'\n", log_level);
         return -EINVAL;
@@ -831,28 +814,28 @@
     return 0;
 }
 
-int do_load_persist_props(int nargs, char **args) {
-    if (nargs == 1) {
+int do_load_persist_props(const std::vector<std::string>& args) {
+    if (args.size() == 1) {
         load_persist_props();
         return 0;
     }
     return -1;
 }
 
-int do_load_all_props(int nargs, char **args) {
-    if (nargs == 1) {
+int do_load_all_props(const std::vector<std::string>& args) {
+    if (args.size() == 1) {
         load_all_props();
         return 0;
     }
     return -1;
 }
 
-int do_wait(int nargs, char **args)
+int do_wait(const std::vector<std::string>& args)
 {
-    if (nargs == 2) {
-        return wait_for_file(args[1], COMMAND_RETRY_TIMEOUT);
-    } else if (nargs == 3) {
-        return wait_for_file(args[1], atoi(args[2]));
+    if (args.size() == 2) {
+        return wait_for_file(args[1].c_str(), COMMAND_RETRY_TIMEOUT);
+    } else if (args.size() == 3) {
+        return wait_for_file(args[1].c_str(), std::stoi(args[2]));
     } else
         return -1;
 }
@@ -869,9 +852,9 @@
     return 0;
 }
 
-int do_installkey(int nargs, char **args)
+int do_installkey(const std::vector<std::string>& args)
 {
-    if (nargs != 2) {
+    if (args.size() != 2) {
         return -1;
     }
 
@@ -880,6 +863,6 @@
         return 0;
     }
 
-    return e4crypt_create_device_key(args[1],
+    return e4crypt_create_device_key(args[1].c_str(),
                                      do_installkeys_ensure_dir_exists);
 }
diff --git a/init/init.cpp b/init/init.cpp
index 4be16ea..c94a6fe 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -32,7 +32,6 @@
 #include <sys/types.h>
 #include <sys/un.h>
 #include <sys/wait.h>
-#include <termios.h>
 #include <unistd.h>
 
 #include <mtd/mtd-user.h>
@@ -53,16 +52,18 @@
 
 #include <memory>
 
+#include "action.h"
+#include "bootchart.h"
 #include "devices.h"
 #include "init.h"
+#include "init_parser.h"
+#include "keychords.h"
 #include "log.h"
 #include "property_service.h"
-#include "bootchart.h"
+#include "service.h"
 #include "signal_handler.h"
-#include "keychords.h"
-#include "init_parser.h"
-#include "util.h"
 #include "ueventd.h"
+#include "util.h"
 #include "watchdogd.h"
 
 struct selabel_handle *sehandle;
@@ -72,14 +73,11 @@
 
 static char qemu[32];
 
-static struct action *cur_action = NULL;
-static struct command *cur_command = NULL;
-
-static int have_console;
-static std::string console_name = "/dev/console";
+int have_console;
+std::string console_name = "/dev/console";
 static time_t process_needs_restart;
 
-static const char *ENV[32];
+const char *ENV[32];
 
 bool waiting_for_exec = false;
 
@@ -94,27 +92,6 @@
     }
 }
 
-void service::NotifyStateChange(const char* new_state) {
-    if (!properties_initialized()) {
-        // If properties aren't available yet, we can't set them.
-        return;
-    }
-
-    if ((flags & SVC_EXEC) != 0) {
-        // 'exec' commands don't have properties tracking their state.
-        return;
-    }
-
-    char prop_name[PROP_NAME_MAX];
-    if (snprintf(prop_name, sizeof(prop_name), "init.svc.%s", name) >= PROP_NAME_MAX) {
-        // If the property name would be too long, we can't set it.
-        ERROR("Property name \"init.svc.%s\" too long; not setting to %s\n", name, new_state);
-        return;
-    }
-
-    property_set(prop_name, new_state);
-}
-
 /* add_environment - add "key=value" to the current environment */
 int add_environment(const char *key, const char *val)
 {
@@ -147,510 +124,80 @@
     return -1;
 }
 
-void zap_stdio(void)
-{
-    int fd;
-    fd = open("/dev/null", O_RDWR);
-    dup2(fd, 0);
-    dup2(fd, 1);
-    dup2(fd, 2);
-    close(fd);
-}
-
-static void open_console()
-{
-    int fd;
-    if ((fd = open(console_name.c_str(), O_RDWR)) < 0) {
-        fd = open("/dev/null", O_RDWR);
-    }
-    ioctl(fd, TIOCSCTTY, 0);
-    dup2(fd, 0);
-    dup2(fd, 1);
-    dup2(fd, 2);
-    close(fd);
-}
-
-static void publish_socket(const char *name, int fd)
-{
-    char key[64] = ANDROID_SOCKET_ENV_PREFIX;
-    char val[64];
-
-    strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
-            name,
-            sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
-    snprintf(val, sizeof(val), "%d", fd);
-    add_environment(key, val);
-
-    /* make sure we don't close-on-exec */
-    fcntl(fd, F_SETFD, 0);
-}
-
-void service_start(struct service *svc, const char *dynamic_args)
-{
-    // Starting a service removes it from the disabled or reset state and
-    // immediately takes it out of the restarting state if it was in there.
-    svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
-    svc->time_started = 0;
-
-    // Running processes require no additional work --- if they're in the
-    // process of exiting, we've ensured that they will immediately restart
-    // on exit, unless they are ONESHOT.
-    if (svc->flags & SVC_RUNNING) {
-        return;
-    }
-
-    bool needs_console = (svc->flags & SVC_CONSOLE);
-    if (needs_console && !have_console) {
-        ERROR("service '%s' requires console\n", svc->name);
-        svc->flags |= SVC_DISABLED;
-        return;
-    }
-
-    struct stat sb;
-    if (stat(svc->args[0], &sb) == -1) {
-        ERROR("cannot find '%s' (%s), disabling '%s'\n", svc->args[0], strerror(errno), svc->name);
-        svc->flags |= SVC_DISABLED;
-        return;
-    }
-
-    if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {
-        ERROR("service '%s' must be one-shot to use dynamic args, disabling\n", svc->args[0]);
-        svc->flags |= SVC_DISABLED;
-        return;
-    }
-
-    char* scon = NULL;
-    if (svc->seclabel) {
-        scon = strdup(svc->seclabel);
-        if (!scon) {
-            ERROR("Out of memory while starting '%s'\n", svc->name);
-            return;
-        }
-    } else {
-        char *mycon = NULL, *fcon = NULL;
-
-        INFO("computing context for service '%s'\n", svc->args[0]);
-        int rc = getcon(&mycon);
-        if (rc < 0) {
-            ERROR("could not get context while starting '%s'\n", svc->name);
-            return;
-        }
-
-        rc = getfilecon(svc->args[0], &fcon);
-        if (rc < 0) {
-            ERROR("could not get context while starting '%s'\n", svc->name);
-            free(mycon);
-            return;
-        }
-
-        rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon);
-        if (rc == 0 && !strcmp(scon, mycon)) {
-            ERROR("Service %s does not have a SELinux domain defined.\n", svc->name);
-            free(mycon);
-            free(fcon);
-            free(scon);
-            return;
-        }
-        free(mycon);
-        free(fcon);
-        if (rc < 0) {
-            ERROR("could not get context while starting '%s'\n", svc->name);
-            return;
-        }
-    }
-
-    NOTICE("Starting service '%s'...\n", svc->name);
-
-    pid_t pid = fork();
-    if (pid == 0) {
-        struct socketinfo *si;
-        struct svcenvinfo *ei;
-        char tmp[32];
-        int fd, sz;
-
-        umask(077);
-        if (properties_initialized()) {
-            get_property_workspace(&fd, &sz);
-            snprintf(tmp, sizeof(tmp), "%d,%d", dup(fd), sz);
-            add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
-        }
-
-        for (ei = svc->envvars; ei; ei = ei->next)
-            add_environment(ei->name, ei->value);
-
-        for (si = svc->sockets; si; si = si->next) {
-            int socket_type = (
-                    !strcmp(si->type, "stream") ? SOCK_STREAM :
-                        (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
-            int s = create_socket(si->name, socket_type,
-                                  si->perm, si->uid, si->gid, si->socketcon ?: scon);
-            if (s >= 0) {
-                publish_socket(si->name, s);
-            }
-        }
-
-        free(scon);
-        scon = NULL;
-
-        if (svc->writepid_files_) {
-            std::string pid_str = android::base::StringPrintf("%d", pid);
-            for (auto& file : *svc->writepid_files_) {
-                if (!android::base::WriteStringToFile(pid_str, file)) {
-                    ERROR("couldn't write %s to %s: %s\n",
-                          pid_str.c_str(), file.c_str(), strerror(errno));
-                }
-            }
-        }
-
-        if (svc->ioprio_class != IoSchedClass_NONE) {
-            if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
-                ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
-                      getpid(), svc->ioprio_class, svc->ioprio_pri, strerror(errno));
-            }
-        }
-
-        if (needs_console) {
-            setsid();
-            open_console();
-        } else {
-            zap_stdio();
-        }
-
-        if (false) {
-            for (size_t n = 0; svc->args[n]; n++) {
-                INFO("args[%zu] = '%s'\n", n, svc->args[n]);
-            }
-            for (size_t n = 0; ENV[n]; n++) {
-                INFO("env[%zu] = '%s'\n", n, ENV[n]);
-            }
-        }
-
-        setpgid(0, getpid());
-
-        // As requested, set our gid, supplemental gids, and uid.
-        if (svc->gid) {
-            if (setgid(svc->gid) != 0) {
-                ERROR("setgid failed: %s\n", strerror(errno));
-                _exit(127);
-            }
-        }
-        if (svc->nr_supp_gids) {
-            if (setgroups(svc->nr_supp_gids, svc->supp_gids) != 0) {
-                ERROR("setgroups failed: %s\n", strerror(errno));
-                _exit(127);
-            }
-        }
-        if (svc->uid) {
-            if (setuid(svc->uid) != 0) {
-                ERROR("setuid failed: %s\n", strerror(errno));
-                _exit(127);
-            }
-        }
-        if (svc->seclabel) {
-            if (setexeccon(svc->seclabel) < 0) {
-                ERROR("cannot setexeccon('%s'): %s\n", svc->seclabel, strerror(errno));
-                _exit(127);
-            }
-        }
-
-        if (!dynamic_args) {
-            if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {
-                ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
-            }
-        } else {
-            char *arg_ptrs[INIT_PARSER_MAXARGS+1];
-            int arg_idx = svc->nargs;
-            char *tmp = strdup(dynamic_args);
-            char *next = tmp;
-            char *bword;
-
-            /* Copy the static arguments */
-            memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));
-
-            while((bword = strsep(&next, " "))) {
-                arg_ptrs[arg_idx++] = bword;
-                if (arg_idx == INIT_PARSER_MAXARGS)
-                    break;
-            }
-            arg_ptrs[arg_idx] = NULL;
-            execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
-        }
-        _exit(127);
-    }
-
-    free(scon);
-
-    if (pid < 0) {
-        ERROR("failed to start '%s'\n", svc->name);
-        svc->pid = 0;
-        return;
-    }
-
-    svc->time_started = gettime();
-    svc->pid = pid;
-    svc->flags |= SVC_RUNNING;
-
-    if ((svc->flags & SVC_EXEC) != 0) {
-        INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n",
-             svc->pid, svc->uid, svc->gid, svc->nr_supp_gids,
-             svc->seclabel ? : "default");
-        waiting_for_exec = true;
-    }
-
-    svc->NotifyStateChange("running");
-}
-
-/* The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART */
-static void service_stop_or_reset(struct service *svc, int how)
-{
-    /* The service is still SVC_RUNNING until its process exits, but if it has
-     * already exited it shoudn't attempt a restart yet. */
-    svc->flags &= ~(SVC_RESTARTING | SVC_DISABLED_START);
-
-    if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) {
-        /* Hrm, an illegal flag.  Default to SVC_DISABLED */
-        how = SVC_DISABLED;
-    }
-        /* if the service has not yet started, prevent
-         * it from auto-starting with its class
-         */
-    if (how == SVC_RESET) {
-        svc->flags |= (svc->flags & SVC_RC_DISABLED) ? SVC_DISABLED : SVC_RESET;
-    } else {
-        svc->flags |= how;
-    }
-
-    if (svc->pid) {
-        NOTICE("Service '%s' is being killed...\n", svc->name);
-        kill(-svc->pid, SIGKILL);
-        svc->NotifyStateChange("stopping");
-    } else {
-        svc->NotifyStateChange("stopped");
-    }
-}
-
-void service_reset(struct service *svc)
-{
-    service_stop_or_reset(svc, SVC_RESET);
-}
-
-void service_stop(struct service *svc)
-{
-    service_stop_or_reset(svc, SVC_DISABLED);
-}
-
-void service_restart(struct service *svc)
-{
-    if (svc->flags & SVC_RUNNING) {
-        /* Stop, wait, then start the service. */
-        service_stop_or_reset(svc, SVC_RESTART);
-    } else if (!(svc->flags & SVC_RESTARTING)) {
-        /* Just start the service since it's not running. */
-        service_start(svc, NULL);
-    } /* else: Service is restarting anyways. */
-}
-
 void property_changed(const char *name, const char *value)
 {
     if (property_triggers_enabled)
-        queue_property_triggers(name, value);
-}
-
-static void restart_service_if_needed(struct service *svc)
-{
-    time_t next_start_time = svc->time_started + 5;
-
-    if (next_start_time <= gettime()) {
-        svc->flags &= (~SVC_RESTARTING);
-        service_start(svc, NULL);
-        return;
-    }
-
-    if ((next_start_time < process_needs_restart) ||
-        (process_needs_restart == 0)) {
-        process_needs_restart = next_start_time;
-    }
+        ActionManager::GetInstance().QueuePropertyTrigger(name, value);
 }
 
 static void restart_processes()
 {
     process_needs_restart = 0;
-    service_for_each_flags(SVC_RESTARTING,
-                           restart_service_if_needed);
+    ServiceManager::GetInstance().
+        ForEachServiceWithFlags(SVC_RESTARTING, [] (Service* s) {
+                s->RestartIfNeeded(process_needs_restart);
+            });
 }
 
-static void msg_start(const char *name)
+static void msg_start(const std::string& name)
 {
-    struct service *svc = NULL;
-    char *tmp = NULL;
-    char *args = NULL;
+    Service* svc = nullptr;
+    std::vector<std::string> vargs;
 
-    if (!strchr(name, ':'))
-        svc = service_find_by_name(name);
-    else {
-        tmp = strdup(name);
-        if (tmp) {
-            args = strchr(tmp, ':');
-            *args = '\0';
-            args++;
+    size_t colon_pos = name.find(':');
+    if (colon_pos == std::string::npos) {
+        svc = ServiceManager::GetInstance().FindServiceByName(name);
+    } else {
+        std::string service_name(name.substr(0, colon_pos));
+        std::string args(name.substr(colon_pos + 1));
+        vargs = android::base::Split(args, " ");
 
-            svc = service_find_by_name(tmp);
-        }
+        svc = ServiceManager::GetInstance().FindServiceByName(service_name);
     }
 
     if (svc) {
-        service_start(svc, args);
+        svc->Start(vargs);
     } else {
-        ERROR("no such service '%s'\n", name);
+        ERROR("no such service '%s'\n", name.c_str());
     }
-    if (tmp)
-        free(tmp);
 }
 
-static void msg_stop(const char *name)
+static void msg_stop(const std::string& name)
 {
-    struct service *svc = service_find_by_name(name);
+    Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
 
     if (svc) {
-        service_stop(svc);
+        svc->Stop();
     } else {
-        ERROR("no such service '%s'\n", name);
+        ERROR("no such service '%s'\n", name.c_str());
     }
 }
 
-static void msg_restart(const char *name)
+static void msg_restart(const std::string& name)
 {
-    struct service *svc = service_find_by_name(name);
+    Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
 
     if (svc) {
-        service_restart(svc);
+        svc->Restart();
     } else {
-        ERROR("no such service '%s'\n", name);
+        ERROR("no such service '%s'\n", name.c_str());
     }
 }
 
-void handle_control_message(const char *msg, const char *arg)
+void handle_control_message(const std::string& msg, const std::string& arg)
 {
-    if (!strcmp(msg,"start")) {
+    if (msg == "start") {
         msg_start(arg);
-    } else if (!strcmp(msg,"stop")) {
+    } else if (msg == "stop") {
         msg_stop(arg);
-    } else if (!strcmp(msg,"restart")) {
+    } else if (msg == "restart") {
         msg_restart(arg);
     } else {
-        ERROR("unknown control msg '%s'\n", msg);
+        ERROR("unknown control msg '%s'\n", msg.c_str());
     }
 }
 
-static struct command *get_first_command(struct action *act)
-{
-    struct listnode *node;
-    node = list_head(&act->commands);
-    if (!node || list_empty(&act->commands))
-        return NULL;
-
-    return node_to_item(node, struct command, clist);
-}
-
-static struct command *get_next_command(struct action *act, struct command *cmd)
-{
-    struct listnode *node;
-    node = cmd->clist.next;
-    if (!node)
-        return NULL;
-    if (node == &act->commands)
-        return NULL;
-
-    return node_to_item(node, struct command, clist);
-}
-
-static int is_last_command(struct action *act, struct command *cmd)
-{
-    return (list_tail(&act->commands) == &cmd->clist);
-}
-
-
-std::string build_triggers_string(struct action *cur_action) {
-    std::string result;
-    struct listnode *node;
-    struct trigger *cur_trigger;
-
-    list_for_each(node, &cur_action->triggers) {
-        cur_trigger = node_to_item(node, struct trigger, nlist);
-        if (node != cur_action->triggers.next) {
-            result.push_back(' ');
-        }
-        result += cur_trigger->name;
-    }
-    return result;
-}
-
-bool expand_command_arguments(int nargs, char** args, std::vector<std::string>* expanded_args) {
-    std::vector<std::string>& strs = *expanded_args;
-    strs.resize(nargs);
-    strs[0] = args[0];
-    for (int i = 1; i < nargs; ++i) {
-        if (expand_props(args[i], &strs[i]) == -1) {
-            ERROR("%s: cannot expand '%s'\n", args[0], args[i]);
-            return false;
-        }
-    }
-    return true;
-}
-
-void execute_one_command() {
-    Timer t;
-
-    if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
-        cur_action = action_remove_queue_head();
-        cur_command = NULL;
-        if (!cur_action) {
-            return;
-        }
-
-        std::string trigger_name = build_triggers_string(cur_action);
-        INFO("processing action %p (%s)\n", cur_action, trigger_name.c_str());
-        cur_command = get_first_command(cur_action);
-    } else {
-        cur_command = get_next_command(cur_action, cur_command);
-    }
-
-    if (!cur_command) {
-        return;
-    }
-    int result = 0;
-    std::vector<std::string> arg_strs;
-    if (!expand_command_arguments(cur_command->nargs, cur_command->args, &arg_strs)) {
-        result = -EINVAL;
-    }
-    if (result == 0) {
-        std::vector<char*> args;
-        for (auto& s : arg_strs) {
-            args.push_back(&s[0]);
-        }
-        result = cur_command->func(args.size(), &args[0]);
-    }
-    if (klog_get_level() >= KLOG_INFO_LEVEL) {
-        std::string cmd_str;
-        for (int i = 0; i < cur_command->nargs; ++i) {
-            if (i > 0) {
-                cmd_str.push_back(' ');
-            }
-            cmd_str += cur_command->args[i];
-        }
-        std::string trigger_name = build_triggers_string(cur_action);
-
-        std::string source;
-        if (cur_command->filename) {
-            source = android::base::StringPrintf(" (%s:%d)", cur_command->filename, cur_command->line);
-        }
-
-        INFO("Command '%s' action=%s%s returned %d took %.2fs\n",
-             cmd_str.c_str(), trigger_name.c_str(), source.c_str(), result, t.duration());
-    }
-}
-
-static int wait_for_coldboot_done_action(int nargs, char **args) {
+static int wait_for_coldboot_done_action(const std::vector<std::string>& args) {
     Timer t;
 
     NOTICE("Waiting for %s...\n", COLDBOOT_DONE);
@@ -680,7 +227,7 @@
  * time. We do not reboot or halt on failures, as this is a best-effort
  * attempt.
  */
-static int mix_hwrng_into_linux_rng_action(int nargs, char **args)
+static int mix_hwrng_into_linux_rng_action(const std::vector<std::string>& args)
 {
     int result = -1;
     int hwrandom_fd = -1;
@@ -742,13 +289,13 @@
     return result;
 }
 
-static int keychord_init_action(int nargs, char **args)
+static int keychord_init_action(const std::vector<std::string>& args)
 {
     keychord_init();
     return 0;
 }
 
-static int console_init_action(int nargs, char **args)
+static int console_init_action(const std::vector<std::string>& args)
 {
     std::string console = property_get("ro.boot.console");
     if (!console.empty()) {
@@ -863,9 +410,9 @@
     if (qemu[0]) import_kernel_cmdline(true, import_kernel_nv);
 }
 
-static int queue_property_triggers_action(int nargs, char **args)
+static int queue_property_triggers_action(const std::vector<std::string>& args)
 {
-    queue_all_property_triggers();
+    ActionManager::GetInstance().QueueAllPropertyTriggers();
     /* enable property triggers */
     property_triggers_enabled = 1;
     return 0;
@@ -1059,36 +606,38 @@
 
     init_parse_config("/init.rc");
 
-    action_for_each_trigger("early-init", action_add_queue_tail);
+    ActionManager& am = ActionManager::GetInstance();
+
+    am.QueueEventTrigger("early-init");
 
     // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
-    queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
+    am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
     // ... so that we can start queuing up actions that require stuff from /dev.
-    queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
-    queue_builtin_action(keychord_init_action, "keychord_init");
-    queue_builtin_action(console_init_action, "console_init");
+    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
+    am.QueueBuiltinAction(keychord_init_action, "keychord_init");
+    am.QueueBuiltinAction(console_init_action, "console_init");
 
     // Trigger all the boot actions to get us started.
-    action_for_each_trigger("init", action_add_queue_tail);
+    am.QueueEventTrigger("init");
 
     // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
     // wasn't ready immediately after wait_for_coldboot_done
-    queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
+    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
 
     // Don't mount filesystems or start core system services in charger mode.
     std::string bootmode = property_get("ro.bootmode");
     if (bootmode == "charger") {
-        action_for_each_trigger("charger", action_add_queue_tail);
+        am.QueueEventTrigger("charger");
     } else {
-        action_for_each_trigger("late-init", action_add_queue_tail);
+        am.QueueEventTrigger("late-init");
     }
 
     // Run all property triggers based on current state of the properties.
-    queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
+    am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
 
     while (true) {
         if (!waiting_for_exec) {
-            execute_one_command();
+            am.ExecuteOneCommand();
             restart_processes();
         }
 
@@ -1099,7 +648,7 @@
                 timeout = 0;
         }
 
-        if (!action_queue_empty() || cur_action) {
+        if (am.HasMoreCommands()) {
             timeout = 0;
         }
 
diff --git a/init/init.h b/init/init.h
index d2b2dfb..345d442 100644
--- a/init/init.h
+++ b/init/init.h
@@ -17,150 +17,28 @@
 #ifndef _INIT_INIT_H
 #define _INIT_INIT_H
 
-#include <sys/types.h>
-
 #include <string>
-#include <vector>
 
-#include <cutils/list.h>
-#include <cutils/iosched_policy.h>
-
-struct command
-{
-        /* list of commands in an action */
-    struct listnode clist;
-
-    int (*func)(int nargs, char **args);
-
-    int line;
-    const char *filename;
-
-    int nargs;
-    char *args[1];
-};
-
-struct trigger {
-    struct listnode nlist;
-    const char *name;
-};
-
-struct action {
-        /* node in list of all actions */
-    struct listnode alist;
-        /* node in the queue of pending actions */
-    struct listnode qlist;
-        /* node in list of actions for a trigger */
-    struct listnode tlist;
-
-    unsigned hash;
-
-        /* list of actions which triggers the commands*/
-    struct listnode triggers;
-    struct listnode commands;
-    struct command *current;
-};
-
-struct socketinfo {
-    struct socketinfo *next;
-    const char *name;
-    const char *type;
-    uid_t uid;
-    gid_t gid;
-    int perm;
-    const char *socketcon;
-};
-
-struct svcenvinfo {
-    struct svcenvinfo *next;
-    const char *name;
-    const char *value;
-};
-
-#define SVC_DISABLED       0x001  // do not autostart with class
-#define SVC_ONESHOT        0x002  // do not restart on exit
-#define SVC_RUNNING        0x004  // currently active
-#define SVC_RESTARTING     0x008  // waiting to restart
-#define SVC_CONSOLE        0x010  // requires console
-#define SVC_CRITICAL       0x020  // will reboot into recovery if keeps crashing
-#define SVC_RESET          0x040  // Use when stopping a process, but not disabling so it can be restarted with its class.
-#define SVC_RC_DISABLED    0x080  // Remember if the disabled flag was set in the rc script.
-#define SVC_RESTART        0x100  // Use to safely restart (stop, wait, start) a service.
-#define SVC_DISABLED_START 0x200  // A start was requested but it was disabled at the time.
-#define SVC_EXEC           0x400  // This synthetic service corresponds to an 'exec'.
-
-#define NR_SVC_SUPP_GIDS 12    /* twelve supplementary groups */
+class Action;
+class Service;
 
 #define COMMAND_RETRY_TIMEOUT 5
 
-struct service {
-    void NotifyStateChange(const char* new_state);
-
-        /* list of all services */
-    struct listnode slist;
-
-    char *name;
-    const char *classname;
-
-    unsigned flags;
-    pid_t pid;
-    time_t time_started;    /* time of last start */
-    time_t time_crashed;    /* first crash within inspection window */
-    int nr_crashed;         /* number of times crashed within window */
-
-    uid_t uid;
-    gid_t gid;
-    gid_t supp_gids[NR_SVC_SUPP_GIDS];
-    size_t nr_supp_gids;
-
-    const char* seclabel;
-
-    struct socketinfo *sockets;
-    struct svcenvinfo *envvars;
-
-    struct action onrestart;  /* Actions to execute on restart. */
-
-    std::vector<std::string>* writepid_files_;
-
-    /* keycodes for triggering this service via /dev/keychord */
-    int *keycodes;
-    int nkeycodes;
-    int keychord_id;
-
-    IoSchedClass ioprio_class;
-    int ioprio_pri;
-
-    int nargs;
-    /* "MUST BE AT THE END OF THE STRUCT" */
-    char *args[1];
-}; /*     ^-------'args' MUST be at the end of this struct! */
-
+extern const char *ENV[32];
 extern bool waiting_for_exec;
+extern int have_console;
+extern std::string console_name;
 extern struct selabel_handle *sehandle;
 extern struct selabel_handle *sehandle_prop;
 
-std::string build_triggers_string(struct action *cur_action);
+void handle_control_message(const std::string& msg, const std::string& arg);
 
-void handle_control_message(const char *msg, const char *arg);
-
-struct service *service_find_by_name(const char *name);
-struct service *service_find_by_pid(pid_t pid);
-struct service *service_find_by_keychord(int keychord_id);
-void service_for_each(void (*func)(struct service *svc));
-void service_for_each_class(const char *classname,
-                            void (*func)(struct service *svc));
-void service_for_each_flags(unsigned matchflags,
-                            void (*func)(struct service *svc));
-void service_stop(struct service *svc);
-void service_reset(struct service *svc);
-void service_restart(struct service *svc);
-void service_start(struct service *svc, const char *dynamic_args);
 void property_changed(const char *name, const char *value);
 
 int selinux_reload_policy(void);
 
-void zap_stdio(void);
-
 void register_epoll_handler(int fd, void (*fn)());
-bool expand_command_arguments(int nargs, char** args, std::vector<std::string>* expanded_args);
 
-#endif	/* _INIT_INIT_H */
+int add_environment(const char* key, const char* val);
+
+#endif  /* _INIT_INIT_H */
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 460f5ac..12f44f7 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -26,11 +26,13 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "action.h"
 #include "init.h"
-#include "parser.h"
 #include "init_parser.h"
 #include "log.h"
+#include "parser.h"
 #include "property_service.h"
+#include "service.h"
 #include "util.h"
 
 #include <base/stringprintf.h>
@@ -38,8 +40,6 @@
 #include <cutils/list.h>
 
 static list_declare(service_list);
-static list_declare(action_list);
-static list_declare(action_queue);
 
 struct import {
     struct listnode list;
@@ -63,8 +63,8 @@
 
 static struct {
     const char *name;
-    int (*func)(int nargs, char **args);
-    unsigned char nargs;
+    int (*func)(const std::vector<std::string>& args);
+    size_t nargs;
     unsigned char flags;
 } keyword_info[KEYWORD_COUNT] = {
     [ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
@@ -78,41 +78,8 @@
 #define kw_nargs(kw) (keyword_info[kw].nargs)
 
 void dump_parser_state() {
-    if (false) {
-        struct listnode* node;
-        list_for_each(node, &service_list) {
-            service* svc = node_to_item(node, struct service, slist);
-            INFO("service %s\n", svc->name);
-            INFO("  class '%s'\n", svc->classname);
-            INFO("  exec");
-            for (int n = 0; n < svc->nargs; n++) {
-                INFO(" '%s'", svc->args[n]);
-            }
-            INFO("\n");
-            for (socketinfo* si = svc->sockets; si; si = si->next) {
-                INFO("  socket %s %s 0%o\n", si->name, si->type, si->perm);
-            }
-        }
-
-        list_for_each(node, &action_list) {
-            action* act = node_to_item(node, struct action, alist);
-            INFO("on ");
-            std::string trigger_name = build_triggers_string(act);
-            INFO("%s", trigger_name.c_str());
-            INFO("\n");
-
-            struct listnode* node2;
-            list_for_each(node2, &act->commands) {
-                command* cmd = node_to_item(node2, struct command, clist);
-                INFO("  %p", cmd->func);
-                for (int n = 0; n < cmd->nargs; n++) {
-                    INFO(" %s", cmd->args[n]);
-                }
-                INFO("\n");
-            }
-            INFO("\n");
-        }
-    }
+    ServiceManager::GetInstance().DumpState();
+    ActionManager::GetInstance().DumpState();
 }
 
 static int lookup_keyword(const char *s)
@@ -217,10 +184,10 @@
 static void parse_line_no_op(struct parse_state*, int, char**) {
 }
 
-int expand_props(const char *src, std::string *dst) {
-    const char *src_ptr = src;
+int expand_props(const std::string& src, std::string* dst) {
+    const char *src_ptr = src.c_str();
 
-    if (!src || !dst) {
+    if (!dst) {
         return -1;
     }
 
@@ -256,7 +223,7 @@
             const char* end = strchr(c, '}');
             if (!end) {
                 // failed to find closing brace, abort.
-                ERROR("unexpected end of string in '%s', looking for }\n", src);
+                ERROR("unexpected end of string in '%s', looking for }\n", src.c_str());
                 goto err;
             }
             prop_name = std::string(c, end);
@@ -269,14 +236,14 @@
         }
 
         if (prop_name.empty()) {
-            ERROR("invalid zero-length prop name in '%s'\n", src);
+            ERROR("invalid zero-length prop name in '%s'\n", src.c_str());
             goto err;
         }
 
         std::string prop_val = property_get(prop_name.c_str());
         if (prop_val.empty()) {
             ERROR("property '%s' doesn't exist while expanding '%s'\n",
-                  prop_name.c_str(), src);
+                  prop_name.c_str(), src.c_str());
             goto err;
         }
 
@@ -348,10 +315,14 @@
 
     int nargs = 0;
 
+    //TODO: Use a parser with const input and remove this copy
+    std::vector<char> data_copy(data.begin(), data.end());
+    data_copy.push_back('\0');
+
     parse_state state;
     state.filename = fn;
     state.line = 0;
-    state.ptr = strdup(data.c_str());  // TODO: fix this code!
+    state.ptr = &data_copy[0];
     state.nexttoken = 0;
     state.parse_line = parse_line_no_op;
 
@@ -438,557 +409,90 @@
     return init_parse_config_file(path);
 }
 
-static int valid_name(const char *name)
-{
-    if (strlen(name) > 16) {
-        return 0;
-    }
-    while (*name) {
-        if (!isalnum(*name) && (*name != '_') && (*name != '-')) {
-            return 0;
-        }
-        name++;
-    }
-    return 1;
-}
-
-struct service *service_find_by_name(const char *name)
-{
-    struct listnode *node;
-    struct service *svc;
-    list_for_each(node, &service_list) {
-        svc = node_to_item(node, struct service, slist);
-        if (!strcmp(svc->name, name)) {
-            return svc;
-        }
-    }
-    return 0;
-}
-
-struct service *service_find_by_pid(pid_t pid)
-{
-    struct listnode *node;
-    struct service *svc;
-    list_for_each(node, &service_list) {
-        svc = node_to_item(node, struct service, slist);
-        if (svc->pid == pid) {
-            return svc;
-        }
-    }
-    return 0;
-}
-
-struct service *service_find_by_keychord(int keychord_id)
-{
-    struct listnode *node;
-    struct service *svc;
-    list_for_each(node, &service_list) {
-        svc = node_to_item(node, struct service, slist);
-        if (svc->keychord_id == keychord_id) {
-            return svc;
-        }
-    }
-    return 0;
-}
-
-void service_for_each(void (*func)(struct service *svc))
-{
-    struct listnode *node;
-    struct service *svc;
-    list_for_each(node, &service_list) {
-        svc = node_to_item(node, struct service, slist);
-        func(svc);
-    }
-}
-
-void service_for_each_class(const char *classname,
-                            void (*func)(struct service *svc))
-{
-    struct listnode *node;
-    struct service *svc;
-    list_for_each(node, &service_list) {
-        svc = node_to_item(node, struct service, slist);
-        if (!strcmp(svc->classname, classname)) {
-            func(svc);
-        }
-    }
-}
-
-void service_for_each_flags(unsigned matchflags,
-                            void (*func)(struct service *svc))
-{
-    struct listnode *node;
-    struct service *svc;
-    list_for_each(node, &service_list) {
-        svc = node_to_item(node, struct service, slist);
-        if (svc->flags & matchflags) {
-            func(svc);
-        }
-    }
-}
-
-void action_for_each_trigger(const char *trigger,
-                             void (*func)(struct action *act))
-{
-    struct listnode *node, *node2;
-    struct action *act;
-    struct trigger *cur_trigger;
-
-    list_for_each(node, &action_list) {
-        act = node_to_item(node, struct action, alist);
-        list_for_each(node2, &act->triggers) {
-            cur_trigger = node_to_item(node2, struct trigger, nlist);
-            if (!strcmp(cur_trigger->name, trigger)) {
-                func(act);
-            }
-        }
-    }
-}
-
-
-void queue_property_triggers(const char *name, const char *value)
-{
-    struct listnode *node, *node2;
-    struct action *act;
-    struct trigger *cur_trigger;
-    bool match;
-    int name_length;
-
-    list_for_each(node, &action_list) {
-        act = node_to_item(node, struct action, alist);
-            match = !name;
-        list_for_each(node2, &act->triggers) {
-            cur_trigger = node_to_item(node2, struct trigger, nlist);
-            if (!strncmp(cur_trigger->name, "property:", strlen("property:"))) {
-                const char *test = cur_trigger->name + strlen("property:");
-                if (!match) {
-                    name_length = strlen(name);
-                    if (!strncmp(name, test, name_length) &&
-                        test[name_length] == '=' &&
-                        (!strcmp(test + name_length + 1, value) ||
-                        !strcmp(test + name_length + 1, "*"))) {
-                        match = true;
-                        continue;
-                    }
-                } else {
-                     const char* equals = strchr(test, '=');
-                     if (equals) {
-                         int length = equals - test;
-                         if (length <= PROP_NAME_MAX) {
-                             std::string prop_name(test, length);
-                             std::string value = property_get(prop_name.c_str());
-
-                             /* does the property exist, and match the trigger value? */
-                             if (!value.empty() && (!strcmp(equals + 1, value.c_str()) ||
-                                !strcmp(equals + 1, "*"))) {
-                                 continue;
-                             }
-                         }
-                     }
-                 }
-             }
-             match = false;
-             break;
-        }
-        if (match) {
-            action_add_queue_tail(act);
-        }
-    }
-}
-
-void queue_all_property_triggers()
-{
-    queue_property_triggers(NULL, NULL);
-}
-
-void queue_builtin_action(int (*func)(int nargs, char **args), const char *name)
-{
-    action* act = (action*) calloc(1, sizeof(*act));
-    trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
-    cur_trigger->name = name;
-    list_init(&act->triggers);
-    list_add_tail(&act->triggers, &cur_trigger->nlist);
-    list_init(&act->commands);
-    list_init(&act->qlist);
-
-    command* cmd = (command*) calloc(1, sizeof(*cmd));
-    cmd->func = func;
-    cmd->args[0] = const_cast<char*>(name);
-    cmd->nargs = 1;
-    list_add_tail(&act->commands, &cmd->clist);
-
-    list_add_tail(&action_list, &act->alist);
-    action_add_queue_tail(act);
-}
-
-void action_add_queue_tail(struct action *act)
-{
-    if (list_empty(&act->qlist)) {
-        list_add_tail(&action_queue, &act->qlist);
-    }
-}
-
-struct action *action_remove_queue_head(void)
-{
-    if (list_empty(&action_queue)) {
-        return 0;
-    } else {
-        struct listnode *node = list_head(&action_queue);
-        struct action *act = node_to_item(node, struct action, qlist);
-        list_remove(node);
-        list_init(node);
-        return act;
-    }
-}
-
-int action_queue_empty()
-{
-    return list_empty(&action_queue);
-}
-
-service* make_exec_oneshot_service(int nargs, char** args) {
-    // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
-    // SECLABEL can be a - to denote default
-    int command_arg = 1;
-    for (int i = 1; i < nargs; ++i) {
-        if (strcmp(args[i], "--") == 0) {
-            command_arg = i + 1;
-            break;
-        }
-    }
-    if (command_arg > 4 + NR_SVC_SUPP_GIDS) {
-        ERROR("exec called with too many supplementary group ids\n");
-        return NULL;
-    }
-
-    int argc = nargs - command_arg;
-    char** argv = (args + command_arg);
-    if (argc < 1) {
-        ERROR("exec called without command\n");
-        return NULL;
-    }
-
-    service* svc = (service*) calloc(1, sizeof(*svc) + sizeof(char*) * argc);
-    if (svc == NULL) {
-        ERROR("Couldn't allocate service for exec of '%s': %s", argv[0], strerror(errno));
-        return NULL;
-    }
-
-    if ((command_arg > 2) && strcmp(args[1], "-")) {
-        svc->seclabel = args[1];
-    }
-    if (command_arg > 3) {
-        svc->uid = decode_uid(args[2]);
-    }
-    if (command_arg > 4) {
-        svc->gid = decode_uid(args[3]);
-        svc->nr_supp_gids = command_arg - 1 /* -- */ - 4 /* exec SECLABEL UID GID */;
-        for (size_t i = 0; i < svc->nr_supp_gids; ++i) {
-            svc->supp_gids[i] = decode_uid(args[4 + i]);
-        }
-    }
-
-    static int exec_count; // Every service needs a unique name.
-    char* name = NULL;
-    asprintf(&name, "exec %d (%s)", exec_count++, argv[0]);
-    if (name == NULL) {
-        ERROR("Couldn't allocate name for exec service '%s'\n", argv[0]);
-        free(svc);
-        return NULL;
-    }
-    svc->name = name;
-    svc->classname = "default";
-    svc->flags = SVC_EXEC | SVC_ONESHOT;
-    svc->nargs = argc;
-    memcpy(svc->args, argv, sizeof(char*) * svc->nargs);
-    svc->args[argc] = NULL;
-    list_add_tail(&service_list, &svc->slist);
-    return svc;
-}
-
 static void *parse_service(struct parse_state *state, int nargs, char **args)
 {
     if (nargs < 3) {
         parse_error(state, "services must have a name and a program\n");
-        return 0;
+        return nullptr;
     }
-    if (!valid_name(args[1])) {
-        parse_error(state, "invalid service name '%s'\n", args[1]);
-        return 0;
-    }
+    std::vector<std::string> str_args(args + 2, args + nargs);
+    std::string ret_err;
+    Service* svc = ServiceManager::GetInstance().AddNewService(args[1], "default",
+                                                               str_args, &ret_err);
 
-    service* svc = (service*) service_find_by_name(args[1]);
-    if (svc) {
-        parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);
-        return 0;
-    }
-
-    nargs -= 2;
-    svc = (service*) calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
     if (!svc) {
-        parse_error(state, "out of memory\n");
-        return 0;
+        parse_error(state, "%s\n", ret_err.c_str());
     }
-    svc->name = strdup(args[1]);
-    svc->classname = "default";
-    memcpy(svc->args, args + 2, sizeof(char*) * nargs);
-    trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
-    svc->args[nargs] = 0;
-    svc->nargs = nargs;
-    list_init(&svc->onrestart.triggers);
-    cur_trigger->name = "onrestart";
-    list_add_tail(&svc->onrestart.triggers, &cur_trigger->nlist);
-    list_init(&svc->onrestart.commands);
-    list_add_tail(&service_list, &svc->slist);
+
     return svc;
 }
 
 static void parse_line_service(struct parse_state *state, int nargs, char **args)
 {
-    struct service *svc = (service*) state->context;
-    struct command *cmd;
-    int i, kw, kw_nargs;
-
     if (nargs == 0) {
         return;
     }
 
-    svc->ioprio_class = IoSchedClass_NONE;
+    Service* svc = static_cast<Service*>(state->context);
+    int kw = lookup_keyword(args[0]);
+    std::vector<std::string> str_args(args, args + nargs);
+    std::string ret_err;
+    bool ret = svc->HandleLine(kw, str_args, &ret_err);
 
-    kw = lookup_keyword(args[0]);
-    switch (kw) {
-    case K_class:
-        if (nargs != 2) {
-            parse_error(state, "class option requires a classname\n");
-        } else {
-            svc->classname = args[1];
-        }
-        break;
-    case K_console:
-        svc->flags |= SVC_CONSOLE;
-        break;
-    case K_disabled:
-        svc->flags |= SVC_DISABLED;
-        svc->flags |= SVC_RC_DISABLED;
-        break;
-    case K_ioprio:
-        if (nargs != 3) {
-            parse_error(state, "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n");
-        } else {
-            svc->ioprio_pri = strtoul(args[2], 0, 8);
-
-            if (svc->ioprio_pri < 0 || svc->ioprio_pri > 7) {
-                parse_error(state, "priority value must be range 0 - 7\n");
-                break;
-            }
-
-            if (!strcmp(args[1], "rt")) {
-                svc->ioprio_class = IoSchedClass_RT;
-            } else if (!strcmp(args[1], "be")) {
-                svc->ioprio_class = IoSchedClass_BE;
-            } else if (!strcmp(args[1], "idle")) {
-                svc->ioprio_class = IoSchedClass_IDLE;
-            } else {
-                parse_error(state, "ioprio option usage: ioprio <rt|be|idle> <0-7>\n");
-            }
-        }
-        break;
-    case K_group:
-        if (nargs < 2) {
-            parse_error(state, "group option requires a group id\n");
-        } else if (nargs > NR_SVC_SUPP_GIDS + 2) {
-            parse_error(state, "group option accepts at most %d supp. groups\n",
-                        NR_SVC_SUPP_GIDS);
-        } else {
-            int n;
-            svc->gid = decode_uid(args[1]);
-            for (n = 2; n < nargs; n++) {
-                svc->supp_gids[n-2] = decode_uid(args[n]);
-            }
-            svc->nr_supp_gids = n - 2;
-        }
-        break;
-    case K_keycodes:
-        if (nargs < 2) {
-            parse_error(state, "keycodes option requires atleast one keycode\n");
-        } else {
-            svc->keycodes = (int*) malloc((nargs - 1) * sizeof(svc->keycodes[0]));
-            if (!svc->keycodes) {
-                parse_error(state, "could not allocate keycodes\n");
-            } else {
-                svc->nkeycodes = nargs - 1;
-                for (i = 1; i < nargs; i++) {
-                    svc->keycodes[i - 1] = atoi(args[i]);
-                }
-            }
-        }
-        break;
-    case K_oneshot:
-        svc->flags |= SVC_ONESHOT;
-        break;
-    case K_onrestart:
-        nargs--;
-        args++;
-        kw = lookup_keyword(args[0]);
-        if (!kw_is(kw, COMMAND)) {
-            parse_error(state, "invalid command '%s'\n", args[0]);
-            break;
-        }
-        kw_nargs = kw_nargs(kw);
-        if (nargs < kw_nargs) {
-            parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
-                kw_nargs > 2 ? "arguments" : "argument");
-            break;
-        }
-
-        cmd = (command*) malloc(sizeof(*cmd) + sizeof(char*) * nargs);
-        cmd->func = kw_func(kw);
-        cmd->nargs = nargs;
-        memcpy(cmd->args, args, sizeof(char*) * nargs);
-        list_add_tail(&svc->onrestart.commands, &cmd->clist);
-        break;
-    case K_critical:
-        svc->flags |= SVC_CRITICAL;
-        break;
-    case K_setenv: { /* name value */
-        if (nargs < 3) {
-            parse_error(state, "setenv option requires name and value arguments\n");
-            break;
-        }
-        svcenvinfo* ei = (svcenvinfo*) calloc(1, sizeof(*ei));
-        if (!ei) {
-            parse_error(state, "out of memory\n");
-            break;
-        }
-        ei->name = args[1];
-        ei->value = args[2];
-        ei->next = svc->envvars;
-        svc->envvars = ei;
-        break;
-    }
-    case K_socket: {/* name type perm [ uid gid context ] */
-        if (nargs < 4) {
-            parse_error(state, "socket option requires name, type, perm arguments\n");
-            break;
-        }
-        if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")
-                && strcmp(args[2],"seqpacket")) {
-            parse_error(state, "socket type must be 'dgram', 'stream' or 'seqpacket'\n");
-            break;
-        }
-        socketinfo* si = (socketinfo*) calloc(1, sizeof(*si));
-        if (!si) {
-            parse_error(state, "out of memory\n");
-            break;
-        }
-        si->name = args[1];
-        si->type = args[2];
-        si->perm = strtoul(args[3], 0, 8);
-        if (nargs > 4)
-            si->uid = decode_uid(args[4]);
-        if (nargs > 5)
-            si->gid = decode_uid(args[5]);
-        if (nargs > 6)
-            si->socketcon = args[6];
-        si->next = svc->sockets;
-        svc->sockets = si;
-        break;
-    }
-    case K_user:
-        if (nargs != 2) {
-            parse_error(state, "user option requires a user id\n");
-        } else {
-            svc->uid = decode_uid(args[1]);
-        }
-        break;
-    case K_seclabel:
-        if (nargs != 2) {
-            parse_error(state, "seclabel option requires a label string\n");
-        } else {
-            svc->seclabel = args[1];
-        }
-        break;
-    case K_writepid:
-        if (nargs < 2) {
-            parse_error(state, "writepid option requires at least one filename\n");
-            break;
-        }
-        svc->writepid_files_ = new std::vector<std::string>;
-        for (int i = 1; i < nargs; ++i) {
-            svc->writepid_files_->push_back(args[i]);
-        }
-        break;
-
-    default:
-        parse_error(state, "invalid option '%s'\n", args[0]);
+    if (!ret) {
+        parse_error(state, "%s\n", ret_err.c_str());
     }
 }
 
-static void *parse_action(struct parse_state *state, int nargs, char **args)
+static void *parse_action(struct parse_state* state, int nargs, char **args)
 {
-    struct trigger *cur_trigger;
-    int i;
-    if (nargs < 2) {
-        parse_error(state, "actions must have a trigger\n");
-        return 0;
+    std::string ret_err;
+    std::vector<std::string> triggers(args + 1, args + nargs);
+    Action* ret = ActionManager::GetInstance().AddNewAction(triggers, &ret_err);
+
+    if (!ret) {
+        parse_error(state, "%s\n", ret_err.c_str());
     }
 
-    action* act = (action*) calloc(1, sizeof(*act));
-    list_init(&act->triggers);
+    return ret;
+}
 
-    for (i = 1; i < nargs; i++) {
-        if (!(i % 2)) {
-            if (strcmp(args[i], "&&")) {
-                struct listnode *node;
-                struct listnode *node2;
-                parse_error(state, "& is the only symbol allowed to concatenate actions\n");
-                list_for_each_safe(node, node2, &act->triggers) {
-                    struct trigger *trigger = node_to_item(node, struct trigger, nlist);
-                    free(trigger);
-                }
-                free(act);
-                return 0;
-            } else
-                continue;
-        }
-        cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
-        cur_trigger->name = args[i];
-        list_add_tail(&act->triggers, &cur_trigger->nlist);
+bool add_command_to_action(Action* action, const std::vector<std::string>& args,
+                           const std::string& filename, int line, std::string* err)
+{
+    int kw;
+    size_t n;
+
+    kw = lookup_keyword(args[0].c_str());
+    if (!kw_is(kw, COMMAND)) {
+        *err = android::base::StringPrintf("invalid command '%s'\n", args[0].c_str());
+        return false;
     }
 
-    list_init(&act->commands);
-    list_init(&act->qlist);
-    list_add_tail(&action_list, &act->alist);
-        /* XXX add to hash */
-    return act;
+    n = kw_nargs(kw);
+    if (args.size() < n) {
+        *err = android::base::StringPrintf("%s requires %zu %s\n",
+                                           args[0].c_str(), n - 1,
+                                           n > 2 ? "arguments" : "argument");
+        return false;
+    }
+
+    action->AddCommand(kw_func(kw), args, filename, line);
+    return true;
 }
 
 static void parse_line_action(struct parse_state* state, int nargs, char **args)
 {
-    struct action *act = (action*) state->context;
-    int kw, n;
-
     if (nargs == 0) {
         return;
     }
 
-    kw = lookup_keyword(args[0]);
-    if (!kw_is(kw, COMMAND)) {
-        parse_error(state, "invalid command '%s'\n", args[0]);
-        return;
+    Action* action = static_cast<Action*>(state->context);
+    std::vector<std::string> str_args(args, args + nargs);
+    std::string ret_err;
+    bool ret = add_command_to_action(action, str_args, state->filename,
+                                     state->line, &ret_err);
+    if (!ret) {
+        parse_error(state, "%s\n", ret_err.c_str());
     }
-
-    n = kw_nargs(kw);
-    if (nargs < n) {
-        parse_error(state, "%s requires %d %s\n", args[0], n - 1,
-            n > 2 ? "arguments" : "argument");
-        return;
-    }
-    command* cmd = (command*) malloc(sizeof(*cmd) + sizeof(char*) * nargs);
-    cmd->func = kw_func(kw);
-    cmd->line = state->line;
-    cmd->filename = state->filename;
-    cmd->nargs = nargs;
-    memcpy(cmd->args, args, sizeof(char*) * nargs);
-    list_add_tail(&act->commands, &cmd->clist);
 }
diff --git a/init/init_parser.h b/init/init_parser.h
index 1ebb1ef..709dca8 100644
--- a/init/init_parser.h
+++ b/init/init_parser.h
@@ -18,24 +18,15 @@
 #define _INIT_INIT_PARSER_H_
 
 #include <string>
+#include <vector>
 
 #define INIT_PARSER_MAXARGS 64
 
-struct action;
-struct service;
-
-struct action *action_remove_queue_head(void);
-void action_add_queue_tail(struct action *act);
-void action_for_each_trigger(const char *trigger,
-                             void (*func)(struct action *act));
-int action_queue_empty(void);
-void queue_property_triggers(const char *name, const char *value);
-void queue_all_property_triggers();
-void queue_builtin_action(int (*func)(int nargs, char **args), const char *name);
+class Action;
 
 bool init_parse_config(const char* path);
-int expand_props(const char *src, std::string *dst);
-
-service* make_exec_oneshot_service(int argc, char** argv);
+int expand_props(const std::string& src, std::string* dst);
+bool add_command_to_action(Action* action, const std::vector<std::string>& args,
+                           const std::string& filename, int line, std::string* err);
 
 #endif
diff --git a/init/init_parser_test.cpp b/init/init_parser_test.cpp
index 170a73a..52aaa37 100644
--- a/init/init_parser_test.cpp
+++ b/init/init_parser_test.cpp
@@ -17,96 +17,97 @@
 #include "init_parser.h"
 
 #include "init.h"
+#include "service.h"
 #include "util.h"
 
 #include <errno.h>
 #include <gtest/gtest.h>
 
-TEST(init_parser, make_exec_oneshot_service_invalid_syntax) {
-    char* argv[10];
-    memset(argv, 0, sizeof(argv));
+#include <string>
+#include <vector>
 
+TEST(init_parser, make_exec_oneshot_service_invalid_syntax) {
+    ServiceManager& sm = ServiceManager::GetInstance();
+    std::vector<std::string> args;
     // Nothing.
-    ASSERT_EQ(nullptr, make_exec_oneshot_service(0, argv));
+    ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
 
     // No arguments to 'exec'.
-    argv[0] = const_cast<char*>("exec");
-    ASSERT_EQ(nullptr, make_exec_oneshot_service(1, argv));
+    args.push_back("exec");
+    ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
 
     // No command in "exec --".
-    argv[1] = const_cast<char*>("--");
-    ASSERT_EQ(nullptr, make_exec_oneshot_service(2, argv));
+    args.push_back("--");
+    ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
 }
 
 TEST(init_parser, make_exec_oneshot_service_too_many_supplementary_gids) {
-    int argc = 0;
-    char* argv[4 + NR_SVC_SUPP_GIDS + 3];
-    argv[argc++] = const_cast<char*>("exec");
-    argv[argc++] = const_cast<char*>("seclabel");
-    argv[argc++] = const_cast<char*>("root"); // uid.
-    argv[argc++] = const_cast<char*>("root"); // gid.
+    ServiceManager& sm = ServiceManager::GetInstance();
+    std::vector<std::string> args;
+    args.push_back("exec");
+    args.push_back("seclabel");
+    args.push_back("root"); // uid.
+    args.push_back("root"); // gid.
     for (int i = 0; i < NR_SVC_SUPP_GIDS; ++i) {
-        argv[argc++] = const_cast<char*>("root"); // Supplementary gid.
+        args.push_back("root"); // Supplementary gid.
     }
-    argv[argc++] = const_cast<char*>("--");
-    argv[argc++] = const_cast<char*>("/system/bin/id");
-    argv[argc] = nullptr;
-    ASSERT_EQ(nullptr, make_exec_oneshot_service(argc, argv));
+    args.push_back("--");
+    args.push_back("/system/bin/id");
+    ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
 }
 
-static void Test_make_exec_oneshot_service(bool dash_dash, bool seclabel, bool uid, bool gid, bool supplementary_gids) {
-    int argc = 0;
-    char* argv[10];
-    argv[argc++] = const_cast<char*>("exec");
+static void Test_make_exec_oneshot_service(bool dash_dash, bool seclabel, bool uid,
+                                           bool gid, bool supplementary_gids) {
+    ServiceManager& sm = ServiceManager::GetInstance();
+    std::vector<std::string> args;
+    args.push_back("exec");
     if (seclabel) {
-        argv[argc++] = const_cast<char*>("u:r:su:s0"); // seclabel
+        args.push_back("u:r:su:s0"); // seclabel
         if (uid) {
-            argv[argc++] = const_cast<char*>("log");      // uid
+            args.push_back("log");      // uid
             if (gid) {
-                argv[argc++] = const_cast<char*>("shell");     // gid
+                args.push_back("shell");     // gid
                 if (supplementary_gids) {
-                    argv[argc++] = const_cast<char*>("system");    // supplementary gid 0
-                    argv[argc++] = const_cast<char*>("adb");       // supplementary gid 1
+                    args.push_back("system");    // supplementary gid 0
+                    args.push_back("adb");       // supplementary gid 1
                 }
             }
         }
     }
     if (dash_dash) {
-        argv[argc++] = const_cast<char*>("--");
+        args.push_back("--");
     }
-    argv[argc++] = const_cast<char*>("/system/bin/toybox");
-    argv[argc++] = const_cast<char*>("id");
-    argv[argc] = nullptr;
-    service* svc = make_exec_oneshot_service(argc, argv);
+    args.push_back("/system/bin/toybox");
+    args.push_back("id");
+    Service* svc = sm.MakeExecOneshotService(args);
     ASSERT_NE(nullptr, svc);
 
     if (seclabel) {
-        ASSERT_STREQ("u:r:su:s0", svc->seclabel);
+        ASSERT_EQ("u:r:su:s0", svc->seclabel());
     } else {
-        ASSERT_EQ(nullptr, svc->seclabel);
+        ASSERT_EQ("", svc->seclabel());
     }
     if (uid) {
-        ASSERT_EQ(decode_uid("log"), svc->uid);
+        ASSERT_EQ(decode_uid("log"), svc->uid());
     } else {
-        ASSERT_EQ(0U, svc->uid);
+        ASSERT_EQ(0U, svc->uid());
     }
     if (gid) {
-        ASSERT_EQ(decode_uid("shell"), svc->gid);
+        ASSERT_EQ(decode_uid("shell"), svc->gid());
     } else {
-        ASSERT_EQ(0U, svc->gid);
+        ASSERT_EQ(0U, svc->gid());
     }
     if (supplementary_gids) {
-        ASSERT_EQ(2U, svc->nr_supp_gids);
-        ASSERT_EQ(decode_uid("system"), svc->supp_gids[0]);
-        ASSERT_EQ(decode_uid("adb"), svc->supp_gids[1]);
+        ASSERT_EQ(2U, svc->supp_gids().size());
+        ASSERT_EQ(decode_uid("system"), svc->supp_gids()[0]);
+        ASSERT_EQ(decode_uid("adb"), svc->supp_gids()[1]);
     } else {
-        ASSERT_EQ(0U, svc->nr_supp_gids);
+        ASSERT_EQ(0U, svc->supp_gids().size());
     }
 
-    ASSERT_EQ(2, svc->nargs);
-    ASSERT_EQ("/system/bin/toybox", svc->args[0]);
-    ASSERT_EQ("id", svc->args[1]);
-    ASSERT_EQ(nullptr, svc->args[2]);
+    ASSERT_EQ(static_cast<std::size_t>(2), svc->args().size());
+    ASSERT_EQ("/system/bin/toybox", svc->args()[0]);
+    ASSERT_EQ("id", svc->args()[1]);
 }
 
 TEST(init_parser, make_exec_oneshot_service_with_everything) {
diff --git a/init/keychords.cpp b/init/keychords.cpp
index c4ebdf9..7a7838d 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -26,20 +26,21 @@
 #include "init.h"
 #include "log.h"
 #include "property_service.h"
+#include "service.h"
 
 static struct input_keychord *keychords = 0;
 static int keychords_count = 0;
 static int keychords_length = 0;
 static int keychord_fd = -1;
 
-void add_service_keycodes(struct service *svc)
+void add_service_keycodes(Service* svc)
 {
     struct input_keychord *keychord;
-    int i, size;
+    size_t i, size;
 
-    if (svc->keycodes) {
+    if (!svc->keycodes().empty()) {
         /* add a new keychord to the list */
-        size = sizeof(*keychord) + svc->nkeycodes * sizeof(keychord->keycodes[0]);
+        size = sizeof(*keychord) + svc->keycodes().size() * sizeof(keychord->keycodes[0]);
         keychords = (input_keychord*) realloc(keychords, keychords_length + size);
         if (!keychords) {
             ERROR("could not allocate keychords\n");
@@ -51,11 +52,11 @@
         keychord = (struct input_keychord *)((char *)keychords + keychords_length);
         keychord->version = KEYCHORD_VERSION;
         keychord->id = keychords_count + 1;
-        keychord->count = svc->nkeycodes;
-        svc->keychord_id = keychord->id;
+        keychord->count = svc->keycodes().size();
+        svc->set_keychord_id(keychord->id);
 
-        for (i = 0; i < svc->nkeycodes; i++) {
-            keychord->keycodes[i] = svc->keycodes[i];
+        for (i = 0; i < svc->keycodes().size(); i++) {
+            keychord->keycodes[i] = svc->keycodes()[i];
         }
         keychords_count++;
         keychords_length += size;
@@ -63,7 +64,6 @@
 }
 
 static void handle_keychord() {
-    struct service *svc;
     int ret;
     __u16 id;
 
@@ -76,10 +76,10 @@
     // Only handle keychords if adb is enabled.
     std::string adb_enabled = property_get("init.svc.adbd");
     if (adb_enabled == "running") {
-        svc = service_find_by_keychord(id);
+        Service* svc = ServiceManager::GetInstance().FindServiceByKeychord(id);
         if (svc) {
-            INFO("Starting service %s from keychord\n", svc->name);
-            service_start(svc, NULL);
+            INFO("Starting service %s from keychord\n", svc->name().c_str());
+            svc->Start();
         } else {
             ERROR("service for keychord %d not found\n", id);
         }
@@ -87,7 +87,7 @@
 }
 
 void keychord_init() {
-    service_for_each(add_service_keycodes);
+    ServiceManager::GetInstance().ForEachService(add_service_keycodes);
 
     // Nothing to do if no services require keychords.
     if (!keychords) {
diff --git a/init/keywords.h b/init/keywords.h
index e637d7d..922feee 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -1,43 +1,45 @@
 #ifndef KEYWORD
-int do_bootchart_init(int nargs, char **args);
-int do_class_start(int nargs, char **args);
-int do_class_stop(int nargs, char **args);
-int do_class_reset(int nargs, char **args);
-int do_domainname(int nargs, char **args);
-int do_enable(int nargs, char **args);
-int do_exec(int nargs, char **args);
-int do_export(int nargs, char **args);
-int do_hostname(int nargs, char **args);
-int do_ifup(int nargs, char **args);
-int do_insmod(int nargs, char **args);
-int do_installkey(int nargs, char **args);
-int do_mkdir(int nargs, char **args);
-int do_mount_all(int nargs, char **args);
-int do_mount(int nargs, char **args);
-int do_powerctl(int nargs, char **args);
-int do_restart(int nargs, char **args);
-int do_restorecon(int nargs, char **args);
-int do_restorecon_recursive(int nargs, char **args);
-int do_rm(int nargs, char **args);
-int do_rmdir(int nargs, char **args);
-int do_setprop(int nargs, char **args);
-int do_setrlimit(int nargs, char **args);
-int do_start(int nargs, char **args);
-int do_stop(int nargs, char **args);
-int do_swapon_all(int nargs, char **args);
-int do_trigger(int nargs, char **args);
-int do_symlink(int nargs, char **args);
-int do_sysclktz(int nargs, char **args);
-int do_write(int nargs, char **args);
-int do_copy(int nargs, char **args);
-int do_chown(int nargs, char **args);
-int do_chmod(int nargs, char **args);
-int do_loglevel(int nargs, char **args);
-int do_load_persist_props(int nargs, char **args);
-int do_load_all_props(int nargs, char **args);
-int do_verity_load_state(int nargs, char **args);
-int do_verity_update_state(int nargs, char **args);
-int do_wait(int nargs, char **args);
+#include <string>
+#include <vector>
+int do_bootchart_init(const std::vector<std::string>& args);
+int do_class_start(const std::vector<std::string>& args);
+int do_class_stop(const std::vector<std::string>& args);
+int do_class_reset(const std::vector<std::string>& args);
+int do_domainname(const std::vector<std::string>& args);
+int do_enable(const std::vector<std::string>& args);
+int do_exec(const std::vector<std::string>& args);
+int do_export(const std::vector<std::string>& args);
+int do_hostname(const std::vector<std::string>& args);
+int do_ifup(const std::vector<std::string>& args);
+int do_insmod(const std::vector<std::string>& args);
+int do_installkey(const std::vector<std::string>& args);
+int do_mkdir(const std::vector<std::string>& args);
+int do_mount_all(const std::vector<std::string>& args);
+int do_mount(const std::vector<std::string>& args);
+int do_powerctl(const std::vector<std::string>& args);
+int do_restart(const std::vector<std::string>& args);
+int do_restorecon(const std::vector<std::string>& args);
+int do_restorecon_recursive(const std::vector<std::string>& args);
+int do_rm(const std::vector<std::string>& args);
+int do_rmdir(const std::vector<std::string>& args);
+int do_setprop(const std::vector<std::string>& args);
+int do_setrlimit(const std::vector<std::string>& args);
+int do_start(const std::vector<std::string>& args);
+int do_stop(const std::vector<std::string>& args);
+int do_swapon_all(const std::vector<std::string>& args);
+int do_trigger(const std::vector<std::string>& args);
+int do_symlink(const std::vector<std::string>& args);
+int do_sysclktz(const std::vector<std::string>& args);
+int do_write(const std::vector<std::string>& args);
+int do_copy(const std::vector<std::string>& args);
+int do_chown(const std::vector<std::string>& args);
+int do_chmod(const std::vector<std::string>& args);
+int do_loglevel(const std::vector<std::string>& args);
+int do_load_persist_props(const std::vector<std::string>& args);
+int do_load_all_props(const std::vector<std::string>& args);
+int do_verity_load_state(const std::vector<std::string>& args);
+int do_verity_update_state(const std::vector<std::string>& args);
+int do_wait(const std::vector<std::string>& args);
 #define __MAKE_KEYWORD_ENUM__
 #define KEYWORD(symbol, flags, nargs, func) K_##symbol,
 enum {
diff --git a/init/parser/tokenizer.cpp b/init/parser/tokenizer.cpp
new file mode 100644
index 0000000..340e0d9
--- /dev/null
+++ b/init/parser/tokenizer.cpp
@@ -0,0 +1,129 @@
+// 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 "tokenizer.h"
+
+namespace init {
+
+Tokenizer::Tokenizer(const std::string& data)
+    : data_(data), eof_(false), pos_(0), tok_start_(0) {
+  current_.type = TOK_START;
+
+  if (data.size() > 0) {
+    cur_char_ = data[0];
+  } else {
+    eof_ = true;
+    cur_char_ = '\0';
+  }
+}
+
+Tokenizer::~Tokenizer() {}
+
+const Tokenizer::Token& Tokenizer::current() {
+  return current_;
+}
+
+bool Tokenizer::Next() {
+  while (!eof_) {
+    AdvWhiteSpace();
+
+    // Check for comments.
+    if (cur_char_ == '#') {
+      AdvChar();
+      // Skip rest of line
+      while (!eof_ && cur_char_ != '\n') {
+        AdvChar();
+      }
+    }
+
+    if (eof_) {
+      break;
+    }
+
+    if (cur_char_ == '\0') {
+      AdvChar();
+    } else if (cur_char_ == '\n') {
+      current_.type = TOK_NEWLINE;
+      current_.text.clear();
+      AdvChar();
+      return true;
+    } else if (cur_char_ == '\\') {
+      AdvChar();  // skip backslash
+      // This is line continuation so
+      // do not generated TOK_NEWLINE at
+      // the next \n.
+      AdvUntil('\n');
+      AdvChar();  // skip \n
+    } else if (cur_char_ == '\"') {
+      AdvChar();
+      StartText();
+      // Grab everything until the next quote.
+      AdvUntil('\"');
+      EndText();
+      AdvChar();  // skip quote.
+      return true;
+    } else {
+      StartText();
+      AdvText();
+      EndText();
+      return true;
+    }
+  }
+  current_.type = TOK_END;
+  current_.text.clear();
+  return false;
+}
+
+void Tokenizer::AdvChar() {
+  pos_++;
+  if (pos_ < data_.size()) {
+    cur_char_ = data_[pos_];
+  } else {
+    eof_ = true;
+    cur_char_ = '\0';
+  }
+}
+
+void Tokenizer::AdvWhiteSpace() {
+  while (cur_char_ == '\t' || cur_char_ == '\r' || cur_char_ == ' ') {
+    AdvChar();
+  }
+}
+
+void Tokenizer::AdvUntil(char x) {
+  while (!eof_ && cur_char_ != x) {
+    AdvChar();
+  }
+}
+
+void Tokenizer::AdvText() {
+  while (cur_char_ != '\t' && cur_char_ != '\r' && cur_char_ != '\0' &&
+         cur_char_ != ' ' && cur_char_ != '\n' && cur_char_ != '#') {
+    AdvChar();
+  }
+}
+
+void Tokenizer::StartText() {
+  current_.text.clear();
+  tok_start_ = pos_;
+  current_.type = TOK_TEXT;
+}
+
+void Tokenizer::EndText() {
+  if (pos_ != tok_start_) {
+    current_.text.append(data_, tok_start_, pos_ - tok_start_);
+  }
+}
+
+}  // namespace init
\ No newline at end of file
diff --git a/init/parser/tokenizer.h b/init/parser/tokenizer.h
new file mode 100644
index 0000000..8312a08
--- /dev/null
+++ b/init/parser/tokenizer.h
@@ -0,0 +1,74 @@
+// 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 _INIT_PARSER_TOKENIZER_H
+#define _INIT_PARSER_TOKENIZER_H
+
+#include <string>
+
+namespace init {
+
+// Used to tokenize a std::string.
+// Call Next() to advance through each token until it returns false,
+// indicating there are no more tokens left in the string.
+// The current token can be accessed with current(), which returns
+// a Token.
+// Supported tokens are:
+// TOK_START - Next() has yet to be called
+// TOK_END - At the end of string
+// TOK_NEWLINE - The end of a line denoted by \n.
+// TOK_TEXT - A word.
+// Comments are denoted with '#' and the tokenizer will ignore
+// the rest of the line.
+// Double quotes can be used to insert whitespace into words.
+// A backslash at the end of a line denotes continuation and
+// a TOK_NEWLINE will not be generated for that line.
+class Tokenizer {
+ public:
+  Tokenizer(const std::string& data);
+  ~Tokenizer();
+
+  enum TokenType { TOK_START, TOK_END, TOK_NEWLINE, TOK_TEXT };
+  struct Token {
+    TokenType type;
+    std::string text;
+  };
+
+  // Returns the curret token.
+  const Token& current();
+
+  // Move to the next token, returns false at the end of input.
+  bool Next();
+
+ private:
+  void GetData();
+  void AdvChar();
+  void AdvText();
+  void AdvUntil(char x);
+  void AdvWhiteSpace();
+  void StartText();
+  void EndText();
+
+  const std::string& data_;
+  Token current_;
+
+  bool eof_;
+  size_t pos_;
+  char cur_char_;
+  size_t tok_start_;
+};
+
+}  // namespace init
+
+#endif
diff --git a/init/parser/tokenizer_test.cpp b/init/parser/tokenizer_test.cpp
new file mode 100644
index 0000000..c4a48df
--- /dev/null
+++ b/init/parser/tokenizer_test.cpp
@@ -0,0 +1,230 @@
+// 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 "tokenizer.h"
+
+#include <errno.h>
+#include <gtest/gtest.h>
+
+#include <string>
+
+namespace init {
+
+#define SETUP_TEST(test_data)  \
+  std::string data(test_data); \
+  Tokenizer tokenizer(data);   \
+  ASSERT_EQ(Tokenizer::TOK_START, tokenizer.current().type)
+
+#define ASSERT_TEXT_TOKEN(test_text)              \
+  ASSERT_TRUE(tokenizer.Next());                  \
+  ASSERT_EQ(test_text, tokenizer.current().text); \
+  ASSERT_EQ(Tokenizer::TOK_TEXT, tokenizer.current().type)
+
+#define ASSERT_NEWLINE_TOKEN()   \
+  ASSERT_TRUE(tokenizer.Next()); \
+  ASSERT_EQ(Tokenizer::TOK_NEWLINE, tokenizer.current().type)
+
+TEST(Tokenizer, Empty) {
+  SETUP_TEST("");
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, Simple) {
+  SETUP_TEST("test");
+  ASSERT_TEXT_TOKEN("test");
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, LeadingWhiteSpace) {
+  SETUP_TEST(" \t  \r  test");
+  ASSERT_TEXT_TOKEN("test");
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, TrailingWhiteSpace) {
+  SETUP_TEST("test \t  \r  ");
+  ASSERT_TEXT_TOKEN("test");
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, WhiteSpace) {
+  SETUP_TEST(" \t  \r  test \t  \r  ");
+  ASSERT_TEXT_TOKEN("test");
+
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, TwoTokens) {
+  SETUP_TEST("  foo   bar ");
+  ASSERT_TEXT_TOKEN("foo");
+  ASSERT_TEXT_TOKEN("bar");
+
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, MultiToken) {
+  SETUP_TEST("one two three four five");
+  ASSERT_TEXT_TOKEN("one");
+  ASSERT_TEXT_TOKEN("two");
+  ASSERT_TEXT_TOKEN("three");
+  ASSERT_TEXT_TOKEN("four");
+  ASSERT_TEXT_TOKEN("five");
+
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, NewLine) {
+  SETUP_TEST("\n");
+  ASSERT_NEWLINE_TOKEN();
+
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, TextNewLine) {
+  SETUP_TEST("test\n");
+  ASSERT_TEXT_TOKEN("test");
+  ASSERT_NEWLINE_TOKEN();
+
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, MultiTextNewLine) {
+  SETUP_TEST("one\ntwo\nthree\n");
+  ASSERT_TEXT_TOKEN("one");
+  ASSERT_NEWLINE_TOKEN();
+  ASSERT_TEXT_TOKEN("two");
+  ASSERT_NEWLINE_TOKEN();
+  ASSERT_TEXT_TOKEN("three");
+  ASSERT_NEWLINE_TOKEN();
+
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, MultiTextNewLineNoLineEnding) {
+  SETUP_TEST("one\ntwo\nthree");
+  ASSERT_TEXT_TOKEN("one");
+  ASSERT_NEWLINE_TOKEN();
+  ASSERT_TEXT_TOKEN("two");
+  ASSERT_NEWLINE_TOKEN();
+  ASSERT_TEXT_TOKEN("three");
+
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, Comment) {
+  SETUP_TEST("#test");
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, CommentWhiteSpace) {
+  SETUP_TEST(" \t  \r  #test \t  \r  ");
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, CommentNewLine) {
+  SETUP_TEST(" #test   \n");
+  ASSERT_NEWLINE_TOKEN();
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, CommentTwoNewLine) {
+  SETUP_TEST(" #test   \n#test");
+  ASSERT_NEWLINE_TOKEN();
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, CommentWithText) {
+  SETUP_TEST("foo bar #test");
+  ASSERT_TEXT_TOKEN("foo");
+  ASSERT_TEXT_TOKEN("bar");
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, CommentWithTextNoSpace) {
+  SETUP_TEST("foo bar#test");
+  ASSERT_TEXT_TOKEN("foo");
+  ASSERT_TEXT_TOKEN("bar");
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, CommentWithTextLineFeed) {
+  SETUP_TEST("foo bar #test\n");
+  ASSERT_TEXT_TOKEN("foo");
+  ASSERT_TEXT_TOKEN("bar");
+  ASSERT_NEWLINE_TOKEN();
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, CommentWithMultiTextLineFeed) {
+  SETUP_TEST("#blah\nfoo bar #test\n#blah");
+  ASSERT_NEWLINE_TOKEN();
+  ASSERT_TEXT_TOKEN("foo");
+  ASSERT_TEXT_TOKEN("bar");
+  ASSERT_NEWLINE_TOKEN();
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, SimpleEscaped) {
+  SETUP_TEST("fo\\no bar");
+  ASSERT_TEXT_TOKEN("fo\\no");
+  ASSERT_TEXT_TOKEN("bar");
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, EscapedLineContNoLineFeed) {
+  SETUP_TEST("fo\\no bar \\ hello");
+  ASSERT_TEXT_TOKEN("fo\\no");
+  ASSERT_TEXT_TOKEN("bar");
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, EscapedLineContLineFeed) {
+  SETUP_TEST("fo\\no bar \\ hello\n");
+  ASSERT_TEXT_TOKEN("fo\\no");
+  ASSERT_TEXT_TOKEN("bar");
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, EscapedLineCont) {
+  SETUP_TEST("fo\\no bar \\\ntest");
+  ASSERT_TEXT_TOKEN("fo\\no");
+  ASSERT_TEXT_TOKEN("bar");
+  ASSERT_TEXT_TOKEN("test");
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, EscapedLineContWithBadChars) {
+  SETUP_TEST("fo\\no bar \\bad bad bad\ntest");
+  ASSERT_TEXT_TOKEN("fo\\no");
+  ASSERT_TEXT_TOKEN("bar");
+  ASSERT_TEXT_TOKEN("test");
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, SimpleQuotes) {
+  SETUP_TEST("foo \"single token\" bar");
+  ASSERT_TEXT_TOKEN("foo");
+  ASSERT_TEXT_TOKEN("single token");
+  ASSERT_TEXT_TOKEN("bar");
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+TEST(Tokenizer, BadQuotes) {
+  SETUP_TEST("foo \"single token");
+  ASSERT_TEXT_TOKEN("foo");
+  ASSERT_TEXT_TOKEN("single token");
+  ASSERT_FALSE(tokenizer.Next());
+}
+
+}  // namespace init
diff --git a/init/perfboot.py b/init/perfboot.py
index 2cd4699..2a17ab6 100755
--- a/init/perfboot.py
+++ b/init/perfboot.py
@@ -40,6 +40,7 @@
 import argparse
 import atexit
 import cStringIO
+import glob
 import inspect
 import logging
 import math
@@ -66,6 +67,8 @@
     'boot_progress_pms_ready',
     'boot_progress_ams_ready',
     'boot_progress_enable_screen',
+    'sf_stop_bootanim',
+    'wm_boot_animation_done',
 ]
 
 
@@ -139,6 +142,7 @@
         def notify_timeout():
             self._timedout = True
         self._timer = threading.Timer(timeout, notify_timeout)
+        self._timer.daemon = True
         self._timer.start()
 
     def is_timedout(self):
@@ -200,11 +204,21 @@
                 output_results(output, record_list, tags)
             if original_dropbox_max_files is not None:
                 restore_dropbox(device, original_dropbox_max_files)
-        except subprocess.CalledProcessError, RuntimeError:
+        except (subprocess.CalledProcessError, RuntimeError):
             pass
     atexit.register(cleanup)
 
 
+def check_dm_verity_settings(device):
+    device.wait()
+    for partition in ['system', 'vendor']:
+        verity_mode = device.get_prop('partition.%s.verified' % partition)
+        if verity_mode is None:
+            logging.warning('dm-verity is not enabled for /%s. Did you run '
+                            'adb disable-verity? That may skew the result.',
+                            partition)
+
+
 def read_event_tags(tags_file):
     """Reads event tags from |tags_file|."""
     if not tags_file:
@@ -226,6 +240,23 @@
                       '|'.join(tags))
 
 
+def filter_event_tags(tags, device):
+    """Drop unknown tags not listed in device's event-log-tags file."""
+    device.wait()
+    supported_tags = set()
+    for l in device.shell(['cat', '/system/etc/event-log-tags']).splitlines():
+        tokens = l.split(' ')
+        if len(tokens) >= 2:
+            supported_tags.add(tokens[1])
+    filtered = []
+    for tag in tags:
+        if tag in supported_tags:
+            filtered.append(tag)
+        else:
+            logging.warning('Unknown tag \'%s\'. Ignoring...', tag)
+    return filtered
+
+
 def get_values(record, tag):
     """Gets values that matches |tag| from |record|."""
     keys = [key for key in record.keys() if key[0] == tag]
@@ -377,10 +408,21 @@
     parser.add_argument('-t', '--tags', help='Specify the filename from which '
                         'event tags are read. Every line contains one event '
                         'tag and the last event tag is used to detect that '
-                        'the device has finished booting.')
+                        'the device has finished booting unless --end-tag is '
+                        'specified.')
+    parser.add_argument('--end-tag', help='An event tag on which the script '
+                        'stops measuring the boot time.')
+    parser.add_argument('--apk-dir', help='Specify the directory which contains '
+                        'APK files to be installed before measuring boot time.')
     return parser.parse_args()
 
 
+def install_apks(device, apk_dir):
+    for apk in glob.glob(os.path.join(apk_dir, '*.apk')):
+        print 'Installing: ' + apk
+        device.install(apk, replace=True)
+
+
 def main():
     args = parse_args()
     if args.verbose:
@@ -393,13 +435,21 @@
         args.output = 'perf-%s-%s.tsv' % (
             device.get_prop('ro.build.flavor'),
             device.get_prop('ro.build.version.incremental'))
+    check_dm_verity_settings(device)
+
+    if args.apk_dir:
+        install_apks(device, args.apk_dir)
 
     record_list = []
-    event_tags = read_event_tags(args.tags)
+    event_tags = filter_event_tags(read_event_tags(args.tags), device)
+    end_tag = args.end_tag or event_tags[-1]
+    if end_tag not in event_tags:
+        sys.exit('%s is not a valid tag.' % end_tag)
+    event_tags = event_tags[0 : event_tags.index(end_tag) + 1]
     init_perf(device, args.output, record_list, event_tags)
     interval_adjuster = IntervalAdjuster(args.interval, device)
     event_tags_re = make_event_tags_re(event_tags)
-    end_tag = event_tags[-1]
+
     for i in range(args.iterations):
         print 'Run #%d ' % i
         record = do_iteration(
diff --git a/init/readme.txt b/init/readme.txt
index 5a758d7..d70c6f3 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -377,6 +377,29 @@
 bootanimation ends at: 33790 31230 (-2560)
 
 
+Systrace
+--------
+Systrace [1] can be used for obtaining performance analysis reports during boot
+time on userdebug or eng builds.
+Here is an example of trace events of "wm" and "am" categories:
+
+  $ANDROID_BUILD_TOP/external/chromium-trace/systrace.py wm am --boot
+
+This command will cause the device to reboot. After the device is rebooted and
+the boot sequence has finished, the trace report is obtained from the device
+and written as trace.html on the host by hitting Ctrl+C.
+
+LIMITATION
+Recording trace events is started after persistent properties are loaded, so
+the trace events that are emitted before that are not recorded. Several
+services such as vold, surfaceflinger, and servicemanager are affected by this
+limitation since they are started before persistent properties are loaded.
+Zygote initialization and the processes that are forked from the zygote are not
+affected.
+
+[1] http://developer.android.com/tools/help/systrace.html
+
+
 Debugging init
 --------------
 By default, programs executed by init will drop stdout and stderr into
diff --git a/init/service.cpp b/init/service.cpp
new file mode 100644
index 0000000..a370d25
--- /dev/null
+++ b/init/service.cpp
@@ -0,0 +1,805 @@
+/*
+ * 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 "service.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <selinux/selinux.h>
+
+#include <base/file.h>
+#include <base/stringprintf.h>
+#include <cutils/android_reboot.h>
+#include <cutils/sockets.h>
+
+#include "action.h"
+#include "init.h"
+#include "init_parser.h"
+#include "keywords.h"
+#include "log.h"
+#include "property_service.h"
+#include "util.h"
+
+#define CRITICAL_CRASH_THRESHOLD    4       // if we crash >4 times ...
+#define CRITICAL_CRASH_WINDOW       (4*60)  // ... in 4 minutes, goto recovery
+
+SocketInfo::SocketInfo() : uid(0), gid(0), perm(0) {
+}
+
+SocketInfo::SocketInfo(const std::string& name, const std::string& type, uid_t uid,
+                       gid_t gid, int perm, const std::string& socketcon)
+    : name(name), type(type), uid(uid), gid(gid), perm(perm), socketcon(socketcon) {
+}
+
+ServiceEnvironmentInfo::ServiceEnvironmentInfo() {
+}
+
+ServiceEnvironmentInfo::ServiceEnvironmentInfo(const std::string& name,
+                                               const std::string& value)
+    : name(name), value(value) {
+}
+
+Service::Service(const std::string& name, const std::string& classname,
+                 const std::vector<std::string>& args)
+    : name_(name), classname_(classname), flags_(0), pid_(0), time_started_(0),
+      time_crashed_(0), nr_crashed_(0), uid_(0), gid_(0), seclabel_(""),
+      ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), args_(args) {
+    onrestart_.InitSingleTrigger("onrestart");
+}
+
+Service::Service(const std::string& name, const std::string& classname,
+                 unsigned flags, uid_t uid, gid_t gid, const std::vector<gid_t>& supp_gids,
+                 const std::string& seclabel,  const std::vector<std::string>& args)
+    : name_(name), classname_(classname), flags_(flags), pid_(0), time_started_(0),
+      time_crashed_(0), nr_crashed_(0), uid_(uid), gid_(gid), supp_gids_(supp_gids),
+      seclabel_(seclabel), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), args_(args) {
+    onrestart_.InitSingleTrigger("onrestart");
+}
+
+void Service::NotifyStateChange(const std::string& new_state) const {
+    if (!properties_initialized()) {
+        // If properties aren't available yet, we can't set them.
+        return;
+    }
+
+    if ((flags_ & SVC_EXEC) != 0) {
+        // 'exec' commands don't have properties tracking their state.
+        return;
+    }
+
+    std::string prop_name = android::base::StringPrintf("init.svc.%s", name_.c_str());
+    if (prop_name.length() >= PROP_NAME_MAX) {
+        // If the property name would be too long, we can't set it.
+        ERROR("Property name \"init.svc.%s\" too long; not setting to %s\n",
+              name_.c_str(), new_state.c_str());
+        return;
+    }
+
+    property_set(prop_name.c_str(), new_state.c_str());
+}
+
+bool Service::Reap() {
+    if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) {
+        NOTICE("Service '%s' (pid %d) killing any children in process group\n",
+               name_.c_str(), pid_);
+        kill(-pid_, SIGKILL);
+    }
+
+    // Remove any sockets we may have created.
+    for (const auto& si : sockets_) {
+        std::string tmp = android::base::StringPrintf(ANDROID_SOCKET_DIR "/%s",
+                                                      si.name.c_str());
+        unlink(tmp.c_str());
+    }
+
+    if (flags_ & SVC_EXEC) {
+        INFO("SVC_EXEC pid %d finished...\n", pid_);
+        return true;
+    }
+
+    pid_ = 0;
+    flags_ &= (~SVC_RUNNING);
+
+    // Oneshot processes go into the disabled state on exit,
+    // except when manually restarted.
+    if ((flags_ & SVC_ONESHOT) && !(flags_ & SVC_RESTART)) {
+        flags_ |= SVC_DISABLED;
+    }
+
+    // Disabled and reset processes do not get restarted automatically.
+    if (flags_ & (SVC_DISABLED | SVC_RESET))  {
+        NotifyStateChange("stopped");
+        return false;
+    }
+
+    time_t now = gettime();
+    if ((flags_ & SVC_CRITICAL) && !(flags_ & SVC_RESTART)) {
+        if (time_crashed_ + CRITICAL_CRASH_WINDOW >= now) {
+            if (++nr_crashed_ > CRITICAL_CRASH_THRESHOLD) {
+                ERROR("critical process '%s' exited %d times in %d minutes; "
+                      "rebooting into recovery mode\n", name_.c_str(),
+                      CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
+                android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+                return false;
+            }
+        } else {
+            time_crashed_ = now;
+            nr_crashed_ = 1;
+        }
+    }
+
+    flags_ &= (~SVC_RESTART);
+    flags_ |= SVC_RESTARTING;
+
+    // Execute all onrestart commands for this service.
+    onrestart_.ExecuteAllCommands();
+
+    NotifyStateChange("restarting");
+    return false;
+}
+
+void Service::DumpState() const {
+    INFO("service %s\n", name_.c_str());
+    INFO("  class '%s'\n", classname_.c_str());
+    INFO("  exec");
+    for (const auto& s : args_) {
+        INFO(" '%s'", s.c_str());
+    }
+    INFO("\n");
+    for (const auto& si : sockets_) {
+        INFO("  socket %s %s 0%o\n", si.name.c_str(), si.type.c_str(), si.perm);
+    }
+}
+
+bool Service::HandleLine(int kw, const std::vector<std::string>& args, std::string* err) {
+    std::vector<std::string> str_args;
+
+    ioprio_class_ = IoSchedClass_NONE;
+
+    switch (kw) {
+    case K_class:
+        if (args.size() != 2) {
+            *err = "class option requires a classname\n";
+            return false;
+        } else {
+            classname_ = args[1];
+        }
+        break;
+    case K_console:
+        flags_ |= SVC_CONSOLE;
+        break;
+    case K_disabled:
+        flags_ |= SVC_DISABLED;
+        flags_ |= SVC_RC_DISABLED;
+        break;
+    case K_ioprio:
+        if (args.size() != 3) {
+            *err = "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n";
+            return false;
+        } else {
+            ioprio_pri_ = std::stoul(args[2], 0, 8);
+
+            if (ioprio_pri_ < 0 || ioprio_pri_ > 7) {
+                *err = "priority value must be range 0 - 7\n";
+                return false;
+            }
+
+            if (args[1] == "rt") {
+                ioprio_class_ = IoSchedClass_RT;
+            } else if (args[1] == "be") {
+                ioprio_class_ = IoSchedClass_BE;
+            } else if (args[1] == "idle") {
+                ioprio_class_ = IoSchedClass_IDLE;
+            } else {
+                *err = "ioprio option usage: ioprio <rt|be|idle> <0-7>\n";
+                return false;
+            }
+        }
+        break;
+    case K_group:
+        if (args.size() < 2) {
+            *err = "group option requires a group id\n";
+            return false;
+        } else if (args.size() > NR_SVC_SUPP_GIDS + 2) {
+            *err = android::base::StringPrintf("group option accepts at most %d supp. groups\n",
+                                               NR_SVC_SUPP_GIDS);
+            return false;
+        } else {
+            gid_ = decode_uid(args[1].c_str());
+            for (std::size_t n = 2; n < args.size(); n++) {
+                supp_gids_.push_back(decode_uid(args[n].c_str()));
+            }
+        }
+        break;
+    case K_keycodes:
+        if (args.size() < 2) {
+            *err = "keycodes option requires atleast one keycode\n";
+            return false;
+        } else {
+            for (std::size_t i = 1; i < args.size(); i++) {
+                keycodes_.push_back(std::stoi(args[i]));
+            }
+        }
+        break;
+    case K_oneshot:
+        flags_ |= SVC_ONESHOT;
+        break;
+    case K_onrestart:
+        if (args.size() < 2) {
+            return false;
+        }
+        str_args.assign(args.begin() + 1, args.end());
+        add_command_to_action(&onrestart_, str_args, "", 0, err);
+        break;
+    case K_critical:
+        flags_ |= SVC_CRITICAL;
+        break;
+    case K_setenv: { /* name value */
+        if (args.size() < 3) {
+            *err = "setenv option requires name and value arguments\n";
+            return false;
+        }
+
+        envvars_.push_back({args[1], args[2]});
+        break;
+    }
+    case K_socket: {/* name type perm [ uid gid context ] */
+        if (args.size() < 4) {
+            *err = "socket option requires name, type, perm arguments\n";
+            return false;
+        }
+        if (args[2] != "dgram" && args[2] != "stream" &&
+            args[2] != "seqpacket") {
+            *err = "socket type must be 'dgram', 'stream' or 'seqpacket'\n";
+            return false;
+        }
+
+        int perm = std::stoul(args[3], 0, 8);
+        uid_t uid = args.size() > 4 ? decode_uid(args[4].c_str()) : 0;
+        gid_t gid = args.size() > 5 ? decode_uid(args[5].c_str()) : 0;
+        std::string socketcon = args.size() > 6 ? args[6] : "";
+
+        sockets_.push_back({args[1], args[2], uid, gid, perm, socketcon});
+        break;
+    }
+    case K_user:
+        if (args.size() != 2) {
+            *err = "user option requires a user id\n";
+            return false;
+        } else {
+            uid_ = decode_uid(args[1].c_str());
+        }
+        break;
+    case K_seclabel:
+        if (args.size() != 2) {
+            *err = "seclabel option requires a label string\n";
+            return false;
+        } else {
+            seclabel_ = args[1];
+        }
+        break;
+    case K_writepid:
+        if (args.size() < 2) {
+            *err = "writepid option requires at least one filename\n";
+            return false;
+        }
+        writepid_files_.assign(args.begin() + 1, args.end());
+        break;
+
+    default:
+        *err = android::base::StringPrintf("invalid option '%s'\n", args[0].c_str());
+        return false;
+    }
+    return true;
+}
+
+bool Service::Start(const std::vector<std::string>& dynamic_args) {
+    // Starting a service removes it from the disabled or reset state and
+    // immediately takes it out of the restarting state if it was in there.
+    flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
+    time_started_ = 0;
+
+    // Running processes require no additional work --- if they're in the
+    // process of exiting, we've ensured that they will immediately restart
+    // on exit, unless they are ONESHOT.
+    if (flags_ & SVC_RUNNING) {
+        return false;
+    }
+
+    bool needs_console = (flags_ & SVC_CONSOLE);
+    if (needs_console && !have_console) {
+        ERROR("service '%s' requires console\n", name_.c_str());
+        flags_ |= SVC_DISABLED;
+        return false;
+    }
+
+    struct stat sb;
+    if (stat(args_[0].c_str(), &sb) == -1) {
+        ERROR("cannot find '%s' (%s), disabling '%s'\n",
+              args_[0].c_str(), strerror(errno), name_.c_str());
+        flags_ |= SVC_DISABLED;
+        return false;
+    }
+
+    if ((!(flags_ & SVC_ONESHOT)) && !dynamic_args.empty()) {
+        ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
+              args_[0].c_str());
+        flags_ |= SVC_DISABLED;
+        return false;
+    }
+
+    std::string scon;
+    if (!seclabel_.empty()) {
+        scon = seclabel_;
+    } else {
+        char* mycon = nullptr;
+        char* fcon = nullptr;
+
+        INFO("computing context for service '%s'\n", args_[0].c_str());
+        int rc = getcon(&mycon);
+        if (rc < 0) {
+            ERROR("could not get context while starting '%s'\n", name_.c_str());
+            return false;
+        }
+
+        rc = getfilecon(args_[0].c_str(), &fcon);
+        if (rc < 0) {
+            ERROR("could not get context while starting '%s'\n", name_.c_str());
+            free(mycon);
+            return false;
+        }
+
+        char* ret_scon = nullptr;
+        rc = security_compute_create(mycon, fcon, string_to_security_class("process"),
+                                     &ret_scon);
+        if (rc == 0) {
+            scon = ret_scon;
+            free(ret_scon);
+        }
+        if (rc == 0 && scon == mycon) {
+            ERROR("Service %s does not have a SELinux domain defined.\n", name_.c_str());
+            free(mycon);
+            free(fcon);
+            return false;
+        }
+        free(mycon);
+        free(fcon);
+        if (rc < 0) {
+            ERROR("could not get context while starting '%s'\n", name_.c_str());
+            return false;
+        }
+    }
+
+    NOTICE("Starting service '%s'...\n", name_.c_str());
+
+    pid_t pid = fork();
+    if (pid == 0) {
+        int fd, sz;
+
+        umask(077);
+        if (properties_initialized()) {
+            get_property_workspace(&fd, &sz);
+            std::string tmp = android::base::StringPrintf("%d,%d", dup(fd), sz);
+            add_environment("ANDROID_PROPERTY_WORKSPACE", tmp.c_str());
+        }
+
+        for (const auto& ei : envvars_) {
+            add_environment(ei.name.c_str(), ei.value.c_str());
+        }
+
+        for (const auto& si : sockets_) {
+            int socket_type = ((si.type == "stream" ? SOCK_STREAM :
+                                (si.type == "dgram" ? SOCK_DGRAM :
+                                 SOCK_SEQPACKET)));
+            const char* socketcon =
+                !si.socketcon.empty() ? si.socketcon.c_str() : scon.c_str();
+
+            int s = create_socket(si.name.c_str(), socket_type, si.perm,
+                                  si.uid, si.gid, socketcon);
+            if (s >= 0) {
+                PublishSocket(si.name, s);
+            }
+        }
+
+        std::string pid_str = android::base::StringPrintf("%d", pid);
+        for (const auto& file : writepid_files_) {
+            if (!android::base::WriteStringToFile(pid_str, file)) {
+                ERROR("couldn't write %s to %s: %s\n",
+                      pid_str.c_str(), file.c_str(), strerror(errno));
+            }
+        }
+
+        if (ioprio_class_ != IoSchedClass_NONE) {
+            if (android_set_ioprio(getpid(), ioprio_class_, ioprio_pri_)) {
+                ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
+                      getpid(), ioprio_class_, ioprio_pri_, strerror(errno));
+            }
+        }
+
+        if (needs_console) {
+            setsid();
+            OpenConsole();
+        } else {
+            ZapStdio();
+        }
+
+        setpgid(0, getpid());
+
+        // As requested, set our gid, supplemental gids, and uid.
+        if (gid_) {
+            if (setgid(gid_) != 0) {
+                ERROR("setgid failed: %s\n", strerror(errno));
+                _exit(127);
+            }
+        }
+        if (!supp_gids_.empty()) {
+            if (setgroups(supp_gids_.size(), &supp_gids_[0]) != 0) {
+                ERROR("setgroups failed: %s\n", strerror(errno));
+                _exit(127);
+            }
+        }
+        if (uid_) {
+            if (setuid(uid_) != 0) {
+                ERROR("setuid failed: %s\n", strerror(errno));
+                _exit(127);
+            }
+        }
+        if (!seclabel_.empty()) {
+            if (setexeccon(seclabel_.c_str()) < 0) {
+                ERROR("cannot setexeccon('%s'): %s\n",
+                      seclabel_.c_str(), strerror(errno));
+                _exit(127);
+            }
+        }
+
+        std::vector<char*> strs;
+        for (const auto& s : args_) {
+            strs.push_back(const_cast<char*>(s.c_str()));
+        }
+        for (const auto& s : dynamic_args) {
+            strs.push_back(const_cast<char*>(s.c_str()));
+        }
+        strs.push_back(nullptr);
+        if (execve(args_[0].c_str(), (char**) &strs[0], (char**) ENV) < 0) {
+            ERROR("cannot execve('%s'): %s\n", args_[0].c_str(), strerror(errno));
+        }
+
+        _exit(127);
+    }
+
+    if (pid < 0) {
+        ERROR("failed to start '%s'\n", name_.c_str());
+        pid_ = 0;
+        return false;
+    }
+
+    time_started_ = gettime();
+    pid_ = pid;
+    flags_ |= SVC_RUNNING;
+
+    if ((flags_ & SVC_EXEC) != 0) {
+        INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n",
+             pid_, uid_, gid_, supp_gids_.size(),
+             !seclabel_.empty() ? seclabel_.c_str() : "default");
+    }
+
+    NotifyStateChange("running");
+    return true;
+}
+
+bool Service::Start() {
+    const std::vector<std::string> null_dynamic_args;
+    return Start(null_dynamic_args);
+}
+
+bool Service::StartIfNotDisabled() {
+    if (!(flags_ & SVC_DISABLED)) {
+        return Start();
+    } else {
+        flags_ |= SVC_DISABLED_START;
+    }
+    return true;
+}
+
+bool Service::Enable() {
+    flags_ &= ~(SVC_DISABLED | SVC_RC_DISABLED);
+    if (flags_ & SVC_DISABLED_START) {
+        return Start();
+    }
+    return true;
+}
+
+void Service::Reset() {
+    StopOrReset(SVC_RESET);
+}
+
+void Service::Stop() {
+    StopOrReset(SVC_DISABLED);
+}
+
+void Service::Restart() {
+    if (flags_ & SVC_RUNNING) {
+        /* Stop, wait, then start the service. */
+        StopOrReset(SVC_RESTART);
+    } else if (!(flags_ & SVC_RESTARTING)) {
+        /* Just start the service since it's not running. */
+        Start();
+    } /* else: Service is restarting anyways. */
+}
+
+void Service::RestartIfNeeded(time_t& process_needs_restart) {
+    time_t next_start_time = time_started_ + 5;
+
+    if (next_start_time <= gettime()) {
+        flags_ &= (~SVC_RESTARTING);
+        Start();
+        return;
+    }
+
+    if ((next_start_time < process_needs_restart) ||
+        (process_needs_restart == 0)) {
+        process_needs_restart = next_start_time;
+    }
+}
+
+/* The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART */
+void Service::StopOrReset(int how) {
+    /* The service is still SVC_RUNNING until its process exits, but if it has
+     * already exited it shoudn't attempt a restart yet. */
+    flags_ &= ~(SVC_RESTARTING | SVC_DISABLED_START);
+
+    if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) {
+        /* Hrm, an illegal flag.  Default to SVC_DISABLED */
+        how = SVC_DISABLED;
+    }
+        /* if the service has not yet started, prevent
+         * it from auto-starting with its class
+         */
+    if (how == SVC_RESET) {
+        flags_ |= (flags_ & SVC_RC_DISABLED) ? SVC_DISABLED : SVC_RESET;
+    } else {
+        flags_ |= how;
+    }
+
+    if (pid_) {
+        NOTICE("Service '%s' is being killed...\n", name_.c_str());
+        kill(-pid_, SIGKILL);
+        NotifyStateChange("stopping");
+    } else {
+        NotifyStateChange("stopped");
+    }
+}
+
+void Service::ZapStdio() const {
+    int fd;
+    fd = open("/dev/null", O_RDWR);
+    dup2(fd, 0);
+    dup2(fd, 1);
+    dup2(fd, 2);
+    close(fd);
+}
+
+void Service::OpenConsole() const {
+    int fd;
+    if ((fd = open(console_name.c_str(), O_RDWR)) < 0) {
+        fd = open("/dev/null", O_RDWR);
+    }
+    ioctl(fd, TIOCSCTTY, 0);
+    dup2(fd, 0);
+    dup2(fd, 1);
+    dup2(fd, 2);
+    close(fd);
+}
+
+void Service::PublishSocket(const std::string& name, int fd) const {
+    std::string key = android::base::StringPrintf(ANDROID_SOCKET_ENV_PREFIX "%s",
+                                                  name.c_str());
+    std::string val = android::base::StringPrintf("%d", fd);
+    add_environment(key.c_str(), val.c_str());
+
+    /* make sure we don't close-on-exec */
+    fcntl(fd, F_SETFD, 0);
+}
+
+int ServiceManager::exec_count_ = 0;
+
+ServiceManager::ServiceManager() {
+}
+
+ServiceManager& ServiceManager::GetInstance() {
+    static ServiceManager instance;
+    return instance;
+}
+
+Service* ServiceManager::AddNewService(const std::string& name,
+                                       const std::string& classname,
+                                       const std::vector<std::string>& args,
+                                       std::string* err) {
+    if (!IsValidName(name)) {
+        *err = android::base::StringPrintf("invalid service name '%s'\n", name.c_str());
+        return nullptr;
+    }
+
+    Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
+    if (svc) {
+        *err = android::base::StringPrintf("ignored duplicate definition of service '%s'\n",
+                                           name.c_str());
+        return nullptr;
+    }
+
+    std::unique_ptr<Service> svc_p(new Service(name, classname, args));
+    if (!svc_p) {
+        ERROR("Couldn't allocate service for service '%s'", name.c_str());
+        return nullptr;
+    }
+    svc = svc_p.get();
+    services_.push_back(std::move(svc_p));
+
+    return svc;
+}
+
+Service* ServiceManager::MakeExecOneshotService(const std::vector<std::string>& args) {
+    // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
+    // SECLABEL can be a - to denote default
+    std::size_t command_arg = 1;
+    for (std::size_t i = 1; i < args.size(); ++i) {
+        if (args[i] == "--") {
+            command_arg = i + 1;
+            break;
+        }
+    }
+    if (command_arg > 4 + NR_SVC_SUPP_GIDS) {
+        ERROR("exec called with too many supplementary group ids\n");
+        return nullptr;
+    }
+
+    if (command_arg >= args.size()) {
+        ERROR("exec called without command\n");
+        return nullptr;
+    }
+    std::vector<std::string> str_args(args.begin() + command_arg, args.end());
+
+    exec_count_++;
+    std::string name = android::base::StringPrintf("exec %d (%s)", exec_count_,
+                                                   str_args[0].c_str());
+    unsigned flags = SVC_EXEC | SVC_ONESHOT;
+
+    std::string seclabel = "";
+    if (command_arg > 2 && args[1] != "-") {
+        seclabel = args[1];
+    }
+    uid_t uid = 0;
+    if (command_arg > 3) {
+        uid = decode_uid(args[2].c_str());
+    }
+    gid_t gid = 0;
+    std::vector<gid_t> supp_gids;
+    if (command_arg > 4) {
+        gid = decode_uid(args[3].c_str());
+        std::size_t nr_supp_gids = command_arg - 1 /* -- */ - 4 /* exec SECLABEL UID GID */;
+        for (size_t i = 0; i < nr_supp_gids; ++i) {
+            supp_gids.push_back(decode_uid(args[4 + i].c_str()));
+        }
+    }
+
+    std::unique_ptr<Service> svc_p(new Service(name, "default", flags, uid, gid,
+                                               supp_gids, seclabel, str_args));
+    if (!svc_p) {
+        ERROR("Couldn't allocate service for exec of '%s'",
+              str_args[0].c_str());
+        return nullptr;
+    }
+    Service* svc = svc_p.get();
+    services_.push_back(std::move(svc_p));
+
+    return svc;
+}
+
+Service* ServiceManager::FindServiceByName(const std::string& name) const {
+    auto svc = std::find_if(services_.begin(), services_.end(),
+                            [&name] (const std::unique_ptr<Service>& s) {
+                                return name == s->name();
+                            });
+    if (svc != services_.end()) {
+        return svc->get();
+    }
+    return nullptr;
+}
+
+Service* ServiceManager::FindServiceByPid(pid_t pid) const {
+    auto svc = std::find_if(services_.begin(), services_.end(),
+                            [&pid] (const std::unique_ptr<Service>& s) {
+                                return s->pid() == pid;
+                            });
+    if (svc != services_.end()) {
+        return svc->get();
+    }
+    return nullptr;
+}
+
+Service* ServiceManager::FindServiceByKeychord(int keychord_id) const {
+    auto svc = std::find_if(services_.begin(), services_.end(),
+                            [&keychord_id] (const std::unique_ptr<Service>& s) {
+                                return s->keychord_id() == keychord_id;
+                            });
+
+    if (svc != services_.end()) {
+        return svc->get();
+    }
+    return nullptr;
+}
+
+void ServiceManager::ForEachService(void (*func)(Service* svc)) const {
+    for (const auto& s : services_) {
+        func(s.get());
+    }
+}
+
+void ServiceManager::ForEachServiceInClass(const std::string& classname,
+                                           void (*func)(Service* svc)) const {
+    for (const auto& s : services_) {
+        if (classname == s->classname()) {
+            func(s.get());
+        }
+    }
+}
+
+void ServiceManager::ForEachServiceWithFlags(unsigned matchflags,
+                                             void (*func)(Service* svc)) const {
+    for (const auto& s : services_) {
+        if (s->flags() & matchflags) {
+            func(s.get());
+        }
+    }
+}
+
+void ServiceManager::RemoveService(const Service& svc)
+{
+    auto svc_it = std::find_if(services_.begin(), services_.end(),
+                               [&svc] (const std::unique_ptr<Service>& s) {
+                                   return svc.name() == s->name();
+                               });
+    if (svc_it == services_.end()) {
+        return;
+    }
+
+    services_.erase(svc_it);
+}
+
+bool ServiceManager::IsValidName(const std::string& name) const
+{
+    if (name.size() > 16) {
+        return false;
+    }
+    for (const auto& c : name) {
+        if (!isalnum(c) && (c != '_') && (c != '-')) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void ServiceManager::DumpState() const
+{
+    for (const auto& s : services_) {
+        s->DumpState();
+    }
+    INFO("\n");
+}
diff --git a/init/service.h b/init/service.h
new file mode 100644
index 0000000..1ecf78a
--- /dev/null
+++ b/init/service.h
@@ -0,0 +1,167 @@
+/*
+ * 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 _INIT_SERVICE_H
+#define _INIT_SERVICE_H
+
+#include <sys/types.h>
+
+#include <cutils/iosched_policy.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "action.h"
+
+#define SVC_DISABLED       0x001  // do not autostart with class
+#define SVC_ONESHOT        0x002  // do not restart on exit
+#define SVC_RUNNING        0x004  // currently active
+#define SVC_RESTARTING     0x008  // waiting to restart
+#define SVC_CONSOLE        0x010  // requires console
+#define SVC_CRITICAL       0x020  // will reboot into recovery if keeps crashing
+#define SVC_RESET          0x040  // Use when stopping a process,
+                                  // but not disabling so it can be restarted with its class.
+#define SVC_RC_DISABLED    0x080  // Remember if the disabled flag was set in the rc script.
+#define SVC_RESTART        0x100  // Use to safely restart (stop, wait, start) a service.
+#define SVC_DISABLED_START 0x200  // A start was requested but it was disabled at the time.
+#define SVC_EXEC           0x400  // This synthetic service corresponds to an 'exec'.
+
+#define NR_SVC_SUPP_GIDS 12    // twelve supplementary groups
+
+class Action;
+class ServiceManager;
+
+struct SocketInfo {
+    SocketInfo();
+    SocketInfo(const std::string& name, const std::string& type, uid_t uid,
+                       gid_t gid, int perm, const std::string& socketcon);
+    std::string name;
+    std::string type;
+    uid_t uid;
+    gid_t gid;
+    int perm;
+    std::string socketcon;
+};
+
+struct ServiceEnvironmentInfo {
+    ServiceEnvironmentInfo();
+    ServiceEnvironmentInfo(const std::string& name, const std::string& value);
+    std::string name;
+    std::string value;
+};
+
+class Service {
+public:
+    Service(const std::string& name, const std::string& classname,
+            const std::vector<std::string>& args);
+
+    Service(const std::string& name, const std::string& classname,
+            unsigned flags, uid_t uid, gid_t gid, const std::vector<gid_t>& supp_gids,
+            const std::string& seclabel,  const std::vector<std::string>& args);
+
+    bool HandleLine(int kw, const std::vector<std::string>& args, std::string* err);
+    bool Start(const std::vector<std::string>& dynamic_args);
+    bool Start();
+    bool StartIfNotDisabled();
+    bool Enable();
+    void Reset();
+    void Stop();
+    void Restart();
+    void RestartIfNeeded(time_t& process_needs_restart);
+    bool Reap();
+    void DumpState() const;
+
+    const std::string& name() const { return name_; }
+    const std::string& classname() const { return classname_; }
+    unsigned flags() const { return flags_; }
+    pid_t pid() const { return pid_; }
+    uid_t uid() const { return uid_; }
+    gid_t gid() const { return gid_; }
+    const std::vector<gid_t>& supp_gids() const { return supp_gids_; }
+    const std::string& seclabel() const { return seclabel_; }
+    const std::vector<int>& keycodes() const { return keycodes_; }
+    int keychord_id() const { return keychord_id_; }
+    void set_keychord_id(int keychord_id) { keychord_id_ = keychord_id; }
+    const std::vector<std::string>& args() const { return args_; }
+
+private:
+    void NotifyStateChange(const std::string& new_state) const;
+    void StopOrReset(int how);
+    void ZapStdio() const;
+    void OpenConsole() const;
+    void PublishSocket(const std::string& name, int fd) const;
+
+    std::string name_;
+    std::string classname_;
+
+    unsigned flags_;
+    pid_t pid_;
+    time_t time_started_;    // time of last start
+    time_t time_crashed_;    // first crash within inspection window
+    int nr_crashed_;         // number of times crashed within window
+
+    uid_t uid_;
+    gid_t gid_;
+    std::vector<gid_t> supp_gids_;
+
+    std::string seclabel_;
+
+    std::vector<SocketInfo> sockets_;
+    std::vector<ServiceEnvironmentInfo> envvars_;
+
+    Action onrestart_;  // Commands to execute on restart.
+
+    std::vector<std::string> writepid_files_;
+
+    // keycodes for triggering this service via /dev/keychord
+    std::vector<int> keycodes_;
+    int keychord_id_;
+
+    IoSchedClass ioprio_class_;
+    int ioprio_pri_;
+
+    std::vector<std::string> args_;
+};
+
+class ServiceManager {
+public:
+    static ServiceManager& GetInstance();
+
+    Service* AddNewService(const std::string& name, const std::string& classname,
+                                           const std::vector<std::string>& args,
+                                           std::string* err);
+    Service* MakeExecOneshotService(const std::vector<std::string>& args);
+    Service* FindServiceByName(const std::string& name) const;
+    Service* FindServiceByPid(pid_t pid) const;
+    Service* FindServiceByKeychord(int keychord_id) const;
+    void ForEachService(void (*func)(Service* svc)) const;
+    void ForEachServiceInClass(const std::string& classname,
+                               void (*func)(Service* svc)) const;
+    void ForEachServiceWithFlags(unsigned matchflags,
+                             void (*func)(Service* svc)) const;
+    void RemoveService(const Service& svc);
+    void DumpState() const;
+private:
+    ServiceManager();
+
+    bool IsValidName(const std::string& name) const;
+
+    static int exec_count_; // Every service needs a unique name.
+    std::vector<std::unique_ptr<Service>> services_;
+};
+
+#endif
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index 6893163..867abbc 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -28,13 +28,12 @@
 #include <cutils/list.h>
 #include <cutils/sockets.h>
 
+#include "action.h"
 #include "init.h"
 #include "log.h"
+#include "service.h"
 #include "util.h"
 
-#define CRITICAL_CRASH_THRESHOLD    4       /* if we crash >4 times ... */
-#define CRITICAL_CRASH_WINDOW       (4*60)  /* ... in 4 minutes, goto recovery */
-
 static int signal_write_fd = -1;
 static int signal_read_fd = -1;
 
@@ -60,11 +59,11 @@
         return false;
     }
 
-    service* svc = service_find_by_pid(pid);
+    Service* svc = ServiceManager::GetInstance().FindServiceByPid(pid);
 
     std::string name;
     if (svc) {
-        name = android::base::StringPrintf("Service '%s' (pid %d)", svc->name, pid);
+        name = android::base::StringPrintf("Service '%s' (pid %d)", svc->name().c_str(), pid);
     } else {
         name = android::base::StringPrintf("Untracked pid %d", pid);
     }
@@ -75,77 +74,11 @@
         return true;
     }
 
-    // TODO: all the code from here down should be a member function on service.
-
-    if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {
-        NOTICE("Service '%s' (pid %d) killing any children in process group\n", svc->name, pid);
-        kill(-pid, SIGKILL);
-    }
-
-    // Remove any sockets we may have created.
-    for (socketinfo* si = svc->sockets; si; si = si->next) {
-        char tmp[128];
-        snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
-        unlink(tmp);
-    }
-
-    if (svc->flags & SVC_EXEC) {
-        INFO("SVC_EXEC pid %d finished...\n", svc->pid);
+    if (svc->Reap()) {
         waiting_for_exec = false;
-        list_remove(&svc->slist);
-        free(svc->name);
-        free(svc);
-        return true;
+        ServiceManager::GetInstance().RemoveService(*svc);
     }
 
-    svc->pid = 0;
-    svc->flags &= (~SVC_RUNNING);
-
-    // Oneshot processes go into the disabled state on exit,
-    // except when manually restarted.
-    if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {
-        svc->flags |= SVC_DISABLED;
-    }
-
-    // Disabled and reset processes do not get restarted automatically.
-    if (svc->flags & (SVC_DISABLED | SVC_RESET))  {
-        svc->NotifyStateChange("stopped");
-        return true;
-    }
-
-    time_t now = gettime();
-    if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) {
-        if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
-            if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
-                ERROR("critical process '%s' exited %d times in %d minutes; "
-                      "rebooting into recovery mode\n", svc->name,
-                      CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
-                android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
-                return true;
-            }
-        } else {
-            svc->time_crashed = now;
-            svc->nr_crashed = 1;
-        }
-    }
-
-    svc->flags &= (~SVC_RESTART);
-    svc->flags |= SVC_RESTARTING;
-
-    // Execute all onrestart commands for this service.
-    struct listnode* node;
-    list_for_each(node, &svc->onrestart.commands) {
-        command* cmd = node_to_item(node, struct command, clist);
-        std::vector<std::string> arg_strs;
-        if (expand_command_arguments(cmd->nargs, cmd->args, &arg_strs)) {
-            std::vector<char*> args;
-            for (auto& s : arg_strs) {
-                args.push_back(&s[0]);
-            }
-            cmd->func(args.size(), &args[0]);
-        }
-    }
-    svc->NotifyStateChange("restarting");
     return true;
 }
 
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 128bb04..97f0ef4 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -102,6 +102,11 @@
   uintptr_t relative_pc = BacktraceMap::GetRelativePc(frame->map, frame->pc);
 
   std::string line(StringPrintf("#%02zu pc %" PRIPTR "  %s", frame->num, relative_pc, map_name));
+  // Special handling for non-zero offset maps, we need to print that
+  // information.
+  if (frame->map.offset != 0) {
+    line += " (offset " + StringPrintf("0x%" PRIxPTR, frame->map.offset) + ")";
+  }
   if (!frame->func_name.empty()) {
     line += " (" + frame->func_name;
     if (frame->func_offset) {
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 6bd7529..9ebd639 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -825,6 +825,15 @@
   EXPECT_EQ("#01 pc 123456dc  MapFake (ProcFake+645)",
 #endif
             backtrace->FormatFrameData(&frame));
+
+  // Check a non-zero map offset.
+  frame.map.offset = 0x1000;
+#if defined(__LP64__)
+  EXPECT_EQ("#01 pc 00000000123456dc  MapFake (offset 0x1000) (ProcFake+645)",
+#else
+  EXPECT_EQ("#01 pc 123456dc  MapFake (offset 0x1000) (ProcFake+645)",
+#endif
+            backtrace->FormatFrameData(&frame));
 }
 
 struct map_test_t {
diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c
index 8946d3c..71bc94b 100644
--- a/libcutils/iosched_policy.c
+++ b/libcutils/iosched_policy.c
@@ -23,7 +23,7 @@
 
 #include <cutils/iosched_policy.h>
 
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
 #include <linux/ioprio.h>
 #include <sys/syscall.h>
 #define __android_unused
@@ -32,7 +32,7 @@
 #endif
 
 int android_set_ioprio(int pid __android_unused, IoSchedClass clazz __android_unused, int ioprio __android_unused) {
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
     if (syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, ioprio | (clazz << IOPRIO_CLASS_SHIFT))) {
         return -1;
     }
@@ -41,7 +41,7 @@
 }
 
 int android_get_ioprio(int pid __android_unused, IoSchedClass *clazz, int *ioprio) {
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
     int rc;
 
     if ((rc = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, pid)) < 0) {
diff --git a/libcutils/process_name.c b/libcutils/process_name.c
index cc931eb..5d28b6f 100644
--- a/libcutils/process_name.c
+++ b/libcutils/process_name.c
@@ -25,19 +25,19 @@
 #include <unistd.h>
 
 #include <cutils/process_name.h>
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
 #include <cutils/properties.h>
 #endif
 
 #define PROCESS_NAME_DEVICE "/sys/qemu_trace/process_name"
 
 static const char* process_name = "unknown";
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
 static int running_in_emulator = -1;
 #endif
 
 void set_process_name(const char* new_name) {
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
     char  propBuf[PROPERTY_VALUE_MAX];
 #endif
 
@@ -59,7 +59,7 @@
     }
 #endif
 
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
     // If we know we are not running in the emulator, then return.
     if (running_in_emulator == 0) {
         return;
diff --git a/libcutils/record_stream.c b/libcutils/record_stream.c
index 6994904..2bc4226 100644
--- a/libcutils/record_stream.c
+++ b/libcutils/record_stream.c
@@ -22,7 +22,7 @@
 #include <cutils/record_stream.h>
 #include <string.h>
 #include <stdint.h>
-#ifdef HAVE_WINSOCK
+#if defined(_WIN32)
 #include <winsock2.h>   /* for ntohl */
 #else
 #include <netinet/in.h>
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index dfc8777..103ff66 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -37,7 +37,7 @@
    return p == SP_DEFAULT ? SP_SYSTEM_DEFAULT : p;
 }
 
-#if defined(HAVE_ANDROID_OS)
+#if defined(__ANDROID__)
 
 #include <pthread.h>
 #include <sched.h>
@@ -142,7 +142,7 @@
  */
 static int getSchedulerGroup(int tid, char* buf, size_t bufLen)
 {
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
     char pathBuf[32];
     char lineBuf[256];
     FILE *fp;
diff --git a/libcutils/socket_inaddr_any_server.c b/libcutils/socket_inaddr_any_server.c
index 6c849de..7f0ccb8 100644
--- a/libcutils/socket_inaddr_any_server.c
+++ b/libcutils/socket_inaddr_any_server.c
@@ -20,7 +20,7 @@
 #include <string.h>
 #include <unistd.h>
 
-#ifndef HAVE_WINSOCK
+#if !defined(_WIN32)
 #include <sys/socket.h>
 #include <sys/select.h>
 #include <sys/types.h>
diff --git a/libcutils/socket_local_client.c b/libcutils/socket_local_client.c
index 7b42daa..2526146 100644
--- a/libcutils/socket_local_client.c
+++ b/libcutils/socket_local_client.c
@@ -22,7 +22,7 @@
 
 #include <cutils/sockets.h>
 
-#ifdef HAVE_WINSOCK
+#if defined(_WIN32)
 
 int socket_local_client(const char *name, int namespaceId, int type)
 {
@@ -30,7 +30,7 @@
     return -1;
 }
 
-#else /* !HAVE_WINSOCK */
+#else /* !_WIN32 */
 
 #include <sys/socket.h>
 #include <sys/un.h>
@@ -165,4 +165,4 @@
     return s;
 }
 
-#endif /* !HAVE_WINSOCK */
+#endif /* !_WIN32 */
diff --git a/libcutils/socket_local_server.c b/libcutils/socket_local_server.c
index 60eb86b..c9acdad 100644
--- a/libcutils/socket_local_server.c
+++ b/libcutils/socket_local_server.c
@@ -23,7 +23,7 @@
 #include <errno.h>
 #include <stddef.h>
 
-#ifdef HAVE_WINSOCK
+#if defined(_WIN32)
 
 int socket_local_server(const char *name, int namespaceId, int type)
 {
@@ -31,7 +31,7 @@
     return -1;
 }
 
-#else /* !HAVE_WINSOCK */
+#else /* !_WIN32 */
 
 #include <sys/socket.h>
 #include <sys/un.h>
@@ -123,4 +123,4 @@
     return s;
 }
 
-#endif /* !HAVE_WINSOCK */
+#endif /* !_WIN32 */
diff --git a/libcutils/socket_loopback_client.c b/libcutils/socket_loopback_client.c
index 9aed7b7..e14cffb 100644
--- a/libcutils/socket_loopback_client.c
+++ b/libcutils/socket_loopback_client.c
@@ -20,7 +20,7 @@
 #include <string.h>
 #include <unistd.h>
 
-#ifndef HAVE_WINSOCK
+#if !defined(_WIN32)
 #include <sys/socket.h>
 #include <sys/select.h>
 #include <sys/types.h>
diff --git a/libcutils/socket_loopback_server.c b/libcutils/socket_loopback_server.c
index 71afce7..b600e34 100644
--- a/libcutils/socket_loopback_server.c
+++ b/libcutils/socket_loopback_server.c
@@ -22,7 +22,7 @@
 
 #define LISTEN_BACKLOG 4
 
-#ifndef HAVE_WINSOCK
+#if !defined(_WIN32)
 #include <sys/socket.h>
 #include <sys/select.h>
 #include <sys/types.h>
diff --git a/libcutils/sockets.c b/libcutils/sockets.c
index 15ede2b..d438782 100644
--- a/libcutils/sockets.c
+++ b/libcutils/sockets.c
@@ -17,7 +17,7 @@
 #include <cutils/sockets.h>
 #include <log/log.h>
 
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
 /* For the socket trust (credentials) check */
 #include <private/android_filesystem_config.h>
 #define __android_unused
@@ -27,7 +27,7 @@
 
 bool socket_peer_is_trusted(int fd __android_unused)
 {
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
     struct ucred cr;
     socklen_t len = sizeof(cr);
     int n = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
diff --git a/liblog/log_read.c b/liblog/log_read.c
index 9c4af30..cfc8a7a 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -37,7 +37,7 @@
 /* branchless on many architectures. */
 #define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
 
-#if (defined(USE_MINGW) || defined(HAVE_WINSOCK))
+#if defined(_WIN32)
 #define WEAK static
 #else
 #define WEAK __attribute__((weak))
@@ -48,7 +48,7 @@
 
 /* Private copy of ../libcutils/socket_local_client.c prevent library loops */
 
-#ifdef HAVE_WINSOCK
+#if defined(_WIN32)
 
 int WEAK socket_local_client(const char *name, int namespaceId, int type)
 {
@@ -56,7 +56,7 @@
     return -ENOSYS;
 }
 
-#else /* !HAVE_WINSOCK */
+#else /* !_WIN32 */
 
 #include <sys/socket.h>
 #include <sys/un.h>
@@ -193,7 +193,7 @@
     return s;
 }
 
-#endif /* !HAVE_WINSOCK */
+#endif /* !_WIN32 */
 /* End of ../libcutils/socket_local_client.c */
 
 #define logger_for_each(logger, logger_list) \
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index a9671a9..32a65ea 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -295,13 +295,13 @@
   // so we save the extra file existence check.
   char cpuinfo_path[1024];
 
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
   snprintf(cpuinfo_path, sizeof(cpuinfo_path), "/system/lib"
 #ifdef __LP64__
       "64"
 #endif  // __LP64__
       "/%s/cpuinfo", instruction_set);
-#else   // !HAVE_ANDROID_OS
+#else   // !__ANDROID__
   // To be able to test on the host, we hardwire a relative path.
   snprintf(cpuinfo_path, sizeof(cpuinfo_path), "./cpuinfo");
 #endif
diff --git a/libnativebridge/tests/PreInitializeNativeBridge_test.cpp b/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
index cec26ce..d3bbebe 100644
--- a/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
+++ b/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
@@ -32,8 +32,8 @@
 
 TEST_F(NativeBridgeTest, PreInitializeNativeBridge) {
     ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
-#ifndef __APPLE__         // Mac OS does not support bind-mount.
-#ifndef HAVE_ANDROID_OS   // Cannot write into the hard-wired location.
+#if !defined(__APPLE__)         // Mac OS does not support bind-mount.
+#if !defined(__ANDROID__)       // Cannot write into the hard-wired location.
     // Try to create our mount namespace.
     if (unshare(CLONE_NEWNS) != -1) {
         // Create a dummy file.
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index 7d2a5fb..956ed30 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -50,7 +50,7 @@
 #define ALOGW printf
 #endif
 
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
 /* SIOCKILLADDR is an Android extension. */
 #define SIOCKILLADDR 0x8939
 #endif
@@ -596,7 +596,7 @@
 
 int ifc_reset_connections(const char *ifname, const int reset_mask)
 {
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
     int result, success;
     in_addr_t myaddr = 0;
     struct ifreq ifr;
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 28be60f..69313ea 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -79,6 +79,9 @@
 static char* allocFromUTF8(const char* in, size_t len)
 {
     if (len > 0) {
+        if (len == SIZE_MAX) {
+            return NULL;
+        }
         SharedBuffer* buf = SharedBuffer::alloc(len+1);
         ALOG_ASSERT(buf, "Unable to allocate shared buffer");
         if (buf) {
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp
index 64204a8..1fca2b2 100644
--- a/libutils/SystemClock.cpp
+++ b/libutils/SystemClock.cpp
@@ -19,7 +19,7 @@
  * System clock functions.
  */
 
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
 #include <linux/ioctl.h>
 #include <linux/rtc.h>
 #include <utils/Atomic.h>
@@ -107,7 +107,7 @@
  */
 int64_t elapsedRealtimeNano()
 {
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
     struct timespec ts;
     int result;
     int64_t timestamp;
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index c3666e4..6dda6b5 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -45,7 +45,7 @@
 
 #include <cutils/sched_policy.h>
 
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
 # define __android_unused
 #else
 # define __android_unused __attribute__((__unused__))
@@ -132,7 +132,7 @@
     pthread_attr_init(&attr);
     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
-#ifdef HAVE_ANDROID_OS  /* valgrind is rejecting RT-priority create reqs */
+#if defined(__ANDROID__)  /* valgrind is rejecting RT-priority create reqs */
     if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) {
         // Now that the pthread_t has a method to find the associated
         // android_thread_id_t (pid) from pthread_t, it would be possible to avoid
@@ -176,7 +176,7 @@
     return 1;
 }
 
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
 static pthread_t android_thread_id_t_to_pthread(android_thread_id_t thread)
 {
     return (pthread_t) thread;
@@ -302,12 +302,10 @@
     gCreateThreadFn = func;
 }
 
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
 int androidSetThreadPriority(pid_t tid, int pri)
 {
     int rc = 0;
-
-#if !defined(_WIN32)
     int lasterr = 0;
 
     if (pri >= ANDROID_PRIORITY_BACKGROUND) {
@@ -325,17 +323,12 @@
     } else {
         errno = lasterr;
     }
-#endif
 
     return rc;
 }
 
 int androidGetThreadPriority(pid_t tid) {
-#if !defined(_WIN32)
     return getpriority(PRIO_PROCESS, tid);
-#else
-    return ANDROID_PRIORITY_NORMAL;
-#endif
 }
 
 #endif
@@ -658,7 +651,7 @@
         mLock("Thread::mLock"),
         mStatus(NO_ERROR),
         mExitPending(false), mRunning(false)
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
         , mTid(-1)
 #endif
 {
@@ -728,7 +721,7 @@
     wp<Thread> weak(strong);
     self->mHoldSelf.clear();
 
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
     // this is very useful for debugging with gdb
     self->mTid = gettid();
 #endif
@@ -839,7 +832,7 @@
     return mRunning;
 }
 
-#ifdef HAVE_ANDROID_OS
+#if defined(__ANDROID__)
 pid_t Thread::getTid() const
 {
     // mTid is not defined until the child initializes it, and the caller may need it earlier
diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp
index fb70e15..201bc41 100644
--- a/libutils/Timers.cpp
+++ b/libutils/Timers.cpp
@@ -23,7 +23,7 @@
 #include <sys/time.h>
 #include <time.h>
 
-#if defined(HAVE_ANDROID_OS)
+#if defined(__ANDROID__)
 nsecs_t systemTime(int clock)
 {
     static const clockid_t clocks[] = {
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index fb876c9..6f4b721 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -18,7 +18,7 @@
 
 #include <stddef.h>
 
-#ifdef HAVE_WINSOCK
+#if defined(_WIN32)
 # undef  nhtol
 # undef  htonl
 # undef  nhtos
diff --git a/libutils/tests/BitSet_test.cpp b/libutils/tests/BitSet_test.cpp
index 38b668a..59d913e 100644
--- a/libutils/tests/BitSet_test.cpp
+++ b/libutils/tests/BitSet_test.cpp
@@ -138,11 +138,11 @@
 TEST_F(BitSet32Test, GetIndexOfBit) {
     b1.markBit(1);
     b1.markBit(4);
-    EXPECT_EQ(b1.getIndexOfBit(1), 0);
-    EXPECT_EQ(b1.getIndexOfBit(4), 1);
+    EXPECT_EQ(0U, b1.getIndexOfBit(1));
+    EXPECT_EQ(1U, b1.getIndexOfBit(4));
     b1.markFirstUnmarkedBit();
-    EXPECT_EQ(b1.getIndexOfBit(1), 1);
-    EXPECT_EQ(b1.getIndexOfBit(4), 2);
+    EXPECT_EQ(1U, b1.getIndexOfBit(1));
+    EXPECT_EQ(2U, b1.getIndexOfBit(4));
 }
 
 class BitSet64Test : public testing::Test {
@@ -260,11 +260,11 @@
 TEST_F(BitSet64Test, GetIndexOfBit) {
     b1.markBit(10);
     b1.markBit(40);
-    EXPECT_EQ(b1.getIndexOfBit(10), 0);
-    EXPECT_EQ(b1.getIndexOfBit(40), 1);
+    EXPECT_EQ(0U, b1.getIndexOfBit(10));
+    EXPECT_EQ(1U, b1.getIndexOfBit(40));
     b1.markFirstUnmarkedBit();
-    EXPECT_EQ(b1.getIndexOfBit(10), 1);
-    EXPECT_EQ(b1.getIndexOfBit(40), 2);
+    EXPECT_EQ(1U, b1.getIndexOfBit(10));
+    EXPECT_EQ(2U, b1.getIndexOfBit(40));
 }
 
 } // namespace android
diff --git a/libutils/tests/LruCache_test.cpp b/libutils/tests/LruCache_test.cpp
index 6534211..6155def 100644
--- a/libutils/tests/LruCache_test.cpp
+++ b/libutils/tests/LruCache_test.cpp
@@ -220,7 +220,7 @@
 
     cache.put(ComplexKey(0), ComplexValue(0));
     cache.put(ComplexKey(1), ComplexValue(1));
-    EXPECT_EQ(2, cache.size());
+    EXPECT_EQ(2U, cache.size());
     assertInstanceCount(2, 3);  // the null value counts as an instance
 }
 
@@ -229,7 +229,7 @@
 
     cache.put(ComplexKey(0), ComplexValue(0));
     cache.put(ComplexKey(1), ComplexValue(1));
-    EXPECT_EQ(2, cache.size());
+    EXPECT_EQ(2U, cache.size());
     assertInstanceCount(2, 3);
     cache.clear();
     assertInstanceCount(0, 1);
@@ -241,7 +241,7 @@
 
         cache.put(ComplexKey(0), ComplexValue(0));
         cache.put(ComplexKey(1), ComplexValue(1));
-        EXPECT_EQ(2, cache.size());
+        EXPECT_EQ(2U, cache.size());
         assertInstanceCount(2, 3);
         cache.removeOldest();
         cache.clear();
@@ -255,13 +255,13 @@
 
     cache.put(ComplexKey(0), ComplexValue(0));
     cache.put(ComplexKey(1), ComplexValue(1));
-    EXPECT_EQ(2, cache.size());
+    EXPECT_EQ(2U, cache.size());
     assertInstanceCount(2, 3);
     cache.clear();
     assertInstanceCount(0, 1);
     cache.put(ComplexKey(0), ComplexValue(0));
     cache.put(ComplexKey(1), ComplexValue(1));
-    EXPECT_EQ(2, cache.size());
+    EXPECT_EQ(2U, cache.size());
     assertInstanceCount(2, 3);
 }
 
@@ -273,7 +273,7 @@
     cache.put(1, "one");
     cache.put(2, "two");
     cache.put(3, "three");
-    EXPECT_EQ(3, cache.size());
+    EXPECT_EQ(3U, cache.size());
     cache.removeOldest();
     EXPECT_EQ(1, callback.callbackCount);
     EXPECT_EQ(1, callback.lastKey);
@@ -288,7 +288,7 @@
     cache.put(1, "one");
     cache.put(2, "two");
     cache.put(3, "three");
-    EXPECT_EQ(3, cache.size());
+    EXPECT_EQ(3U, cache.size());
     cache.clear();
     EXPECT_EQ(3, callback.callbackCount);
 }
diff --git a/libutils/tests/Vector_test.cpp b/libutils/tests/Vector_test.cpp
index d29c054..0ba7161 100644
--- a/libutils/tests/Vector_test.cpp
+++ b/libutils/tests/Vector_test.cpp
@@ -45,26 +45,26 @@
     vector.add(2);
     vector.add(3);
 
-    EXPECT_EQ(vector.size(), 3);
+    EXPECT_EQ(3U, vector.size());
 
     // copy the vector
     other = vector;
 
-    EXPECT_EQ(other.size(), 3);
+    EXPECT_EQ(3U, other.size());
 
     // add an element to the first vector
     vector.add(4);
 
     // make sure the sizes are correct
-    EXPECT_EQ(vector.size(), 4);
-    EXPECT_EQ(other.size(), 3);
+    EXPECT_EQ(4U, vector.size());
+    EXPECT_EQ(3U, other.size());
 
     // add an element to the copy
     other.add(5);
 
     // make sure the sizes are correct
-    EXPECT_EQ(vector.size(), 4);
-    EXPECT_EQ(other.size(), 4);
+    EXPECT_EQ(4U, vector.size());
+    EXPECT_EQ(4U, other.size());
 
     // make sure the content of both vectors are correct
     EXPECT_EQ(vector[3], 4);
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index d584925..823a842 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -72,7 +72,7 @@
             return;
         }
         entry = new LogTimeEntry(mReader, client, mNonBlock, mTail, mLogMask, mPid, mStart);
-        times.push_back(entry);
+        times.push_front(entry);
     }
 
     client->incRef();
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 0f5071b..db3f26c 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -217,19 +217,22 @@
     return len;
 }
 
-// If we're using more than 256K of memory for log entries, prune
-// at least 10% of the log entries.
+// Prune at most 10% of the log entries or 256, whichever is less.
 //
 // mLogElementsLock must be held when this function is called.
 void LogBuffer::maybePrune(log_id_t id) {
     size_t sizes = stats.sizes(id);
-    if (sizes > log_buffer_size(id)) {
-        size_t sizeOver90Percent = sizes - ((log_buffer_size(id) * 9) / 10);
+    unsigned long maxSize = log_buffer_size(id);
+    if (sizes > maxSize) {
+        size_t sizeOver = sizes - ((maxSize * 9) / 10);
         size_t elements = stats.elements(id);
-        unsigned long pruneRows = elements * sizeOver90Percent / sizes;
-        elements /= 10;
-        if (pruneRows <= elements) {
-            pruneRows = elements;
+        size_t minElements = elements / 10;
+        unsigned long pruneRows = elements * sizeOver / sizes;
+        if (pruneRows <= minElements) {
+            pruneRows = minElements;
+        }
+        if (pruneRows > 256) {
+            pruneRows = 256;
         }
         prune(id, pruneRows);
     }
@@ -237,7 +240,12 @@
 
 LogBufferElementCollection::iterator LogBuffer::erase(LogBufferElementCollection::iterator it) {
     LogBufferElement *e = *it;
+    log_id_t id = e->getLogId();
+    LogBufferIteratorMap::iterator f = mLastWorstUid[id].find(e->getUid());
 
+    if ((f != mLastWorstUid[id].end()) && (it == f->second)) {
+        mLastWorstUid[id].erase(f);
+    }
     it = mLogElements.erase(it);
     stats.subtract(e);
     delete e;
@@ -396,8 +404,17 @@
 
         bool kick = false;
         bool leading = true;
+        it = mLogElements.begin();
+        if (worst != (uid_t) -1) {
+            LogBufferIteratorMap::iterator f = mLastWorstUid[id].find(worst);
+            if ((f != mLastWorstUid[id].end())
+                    && (f->second != mLogElements.end())) {
+                leading = false;
+                it = f->second;
+            }
+        }
         LogBufferElementLast last;
-        for(it = mLogElements.begin(); it != mLogElements.end();) {
+        while (it != mLogElements.end()) {
             LogBufferElement *e = *it;
 
             if (oldest && (oldest->mStart <= e->getSequence())) {
@@ -447,8 +464,10 @@
                 continue;
             }
 
+            // unmerged drop message
             if (dropped) {
                 last.add(e);
+                mLastWorstUid[id][e->getUid()] = it;
                 ++it;
                 continue;
             }
@@ -493,6 +512,7 @@
                     delete e;
                 } else {
                     last.add(e);
+                    mLastWorstUid[id][e->getUid()] = it;
                     ++it;
                 }
             }
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index a13fded..e94598c 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -19,9 +19,10 @@
 
 #include <sys/types.h>
 
+#include <list>
+
 #include <log/log.h>
 #include <sysutils/SocketClient.h>
-#include <utils/List.h>
 
 #include <private/android_filesystem_config.h>
 
@@ -30,7 +31,7 @@
 #include "LogStatistics.h"
 #include "LogWhiteBlackList.h"
 
-typedef android::List<LogBufferElement *> LogBufferElementCollection;
+typedef std::list<LogBufferElement *> LogBufferElementCollection;
 
 class LogBuffer {
     LogBufferElementCollection mLogElements;
@@ -39,6 +40,11 @@
     LogStatistics stats;
 
     PruneList mPrune;
+    // watermark of any worst/chatty uid processing
+    typedef std::unordered_map<uid_t,
+                               LogBufferElementCollection::iterator>
+                LogBufferIteratorMap;
+    LogBufferIteratorMap mLastWorstUid[LOG_ID_MAX];
 
     unsigned long mMaxSize[LOG_ID_MAX];
 
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index eff26f5..1e6f55f 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -254,6 +254,7 @@
     if ((cp = now.strptime(*buf, "[ %s.%q]"))) {
         static const char suspend[] = "PM: suspend entry ";
         static const char resume[] = "PM: suspend exit ";
+        static const char healthd[] = "healthd: battery ";
         static const char suspended[] = "Suspended for ";
 
         if (isspace(*cp)) {
@@ -263,6 +264,15 @@
             calculateCorrection(now, cp + sizeof(suspend) - 1);
         } else if (!strncmp(cp, resume, sizeof(resume) - 1)) {
             calculateCorrection(now, cp + sizeof(resume) - 1);
+        } else if (!strncmp(cp, healthd, sizeof(healthd) - 1)) {
+            // look for " 2???-??-?? ??:??:??.????????? ???"
+            const char *tp;
+            for (tp = cp + sizeof(healthd) - 1; *tp && (*tp != '\n'); ++tp) {
+                if ((tp[0] == ' ') && (tp[1] == '2') && (tp[5] == '-')) {
+                    calculateCorrection(now, tp + 1);
+                    break;
+                }
+            }
         } else if (!strncmp(cp, suspended, sizeof(suspended) - 1)) {
             log_time real;
             char *endp;
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index 783bce6..39bcdd4 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -20,8 +20,10 @@
 #include <pthread.h>
 #include <time.h>
 #include <sys/types.h>
+
+#include <list>
+
 #include <sysutils/SocketClient.h>
-#include <utils/List.h>
 #include <log/log.h>
 
 class LogReader;
@@ -107,6 +109,6 @@
     static int FilterSecondPass(const LogBufferElement *element, void *me);
 };
 
-typedef android::List<LogTimeEntry *> LastLogTimes;
+typedef std::list<LogTimeEntry *> LastLogTimes;
 
-#endif
+#endif // _LOGD_LOG_TIMES_H__
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index 277b3ca..16dd6d2 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -50,18 +50,14 @@
 }
 
 PruneList::PruneList() : mWorstUidEnabled(true) {
-    mNaughty.clear();
-    mNice.clear();
 }
 
 PruneList::~PruneList() {
     PruneCollection::iterator it;
     for (it = mNice.begin(); it != mNice.end();) {
-        delete (*it);
         it = mNice.erase(it);
     }
     for (it = mNaughty.begin(); it != mNaughty.end();) {
-        delete (*it);
         it = mNaughty.erase(it);
     }
 }
@@ -70,11 +66,9 @@
     mWorstUidEnabled = true;
     PruneCollection::iterator it;
     for (it = mNice.begin(); it != mNice.end();) {
-        delete (*it);
         it = mNice.erase(it);
     }
     for (it = mNaughty.begin(); it != mNaughty.end();) {
-        delete (*it);
         it = mNaughty.erase(it);
     }
 
@@ -142,28 +136,28 @@
         // insert sequentially into list
         PruneCollection::iterator it = list->begin();
         while (it != list->end()) {
-            Prune *p = *it;
-            int m = uid - p->mUid;
+            Prune &p = *it;
+            int m = uid - p.mUid;
             if (m == 0) {
-                if (p->mPid == p->pid_all) {
+                if (p.mPid == p.pid_all) {
                     break;
                 }
-                if ((pid == p->pid_all) && (p->mPid != p->pid_all)) {
+                if ((pid == p.pid_all) && (p.mPid != p.pid_all)) {
                     it = list->erase(it);
                     continue;
                 }
-                m = pid - p->mPid;
+                m = pid - p.mPid;
             }
             if (m <= 0) {
                 if (m < 0) {
-                    list->insert(it, new Prune(uid,pid));
+                    list->insert(it, Prune(uid,pid));
                 }
                 break;
             }
             ++it;
         }
         if (it == list->end()) {
-            list->push_back(new Prune(uid,pid));
+            list->push_back(Prune(uid,pid));
         }
         if (!*str) {
             break;
@@ -193,7 +187,7 @@
 
     for (it = mNice.begin(); it != mNice.end(); ++it) {
         char *a = NULL;
-        (*it)->format(&a);
+        (*it).format(&a);
 
         string.appendFormat(fmt, a);
         fmt = nice_format;
@@ -205,7 +199,7 @@
     fmt = naughty_format + (*fmt != ' ');
     for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
         char *a = NULL;
-        (*it)->format(&a);
+        (*it).format(&a);
 
         string.appendFormat(fmt, a);
         fmt = naughty_format;
@@ -223,7 +217,7 @@
 bool PruneList::naughty(LogBufferElement *element) {
     PruneCollection::iterator it;
     for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
-        if (!(*it)->cmp(element)) {
+        if (!(*it).cmp(element)) {
             return true;
         }
     }
@@ -233,7 +227,7 @@
 bool PruneList::nice(LogBufferElement *element) {
     PruneCollection::iterator it;
     for (it = mNice.begin(); it != mNice.end(); ++it) {
-        if (!(*it)->cmp(element)) {
+        if (!(*it).cmp(element)) {
             return true;
         }
     }
diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h
index 5f60801..57cd03b 100644
--- a/logd/LogWhiteBlackList.h
+++ b/logd/LogWhiteBlackList.h
@@ -19,7 +19,7 @@
 
 #include <sys/types.h>
 
-#include <utils/List.h>
+#include <list>
 
 #include <LogBufferElement.h>
 
@@ -47,7 +47,7 @@
     void format(char **strp);
 };
 
-typedef android::List<Prune *> PruneCollection;
+typedef std::list<Prune> PruneCollection;
 
 class PruneList {
     PruneCollection mNaughty;
diff --git a/logwrapper/include/logwrap/logwrap.h b/logwrapper/include/logwrap/logwrap.h
index 4307a30..449461f 100644
--- a/logwrapper/include/logwrap/logwrap.h
+++ b/logwrapper/include/logwrap/logwrap.h
@@ -19,6 +19,7 @@
 #define __LIBS_LOGWRAP_H
 
 #include <stdbool.h>
+#include <stdint.h>
 
 __BEGIN_DECLS
 
@@ -53,6 +54,9 @@
  *           the specified log until the child has exited.
  *   file_path: if log_target has the LOG_FILE bit set, then this parameter
  *           must be set to the pathname of the file to log to.
+ *   opts: set to non-NULL if you want to use one or more of the
+ *           FORK_EXECVP_OPTION_* features.
+ *   opts_len: the length of the opts array. When opts is NULL, pass 0.
  *
  * Return value:
  *   0 when logwrap successfully run the child process and captured its status
@@ -68,8 +72,22 @@
 #define LOG_KLOG        2
 #define LOG_FILE        4
 
+/* Write data to child's stdin. */
+#define FORK_EXECVP_OPTION_INPUT    0
+
+struct AndroidForkExecvpOption {
+    int opt_type;
+    union {
+        struct {
+            const uint8_t* input;
+            size_t input_len;
+        } opt_input;
+    };
+};
+
 int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
-        int log_target, bool abbreviated, char *file_path);
+        int log_target, bool abbreviated, char *file_path,
+        const struct AndroidForkExecvpOption* opts, size_t opts_len);
 
 /* Similar to above, except abbreviated logging is not available, and if logwrap
  * is true, logging is to the Android system log, and if false, there is no
@@ -79,7 +97,8 @@
                                      bool ignore_int_quit, bool logwrap)
 {
     return android_fork_execvp_ext(argc, argv, status, ignore_int_quit,
-                                   (logwrap ? LOG_ALOG : LOG_NONE), false, NULL);
+                                   (logwrap ? LOG_ALOG : LOG_NONE), false, NULL,
+                                   NULL, 0);
 }
 
 __END_DECLS
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 777dafe..c7b4835 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -474,7 +474,8 @@
 }
 
 int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
-        int log_target, bool abbreviated, char *file_path) {
+        int log_target, bool abbreviated, char *file_path,
+        const struct AndroidForkExecvpOption* opts, size_t opts_len) {
     pid_t pid;
     int parent_ptty;
     int child_ptty;
@@ -483,6 +484,7 @@
     sigset_t blockset;
     sigset_t oldset;
     int rc = 0;
+    size_t i;
 
     rc = pthread_mutex_lock(&fd_mutex);
     if (rc) {
@@ -529,7 +531,13 @@
         pthread_sigmask(SIG_SETMASK, &oldset, NULL);
         close(parent_ptty);
 
-        // redirect stdout and stderr
+        // redirect stdin, stdout and stderr
+        for (i = 0; i < opts_len; ++i) {
+            if (opts[i].opt_type == FORK_EXECVP_OPTION_INPUT) {
+                dup2(child_ptty, 0);
+                break;
+            }
+        }
         dup2(child_ptty, 1);
         dup2(child_ptty, 2);
         close(child_ptty);
@@ -546,6 +554,22 @@
             sigaction(SIGQUIT, &ignact, &quitact);
         }
 
+        for (i = 0; i < opts_len; ++i) {
+            if (opts[i].opt_type == FORK_EXECVP_OPTION_INPUT) {
+                size_t left = opts[i].opt_input.input_len;
+                const uint8_t* input = opts[i].opt_input.input;
+                while (left > 0) {
+                    ssize_t res =
+                        TEMP_FAILURE_RETRY(write(parent_ptty, input, left));
+                    if (res < 0) {
+                        break;
+                    }
+                    left -= res;
+                    input += res;
+                }
+            }
+        }
+
         rc = parent(argv[0], parent_ptty, pid, status, log_target,
                     abbreviated, file_path);
     }
diff --git a/logwrapper/logwrapper.c b/logwrapper/logwrapper.c
index 9e0385d..55b71c7 100644
--- a/logwrapper/logwrapper.c
+++ b/logwrapper/logwrapper.c
@@ -81,7 +81,7 @@
     }
 
     rc = android_fork_execvp_ext(argc, &argv[0], &status, true,
-                                 log_target, abbreviated, NULL);
+                                 log_target, abbreviated, NULL, NULL, 0);
     if (!rc) {
         if (WIFEXITED(status))
             rc = WEXITSTATUS(status);
diff --git a/metrics/MODULE_LICENSE_BSD b/metrics/MODULE_LICENSE_BSD
deleted file mode 100644
index e69de29..0000000
--- a/metrics/MODULE_LICENSE_BSD
+++ /dev/null
diff --git a/metrics/NOTICE b/metrics/NOTICE
deleted file mode 100644
index b9e779f..0000000
--- a/metrics/NOTICE
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//    * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//    * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//    * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/metrics/init/metrics_daemon.conf b/metrics/init/metrics_daemon.conf
deleted file mode 100644
index e6932cf..0000000
--- a/metrics/init/metrics_daemon.conf
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-description     "Metrics collection daemon"
-author          "chromium-os-dev@chromium.org"
-
-# The metrics daemon is responsible for receiving and forwarding to
-# chrome UMA statistics not produced by chrome.
-start on starting system-services
-stop on stopping system-services
-respawn
-
-# metrics will update the next line to add -uploader for embedded builds.
-env DAEMON_FLAGS=""
-
-expect fork
-exec metrics_daemon ${DAEMON_FLAGS}
diff --git a/metrics/init/metrics_library.conf b/metrics/init/metrics_library.conf
deleted file mode 100644
index 03016d1..0000000
--- a/metrics/init/metrics_library.conf
+++ /dev/null
@@ -1,25 +0,0 @@
-# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-description     "Metrics Library upstart file"
-author          "chromium-os-dev@chromium.org"
-
-# The metrics library is used by several programs (daemons and others)
-# to send UMA stats.
-start on starting boot-services
-
-pre-start script
-  # Create the file used as communication endpoint for metrics.
-  METRICS_DIR=/var/lib/metrics
-  EVENTS_FILE=${METRICS_DIR}/uma-events
-  mkdir -p ${METRICS_DIR}
-  touch ${EVENTS_FILE}
-  chown chronos.chronos ${EVENTS_FILE}
-  chmod 666 ${EVENTS_FILE}
-  # TRANSITION ONLY.
-  # TODO(semenzato) Remove after Chrome change, see issue 447256.
-  # Let Chrome read the metrics file from the old location.
-  mkdir -p /var/run/metrics
-  ln -sf ${EVENTS_FILE} /var/run/metrics
-end script
diff --git a/metrics/make_tests.sh b/metrics/make_tests.sh
deleted file mode 100755
index 9dcc804..0000000
--- a/metrics/make_tests.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-
-# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Builds tests.
-
-set -e
-make tests
-mkdir -p "${OUT_DIR}"
-cp *_test "${OUT_DIR}"
diff --git a/metrics/metrics_library_mock.h b/metrics/metrics_library_mock.h
deleted file mode 100644
index 99892bf..0000000
--- a/metrics/metrics_library_mock.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef METRICS_METRICS_LIBRARY_MOCK_H_
-#define METRICS_METRICS_LIBRARY_MOCK_H_
-
-#include <string>
-
-#include "metrics/metrics_library.h"
-
-#include <gmock/gmock.h>
-
-class MetricsLibraryMock : public MetricsLibraryInterface {
- public:
-  bool metrics_enabled_ = true;
-
-  MOCK_METHOD0(Init, void());
-  MOCK_METHOD5(SendToUMA, bool(const std::string& name, int sample,
-                               int min, int max, int nbuckets));
-  MOCK_METHOD3(SendEnumToUMA, bool(const std::string& name, int sample,
-                                   int max));
-  MOCK_METHOD2(SendSparseToUMA, bool(const std::string& name, int sample));
-  MOCK_METHOD1(SendUserActionToUMA, bool(const std::string& action));
-
-  bool AreMetricsEnabled() override {return metrics_enabled_;};
-};
-
-#endif  // METRICS_METRICS_LIBRARY_MOCK_H_
diff --git a/metrics/persistent_integer_mock.h b/metrics/persistent_integer_mock.h
deleted file mode 100644
index 2061e55..0000000
--- a/metrics/persistent_integer_mock.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef METRICS_PERSISTENT_INTEGER_MOCK_H_
-#define METRICS_PERSISTENT_INTEGER_MOCK_H_
-
-#include <string>
-
-#include <gmock/gmock.h>
-
-#include "metrics/persistent_integer.h"
-
-namespace chromeos_metrics {
-
-class PersistentIntegerMock : public PersistentInteger {
- public:
-  explicit PersistentIntegerMock(const std::string& name)
-      : PersistentInteger(name) {}
-    MOCK_METHOD1(Add, void(int64_t count));
-};
-
-}  // namespace chromeos_metrics
-
-#endif  // METRICS_PERSISTENT_INTEGER_MOCK_H_
diff --git a/metrics/platform2_preinstall.sh b/metrics/platform2_preinstall.sh
deleted file mode 100755
index ccf353f..0000000
--- a/metrics/platform2_preinstall.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-set -e
-
-OUT=$1
-shift
-for v; do
-  sed -e "s/@BSLOT@/${v}/g" libmetrics.pc.in > "${OUT}/lib/libmetrics-${v}.pc"
-done
diff --git a/metrics/syslog_parser.sh b/metrics/syslog_parser.sh
deleted file mode 100755
index 7d064be..0000000
--- a/metrics/syslog_parser.sh
+++ /dev/null
@@ -1,69 +0,0 @@
-#! /bin/sh
-
-# This script parses /var/log/syslog for messages from programs that log
-# uptime and disk stats (number of sectors read).  It then outputs
-# these stats in a format usable by the metrics collector, which forwards
-# them to autotest and UMA.
-
-# To add a new metric add a line below, as PROGRAM_NAME  METRIC_NAME.
-# PROGRAM_NAME is the name of the job whose start time we
-# are interested in.  METRIC_NAME is the prefix we want to use for
-# reporting to UMA and autotest.  The script prepends "Time" and
-# "Sectors" to METRIC_NAME for the two available measurements, uptime
-# and number of sectors read thus far.
-
-# You will need to emit messages similar to the following in order to add a
-# a metric using this process.  You will need to emit both a start and stop
-# time and the metric reported will be the difference in values
-
-# Nov 15 08:05 localhost PROGRAM_NAME[822]: start METRIC_NAME time 12 sectors 56
-# Nov 15 08:05 localhost PROGRAM_NAME[822]: stop METRIC_NAME time 24 sectors 68
-
-# If you add metrics without a start, it is assumed you are requesting the
-# time differece from system start
-
-# Metrics we are interested in measuring
-METRICS="
-upstart start_x
-"
-
-first=1
-program=""
-
-# Get the metrics for all things
-for m in $METRICS
-do
-  if [ $first -eq 1 ]
-  then
-    first=0
-    program_name=$m
-  else
-    first=1
-    metrics_name=$m
-
-    # Example of line from /var/log/messages:
-    # Nov 15 08:05:42 localhost connmand[822]: start metric time 12 sectors 56
-    # "upstart:" is $5, 1234 is $9, etc.
-    program="${program}/$program_name([[0-9]+]:|:) start $metrics_name/\
-    {
-      metrics_start[\"${metrics_name}Time\"] = \$9;
-      metrics_start[\"${metrics_name}Sectors\"] = \$11;
-    }"
-    program="${program}/$program_name([[0-9]+]:|:) stop $metrics_name/\
-    {
-        metrics_stop[\"${metrics_name}Time\"] = \$9;
-        metrics_stop[\"${metrics_name}Sectors\"] = \$11;
-    }"
-  fi
-done
-
-# Do all the differencing here
-program="${program}\
-END{
-  for (i in metrics_stop) {
-    value_time = metrics_stop[i] - metrics_start[i];
-    print i \"=\" value_time;
-  }
-}"
-
-exec awk "$program" /var/log/syslog
diff --git a/metrics/uploader/metrics_hashes.cc b/metrics/uploader/metrics_hashes.cc
deleted file mode 100644
index 87405a3..0000000
--- a/metrics/uploader/metrics_hashes.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "metrics/uploader/metrics_hashes.h"
-
-#include "base/logging.h"
-#include "base/md5.h"
-#include "base/sys_byteorder.h"
-
-namespace metrics {
-
-namespace {
-
-// Converts the 8-byte prefix of an MD5 hash into a uint64 value.
-inline uint64_t HashToUInt64(const std::string& hash) {
-  uint64_t value;
-  DCHECK_GE(hash.size(), sizeof(value));
-  memcpy(&value, hash.data(), sizeof(value));
-  return base::HostToNet64(value);
-}
-
-}  // namespace
-
-uint64_t HashMetricName(const std::string& name) {
-  // Create an MD5 hash of the given |name|, represented as a byte buffer
-  // encoded as an std::string.
-  base::MD5Context context;
-  base::MD5Init(&context);
-  base::MD5Update(&context, name);
-
-  base::MD5Digest digest;
-  base::MD5Final(&digest, &context);
-
-  std::string hash_str(reinterpret_cast<char*>(digest.a), arraysize(digest.a));
-  return HashToUInt64(hash_str);
-}
-
-}  // namespace metrics
diff --git a/metrics/uploader/metrics_hashes.h b/metrics/uploader/metrics_hashes.h
deleted file mode 100644
index 8679077..0000000
--- a/metrics/uploader/metrics_hashes.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef METRICS_UPLOADER_METRICS_HASHES_H_
-#define METRICS_UPLOADER_METRICS_HASHES_H_
-
-#include <string>
-
-namespace metrics {
-
-// Computes a uint64 hash of a given string based on its MD5 hash. Suitable for
-// metric names.
-uint64_t HashMetricName(const std::string& name);
-
-}  // namespace metrics
-
-#endif  // METRICS_UPLOADER_METRICS_HASHES_H_
diff --git a/metrics/uploader/metrics_hashes_unittest.cc b/metrics/uploader/metrics_hashes_unittest.cc
deleted file mode 100644
index f7e390f..0000000
--- a/metrics/uploader/metrics_hashes_unittest.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "metrics/uploader/metrics_hashes.h"
-
-#include <base/format_macros.h>
-#include <base/macros.h>
-#include <base/strings/stringprintf.h>
-#include <gtest/gtest.h>
-
-namespace metrics {
-
-// Make sure our ID hashes are the same as what we see on the server side.
-TEST(MetricsUtilTest, HashMetricName) {
-  static const struct {
-    std::string input;
-    std::string output;
-  } cases[] = {
-    {"Back", "0x0557fa923dcee4d0"},
-    {"Forward", "0x67d2f6740a8eaebf"},
-    {"NewTab", "0x290eb683f96572f1"},
-  };
-
-  for (size_t i = 0; i < arraysize(cases); ++i) {
-    uint64_t hash = HashMetricName(cases[i].input);
-    std::string hash_hex = base::StringPrintf("0x%016" PRIx64, hash);
-    EXPECT_EQ(cases[i].output, hash_hex);
-  }
-}
-
-}  // namespace metrics
diff --git a/metrics/uploader/metrics_log.cc b/metrics/uploader/metrics_log.cc
deleted file mode 100644
index 4d493b8..0000000
--- a/metrics/uploader/metrics_log.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "uploader/metrics_log.h"
-
-#include <string>
-
-#include "metrics/uploader/proto/system_profile.pb.h"
-#include "uploader/system_profile_setter.h"
-
-// We use default values for the MetricsLogBase constructor as the setter will
-// override them.
-MetricsLog::MetricsLog()
-    : MetricsLogBase("", 0, metrics::MetricsLogBase::ONGOING_LOG, "") {
-}
-
-void MetricsLog::IncrementUserCrashCount() {
-  metrics::SystemProfileProto::Stability* stability(
-      uma_proto()->mutable_system_profile()->mutable_stability());
-  int current = stability->other_user_crash_count();
-  stability->set_other_user_crash_count(current + 1);
-}
-
-void MetricsLog::IncrementKernelCrashCount() {
-  metrics::SystemProfileProto::Stability* stability(
-      uma_proto()->mutable_system_profile()->mutable_stability());
-  int current = stability->kernel_crash_count();
-  stability->set_kernel_crash_count(current + 1);
-}
-
-void MetricsLog::IncrementUncleanShutdownCount() {
-  metrics::SystemProfileProto::Stability* stability(
-      uma_proto()->mutable_system_profile()->mutable_stability());
-  int current = stability->unclean_system_shutdown_count();
-  stability->set_unclean_system_shutdown_count(current + 1);
-}
-
-void MetricsLog::PopulateSystemProfile(SystemProfileSetter* profile_setter) {
-  profile_setter->Populate(uma_proto());
-}
diff --git a/metrics/uploader/mock/mock_system_profile_setter.h b/metrics/uploader/mock/mock_system_profile_setter.h
deleted file mode 100644
index c6e8f0d..0000000
--- a/metrics/uploader/mock/mock_system_profile_setter.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef METRICS_UPLOADER_MOCK_MOCK_SYSTEM_PROFILE_SETTER_H_
-#define METRICS_UPLOADER_MOCK_MOCK_SYSTEM_PROFILE_SETTER_H_
-
-#include "uploader/system_profile_setter.h"
-
-namespace metrics {
-class ChromeUserMetricsExtension;
-}
-
-// Mock profile setter used for testing.
-class MockSystemProfileSetter : public SystemProfileSetter {
- public:
-  void Populate(metrics::ChromeUserMetricsExtension* profile_proto) override {}
-};
-
-#endif  // METRICS_UPLOADER_MOCK_MOCK_SYSTEM_PROFILE_SETTER_H_
diff --git a/metrics/uploader/mock/sender_mock.cc b/metrics/uploader/mock/sender_mock.cc
deleted file mode 100644
index 064ec6d..0000000
--- a/metrics/uploader/mock/sender_mock.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "uploader/mock/sender_mock.h"
-
-SenderMock::SenderMock() {
-  Reset();
-}
-
-bool SenderMock::Send(const std::string& content, const std::string& hash) {
-  send_call_count_ += 1;
-  last_message_ = content;
-  is_good_proto_ = last_message_proto_.ParseFromString(content);
-  return should_succeed_;
-}
-
-void SenderMock::Reset() {
-  send_call_count_ = 0;
-  last_message_ = "";
-  should_succeed_ = true;
-  last_message_proto_.Clear();
-  is_good_proto_ = false;
-}
diff --git a/metrics/uploader/proto/user_action_event.proto b/metrics/uploader/proto/user_action_event.proto
deleted file mode 100644
index 30a9318..0000000
--- a/metrics/uploader/proto/user_action_event.proto
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2014 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.
-//
-// Stores information about an event that occurs in response to a user action,
-// e.g. an interaction with a browser UI element.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-option java_outer_classname = "UserActionEventProtos";
-option java_package = "org.chromium.components.metrics";
-
-package metrics;
-
-// Next tag: 3
-message UserActionEventProto {
-  // The name of the action, hashed.
-  optional fixed64 name_hash = 1;
-
-  // The timestamp for the event, in seconds since the epoch.
-  optional int64 time = 2;
-}
diff --git a/metrics/uploader/sender.h b/metrics/uploader/sender.h
deleted file mode 100644
index 5211834..0000000
--- a/metrics/uploader/sender.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef METRICS_UPLOADER_SENDER_H_
-#define METRICS_UPLOADER_SENDER_H_
-
-#include <string>
-
-// Abstract class for a Sender that uploads a metrics message.
-class Sender {
- public:
-  virtual ~Sender() {}
-  // Sends a message |content| with its sha1 hash |hash|
-  virtual bool Send(const std::string& content, const std::string& hash) = 0;
-};
-
-#endif  // METRICS_UPLOADER_SENDER_H_
diff --git a/metrics/uploader/sender_http.cc b/metrics/uploader/sender_http.cc
deleted file mode 100644
index 8488b66..0000000
--- a/metrics/uploader/sender_http.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "metrics/uploader/sender_http.h"
-
-#include <string>
-
-#include <base/logging.h>
-#include <base/strings/string_number_conversions.h>
-#include <chromeos/http/http_utils.h>
-#include <chromeos/mime_utils.h>
-
-HttpSender::HttpSender(const std::string server_url)
-    : server_url_(server_url) {}
-
-bool HttpSender::Send(const std::string& content,
-                      const std::string& content_hash) {
-  const std::string hash =
-      base::HexEncode(content_hash.data(), content_hash.size());
-
-  chromeos::http::HeaderList headers = {{"X-Chrome-UMA-Log-SHA1", hash}};
-  chromeos::ErrorPtr error;
-  auto response = chromeos::http::PostTextAndBlock(
-      server_url_,
-      content,
-      chromeos::mime::application::kWwwFormUrlEncoded,
-      headers,
-      chromeos::http::Transport::CreateDefault(),
-      &error);
-  if (!response || response->ExtractDataAsString() != "OK") {
-    if (error) {
-      DLOG(ERROR) << "Failed to send data: " << error->GetMessage();
-    }
-    return false;
-  }
-  return true;
-}
diff --git a/metrics/uploader/sender_http.h b/metrics/uploader/sender_http.h
deleted file mode 100644
index 4880b28..0000000
--- a/metrics/uploader/sender_http.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef METRICS_UPLOADER_SENDER_HTTP_H_
-#define METRICS_UPLOADER_SENDER_HTTP_H_
-
-#include <string>
-
-#include <base/macros.h>
-
-#include "metrics/uploader/sender.h"
-
-// Sender implemented using http_utils from libchromeos
-class HttpSender : public Sender {
- public:
-  explicit HttpSender(std::string server_url);
-  ~HttpSender() override = default;
-  // Sends |content| whose SHA1 hash is |hash| to server_url with a synchronous
-  // POST request to server_url.
-  bool Send(const std::string& content, const std::string& hash) override;
-
- private:
-  const std::string server_url_;
-
-  DISALLOW_COPY_AND_ASSIGN(HttpSender);
-};
-
-#endif  // METRICS_UPLOADER_SENDER_HTTP_H_
diff --git a/metrics/uploader/system_profile_cache.cc b/metrics/uploader/system_profile_cache.cc
deleted file mode 100644
index ea4a38c..0000000
--- a/metrics/uploader/system_profile_cache.cc
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "metrics/uploader/system_profile_cache.h"
-
-#include <string>
-#include <vector>
-
-#include "base/files/file_util.h"
-#include "base/guid.h"
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/sys_info.h"
-#include "metrics/persistent_integer.h"
-#include "metrics/uploader/metrics_log_base.h"
-#include "metrics/uploader/proto/chrome_user_metrics_extension.pb.h"
-#include "vboot/crossystem.h"
-
-namespace {
-
-const char kPersistentGUIDFile[] = "/var/lib/metrics/Sysinfo.GUID";
-const char kPersistentSessionIdFilename[] = "Sysinfo.SessionId";
-const char kProductIdFieldName[] = "GOOGLE_METRICS_PRODUCT_ID";
-
-}  // namespace
-
-std::string ChannelToString(
-    const metrics::SystemProfileProto_Channel& channel) {
-  switch (channel) {
-    case metrics::SystemProfileProto::CHANNEL_STABLE:
-    return "STABLE";
-  case metrics::SystemProfileProto::CHANNEL_DEV:
-    return "DEV";
-  case metrics::SystemProfileProto::CHANNEL_BETA:
-    return "BETA";
-  case metrics::SystemProfileProto::CHANNEL_CANARY:
-    return "CANARY";
-  default:
-    return "UNKNOWN";
-  }
-}
-
-SystemProfileCache::SystemProfileCache()
-    : initialized_(false),
-    testing_(false),
-    config_root_("/"),
-    session_id_(new chromeos_metrics::PersistentInteger(
-        kPersistentSessionIdFilename)) {
-}
-
-SystemProfileCache::SystemProfileCache(bool testing,
-                                       const std::string& config_root)
-    : initialized_(false),
-      testing_(testing),
-      config_root_(config_root),
-      session_id_(new chromeos_metrics::PersistentInteger(
-          kPersistentSessionIdFilename)) {
-}
-
-bool SystemProfileCache::Initialize() {
-  CHECK(!initialized_)
-      << "this should be called only once in the metrics_daemon lifetime.";
-
-  std::string chromeos_version;
-  std::string board;
-  std::string build_type;
-  if (!base::SysInfo::GetLsbReleaseValue("CHROMEOS_RELEASE_NAME",
-                                         &profile_.os_name) ||
-      !base::SysInfo::GetLsbReleaseValue("CHROMEOS_RELEASE_VERSION",
-                                         &profile_.os_version) ||
-      !base::SysInfo::GetLsbReleaseValue("CHROMEOS_RELEASE_BOARD", &board) ||
-      !base::SysInfo::GetLsbReleaseValue("CHROMEOS_RELEASE_BUILD_TYPE",
-                                         &build_type) ||
-      !GetChromeOSVersion(&chromeos_version) ||
-      !GetHardwareId(&profile_.hardware_class)) {
-    DLOG(ERROR) << "failing to initialize profile cache";
-    return false;
-  }
-
-  std::string channel_string;
-  base::SysInfo::GetLsbReleaseValue("CHROMEOS_RELEASE_TRACK", &channel_string);
-  profile_.channel = ProtoChannelFromString(channel_string);
-
-  profile_.app_version = chromeos_version + " (" + build_type + ")" +
-      ChannelToString(profile_.channel) + " " + board;
-
-  // If the product id is not defined, use the default one from the protobuf.
-  profile_.product_id = metrics::ChromeUserMetricsExtension::CHROME;
-  if (GetProductId(&profile_.product_id)) {
-    DLOG(INFO) << "Set the product id to " << profile_.product_id;
-  }
-
-  profile_.client_id =
-      testing_ ? "client_id_test" : GetPersistentGUID(kPersistentGUIDFile);
-
-  // Increment the session_id everytime we initialize this. If metrics_daemon
-  // does not crash, this should correspond to the number of reboots of the
-  // system.
-  // TODO(bsimonnet): Change this to map to the number of time system-services
-  // is started.
-  session_id_->Add(1);
-  profile_.session_id = static_cast<int32_t>(session_id_->Get());
-
-  initialized_ = true;
-  return initialized_;
-}
-
-bool SystemProfileCache::InitializeOrCheck() {
-  return initialized_ || Initialize();
-}
-
-void SystemProfileCache::Populate(
-    metrics::ChromeUserMetricsExtension* metrics_proto) {
-  CHECK(metrics_proto);
-  CHECK(InitializeOrCheck())
-      << "failed to initialize system information.";
-
-  // The client id is hashed before being sent.
-  metrics_proto->set_client_id(
-      metrics::MetricsLogBase::Hash(profile_.client_id));
-  metrics_proto->set_session_id(profile_.session_id);
-
-  // Sets the product id.
-  metrics_proto->set_product(profile_.product_id);
-
-  metrics::SystemProfileProto* profile_proto =
-      metrics_proto->mutable_system_profile();
-  profile_proto->mutable_hardware()->set_hardware_class(
-      profile_.hardware_class);
-  profile_proto->set_app_version(profile_.app_version);
-  profile_proto->set_channel(profile_.channel);
-
-  metrics::SystemProfileProto_OS* os = profile_proto->mutable_os();
-  os->set_name(profile_.os_name);
-  os->set_version(profile_.os_version);
-}
-
-std::string SystemProfileCache::GetPersistentGUID(const std::string& filename) {
-  std::string guid;
-  base::FilePath filepath(filename);
-  if (!base::ReadFileToString(filepath, &guid)) {
-    guid = base::GenerateGUID();
-    // If we can't read or write the file, the guid will not be preserved during
-    // the next reboot. Crash.
-    CHECK(base::WriteFile(filepath, guid.c_str(), guid.size()));
-  }
-  return guid;
-}
-
-bool SystemProfileCache::GetChromeOSVersion(std::string* version) {
-  if (testing_) {
-    *version = "0.0.0.0";
-    return true;
-  }
-
-  std::string milestone, build, branch, patch;
-  unsigned tmp;
-  if (base::SysInfo::GetLsbReleaseValue("CHROMEOS_RELEASE_CHROME_MILESTONE",
-                                        &milestone) &&
-      base::SysInfo::GetLsbReleaseValue("CHROMEOS_RELEASE_BUILD_NUMBER",
-                                        &build) &&
-      base::SysInfo::GetLsbReleaseValue("CHROMEOS_RELEASE_BRANCH_NUMBER",
-                                        &branch) &&
-      base::SysInfo::GetLsbReleaseValue("CHROMEOS_RELEASE_PATCH_NUMBER",
-                                        &patch)) {
-    // Convert to uint to ensure those fields are positive numbers.
-    if (base::StringToUint(milestone, &tmp) &&
-        base::StringToUint(build, &tmp) &&
-        base::StringToUint(branch, &tmp) &&
-        base::StringToUint(patch, &tmp)) {
-      std::vector<std::string> parts = {milestone, build, branch, patch};
-      *version = JoinString(parts, '.');
-      return true;
-    }
-    DLOG(INFO) << "The milestone, build, branch or patch is not a positive "
-               << "number.";
-    return false;
-  }
-  DLOG(INFO) << "Field missing from /etc/lsb-release";
-  return false;
-}
-
-bool SystemProfileCache::GetHardwareId(std::string* hwid) {
-  CHECK(hwid);
-
-  if (testing_) {
-    // if we are in test mode, we do not call crossystem directly.
-    DLOG(INFO) << "skipping hardware id";
-    *hwid = "";
-    return true;
-  }
-
-  char buffer[128];
-  if (buffer != VbGetSystemPropertyString("hwid", buffer, sizeof(buffer))) {
-    LOG(ERROR) << "error getting hwid";
-    return false;
-  }
-
-  *hwid = std::string(buffer);
-  return true;
-}
-
-bool SystemProfileCache::GetProductId(int* product_id) const {
-  chromeos::OsReleaseReader reader;
-  if (testing_) {
-    base::FilePath root(config_root_);
-    reader.LoadTestingOnly(root);
-  } else {
-    reader.Load();
-  }
-
-  std::string id;
-  if (reader.GetString(kProductIdFieldName, &id)) {
-    CHECK(base::StringToInt(id, product_id)) << "Failed to convert product_id "
-                                             << id << " to int.";
-    return true;
-  }
-  return false;
-}
-
-metrics::SystemProfileProto_Channel SystemProfileCache::ProtoChannelFromString(
-    const std::string& channel) {
-
-  if (channel == "stable-channel") {
-    return metrics::SystemProfileProto::CHANNEL_STABLE;
-  } else if (channel == "dev-channel") {
-    return metrics::SystemProfileProto::CHANNEL_DEV;
-  } else if (channel == "beta-channel") {
-    return metrics::SystemProfileProto::CHANNEL_BETA;
-  } else if (channel == "canary-channel") {
-    return metrics::SystemProfileProto::CHANNEL_CANARY;
-  }
-
-  DLOG(INFO) << "unknown channel: " << channel;
-  return metrics::SystemProfileProto::CHANNEL_UNKNOWN;
-}
diff --git a/metrics/uploader/system_profile_setter.h b/metrics/uploader/system_profile_setter.h
deleted file mode 100644
index c535664..0000000
--- a/metrics/uploader/system_profile_setter.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef METRICS_UPLOADER_SYSTEM_PROFILE_SETTER_H_
-#define METRICS_UPLOADER_SYSTEM_PROFILE_SETTER_H_
-
-namespace metrics {
-class ChromeUserMetricsExtension;
-}
-
-// Abstract class used to delegate populating SystemProfileProto with system
-// information to simplify testing.
-class SystemProfileSetter {
- public:
-  virtual ~SystemProfileSetter() {}
-  // Populates the protobuf with system informations.
-  virtual void Populate(metrics::ChromeUserMetricsExtension* profile_proto) = 0;
-};
-
-#endif  // METRICS_UPLOADER_SYSTEM_PROFILE_SETTER_H_
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
new file mode 100644
index 0000000..9fd8eda
--- /dev/null
+++ b/metricsd/Android.mk
@@ -0,0 +1,127 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(HOST_OS),linux)
+
+LOCAL_INIT_SERVICE := metrics_daemon
+
+metrics_cpp_extension := .cc
+libmetrics_sources := \
+  c_metrics_library.cc \
+  metrics_library.cc \
+  serialization/metric_sample.cc \
+  serialization/serialization_utils.cc
+
+metrics_client_sources := \
+  metrics_client.cc
+
+metrics_daemon_sources := \
+  metrics_daemon.cc \
+  metrics_daemon_main.cc \
+  persistent_integer.cc \
+  uploader/metrics_hashes.cc \
+  uploader/metrics_log_base.cc \
+  uploader/metrics_log.cc \
+  uploader/sender_http.cc \
+  uploader/system_profile_cache.cc \
+  uploader/upload_service.cc \
+  serialization/metric_sample.cc \
+  serialization/serialization_utils.cc
+
+metrics_CFLAGS := -Wall \
+  -Wno-char-subscripts \
+  -Wno-missing-field-initializers \
+  -Wno-unused-function \
+  -Wno-unused-parameter \
+  -Werror \
+  -fvisibility=default
+metrics_CPPFLAGS := -Wno-non-virtual-dtor \
+  -Wno-sign-promo \
+  -Wno-strict-aliasing \
+  -fvisibility=default
+metrics_includes := external/gtest/include \
+  $(LOCAL_PATH)/include
+metrics_shared_libraries := libchrome libchromeos
+
+# Shared library for metrics.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libmetrics
+LOCAL_C_INCLUDES := $(metrics_includes)
+LOCAL_CFLAGS := $(metrics_CFLAGS)
+LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
+LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := $(metrics_shared_libraries)
+LOCAL_SRC_FILES := $(libmetrics_sources)
+include $(BUILD_SHARED_LIBRARY)
+
+# CLI client for metrics.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := metrics_client
+LOCAL_C_INCLUDES := $(metrics_includes)
+LOCAL_CFLAGS := $(metrics_CFLAGS)
+LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
+LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
+LOCAL_SHARED_LIBRARIES := $(metrics_shared_libraries) \
+  libmetrics
+LOCAL_SRC_FILES := $(metrics_client_sources)
+include $(BUILD_EXECUTABLE)
+
+# Protobuf library for metrics_daemon.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := metrics_daemon_protos
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+generated_sources_dir := $(call local-generated-sources-dir)
+LOCAL_EXPORT_C_INCLUDE_DIRS += \
+    $(generated_sources_dir)/proto/system/core/metricsd
+LOCAL_SRC_FILES :=  $(call all-proto-files-under,uploader/proto)
+LOCAL_STATIC_LIBRARIES := libprotobuf-cpp-lite
+include $(BUILD_STATIC_LIBRARY)
+
+# metrics daemon.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(LOCAL_INIT_SERVICE)
+LOCAL_C_INCLUDES := $(metrics_includes) \
+  external/libchromeos
+LOCAL_CFLAGS := $(metrics_CFLAGS)
+LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
+LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
+LOCAL_REQUIRED_MODULES := init.$(LOCAL_INIT_SERVICE).rc
+LOCAL_RTTI_FLAG := -frtti
+LOCAL_SHARED_LIBRARIES := $(metrics_shared_libraries) \
+  libmetrics \
+  libprotobuf-cpp-lite \
+  libchromeos-http \
+  libchromeos-dbus \
+  libdbus
+LOCAL_SRC_FILES := $(metrics_daemon_sources)
+LOCAL_STATIC_LIBRARIES := metrics_daemon_protos
+include $(BUILD_EXECUTABLE)
+
+ifdef INITRC_TEMPLATE
+include $(CLEAR_VARS)
+LOCAL_MODULE := init.$(LOCAL_INIT_SERVICE).rc
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_INITRCD)
+LOCAL_SRC_FILES := init.$(LOCAL_INIT_SERVICE).rc
+include $(BUILD_PREBUILT)
+endif # INITRC_TEMPLATE
+
+endif # HOST_OS == linux
diff --git a/metrics/OWNERS b/metricsd/OWNERS
similarity index 100%
rename from metrics/OWNERS
rename to metricsd/OWNERS
diff --git a/metrics/README b/metricsd/README
similarity index 90%
rename from metrics/README
rename to metricsd/README
index 4b92af3..d4c9a0e 100644
--- a/metrics/README
+++ b/metricsd/README
@@ -1,6 +1,18 @@
-Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
+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.
+
+================================================================================
 
 The Chrome OS "metrics" package contains utilities for client-side user metric
 collection.
diff --git a/metrics/WATCHLISTS b/metricsd/WATCHLISTS
similarity index 100%
rename from metrics/WATCHLISTS
rename to metricsd/WATCHLISTS
diff --git a/metrics/c_metrics_library.cc b/metricsd/c_metrics_library.cc
similarity index 79%
rename from metrics/c_metrics_library.cc
rename to metricsd/c_metrics_library.cc
index 90a2d59..0503876 100644
--- a/metrics/c_metrics_library.cc
+++ b/metricsd/c_metrics_library.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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.
+ */
 
 //
 // C wrapper to libmetrics
diff --git a/metricsd/constants.h b/metricsd/constants.h
new file mode 100644
index 0000000..56dac0d
--- /dev/null
+++ b/metricsd/constants.h
@@ -0,0 +1,29 @@
+//
+// 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 METRICS_CONSTANTS_H_
+#define METRICS_CONSTANTS_H_
+
+namespace metrics {
+static const char kMetricsDirectory[] = "/data/misc/metrics/";
+static const char kMetricsEventsFilePath[] = "/data/misc/metrics/uma-events";
+static const char kMetricsGUIDFilePath[] = "/data/misc/metrics/Sysinfo.GUID";
+static const char kMetricsServer[] = "https://clients4.google.com/uma/v2";
+static const char kConsentFilePath[] = "/data/misc/metrics/enabled";
+static const char kDefaultVersion[] = "0.0.0.0";
+}  // namespace metrics
+
+#endif  // METRICS_CONSTANTS_H_
diff --git a/metrics/c_metrics_library.h b/metricsd/include/metrics/c_metrics_library.h
similarity index 71%
rename from metrics/c_metrics_library.h
rename to metricsd/include/metrics/c_metrics_library.h
index 7f78e43..4e7e666 100644
--- a/metrics/c_metrics_library.h
+++ b/metricsd/include/metrics/c_metrics_library.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 METRICS_C_METRICS_LIBRARY_H_
 #define METRICS_C_METRICS_LIBRARY_H_
diff --git a/metrics/metrics_library.h b/metricsd/include/metrics/metrics_library.h
similarity index 89%
rename from metrics/metrics_library.h
rename to metricsd/include/metrics/metrics_library.h
index a90f3e6..4917a7c 100644
--- a/metrics/metrics_library.h
+++ b/metricsd/include/metrics/metrics_library.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 METRICS_METRICS_LIBRARY_H_
 #define METRICS_METRICS_LIBRARY_H_
@@ -14,8 +26,6 @@
 #include <base/memory/scoped_ptr.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
-#include "policy/libpolicy.h"
-
 class MetricsLibraryInterface {
  public:
   virtual void Init() = 0;
@@ -28,7 +38,7 @@
   virtual ~MetricsLibraryInterface() {}
 };
 
-// Library used to send metrics to both Autotest and Chrome/UMA.
+// Library used to send metrics to Chrome/UMA.
 class MetricsLibrary : public MetricsLibraryInterface {
  public:
   MetricsLibrary();
@@ -109,9 +119,6 @@
   // number in the histograms dashboard).
   bool SendCrosEventToUMA(const std::string& event);
 
-  // Sends to Autotest and returns true on success.
-  static bool SendToAutotest(const std::string& name, int value);
-
  private:
   friend class CMetricsLibraryTest;
   friend class MetricsLibraryTest;
@@ -130,9 +137,6 @@
                        char* buffer, int buffer_size,
                        bool* result);
 
-  // This function is used by tests only to mock the device policies.
-  void SetPolicyProvider(policy::PolicyProvider* provider);
-
   // Time at which we last checked if metrics were enabled.
   static time_t cached_enabled_time_;
 
@@ -142,8 +146,6 @@
   std::string uma_events_file_;
   std::string consent_file_;
 
-  scoped_ptr<policy::PolicyProvider> policy_provider_;
-
   DISALLOW_COPY_AND_ASSIGN(MetricsLibrary);
 };
 
diff --git a/metricsd/init.metrics_daemon.rc b/metricsd/init.metrics_daemon.rc
new file mode 100644
index 0000000..ad78ea5
--- /dev/null
+++ b/metricsd/init.metrics_daemon.rc
@@ -0,0 +1,8 @@
+on boot
+    mkdir /data/misc/metrics 0700 system system
+
+service metrics_daemon /system/bin/metrics_daemon --uploader -nodaemon
+    class late_start
+    user system
+    group system dbus inet
+    seclabel u:r:brillo:s0
diff --git a/metrics/libmetrics-334380.gyp b/metricsd/libmetrics-334380.gyp
similarity index 100%
rename from metrics/libmetrics-334380.gyp
rename to metricsd/libmetrics-334380.gyp
diff --git a/metrics/libmetrics.gypi b/metricsd/libmetrics.gypi
similarity index 100%
rename from metrics/libmetrics.gypi
rename to metricsd/libmetrics.gypi
diff --git a/metrics/libmetrics.pc.in b/metricsd/libmetrics.pc.in
similarity index 100%
rename from metrics/libmetrics.pc.in
rename to metricsd/libmetrics.pc.in
diff --git a/metrics/metrics.gyp b/metricsd/metrics.gyp
similarity index 100%
rename from metrics/metrics.gyp
rename to metricsd/metrics.gyp
diff --git a/metrics/metrics_client.cc b/metricsd/metrics_client.cc
similarity index 71%
rename from metrics/metrics_client.cc
rename to metricsd/metrics_client.cc
index bbe9dcd..57e96c2 100644
--- a/metrics/metrics_client.cc
+++ b/metricsd/metrics_client.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 <cstdio>
 #include <cstdlib>
@@ -19,17 +31,15 @@
 
 void ShowUsage() {
   fprintf(stderr,
-          "Usage:  metrics_client [-ab] [-t] name sample min max nbuckets\n"
-          "        metrics_client [-ab] -e   name sample max\n"
-          "        metrics_client [-ab] -s   name sample\n"
-          "        metrics_client [-ab] -v   event\n"
+          "Usage:  metrics_client [-t] name sample min max nbuckets\n"
+          "        metrics_client -e   name sample max\n"
+          "        metrics_client -s   name sample\n"
+          "        metrics_client -v   event\n"
           "        metrics_client -u action\n"
           "        metrics_client [-cg]\n"
           "\n"
-          "  default: send metric with integer values to Chrome only\n"
+          "  default: send metric with integer values \n"
           "           |min| > 0, |min| <= sample < |max|\n"
-          "  -a: send metric (name/sample) to Autotest only\n"
-          "  -b: send metric to both Chrome and Autotest\n"
           "  -c: return exit status 0 if user consents to stats, 1 otherwise,\n"
           "      in guest mode always return 1\n"
           "  -e: send linear/enumeration histogram data\n"
@@ -64,9 +74,7 @@
 static int SendStats(char* argv[],
                      int name_index,
                      enum Mode mode,
-                     bool secs_to_msecs,
-                     bool send_to_autotest,
-                     bool send_to_chrome) {
+                     bool secs_to_msecs) {
   const char* name = argv[name_index];
   int sample;
   if (secs_to_msecs) {
@@ -75,25 +83,18 @@
     sample = ParseInt(argv[name_index + 1]);
   }
 
-  // Send metrics
-  if (send_to_autotest) {
-    MetricsLibrary::SendToAutotest(name, sample);
-  }
-
-  if (send_to_chrome) {
-    MetricsLibrary metrics_lib;
-    metrics_lib.Init();
-    if (mode == kModeSendSparseSample) {
-      metrics_lib.SendSparseToUMA(name, sample);
-    } else if (mode == kModeSendEnumSample) {
-      int max = ParseInt(argv[name_index + 2]);
-      metrics_lib.SendEnumToUMA(name, sample, max);
-    } else {
-      int min = ParseInt(argv[name_index + 2]);
-      int max = ParseInt(argv[name_index + 3]);
-      int nbuckets = ParseInt(argv[name_index + 4]);
-      metrics_lib.SendToUMA(name, sample, min, max, nbuckets);
-    }
+  MetricsLibrary metrics_lib;
+  metrics_lib.Init();
+  if (mode == kModeSendSparseSample) {
+    metrics_lib.SendSparseToUMA(name, sample);
+  } else if (mode == kModeSendEnumSample) {
+    int max = ParseInt(argv[name_index + 2]);
+    metrics_lib.SendEnumToUMA(name, sample, max);
+  } else {
+    int min = ParseInt(argv[name_index + 2]);
+    int max = ParseInt(argv[name_index + 3]);
+    int nbuckets = ParseInt(argv[name_index + 4]);
+    metrics_lib.SendToUMA(name, sample, min, max, nbuckets);
   }
   return 0;
 }
@@ -133,22 +134,12 @@
 
 int main(int argc, char** argv) {
   enum Mode mode = kModeSendSample;
-  bool send_to_autotest = false;
-  bool send_to_chrome = true;
   bool secs_to_msecs = false;
 
   // Parse arguments
   int flag;
   while ((flag = getopt(argc, argv, "abcegstuv")) != -1) {
     switch (flag) {
-      case 'a':
-        send_to_autotest = true;
-        send_to_chrome = false;
-        break;
-      case 'b':
-        send_to_chrome = true;
-        send_to_autotest = true;
-        break;
       case 'c':
         mode = kModeHasConsent;
         break;
@@ -203,9 +194,7 @@
       return SendStats(argv,
                        arg_index,
                        mode,
-                       secs_to_msecs,
-                       send_to_autotest,
-                       send_to_chrome);
+                       secs_to_msecs);
     case kModeSendUserAction:
       return SendUserAction(argv, arg_index);
     case kModeSendCrosEvent:
diff --git a/metrics/metrics_daemon.cc b/metricsd/metrics_daemon.cc
similarity index 90%
rename from metrics/metrics_daemon.cc
rename to metricsd/metrics_daemon.cc
index 880e90c..069f68e 100644
--- a/metrics/metrics_daemon.cc
+++ b/metricsd/metrics_daemon.cc
@@ -1,8 +1,20 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 "metrics/metrics_daemon.h"
+#include "metrics_daemon.h"
 
 #include <fcntl.h>
 #include <inttypes.h>
@@ -11,6 +23,7 @@
 #include <sysexits.h>
 #include <time.h>
 
+#include <base/bind.h>
 #include <base/files/file_path.h>
 #include <base/files/file_util.h>
 #include <base/hash.h>
@@ -20,9 +33,10 @@
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
 #include <base/sys_info.h>
-#include <chromeos/dbus/service_constants.h>
 #include <dbus/dbus.h>
 #include <dbus/message.h>
+
+#include "constants.h"
 #include "uploader/upload_service.h"
 
 using base::FilePath;
@@ -44,10 +58,6 @@
 const char kCrashReporterMatchRule[] =
     "type='signal',interface='%s',path='/',member='%s'";
 
-// Build type of an official build.
-// See src/third_party/chromiumos-overlay/chromeos/scripts/cros_set_lsb_release.
-const char kOfficialBuild[] = "Official Build";
-
 const int kSecondsPerMinute = 60;
 const int kMinutesPerHour = 60;
 const int kHoursPerDay = 24;
@@ -199,28 +209,21 @@
   if (version_hash_is_cached)
     return cached_version_hash;
   version_hash_is_cached = true;
-  std::string version;
-  if (base::SysInfo::GetLsbReleaseValue("CHROMEOS_RELEASE_VERSION", &version)) {
-    cached_version_hash = base::Hash(version);
-  } else if (testing_) {
+  std::string version = metrics::kDefaultVersion;
+  // The version might not be set for development devices. In this case, use the
+  // zero version.
+  base::SysInfo::GetLsbReleaseValue("BRILLO_VERSION", &version);
+  cached_version_hash = base::Hash(version);
+  if (testing_) {
     cached_version_hash = 42;  // return any plausible value for the hash
-  } else {
-    LOG(FATAL) << "could not find CHROMEOS_RELEASE_VERSION";
   }
   return cached_version_hash;
 }
 
-bool MetricsDaemon::IsOnOfficialBuild() const {
-  std::string build_type;
-  return (base::SysInfo::GetLsbReleaseValue("CHROMEOS_RELEASE_BUILD_TYPE",
-                                            &build_type) &&
-          build_type == kOfficialBuild);
-}
-
 void MetricsDaemon::Init(bool testing,
                          bool uploader_active,
+                         bool dbus_enabled,
                          MetricsLibraryInterface* metrics_lib,
-                         const string& diskstats_path,
                          const string& vmstats_path,
                          const string& scaling_max_freq_path,
                          const string& cpuinfo_max_freq_path,
@@ -230,6 +233,7 @@
                          const string& config_root) {
   testing_ = testing;
   uploader_active_ = uploader_active;
+  dbus_enabled_ = dbus_enabled;
   config_root_ = config_root;
   DCHECK(metrics_lib != nullptr);
   metrics_lib_ = metrics_lib;
@@ -279,77 +283,58 @@
   weekly_cycle_.reset(new PersistentInteger("weekly.cycle"));
   version_cycle_.reset(new PersistentInteger("version.cycle"));
 
-  diskstats_path_ = diskstats_path;
   vmstats_path_ = vmstats_path;
   scaling_max_freq_path_ = scaling_max_freq_path;
   cpuinfo_max_freq_path_ = cpuinfo_max_freq_path;
-
-  // If testing, initialize Stats Reporter without connecting DBus
-  if (testing_)
-    StatsReporterInit();
 }
 
 int MetricsDaemon::OnInit() {
-  int return_code = chromeos::DBusDaemon::OnInit();
+  int return_code = dbus_enabled_ ? chromeos::DBusDaemon::OnInit() :
+      chromeos::Daemon::OnInit();
   if (return_code != EX_OK)
     return return_code;
 
-  StatsReporterInit();
-
-  // Start collecting meminfo stats.
-  ScheduleMeminfoCallback(kMetricMeminfoInterval);
-  memuse_final_time_ = GetActiveTime() + kMemuseIntervals[0];
-  ScheduleMemuseCallback(kMemuseIntervals[0]);
-
   if (testing_)
     return EX_OK;
 
-  bus_->AssertOnDBusThread();
-  CHECK(bus_->SetUpAsyncOperations());
+  if (dbus_enabled_) {
+    bus_->AssertOnDBusThread();
+    CHECK(bus_->SetUpAsyncOperations());
 
-  if (bus_->is_connected()) {
-    const std::string match_rule =
-        base::StringPrintf(kCrashReporterMatchRule,
-                           kCrashReporterInterface,
-                           kCrashReporterUserCrashSignal);
+    if (bus_->is_connected()) {
+      const std::string match_rule =
+          base::StringPrintf(kCrashReporterMatchRule,
+                             kCrashReporterInterface,
+                             kCrashReporterUserCrashSignal);
 
-    bus_->AddFilterFunction(&MetricsDaemon::MessageFilter, this);
+      bus_->AddFilterFunction(&MetricsDaemon::MessageFilter, this);
 
-    DBusError error;
-    dbus_error_init(&error);
-    bus_->AddMatch(match_rule, &error);
+      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;
+      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;
     }
-  } else {
-    LOG(ERROR) << "DBus isn't connected.";
-    return EX_UNAVAILABLE;
   }
 
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::Bind(&MetricsDaemon::HandleUpdateStatsTimeout,
-                 base::Unretained(this)),
-      base::TimeDelta::FromMilliseconds(kUpdateStatsIntervalMs));
-
   if (uploader_active_) {
-    if (IsOnOfficialBuild()) {
-      LOG(INFO) << "uploader enabled";
-      upload_service_.reset(
-          new UploadService(new SystemProfileCache(), metrics_lib_, server_));
-      upload_service_->Init(upload_interval_, metrics_file_);
-    } else {
-      LOG(INFO) << "uploader disabled on non-official build";
-    }
+    upload_service_.reset(
+        new UploadService(new SystemProfileCache(), metrics_lib_, server_));
+    upload_service_->Init(upload_interval_, metrics_file_);
   }
 
   return EX_OK;
 }
 
 void MetricsDaemon::OnShutdown(int* return_code) {
-  if (!testing_ && bus_->is_connected()) {
+  if (!testing_ && dbus_enabled_ && bus_->is_connected()) {
     const std::string match_rule =
         base::StringPrintf(kCrashReporterMatchRule,
                            kCrashReporterInterface,
@@ -520,41 +505,6 @@
       base::TimeDelta::FromSeconds(wait));
 }
 
-bool MetricsDaemon::DiskStatsReadStats(uint64_t* read_sectors,
-                                       uint64_t* write_sectors) {
-  int nchars;
-  int nitems;
-  bool success = false;
-  char line[200];
-  if (diskstats_path_.empty()) {
-    return false;
-  }
-  int file = HANDLE_EINTR(open(diskstats_path_.c_str(), O_RDONLY));
-  if (file < 0) {
-    PLOG(WARNING) << "cannot open " << diskstats_path_;
-    return false;
-  }
-  nchars = HANDLE_EINTR(read(file, line, sizeof(line)));
-  if (nchars < 0) {
-    PLOG(WARNING) << "cannot read from " << diskstats_path_;
-    return false;
-  } else {
-    LOG_IF(WARNING, nchars == sizeof(line))
-        << "line too long in " << diskstats_path_;
-    line[nchars] = '\0';
-    nitems = sscanf(line, "%*d %*d %" PRIu64 " %*d %*d %*d %" PRIu64,
-                    read_sectors, write_sectors);
-    if (nitems == 2) {
-      success = true;
-    } else {
-      LOG(WARNING) << "found " << nitems << " items in "
-                   << diskstats_path_ << ", expected 2";
-    }
-  }
-  IGNORE_EINTR(close(file));
-  return success;
-}
-
 bool MetricsDaemon::VmStatsParseStats(const char* stats,
                                       struct VmstatRecord* record) {
   // a mapping of string name to field in VmstatRecord and whether we found it
diff --git a/metrics/metrics_daemon.h b/metricsd/metrics_daemon.h
similarity index 94%
rename from metrics/metrics_daemon.h
rename to metricsd/metrics_daemon.h
index b1b2d11..6f5a3bf 100644
--- a/metrics/metrics_daemon.h
+++ b/metricsd/metrics_daemon.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 METRICS_METRICS_DAEMON_H_
 #define METRICS_METRICS_DAEMON_H_
@@ -18,7 +30,7 @@
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
 #include "metrics/metrics_library.h"
-#include "metrics/persistent_integer.h"
+#include "persistent_integer.h"
 #include "uploader/upload_service.h"
 
 using chromeos_metrics::PersistentInteger;
@@ -31,8 +43,8 @@
   // 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& vmstats_path,
             const std::string& cpuinfo_max_freq_path,
             const std::string& scaling_max_freq_path,
@@ -269,9 +281,6 @@
   // to a unsigned 32-bit int.
   uint32_t GetOsVersionHash();
 
-  // Returns true if the system is using an official build.
-  bool IsOnOfficialBuild() const;
-
   // Updates stats, additionally sending them to UMA if enough time has elapsed
   // since the last report.
   void UpdateStats(base::TimeTicks now_ticks, base::Time now_wall_time);
@@ -293,6 +302,10 @@
   // 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.
   std::string config_root_;
 
@@ -356,7 +369,6 @@
   scoped_ptr<PersistentInteger> unclean_shutdowns_daily_count_;
   scoped_ptr<PersistentInteger> unclean_shutdowns_weekly_count_;
 
-  std::string diskstats_path_;
   std::string vmstats_path_;
   std::string scaling_max_freq_path_;
   std::string cpuinfo_max_freq_path_;
diff --git a/metrics/metrics_daemon_main.cc b/metricsd/metrics_daemon_main.cc
similarity index 64%
rename from metrics/metrics_daemon_main.cc
rename to metricsd/metrics_daemon_main.cc
index 1f64ef3..c3d5cab 100644
--- a/metrics/metrics_daemon_main.cc
+++ b/metricsd/metrics_daemon_main.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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>
@@ -8,40 +20,15 @@
 #include <base/strings/string_util.h>
 #include <chromeos/flag_helper.h>
 #include <chromeos/syslog_logging.h>
-#include <rootdev/rootdev.h>
 
-#include "metrics/metrics_daemon.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/";
-  std::string dev_path;
-  std::string dev_name;
-
-  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/".
-  if (!base::StartsWithASCII(dev_path, dev_prefix, false)) {
-    LOG(WARNING) << "unexpected root device " << dev_path;
-    return "";
-  }
-  // Get the device name, e.g. "sda" from "/dev/sda".
-  dev_name = dev_path.substr(dev_prefix.length());
-  return "/sys/class/block/" + dev_name + "/stat";
-}
-
 int main(int argc, char** argv) {
   DEFINE_bool(daemon, true, "run as daemon (use -nodaemon for debugging)");
 
@@ -54,16 +41,19 @@
               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,
-                "https://clients4.google.com/uma/v2",
+                metrics::kMetricsServer,
                 "Server to upload the metrics to. (needs -uploader)");
   DEFINE_string(metrics_file,
-                "/var/lib/metrics/uma-events",
+                metrics::kMetricsEventsFilePath,
                 "File to use as a proxy for uploading the metrics");
   DEFINE_string(config_root,
                 "/", "Root of the configuration files (testing only)");
@@ -83,8 +73,8 @@
   MetricsDaemon daemon;
   daemon.Init(FLAGS_uploader_test,
               FLAGS_uploader | FLAGS_uploader_test,
+              FLAGS_withdbus,
               &metrics_lib,
-              MetricsMainDiskStatsPath(),
               "/proc/vmstat",
               kScalingMaxFreqPath,
               kCpuinfoMaxFreqPath,
diff --git a/metrics/metrics_daemon_test.cc b/metricsd/metrics_daemon_test.cc
similarity index 95%
rename from metrics/metrics_daemon_test.cc
rename to metricsd/metrics_daemon_test.cc
index 7dafbd6..9b5b58e 100644
--- a/metrics/metrics_daemon_test.cc
+++ b/metricsd/metrics_daemon_test.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 <inttypes.h>
 #include <utime.h>
@@ -15,9 +27,9 @@
 #include <chromeos/dbus/service_constants.h>
 #include <gtest/gtest.h>
 
-#include "metrics/metrics_daemon.h"
-#include "metrics/metrics_library_mock.h"
-#include "metrics/persistent_integer_mock.h"
+#include "metrics_daemon.h"
+#include "metrics_library_mock.h"
+#include "persistent_integer_mock.h"
 
 using base::FilePath;
 using base::StringPrintf;
@@ -44,8 +56,6 @@
 static const char kFakeVmStatsName[] = "fake-vm-stats";
 static const char kFakeScalingMaxFreqPath[] = "fake-scaling-max-freq";
 static const char kFakeCpuinfoMaxFreqPath[] = "fake-cpuinfo-max-freq";
-static const char kMetricsServer[] = "https://clients4.google.com/uma/v2";
-static const char kMetricsFilePath[] = "/var/lib/metrics/uma-events";
 
 class MetricsDaemonTest : public testing::Test {
  protected:
diff --git a/metrics/metrics_library.cc b/metricsd/metrics_library.cc
similarity index 68%
rename from metrics/metrics_library.cc
rename to metricsd/metrics_library.cc
index 70c8eac..c1998a6 100644
--- a/metrics/metrics_library.cc
+++ b/metricsd/metrics_library.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 "metrics/metrics_library.h"
 
@@ -13,14 +25,10 @@
 #include <cstdio>
 #include <cstring>
 
-#include "metrics/serialization/metric_sample.h"
-#include "metrics/serialization/serialization_utils.h"
+#include "constants.h"
+#include "serialization/metric_sample.h"
+#include "serialization/serialization_utils.h"
 
-#include "policy/device_policy.h"
-
-static const char kAutotestPath[] = "/var/log/metrics/autotest-events";
-static const char kUMAEventsPath[] = "/var/lib/metrics/uma-events";
-static const char kConsentFile[] = "/home/chronos/Consent To Send Stats";
 static const char kCrosEventHistogramName[] = "Platform.CrOSEvent";
 static const int kCrosEventHistogramMax = 100;
 
@@ -48,7 +56,7 @@
 time_t MetricsLibrary::cached_enabled_time_ = 0;
 bool MetricsLibrary::cached_enabled_ = false;
 
-MetricsLibrary::MetricsLibrary() : consent_file_(kConsentFile) {}
+MetricsLibrary::MetricsLibrary() : consent_file_(metrics::kConsentFilePath) {}
 MetricsLibrary::~MetricsLibrary() {}
 
 // We take buffer and buffer_size as parameters in order to simplify testing
@@ -123,47 +131,13 @@
   time_t this_check_time = time(nullptr);
   if (this_check_time != cached_enabled_time_) {
     cached_enabled_time_ = this_check_time;
-
-    if (!policy_provider_.get())
-      policy_provider_.reset(new policy::PolicyProvider());
-    policy_provider_->Reload();
-    // We initialize with the default value which is false and will be preserved
-    // if the policy is not set.
-    bool enabled = false;
-    bool has_policy = false;
-    if (policy_provider_->device_policy_is_loaded()) {
-      has_policy =
-          policy_provider_->GetDevicePolicy().GetMetricsEnabled(&enabled);
-    }
-    // If policy couldn't be loaded or the metrics policy is not set we should
-    // still respect the consent file if it is present for migration purposes.
-    // TODO(pastarmovj)
-    if (!has_policy) {
-      enabled = stat(consent_file_.c_str(), &stat_buffer) >= 0;
-    }
-
-    if (enabled && !IsGuestMode())
-      cached_enabled_ = true;
-    else
-      cached_enabled_ = false;
+    cached_enabled_ = stat(consent_file_.c_str(), &stat_buffer) >= 0;
   }
   return cached_enabled_;
 }
 
 void MetricsLibrary::Init() {
-  uma_events_file_ = kUMAEventsPath;
-}
-
-bool MetricsLibrary::SendToAutotest(const std::string& name, int value) {
-  FILE* autotest_file = fopen(kAutotestPath, "a+");
-  if (autotest_file == nullptr) {
-    PLOG(ERROR) << kAutotestPath << ": fopen";
-    return false;
-  }
-
-  fprintf(autotest_file, "%s=%d\n", name.c_str(), value);
-  fclose(autotest_file);
-  return true;
+  uma_events_file_ = metrics::kMetricsEventsFilePath;
 }
 
 bool MetricsLibrary::SendToUMA(const std::string& name,
@@ -174,34 +148,30 @@
   return metrics::SerializationUtils::WriteMetricToFile(
       *metrics::MetricSample::HistogramSample(name, sample, min, max, nbuckets)
            .get(),
-      kUMAEventsPath);
+      metrics::kMetricsEventsFilePath);
 }
 
 bool MetricsLibrary::SendEnumToUMA(const std::string& name, int sample,
                                    int max) {
   return metrics::SerializationUtils::WriteMetricToFile(
       *metrics::MetricSample::LinearHistogramSample(name, sample, max).get(),
-      kUMAEventsPath);
+      metrics::kMetricsEventsFilePath);
 }
 
 bool MetricsLibrary::SendSparseToUMA(const std::string& name, int sample) {
   return metrics::SerializationUtils::WriteMetricToFile(
       *metrics::MetricSample::SparseHistogramSample(name, sample).get(),
-      kUMAEventsPath);
+      metrics::kMetricsEventsFilePath);
 }
 
 bool MetricsLibrary::SendUserActionToUMA(const std::string& action) {
   return metrics::SerializationUtils::WriteMetricToFile(
-      *metrics::MetricSample::UserActionSample(action).get(), kUMAEventsPath);
+      *metrics::MetricSample::UserActionSample(action).get(), metrics::kMetricsEventsFilePath);
 }
 
 bool MetricsLibrary::SendCrashToUMA(const char *crash_kind) {
   return metrics::SerializationUtils::WriteMetricToFile(
-      *metrics::MetricSample::CrashSample(crash_kind).get(), kUMAEventsPath);
-}
-
-void MetricsLibrary::SetPolicyProvider(policy::PolicyProvider* provider) {
-  policy_provider_.reset(provider);
+      *metrics::MetricSample::CrashSample(crash_kind).get(), metrics::kMetricsEventsFilePath);
 }
 
 bool MetricsLibrary::SendCrosEventToUMA(const std::string& event) {
diff --git a/metricsd/metrics_library_mock.h b/metricsd/metrics_library_mock.h
new file mode 100644
index 0000000..3de87a9
--- /dev/null
+++ b/metricsd/metrics_library_mock.h
@@ -0,0 +1,41 @@
+/*
+ * 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 METRICS_METRICS_LIBRARY_MOCK_H_
+#define METRICS_METRICS_LIBRARY_MOCK_H_
+
+#include <string>
+
+#include "metrics/metrics_library.h"
+
+#include <gmock/gmock.h>
+
+class MetricsLibraryMock : public MetricsLibraryInterface {
+ public:
+  bool metrics_enabled_ = true;
+
+  MOCK_METHOD0(Init, void());
+  MOCK_METHOD5(SendToUMA, bool(const std::string& name, int sample,
+                               int min, int max, int nbuckets));
+  MOCK_METHOD3(SendEnumToUMA, bool(const std::string& name, int sample,
+                                   int max));
+  MOCK_METHOD2(SendSparseToUMA, bool(const std::string& name, int sample));
+  MOCK_METHOD1(SendUserActionToUMA, bool(const std::string& action));
+
+  bool AreMetricsEnabled() override {return metrics_enabled_;};
+};
+
+#endif  // METRICS_METRICS_LIBRARY_MOCK_H_
diff --git a/metrics/metrics_library_test.cc b/metricsd/metrics_library_test.cc
similarity index 92%
rename from metrics/metrics_library_test.cc
rename to metricsd/metrics_library_test.cc
index 7ede303..c58e3fb 100644
--- a/metrics/metrics_library_test.cc
+++ b/metricsd/metrics_library_test.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 <cstring>
 
diff --git a/metrics/persistent_integer.cc b/metricsd/persistent_integer.cc
similarity index 74%
rename from metrics/persistent_integer.cc
rename to metricsd/persistent_integer.cc
index dd38f1e..9fa5c1e 100644
--- a/metrics/persistent_integer.cc
+++ b/metricsd/persistent_integer.cc
@@ -1,22 +1,29 @@
-// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 "metrics/persistent_integer.h"
+#include "persistent_integer.h"
 
 #include <fcntl.h>
 
 #include <base/logging.h>
 #include <base/posix/eintr_wrapper.h>
 
+#include "constants.h"
 #include "metrics/metrics_library.h"
 
-namespace {
-
-// The directory for the persistent storage.
-const char kBackingFilesDirectory[] = "/var/lib/metrics/";
-
-}
 
 namespace chromeos_metrics {
 
@@ -31,7 +38,7 @@
   if (testing_) {
     backing_file_name_ = name_;
   } else {
-    backing_file_name_ = kBackingFilesDirectory + name_;
+    backing_file_name_ = metrics::kMetricsDirectory + name_;
   }
 }
 
diff --git a/metrics/persistent_integer.h b/metricsd/persistent_integer.h
similarity index 73%
rename from metrics/persistent_integer.h
rename to metricsd/persistent_integer.h
index b1cfcf4..fec001f 100644
--- a/metrics/persistent_integer.h
+++ b/metricsd/persistent_integer.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 METRICS_PERSISTENT_INTEGER_H_
 #define METRICS_PERSISTENT_INTEGER_H_
diff --git a/metricsd/persistent_integer_mock.h b/metricsd/persistent_integer_mock.h
new file mode 100644
index 0000000..acc5389
--- /dev/null
+++ b/metricsd/persistent_integer_mock.h
@@ -0,0 +1,37 @@
+/*
+ * 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 METRICS_PERSISTENT_INTEGER_MOCK_H_
+#define METRICS_PERSISTENT_INTEGER_MOCK_H_
+
+#include <string>
+
+#include <gmock/gmock.h>
+
+#include "persistent_integer.h"
+
+namespace chromeos_metrics {
+
+class PersistentIntegerMock : public PersistentInteger {
+ public:
+  explicit PersistentIntegerMock(const std::string& name)
+      : PersistentInteger(name) {}
+    MOCK_METHOD1(Add, void(int64_t count));
+};
+
+}  // namespace chromeos_metrics
+
+#endif  // METRICS_PERSISTENT_INTEGER_MOCK_H_
diff --git a/metrics/persistent_integer_test.cc b/metricsd/persistent_integer_test.cc
similarity index 71%
rename from metrics/persistent_integer_test.cc
rename to metricsd/persistent_integer_test.cc
index a56aede..19801f9 100644
--- a/metrics/persistent_integer_test.cc
+++ b/metricsd/persistent_integer_test.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 <gtest/gtest.h>
 
@@ -8,7 +20,7 @@
 #include <base/files/file_enumerator.h>
 #include <base/files/file_util.h>
 
-#include "metrics/persistent_integer.h"
+#include "persistent_integer.h"
 
 const char kBackingFileName[] = "1.pibakf";
 const char kBackingFilePattern[] = "*.pibakf";
diff --git a/metrics/serialization/metric_sample.cc b/metricsd/serialization/metric_sample.cc
similarity index 89%
rename from metrics/serialization/metric_sample.cc
rename to metricsd/serialization/metric_sample.cc
index 5447497..76a47c0 100644
--- a/metrics/serialization/metric_sample.cc
+++ b/metricsd/serialization/metric_sample.cc
@@ -1,8 +1,20 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 "metrics/serialization/metric_sample.h"
+#include "serialization/metric_sample.h"
 
 #include <string>
 #include <vector>
diff --git a/metrics/serialization/metric_sample.h b/metricsd/serialization/metric_sample.h
similarity index 85%
rename from metrics/serialization/metric_sample.h
rename to metricsd/serialization/metric_sample.h
index 877114d..5a4e4ae 100644
--- a/metrics/serialization/metric_sample.h
+++ b/metricsd/serialization/metric_sample.h
@@ -1,6 +1,18 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 METRICS_SERIALIZATION_METRIC_SAMPLE_H_
 #define METRICS_SERIALIZATION_METRIC_SAMPLE_H_
diff --git a/metrics/serialization/serialization_utils.cc b/metricsd/serialization/serialization_utils.cc
similarity index 90%
rename from metrics/serialization/serialization_utils.cc
rename to metricsd/serialization/serialization_utils.cc
index 9aa076a..6dd8258 100644
--- a/metrics/serialization/serialization_utils.cc
+++ b/metricsd/serialization/serialization_utils.cc
@@ -1,8 +1,20 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 "metrics/serialization/serialization_utils.h"
+#include "serialization/serialization_utils.h"
 
 #include <sys/file.h>
 
@@ -17,7 +29,7 @@
 #include "base/memory/scoped_vector.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
-#include "metrics/serialization/metric_sample.h"
+#include "serialization/metric_sample.h"
 
 #define READ_WRITE_ALL_FILE_FLAGS \
   (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
diff --git a/metrics/serialization/serialization_utils.h b/metricsd/serialization/serialization_utils.h
similarity index 71%
rename from metrics/serialization/serialization_utils.h
rename to metricsd/serialization/serialization_utils.h
index 5af6166..67d4675 100644
--- a/metrics/serialization/serialization_utils.h
+++ b/metricsd/serialization/serialization_utils.h
@@ -1,6 +1,18 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 METRICS_SERIALIZATION_SERIALIZATION_UTILS_H_
 #define METRICS_SERIALIZATION_SERIALIZATION_UTILS_H_
diff --git a/metrics/serialization/serialization_utils_unittest.cc b/metricsd/serialization/serialization_utils_unittest.cc
similarity index 88%
rename from metrics/serialization/serialization_utils_unittest.cc
rename to metricsd/serialization/serialization_utils_unittest.cc
index 34d76cf..7a572de 100644
--- a/metrics/serialization/serialization_utils_unittest.cc
+++ b/metricsd/serialization/serialization_utils_unittest.cc
@@ -1,8 +1,20 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 "metrics/serialization/serialization_utils.h"
+#include "serialization/serialization_utils.h"
 
 #include <base/files/file_util.h>
 #include <base/files/scoped_temp_dir.h>
@@ -10,7 +22,7 @@
 #include <base/strings/stringprintf.h>
 #include <gtest/gtest.h>
 
-#include "metrics/serialization/metric_sample.h"
+#include "serialization/metric_sample.h"
 
 namespace metrics {
 namespace {
diff --git a/metrics/timer.cc b/metricsd/timer.cc
similarity index 80%
rename from metrics/timer.cc
rename to metricsd/timer.cc
index 99f68fe..7b00cc0 100644
--- a/metrics/timer.cc
+++ b/metricsd/timer.cc
@@ -1,8 +1,20 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 "metrics/timer.h"
+#include "timer.h"
 
 #include <string>
 
diff --git a/metrics/timer.h b/metricsd/timer.h
similarity index 88%
rename from metrics/timer.h
rename to metricsd/timer.h
index 52cc578..b36ffff 100644
--- a/metrics/timer.h
+++ b/metricsd/timer.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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.
+ */
 
 // Timer - class that provides timer tracking.
 
diff --git a/metrics/timer_mock.h b/metricsd/timer_mock.h
similarity index 63%
rename from metrics/timer_mock.h
rename to metricsd/timer_mock.h
index 2f2d0f4..8c9e8d8 100644
--- a/metrics/timer_mock.h
+++ b/metricsd/timer_mock.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 METRICS_TIMER_MOCK_H_
 #define METRICS_TIMER_MOCK_H_
@@ -9,7 +21,7 @@
 
 #include <gmock/gmock.h>
 
-#include "metrics/timer.h"
+#include "timer.h"
 
 namespace chromeos_metrics {
 
diff --git a/metrics/timer_test.cc b/metricsd/timer_test.cc
similarity index 95%
rename from metrics/timer_test.cc
rename to metricsd/timer_test.cc
index ec6c6bd..ab027d4 100644
--- a/metrics/timer_test.cc
+++ b/metricsd/timer_test.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 <stdint.h>
 
@@ -8,9 +20,9 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
-#include "metrics/metrics_library_mock.h"
-#include "metrics/timer.h"
-#include "metrics/timer_mock.h"
+#include "metrics_library_mock.h"
+#include "timer.h"
+#include "timer_mock.h"
 
 using ::testing::_;
 using ::testing::Return;
diff --git a/metricsd/uploader/metrics_hashes.cc b/metricsd/uploader/metrics_hashes.cc
new file mode 100644
index 0000000..208c560
--- /dev/null
+++ b/metricsd/uploader/metrics_hashes.cc
@@ -0,0 +1,51 @@
+/*
+ * 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 "uploader/metrics_hashes.h"
+
+#include "base/logging.h"
+#include "base/md5.h"
+#include "base/sys_byteorder.h"
+
+namespace metrics {
+
+namespace {
+
+// Converts the 8-byte prefix of an MD5 hash into a uint64 value.
+inline uint64_t HashToUInt64(const std::string& hash) {
+  uint64_t value;
+  DCHECK_GE(hash.size(), sizeof(value));
+  memcpy(&value, hash.data(), sizeof(value));
+  return base::HostToNet64(value);
+}
+
+}  // namespace
+
+uint64_t HashMetricName(const std::string& name) {
+  // Create an MD5 hash of the given |name|, represented as a byte buffer
+  // encoded as an std::string.
+  base::MD5Context context;
+  base::MD5Init(&context);
+  base::MD5Update(&context, name);
+
+  base::MD5Digest digest;
+  base::MD5Final(&digest, &context);
+
+  std::string hash_str(reinterpret_cast<char*>(digest.a), arraysize(digest.a));
+  return HashToUInt64(hash_str);
+}
+
+}  // namespace metrics
diff --git a/base/test_utils.h b/metricsd/uploader/metrics_hashes.h
similarity index 64%
copy from base/test_utils.h
copy to metricsd/uploader/metrics_hashes.h
index 132d3a7..1082b42 100644
--- a/base/test_utils.h
+++ b/metricsd/uploader/metrics_hashes.h
@@ -14,19 +14,17 @@
  * limitations under the License.
  */
 
-#ifndef TEST_UTILS_H
-#define TEST_UTILS_H
+#ifndef METRICS_UPLOADER_METRICS_HASHES_H_
+#define METRICS_UPLOADER_METRICS_HASHES_H_
 
-class TemporaryFile {
- public:
-  TemporaryFile();
-  ~TemporaryFile();
+#include <string>
 
-  int fd;
-  char filename[1024];
+namespace metrics {
 
- private:
-  void init(const char* tmp_dir);
-};
+// Computes a uint64 hash of a given string based on its MD5 hash. Suitable for
+// metric names.
+uint64_t HashMetricName(const std::string& name);
 
-#endif // TEST_UTILS_H
+}  // namespace metrics
+
+#endif  // METRICS_UPLOADER_METRICS_HASHES_H_
diff --git a/metricsd/uploader/metrics_hashes_unittest.cc b/metricsd/uploader/metrics_hashes_unittest.cc
new file mode 100644
index 0000000..b8c2575
--- /dev/null
+++ b/metricsd/uploader/metrics_hashes_unittest.cc
@@ -0,0 +1,44 @@
+/*
+ * 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 "uploader/metrics_hashes.h"
+
+#include <base/format_macros.h>
+#include <base/macros.h>
+#include <base/strings/stringprintf.h>
+#include <gtest/gtest.h>
+
+namespace metrics {
+
+// Make sure our ID hashes are the same as what we see on the server side.
+TEST(MetricsUtilTest, HashMetricName) {
+  static const struct {
+    std::string input;
+    std::string output;
+  } cases[] = {
+    {"Back", "0x0557fa923dcee4d0"},
+    {"Forward", "0x67d2f6740a8eaebf"},
+    {"NewTab", "0x290eb683f96572f1"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    uint64_t hash = HashMetricName(cases[i].input);
+    std::string hash_hex = base::StringPrintf("0x%016" PRIx64, hash);
+    EXPECT_EQ(cases[i].output, hash_hex);
+  }
+}
+
+}  // namespace metrics
diff --git a/metricsd/uploader/metrics_log.cc b/metricsd/uploader/metrics_log.cc
new file mode 100644
index 0000000..1f16ca1
--- /dev/null
+++ b/metricsd/uploader/metrics_log.cc
@@ -0,0 +1,53 @@
+/*
+ * 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 "uploader/metrics_log.h"
+
+#include <string>
+
+#include "uploader/proto/system_profile.pb.h"
+#include "uploader/system_profile_setter.h"
+
+// We use default values for the MetricsLogBase constructor as the setter will
+// override them.
+MetricsLog::MetricsLog()
+    : MetricsLogBase("", 0, metrics::MetricsLogBase::ONGOING_LOG, "") {
+}
+
+void MetricsLog::IncrementUserCrashCount() {
+  metrics::SystemProfileProto::Stability* stability(
+      uma_proto()->mutable_system_profile()->mutable_stability());
+  int current = stability->other_user_crash_count();
+  stability->set_other_user_crash_count(current + 1);
+}
+
+void MetricsLog::IncrementKernelCrashCount() {
+  metrics::SystemProfileProto::Stability* stability(
+      uma_proto()->mutable_system_profile()->mutable_stability());
+  int current = stability->kernel_crash_count();
+  stability->set_kernel_crash_count(current + 1);
+}
+
+void MetricsLog::IncrementUncleanShutdownCount() {
+  metrics::SystemProfileProto::Stability* stability(
+      uma_proto()->mutable_system_profile()->mutable_stability());
+  int current = stability->unclean_system_shutdown_count();
+  stability->set_unclean_system_shutdown_count(current + 1);
+}
+
+bool MetricsLog::PopulateSystemProfile(SystemProfileSetter* profile_setter) {
+  return profile_setter->Populate(uma_proto());
+}
diff --git a/metrics/uploader/metrics_log.h b/metricsd/uploader/metrics_log.h
similarity index 60%
rename from metrics/uploader/metrics_log.h
rename to metricsd/uploader/metrics_log.h
index 5796325..5e09070 100644
--- a/metrics/uploader/metrics_log.h
+++ b/metricsd/uploader/metrics_log.h
@@ -1,6 +1,18 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 METRICS_UPLOADER_METRICS_LOG_H_
 #define METRICS_UPLOADER_METRICS_LOG_H_
@@ -9,7 +21,7 @@
 
 #include <base/macros.h>
 
-#include "metrics/uploader/metrics_log_base.h"
+#include "uploader/metrics_log_base.h"
 
 // This file defines a set of user experience metrics data recorded by
 // the MetricsService. This is the unit of data that is sent to the server.
@@ -27,7 +39,7 @@
   void IncrementUncleanShutdownCount();
 
   // Populate the system profile with system information using setter.
-  void PopulateSystemProfile(SystemProfileSetter* setter);
+  bool PopulateSystemProfile(SystemProfileSetter* setter);
 
  private:
   FRIEND_TEST(UploadServiceTest, LogContainsAggregatedValues);
diff --git a/metrics/uploader/metrics_log_base.cc b/metricsd/uploader/metrics_log_base.cc
similarity index 83%
rename from metrics/uploader/metrics_log_base.cc
rename to metricsd/uploader/metrics_log_base.cc
index 7fe1ae1..ee325ae 100644
--- a/metrics/uploader/metrics_log_base.cc
+++ b/metricsd/uploader/metrics_log_base.cc
@@ -1,15 +1,27 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 "metrics/uploader/metrics_log_base.h"
+#include "uploader/metrics_log_base.h"
 
 #include "base/metrics/histogram_base.h"
 #include "base/metrics/histogram_samples.h"
-#include "metrics/uploader/metrics_hashes.h"
-#include "metrics/uploader/proto/histogram_event.pb.h"
-#include "metrics/uploader/proto/system_profile.pb.h"
-#include "metrics/uploader/proto/user_action_event.pb.h"
+#include "uploader/metrics_hashes.h"
+#include "uploader/proto/histogram_event.pb.h"
+#include "uploader/proto/system_profile.pb.h"
+#include "uploader/proto/user_action_event.pb.h"
 
 using base::Histogram;
 using base::HistogramBase;
diff --git a/metrics/uploader/metrics_log_base.h b/metricsd/uploader/metrics_log_base.h
similarity index 84%
rename from metrics/uploader/metrics_log_base.h
rename to metricsd/uploader/metrics_log_base.h
index e871c0f..f4e1995 100644
--- a/metrics/uploader/metrics_log_base.h
+++ b/metricsd/uploader/metrics_log_base.h
@@ -1,6 +1,18 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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.
+ */
 
 // This file defines a set of user experience metrics data recorded by
 // the MetricsService.  This is the unit of data that is sent to the server.
@@ -13,7 +25,7 @@
 #include "base/macros.h"
 #include "base/metrics/histogram.h"
 #include "base/time/time.h"
-#include "metrics/uploader/proto/chrome_user_metrics_extension.pb.h"
+#include "uploader/proto/chrome_user_metrics_extension.pb.h"
 
 namespace base {
 class HistogramSamples;
diff --git a/metrics/uploader/metrics_log_base_unittest.cc b/metricsd/uploader/metrics_log_base_unittest.cc
similarity index 84%
rename from metrics/uploader/metrics_log_base_unittest.cc
rename to metricsd/uploader/metrics_log_base_unittest.cc
index 5da428a..980afd5 100644
--- a/metrics/uploader/metrics_log_base_unittest.cc
+++ b/metricsd/uploader/metrics_log_base_unittest.cc
@@ -1,8 +1,20 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 "metrics/uploader/metrics_log_base.h"
+#include "uploader/metrics_log_base.h"
 
 #include <string>
 
@@ -10,7 +22,7 @@
 #include <base/metrics/sample_vector.h>
 #include <gtest/gtest.h>
 
-#include "metrics/uploader/proto/chrome_user_metrics_extension.pb.h"
+#include "uploader/proto/chrome_user_metrics_extension.pb.h"
 
 namespace metrics {
 
diff --git a/metricsd/uploader/mock/mock_system_profile_setter.h b/metricsd/uploader/mock/mock_system_profile_setter.h
new file mode 100644
index 0000000..c714e9c
--- /dev/null
+++ b/metricsd/uploader/mock/mock_system_profile_setter.h
@@ -0,0 +1,32 @@
+/*
+ * 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 METRICS_UPLOADER_MOCK_MOCK_SYSTEM_PROFILE_SETTER_H_
+#define METRICS_UPLOADER_MOCK_MOCK_SYSTEM_PROFILE_SETTER_H_
+
+#include "uploader/system_profile_setter.h"
+
+namespace metrics {
+class ChromeUserMetricsExtension;
+}
+
+// Mock profile setter used for testing.
+class MockSystemProfileSetter : public SystemProfileSetter {
+ public:
+  void Populate(metrics::ChromeUserMetricsExtension* profile_proto) override {}
+};
+
+#endif  // METRICS_UPLOADER_MOCK_MOCK_SYSTEM_PROFILE_SETTER_H_
diff --git a/metricsd/uploader/mock/sender_mock.cc b/metricsd/uploader/mock/sender_mock.cc
new file mode 100644
index 0000000..bb4dc7d
--- /dev/null
+++ b/metricsd/uploader/mock/sender_mock.cc
@@ -0,0 +1,36 @@
+/*
+ * 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 "uploader/mock/sender_mock.h"
+
+SenderMock::SenderMock() {
+  Reset();
+}
+
+bool SenderMock::Send(const std::string& content, const std::string& hash) {
+  send_call_count_ += 1;
+  last_message_ = content;
+  is_good_proto_ = last_message_proto_.ParseFromString(content);
+  return should_succeed_;
+}
+
+void SenderMock::Reset() {
+  send_call_count_ = 0;
+  last_message_ = "";
+  should_succeed_ = true;
+  last_message_proto_.Clear();
+  is_good_proto_ = false;
+}
diff --git a/metrics/uploader/mock/sender_mock.h b/metricsd/uploader/mock/sender_mock.h
similarity index 64%
rename from metrics/uploader/mock/sender_mock.h
rename to metricsd/uploader/mock/sender_mock.h
index 159b645..e79233f 100644
--- a/metrics/uploader/mock/sender_mock.h
+++ b/metricsd/uploader/mock/sender_mock.h
@@ -1,6 +1,18 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 METRICS_UPLOADER_MOCK_SENDER_MOCK_H_
 #define METRICS_UPLOADER_MOCK_SENDER_MOCK_H_
@@ -8,7 +20,7 @@
 #include <string>
 
 #include "base/compiler_specific.h"
-#include "metrics/uploader/proto/chrome_user_metrics_extension.pb.h"
+#include "uploader/proto/chrome_user_metrics_extension.pb.h"
 #include "uploader/sender.h"
 
 class SenderMock : public Sender {
diff --git a/metrics/uploader/proto/README b/metricsd/uploader/proto/README
similarity index 62%
rename from metrics/uploader/proto/README
rename to metricsd/uploader/proto/README
index 9bd3249..4292a40 100644
--- a/metrics/uploader/proto/README
+++ b/metricsd/uploader/proto/README
@@ -1,6 +1,18 @@
-Copyright 2015 The Chromium OS Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
+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.
+
+
 
 
 This directory contains the protocol buffers used by the standalone metrics
diff --git a/metrics/uploader/proto/chrome_user_metrics_extension.proto b/metricsd/uploader/proto/chrome_user_metrics_extension.proto
similarity index 72%
rename from metrics/uploader/proto/chrome_user_metrics_extension.proto
rename to metricsd/uploader/proto/chrome_user_metrics_extension.proto
index f712fc9..a07830f 100644
--- a/metrics/uploader/proto/chrome_user_metrics_extension.proto
+++ b/metricsd/uploader/proto/chrome_user_metrics_extension.proto
@@ -1,6 +1,18 @@
-// Copyright 2014 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.
+/*
+ * 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.
+ */
 //
 // Protocol buffer for Chrome UMA (User Metrics Analysis).
 //
@@ -14,9 +26,9 @@
 
 package metrics;
 
-import "histogram_event.proto";
-import "system_profile.proto";
-import "user_action_event.proto";
+import "system/core/metricsd/uploader/proto/histogram_event.proto";
+import "system/core/metricsd/uploader/proto/system_profile.proto";
+import "system/core/metricsd/uploader/proto/user_action_event.proto";
 
 // Next tag: 13
 message ChromeUserMetricsExtension {
diff --git a/metrics/uploader/proto/histogram_event.proto b/metricsd/uploader/proto/histogram_event.proto
similarity index 71%
rename from metrics/uploader/proto/histogram_event.proto
rename to metricsd/uploader/proto/histogram_event.proto
index 4b68094..3825063 100644
--- a/metrics/uploader/proto/histogram_event.proto
+++ b/metricsd/uploader/proto/histogram_event.proto
@@ -1,6 +1,18 @@
-// Copyright 2014 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.
+/*
+ * 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.
+ */
 //
 // Histogram-collected metrics.
 
diff --git a/metrics/uploader/proto/system_profile.proto b/metricsd/uploader/proto/system_profile.proto
similarity index 97%
rename from metrics/uploader/proto/system_profile.proto
rename to metricsd/uploader/proto/system_profile.proto
index d33ff60..4cab0d9 100644
--- a/metrics/uploader/proto/system_profile.proto
+++ b/metricsd/uploader/proto/system_profile.proto
@@ -1,6 +1,18 @@
-// Copyright 2014 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.
+/*
+ * 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.
+ */
 //
 // Stores information about the user's brower and system configuration.
 // The system configuration fields are recorded once per client session.
diff --git a/metricsd/uploader/proto/user_action_event.proto b/metricsd/uploader/proto/user_action_event.proto
new file mode 100644
index 0000000..464f3c8
--- /dev/null
+++ b/metricsd/uploader/proto/user_action_event.proto
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+//
+// Stores information about an event that occurs in response to a user action,
+// e.g. an interaction with a browser UI element.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+option java_outer_classname = "UserActionEventProtos";
+option java_package = "org.chromium.components.metrics";
+
+package metrics;
+
+// Next tag: 3
+message UserActionEventProto {
+  // The name of the action, hashed.
+  optional fixed64 name_hash = 1;
+
+  // The timestamp for the event, in seconds since the epoch.
+  optional int64 time = 2;
+}
diff --git a/base/test_utils.h b/metricsd/uploader/sender.h
similarity index 63%
copy from base/test_utils.h
copy to metricsd/uploader/sender.h
index 132d3a7..369c9c2 100644
--- a/base/test_utils.h
+++ b/metricsd/uploader/sender.h
@@ -14,19 +14,17 @@
  * limitations under the License.
  */
 
-#ifndef TEST_UTILS_H
-#define TEST_UTILS_H
+#ifndef METRICS_UPLOADER_SENDER_H_
+#define METRICS_UPLOADER_SENDER_H_
 
-class TemporaryFile {
+#include <string>
+
+// Abstract class for a Sender that uploads a metrics message.
+class Sender {
  public:
-  TemporaryFile();
-  ~TemporaryFile();
-
-  int fd;
-  char filename[1024];
-
- private:
-  void init(const char* tmp_dir);
+  virtual ~Sender() {}
+  // Sends a message |content| with its sha1 hash |hash|
+  virtual bool Send(const std::string& content, const std::string& hash) = 0;
 };
 
-#endif // TEST_UTILS_H
+#endif  // METRICS_UPLOADER_SENDER_H_
diff --git a/metricsd/uploader/sender_http.cc b/metricsd/uploader/sender_http.cc
new file mode 100644
index 0000000..953afc1
--- /dev/null
+++ b/metricsd/uploader/sender_http.cc
@@ -0,0 +1,50 @@
+/*
+ * 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 "uploader/sender_http.h"
+
+#include <string>
+
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <chromeos/http/http_utils.h>
+#include <chromeos/mime_utils.h>
+
+HttpSender::HttpSender(const std::string server_url)
+    : server_url_(server_url) {}
+
+bool HttpSender::Send(const std::string& content,
+                      const std::string& content_hash) {
+  const std::string hash =
+      base::HexEncode(content_hash.data(), content_hash.size());
+
+  chromeos::http::HeaderList headers = {{"X-Chrome-UMA-Log-SHA1", hash}};
+  chromeos::ErrorPtr error;
+  auto response = chromeos::http::PostTextAndBlock(
+      server_url_,
+      content,
+      chromeos::mime::application::kWwwFormUrlEncoded,
+      headers,
+      chromeos::http::Transport::CreateDefault(),
+      &error);
+  if (!response || response->ExtractDataAsString() != "OK") {
+    if (error) {
+      DLOG(ERROR) << "Failed to send data: " << error->GetMessage();
+    }
+    return false;
+  }
+  return true;
+}
diff --git a/metricsd/uploader/sender_http.h b/metricsd/uploader/sender_http.h
new file mode 100644
index 0000000..6249d90
--- /dev/null
+++ b/metricsd/uploader/sender_http.h
@@ -0,0 +1,41 @@
+/*
+ * 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 METRICS_UPLOADER_SENDER_HTTP_H_
+#define METRICS_UPLOADER_SENDER_HTTP_H_
+
+#include <string>
+
+#include <base/macros.h>
+
+#include "uploader/sender.h"
+
+// Sender implemented using http_utils from libchromeos
+class HttpSender : public Sender {
+ public:
+  explicit HttpSender(std::string server_url);
+  ~HttpSender() override = default;
+  // Sends |content| whose SHA1 hash is |hash| to server_url with a synchronous
+  // POST request to server_url.
+  bool Send(const std::string& content, const std::string& hash) override;
+
+ private:
+  const std::string server_url_;
+
+  DISALLOW_COPY_AND_ASSIGN(HttpSender);
+};
+
+#endif  // METRICS_UPLOADER_SENDER_HTTP_H_
diff --git a/metricsd/uploader/system_profile_cache.cc b/metricsd/uploader/system_profile_cache.cc
new file mode 100644
index 0000000..7dd0323
--- /dev/null
+++ b/metricsd/uploader/system_profile_cache.cc
@@ -0,0 +1,167 @@
+/*
+ * 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 "uploader/system_profile_cache.h"
+
+#include <base/files/file_util.h>
+#include <base/guid.h>
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_util.h>
+#include <base/sys_info.h>
+#include <string>
+#include <vector>
+
+#include "constants.h"
+#include "persistent_integer.h"
+#include "uploader/metrics_log_base.h"
+#include "uploader/proto/chrome_user_metrics_extension.pb.h"
+
+namespace {
+
+const char kPersistentSessionIdFilename[] = "Sysinfo.SessionId";
+
+}  // namespace
+
+std::string ChannelToString(
+    const metrics::SystemProfileProto_Channel& channel) {
+  switch (channel) {
+    case metrics::SystemProfileProto::CHANNEL_STABLE:
+    return "STABLE";
+  case metrics::SystemProfileProto::CHANNEL_DEV:
+    return "DEV";
+  case metrics::SystemProfileProto::CHANNEL_BETA:
+    return "BETA";
+  case metrics::SystemProfileProto::CHANNEL_CANARY:
+    return "CANARY";
+  default:
+    return "UNKNOWN";
+  }
+}
+
+SystemProfileCache::SystemProfileCache()
+    : initialized_(false),
+    testing_(false),
+    config_root_("/"),
+    session_id_(new chromeos_metrics::PersistentInteger(
+        kPersistentSessionIdFilename)) {
+}
+
+SystemProfileCache::SystemProfileCache(bool testing,
+                                       const std::string& config_root)
+    : initialized_(false),
+      testing_(testing),
+      config_root_(config_root),
+      session_id_(new chromeos_metrics::PersistentInteger(
+          kPersistentSessionIdFilename)) {
+}
+
+bool SystemProfileCache::Initialize() {
+  CHECK(!initialized_)
+      << "this should be called only once in the metrics_daemon lifetime.";
+
+  if (!base::SysInfo::GetLsbReleaseValue("BRILLO_BUILD_TARGET_ID",
+                                         &profile_.build_target_id)) {
+    LOG(ERROR) << "BRILLO_BUILD_TARGET_ID is not set in /etc/lsb-release.";
+    return false;
+  }
+
+  std::string channel;
+  if (!base::SysInfo::GetLsbReleaseValue("BRILLO_CHANNEL", &channel) ||
+      !base::SysInfo::GetLsbReleaseValue("BRILLO_VERSION", &profile_.version)) {
+    // If the channel or version is missing, the image is not official.
+    // In this case, set the channel to unknown and the version to 0.0.0.0 to
+    // avoid polluting the production data.
+    channel = "";
+    profile_.version = metrics::kDefaultVersion;
+
+  }
+  profile_.client_id =
+      testing_ ? "client_id_test" :
+      GetPersistentGUID(metrics::kMetricsGUIDFilePath);
+  profile_.hardware_class = "unknown";
+  profile_.channel = ProtoChannelFromString(channel);
+
+  // Increment the session_id everytime we initialize this. If metrics_daemon
+  // does not crash, this should correspond to the number of reboots of the
+  // system.
+  session_id_->Add(1);
+  profile_.session_id = static_cast<int32_t>(session_id_->Get());
+
+  initialized_ = true;
+  return initialized_;
+}
+
+bool SystemProfileCache::InitializeOrCheck() {
+  return initialized_ || Initialize();
+}
+
+bool SystemProfileCache::Populate(
+    metrics::ChromeUserMetricsExtension* metrics_proto) {
+  CHECK(metrics_proto);
+  if (not InitializeOrCheck()) {
+    return false;
+  }
+
+  // The client id is hashed before being sent.
+  metrics_proto->set_client_id(
+      metrics::MetricsLogBase::Hash(profile_.client_id));
+  metrics_proto->set_session_id(profile_.session_id);
+
+  // Sets the product id.
+  metrics_proto->set_product(9);
+
+  metrics::SystemProfileProto* profile_proto =
+      metrics_proto->mutable_system_profile();
+  profile_proto->mutable_hardware()->set_hardware_class(
+      profile_.hardware_class);
+  profile_proto->set_app_version(profile_.version);
+  profile_proto->set_channel(profile_.channel);
+  metrics::SystemProfileProto_BrilloDeviceData* device_data =
+      profile_proto->mutable_brillo();
+  device_data->set_build_target_id(profile_.build_target_id);
+
+  return true;
+}
+
+std::string SystemProfileCache::GetPersistentGUID(
+    const std::string& filename) {
+  std::string guid;
+  base::FilePath filepath(filename);
+  if (!base::ReadFileToString(filepath, &guid)) {
+    guid = base::GenerateGUID();
+    // If we can't read or write the file, the guid will not be preserved during
+    // the next reboot. Crash.
+    CHECK(base::WriteFile(filepath, guid.c_str(), guid.size()));
+  }
+  return guid;
+}
+
+metrics::SystemProfileProto_Channel SystemProfileCache::ProtoChannelFromString(
+    const std::string& channel) {
+  if (channel == "stable") {
+    return metrics::SystemProfileProto::CHANNEL_STABLE;
+  } else if (channel == "dev") {
+    return metrics::SystemProfileProto::CHANNEL_DEV;
+  } else if (channel == "beta") {
+    return metrics::SystemProfileProto::CHANNEL_BETA;
+  } else if (channel == "canary") {
+    return metrics::SystemProfileProto::CHANNEL_CANARY;
+  }
+
+  DLOG(INFO) << "unknown channel: " << channel;
+  return metrics::SystemProfileProto::CHANNEL_UNKNOWN;
+}
diff --git a/metrics/uploader/system_profile_cache.h b/metricsd/uploader/system_profile_cache.h
similarity index 62%
rename from metrics/uploader/system_profile_cache.h
rename to metricsd/uploader/system_profile_cache.h
index e7a7337..ac80b47 100644
--- a/metrics/uploader/system_profile_cache.h
+++ b/metricsd/uploader/system_profile_cache.h
@@ -1,6 +1,18 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 METRICS_UPLOADER_SYSTEM_PROFILE_CACHE_H_
 #define METRICS_UPLOADER_SYSTEM_PROFILE_CACHE_H_
@@ -12,24 +24,21 @@
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
-#include "chromeos/osrelease_reader.h"
-#include "metrics/persistent_integer.h"
-#include "metrics/uploader/proto/system_profile.pb.h"
-#include "metrics/uploader/system_profile_setter.h"
+#include "persistent_integer.h"
+#include "uploader/proto/system_profile.pb.h"
+#include "uploader/system_profile_setter.h"
 
 namespace metrics {
 class ChromeUserMetricsExtension;
 }
 
 struct SystemProfile {
-  std::string os_name;
-  std::string os_version;
-  metrics::SystemProfileProto::Channel channel;
-  std::string app_version;
+  std::string version;
   std::string hardware_class;
   std::string client_id;
-  int32_t session_id;
-  int32_t product_id;
+  int session_id;
+  metrics::SystemProfileProto::Channel channel;
+  std::string build_target_id;
 };
 
 // Retrieves general system informations needed by the protobuf for context and
@@ -43,9 +52,9 @@
   SystemProfileCache(bool testing, const std::string& config_root);
 
   // Populates the ProfileSystem protobuf with system information.
-  void Populate(metrics::ChromeUserMetricsExtension* profile_proto) override;
+  bool Populate(metrics::ChromeUserMetricsExtension* metrics_proto) override;
 
-  // Converts a string representation of the channel (|channel|-channel) to a
+  // Converts a string representation of the channel to a
   // SystemProfileProto_Channel
   static metrics::SystemProfileProto_Channel ProtoChannelFromString(
       const std::string& channel);
@@ -66,21 +75,6 @@
   // Initializes |profile_| only if it has not been yet initialized.
   bool InitializeOrCheck();
 
-  // Gets the hardware ID using crossystem
-  bool GetHardwareId(std::string* hwid);
-
-  // Gets the product ID from the GOOGLE_METRICS_PRODUCT_ID field.
-  bool GetProductId(int* product_id) const;
-
-  // Generate the formatted chromeos version from the fields in
-  // /etc/lsb-release. The format is A.B.C.D where A, B, C and D are positive
-  // integer representing:
-  // * the chrome milestone
-  // * the build number
-  // * the branch number
-  // * the patch number
-  bool GetChromeOSVersion(std::string* version);
-
   bool initialized_;
   bool testing_;
   std::string config_root_;
diff --git a/metricsd/uploader/system_profile_setter.h b/metricsd/uploader/system_profile_setter.h
new file mode 100644
index 0000000..bd3ff42
--- /dev/null
+++ b/metricsd/uploader/system_profile_setter.h
@@ -0,0 +1,33 @@
+/*
+ * 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 METRICS_UPLOADER_SYSTEM_PROFILE_SETTER_H_
+#define METRICS_UPLOADER_SYSTEM_PROFILE_SETTER_H_
+
+namespace metrics {
+class ChromeUserMetricsExtension;
+}
+
+// Abstract class used to delegate populating SystemProfileProto with system
+// information to simplify testing.
+class SystemProfileSetter {
+ public:
+  virtual ~SystemProfileSetter() {}
+  // Populates the protobuf with system informations.
+  virtual bool Populate(metrics::ChromeUserMetricsExtension* profile_proto) = 0;
+};
+
+#endif  // METRICS_UPLOADER_SYSTEM_PROFILE_SETTER_H_
diff --git a/metrics/uploader/upload_service.cc b/metricsd/uploader/upload_service.cc
similarity index 84%
rename from metrics/uploader/upload_service.cc
rename to metricsd/uploader/upload_service.cc
index 92c9e10..2335630 100644
--- a/metrics/uploader/upload_service.cc
+++ b/metricsd/uploader/upload_service.cc
@@ -1,8 +1,20 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 "metrics/uploader/upload_service.h"
+#include "uploader/upload_service.h"
 
 #include <string>
 
@@ -17,11 +29,11 @@
 #include <base/metrics/statistics_recorder.h>
 #include <base/sha1.h>
 
-#include "metrics/serialization/metric_sample.h"
-#include "metrics/serialization/serialization_utils.h"
-#include "metrics/uploader/metrics_log.h"
-#include "metrics/uploader/sender_http.h"
-#include "metrics/uploader/system_profile_cache.h"
+#include "serialization/metric_sample.h"
+#include "serialization/serialization_utils.h"
+#include "uploader/metrics_log.h"
+#include "uploader/sender_http.h"
+#include "uploader/system_profile_setter.h"
 
 const int UploadService::kMaxFailedUpload = 10;
 
@@ -61,7 +73,6 @@
   CHECK(!staged_log_) << "the staged log should be discarded before starting "
                          "a new metrics log";
   MetricsLog* log = new MetricsLog();
-  log->PopulateSystemProfile(system_profile_setter_.get());
   current_log_.reset(log);
 }
 
@@ -85,13 +96,12 @@
   // Previous upload successful, reading metrics sample from the file.
   ReadMetrics();
   GatherHistograms();
-
-  // No samples found. Exit to avoid sending an empty log.
-  if (!current_log_)
-    return;
-
   StageCurrentLog();
-  SendStagedLog();
+
+  // If a log is available for upload, upload it.
+  if (staged_log_) {
+    SendStagedLog();
+  }
 }
 
 void UploadService::SendStagedLog() {
@@ -213,6 +223,11 @@
 
   staged_log_.swap(current_log_);
   staged_log_->CloseLog();
+  if (!staged_log_->PopulateSystemProfile(system_profile_setter_.get())) {
+    LOG(WARNING) << "Error while adding metadata to the log. Discarding the "
+                 << "log.";
+    staged_log_.reset();
+  }
   failed_upload_count_ = 0;
 }
 
diff --git a/metrics/uploader/upload_service.h b/metricsd/uploader/upload_service.h
similarity index 87%
rename from metrics/uploader/upload_service.h
rename to metricsd/uploader/upload_service.h
index ebbb54f..7f2f413 100644
--- a/metrics/uploader/upload_service.h
+++ b/metricsd/uploader/upload_service.h
@@ -1,6 +1,18 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 METRICS_UPLOADER_UPLOAD_SERVICE_H_
 #define METRICS_UPLOADER_UPLOAD_SERVICE_H_
@@ -12,9 +24,9 @@
 #include "base/metrics/histogram_snapshot_manager.h"
 
 #include "metrics/metrics_library.h"
-#include "metrics/uploader/metrics_log.h"
-#include "metrics/uploader/sender.h"
-#include "metrics/uploader/system_profile_cache.h"
+#include "uploader/metrics_log.h"
+#include "uploader/sender.h"
+#include "uploader/system_profile_cache.h"
 
 namespace metrics {
 class ChromeUserMetricsExtension;
diff --git a/metrics/uploader/upload_service_test.cc b/metricsd/uploader/upload_service_test.cc
similarity index 88%
rename from metrics/uploader/upload_service_test.cc
rename to metricsd/uploader/upload_service_test.cc
index ee17e15..cbb5277 100644
--- a/metrics/uploader/upload_service_test.cc
+++ b/metricsd/uploader/upload_service_test.cc
@@ -1,6 +1,18 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 <gtest/gtest.h>
 
@@ -9,19 +21,16 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
 #include "base/sys_info.h"
-#include "metrics/metrics_library_mock.h"
-#include "metrics/serialization/metric_sample.h"
-#include "metrics/uploader/metrics_log.h"
-#include "metrics/uploader/mock/mock_system_profile_setter.h"
-#include "metrics/uploader/mock/sender_mock.h"
-#include "metrics/uploader/proto/chrome_user_metrics_extension.pb.h"
-#include "metrics/uploader/proto/histogram_event.pb.h"
-#include "metrics/uploader/proto/system_profile.pb.h"
-#include "metrics/uploader/system_profile_cache.h"
-#include "metrics/uploader/upload_service.h"
-
-static const char kMetricsServer[] = "https://clients4.google.com/uma/v2";
-static const char kMetricsFilePath[] = "/var/run/metrics/uma-events";
+#include "metrics_library_mock.h"
+#include "serialization/metric_sample.h"
+#include "uploader/metrics_log.h"
+#include "uploader/mock/mock_system_profile_setter.h"
+#include "uploader/mock/sender_mock.h"
+#include "uploader/proto/chrome_user_metrics_extension.pb.h"
+#include "uploader/proto/histogram_event.pb.h"
+#include "uploader/proto/system_profile.pb.h"
+#include "uploader/system_profile_cache.h"
+#include "uploader/upload_service.h"
 
 class UploadServiceTest : public testing::Test {
  protected:
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index d6dad2d..e1ba2e9 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -13,6 +13,20 @@
 
 include $(BUILD_PREBUILT)
 endif
+
+#######################################
+# asan.options
+ifeq (address,$(strip $(SANITIZE_TARGET)))
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := asan.options
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_PATH := $(TARGET_OUT)
+
+include $(BUILD_PREBUILT)
+endif
+
 #######################################
 # init.environ.rc
 
@@ -21,20 +35,29 @@
 LOCAL_MODULE := init.environ.rc
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
 
+EXPORT_GLOBAL_ASAN_OPTIONS :=
+ifeq (address,$(strip $(SANITIZE_TARGET)))
+  EXPORT_GLOBAL_ASAN_OPTIONS := export ASAN_OPTIONS include=/system/asan.options
+  LOCAL_REQUIRED_MODULES := asan.options
+endif
 # Put it here instead of in init.rc module definition,
 # because init.rc is conditionally included.
 #
-# create some directories (some are mount points)
-LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
-    sbin dev proc sys system data oem acct cache config storage mnt root)
+# create some directories (some are mount points) and symlinks
+local_post_install_cmd_base := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
+    sbin dev proc sys system data oem acct cache config storage mnt root); \
+    ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
+    ln -sf /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \
+    ln -sf /storage/self/primary $(TARGET_ROOT_OUT)/sdcard
+ifdef BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE
+  LOCAL_POST_INSTALL_CMD := $(local_post_install_cmd_base); mkdir -p $(TARGET_ROOT_OUT)/vendor
+else
+  LOCAL_POST_INSTALL_CMD := $(local_post_install_cmd_base)
+endif
+local_post_install_cmd_base :=
 
 include $(BUILD_SYSTEM)/base_rules.mk
 
-EXPORT_GLOBAL_ASAN_OPTIONS :=
-ifeq (address,$(strip $(SANITIZE_TARGET)))
-  EXPORT_GLOBAL_ASAN_OPTIONS := export ASAN_OPTIONS allow_user_segv_handler=1:detect_odr_violation=0:alloc_dealloc_mismatch=0
-endif
-
 # Regenerate init.environ.rc if PRODUCT_BOOTCLASSPATH has changed.
 bcp_md5 := $(word 1, $(shell echo $(PRODUCT_BOOTCLASSPATH) $(PRODUCT_SYSTEM_SERVER_CLASSPATH) | $(MD5SUM)))
 bcp_dep := $(intermediates)/$(bcp_md5).bcp.dep
diff --git a/rootdir/asan.options b/rootdir/asan.options
new file mode 100644
index 0000000..2f12341
--- /dev/null
+++ b/rootdir/asan.options
@@ -0,0 +1 @@
+allow_user_segv_handler=1:detect_odr_violation=0:alloc_dealloc_mismatch=0:allocator_may_return_null=1
diff --git a/rootdir/init.rc b/rootdir/init.rc
index f5febde..12999bd 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -259,6 +259,7 @@
     chmod 0660 /data/misc/wifi/wpa_supplicant.conf
     mkdir /data/local 0751 root root
     mkdir /data/misc/media 0700 media media
+    mkdir /data/misc/boottrace 0771 system shell
 
     # For security reasons, /data/local/tmp should always be empty.
     # Do not place files or directories in /data/local/tmp
diff --git a/rootdir/init.trace.rc b/rootdir/init.trace.rc
index 50944e6..cde9c37 100644
--- a/rootdir/init.trace.rc
+++ b/rootdir/init.trace.rc
@@ -16,6 +16,16 @@
     chown root shell /sys/kernel/debug/tracing/events/power/cpu_idle/enable
     chown root shell /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
     chown root shell /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
+    chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
+    chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
+    chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
+    chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
+    chown root shell /sys/kernel/debug/tracing/events/binder/binder_transaction/enable
+    chown root shell /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable
+    chown root shell /sys/kernel/debug/tracing/events/binder/binder_lock/enable
+    chown root shell /sys/kernel/debug/tracing/events/binder/binder_locked/enable
+    chown root shell /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
+
     chown root shell /sys/kernel/debug/tracing/tracing_on
 
     chmod 0664 /sys/kernel/debug/tracing/trace_clock
@@ -28,8 +38,25 @@
     chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_idle/enable
     chmod 0664 /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
     chmod 0664 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
     chmod 0664 /sys/kernel/debug/tracing/tracing_on
+    chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_transaction/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_lock/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_locked/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
 
 # Allow only the shell group to read and truncate the kernel trace.
     chown root shell /sys/kernel/debug/tracing/trace
     chmod 0660 /sys/kernel/debug/tracing/trace
+
+on property:persist.debug.atrace.boottrace=1
+    start boottrace
+
+# Run atrace with the categories written in a file
+service boottrace /system/bin/atrace --async_start -f /data/misc/boottrace/categories
+    disabled
+    oneshot
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 273b263..2ae7ed2 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -2,7 +2,7 @@
 
 
 common_cflags := \
-    -Werror -Wno-unused-parameter \
+    -Werror -Wno-unused-parameter -Wno-unused-const-variable \
     -I$(LOCAL_PATH)/upstream-netbsd/include/ \
     -include bsd-compatibility.h \
 
@@ -42,7 +42,6 @@
     getevent \
     iftop \
     ioctl \
-    ionice \
     log \
     ls \
     lsof \
@@ -50,13 +49,11 @@
     newfs_msdos \
     ps \
     prlimit \
-    renice \
     sendevent \
     start \
     stop \
     top \
     uptime \
-    watchprops \
 
 ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS)
 
diff --git a/toolbox/ionice.c b/toolbox/ionice.c
deleted file mode 100644
index 7abc261..0000000
--- a/toolbox/ionice.c
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <cutils/iosched_policy.h>
-
-static char *classes[] = {"none", "rt", "be", "idle", NULL};
-
-int ionice_main(int argc, char *argv[])
-{
-    IoSchedClass clazz = IoSchedClass_NONE;
-    int ioprio = 0;
-    int pid;
-
-    if(argc != 2 && argc != 4) {
-        fprintf(stderr, "usage: ionice <pid> [none|rt|be|idle] [prio]\n");
-        return 1;
-    }
-
-    if (!(pid = atoi(argv[1]))) {
-        fprintf(stderr, "Invalid pid specified\n");
-        return 1;
-    }
-
-    if (argc == 2) {
-        if (android_get_ioprio(pid, &clazz, &ioprio)) {
-            fprintf(stderr, "Failed to read priority (%s)\n", strerror(errno));
-            return 1;
-        }
-        fprintf(stdout, "Pid %d, class %s (%d), prio %d\n", pid, classes[clazz], clazz, ioprio);
-        return 0;
-    }
-
-    if (!strcmp(argv[2], "none")) {
-        clazz = IoSchedClass_NONE;
-    } else if (!strcmp(argv[2], "rt")) {
-        clazz = IoSchedClass_RT;
-    } else if (!strcmp(argv[2], "be")) {
-        clazz = IoSchedClass_BE;
-    } else if (!strcmp(argv[2], "idle")) {
-        clazz = IoSchedClass_IDLE;
-    } else {
-        fprintf(stderr, "Unsupported class '%s'\n", argv[2]);
-        return 1;
-    }
-
-    ioprio = atoi(argv[3]);
-
-    printf("Setting pid %d i/o class to %d, prio %d\n", pid, clazz, ioprio);
-    if (android_set_ioprio(pid, clazz, ioprio)) {
-        fprintf(stderr, "Failed to set priority (%s)\n", strerror(errno));
-        return 1;
-    }
-
-    return 0;
-}
diff --git a/toolbox/renice.c b/toolbox/renice.c
deleted file mode 100644
index 99a06f4..0000000
--- a/toolbox/renice.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (c) 2008, The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the 
- *    distribution.
- *  * Neither the name of Google, Inc. nor the names of its contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sched.h>
-#include <getopt.h>
-
-static void
-usage(const char *s)
-{
-    fprintf(stderr, "USAGE: %s [[-r] [-t TYPE] priority pids ...] [-g pid]\n", s);
-    exit(EXIT_FAILURE);
-}
-
-void print_prio(pid_t pid)
-{
-    int sched;
-    struct sched_param sp;
-
-    printf("pid %d's priority: %d\n", pid, getpriority(PRIO_PROCESS, pid));
-
-    printf("scheduling class: ");
-    sched = sched_getscheduler(pid);
-    switch (sched) {
-    case SCHED_FIFO:
-        printf("FIFO\n");
-        break;
-    case SCHED_RR:
-        printf("RR\n");
-        break;
-    case SCHED_OTHER:
-        printf("Normal\n");
-        break;
-    case -1:
-        perror("sched_getscheduler");
-        break;
-    default:
-        printf("Unknown\n");
-    }
-
-    sched_getparam(pid, &sp);
-    printf("RT prio: %d (of %d to %d)\n", sp.sched_priority,
-           sched_get_priority_min(sched), sched_get_priority_max(sched));
-}
-
-int get_sched(char *str)
-{
-    if (strcasecmp(str, "RR") == 0)
-        return SCHED_RR;
-    else if (strcasecmp(str, "FIFO") == 0)
-        return SCHED_FIFO;
-    else if (strcasecmp(str, "NORMAL") == 0)
-        return SCHED_OTHER;
-    else if (strcasecmp(str, "OTHER") == 0)
-        return SCHED_OTHER;
-    return SCHED_RR;
-}
-
-int renice_main(int argc, char *argv[])
-{
-    int prio;
-    int realtime = 0;
-    int opt;
-    int sched = SCHED_RR;
-    char *cmd = argv[0];
-
-    do {
-        opt = getopt(argc, argv, "rt:g:");
-        if (opt == -1)
-            break;
-        switch (opt) {
-        case 'r':
-            // do realtime priority adjustment
-            realtime = 1;
-            break;
-        case 't':
-            sched = get_sched(optarg);
-            break;
-        case 'g':
-            print_prio(atoi(optarg));
-            return 0;
-        default:
-            usage(cmd);
-        }
-    } while (1);
-
-    argc -= optind;
-    argv += optind;
-
-    if (argc < 1)
-        usage(cmd);
-
-    prio = atoi(argv[0]);
-    argc--;
-    argv++;
-
-    if (argc < 1)
-        usage(cmd);
-
-    while(argc) {
-        pid_t pid;
-
-        pid = atoi(argv[0]);
-        argc--;
-        argv++;
-
-        if (realtime) {
-            struct sched_param sp = { .sched_priority = prio };
-            int ret;
-
-            ret = sched_setscheduler(pid, sched, &sp);
-            if (ret) {
-                perror("sched_set_scheduler");
-                exit(EXIT_FAILURE);
-            }
-        } else {
-            int ret;
-
-            ret = setpriority(PRIO_PROCESS, pid, prio);
-            if (ret) {
-                perror("setpriority");
-                exit(EXIT_FAILURE);
-            }
-        }
-    }
-
-    return 0;
-}
diff --git a/toolbox/watchprops.c b/toolbox/watchprops.c
deleted file mode 100644
index cd62922..0000000
--- a/toolbox/watchprops.c
+++ /dev/null
@@ -1,92 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <errno.h>
-
-#include <cutils/properties.h>
-#include <cutils/hashmap.h>
-
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
-static int str_hash(void *key)
-{
-    return hashmapHash(key, strlen(key));
-}
-
-static bool str_equals(void *keyA, void *keyB)
-{
-    return strcmp(keyA, keyB) == 0;
-}
-
-static void announce(char *name, char *value)
-{
-    unsigned char *x;
-    
-    for(x = (unsigned char *)value; *x; x++) {
-        if((*x < 32) || (*x > 127)) *x = '.';
-    }
-
-    fprintf(stderr,"%10d %s = '%s'\n", (int) time(0), name, value);
-}
-
-static void add_to_watchlist(Hashmap *watchlist, const char *name,
-        const prop_info *pi)
-{
-    char *key = strdup(name);
-    unsigned *value = malloc(sizeof(unsigned));
-    if (!key || !value)
-        exit(1);
-
-    *value = __system_property_serial(pi);
-    hashmapPut(watchlist, key, value);
-}
-
-static void populate_watchlist(const prop_info *pi, void *cookie)
-{
-    Hashmap *watchlist = cookie;
-    char name[PROP_NAME_MAX];
-    char value_unused[PROP_VALUE_MAX];
-
-    __system_property_read(pi, name, value_unused);
-    add_to_watchlist(watchlist, name, pi);
-}
-
-static void update_watchlist(const prop_info *pi, void *cookie)
-{
-    Hashmap *watchlist = cookie;
-    char name[PROP_NAME_MAX];
-    char value[PROP_VALUE_MAX];
-    unsigned *serial;
-
-    __system_property_read(pi, name, value);
-    serial = hashmapGet(watchlist, name);
-    if (!serial) {
-        add_to_watchlist(watchlist, name, pi);
-        announce(name, value);
-    } else {
-        unsigned tmp = __system_property_serial(pi);
-        if (*serial != tmp) {
-            *serial = tmp;
-            announce(name, value);
-        }
-    }
-}
-
-int watchprops_main(int argc, char *argv[])
-{
-    unsigned serial;
-    
-    Hashmap *watchlist = hashmapCreate(1024, str_hash, str_equals);
-    if (!watchlist)
-        exit(1);
-
-    __system_property_foreach(populate_watchlist, watchlist);
-
-    for(serial = 0;;) {
-        serial = __system_property_wait_any(serial);
-        __system_property_foreach(update_watchlist, watchlist);
-    }
-    return 0;
-}