Merge "init: Use classes for parsing and clean up memory allocations"
diff --git a/adb/Android.mk b/adb/Android.mk
index e271a63..41016ee 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -79,6 +79,12 @@
     sysdeps_win32.cpp \
     usb_windows.cpp \
 
+LIBADB_TEST_linux_SRCS := \
+    fdevent_test.cpp \
+
+LIBADB_TEST_darwin_SRCS := \
+    fdevent_test.cpp \
+
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
 LOCAL_MODULE := libadbd
@@ -88,7 +94,6 @@
     adb_auth_client.cpp \
     fdevent.cpp \
     jdwp_service.cpp \
-    qemu_tracing.cpp \
     usb_linux_client.cpp \
 
 LOCAL_SANITIZE := $(adb_target_sanitize)
@@ -118,6 +123,8 @@
 
 ifeq ($(HOST_OS),windows)
     LOCAL_C_INCLUDES += development/host/windows/usb/api/
+else
+    LOCAL_MULTILIB := 64
 endif
 
 include $(BUILD_HOST_STATIC_LIBRARY)
@@ -126,7 +133,10 @@
 LOCAL_CLANG := true
 LOCAL_MODULE := adbd_test
 LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS)
-LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS)
+LOCAL_SRC_FILES := \
+    $(LIBADB_TEST_SRCS) \
+    $(LIBADB_TEST_linux_SRCS) \
+
 LOCAL_SANITIZE := $(adb_target_sanitize)
 LOCAL_STATIC_LIBRARIES := libadbd
 LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
@@ -139,7 +149,11 @@
 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_SRC_FILES := \
+    $(LIBADB_TEST_SRCS) \
+    $(LIBADB_TEST_$(HOST_OS)_SRCS) \
+    services.cpp \
+
 LOCAL_SANITIZE := $(adb_host_sanitize)
 LOCAL_SHARED_LIBRARIES := liblog libbase
 LOCAL_STATIC_LIBRARIES := \
@@ -184,7 +198,6 @@
 
 ifeq ($(HOST_OS),linux)
     LOCAL_LDLIBS += -lrt -ldl -lpthread
-    LOCAL_CFLAGS += -DWORKAROUND_BUG6558362
 endif
 
 ifeq ($(HOST_OS),darwin)
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 29c9481..eb01da8 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -243,7 +243,12 @@
     D("adb: offline\n");
     //Close the associated usb
     t->online = 0;
-    run_transport_disconnects(t);
+
+    // This is necessary to avoid a race condition that occurred when a transport closes
+    // while a client socket is still active.
+    close_all_sockets(t);
+
+    t->RunDisconnects();
 }
 
 #if DEBUG_PACKETS
@@ -575,6 +580,107 @@
 
 #if ADB_HOST
 
+#ifdef _WIN32
+
+static bool _make_handle_noninheritable(HANDLE h) {
+    if (h != INVALID_HANDLE_VALUE && h != NULL) {
+        if (!SetHandleInformation(h, HANDLE_FLAG_INHERIT, 0)) {
+            // Show the handle value to give us a clue in case we have problems
+            // with pseudo-handle values.
+            fprintf(stderr, "Cannot make handle 0x%p non-inheritable: %s\n",
+                    h, SystemErrorCodeToString(GetLastError()).c_str());
+            return false;
+        }
+    }
+
+    return true;
+}
+
+// Create anonymous pipe, preventing inheritance of the read pipe and setting
+// security of the write pipe to sa.
+static bool _create_anonymous_pipe(unique_handle* pipe_read_out,
+                                   unique_handle* pipe_write_out,
+                                   SECURITY_ATTRIBUTES* sa) {
+    HANDLE pipe_read_raw = NULL;
+    HANDLE pipe_write_raw = NULL;
+    if (!CreatePipe(&pipe_read_raw, &pipe_write_raw, sa, 0)) {
+        fprintf(stderr, "Cannot create pipe: %s\n",
+                SystemErrorCodeToString(GetLastError()).c_str());
+        return false;
+    }
+
+    unique_handle pipe_read(pipe_read_raw);
+    pipe_read_raw = NULL;
+    unique_handle pipe_write(pipe_write_raw);
+    pipe_write_raw = NULL;
+
+    if (!_make_handle_noninheritable(pipe_read.get())) {
+        return false;
+    }
+
+    *pipe_read_out = std::move(pipe_read);
+    *pipe_write_out = std::move(pipe_write);
+
+    return true;
+}
+
+// Read from a pipe (that we take ownership of) and write what is returned to
+// GetStdHandle(nStdHandle). Return on error or when the pipe is closed.
+static unsigned _redirect_pipe_thread(HANDLE h, DWORD nStdHandle) {
+    // Take ownership of the HANDLE and close when we're done.
+    unique_handle   read_pipe(h);
+    const HANDLE    write_handle = GetStdHandle(nStdHandle);
+    const char*     output_name = nStdHandle == STD_OUTPUT_HANDLE ?
+                                      "stdout" : "stderr";
+
+    while (true) {
+        char    buf[64 * 1024];
+        DWORD   bytes_read = 0;
+        if (!ReadFile(read_pipe.get(), buf, sizeof(buf), &bytes_read, NULL)) {
+            const DWORD err = GetLastError();
+            // ERROR_BROKEN_PIPE is expected when the subprocess closes
+            // the other end of the pipe.
+            if (err == ERROR_BROKEN_PIPE) {
+                return EXIT_SUCCESS;
+            } else {
+                fprintf(stderr, "Failed to read from %s: %s\n", output_name,
+                        SystemErrorCodeToString(err).c_str());
+                return EXIT_FAILURE;
+            }
+        }
+
+        // Don't try to write if our stdout/stderr was not setup by the
+        // parent process.
+        if (write_handle != NULL && write_handle != INVALID_HANDLE_VALUE) {
+            DWORD   bytes_written = 0;
+            if (!WriteFile(write_handle, buf, bytes_read, &bytes_written,
+                           NULL)) {
+                fprintf(stderr, "Failed to write to %s: %s\n", output_name,
+                        SystemErrorCodeToString(GetLastError()).c_str());
+                return EXIT_FAILURE;
+            }
+
+            if (bytes_written != bytes_read) {
+                fprintf(stderr, "Only wrote %lu of %lu bytes to %s\n",
+                        bytes_written, bytes_read, output_name);
+                return EXIT_FAILURE;
+            }
+        }
+    }
+}
+
+static unsigned __stdcall _redirect_stdout_thread(HANDLE h) {
+    adb_thread_setname("stdout redirect");
+    return _redirect_pipe_thread(h, STD_OUTPUT_HANDLE);
+}
+
+static unsigned __stdcall _redirect_stderr_thread(HANDLE h) {
+    adb_thread_setname("stderr redirect");
+    return _redirect_pipe_thread(h, STD_ERROR_HANDLE);
+}
+
+#endif
+
 int launch_server(int server_port)
 {
 #if defined(_WIN32)
@@ -582,58 +688,42 @@
     /* we create a PIPE that will be used to wait for the server's "OK" */
     /* message since the pipe handles must be inheritable, we use a     */
     /* security attribute                                               */
-    HANDLE                nul_read, nul_write;
-    HANDLE                pipe_read, pipe_write;
-    HANDLE                stdout_handle, stderr_handle;
     SECURITY_ATTRIBUTES   sa;
-    STARTUPINFOW          startup;
-    PROCESS_INFORMATION   pinfo;
-    WCHAR                 program_path[ MAX_PATH ];
-    int                   ret;
-
     sa.nLength = sizeof(sa);
     sa.lpSecurityDescriptor = NULL;
     sa.bInheritHandle = TRUE;
 
-    /* Redirect stdin and stderr to Windows /dev/null. If we instead pass our
-     * stdin/stderr handles and they are console handles, when the adb server
-     * starts up, the C Runtime will see console handles for a process that
-     * isn't connected to a console and it will configure stderr to be closed.
-     * At that point, freopen() could be used to reopen stderr, but it would
-     * take more massaging to fixup the file descriptor number that freopen()
-     * uses. It's simplest to avoid all of this complexity by just redirecting
-     * stdin/stderr to `nul' and then the C Runtime acts as expected.
-     */
-    nul_read = CreateFileW(L"nul", GENERIC_READ,
-                           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) failed: %s\n",
+    // Redirect stdin to Windows /dev/null. If we instead pass an original
+    // stdin/stdout/stderr handle and it is a console handle, when the adb
+    // server starts up, the C Runtime will see a console handle for a process
+    // that isn't connected to a console and it will configure
+    // stdin/stdout/stderr to be closed. At that point, freopen() could be used
+    // to reopen stderr/out, but it would take more massaging to fixup the file
+    // descriptor number that freopen() uses. It's simplest to avoid all of this
+    // complexity by just redirecting stdin to `nul' and then the C Runtime acts
+    // as expected.
+    unique_handle   nul_read(CreateFileW(L"nul", GENERIC_READ,
+            FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING,
+            FILE_ATTRIBUTE_NORMAL, NULL));
+    if (nul_read.get() == INVALID_HANDLE_VALUE) {
+        fprintf(stderr, "Cannot open 'nul': %s\n",
                 SystemErrorCodeToString(GetLastError()).c_str());
         return -1;
     }
 
-    nul_write = CreateFileW(L"nul", GENERIC_WRITE,
-                            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) failed: %s\n",
-                SystemErrorCodeToString(GetLastError()).c_str());
-        CloseHandle(nul_read);
+    // create pipes with non-inheritable read handle, inheritable write handle
+    unique_handle   ack_read, ack_write;
+    if (!_create_anonymous_pipe(&ack_read, &ack_write, &sa)) {
         return -1;
     }
