am f10e1ed1: (-s ours) am 2e406f64: am 9a995b2c: Merge "Use __ANDROID__ instead of __BRILLO__."

* commit 'f10e1ed1b2229700df0cc31cf7c8fb67a1ecbd55':
diff --git a/adb/Android.mk b/adb/Android.mk
index e2d0bb1..df0c7a1 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -118,6 +118,8 @@
 
 ifeq ($(HOST_OS),windows)
     LOCAL_C_INCLUDES += development/host/windows/usb/api/
+else
+    LOCAL_MULTILIB := 64
 endif
 
 include $(BUILD_HOST_STATIC_LIBRARY)
@@ -277,6 +279,8 @@
 
 LOCAL_MODULE := adbd
 
+LOCAL_INIT_RC := adbd.rc
+
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT
index 63000f2..30c21f7 100644
--- a/adb/SERVICES.TXT
+++ b/adb/SERVICES.TXT
@@ -237,7 +237,7 @@
     Note that there is no single-shot service to retrieve the list only once.
 
 sync:
-    This starts the file synchronisation service, used to implement "adb push"
+    This starts the file synchronization service, used to implement "adb push"
     and "adb pull". Since this service is pretty complex, it will be detailed
     in a companion document named SYNC.TXT
 
diff --git a/adb/SYNC.TXT b/adb/SYNC.TXT
index e74d217..06d7804 100644
--- a/adb/SYNC.TXT
+++ b/adb/SYNC.TXT
@@ -25,12 +25,9 @@
 
 The following sync requests are accepted:
 LIST - List the files in a folder
+RECV - Retrieve a file from device
 SEND - Send a file to device
-RECV - Retreive a file from device
-
-Not yet documented:
 STAT - Stat a file
-ULNK - Unlink (remove) a file. (Not currently supported)
 
 For all of the sync request above the must be followed by length number of
 bytes containing an utf-8 string with a remote filename.
@@ -40,7 +37,7 @@
 respond with zero or more directory entries or "dents".
 
 The directory entries will be returned in the following form
-1. A four-byte sync response id beeing "DENT"
+1. A four-byte sync response id "DENT"
 2. A four-byte integer representing file mode.
 3. A four-byte integer representing file size.
 4. A four-byte integer representing last modified time.
@@ -60,13 +57,13 @@
   adb push disk_image /some_block_device
 to work.
 
-After this the actual file is sent in chunks. Each chucks has the following
+After this the actual file is sent in chunks. Each chunk has the following
 format.
 A sync request with id "DATA" and length equal to the chunk size. After
 follows chunk size number of bytes. This is repeated until the file is
-transfered. Each chunk must not be larger than 64k.
+transferred. Each chunk must not be larger than 64k.
 
-When the file is tranfered a sync request "DONE" is sent, where length is set
+When the file is transferred a sync request "DONE" is sent, where length is set
 to the last modified time for the file. The server responds to this last
 request (but not to chuck requests) with an "OKAY" sync response (length can
 be ignored).
@@ -77,8 +74,8 @@
 the file that will be returned. Just as for the SEND sync request the file
 received is split up into chunks. The sync response id is "DATA" and length is
 the chuck size. After follows chunk size number of bytes. This is repeated
-until the file is transfered. Each chuck will not be larger than 64k.
+until the file is transferred. Each chuck will not be larger than 64k.
 
-When the file is transfered a sync resopnse "DONE" is retrieved where the
+When the file is transferred a sync response "DONE" is retrieved where the
 length can be ignored.
 
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 29c9481..a0501a6 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -243,6 +243,11 @@
     D("adb: offline\n");
     //Close the associated usb
     t->online = 0;
+
+    // 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);
+
     run_transport_disconnects(t);
 }
 
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index 4bf647c..a1bbb78 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -44,28 +44,6 @@
 static int __adb_server_port = DEFAULT_ADB_PORT;
 static const char* __adb_server_name = NULL;
 
-static std::string perror_str(const char* msg) {
-    return android::base::StringPrintf("%s: %s", msg, strerror(errno));
-}
-
-static bool ReadProtocolString(int fd, std::string* s, std::string* error) {
-    char buf[5];
-    if (!ReadFdExactly(fd, buf, 4)) {
-        *error = perror_str("protocol fault (couldn't read status length)");
-        return false;
-    }
-    buf[4] = 0;
-
-    unsigned long len = strtoul(buf, 0, 16);
-    s->resize(len, '\0');
-    if (!ReadFdExactly(fd, &(*s)[0], len)) {
-        *error = perror_str("protocol fault (couldn't read status message)");
-        return false;
-    }
-
-    return true;
-}
-
 void adb_set_transport(TransportType type, const char* serial)
 {
     __adb_transport = type;
@@ -175,7 +153,7 @@
         return -1;
     }
 
-    if(!SendProtocolString(fd, service)) {
+    if (!SendProtocolString(fd, service)) {
         *error = perror_str("write failure during connection");
         adb_close(fd);
         return -1;
diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp
index 5ae6ec3..7092609 100644
--- a/adb/adb_io.cpp
+++ b/adb/adb_io.cpp
@@ -32,7 +32,27 @@
         length = 0xffff;
     }
 
-    return WriteFdFmt(fd, "%04x", length) && WriteFdExactly(fd, s);
+    // The cost of sending two strings outweighs the cost of formatting.
+    // "adb sync" performance is affected by this.
+    return WriteFdFmt(fd, "%04x%.*s", length, length, s.c_str());
+}
+
+bool ReadProtocolString(int fd, std::string* s, std::string* error) {
+    char buf[5];
+    if (!ReadFdExactly(fd, buf, 4)) {
+        *error = perror_str("protocol fault (couldn't read status length)");
+        return false;
+    }
+    buf[4] = 0;
+
+    unsigned long len = strtoul(buf, 0, 16);
+    s->resize(len, '\0');
+    if (!ReadFdExactly(fd, &(*s)[0], len)) {
+        *error = perror_str("protocol fault (couldn't read status message)");
+        return false;
+    }
+
+    return true;
 }
 
 bool SendOkay(int fd) {
diff --git a/adb/adb_io.h b/adb/adb_io.h
index 8d50a6d..9c3b2a5 100644
--- a/adb/adb_io.h
+++ b/adb/adb_io.h
@@ -30,23 +30,22 @@
 // Writes a protocol-format string; a four hex digit length followed by the string data.
 bool SendProtocolString(int fd, const std::string& s);
 
-/*
- * Reads exactly len bytes from fd into buf.
- *
- * Returns false if there is an error or if EOF was reached before len bytes
- * were read. If EOF was found, errno will be set to 0.
- *
- * If this function fails, the contents of buf are undefined.
- */
-bool ReadFdExactly(int fd, void *buf, size_t len);
+// Reads a protocol-format string; a four hex digit length followed by the string data.
+bool ReadProtocolString(int fd, std::string* s, std::string* error);
 
-/*
- * Writes exactly len bytes from buf to fd.
- *
- * Returns false if there is an error or if the fd was closed before the write
- * completed. If the other end of the fd (such as in a socket, pipe, or fifo),
- * is closed, errno will be set to 0.
- */
+// Reads exactly len bytes from fd into buf.
+//
+// Returns false if there is an error or if EOF was reached before len bytes
+// were read. If EOF was found, errno will be set to 0.
+//
+// If this function fails, the contents of buf are undefined.
+bool ReadFdExactly(int fd, void* buf, size_t len);
+
+// Writes exactly len bytes from buf to fd.
+//
+// Returns false if there is an error or if the fd was closed before the write
+// completed. If the other end of the fd (such as in a socket, pipe, or fifo),
+// is closed, errno will be set to 0.
 bool WriteFdExactly(int fd, const void* buf, size_t len);
 
 // Same as above, but for strings.
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index ca843bd..e5dc692 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -225,3 +225,7 @@
                << " (" << *canonical_address << ")";
     return true;
 }
+
+std::string perror_str(const char* msg) {
+    return android::base::StringPrintf("%s: %s", msg, strerror(errno));
+}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 739efcc..b38ec59 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -44,4 +44,6 @@
                          std::string* host, int* port,
                          std::string* error);
 
+std::string perror_str(const char* msg);
+
 #endif
diff --git a/adb/adbd.rc b/adb/adbd.rc
new file mode 100644
index 0000000..b91d8b5
--- /dev/null
+++ b/adb/adbd.rc
@@ -0,0 +1,14 @@
+on post-fs-data
+    mkdir /data/misc/adb 02750 system shell
+    mkdir /data/adb 0700 root root
+
+# adbd is controlled via property triggers in init.<platform>.usb.rc
+service adbd /sbin/adbd --root_seclabel=u:r:su:s0
+    class core
+    socket adbd stream 660 system system
+    disabled
+    seclabel u:r:adbd:s0
+
+# adbd on at boot in emulator
+on property:ro.kernel.qemu=1
+    start adbd
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 206442a..39bb02b 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -134,6 +134,7 @@
     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) {
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 5c5b633..ed25f3b 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -284,10 +284,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;
         }
 
@@ -340,11 +337,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) {
@@ -389,17 +382,13 @@
     fdi = fds[1];
     free(fds);
 
-    for(;;) {
+    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;
@@ -897,14 +886,14 @@
 }
 
 static void parse_push_pull_args(const char **arg, int narg, char const **path1,
-                                 char const **path2, int *show_progress,
+                                 char const **path2, bool* show_progress,
                                  int *copy_attrs) {
-    *show_progress = 0;
+    *show_progress = false;
     *copy_attrs = 0;
 
     while (narg > 0) {
         if (!strcmp(*arg, "-p")) {
-            *show_progress = 1;
+            *show_progress = true;
         } else if (!strcmp(*arg, "-a")) {
             *copy_attrs = 1;
         } else {
@@ -1339,33 +1328,25 @@
     /* do_sync_*() commands */
     else if (!strcmp(argv[0], "ls")) {
         if (argc != 2) return usage();
-        return do_sync_ls(argv[1]);
+        return do_sync_ls(argv[1]) ? 0 : 1;
     }
     else if (!strcmp(argv[0], "push")) {
-        int show_progress = 0;
-        int copy_attrs = 0; // unused
+        bool show_progress = false;
+        int copy_attrs = 0;
         const char* lpath = NULL, *rpath = NULL;
 
         parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress, &copy_attrs);
-
-        if ((lpath != NULL) && (rpath != NULL)) {
-            return do_sync_push(lpath, rpath, show_progress);
-        }
-
-        return usage();
+        if (!lpath || !rpath || copy_attrs != 0) return usage();
+        return do_sync_push(lpath, rpath, show_progress) ? 0 : 1;
     }
     else if (!strcmp(argv[0], "pull")) {
-        int show_progress = 0;
+        bool show_progress = false;
         int copy_attrs = 0;
         const char* rpath = NULL, *lpath = ".";
 
         parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress, &copy_attrs);
-
-        if (rpath != NULL) {
-            return do_sync_pull(rpath, lpath, show_progress, copy_attrs);
-        }
-
-        return usage();
+        if (!rpath) return usage();
+        return do_sync_pull(rpath, lpath, show_progress, copy_attrs) ? 0 : 1;
     }
     else if (!strcmp(argv[0], "install")) {
         if (argc < 2) return usage();
@@ -1409,20 +1390,20 @@
         std::string vendor_src_path = product_file("vendor");
         std::string oem_src_path = product_file("oem");
 
-        int rc = 0;
-        if (rc == 0 && (src.empty() || src == "system")) {
-            rc = do_sync_sync(system_src_path, "/system", list_only);
+        bool okay = true;
+        if (okay && (src.empty() || src == "system")) {
+            okay = do_sync_sync(system_src_path, "/system", list_only);
         }
-        if (rc == 0 && (src.empty() || src == "vendor") && directory_exists(vendor_src_path)) {
-            rc = do_sync_sync(vendor_src_path, "/vendor", list_only);
+        if (okay && (src.empty() || src == "vendor") && directory_exists(vendor_src_path)) {
+            okay = do_sync_sync(vendor_src_path, "/vendor", list_only);
         }
-        if (rc == 0 && (src.empty() || src == "oem") && directory_exists(oem_src_path)) {
-            rc = do_sync_sync(oem_src_path, "/oem", list_only);
+        if (okay && (src.empty() || src == "oem") && directory_exists(oem_src_path)) {
+            okay = do_sync_sync(oem_src_path, "/oem", list_only);
         }
-        if (rc == 0 && (src.empty() || src == "data")) {
-            rc = do_sync_sync(data_src_path, "/data", list_only);
+        if (okay && (src.empty() || src == "data")) {
+            okay = do_sync_sync(data_src_path, "/data", list_only);
         }
-        return rc;
+        return okay ? 0 : 1;
     }
     /* passthrough commands */
     else if (!strcmp(argv[0],"get-state") ||
@@ -1543,20 +1524,16 @@
         return -1;
     }
 
+    int result = -1;
     const char* apk_file = argv[last_apk];
     std::string apk_dest = android::base::StringPrintf(where, adb_basename(apk_file).c_str());
-    int err = do_sync_push(apk_file, apk_dest.c_str(), 0 /* no show progress */);
-    if (err) {
-        goto cleanup_apk;
-    } else {
-        argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
-    }
-
-    err = pm_command(transport, serial, argc, argv);
+    if (!do_sync_push(apk_file, apk_dest.c_str(), false)) goto cleanup_apk;
+    argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
+    result = pm_command(transport, serial, argc, argv);
 
 cleanup_apk:
     delete_file(transport, serial, apk_dest);
-    return err;
+    return result;
 }
 
 static int install_multiple_app(TransportType transport, const char* serial, int argc,
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index a8abade..d25bbfb 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2006, Brian Swetland <swetland@frotz.net>
 **
-** 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -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);
     }
@@ -688,7 +688,7 @@
     fdevent_subproc_setup();
 #endif // !ADB_HOST
 
-    for(;;) {
+    while (true) {
         D("--- ---- waiting for events\n");
 
         fdevent_process();
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index da80013..e70d550 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -27,6 +27,8 @@
 #include <time.h>
 #include <utime.h>
 
+#include <memory>
+
 #include "sysdeps.h"
 
 #include "adb.h"
@@ -35,36 +37,21 @@
 #include "adb_utils.h"
 #include "file_sync_service.h"
 
+#include <base/strings.h>
 #include <base/stringprintf.h>
 
-static unsigned long long total_bytes;
-static long long start_time;
+struct syncsendbuf {
+    unsigned id;
+    unsigned size;
+    char data[SYNC_DATA_MAX];
+};
 
-static long long NOW()
-{
+static syncsendbuf send_buffer;
+
+static long long NOW() {
     struct timeval tv;
     gettimeofday(&tv, 0);
-    return ((long long) tv.tv_usec) +
-        1000000LL * ((long long) tv.tv_sec);
-}
-
-static void BEGIN()
-{
-    total_bytes = 0;
-    start_time = NOW();
-}
-
-static void END()
-{
-    long long t = NOW() - start_time;
-    if(total_bytes == 0) return;
-
-    if (t == 0)  /* prevent division by 0 :-) */
-        t = 1000000;
-
-    fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n",
-            ((total_bytes * 1000000LL) / t) / 1024LL,
-            total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
+    return ((long long) tv.tv_usec) + 1000000LL * ((long long) tv.tv_sec);
 }
 
 static void print_transfer_progress(uint64_t bytes_current,
@@ -82,148 +69,123 @@
     fflush(stderr);
 }
 
-static void sync_quit(int fd) {
-    syncmsg msg;
-
-    msg.req.id = ID_QUIT;
-    msg.req.namelen = 0;
-
-    WriteFdExactly(fd, &msg.req, sizeof(msg.req));
-}
-
-typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
-
-static int sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
-    int len = strlen(path);
-    if (len > 1024) goto fail;
-
-    syncmsg msg;
-    msg.req.id = ID_LIST;
-    msg.req.namelen = htoll(len);
-
-    if (!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || !WriteFdExactly(fd, path, len)) {
-        goto fail;
+static bool SendRequest(int fd, int id, const char* path) {
+    size_t path_length = strlen(path);
+    if (path_length > 1024) {
+        fprintf(stderr, "SendRequest failed: path too long: %zu", path_length);
+        return false;
     }
 
-    for (;;) {
-        if (!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break;
-        if (msg.dent.id == ID_DONE) return 0;
-        if (msg.dent.id != ID_DENT) break;
+    // Sending header and payload in a single write makes a noticeable
+    // difference to "adb sync" performance.
+    char buf[sizeof(SyncRequest) + path_length] __attribute__((aligned(8)));
+    SyncRequest* req = reinterpret_cast<SyncRequest*>(buf);
+    req->id = id;
+    req->path_length = path_length;
+    char* data = reinterpret_cast<char*>(req + 1);
+    memcpy(data, path, path_length);
 
-        len = ltohl(msg.dent.namelen);
-        if (len > 256) break;
-
-        char buf[257];
-        if (!ReadFdExactly(fd, buf, len)) break;
-        buf[len] = 0;
-
-        func(ltohl(msg.dent.mode), ltohl(msg.dent.size), ltohl(msg.dent.time), buf, cookie);
-    }
-
-fail:
-    adb_close(fd);
-    return -1;
+    return WriteFdExactly(fd, buf, sizeof(buf));
 }
 
-struct syncsendbuf {
-    unsigned id;
-    unsigned size;
-    char data[SYNC_DATA_MAX];
+class SyncConnection {
+  public:
+    SyncConnection() : total_bytes(0), start_time_(NOW()) {
+        max = SYNC_DATA_MAX; // TODO: decide at runtime.
+
+        std::string error;
+        fd = adb_connect("sync:", &error);
+        if (fd < 0) {
+            fprintf(stderr, "error: %s\n", error.c_str());
+        }
+    }
+
+    ~SyncConnection() {
+        if (!IsValid()) return;
+
+        SendQuit();
+        ShowTransferRate();
+        adb_close(fd);
+    }
+
+    bool IsValid() { return fd >= 0; }
+
+    uint64_t total_bytes;
+
+    // TODO: add a char[max] buffer here, to replace syncsendbuf...
+    int fd;
+    size_t max;
+
+  private:
+    uint64_t start_time_;
+
+    void SendQuit() {
+        SendRequest(fd, ID_QUIT, ""); // TODO: add a SendResponse?
+    }
+
+    void ShowTransferRate() {
+        uint64_t t = NOW() - start_time_;
+        if (total_bytes == 0 || t == 0) return;
+
+        fprintf(stderr, "%lld KB/s (%" PRId64 " bytes in %lld.%03llds)\n",
+                ((total_bytes * 1000000LL) / t) / 1024LL,
+                total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
+    }
 };
 
-static syncsendbuf send_buffer;
+typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name, void* cookie);
 
-static int sync_readtime(int fd, const char* path, unsigned int* timestamp, unsigned int* mode) {
-    syncmsg msg;
-    int len = strlen(path);
+static bool sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
+    if (!SendRequest(fd, ID_LIST, path)) return false;
 
-    msg.req.id = ID_STAT;
-    msg.req.namelen = htoll(len);
+    while (true) {
+        syncmsg msg;
+        if (!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) return false;
 
-    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
-       !WriteFdExactly(fd, path, len)) {
-        return -1;
+        if (msg.dent.id == ID_DONE) return true;
+        if (msg.dent.id != ID_DENT) return false;
+
+        size_t len = msg.dent.namelen;
+        if (len > 256) return false; // TODO: resize buffer? continue?
+
+        char buf[257];
+        if (!ReadFdExactly(fd, buf, len)) return false;
+        buf[len] = 0;
+
+        func(msg.dent.mode, msg.dent.size, msg.dent.time, buf, cookie);
     }
-
-    if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
-        return -1;
-    }
-
-    if(msg.stat.id != ID_STAT) {
-        return -1;
-    }
-
-    *timestamp = ltohl(msg.stat.time);
-    *mode = ltohl(msg.stat.mode);
-    return 0;
 }
 
-static int sync_start_readtime(int fd, const char *path)
-{
-    syncmsg msg;
-    int len = strlen(path);
-
-    msg.req.id = ID_STAT;
-    msg.req.namelen = htoll(len);
-
-    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
-       !WriteFdExactly(fd, path, len)) {
-        return -1;
-    }
-
-    return 0;
+static bool sync_start_stat(SyncConnection& sc, const char* path) {
+    return SendRequest(sc.fd, ID_STAT, path);
 }
 
-static int sync_finish_readtime(int fd, unsigned int *timestamp,
-                                unsigned int *mode, unsigned int *size)
-{
+static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
+                             unsigned int* mode, unsigned int* size) {
     syncmsg msg;
+    if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
+        return false;
+    }
 
-    if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat)))
-        return -1;
+    if (timestamp) *timestamp = msg.stat.time;
+    if (mode) *mode = msg.stat.mode;
+    if (size) *size = msg.stat.size;
 
-    if(msg.stat.id != ID_STAT)
-        return -1;
-
-    *timestamp = ltohl(msg.stat.time);
-    *mode = ltohl(msg.stat.mode);
-    *size = ltohl(msg.stat.size);
-
-    return 0;
+    return true;
 }
 
-static int sync_readmode(int fd, const char* path, unsigned* mode) {
-    syncmsg msg;
-    int len = strlen(path);
-
-    msg.req.id = ID_STAT;
-    msg.req.namelen = htoll(len);
-
-    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
-       !WriteFdExactly(fd, path, len)) {
-        return -1;
-    }
-
-    if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
-        return -1;
-    }
-
-    if(msg.stat.id != ID_STAT) {
-        return -1;
-    }
-
-    *mode = ltohl(msg.stat.mode);
-    return 0;
+static bool sync_stat(SyncConnection& sc, const char* path,
+                      unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
+    return sync_start_stat(sc, path) && sync_finish_stat(sc, timestamp, mode, size);
 }
 
-static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, bool show_progress)
-{
-    int lfd, err = 0;
+static int write_data_file(SyncConnection& sc, const char* path, syncsendbuf* sbuf, bool show_progress) {
+    int err = 0;
     unsigned long long size = 0;
 
-    lfd = adb_open(path, O_RDONLY);
-    if(lfd < 0) {
-        fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
+    int lfd = adb_open(path, O_RDONLY);
+    if (lfd < 0) {
+        fprintf(stderr, "cannot open '%s': %s\n", path, strerror(errno));
         return -1;
     }
 
@@ -231,7 +193,7 @@
         // Determine local file size.
         struct stat st;
         if (stat(path, &st)) {
-            fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
+            fprintf(stderr, "cannot stat '%s': %s\n", path, strerror(errno));
             return -1;
         }
 
@@ -239,29 +201,22 @@
     }
 
     sbuf->id = ID_DATA;
-    for(;;) {
-        int ret;
-
-        ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX);
-        if(!ret)
-            break;
-
-        if(ret < 0) {
-            if(errno == EINTR)
-                continue;
-            fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
+    while (true) {
+        int ret = adb_read(lfd, sbuf->data, sc.max);
+        if (ret <= 0) {
+            if (ret < 0) fprintf(stderr, "cannot read '%s': %s\n", path, strerror(errno));
             break;
         }
 
-        sbuf->size = htoll(ret);
-        if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + ret)){
+        sbuf->size = ret;
+        if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + ret)) {
             err = -1;
             break;
         }
-        total_bytes += ret;
+        sc.total_bytes += ret;
 
         if (show_progress) {
-            print_transfer_progress(total_bytes, size);
+            print_transfer_progress(sc.total_bytes, size);
         }
     }
 
@@ -269,176 +224,98 @@
     return err;
 }
 
-static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
-                             bool show_progress)
-{
-    int err = 0;
-    int total = 0;
-
-    sbuf->id = ID_DATA;
-    while (total < size) {
-        int count = size - total;
-        if (count > SYNC_DATA_MAX) {
-            count = SYNC_DATA_MAX;
-        }
-
-        memcpy(sbuf->data, &file_buffer[total], count);
-        sbuf->size = htoll(count);
-        if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + count)){
-            err = -1;
-            break;
-        }
-        total += count;
-        total_bytes += count;
-
-        if (show_progress) {
-            print_transfer_progress(total, size);
-        }
-    }
-
-    return err;
-}
-
 #if defined(_WIN32)