-
-    /* create pipe, and ensure its read handle isn't inheritable */
-    ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
-    if (!ret) {
-        fprintf(stderr, "CreatePipe() failed: %s\n",
-                SystemErrorCodeToString(GetLastError()).c_str());
-        CloseHandle(nul_read);
-        CloseHandle(nul_write);
+    unique_handle   stdout_read, stdout_write;
+    if (!_create_anonymous_pipe(&stdout_read, &stdout_write, &sa)) {
         return -1;
     }
-
-    SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
+    unique_handle   stderr_read, stderr_write;
+    if (!_create_anonymous_pipe(&stderr_read, &stderr_write, &sa)) {
+        return -1;
+    }
 
     /* Some programs want to launch an adb command and collect its output by
      * calling CreateProcess with inheritable stdout/stderr handles, then
@@ -645,52 +735,64 @@
      * the calling process is stuck while read()-ing from the stdout/stderr
      * descriptors, because they're connected to corresponding handles in the
      * adb server process (even if the latter never uses/writes to them).
+     * Note that even if we don't pass these handles in the STARTUPINFO struct,
+     * if they're marked inheritable, they're still inherited, requiring us to
+     * deal with this.
+     *
+     * If we're still having problems with inheriting random handles in the
+     * future, consider using PROC_THREAD_ATTRIBUTE_HANDLE_LIST to explicitly
+     * specify which handles should be inherited: http://blogs.msdn.com/b/oldnewthing/archive/2011/12/16/10248328.aspx
      */
-    stdout_handle = GetStdHandle( STD_OUTPUT_HANDLE );
-    stderr_handle = GetStdHandle( STD_ERROR_HANDLE );
-    if (stdout_handle != INVALID_HANDLE_VALUE) {
-        SetHandleInformation( stdout_handle, HANDLE_FLAG_INHERIT, 0 );
+    if (!_make_handle_noninheritable(GetStdHandle(STD_INPUT_HANDLE))) {
+        return -1;
     }
-    if (stderr_handle != INVALID_HANDLE_VALUE) {
-        SetHandleInformation( stderr_handle, HANDLE_FLAG_INHERIT, 0 );
+    if (!_make_handle_noninheritable(GetStdHandle(STD_OUTPUT_HANDLE))) {
+        return -1;
+    }
+    if (!_make_handle_noninheritable(GetStdHandle(STD_ERROR_HANDLE))) {
+        return -1;
     }
 
+    STARTUPINFOW    startup;
     ZeroMemory( &startup, sizeof(startup) );
     startup.cb = sizeof(startup);
-    startup.hStdInput  = nul_read;
-    startup.hStdOutput = nul_write;
-    startup.hStdError  = nul_write;
+    startup.hStdInput  = nul_read.get();
+    startup.hStdOutput = stdout_write.get();
+    startup.hStdError  = stderr_write.get();
     startup.dwFlags    = STARTF_USESTDHANDLES;
 
-    ZeroMemory( &pinfo, sizeof(pinfo) );
+    // 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 ack_write_as_int = cast_handle_to_int(ack_write.get());
+    if (cast_int_to_handle(ack_write_as_int) != ack_write.get()) {
+        // 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, "Cannot fit pipe handle value into 32-bits: 0x%p\n",
+                ack_write.get());
+        return -1;
+    }
 
-    /* get path of current program */
-    DWORD module_result = GetModuleFileNameW(NULL, program_path,
-                                             arraysize(program_path));
-    if ((module_result == arraysize(program_path)) || (module_result == 0)) {
+    // get path of current program
+    WCHAR       program_path[MAX_PATH];
+    const 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",
+        fprintf(stderr, "Cannot get executable path: %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];
+    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(
+              ack_write_as_int);
+
+    PROCESS_INFORMATION   pinfo;
+    ZeroMemory(&pinfo, sizeof(pinfo));
+
+    if (!CreateProcessW(
             program_path,                              /* program path  */
             args,
                                     /* the fork-server argument will set the
@@ -702,38 +804,113 @@
             NULL,                     /* use parent's environment block */
             NULL,                    /* use parent's starting directory */
             &startup,                 /* startup info, i.e. std handles */
-            &pinfo );
-
-    CloseHandle( nul_read );
-    CloseHandle( nul_write );
-    CloseHandle( pipe_write );
-
-    if (!ret) {
-        fprintf(stderr, "CreateProcess failed: %s\n",
+            &pinfo )) {
+        fprintf(stderr, "Cannot create process: %s\n",
                 SystemErrorCodeToString(GetLastError()).c_str());
-        CloseHandle( pipe_read );
         return -1;
     }
 
-    CloseHandle( pinfo.hProcess );
-    CloseHandle( pinfo.hThread );
+    unique_handle   process_handle(pinfo.hProcess);
+    pinfo.hProcess = NULL;
 
-    /* wait for the "OK\n" message */
+    // Close handles that we no longer need to complete the rest.
+    CloseHandle(pinfo.hThread);
+    pinfo.hThread = NULL;
+
+    nul_read.reset();
+    ack_write.reset();
+    stdout_write.reset();
+    stderr_write.reset();
+
+    // Start threads to read from subprocess stdout/stderr and write to ours
+    // to make subprocess errors easier to diagnose.
+
+    // In the past, reading from a pipe before the child process's C Runtime
+    // started up and called GetFileType() caused a hang: http://blogs.msdn.com/b/oldnewthing/archive/2011/12/02/10243553.aspx#10244216
+    // This is reportedly fixed in Windows Vista: https://support.microsoft.com/en-us/kb/2009703
+    // I was unable to reproduce the problem on Windows XP. It sounds like a
+    // Windows Update may have fixed this: https://www.duckware.com/tech/peeknamedpipe.html
+    unique_handle   stdout_thread(reinterpret_cast<HANDLE>(
+            _beginthreadex(NULL, 0, _redirect_stdout_thread, stdout_read.get(),
+                           0, NULL)));
+    if (stdout_thread.get() == nullptr) {
+        fprintf(stderr, "Cannot create thread: %s\n", strerror(errno));
+        return -1;
+    }
+    stdout_read.release();  // Transfer ownership to new thread
+
+    unique_handle   stderr_thread(reinterpret_cast<HANDLE>(
+            _beginthreadex(NULL, 0, _redirect_stderr_thread, stderr_read.get(),
+                           0, NULL)));
+    if (stderr_thread.get() == nullptr) {
+        fprintf(stderr, "Cannot create thread: %s\n", strerror(errno));
+        return -1;
+    }
+    stderr_read.release();  // Transfer ownership to new thread
+
+    bool    got_ack = false;
+
+    // Wait for the "OK\n" message, for the pipe to be closed, or other error.
     {
-        char  temp[3];
-        DWORD  count;
+        char    temp[3];
+        DWORD   count = 0;
 
-        ret = ReadFile( pipe_read, temp, 3, &count, NULL );
-        CloseHandle( pipe_read );
-        if ( !ret ) {
-            fprintf(stderr, "could not read ok from ADB Server, error: %s\n",
-                    SystemErrorCodeToString(GetLastError()).c_str());
-            return -1;
+        if (ReadFile(ack_read.get(), temp, sizeof(temp), &count, NULL)) {
+            const CHAR  expected[] = "OK\n";
+            const DWORD expected_length = arraysize(expected) - 1;
+            if (count == expected_length &&
+                memcmp(temp, expected, expected_length) == 0) {
+                got_ack = true;
+            } else {
+                fprintf(stderr, "ADB server didn't ACK\n");
+            }
+        } else {
+            const DWORD err = GetLastError();
+            // If the ACK was not written and the process exited, GetLastError()
+            // is probably ERROR_BROKEN_PIPE, in which case that info is not
+            // useful to the user.
+            fprintf(stderr, "could not read ok from ADB Server%s\n",
+                    err == ERROR_BROKEN_PIPE ? "" :
+                    android::base::StringPrintf(": %s",
+                            SystemErrorCodeToString(err).c_str()).c_str());
         }
-        if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
-            fprintf(stderr, "ADB server didn't ACK\n" );
-            return -1;
+    }
+
+    // Always try to wait a bit for threads reading stdout/stderr to finish.
+    // If the process started ok, it should close the pipes causing the threads
+    // to finish. If the process had an error, it should exit, also causing
+    // the pipes to be closed. In that case we want to read all of the output
+    // and write it out so that the user can diagnose failures.
+    const DWORD     thread_timeout_ms = 15 * 1000;
+    const HANDLE    threads[] = { stdout_thread.get(), stderr_thread.get() };
+    const DWORD     wait_result = WaitForMultipleObjects(arraysize(threads),
+            threads, TRUE, thread_timeout_ms);
+    if (wait_result == WAIT_TIMEOUT) {
+        // Threads did not finish after waiting a little while. Perhaps the
+        // server didn't close pipes, or it is hung.
+        fprintf(stderr, "Timed-out waiting for threads to finish reading from "
+                "ADB Server\n");
+        // Process handles are signaled when the process exits, so if we wait
+        // on the handle for 0 seconds and it returns 'timeout', that means that
+        // the process is still running.
+        if (WaitForSingleObject(process_handle.get(), 0) == WAIT_TIMEOUT) {
+            // We could TerminateProcess(), but that seems somewhat presumptive.
+            fprintf(stderr, "ADB Server is running: process id %lu\n",
+                    pinfo.dwProcessId);
         }
+        return -1;
+    }
+
+    if (wait_result != WAIT_OBJECT_0) {
+        fprintf(stderr, "Unexpected result waiting for threads: %lu: %s\n",
+                wait_result, SystemErrorCodeToString(GetLastError()).c_str());
+        return -1;
+    }
+
+    // For now ignore the thread exit codes and assume they worked properly.
+
+    if (!got_ack) {
+        return -1;
     }
 #else /* !defined(_WIN32) */
     char    path[PATH_MAX];
@@ -967,8 +1144,7 @@
     if (!strncmp(service, "disconnect:", 11)) {
         const std::string address(service + 11);
         if (address.empty()) {
-            // disconnect from all TCP devices
-            unregister_all_tcp_transports();
+            kick_all_tcp_devices();
             return SendOkay(reply_fd, "disconnected everything");
         }
 
@@ -985,7 +1161,7 @@
             return SendFail(reply_fd, android::base::StringPrintf("no such device '%s'",
                                                                   serial.c_str()));
         }
-        unregister_transport(t);
+        kick_transport(t);
         return SendOkay(reply_fd, android::base::StringPrintf("disconnected %s", address.c_str()));
     }
 
diff --git a/adb/adb.h b/adb/adb.h
index 6855f3b..8b3359e 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -157,8 +157,6 @@
 {
     void        (*func)(void*  opaque, atransport*  t);
     void*         opaque;
-    adisconnect*  next;
-    adisconnect*  prev;
 };
 
 
@@ -229,8 +227,8 @@
 void connect_to_remote(asocket *s, const char *destination);
 void connect_to_smartsocket(asocket *s);
 
-void fatal(const char *fmt, ...);
-void fatal_errno(const char *fmt, ...);
+void fatal(const char *fmt, ...) __attribute__((noreturn));
+void fatal_errno(const char *fmt, ...) __attribute__((noreturn));
 
 void handle_packet(apacket *p, atransport *t);
 
diff --git a/adb/adb_auth_client.cpp b/adb/adb_auth_client.cpp
index be28202..c3af024 100644
--- a/adb/adb_auth_client.cpp
+++ b/adb/adb_auth_client.cpp
@@ -47,7 +47,7 @@
 static int framework_fd = -1;
 
 static void usb_disconnected(void* unused, atransport* t);
-static struct adisconnect usb_disconnect = { usb_disconnected, 0, 0, 0 };
+static struct adisconnect usb_disconnect = { usb_disconnected, nullptr};
 static atransport* usb_transport;
 static bool needs_retry = false;
 
@@ -164,7 +164,6 @@
 static void usb_disconnected(void* unused, atransport* t)
 {
     D("USB disconnect\n");
-    remove_transport_disconnect(usb_transport, &usb_disconnect);
     usb_transport = NULL;
     needs_retry = false;
 }
@@ -196,7 +195,7 @@
 
     if (!usb_transport) {
         usb_transport = t;
-        add_transport_disconnect(t, &usb_disconnect);
+        t->AddDisconnect(&usb_disconnect);
     }
 
     if (framework_fd < 0) {
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index 8fb2d19..d5b1fd5 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -101,13 +101,15 @@
         free((char*)l->connect_to);
 
     if (l->transport) {
-        remove_transport_disconnect(l->transport, &l->disconnect);
+        l->transport->RemoveDisconnect(&l->disconnect);
     }
     free(l);
 }
 
-static void listener_disconnect(void* listener, atransport* t) {
-    free_listener(reinterpret_cast<alistener*>(listener));
+static void listener_disconnect(void* arg, atransport*) {
+    alistener* listener = reinterpret_cast<alistener*>(arg);
+    listener->transport = nullptr;
+    free_listener(listener);
 }
 
 static int local_name_to_fd(const char* name, std::string* error) {
@@ -159,7 +161,7 @@
 
     for (l = listener_list.next; l != &listener_list; l = l->next) {
         if (!strcmp(local_name, l->local_name)) {
-            listener_disconnect(l, l->transport);
+            free_listener(l);
             return INSTALL_STATUS_OK;
         }
     }
@@ -174,7 +176,7 @@
         // Never remove smart sockets.
         if (l->connect_to[0] == '*')
             continue;
-        listener_disconnect(l, l->transport);
+        free_listener(l);
     }
 }
 
@@ -209,9 +211,9 @@
             free((void*) l->connect_to);
             l->connect_to = cto;
             if (l->transport != transport) {
-                remove_transport_disconnect(l->transport, &l->disconnect);
+                l->transport->RemoveDisconnect(&l->disconnect);
                 l->transport = transport;
-                add_transport_disconnect(l->transport, &l->disconnect);
+                l->transport->AddDisconnect(&l->disconnect);
             }
             return INSTALL_STATUS_OK;
         }
@@ -260,7 +262,7 @@
     if (transport) {
         listener->disconnect.opaque = listener;
         listener->disconnect.func   = listener_disconnect;
-        add_transport_disconnect(transport, &listener->disconnect);
+        transport->AddDisconnect(&listener->disconnect);
     }
     return INSTALL_STATUS_OK;
 
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index dbc7ec8..4e03165 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -40,22 +40,7 @@
     TRACE_SERVICES,
     TRACE_AUTH,
     TRACE_FDEVENT,
-} ;
-
-#if !ADB_HOST
-/*
- * When running inside the emulator, guest's adbd can connect to 'adb-debug'
- * qemud service that can display adb trace messages (on condition that emulator
- * has been started with '-debug adb' option).
- */
-
-/* Delivers a trace message to the emulator via QEMU pipe. */
-void adb_qemu_trace(const char* fmt, ...);
-/* Macro to use to send ADB trace messages to the emulator. */
-#define DQ(...)    adb_qemu_trace(__VA_ARGS__)
-#else
-#define DQ(...) ((void)0)
-#endif  /* !ADB_HOST */
+};
 
 extern int adb_trace_mask;
 extern unsigned char adb_trace_output_count;
@@ -65,51 +50,43 @@
 
 /* you must define TRACE_TAG before using this macro */
 #if ADB_HOST
-#  define  D(...)                                      \
-        do {                                           \
-            if (ADB_TRACING) {                         \
-                int save_errno = errno;                \
-                adb_mutex_lock(&D_lock);               \
-                fprintf(stderr, "%16s: %5d:%5lu | ",   \
-                        __FUNCTION__,                  \
-                        getpid(), adb_thread_id());    \
-                errno = save_errno;                    \
-                fprintf(stderr, __VA_ARGS__ );         \
-                fflush(stderr);                        \
-                adb_mutex_unlock(&D_lock);             \
-                errno = save_errno;                    \
-           }                                           \
+#  define D(fmt, ...) \
+        do { \
+            if (ADB_TRACING) { \
+                int saved_errno = errno; \
+                adb_mutex_lock(&D_lock); \
+                errno = saved_errno; \
+                fprintf(stderr, "%5d:%5lu %s | " fmt, \
+                        getpid(), adb_thread_id(), __FUNCTION__, ## __VA_ARGS__); \
+                fflush(stderr); \
+                adb_mutex_unlock(&D_lock); \
+                errno = saved_errno; \
+           } \
         } while (0)
-#  define  DR(...)                                     \
-        do {                                           \
-            if (ADB_TRACING) {                         \
-                int save_errno = errno;                \
-                adb_mutex_lock(&D_lock);               \
-                errno = save_errno;                    \
-                fprintf(stderr, __VA_ARGS__ );         \
-                fflush(stderr);                        \
-                adb_mutex_unlock(&D_lock);             \
-                errno = save_errno;                    \
-           }                                           \
+#  define DR(...) \
+        do { \
+            if (ADB_TRACING) { \
+                int saved_errno = errno; \
+                adb_mutex_lock(&D_lock); \
+                errno = saved_errno; \
+                fprintf(stderr, __VA_ARGS__); \
+                fflush(stderr); \
+                adb_mutex_unlock(&D_lock); \
+                errno = saved_errno; \
+           } \
         } while (0)
 #else
-#  define  D(...)                                      \
-        do {                                           \
-            if (ADB_TRACING) {                         \
-                __android_log_print(                   \
-                    ANDROID_LOG_INFO,                  \
-                    __FUNCTION__,                      \
-                    __VA_ARGS__ );                     \
-            }                                          \
+#  define D(...) \
+        do { \
+            if (ADB_TRACING) { \
+                __android_log_print(ANDROID_LOG_INFO, __FUNCTION__, __VA_ARGS__); \
+            } \
         } while (0)
-#  define  DR(...)                                     \
-        do {                                           \
-            if (ADB_TRACING) {                         \
-                __android_log_print(                   \
-                    ANDROID_LOG_INFO,                  \
-                    __FUNCTION__,                      \
-                    __VA_ARGS__ );                     \
-            }                                          \
+#  define DR(...) \
+        do { \
+            if (ADB_TRACING) { \
+                __android_log_print(ANDROID_LOG_INFO, __FUNCTION__, __VA_ARGS__); \
+            } \
         } while (0)
 #endif /* ADB_HOST */
 
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 39bb02b..8d644d9 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -36,46 +36,12 @@
 #include "adb_listeners.h"
 #include "transport.h"
 
-#if defined(WORKAROUND_BUG6558362) && defined(__linux__)
-static const bool kWorkaroundBug6558362 = true;
-#else
-static const bool kWorkaroundBug6558362 = false;
-#endif
-
-static void adb_workaround_affinity(void) {
-#if defined(__linux__)
-    const char affinity_env[] = "ADB_CPU_AFFINITY_BUG6558362";
-    const char* cpunum_str = getenv(affinity_env);
-    if (cpunum_str == nullptr || *cpunum_str == '\0') {
-        return;
-    }
-
-    char* strtol_res;
-    int cpu_num = strtol(cpunum_str, &strtol_res, 0);
-    if (*strtol_res != '\0') {
-        fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str,
-              affinity_env);
-    }
-
-    cpu_set_t cpu_set;
-    sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
-    D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
-
-    CPU_ZERO(&cpu_set);
-    CPU_SET(cpu_num, &cpu_set);
-    sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
-
-    sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
-    D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
-#else
-    // No workaround was ever implemented for the other platforms.
-#endif
-}
-
 #if defined(_WIN32)
 static const char kNullFileName[] = "NUL";
 
 static BOOL WINAPI ctrlc_handler(DWORD type) {
+    // TODO: Consider trying to kill a starting up adb server (if we're in
+    // launch_server) by calling GenerateConsoleCtrlEvent().
     exit(STATUS_CONTROL_C_EXIT);
     return TRUE;
 }
@@ -128,17 +94,26 @@
     }
     unix_close(fd);
 
-#ifdef _WIN32
-    // On Windows, stderr is buffered by default, so switch to non-buffered
-    // to match Linux.
-    setvbuf(stderr, NULL, _IONBF, 0);
-#endif
     fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid());
     LOG(INFO) << adb_version();
 }
 
 int adb_main(int is_daemon, int server_port, int ack_reply_fd) {
 #if defined(_WIN32)
+    // adb start-server starts us up with stdout and stderr hooked up to
+    // anonymous pipes to. When the C Runtime sees this, it makes stderr and
+    // stdout buffered, but to improve the chance that error output is seen,
+    // unbuffer stdout and stderr just like if we were run at the console.
+    // This also keeps stderr unbuffered when it is redirected to adb.log.
+    if (is_daemon) {
+        if (setvbuf(stdout, NULL, _IONBF, 0) == -1) {
+            fatal("cannot make stdout unbuffered: %s", strerror(errno));
+        }
+        if (setvbuf(stderr, NULL, _IONBF, 0) == -1) {
+            fatal("cannot make stderr unbuffered: %s", strerror(errno));
+        }
+    }
+
     SetConsoleCtrlHandler(ctrlc_handler, TRUE);
 #else
     signal(SIGPIPE, SIG_IGN);
@@ -146,10 +121,6 @@
 
     init_transport_registration();
 
-    if (kWorkaroundBug6558362 && is_daemon) {
-        adb_workaround_affinity();
-    }
-
     usb_init();
     local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
     adb_auth_init();
@@ -162,6 +133,12 @@
 
     // Inform our parent that we are up and running.
     if (is_daemon) {
+        close_stdin();
+        setup_daemon_logging();
+
+        // Any error output written to stderr now goes to adb.log. We could
+        // keep around a copy of the stderr fd and use that to write any errors
+        // encountered by the following code, but that is probably overkill.
 #if defined(_WIN32)
         const HANDLE ack_reply_handle = cast_int_to_handle(ack_reply_fd);
         const CHAR ack[] = "OK\n";
@@ -184,8 +161,6 @@
         }
         unix_close(ack_reply_fd);
 #endif
-        close_stdin();
-        setup_daemon_logging();
     }
 
     D("Event loop starting\n");
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index e1e21ed..6325e64 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -276,10 +276,7 @@
     count--;
     while (count > 0) {
         int len = adb_read(fd, buf, count);
-        if (len == 0) {
-            break;
-        } else if (len < 0) {
-            if (errno == EINTR) continue;
+        if (len <= 0) {
             break;
         }
 
@@ -332,11 +329,7 @@
             break;
         }
         if (len < 0) {
-            if (errno == EINTR) {
-                D("copy_to_file() : EINTR, retrying\n");
-                continue;
-            }
-            D("copy_to_file() : error %d\n", errno);
+            D("copy_to_file(): read failed: %s\n", strerror(errno));
             break;
         }
         if (outFd == STDOUT_FILENO) {
@@ -381,17 +374,15 @@
     fdi = fds[1];
     free(fds);
 
+    adb_thread_setname("stdin reader");
+
     while (true) {
         /* fdi is really the client's stdin, so use read, not adb_read here */
         D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi);
         r = unix_read(fdi, buf, 1024);
         D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi);
-        if(r == 0) break;
-        if(r < 0) {
-            if(errno == EINTR) continue;
-            break;
-        }
-        for(n = 0; n < r; n++){
+        if (r <= 0) break;
+        for (n = 0; n < r; n++){
             switch(buf[n]) {
             case '\n':
                 state = 1;
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index dc89639..2eba625 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -35,7 +35,6 @@
 #include "adb_auth.h"
 #include "adb_listeners.h"
 #include "transport.h"
-#include "qemu_tracing.h"
 
 static const char* root_seclabel = nullptr;
 
@@ -262,10 +261,6 @@
 
     adb_trace_init(argv);
 
-    /* If adbd runs inside the emulator this will enable adb tracing via
-     * adb-debug qemud service in the emulator. */
-    adb_qemu_trace_init();
-
     D("Handling main()\n");
     return adbd_main(DEFAULT_ADB_PORT);
 }
diff --git a/adb/device.py b/adb/device.py
index 5b33ff2..c5b5eea 100644
--- a/adb/device.py
+++ b/adb/device.py
@@ -17,6 +17,7 @@
 import os
 import re
 import subprocess
+import tempfile
 
 
 class FindDeviceError(RuntimeError):
@@ -99,6 +100,36 @@
 
     return _get_unique_device(product)
 
+# Call this instead of subprocess.check_output() to work-around issue in Python
+# 2's subprocess class on Windows where it doesn't support Unicode. This
+# writes the command line to a UTF-8 batch file that is properly interpreted
+# by cmd.exe.
+def _subprocess_check_output(*popenargs, **kwargs):
+    # Only do this slow work-around if Unicode is in the cmd line.
+    if (os.name == 'nt' and
+            any(isinstance(arg, unicode) for arg in popenargs[0])):
+        # cmd.exe requires a suffix to know that it is running a batch file
+        tf = tempfile.NamedTemporaryFile('wb', suffix='.cmd', delete=False)
+        # @ in batch suppresses echo of the current line.
+        # Change the codepage to 65001, the UTF-8 codepage.
+        tf.write('@chcp 65001 > nul\r\n')
+        tf.write('@')
+        # Properly quote all the arguments and encode in UTF-8.
+        tf.write(subprocess.list2cmdline(popenargs[0]).encode('utf-8'))
+        tf.close()
+
+        try:
+            result = subprocess.check_output(['cmd.exe', '/c', tf.name],
+                                             **kwargs)
+        except subprocess.CalledProcessError as e:
+            # Show real command line instead of the cmd.exe command line.
+            raise subprocess.CalledProcessError(e.returncode, popenargs[0],
+                                                output=e.output)
+        finally:
+            os.remove(tf.name)
+        return result
+    else:
+        return subprocess.check_output(*popenargs, **kwargs)
 
 class AndroidDevice(object):
     # Delimiter string to indicate the start of the exit code.
@@ -166,13 +197,13 @@
 
     def _simple_call(self, cmd):
         logging.info(' '.join(self.adb_cmd + cmd))
-        return subprocess.check_output(
+        return _subprocess_check_output(
             self.adb_cmd + cmd, stderr=subprocess.STDOUT)
 
     def shell(self, cmd):
         logging.info(' '.join(self.adb_cmd + ['shell'] + cmd))
         cmd = self._make_shell_cmd(cmd)
-        out = subprocess.check_output(cmd)
+        out = _subprocess_check_output(cmd)
         rc, out = self._parse_shell_output(out)
         if rc != 0:
             error = subprocess.CalledProcessError(rc, cmd)
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index e722d66..d25bbfb 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -205,8 +205,8 @@
 
     n = epoll_wait(epoll_fd, events, 256, -1);
 
-    if(n < 0) {
-        if(errno == EINTR) return;
+    if (n < 0) {
+        if (errno == EINTR) return;
         perror("epoll_wait");
         exit(1);
     }
diff --git a/adb/fdevent.h b/adb/fdevent.h
index 8d84b29..ca1494c 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -23,7 +23,6 @@
 #define FDE_READ              0x0001
 #define FDE_WRITE             0x0002
 #define FDE_ERROR             0x0004
-#define FDE_TIMEOUT           0x0008
 
 /* features that may be set (via the events set/add/del interface) */
 #define FDE_DONT_CLOSE        0x0080
diff --git a/adb/fdevent_test.cpp b/adb/fdevent_test.cpp
new file mode 100644
index 0000000..f7622b5
--- /dev/null
+++ b/adb/fdevent_test.cpp
@@ -0,0 +1,152 @@
+/*
+ * 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 "fdevent.h"
+
+#include <gtest/gtest.h>
+
+#include <queue>
+#include <string>
+#include <vector>
+
+#include <pthread.h>
+#include <signal.h>
+
+#include "adb_io.h"
+
+class SignalHandlerRegister {
+  public:
+    SignalHandlerRegister(const std::vector<int>& signums, void (*handler)(int)) {
+        for (auto& sig : signums) {
+            sig_t old_handler = signal(sig, handler);
+            saved_signal_handlers_.push_back(std::make_pair(sig, old_handler));
+        }
+    }
+
+    ~SignalHandlerRegister() {
+        for (auto& pair : saved_signal_handlers_) {
+            signal(pair.first, pair.second);
+        }
+    }
+
+  private:
+    std::vector<std::pair<int, sig_t>> saved_signal_handlers_;
+};
+
+class FdHandler {
+  public:
+    FdHandler(int read_fd, int write_fd) : read_fd_(read_fd), write_fd_(write_fd) {
+        fdevent_install(&read_fde_, read_fd_, FdEventCallback, this);
+        fdevent_add(&read_fde_, FDE_READ | FDE_ERROR);
+        fdevent_install(&write_fde_, write_fd_, FdEventCallback, this);
+        fdevent_add(&write_fde_, FDE_ERROR);
+    }
+
+  private:
+    static void FdEventCallback(int fd, unsigned events, void* userdata) {
+        FdHandler* handler = reinterpret_cast<FdHandler*>(userdata);
+        ASSERT_EQ(0u, (events & ~(FDE_READ | FDE_WRITE))) << "unexpected events: " << events;
+        if (events & FDE_READ) {
+            ASSERT_EQ(fd, handler->read_fd_);
+            char c;
+            ASSERT_EQ(1, read(fd, &c, 1));
+            handler->queue_.push(c);
+            fdevent_add(&handler->write_fde_, FDE_WRITE);
+        }
+        if (events & FDE_WRITE) {
+            ASSERT_EQ(fd, handler->write_fd_);
+            ASSERT_FALSE(handler->queue_.empty());
+            char c = handler->queue_.front();
+            handler->queue_.pop();
+            ASSERT_EQ(1, write(fd, &c, 1));
+            if (handler->queue_.empty()) {
+              fdevent_del(&handler->write_fde_, FDE_WRITE);
+            }
+        }
+    }
+
+  private:
+    const int read_fd_;
+    const int write_fd_;
+    fdevent read_fde_;
+    fdevent write_fde_;
+    std::queue<char> queue_;
+};
+
+static void signal_handler(int) {
+    pthread_exit(nullptr);
+}
+
+struct ThreadArg {
+    int first_read_fd;
+    int last_write_fd;
+    size_t middle_pipe_count;
+};
+
+static void FdEventThreadFunc(ThreadArg* arg) {
+    SignalHandlerRegister signal_handler_register({SIGUSR1}, signal_handler);
+
+    std::vector<int> read_fds;
+    std::vector<int> write_fds;
+
+    read_fds.push_back(arg->first_read_fd);
+    for (size_t i = 0; i < arg->middle_pipe_count; ++i) {
+        int fds[2];
+        ASSERT_EQ(0, pipe(fds));
+        read_fds.push_back(fds[0]);
+        write_fds.push_back(fds[1]);
+    }
+    write_fds.push_back(arg->last_write_fd);
+
+    std::vector<std::unique_ptr<FdHandler>> fd_handlers;
+    for (size_t i = 0; i < read_fds.size(); ++i) {
+        fd_handlers.push_back(std::unique_ptr<FdHandler>(new FdHandler(read_fds[i], write_fds[i])));
+    }
+
+    fdevent_loop();
+}
+
+TEST(fdevent, smoke) {
+    const size_t PIPE_COUNT = 10;
+    const size_t MESSAGE_LOOP_COUNT = 100;
+    const std::string MESSAGE = "fdevent_test";
+    int fd_pair1[2];
+    int fd_pair2[2];
+    ASSERT_EQ(0, pipe(fd_pair1));
+    ASSERT_EQ(0, pipe(fd_pair2));
+    pthread_t thread;
+    ThreadArg thread_arg;
+    thread_arg.first_read_fd = fd_pair1[0];
+    thread_arg.last_write_fd = fd_pair2[1];
+    thread_arg.middle_pipe_count = PIPE_COUNT;
+    int writer = fd_pair1[1];
+    int reader = fd_pair2[0];
+
+    ASSERT_EQ(0, pthread_create(&thread, nullptr,
+                                reinterpret_cast<void* (*)(void*)>(FdEventThreadFunc),
+                                &thread_arg));
+
+    for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) {
+        std::string read_buffer = MESSAGE;
+        std::string write_buffer(MESSAGE.size(), 'a');
+        ASSERT_TRUE(WriteFdExactly(writer, read_buffer.c_str(), read_buffer.size()));
+        ASSERT_TRUE(ReadFdExactly(reader, &write_buffer[0], write_buffer.size()));
+        ASSERT_EQ(read_buffer, write_buffer);
+    }
+
+    ASSERT_EQ(0, pthread_kill(thread, SIGUSR1));
+    ASSERT_EQ(0, pthread_join(thread, nullptr));
+}
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index ab11619..94876ee 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -179,44 +179,41 @@
     return sync_start_stat(sc, path) && sync_finish_stat(sc, timestamp, mode, size);
 }
 
-static int write_data_file(SyncConnection& sc, const char* path, syncsendbuf* sbuf, bool show_progress) {
-    int err = 0;
+static bool write_data_file(SyncConnection& sc, const char* path, syncsendbuf* sbuf, bool show_progress) {
     unsigned long long size = 0;
-
-    int lfd = adb_open(path, O_RDONLY);
-    if (lfd < 0) {
-        fprintf(stderr, "cannot open '%s': %s\n", path, strerror(errno));
-        return -1;
-    }
-
     if (show_progress) {
         // Determine local file size.
         struct stat st;
-        if (stat(path, &st)) {
+        if (stat(path, &st) == -1) {
             fprintf(stderr, "cannot stat '%s': %s\n", path, strerror(errno));
-            return -1;
+            return false;
         }
 
         size = st.st_size;
     }
 
+    int lfd = adb_open(path, O_RDONLY);
+    if (lfd < 0) {
+        fprintf(stderr, "cannot open '%s': %s\n", path, strerror(errno));
+        return false;
+    }
+
     sbuf->id = ID_DATA;
     while (true) {
         int ret = adb_read(lfd, sbuf->data, sc.max);
-        if (!ret)
-            break;
-
-        if (ret < 0) {
-            if(errno == EINTR)
-                continue;
-            fprintf(stderr, "cannot read '%s': %s\n", path, strerror(errno));
+        if (ret <= 0) {
+            if (ret < 0) {
+                fprintf(stderr, "cannot read '%s': %s\n", path, strerror(errno));
+                adb_close(lfd);
+                return false;
+            }
             break;
         }
 
         sbuf->size = ret;
         if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + ret)) {
-            err = -1;
-            break;
+            adb_close(lfd);
+            return false;
         }
         sc.total_bytes += ret;
 
@@ -226,17 +223,17 @@
     }
 
     adb_close(lfd);
-    return err;
+    return true;
 }
 
 #if defined(_WIN32)
-extern int write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) __attribute__((error("no symlinks on Windows")));
+extern bool write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) __attribute__((error("no symlinks on Windows")));
 #else
-static int write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) {
+static bool write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) {
     ssize_t len = readlink(path, sbuf->data, sc.max - 1);
     if (len < 0) {
         fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
-        return -1;
+        return false;
     }
     sbuf->data[len] = '\0';
 
@@ -244,12 +241,12 @@
     sbuf->id = ID_DATA;
 
     if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + len + 1)) {
-        return -1;
+        return false;
     }
 
     sc.total_bytes += len + 1;
 
-    return 0;
+    return true;
 }
 #endif
 
@@ -262,9 +259,9 @@
     if (!SendRequest(sc.fd, ID_SEND, path_and_mode.c_str())) goto fail;
 
     if (S_ISREG(mode)) {
-        write_data_file(sc, lpath, sbuf, show_progress);
+        if (!write_data_file(sc, lpath, sbuf, show_progress)) return false;
     } else if (S_ISLNK(mode)) {
-        write_data_link(sc, lpath, sbuf);
+        if (!write_data_link(sc, lpath, sbuf)) return false;
     } else {
         goto fail;
     }
@@ -330,6 +327,7 @@
 
     while (true) {
         if(!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
+            adb_close(lfd);
             return -1;
         }
         id = msg.data.id;
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 3e46447..3793b8e 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -71,6 +71,7 @@
             if (chown(partial_path.c_str(), uid, gid) == -1) {
                 return false;
             }
+            // Not all filesystems support setting SELinux labels. http://b/23530370.
             selinux_android_restorecon(partial_path.c_str(), 0);
         }
     }
@@ -128,101 +129,90 @@
     return WriteFdExactly(s, &msg.dent, sizeof(msg.dent));
 }
 
-static bool fail_message(int s, const std::string& reason) {
+static bool SendSyncFail(int fd, const std::string& reason) {
     D("sync: failure: %s\n", reason.c_str());
 
     syncmsg msg;
     msg.data.id = ID_FAIL;
     msg.data.size = reason.size();
-    return WriteFdExactly(s, &msg.data, sizeof(msg.data)) && WriteFdExactly(s, reason);
+    return WriteFdExactly(fd, &msg.data, sizeof(msg.data)) && WriteFdExactly(fd, reason);
 }
 
-// TODO: callers of this have already failed, and should probably ignore its
-// return value (http://b/23437039).
-static bool fail_errno(int s) {
-    return fail_message(s, strerror(errno));
+static bool SendSyncFailErrno(int fd, const std::string& reason) {
+    return SendSyncFail(fd, android::base::StringPrintf("%s: %s", reason.c_str(), strerror(errno)));
 }
 
-static bool handle_send_file(int s, char *path, uid_t uid,
+static bool handle_send_file(int s, const char* path, uid_t uid,
                              gid_t gid, mode_t mode, std::vector<char>& buffer, bool do_unlink) {
     syncmsg msg;
     unsigned int timestamp = 0;
 
     int fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
-    if(fd < 0 && errno == ENOENT) {
+    if (fd < 0 && errno == ENOENT) {
         if (!secure_mkdirs(path)) {
-            if (fail_errno(s)) return false;
-            fd = -1;
-        } else {
-            fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
+            SendSyncFailErrno(s, "secure_mkdirs failed");
+            goto fail;
         }
+        fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
     }
-    if(fd < 0 && errno == EEXIST) {
+    if (fd < 0 && errno == EEXIST) {
         fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode);
     }
-    if(fd < 0) {
-        if (fail_errno(s)) return false;
-        fd = -1;
+    if (fd < 0) {
+        SendSyncFailErrno(s, "couldn't create file");
+        goto fail;
     } else {
-        if(fchown(fd, uid, gid) != 0) {
-            fail_errno(s);
-            errno = 0;
+        if (fchown(fd, uid, gid) == -1) {
+            SendSyncFailErrno(s, "fchown failed");
+            goto fail;
         }
 
-        /*
-         * fchown clears the setuid bit - restore it if present.
-         * Ignore the result of calling fchmod. It's not supported
-         * by all filesystems. b/12441485
-         */
+        // Not all filesystems support setting SELinux labels. http://b/23530370.
+        selinux_android_restorecon(path, 0);
+
+        // fchown clears the setuid bit - restore it if present.
+        // Ignore the result of calling fchmod. It's not supported
+        // by all filesystems. b/12441485
         fchmod(fd, mode);
     }
 
     while (true) {
         unsigned int len;
 
-        if(!ReadFdExactly(s, &msg.data, sizeof(msg.data)))
-            goto fail;
+        if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) goto fail;
 
-        if(msg.data.id != ID_DATA) {
-            if(msg.data.id == ID_DONE) {
+        if (msg.data.id != ID_DATA) {
+            if (msg.data.id == ID_DONE) {
                 timestamp = msg.data.size;
                 break;
             }
-            fail_message(s, "invalid data message");
+            SendSyncFail(s, "invalid data message");
             goto fail;
         }
         len = msg.data.size;
         if (len > buffer.size()) { // TODO: resize buffer?
-            fail_message(s, "oversize data message");
+            SendSyncFail(s, "oversize data message");
             goto fail;
         }
+
         if (!ReadFdExactly(s, &buffer[0], len)) goto fail;
 
-        if (fd < 0) continue;
-
         if (!WriteFdExactly(fd, &buffer[0], len)) {
-            int saved_errno = errno;
-            adb_close(fd);
-            if (do_unlink) adb_unlink(path);
-            fd = -1;
-            errno = saved_errno;
-            if (fail_errno(s)) return false;
+            SendSyncFailErrno(s, "write failed");
+            goto fail;
         }
     }
 
-    if(fd >= 0) {
-        struct utimbuf u;
-        adb_close(fd);
-        selinux_android_restorecon(path, 0);
-        u.actime = timestamp;
-        u.modtime = timestamp;
-        utime(path, &u);
+    adb_close(fd);
 
-        msg.status.id = ID_OKAY;
-        msg.status.msglen = 0;
-        if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false;
-    }
-    return true;
+    utimbuf u;
+    u.actime = timestamp;
+    u.modtime = timestamp;
+    utime(path, &u);
+
+    msg.status.id = ID_OKAY;
+    msg.status.msglen = 0;
+    return WriteFdExactly(s, &msg.status, sizeof(msg.status));
 
 fail:
     if (fd >= 0) adb_close(fd);
@@ -231,9 +221,9 @@
 }
 
 #if defined(_WIN32)
-extern bool handle_send_link(int s, char *path, std::vector<char>& buffer) __attribute__((error("no symlinks on Windows")));
+extern bool handle_send_link(int s, const std::string& path, std::vector<char>& buffer) __attribute__((error("no symlinks on Windows")));
 #else
-static bool handle_send_link(int s, char *path, std::vector<char>& buffer) {
+static bool handle_send_link(int s, const std::string& path, std::vector<char>& buffer) {
     syncmsg msg;
     unsigned int len;
     int ret;
@@ -241,27 +231,27 @@
     if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false;
 
     if (msg.data.id != ID_DATA) {
-        fail_message(s, "invalid data message: expected ID_DATA");
+        SendSyncFail(s, "invalid data message: expected ID_DATA");
         return false;
     }
 
     len = msg.data.size;
     if (len > buffer.size()) { // TODO: resize buffer?
-        fail_message(s, "oversize data message");
+        SendSyncFail(s, "oversize data message");
         return false;
     }
     if (!ReadFdExactly(s, &buffer[0], len)) return false;
 
-    ret = symlink(&buffer[0], path);
+    ret = symlink(&buffer[0], path.c_str());
     if (ret && errno == ENOENT) {
         if (!secure_mkdirs(path)) {
-            fail_errno(s);
+            SendSyncFailErrno(s, "secure_mkdirs failed");
             return false;
         }
-        ret = symlink(&buffer[0], path);
+        ret = symlink(&buffer[0], path.c_str());
     }
     if (ret) {
-        fail_errno(s);
+        SendSyncFailErrno(s, "symlink failed");
         return false;
     }
 
@@ -272,7 +262,7 @@
         msg.status.msglen = 0;
         if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false;
     } else {
-        fail_message(s, "invalid data message: expected ID_DONE");
+        SendFail(s, "invalid data message: expected ID_DONE");
         return false;
     }
 
@@ -280,59 +270,55 @@
 }
 #endif
 
-static bool do_send(int s, char* path, std::vector<char>& buffer) {
-    unsigned int mode;
-    bool is_link = false;
-    bool do_unlink;
-
-    char* tmp = strrchr(path,',');
-    if(tmp) {
-        *tmp = 0;
-        errno = 0;
-        mode = strtoul(tmp + 1, NULL, 0);
-        is_link = S_ISLNK((mode_t) mode);
-        mode &= 0777;
-    }
-    if(!tmp || errno) {
-        mode = 0644;
-        is_link = 0;
-        do_unlink = true;
-    } else {
-        struct stat st;
-        /* Don't delete files before copying if they are not "regular" */
-        do_unlink = lstat(path, &st) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode);
-        if (do_unlink) {
-            adb_unlink(path);
-        }
+static bool do_send(int s, const std::string& spec, std::vector<char>& buffer) {
+    // 'spec' is of the form "/some/path,0755". Break it up.
+    size_t comma = spec.find_last_of(',');
+    if (comma == std::string::npos) {
+        SendFail(s, "missing , in ID_SEND");
+        return false;
     }
 
-    if (is_link) {
-        return handle_send_link(s, path, buffer);
+    std::string path = spec.substr(0, comma);
+
+    errno = 0;
+    mode_t mode = strtoul(spec.substr(comma + 1).c_str(), nullptr, 0);
+    if (errno != 0) {
+        SendFail(s, "bad mode");
+        return false;
     }
 
+    // Don't delete files before copying if they are not "regular" or symlinks.
+    struct stat st;
+    bool do_unlink = (lstat(path.c_str(), &st) == -1) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode);
+    if (do_unlink) {
+        adb_unlink(path.c_str());
+    }
+
+    if (S_ISLNK(mode)) {
+        return handle_send_link(s, path.c_str(), buffer);
+    }
+
+    // Copy user permission bits to "group" and "other" permissions.
+    mode &= 0777;
+    mode |= ((mode >> 3) & 0070);
+    mode |= ((mode >> 3) & 0007);
+
     uid_t uid = -1;
     gid_t gid = -1;
     uint64_t cap = 0;
-
-    /* copy user permission bits to "group" and "other" permissions */
-    mode |= ((mode >> 3) & 0070);
-    mode |= ((mode >> 3) & 0007);
-
-    tmp = path;
-    if(*tmp == '/') {
-        tmp++;
-    }
     if (should_use_fs_config(path)) {
-        fs_config(tmp, 0, &uid, &gid, &mode, &cap);
+        unsigned int broken_api_hack = mode;
+        fs_config(path.c_str(), 0, &uid, &gid, &broken_api_hack, &cap);
+        mode = broken_api_hack;
     }
-    return handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
+    return handle_send_file(s, path.c_str(), uid, gid, mode, buffer, do_unlink);
 }
 
 static bool do_recv(int s, const char* path, std::vector<char>& buffer) {
     int fd = adb_open(path, O_RDONLY | O_CLOEXEC);
     if (fd < 0) {
-        if (fail_errno(s)) return false;
-        return true;
+        SendSyncFailErrno(s, "open failed");
+        return false;
     }
 
     syncmsg msg;
@@ -341,10 +327,9 @@
         int r = adb_read(fd, &buffer[0], buffer.size());
         if (r <= 0) {
             if (r == 0) break;
-            if (errno == EINTR) continue;
-            bool status = fail_errno(s);
+            SendSyncFailErrno(s, "read failed");
             adb_close(fd);
-            return status;
+            return false;
         }
         msg.data.size = r;
         if (!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || !WriteFdExactly(s, &buffer[0], r)) {
@@ -365,17 +350,17 @@
 
     SyncRequest request;
     if (!ReadFdExactly(fd, &request, sizeof(request))) {
-        fail_message(fd, "command read failure");
+        SendSyncFail(fd, "command read failure");
         return false;
     }
     size_t path_length = request.path_length;
     if (path_length > 1024) {
-        fail_message(fd, "path too long");
+        SendSyncFail(fd, "path too long");
         return false;
     }
     char name[1025];
     if (!ReadFdExactly(fd, name, path_length)) {
-        fail_message(fd, "filename read failure");
+        SendSyncFail(fd, "filename read failure");
         return false;
     }
     name[path_length] = 0;
@@ -399,7 +384,7 @@
       case ID_QUIT:
         return false;
       default:
-        fail_message(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)",
+        SendSyncFail(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)",
                                                      id, request.id));
         return false;
     }
diff --git a/adb/qemu_tracing.cpp b/adb/qemu_tracing.cpp
deleted file mode 100644
index f31eae8..0000000
--- a/adb/qemu_tracing.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Implements ADB tracing inside the emulator.
- */
-
-#include <stdarg.h>
-
-#include "sysdeps.h"
-#include "qemu_tracing.h"
-
-/*
- * 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.
- */
-
-#undef open
-#undef write
-#define open    adb_open
-#define write   adb_write
-#include <hardware/qemu_pipe.h>
-#undef open
-#undef write
-#define open    ___xxx_open
-#define write   ___xxx_write
-
-/* A handle to adb-debug qemud service in the emulator. */
-int   adb_debug_qemu = -1;
-
-/* Initializes connection with the adb-debug qemud service in the emulator. */
-int adb_qemu_trace_init(void)
-{
-    char con_name[32];
-
-    if (adb_debug_qemu >= 0) {
-        return 0;
-    }
-
-    /* adb debugging QEMUD service connection request. */
-    snprintf(con_name, sizeof(con_name), "qemud:adb-debug");
-    adb_debug_qemu = qemu_pipe_open(con_name);
-    return (adb_debug_qemu >= 0) ? 0 : -1;
-}
-
-void adb_qemu_trace(const char* fmt, ...)
-{
-    va_list args;
-    va_start(args, fmt);
-    char msg[1024];
-
-    if (adb_debug_qemu >= 0) {
-        vsnprintf(msg, sizeof(msg), fmt, args);
-        adb_write(adb_debug_qemu, msg, strlen(msg));
-    }
-}
diff --git a/adb/qemu_tracing.h b/adb/qemu_tracing.h
deleted file mode 100644
index ff42d4f..0000000
--- a/adb/qemu_tracing.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Implements ADB tracing inside the emulator.
- */
-
-#ifndef __QEMU_TRACING_H
-#define __QEMU_TRACING_H
-
-/* Initializes connection with the adb-debug qemud service in the emulator. */
-int adb_qemu_trace_init(void);
-void adb_qemu_trace(const char* fmt, ...);
-
-#endif /* __QEMU_TRACING_H */
diff --git a/adb/services.cpp b/adb/services.cpp
index c8c2d54..4606804 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -67,6 +67,7 @@
 void *service_bootstrap_func(void *x)
 {
     stinfo* sti = reinterpret_cast<stinfo*>(x);
+    adb_thread_setname(android::base::StringPrintf("service %d", sti->fd));
     sti->func(sti->fd, sti->cookie);
     free(sti);
     return 0;
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index d8ea2ee..9c13936 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -360,9 +360,12 @@
         } else {
             p->len = max_payload - avail;
 
+            // s->peer->enqueue() may call s->close() and free s,
+            // so save variables for debug printing below.
+            unsigned saved_id = s->id;
+            int saved_fd = s->fd;
             r = s->peer->enqueue(s->peer, p);
-            D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd,
-              r);
+            D("LS(%u): fd=%d post peer->enqueue(). r=%d\n", saved_id, saved_fd, r);
 
             if (r < 0) {
                     /* error return means they closed us as a side-effect
@@ -468,14 +471,6 @@
 }
 #endif /* ADB_HOST */
 
-/* a Remote socket is used to send/receive data to/from a given transport object
-** it needs to be closed when the transport is forcibly destroyed by the user
-*/
-struct aremotesocket {
-    asocket      socket;
-    adisconnect  disconnect;
-};
-
 static int remote_socket_enqueue(asocket *s, apacket *p)
 {
     D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n",
@@ -523,33 +518,17 @@
     D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n",
       s->id, s->fd, s->peer?s->peer->fd:-1);
     D("RS(%d): closed\n", s->id);
-    remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
     free(s);
 }
 
-static void remote_socket_disconnect(void*  _s, atransport*  t)
-{
-    asocket* s = reinterpret_cast<asocket*>(_s);
-    asocket* peer = s->peer;
-
-    D("remote_socket_disconnect RS(%d)\n", s->id);
-    if (peer) {
-        peer->peer = NULL;
-        peer->close(peer);
-    }
-    remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
-    free(s);
-}
-
-/* Create an asocket to exchange packets with a remote service through transport
-  |t|. Where |id| is the socket id of the corresponding service on the other
-   side of the transport (it is allocated by the remote side and _cannot_ be 0).
-   Returns a new non-NULL asocket handle. */
+// Create a remote socket to exchange packets with a remote service through transport
+// |t|. Where |id| is the socket id of the corresponding service on the other
+//  side of the transport (it is allocated by the remote side and _cannot_ be 0).
+// Returns a new non-NULL asocket handle.
 asocket *create_remote_socket(unsigned id, atransport *t)
 {
     if (id == 0) fatal("invalid remote socket id (0)");
-    asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(aremotesocket)));
-    adisconnect* dis = &reinterpret_cast<aremotesocket*>(s)->disconnect;
+    asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
 
     if (s == NULL) fatal("cannot allocate socket");
     s->id = id;
@@ -559,9 +538,6 @@
     s->close = remote_socket_close;
     s->transport = t;
 
-    dis->func   = remote_socket_disconnect;
-    dis->opaque = s;
-    add_transport_disconnect( t, dis );
     D("RS(%d): created\n", s->id);
     return s;
 }
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 6f3c443..5918a94 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -71,6 +71,7 @@
 #include <windows.h>
 #include <ws2tcpip.h>
 
+#include <memory>   // unique_ptr
 #include <string>   // Prototypes for narrow() and widen() use std::(w)string.
 
 #include "fdevent.h"
@@ -110,6 +111,13 @@
     return (tid != static_cast<uintptr_t>(-1L));
 }
 
+static __inline__ int adb_thread_setname(const std::string& name) {
+    // TODO: See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx for how to set
+    // the thread name in Windows. Unfortunately, it only works during debugging, but
+    // our build process doesn't generate PDB files needed for debugging.
+    return 0;
+}
+
 static __inline__  unsigned long adb_thread_id()
 {
     return GetCurrentThreadId();
@@ -355,6 +363,21 @@
     return reinterpret_cast<HANDLE>(static_cast<INT_PTR>(fd));
 }
 
+// Deleter for unique_handle. Adapted from many sources, including:
+// http://stackoverflow.com/questions/14841396/stdunique-ptr-deleters-and-the-win32-api
+// https://visualstudiomagazine.com/articles/2013/09/01/get-a-handle-on-the-windows-api.aspx
+class handle_deleter {
+public:
+    typedef HANDLE pointer;
+
+    void operator()(HANDLE h);
+};
+
+// Like std::unique_ptr, but for Windows HANDLE objects that should be
+// CloseHandle()'d. Operator bool() only checks if the handle != nullptr,
+// but does not check if the handle != INVALID_HANDLE_VALUE.
+typedef std::unique_ptr<HANDLE, handle_deleter> unique_handle;
+
 #else /* !_WIN32 a.k.a. Unix */
 
 #include "fdevent.h"
@@ -601,7 +624,26 @@
     return (errno == 0);
 }
 
-static __inline__  int  adb_socket_setbufsize( int   fd, int  bufsize )
+static __inline__ int adb_thread_setname(const std::string& name) {
+#ifdef __APPLE__
+    return pthread_setname_np(name.c_str());
+#else
+    const char *s = name.c_str();
+
+    // pthread_setname_np fails rather than truncating long strings.
+    const int max_task_comm_len = 16; // including the null terminator
+    if (name.length() > (max_task_comm_len - 1)) {
+        char buf[max_task_comm_len];
+        strncpy(buf, name.c_str(), sizeof(buf) - 1);
+        buf[sizeof(buf) - 1] = '\0';
+        s = buf;
+    }
+
+    return pthread_setname_np(pthread_self(), s) ;
+#endif
+}
+
+static __inline__  int  adb_socket_setbufsize(int fd, int  bufsize )
 {
     int opt = bufsize;
     return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index f534d61..015f89e 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -112,6 +112,22 @@
   return msg;
 }
 
+void handle_deleter::operator()(HANDLE h) {
+    // CreateFile() is documented to return INVALID_HANDLE_FILE on error,
+    // implying that NULL is a valid handle, but this is probably impossible.
+    // Other APIs like CreateEvent() are documented to return NULL on error,
+    // implying that INVALID_HANDLE_VALUE is a valid handle, but this is also
+    // probably impossible. Thus, consider both NULL and INVALID_HANDLE_VALUE
+    // as invalid handles. std::unique_ptr won't call a deleter with NULL, so we
+    // only need to check for INVALID_HANDLE_VALUE.
+    if (h != INVALID_HANDLE_VALUE) {
+        if (!CloseHandle(h)) {
+            D("CloseHandle(%p) failed: %s\n", h,
+              SystemErrorCodeToString(GetLastError()).c_str());
+        }
+    }
+}
+
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
diff --git a/adb/test_device.py b/adb/test_device.py
index c893ad4..2006937 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -215,12 +215,18 @@
     def test_install_argument_escaping(self):
         """Make sure that install argument escaping works."""
         # http://b/20323053
-        tf = tempfile.NamedTemporaryFile('wb', suffix='-text;ls;1.apk')
+        tf = tempfile.NamedTemporaryFile('wb', suffix='-text;ls;1.apk',
+                                         delete=False)
+        tf.close()
         self.assertIn("-text;ls;1.apk", self.device.install(tf.name))
+        os.remove(tf.name)
 
         # http://b/3090932
-        tf = tempfile.NamedTemporaryFile('wb', suffix="-Live Hold'em.apk")
+        tf = tempfile.NamedTemporaryFile('wb', suffix="-Live Hold'em.apk",
+                                         delete=False)
+        tf.close()
         self.assertIn("-Live Hold'em.apk", self.device.install(tf.name))
+        os.remove(tf.name)
 
 
 class RootUnrootTest(DeviceTest):
@@ -451,19 +457,24 @@
 
     def test_unicode_paths(self):
         """Ensure that we can support non-ASCII paths, even on Windows."""
-        name = u'로보카 폴리'.encode('utf-8')
+        name = u'로보카 폴리'
 
         ## push.
-        tf = tempfile.NamedTemporaryFile('wb', suffix=name)
-        self.device.push(tf.name, '/data/local/tmp/adb-test-{}'.format(name))
+        tf = tempfile.NamedTemporaryFile('wb', suffix=name, delete=False)
+        tf.close()
+        self.device.push(tf.name, u'/data/local/tmp/adb-test-{}'.format(name))
+        os.remove(tf.name)
         self.device.shell(['rm', '-f', '/data/local/tmp/adb-test-*'])
 
         # pull.
-        cmd = ['touch', '"/data/local/tmp/adb-test-{}"'.format(name)]
+        cmd = ['touch', u'"/data/local/tmp/adb-test-{}"'.format(name)]
         self.device.shell(cmd)
 
-        tf = tempfile.NamedTemporaryFile('wb', suffix=name)
-        self.device.pull('/data/local/tmp/adb-test-{}'.format(name), tf.name)
+        tf = tempfile.NamedTemporaryFile('wb', suffix=name, delete=False)
+        tf.close()
+        self.device.pull(u'/data/local/tmp/adb-test-{}'.format(name), tf.name)
+        os.remove(tf.name)
+        self.device.shell(['rm', '-f', '/data/local/tmp/adb-test-*'])
 
 
 def main():
diff --git a/adb/transport.cpp b/adb/transport.cpp
index ea673f2..5a962de 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -28,6 +28,7 @@
 
 #include <list>
 
+#include <base/logging.h>
 #include <base/stringprintf.h>
 #include <base/strings.h>
 
@@ -41,53 +42,6 @@
 
 ADB_MUTEX_DEFINE( transport_lock );
 
-void kick_transport(atransport* t)
-{
-    if (t && !t->kicked)
-    {
-        int  kicked;
-
-        adb_mutex_lock(&transport_lock);
-        kicked = t->kicked;
-        if (!kicked)
-            t->kicked = 1;
-        adb_mutex_unlock(&transport_lock);
-
-        if (!kicked)
-            t->kick(t);
-    }
-}
-
-// Each atransport contains a list of adisconnects (t->disconnects).
-// An adisconnect contains a link to the next/prev adisconnect, a function
-// pointer to a disconnect callback which takes a void* piece of user data and
-// the atransport, and some user data for the callback (helpfully named
-// "opaque").
-//
-// The list is circular. New items are added to the entry member of the list
-// (t->disconnects) by add_transport_disconnect.
-//
-// run_transport_disconnects invokes each function in the list.
-//
-// Gotchas:
-//   * run_transport_disconnects assumes that t->disconnects is non-null, so
-//     this can't be run on a zeroed atransport.
-//   * The callbacks in this list are not removed when called, and this function
-//     is not guarded against running more than once. As such, ensure that this
-//     function is not called multiple times on the same atransport.
-//     TODO(danalbert): Just fix this so that it is guarded once you have tests.
-void run_transport_disconnects(atransport* t)
-{
-    adisconnect*  dis = t->disconnects.next;
-
-    D("%s: run_transport_disconnects\n", t->serial);
-    while (dis != &t->disconnects) {
-        adisconnect*  next = dis->next;
-        dis->func( dis->opaque, t );
-        dis = next;
-    }
-}
-
 static void dump_packet(const char* name, const char* func, apacket* p) {
     unsigned  command = p->msg.command;
     int       len     = p->msg.data_length;
@@ -140,8 +94,7 @@
             len -= 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;
+            D("%s: read_packet (fd=%d), error ret=%d: %s\n", name, fd, r, strerror(errno));
             return -1;
         }
     }
@@ -171,8 +124,7 @@
             len -= r;
             p += r;
         } else {
-            D("%s: write_packet (fd=%d) error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
-            if((r < 0) && (errno == EINTR)) continue;
+            D("%s: write_packet (fd=%d) error ret=%d: %s\n", name, fd, r, strerror(errno));
             return -1;
         }
     }
@@ -223,25 +175,27 @@
     }
 }
 
-/* The transport is opened by transport_register_func before
-** the input and output threads are started.
-**
-** The output thread issues a SYNC(1, token) message to let
-** the input thread know to start things up.  In the event
-** of transport IO failure, the output thread will post a
-** SYNC(0,0) message to ensure shutdown.
-**
-** The transport will not actually be closed until both
-** threads exit, but the input thread will kick the transport
-** on its way out to disconnect the underlying device.
-*/
-
-static void *output_thread(void *_t)
+// The transport is opened by transport_register_func before
+// the read_transport and write_transport threads are started.
+//
+// The read_transport thread issues a SYNC(1, token) message to let
+// the write_transport thread know to start things up.  In the event
+// of transport IO failure, the read_transport thread will post a
+// SYNC(0,0) message to ensure shutdown.
+//
+// The transport will not actually be closed until both threads exit, but the threads
+// will kick the transport on their way out to disconnect the underlying device.
+//
+// read_transport thread reads data from a transport (representing a usb/tcp connection),
+// and makes the main thread call handle_packet().
+static void *read_transport_thread(void *_t)
 {
     atransport *t = reinterpret_cast<atransport*>(_t);
     apacket *p;
 
-    D("%s: starting transport output thread on fd %d, SYNC online (%d)\n",
+    adb_thread_setname(android::base::StringPrintf("<-%s",
+                                                   (t->serial != nullptr ? t->serial : "transport")));
+    D("%s: starting read_transport thread on fd %d, SYNC online (%d)\n",
        t->serial, t->fd, t->sync_token + 1);
     p = get_apacket();
     p->msg.command = A_SYNC;
@@ -285,19 +239,23 @@
     }
 
 oops:
-    D("%s: transport output thread is exiting\n", t->serial);
+    D("%s: read_transport thread is exiting\n", t->serial);
     kick_transport(t);
     transport_unref(t);
     return 0;
 }
 