-extern int write_data_link(int fd, const char *path, syncsendbuf *sbuf) __attribute__((error("no symlinks on Windows")));
+extern int write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) __attribute__((error("no symlinks on Windows")));
 #else
-static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
-{
-    int len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
+static int 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;
     }
     sbuf->data[len] = '\0';
 
-    sbuf->size = htoll(len + 1);
+    sbuf->size = len + 1;
     sbuf->id = ID_DATA;
 
-    if (!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1)) {
+    if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + len + 1)) {
         return -1;
     }
 
-    total_bytes += len + 1;
+    sc.total_bytes += len + 1;
 
     return 0;
 }
 #endif
 
-static int sync_send(int fd, const char *lpath, const char *rpath,
-                     unsigned mtime, mode_t mode, bool show_progress)
+static bool sync_send(SyncConnection& sc, const char *lpath, const char *rpath,
+                      unsigned mtime, mode_t mode, bool show_progress)
 {
+    syncsendbuf* sbuf = &send_buffer;
+
+    std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
+    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);
+    } else if (S_ISLNK(mode)) {
+        write_data_link(sc, lpath, sbuf);
+    } else {
+        goto fail;
+    }
+
     syncmsg msg;
-    int len, r;
-    syncsendbuf *sbuf = &send_buffer;
-    char* file_buffer = NULL;
-    int size = 0;
-    char tmp[64];
-
-    len = strlen(rpath);
-    if(len > 1024) goto fail;
-
-    snprintf(tmp, sizeof(tmp), ",%d", mode);
-    r = strlen(tmp);
-
-    msg.req.id = ID_SEND;
-    msg.req.namelen = htoll(len + r);
-
-    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
-       !WriteFdExactly(fd, rpath, len) || !WriteFdExactly(fd, tmp, r)) {
-        free(file_buffer);
-        goto fail;
-    }
-
-    if (file_buffer) {
-        write_data_buffer(fd, file_buffer, size, sbuf, show_progress);
-        free(file_buffer);
-    } else if (S_ISREG(mode))
-        write_data_file(fd, lpath, sbuf, show_progress);
-    else if (S_ISLNK(mode))
-        write_data_link(fd, lpath, sbuf);
-    else
-        goto fail;
-
     msg.data.id = ID_DONE;
-    msg.data.size = htoll(mtime);
-    if(!WriteFdExactly(fd, &msg.data, sizeof(msg.data)))
-        goto fail;
+    msg.data.size = mtime;
+    if (!WriteFdExactly(sc.fd, &msg.data, sizeof(msg.data))) goto fail;
 
-    if(!ReadFdExactly(fd, &msg.status, sizeof(msg.status)))
-        return -1;
+    if (!ReadFdExactly(sc.fd, &msg.status, sizeof(msg.status))) goto fail;
 