-static void *input_thread(void *_t)
+// write_transport thread gets packets sent by the main thread (through send_packet()),
+// and writes to a transport (representing a usb/tcp connection).
+static void *write_transport_thread(void *_t)
 {
     atransport *t = reinterpret_cast<atransport*>(_t);
     apacket *p;
     int active = 0;
 
-    D("%s: starting transport input thread, reading from fd %d\n",
+    adb_thread_setname(android::base::StringPrintf("->%s",
+                                                   (t->serial != nullptr ? t->serial : "transport")));
+    D("%s: starting write_transport thread, reading from fd %d\n",
        t->serial, t->fd);
 
     for(;;){
@@ -332,16 +290,25 @@
         put_apacket(p);
     }
 
-    // this is necessary to avoid a race condition that occured when a transport closes
-    // while a client socket is still active.
-    close_all_sockets(t);
-
-    D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd);
+    D("%s: write_transport thread is exiting, fd %d\n", t->serial, t->fd);
     kick_transport(t);
     transport_unref(t);
     return 0;
 }
 
+static void kick_transport_locked(atransport* t) {
+    CHECK(t != nullptr);
+    if (!t->kicked) {
+        t->kicked = true;
+        t->kick(t);
+    }
+}
+
+void kick_transport(atransport* t) {
+    adb_mutex_lock(&transport_lock);
+    kick_transport_locked(t);
+    adb_mutex_unlock(&transport_lock);
+}
 
 static int transport_registration_send = -1;
 static int transport_registration_recv = -1;
@@ -489,9 +456,7 @@
             len -= r;
             p   += r;
         } else {
-            if((r < 0) && (errno == EINTR)) continue;
-            D("transport_read_action: on fd %d, error %d: %s\n",
-              fd, errno, strerror(errno));
+            D("transport_read_action: on fd %d: %s\n", fd, strerror(errno));
             return -1;
         }
     }
@@ -511,9 +476,7 @@
             len -= r;
             p   += r;
         } else {
-            if((r < 0) && (errno == EINTR)) continue;
-            D("transport_write_action: on fd %d, error %d: %s\n",
-              fd, errno, strerror(errno));
+            D("transport_write_action: on fd %d: %s\n", fd, strerror(errno));
             return -1;
         }
     }
@@ -549,8 +512,6 @@
         transport_list.remove(t);
         adb_mutex_unlock(&transport_lock);
 
-        run_transport_disconnects(t);
-
         if (t->product)
             free(t->product);
         if (t->serial)
@@ -589,12 +550,12 @@
 
         fdevent_set(&(t->transport_fde), FDE_READ);
 
-        if (!adb_thread_create(input_thread, t)) {
-            fatal_errno("cannot create input thread");
+        if (!adb_thread_create(write_transport_thread, t)) {
+            fatal_errno("cannot create write_transport thread");
         }
 
-        if (!adb_thread_create(output_thread, t)) {
-            fatal_errno("cannot create output thread");
+        if (!adb_thread_create(read_transport_thread, t)) {
+            fatal_errno("cannot create read_transport thread");
         }
     }
 
@@ -603,8 +564,6 @@
     transport_list.push_front(t);
     adb_mutex_unlock(&transport_lock);
 
-    t->disconnects.next = t->disconnects.prev = &t->disconnects;
-
     update_transports();
 }
 
@@ -652,48 +611,22 @@
 }
 
 