-    if(msg.status.id != ID_OKAY) {
-        if(msg.status.id == ID_FAIL) {
-            len = ltohl(msg.status.msglen);
-            if(len > 256) len = 256;
-            if(!ReadFdExactly(fd, sbuf->data, len)) {
-                return -1;
-            }
+    if (msg.status.id != ID_OKAY) {
+        if (msg.status.id == ID_FAIL) {
+            size_t len = msg.status.msglen;
+            if (len > 256) len = 256;
+            if (!ReadFdExactly(sc.fd, sbuf->data, len)) goto fail;
             sbuf->data[len] = 0;
-        } else
+        } else {
             strcpy(sbuf->data, "unknown reason");
-
-        fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
-        return -1;
+        }
+        fprintf(stderr, "failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
+        return false;
     }
 
-    return 0;
+    return true;
 
 fail:
-    fprintf(stderr,"protocol failure\n");
-    adb_close(fd);
-    return -1;
+    fprintf(stderr, "protocol failure\n");
+    return false;
 }
 
-static int sync_recv(int fd, const char* rpath, const char* lpath, bool show_progress) {
+static int sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, bool show_progress) {
     syncmsg msg;
-    int len;
     int lfd = -1;
     char *buffer = send_buffer.data;
     unsigned id;
-    unsigned long long size = 0;
 
-    len = strlen(rpath);
-    if(len > 1024) return -1;
+    size_t len = strlen(rpath);
+    if (len > 1024) return -1;
 
+    unsigned size = 0;
     if (show_progress) {
-        // Determine remote file size.
-        syncmsg stat_msg;
-        stat_msg.req.id = ID_STAT;
-        stat_msg.req.namelen = htoll(len);
-
-        if (!WriteFdExactly(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
-            !WriteFdExactly(fd, rpath, len)) {
-            return -1;
-        }
-
-        if (!ReadFdExactly(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
-            return -1;
-        }
-
-        if (stat_msg.stat.id != ID_STAT) return -1;
-
-        size = ltohl(stat_msg.stat.size);
+        if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return -1;
     }
 
-    msg.req.id = ID_RECV;
-    msg.req.namelen = htoll(len);
-    if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
-       !WriteFdExactly(fd, rpath, len)) {
-        return -1;
-    }
+    if (!SendRequest(sc.fd, ID_RECV, rpath)) return -1;
+    if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) return -1;
 
-    if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
-        return -1;
-    }
     id = msg.data.id;
 
-    if((id == ID_DATA) || (id == ID_DONE)) {
+    if (id == ID_DATA || id == ID_DONE) {
         adb_unlink(lpath);
         mkdirs(lpath);
         lfd = adb_creat(lpath, 0644);
         if(lfd < 0) {
-            fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
+            fprintf(stderr, "cannot create '%s': %s\n", lpath, strerror(errno));
             return -1;
         }
         goto handle_data;
@@ -446,37 +323,37 @@
         goto remote_error;
     }
 
-    for(;;) {
-        if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
+    while (true) {
+        if(!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
             return -1;
         }
         id = msg.data.id;
 
     handle_data:
-        len = ltohl(msg.data.size);
-        if(id == ID_DONE) break;
-        if(id != ID_DATA) goto remote_error;
-        if(len > SYNC_DATA_MAX) {
-            fprintf(stderr,"data overrun\n");
+        len = msg.data.size;
+        if (id == ID_DONE) break;
+        if (id != ID_DATA) goto remote_error;
+        if (len > sc.max) {
+            fprintf(stderr, "msg.data.size too large: %zu (max %zu)\n", len, sc.max);
             adb_close(lfd);
             return -1;
         }
 
-        if(!ReadFdExactly(fd, buffer, len)) {
+        if(!ReadFdExactly(sc.fd, buffer, len)) {
             adb_close(lfd);
             return -1;
         }
 
         if(!WriteFdExactly(lfd, buffer, len)) {
-            fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
+            fprintf(stderr, "cannot write '%s': %s\n", rpath, strerror(errno));
             adb_close(lfd);
             return -1;
         }
 
-        total_bytes += len;
+        sc.total_bytes += len;
 
         if (show_progress) {
-            print_transfer_progress(total_bytes, size);
+            print_transfer_progress(sc.total_bytes, size);
         }
     }
 
@@ -488,9 +365,9 @@
     adb_unlink(lpath);
 
     if(id == ID_FAIL) {
-        len = ltohl(msg.data.size);
+        len = msg.data.size;
         if(len > 256) len = 256;
-        if(!ReadFdExactly(fd, buffer, len)) {
+        if(!ReadFdExactly(sc.fd, buffer, len)) {
             return -1;
         }
         buffer[len] = 0;
@@ -498,31 +375,20 @@
         memcpy(buffer, &id, 4);
         buffer[4] = 0;
     }
-    fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
+    fprintf(stderr, "failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
     return 0;
 }
 
-/* --- */
 static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
-                          const char *name, void *cookie)
-{
+                          const char* name, void* /*cookie*/) {
     printf("%08x %08x %08x %s\n", mode, size, time, name);
 }
 
-int do_sync_ls(const char* path) {
-    std::string error;
-    int fd = adb_connect("sync:", &error);
-    if (fd < 0) {
-        fprintf(stderr,"error: %s\n", error.c_str());
-        return 1;
-    }
+bool do_sync_ls(const char* path) {
+    SyncConnection sc;
+    if (!sc.IsValid()) return false;
 
-    if (sync_ls(fd, path, do_sync_ls_cb, 0)) {
-        return 1;
-    }
-
-    sync_quit(fd);
-    return 0;
+    return sync_ls(sc.fd, path, do_sync_ls_cb, 0);
 }
 
 struct copyinfo
@@ -545,7 +411,7 @@
 
     copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
     if(ci == 0) {
-        fprintf(stderr,"out of memory\n");
+        fprintf(stderr, "out of memory\n");
         abort();
     }
 
@@ -562,54 +428,41 @@
     return ci;
 }
 
+static bool IsDotOrDotDot(const char* name) {
+    return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
+}
 
-static int local_build_list(copyinfo **filelist,
-                            const char *lpath, const char *rpath)
-{
-    DIR *d;
-    struct dirent *de;
-    struct stat st;
+static int local_build_list(copyinfo** filelist, const char* lpath, const char* rpath) {
     copyinfo *dirlist = 0;
     copyinfo *ci, *next;
 
-    d = opendir(lpath);
-    if(d == 0) {
-        fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
+    std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(lpath), closedir);
+    if (!dir) {
+        fprintf(stderr, "cannot open '%s': %s\n", lpath, strerror(errno));
         return -1;
     }
 
-    while((de = readdir(d))) {
+    dirent *de;
+    while ((de = readdir(dir.get()))) {
+        if (IsDotOrDotDot(de->d_name)) continue;
+
         char stat_path[PATH_MAX];
-        char *name = de->d_name;
-
-        if(name[0] == '.') {
-            if(name[1] == 0) continue;
-            if((name[1] == '.') && (name[2] == 0)) continue;
-        }
-
-        /*
-         * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
-         * always returns DT_UNKNOWN, so we just use stat() for all cases.
-         */
-        if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
+        if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path)) {
+            fprintf(stderr, "skipping long path '%s%s'\n", lpath, de->d_name);
             continue;
+        }
         strcpy(stat_path, lpath);
         strcat(stat_path, de->d_name);
 
-        if(!lstat(stat_path, &st)) {
+        struct stat st;
+        if (!lstat(stat_path, &st)) {
             if (S_ISDIR(st.st_mode)) {
-                ci = mkcopyinfo(lpath, rpath, name, 1);
+                ci = mkcopyinfo(lpath, rpath, de->d_name, 1);
                 ci->next = dirlist;
                 dirlist = ci;
             } else {
-                ci = mkcopyinfo(lpath, rpath, name, 0);
-                if(lstat(ci->src, &st)) {
-                    fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
-                    free(ci);
-                    closedir(d);
-                    return -1;
-                }
-                if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
+                ci = mkcopyinfo(lpath, rpath, de->d_name, 0);
+                if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
                     fprintf(stderr, "skipping special file '%s'\n", ci->src);
                     free(ci);
                 } else {
@@ -625,9 +478,9 @@
         }
     }
 
-    closedir(d);
-
-    for(ci = dirlist; ci != 0; ci = next) {
+    // Close this directory and recurse.
+    dir.reset();
+    for (ci = dirlist; ci != 0; ci = next) {
         next = ci->next;
         local_build_list(filelist, ci->src, ci->dst);
         free(ci);
@@ -636,60 +489,55 @@
     return 0;
 }
 
-
-static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, int checktimestamps, int listonly)
-{
+static bool copy_local_dir_remote(SyncConnection& sc, const char* lpath, const char* rpath,
+                                  bool check_timestamps, bool list_only) {
     copyinfo *filelist = 0;
     copyinfo *ci, *next;
     int pushed = 0;
     int skipped = 0;
 
-    if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
-    if(lpath[strlen(lpath) - 1] != '/') {
+    if ((lpath[0] == 0) || (rpath[0] == 0)) return false;
+    if (lpath[strlen(lpath) - 1] != '/') {
         int  tmplen = strlen(lpath)+2;
         char *tmp = reinterpret_cast<char*>(malloc(tmplen));
-        if(tmp == 0) return -1;
+        if(tmp == 0) return false;
         snprintf(tmp, tmplen, "%s/",lpath);
         lpath = tmp;
     }
-    if(rpath[strlen(rpath) - 1] != '/') {
+    if (rpath[strlen(rpath) - 1] != '/') {
         int tmplen = strlen(rpath)+2;
         char *tmp = reinterpret_cast<char*>(malloc(tmplen));
-        if(tmp == 0) return -1;
+        if(tmp == 0) return false;
         snprintf(tmp, tmplen, "%s/",rpath);
         rpath = tmp;
     }
 
-    if(local_build_list(&filelist, lpath, rpath)) {
-        return -1;
+    if (local_build_list(&filelist, lpath, rpath)) {
+        return false;
     }
 
-    if(checktimestamps){
-        for(ci = filelist; ci != 0; ci = ci->next) {
-            if(sync_start_readtime(fd, ci->dst)) {
-                return 1;
-            }
+    if (check_timestamps) {
+        for (ci = filelist; ci != 0; ci = ci->next) {
+            if (!sync_start_stat(sc, ci->dst)) return false;
         }
         for(ci = filelist; ci != 0; ci = ci->next) {
             unsigned int timestamp, mode, size;
-            if(sync_finish_readtime(fd, &timestamp, &mode, &size))
-                return 1;
-            if(size == ci->size) {
+            if (!sync_finish_stat(sc, &timestamp, &mode, &size)) return false;
+            if (size == ci->size) {
                 /* for links, we cannot update the atime/mtime */
-                if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
-                    (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
+                if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
+                        (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) {
                     ci->flag = 1;
+                }
             }
         }
     }
-    for(ci = filelist; ci != 0; ci = next) {
+    for (ci = filelist; ci != 0; ci = next) {
         next = ci->next;
-        if(ci->flag == 0) {
-            fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
-            if(!listonly &&
-               sync_send(fd, ci->src, ci->dst, ci->time, ci->mode,
-                         0 /* no show progress */)) {
-                return 1;
+        if (ci->flag == 0) {
+            fprintf(stderr, "%spush: %s -> %s\n", list_only ? "would " : "", ci->src, ci->dst);
+            if (!list_only && !sync_send(sc, ci->src, ci->dst, ci->time, ci->mode, false)) {
+                return false;
             }
             pushed++;
         } else {
@@ -698,55 +546,37 @@
         free(ci);
     }
 
-    fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
+    fprintf(stderr, "%d file%s pushed. %d file%s skipped.\n",
             pushed, (pushed == 1) ? "" : "s",
             skipped, (skipped == 1) ? "" : "s");
 
-    return 0;
+    return true;
 }
 
-
-int do_sync_push(const char* lpath, const char* rpath, bool show_progress) {
-    std::string error;
-    int fd = adb_connect("sync:", &error);
-    if (fd < 0) {
-        fprintf(stderr,"error: %s\n", error.c_str());
-        return 1;
-    }
+bool do_sync_push(const char* lpath, const char* rpath, bool show_progress) {
+    SyncConnection sc;
+    if (!sc.IsValid()) return false;
 
     struct stat st;
     if (stat(lpath, &st)) {
-        fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
-        sync_quit(fd);
-        return 1;
+        fprintf(stderr, "cannot stat '%s': %s\n", lpath, strerror(errno));
+        return false;
     }
 
     if (S_ISDIR(st.st_mode)) {
-        BEGIN();
-        if (copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
-            return 1;
-        }
-    } else {
-        unsigned mode;
-        if (sync_readmode(fd, rpath, &mode)) {
-            return 1;
-        }
-        std::string path_holder;
-        if ((mode != 0) && S_ISDIR(mode)) {
-            // If we're copying a local file to a remote directory,
-            // we really want to copy to remote_dir + "/" + local_filename.
-            path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
-            rpath = path_holder.c_str();
-        }
-        BEGIN();
-        if (sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
-            return 1;
-        }
+        return copy_local_dir_remote(sc, lpath, rpath, false, false);
     }
 
-    END();
-    sync_quit(fd);
-    return 0;
+    unsigned mode;
+    if (!sync_stat(sc, rpath, nullptr, &mode, nullptr)) return false;
+    std::string path_holder;
+    if (mode != 0 && S_ISDIR(mode)) {
+        // If we're copying a local file to a remote directory,
+        // we really want to copy to remote_dir + "/" + local_filename.
+        path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
+        rpath = path_holder.c_str();
+    }
+    return sync_send(sc, lpath, rpath, st.st_mtime, st.st_mode, show_progress);
 }
 
 
@@ -766,11 +596,8 @@
     if (S_ISDIR(mode)) {
         copyinfo **dirlist = args->dirlist;
 
-        /* Don't try recursing down "." or ".." */
-        if (name[0] == '.') {
-            if (name[1] == '\0') return;
-            if ((name[1] == '.') && (name[2] == '\0')) return;
-        }
+        // Don't try recursing down "." or "..".
+        if (IsDotOrDotDot(name)) return;
 
         ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
         ci->next = *dirlist;
@@ -789,9 +616,8 @@
     }
 }
 
-static int remote_build_list(int syncfd, copyinfo **filelist,
-                             const char *rpath, const char *lpath)
-{
+static bool remote_build_list(int syncfd, copyinfo **filelist,
+                              const char *rpath, const char *lpath) {
     copyinfo *dirlist = NULL;
     sync_ls_build_list_cb_args args;
 
@@ -800,22 +626,22 @@
     args.rpath = rpath;
     args.lpath = lpath;
 
-    /* Put the files/dirs in rpath on the lists. */
-    if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
-        return 1;
+    // Put the files/dirs in rpath on the lists.
+    if (!sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
+        return false;
     }
 
-    /* Recurse into each directory we found. */
+    // Recurse into each directory we found.
     while (dirlist != NULL) {
         copyinfo *next = dirlist->next;
-        if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
-            return 1;
+        if (!remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
+            return false;
         }
         free(dirlist);
         dirlist = next;
     }
 
-    return 0;
+    return true;
 }
 
 static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
@@ -831,101 +657,57 @@
     return r1 ? : r2;
 }
 
-/* Return a copy of the path string with / appended if needed */
-static char *add_slash_to_path(const char *path)
-{
-    if (path[strlen(path) - 1] != '/') {
-        size_t len = strlen(path) + 2;
-        char *path_with_slash = reinterpret_cast<char*>(malloc(len));
-        if (path_with_slash == NULL)
-            return NULL;
-        snprintf(path_with_slash, len, "%s/", path);
-        return path_with_slash;
-    } else {
-        return strdup(path);
-    }
-}
+static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const char* lpath,
+                                  int copy_attrs) {
+    // Make sure that both directory paths end in a slash.
+    std::string rpath_clean(rpath);
+    std::string lpath_clean(lpath);
+    if (rpath_clean.empty() || lpath_clean.empty()) return false;
+    if (rpath_clean.back() != '/') rpath_clean.push_back('/');
+    if (lpath_clean.back() != '/') lpath_clean.push_back('/');
 
-static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
-                                 int copy_attrs)
-{
-    copyinfo *filelist = 0;
-    copyinfo *ci, *next;
+    // Recursively build the list of files to copy.
+    fprintf(stderr, "pull: building file list...\n");
+    copyinfo* filelist = nullptr;
+    if (!remote_build_list(sc.fd, &filelist, rpath_clean.c_str(), lpath_clean.c_str())) return false;
+
     int pulled = 0;
     int skipped = 0;
-    char *rpath_clean = NULL;
-    char *lpath_clean = NULL;
-    int ret = 0;
-
-    if (rpath[0] == '\0' || lpath[0] == '\0') {
-        ret = -1;
-        goto finish;
-    }
-
-    /* Make sure that both directory paths end in a slash. */
-    rpath_clean = add_slash_to_path(rpath);
-    if (!rpath_clean) {
-        ret = -1;
-        goto finish;
-    }
-    lpath_clean = add_slash_to_path(lpath);
-    if (!lpath_clean) {
-        ret = -1;
-        goto finish;
-    }
-
-    /* Recursively build the list of files to copy. */
-    fprintf(stderr, "pull: building file list...\n");
-    if (remote_build_list(fd, &filelist, rpath_clean, lpath_clean)) {
-        ret = -1;
-        goto finish;
-    }
-
-    for (ci = filelist; ci != 0; ci = next) {
-        next = ci->next;
+    copyinfo* ci = filelist;
+    while (ci) {
+        copyinfo* next = ci->next;
         if (ci->flag == 0) {
             fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
-            if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
-                ret = -1;
-                goto finish;
+            if (sync_recv(sc, ci->src, ci->dst, false)) {
+                return false;
             }
 
             if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
-                ret = -1;
-                goto finish;
+                return false;
             }
             pulled++;
         } else {
             skipped++;
         }
         free(ci);
+        ci = next;
     }
 
     fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
             pulled, (pulled == 1) ? "" : "s",
             skipped, (skipped == 1) ? "" : "s");
-
-finish:
-    free(lpath_clean);
-    free(rpath_clean);
-    return ret;
+    return true;
 }
 
-int do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs) {
-    std::string error;
-    int fd = adb_connect("sync:", &error);
-    if (fd < 0) {
-        fprintf(stderr,"error: %s\n", error.c_str());
-        return 1;
-    }
+bool do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs) {
+    SyncConnection sc;
+    if (!sc.IsValid()) return false;
 
     unsigned mode, time;
-    if (sync_readtime(fd, rpath, &time, &mode)) {
-        return 1;
-    }
+    if (!sync_stat(sc, rpath, &time, &mode, nullptr)) return false;
     if (mode == 0) {
-        fprintf(stderr,"remote object '%s' does not exist\n", rpath);
-        return 1;
+        fprintf(stderr, "remote object '%s' does not exist\n", rpath);
+        return false;
     }
 
     if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
@@ -939,44 +721,27 @@
                 lpath = path_holder.c_str();
             }
         }
-        BEGIN();
-        if (sync_recv(fd, rpath, lpath, show_progress)) {
-            return 1;
+        if (sync_recv(sc, rpath, lpath, show_progress)) {
+            return false;
         } else {
             if (copy_attrs && set_time_and_mode(lpath, time, mode)) {
-                return 1;
+                return false;
             }
         }
-    } else if(S_ISDIR(mode)) {
-        BEGIN();
-        if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
-            return 1;
-        }
-    } else {
-        fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
-        return 1;
+        return true;
+    } else if (S_ISDIR(mode)) {
+        return copy_remote_dir_local(sc, rpath, lpath, copy_attrs);
     }
-    END();
-    sync_quit(fd);
-    return 0;
+
+    fprintf(stderr, "remote object '%s' not a file or directory\n", rpath);
+    return false;
 }
 
-int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only)
-{
+bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
     fprintf(stderr, "syncing %s...\n", rpath.c_str());
 
-    std::string error;
-    int fd = adb_connect("sync:", &error);
-    if (fd < 0) {
-        fprintf(stderr, "error: %s\n", error.c_str());
-        return 1;
-    }
+    SyncConnection sc;
+    if (!sc.IsValid()) return false;
 
-    BEGIN();
-    if (copy_local_dir_remote(fd, lpath.c_str(), rpath.c_str(), 1, list_only)) {
-        return 1;
-    }
-    END();
-    sync_quit(fd);
-    return 0;
+    return copy_local_dir_remote(sc, lpath.c_str(), rpath.c_str(), true, list_only);
 }
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index a503327..536dbbc 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -34,6 +34,7 @@
 #include "adb_io.h"
 #include "private/android_filesystem_config.h"
 
+#include <base/stringprintf.h>
 #include <base/strings.h>
 
 static bool should_use_fs_config(const std::string& path) {
@@ -70,44 +71,30 @@
             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);
         }
     }
     return true;
 }
 
-static int do_stat(int s, const char *path)
-{
+static bool do_stat(int s, const char* path) {
     syncmsg msg;
-    struct stat st;
-
     msg.stat.id = ID_STAT;
 
-    if(lstat(path, &st)) {
-        msg.stat.mode = 0;
-        msg.stat.size = 0;
-        msg.stat.time = 0;
-    } else {
-        msg.stat.mode = htoll(st.st_mode);
-        msg.stat.size = htoll(st.st_size);
-        msg.stat.time = htoll(st.st_mtime);
-    }
+    struct stat st;
+    memset(&st, 0, sizeof(st));
+    // TODO: add a way to report that the stat failed!
+    lstat(path, &st);
+    msg.stat.mode = st.st_mode;
+    msg.stat.size = st.st_size;
+    msg.stat.time = st.st_mtime;
 
-    return WriteFdExactly(s, &msg.stat, sizeof(msg.stat)) ? 0 : -1;
+    return WriteFdExactly(s, &msg.stat, sizeof(msg.stat));
 }
 
-static int do_list(int s, const char *path)
-{
-    struct dirent *de;
-    struct stat st;
-
-    char tmp[1024 + 256 + 1];
-    char *fname;
-
-    size_t len = strlen(path);
-    memcpy(tmp, path, len);
-    tmp[len] = '/';
-    fname = tmp + len + 1;
+static bool do_list(int s, const char* path) {
+    dirent* de;
 
     syncmsg msg;
     msg.dent.id = ID_DENT;
@@ -116,22 +103,19 @@
     if (!d) goto done;
 
     while ((de = readdir(d.get()))) {
-        int len = strlen(de->d_name);
+        std::string filename(android::base::StringPrintf("%s/%s", path, de->d_name));
 
-            /* not supposed to be possible, but
-               if it does happen, let's not buffer overrun */
-        if(len > 256) continue;
+        struct stat st;
+        if (lstat(filename.c_str(), &st) == 0) {
+            size_t d_name_length = strlen(de->d_name);
+            msg.dent.mode = st.st_mode;
+            msg.dent.size = st.st_size;
+            msg.dent.time = st.st_mtime;
+            msg.dent.namelen = d_name_length;
 
-        strcpy(fname, de->d_name);
-        if(lstat(tmp, &st) == 0) {
-            msg.dent.mode = htoll(st.st_mode);
-            msg.dent.size = htoll(st.st_size);
-            msg.dent.time = htoll(st.st_mtime);
-            msg.dent.namelen = htoll(len);
-
-            if(!WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ||
-               !WriteFdExactly(s, de->d_name, len)) {
-                return -1;
+            if (!WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ||
+                    !WriteFdExactly(s, de->d_name, d_name_length)) {
+                return false;
             }
         }
     }
@@ -142,255 +126,215 @@
     msg.dent.size = 0;
     msg.dent.time = 0;
     msg.dent.namelen = 0;
-    return WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ? 0 : -1;
+    return WriteFdExactly(s, &msg.dent, sizeof(msg.dent));
 }
 
-static int fail_message(int s, const char *reason)
-{
+static bool SendSyncFail(int fd, const std::string& reason) {
+    D("sync: failure: %s\n", reason.c_str());
+
     syncmsg msg;
-    int len = strlen(reason);
-
-    D("sync: failure: %s\n", reason);
-
     msg.data.id = ID_FAIL;
-    msg.data.size = htoll(len);
-    if(!WriteFdExactly(s, &msg.data, sizeof(msg.data)) ||
-       !WriteFdExactly(s, reason, len)) {
-        return -1;
-    } else {
-        return 0;
-    }
+    msg.data.size = reason.size();
+    return WriteFdExactly(fd, &msg.data, sizeof(msg.data)) && WriteFdExactly(fd, reason);
 }
 
-static int 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 int handle_send_file(int s, char *path, uid_t uid,
-        gid_t gid, mode_t mode, char *buffer, bool do_unlink)
-{
+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;
 
-    fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
-    if(fd < 0 && errno == ENOENT) {
+    int fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
+    if (fd < 0 && errno == ENOENT) {
         if (!secure_mkdirs(path)) {
-            if(fail_errno(s))
-                return -1;
-            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 -1;
-        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);
     }
 
-    for(;;) {
+    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) {
-                timestamp = ltohl(msg.data.size);
+        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 = ltohl(msg.data.size);
-        if(len > SYNC_DATA_MAX) {
-            fail_message(s, "oversize data message");
+        len = msg.data.size;
+        if (len > buffer.size()) { // TODO: resize buffer?
+            SendSyncFail(s, "oversize data message");
             goto fail;
         }
-        if(!ReadFdExactly(s, buffer, len))
-            goto fail;
 
-        if(fd < 0)
-            continue;
-        if(!WriteFdExactly(fd, buffer, len)) {
-            int saved_errno = errno;
-            adb_close(fd);
-            if (do_unlink) adb_unlink(path);
-            fd = -1;
-            errno = saved_errno;
-            if(fail_errno(s)) return -1;
+        if (!ReadFdExactly(s, &buffer[0], len)) goto fail;
+
+        if (!WriteFdExactly(fd, &buffer[0], len)) {
+            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 -1;
-    }
-    return 0;
+    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);
+    if (fd >= 0) adb_close(fd);
     if (do_unlink) adb_unlink(path);
-    return -1;
+    return false;
 }
 
 #if defined(_WIN32)
-extern int handle_send_link(int s, char *path, 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 int handle_send_link(int s, char *path, char *buffer)
-{
+static bool handle_send_link(int s, const std::string& path, std::vector<char>& buffer) {
     syncmsg msg;
     unsigned int len;
     int ret;
 
-    if(!ReadFdExactly(s, &msg.data, sizeof(msg.data)))
-        return -1;
+    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");
-        return -1;
+    if (msg.data.id != ID_DATA) {
+        SendSyncFail(s, "invalid data message: expected ID_DATA");
+        return false;
     }
 
-    len = ltohl(msg.data.size);
-    if(len > SYNC_DATA_MAX) {
-        fail_message(s, "oversize data message");
-        return -1;
+    len = msg.data.size;
+    if (len > buffer.size()) { // TODO: resize buffer?
+        SendSyncFail(s, "oversize data message");
+        return false;
     }
-    if(!ReadFdExactly(s, buffer, len))
-        return -1;
+    if (!ReadFdExactly(s, &buffer[0], len)) return false;
 
-    ret = symlink(buffer, path);
-    if(ret && errno == ENOENT) {
+    ret = symlink(&buffer[0], path.c_str());
+    if (ret && errno == ENOENT) {
         if (!secure_mkdirs(path)) {
-            fail_errno(s);
-            return -1;
+            SendSyncFailErrno(s, "secure_mkdirs failed");
+            return false;
         }
-        ret = symlink(buffer, path);
+        ret = symlink(&buffer[0], path.c_str());
     }
-    if(ret) {
-        fail_errno(s);
-        return -1;
+    if (ret) {
+        SendSyncFailErrno(s, "symlink failed");
+        return false;
     }
 
-    if(!ReadFdExactly(s, &msg.data, sizeof(msg.data)))
-        return -1;
+    if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false;
 
-    if(msg.data.id == ID_DONE) {
+    if (msg.data.id == ID_DONE) {
         msg.status.id = ID_OKAY;
         msg.status.msglen = 0;
-        if(!WriteFdExactly(s, &msg.status, sizeof(msg.status)))
-            return -1;
+        if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false;
     } else {
-        fail_message(s, "invalid data message: expected ID_DONE");
-        return -1;
+        SendFail(s, "invalid data message: expected ID_DONE");
+        return false;
     }
 
-    return 0;
+    return true;
 }
 #endif
 
-static int do_send(int s, char *path, 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, NULL, &uid, &gid, &mode, &cap);
+        unsigned int broken_api_hack = mode;
+        fs_config(path.c_str(), 0, nullptr, &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 int do_recv(int s, const char *path, char *buffer)
-{
-    syncmsg msg;
-    int fd, r;
-
-    fd = adb_open(path, O_RDONLY | O_CLOEXEC);
-    if(fd < 0) {
-        if(fail_errno(s)) return -1;
-        return 0;
+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) {
+        SendSyncFailErrno(s, "open failed");
+        return false;
     }
 
+    syncmsg msg;
     msg.data.id = ID_DATA;
-    for(;;) {
-        r = adb_read(fd, buffer, SYNC_DATA_MAX);
-        if(r <= 0) {
-            if(r == 0) break;
-            if(errno == EINTR) continue;
-            r = fail_errno(s);
+    while (true) {
+        int r = adb_read(fd, &buffer[0], buffer.size());
+        if (r <= 0) {
+            if (r == 0) break;
+            SendSyncFailErrno(s, "read failed");
             adb_close(fd);
-            return r;
+            return false;
         }
-        msg.data.size = htoll(r);
-        if(!WriteFdExactly(s, &msg.data, sizeof(msg.data)) ||
-           !WriteFdExactly(s, buffer, r)) {
+        msg.data.size = r;
+        if (!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || !WriteFdExactly(s, &buffer[0], r)) {
             adb_close(fd);
-            return -1;
+            return false;
         }
     }
 
@@ -398,66 +342,62 @@
 
     msg.data.id = ID_DONE;
     msg.data.size = 0;
-    if(!WriteFdExactly(s, &msg.data, sizeof(msg.data))) {
-        return -1;
-    }
-
-    return 0;
+    return WriteFdExactly(s, &msg.data, sizeof(msg.data));
 }
 
-void file_sync_service(int fd, void *cookie)
-{
-    syncmsg msg;
+static bool handle_sync_command(int fd, std::vector<char>& buffer) {
+    D("sync: waiting for request\n");
+
+    SyncRequest request;
+    if (!ReadFdExactly(fd, &request, sizeof(request))) {
+        SendSyncFail(fd, "command read failure");
+        return false;
+    }
+    size_t path_length = request.path_length;
+    if (path_length > 1024) {
+        SendSyncFail(fd, "path too long");
+        return false;
+    }
     char name[1025];
-    unsigned namelen;
+    if (!ReadFdExactly(fd, name, path_length)) {
+        SendSyncFail(fd, "filename read failure");
+        return false;
+    }
+    name[path_length] = 0;
 
-    char *buffer = reinterpret_cast<char*>(malloc(SYNC_DATA_MAX));
-    if(buffer == 0) goto fail;
+    const char* id = reinterpret_cast<const char*>(&request.id);
+    D("sync: '%.4s' '%s'\n", id, name);
 
-    for(;;) {
-        D("sync: waiting for command\n");
-
-        if(!ReadFdExactly(fd, &msg.req, sizeof(msg.req))) {
-            fail_message(fd, "command read failure");
-            break;
-        }
-        namelen = ltohl(msg.req.namelen);
-        if(namelen > 1024) {
-            fail_message(fd, "invalid namelen");
-            break;
-        }
-        if(!ReadFdExactly(fd, name, namelen)) {
-            fail_message(fd, "filename read failure");
-            break;
-        }
-        name[namelen] = 0;
-
-        msg.req.namelen = 0;
-        D("sync: '%s' '%s'\n", (char*) &msg.req, name);
-
-        switch(msg.req.id) {
-        case ID_STAT:
-            if(do_stat(fd, name)) goto fail;
-            break;
-        case ID_LIST:
-            if(do_list(fd, name)) goto fail;
-            break;
-        case ID_SEND:
-            if(do_send(fd, name, buffer)) goto fail;
-            break;
-        case ID_RECV:
-            if(do_recv(fd, name, buffer)) goto fail;
-            break;
-        case ID_QUIT:
-            goto fail;
-        default:
-            fail_message(fd, "unknown command");
-            goto fail;
-        }
+    switch (request.id) {
+      case ID_STAT:
+        if (!do_stat(fd, name)) return false;
+        break;
+      case ID_LIST:
+        if (!do_list(fd, name)) return false;
+        break;
+      case ID_SEND:
+        if (!do_send(fd, name, buffer)) return false;
+        break;
+      case ID_RECV:
+        if (!do_recv(fd, name, buffer)) return false;
+        break;
+      case ID_QUIT:
+        return false;
+      default:
+        SendSyncFail(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)",
+                                                     id, request.id));
+        return false;
     }
 
-fail:
-    if(buffer != 0) free(buffer);
+    return true;
+}
+
+void file_sync_service(int fd, void* cookie) {
+    std::vector<char> buffer(SYNC_DATA_MAX);
+
+    while (handle_sync_command(fd, buffer)) {
+    }
+
     D("sync: done\n");
     adb_close(fd);
 }
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 1d3e3bd..67ed3fc 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -19,14 +19,10 @@
 
 #include <string>
 
-#define htoll(x) (x)
-#define ltohl(x) (x)
-
 #define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
 
 #define ID_STAT MKID('S','T','A','T')
 #define ID_LIST MKID('L','I','S','T')
-#define ID_ULNK MKID('U','L','N','K')
 #define ID_SEND MKID('S','E','N','D')
 #define ID_RECV MKID('R','E','C','V')
 #define ID_DENT MKID('D','E','N','T')
@@ -36,41 +32,41 @@
 #define ID_FAIL MKID('F','A','I','L')
 #define ID_QUIT MKID('Q','U','I','T')
 
+struct SyncRequest {
+    uint32_t id;  // ID_STAT, et cetera.
+    uint32_t path_length;  // <= 1024
+    // Followed by 'path_length' bytes of path (not NUL-terminated).
+} __attribute__((packed)) ;
+
 union syncmsg {
-    unsigned id;
-    struct {
-        unsigned id;
-        unsigned namelen;
-    } req;
-    struct {
+    struct __attribute__((packed)) {
         unsigned id;
         unsigned mode;
         unsigned size;
         unsigned time;
     } stat;
-    struct {
+    struct __attribute__((packed)) {
         unsigned id;
         unsigned mode;
         unsigned size;
         unsigned time;
         unsigned namelen;
     } dent;
-    struct {
+    struct __attribute__((packed)) {
         unsigned id;
         unsigned size;
     } data;
-    struct {
+    struct __attribute__((packed)) {
         unsigned id;
         unsigned msglen;
     } status;
-} ;
+};
 
-
-void file_sync_service(int fd, void *cookie);
-int do_sync_ls(const char *path);
-int do_sync_push(const char *lpath, const char *rpath, bool show_progress);
-int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only);
-int do_sync_pull(const char *rpath, const char *lpath, bool show_progress, int pullTime);
+void file_sync_service(int fd, void* cookie);
+bool do_sync_ls(const char* path);
+bool do_sync_push(const char* lpath, const char* rpath, bool show_progress);
+bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only);
+bool do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs);
 
 #define SYNC_DATA_MAX (64*1024)
 
diff --git a/adb/services.cpp b/adb/services.cpp
index 255be09..c8c2d54 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -438,8 +438,7 @@
 }
 #endif
 
-int service_to_fd(const char *name)
-{
+int service_to_fd(const char* name) {
     int ret = -1;
 
     if(!strncmp(name, "tcp:", 4)) {
@@ -503,13 +502,11 @@
     } else if(!strncmp(name, "unroot:", 7)) {
         ret = create_service_thread(restart_unroot_service, NULL);
     } else if(!strncmp(name, "backup:", 7)) {
-        ret = create_subproc_thread(
-                android::base::StringPrintf("/system/bin/bu backup %s",
-                                            (name + 7)).c_str(),
-                SubprocessType::kRaw);
-    } else if(!strncmp(name, "restore:", 8)) {
-        ret = create_subproc_thread("/system/bin/bu restore",
+        ret = create_subproc_thread(android::base::StringPrintf("/system/bin/bu backup %s",
+                                                                (name + 7)).c_str(),
                                     SubprocessType::kRaw);
+    } else if(!strncmp(name, "restore:", 8)) {
+        ret = create_subproc_thread("/system/bin/bu restore", SubprocessType::kRaw);
     } else if(!strncmp(name, "tcpip:", 6)) {
         int port;
         if (sscanf(name + 6, "%d", &port) != 1) {
@@ -667,8 +664,7 @@
 #endif
 
 #if ADB_HOST
-asocket*  host_service_to_socket(const char*  name, const char *serial)
-{
+asocket* host_service_to_socket(const char* name, const char* serial) {
     if (!strcmp(name,"track-devices")) {
         return create_device_tracker();
     } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 2ea4d44..5e4ffbb 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -140,8 +140,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 +170,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;
         }
     }
@@ -332,10 +330,6 @@
         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);
     kick_transport(t);
     transport_unref(t);
@@ -489,9 +483,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 +503,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;
         }
     }
@@ -865,8 +855,7 @@
 }
 
 bool atransport::CanUseFeature(const std::string& feature) const {
-    return has_feature(feature) &&
-           supported_features().count(feature) > 0;
+    return has_feature(feature) && supported_features().count(feature) > 0;
 }
 
 #if ADB_HOST
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index b1b3538..dc44f16 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -64,6 +64,14 @@
     struct usb_endpoint_descriptor_no_audio sink;
 } __attribute__((packed));
 
+struct ss_func_desc {
+    struct usb_interface_descriptor intf;
+    struct usb_endpoint_descriptor_no_audio source;
+    struct usb_ss_ep_comp_descriptor source_comp;
+    struct usb_endpoint_descriptor_no_audio sink;
+    struct usb_ss_ep_comp_descriptor sink_comp;
+} __attribute__((packed));
+
 struct desc_v1 {
     struct usb_functionfs_descs_head_v1 {
         __le32 magic;
@@ -79,7 +87,9 @@
     // The rest of the structure depends on the flags in the header.
     __le32 fs_count;
     __le32 hs_count;
+    __le32 ss_count;
     struct func_desc fs_descs, hs_descs;
+    struct ss_func_desc ss_descs;
 } __attribute__((packed));
 
 static struct func_desc fs_descriptors = {
@@ -136,6 +146,41 @@
     },
 };
 
+static struct ss_func_desc ss_descriptors = {
+    .intf = {
+        .bLength = sizeof(ss_descriptors.intf),
+        .bDescriptorType = USB_DT_INTERFACE,
+        .bInterfaceNumber = 0,
+        .bNumEndpoints = 2,
+        .bInterfaceClass = ADB_CLASS,
+        .bInterfaceSubClass = ADB_SUBCLASS,
+        .bInterfaceProtocol = ADB_PROTOCOL,
+        .iInterface = 1, /* first string from the provided table */
+    },
+    .source = {
+        .bLength = sizeof(ss_descriptors.source),
+        .bDescriptorType = USB_DT_ENDPOINT,
+        .bEndpointAddress = 1 | USB_DIR_OUT,
+        .bmAttributes = USB_ENDPOINT_XFER_BULK,
+        .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+    },
+    .source_comp = {
+        .bLength = sizeof(ss_descriptors.source_comp),
+        .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+    },
+    .sink = {
+        .bLength = sizeof(ss_descriptors.sink),
+        .bDescriptorType = USB_DT_ENDPOINT,
+        .bEndpointAddress = 2 | USB_DIR_IN,
+        .bmAttributes = USB_ENDPOINT_XFER_BULK,
+        .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+    },
+    .sink_comp = {
+        .bLength = sizeof(ss_descriptors.sink_comp),
+        .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+    },
+};
+
 #define STR_INTERFACE_ "ADB Interface"
 
 static const struct {
@@ -284,11 +329,14 @@
 
     v2_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
     v2_descriptor.header.length = cpu_to_le32(sizeof(v2_descriptor));
-    v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC;
+    v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
+                                 FUNCTIONFS_HAS_SS_DESC;
     v2_descriptor.fs_count = 3;
     v2_descriptor.hs_count = 3;
+    v2_descriptor.ss_count = 5;
     v2_descriptor.fs_descs = fs_descriptors;
     v2_descriptor.hs_descs = hs_descriptors;
+    v2_descriptor.ss_descs = ss_descriptors;
 
     if (h->control < 0) { // might have already done this before
         D("OPENING %s\n", USB_FFS_ADB_EP0);
@@ -383,17 +431,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;
@@ -414,20 +457,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 afa08c1..0ce85f3 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -29,6 +29,9 @@
 #include <inttypes.h>
 #include <stdio.h>
 
+#include <base/logging.h>
+#include <base/stringprintf.h>
+
 #include "adb.h"
 #include "transport.h"
 
@@ -81,7 +84,7 @@
     matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
 
     if (!matchingDict) {
-        DBG("ERR: Couldn't create USB matching dictionary.\n");
+        LOG(ERROR) << "Couldn't create USB matching dictionary.";
         return -1;
     }
 
@@ -115,7 +118,7 @@
     IOUSBDeviceInterface197  **dev = NULL;
     HRESULT                  result;
     SInt32                   score;
-    UInt32                   locationId;
+    uint32_t                 locationId;
     UInt8                    if_class, subclass, protocol;
     UInt16                   vendor;
     UInt16                   product;
@@ -132,7 +135,7 @@
                                                &plugInInterface, &score);
         IOObjectRelease(usbInterface);
         if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
-            DBG("ERR: Unable to create an interface plug-in (%08x)\n", kr);
+            LOG(ERROR) << "Unable to create an interface plug-in (" << std::hex << kr << ")";
             continue;
         }
 
@@ -143,7 +146,7 @@
         //* We only needed the plugin to get the interface, so discard it
         (*plugInInterface)->Release(plugInInterface);
         if (result || !iface) {
-            DBG("ERR: Couldn't query the interface (%08x)\n", (int) result);
+            LOG(ERROR) << "Couldn't query the interface (" << std::hex << result << ")";
             continue;
         }
 
@@ -152,7 +155,8 @@
         kr = (*iface)->GetInterfaceProtocol(iface, &protocol);
         if(if_class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) {
             // Ignore non-ADB devices.
-            DBG("Ignoring interface with incorrect class/subclass/protocol - %d, %d, %d\n", if_class, subclass, protocol);
+            LOG(DEBUG) << "Ignoring interface with incorrect class/subclass/protocol - " << if_class
+                       << ", " << subclass << ", " << protocol;
             (*iface)->Release(iface);
             continue;
         }
@@ -163,7 +167,7 @@
         //* Gotta love OS X
         kr = (*iface)->GetDevice(iface, &usbDevice);
         if (kIOReturnSuccess != kr || !usbDevice) {
-            DBG("ERR: Couldn't grab device from interface (%08x)\n", kr);
+            LOG(ERROR) << "Couldn't grab device from interface (" << std::hex << kr << ")";
             continue;
         }
 
@@ -177,7 +181,7 @@
         //* only needed this to find the plugin
         (void)IOObjectRelease(usbDevice);
         if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
-            DBG("ERR: Unable to create a device plug-in (%08x)\n", kr);
+            LOG(ERROR) << "Unable to create a device plug-in (" << std::hex << kr << ")";
             continue;
         }
 
@@ -186,8 +190,7 @@
         //* only needed this to query the plugin
         (*plugInInterface)->Release(plugInInterface);
         if (result || !dev) {
-            DBG("ERR: Couldn't create a device interface (%08x)\n",
-                (int) result);
+            LOG(ERROR) << "Couldn't create a device interface (" << std::hex << result << ")";
             continue;
         }
 
@@ -197,74 +200,74 @@
         kr = (*dev)->GetDeviceProduct(dev, &product);
         kr = (*dev)->GetLocationID(dev, &locationId);
         if (kr == 0) {
-            snprintf(devpathBuf, sizeof(devpathBuf), "usb:%" PRIu32 "X",
-	             (unsigned int)locationId);
+            snprintf(devpathBuf, sizeof(devpathBuf), "usb:%" PRIu32 "X", locationId);
             devpath = devpathBuf;
         }
         kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
 
-	if (serialIndex > 0) {
-		IOUSBDevRequest req;
-		UInt16          buffer[256];
-		UInt16          languages[128];
+        if (serialIndex > 0) {
+            IOUSBDevRequest req;
+            UInt16          buffer[256];
+            UInt16          languages[128];
 
-		memset(languages, 0, sizeof(languages));
+            memset(languages, 0, sizeof(languages));
 
-		req.bmRequestType =
-			USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
-		req.bRequest = kUSBRqGetDescriptor;
-		req.wValue = (kUSBStringDesc << 8) | 0;
-		req.wIndex = 0;
-		req.pData = languages;
-		req.wLength = sizeof(languages);
-		kr = (*dev)->DeviceRequest(dev, &req);
+            req.bmRequestType =
+                    USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+            req.bRequest = kUSBRqGetDescriptor;
+            req.wValue = (kUSBStringDesc << 8) | 0;
+            req.wIndex = 0;
+            req.pData = languages;
+            req.wLength = sizeof(languages);
+            kr = (*dev)->DeviceRequest(dev, &req);
 
-		if (kr == kIOReturnSuccess && req.wLenDone > 0) {
+            if (kr == kIOReturnSuccess && req.wLenDone > 0) {
 
-			int langCount = (req.wLenDone - 2) / 2, lang;
+                int langCount = (req.wLenDone - 2) / 2, lang;
 
-			for (lang = 1; lang <= langCount; lang++) {
+                for (lang = 1; lang <= langCount; lang++) {
 
-                                memset(buffer, 0, sizeof(buffer));
-                                memset(&req, 0, sizeof(req));
+                    memset(buffer, 0, sizeof(buffer));
+                    memset(&req, 0, sizeof(req));
 
-				req.bmRequestType =
-					USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
-				req.bRequest = kUSBRqGetDescriptor;
-				req.wValue = (kUSBStringDesc << 8) | serialIndex;
-				req.wIndex = languages[lang];
-				req.pData = buffer;
-				req.wLength = sizeof(buffer);
-				kr = (*dev)->DeviceRequest(dev, &req);
+                    req.bmRequestType =
+                            USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+                    req.bRequest = kUSBRqGetDescriptor;
+                    req.wValue = (kUSBStringDesc << 8) | serialIndex;
+                    req.wIndex = languages[lang];
+                    req.pData = buffer;
+                    req.wLength = sizeof(buffer);
+                    kr = (*dev)->DeviceRequest(dev, &req);
 
-				if (kr == kIOReturnSuccess && req.wLenDone > 0) {
-					int i, count;
+                    if (kr == kIOReturnSuccess && req.wLenDone > 0) {
+                        int i, count;
 
-					// skip first word, and copy the rest to the serial string,
-					// changing shorts to bytes.
-					count = (req.wLenDone - 1) / 2;
-					for (i = 0; i < count; i++)
-						serial[i] = buffer[i + 1];
-					serial[i] = 0;
-                                        break;
-				}
-			}
-		}
-	}
+                        // skip first word, and copy the rest to the serial string,
+                        // changing shorts to bytes.
+                        count = (req.wLenDone - 1) / 2;
+                        for (i = 0; i < count; i++)
+                                serial[i] = buffer[i + 1];
+                        serial[i] = 0;
+                        break;
+                    }
+                }
+            }
+        }
+
         (*dev)->Release(dev);
 
-        DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product,
-            serial);
+        LOG(INFO) << android::base::StringPrintf("Found vid=%04x pid=%04x serial=%s\n",
+                        vendor, product, serial);
 
         usb_handle* handle = CheckInterface((IOUSBInterfaceInterface190**)iface,
                                             vendor, product);
         if (handle == NULL) {
-            DBG("ERR: Could not find device interface: %08x\n", kr);
+            LOG(ERROR) << "Could not find device interface";
             (*iface)->Release(iface);
             continue;
         }
 
-        DBG("AndroidDeviceAdded calling register_usb_transport\n");
+        LOG(DEBUG) << "AndroidDeviceAdded calling register_usb_transport";
         register_usb_transport(handle, (serial[0] ? serial : NULL), devpath, 1);
 
         // Register for an interest notification of this device being removed.
@@ -278,7 +281,7 @@
                 &handle->usbNotification);
 
         if (kIOReturnSuccess != kr) {
-            DBG("ERR: Unable to create interest notification (%08x)\n", kr);
+            LOG(ERROR) << "Unable to create interest notification (" << std::hex << kr << ")";
         }
     }
 }
@@ -290,10 +293,10 @@
 
     if (messageType == kIOMessageServiceIsTerminated) {
         if (!handle) {
-            DBG("ERR: NULL handle\n");
+            LOG(ERROR) << "NULL handle";
             return;
         }
-        DBG("AndroidInterfaceNotify\n");
+        LOG(DEBUG) << "AndroidInterfaceNotify";
         IOObjectRelease(handle->usbNotification);
         usb_kick(handle);
     }
@@ -305,7 +308,7 @@
 static bool ClearPipeStallBothEnds(IOUSBInterfaceInterface190** interface, UInt8 bulkEp) {
     IOReturn rc = (*interface)->ClearPipeStallBothEnds(interface, bulkEp);
     if (rc != kIOReturnSuccess) {
-        DBG("ERR: Could not clear pipe: (%08x)\n",  rc);
+        LOG(ERROR) << "Could not clear pipe stall both ends: " << std::hex << rc;
         return false;
     }
     return true;
@@ -325,14 +328,14 @@
     //* the endpoints in the interface descriptor to be instantiated
     kr = (*interface)->USBInterfaceOpen(interface);
     if (kr != kIOReturnSuccess) {
-        DBG("ERR: Could not open interface: (%08x)\n", kr);
+        LOG(ERROR) << "Could not open interface: " << std::hex << kr;
         return NULL;
     }
 
     //* Get the number of endpoints associated with this interface
     kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
     if (kr != kIOReturnSuccess) {
-        DBG("ERR: Unable to get number of endpoints: (%08x)\n", kr);
+        LOG(ERROR) << "Unable to get number of endpoints: " << std::hex << kr;
         goto err_get_num_ep;
     }
 
@@ -340,7 +343,7 @@
     if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess ||
             (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess ||
             (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess) {
-            DBG("ERR: Unable to get interface class, subclass and protocol\n");
+            LOG(ERROR) << "Unable to get interface class, subclass and protocol";
             goto err_get_interface_class;
     }
 
@@ -365,7 +368,8 @@
         kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
                 &number, &transferType, &maxPacketSize, &interval);
         if (kr != kIOReturnSuccess) {
-            DBG("ERR: FindDeviceInterface - could not get pipe properties (%08x)\n", kr);
+            LOG(ERROR) << "FindDeviceInterface - could not get pipe properties: "
+                       << std::hex << kr;
             goto err_get_pipe_props;
         }
 
@@ -414,12 +418,12 @@
     IOObjectRelease(notificationIterator);
     IONotificationPortDestroy(notificationPort);
 
-    DBG("RunLoopThread done\n");
+    LOG(DEBUG) << "RunLoopThread done";
     return NULL;
 }
 
 static void usb_cleanup() {
-    DBG("usb_cleanup\n");
+    LOG(DEBUG) << "usb_cleanup";
     close_usb_devices();
     if (currentRunLoop)
         CFRunLoopStop(currentRunLoop);
@@ -460,18 +464,17 @@
         return -1;
 
     if (NULL == handle->interface) {
-        DBG("ERR: usb_write interface was null\n");
+        LOG(ERROR) << "usb_write interface was null";
         return -1;
     }
 
     if (0 == handle->bulkOut) {
-        DBG("ERR: bulkOut endpoint not assigned\n");
+        LOG(ERROR) << "bulkOut endpoint not assigned";
         return -1;
     }
 
     result =
-        (*handle->interface)->WritePipe(
-                              handle->interface, handle->bulkOut, (void *)buf, len);
+        (*handle->interface)->WritePipe(handle->interface, handle->bulkOut, (void *)buf, len);
 
     if ((result == 0) && (handle->zero_mask)) {
         /* we need 0-markers and our transfer */
@@ -485,7 +488,7 @@
     if (0 == result)
         return 0;
 
-    DBG("ERR: usb_write failed with status %d\n", result);
+    LOG(ERROR) << "usb_write failed with status: " << std::hex << result;
     return -1;
 }
 
@@ -503,19 +506,19 @@
     }
 
     if (NULL == handle->interface) {
-        DBG("ERR: usb_read interface was null\n");
+        LOG(ERROR) << "usb_read interface was null";
         return -1;
     }
 
     if (0 == handle->bulkIn) {
-        DBG("ERR: bulkIn endpoint not assigned\n");
+        LOG(ERROR) << "bulkIn endpoint not assigned";
         return -1;
     }
 
     result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes);
 
     if (kIOUSBPipeStalled == result) {
-        DBG(" Pipe stalled, clearing stall.\n");
+        LOG(ERROR) << "Pipe stalled, clearing stall.\n";
         (*handle->interface)->ClearPipeStall(handle->interface, handle->bulkIn);
         result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes);
     }
@@ -523,7 +526,7 @@
     if (kIOReturnSuccess == result)
         return 0;
     else {
-        DBG("ERR: usb_read failed with status %x\n", result);
+        LOG(ERROR) << "usb_read failed with status: " << std::hex << result;
     }
 
     return -1;
@@ -536,6 +539,7 @@
 
 void usb_kick(usb_handle *handle)
 {
+    LOG(INFO) << "Kicking handle";
     /* release the interface */
     if (!handle)
         return;
diff --git a/crash_reporter/Android.mk b/crash_reporter/Android.mk
new file mode 100644
index 0000000..6b98af4
--- /dev/null
+++ b/crash_reporter/Android.mk
@@ -0,0 +1,129 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(HOST_OS),linux)
+
+crash_reporter_cpp_extension := .cc
+
+crash_reporter_src := crash_collector.cc \
+    kernel_collector.cc \
+    kernel_warning_collector.cc \
+    udev_collector.cc \
+    unclean_shutdown_collector.cc \
+    user_collector.cc
+
+crash_reporter_includes := external/gtest/include
+
+crash_reporter_test_src := crash_collector_test.cc \
+    crash_reporter_logs_test.cc \
+    kernel_collector_test.cc \
+    testrunner.cc \
+    udev_collector_test.cc \
+    unclean_shutdown_collector_test.cc \
+    user_collector_test.cc
+
+warn_collector_src := warn_collector.l
+
+# Crash reporter static library.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcrash
+LOCAL_CPP_EXTENSION := $(crash_reporter_cpp_extension)
+LOCAL_C_INCLUDES := $(crash_reporter_includes)
+LOCAL_RTTI_FLAG := -frtti
+LOCAL_SHARED_LIBRARIES := libchrome \
+    libchromeos \
+    libcutils \
+    libdbus \
+    libmetrics \
+    libpcrecpp
+LOCAL_SRC_FILES := $(crash_reporter_src)
+include $(BUILD_STATIC_LIBRARY)
+
+# Crash reporter client.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := crash_reporter
+LOCAL_CPP_EXTENSION := $(crash_reporter_cpp_extension)
+LOCAL_C_INCLUDES := $(crash_reporter_includes)
+LOCAL_REQUIRED_MODULES := core2md \
+    crash_reporter_logs.conf \
+    crash_sender \
+    dbus-send \
+    init.crash_reporter.rc
+LOCAL_RTTI_FLAG := -frtti
+LOCAL_SHARED_LIBRARIES := libchrome \
+    libchromeos \
+    libcutils \
+    libdbus \
+    libmetrics \
+    libpcrecpp
+LOCAL_SRC_FILES := crash_reporter.cc
+LOCAL_STATIC_LIBRARIES := libcrash
+include $(BUILD_EXECUTABLE)
+
+# Crash sender script.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := crash_sender
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
+LOCAL_SRC_FILES := crash_sender
+include $(BUILD_PREBUILT)
+
+# Warn collector client.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := warn_collector
+LOCAL_CPP_EXTENSION := $(crash_reporter_cpp_extension)
+LOCAL_SHARED_LIBRARIES := libmetrics
+LOCAL_SRC_FILES := $(warn_collector_src)
+include $(BUILD_EXECUTABLE)
+
+# Crash reporter init script.
+# ========================================================
+ifdef TARGET_COPY_OUT_INITRCD
+include $(CLEAR_VARS)
+LOCAL_MODULE := init.crash_reporter.rc
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_INITRCD)
+LOCAL_SRC_FILES := init.crash_reporter.rc
+include $(BUILD_PREBUILT)
+endif
+
+# Crash reporter logs conf file.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := crash_reporter_logs.conf
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/etc
+LOCAL_SRC_FILES := crash_reporter_logs.conf
+include $(BUILD_PREBUILT)
+
+# Crash reporter tests.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := crash_reporter_tests
+LOCAL_CPP_EXTENSION := $(crash_reporter_cpp_extension)
+LOCAL_SHARED_LIBRARIES := libchrome \
+    libchromeos \
+    libdbus \
+    libpcrecpp
+LOCAL_SRC_FILES := $(crash_reporter_test_src)
+LOCAL_STATIC_LIBRARIES := libcrash libgmock
+include $(BUILD_NATIVE_TEST)
+
+endif # HOST_OS == linux
diff --git a/crash_reporter/MODULE_LICENSE_BSD b/crash_reporter/MODULE_LICENSE_BSD
deleted file mode 100644
index e69de29..0000000
--- a/crash_reporter/MODULE_LICENSE_BSD
+++ /dev/null
diff --git a/crash_reporter/NOTICE b/crash_reporter/NOTICE
deleted file mode 100644
index b9e779f..0000000
--- a/crash_reporter/NOTICE
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//    * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//    * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//    * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/crash_reporter/crash_collector.cc b/crash_reporter/crash_collector.cc
index 5406160..77755f4 100644
--- a/crash_reporter/crash_collector.cc
+++ b/crash_reporter/crash_collector.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 "crash_collector.h"
 
diff --git a/crash_reporter/crash_collector.h b/crash_reporter/crash_collector.h
index 0c28048..cfd76fd 100644
--- a/crash_reporter/crash_collector.h
+++ b/crash_reporter/crash_collector.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #ifndef CRASH_REPORTER_CRASH_COLLECTOR_H_
 #define CRASH_REPORTER_CRASH_COLLECTOR_H_
diff --git a/crash_reporter/crash_collector_test.cc b/crash_reporter/crash_collector_test.cc
index 28c4462..32cbe9f 100644
--- a/crash_reporter/crash_collector_test.cc
+++ b/crash_reporter/crash_collector_test.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 "crash_collector_test.h"
 
diff --git a/crash_reporter/crash_collector_test.h b/crash_reporter/crash_collector_test.h
index c875d44..cfbb97b 100644
--- a/crash_reporter/crash_collector_test.h
+++ b/crash_reporter/crash_collector_test.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #ifndef CRASH_REPORTER_CRASH_COLLECTOR_TEST_H_
 #define CRASH_REPORTER_CRASH_COLLECTOR_TEST_H_
diff --git a/crash_reporter/crash_reporter.cc b/crash_reporter/crash_reporter.cc
index 0e45992..23bd342 100644
--- a/crash_reporter/crash_reporter.cc
+++ b/crash_reporter/crash_reporter.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 <fcntl.h>  // for open
 
@@ -74,7 +86,7 @@
 static void CountUserCrash() {
   SendCrashMetrics(kCrashKindUser, "user");
   std::string command = StringPrintf(
-      "/usr/bin/dbus-send --type=signal --system / \"%s\" &",
+      "/system/bin/dbus-send --type=signal --system / \"%s\" &",
       kUserCrashSignal);
   // Announce through D-Bus whenever a user crash happens. This is
   // used by the metrics daemon to log active use time between
diff --git a/crash_reporter/crash_reporter_logs.conf b/crash_reporter/crash_reporter_logs.conf
index f5ca80c..7db308c 100644
--- a/crash_reporter/crash_reporter_logs.conf
+++ b/crash_reporter/crash_reporter_logs.conf
@@ -1,6 +1,16 @@
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can
-# be found in the LICENSE file.
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
 
 # This file is parsed by chromeos::KeyValueStore. It has the format:
 #
diff --git a/crash_reporter/crash_reporter_logs_test.cc b/crash_reporter/crash_reporter_logs_test.cc
index 9879470..c9ca02d 100644
--- a/crash_reporter/crash_reporter_logs_test.cc
+++ b/crash_reporter/crash_reporter_logs_test.cc
@@ -1,6 +1,18 @@
-// Copyright 2015 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #include <string>
 
diff --git a/crash_reporter/crash_sender b/crash_reporter/crash_sender
index 641ae2d..fa2f8fc 100755
--- a/crash_reporter/crash_sender
+++ b/crash_reporter/crash_sender
@@ -1,8 +1,18 @@
 #!/bin/sh
 
-# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
+# Copyright (C) 2010 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.
 
 set -e
 
diff --git a/crash_reporter/init.crash_reporter.rc b/crash_reporter/init.crash_reporter.rc
index f65371a..6882b77 100644
--- a/crash_reporter/init.crash_reporter.rc
+++ b/crash_reporter/init.crash_reporter.rc
@@ -12,7 +12,6 @@
 
     # Create crash directories.
     mkdir /data/misc/crash_reporter 0700 root root
-    mkdir /data/local/tmp/crash_reporter 0700 root root
 
 service crash_reporter /system/bin/crash_reporter --init
     class late_start
diff --git a/crash_reporter/kernel_collector.cc b/crash_reporter/kernel_collector.cc
index b3cbede..12b00b9 100644
--- a/crash_reporter/kernel_collector.cc
+++ b/crash_reporter/kernel_collector.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 "kernel_collector.h"
 
diff --git a/crash_reporter/kernel_collector.h b/crash_reporter/kernel_collector.h
index 5fc4ac2..206ee26 100644
--- a/crash_reporter/kernel_collector.h
+++ b/crash_reporter/kernel_collector.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #ifndef CRASH_REPORTER_KERNEL_COLLECTOR_H_
 #define CRASH_REPORTER_KERNEL_COLLECTOR_H_
diff --git a/crash_reporter/kernel_collector_test.cc b/crash_reporter/kernel_collector_test.cc
index a534803..e690b77 100644
--- a/crash_reporter/kernel_collector_test.cc
+++ b/crash_reporter/kernel_collector_test.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 "kernel_collector_test.h"
 
diff --git a/crash_reporter/kernel_collector_test.h b/crash_reporter/kernel_collector_test.h
index d450134..f689e7d 100644
--- a/crash_reporter/kernel_collector_test.h
+++ b/crash_reporter/kernel_collector_test.h
@@ -1,6 +1,18 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #ifndef CRASH_REPORTER_KERNEL_COLLECTOR_TEST_H_
 #define CRASH_REPORTER_KERNEL_COLLECTOR_TEST_H_
diff --git a/crash_reporter/kernel_log_collector.sh b/crash_reporter/kernel_log_collector.sh
index d38479e..82512c2 100644
--- a/crash_reporter/kernel_log_collector.sh
+++ b/crash_reporter/kernel_log_collector.sh
@@ -1,8 +1,18 @@
 #!/bin/sh
 
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
+# Copyright (C) 2013 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.
 
 # Usage example: "kernel_log_collector.sh XXX YYY"
 # This script searches logs in the /var/log/messages which have the keyword XXX.
diff --git a/crash_reporter/kernel_warning_collector.cc b/crash_reporter/kernel_warning_collector.cc
index 4cf7640..e28e8fd 100644
--- a/crash_reporter/kernel_warning_collector.cc
+++ b/crash_reporter/kernel_warning_collector.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 "kernel_warning_collector.h"
 
diff --git a/crash_reporter/kernel_warning_collector.h b/crash_reporter/kernel_warning_collector.h
index 82c509c..5ccb780 100644
--- a/crash_reporter/kernel_warning_collector.h
+++ b/crash_reporter/kernel_warning_collector.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #ifndef CRASH_REPORTER_KERNEL_WARNING_COLLECTOR_H_
 #define CRASH_REPORTER_KERNEL_WARNING_COLLECTOR_H_
diff --git a/crash_reporter/list_proxies.cc b/crash_reporter/list_proxies.cc
index de6ef0a..a39441d 100644
--- a/crash_reporter/list_proxies.cc
+++ b/crash_reporter/list_proxies.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2011 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 <sysexits.h>
 #include <unistd.h>  // for isatty()
diff --git a/crash_reporter/testrunner.cc b/crash_reporter/testrunner.cc
index d45bbf8..a8c717e 100644
--- a/crash_reporter/testrunner.cc
+++ b/crash_reporter/testrunner.cc
@@ -1,6 +1,18 @@
-// Copyright 2015 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #include <chromeos/test_helpers.h>
 #include <gtest/gtest.h>
diff --git a/crash_reporter/udev_collector.cc b/crash_reporter/udev_collector.cc
index 85f40db..576fdbd 100644
--- a/crash_reporter/udev_collector.cc
+++ b/crash_reporter/udev_collector.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 "udev_collector.h"
 
diff --git a/crash_reporter/udev_collector.h b/crash_reporter/udev_collector.h
index d9b37eb..e267b75 100644
--- a/crash_reporter/udev_collector.h
+++ b/crash_reporter/udev_collector.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #ifndef CRASH_REPORTER_UDEV_COLLECTOR_H_
 #define CRASH_REPORTER_UDEV_COLLECTOR_H_
diff --git a/crash_reporter/udev_collector_test.cc b/crash_reporter/udev_collector_test.cc
index 4897b91..a6643fb 100644
--- a/crash_reporter/udev_collector_test.cc
+++ b/crash_reporter/udev_collector_test.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #include <base/files/file_enumerator.h>
 #include <base/files/file_util.h>
diff --git a/crash_reporter/unclean_shutdown_collector.cc b/crash_reporter/unclean_shutdown_collector.cc
index a6da1bb..8a092ec 100644
--- a/crash_reporter/unclean_shutdown_collector.cc
+++ b/crash_reporter/unclean_shutdown_collector.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2010 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 "unclean_shutdown_collector.h"
 
diff --git a/crash_reporter/unclean_shutdown_collector.h b/crash_reporter/unclean_shutdown_collector.h
index 2ce0842..5bc9968 100644
--- a/crash_reporter/unclean_shutdown_collector.h
+++ b/crash_reporter/unclean_shutdown_collector.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #ifndef CRASH_REPORTER_UNCLEAN_SHUTDOWN_COLLECTOR_H_
 #define CRASH_REPORTER_UNCLEAN_SHUTDOWN_COLLECTOR_H_
diff --git a/crash_reporter/unclean_shutdown_collector_test.cc b/crash_reporter/unclean_shutdown_collector_test.cc
index dc420fb..c5c0662 100644
--- a/crash_reporter/unclean_shutdown_collector_test.cc
+++ b/crash_reporter/unclean_shutdown_collector_test.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2010 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 "unclean_shutdown_collector.h"
 
diff --git a/crash_reporter/user_collector.cc b/crash_reporter/user_collector.cc
index 6bf9120..61ccc37 100644
--- a/crash_reporter/user_collector.cc
+++ b/crash_reporter/user_collector.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 "user_collector.h"
 
@@ -12,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>
@@ -25,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";
@@ -33,7 +47,7 @@
 
 static const char kStatePrefix[] = "State:\t";
 
-static const char kCoreTempFolder[] = "/data/local/tmp/crash_reporter";
+static const char kCoreTempFolder[] = "/data/misc/crash_reporter/tmp";
 
 // Define an otherwise invalid value that represents an unknown UID.
 static const uid_t kUnknownUid = -1;
@@ -65,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/crash_reporter/user_collector.h b/crash_reporter/user_collector.h
index dd42457..8c38aa2 100644
--- a/crash_reporter/user_collector.h
+++ b/crash_reporter/user_collector.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #ifndef CRASH_REPORTER_USER_COLLECTOR_H_
 #define CRASH_REPORTER_USER_COLLECTOR_H_
diff --git a/crash_reporter/user_collector_test.cc b/crash_reporter/user_collector_test.cc
index 3c59521..4419e7c 100644
--- a/crash_reporter/user_collector_test.cc
+++ b/crash_reporter/user_collector_test.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 "user_collector.h"
 
diff --git a/crash_reporter/warn_collector.l b/crash_reporter/warn_collector.l
index de746fe..70ab25c 100644
--- a/crash_reporter/warn_collector.l
+++ b/crash_reporter/warn_collector.l
@@ -1,6 +1,17 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  *
  * This flex program reads /var/log/messages as it grows and saves kernel
  * warnings to files.  It keeps track of warnings it has seen (based on
diff --git a/crash_reporter/warn_collector_test.c b/crash_reporter/warn_collector_test.c
index 7e25d01..7ebe0a8 100644
--- a/crash_reporter/warn_collector_test.c
+++ b/crash_reporter/warn_collector_test.c
@@ -1,6 +1,17 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
+/*
+ * Copyright (C) 2013 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.
  */
 
 /*
diff --git a/crash_reporter/warn_collector_test.sh b/crash_reporter/warn_collector_test.sh
index d9bb6f9..a5af16c 100755
--- a/crash_reporter/warn_collector_test.sh
+++ b/crash_reporter/warn_collector_test.sh
@@ -1,7 +1,18 @@
 #! /bin/bash
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
+
+# Copyright (C) 2013 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.
 
 # Test for warn_collector.  Run the warn collector in the background, emulate
 # the kernel by appending lines to the log file "messages", and observe the log
diff --git a/crash_reporter/warn_collector_test_reporter.sh b/crash_reporter/warn_collector_test_reporter.sh
index d8f3fad..b6096ed 100755
--- a/crash_reporter/warn_collector_test_reporter.sh
+++ b/crash_reporter/warn_collector_test_reporter.sh
@@ -1,7 +1,18 @@
 #! /bin/sh
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
+
+# Copyright (C) 2013 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.
 
 # Replacement for the crash reporter, for testing.  Log the first line of the
 # "warning" file, which by convention contains the warning hash, and remove the
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 3fca709..f7a5f82 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -27,6 +27,9 @@
 
 LOCAL_CPPFLAGS := $(common_cppflags)
 
+LOCAL_INIT_RC_32 := debuggerd.rc
+LOCAL_INIT_RC_64 := debuggerd64.rc
+
 ifeq ($(TARGET_IS_64_BIT),true)
 LOCAL_CPPFLAGS += -DTARGET_IS_64_BIT
 endif
diff --git a/debuggerd/debuggerd.rc b/debuggerd/debuggerd.rc
new file mode 100644
index 0000000..4338ae9
--- /dev/null
+++ b/debuggerd/debuggerd.rc
@@ -0,0 +1,2 @@
+service debuggerd /system/bin/debuggerd
+    class main
diff --git a/debuggerd/debuggerd64.rc b/debuggerd/debuggerd64.rc
new file mode 100644
index 0000000..341a329
--- /dev/null
+++ b/debuggerd/debuggerd64.rc
@@ -0,0 +1,2 @@
+service debuggerd64 /system/bin/debuggerd64
+    class main
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 5d7b151..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,19 +167,15 @@
     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) {
+    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;
 
@@ -246,21 +227,20 @@
         if(usb) return usb;
         if(announce) {
             announce = 0;
-            fprintf(stderr,"< waiting for device >\n");
+            fprintf(stderr, "< waiting for %s >\n", serial ? serial : "any device");
         }
         usleep(1000);
     }
 }
 
-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/fastboot/usb_osx.cpp b/fastboot/usb_osx.cpp
index 7ae2aa5..45ae833 100644
--- a/fastboot/usb_osx.cpp
+++ b/fastboot/usb_osx.cpp
@@ -293,6 +293,13 @@
 
     // So, we have a device, finally. Grab its vitals.
 
+
+    kr = (*dev)->USBDeviceOpen(dev);
+    if (kr != 0) {
+        WARN("USBDeviceOpen");
+        goto out;
+    }
+
     kr = (*dev)->GetDeviceVendor(dev, &handle->info.dev_vendor);
     if (kr != 0) {
         ERR("GetDeviceVendor");
@@ -365,12 +372,16 @@
         goto error;
     }
 
+    out:
+
+    (*dev)->USBDeviceClose(dev);
     (*dev)->Release(dev);
     return 0;
 
     error:
 
     if (dev != NULL) {
+        (*dev)->USBDeviceClose(dev);
         (*dev)->Release(dev);
     }
 
diff --git a/gatekeeperd/Android.mk b/gatekeeperd/Android.mk
index 55b2d5e..3f78955 100644
--- a/gatekeeperd/Android.mk
+++ b/gatekeeperd/Android.mk
@@ -36,6 +36,7 @@
 	libkeystore_binder
 LOCAL_STATIC_LIBRARIES := libscrypt_static
 LOCAL_C_INCLUDES := external/scrypt/lib/crypto
+LOCAL_INIT_RC := gatekeeperd.rc
 include $(BUILD_EXECUTABLE)
 
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/gatekeeperd/gatekeeperd.rc b/gatekeeperd/gatekeeperd.rc
new file mode 100644
index 0000000..3f1b92d
--- /dev/null
+++ b/gatekeeperd/gatekeeperd.rc
@@ -0,0 +1,3 @@
+service gatekeeperd /system/bin/gatekeeperd /data/misc/gatekeeper
+    class late_start
+    user system
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index ed773d0..cb77a8e 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -183,6 +183,7 @@
     props.chargerWirelessOnline = false;
     props.batteryStatus = BATTERY_STATUS_UNKNOWN;
     props.batteryHealth = BATTERY_HEALTH_UNKNOWN;
+    props.maxChargingCurrent = 0;
 
     if (!mHealthdConfig->batteryPresentPath.isEmpty())
         props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
@@ -194,6 +195,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);
@@ -237,6 +247,15 @@
                     KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
                                  mChargerNames[i].string());
                 }
+                path.clear();
+                path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
+                                  mChargerNames[i].string());
+                if (access(path.string(), R_OK) == 0) {
+                    int maxChargingCurrent = getIntField(path);
+                    if (props.maxChargingCurrent < maxChargingCurrent) {
+                        props.maxChargingCurrent = maxChargingCurrent;
+                    }
+                }
             }
         }
     }
@@ -245,7 +264,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 +274,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" : "",
@@ -365,9 +392,9 @@
     int v;
     char vs[128];
 
-    snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d\n",
+    snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d current_max: %d\n",
              props.chargerAcOnline, props.chargerUsbOnline,
-             props.chargerWirelessOnline);
+             props.chargerWirelessOnline, props.maxChargingCurrent);
     write(fd, vs, strlen(vs));
     snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
              props.batteryStatus, props.batteryHealth, props.batteryPresent);
@@ -394,6 +421,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 +518,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 +534,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 +611,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 b0002cc..85888c3 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,
     .boot_min_cap = 0,
     .screen_on = NULL,
diff --git a/healthd/healthd.h b/healthd/healthd.h
index 84b6d76..34ea55f 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 *);
     int boot_min_cap;
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/utils/JenkinsHash.h b/include/utils/JenkinsHash.h
index 7da5dbd..027c10c 100644
--- a/include/utils/JenkinsHash.h
+++ b/include/utils/JenkinsHash.h
@@ -29,6 +29,9 @@
 /* The Jenkins hash of a sequence of 32 bit words A, B, C is:
  * Whiten(Mix(Mix(Mix(0, A), B), C)) */
 
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
 inline uint32_t JenkinsHashMix(uint32_t hash, uint32_t data) {
     hash += data;
     hash += (hash << 10);
diff --git a/init/action.cpp b/init/action.cpp
index 2eb809e..dd366d3 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -154,7 +154,7 @@
     const static std::string prop_str("property:");
     for (std::size_t i = 0; i < args.size(); ++i) {
         if (i % 2) {
-            if (args[i].compare("&&")) {
+            if (args[i] != "&&") {
                 *err = "&& is the only symbol allowed to concatenate actions";
                 return false;
             } else {
@@ -189,24 +189,24 @@
 bool Action::CheckPropertyTriggers(const std::string& name,
                                    const std::string& value) const
 {
-    bool found = !name.compare("");
+    bool found = name.empty();
     if (property_triggers_.empty()) {
         return true;
     }
 
     for (const auto& t : property_triggers_) {
-        if (!t.first.compare(name)) {
-            if (t.second.compare("*") &&
-                t.second.compare(value)) {
+        const auto& trigger_name = t.first;
+        const auto& trigger_value = t.second;
+        if (trigger_name == name) {
+            if (trigger_value != "*" && trigger_value != value) {
                 return false;
             } else {
                 found = true;
             }
         } else {
-            std::string prop_val = property_get(t.first.c_str());
-            if (prop_val.empty() ||
-                (t.second.compare("*") &&
-                 t.second.compare(prop_val))) {
+            std::string prop_val = property_get(trigger_name.c_str());
+            if (prop_val.empty() || (trigger_value != "*" &&
+                                     trigger_value != prop_val)) {
                 return false;
             }
         }
@@ -217,7 +217,7 @@
 bool Action::CheckEventTrigger(const std::string& trigger) const
 {
     return !event_trigger_.empty() &&
-        !trigger.compare(event_trigger_) &&
+        trigger == event_trigger_ &&
         CheckPropertyTriggers();
 }
 
@@ -229,10 +229,8 @@
 
 bool Action::TriggersEqual(const class Action& other) const
 {
-    return property_triggers_.size() == other.property_triggers_.size() &&
-        std::equal(property_triggers_.begin(), property_triggers_.end(),
-                   other.property_triggers_.begin()) &&
-        !event_trigger_.compare(other.event_trigger_);
+    return property_triggers_ == other.property_triggers_ &&
+        event_trigger_ == other.event_trigger_;
 }
 
 std::string Action::BuildTriggersString() const
@@ -255,19 +253,53 @@
 
 void Action::DumpState() const
 {
-    INFO("on ");
     std::string trigger_name = BuildTriggersString();
-    INFO("%s", trigger_name.c_str());
-    INFO("\n");
+    INFO("on %s\n", trigger_name.c_str());
 
     for (const auto& c : commands_) {
         std::string cmd_str = c->BuildCommandString();
-        INFO(" %s", cmd_str.c_str());
+        INFO(" %s\n", cmd_str.c_str());
     }
     INFO("\n");
 }
 
-ActionManager::ActionManager() : cur_command_(0)
+
+class EventTrigger : public Trigger {
+public:
+    EventTrigger(const std::string& trigger) : trigger_(trigger) {
+    }
+    bool CheckTriggers(const Action* action) override {
+        return action->CheckEventTrigger(trigger_);
+    }
+private:
+    std::string trigger_;
+};
+
+class PropertyTrigger : public Trigger {
+public:
+    PropertyTrigger(const std::string& name, const std::string& value)
+        : name_(name), value_(value) {
+    }
+    bool CheckTriggers(const Action* action) override {
+        return action->CheckPropertyTrigger(name_, value_);
+    }
+private:
+    std::string name_;
+    std::string value_;
+};
+
+class BuiltinTrigger : public Trigger {
+public:
+    BuiltinTrigger(Action* action) : action_(action) {
+    }
+    bool CheckTriggers(const Action* action) override {
+        return action == action_;
+    }
+private:
+    Action* action_;
+};
+
+ActionManager::ActionManager() : current_command_(0)
 {
 }
 
@@ -278,21 +310,13 @@
 
 void ActionManager::QueueEventTrigger(const std::string& trigger)
 {
-    for (const auto& a : action_list_) {
-        if (a->CheckEventTrigger(trigger)) {
-            action_queue_.push(a);
-        }
-    }
+    trigger_queue_.push(std::make_unique<EventTrigger>(trigger));
 }
 
 void ActionManager::QueuePropertyTrigger(const std::string& name,
                                          const std::string& value)
 {
-    for (const auto& a : action_list_) {
-        if (a->CheckPropertyTrigger(name, value)) {
-            action_queue_.push(a);
-        }
-    }
+    trigger_queue_.push(std::make_unique<PropertyTrigger>(name, value));
 }
 
 void ActionManager::QueueAllPropertyTriggers()
@@ -312,35 +336,45 @@
 
     act->AddCommand(func, name_vector);
 
-    action_queue_.push(act);
+    actions_.push_back(act);
+    trigger_queue_.push(std::make_unique<BuiltinTrigger>(act));
 }
 
 void ActionManager::ExecuteOneCommand() {
-    if (action_queue_.empty()) {
+    while (current_executing_actions_.empty() && !trigger_queue_.empty()) {
+        std::copy_if(actions_.begin(), actions_.end(),
+                     std::back_inserter(current_executing_actions_),
+                     [this] (Action* act) {
+                         return trigger_queue_.front()->CheckTriggers(act);
+                     });
+        trigger_queue_.pop();
+    }
+
+    if (current_executing_actions_.empty()) {
         return;
     }
 
-    Action* action = action_queue_.front();
+    Action* action = current_executing_actions_.back();
     if (!action->NumCommands()) {
-        action_queue_.pop();
+        current_executing_actions_.pop_back();
         return;
     }
 
-    if (cur_command_ == 0) {
+    if (current_command_ == 0) {
         std::string trigger_name = action->BuildTriggersString();
         INFO("processing action %p (%s)\n", action, trigger_name.c_str());
     }
 
-    action->ExecuteOneCommand(cur_command_++);
-    if (cur_command_ == action->NumCommands()) {
-        cur_command_ = 0;
-        action_queue_.pop();
+    action->ExecuteOneCommand(current_command_++);
+    if (current_command_ == action->NumCommands()) {
+        current_command_ = 0;
+        current_executing_actions_.pop_back();
     }
 }
 
 bool ActionManager::HasMoreCommands() const
 {
-    return !action_queue_.empty();
+    return !current_executing_actions_.empty() || !trigger_queue_.empty();
 }
 
 Action* ActionManager::AddNewAction(const std::vector<std::string>& triggers,
@@ -357,21 +391,21 @@
     }
 
     auto old_act_it =
-        std::find_if(action_list_.begin(), action_list_.end(),
+        std::find_if(actions_.begin(), actions_.end(),
                      [&act] (Action* a) { return act->TriggersEqual(*a); });
 
-    if (old_act_it != action_list_.end()) {
+    if (old_act_it != actions_.end()) {
         delete act;
         return *old_act_it;
     }
 
-    action_list_.push_back(act);
+    actions_.push_back(act);
     return act;
 }
 
 void ActionManager::DumpState() const
 {
-    for (const auto& a : action_list_) {
+    for (const auto& a : actions_) {
         a->DumpState();
     }
     INFO("\n");
diff --git a/init/action.h b/init/action.h
index ae28fe1..5088c71 100644
--- a/init/action.h
+++ b/init/action.h
@@ -54,6 +54,12 @@
     std::vector<Command*> commands_;
 };
 
+class Trigger {
+public:
+    virtual ~Trigger() { }
+    virtual bool CheckTriggers(const Action* action) = 0;
+};
+
 class ActionManager {
 public:
     static ActionManager& GetInstance();
@@ -74,9 +80,10 @@
     ActionManager(ActionManager const&) = delete;
     void operator=(ActionManager const&) = delete;
 
-    std::vector<Action*> action_list_;
-    std::queue<Action*> action_queue_;
-    std::size_t cur_command_;
+    std::vector<Action*> actions_;
+    std::queue<std::unique_ptr<Trigger>> trigger_queue_;
+    std::vector<Action*> current_executing_actions_;
+    std::size_t current_command_;
 };
 
 #endif
diff --git a/init/builtins.cpp b/init/builtins.cpp
index e663501..7a4f7c1 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -427,6 +427,19 @@
     while (1) { pause(); }  // never reached
 }
 
+void import_late()
+{
+    static const std::vector<std::string> init_directories = {
+        "/system/etc/init",
+        "/vendor/etc/init",
+        "/odm/etc/init"
+    };
+
+    for (const auto& dir : init_directories) {
+        init_parse_config(dir.c_str());
+    }
+}
+
 /*
  * This function might request a reboot, in which case it will
  * not return.
@@ -478,6 +491,8 @@
         return -1;
     }
 
+    import_late();
+
     if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
         property_set("vold.decrypt", "trigger_encryption");
     } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
@@ -822,9 +837,9 @@
     return -1;
 }
 
-int do_load_all_props(const std::vector<std::string>& args) {
+int do_load_system_props(const std::vector<std::string>& args) {
     if (args.size() == 1) {
-        load_all_props();
+        load_system_props();
         return 0;
     }
     return -1;
@@ -852,17 +867,30 @@
     return 0;
 }
 
+static bool is_file_crypto() {
+    std::string value = property_get("ro.crypto.type");
+    return value == "file";
+}
+
 int do_installkey(const std::vector<std::string>& args)
 {
     if (args.size() != 2) {
         return -1;
     }
-
-    std::string prop_value = property_get("ro.crypto.type");
-    if (prop_value != "file") {
+    if (!is_file_crypto()) {
         return 0;
     }
-
     return e4crypt_create_device_key(args[1].c_str(),
                                      do_installkeys_ensure_dir_exists);
 }
+
+int do_setusercryptopolicies(const std::vector<std::string>& args)
+{
+    if (args.size() != 2) {
+        return -1;
+    }
+    if (!is_file_crypto()) {
+        return 0;
+    }
+    return e4crypt_set_user_crypto_policies(args[1].c_str());
+}
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 12f44f7..983eacd 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -127,7 +127,7 @@
     case 'l':
         if (!strcmp(s, "oglevel")) return K_loglevel;
         if (!strcmp(s, "oad_persist_props")) return K_load_persist_props;
-        if (!strcmp(s, "oad_all_props")) return K_load_all_props;
+        if (!strcmp(s, "oad_system_props")) return K_load_system_props;
         break;
     case 'm':
         if (!strcmp(s, "kdir")) return K_mkdir;
@@ -155,6 +155,7 @@
         if (!strcmp(s, "etenv")) return K_setenv;
         if (!strcmp(s, "etprop")) return K_setprop;
         if (!strcmp(s, "etrlimit")) return K_setrlimit;
+        if (!strcmp(s, "etusercryptopolicies")) return K_setusercryptopolicies;
         if (!strcmp(s, "ocket")) return K_socket;
         if (!strcmp(s, "tart")) return K_start;
         if (!strcmp(s, "top")) return K_stop;
diff --git a/init/keywords.h b/init/keywords.h
index 922feee..ddada58 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -24,6 +24,7 @@
 int do_rmdir(const std::vector<std::string>& args);
 int do_setprop(const std::vector<std::string>& args);
 int do_setrlimit(const std::vector<std::string>& args);
+int do_setusercryptopolicies(const std::vector<std::string>& args);
 int do_start(const std::vector<std::string>& args);
 int do_stop(const std::vector<std::string>& args);
 int do_swapon_all(const std::vector<std::string>& args);
@@ -36,7 +37,7 @@
 int do_chmod(const std::vector<std::string>& args);
 int do_loglevel(const std::vector<std::string>& args);
 int do_load_persist_props(const std::vector<std::string>& args);
-int do_load_all_props(const std::vector<std::string>& args);
+int do_load_system_props(const std::vector<std::string>& args);
 int do_verity_load_state(const std::vector<std::string>& args);
 int do_verity_update_state(const std::vector<std::string>& args);
 int do_wait(const std::vector<std::string>& args);
@@ -68,7 +69,7 @@
     KEYWORD(installkey,  COMMAND, 1, do_installkey)
     KEYWORD(ioprio,      OPTION,  0, 0)
     KEYWORD(keycodes,    OPTION,  0, 0)
-    KEYWORD(load_all_props,        COMMAND, 0, do_load_all_props)
+    KEYWORD(load_system_props,     COMMAND, 0, do_load_system_props)
     KEYWORD(load_persist_props,    COMMAND, 0, do_load_persist_props)
     KEYWORD(loglevel,    COMMAND, 1, do_loglevel)
     KEYWORD(mkdir,       COMMAND, 1, do_mkdir)
@@ -88,6 +89,7 @@
     KEYWORD(setenv,      OPTION,  2, 0)
     KEYWORD(setprop,     COMMAND, 2, do_setprop)
     KEYWORD(setrlimit,   COMMAND, 3, do_setrlimit)
+    KEYWORD(setusercryptopolicies,   COMMAND, 1, do_setusercryptopolicies)
     KEYWORD(socket,      OPTION,  0, 0)
     KEYWORD(start,       COMMAND, 1, do_start)
     KEYWORD(stop,        COMMAND, 1, do_stop)
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 7194820..a37d6f6 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -555,16 +555,10 @@
     close(fd);
 }
 
-void load_all_props() {
+void load_system_props() {
     load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
     load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);
     load_properties_from_file(PROP_PATH_FACTORY, "ro.*");
-
-    load_override_properties();
-
-    /* Read persistent properties after all default values have been loaded. */
-    load_persistent_properties();
-
     load_recovery_id_prop();
 }
 
diff --git a/init/property_service.h b/init/property_service.h
index 51d7404..f30577b 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -24,7 +24,7 @@
 extern void property_init(void);
 extern void property_load_boot_defaults(void);
 extern void load_persist_props(void);
-extern void load_all_props(void);
+extern void load_system_props(void);
 extern void start_property_service(void);
 void get_property_workspace(int *fd, int *sz);
 std::string property_get(const char* name);
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 128bb04..97f0ef4 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -102,6 +102,11 @@
   uintptr_t relative_pc = BacktraceMap::GetRelativePc(frame->map, frame->pc);
 
   std::string line(StringPrintf("#%02zu pc %" PRIPTR "  %s", frame->num, relative_pc, map_name));
+  // Special handling for non-zero offset maps, we need to print that
+  // information.
+  if (frame->map.offset != 0) {
+    line += " (offset " + StringPrintf("0x%" PRIxPTR, frame->map.offset) + ")";
+  }
   if (!frame->func_name.empty()) {
     line += " (" + frame->func_name;
     if (frame->func_offset) {
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 6bd7529..9ebd639 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -825,6 +825,15 @@
   EXPECT_EQ("#01 pc 123456dc  MapFake (ProcFake+645)",
 #endif
             backtrace->FormatFrameData(&frame));
+
+  // Check a non-zero map offset.
+  frame.map.offset = 0x1000;
+#if defined(__LP64__)
+  EXPECT_EQ("#01 pc 00000000123456dc  MapFake (offset 0x1000) (ProcFake+645)",
+#else
+  EXPECT_EQ("#01 pc 123456dc  MapFake (offset 0x1000) (ProcFake+645)",
+#endif
+            backtrace->FormatFrameData(&frame));
 }
 
 struct map_test_t {
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 6fb8c22..2728a05 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -126,6 +126,8 @@
 LOCAL_CFLAGS += -DUSE_CPUSETS
 endif
 LOCAL_CFLAGS += -Werror -Wall -Wextra -std=gnu90
+LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -139,6 +141,8 @@
 endif
 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/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/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index 697db25..11e7988 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -70,10 +70,6 @@
 # libhardware, but this at least gets us built.
 LOCAL_SHARED_LIBRARIES += libhardware_legacy
 LOCAL_CFLAGS += -DWITH_LIB_HARDWARE
-# t32cb16blend.S does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
-# arch-arm64/col32cb16blend.S does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libpixelflinger/arch-arm64/col32cb16blend.S b/libpixelflinger/arch-arm64/col32cb16blend.S
index 18a01fd..8d9c7c4 100644
--- a/libpixelflinger/arch-arm64/col32cb16blend.S
+++ b/libpixelflinger/arch-arm64/col32cb16blend.S
@@ -26,7 +26,7 @@
  * SUCH DAMAGE.
  */
     .text
-    .align
+    .align 0
 
     .global scanline_col32cb16blend_arm64
 
diff --git a/libpixelflinger/arch-arm64/t32cb16blend.S b/libpixelflinger/arch-arm64/t32cb16blend.S
index 7da8cf5..230f47b 100644
--- a/libpixelflinger/arch-arm64/t32cb16blend.S
+++ b/libpixelflinger/arch-arm64/t32cb16blend.S
@@ -26,7 +26,7 @@
  * SUCH DAMAGE.
  */
     .text
-    .align
+    .align 0
 
     .global scanline_t32cb16blend_arm64
 
diff --git a/libpixelflinger/t32cb16blend.S b/libpixelflinger/t32cb16blend.S
index caf9eb7..1d40ad4 100644
--- a/libpixelflinger/t32cb16blend.S
+++ b/libpixelflinger/t32cb16blend.S
@@ -17,6 +17,7 @@
 
 
 	.text
+	.syntax unified
 	.align
 	
 	.global scanline_t32cb16blend_arm
@@ -146,7 +147,7 @@
     tst     r0, #0x3
     beq     aligned
     subs    r2, r2, #1
-    ldmlofd	sp!, {r4-r7, lr}        // return
+    ldmfdlo sp!, {r4-r7, lr}        // return
     bxlo    lr
 
 last:
@@ -197,6 +198,6 @@
     mov     r4, r5
 
 9:  adds    r2, r2, #1
-    ldmlofd sp!, {r4-r7, lr}        // return
+    ldmfdlo sp!, {r4-r7, lr}        // return
     bxlo    lr
     b       last
diff --git a/libpixelflinger/tests/arch-arm64/assembler/Android.mk b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
index 448d298..bd0f24b 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
@@ -5,9 +5,6 @@
     arm64_assembler_test.cpp\
     asm_test_jacket.S
 
-# asm_test_jacket.S does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
-
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
     libpixelflinger
diff --git a/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S b/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
index a1392c2..f44859f 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
+++ b/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
@@ -27,7 +27,7 @@
  */
 
     .text
-    .align
+    .align 0
 
     .global asm_test_jacket
 
diff --git a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
index 5d69203..3368eb0 100644
--- a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
@@ -5,8 +5,6 @@
     col32cb16blend_test.c \
     ../../../arch-arm64/col32cb16blend.S
 
-LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
-
 LOCAL_SHARED_LIBRARIES :=
 
 LOCAL_C_INCLUDES :=
diff --git a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
index 2c1379b..8e5ec5e 100644
--- a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
@@ -5,8 +5,6 @@
     t32cb16blend_test.c \
     ../../../arch-arm64/t32cb16blend.S
 
-LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
-
 LOCAL_SHARED_LIBRARIES :=
 
 LOCAL_C_INCLUDES :=
diff --git a/libsparse/backed_block.c b/libsparse/backed_block.c
index 3e72b57..794cd6b 100644
--- a/libsparse/backed_block.c
+++ b/libsparse/backed_block.c
@@ -221,7 +221,8 @@
 		}
 		break;
 	case BACKED_BLOCK_FILE:
-		if (a->file.filename != b->file.filename ||
+		/* Already make sure b->type is BACKED_BLOCK_FILE */
+		if (strcmp(a->file.filename, b->file.filename) ||
 				a->file.offset + a->len != b->file.offset) {
 			return -EINVAL;
 		}
@@ -279,7 +280,10 @@
 	}
 
 	merge_bb(bbl, new_bb, new_bb->next);
-	merge_bb(bbl, bb, new_bb);
+	if (!merge_bb(bbl, bb, new_bb)) {
+		/* new_bb destroyed, point to retained as last_used */
+		bbl->last_used = bb;
+	}
 
 	return 0;
 }
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 677d1e7..a299962 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -92,6 +92,8 @@
         libdl
 
 LOCAL_MODULE := libutils
+LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
 include $(BUILD_STATIC_LIBRARY)
 
 # For the device, shared
@@ -106,8 +108,26 @@
         liblog
 LOCAL_CFLAGS := -Werror
 
+LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
 include $(BUILD_SHARED_LIBRARY)
 
+# Include subdirectory makefiles
+# ============================================================
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := SharedBufferTest
+LOCAL_STATIC_LIBRARIES := libutils libcutils
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SRC_FILES := SharedBufferTest.cpp
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := SharedBufferTest
+LOCAL_STATIC_LIBRARIES := libutils libcutils
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SRC_FILES := SharedBufferTest.cpp
+include $(BUILD_HOST_NATIVE_TEST)
 
 # Build the tests in the tests/ subdirectory.
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/libutils/JenkinsHash.cpp b/libutils/JenkinsHash.cpp
index 52c9bb7..ff5d252 100644
--- a/libutils/JenkinsHash.cpp
+++ b/libutils/JenkinsHash.cpp
@@ -19,10 +19,14 @@
  * should still be quite good.
  **/
 
+#include <stdlib.h>
 #include <utils/JenkinsHash.h>
 
 namespace android {
 
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
 hash_t JenkinsHashWhiten(uint32_t hash) {
     hash += (hash << 3);
     hash ^= (hash >> 11);
@@ -31,6 +35,9 @@
 }
 
 uint32_t JenkinsHashMixBytes(uint32_t hash, const uint8_t* bytes, size_t size) {
+    if (size > UINT32_MAX) {
+        abort();
+    }
     hash = JenkinsHashMix(hash, (uint32_t)size);
     size_t i;
     for (i = 0; i < (size & -4); i += 4) {
@@ -47,6 +54,9 @@
 }
 
 uint32_t JenkinsHashMixShorts(uint32_t hash, const uint16_t* shorts, size_t size) {
+    if (size > UINT32_MAX) {
+        abort();
+    }
     hash = JenkinsHashMix(hash, (uint32_t)size);
     size_t i;
     for (i = 0; i < (size & -2); i += 2) {
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index 3555fb7..947551a 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -14,9 +14,12 @@
  * limitations under the License.
  */
 
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include <log/log.h>
 #include <utils/SharedBuffer.h>
 #include <utils/Atomic.h>
 
@@ -26,6 +29,11 @@
 
 SharedBuffer* SharedBuffer::alloc(size_t size)
 {
+    // Don't overflow if the combined size of the buffer / header is larger than
+    // size_max.
+    LOG_ALWAYS_FATAL_IF((size >= (SIZE_MAX - sizeof(SharedBuffer))),
+                        "Invalid buffer size %zu", size);
+
     SharedBuffer* sb = static_cast<SharedBuffer *>(malloc(sizeof(SharedBuffer) + size));
     if (sb) {
         sb->mRefs = 1;
@@ -52,7 +60,7 @@
         memcpy(sb->data(), data(), size());
         release();
     }
-    return sb;    
+    return sb;
 }
 
 SharedBuffer* SharedBuffer::editResize(size_t newSize) const
@@ -60,6 +68,11 @@
     if (onlyOwner()) {
         SharedBuffer* buf = const_cast<SharedBuffer*>(this);
         if (buf->mSize == newSize) return buf;
+        // Don't overflow if the combined size of the new buffer / header is larger than
+        // size_max.
+        LOG_ALWAYS_FATAL_IF((newSize >= (SIZE_MAX - sizeof(SharedBuffer))),
+                            "Invalid buffer size %zu", newSize);
+
         buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize);
         if (buf != NULL) {
             buf->mSize = newSize;
diff --git a/libutils/SharedBufferTest.cpp b/libutils/SharedBufferTest.cpp
new file mode 100644
index 0000000..d88fbf3
--- /dev/null
+++ b/libutils/SharedBufferTest.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#define __STDC_LIMIT_MACROS
+
+#include <utils/SharedBuffer.h>
+
+#include <gtest/gtest.h>
+
+#include <memory>
+#include <stdint.h>
+
+TEST(SharedBufferTest, TestAlloc) {
+  EXPECT_DEATH(android::SharedBuffer::alloc(SIZE_MAX), "");
+  EXPECT_DEATH(android::SharedBuffer::alloc(SIZE_MAX - sizeof(android::SharedBuffer)), "");
+
+  // Make sure we don't die here.
+  // Check that null is returned, as we are asking for the whole address space.
+  android::SharedBuffer* buf =
+      android::SharedBuffer::alloc(SIZE_MAX - sizeof(android::SharedBuffer) - 1);
+  ASSERT_TRUE(NULL == buf);
+
+  buf = android::SharedBuffer::alloc(0);
+  ASSERT_FALSE(NULL == buf);
+  ASSERT_EQ(0U, buf->size());
+  buf->release();
+}
+
+TEST(SharedBufferTest, TestEditResize) {
+  android::SharedBuffer* buf = android::SharedBuffer::alloc(10);
+  EXPECT_DEATH(buf->editResize(SIZE_MAX - sizeof(android::SharedBuffer)), "");
+  buf = android::SharedBuffer::alloc(10);
+  EXPECT_DEATH(buf->editResize(SIZE_MAX), "");
+
+  buf = android::SharedBuffer::alloc(10);
+  // Make sure we don't die here.
+  // Check that null is returned, as we are asking for the whole address space.
+  buf = buf->editResize(SIZE_MAX - sizeof(android::SharedBuffer) - 1);
+  ASSERT_TRUE(NULL == buf);
+
+  buf = android::SharedBuffer::alloc(10);
+  buf = buf->editResize(0);
+  ASSERT_EQ(0U, buf->size());
+  buf->release();
+}
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 69313ea..2d06023 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+
 #include <utils/String8.h>
 
 #include <utils/Compat.h>
diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp
index 30ca663..bdb54b1 100644
--- a/libutils/VectorImpl.cpp
+++ b/libutils/VectorImpl.cpp
@@ -551,6 +551,10 @@
 
 ssize_t SortedVectorImpl::_indexOrderOf(const void* item, size_t* order) const
 {
+    if (order) *order = 0;
+    if (isEmpty()) {
+        return NAME_NOT_FOUND;
+    }
     // binary search
     ssize_t err = NAME_NOT_FOUND;
     ssize_t l = 0;
diff --git a/lmkd/Android.mk b/lmkd/Android.mk
index 39081d6..8c88661 100644
--- a/lmkd/Android.mk
+++ b/lmkd/Android.mk
@@ -7,4 +7,6 @@
 
 LOCAL_MODULE := lmkd
 
+LOCAL_INIT_RC := lmkd.rc
+
 include $(BUILD_EXECUTABLE)
diff --git a/lmkd/lmkd.rc b/lmkd/lmkd.rc
new file mode 100644
index 0000000..83c5ff0
--- /dev/null
+++ b/lmkd/lmkd.rc
@@ -0,0 +1,4 @@
+service lmkd /system/bin/lmkd
+    class core
+    critical
+    socket lmkd seqpacket 0660 system system
diff --git a/logcat/Android.mk b/logcat/Android.mk
index 7115f9b..844ab8b 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -11,6 +11,8 @@
 
 LOCAL_CFLAGS := -Werror
 
+LOCAL_INIT_RC := logcatd.rc
+
 include $(BUILD_EXECUTABLE)
 
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/logcat/logcatd.rc b/logcat/logcatd.rc
new file mode 100644
index 0000000..0bc581e
--- /dev/null
+++ b/logcat/logcatd.rc
@@ -0,0 +1,13 @@
+on property:persist.logd.logpersistd=logcatd
+    # all exec/services are called with umask(077), so no gain beyond 0700
+    mkdir /data/misc/logd 0700 logd log
+    # logd for write to /data/misc/logd, log group for read from pstore (-L)
+    exec - logd log -- /system/bin/logcat -L -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 64 -n 256
+    start logcatd
+
+service logcatd /system/bin/logcat -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 64 -n 256
+    class late_start
+    disabled
+    # logd for write to /data/misc/logd, log group for read from log daemon
+    user logd
+    group log
diff --git a/logd/Android.mk b/logd/Android.mk
index 615d030..01c51c7 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -4,6 +4,8 @@
 
 LOCAL_MODULE:= logd
 
+LOCAL_INIT_RC := logd.rc
+
 LOCAL_SRC_FILES := \
     main.cpp \
     LogCommand.cpp \
@@ -25,7 +27,7 @@
     libsysutils \
     liblog \
     libcutils \
-    libutils
+    libbase
 
 # This is what we want to do:
 #  event_logtags = $(shell \
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 489bea6..031c740 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -25,6 +25,9 @@
 #include <sys/socket.h>
 #include <sys/types.h>
 
+#include <string>
+
+#include <base/stringprintf.h>
 #include <cutils/sockets.h>
 #include <private/android_filesystem_config.h>
 #include <sysutils/SocketClient.h>
@@ -189,22 +192,13 @@
         mBuf(*buf) {
 }
 
-static void package_string(char **strp) {
-    const char *a = *strp;
-    if (!a) {
-        a = "";
-    }
-
+static std::string package_string(const std::string &str) {
     // Calculate total buffer size prefix, count is the string length w/o nul
     char fmt[32];
-    for(size_t l = strlen(a), y = 0, x = 6; y != x; y = x, x = strlen(fmt) - 2) {
+    for(size_t l = str.length(), y = 0, x = 6; y != x; y = x, x = strlen(fmt) - 2) {
         snprintf(fmt, sizeof(fmt), "%zu\n%%s\n\f", l + x);
     }
-
-    char *b = *strp;
-    *strp = NULL;
-    asprintf(strp, fmt, a);
-    free(b);
+    return android::base::StringPrintf(fmt, str.c_str());
 }
 
 int CommandListener::GetStatisticsCmd::runCommand(SocketClient *cli,
@@ -228,16 +222,7 @@
         }
     }
 
-    char *buf = NULL;
-
-    mBuf.formatStatistics(&buf, uid, logMask);
-    if (!buf) {
-        cli->sendMsg("Failed");
-    } else {
-        package_string(&buf);
-        cli->sendMsg(buf);
-        free(buf);
-    }
+    cli->sendMsg(package_string(mBuf.formatStatistics(uid, logMask)).c_str());
     return 0;
 }
 
@@ -249,15 +234,7 @@
 int CommandListener::GetPruneListCmd::runCommand(SocketClient *cli,
                                          int /*argc*/, char ** /*argv*/) {
     setname();
-    char *buf = NULL;
-    mBuf.formatPrune(&buf);
-    if (!buf) {
-        cli->sendMsg("Failed");
-    } else {
-        package_string(&buf);
-        cli->sendMsg(buf);
-        free(buf);
-    }
+    cli->sendMsg(package_string(mBuf.formatPrune()).c_str());
     return 0;
 }
 
@@ -274,20 +251,15 @@
         return 0;
     }
 
-    char *cp = NULL;
+    std::string str;
     for (int i = 1; i < argc; ++i) {
-        char *p = cp;
-        if (p) {
-            cp = NULL;
-            asprintf(&cp, "%s %s", p, argv[i]);
-            free(p);
-        } else {
-            asprintf(&cp, "%s", argv[i]);
+        if (str.length()) {
+            str += " ";
         }
+        str += argv[i];
     }
 
-    int ret = mBuf.initPrune(cp);
-    free(cp);
+    int ret = mBuf.initPrune(str.c_str());
 
     if (ret) {
         cli->sendMsg("Invalid");
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index d584925..823a842 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -72,7 +72,7 @@
             return;
         }
         entry = new LogTimeEntry(mReader, client, mNonBlock, mTail, mLogMask, mPid, mStart);
-        times.push_back(entry);
+        times.push_front(entry);
     }
 
     client->incRef();
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index b9e8973..c609870 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -217,34 +217,35 @@
     return len;
 }
 
-// If we're using more than 256K of memory for log entries, prune
-// at least 10% of the log entries. For sizes above 1M, prune at
-// least 1% of the log entries.
+// Prune at most 10% of the log entries or 256, whichever is less.
 //
 // mLogElementsLock must be held when this function is called.
 void LogBuffer::maybePrune(log_id_t id) {
     size_t sizes = stats.sizes(id);
     unsigned long maxSize = log_buffer_size(id);
     if (sizes > maxSize) {
-        size_t sizeOver, minElements, elements = stats.elements(id);
-        if (maxSize > (4 * LOG_BUFFER_SIZE)) {
-            sizeOver = sizes - ((maxSize * 99) / 100);
-            minElements = elements / 100;
-        } else {
-            sizeOver = sizes - ((maxSize * 9) / 10);
-            minElements = elements / 10;
-        }
+        size_t sizeOver = sizes - ((maxSize * 9) / 10);
+        size_t elements = stats.elements(id);
+        size_t minElements = elements / 10;
         unsigned long pruneRows = elements * sizeOver / sizes;
         if (pruneRows <= minElements) {
             pruneRows = minElements;
         }
+        if (pruneRows > 256) {
+            pruneRows = 256;
+        }
         prune(id, pruneRows);
     }
 }
 
 LogBufferElementCollection::iterator LogBuffer::erase(LogBufferElementCollection::iterator it) {
     LogBufferElement *e = *it;
+    log_id_t id = e->getLogId();
+    LogBufferIteratorMap::iterator f = mLastWorstUid[id].find(e->getUid());
 
+    if ((f != mLastWorstUid[id].end()) && (it == f->second)) {
+        mLastWorstUid[id].erase(f);
+    }
     it = mLogElements.erase(it);
     stats.subtract(e);
     delete e;
@@ -403,8 +404,17 @@
 
         bool kick = false;
         bool leading = true;
+        it = mLogElements.begin();
+        if (worst != (uid_t) -1) {
+            LogBufferIteratorMap::iterator f = mLastWorstUid[id].find(worst);
+            if ((f != mLastWorstUid[id].end())
+                    && (f->second != mLogElements.end())) {
+                leading = false;
+                it = f->second;
+            }
+        }
         LogBufferElementLast last;
-        for(it = mLogElements.begin(); it != mLogElements.end();) {
+        while (it != mLogElements.end()) {
             LogBufferElement *e = *it;
 
             if (oldest && (oldest->mStart <= e->getSequence())) {
@@ -454,8 +464,14 @@
                 continue;
             }
 
+            // unmerged drop message
             if (dropped) {
                 last.add(e);
+                if ((e->getUid() == worst)
+                        || (mLastWorstUid[id].find(e->getUid())
+                            == mLastWorstUid[id].end())) {
+                    mLastWorstUid[id][e->getUid()] = it;
+                }
                 ++it;
                 continue;
             }
@@ -500,6 +516,7 @@
                     delete e;
                 } else {
                     last.add(e);
+                    mLastWorstUid[id][e->getUid()] = it;
                     ++it;
                 }
             }
@@ -677,10 +694,12 @@
     return max;
 }
 
-void LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) {
+std::string LogBuffer::formatStatistics(uid_t uid, unsigned int logMask) {
     pthread_mutex_lock(&mLogElementsLock);
 
-    stats.format(strp, uid, logMask);
+    std::string ret = stats.format(uid, logMask);
 
     pthread_mutex_unlock(&mLogElementsLock);
+
+    return ret;
 }
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index a13fded..fcb05f5 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -19,9 +19,11 @@
 
 #include <sys/types.h>
 
+#include <list>
+#include <string>
+
 #include <log/log.h>
 #include <sysutils/SocketClient.h>
-#include <utils/List.h>
 
 #include <private/android_filesystem_config.h>
 
@@ -30,7 +32,7 @@
 #include "LogStatistics.h"
 #include "LogWhiteBlackList.h"
 
-typedef android::List<LogBufferElement *> LogBufferElementCollection;
+typedef std::list<LogBufferElement *> LogBufferElementCollection;
 
 class LogBuffer {
     LogBufferElementCollection mLogElements;
@@ -39,6 +41,11 @@
     LogStatistics stats;
 
     PruneList mPrune;
+    // watermark of any worst/chatty uid processing
+    typedef std::unordered_map<uid_t,
+                               LogBufferElementCollection::iterator>
+                LogBufferIteratorMap;
+    LogBufferIteratorMap mLastWorstUid[LOG_ID_MAX];
 
     unsigned long mMaxSize[LOG_ID_MAX];
 
@@ -61,15 +68,14 @@
     int setSize(log_id_t id, unsigned long size);
     unsigned long getSizeUsed(log_id_t id);
     // *strp uses malloc, use free to release.
-    void formatStatistics(char **strp, uid_t uid, unsigned int logMask);
+    std::string formatStatistics(uid_t uid, unsigned int logMask);
 
     void enableStatistics() {
         stats.enableStatistics();
     }
 
-    int initPrune(char *cp) { return mPrune.init(cp); }
-    // *strp uses malloc, use free to release.
-    void formatPrune(char **strp) { mPrune.format(strp); }
+    int initPrune(const char *cp) { return mPrune.init(cp); }
+    std::string formatPrune() { return mPrune.format(); }
 
     // helper must be protected directly or implicitly by lock()/unlock()
     char *pidToName(pid_t pid) { return stats.pidToName(pid); }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 48c2fe6..61fd559 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -20,9 +20,9 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <base/stringprintf.h>
 #include <log/logger.h>
 #include <private/android_filesystem_config.h>
-#include <utils/String8.h>
 
 #include "LogStatistics.h"
 
@@ -183,8 +183,10 @@
     return name;
 }
 
-static void format_line(android::String8 &output,
-        android::String8 &name, android::String8 &size, android::String8 &pruned) {
+static std::string format_line(
+        const std::string &name,
+        const std::string &size,
+        const std::string &pruned) {
     static const size_t pruned_len = 6;
     static const size_t total_len = 70 + pruned_len;
 
@@ -193,26 +195,21 @@
                                 total_len - name.length() - drop_len - 1);
 
     if (pruned.length()) {
-        output.appendFormat("%s%*s%*s\n", name.string(),
-                                          (int)size_len, size.string(),
-                                          (int)drop_len, pruned.string());
+        return android::base::StringPrintf("%s%*s%*s\n", name.c_str(),
+                                           (int)size_len, size.c_str(),
+                                           (int)drop_len, pruned.c_str());
     } else {
-        output.appendFormat("%s%*s\n", name.string(),
-                                       (int)size_len, size.string());
+        return android::base::StringPrintf("%s%*s\n", name.c_str(),
+                                           (int)size_len, size.c_str());
     }
 }
 
-void LogStatistics::format(char **buf, uid_t uid, unsigned int logMask) {
+std::string LogStatistics::format(uid_t uid, unsigned int logMask) {
     static const unsigned short spaces_total = 19;
 
-    if (*buf) {
-        free(*buf);
-        *buf = NULL;
-    }
-
     // Report on total logging, current and for all time
 
-    android::String8 output("size/num");
+    std::string output = "size/num";
     size_t oldLength;
     short spaces = 1;
 
@@ -224,12 +221,13 @@
         if (spaces < 0) {
             spaces = 0;
         }
-        output.appendFormat("%*s%s", spaces, "", android_log_id_to_name(id));
+        output += android::base::StringPrintf("%*s%s", spaces, "",
+                                              android_log_id_to_name(id));
         spaces += spaces_total + oldLength - output.length();
     }
 
     spaces = 4;
-    output.appendFormat("\nTotal");
+    output += android::base::StringPrintf("\nTotal");
 
     log_id_for_each(id) {
         if (!(logMask & (1 << id))) {
@@ -239,13 +237,14 @@
         if (spaces < 0) {
             spaces = 0;
         }
-        output.appendFormat("%*s%zu/%zu", spaces, "",
-                            sizesTotal(id), elementsTotal(id));
+        output += android::base::StringPrintf("%*s%zu/%zu", spaces, "",
+                                              sizesTotal(id),
+                                              elementsTotal(id));
         spaces += spaces_total + oldLength - output.length();
     }
 
     spaces = 6;
-    output.appendFormat("\nNow");
+    output += android::base::StringPrintf("\nNow");
 
     log_id_for_each(id) {
         if (!(logMask & (1 << id))) {
@@ -258,7 +257,8 @@
             if (spaces < 0) {
                 spaces = 0;
             }
-            output.appendFormat("%*s%zu/%zu", spaces, "", sizes(id), els);
+            output += android::base::StringPrintf("%*s%zu/%zu", spaces, "",
+                                                  sizes(id), els);
             spaces -= output.length() - oldLength;
         }
         spaces += spaces_total;
@@ -284,53 +284,54 @@
             }
 
             if (!headerPrinted) {
-                output.appendFormat("\n\n");
-                android::String8 name("");
+                output += android::base::StringPrintf("\n\n");
+                std::string name;
                 if (uid == AID_ROOT) {
-                    name.appendFormat(
+                    name = android::base::StringPrintf(
                         "Chattiest UIDs in %s log buffer:",
                         android_log_id_to_name(id));
                 } else {
-                    name.appendFormat(
+                    name = android::base::StringPrintf(
                         "Logging for your UID in %s log buffer:",
                         android_log_id_to_name(id));
                 }
-                android::String8 size("Size");
-                android::String8 pruned("Pruned");
+                std::string size = "Size";
+                std::string pruned = "Pruned";
                 if (!worstUidEnabledForLogid(id)) {
-                    pruned.setTo("");
+                    pruned = "";
                 }
-                format_line(output, name, size, pruned);
+                output += format_line(name, size, pruned);
 
-                name.setTo("UID   PACKAGE");
-                size.setTo("BYTES");
-                pruned.setTo("LINES");
+                name = "UID   PACKAGE";
+                size = "BYTES";
+                pruned = "LINES";
                 if (!worstUidEnabledForLogid(id)) {
-                    pruned.setTo("");
+                    pruned = "";
                 }
-                format_line(output, name, size, pruned);
+                output += format_line(name, size, pruned);
 
                 headerPrinted = true;
             }
 
-            android::String8 name("");
-            name.appendFormat("%u", u);
+            std::string name = android::base::StringPrintf("%u", u);
             char *n = uidToName(u);
             if (n) {
-                name.appendFormat("%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", n);
+                name += android::base::StringPrintf(
+                    "%*s%s", (int)std::max(6 - name.length(), (size_t)1),
+                    "", n);
                 free(n);
             }
 
-            android::String8 size("");
-            size.appendFormat("%zu", entry->getSizes());
+            std::string size = android::base::StringPrintf("%zu",
+                                                           entry->getSizes());
 
-            android::String8 pruned("");
+            std::string pruned = "";
             size_t dropped = entry->getDropped();
             if (dropped) {
-                pruned.appendFormat("%zu", dropped);
+                pruned = android::base::StringPrintf("%zu", dropped);
             }
 
-            format_line(output, name, size, pruned);
+            output += format_line(name, size, pruned);
         }
     }
 
@@ -347,48 +348,52 @@
             }
 
             if (!headerPrinted) {
-                output.appendFormat("\n\n");
-                android::String8 name("");
+                output += android::base::StringPrintf("\n\n");
+                std::string name;
                 if (uid == AID_ROOT) {
-                    name.appendFormat("Chattiest PIDs:");
+                    name = android::base::StringPrintf("Chattiest PIDs:");
                 } else {
-                    name.appendFormat("Logging for this PID:");
+                    name = android::base::StringPrintf("Logging for this PID:");
                 }
-                android::String8 size("Size");
-                android::String8 pruned("Pruned");
-                format_line(output, name, size, pruned);
+                std::string size = "Size";
+                std::string pruned = "Pruned";
+                output += format_line(name, size, pruned);
 
-                name.setTo("  PID/UID   COMMAND LINE");
-                size.setTo("BYTES");
-                pruned.setTo("LINES");
-                format_line(output, name, size, pruned);
+                name = "  PID/UID   COMMAND LINE";
+                size = "BYTES";
+                pruned = "LINES";
+                output += format_line(name, size, pruned);
 
                 headerPrinted = true;
             }
 
-            android::String8 name("");
-            name.appendFormat("%5u/%u", entry->getKey(), u);
+            std::string name = android::base::StringPrintf("%5u/%u",
+                                                           entry->getKey(), u);
             const char *n = entry->getName();
             if (n) {
-                name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", n);
+                name += android::base::StringPrintf(
+                    "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
+                    "", n);
             } else {
                 char *un = uidToName(u);
                 if (un) {
-                    name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", un);
+                    name += android::base::StringPrintf(
+                        "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
+                        "", un);
                     free(un);
                 }
             }
 
-            android::String8 size("");
-            size.appendFormat("%zu", entry->getSizes());
+            std::string size = android::base::StringPrintf("%zu",
+                                                           entry->getSizes());
 
-            android::String8 pruned("");
+            std::string pruned = "";
             size_t dropped = entry->getDropped();
             if (dropped) {
-                pruned.appendFormat("%zu", dropped);
+                pruned = android::base::StringPrintf("%zu", dropped);
             }
 
-            format_line(output, name, size, pruned);
+            output += format_line(name, size, pruned);
         }
     }
 
@@ -406,46 +411,50 @@
             }
 
             if (!headerPrinted) { // Only print header if we have table to print
-                output.appendFormat("\n\n");
-                android::String8 name("Chattiest TIDs:");
-                android::String8 size("Size");
-                android::String8 pruned("Pruned");
-                format_line(output, name, size, pruned);
+                output += android::base::StringPrintf("\n\n");
+                std::string name = "Chattiest TIDs:";
+                std::string size = "Size";
+                std::string pruned = "Pruned";
+                output += format_line(name, size, pruned);
 
-                name.setTo("  TID/UID   COMM");
-                size.setTo("BYTES");
-                pruned.setTo("LINES");
-                format_line(output, name, size, pruned);
+                name = "  TID/UID   COMM";
+                size = "BYTES";
+                pruned = "LINES";
+                output += format_line(name, size, pruned);
 
                 headerPrinted = true;
             }
 
-            android::String8 name("");
-            name.appendFormat("%5u/%u", entry->getKey(), u);
+            std::string name = android::base::StringPrintf("%5u/%u",
+                                                           entry->getKey(), u);
             const char *n = entry->getName();
             if (n) {
-                name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", n);
+                name += android::base::StringPrintf(
+                    "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
+                    "", n);
             } else {
                 // if we do not have a PID name, lets punt to try UID name?
                 char *un = uidToName(u);
                 if (un) {
-                    name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", un);
+                    name += android::base::StringPrintf(
+                        "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
+                        "", un);
                     free(un);
                 }
                 // We tried, better to not have a name at all, we still
                 // have TID/UID by number to report in any case.
             }
 
-            android::String8 size("");
-            size.appendFormat("%zu", entry->getSizes());
+            std::string size = android::base::StringPrintf("%zu",
+                                                           entry->getSizes());
 
-            android::String8 pruned("");
+            std::string pruned = "";
             size_t dropped = entry->getDropped();
             if (dropped) {
-                pruned.appendFormat("%zu", dropped);
+                pruned = android::base::StringPrintf("%zu", dropped);
             }
 
-            format_line(output, name, size, pruned);
+            output += format_line(name, size, pruned);
         }
     }
 
@@ -461,40 +470,44 @@
                 continue;
             }
 
-            android::String8 pruned("");
+            std::string pruned = "";
 
             if (!headerPrinted) {
-                output.appendFormat("\n\n");
-                android::String8 name("Chattiest events log buffer TAGs:");
-                android::String8 size("Size");
-                format_line(output, name, size, pruned);
+                output += android::base::StringPrintf("\n\n");
+                std::string name = "Chattiest events log buffer TAGs:";
+                std::string size = "Size";
+                output += format_line(name, size, pruned);
 
-                name.setTo("    TAG/UID   TAGNAME");
-                size.setTo("BYTES");
-                format_line(output, name, size, pruned);
+                name = "    TAG/UID   TAGNAME";
+                size = "BYTES";
+                output += format_line(name, size, pruned);
 
                 headerPrinted = true;
             }
 
-            android::String8 name("");
+            std::string name;
             if (u == (uid_t)-1) {
-                name.appendFormat("%7u", entry->getKey());
+                name = android::base::StringPrintf("%7u",
+                                                   entry->getKey());
             } else {
-                name.appendFormat("%7u/%u", entry->getKey(), u);
+                name = android::base::StringPrintf("%7u/%u",
+                                                   entry->getKey(), u);
             }
             const char *n = entry->getName();
             if (n) {
-                name.appendFormat("%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", n);
+                name += android::base::StringPrintf(
+                    "%*s%s", (int)std::max(14 - name.length(), (size_t)1),
+                    "", n);
             }
 
-            android::String8 size("");
-            size.appendFormat("%zu", entry->getSizes());
+            std::string size = android::base::StringPrintf("%zu",
+                                                           entry->getSizes());
 
-            format_line(output, name, size, pruned);
+            output += format_line(name, size, pruned);
         }
     }
 
-    *buf = strdup(output.string());
+    return output;
 }
 
 namespace android {
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 760d6b2..61000d2 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -331,8 +331,7 @@
     size_t sizesTotal(log_id_t id) const { return mSizesTotal[id]; }
     size_t elementsTotal(log_id_t id) const { return mElementsTotal[id]; }
 
-    // *strp = malloc, balance with free
-    void format(char **strp, uid_t uid, unsigned int logMask);
+    std::string format(uid_t uid, unsigned int logMask);
 
     // helper (must be locked directly or implicitly by mLogElementsLock)
     char *pidToName(pid_t pid);
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index 783bce6..39bcdd4 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -20,8 +20,10 @@
 #include <pthread.h>
 #include <time.h>
 #include <sys/types.h>
+
+#include <list>
+
 #include <sysutils/SocketClient.h>
-#include <utils/List.h>
 #include <log/log.h>
 
 class LogReader;
@@ -107,6 +109,6 @@
     static int FilterSecondPass(const LogBufferElement *element, void *me);
 };
 
-typedef android::List<LogTimeEntry *> LastLogTimes;
+typedef std::list<LogTimeEntry *> LastLogTimes;
 
-#endif
+#endif // _LOGD_LOG_TIMES_H__
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index 277b3ca..ad005ec 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -16,7 +16,7 @@
 
 #include <ctype.h>
 
-#include <utils/String8.h>
+#include <base/stringprintf.h>
 
 #include "LogWhiteBlackList.h"
 
@@ -35,46 +35,40 @@
     return uid - mUid;
 }
 
-void Prune::format(char **strp) {
+std::string Prune::format() {
     if (mUid != uid_all) {
         if (mPid != pid_all) {
-            asprintf(strp, "%u/%u", mUid, mPid);
-        } else {
-            asprintf(strp, "%u", mUid);
+            return android::base::StringPrintf("%u/%u", mUid, mPid);
         }
-    } else if (mPid != pid_all) {
-        asprintf(strp, "/%u", mPid);
-    } else { // NB: mPid == pid_all can not happen if mUid == uid_all
-        asprintf(strp, "/");
+        return android::base::StringPrintf("%u", mUid);
     }
+    if (mPid != pid_all) {
+        return android::base::StringPrintf("/%u", mPid);
+    }
+    // NB: mPid == pid_all can not happen if mUid == uid_all
+    return std::string("/");
 }
 
 PruneList::PruneList() : mWorstUidEnabled(true) {
-    mNaughty.clear();
-    mNice.clear();
 }
 
 PruneList::~PruneList() {
     PruneCollection::iterator it;
     for (it = mNice.begin(); it != mNice.end();) {
-        delete (*it);
         it = mNice.erase(it);
     }
     for (it = mNaughty.begin(); it != mNaughty.end();) {
-        delete (*it);
         it = mNaughty.erase(it);
     }
 }
 
-int PruneList::init(char *str) {
+int PruneList::init(const char *str) {
     mWorstUidEnabled = true;
     PruneCollection::iterator it;
     for (it = mNice.begin(); it != mNice.end();) {
-        delete (*it);
         it = mNice.erase(it);
     }
     for (it = mNaughty.begin(); it != mNaughty.end();) {
-        delete (*it);
         it = mNaughty.erase(it);
     }
 
@@ -142,28 +136,28 @@
         // insert sequentially into list
         PruneCollection::iterator it = list->begin();
         while (it != list->end()) {
-            Prune *p = *it;
-            int m = uid - p->mUid;
+            Prune &p = *it;
+            int m = uid - p.mUid;
             if (m == 0) {
-                if (p->mPid == p->pid_all) {
+                if (p.mPid == p.pid_all) {
                     break;
                 }
-                if ((pid == p->pid_all) && (p->mPid != p->pid_all)) {
+                if ((pid == p.pid_all) && (p.mPid != p.pid_all)) {
                     it = list->erase(it);
                     continue;
                 }
-                m = pid - p->mPid;
+                m = pid - p.mPid;
             }
             if (m <= 0) {
                 if (m < 0) {
-                    list->insert(it, new Prune(uid,pid));
+                    list->insert(it, Prune(uid,pid));
                 }
                 break;
             }
             ++it;
         }
         if (it == list->end()) {
-            list->push_back(new Prune(uid,pid));
+            list->push_back(Prune(uid,pid));
         }
         if (!*str) {
             break;
@@ -173,47 +167,32 @@
     return 0;
 }
 
-void PruneList::format(char **strp) {
-    if (*strp) {
-        free(*strp);
-        *strp = NULL;
-    }
-
+std::string PruneList::format() {
     static const char nice_format[] = " %s";
     const char *fmt = nice_format + 1;
 
-    android::String8 string;
+    std::string string;
 
     if (mWorstUidEnabled) {
-        string.setTo("~!");
+        string = "~!";
         fmt = nice_format;
     }
 
     PruneCollection::iterator it;
 
     for (it = mNice.begin(); it != mNice.end(); ++it) {
-        char *a = NULL;
-        (*it)->format(&a);
-
-        string.appendFormat(fmt, a);
+        string += android::base::StringPrintf(fmt, (*it).format().c_str());
         fmt = nice_format;
-
-        free(a);
     }
 
     static const char naughty_format[] = " ~%s";
     fmt = naughty_format + (*fmt != ' ');
     for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
-        char *a = NULL;
-        (*it)->format(&a);
-
-        string.appendFormat(fmt, a);
+        string += android::base::StringPrintf(fmt, (*it).format().c_str());
         fmt = naughty_format;
-
-        free(a);
     }
 
-    *strp = strdup(string.string());
+    return string;
 }
 
 // ToDo: Lists are in sorted order, Prune->cmp() returns + or -
@@ -223,7 +202,7 @@
 bool PruneList::naughty(LogBufferElement *element) {
     PruneCollection::iterator it;
     for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
-        if (!(*it)->cmp(element)) {
+        if (!(*it).cmp(element)) {
             return true;
         }
     }
@@ -233,7 +212,7 @@
 bool PruneList::nice(LogBufferElement *element) {
     PruneCollection::iterator it;
     for (it = mNice.begin(); it != mNice.end(); ++it) {
-        if (!(*it)->cmp(element)) {
+        if (!(*it).cmp(element)) {
             return true;
         }
     }
diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h
index 5f60801..00e1cad 100644
--- a/logd/LogWhiteBlackList.h
+++ b/logd/LogWhiteBlackList.h
@@ -19,7 +19,8 @@
 
 #include <sys/types.h>
 
-#include <utils/List.h>
+#include <list>
+#include <string.h>
 
 #include <LogBufferElement.h>
 
@@ -43,11 +44,10 @@
 
     int cmp(LogBufferElement *e) const { return cmp(e->getUid(), e->getPid()); }
 
-    // *strp is malloc'd, use free to release
-    void format(char **strp);
+    std::string format();
 };
 
-typedef android::List<Prune *> PruneCollection;
+typedef std::list<Prune> PruneCollection;
 
 class PruneList {
     PruneCollection mNaughty;
@@ -58,7 +58,7 @@
     PruneList();
     ~PruneList();
 
-    int init(char *str);
+    int init(const char *str);
 
     bool naughty(LogBufferElement *element);
     bool naughty(void) { return !mNaughty.empty(); }
@@ -66,8 +66,7 @@
     bool nice(void) { return !mNice.empty(); }
     bool worstUidEnabled() const { return mWorstUidEnabled; }
 
-    // *strp is malloc'd, use free to release
-    void format(char **strp);
+    std::string format();
 };
 
 #endif // _LOGD_LOG_WHITE_BLACK_LIST_H__
diff --git a/logd/logd.rc b/logd/logd.rc
new file mode 100644
index 0000000..da6a0bc
--- /dev/null
+++ b/logd/logd.rc
@@ -0,0 +1,10 @@
+service logd /system/bin/logd
+    class core
+    socket logd stream 0666 logd logd
+    socket logdr seqpacket 0666 logd logd
+    socket logdw dgram 0222 logd logd
+    group root system
+
+service logd-reinit /system/bin/logd --reinit
+    oneshot
+    disabled
diff --git a/logwrapper/Android.mk b/logwrapper/Android.mk
index 61b4659..ad45b2c 100644
--- a/logwrapper/Android.mk
+++ b/logwrapper/Android.mk
@@ -11,7 +11,7 @@
 LOCAL_SHARED_LIBRARIES := libcutils liblog
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror -std=gnu99
 include $(BUILD_STATIC_LIBRARY)
 
 # ========================================================
@@ -23,7 +23,7 @@
 LOCAL_WHOLE_STATIC_LIBRARIES := liblogwrap
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror -std=gnu99
 include $(BUILD_SHARED_LIBRARY)
 
 # ========================================================
@@ -33,5 +33,5 @@
 LOCAL_SRC_FILES:= logwrapper.c
 LOCAL_MODULE := logwrapper
 LOCAL_STATIC_LIBRARIES := liblog liblogwrap libcutils
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror -std=gnu99
 include $(BUILD_EXECUTABLE)
diff --git a/logwrapper/include/logwrap/logwrap.h b/logwrapper/include/logwrap/logwrap.h
index 449461f..89a8fdd 100644
--- a/logwrapper/include/logwrap/logwrap.h
+++ b/logwrapper/include/logwrap/logwrap.h
@@ -73,7 +73,9 @@
 #define LOG_FILE        4
 
 /* Write data to child's stdin. */
-#define FORK_EXECVP_OPTION_INPUT    0
+#define FORK_EXECVP_OPTION_INPUT             0
+/* Capture data from child's stdout and stderr. */
+#define FORK_EXECVP_OPTION_CAPTURE_OUTPUT    1
 
 struct AndroidForkExecvpOption {
     int opt_type;
@@ -82,6 +84,12 @@
             const uint8_t* input;
             size_t input_len;
         } opt_input;
+        struct {
+            void (*on_output)(const uint8_t* /*output*/,
+                              size_t /*output_len*/,
+                              void* /* user_pointer */);
+            void* user_pointer;
+        } opt_capture_output;
     };
 };
 
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 29aaad4..28d6de7 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -291,7 +291,8 @@
 }
 
 static int parent(const char *tag, int parent_read, pid_t pid,
-        int *chld_sts, int log_target, bool abbreviated, char *file_path) {
+        int *chld_sts, int log_target, bool abbreviated, char *file_path,
+        const struct AndroidForkExecvpOption* opts, size_t opts_len) {
     int status = 0;
     char buffer[4096];
     struct pollfd poll_fds[] = {
@@ -358,6 +359,13 @@
             sz = TEMP_FAILURE_RETRY(
                 read(parent_read, &buffer[b], sizeof(buffer) - 1 - b));
 
+            for (size_t i = 0; sz > 0 && i < opts_len; ++i) {
+                if (opts[i].opt_type == FORK_EXECVP_OPTION_CAPTURE_OUTPUT) {
+                  opts[i].opt_capture_output.on_output(
+                      (uint8_t*)&buffer[b], sz, opts[i].opt_capture_output.user_pointer);
+                }
+            }
+
             sz += b;
             // Log one line at a time
             for (b = 0; b < sz; b++) {
@@ -484,7 +492,6 @@
     sigset_t blockset;
     sigset_t oldset;
     int rc = 0;
-    size_t i;
 
     rc = pthread_mutex_lock(&fd_mutex);
     if (rc) {
@@ -532,7 +539,7 @@
         close(parent_ptty);
 
         // redirect stdin, stdout and stderr
-        for (i = 0; i < opts_len; ++i) {
+        for (size_t i = 0; i < opts_len; ++i) {
             if (opts[i].opt_type == FORK_EXECVP_OPTION_INPUT) {
                 dup2(child_ptty, 0);
                 break;
@@ -554,7 +561,7 @@
             sigaction(SIGQUIT, &ignact, &quitact);
         }
 
-        for (i = 0; i < opts_len; ++i) {
+        for (size_t i = 0; i < opts_len; ++i) {
             if (opts[i].opt_type == FORK_EXECVP_OPTION_INPUT) {
                 size_t left = opts[i].opt_input.input_len;
                 const uint8_t* input = opts[i].opt_input.input;
@@ -571,7 +578,7 @@
         }
 
         rc = parent(argv[0], parent_ptty, pid, status, log_target,
-                    abbreviated, file_path);
+                    abbreviated, file_path, opts, opts_len);
     }
 
     if (ignore_int_quit) {
diff --git a/metricsd/constants.h b/metricsd/constants.h
index d65e0e0..56dac0d 100644
--- a/metricsd/constants.h
+++ b/metricsd/constants.h
@@ -21,7 +21,7 @@
 static const char kMetricsDirectory[] = "/data/misc/metrics/";
 static const char kMetricsEventsFilePath[] = "/data/misc/metrics/uma-events";
 static const char kMetricsGUIDFilePath[] = "/data/misc/metrics/Sysinfo.GUID";
-static const char kMetricsServer[] = "http://clients4.google.com/uma/v2";
+static const char kMetricsServer[] = "https://clients4.google.com/uma/v2";
 static const char kConsentFilePath[] = "/data/misc/metrics/enabled";
 static const char kDefaultVersion[] = "0.0.0.0";
 }  // namespace metrics
diff --git a/metricsd/init.metrics_daemon.rc b/metricsd/init.metrics_daemon.rc
index ad78ea5..73ce673 100644
--- a/metricsd/init.metrics_daemon.rc
+++ b/metricsd/init.metrics_daemon.rc
@@ -1,5 +1,5 @@
 on boot
-    mkdir /data/misc/metrics 0700 system system
+    mkdir /data/misc/metrics 0770 system system
 
 service metrics_daemon /system/bin/metrics_daemon --uploader -nodaemon
     class late_start
diff --git a/metricsd/uploader/metrics_log.cc b/metricsd/uploader/metrics_log.cc
index 5f4c599..1f16ca1 100644
--- a/metricsd/uploader/metrics_log.cc
+++ b/metricsd/uploader/metrics_log.cc
@@ -48,6 +48,6 @@
   stability->set_unclean_system_shutdown_count(current + 1);
 }
 
-void MetricsLog::PopulateSystemProfile(SystemProfileSetter* profile_setter) {
-  profile_setter->Populate(uma_proto());
+bool MetricsLog::PopulateSystemProfile(SystemProfileSetter* profile_setter) {
+  return profile_setter->Populate(uma_proto());
 }
diff --git a/metricsd/uploader/metrics_log.h b/metricsd/uploader/metrics_log.h
index 50fed89..5e09070 100644
--- a/metricsd/uploader/metrics_log.h
+++ b/metricsd/uploader/metrics_log.h
@@ -39,7 +39,7 @@
   void IncrementUncleanShutdownCount();
 
   // Populate the system profile with system information using setter.
-  void PopulateSystemProfile(SystemProfileSetter* setter);
+  bool PopulateSystemProfile(SystemProfileSetter* setter);
 
  private:
   FRIEND_TEST(UploadServiceTest, LogContainsAggregatedValues);
diff --git a/metricsd/uploader/system_profile_cache.cc b/metricsd/uploader/system_profile_cache.cc
index 35910d7..7dd0323 100644
--- a/metricsd/uploader/system_profile_cache.cc
+++ b/metricsd/uploader/system_profile_cache.cc
@@ -75,7 +75,7 @@
 
   if (!base::SysInfo::GetLsbReleaseValue("BRILLO_BUILD_TARGET_ID",
                                          &profile_.build_target_id)) {
-    LOG(ERROR) << "Could not initialize system profile.";
+    LOG(ERROR) << "BRILLO_BUILD_TARGET_ID is not set in /etc/lsb-release.";
     return false;
   }
 
@@ -109,11 +109,12 @@
   return initialized_ || Initialize();
 }
 
-void SystemProfileCache::Populate(
+bool SystemProfileCache::Populate(
     metrics::ChromeUserMetricsExtension* metrics_proto) {
   CHECK(metrics_proto);
-  CHECK(InitializeOrCheck())
-      << "failed to initialize system information.";
+  if (not InitializeOrCheck()) {
+    return false;
+  }
 
   // The client id is hashed before being sent.
   metrics_proto->set_client_id(
@@ -132,6 +133,8 @@
   metrics::SystemProfileProto_BrilloDeviceData* device_data =
       profile_proto->mutable_brillo();
   device_data->set_build_target_id(profile_.build_target_id);
+
+  return true;
 }
 
 std::string SystemProfileCache::GetPersistentGUID(
diff --git a/metricsd/uploader/system_profile_cache.h b/metricsd/uploader/system_profile_cache.h
index c53a18e..ac80b47 100644
--- a/metricsd/uploader/system_profile_cache.h
+++ b/metricsd/uploader/system_profile_cache.h
@@ -52,7 +52,7 @@
   SystemProfileCache(bool testing, const std::string& config_root);
 
   // Populates the ProfileSystem protobuf with system information.
-  void Populate(metrics::ChromeUserMetricsExtension* metrics_proto) override;
+  bool Populate(metrics::ChromeUserMetricsExtension* metrics_proto) override;
 
   // Converts a string representation of the channel to a
   // SystemProfileProto_Channel
diff --git a/metricsd/uploader/system_profile_setter.h b/metricsd/uploader/system_profile_setter.h
index cd311a4..bd3ff42 100644
--- a/metricsd/uploader/system_profile_setter.h
+++ b/metricsd/uploader/system_profile_setter.h
@@ -27,7 +27,7 @@
  public:
   virtual ~SystemProfileSetter() {}
   // Populates the protobuf with system informations.
-  virtual void Populate(metrics::ChromeUserMetricsExtension* profile_proto) = 0;
+  virtual bool Populate(metrics::ChromeUserMetricsExtension* profile_proto) = 0;
 };
 
 #endif  // METRICS_UPLOADER_SYSTEM_PROFILE_SETTER_H_
diff --git a/metricsd/uploader/upload_service.cc b/metricsd/uploader/upload_service.cc
index 63b5789..2335630 100644
--- a/metricsd/uploader/upload_service.cc
+++ b/metricsd/uploader/upload_service.cc
@@ -73,7 +73,6 @@
   CHECK(!staged_log_) << "the staged log should be discarded before starting "
                          "a new metrics log";
   MetricsLog* log = new MetricsLog();
-  log->PopulateSystemProfile(system_profile_setter_.get());
   current_log_.reset(log);
 }
 
@@ -97,13 +96,12 @@
   // Previous upload successful, reading metrics sample from the file.
   ReadMetrics();
   GatherHistograms();
-
-  // No samples found. Exit to avoid sending an empty log.
-  if (!current_log_)
-    return;
-
   StageCurrentLog();
-  SendStagedLog();
+
+  // If a log is available for upload, upload it.
+  if (staged_log_) {
+    SendStagedLog();
+  }
 }
 
 void UploadService::SendStagedLog() {
@@ -225,6 +223,11 @@
 
   staged_log_.swap(current_log_);
   staged_log_->CloseLog();
+  if (!staged_log_->PopulateSystemProfile(system_profile_setter_.get())) {
+    LOG(WARNING) << "Error while adding metadata to the log. Discarding the "
+                 << "log.";
+    staged_log_.reset();
+  }
   failed_upload_count_ = 0;
 }
 
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index e1ba2e9..f853fac 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -2,8 +2,6 @@
 
 #######################################
 # init.rc
-# Only copy init.rc if the target doesn't have its own.
-ifneq ($(TARGET_PROVIDES_INIT_RC),true)
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := init.rc
@@ -12,7 +10,6 @@
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
 
 include $(BUILD_PREBUILT)
-endif
 
 #######################################
 # asan.options
diff --git a/rootdir/init.rc b/rootdir/init.rc
index b48c72b..5febc60 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -84,10 +84,17 @@
     write /proc/sys/kernel/panic_on_oops 1
     write /proc/sys/kernel/hung_task_timeout_secs 0
     write /proc/cpu/alignment 4
+
+    # scheduler tunables
+    # Disable auto-scaling of scheduler tunables with hotplug. The tunables
+    # will vary across devices in unpredictable ways if allowed to scale with
+    # cpu cores.
+    write /proc/sys/kernel/sched_tunable_scaling 0
     write /proc/sys/kernel/sched_latency_ns 10000000
     write /proc/sys/kernel/sched_wakeup_granularity_ns 2000000
     write /proc/sys/kernel/sched_compat_yield 1
     write /proc/sys/kernel/sched_child_runs_first 0
+
     write /proc/sys/kernel/randomize_va_space 2
     write /proc/sys/kernel/kptr_restrict 2
     write /proc/sys/vm/mmap_min_addr 32768
@@ -178,8 +185,11 @@
     trigger late-init
 
 # Load properties from /system/ + /factory after fs mount.
-on load_all_props_action
-    load_all_props
+on load_system_props_action
+    load_system_props
+
+on load_persist_props_action
+    load_persist_props
     start logd
     start logd-reinit
 
@@ -192,12 +202,16 @@
     trigger early-fs
     trigger fs
     trigger post-fs
-    trigger post-fs-data
 
     # Load properties from /system/ + /factory after fs mount. Place
     # this in another action so that the load will be scheduled after the prior
     # issued fs triggers have completed.
-    trigger load_all_props_action
+    trigger load_system_props_action
+
+    # Now we can mount /data. File encryption requires keymaster to decrypt
+    # /data, which in turn can only be loaded when system properties are present
+    trigger post-fs-data
+    trigger load_persist_props_action
 
     # Remove a file to wake up anything waiting for firmware.
     trigger firmware_mounts_complete
@@ -270,7 +284,6 @@
 
     # create basic filesystem structure
     mkdir /data/misc 01771 system misc
-    mkdir /data/misc/adb 02750 system shell
     mkdir /data/misc/bluedroid 02770 bluetooth net_bt_stack
     # Fix the access permissions and group ownership for 'bt_config.conf'
     chmod 0660 /data/misc/bluedroid/bt_config.conf
@@ -330,7 +343,6 @@
     # the following directory.
     mkdir /data/mediadrm 0770 mediadrm mediadrm
 
-    mkdir /data/adb 0700 root root
     mkdir /data/anr 0775 system system
 
     # symlink to bugreport storage location
@@ -348,6 +360,8 @@
     mkdir /data/system/heapdump 0700 system system
     mkdir /data/user 0711 system system
 
+    setusercryptopolicies /data/user
+
     # Reload policy from /data/security if present.
     setprop selinux.reload_policy 1
 
@@ -515,17 +529,6 @@
     critical
     seclabel u:r:ueventd:s0
 
-service logd /system/bin/logd
-    class core
-    socket logd stream 0666 logd logd
-    socket logdr seqpacket 0666 logd logd
-    socket logdw dgram 0222 logd logd
-    group root system
-
-service logd-reinit /system/bin/logd --reinit
-    oneshot
-    disabled
-
 service healthd /sbin/healthd
     class core
     critical
@@ -543,147 +546,10 @@
 on property:ro.debuggable=1
     start console
 
-# adbd is controlled via property triggers in init.<platform>.usb.rc
-service adbd /sbin/adbd --root_seclabel=u:r:su:s0
-    class core
-    socket adbd stream 660 system system
-    disabled
-    seclabel u:r:adbd:s0
-
-# adbd on at boot in emulator
-on property:ro.kernel.qemu=1
-    start adbd
-
-service lmkd /system/bin/lmkd
-    class core
-    critical
-    socket lmkd seqpacket 0660 system system
-
-service servicemanager /system/bin/servicemanager
-    class core
-    user system
-    group system
-    critical
-    onrestart restart healthd
-    onrestart restart zygote
-    onrestart restart media
-    onrestart restart surfaceflinger
-    onrestart restart drm
-
-service vold /system/bin/vold \
-        --blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:blkid_untrusted:s0 \
-        --fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0
-    class core
-    socket vold stream 0660 root mount
-    socket cryptd stream 0660 root mount
-    ioprio be 2
-
-service netd /system/bin/netd
-    class main
-    socket netd stream 0660 root system
-    socket dnsproxyd stream 0660 root inet
-    socket mdns stream 0660 root system
-    socket fwmarkd stream 0660 root inet
-
-service debuggerd /system/bin/debuggerd
-    class main
-
-service debuggerd64 /system/bin/debuggerd64
-    class main
-
-service ril-daemon /system/bin/rild
-    class main
-    socket rild stream 660 root radio
-    socket sap_uim_socket1 stream 660 bluetooth bluetooth
-    socket rild-debug stream 660 radio system
-    user root
-    group radio cache inet misc audio log
-
-service surfaceflinger /system/bin/surfaceflinger
-    class core
-    user system
-    group graphics drmrpc
-    onrestart restart zygote
-
-service drm /system/bin/drmserver
-    class main
-    user drm
-    group drm system inet drmrpc
-
-service media /system/bin/mediaserver
-    class main
-    user media
-    group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
-    ioprio rt 4
-
-# One shot invocation to deal with encrypted volume.
-service defaultcrypto /system/bin/vdc --wait cryptfs mountdefaultencrypted
-    disabled
-    oneshot
-    # vold will set vold.decrypt to trigger_restart_framework (default
-    # encryption) or trigger_restart_min_framework (other encryption)
-
-# One shot invocation to encrypt unencrypted volumes
-service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace default
-    disabled
-    oneshot
-    # vold will set vold.decrypt to trigger_restart_framework (default
-    # encryption)
-
-service bootanim /system/bin/bootanimation
-    class core
-    user graphics
-    group graphics audio
-    disabled
-    oneshot
-
-service gatekeeperd /system/bin/gatekeeperd /data/misc/gatekeeper
-    class late_start
-    user system
-
-service installd /system/bin/installd
-    class main
-    socket installd stream 600 system system
-
 service flash_recovery /system/bin/install-recovery.sh
     class main
     oneshot
 
-service racoon /system/bin/racoon
-    class main
-    socket racoon stream 600 system system
-    # IKE uses UDP port 500. Racoon will setuid to vpn after binding the port.
-    group vpn net_admin inet
-    disabled
-    oneshot
-
-service mtpd /system/bin/mtpd
-    class main
-    socket mtpd stream 600 system system
-    user vpn
-    group vpn net_admin inet net_raw
-    disabled
-    oneshot
-
-service keystore /system/bin/keystore /data/misc/keystore
-    class main
-    user keystore
-    group keystore drmrpc
-
-service dumpstate /system/bin/dumpstate -s
-    class main
-    socket dumpstate stream 0660 shell log
-    disabled
-    oneshot
-
-service mdnsd /system/bin/mdnsd
-    class main
-    user mdnsr
-    group inet net_raw
-    socket mdnsd stream 0660 mdnsr inet
-    disabled
-    oneshot
-
 service uncrypt /system/bin/uncrypt
     class main
     disabled
@@ -693,22 +559,3 @@
     class main
     disabled
     oneshot
-
-service perfprofd /system/xbin/perfprofd
-    class late_start
-    user root
-    oneshot
-
-on property:persist.logd.logpersistd=logcatd
-    # all exec/services are called with umask(077), so no gain beyond 0700
-    mkdir /data/misc/logd 0700 logd log
-    # logd for write to /data/misc/logd, log group for read from pstore (-L)
-    exec - logd log -- /system/bin/logcat -L -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 64 -n 256
-    start logcatd
-
-service logcatd /system/bin/logcat -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 64 -n 256
-    class late_start
-    disabled
-    # logd for write to /data/misc/logd, log group for read from log daemon
-    user logd
-    group log
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index e290ca4..6482230 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -89,3 +89,34 @@
 # when changing the default configuration
 on property:persist.sys.usb.config=*
     setprop sys.usb.config ${persist.sys.usb.config}
+
+#
+# USB type C
+#
+
+# USB mode changes
+on property:sys.usb.typec.mode=dfp
+    write /sys/class/dual_role_usb/otg_default/mode ${sys.usb.typec.mode}
+    setprop sys.usb.typec.state ${sys.usb.typec.mode}
+
+on property:sys.usb.typec.mode=ufp
+    write /sys/class/dual_role_usb/otg_default/mode ${sys.usb.typec.mode}
+    setprop sys.usb.typec.state ${sys.usb.typec.mode}
+
+# USB data role changes
+on property:sys.usb.typec.data_role=device
+    write /sys/class/dual_role_usb/otg_default/data_role ${sys.usb.typec.data}
+    setprop sys.usb.typec.state ${sys.usb.typec.data_role}
+
+on property:sys.usb.typec.data_role=host
+    write /sys/class/dual_role_usb/otg_default/data_role ${sys.usb.typec.data}
+    setprop sys.usb.typec.state ${sys.usb.typec.data_role}
+
+# USB power role changes
+on property:sys.usb.typec.power_role=source
+    write /sys/class/dual_role_usb/otg_default/power_role ${sys.usb.typec.power}
+    setprop sys.usb.typec.state ${sys.usb.typec.power_role}
+
+on property:sys.usb.typec.power_role=sink
+    write /sys/class/dual_role_usb/otg_default/power_role ${sys.usb.typec.power}
+    setprop sys.usb.typec.state ${sys.usb.typec.power_role}
diff --git a/toolbox/lsof.c b/toolbox/lsof.c
index 982f5aa..198ca52 100644
--- a/toolbox/lsof.c
+++ b/toolbox/lsof.c
@@ -29,6 +29,7 @@
  * SUCH DAMAGE.
  */
 
+#include <ctype.h>
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -57,7 +58,7 @@
 
 static void print_header()
 {
-    printf("%-9s %5s %10s %4s %9s %18s %9s %10s %s\n",
+    printf("%-9s %5s %10s %4s   %9s %18s %9s %10s %s\n",
             "COMMAND",
             "PID",
             "USER",
@@ -69,12 +70,12 @@
             "NAME");
 }
 
-static void print_type(char *type, struct pid_info_t* info)
+static void print_symlink(const char* name, const char* path, struct pid_info_t* info)
 {
     static ssize_t link_dest_size;
     static char link_dest[PATH_MAX];
 
-    strlcat(info->path, type, sizeof(info->path));
+    strlcat(info->path, path, sizeof(info->path));
     if ((link_dest_size = readlink(info->path, link_dest, sizeof(link_dest)-1)) < 0) {
         if (errno == ENOENT)
             goto out;
@@ -88,9 +89,53 @@
     if (!strcmp(link_dest, "/"))
         goto out;
 
-    printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n",
-            info->cmdline, info->pid, info->user, type,
-            "???", "???", "???", "???", link_dest);
+    const char* fd = name;
+    char rw = ' ';
+    char locks = ' '; // TODO: read /proc/locks
+
+    const char* type = "unknown";
+    char device[32] = "?";
+    char size_off[32] = "?";
+    char node[32] = "?";
+
+    struct stat sb;
+    if (lstat(link_dest, &sb) != -1) {
+        switch ((sb.st_mode & S_IFMT)) {
+          case S_IFSOCK: type = "sock"; break; // TODO: what domain?
+          case S_IFLNK: type = "LINK"; break;
+          case S_IFREG: type = "REG"; break;
+          case S_IFBLK: type = "BLK"; break;
+          case S_IFDIR: type = "DIR"; break;
+          case S_IFCHR: type = "CHR"; break;
+          case S_IFIFO: type = "FIFO"; break;
+        }
+        snprintf(device, sizeof(device), "%d,%d", (int) sb.st_dev, (int) sb.st_rdev);
+        snprintf(node, sizeof(node), "%d", (int) sb.st_ino);
+        snprintf(size_off, sizeof(size_off), "%d", (int) sb.st_size);
+    }
+
+    if (!name) {
+        // We're looking at an fd, so read its flags.
+        fd = path;
+        char fdinfo_path[PATH_MAX];
+        snprintf(fdinfo_path, sizeof(fdinfo_path), "/proc/%d/fdinfo/%s", info->pid, path);
+        FILE* fp = fopen(fdinfo_path, "r");
+        if (fp != NULL) {
+            int pos;
+            unsigned flags;
+
+            if (fscanf(fp, "pos: %d flags: %o", &pos, &flags) == 2) {
+                flags &= O_ACCMODE;
+                if (flags == O_RDONLY) rw = 'r';
+                else if (flags == O_WRONLY) rw = 'w';
+                else rw = 'u';
+            }
+            fclose(fp);
+        }
+    }
+
+    printf("%-9s %5d %10s %4s%c%c %9s %18s %9s %10s %s\n",
+            info->cmdline, info->pid, info->user, fd, rw, locks, type, device, size_off, node, link_dest);
 
 out:
     info->path[info->parent_length] = '\0';
@@ -111,15 +156,14 @@
     if (!maps)
         goto out;
 
-    while (fscanf(maps, "%*x-%*x %*s %zx %s %ld %s\n", &offset, device, &inode,
-            file) == 4) {
+    while (fscanf(maps, "%*x-%*x %*s %zx %s %ld %s\n", &offset, device, &inode, file) == 4) {
         // We don't care about non-file maps
         if (inode == 0 || !strcmp(device, "00:00"))
             continue;
 
-        printf("%-9s %5d %10s %4s %9s %18s %9zd %10ld %s\n",
+        printf("%-9s %5d %10s %4s   %9s %18s %9zd %10ld %s\n",
                 info->cmdline, info->pid, info->user, "mem",
-                "???", device, offset, inode, file);
+                "REG", device, offset, inode, file);
     }
 
     fclose(maps);
@@ -141,7 +185,7 @@
     if (dir == NULL) {
         char msg[BUF_MAX];
         snprintf(msg, sizeof(msg), "%s (opendir: %s)", info->path, strerror(errno));
-        printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n",
+        printf("%-9s %5d %10s %4s   %9s %18s %9s %10s %s\n",
                 info->cmdline, info->pid, info->user, "FDS",
                 "", "", "", "", msg);
         goto out;
@@ -152,7 +196,7 @@
         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
             continue;
 
-        print_type(de->d_name, info);
+        print_symlink(NULL, de->d_name, info);
     }
     closedir(dir);
 
@@ -207,10 +251,9 @@
     strlcpy(info.cmdline, basename(cmdline), sizeof(info.cmdline));
 
     // Read each of these symlinks
-    print_type("cwd", &info);
-    print_type("exe", &info);
-    print_type("root", &info);
-
+    print_symlink("cwd", "cwd", &info);
+    print_symlink("txt", "exe", &info);
+    print_symlink("rtd", "root", &info);
     print_fds(&info);
     print_maps(&info);
 }