-static void transport_unref_locked(atransport *t)
-{
+static void transport_unref(atransport* t) {
+    CHECK(t != nullptr);
+    adb_mutex_lock(&transport_lock);
+    CHECK_GT(t->ref_count, 0u);
     t->ref_count--;
     if (t->ref_count == 0) {
         D("transport: %s unref (kicking and closing)\n", t->serial);
-        if (!t->kicked) {
-            t->kicked = 1;
-            t->kick(t);
-        }
+        kick_transport_locked(t);
         t->close(t);
         remove_transport(t);
     } else {
-        D("transport: %s unref (count=%d)\n", t->serial, t->ref_count);
+        D("transport: %s unref (count=%zu)\n", t->serial, t->ref_count);
     }
-}
-
-static void transport_unref(atransport *t)
-{
-    if (t) {
-        adb_mutex_lock(&transport_lock);
-        transport_unref_locked(t);
-        adb_mutex_unlock(&transport_lock);
-    }
-}
-
-void add_transport_disconnect(atransport*  t, adisconnect*  dis)
-{
-    adb_mutex_lock(&transport_lock);
-    dis->next       = &t->disconnects;
-    dis->prev       = dis->next->prev;
-    dis->prev->next = dis;
-    dis->next->prev = dis;
     adb_mutex_unlock(&transport_lock);
 }
 
-void remove_transport_disconnect(atransport*  t, adisconnect*  dis)
-{
-    dis->prev->next = dis->next;
-    dis->next->prev = dis->prev;
-    dis->next = dis->prev = dis;
-}
-
 static int qual_match(const char *to_test,
                       const char *prefix, const char *qual, bool sanitize_qual)
 {
@@ -868,6 +801,21 @@
     return has_feature(feature) && supported_features().count(feature) > 0;
 }
 
+void atransport::AddDisconnect(adisconnect* disconnect) {
+    disconnects_.push_back(disconnect);
+}
+
+void atransport::RemoveDisconnect(adisconnect* disconnect) {
+    disconnects_.remove(disconnect);
+}
+
+void atransport::RunDisconnects() {
+    for (auto& disconnect : disconnects_) {
+        disconnect->func(disconnect->opaque, this);
+    }
+    disconnects_.clear();
+}
+
 #if ADB_HOST
 
 static void append_transport_info(std::string* result, const char* key,
@@ -977,7 +925,7 @@
     atransport* result = nullptr;
 
     adb_mutex_lock(&transport_lock);
-    for (auto t : transport_list) {
+    for (auto& t : transport_list) {
         if (t->serial && strcmp(serial, t->serial) == 0) {
             result = t;
             break;
@@ -988,35 +936,18 @@
     return result;
 }
 
-void unregister_transport(atransport *t)
-{
+void kick_all_tcp_devices() {
     adb_mutex_lock(&transport_lock);
-    transport_list.remove(t);
-    adb_mutex_unlock(&transport_lock);
-
-    kick_transport(t);
-    transport_unref(t);
-}
-
-// Unregisters all non-emulator TCP transports.
-void unregister_all_tcp_transports() {
-    adb_mutex_lock(&transport_lock);
-    for (auto it = transport_list.begin(); it != transport_list.end(); ) {
-        atransport* t = *it;
+    for (auto& t : transport_list) {
+        // TCP/IP devices have adb_port == 0.
         if (t->type == kTransportLocal && t->adb_port == 0) {
-            // We cannot call kick_transport when holding transport_lock.
-            if (!t->kicked) {
-                t->kicked = 1;
-                t->kick(t);
-            }
-            transport_unref_locked(t);
-
-            it = transport_list.erase(it);
-        } else {
-            ++it;
+            // Kicking breaks the read_transport thread of this transport out of any read, then
+            // the read_transport thread will notify the main thread to make this transport
+            // offline. Then the main thread will notify the write_transport thread to exit.
+            // Finally, this transport will be closed and freed in the main thread.
+            kick_transport_locked(t);
         }
     }
-
     adb_mutex_unlock(&transport_lock);
 }
 
diff --git a/adb/transport.h b/adb/transport.h
index e809407..3b56c55 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -19,6 +19,7 @@
 
 #include <sys/types.h>
 
+#include <list>
 #include <string>
 #include <unordered_set>
 
@@ -52,7 +53,7 @@
     int fd = -1;
     int transport_socket = -1;
     fdevent transport_fde;
-    int ref_count = 0;
+    size_t ref_count = 0;
     uint32_t sync_token = 0;
     ConnectionState connection_state = kCsOffline;
     bool online = false;
@@ -71,9 +72,6 @@
     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;
@@ -96,6 +94,10 @@
     // feature.
     bool CanUseFeature(const std::string& feature) const;
 
+    void AddDisconnect(adisconnect* disconnect);
+    void RemoveDisconnect(adisconnect* disconnect);
+    void RunDisconnects();
+
 private:
     // A set of features transmitted in the banner with the initial connection.
     // This is stored in the banner as 'features=feature0,feature1,etc'.
@@ -103,6 +105,9 @@
     int protocol_version;
     size_t max_payload;
 
+    // A list of adisconnect callbacks called when the transport is kicked.
+    std::list<adisconnect*> disconnects_;
+
     DISALLOW_COPY_AND_ASSIGN(atransport);
 };
 
@@ -114,18 +119,13 @@
  */
 atransport* acquire_one_transport(ConnectionState state, TransportType type,
                                   const char* serial, std::string* error_out);
-void add_transport_disconnect(atransport* t, adisconnect* dis);
-void remove_transport_disconnect(atransport* t, adisconnect* dis);
 void kick_transport(atransport* t);
-void run_transport_disconnects(atransport* t);
 void update_transports(void);
 
-/* transports are ref-counted
-** get_device_transport does an acquire on your behalf before returning
-*/
 void init_transport_registration(void);
 std::string list_transports(bool long_listing);
 atransport* find_transport(const char* serial);
+void kick_all_tcp_devices();
 
 void register_usb_transport(usb_handle* h, const char* serial,
                             const char* devpath, unsigned writeable);
@@ -136,10 +136,6 @@
 // This should only be used for transports with connection_state == kCsNoPerm.
 void unregister_usb_transport(usb_handle* usb);
 
-/* these should only be used for the "adb disconnect" command */
-void unregister_transport(atransport* t);
-void unregister_all_tcp_transports();
-
 int check_header(apacket* p, atransport* t);
 int check_data(apacket* p);
 
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 6a17497..6821cfc 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -123,6 +123,7 @@
 #if ADB_HOST
 static void *client_socket_thread(void *x)
 {
+    adb_thread_setname("client_socket_thread");
     D("transport: client_socket_thread() starting\n");
     while (true) {
         int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
@@ -146,6 +147,7 @@
     socklen_t alen;
     int port = (int) (uintptr_t) arg;
 
+    adb_thread_setname("server socket");
     D("transport: server_socket_thread() starting\n");
     serverfd = -1;
     for(;;) {
@@ -231,6 +233,7 @@
     char tmp[256];
     char con_name[32];
 
+    adb_thread_setname("qemu socket");
     D("transport: qemu_socket_thread() starting\n");
 
     /* adb QEMUD service connection request. */
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 743d97d..10872ac 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -51,9 +51,6 @@
         EXPECT_EQ(adb_port, rhs.adb_port);
         EXPECT_EQ(kicked, rhs.kicked);
 
-        EXPECT_EQ(
-            0, memcmp(&disconnects, &rhs.disconnects, sizeof(adisconnect)));
-
         EXPECT_EQ(key, rhs.key);
         EXPECT_EQ(0, memcmp(token, rhs.token, TOKEN_SIZE));
         EXPECT_EQ(0, memcmp(&auth_fde, &rhs.auth_fde, sizeof(fdevent)));
@@ -118,12 +115,33 @@
   ASSERT_EQ(expected, t);
 }
 
-// Disabled because the function currently segfaults for a zeroed atransport. I
-// 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) {
+static void DisconnectFunc(void* arg, atransport*) {
+    int* count = reinterpret_cast<int*>(arg);
+    ++*count;
+}
+
+TEST(transport, RunDisconnects) {
     atransport t;
-    run_transport_disconnects(&t);
+    // RunDisconnects() can be called with an empty atransport.
+    t.RunDisconnects();
+
+    int count = 0;
+    adisconnect disconnect;
+    disconnect.func = DisconnectFunc;
+    disconnect.opaque = &count;
+    t.AddDisconnect(&disconnect);
+    t.RunDisconnects();
+    ASSERT_EQ(1, count);
+
+    // disconnect should have been removed automatically.
+    t.RunDisconnects();
+    ASSERT_EQ(1, count);
+
+    count = 0;
+    t.AddDisconnect(&disconnect);
+    t.RemoveDisconnect(&disconnect);
+    t.RunDisconnects();
+    ASSERT_EQ(0, count);
 }
 
 TEST(transport, add_feature) {
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index dd22712..65b8735 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -572,6 +572,7 @@
 }
 
 static void* device_poll_thread(void* unused) {
+    adb_thread_setname("device poll");
     D("Created device thread\n");
     while (true) {
         // TODO: Use inotify.
@@ -591,6 +592,6 @@
     sigaction(SIGALRM, &actions, nullptr);
 
     if (!adb_thread_create(device_poll_thread, nullptr)) {
-        fatal_errno("cannot create input thread");
+        fatal_errno("cannot create device_poll thread");
     }
 }
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index c6ad00d..e1d7594 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -209,6 +209,8 @@
     struct usb_handle *usb = (struct usb_handle *)x;
     int fd;
 
+    adb_thread_setname("usb open");
+
     while (true) {
         // wait until the USB device needs opening
         adb_mutex_lock(&usb->lock);
@@ -403,6 +405,8 @@
 {
     struct usb_handle *usb = (struct usb_handle *)x;
 
+    adb_thread_setname("usb ffs open");
+
     while (true) {
         // wait until the USB device needs opening
         adb_mutex_lock(&usb->lock);
@@ -431,17 +435,12 @@
 static int bulk_write(int bulk_in, const uint8_t* buf, size_t length)
 {
     size_t count = 0;
-    int ret;
 
-    do {
-        ret = adb_write(bulk_in, buf + count, length - count);
-        if (ret < 0) {
-            if (errno != EINTR)
-                return ret;
-        } else {
-            count += ret;
-        }
-    } while (count < length);
+    while (count < length) {
+        int ret = adb_write(bulk_in, buf + count, length - count);
+        if (ret < 0) return -1;
+        count += ret;
+    }
 
     D("[ bulk_write done fd=%d ]\n", bulk_in);
     return count;
@@ -462,20 +461,15 @@
 static int bulk_read(int bulk_out, uint8_t* buf, size_t length)
 {
     size_t count = 0;
-    int ret;
 
-    do {
-        ret = adb_read(bulk_out, buf + count, length - count);
+    while (count < length) {
+        int ret = adb_read(bulk_out, buf + count, length - count);
         if (ret < 0) {
-            if (errno != EINTR) {
-                D("[ bulk_read failed fd=%d length=%zu count=%zu ]\n",
-                                           bulk_out, length, count);
-                return ret;
-            }
-        } else {
-            count += ret;
+            D("[ bulk_read failed fd=%d length=%zu count=%zu ]\n", bulk_out, length, count);
+            return -1;
         }
-    } while (count < length);
+        count += ret;
+    }
 
     return count;
 }
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index 2ba3ff7..8037606 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -118,7 +118,7 @@
     IOUSBDeviceInterface197  **dev = NULL;
     HRESULT                  result;
     SInt32                   score;
-    UInt32                   locationId;
+    uint32_t                 locationId;
     UInt8                    if_class, subclass, protocol;
     UInt16                   vendor;
     UInt16                   product;
@@ -403,6 +403,7 @@
 
 void* RunLoopThread(void* unused)
 {
+    adb_thread_setname("RunLoop");
     InitUSB();
 
     currentRunLoop = CFRunLoopGetCurrent();
@@ -438,7 +439,7 @@
         adb_cond_init(&start_cond, NULL);
 
         if (!adb_thread_create(RunLoopThread, nullptr)) {
-            fatal_errno("cannot create input thread");
+            fatal_errno("cannot create RunLoop thread");
         }
 
         // Wait for initialization to finish
diff --git a/adb/usb_windows.cpp b/adb/usb_windows.cpp
index b8cc5cf..ab36475 100644
--- a/adb/usb_windows.cpp
+++ b/adb/usb_windows.cpp
@@ -171,6 +171,7 @@
 }
 
 void* device_poll_thread(void* unused) {
+  adb_thread_setname("Device Poll");
   D("Created device thread\n");
 
   while(1) {
@@ -208,6 +209,7 @@
   // of a developer's interactive session, a window message pump is more
   // appropriate.
   D("Created power notification thread\n");
+  adb_thread_setname("Power Notifier");
 
   // Window class names are process specific.
   static const WCHAR kPowerNotificationWindowClassName[] =
diff --git a/base/file.cpp b/base/file.cpp
index 9a340b7..3468dcf 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -28,6 +28,10 @@
 #include "cutils/log.h"
 #include "utils/Compat.h"
 
+#if !defined(_WIN32)
+#define O_BINARY 0
+#endif
+
 namespace android {
 namespace base {
 
@@ -45,8 +49,7 @@
 bool ReadFileToString(const std::string& path, std::string* content) {
   content->clear();
 
-  int fd =
-      TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
+  int fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
   if (fd == -1) {
     return false;
   }
@@ -80,9 +83,8 @@
 #if !defined(_WIN32)
 bool WriteStringToFile(const std::string& content, const std::string& path,
                        mode_t mode, uid_t owner, gid_t group) {
-  int fd = TEMP_FAILURE_RETRY(
-      open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
-           mode));
+  int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
+  int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
   if (fd == -1) {
     ALOGE("android::WriteStringToFile open failed: %s", strerror(errno));
     return false;
@@ -108,9 +110,8 @@
 #endif
 
 bool WriteStringToFile(const std::string& content, const std::string& path) {
-  int fd = TEMP_FAILURE_RETRY(
-      open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
-           DEFFILEMODE));
+  int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
+  int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, DEFFILEMODE));
   if (fd == -1) {
     return false;
   }
diff --git a/crash_reporter/user_collector.cc b/crash_reporter/user_collector.cc
index ee24648..61ccc37 100644
--- a/crash_reporter/user_collector.cc
+++ b/crash_reporter/user_collector.cc
@@ -24,6 +24,7 @@
 #include <stdint.h>
 #include <sys/cdefs.h>  // For __WORDSIZE
 #include <sys/types.h>  // For getpwuid_r, getgrnam_r, WEXITSTATUS.
+#include <unistd.h>  // For setgroups
 
 #include <string>
 #include <vector>
@@ -37,6 +38,7 @@
 #include <chromeos/process.h>
 #include <chromeos/syslog_logging.h>
 #include <cutils/properties.h>
+#include <private/android_filesystem_config.h>
 
 static const char kCollectionErrorSignature[] =
     "crash_reporter-user-collection";
@@ -77,6 +79,11 @@
   core2md_failure_ = core2md_failure;
   directory_failure_ = directory_failure;
   filter_in_ = filter_in;
+
+  gid_t groups[] = { AID_SYSTEM, AID_DBUS };
+  if (setgroups(arraysize(groups), groups) != 0) {
+    PLOG(FATAL) << "Unable to set groups to system and dbus";
+  }
 }
 
 UserCollector::~UserCollector() {
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index d8905a6..c1028ef 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -32,32 +32,27 @@
 #include <stdlib.h>
 #include <string.h>
 
-void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline)
+void bootimg_set_cmdline(boot_img_hdr* h, const char* cmdline)
 {
     strcpy((char*) h->cmdline, cmdline);
 }
 
-boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset,
-                        void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset,
-                        void *second, unsigned second_size, unsigned second_offset,
-                        unsigned page_size, unsigned base, unsigned tags_offset,
-                        unsigned *bootimg_size)
+boot_img_hdr* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offset,
+                        void* ramdisk, int64_t ramdisk_size, off_t ramdisk_offset,
+                        void* second, int64_t second_size, off_t second_offset,
+                        size_t page_size, size_t base, off_t tags_offset,
+                        int64_t* bootimg_size)
 {
-    unsigned kernel_actual;
-    unsigned ramdisk_actual;
-    unsigned second_actual;
-    unsigned page_mask;
+    size_t page_mask = page_size - 1;
 
-    page_mask = page_size - 1;
-
-    kernel_actual = (kernel_size + page_mask) & (~page_mask);
-    ramdisk_actual = (ramdisk_size + page_mask) & (~page_mask);
-    second_actual = (second_size + page_mask) & (~page_mask);
+    int64_t kernel_actual = (kernel_size + page_mask) & (~page_mask);
+    int64_t ramdisk_actual = (ramdisk_size + page_mask) & (~page_mask);
+    int64_t second_actual = (second_size + page_mask) & (~page_mask);
 
     *bootimg_size = page_size + kernel_actual + ramdisk_actual + second_actual;
 
     boot_img_hdr* hdr = reinterpret_cast<boot_img_hdr*>(calloc(*bootimg_size, 1));
-    if (hdr == 0) {
+    if (hdr == nullptr) {
         return hdr;
     }
 
@@ -74,12 +69,9 @@
 
     hdr->page_size =    page_size;
 
+    memcpy(hdr->magic + page_size, kernel, kernel_size);
+    memcpy(hdr->magic + page_size + kernel_actual, ramdisk, ramdisk_size);
+    memcpy(hdr->magic + page_size + kernel_actual + ramdisk_actual, second, second_size);
 
-    memcpy(hdr->magic + page_size,
-           kernel, kernel_size);
-    memcpy(hdr->magic + page_size + kernel_actual,
-           ramdisk, ramdisk_size);
-    memcpy(hdr->magic + page_size + kernel_actual + ramdisk_actual,
-           second, second_size);
     return hdr;
 }
diff --git a/fastboot/bootimg_utils.h b/fastboot/bootimg_utils.h
index b1a86cd..fcc8662 100644
--- a/fastboot/bootimg_utils.h
+++ b/fastboot/bootimg_utils.h
@@ -30,20 +30,14 @@
 #define _FASTBOOT_BOOTIMG_UTILS_H_
 
 #include <bootimg.h>
+#include <inttypes.h>
+#include <sys/types.h>
 
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
-boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset,
-                        void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset,
-                        void *second, unsigned second_size, unsigned second_offset,
-                        unsigned page_size, unsigned base, unsigned tags_offset,
-                        unsigned *bootimg_size);
-
-#if defined(__cplusplus)
-}
-#endif
+void bootimg_set_cmdline(boot_img_hdr* h, const char* cmdline);
+boot_img_hdr* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offset,
+                        void* ramdisk, int64_t ramdisk_size, off_t ramdisk_offset,
+                        void* second, int64_t second_size, off_t second_offset,
+                        size_t page_size, size_t base, off_t tags_offset,
+                        int64_t* bootimg_size);
 
 #endif
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 66b8140..a0e990a 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -31,7 +31,6 @@
 
 #include <errno.h>
 #include <stdarg.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -39,12 +38,6 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#ifdef USE_MINGW
-#include <fcntl.h>
-#else
-#include <sys/mman.h>
-#endif
-
 #define ARRAY_SIZE(x)           (sizeof(x)/sizeof(x[0]))
 
 #define OP_DOWNLOAD   1
@@ -58,15 +51,17 @@
 
 #define CMD_SIZE 64
 
-struct Action
-{
+struct Action {
     unsigned op;
-    Action *next;
+    Action* next;
 
     char cmd[CMD_SIZE];
-    const char *prod;
-    void *data;
-    unsigned size;
+    const char* prod;
+    void* data;
+
+    // The protocol only supports 32-bit sizes, so you'll have to break
+    // anything larger into chunks.
+    uint32_t size;
 
     const char *msg;
     int (*func)(Action* a, int status, const char* resp);
@@ -267,7 +262,7 @@
 }
 
 void fb_queue_require(const char *prod, const char *var,
-                      int invert, unsigned nvalues, const char **value)
+                      bool invert, size_t nvalues, const char **value)
 {
     Action *a;
     a = queue_action(OP_QUERY, "getvar:%s", var);
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 4dbf32f..e2971f2 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -34,7 +34,6 @@
 #include <getopt.h>
 #include <inttypes.h>
 #include <limits.h>
-#include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -67,12 +66,12 @@
 static int64_t sparse_limit = -1;
 static int64_t target_sparse_limit = -1;
 
-unsigned page_size = 2048;
-unsigned base_addr      = 0x10000000;
-unsigned kernel_offset  = 0x00008000;
-unsigned ramdisk_offset = 0x01000000;
-unsigned second_offset  = 0x00f00000;
-unsigned tags_offset    = 0x00000100;
+static unsigned page_size = 2048;
+static unsigned base_addr      = 0x10000000;
+static unsigned kernel_offset  = 0x00008000;
+static unsigned ramdisk_offset = 0x01000000;
+static unsigned second_offset  = 0x00f00000;
+static unsigned tags_offset    = 0x00000100;
 
 enum fb_buffer_type {
     FB_BUFFER,
@@ -81,8 +80,8 @@
 
 struct fastboot_buffer {
     enum fb_buffer_type type;
-    void *data;
-    unsigned int sz;
+    void* data;
+    int64_t sz;
 };
 
 static struct {
@@ -97,8 +96,7 @@
     {"vendor.img", "vendor.sig", "vendor", true},
 };
 
-char *find_item(const char *item, const char *product)
-{
+static char* find_item(const char* item, const char* product) {
     char *dir;
     const char *fn;
     char path[PATH_MAX + 128];
@@ -139,36 +137,26 @@
     return strdup(path);
 }
 
-static int64_t file_size(int fd)
-{
-    struct stat st;
-    int ret;
-
-    ret = fstat(fd, &st);
-
-    return ret ? -1 : st.st_size;
+static int64_t get_file_size(int fd) {
+    struct stat sb;
+    return fstat(fd, &sb) == -1 ? -1 : sb.st_size;
 }
 
-static void *load_fd(int fd, unsigned *_sz)
-{
-    char *data;
-    int sz;
+static void* load_fd(int fd, int64_t* sz) {
     int errno_tmp;
+    char* data = nullptr;
 
-    data = 0;
-
-    sz = file_size(fd);
-    if (sz < 0) {
+    *sz = get_file_size(fd);
+    if (*sz < 0) {
         goto oops;
     }
 
-    data = (char*) malloc(sz);
-    if(data == 0) goto oops;
+    data = (char*) malloc(*sz);
+    if (data == nullptr) goto oops;
 
-    if(read(fd, data, sz) != sz) goto oops;
+    if(read(fd, data, *sz) != *sz) goto oops;
     close(fd);
 
-    if(_sz) *_sz = sz;
     return data;
 
 oops:
@@ -179,17 +167,13 @@
     return 0;
 }
 
-static void *load_file(const char *fn, unsigned *_sz)
-{
-    int fd;
-
-    fd = open(fn, O_RDONLY | O_BINARY);
-    if(fd < 0) return 0;
-
-    return load_fd(fd, _sz);
+static void* load_file(const char* fn, int64_t* sz) {
+    int fd = open(fn, O_RDONLY | O_BINARY);
+    if (fd == -1) return nullptr;
+    return load_fd(fd, sz);
 }
 
-int match_fastboot_with_serial(usb_ifc_info* info, const char* local_serial) {
+static 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;
@@ -206,14 +190,12 @@
     return 0;
 }
 
-int match_fastboot(usb_ifc_info *info)
-{
+static int match_fastboot(usb_ifc_info* info) {
     return match_fastboot_with_serial(info, serial);
 }
 
-int list_devices_callback(usb_ifc_info *info)
-{
-    if (match_fastboot_with_serial(info, NULL) == 0) {
+static int list_devices_callback(usb_ifc_info* info) {
+    if (match_fastboot_with_serial(info, nullptr) == 0) {
         const char* serial = info->serial_number;
         if (!info->writable) {
             serial = "no permissions"; // like "adb devices"
@@ -234,8 +216,7 @@
     return -1;
 }
 
-usb_handle *open_device(void)
-{
+static usb_handle* open_device() {
     static usb_handle *usb = 0;
     int announce = 1;
 
@@ -252,15 +233,14 @@
     }
 }
 
-void list_devices(void) {
+static void list_devices() {
     // We don't actually open a USB device here,
     // just getting our callback called so we can
     // list all the connected devices.
     usb_open(list_devices_callback);
 }
 
-void usage(void)
-{
+static void usage() {
     fprintf(stderr,
 /*           1234567890123456789012345678901234567890123456789012345678901234567890123456 */
             "usage: fastboot [ <option> ] <command>\n"
@@ -315,31 +295,26 @@
         );
 }
 
-void *load_bootable_image(const char *kernel, const char *ramdisk,
-                          const char *secondstage, unsigned *sz,
-                          const char *cmdline)
-{
-    void *kdata = 0, *rdata = 0, *sdata = 0;
-    unsigned ksize = 0, rsize = 0, ssize = 0;
-    void *bdata;
-    unsigned bsize;
-
-    if(kernel == 0) {
+static void* load_bootable_image(const char* kernel, const char* ramdisk,
+                                 const char* secondstage, int64_t* sz,
+                                 const char* cmdline) {
+    if (kernel == nullptr) {
         fprintf(stderr, "no image specified\n");
         return 0;
     }
 
-    kdata = load_file(kernel, &ksize);
-    if(kdata == 0) {
+    int64_t ksize;
+    void* kdata = load_file(kernel, &ksize);
+    if (kdata == nullptr) {
         fprintf(stderr, "cannot load '%s': %s\n", kernel, strerror(errno));
         return 0;
     }
 
-        /* is this actually a boot image? */
+    // Is this actually a boot image?
     if(!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
-        if(cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
+        if (cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
 
-        if(ramdisk) {
+        if (ramdisk) {
             fprintf(stderr, "cannot boot a boot.img *and* ramdisk\n");
             return 0;
         }
@@ -348,39 +323,44 @@
         return kdata;
     }
 
-    if(ramdisk) {
+    void* rdata = nullptr;
+    int64_t rsize = 0;
+    if (ramdisk) {
         rdata = load_file(ramdisk, &rsize);
-        if(rdata == 0) {
+        if (rdata == nullptr) {
             fprintf(stderr,"cannot load '%s': %s\n", ramdisk, strerror(errno));
             return  0;
         }
     }
 
+    void* sdata = nullptr;
+    int64_t ssize = 0;
     if (secondstage) {
         sdata = load_file(secondstage, &ssize);
-        if(sdata == 0) {
+        if (sdata == nullptr) {
             fprintf(stderr,"cannot load '%s': %s\n", secondstage, strerror(errno));
             return  0;
         }
     }
 
     fprintf(stderr,"creating boot image...\n");
-    bdata = mkbootimg(kdata, ksize, kernel_offset,
+    int64_t bsize = 0;
+    void* bdata = mkbootimg(kdata, ksize, kernel_offset,
                       rdata, rsize, ramdisk_offset,
                       sdata, ssize, second_offset,
                       page_size, base_addr, tags_offset, &bsize);
-    if(bdata == 0) {
+    if (bdata == nullptr) {
         fprintf(stderr,"failed to create boot.img\n");
         return 0;
     }
-    if(cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline);
-    fprintf(stderr,"creating boot image - %d bytes\n", bsize);
+    if (cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline);
+    fprintf(stderr, "creating boot image - %" PRId64 " bytes\n", bsize);
     *sz = bsize;
 
     return bdata;
 }
 
-static void* unzip_file(ZipArchiveHandle zip, const char* entry_name, unsigned* sz)
+static void* unzip_file(ZipArchiveHandle zip, const char* entry_name, int64_t* sz)
 {
     ZipString zip_entry_name(entry_name);
     ZipEntry zip_entry;
@@ -392,8 +372,8 @@
     *sz = zip_entry.uncompressed_length;
 
     uint8_t* data = reinterpret_cast<uint8_t*>(malloc(zip_entry.uncompressed_length));
-    if (data == NULL) {
-        fprintf(stderr, "failed to allocate %u bytes for '%s'\n", *sz, entry_name);
+    if (data == nullptr) {
+        fprintf(stderr, "failed to allocate %" PRId64 " bytes for '%s'\n", *sz, entry_name);
         return 0;
     }
 
@@ -438,7 +418,7 @@
 
 static int unzip_to_file(ZipArchiveHandle zip, char* entry_name) {
     FILE* fp = tmpfile();
-    if (fp == NULL) {
+    if (fp == nullptr) {
         fprintf(stderr, "failed to create temporary file for '%s': %s\n",
                 entry_name, strerror(errno));
         return -1;
@@ -478,7 +458,7 @@
 static int setup_requirement_line(char *name)
 {
     char *val[MAX_OPTIONS];
-    char *prod = NULL;
+    char *prod = nullptr;
     unsigned n, count;
     char *x;
     int invert = 0;
@@ -539,13 +519,10 @@
     return 0;
 }
 
-static void setup_requirements(char *data, unsigned sz)
-{
-    char *s;
-
-    s = data;
+static void setup_requirements(char* data, int64_t sz) {
+    char* s = data;
     while (sz-- > 0) {
-        if(*s == '\n') {
+        if (*s == '\n') {
             *s++ = 0;
             if (setup_requirement_line(data)) {
                 die("out of memory");
@@ -557,8 +534,7 @@
     }
 }
 
-void queue_info_dump(void)
-{
+static void queue_info_dump() {
     fb_queue_notice("--------------------------------------------");
     fb_queue_display("version-bootloader", "Bootloader Version...");
     fb_queue_display("version-baseband",   "Baseband Version.....");
@@ -573,7 +549,7 @@
         die("cannot sparse read file\n");
     }
 
-    int files = sparse_file_resparse(s, max_size, NULL, 0);
+    int files = sparse_file_resparse(s, max_size, nullptr, 0);
     if (files < 0) {
         die("Failed to resparse\n");
     }
@@ -598,7 +574,7 @@
     int status = fb_getvar(usb, response, "max-download-size");
 
     if (!status) {
-        limit = strtoul(response, NULL, 0);
+        limit = strtoul(response, nullptr, 0);
         if (limit > 0) {
             fprintf(stderr, "target reported max download size of %" PRId64 " bytes\n",
                     limit);
@@ -643,35 +619,27 @@
     /* The function fb_format_supported() currently returns the value
      * we want, so just call it.
      */
-     return fb_format_supported(usb, part, NULL);
+     return fb_format_supported(usb, part, nullptr);
 }
 
-static int load_buf_fd(usb_handle *usb, int fd,
-        struct fastboot_buffer *buf)
-{
-    int64_t sz64;
-    void *data;
-    int64_t limit;
-
-
-    sz64 = file_size(fd);
-    if (sz64 < 0) {
+static int load_buf_fd(usb_handle* usb, int fd, struct fastboot_buffer* buf) {
+    int64_t sz = get_file_size(fd);
+    if (sz == -1) {
         return -1;
     }
 
-    lseek(fd, 0, SEEK_SET);
-    limit = get_sparse_limit(usb, sz64);
+    lseek64(fd, 0, SEEK_SET);
+    int64_t limit = get_sparse_limit(usb, sz);
     if (limit) {
-        struct sparse_file **s = load_sparse_files(fd, limit);
-        if (s == NULL) {
+        sparse_file** s = load_sparse_files(fd, limit);
+        if (s == nullptr) {
             return -1;
         }
         buf->type = FB_BUFFER_SPARSE;
         buf->data = s;
     } else {
-        unsigned int sz;
-        data = load_fd(fd, &sz);
-        if (data == 0) return -1;
+        void* data = load_fd(fd, &sz);
+        if (data == nullptr) return -1;
         buf->type = FB_BUFFER;
         buf->data = data;
         buf->sz = sz;
@@ -701,8 +669,8 @@
         case FB_BUFFER_SPARSE:
             s = reinterpret_cast<sparse_file**>(buf->data);
             while (*s) {
-                int64_t sz64 = sparse_file_len(*s, true, false);
-                fb_queue_flash_sparse(pname, *s++, sz64);
+                int64_t sz = sparse_file_len(*s, true, false);
+                fb_queue_flash_sparse(pname, *s++, sz);
             }
             break;
         case FB_BUFFER:
@@ -713,8 +681,7 @@
     }
 }
 
-void do_flash(usb_handle *usb, const char *pname, const char *fname)
-{
+static void do_flash(usb_handle* usb, const char* pname, const char* fname) {
     struct fastboot_buffer buf;
 
     if (load_buf(usb, fname, &buf)) {
@@ -723,17 +690,15 @@
     flash_buf(pname, &buf);
 }
 
-void do_update_signature(ZipArchiveHandle zip, char *fn)
-{
-    unsigned sz;
+static void do_update_signature(ZipArchiveHandle zip, char* fn) {
+    int64_t sz;
     void* data = unzip_file(zip, fn, &sz);
-    if (data == 0) return;
+    if (data == nullptr) return;
     fb_queue_download("signature", data, sz);
     fb_queue_command("signature", "installing signature");
 }
 
-void do_update(usb_handle *usb, const char *filename, int erase_first)
-{
+static void do_update(usb_handle* usb, const char* filename, bool erase_first) {
     queue_info_dump();
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
@@ -745,9 +710,9 @@
         die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
     }
 
-    unsigned sz;
+    int64_t sz;
     void* data = unzip_file(zip, "android-info.txt", &sz);
-    if (data == 0) {
+    if (data == nullptr) {
         CloseArchive(zip);
         die("update package '%s' has no android-info.txt", filename);
     }
@@ -780,36 +745,33 @@
     CloseArchive(zip);
 }
 
-void do_send_signature(char *fn)
-{
-    void *data;
-    unsigned sz;
-    char *xtn;
-
-    xtn = strrchr(fn, '.');
+static void do_send_signature(char* fn) {
+    char* xtn = strrchr(fn, '.');
     if (!xtn) return;
+
     if (strcmp(xtn, ".img")) return;
 
-    strcpy(xtn,".sig");
-    data = load_file(fn, &sz);
-    strcpy(xtn,".img");
-    if (data == 0) return;
+    strcpy(xtn, ".sig");
+
+    int64_t sz;
+    void* data = load_file(fn, &sz);
+    strcpy(xtn, ".img");
+    if (data == nullptr) return;
     fb_queue_download("signature", data, sz);
     fb_queue_command("signature", "installing signature");
 }
 
-void do_flashall(usb_handle *usb, int erase_first)
-{
+static void do_flashall(usb_handle* usb, int erase_first) {
     queue_info_dump();
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
 
     char* fname = find_item("info", product);
-    if (fname == 0) die("cannot find android-info.txt");
+    if (fname == nullptr) die("cannot find android-info.txt");
 
-    unsigned sz;
+    int64_t sz;
     void* data = load_file(fname, &sz);
-    if (data == 0) die("could not load android-info.txt: %s", strerror(errno));
+    if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno));
 
     setup_requirements(reinterpret_cast<char*>(data), sz);
 
@@ -832,8 +794,7 @@
 #define skip(n) do { argc -= (n); argv += (n); } while (0)
 #define require(n) do { if (argc < (n)) {usage(); exit(1);}} while (0)
 
-int do_oem_command(int argc, char **argv)
-{
+static int do_oem_command(int argc, char** argv) {
     char command[256];
     if (argc <= 1) return 0;
 
@@ -890,16 +851,15 @@
     return num;
 }
 
-void fb_perform_format(usb_handle* usb,
-                       const char *partition, int skip_if_not_supported,
-                       const char *type_override, const char *size_override)
-{
+static void fb_perform_format(usb_handle* usb,
+                              const char *partition, int skip_if_not_supported,
+                              const char *type_override, const char *size_override) {
     char pTypeBuff[FB_RESPONSE_SZ + 1], pSizeBuff[FB_RESPONSE_SZ + 1];
     char *pType = pTypeBuff;
     char *pSize = pSizeBuff;
     unsigned int limit = INT_MAX;
     struct fastboot_buffer buf;
-    const char *errMsg = NULL;
+    const char *errMsg = nullptr;
     const struct fs_generator *gen;
     uint64_t pSz;
     int status;
@@ -949,7 +909,7 @@
         return;
     }
 
-    pSz = strtoll(pSize, (char **)NULL, 16);
+    pSz = strtoll(pSize, (char **)nullptr, 16);
 
     fd = fileno(tmpfile());
     if (fs_generator_generate(gen, fd, pSz)) {
@@ -982,9 +942,9 @@
     int wants_wipe = 0;
     int wants_reboot = 0;
     int wants_reboot_bootloader = 0;
-    int erase_first = 1;
+    bool erase_first = true;
     void *data;
-    unsigned sz;
+    int64_t sz;
     int status;
     int c;
     int longindex;
@@ -1020,7 +980,7 @@
             usage();
             return 1;
         case 'i': {
-                char *endptr = NULL;
+                char *endptr = nullptr;
                 unsigned long val;
 
                 val = strtoul(optarg, &endptr, 0);
@@ -1036,7 +996,7 @@
             long_listing = 1;
             break;
         case 'n':
-            page_size = (unsigned)strtoul(optarg, NULL, 0);
+            page_size = (unsigned)strtoul(optarg, nullptr, 0);
             if (!page_size) die("invalid page size");
             break;
         case 'p':
@@ -1058,7 +1018,7 @@
             }
             break;
         case 'u':
-            erase_first = 0;
+            erase_first = false;
             break;
         case 'w':
             wants_wipe = 1;
@@ -1067,8 +1027,8 @@
             return 1;
         case 0:
             if (strcmp("unbuffered", longopts[longindex].name) == 0) {
-                setvbuf(stdout, NULL, _IONBF, 0);
-                setvbuf(stderr, NULL, _IONBF, 0);
+                setvbuf(stdout, nullptr, _IONBF, 0);
+                setvbuf(stderr, nullptr, _IONBF, 0);
             } else if (strcmp("version", longopts[longindex].name) == 0) {
                 fprintf(stdout, "fastboot version %s\n", FASTBOOT_REVISION);
                 return 0;
@@ -1108,7 +1068,7 @@
         } else if(!strcmp(*argv, "erase")) {
             require(2);
 
-            if (fb_format_supported(usb, argv[1], NULL)) {
+            if (fb_format_supported(usb, argv[1], nullptr)) {
                 fprintf(stderr, "******** Did you mean to fastboot format this partition?\n");
             }
 
@@ -1116,8 +1076,8 @@
             skip(2);
         } else if(!strncmp(*argv, "format", strlen("format"))) {
             char *overrides;
-            char *type_override = NULL;
-            char *size_override = NULL;
+            char *type_override = nullptr;
+            char *size_override = nullptr;
             require(2);
             /*
              * Parsing for: "format[:[type][:[size]]]"
@@ -1138,8 +1098,8 @@
                 }
                 type_override = overrides;
             }
-            if (type_override && !type_override[0]) type_override = NULL;
-            if (size_override && !size_override[0]) size_override = NULL;
+            if (type_override && !type_override[0]) type_override = nullptr;
+            if (size_override && !size_override[0]) size_override = nullptr;
             if (erase_first && needs_erase(usb, argv[1])) {
                 fb_queue_erase(argv[1]);
             }
@@ -1148,7 +1108,7 @@
         } else if(!strcmp(*argv, "signature")) {
             require(2);
             data = load_file(argv[1], &sz);
-            if (data == 0) die("could not load '%s': %s", argv[1], strerror(errno));
+            if (data == nullptr) die("could not load '%s': %s", argv[1], strerror(errno));
             if (sz != 256) die("signature must be 256 bytes");
             fb_queue_download("signature", data, sz);
             fb_queue_command("signature", "installing signature");
@@ -1258,9 +1218,9 @@
 
     if (wants_wipe) {
         fb_queue_erase("userdata");
-        fb_perform_format(usb, "userdata", 1, NULL, NULL);
+        fb_perform_format(usb, "userdata", 1, nullptr, nullptr);
         fb_queue_erase("cache");
-        fb_perform_format(usb, "cache", 1, NULL, NULL);
+        fb_perform_format(usb, "cache", 1, nullptr, nullptr);
     }
     if (wants_reboot) {
         fb_queue_reboot();
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 481c501..091a70f 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -29,18 +29,17 @@
 #ifndef _FASTBOOT_H_
 #define _FASTBOOT_H_
 
-#include "usb.h"
+#include <inttypes.h>
+#include <stdlib.h>
 
-#if defined(__cplusplus)
-extern "C" {
-#endif
+#include "usb.h"
 
 struct sparse_file;
 
 /* protocol.c - fastboot protocol */
 int fb_command(usb_handle *usb, const char *cmd);
 int fb_command_response(usb_handle *usb, const char *cmd, char *response);
-int fb_download_data(usb_handle *usb, const void *data, unsigned size);
+int fb_download_data(usb_handle *usb, const void *data, uint32_t size);
 int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s);
 char *fb_get_error(void);
 
@@ -50,17 +49,17 @@
 /* engine.c - high level command queue engine */
 int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...);
 int fb_format_supported(usb_handle *usb, const char *partition, const char *type_override);
-void fb_queue_flash(const char *ptn, void *data, unsigned sz);
-void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz);
+void fb_queue_flash(const char *ptn, void *data, uint32_t sz);
+void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, uint32_t sz);
 void fb_queue_erase(const char *ptn);
-void fb_queue_format(const char *ptn, int skip_if_not_supported, unsigned int max_chunk_sz);
-void fb_queue_require(const char *prod, const char *var, int invert,
-        unsigned nvalues, const char **value);
+void fb_queue_format(const char *ptn, int skip_if_not_supported, int32_t max_chunk_sz);
+void fb_queue_require(const char *prod, const char *var, bool invert,
+                      size_t nvalues, const char **value);
 void fb_queue_display(const char *var, const char *prettyname);
-void fb_queue_query_save(const char *var, char *dest, unsigned dest_size);
+void fb_queue_query_save(const char *var, char *dest, uint32_t dest_size);
 void fb_queue_reboot(void);
 void fb_queue_command(const char *cmd, const char *msg);
-void fb_queue_download(const char *name, void *data, unsigned size);
+void fb_queue_download(const char *name, void *data, uint32_t size);
 void fb_queue_notice(const char *notice);
 void fb_queue_wait_for_disconnect(void);
 int fb_execute_queue(usb_handle *usb);
@@ -76,8 +75,4 @@
 /* Current product */
 extern char cur_product[FB_RESPONSE_SZ + 1];
 
-#if defined(__cplusplus)
-}
-#endif
-
 #endif
diff --git a/fastboot/fastboot_protocol.txt b/fastboot/fastboot_protocol.txt
index 37b1959..bb73d8a 100644
--- a/fastboot/fastboot_protocol.txt
+++ b/fastboot/fastboot_protocol.txt
@@ -41,7 +41,7 @@
 
    d. DATA -> the requested command is ready for the data phase.
       A DATA response packet will be 12 bytes long, in the form of
-      DATA00000000 where the 8 digit hexidecimal number represents
+      DATA00000000 where the 8 digit hexadecimal number represents
       the total data size to transfer.
 
 3. Data phase.  Depending on the command, the host or client will 
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index d8f9e16..c58a505 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -6,21 +6,12 @@
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdarg.h>
-#include <stdbool.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <sparse/sparse.h>
 #include <unistd.h>
 
-#ifdef USE_MINGW
-#include <fcntl.h>
-#else
-#include <sys/mman.h>
-#endif
-
-
+#include <sparse/sparse.h>
 
 static int generate_ext4_image(int fd, long long partSize)
 {
@@ -48,15 +39,13 @@
 #endif
 };
 
-const struct fs_generator* fs_get_generator(const char *fs_type)
-{
-    unsigned i;
-
-    for (i = 0; i < sizeof(generators) / sizeof(*generators); i++)
-        if (!strcmp(generators[i].fs_type, fs_type))
+const struct fs_generator* fs_get_generator(const char* fs_type) {
+    for (size_t i = 0; i < sizeof(generators) / sizeof(*generators); i++) {
+        if (strcmp(generators[i].fs_type, fs_type) == 0) {
             return generators + i;
-
-    return NULL;
+        }
+    }
+    return nullptr;
 }
 
 int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize)
diff --git a/fastboot/fs.h b/fastboot/fs.h
index 307772b..8444081 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -3,18 +3,10 @@
 
 #include <stdint.h>
 
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
 struct fs_generator;
 
 const struct fs_generator* fs_get_generator(const char *fs_type);
 int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize);
 
-#if defined(__cplusplus)
-}
-#endif
-
 #endif
 
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
index 00c8a03..cbd48e8 100644
--- a/fastboot/protocol.cpp
+++ b/fastboot/protocol.cpp
@@ -26,8 +26,6 @@
  * SUCH DAMAGE.
  */
 
-#define min(a, b) \
-    ({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; })
 #define round_down(a, b) \
     ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); })
 
@@ -36,6 +34,8 @@
 #include <string.h>
 #include <errno.h>
 
+#include <algorithm>
+
 #include <sparse/sparse.h>
 
 #include "fastboot.h"
@@ -47,40 +47,38 @@
     return ERROR;
 }
 
-static int check_response(usb_handle *usb, unsigned int size, char *response)
-{
-    unsigned char status[65];
-    int r;
+static int check_response(usb_handle* usb, uint32_t size, char* response) {
+    char status[65];
 
-    for(;;) {
-        r = usb_read(usb, status, 64);
-        if(r < 0) {
+    while (true) {
+        int r = usb_read(usb, status, 64);
+        if (r < 0) {
             sprintf(ERROR, "status read failed (%s)", strerror(errno));
             usb_close(usb);
             return -1;
         }
         status[r] = 0;
 
-        if(r < 4) {
+        if (r < 4) {
             sprintf(ERROR, "status malformed (%d bytes)", r);
             usb_close(usb);
             return -1;
         }
 
-        if(!memcmp(status, "INFO", 4)) {
+        if (!memcmp(status, "INFO", 4)) {
             fprintf(stderr,"(bootloader) %s\n", status + 4);
             continue;
         }
 
-        if(!memcmp(status, "OKAY", 4)) {
-            if(response) {
+        if (!memcmp(status, "OKAY", 4)) {
+            if (response) {
                 strcpy(response, (char*) status + 4);
             }
             return 0;
         }
 
-        if(!memcmp(status, "FAIL", 4)) {
-            if(r > 4) {
+        if (!memcmp(status, "FAIL", 4)) {
+            if (r > 4) {
                 sprintf(ERROR, "remote: %s", status + 4);
             } else {
                 strcpy(ERROR, "remote failure");
@@ -88,9 +86,9 @@
             return -1;
         }
 
-        if(!memcmp(status, "DATA", 4) && size > 0){
-            unsigned dsize = strtoul((char*) status + 4, 0, 16);
-            if(dsize > size) {
+        if (!memcmp(status, "DATA", 4) && size > 0){
+            uint32_t dsize = strtol(status + 4, 0, 16);
+            if (dsize > size) {
                 strcpy(ERROR, "data size too large");
                 usb_close(usb);
                 return -1;
@@ -106,22 +104,19 @@
     return -1;
 }
 
-static int _command_start(usb_handle *usb, const char *cmd, unsigned size,
-                          char *response)
-{
-    int cmdsize = strlen(cmd);
-
-    if(response) {
-        response[0] = 0;
-    }
-
-    if(cmdsize > 64) {
-        sprintf(ERROR,"command too large");
+static int _command_start(usb_handle* usb, const char* cmd, uint32_t size, char* response) {
+    size_t cmdsize = strlen(cmd);
+    if (cmdsize > 64) {
+        sprintf(ERROR, "command too large");
         return -1;
     }
 
-    if(usb_write(usb, cmd, cmdsize) != cmdsize) {
-        sprintf(ERROR,"command write failed (%s)", strerror(errno));
+    if (response) {
+        response[0] = 0;
+    }
+
+    if (usb_write(usb, cmd, cmdsize) != static_cast<int>(cmdsize)) {
+        sprintf(ERROR, "command write failed (%s)", strerror(errno));
         usb_close(usb);
         return -1;
     }
@@ -129,45 +124,32 @@
     return check_response(usb, size, response);
 }
 
-static int _command_data(usb_handle *usb, const void *data, unsigned size)
-{
-    int r;
-
-    r = usb_write(usb, data, size);
-    if(r < 0) {
+static int _command_data(usb_handle* usb, const void* data, uint32_t size) {
+    int r = usb_write(usb, data, size);
+    if (r < 0) {
         sprintf(ERROR, "data transfer failure (%s)", strerror(errno));
         usb_close(usb);
         return -1;
     }
-    if(r != ((int) size)) {
+    if (r != ((int) size)) {
         sprintf(ERROR, "data transfer failure (short transfer)");
         usb_close(usb);
         return -1;
     }
-
     return r;
 }
 
-static int _command_end(usb_handle *usb)
-{
-    int r;
-    r = check_response(usb, 0, 0);
-    if(r < 0) {
-        return -1;
-    }
-    return 0;
+static int _command_end(usb_handle* usb) {
+    return check_response(usb, 0, 0) < 0 ? -1 : 0;
 }
 
-static int _command_send(usb_handle *usb, const char *cmd,
-                         const void *data, unsigned size,
-                         char *response)
-{
-    int r;
+static int _command_send(usb_handle* usb, const char* cmd, const void* data, uint32_t size,
+                         char* response) {
     if (size == 0) {
         return -1;
     }
 
-    r = _command_start(usb, cmd, size, response);
+    int r = _command_start(usb, cmd, size, response);
     if (r < 0) {
         return -1;
     }
@@ -178,42 +160,29 @@
     }
 
     r = _command_end(usb);
-    if(r < 0) {
+    if (r < 0) {
         return -1;
     }
 
     return size;
 }
 
-static int _command_send_no_data(usb_handle *usb, const char *cmd,
-                                 char *response)
-{
+static int _command_send_no_data(usb_handle* usb, const char* cmd, char* response) {
     return _command_start(usb, cmd, 0, response);
 }
 
-int fb_command(usb_handle *usb, const char *cmd)
-{
+int fb_command(usb_handle* usb, const char* cmd) {
     return _command_send_no_data(usb, cmd, 0);
 }
 
-int fb_command_response(usb_handle *usb, const char *cmd, char *response)
-{
+int fb_command_response(usb_handle* usb, const char* cmd, char* response) {
     return _command_send_no_data(usb, cmd, response);
 }
 
-int fb_download_data(usb_handle *usb, const void *data, unsigned size)
-{
+int fb_download_data(usb_handle* usb, const void* data, uint32_t size) {
     char cmd[64];
-    int r;
-
     sprintf(cmd, "download:%08x", size);
-    r = _command_send(usb, cmd, data, size, 0);
-
-    if(r < 0) {
-        return -1;
-    } else {
-        return 0;
-    }
+    return _command_send(usb, cmd, data, size, 0) < 0 ? -1 : 0;
 }
 
 #define USB_BUF_SIZE 1024
@@ -228,7 +197,7 @@
     const char* ptr = reinterpret_cast<const char*>(data);
 
     if (usb_buf_len) {
-        to_write = min(USB_BUF_SIZE - usb_buf_len, len);
+        to_write = std::min(USB_BUF_SIZE - usb_buf_len, len);
 
         memcpy(usb_buf + usb_buf_len, ptr, to_write);
         usb_buf_len += to_write;
@@ -270,32 +239,25 @@
     return 0;
 }
 
-static int fb_download_data_sparse_flush(usb_handle *usb)
-{
-    int r;
-
+static int fb_download_data_sparse_flush(usb_handle* usb) {
     if (usb_buf_len > 0) {
-        r = _command_data(usb, usb_buf, usb_buf_len);
-        if (r != usb_buf_len) {
+        if (_command_data(usb, usb_buf, usb_buf_len) != usb_buf_len) {
             return -1;
         }
         usb_buf_len = 0;
     }
-
     return 0;
 }
 
-int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s)
-{
-    char cmd[64];
-    int r;
+int fb_download_data_sparse(usb_handle* usb, struct sparse_file* s) {
     int size = sparse_file_len(s, true, false);
     if (size <= 0) {
         return -1;
     }
 
+    char cmd[64];
     sprintf(cmd, "download:%08x", size);
-    r = _command_start(usb, cmd, size, 0);
+    int r = _command_start(usb, cmd, size, 0);
     if (r < 0) {
         return -1;
     }
diff --git a/fastboot/usb.h b/fastboot/usb.h
index c7b748e..0fda41a 100644
--- a/fastboot/usb.h
+++ b/fastboot/usb.h
@@ -29,16 +29,9 @@
 #ifndef _USB_H_
 #define _USB_H_
 
-#if defined(__cplusplus)
-extern "C" {
-#endif
+struct usb_handle;
 
-typedef struct usb_handle usb_handle;
-
-typedef struct usb_ifc_info usb_ifc_info;
-
-struct usb_ifc_info
-{
+struct usb_ifc_info {
         /* from device descriptor */
     unsigned short dev_vendor;
     unsigned short dev_product;
@@ -68,8 +61,4 @@
 int usb_write(usb_handle *h, const void *_data, int len);
 int usb_wait_for_disconnect(usb_handle *h);
 
-#if defined(__cplusplus)
-}
-#endif
-
 #endif
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 8b0f714..d77d41f 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -20,6 +20,8 @@
 #include <string.h>
 #include <sys/mount.h>
 
+#include <cutils/properties.h>
+
 #include "fs_mgr_priv.h"
 
 struct fs_mgr_flag_values {
@@ -70,6 +72,7 @@
     { "zramsize=",   MF_ZRAMSIZE },
     { "verify",      MF_VERIFY },
     { "noemulatedsd", MF_NOEMULATEDSD },
+    { "slotselect",  MF_SLOTSELECT },
     { "defaults",    0 },
     { 0,             0 },
 };
@@ -307,6 +310,23 @@
         fstab->recs[cnt].partnum = flag_vals.partnum;
         fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
         fstab->recs[cnt].zram_size = flag_vals.zram_size;
+
+        /* If an A/B partition, modify block device to be the real block device */
+        if (fstab->recs[cnt].fs_mgr_flags & MF_SLOTSELECT) {
+            char propbuf[PROPERTY_VALUE_MAX];
+            char *tmp;
+
+            /* use the kernel parameter if set */
+            property_get("ro.boot.slot_suffix", propbuf, "");
+
+            if (asprintf(&tmp, "%s%s", fstab->recs[cnt].blk_device, propbuf) > 0) {
+                free(fstab->recs[cnt].blk_device);
+                fstab->recs[cnt].blk_device = tmp;
+            } else {
+                ERROR("Error updating block device name\n");
+                goto err;
+            }
+        }
         cnt++;
     }
     fclose(fstab_file);
@@ -448,3 +468,8 @@
 {
     return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
 }
+
+int fs_mgr_is_slotselect(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_SLOTSELECT;
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index d56111a..cc02bac 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -77,6 +77,7 @@
 #define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only
                                  external storage */
 #define MF_FILEENCRYPTION 0x2000
+#define MF_SLOTSELECT   0x8000
 
 #define DM_BUF_SIZE 4096
 
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index ed773d0..e280fdc 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -194,6 +194,15 @@
         getIntField(mHealthdConfig->batteryCapacityPath);
     props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
 
+    if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
+        props.batteryCurrent = getIntField(mHealthdConfig->batteryCurrentNowPath) / 1000;
+
+    if (!mHealthdConfig->batteryFullChargePath.isEmpty())
+        props.batteryFullCharge = getIntField(mHealthdConfig->batteryFullChargePath);
+
+    if (!mHealthdConfig->batteryCycleCountPath.isEmpty())
+        props.batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
+
     props.batteryTemperature = mBatteryFixedTemperature ?
         mBatteryFixedTemperature :
         getIntField(mHealthdConfig->batteryTemperaturePath);
@@ -245,7 +254,7 @@
 
     if (logthis) {
         char dmesgline[256];
-
+        size_t len;
         if (props.batteryPresent) {
             snprintf(dmesgline, sizeof(dmesgline),
                  "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
@@ -255,19 +264,27 @@
                  abs(props.batteryTemperature % 10), props.batteryHealth,
                  props.batteryStatus);
 
+            len = strlen(dmesgline);
             if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
-                int c = getIntField(mHealthdConfig->batteryCurrentNowPath);
-                char b[20];
+                len += snprintf(dmesgline + len, sizeof(dmesgline) - len,
+                                " c=%d", props.batteryCurrent);
+            }
 
-                snprintf(b, sizeof(b), " c=%d", c / 1000);
-                strlcat(dmesgline, b, sizeof(dmesgline));
+            if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
+                len += snprintf(dmesgline + len, sizeof(dmesgline) - len,
+                                " fc=%d", props.batteryFullCharge);
+            }
+
+            if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
+                len += snprintf(dmesgline + len, sizeof(dmesgline) - len,
+                                " cc=%d", props.batteryCycleCount);
             }
         } else {
             snprintf(dmesgline, sizeof(dmesgline),
                  "battery none");
         }
 
-        size_t len = strlen(dmesgline);
+        len = strlen(dmesgline);
         snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
                  props.chargerAcOnline ? "a" : "",
                  props.chargerUsbOnline ? "u" : "",
@@ -394,6 +411,21 @@
         snprintf(vs, sizeof(vs), "charge counter: %d\n", v);
         write(fd, vs, strlen(vs));
     }
+
+    if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+        snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrent);
+        write(fd, vs, strlen(vs));
+    }
+
+    if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
+        snprintf(vs, sizeof(vs), "cycle count: %d\n", props.batteryCycleCount);
+        write(fd, vs, strlen(vs));
+    }
+
+    if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
+        snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullCharge);
+        write(fd, vs, strlen(vs));
+    }
 }
 
 void BatteryMonitor::init(struct healthd_config *hc) {
@@ -476,6 +508,14 @@
                     }
                 }
 
+                if (mHealthdConfig->batteryFullChargePath.isEmpty()) {
+                    path.clear();
+                    path.appendFormat("%s/%s/charge_full",
+                                      POWER_SUPPLY_SYSFS_PATH, name);
+                    if (access(path, R_OK) == 0)
+                        mHealthdConfig->batteryFullChargePath = path;
+                }
+
                 if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
                     path.clear();
                     path.appendFormat("%s/%s/current_now",
@@ -484,6 +524,14 @@
                         mHealthdConfig->batteryCurrentNowPath = path;
                 }
 
+                if (mHealthdConfig->batteryCycleCountPath.isEmpty()) {
+                    path.clear();
+                    path.appendFormat("%s/%s/cycle_count",
+                                      POWER_SUPPLY_SYSFS_PATH, name);
+                    if (access(path, R_OK) == 0)
+                        mHealthdConfig->batteryCycleCountPath = path;
+                }
+
                 if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
                     path.clear();
                     path.appendFormat("%s/%s/current_avg",
@@ -553,6 +601,12 @@
             KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
         if (mHealthdConfig->batteryTechnologyPath.isEmpty())
             KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
+	if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n");
+        if (mHealthdConfig->batteryFullChargePath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n");
+        if (mHealthdConfig->batteryCycleCountPath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryCycleCountPath not found\n");
     }
 
     if (property_get("ro.boot.fake_battery", pval, NULL) > 0
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index 1fee855..cc6824a 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -52,6 +52,8 @@
     .batteryCurrentNowPath = String8(String8::kEmptyString),
     .batteryCurrentAvgPath = String8(String8::kEmptyString),
     .batteryChargeCounterPath = String8(String8::kEmptyString),
+    .batteryFullChargePath = String8(String8::kEmptyString),
+    .batteryCycleCountPath = String8(String8::kEmptyString),
     .energyCounter = NULL,
     .screen_on = NULL,
 };
diff --git a/healthd/healthd.h b/healthd/healthd.h
index 4704f0b..048fcd5 100644
--- a/healthd/healthd.h
+++ b/healthd/healthd.h
@@ -65,6 +65,8 @@
     android::String8 batteryCurrentNowPath;
     android::String8 batteryCurrentAvgPath;
     android::String8 batteryChargeCounterPath;
+    android::String8 batteryFullChargePath;
+    android::String8 batteryCycleCountPath;
 
     int (*energyCounter)(int64_t *);
     bool (*screen_on)(android::BatteryProperties *props);
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index 6d9b3bc..9c077d6 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -71,7 +71,7 @@
 #define ATRACE_TAG_LAST             ATRACE_TAG_PACKAGE_MANAGER
 
 // Reserved for initialization.
-#define ATRACE_TAG_NOT_READY        (1LL<<63)
+#define ATRACE_TAG_NOT_READY        (1ULL<<63)
 
 #define ATRACE_TAG_VALID_MASK ((ATRACE_TAG_LAST - 1) | ATRACE_TAG_LAST)
 
diff --git a/include/log/log.h b/include/log/log.h
index 0b17574..1cdf7bc 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -563,6 +563,12 @@
 #define android_btWriteLog(tag, type, payload, len) \
     __android_log_btwrite(tag, type, payload, len)
 
+#define android_errorWriteLog(tag, subTag) \
+    __android_log_error_write(tag, subTag, -1, NULL, 0)
+
+#define android_errorWriteWithInfoLog(tag, subTag, uid, data, dataLen) \
+    __android_log_error_write(tag, subTag, uid, data, dataLen)
+
 /*
  *    IF_ALOG uses android_testLog, but IF_ALOG can be overridden.
  *    android_testLog will remain constant in its purpose as a wrapper
@@ -612,6 +618,9 @@
  */
 int __android_log_is_loggable(int prio, const char *tag, int def);
 
+int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data,
+                              uint32_t dataLen);
+
 /*
  * Send a simple string to the log.
  */
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 5330949..f9060c4 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -123,6 +123,8 @@
 LOCAL_C_INCLUDES := $(libcutils_c_includes)
 LOCAL_STATIC_LIBRARIES := liblog
 LOCAL_CFLAGS += -Werror -Wall -Wextra -std=gnu90
+LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -133,6 +135,8 @@
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_CFLAGS += -Werror -Wall -Wextra
 LOCAL_C_INCLUDES := $(libcutils_c_includes)
+LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libcutils/arch-mips/android_memset.c b/libcutils/arch-mips/android_memset.c
index a6b7496..c0fe3d1 100644
--- a/libcutils/arch-mips/android_memset.c
+++ b/libcutils/arch-mips/android_memset.c
@@ -30,6 +30,9 @@
 
 #include <cutils/memory.h>
 
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
 void android_memset16(uint16_t* dst, uint16_t value, size_t size)
 {
    /* optimized version of
@@ -46,7 +49,7 @@
    }
    /* dst is now 32-bit-aligned */
    /* fill body with 32-bit pairs */
-   uint32_t value32 = (value << 16) | value;
+   uint32_t value32 = (((uint32_t)value) << 16) | ((uint32_t)value);
    android_memset32((uint32_t*) dst, value32, size<<1);
    if (size & 1) {
       dst[size-1] = value;  /* fill unpaired last elem */
@@ -54,6 +57,9 @@
 }
 
 
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
 void android_memset32(uint32_t* dst, uint32_t value, size_t size)
 {
    /* optimized version of
@@ -70,7 +76,7 @@
    }
    /* dst is now 64-bit aligned */
    /* fill body with 64-bit pairs */
-   uint64_t value64 = (((uint64_t)value)<<32) | value;
+   uint64_t value64 = (((uint64_t)value) << 32) | ((uint64_t)value);
    uint64_t* dst64 = (uint64_t*)dst;
 
    while (size >= 12) {
@@ -86,7 +92,8 @@
 
    /* fill remainder with original 32-bit single-elem loop */
    dst = (uint32_t*) dst64;
-   while (size--) {
+   while (size != 0) {
+       size--;
       *dst++ = value;
    }
 
diff --git a/libcutils/hashmap.c b/libcutils/hashmap.c
index 65539ea..ede3b98 100644
--- a/libcutils/hashmap.c
+++ b/libcutils/hashmap.c
@@ -77,6 +77,9 @@
 /**
  * Hashes the given key.
  */
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
 static inline int hashKey(Hashmap* map, void* key) {
     int h = map->hash(key);
 
@@ -152,6 +155,10 @@
     free(map);
 }
 
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
+/* FIXME: relies on signed integer overflow, which is undefined behavior */
 int hashmapHash(void* key, size_t keySize) {
     int h = keySize;
     char* data = (char*) key;
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
index 924289a..4f23d09 100644
--- a/libcutils/str_parms.c
+++ b/libcutils/str_parms.c
@@ -42,6 +42,9 @@
 }
 
 /* use djb hash unless we find it inadequate */
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
 static int str_hash_fn(void *str)
 {
     uint32_t hash = 5381;
diff --git a/libcutils/strdup16to8.c b/libcutils/strdup16to8.c
index 1a8ba86..4dc987e 100644
--- a/libcutils/strdup16to8.c
+++ b/libcutils/strdup16to8.c
@@ -55,7 +55,8 @@
     /* Fast path for the usual case where 3*len is < SIZE_MAX-1.
      */
     if (len < (SIZE_MAX-1)/3) {
-        while (len--) {
+        while (len != 0) {
+            len--;
             unsigned int uic = *utf16Str++;
 
             if (uic > 0x07ff)
@@ -69,7 +70,8 @@
     }
 
     /* The slower but paranoid version */
-    while (len--) {
+    while (len != 0) {
+        len--;
         unsigned int  uic     = *utf16Str++;
         size_t        utf8Cur = utf8Len;
 
@@ -112,7 +114,8 @@
      * strnlen16to8() properly or at a minimum checked the result of
      * its malloc(SIZE_MAX) in case of overflow.
      */
-    while (len--) {
+    while (len != 0) {
+        len--;
         unsigned int uic = *utf16Str++;
 
         if (uic > 0x07ff) {
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 930dcf7..5eed634 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -24,7 +24,7 @@
 # so make sure we do not regret hard-coding it as follows:
 liblog_cflags := -DLIBLOG_LOG_TAG=1005
 
-liblog_sources := logd_write.c
+liblog_sources := logd_write.c log_event_write.c
 
 # some files must not be compiled when building against Mingw
 # they correspond to features not used by our host development tools
diff --git a/liblog/log_event_write.c b/liblog/log_event_write.c
new file mode 100644
index 0000000..0bc42d5
--- /dev/null
+++ b/liblog/log_event_write.c
@@ -0,0 +1,88 @@
+/*
+ * 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 <errno.h>
+#include <string.h>
+
+#include <log/log.h>
+#include <log/logger.h>
+
+#define MAX_EVENT_PAYLOAD 512
+#define MAX_SUBTAG_LEN 32
+
+static inline void copy4LE(uint8_t *buf, size_t pos, int val)
+{
+    buf[pos] = val & 0xFF;
+    buf[pos+1] = (val >> 8) & 0xFF;
+    buf[pos+2] = (val >> 16) & 0xFF;
+    buf[pos+3] = (val >> 24) & 0xFF;
+}
+
+int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data,
+                              uint32_t dataLen)
+{
+    uint8_t buf[MAX_EVENT_PAYLOAD];
+    size_t pos = 0;
+    uint32_t subTagLen = 0;
+    uint32_t roomLeftForData = 0;
+
+    if ((subTag == NULL) || ((data == NULL) && (dataLen != 0))) return -EINVAL;
+
+    subTagLen = strlen(subTag);
+
+    // Truncate subtags that are too long.
+    subTagLen = subTagLen > MAX_SUBTAG_LEN ? MAX_SUBTAG_LEN : subTagLen;
+
+    // Truncate dataLen if it is too long.
+    roomLeftForData = MAX_EVENT_PAYLOAD -
+            (1 + // EVENT_TYPE_LIST
+             1 + // Number of elements in list
+             1 + // EVENT_TYPE_STRING
+             sizeof(subTagLen) +
+             subTagLen +
+             1 + // EVENT_TYPE_INT
+             sizeof(uid) +
+             1 + // EVENT_TYPE_STRING
+             sizeof(dataLen));
+    dataLen = dataLen > roomLeftForData ? roomLeftForData : dataLen;
+
+    buf[pos++] = EVENT_TYPE_LIST;
+    buf[pos++] = 3; // Number of elements in the list (subTag, uid, data)
+
+    // Write sub tag.
+    buf[pos++] = EVENT_TYPE_STRING;
+    copy4LE(buf, pos, subTagLen);
+    pos += 4;
+    memcpy(&buf[pos], subTag, subTagLen);
+    pos += subTagLen;
+
+    // Write UID.
+    buf[pos++] = EVENT_TYPE_INT;
+    copy4LE(buf, pos, uid);
+    pos += 4;
+
+    // Write data.
+    buf[pos++] = EVENT_TYPE_STRING;
+    copy4LE(buf, pos, dataLen);
+    pos += 4;
+    if (dataLen != 0)
+    {
+        memcpy(&buf[pos], data, dataLen);
+        pos += dataLen;
+    }
+
+    return __android_log_bwrite(tag, buf, pos);
+}
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index abe0239..c987041 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -17,6 +17,7 @@
 #include <fcntl.h>
 #include <inttypes.h>
 #include <signal.h>
+#include <string.h>
 
 #include <cutils/properties.h>
 #include <gtest/gtest.h>
@@ -876,3 +877,398 @@
     property_set(key, hold[2]);
     property_set(key + base_offset, hold[3]);
 }
+
+static inline int32_t get4LE(const char* src)
+{
+    return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+}
+
+TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__typical) {
+    const int TAG = 123456781;
+    const char SUBTAG[] = "test-subtag";
+    const int UID = -1;
+    const int DATA_LEN = 200;
+    struct logger_list *logger_list;
+
+    pid_t pid = getpid();
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+    ASSERT_LT(0, android_errorWriteWithInfoLog(
+            TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
+
+    sleep(2);
+
+    int count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        char *eventData = log_msg.msg();
+
+        // Tag
+        int tag = get4LE(eventData);
+        eventData += 4;
+
+        if (tag != TAG) {
+            continue;
+        }
+
+        // List type
+        ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
+        eventData++;
+
+        // Number of elements in list
+        ASSERT_EQ(3, eventData[0]);
+        eventData++;
+
+        // Element #1: string type for subtag
+        ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+        eventData++;
+
+        ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
+        eventData +=4;
+
+        if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
+            continue;
+        }
+        eventData += strlen(SUBTAG);
+
+        // Element #2: int type for uid
+        ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
+        eventData++;
+
+        ASSERT_EQ(UID, get4LE(eventData));
+        eventData += 4;
+
+        // Element #3: string type for data
+        ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+        eventData++;
+
+        ASSERT_EQ(DATA_LEN, get4LE(eventData));
+        eventData += 4;
+
+        if (memcmp(max_payload_buf, eventData, DATA_LEN)) {
+            continue;
+        }
+
+        ++count;
+    }
+
+    EXPECT_EQ(1, count);
+
+    android_logger_list_close(logger_list);
+}
+
+TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__data_too_large) {
+    const int TAG = 123456782;
+    const char SUBTAG[] = "test-subtag";
+    const int UID = -1;
+    const int DATA_LEN = sizeof(max_payload_buf);
+    struct logger_list *logger_list;
+
+    pid_t pid = getpid();
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+    ASSERT_LT(0, android_errorWriteWithInfoLog(
+            TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
+
+    sleep(2);
+
+    int count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        char *eventData = log_msg.msg();
+        char *original = eventData;
+
+        // Tag
+        int tag = get4LE(eventData);
+        eventData += 4;
+
+        if (tag != TAG) {
+            continue;
+        }
+
+        // List type
+        ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
+        eventData++;
+
+        // Number of elements in list
+        ASSERT_EQ(3, eventData[0]);
+        eventData++;
+
+        // Element #1: string type for subtag
+        ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+        eventData++;
+
+        ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
+        eventData +=4;
+
+        if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
+            continue;
+        }
+        eventData += strlen(SUBTAG);
+
+        // Element #2: int type for uid
+        ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
+        eventData++;
+
+        ASSERT_EQ(UID, get4LE(eventData));
+        eventData += 4;
+
+        // Element #3: string type for data
+        ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+        eventData++;
+
+        size_t dataLen = get4LE(eventData);
+        eventData += 4;
+
+        if (memcmp(max_payload_buf, eventData, dataLen)) {
+            continue;
+        }
+        eventData += dataLen;
+
+        // 4 bytes for the tag, and 512 bytes for the log since the max_payload_buf should be
+        // truncated.
+        ASSERT_EQ(4 + 512, eventData - original);
+
+        ++count;
+    }
+
+    EXPECT_EQ(1, count);
+
+    android_logger_list_close(logger_list);
+}
+
+TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__null_data) {
+    const int TAG = 123456783;
+    const char SUBTAG[] = "test-subtag";
+    const int UID = -1;
+    const int DATA_LEN = 200;
+    struct logger_list *logger_list;
+
+    pid_t pid = getpid();
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+    ASSERT_GT(0, android_errorWriteWithInfoLog(
+            TAG, SUBTAG, UID, NULL, DATA_LEN));
+
+    sleep(2);
+
+    int count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        char *eventData = log_msg.msg();
+
+        // Tag
+        int tag = get4LE(eventData);
+        eventData += 4;
+
+        if (tag == TAG) {
+            // This tag should not have been written because the data was null
+            count++;
+            break;
+        }
+    }
+
+    EXPECT_EQ(0, count);
+
+    android_logger_list_close(logger_list);
+}
+
+TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__subtag_too_long) {
+    const int TAG = 123456784;
+    const char SUBTAG[] = "abcdefghijklmnopqrstuvwxyz now i know my abc";
+    const int UID = -1;
+    const int DATA_LEN = 200;
+    struct logger_list *logger_list;
+
+    pid_t pid = getpid();
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+    ASSERT_LT(0, android_errorWriteWithInfoLog(
+            TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
+
+    sleep(2);
+
+    int count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        char *eventData = log_msg.msg();
+
+        // Tag
+        int tag = get4LE(eventData);
+        eventData += 4;
+
+        if (tag != TAG) {
+            continue;
+        }
+
+        // List type
+        ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
+        eventData++;
+
+        // Number of elements in list
+        ASSERT_EQ(3, eventData[0]);
+        eventData++;
+
+        // Element #1: string type for subtag
+        ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+        eventData++;
+
+        // The subtag is longer than 32 and should be truncated to that.
+        ASSERT_EQ(32, get4LE(eventData));
+        eventData +=4;
+
+        if (memcmp(SUBTAG, eventData, 32)) {
+            continue;
+        }
+        eventData += 32;
+
+        // Element #2: int type for uid
+        ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
+        eventData++;
+
+        ASSERT_EQ(UID, get4LE(eventData));
+        eventData += 4;
+
+        // Element #3: string type for data
+        ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+        eventData++;
+
+        ASSERT_EQ(DATA_LEN, get4LE(eventData));
+        eventData += 4;
+
+        if (memcmp(max_payload_buf, eventData, DATA_LEN)) {
+            continue;
+        }
+
+        ++count;
+    }
+
+    EXPECT_EQ(1, count);
+
+    android_logger_list_close(logger_list);
+}
+
+TEST(liblog, android_errorWriteLog__android_logger_list_read__success) {
+    const int TAG = 123456785;
+    const char SUBTAG[] = "test-subtag";
+    struct logger_list *logger_list;
+
+    pid_t pid = getpid();
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+    ASSERT_LT(0, android_errorWriteLog(TAG, SUBTAG));
+
+    sleep(2);
+
+    int count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        char *eventData = log_msg.msg();
+
+        // Tag
+        int tag = get4LE(eventData);
+        eventData += 4;
+
+        if (tag != TAG) {
+            continue;
+        }
+
+        // List type
+        ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
+        eventData++;
+
+        // Number of elements in list
+        ASSERT_EQ(3, eventData[0]);
+        eventData++;
+
+        // Element #1: string type for subtag
+        ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+        eventData++;
+
+        ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
+        eventData +=4;
+
+        if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
+            continue;
+        }
+        ++count;
+    }
+
+    EXPECT_EQ(1, count);
+
+    android_logger_list_close(logger_list);
+}
+
+TEST(liblog, android_errorWriteLog__android_logger_list_read__null_subtag) {
+    const int TAG = 123456786;
+    struct logger_list *logger_list;
+
+    pid_t pid = getpid();
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+    ASSERT_GT(0, android_errorWriteLog(TAG, NULL));
+
+    sleep(2);
+
+    int count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        char *eventData = log_msg.msg();
+
+        // Tag
+        int tag = get4LE(eventData);
+        eventData += 4;
+
+        if (tag == TAG) {
+            // This tag should not have been written because the data was null
+            count++;
+            break;
+        }
+    }
+
+    EXPECT_EQ(0, count);
+
+    android_logger_list_close(logger_list);
+}
diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp
index bdb54b1..2f770f5 100644
--- a/libutils/VectorImpl.cpp
+++ b/libutils/VectorImpl.cpp
@@ -198,7 +198,10 @@
                     _do_copy(next, curr, 1);
                     next = curr;
                     --j;
-                    curr = reinterpret_cast<char*>(array) + mItemSize*(j);                    
+                    curr = NULL;
+                    if (j >= 0) {
+                        curr = reinterpret_cast<char*>(array) + mItemSize*(j);
+                    }
                 } while (j>=0 && (cmp(curr, temp, state) > 0));
 
                 _do_destroy(next, 1);
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 6ea4109..a93369e 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -413,6 +413,12 @@
                 it = f->second;
             }
         }
+        static const timespec too_old = {
+            EXPIRE_HOUR_THRESHOLD * 60 * 60, 0
+        };
+        LogBufferElementCollection::iterator lastt;
+        lastt = mLogElements.end();
+        --lastt;
         LogBufferElementLast last;
         while (it != mLogElements.end()) {
             LogBufferElement *e = *it;
@@ -464,27 +470,24 @@
                 continue;
             }
 
+            if ((e->getRealTime() < ((*lastt)->getRealTime() - too_old))
+                    || (e->getRealTime() > (*lastt)->getRealTime())) {
+                break;
+            }
+
             // unmerged drop message
             if (dropped) {
                 last.add(e);
-                mLastWorstUid[id][e->getUid()] = it;
+                if ((e->getUid() == worst)
+                        || (mLastWorstUid[id].find(e->getUid())
+                            == mLastWorstUid[id].end())) {
+                    mLastWorstUid[id][e->getUid()] = it;
+                }
                 ++it;
                 continue;
             }
 
             if (e->getUid() != worst) {
-                if (leading) {
-                    static const timespec too_old = {
-                        EXPIRE_HOUR_THRESHOLD * 60 * 60, 0
-                    };
-                    LogBufferElementCollection::iterator last;
-                    last = mLogElements.end();
-                    --last;
-                    if ((e->getRealTime() < ((*last)->getRealTime() - too_old))
-                            || (e->getRealTime() > (*last)->getRealTime())) {
-                        break;
-                    }
-                }
                 leading = false;
                 last.clear(e);
                 ++it;
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index 1e6f55f..febf775 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -48,7 +48,7 @@
     char c;
     while (((c = *s++)) && (++len <= max_prio_len)) {
         if (!isdigit(c)) {
-            return (c == '>') ? s : NULL;
+            return ((c == '>') && (*s == '[')) ? s : NULL;
         }
     }
     return NULL;
@@ -294,6 +294,22 @@
     }
 }
 
+pid_t LogKlog::sniffPid(const char *cp) {
+    while (*cp) {
+        // Mediatek kernels with modified printk
+        if (*cp == '[') {
+            int pid = 0;
+            char dummy;
+            if (sscanf(cp, "[%d:%*[a-z_./0-9:A-Z]]%c", &pid, &dummy) == 2) {
+                return pid;
+            }
+            break; // Only the first one
+        }
+        ++cp;
+    }
+    return 0;
+}
+
 // Passed the entire SYSLOG_ACTION_READ_ALL buffer and interpret a
 // compensated start time.
 void LogKlog::synchronize(const char *buf) {
@@ -417,9 +433,9 @@
 
     // sniff for start marker
     const char klogd_message[] = "logd.klogd: ";
-    if (!strncmp(buf, klogd_message, sizeof(klogd_message) - 1)) {
-        char *endp;
-        uint64_t sig = strtoll(buf + sizeof(klogd_message) - 1, &endp, 10);
+    const char *start = strstr(buf, klogd_message);
+    if (start) {
+        uint64_t sig = strtoll(start + sizeof(klogd_message) - 1, NULL, 10);
         if (sig == signature.nsec()) {
             if (initialized) {
                 enableLogging = true;
@@ -435,10 +451,10 @@
         return 0;
     }
 
-    // Parse pid, tid and uid (not possible)
-    const pid_t pid = 0;
-    const pid_t tid = 0;
-    const uid_t uid = 0;
+    // Parse pid, tid and uid
+    const pid_t pid = sniffPid(buf);
+    const pid_t tid = pid;
+    const uid_t uid = pid ? logbuf->pidToUid(pid) : 0;
 
     // Parse (rules at top) to pull out a tag from the incoming kernel message.
     // Some may view the following as an ugly heuristic, the desire is to
@@ -450,7 +466,7 @@
     if (!*buf) {
         return 0;
     }
-    const char *start = buf;
+    start = buf;
     const char *tag = "";
     const char *etag = tag;
     if (!isspace(*buf)) {
@@ -461,7 +477,14 @@
             // <PRI>[<TIME>] "[INFO]"<tag> ":" message
             bt = buf + 6;
         }
-        for(et = bt; *et && (*et != ':') && !isspace(*et); ++et);
+        for(et = bt; *et && (*et != ':') && !isspace(*et); ++et) {
+           // skip ':' within [ ... ]
+           if (*et == '[') {
+               while (*et && *et != ']') {
+                   ++et;
+               }
+            }
+        }
         for(cp = et; isspace(*cp); ++cp);
         size_t size;
 
@@ -557,7 +580,17 @@
             etag = tag = "";
         }
     }
-    size_t l = etag - tag;
+    // Suppress additional stutter in tag:
+    //   eg: [143:healthd]healthd -> [143:healthd]
+    size_t taglen = etag - tag;
+    // Mediatek-special printk induced stutter
+    char *np = strrchr(tag, ']');
+    if (np && (++np < etag)) {
+        size_t s = etag - np;
+        if (((s + s) < taglen) && !strncmp(np, np - 1 - s, s)) {
+            taglen = np - tag;
+        }
+    }
     // skip leading space
     while (isspace(*buf)) {
         ++buf;
@@ -568,11 +601,11 @@
         --b;
     }
     // trick ... allow tag with empty content to be logged. log() drops empty
-    if (!b && l) {
+    if (!b && taglen) {
         buf = " ";
         b = 1;
     }
-    size_t n = 1 + l + 1 + b + 1;
+    size_t n = 1 + taglen + 1 + b + 1;
 
     // Allocate a buffer to hold the interpreted log message
     int rc = n;
@@ -581,15 +614,15 @@
         rc = -ENOMEM;
         return rc;
     }
-    char *np = newstr;
+    np = newstr;
 
     // Convert priority into single-byte Android logger priority
     *np = convertKernelPrioToAndroidPrio(pri);
     ++np;
 
     // Copy parsed tag following priority
-    strncpy(np, tag, l);
-    np += l;
+    strncpy(np, tag, taglen);
+    np += taglen;
     *np = '\0';
     ++np;
 
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index 24b2685..7e4fde0 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -47,6 +47,7 @@
 
 protected:
     void sniffTime(log_time &now, const char **buf, bool reverse);
+    pid_t sniffPid(const char *buf);
     void calculateCorrection(const log_time &monotonic, const char *real_string);
     virtual bool onDataAvailable(SocketClient *cli);
 
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
index 9fd8eda..89fa222 100644
--- a/metricsd/Android.mk
+++ b/metricsd/Android.mk
@@ -110,6 +110,7 @@
   libprotobuf-cpp-lite \
   libchromeos-http \
   libchromeos-dbus \
+  libcutils \
   libdbus
 LOCAL_SRC_FILES := $(metrics_daemon_sources)
 LOCAL_STATIC_LIBRARIES := metrics_daemon_protos
diff --git a/metricsd/constants.h b/metricsd/constants.h
index 56dac0d..15c15d9 100644
--- a/metricsd/constants.h
+++ b/metricsd/constants.h
@@ -24,6 +24,11 @@
 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";
+
+// System properties used.
+static const char kBuildTargetIdProperty[] = "ro.product.build_target_id";
+static const char kChannelProperty[] = "ro.product.channel";
+static const char kProductVersionProperty[] = "ro.product.version";
 }  // namespace metrics
 
 #endif  // METRICS_CONSTANTS_H_
diff --git a/metricsd/metrics_daemon.cc b/metricsd/metrics_daemon.cc
index 069f68e..5855cee 100644
--- a/metricsd/metrics_daemon.cc
+++ b/metricsd/metrics_daemon.cc
@@ -32,7 +32,7 @@
 #include <base/strings/string_split.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
-#include <base/sys_info.h>
+#include <cutils/properties.h>
 #include <dbus/dbus.h>
 #include <dbus/message.h>
 
@@ -209,10 +209,13 @@
   if (version_hash_is_cached)
     return cached_version_hash;
   version_hash_is_cached = true;
-  std::string version = metrics::kDefaultVersion;
+
+  char version[PROPERTY_VALUE_MAX];
   // The version might not be set for development devices. In this case, use the
   // zero version.
-  base::SysInfo::GetLsbReleaseValue("BRILLO_VERSION", &version);
+  property_get(metrics::kProductVersionProperty, version,
+               metrics::kDefaultVersion);
+
   cached_version_hash = base::Hash(version);
   if (testing_) {
     cached_version_hash = 42;  // return any plausible value for the hash
diff --git a/metricsd/uploader/system_profile_cache.cc b/metricsd/uploader/system_profile_cache.cc
index 7dd0323..21ec229 100644
--- a/metricsd/uploader/system_profile_cache.cc
+++ b/metricsd/uploader/system_profile_cache.cc
@@ -21,7 +21,7 @@
 #include <base/logging.h>
 #include <base/strings/string_number_conversions.h>
 #include <base/strings/string_util.h>
-#include <base/sys_info.h>
+#include <cutils/properties.h>
 #include <string>
 #include <vector>
 
@@ -73,21 +73,28 @@
   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.";
+  char property_value[PROPERTY_VALUE_MAX];
+  property_get(metrics::kBuildTargetIdProperty, property_value, "");
+  profile_.build_target_id = std::string(property_value);
+
+  if (profile_.build_target_id.empty()) {
+    LOG(ERROR) << "System property " << metrics::kBuildTargetIdProperty
+               << " is not set.";
     return false;
   }
 
-  std::string channel;
-  if (!base::SysInfo::GetLsbReleaseValue("BRILLO_CHANNEL", &channel) ||
-      !base::SysInfo::GetLsbReleaseValue("BRILLO_VERSION", &profile_.version)) {
+  property_get(metrics::kChannelProperty, property_value, "");
+  std::string channel(property_value);
+
+  property_get(metrics::kProductVersionProperty, property_value, "");
+  profile_.version = std::string(property_value);
+
+  if (channel.empty() || profile_.version.empty()) {
     // 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" :
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 2ae7ed2..24f702f 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -53,7 +53,6 @@
     start \
     stop \
     top \
-    uptime \
 
 ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS)
 
diff --git a/toolbox/uptime.c b/toolbox/uptime.c
deleted file mode 100644
index ebfb15e..0000000
--- a/toolbox/uptime.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2010, 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 <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-static void format_time(int time, char* buffer) {
-    int seconds = time % 60;
-    time /= 60;
-    int minutes = time % 60;
-    time /= 60;
-    int hours = time % 24;
-    int days = time / 24;
-
-    if (days > 0) {
-        sprintf(buffer, "%d day%s, %02d:%02d:%02d", days, (days == 1) ? "" : "s", hours, minutes, seconds);
-    } else {
-        sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds);
-    }
-}
-
-int uptime_main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) {
-    FILE* file = fopen("/proc/uptime", "r");
-    if (!file) {
-        fprintf(stderr, "Could not open /proc/uptime\n");
-        return -1;
-    }
-    float idle_time;
-    if (fscanf(file, "%*f %f", &idle_time) != 1) {
-        fprintf(stderr, "Could not parse /proc/uptime\n");
-        fclose(file);
-        return -1;
-    }
-    fclose(file);
-
-    struct timespec up_timespec;
-    if (clock_gettime(CLOCK_MONOTONIC, &up_timespec) == -1) {
-        fprintf(stderr, "Could not get monotonic time: %s\n", strerror(errno));
-	return -1;
-    }
-    float up_time = up_timespec.tv_sec + up_timespec.tv_nsec / 1e9;
-
-    struct timespec elapsed_timespec;
-    if (clock_gettime(CLOCK_BOOTTIME, &elapsed_timespec) == -1) {
-        fprintf(stderr, "Could not get boot time: %s\n", strerror(errno));
-        return -1;
-    }
-    int elapsed = elapsed_timespec.tv_sec;
-
-    char up_string[100], idle_string[100], sleep_string[100];
-    format_time(elapsed, up_string);
-    format_time((int)idle_time, idle_string);
-    format_time((int)(elapsed - up_time), sleep_string);
-    printf("up time: %s, idle time: %s, sleep time: %s\n", up_string, idle_string, sleep_string);
-
-    return 0;
-}