Merge "Add explicit cast to shut off clang warnings." am: 79cfba55e9 am: 7a2aa9d26d
am: 493eaed7fe

* commit '493eaed7fe40455562607b10fd7997581341dd7b':
diff --git a/adb/Android.mk b/adb/Android.mk
index c38cf93..9c8ab6d 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -160,6 +160,19 @@
 LOCAL_SHARED_LIBRARIES := libbase libcutils
 include $(BUILD_NATIVE_TEST)
 
+# libdiagnose_usb
+# =========================================================
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libdiagnose_usb
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_CFLAGS := $(LIBADB_CFLAGS)
+LOCAL_SRC_FILES := diagnose_usb.cpp
+# Even though we're building a static library (and thus there's no link step for
+# this to take effect), this adds the includes to our path.
+LOCAL_STATIC_LIBRARIES := libbase
+include $(BUILD_HOST_STATIC_LIBRARY)
+
 # adb_test
 # =========================================================
 
@@ -185,6 +198,7 @@
     libadb \
     libcrypto_static \
     libcutils \
+    libdiagnose_usb \
 
 # Set entrypoint to wmain from sysdeps_win32.cpp instead of main
 LOCAL_LDFLAGS_windows := -municode
@@ -193,6 +207,8 @@
 LOCAL_LDLIBS_windows := -lws2_32 -luserenv
 LOCAL_STATIC_LIBRARIES_windows := AdbWinApi
 
+LOCAL_MULTILIB := first
+
 include $(BUILD_HOST_NATIVE_TEST)
 
 # adb device tracker (used by ddms) test tool
@@ -261,6 +277,7 @@
     libadb \
     libbase \
     libcrypto_static \
+    libdiagnose_usb \
     liblog \
 
 # Don't use libcutils on Windows.
@@ -331,6 +348,9 @@
     libsquashfs_utils \
     libcutils \
     libbase \
-    libcrypto_static
+    libcrypto_static \
+    libminijail \
+    libminijail_generated \
+    libcap
 
 include $(BUILD_EXECUTABLE)
diff --git a/adb/adb.cpp b/adb/adb.cpp
index c39c178..c03d7db 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -33,10 +33,10 @@
 #include <string>
 #include <vector>
 
-#include <base/logging.h>
-#include <base/macros.h>
-#include <base/stringprintf.h>
-#include <base/strings.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 
 #include "adb_auth.h"
 #include "adb_io.h"
diff --git a/adb/adb.h b/adb/adb.h
index 5187c81..9020fc3 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -22,7 +22,7 @@
 
 #include <string>
 
-#include <base/macros.h>
+#include <android-base/macros.h>
 
 #include "adb_trace.h"
 #include "fdevent.h"
@@ -214,14 +214,14 @@
 void local_connect(int port);
 int  local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error);
 
-/* usb host/client interface */
+// USB host/client interface.
 void usb_init();
 int usb_write(usb_handle *h, const void *data, int len);
 int usb_read(usb_handle *h, void *data, int len);
 int usb_close(usb_handle *h);
 void usb_kick(usb_handle *h);
 
-/* used for USB device detection */
+// USB device detection.
 #if ADB_HOST
 int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
 #endif
diff --git a/adb/adb_auth_client.cpp b/adb/adb_auth_client.cpp
index 463b496..c4ffc85 100644
--- a/adb/adb_auth_client.cpp
+++ b/adb/adb_auth_client.cpp
@@ -228,13 +228,13 @@
 
 static void adb_auth_listener(int fd, unsigned events, void *data)
 {
-    struct sockaddr addr;
+    sockaddr_storage addr;
     socklen_t alen;
     int s;
 
     alen = sizeof(addr);
 
-    s = adb_socket_accept(fd, &addr, &alen);
+    s = adb_socket_accept(fd, reinterpret_cast<sockaddr*>(&addr), &alen);
     if (s < 0) {
         D("Failed to accept: errno=%d", errno);
         return;
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index e11bff0..facacef 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -43,7 +43,7 @@
 #include "mincrypt/rsa.h"
 #undef RSA_verify
 
-#include <base/strings.h>
+#include <android-base/strings.h>
 #include <cutils/list.h>
 
 #include <openssl/evp.h>
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index ddeb5f1..cb5e488 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -31,8 +31,8 @@
 #include <string>
 #include <vector>
 
-#include <base/stringprintf.h>
-#include <base/strings.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <cutils/sockets.h>
 
 #include "adb_io.h"
diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp
index a37fbc0..176b7bd 100644
--- a/adb/adb_io.cpp
+++ b/adb/adb_io.cpp
@@ -20,7 +20,7 @@
 
 #include <unistd.h>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 
 #include "adb_trace.h"
 #include "adb_utils.h"
diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp
index 6928a90..21a82e8 100644
--- a/adb/adb_io_test.cpp
+++ b/adb/adb_io_test.cpp
@@ -27,8 +27,8 @@
 
 #include <string>
 
-#include "base/file.h"
-#include "base/test_utils.h"
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
 
 // All of these tests fail on Windows because they use the C Runtime open(),
 // but the adb_io APIs expect file descriptors from adb_open(). This could
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index d5b1fd5..e8c2338 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -19,7 +19,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 #include <cutils/sockets.h>
 
 #include "sysdeps.h"
@@ -33,21 +33,18 @@
 };
 
 static void ss_listener_event_func(int _fd, unsigned ev, void *_l) {
-    asocket *s;
+    if (ev & FDE_READ) {
+        sockaddr_storage ss;
+        sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
+        socklen_t alen = sizeof(ss);
+        int fd = adb_socket_accept(_fd, addrp, &alen);
+        if (fd < 0) return;
 
-    if(ev & FDE_READ) {
-        struct sockaddr addr;
-        socklen_t alen;
-        int fd;
+        int rcv_buf_size = CHUNK_SIZE;
+        adb_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcv_buf_size, sizeof(rcv_buf_size));
 
-        alen = sizeof(addr);
-        fd = adb_socket_accept(_fd, &addr, &alen);
-        if(fd < 0) return;
-
-        adb_socket_setbufsize(fd, CHUNK_SIZE);
-
-        s = create_local_socket(fd);
-        if(s) {
+        asocket* s = create_local_socket(fd);
+        if (s) {
             connect_to_smartsocket(s);
             return;
         }
@@ -62,12 +59,13 @@
     asocket *s;
 
     if (ev & FDE_READ) {
-        struct sockaddr addr;
+        sockaddr_storage ss;
+        sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
         socklen_t alen;
         int fd;
 
-        alen = sizeof(addr);
-        fd = adb_socket_accept(_fd, &addr, &alen);
+        alen = sizeof(ss);
+        fd = adb_socket_accept(_fd, addrp, &alen);
         if (fd < 0) {
             return;
         }
@@ -83,7 +81,7 @@
     }
 }
 
-static void  free_listener(alistener*  l)
+static void free_listener(alistener*  l)
 {
     if (l->next) {
         l->next->prev = l->prev;
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index cf99df7..62900c0 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -21,8 +21,8 @@
 #include <unordered_map>
 #include <vector>
 
-#include <base/logging.h>
-#include <base/strings.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
 
 #include "adb.h"
 
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index 78b2deb..d50f947 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -17,8 +17,8 @@
 #ifndef __ADB_TRACE_H
 #define __ADB_TRACE_H
 
-#include <base/logging.h>
-#include <base/stringprintf.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 
 /* IMPORTANT: if you change the following list, don't
  * forget to update the corresponding 'tags' table in
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 42f1c7d..b132118 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -26,16 +26,35 @@
 
 #include <algorithm>
 
-#include <base/logging.h>
-#include <base/stringprintf.h>
-#include <base/strings.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 
+#include "adb.h"
 #include "adb_trace.h"
 #include "sysdeps.h"
 
 ADB_MUTEX_DEFINE(basename_lock);
 ADB_MUTEX_DEFINE(dirname_lock);
 
+#if defined(_WIN32)
+constexpr char kNullFileName[] = "NUL";
+#else
+constexpr char kNullFileName[] = "/dev/null";
+#endif
+
+void close_stdin() {
+    int fd = unix_open(kNullFileName, O_RDONLY);
+    if (fd == -1) {
+        fatal_errno("failed to open %s", kNullFileName);
+    }
+
+    if (TEMP_FAILURE_RETRY(dup2(fd, STDIN_FILENO)) == -1) {
+        fatal_errno("failed to redirect stdin to %s", kNullFileName);
+    }
+    unix_close(fd);
+}
+
 bool getcwd(std::string* s) {
   char* cwd = getcwd(nullptr, 0);
   if (cwd != nullptr) *s = cwd;
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 537d0e4..388d7dd 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -19,6 +19,8 @@
 
 #include <string>
 
+void close_stdin();
+
 bool getcwd(std::string* cwd);
 bool directory_exists(const std::string& path);
 
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index 93c20cb..4508bca 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -30,8 +30,8 @@
 
 #include "sysdeps.h"
 
-#include <base/macros.h>
-#include <base/test_utils.h>
+#include <android-base/macros.h>
+#include <android-base/test_utils.h>
 
 #ifdef _WIN32
 static std::string subdir(const char* parent, const char* child) {
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 04b9882..b37d04d 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -27,18 +27,17 @@
 #include <sched.h>
 #endif
 
-#include "base/file.h"
-#include "base/logging.h"
-#include "base/stringprintf.h"
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 
 #include "adb.h"
 #include "adb_auth.h"
 #include "adb_listeners.h"
+#include "adb_utils.h"
 #include "transport.h"
 
 #if defined(_WIN32)
-static const char kNullFileName[] = "NUL";
-
 static BOOL WINAPI ctrlc_handler(DWORD type) {
     // TODO: Consider trying to kill a starting up adb server (if we're in
     // launch_server) by calling GenerateConsoleCtrlEvent().
@@ -66,24 +65,11 @@
     return temp_path_utf8 + log_name;
 }
 #else
-static const char kNullFileName[] = "/dev/null";
-
 static std::string GetLogFilePath() {
     return std::string("/tmp/adb.log");
 }
 #endif
 
-static void close_stdin() {
-    int fd = unix_open(kNullFileName, O_RDONLY);
-    if (fd == -1) {
-        fatal("cannot open '%s': %s", kNullFileName, strerror(errno));
-    }
-    if (dup2(fd, STDIN_FILENO) == -1) {
-        fatal("cannot redirect stdin: %s", strerror(errno));
-    }
-    unix_close(fd);
-}
-
 static void setup_daemon_logging(void) {
     const std::string log_file_path(GetLogFilePath());
     int fd = unix_open(log_file_path.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0640);
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index bd3813e..a025ed7 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -35,9 +35,9 @@
 #include <string>
 #include <vector>
 
-#include <base/logging.h>
-#include <base/stringprintf.h>
-#include <base/strings.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 
 #if !defined(_WIN32)
 #include <signal.h>
@@ -112,9 +112,10 @@
         "                                 (-a preserves file timestamp and mode)\n"
         "  adb sync [ <directory> ]     - copy host->device only if changed\n"
         "                                 (-l means list but don't copy)\n"
-        "  adb shell [-e escape] [-Tt] [-x] [command]\n"
+        "  adb shell [-e escape] [-n] [-Tt] [-x] [command]\n"
         "                               - run remote shell command (interactive shell if no command given)\n"
         "                                 (-e: choose escape character, or \"none\"; default '~')\n"
+        "                                 (-n: don't read from stdin)\n"
         "                                 (-T: disable PTY allocation)\n"
         "                                 (-t: force PTY allocation)\n"
         "                                 (-x: disable remote exit codes and stdout/stderr separation)\n"
@@ -203,7 +204,10 @@
         "  adb version                  - show version num\n"
         "\n"
         "scripting:\n"
-        "  adb wait-for-device          - block until device is online\n"
+        "  adb wait-for[-<transport>]-<state>\n"
+        "                               - wait for device to be in the given state:\n"
+        "                                 device, recovery, sideload, or bootloader\n"
+        "                                 Transport is: usb, local or any [default=any]\n"
         "  adb start-server             - ensure that there is a server running\n"
         "  adb kill-server              - kill the server if it is running\n"
         "  adb get-state                - prints: offline | bootloader | device\n"
@@ -733,6 +737,11 @@
             use_shell_protocol = false;
             --argc;
             ++argv;
+        } else if (!strcmp(argv[0], "-n")) {
+            close_stdin();
+
+            --argc;
+            ++argv;
         } else {
             break;
         }
@@ -1004,19 +1013,49 @@
 #endif /* !defined(_WIN32) */
 }
 
+static bool check_wait_for_device_syntax(const char* service) {
+    // TODO: when we have libc++ for Windows, use a regular expression instead.
+    // wait-for-((any|local|usb)-)?(bootloader|device|recovery|sideload)
+
+    char type[20];
+    char state[20];
+    int length = 0;
+    if (sscanf(service, "wait-for-%20[a-z]-%20[a-z]%n", type, state, &length) < 2 ||
+        length != static_cast<int>(strlen(service))) {
+        fprintf(stderr, "adb: couldn't parse 'wait-for' command: %s\n", service);
+        return false;
+    }
+
+    if (strcmp(type, "any") != 0 && strcmp(type, "local") != 0 && strcmp(type, "usb") != 0) {
+        fprintf(stderr, "adb: unknown type %s; expected 'any', 'local', or 'usb'\n", type);
+        return false;
+    }
+    if (strcmp(state, "bootloader") != 0 && strcmp(state, "device") != 0 &&
+        strcmp(state, "recovery") != 0 && strcmp(state, "sideload") != 0) {
+        fprintf(stderr, "adb: unknown state %s; "
+                        "expected 'bootloader', 'device', 'recovery', or 'sideload'\n", state);
+        return false;
+    }
+    return true;
+}
+
 static bool wait_for_device(const char* service, TransportType t, const char* serial) {
     // Was the caller vague about what they'd like us to wait for?
     // If so, check they weren't more specific in their choice of transport type.
     if (strcmp(service, "wait-for-device") == 0) {
         if (t == kTransportUsb) {
-            service = "wait-for-usb";
+            service = "wait-for-usb-device";
         } else if (t == kTransportLocal) {
-            service = "wait-for-local";
+            service = "wait-for-local-device";
         } else {
-            service = "wait-for-any";
+            service = "wait-for-any-device";
         }
     }
 
+    if (!check_wait_for_device_syntax(service)) {
+        return false;
+    }
+
     std::string cmd = format_host_command(service, t, serial);
     return adb_command(cmd);
 }
@@ -1854,8 +1893,7 @@
     adb_close(remoteFd);
 
     if (strncmp("Success", buf, 7)) {
-        fprintf(stderr, "Failed to write %s\n", file);
-        fputs(buf, stderr);
+        fprintf(stderr, "Failed to install %s: %s", file, buf);
         return 1;
     }
     fputs(buf, stderr);
diff --git a/adb/console.cpp b/adb/console.cpp
index 5a9c6ab..15c6abd 100644
--- a/adb/console.cpp
+++ b/adb/console.cpp
@@ -18,9 +18,9 @@
 
 #include <stdio.h>
 
-#include <base/file.h>
-#include <base/logging.h>
-#include <base/strings.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
 #include <cutils/sockets.h>
 
 #include "adb.h"
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index f4e054e3..78db69d 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -25,15 +25,20 @@
 #include <getopt.h>
 #include <sys/prctl.h>
 
-#include "base/logging.h"
-#include "base/stringprintf.h"
+#include <memory>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <libminijail.h>
+
 #include "cutils/properties.h"
 #include "private/android_filesystem_config.h"
-#include "selinux/selinux.h"
+#include "selinux/android.h"
 
 #include "adb.h"
 #include "adb_auth.h"
 #include "adb_listeners.h"
+#include "adb_utils.h"
 #include "transport.h"
 
 static const char* root_seclabel = nullptr;
@@ -52,12 +57,7 @@
             continue;
         }
 
-        int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
-
-        // Some kernels don't have file capabilities compiled in, and
-        // prctl(PR_CAPBSET_DROP) returns EINVAL. Don't automatically
-        // die when we see such misconfigured kernels.
-        if ((err < 0) && (errno != EINVAL)) {
+        if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0) == -1) {
             PLOG(FATAL) << "Could not drop capabilities";
         }
     }
@@ -90,12 +90,12 @@
     bool adb_root = (strcmp(value, "1") == 0);
     bool adb_unroot = (strcmp(value, "0") == 0);
 
-    // ...except "adb root" lets you keep privileges in a debuggable build.
+    // ... except "adb root" lets you keep privileges in a debuggable build.
     if (ro_debuggable && adb_root) {
         drop = false;
     }
 
-    // ...and "adb unroot" lets you explicitly drop privileges.
+    // ... and "adb unroot" lets you explicitly drop privileges.
     if (adb_unroot) {
         drop = true;
     }
@@ -106,6 +106,62 @@
 #endif // ALLOW_ADBD_ROOT
 }
 
+static void drop_privileges(int server_port) {
+    std::unique_ptr<minijail, void (*)(minijail*)> jail(minijail_new(),
+                                                        &minijail_destroy);
+
+    // Add extra groups:
+    // AID_ADB to access the USB driver
+    // AID_LOG to read system logs (adb logcat)
+    // AID_INPUT to diagnose input issues (getevent)
+    // AID_INET to diagnose network issues (ping)
+    // AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
+    // AID_SDCARD_R to allow reading from the SD card
+    // AID_SDCARD_RW to allow writing to the SD card
+    // AID_NET_BW_STATS to read out qtaguid statistics
+    // AID_READPROC for reading /proc entries across UID boundaries
+    gid_t groups[] = {AID_ADB,      AID_LOG,       AID_INPUT,
+                      AID_INET,     AID_NET_BT,    AID_NET_BT_ADMIN,
+                      AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS,
+                      AID_READPROC};
+    if (minijail_set_supplementary_gids(
+            jail.get(),
+            sizeof(groups) / sizeof(groups[0]),
+            groups) != 0) {
+        LOG(FATAL) << "Could not configure supplementary groups";
+    }
+
+    // Don't listen on a port (default 5037) if running in secure mode.
+    // Don't run as root if running in secure mode.
+    if (should_drop_privileges()) {
+        drop_capabilities_bounding_set_if_needed();
+
+        minijail_change_gid(jail.get(), AID_SHELL);
+        minijail_change_uid(jail.get(), AID_SHELL);
+        // minijail_enter() will abort if any priv-dropping step fails.
+        minijail_enter(jail.get());
+
+        D("Local port disabled");
+    } else {
+        // minijail_enter() will abort if any priv-dropping step fails.
+        minijail_enter(jail.get());
+
+        if (root_seclabel != nullptr) {
+            if (selinux_android_setcon(root_seclabel) < 0) {
+                LOG(FATAL) << "Could not set SELinux context";
+            }
+        }
+        std::string error;
+        std::string local_name =
+            android::base::StringPrintf("tcp:%d", server_port);
+        if (install_listener(local_name, "*smartsocket*", nullptr, 0,
+                             &error)) {
+            LOG(FATAL) << "Could not install *smartsocket* listener: "
+                       << error;
+        }
+    }
+}
+
 int adbd_main(int server_port) {
     umask(0);
 
@@ -133,53 +189,7 @@
           " unchanged.\n");
     }
 
-    // Add extra groups:
-    // AID_ADB to access the USB driver
-    // AID_LOG to read system logs (adb logcat)
-    // AID_INPUT to diagnose input issues (getevent)
-    // AID_INET to diagnose network issues (ping)
-    // AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
-    // AID_SDCARD_R to allow reading from the SD card
-    // AID_SDCARD_RW to allow writing to the SD card
-    // AID_NET_BW_STATS to read out qtaguid statistics
-    // AID_READPROC for reading /proc entries across UID boundaries
-    gid_t groups[] = {AID_ADB,      AID_LOG,       AID_INPUT,
-                      AID_INET,     AID_NET_BT,    AID_NET_BT_ADMIN,
-                      AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS,
-                      AID_READPROC };
-    if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) {
-        PLOG(FATAL) << "Could not set supplemental groups";
-    }
-
-    /* don't listen on a port (default 5037) if running in secure mode */
-    /* don't run as root if we are running in secure mode */
-    if (should_drop_privileges()) {
-        drop_capabilities_bounding_set_if_needed();
-
-        /* then switch user and group to "shell" */
-        if (setgid(AID_SHELL) != 0) {
-            PLOG(FATAL) << "Could not setgid";
-        }
-        if (setuid(AID_SHELL) != 0) {
-            PLOG(FATAL) << "Could not setuid";
-        }
-
-        D("Local port disabled");
-    } else {
-        if (root_seclabel != nullptr) {
-            if (setcon(root_seclabel) < 0) {
-                LOG(FATAL) << "Could not set SELinux context";
-            }
-        }
-        std::string error;
-        std::string local_name =
-            android::base::StringPrintf("tcp:%d", server_port);
-        if (install_listener(local_name, "*smartsocket*", nullptr, 0,
-                             &error)) {
-            LOG(FATAL) << "Could not install *smartsocket* listener: "
-                << error;
-        }
-    }
+    drop_privileges(server_port);
 
     bool is_usb = false;
     if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) {
@@ -217,16 +227,6 @@
     return 0;
 }
 
-static void close_stdin() {
-    int fd = unix_open("/dev/null", O_RDONLY);
-    if (fd == -1) {
-        perror("failed to open /dev/null, stdin will remain open");
-        return;
-    }
-    dup2(fd, STDIN_FILENO);
-    unix_close(fd);
-}
-
 int main(int argc, char** argv) {
     while (true) {
         static struct option opts[] = {
diff --git a/adb/diagnose_usb.cpp b/adb/diagnose_usb.cpp
new file mode 100644
index 0000000..0f067b0
--- /dev/null
+++ b/adb/diagnose_usb.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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 "diagnose_usb.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <android-base/stringprintf.h>
+
+#if defined(__linux__)
+#include <grp.h>
+#endif
+
+static const char kPermissionsHelpUrl[] = "http://developer.android.com/tools/device.html";
+
+// Returns a message describing any potential problems we find with udev, or nullptr if we can't
+// find plugdev information (i.e. udev is not installed).
+static const char* GetUdevProblem() {
+#if defined(__linux__)
+    errno = 0;
+    group* plugdev_group = getgrnam("plugdev");
+
+    if (plugdev_group == nullptr) {
+        if (errno != 0) {
+            perror("failed to read plugdev group info");
+        }
+        // We can't give any generally useful advice here, just let the caller print the help URL.
+        return nullptr;
+    }
+
+    // getgroups(2) indicates that the group_member() may not check the egid so we check it
+    // additionally just to be sure.
+    if (group_member(plugdev_group->gr_gid) || getegid() == plugdev_group->gr_gid) {
+        // The user is in plugdev so the problem is likely with the udev rules.
+        return "verify udev rules";
+    }
+    return "udev requires plugdev group membership";
+#else
+    return nullptr;
+#endif
+}
+
+// Short help text must be a single line, and will look something like:
+//   no permissions (reason); see <URL>
+std::string UsbNoPermissionsShortHelpText() {
+    std::string help_text = "no permissions";
+
+    const char* problem = GetUdevProblem();
+    if (problem != nullptr) {
+        help_text += android::base::StringPrintf(" (%s)", problem);
+    }
+
+    return android::base::StringPrintf("%s; see [%s]", help_text.c_str(), kPermissionsHelpUrl);
+}
+
+// Long help text can span multiple lines and should provide more detailed information.
+std::string UsbNoPermissionsLongHelpText() {
+    std::string header = "insufficient permissions for device";
+
+    const char* problem = GetUdevProblem();
+    if (problem != nullptr) {
+        header += android::base::StringPrintf(": %s", problem);
+    }
+
+    return android::base::StringPrintf("%s.\nSee [%s] for more information.",
+                                       header.c_str(), kPermissionsHelpUrl);
+}
diff --git a/adb/diagnose_usb.h b/adb/diagnose_usb.h
new file mode 100644
index 0000000..325b2e3
--- /dev/null
+++ b/adb/diagnose_usb.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DIAGNOSE_LINUX_USB_H
+#define __DIAGNOSE_LINUX_USB_H
+
+#include <string>
+
+// USB permission error help text. The short version will be one line, long may be multi-line.
+// Returns a string message to print, or an empty string if no problems could be found.
+std::string UsbNoPermissionsShortHelpText();
+std::string UsbNoPermissionsLongHelpText();
+
+#endif
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 46547b9..25e8376 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -31,8 +31,8 @@
 #include <unordered_map>
 #include <vector>
 
-#include <base/logging.h>
-#include <base/stringprintf.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 
 #include "adb_io.h"
 #include "adb_trace.h"
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index ad38369..0fa5917 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -41,9 +41,9 @@
 #include "file_sync_service.h"
 #include "line_printer.h"
 
-#include <base/file.h>
-#include <base/strings.h>
-#include <base/stringprintf.h>
+#include <android-base/file.h>
+#include <android-base/strings.h>
+#include <android-base/stringprintf.h>
 
 struct syncsendbuf {
     unsigned id;
@@ -51,9 +51,44 @@
     char data[SYNC_DATA_MAX];
 };
 
+static void ensure_trailing_separators(std::string& local_path, std::string& remote_path) {
+    if (!adb_is_separator(local_path.back())) {
+        local_path.push_back(OS_PATH_SEPARATOR);
+    }
+    if (remote_path.back() != '/') {
+        remote_path.push_back('/');
+    }
+}
+
+struct copyinfo {
+    std::string lpath;
+    std::string rpath;
+    unsigned int time = 0;
+    unsigned int mode;
+    uint64_t size = 0;
+    bool skip = false;
+
+    copyinfo(const std::string& local_path,
+             const std::string& remote_path,
+             const std::string& name,
+             unsigned int mode)
+            : lpath(local_path), rpath(remote_path), mode(mode) {
+        ensure_trailing_separators(lpath, rpath);
+        lpath.append(name);
+        rpath.append(name);
+        if (S_ISDIR(mode)) {
+            ensure_trailing_separators(lpath, rpath);
+        }
+    }
+};
+
 class SyncConnection {
   public:
-    SyncConnection() : total_bytes(0), start_time_ms_(CurrentTimeMs()) {
+    SyncConnection()
+            : total_bytes_(0),
+              start_time_ms_(CurrentTimeMs()),
+              expected_total_bytes_(0),
+              expect_multiple_files_(false) {
         max = SYNC_DATA_MAX; // TODO: decide at runtime.
 
         std::string error;
@@ -76,6 +111,8 @@
             ReadOrderlyShutdown(fd);
         }
         adb_close(fd);
+
+        line_printer_.KeepInfoLine();
     }
 
     bool IsValid() { return fd >= 0; }
@@ -103,11 +140,9 @@
     // Sending header, payload, and footer in a single write makes a huge
     // difference to "adb sync" performance.
     bool SendSmallFile(const char* path_and_mode,
-                       const char* rpath,
-                       const char* data, size_t data_length,
-                       unsigned mtime) {
-        Print(rpath);
-
+                       const char* lpath, const char* rpath,
+                       unsigned mtime,
+                       const char* data, size_t data_length) {
         size_t path_length = strlen(path_and_mode);
         if (path_length > 1024) {
             Error("SendSmallFile failed: path too long: %zu", path_length);
@@ -116,8 +151,8 @@
         }
 
         std::vector<char> buf(sizeof(SyncRequest) + path_length +
-                 sizeof(SyncRequest) + data_length +
-                 sizeof(SyncRequest));
+                              sizeof(SyncRequest) + data_length +
+                              sizeof(SyncRequest));
         char* p = &buf[0];
 
         SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
@@ -139,12 +174,63 @@
         req_done->path_length = mtime;
         p += sizeof(SyncRequest);
 
-        if (!WriteFdExactly(fd, &buf[0], (p - &buf[0]))) return false;
-
-        total_bytes += data_length;
+        WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
+        total_bytes_ += data_length;
         return true;
     }
 
+    bool SendLargeFile(const char* path_and_mode,
+                       const char* lpath, const char* rpath,
+                       unsigned mtime) {
+        if (!SendRequest(ID_SEND, path_and_mode)) {
+            Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
+            return false;
+        }
+
+        struct stat st;
+        if (stat(lpath, &st) == -1) {
+            Error("cannot stat '%s': %s", lpath, strerror(errno));
+            return false;
+        }
+
+        uint64_t total_size = st.st_size;
+        uint64_t bytes_copied = 0;
+
+        int lfd = adb_open(lpath, O_RDONLY);
+        if (lfd < 0) {
+            Error("opening '%s' locally failed: %s", lpath, strerror(errno));
+            return false;
+        }
+
+        syncsendbuf sbuf;
+        sbuf.id = ID_DATA;
+        while (true) {
+            int bytes_read = adb_read(lfd, sbuf.data, max);
+            if (bytes_read == -1) {
+                Error("reading '%s' locally failed: %s", lpath, strerror(errno));
+                adb_close(lfd);
+                return false;
+            } else if (bytes_read == 0) {
+                break;
+            }
+
+            sbuf.size = bytes_read;
+            WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + bytes_read);
+
+            total_bytes_ += bytes_read;
+            bytes_copied += bytes_read;
+
+            ReportProgress(rpath, bytes_copied, total_size);
+        }
+
+        adb_close(lfd);
+
+        syncmsg msg;
+        msg.data.id = ID_DONE;
+        msg.data.size = mtime;
+        return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
+    }
+
     bool CopyDone(const char* from, const char* to) {
         syncmsg msg;
         if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
@@ -175,27 +261,52 @@
 
     std::string TransferRate() {
         uint64_t ms = CurrentTimeMs() - start_time_ms_;
-        if (total_bytes == 0 || ms == 0) return "";
+        if (total_bytes_ == 0 || ms == 0) return "";
 
         double s = static_cast<double>(ms) / 1000LL;
-        double rate = (static_cast<double>(total_bytes) / s) / (1024*1024);
+        double rate = (static_cast<double>(total_bytes_) / s) / (1024*1024);
         return android::base::StringPrintf(" %.1f MB/s (%" PRId64 " bytes in %.3fs)",
-                                           rate, total_bytes, s);
+                                           rate, total_bytes_, s);
     }
 
-    void Print(const std::string& s) {
-        // TODO: we actually don't want ELIDE; we want "ELIDE if smart, FULL if dumb".
-        line_printer_.Print(s, LinePrinter::ELIDE);
+    void ReportProgress(const char* file, uint64_t file_copied_bytes, uint64_t file_total_bytes) {
+        char overall_percentage_str[5] = "?";
+        if (expected_total_bytes_ != 0) {
+            int overall_percentage = static_cast<int>(total_bytes_ * 100 / expected_total_bytes_);
+            // If we're pulling symbolic links, we'll pull the target of the link rather than
+            // just create a local link, and that will cause us to go over 100%.
+            if (overall_percentage <= 100) {
+                snprintf(overall_percentage_str, sizeof(overall_percentage_str), "%d%%",
+                         overall_percentage);
+            }
+        }
+
+        if (file_copied_bytes > file_total_bytes || file_total_bytes == 0) {
+            // This case can happen if we're racing against something that wrote to the file
+            // between our stat and our read, or if we're reading a magic file that lies about
+            // its size. Just show how much we've copied.
+            Printf("[%4s] %s: %" PRId64 "/?", overall_percentage_str, file, file_copied_bytes);
+        } else {
+            // If we're transferring multiple files, we want to know how far through the current
+            // file we are, as well as the overall percentage.
+            if (expect_multiple_files_) {
+                int file_percentage = static_cast<int>(file_copied_bytes * 100 / file_total_bytes);
+                Printf("[%4s] %s: %d%%", overall_percentage_str, file, file_percentage);
+            } else {
+                Printf("[%4s] %s", overall_percentage_str, file);
+            }
+        }
     }
 
     void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
         std::string s;
+
         va_list ap;
         va_start(ap, fmt);
         android::base::StringAppendV(&s, fmt, ap);
         va_end(ap);
 
-        Print(s);
+        line_printer_.Print(s, LinePrinter::INFO);
     }
 
     void Error(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
@@ -206,7 +317,7 @@
         android::base::StringAppendV(&s, fmt, ap);
         va_end(ap);
 
-        line_printer_.Print(s, LinePrinter::FULL);
+        line_printer_.Print(s, LinePrinter::ERROR);
     }
 
     void Warning(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
@@ -217,10 +328,25 @@
         android::base::StringAppendV(&s, fmt, ap);
         va_end(ap);
 
-        line_printer_.Print(s, LinePrinter::FULL);
+        line_printer_.Print(s, LinePrinter::WARNING);
     }
 
-    uint64_t total_bytes;
+    void ComputeExpectedTotalBytes(const std::vector<copyinfo>& file_list) {
+        expected_total_bytes_ = 0;
+        for (const copyinfo& ci : file_list) {
+            // Unfortunately, this doesn't work for symbolic links, because we'll copy the
+            // target of the link rather than just creating a link. (But ci.size is the link size.)
+            if (!ci.skip) expected_total_bytes_ += ci.size;
+        }
+        expect_multiple_files_ = true;
+    }
+
+    void SetExpectedTotalBytes(uint64_t expected_total_bytes) {
+        expected_total_bytes_ = expected_total_bytes;
+        expect_multiple_files_ = false;
+    }
+
+    uint64_t total_bytes_;
 
     // TODO: add a char[max] buffer here, to replace syncsendbuf...
     int fd;
@@ -229,12 +355,36 @@
   private:
     uint64_t start_time_ms_;
 
+    uint64_t expected_total_bytes_;
+    bool expect_multiple_files_;
+
     LinePrinter line_printer_;
 
     bool SendQuit() {
         return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
     }
 
+    bool WriteOrDie(const char* from, const char* to, const void* data, size_t data_length) {
+        if (!WriteFdExactly(fd, data, data_length)) {
+            if (errno == ECONNRESET) {
+                // Assume adbd told us why it was closing the connection, and
+                // try to read failure reason from adbd.
+                syncmsg msg;
+                if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
+                    Error("failed to copy '%s' to '%s': no response: %s", from, to, strerror(errno));
+                } else if (msg.status.id != ID_FAIL) {
+                    Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from, to, msg.status.id);
+                } else {
+                    ReportCopyFailure(from, to, msg);
+                }
+            } else {
+                Error("%zu-byte write failed: %s", data_length, strerror(errno));
+            }
+            _exit(1);
+        }
+        return true;
+    }
+
     static uint64_t CurrentTimeMs() {
         struct timeval tv;
         gettimeofday(&tv, 0); // (Not clock_gettime because of Mac/Windows.)
@@ -285,68 +435,6 @@
     return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, size);
 }
 
-static bool SendLargeFile(SyncConnection& sc, const char* path_and_mode,
-                          const char* lpath, const char* rpath,
-                          unsigned mtime) {
-    if (!sc.SendRequest(ID_SEND, path_and_mode)) {
-        sc.Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
-        return false;
-    }
-
-    struct stat st;
-    if (stat(lpath, &st) == -1) {
-        sc.Error("cannot stat '%s': %s", lpath, strerror(errno));
-        return false;
-    }
-
-    uint64_t total_size = st.st_size;
-    uint64_t bytes_copied = 0;
-
-    int lfd = adb_open(lpath, O_RDONLY);
-    if (lfd < 0) {
-        sc.Error("cannot open '%s': %s", lpath, strerror(errno));
-        return false;
-    }
-
-    syncsendbuf sbuf;
-    sbuf.id = ID_DATA;
-    while (true) {
-        int ret = adb_read(lfd, sbuf.data, sc.max);
-        if (ret <= 0) {
-            if (ret < 0) {
-                sc.Error("cannot read '%s': %s", lpath, strerror(errno));
-                adb_close(lfd);
-                return false;
-            }
-            break;
-        }
-
-        sbuf.size = ret;
-        if (!WriteFdExactly(sc.fd, &sbuf, sizeof(unsigned) * 2 + ret)) {
-            adb_close(lfd);
-            return false;
-        }
-        sc.total_bytes += ret;
-
-        bytes_copied += ret;
-
-        int percentage = static_cast<int>(bytes_copied * 100 / total_size);
-        sc.Printf("%s: %d%%", rpath, percentage);
-    }
-
-    adb_close(lfd);
-
-    syncmsg msg;
-    msg.data.id = ID_DONE;
-    msg.data.size = mtime;
-    if (!WriteFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
-        sc.Error("failed to send ID_DONE message for '%s': %s", rpath, strerror(errno));
-        return false;
-    }
-
-    return true;
-}
-
 static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
                       unsigned mtime, mode_t mode)
 {
@@ -362,7 +450,9 @@
         }
         buf[data_length++] = '\0';
 
-        if (!sc.SendSmallFile(path_and_mode.c_str(), rpath, buf, data_length, mtime)) return false;
+        if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime, buf, data_length)) {
+            return false;
+        }
         return sc.CopyDone(lpath, rpath);
 #endif
     }
@@ -383,11 +473,12 @@
             sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
             return false;
         }
-        if (!sc.SendSmallFile(path_and_mode.c_str(), rpath, data.data(), data.size(), mtime)) {
+        if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime,
+                              data.data(), data.size())) {
             return false;
         }
     } else {
-        if (!SendLargeFile(sc, path_and_mode.c_str(), lpath, rpath, mtime)) {
+        if (!sc.SendLargeFile(path_and_mode.c_str(), lpath, rpath, mtime)) {
             return false;
         }
     }
@@ -395,8 +486,6 @@
 }
 
 static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath) {
-    sc.Print(rpath);
-
     unsigned size = 0;
     if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return false;
 
@@ -454,12 +543,11 @@
             return false;
         }
 
-        sc.total_bytes += msg.data.size;
+        sc.total_bytes_ += msg.data.size;
 
         bytes_copied += msg.data.size;
 
-        int percentage = static_cast<int>(bytes_copied * 100 / size);
-        sc.Printf("%s: %d%%", rpath, percentage);
+        sc.ReportProgress(rpath, bytes_copied, size);
     }
 
     adb_close(lfd);
@@ -476,50 +564,11 @@
     });
 }
 
-struct copyinfo
-{
-    std::string lpath;
-    std::string rpath;
-    unsigned int time;
-    unsigned int mode;
-    uint64_t size;
-    bool skip;
-};
-
-static void ensure_trailing_separator(std::string& lpath, std::string& rpath) {
-    if (!adb_is_separator(lpath.back())) {
-        lpath.push_back(OS_PATH_SEPARATOR);
-    }
-    if (rpath.back() != '/') {
-        rpath.push_back('/');
-    }
-}
-
-static copyinfo mkcopyinfo(std::string lpath, std::string rpath,
-                           const std::string& name, unsigned int mode) {
-    copyinfo result;
-    result.lpath = std::move(lpath);
-    result.rpath = std::move(rpath);
-    ensure_trailing_separator(result.lpath, result.rpath);
-    result.lpath.append(name);
-    result.rpath.append(name);
-
-    if (S_ISDIR(mode)) {
-        ensure_trailing_separator(result.lpath, result.rpath);
-    }
-
-    result.time = 0;
-    result.mode = mode;
-    result.size = 0;
-    result.skip = false;
-    return result;
-}
-
 static bool IsDotOrDotDot(const char* name) {
     return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
 }
 
-static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* filelist,
+static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
                              const std::string& lpath,
                              const std::string& rpath) {
     std::vector<copyinfo> dirlist;
@@ -546,17 +595,18 @@
             continue;
         }
 
-        copyinfo ci = mkcopyinfo(lpath, rpath, de->d_name, st.st_mode);
+        copyinfo ci(lpath, rpath, de->d_name, st.st_mode);
         if (S_ISDIR(st.st_mode)) {
             dirlist.push_back(ci);
         } else {
             if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
                 sc.Error("skipping special file '%s'", lpath.c_str());
+                ci.skip = true;
             } else {
                 ci.time = st.st_mtime;
                 ci.size = st.st_size;
-                filelist->push_back(ci);
             }
+            file_list->push_back(ci);
         }
     }
 
@@ -569,15 +619,14 @@
         // TODO(b/25566053): Make pushing empty directories work.
         // TODO(b/25457350): We don't preserve permissions on directories.
         sc.Warning("skipping empty directory '%s'", lpath.c_str());
-        copyinfo ci = mkcopyinfo(adb_dirname(lpath), adb_dirname(rpath),
-                                 adb_basename(lpath), S_IFDIR);
+        copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(lpath), S_IFDIR);
         ci.skip = true;
-        filelist->push_back(ci);
+        file_list->push_back(ci);
         return true;
     }
 
     for (const copyinfo& ci : dirlist) {
-        local_build_list(sc, filelist, ci.lpath, ci.rpath);
+        local_build_list(sc, file_list, ci.lpath, ci.rpath);
     }
 
     return true;
@@ -588,29 +637,29 @@
                                   bool list_only) {
     // Make sure that both directory paths end in a slash.
     // Both paths are known to be nonempty, so we don't need to check.
-    ensure_trailing_separator(lpath, rpath);
+    ensure_trailing_separators(lpath, rpath);
 
     // Recursively build the list of files to copy.
-    std::vector<copyinfo> filelist;
+    std::vector<copyinfo> file_list;
     int pushed = 0;
     int skipped = 0;
-    if (!local_build_list(sc, &filelist, lpath, rpath)) {
+    if (!local_build_list(sc, &file_list, lpath, rpath)) {
         return false;
     }
 
     if (check_timestamps) {
-        for (const copyinfo& ci : filelist) {
+        for (const copyinfo& ci : file_list) {
             if (!sc.SendRequest(ID_STAT, ci.rpath.c_str())) {
                 return false;
             }
         }
-        for (copyinfo& ci : filelist) {
+        for (copyinfo& ci : file_list) {
             unsigned int timestamp, mode, size;
             if (!sync_finish_stat(sc, &timestamp, &mode, &size)) {
                 return false;
             }
             if (size == ci.size) {
-                /* for links, we cannot update the atime/mtime */
+                // 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)) {
                     ci.skip = true;
@@ -619,14 +668,14 @@
         }
     }
 
-    for (const copyinfo& ci : filelist) {
+    sc.ComputeExpectedTotalBytes(file_list);
+
+    for (const copyinfo& ci : file_list) {
         if (!ci.skip) {
             if (list_only) {
-                sc.Error("would push: %s -> %s", ci.lpath.c_str(),
-                         ci.rpath.c_str());
+                sc.Error("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
             } else {
-                if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time,
-                               ci.mode)) {
+                if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode)) {
                     return false;
                 }
             }
@@ -636,7 +685,7 @@
         }
     }
 
-    sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s\n", rpath.c_str(),
+    sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s", rpath.c_str(),
               pushed, (pushed == 1) ? "" : "s", skipped,
               (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
     return true;
@@ -708,23 +757,34 @@
                 "%s/%s", dst_path, adb_basename(src_path).c_str());
             dst_path = path_holder.c_str();
         }
+        sc.SetExpectedTotalBytes(st.st_size);
         success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode);
     }
 
-    sc.Print("\n");
     return success;
 }
 
+static bool remote_symlink_isdir(SyncConnection& sc, const std::string& rpath) {
+    unsigned mode;
+    std::string dir_path = rpath;
+    dir_path.push_back('/');
+    if (!sync_stat(sc, dir_path.c_str(), nullptr, &mode, nullptr)) {
+        sc.Error("failed to stat remote symlink '%s'", dir_path.c_str());
+        return false;
+    }
+    return S_ISDIR(mode);
+}
+
 static bool remote_build_list(SyncConnection& sc,
-                              std::vector<copyinfo>* filelist,
+                              std::vector<copyinfo>* file_list,
                               const std::string& rpath,
                               const std::string& lpath) {
     std::vector<copyinfo> dirlist;
+    std::vector<copyinfo> linklist;
     bool empty_dir = true;
 
     // Put the files/dirs in rpath on the lists.
-    auto callback = [&](unsigned mode, unsigned size, unsigned time,
-                        const char* name) {
+    auto callback = [&](unsigned mode, unsigned size, unsigned time, const char* name) {
         if (IsDotOrDotDot(name)) {
             return;
         }
@@ -732,15 +792,15 @@
         // We found a child that isn't '.' or '..'.
         empty_dir = false;
 
-        copyinfo ci = mkcopyinfo(lpath, rpath, name, mode);
+        copyinfo ci(lpath, rpath, name, mode);
         if (S_ISDIR(mode)) {
             dirlist.push_back(ci);
-        } else if (S_ISREG(mode) || S_ISLNK(mode)) {
+        } else if (S_ISLNK(mode)) {
+            linklist.push_back(ci);
+        } else {
             ci.time = time;
             ci.size = size;
-            filelist->push_back(ci);
-        } else {
-            sc.Warning("skipping special file '%s'\n", name);
+            file_list->push_back(ci);
         }
     };
 
@@ -748,19 +808,27 @@
         return false;
     }
 
-    // Add the current directory to the list if it was empty, to ensure that
-    // it gets created.
+    // Add the current directory to the list if it was empty, to ensure that it gets created.
     if (empty_dir) {
-        filelist->push_back(mkcopyinfo(adb_dirname(lpath), adb_dirname(rpath),
-                                       adb_basename(rpath), S_IFDIR));
+        copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(rpath), S_IFDIR);
+        file_list->push_back(ci);
         return true;
     }
 
+    // Check each symlink we found to see whether it's a file or directory.
+    for (copyinfo& link_ci : linklist) {
+        if (remote_symlink_isdir(sc, link_ci.rpath)) {
+            dirlist.emplace_back(std::move(link_ci));
+        } else {
+            file_list->emplace_back(std::move(link_ci));
+        }
+    }
+
     // Recurse into each directory we found.
     while (!dirlist.empty()) {
         copyinfo current = dirlist.back();
         dirlist.pop_back();
-        if (!remote_build_list(sc, filelist, current.rpath, current.lpath)) {
+        if (!remote_build_list(sc, file_list, current.rpath, current.lpath)) {
             return false;
         }
     }
@@ -785,21 +853,21 @@
                                   std::string lpath, bool copy_attrs) {
     // Make sure that both directory paths end in a slash.
     // Both paths are known to be nonempty, so we don't need to check.
-    ensure_trailing_separator(lpath, rpath);
+    ensure_trailing_separators(lpath, rpath);
 
     // Recursively build the list of files to copy.
-    sc.Print("pull: building file list...");
-    std::vector<copyinfo> filelist;
-    if (!remote_build_list(sc, &filelist, rpath.c_str(), lpath.c_str())) {
+    sc.Printf("pull: building file list...");
+    std::vector<copyinfo> file_list;
+    if (!remote_build_list(sc, &file_list, rpath.c_str(), lpath.c_str())) {
         return false;
     }
 
+    sc.ComputeExpectedTotalBytes(file_list);
+
     int pulled = 0;
     int skipped = 0;
-    for (const copyinfo &ci : filelist) {
+    for (const copyinfo &ci : file_list) {
         if (!ci.skip) {
-            sc.Printf("pull: %s -> %s", ci.rpath.c_str(), ci.lpath.c_str());
-
             if (S_ISDIR(ci.mode)) {
                 // Entry is for an empty directory, create it and continue.
                 // TODO(b/25457350): We don't preserve permissions on directories.
@@ -825,7 +893,7 @@
         }
     }
 
-    sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s\n", rpath.c_str(),
+    sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s", rpath.c_str(),
               pulled, (pulled == 1) ? "" : "s", skipped,
               (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
     return true;
@@ -877,8 +945,9 @@
 
     for (const char* src_path : srcs) {
         const char* dst_path = dst;
-        unsigned src_mode, src_time;
-        if (!sync_stat(sc, src_path, &src_time, &src_mode, nullptr)) {
+        unsigned src_mode, src_time, src_size;
+        if (!sync_stat(sc, src_path, &src_time, &src_mode, &src_size)) {
+            sc.Error("failed to stat remote object '%s'", src_path);
             return false;
         }
         if (src_mode == 0) {
@@ -887,28 +956,17 @@
             continue;
         }
 
-        if (S_ISREG(src_mode)) {
-            std::string path_holder;
-            if (dst_isdir) {
-                // If we're copying a remote file to a local directory, we
-                // really want to copy to local_dir + OS_PATH_SEPARATOR +
-                // basename(remote).
-                path_holder = android::base::StringPrintf(
-                    "%s%c%s", dst_path, OS_PATH_SEPARATOR,
-                    adb_basename(src_path).c_str());
-                dst_path = path_holder.c_str();
-            }
-            if (!sync_recv(sc, src_path, dst_path)) {
-                success = false;
-                continue;
-            } else {
-                if (copy_attrs &&
-                    set_time_and_mode(dst_path, src_time, src_mode) != 0) {
-                    success = false;
-                    continue;
-                }
-            }
-        } else if (S_ISDIR(src_mode)) {
+        bool src_isdir = S_ISDIR(src_mode);
+        if (S_ISLNK(src_mode)) {
+            src_isdir = remote_symlink_isdir(sc, src_path);
+        }
+
+        if ((src_mode & (S_IFREG | S_IFDIR | S_IFBLK | S_IFCHR)) == 0) {
+            sc.Error("skipping remote object '%s' (mode = 0o%o)", src_path, src_mode);
+            continue;
+        }
+
+        if (src_isdir) {
             std::string dst_dir = dst;
 
             // If the destination path existed originally, the source directory
@@ -924,17 +982,32 @@
                 dst_dir.append(adb_basename(src_path));
             }
 
-            success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(),
-                                             copy_attrs);
+            success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs);
             continue;
         } else {
-            sc.Error("remote object '%s' not a file or directory", src_path);
-            success = false;
-            continue;
+            std::string path_holder;
+            if (dst_isdir) {
+                // If we're copying a remote file to a local directory, we
+                // really want to copy to local_dir + OS_PATH_SEPARATOR +
+                // basename(remote).
+                path_holder = android::base::StringPrintf("%s%c%s", dst_path, OS_PATH_SEPARATOR,
+                                                          adb_basename(src_path).c_str());
+                dst_path = path_holder.c_str();
+            }
+
+            sc.SetExpectedTotalBytes(src_size);
+            if (!sync_recv(sc, src_path, dst_path)) {
+                success = false;
+                continue;
+            }
+
+            if (copy_attrs && set_time_and_mode(dst_path, src_time, src_mode) != 0) {
+                success = false;
+                continue;
+            }
         }
     }
 
-    sc.Print("\n");
     return success;
 }
 
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 7484a7c..781968b 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -35,8 +35,8 @@
 #include "adb_utils.h"
 #include "private/android_filesystem_config.h"
 
-#include <base/stringprintf.h>
-#include <base/strings.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 
 static bool should_use_fs_config(const std::string& path) {
     // TODO: use fs_config to configure permissions on /data.
@@ -394,6 +394,18 @@
 void file_sync_service(int fd, void* cookie) {
     std::vector<char> buffer(SYNC_DATA_MAX);
 
+    // If there's a problem on the device, we'll send an ID_FAIL message and
+    // close the socket. Unfortunately the kernel will sometimes throw that
+    // data away if the other end keeps writing without reading (which is
+    // the normal case with our protocol --- they won't read until the end).
+    // So set SO_LINGER to give the client 20s to get around to reading our
+    // failure response. Without this, the other side's ability to report
+    // useful errors is reduced.
+    struct linger l;
+    l.l_onoff = 1;
+    l.l_linger = 20;
+    adb_setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
+
     while (handle_sync_command(fd, buffer)) {
     }
 
diff --git a/adb/jdwp_service.cpp b/adb/jdwp_service.cpp
index cc2d44e..3c812cc 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/jdwp_service.cpp
@@ -460,11 +460,11 @@
                    const char*   sockname,
                    int           socknamelen )
 {
-    struct sockaddr_un   addr;
-    socklen_t            addrlen;
-    int                  s;
-    int                  maxpath = sizeof(addr.sun_path);
-    int                  pathlen = socknamelen;
+    sockaddr_un   addr;
+    socklen_t     addrlen;
+    int           s;
+    int           maxpath = sizeof(addr.sun_path);
+    int           pathlen = socknamelen;
 
     if (pathlen >= maxpath) {
         D( "vm debug control socket name too long (%d extra chars)",
@@ -485,7 +485,7 @@
 
     addrlen = (pathlen + sizeof(addr.sun_family));
 
-    if (bind(s, (struct sockaddr*)&addr, addrlen) < 0) {
+    if (bind(s, reinterpret_cast<sockaddr*>(&addr), addrlen) < 0) {
         D( "could not bind vm debug control socket: %d: %s",
            errno, strerror(errno) );
         adb_close(s);
@@ -523,13 +523,14 @@
     JdwpControl*  control = (JdwpControl*) _control;
 
     if (events & FDE_READ) {
-        struct sockaddr   addr;
-        socklen_t         addrlen = sizeof(addr);
-        int               s = -1;
-        JdwpProcess*      proc;
+        sockaddr_storage   ss;
+        sockaddr*          addrp = reinterpret_cast<sockaddr*>(&ss);
+        socklen_t          addrlen = sizeof(ss);
+        int                s = -1;
+        JdwpProcess*       proc;
 
         do {
-            s = adb_socket_accept( control->listen_socket, &addr, &addrlen );
+            s = adb_socket_accept(control->listen_socket, addrp, &addrlen);
             if (s < 0) {
                 if (errno == EINTR)
                     continue;
diff --git a/adb/line_printer.cpp b/adb/line_printer.cpp
index 4c57c7e..e8fe6c9 100644
--- a/adb/line_printer.cpp
+++ b/adb/line_printer.cpp
@@ -43,7 +43,7 @@
   return result;
 }
 
-LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) {
+LinePrinter::LinePrinter() : have_blank_line_(true) {
 #ifndef _WIN32
   const char* term = getenv("TERM");
   smart_terminal_ = unix_isatty(1) && term && string(term) != "dumb";
@@ -59,20 +59,24 @@
 #endif
 }
 
+static void Out(const std::string& s) {
+  // Avoid printf and C strings, since the actual output might contain null
+  // bytes like UTF-16 does (yuck).
+  fwrite(s.data(), 1, s.size(), stdout);
+}
+
 void LinePrinter::Print(string to_print, LineType type) {
-  if (console_locked_) {
-    line_buffer_ = to_print;
-    line_type_ = type;
+  if (!smart_terminal_) {
+    Out(to_print);
     return;
   }
 
-  if (smart_terminal_) {
-    printf("\r");  // Print over previous line, if any.
-    // On Windows, calling a C library function writing to stdout also handles
-    // pausing the executable when the "Pause" key or Ctrl-S is pressed.
-  }
+  // Print over previous line, if any.
+  // On Windows, calling a C library function writing to stdout also handles
+  // pausing the executable when the "Pause" key or Ctrl-S is pressed.
+  printf("\r");
 
-  if (smart_terminal_ && type == ELIDE) {
+  if (type == INFO) {
 #ifdef _WIN32
     CONSOLE_SCREEN_BUFFER_INFO csbi;
     GetConsoleScreenBufferInfo(console_, &csbi);
@@ -105,57 +109,19 @@
     if ((ioctl(0, TIOCGWINSZ, &size) == 0) && size.ws_col) {
       to_print = ElideMiddle(to_print, size.ws_col);
     }
-    printf("%s", to_print.c_str());
+    Out(to_print);
     printf("\x1B[K");  // Clear to end of line.
     fflush(stdout);
 #endif
 
     have_blank_line_ = false;
   } else {
-    printf("%s\n", to_print.c_str());
+    Out(to_print);
+    Out("\n");
+    have_blank_line_ = true;
   }
 }
 
-void LinePrinter::PrintOrBuffer(const char* data, size_t size) {
-  if (console_locked_) {
-    output_buffer_.append(data, size);
-  } else {
-    // Avoid printf and C strings, since the actual output might contain null
-    // bytes like UTF-16 does (yuck).
-    fwrite(data, 1, size, stdout);
-  }
-}
-
-void LinePrinter::PrintOnNewLine(const string& to_print) {
-  if (console_locked_ && !line_buffer_.empty()) {
-    output_buffer_.append(line_buffer_);
-    output_buffer_.append(1, '\n');
-    line_buffer_.clear();
-  }
-  if (!have_blank_line_) {
-    PrintOrBuffer("\n", 1);
-  }
-  if (!to_print.empty()) {
-    PrintOrBuffer(&to_print[0], to_print.size());
-  }
-  have_blank_line_ = to_print.empty() || *to_print.rbegin() == '\n';
-}
-
-void LinePrinter::SetConsoleLocked(bool locked) {
-  if (locked == console_locked_)
-    return;
-
-  if (locked)
-    PrintOnNewLine("");
-
-  console_locked_ = locked;
-
-  if (!locked) {
-    PrintOnNewLine(output_buffer_);
-    if (!line_buffer_.empty()) {
-      Print(line_buffer_, line_type_);
-    }
-    output_buffer_.clear();
-    line_buffer_.clear();
-  }
+void LinePrinter::KeepInfoLine() {
+  if (!have_blank_line_) Out("\n");
 }
diff --git a/adb/line_printer.h b/adb/line_printer.h
index 3d0a5bd..42345e2 100644
--- a/adb/line_printer.h
+++ b/adb/line_printer.h
@@ -26,20 +26,14 @@
   bool is_smart_terminal() const { return smart_terminal_; }
   void set_smart_terminal(bool smart) { smart_terminal_ = smart; }
 
-  enum LineType {
-    FULL,
-    ELIDE
-  };
-  /// Overprints the current line. If type is ELIDE, elides to_print to fit on
-  /// one line.
+  enum LineType { INFO, WARNING, ERROR };
+
+  /// Outputs the given line. INFO output will be overwritten.
+  /// WARNING and ERROR appear on a line to themselves.
   void Print(std::string to_print, LineType type);
 
-  /// Prints a string on a new line, not overprinting previous output.
-  void PrintOnNewLine(const std::string& to_print);
-
-  /// Lock or unlock the console.  Any output sent to the LinePrinter while the
-  /// console is locked will not be printed until it is unlocked.
-  void SetConsoleLocked(bool locked);
+  /// If there's an INFO line, keep it. If not, do nothing.
+  void KeepInfoLine();
 
  private:
   /// Whether we can do fancy terminal control codes.
@@ -48,24 +42,9 @@
   /// Whether the caret is at the beginning of a blank line.
   bool have_blank_line_;
 
-  /// Whether console is locked.
-  bool console_locked_;
-
-  /// Buffered current line while console is locked.
-  std::string line_buffer_;
-
-  /// Buffered line type while console is locked.
-  LineType line_type_;
-
-  /// Buffered console output while console is locked.
-  std::string output_buffer_;
-
 #ifdef _WIN32
   void* console_;
 #endif
-
-  /// Print the given data to the console, or buffer it if it is locked.
-  void PrintOrBuffer(const char *data, size_t size);
 };
 
 #endif  // NINJA_LINE_PRINTER_H_
diff --git a/adb/services.cpp b/adb/services.cpp
index 41da4b8..20166ce 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -31,9 +31,9 @@
 #include <unistd.h>
 #endif
 
-#include <base/file.h>
-#include <base/stringprintf.h>
-#include <base/strings.h>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <cutils/sockets.h>
 
 #if !ADB_HOST
@@ -356,19 +356,19 @@
 #if ADB_HOST
 struct state_info {
     TransportType transport_type;
-    char* serial;
+    std::string serial;
     ConnectionState state;
 };
 
-static void wait_for_state(int fd, void* cookie) {
-    state_info* sinfo = reinterpret_cast<state_info*>(cookie);
+static void wait_for_state(int fd, void* data) {
+    std::unique_ptr<state_info> sinfo(reinterpret_cast<state_info*>(data));
 
     D("wait_for_state %d", sinfo->state);
 
     while (true) {
         bool is_ambiguous = false;
         std::string error = "unknown error";
-        atransport* t = acquire_one_transport(sinfo->transport_type, sinfo->serial,
+        atransport* t = acquire_one_transport(sinfo->transport_type, sinfo->serial.c_str(),
                                               &is_ambiguous, &error);
         if (t != nullptr && t->connection_state == sinfo->state) {
             SendOkay(fd);
@@ -382,10 +382,6 @@
         }
     }
 
-    if (sinfo->serial) {
-        free(sinfo->serial);
-    }
-    free(sinfo);
     adb_close(fd);
     D("wait_for_state is done");
 }
@@ -491,38 +487,43 @@
 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-"))) {
-        auto sinfo = reinterpret_cast<state_info*>(malloc(sizeof(state_info)));
-        if (sinfo == nullptr) {
-            fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno));
-            return NULL;
-        }
-
-        if (serial)
-            sinfo->serial = strdup(serial);
-        else
-            sinfo->serial = NULL;
-
+    } else if (android::base::StartsWith(name, "wait-for-")) {
         name += strlen("wait-for-");
 
-        if (!strncmp(name, "local", strlen("local"))) {
-            sinfo->transport_type = kTransportLocal;
-            sinfo->state = kCsDevice;
-        } else if (!strncmp(name, "usb", strlen("usb"))) {
-            sinfo->transport_type = kTransportUsb;
-            sinfo->state = kCsDevice;
-        } else if (!strncmp(name, "any", strlen("any"))) {
-            sinfo->transport_type = kTransportAny;
-            sinfo->state = kCsDevice;
-        } else {
-            if (sinfo->serial) {
-                free(sinfo->serial);
-            }
-            free(sinfo);
-            return NULL;
+        std::unique_ptr<state_info> sinfo(new state_info);
+        if (sinfo == nullptr) {
+            fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno));
+            return nullptr;
         }
 
-        int fd = create_service_thread(wait_for_state, sinfo);
+        if (serial) sinfo->serial = serial;
+
+        if (android::base::StartsWith(name, "local")) {
+            name += strlen("local");
+            sinfo->transport_type = kTransportLocal;
+        } else if (android::base::StartsWith(name, "usb")) {
+            name += strlen("usb");
+            sinfo->transport_type = kTransportUsb;
+        } else if (android::base::StartsWith(name, "any")) {
+            name += strlen("any");
+            sinfo->transport_type = kTransportAny;
+        } else {
+            return nullptr;
+        }
+
+        if (!strcmp(name, "-device")) {
+            sinfo->state = kCsDevice;
+        } else if (!strcmp(name, "-recovery")) {
+            sinfo->state = kCsRecovery;
+        } else if (!strcmp(name, "-sideload")) {
+            sinfo->state = kCsSideload;
+        } else if (!strcmp(name, "-bootloader")) {
+            sinfo->state = kCsBootloader;
+        } else {
+            return nullptr;
+        }
+
+        int fd = create_service_thread(wait_for_state, sinfo.release());
         return create_local_socket(fd);
     } else if (!strncmp(name, "connect:", 8)) {
         char* host = strdup(name + 8);
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index 2e41fe6..366ed07 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -88,9 +88,12 @@
 #include <termios.h>
 
 #include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
 
-#include <base/logging.h>
-#include <base/stringprintf.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 #include <paths.h>
 
 #include "adb.h"
@@ -237,13 +240,55 @@
     ScopedFd parent_error_sfd, child_error_sfd;
     char pts_name[PATH_MAX];
 
-    // Create a socketpair for the fork() child to report any errors back to
-    // the parent. Since we use threads, logging directly from the child could
-    // create a race condition.
+    // Create a socketpair for the fork() child to report any errors back to the parent. Since we
+    // use threads, logging directly from the child might deadlock due to locks held in another
+    // thread during the fork.
     if (!CreateSocketpair(&parent_error_sfd, &child_error_sfd)) {
         LOG(ERROR) << "failed to create pipe for subprocess error reporting";
     }
 
+    // Construct the environment for the child before we fork.
+    passwd* pw = getpwuid(getuid());
+    std::unordered_map<std::string, std::string> env;
+    if (environ) {
+        char** current = environ;
+        while (char* env_cstr = *current++) {
+            std::string env_string = env_cstr;
+            char* delimiter = strchr(env_string.c_str(), '=');
+
+            // Drop any values that don't contain '='.
+            if (delimiter) {
+                *delimiter++ = '\0';
+                env[env_string.c_str()] = delimiter;
+            }
+        }
+    }
+
+    if (pw != nullptr) {
+        // TODO: $HOSTNAME? Normally bash automatically sets that, but mksh doesn't.
+        env["HOME"] = pw->pw_dir;
+        env["LOGNAME"] = pw->pw_name;
+        env["USER"] = pw->pw_name;
+        env["SHELL"] = pw->pw_shell;
+    }
+
+    if (!terminal_type_.empty()) {
+        env["TERM"] = terminal_type_;
+    }
+
+    std::vector<std::string> joined_env;
+    for (auto it : env) {
+        const char* key = it.first.c_str();
+        const char* value = it.second.c_str();
+        joined_env.push_back(android::base::StringPrintf("%s=%s", key, value));
+    }
+
+    std::vector<const char*> cenv;
+    for (const std::string& str : joined_env) {
+        cenv.push_back(str.c_str());
+    }
+    cenv.push_back(nullptr);
+
     if (type_ == SubprocessType::kPty) {
         int fd;
         pid_ = forkpty(&fd, pts_name, nullptr, nullptr);
@@ -286,26 +331,14 @@
         parent_error_sfd.Reset();
         close_on_exec(child_error_sfd.fd());
 
-        // TODO: $HOSTNAME? Normally bash automatically sets that, but mksh doesn't.
-        passwd* pw = getpwuid(getuid());
-        if (pw != nullptr) {
-            setenv("HOME", pw->pw_dir, 1);
-            setenv("LOGNAME", pw->pw_name, 1);
-            setenv("SHELL", pw->pw_shell, 1);
-            setenv("USER", pw->pw_name, 1);
-        }
-        if (!terminal_type_.empty()) {
-            setenv("TERM", terminal_type_.c_str(), 1);
-        }
-
         if (is_interactive()) {
-            execl(_PATH_BSHELL, _PATH_BSHELL, "-", nullptr);
+            execle(_PATH_BSHELL, _PATH_BSHELL, "-", nullptr, cenv.data());
         } else {
-            execl(_PATH_BSHELL, _PATH_BSHELL, "-c", command_.c_str(), nullptr);
+            execle(_PATH_BSHELL, _PATH_BSHELL, "-c", command_.c_str(), nullptr, cenv.data());
         }
         WriteFdExactly(child_error_sfd.fd(), "exec '" _PATH_BSHELL "' failed");
         child_error_sfd.Reset();
-        exit(-1);
+        _Exit(1);
     }
 
     // Subprocess parent.
@@ -320,6 +353,7 @@
         return false;
     }
 
+    D("subprocess parent: exec completed");
     if (protocol_ == SubprocessProtocol::kNone) {
         // No protocol: all streams pass through the stdinout FD and hook
         // directly into the local socket for raw data transfer.
@@ -357,6 +391,7 @@
         return false;
     }
 
+    D("subprocess parent: completed");
     return true;
 }
 
diff --git a/adb/shell_service.h b/adb/shell_service.h
index 6f8ea9b..e3d676a 100644
--- a/adb/shell_service.h
+++ b/adb/shell_service.h
@@ -27,7 +27,7 @@
 
 #include <stdint.h>
 
-#include <base/macros.h>
+#include <android-base/macros.h>
 
 #include "adb.h"
 
diff --git a/adb/shell_service_test.cpp b/adb/shell_service_test.cpp
index a012f3e..c85232b 100644
--- a/adb/shell_service_test.cpp
+++ b/adb/shell_service_test.cpp
@@ -23,7 +23,7 @@
 #include <string>
 #include <vector>
 
-#include <base/strings.h>
+#include <android-base/strings.h>
 
 #include "adb.h"
 #include "adb_io.h"
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index cba66fc..2190c61 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -29,7 +29,7 @@
 #include <string>
 
 // Include this before open/unlink are defined as macros below.
-#include <base/utf8.h>
+#include <android-base/utf8.h>
 
 /*
  * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
@@ -242,18 +242,6 @@
 #undef   setsockopt
 #define  setsockopt  ___xxx_setsockopt
 
-static __inline__  int  adb_socket_setbufsize( int   fd, int  bufsize )
-{
-    int opt = bufsize;
-    return adb_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const void*)&opt, sizeof(opt));
-}
-
-static __inline__ void  disable_tcp_nagle( int  fd )
-{
-    int  on = 1;
-    adb_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void*)&on, sizeof(on));
-}
-
 extern int  adb_socketpair( int  sv[2] );
 
 static __inline__ int adb_is_absolute_host_path(const char* path) {
@@ -670,18 +658,6 @@
 #endif
 }
 
-static __inline__  int  adb_socket_setbufsize(int fd, int  bufsize )
-{
-    int opt = bufsize;
-    return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
-}
-
-static __inline__ void  disable_tcp_nagle(int fd)
-{
-    int  on = 1;
-    setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on) );
-}
-
 static __inline__ int  adb_setsockopt( int  fd, int  level, int  optname, const void*  optval, socklen_t  optlen )
 {
     return setsockopt( fd, level, optname, optval, optlen );
@@ -739,4 +715,9 @@
 
 #endif /* !_WIN32 */
 
+static inline void disable_tcp_nagle(int fd) {
+    int off = 1;
+    adb_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off));
+}
+
 #endif /* _ADB_SYSDEPS_H */
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 81dcb41..0a2a8f6 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -32,10 +32,10 @@
 
 #include <cutils/sockets.h>
 
-#include <base/logging.h>
-#include <base/stringprintf.h>
-#include <base/strings.h>
-#include <base/utf8.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/utf8.h>
 
 #include "adb.h"
 
diff --git a/adb/sysdeps_win32_test.cpp b/adb/sysdeps_win32_test.cpp
index 55b5eb4..81923cb 100755
--- a/adb/sysdeps_win32_test.cpp
+++ b/adb/sysdeps_win32_test.cpp
@@ -18,7 +18,7 @@
 
 #include "sysdeps.h"
 
-#include "base/test_utils.h"
+#include <android-base/test_utils.h>
 
 TEST(sysdeps_win32, adb_getenv) {
     // Insert all test env vars before first call to adb_getenv() which will
diff --git a/adb/test_device.py b/adb/test_device.py
new file mode 100644
index 0000000..afc061a
--- /dev/null
+++ b/adb/test_device.py
@@ -0,0 +1,985 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# 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.
+#
+from __future__ import print_function
+
+import contextlib
+import hashlib
+import os
+import posixpath
+import random
+import re
+import shlex
+import shutil
+import signal
+import socket
+import string
+import subprocess
+import sys
+import tempfile
+import unittest
+
+import mock
+
+import adb
+
+
+def requires_root(func):
+    def wrapper(self, *args):
+        if self.device.get_prop('ro.debuggable') != '1':
+            raise unittest.SkipTest('requires rootable build')
+
+        was_root = self.device.shell(['id', '-un'])[0].strip() == 'root'
+        if not was_root:
+            self.device.root()
+            self.device.wait()
+
+        try:
+            func(self, *args)
+        finally:
+            if not was_root:
+                self.device.unroot()
+                self.device.wait()
+
+    return wrapper
+
+
+def requires_non_root(func):
+    def wrapper(self, *args):
+        was_root = self.device.shell(['id', '-un'])[0].strip() == 'root'
+        if was_root:
+            self.device.unroot()
+            self.device.wait()
+
+        try:
+            func(self, *args)
+        finally:
+            if was_root:
+                self.device.root()
+                self.device.wait()
+
+    return wrapper
+
+
+class GetDeviceTest(unittest.TestCase):
+    def setUp(self):
+        self.android_serial = os.getenv('ANDROID_SERIAL')
+        if 'ANDROID_SERIAL' in os.environ:
+            del os.environ['ANDROID_SERIAL']
+
+    def tearDown(self):
+        if self.android_serial is not None:
+            os.environ['ANDROID_SERIAL'] = self.android_serial
+        else:
+            if 'ANDROID_SERIAL' in os.environ:
+                del os.environ['ANDROID_SERIAL']
+
+    @mock.patch('adb.device.get_devices')
+    def test_explicit(self, mock_get_devices):
+        mock_get_devices.return_value = ['foo', 'bar']
+        device = adb.get_device('foo')
+        self.assertEqual(device.serial, 'foo')
+
+    @mock.patch('adb.device.get_devices')
+    def test_from_env(self, mock_get_devices):
+        mock_get_devices.return_value = ['foo', 'bar']
+        os.environ['ANDROID_SERIAL'] = 'foo'
+        device = adb.get_device()
+        self.assertEqual(device.serial, 'foo')
+
+    @mock.patch('adb.device.get_devices')
+    def test_arg_beats_env(self, mock_get_devices):
+        mock_get_devices.return_value = ['foo', 'bar']
+        os.environ['ANDROID_SERIAL'] = 'bar'
+        device = adb.get_device('foo')
+        self.assertEqual(device.serial, 'foo')
+
+    @mock.patch('adb.device.get_devices')
+    def test_no_such_device(self, mock_get_devices):
+        mock_get_devices.return_value = ['foo', 'bar']
+        self.assertRaises(adb.DeviceNotFoundError, adb.get_device, ['baz'])
+
+        os.environ['ANDROID_SERIAL'] = 'baz'
+        self.assertRaises(adb.DeviceNotFoundError, adb.get_device)
+
+    @mock.patch('adb.device.get_devices')
+    def test_unique_device(self, mock_get_devices):
+        mock_get_devices.return_value = ['foo']
+        device = adb.get_device()
+        self.assertEqual(device.serial, 'foo')
+
+    @mock.patch('adb.device.get_devices')
+    def test_no_unique_device(self, mock_get_devices):
+        mock_get_devices.return_value = ['foo', 'bar']
+        self.assertRaises(adb.NoUniqueDeviceError, adb.get_device)
+
+
+class DeviceTest(unittest.TestCase):
+    def setUp(self):
+        self.device = adb.get_device()
+
+
+class ForwardReverseTest(DeviceTest):
+    def _test_no_rebind(self, description, direction_list, direction,
+                       direction_no_rebind, direction_remove_all):
+        msg = direction_list()
+        self.assertEqual('', msg.strip(),
+                         description + ' list must be empty to run this test.')
+
+        # Use --no-rebind with no existing binding
+        direction_no_rebind('tcp:5566', 'tcp:6655')
+        msg = direction_list()
+        self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
+
+        # Use --no-rebind with existing binding
+        with self.assertRaises(subprocess.CalledProcessError):
+            direction_no_rebind('tcp:5566', 'tcp:6677')
+        msg = direction_list()
+        self.assertFalse(re.search(r'tcp:5566.+tcp:6677', msg))
+        self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
+
+        # Use the absence of --no-rebind with existing binding
+        direction('tcp:5566', 'tcp:6677')
+        msg = direction_list()
+        self.assertFalse(re.search(r'tcp:5566.+tcp:6655', msg))
+        self.assertTrue(re.search(r'tcp:5566.+tcp:6677', msg))
+
+        direction_remove_all()
+        msg = direction_list()
+        self.assertEqual('', msg.strip())
+
+    def test_forward_no_rebind(self):
+        self._test_no_rebind('forward', self.device.forward_list,
+                            self.device.forward, self.device.forward_no_rebind,
+                            self.device.forward_remove_all)
+
+    def test_reverse_no_rebind(self):
+        self._test_no_rebind('reverse', self.device.reverse_list,
+                            self.device.reverse, self.device.reverse_no_rebind,
+                            self.device.reverse_remove_all)
+
+    def test_forward(self):
+        msg = self.device.forward_list()
+        self.assertEqual('', msg.strip(),
+                         'Forwarding list must be empty to run this test.')
+        self.device.forward('tcp:5566', 'tcp:6655')
+        msg = self.device.forward_list()
+        self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
+        self.device.forward('tcp:7788', 'tcp:8877')
+        msg = self.device.forward_list()
+        self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
+        self.assertTrue(re.search(r'tcp:7788.+tcp:8877', msg))
+        self.device.forward_remove('tcp:5566')
+        msg = self.device.forward_list()
+        self.assertFalse(re.search(r'tcp:5566.+tcp:6655', msg))
+        self.assertTrue(re.search(r'tcp:7788.+tcp:8877', msg))
+        self.device.forward_remove_all()
+        msg = self.device.forward_list()
+        self.assertEqual('', msg.strip())
+
+    def test_reverse(self):
+        msg = self.device.reverse_list()
+        self.assertEqual('', msg.strip(),
+                         'Reverse forwarding list must be empty to run this test.')
+        self.device.reverse('tcp:5566', 'tcp:6655')
+        msg = self.device.reverse_list()
+        self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
+        self.device.reverse('tcp:7788', 'tcp:8877')
+        msg = self.device.reverse_list()
+        self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
+        self.assertTrue(re.search(r'tcp:7788.+tcp:8877', msg))
+        self.device.reverse_remove('tcp:5566')
+        msg = self.device.reverse_list()
+        self.assertFalse(re.search(r'tcp:5566.+tcp:6655', msg))
+        self.assertTrue(re.search(r'tcp:7788.+tcp:8877', msg))
+        self.device.reverse_remove_all()
+        msg = self.device.reverse_list()
+        self.assertEqual('', msg.strip())
+
+    # Note: If you run this test when adb connect'd to a physical device over
+    # TCP, it will fail in adb reverse due to https://code.google.com/p/android/issues/detail?id=189821
+    def test_forward_reverse_echo(self):
+        """Send data through adb forward and read it back via adb reverse"""
+        forward_port = 12345
+        reverse_port = forward_port + 1
+        forward_spec = "tcp:" + str(forward_port)
+        reverse_spec = "tcp:" + str(reverse_port)
+        forward_setup = False
+        reverse_setup = False
+
+        try:
+            # listen on localhost:forward_port, connect to remote:forward_port
+            self.device.forward(forward_spec, forward_spec)
+            forward_setup = True
+            # listen on remote:forward_port, connect to localhost:reverse_port
+            self.device.reverse(forward_spec, reverse_spec)
+            reverse_setup = True
+
+            listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            with contextlib.closing(listener):
+                # Use SO_REUSEADDR so that subsequent runs of the test can grab
+                # the port even if it is in TIME_WAIT.
+                listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+
+                # Listen on localhost:reverse_port before connecting to
+                # localhost:forward_port because that will cause adb to connect
+                # back to localhost:reverse_port.
+                listener.bind(('127.0.0.1', reverse_port))
+                listener.listen(4)
+
+                client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+                with contextlib.closing(client):
+                    # Connect to the listener.
+                    client.connect(('127.0.0.1', forward_port))
+
+                    # Accept the client connection.
+                    accepted_connection, addr = listener.accept()
+                    with contextlib.closing(accepted_connection) as server:
+                        data = 'hello'
+
+                        # Send data into the port setup by adb forward.
+                        client.sendall(data)
+                        # Explicitly close() so that server gets EOF.
+                        client.close()
+
+                        # Verify that the data came back via adb reverse.
+                        self.assertEqual(data, server.makefile().read())
+        finally:
+            if reverse_setup:
+                self.device.reverse_remove(forward_spec)
+            if forward_setup:
+                self.device.forward_remove(forward_spec)
+
+
+class ShellTest(DeviceTest):
+    def _interactive_shell(self, shell_args, input):
+        """Runs an interactive adb shell.
+
+        Args:
+          shell_args: List of string arguments to `adb shell`.
+          input: String input to send to the interactive shell.
+
+        Returns:
+          The remote exit code.
+
+        Raises:
+          unittest.SkipTest: The device doesn't support exit codes.
+        """
+        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+            raise unittest.SkipTest('exit codes are unavailable on this device')
+
+        proc = subprocess.Popen(
+                self.device.adb_cmd + ['shell'] + shell_args,
+                stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+                stderr=subprocess.PIPE)
+        # Closing host-side stdin doesn't trigger a PTY shell to exit so we need
+        # to explicitly add an exit command to close the session from the device
+        # side, plus the necessary newline to complete the interactive command.
+        proc.communicate(input + '; exit\n')
+        return proc.returncode
+
+    def test_cat(self):
+        """Check that we can at least cat a file."""
+        out = self.device.shell(['cat', '/proc/uptime'])[0].strip()
+        elements = out.split()
+        self.assertEqual(len(elements), 2)
+
+        uptime, idle = elements
+        self.assertGreater(float(uptime), 0.0)
+        self.assertGreater(float(idle), 0.0)
+
+    def test_throws_on_failure(self):
+        self.assertRaises(adb.ShellError, self.device.shell, ['false'])
+
+    def test_output_not_stripped(self):
+        out = self.device.shell(['echo', 'foo'])[0]
+        self.assertEqual(out, 'foo' + self.device.linesep)
+
+    def test_shell_nocheck_failure(self):
+        rc, out, _ = self.device.shell_nocheck(['false'])
+        self.assertNotEqual(rc, 0)
+        self.assertEqual(out, '')
+
+    def test_shell_nocheck_output_not_stripped(self):
+        rc, out, _ = self.device.shell_nocheck(['echo', 'foo'])
+        self.assertEqual(rc, 0)
+        self.assertEqual(out, 'foo' + self.device.linesep)
+
+    def test_can_distinguish_tricky_results(self):
+        # If result checking on ADB shell is naively implemented as
+        # `adb shell <cmd>; echo $?`, we would be unable to distinguish the
+        # output from the result for a cmd of `echo -n 1`.
+        rc, out, _ = self.device.shell_nocheck(['echo', '-n', '1'])
+        self.assertEqual(rc, 0)
+        self.assertEqual(out, '1')
+
+    def test_line_endings(self):
+        """Ensure that line ending translation is not happening in the pty.
+
+        Bug: http://b/19735063
+        """
+        output = self.device.shell(['uname'])[0]
+        self.assertEqual(output, 'Linux' + self.device.linesep)
+
+    def test_pty_logic(self):
+        """Tests that a PTY is allocated when it should be.
+
+        PTY allocation behavior should match ssh; some behavior requires
+        a terminal stdin to test so this test will be skipped if stdin
+        is not a terminal.
+        """
+        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+            raise unittest.SkipTest('PTY arguments unsupported on this device')
+        if not os.isatty(sys.stdin.fileno()):
+            raise unittest.SkipTest('PTY tests require stdin terminal')
+
+        def check_pty(args):
+            """Checks adb shell PTY allocation.
+
+            Tests |args| for terminal and non-terminal stdin.
+
+            Args:
+                args: -Tt args in a list (e.g. ['-t', '-t']).
+
+            Returns:
+                A tuple (<terminal>, <non-terminal>). True indicates
+                the corresponding shell allocated a remote PTY.
+            """
+            test_cmd = self.device.adb_cmd + ['shell'] + args + ['[ -t 0 ]']
+
+            terminal = subprocess.Popen(
+                    test_cmd, stdin=None,
+                    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            terminal.communicate()
+
+            non_terminal = subprocess.Popen(
+                    test_cmd, stdin=subprocess.PIPE,
+                    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            non_terminal.communicate()
+
+            return (terminal.returncode == 0, non_terminal.returncode == 0)
+
+        # -T: never allocate PTY.
+        self.assertEqual((False, False), check_pty(['-T']))
+
+        # No args: PTY only if stdin is a terminal and shell is interactive,
+        # which is difficult to reliably test from a script.
+        self.assertEqual((False, False), check_pty([]))
+
+        # -t: PTY if stdin is a terminal.
+        self.assertEqual((True, False), check_pty(['-t']))
+
+        # -t -t: always allocate PTY.
+        self.assertEqual((True, True), check_pty(['-t', '-t']))
+
+    def test_shell_protocol(self):
+        """Tests the shell protocol on the device.
+
+        If the device supports shell protocol, this gives us the ability
+        to separate stdout/stderr and return the exit code directly.
+
+        Bug: http://b/19734861
+        """
+        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+            raise unittest.SkipTest('shell protocol unsupported on this device')
+
+        # Shell protocol should be used by default.
+        result = self.device.shell_nocheck(
+                shlex.split('echo foo; echo bar >&2; exit 17'))
+        self.assertEqual(17, result[0])
+        self.assertEqual('foo' + self.device.linesep, result[1])
+        self.assertEqual('bar' + self.device.linesep, result[2])
+
+        self.assertEqual(17, self._interactive_shell([], 'exit 17'))
+
+        # -x flag should disable shell protocol.
+        result = self.device.shell_nocheck(
+                shlex.split('-x echo foo; echo bar >&2; exit 17'))
+        self.assertEqual(0, result[0])
+        self.assertEqual('foo{0}bar{0}'.format(self.device.linesep), result[1])
+        self.assertEqual('', result[2])
+
+        self.assertEqual(0, self._interactive_shell(['-x'], 'exit 17'))
+
+    def test_non_interactive_sigint(self):
+        """Tests that SIGINT in a non-interactive shell kills the process.
+
+        This requires the shell protocol in order to detect the broken
+        pipe; raw data transfer mode will only see the break once the
+        subprocess tries to read or write.
+
+        Bug: http://b/23825725
+        """
+        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+            raise unittest.SkipTest('shell protocol unsupported on this device')
+
+        # Start a long-running process.
+        sleep_proc = subprocess.Popen(
+                self.device.adb_cmd + shlex.split('shell echo $$; sleep 60'),
+                stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+                stderr=subprocess.STDOUT)
+        remote_pid = sleep_proc.stdout.readline().strip()
+        self.assertIsNone(sleep_proc.returncode, 'subprocess terminated early')
+        proc_query = shlex.split('ps {0} | grep {0}'.format(remote_pid))
+
+        # Verify that the process is running, send signal, verify it stopped.
+        self.device.shell(proc_query)
+        os.kill(sleep_proc.pid, signal.SIGINT)
+        sleep_proc.communicate()
+        self.assertEqual(1, self.device.shell_nocheck(proc_query)[0],
+                         'subprocess failed to terminate')
+
+    def test_non_interactive_stdin(self):
+        """Tests that non-interactive shells send stdin."""
+        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+            raise unittest.SkipTest('non-interactive stdin unsupported '
+                                    'on this device')
+
+        # Test both small and large inputs.
+        small_input = 'foo'
+        large_input = '\n'.join(c * 100 for c in (string.ascii_letters +
+                                                  string.digits))
+
+        for input in (small_input, large_input):
+            proc = subprocess.Popen(self.device.adb_cmd + ['shell', 'cat'],
+                                    stdin=subprocess.PIPE,
+                                    stdout=subprocess.PIPE,
+                                    stderr=subprocess.PIPE)
+            stdout, stderr = proc.communicate(input)
+            self.assertEqual(input.splitlines(), stdout.splitlines())
+            self.assertEqual('', stderr)
+
+
+class ArgumentEscapingTest(DeviceTest):
+    def test_shell_escaping(self):
+        """Make sure that argument escaping is somewhat sane."""
+
+        # http://b/19734868
+        # Note that this actually matches ssh(1)'s behavior --- it's
+        # converted to `sh -c echo hello; echo world` which sh interprets
+        # as `sh -c echo` (with an argument to that shell of "hello"),
+        # and then `echo world` back in the first shell.
+        result = self.device.shell(
+            shlex.split("sh -c 'echo hello; echo world'"))[0]
+        result = result.splitlines()
+        self.assertEqual(['', 'world'], result)
+        # If you really wanted "hello" and "world", here's what you'd do:
+        result = self.device.shell(
+            shlex.split(r'echo hello\;echo world'))[0].splitlines()
+        self.assertEqual(['hello', 'world'], result)
+
+        # http://b/15479704
+        result = self.device.shell(shlex.split("'true && echo t'"))[0].strip()
+        self.assertEqual('t', result)
+        result = self.device.shell(
+            shlex.split("sh -c 'true && echo t'"))[0].strip()
+        self.assertEqual('t', result)
+
+        # http://b/20564385
+        result = self.device.shell(shlex.split('FOO=a BAR=b echo t'))[0].strip()
+        self.assertEqual('t', result)
+        result = self.device.shell(
+            shlex.split(r'echo -n 123\;uname'))[0].strip()
+        self.assertEqual('123Linux', result)
+
+    def test_install_argument_escaping(self):
+        """Make sure that install argument escaping works."""
+        # http://b/20323053, http://b/3090932.
+        for file_suffix in ('-text;ls;1.apk', "-Live Hold'em.apk"):
+            tf = tempfile.NamedTemporaryFile('wb', suffix=file_suffix,
+                                             delete=False)
+            tf.close()
+
+            # Installing bogus .apks fails if the device supports exit codes.
+            try:
+                output = self.device.install(tf.name)
+            except subprocess.CalledProcessError as e:
+                output = e.output
+
+            self.assertIn(file_suffix, output)
+            os.remove(tf.name)
+
+
+class RootUnrootTest(DeviceTest):
+    def _test_root(self):
+        message = self.device.root()
+        if 'adbd cannot run as root in production builds' in message:
+            return
+        self.device.wait()
+        self.assertEqual('root', self.device.shell(['id', '-un'])[0].strip())
+
+    def _test_unroot(self):
+        self.device.unroot()
+        self.device.wait()
+        self.assertEqual('shell', self.device.shell(['id', '-un'])[0].strip())
+
+    def test_root_unroot(self):
+        """Make sure that adb root and adb unroot work, using id(1)."""
+        if self.device.get_prop('ro.debuggable') != '1':
+            raise unittest.SkipTest('requires rootable build')
+
+        original_user = self.device.shell(['id', '-un'])[0].strip()
+        try:
+            if original_user == 'root':
+                self._test_unroot()
+                self._test_root()
+            elif original_user == 'shell':
+                self._test_root()
+                self._test_unroot()
+        finally:
+            if original_user == 'root':
+                self.device.root()
+            else:
+                self.device.unroot()
+            self.device.wait()
+
+
+class TcpIpTest(DeviceTest):
+    def test_tcpip_failure_raises(self):
+        """adb tcpip requires a port.
+
+        Bug: http://b/22636927
+        """
+        self.assertRaises(
+            subprocess.CalledProcessError, self.device.tcpip, '')
+        self.assertRaises(
+            subprocess.CalledProcessError, self.device.tcpip, 'foo')
+
+
+class SystemPropertiesTest(DeviceTest):
+    def test_get_prop(self):
+        self.assertEqual(self.device.get_prop('init.svc.adbd'), 'running')
+
+    @requires_root
+    def test_set_prop(self):
+        prop_name = 'foo.bar'
+        self.device.shell(['setprop', prop_name, '""'])
+
+        self.device.set_prop(prop_name, 'qux')
+        self.assertEqual(
+            self.device.shell(['getprop', prop_name])[0].strip(), 'qux')
+
+
+def compute_md5(string):
+    hsh = hashlib.md5()
+    hsh.update(string)
+    return hsh.hexdigest()
+
+
+def get_md5_prog(device):
+    """Older platforms (pre-L) had the name md5 rather than md5sum."""
+    try:
+        device.shell(['md5sum', '/proc/uptime'])
+        return 'md5sum'
+    except adb.ShellError:
+        return 'md5'
+
+
+class HostFile(object):
+    def __init__(self, handle, checksum):
+        self.handle = handle
+        self.checksum = checksum
+        self.full_path = handle.name
+        self.base_name = os.path.basename(self.full_path)
+
+
+class DeviceFile(object):
+    def __init__(self, checksum, full_path):
+        self.checksum = checksum
+        self.full_path = full_path
+        self.base_name = posixpath.basename(self.full_path)
+
+
+def make_random_host_files(in_dir, num_files):
+    min_size = 1 * (1 << 10)
+    max_size = 16 * (1 << 10)
+
+    files = []
+    for _ in xrange(num_files):
+        file_handle = tempfile.NamedTemporaryFile(dir=in_dir, delete=False)
+
+        size = random.randrange(min_size, max_size, 1024)
+        rand_str = os.urandom(size)
+        file_handle.write(rand_str)
+        file_handle.flush()
+        file_handle.close()
+
+        md5 = compute_md5(rand_str)
+        files.append(HostFile(file_handle, md5))
+    return files
+
+
+def make_random_device_files(device, in_dir, num_files, prefix='device_tmpfile'):
+    min_size = 1 * (1 << 10)
+    max_size = 16 * (1 << 10)
+
+    files = []
+    for file_num in xrange(num_files):
+        size = random.randrange(min_size, max_size, 1024)
+
+        base_name = prefix + str(file_num)
+        full_path = posixpath.join(in_dir, base_name)
+
+        device.shell(['dd', 'if=/dev/urandom', 'of={}'.format(full_path),
+                      'bs={}'.format(size), 'count=1'])
+        dev_md5, _ = device.shell([get_md5_prog(device), full_path])[0].split()
+
+        files.append(DeviceFile(dev_md5, full_path))
+    return files
+
+
+class FileOperationsTest(DeviceTest):
+    SCRATCH_DIR = '/data/local/tmp'
+    DEVICE_TEMP_FILE = SCRATCH_DIR + '/adb_test_file'
+    DEVICE_TEMP_DIR = SCRATCH_DIR + '/adb_test_dir'
+
+    def _verify_remote(self, checksum, remote_path):
+        dev_md5, _ = self.device.shell([get_md5_prog(self.device),
+                                        remote_path])[0].split()
+        self.assertEqual(checksum, dev_md5)
+
+    def _verify_local(self, checksum, local_path):
+        with open(local_path, 'rb') as host_file:
+            host_md5 = compute_md5(host_file.read())
+            self.assertEqual(host_md5, checksum)
+
+    def test_push(self):
+        """Push a randomly generated file to specified device."""
+        kbytes = 512
+        tmp = tempfile.NamedTemporaryFile(mode='wb', delete=False)
+        rand_str = os.urandom(1024 * kbytes)
+        tmp.write(rand_str)
+        tmp.close()
+
+        self.device.shell(['rm', '-rf', self.DEVICE_TEMP_FILE])
+        self.device.push(local=tmp.name, remote=self.DEVICE_TEMP_FILE)
+
+        self._verify_remote(compute_md5(rand_str), self.DEVICE_TEMP_FILE)
+        self.device.shell(['rm', '-f', self.DEVICE_TEMP_FILE])
+
+        os.remove(tmp.name)
+
+    def test_push_dir(self):
+        """Push a randomly generated directory of files to the device."""
+        self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        self.device.shell(['mkdir', self.DEVICE_TEMP_DIR])
+
+        try:
+            host_dir = tempfile.mkdtemp()
+
+            # Make sure the temp directory isn't setuid, or else adb will complain.
+            os.chmod(host_dir, 0o700)
+
+            # Create 32 random files.
+            temp_files = make_random_host_files(in_dir=host_dir, num_files=32)
+            self.device.push(host_dir, self.DEVICE_TEMP_DIR)
+
+            for temp_file in temp_files:
+                remote_path = posixpath.join(self.DEVICE_TEMP_DIR,
+                                             os.path.basename(host_dir),
+                                             temp_file.base_name)
+                self._verify_remote(temp_file.checksum, remote_path)
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        finally:
+            if host_dir is not None:
+                shutil.rmtree(host_dir)
+
+    @unittest.expectedFailure # b/25566053
+    def test_push_empty(self):
+        """Push a directory containing an empty directory to the device."""
+        self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        self.device.shell(['mkdir', self.DEVICE_TEMP_DIR])
+
+        try:
+            host_dir = tempfile.mkdtemp()
+
+            # Make sure the temp directory isn't setuid, or else adb will complain.
+            os.chmod(host_dir, 0o700)
+
+            # Create an empty directory.
+            os.mkdir(os.path.join(host_dir, 'empty'))
+
+            self.device.push(host_dir, self.DEVICE_TEMP_DIR)
+
+            test_empty_cmd = ['[', '-d',
+                              os.path.join(self.DEVICE_TEMP_DIR, 'empty')]
+            rc, _, _ = self.device.shell_nocheck(test_empty_cmd)
+            self.assertEqual(rc, 0)
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        finally:
+            if host_dir is not None:
+                shutil.rmtree(host_dir)
+
+    def test_multiple_push(self):
+        """Push multiple files to the device in one adb push command.
+
+        Bug: http://b/25324823
+        """
+
+        self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        self.device.shell(['mkdir', self.DEVICE_TEMP_DIR])
+
+        try:
+            host_dir = tempfile.mkdtemp()
+
+            # Create some random files and a subdirectory containing more files.
+            temp_files = make_random_host_files(in_dir=host_dir, num_files=4)
+
+            subdir = os.path.join(host_dir, "subdir")
+            os.mkdir(subdir)
+            subdir_temp_files = make_random_host_files(in_dir=subdir,
+                                                       num_files=4)
+
+            paths = map(lambda temp_file: temp_file.full_path, temp_files)
+            paths.append(subdir)
+            self.device._simple_call(['push'] + paths + [self.DEVICE_TEMP_DIR])
+
+            for temp_file in temp_files:
+                remote_path = posixpath.join(self.DEVICE_TEMP_DIR,
+                                             temp_file.base_name)
+                self._verify_remote(temp_file.checksum, remote_path)
+
+            for subdir_temp_file in subdir_temp_files:
+                remote_path = posixpath.join(self.DEVICE_TEMP_DIR,
+                                             # BROKEN: http://b/25394682
+                                             # "subdir",
+                                             temp_file.base_name)
+                self._verify_remote(temp_file.checksum, remote_path)
+
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        finally:
+            if host_dir is not None:
+                shutil.rmtree(host_dir)
+
+
+    def _test_pull(self, remote_file, checksum):
+        tmp_write = tempfile.NamedTemporaryFile(mode='wb', delete=False)
+        tmp_write.close()
+        self.device.pull(remote=remote_file, local=tmp_write.name)
+        with open(tmp_write.name, 'rb') as tmp_read:
+            host_contents = tmp_read.read()
+            host_md5 = compute_md5(host_contents)
+        self.assertEqual(checksum, host_md5)
+        os.remove(tmp_write.name)
+
+    @requires_non_root
+    def test_pull_error_reporting(self):
+        self.device.shell(['touch', self.DEVICE_TEMP_FILE])
+        self.device.shell(['chmod', 'a-rwx', self.DEVICE_TEMP_FILE])
+
+        try:
+            output = self.device.pull(remote=self.DEVICE_TEMP_FILE, local='x')
+        except subprocess.CalledProcessError as e:
+            output = e.output
+
+        self.assertIn('Permission denied', output)
+
+        self.device.shell(['rm', '-f', self.DEVICE_TEMP_FILE])
+
+    def test_pull(self):
+        """Pull a randomly generated file from specified device."""
+        kbytes = 512
+        self.device.shell(['rm', '-rf', self.DEVICE_TEMP_FILE])
+        cmd = ['dd', 'if=/dev/urandom',
+               'of={}'.format(self.DEVICE_TEMP_FILE), 'bs=1024',
+               'count={}'.format(kbytes)]
+        self.device.shell(cmd)
+        dev_md5, _ = self.device.shell(
+            [get_md5_prog(self.device), self.DEVICE_TEMP_FILE])[0].split()
+        self._test_pull(self.DEVICE_TEMP_FILE, dev_md5)
+        self.device.shell_nocheck(['rm', self.DEVICE_TEMP_FILE])
+
+    def test_pull_dir(self):
+        """Pull a randomly generated directory of files from the device."""
+        try:
+            host_dir = tempfile.mkdtemp()
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+            self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR])
+
+            # Populate device directory with random files.
+            temp_files = make_random_device_files(
+                self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32)
+
+            self.device.pull(remote=self.DEVICE_TEMP_DIR, local=host_dir)
+
+            for temp_file in temp_files:
+                host_path = os.path.join(
+                    host_dir, posixpath.basename(self.DEVICE_TEMP_DIR),
+                    temp_file.base_name)
+                self._verify_local(temp_file.checksum, host_path)
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        finally:
+            if host_dir is not None:
+                shutil.rmtree(host_dir)
+
+    def test_pull_symlink_dir(self):
+        """Pull a symlink to a directory of symlinks to files."""
+        try:
+            host_dir = tempfile.mkdtemp()
+
+            remote_dir = posixpath.join(self.DEVICE_TEMP_DIR, 'contents')
+            remote_links = posixpath.join(self.DEVICE_TEMP_DIR, 'links')
+            remote_symlink = posixpath.join(self.DEVICE_TEMP_DIR, 'symlink')
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+            self.device.shell(['mkdir', '-p', remote_dir, remote_links])
+            self.device.shell(['ln', '-s', remote_links, remote_symlink])
+
+            # Populate device directory with random files.
+            temp_files = make_random_device_files(
+                self.device, in_dir=remote_dir, num_files=32)
+
+            for temp_file in temp_files:
+                self.device.shell(
+                    ['ln', '-s', '../contents/{}'.format(temp_file.base_name),
+                     posixpath.join(remote_links, temp_file.base_name)])
+
+            self.device.pull(remote=remote_symlink, local=host_dir)
+
+            for temp_file in temp_files:
+                host_path = os.path.join(
+                    host_dir, 'symlink', temp_file.base_name)
+                self._verify_local(temp_file.checksum, host_path)
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        finally:
+            if host_dir is not None:
+                shutil.rmtree(host_dir)
+
+    def test_pull_empty(self):
+        """Pull a directory containing an empty directory from the device."""
+        try:
+            host_dir = tempfile.mkdtemp()
+
+            remote_empty_path = posixpath.join(self.DEVICE_TEMP_DIR, 'empty')
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+            self.device.shell(['mkdir', '-p', remote_empty_path])
+
+            self.device.pull(remote=remote_empty_path, local=host_dir)
+            self.assertTrue(os.path.isdir(os.path.join(host_dir, 'empty')))
+        finally:
+            if host_dir is not None:
+                shutil.rmtree(host_dir)
+
+    def test_multiple_pull(self):
+        """Pull a randomly generated directory of files from the device."""
+
+        try:
+            host_dir = tempfile.mkdtemp()
+
+            subdir = posixpath.join(self.DEVICE_TEMP_DIR, "subdir")
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+            self.device.shell(['mkdir', '-p', subdir])
+
+            # Create some random files and a subdirectory containing more files.
+            temp_files = make_random_device_files(
+                self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=4)
+
+            subdir_temp_files = make_random_device_files(
+                self.device, in_dir=subdir, num_files=4, prefix='subdir_')
+
+            paths = map(lambda temp_file: temp_file.full_path, temp_files)
+            paths.append(subdir)
+            self.device._simple_call(['pull'] + paths + [host_dir])
+
+            for temp_file in temp_files:
+                local_path = os.path.join(host_dir, temp_file.base_name)
+                self._verify_local(temp_file.checksum, local_path)
+
+            for subdir_temp_file in subdir_temp_files:
+                local_path = os.path.join(host_dir,
+                                          "subdir",
+                                          subdir_temp_file.base_name)
+                self._verify_local(subdir_temp_file.checksum, local_path)
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        finally:
+            if host_dir is not None:
+                shutil.rmtree(host_dir)
+
+    def test_sync(self):
+        """Sync a randomly generated directory of files to specified device."""
+
+        try:
+            base_dir = tempfile.mkdtemp()
+
+            # Create mirror device directory hierarchy within base_dir.
+            full_dir_path = base_dir + self.DEVICE_TEMP_DIR
+            os.makedirs(full_dir_path)
+
+            # Create 32 random files within the host mirror.
+            temp_files = make_random_host_files(in_dir=full_dir_path, num_files=32)
+
+            # Clean up any trash on the device.
+            device = adb.get_device(product=base_dir)
+            device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+
+            device.sync('data')
+
+            # Confirm that every file on the device mirrors that on the host.
+            for temp_file in temp_files:
+                device_full_path = posixpath.join(self.DEVICE_TEMP_DIR,
+                                                  temp_file.base_name)
+                dev_md5, _ = device.shell(
+                    [get_md5_prog(self.device), device_full_path])[0].split()
+                self.assertEqual(temp_file.checksum, dev_md5)
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        finally:
+            if base_dir is not None:
+                shutil.rmtree(base_dir)
+
+    def test_unicode_paths(self):
+        """Ensure that we can support non-ASCII paths, even on Windows."""
+        name = u'로보카 폴리'
+
+        self.device.shell(['rm', '-f', '/data/local/tmp/adb-test-*'])
+        remote_path = u'/data/local/tmp/adb-test-{}'.format(name)
+
+        ## push.
+        tf = tempfile.NamedTemporaryFile('wb', suffix=name, delete=False)
+        tf.close()
+        self.device.push(tf.name, remote_path)
+        os.remove(tf.name)
+        self.assertFalse(os.path.exists(tf.name))
+
+        # Verify that the device ended up with the expected UTF-8 path
+        output = self.device.shell(
+                ['ls', '/data/local/tmp/adb-test-*'])[0].strip()
+        self.assertEqual(remote_path.encode('utf-8'), output)
+
+        # pull.
+        self.device.pull(remote_path, tf.name)
+        self.assertTrue(os.path.exists(tf.name))
+        os.remove(tf.name)
+        self.device.shell(['rm', '-f', '/data/local/tmp/adb-test-*'])
+
+
+def main():
+    random.seed(0)
+    if len(adb.get_devices()) > 0:
+        suite = unittest.TestLoader().loadTestsFromName(__name__)
+        unittest.TextTestRunner(verbosity=3).run(suite)
+    else:
+        print('Test suite must be run with attached devices')
+
+
+if __name__ == '__main__':
+    main()
diff --git a/adb/test_track_devices.cpp b/adb/test_track_devices.cpp
index 6f658f6..b10f8ee 100644
--- a/adb/test_track_devices.cpp
+++ b/adb/test_track_devices.cpp
@@ -9,7 +9,7 @@
 #include <sys/socket.h>
 #include <unistd.h>
 
-#include <base/file.h>
+#include <android-base/file.h>
 
 static void
 panic( const char*  msg )
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 2f18f20..f8c8c61 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -29,12 +29,13 @@
 #include <algorithm>
 #include <list>
 
-#include <base/logging.h>
-#include <base/stringprintf.h>
-#include <base/strings.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 
 #include "adb.h"
 #include "adb_utils.h"
+#include "diagnose_usb.h"
 
 static void transport_unref(atransport *t);
 
@@ -674,7 +675,9 @@
     adb_mutex_lock(&transport_lock);
     for (const auto& t : transport_list) {
         if (t->connection_state == kCsNoPerm) {
-            *error_out = "insufficient permissions for device";
+#if ADB_HOST
+            *error_out = UsbNoPermissionsLongHelpText();
+#endif
             continue;
         }
 
@@ -748,17 +751,17 @@
     return result;
 }
 
-const char* atransport::connection_state_name() const {
+const std::string atransport::connection_state_name() const {
     switch (connection_state) {
-    case kCsOffline: return "offline";
-    case kCsBootloader: return "bootloader";
-    case kCsDevice: return "device";
-    case kCsHost: return "host";
-    case kCsRecovery: return "recovery";
-    case kCsNoPerm: return "no permissions";
-    case kCsSideload: return "sideload";
-    case kCsUnauthorized: return "unauthorized";
-    default: return "unknown";
+        case kCsOffline: return "offline";
+        case kCsBootloader: return "bootloader";
+        case kCsDevice: return "device";
+        case kCsHost: return "host";
+        case kCsRecovery: return "recovery";
+        case kCsNoPerm: return UsbNoPermissionsShortHelpText();
+        case kCsSideload: return "sideload";
+        case kCsUnauthorized: return "unauthorized";
+        default: return "unknown";
     }
 }
 
@@ -785,9 +788,7 @@
     // Local static allocation to avoid global non-POD variables.
     static const FeatureSet* features = new FeatureSet{
         kFeatureShell2,
-        // Internal master has 'cmd'. AOSP master doesn't.
-        // kFeatureCmd
-
+        kFeatureCmd
         // Increment ADB_SERVER_VERSION whenever the feature list changes to
         // make sure that the adb client and server features stay in sync
         // (http://b/24370690).
@@ -866,7 +867,8 @@
         *result += '\t';
         *result += t->connection_state_name();
     } else {
-        android::base::StringAppendF(result, "%-22s %s", serial, t->connection_state_name());
+        android::base::StringAppendF(result, "%-22s %s", serial,
+                                     t->connection_state_name().c_str());
 
         append_transport_info(result, "", t->devpath, false);
         append_transport_info(result, "product:", t->product, false);
diff --git a/adb/transport.h b/adb/transport.h
index d9845b6..76d6afa 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -90,7 +90,7 @@
     fdevent auth_fde;
     size_t failed_auth_attempts = 0;
 
-    const char* connection_state_name() const;
+    const std::string connection_state_name() const;
 
     void update_version(int version, size_t payload);
     int get_protocol_version() const;
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index bf0cc3c..d2a375a 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -25,7 +25,7 @@
 #include <string.h>
 #include <sys/types.h>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 #include <cutils/sockets.h>
 
 #if !ADB_HOST
@@ -143,7 +143,8 @@
 static void *server_socket_thread(void * arg)
 {
     int serverfd, fd;
-    struct sockaddr addr;
+    sockaddr_storage ss;
+    sockaddr *addrp = reinterpret_cast<sockaddr*>(&ss);
     socklen_t alen;
     int port = (int) (uintptr_t) arg;
 
@@ -162,9 +163,9 @@
             close_on_exec(serverfd);
         }
 
-        alen = sizeof(addr);
+        alen = sizeof(ss);
         D("server: trying to get new connection from %d", port);
-        fd = adb_socket_accept(serverfd, &addr, &alen);
+        fd = adb_socket_accept(serverfd, addrp, &alen);
         if(fd >= 0) {
             D("server: new connection on fd %d", fd);
             close_on_exec(fd);
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index 0358b62..ed5d2d67 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -39,9 +39,9 @@
 #include <mutex>
 #include <string>
 
-#include <base/file.h>
-#include <base/stringprintf.h>
-#include <base/strings.h>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 
 #include "adb.h"
 #include "transport.h"
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index 3495a71..a4f1a70 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -30,6 +30,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <algorithm>
+
 #include "adb.h"
 #include "transport.h"
 
@@ -37,6 +39,13 @@
 #define MAX_PACKET_SIZE_HS	512
 #define MAX_PACKET_SIZE_SS	1024
 
+// Writes larger than 16k fail on some devices (seed with 3.10.49-g209ea2f in particular).
+#define USB_FFS_MAX_WRITE 16384
+
+// The kernel allocates a contiguous buffer for reads, which can fail for large ones due to
+// fragmentation. 16k chosen arbitrarily to match the write limit.
+#define USB_FFS_MAX_READ 16384
+
 #define cpu_to_le16(x)  htole16(x)
 #define cpu_to_le32(x)  htole32(x)
 
@@ -456,56 +465,40 @@
     return 0;
 }
 
-static int bulk_write(int bulk_in, const uint8_t* buf, size_t length)
-{
-    size_t count = 0;
-
-    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 ]", bulk_in);
-    return count;
-}
-
-static int usb_ffs_write(usb_handle* h, const void* data, int len)
-{
+static int usb_ffs_write(usb_handle* h, const void* data, int len) {
     D("about to write (fd=%d, len=%d)", h->bulk_in, len);
-    int n = bulk_write(h->bulk_in, reinterpret_cast<const uint8_t*>(data), len);
-    if (n != len) {
-        D("ERROR: fd = %d, n = %d: %s", h->bulk_in, n, strerror(errno));
-        return -1;
+
+    const char* buf = static_cast<const char*>(data);
+    while (len > 0) {
+        int write_len = std::min(USB_FFS_MAX_WRITE, len);
+        int n = adb_write(h->bulk_in, buf, write_len);
+        if (n < 0) {
+            D("ERROR: fd = %d, n = %d: %s", h->bulk_in, n, strerror(errno));
+            return -1;
+        }
+        buf += n;
+        len -= n;
     }
+
     D("[ done fd=%d ]", h->bulk_in);
     return 0;
 }
 
-static int bulk_read(int bulk_out, uint8_t* buf, size_t length)
-{
-    size_t count = 0;
+static int usb_ffs_read(usb_handle* h, void* data, int len) {
+    D("about to read (fd=%d, len=%d)", h->bulk_out, len);
 
-    while (count < length) {
-        int ret = adb_read(bulk_out, buf + count, length - count);
-        if (ret < 0) {
-            D("[ bulk_read failed fd=%d length=%zu count=%zu ]", bulk_out, length, count);
+    char* buf = static_cast<char*>(data);
+    while (len > 0) {
+        int read_len = std::min(USB_FFS_MAX_READ, len);
+        int n = adb_read(h->bulk_out, buf, read_len);
+        if (n < 0) {
+            D("ERROR: fd = %d, n = %d: %s", h->bulk_out, n, strerror(errno));
             return -1;
         }
-        count += ret;
+        buf += n;
+        len -= n;
     }
 
-    return count;
-}
-
-static int usb_ffs_read(usb_handle* h, void* data, int len)
-{
-    D("about to read (fd=%d, len=%d)", h->bulk_out, len);
-    int n = bulk_read(h->bulk_out, reinterpret_cast<uint8_t*>(data), len);
-    if (n != len) {
-        D("ERROR: fd = %d, n = %d: %s", h->bulk_out, n, strerror(errno));
-        return -1;
-    }
     D("[ done fd=%d ]", h->bulk_out);
     return 0;
 }
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index e0dcc756..148be1d 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -29,8 +29,8 @@
 #include <inttypes.h>
 #include <stdio.h>
 
-#include <base/logging.h>
-#include <base/stringprintf.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 
 #include "adb.h"
 #include "transport.h"
diff --git a/base/file.cpp b/base/file.cpp
index 7b5e7b1..f444c0c 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "base/file.h"
+#include "android-base/file.h"
 
 #include <errno.h>
 #include <fcntl.h>
@@ -23,8 +23,8 @@
 
 #include <string>
 
-#include "base/macros.h"  // For TEMP_FAILURE_RETRY on Darwin.
-#include "base/utf8.h"
+#include "android-base/macros.h"  // For TEMP_FAILURE_RETRY on Darwin.
+#include "android-base/utf8.h"
 #define LOG_TAG "base.file"
 #include "cutils/log.h"
 #include "utils/Compat.h"
diff --git a/base/file_test.cpp b/base/file_test.cpp
index 77b9268..1bf83a4 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "base/file.h"
+#include "android-base/file.h"
 
 #include <gtest/gtest.h>
 
@@ -24,7 +24,7 @@
 
 #include <string>
 
-#include "base/test_utils.h"
+#include "android-base/test_utils.h"
 
 TEST(file, ReadFileToString_ENOENT) {
   std::string s("hello");
diff --git a/base/include/base/file.h b/base/include/android-base/file.h
similarity index 100%
rename from base/include/base/file.h
rename to base/include/android-base/file.h
diff --git a/base/include/base/logging.h b/base/include/android-base/logging.h
similarity index 99%
rename from base/include/base/logging.h
rename to base/include/android-base/logging.h
index 30f6906..cd526d0 100644
--- a/base/include/base/logging.h
+++ b/base/include/android-base/logging.h
@@ -29,7 +29,7 @@
 #include <memory>
 #include <ostream>
 
-#include "base/macros.h"
+#include "android-base/macros.h"
 
 namespace android {
 namespace base {
diff --git a/base/include/base/macros.h b/base/include/android-base/macros.h
similarity index 100%
rename from base/include/base/macros.h
rename to base/include/android-base/macros.h
diff --git a/base/include/base/memory.h b/base/include/android-base/memory.h
similarity index 100%
rename from base/include/base/memory.h
rename to base/include/android-base/memory.h
diff --git a/base/include/base/parseint.h b/base/include/android-base/parseint.h
similarity index 100%
rename from base/include/base/parseint.h
rename to base/include/android-base/parseint.h
diff --git a/base/include/base/stringprintf.h b/base/include/android-base/stringprintf.h
similarity index 100%
rename from base/include/base/stringprintf.h
rename to base/include/android-base/stringprintf.h
diff --git a/base/include/base/strings.h b/base/include/android-base/strings.h
similarity index 100%
rename from base/include/base/strings.h
rename to base/include/android-base/strings.h
diff --git a/base/include/base/test_utils.h b/base/include/android-base/test_utils.h
similarity index 96%
rename from base/include/base/test_utils.h
rename to base/include/android-base/test_utils.h
index 402e0a5..3f6872c 100644
--- a/base/include/base/test_utils.h
+++ b/base/include/android-base/test_utils.h
@@ -19,7 +19,7 @@
 
 #include <string>
 
-#include <base/macros.h>
+#include <android-base/macros.h>
 
 class TemporaryFile {
  public:
diff --git a/base/include/base/unique_fd.h b/base/include/android-base/unique_fd.h
similarity index 97%
rename from base/include/base/unique_fd.h
rename to base/include/android-base/unique_fd.h
index 4117775..d3b27ca 100644
--- a/base/include/base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -19,7 +19,7 @@
 
 #include <unistd.h>
 
-#include <base/macros.h>
+#include <android-base/macros.h>
 
 /* Container for a file descriptor that automatically closes the descriptor as
  * it goes out of scope.
diff --git a/base/include/base/utf8.h b/base/include/android-base/utf8.h
similarity index 100%
rename from base/include/base/utf8.h
rename to base/include/android-base/utf8.h
diff --git a/base/logging.cpp b/base/logging.cpp
index 85f8b3f..a385902 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -18,7 +18,7 @@
 #include <windows.h>
 #endif
 
-#include "base/logging.h"
+#include "android-base/logging.h"
 
 #include <libgen.h>
 
@@ -40,8 +40,8 @@
 #include <mutex>
 #endif
 
-#include "base/macros.h"
-#include "base/strings.h"
+#include "android-base/macros.h"
+#include "android-base/strings.h"
 #include "cutils/threads.h"
 
 // Headers for LogMessage::LogLine.
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
index 70f9952..3de42b7 100644
--- a/base/logging_test.cpp
+++ b/base/logging_test.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "base/logging.h"
+#include "android-base/logging.h"
 
 #include <libgen.h>
 
@@ -25,9 +25,9 @@
 #include <regex>
 #include <string>
 
-#include "base/file.h"
-#include "base/stringprintf.h"
-#include "base/test_utils.h"
+#include "android-base/file.h"
+#include "android-base/stringprintf.h"
+#include "android-base/test_utils.h"
 
 #include <gtest/gtest.h>
 
diff --git a/base/parseint_test.cpp b/base/parseint_test.cpp
index 8a11d29..6a3ba31 100644
--- a/base/parseint_test.cpp
+++ b/base/parseint_test.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "base/parseint.h"
+#include "android-base/parseint.h"
 
 #include <gtest/gtest.h>
 
diff --git a/base/stringprintf.cpp b/base/stringprintf.cpp
index d55ff52..78e1e8d 100644
--- a/base/stringprintf.cpp
+++ b/base/stringprintf.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "base/stringprintf.h"
+#include "android-base/stringprintf.h"
 
 #include <stdio.h>
 
diff --git a/base/stringprintf_test.cpp b/base/stringprintf_test.cpp
index 5cc2086..fc009b1 100644
--- a/base/stringprintf_test.cpp
+++ b/base/stringprintf_test.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "base/stringprintf.h"
+#include "android-base/stringprintf.h"
 
 #include <gtest/gtest.h>
 
diff --git a/base/strings.cpp b/base/strings.cpp
index d687e3c..b8775df 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "base/strings.h"
+#include "android-base/strings.h"
 
 #include <stdlib.h>
 #include <string.h>
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 5f67575..30ae29e 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "base/strings.h"
+#include "android-base/strings.h"
 
 #include <gtest/gtest.h>
 
diff --git a/base/test_main.cpp b/base/test_main.cpp
index 546923d..7fa6a84 100644
--- a/base/test_main.cpp
+++ b/base/test_main.cpp
@@ -16,7 +16,7 @@
 
 #include <gtest/gtest.h>
 
-#include "base/logging.h"
+#include "android-base/logging.h"
 
 int main(int argc, char** argv) {
   ::testing::InitGoogleTest(&argc, argv);
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 22641e7..337ba7c 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include "base/logging.h"
-#include "base/test_utils.h"
+#include "android-base/logging.h"
+#include "android-base/test_utils.h"
 #include "utils/Compat.h" // For OS_PATH_SEPARATOR.
 
 #include <fcntl.h>
diff --git a/base/utf8.cpp b/base/utf8.cpp
index 99f0f54..3cca700 100755
--- a/base/utf8.cpp
+++ b/base/utf8.cpp
@@ -16,13 +16,13 @@
 
 #include <windows.h>
 
-#include "base/utf8.h"
+#include "android-base/utf8.h"
 
 #include <fcntl.h>
 
 #include <string>
 
-#include "base/logging.h"
+#include "android-base/logging.h"
 
 namespace android {
 namespace base {
diff --git a/base/utf8_test.cpp b/base/utf8_test.cpp
index 13f6431..dde7490 100755
--- a/base/utf8_test.cpp
+++ b/base/utf8_test.cpp
@@ -14,11 +14,11 @@
 * limitations under the License.
 */
 
-#include "base/utf8.h"
+#include "android-base/utf8.h"
 
 #include <gtest/gtest.h>
 
-#include "base/macros.h"
+#include "android-base/macros.h"
 
 namespace android {
 namespace base {
diff --git a/crash_reporter/Android.mk b/crash_reporter/Android.mk
index 81cb458..565963c 100644
--- a/crash_reporter/Android.mk
+++ b/crash_reporter/Android.mk
@@ -43,11 +43,12 @@
 LOCAL_C_INCLUDES := $(crash_reporter_includes)
 LOCAL_RTTI_FLAG := -frtti
 LOCAL_SHARED_LIBRARIES := libchrome \
+    libbinder \
     libbrillo \
     libcutils \
-    libdbus \
     libmetrics \
     libpcrecpp
+LOCAL_STATIC_LIBRARIES := libmetricscollectorservice
 LOCAL_SRC_FILES := $(crash_reporter_src)
 include $(BUILD_STATIC_LIBRARY)
 
@@ -60,18 +61,19 @@
 LOCAL_REQUIRED_MODULES := core2md \
     crash_reporter_logs.conf \
     crash_sender \
-    crash_server \
-    dbus-send
+    crash_server
 LOCAL_INIT_RC := crash_reporter.rc
 LOCAL_RTTI_FLAG := -frtti
 LOCAL_SHARED_LIBRARIES := libchrome \
+    libbinder \
     libbrillo \
     libcutils \
-    libdbus \
     libmetrics \
-    libpcrecpp
+    libpcrecpp \
+    libutils
 LOCAL_SRC_FILES := crash_reporter.cc
-LOCAL_STATIC_LIBRARIES := libcrash
+LOCAL_STATIC_LIBRARIES := libcrash \
+    libmetricscollectorservice
 include $(BUILD_EXECUTABLE)
 
 # Crash sender script.
@@ -140,7 +142,6 @@
 LOCAL_SHARED_LIBRARIES := libchrome \
     libbrillo \
     libcutils \
-    libdbus \
     libpcrecpp
 LOCAL_SRC_FILES := $(crash_reporter_test_src)
 LOCAL_STATIC_LIBRARIES := libcrash libgmock
diff --git a/crash_reporter/crash_collector.cc b/crash_reporter/crash_collector.cc
index 2a9d1d3..b3fdcb4 100644
--- a/crash_reporter/crash_collector.cc
+++ b/crash_reporter/crash_collector.cc
@@ -47,7 +47,6 @@
 const char kDefaultLogConfig[] = "/etc/crash_reporter_logs.conf";
 const char kDefaultUserName[] = "chronos";
 const char kLeaveCoreFile[] = "/data/misc/crash_reporter/.leave_core";
-const char kLsbRelease[] = "/etc/lsb-release";
 const char kShellPath[] = "/system/bin/sh";
 const char kSystemCrashPath[] = "/data/misc/crash_reporter/crash";
 const char kUploadVarPrefix[] = "upload_var_";
@@ -90,8 +89,7 @@
 using base::StringPrintf;
 
 CrashCollector::CrashCollector()
-    : lsb_release_(kLsbRelease),
-      log_config_path_(kDefaultLogConfig) {
+    : log_config_path_(kDefaultLogConfig) {
 }
 
 CrashCollector::~CrashCollector() {
diff --git a/crash_reporter/crash_collector.h b/crash_reporter/crash_collector.h
index cfd76fd..24cbfb3 100644
--- a/crash_reporter/crash_collector.h
+++ b/crash_reporter/crash_collector.h
@@ -158,7 +158,6 @@
   IsFeedbackAllowedFunction is_feedback_allowed_function_;
   std::string extra_metadata_;
   base::FilePath forced_crash_directory_;
-  std::string lsb_release_;
   base::FilePath log_config_path_;
 
  private:
diff --git a/crash_reporter/crash_collector_test.cc b/crash_reporter/crash_collector_test.cc
index d00a5b5..b55c324 100644
--- a/crash_reporter/crash_collector_test.cc
+++ b/crash_reporter/crash_collector_test.cc
@@ -177,15 +177,8 @@
 TEST_F(CrashCollectorTest, MetaData) {
   const char kMetaFileBasename[] = "generated.meta";
   FilePath meta_file = test_dir_.Append(kMetaFileBasename);
-  FilePath lsb_release = test_dir_.Append("lsb-release");
   FilePath payload_file = test_dir_.Append("payload-file");
   std::string contents;
-  collector_.lsb_release_ = lsb_release.value();
-  const char kLsbContents[] =
-      "CHROMEOS_RELEASE_BOARD=lumpy\n"
-      "CHROMEOS_RELEASE_VERSION=6727.0.2015_01_26_0853\n"
-      "CHROMEOS_RELEASE_NAME=Chromium OS\n";
-  ASSERT_TRUE(base::WriteFile(lsb_release, kLsbContents, strlen(kLsbContents)));
   const char kPayload[] = "foo";
   ASSERT_TRUE(base::WriteFile(payload_file, kPayload, strlen(kPayload)));
   collector_.AddCrashMetaData("foo", "bar");
@@ -194,7 +187,6 @@
   const char kExpectedMeta[] =
       "foo=bar\n"
       "exec_name=kernel\n"
-      "ver=6727.0.2015_01_26_0853\n"
       "payload=test/payload-file\n"
       "payload_size=3\n"
       "done=1\n";
diff --git a/crash_reporter/crash_reporter.cc b/crash_reporter/crash_reporter.cc
index 3955fe5..26ffa38 100644
--- a/crash_reporter/crash_reporter.cc
+++ b/crash_reporter/crash_reporter.cc
@@ -25,10 +25,13 @@
 #include <base/strings/string_split.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
+#include <binder/IServiceManager.h>
 #include <brillo/flag_helper.h>
-#include <brillo/process.h>
 #include <brillo/syslog_logging.h>
+#include <metrics/metrics_collector_service_client.h>
 #include <metrics/metrics_library.h>
+#include <utils/String16.h>
+
 
 #include "kernel_collector.h"
 #include "kernel_warning_collector.h"
@@ -37,8 +40,6 @@
 #include "user_collector.h"
 
 static const char kCrashCounterHistogram[] = "Logging.CrashCounter";
-static const char kUserCrashSignal[] =
-    "org.chromium.CrashReporter.UserCrash";
 static const char kKernelCrashDetected[] = "/var/run/kernel-crash-detected";
 static const char kUncleanShutdownDetected[] =
     "/var/run/unclean-shutdown-detected";
@@ -56,6 +57,7 @@
 
 static MetricsLibrary s_metrics_lib;
 
+using android::brillo::metrics::IMetricsCollectorService;
 using base::FilePath;
 using base::StringPrintf;
 
@@ -88,32 +90,14 @@
 
 static void CountUserCrash() {
   SendCrashMetrics(kCrashKindUser, "user");
-  // Announce through D-Bus whenever a user crash happens. This is
-  // used by the metrics daemon to log active use time between
-  // crashes.
-  //
-  // We run in the background in case dbus-daemon itself is crashed
-  // and not responding.  This allows us to not block and potentially
-  // deadlock on a dbus-daemon crash.  If dbus-daemon crashes without
-  // restarting, each crash will fork off a lot of dbus-send
-  // processes.  Such a system is in a unusable state and will need
-  // to be restarted anyway.
-  //
-  // Note: This will mean that the dbus-send process will become a zombie and
-  // reparent to init for reaping, but that's OK -- see above.
+  // Tell the metrics collector about the user crash, in order to log active
+  // use time between crashes.
+  MetricsCollectorServiceClient metrics_collector_service;
 
-  brillo::ProcessImpl dbus_send;
-  dbus_send.AddArg("/system/bin/dbus-send");
-  dbus_send.AddArg("--type=signal");
-  dbus_send.AddArg("--system");
-  dbus_send.AddArg("/");
-  dbus_send.AddArg(kUserCrashSignal);
-  bool status = dbus_send.Start();
-  if (status) {
-    dbus_send.Release();
-  } else {
-    PLOG(WARNING) << "Sending UserCrash DBus signal failed";
-  }
+  if (metrics_collector_service.Init())
+    metrics_collector_service.notifyUserCrash();
+  else
+    LOG(ERROR) << "Failed to send user crash notification to metrics_collector";
 }
 
 
diff --git a/crash_reporter/crash_reporter_logs_test.cc b/crash_reporter/crash_reporter_logs_test.cc
index e778002..77f5a7f 100644
--- a/crash_reporter/crash_reporter_logs_test.cc
+++ b/crash_reporter/crash_reporter_logs_test.cc
@@ -23,10 +23,11 @@
 namespace {
 
 // Name of the checked-in configuration file containing log-collection commands.
-const char kConfigFile[] = "crash_reporter_logs.conf";
+const char kConfigFile[] = "/system/etc/crash_reporter_logs.conf";
 
-// Executable name for Chrome. kConfigFile is expected to contain this entry.
-const char kChromeExecName[] = "chrome";
+// Signature name for crash_reporter user collection.
+// kConfigFile is expected to contain this entry.
+const char kUserCollectorSignature[] = "crash_reporter-user-collection";
 
 }  // namespace
 
@@ -35,6 +36,6 @@
   brillo::KeyValueStore store;
   ASSERT_TRUE(store.Load(base::FilePath(kConfigFile)));
   std::string command;
-  EXPECT_TRUE(store.GetString(kChromeExecName, &command));
+  EXPECT_TRUE(store.GetString(kUserCollectorSignature, &command));
   EXPECT_FALSE(command.empty());
 }
diff --git a/crash_reporter/crash_sender b/crash_reporter/crash_sender
index 95204a4..a430ab5 100755
--- a/crash_reporter/crash_sender
+++ b/crash_reporter/crash_sender
@@ -65,6 +65,7 @@
 # Path to a directory of restricted certificates which includes
 # a certificate for the crash server.
 RESTRICTED_CERTIFICATES_PATH="/system/etc/security/cacerts"
+RESTRICTED_CERTIFICATES_PATH_GOOGLE="/system/etc/security/cacerts_google"
 
 # File whose existence implies we're running and not to start again.
 RUN_FILE="${CRASH_STATE_DIR}/run/crash_sender.pid"
@@ -183,6 +184,18 @@
   fi
 }
 
+# Returns the path of the certificates directory to be used when sending
+# reports to the crash server.
+# If crash_reporter.full_certs=1, return the full certificates path.
+# Otherwise return the Google-specific certificates path.
+get_certificates_path() {
+  if [ "$(getprop crash_reporter.full_certs)" = "1" ]; then
+    echo "${RESTRICTED_CERTIFICATES_PATH}"
+  else
+    echo "${RESTRICTED_CERTIFICATES_PATH_GOOGLE}"
+  fi
+}
+
 # Return 0 if the uploading of device coredumps is allowed.
 is_device_coredump_upload_allowed() {
   [ -f "${DEVCOREDUMP_UPLOAD_FLAG_FILE}" ] && return 0
@@ -455,7 +468,7 @@
 
   set +e
   curl "${url}" -f -v ${proxy:+--proxy "$proxy"} \
-    --capath "${RESTRICTED_CERTIFICATES_PATH}" --ciphers HIGH \
+    --capath "$(get_certificates_path)" --ciphers HIGH \
     -F "prod=${product}" \
     -F "ver=${version}" \
     -F "bdk_version=${bdk_version}" \
@@ -682,7 +695,7 @@
   # (like with autotests) that we're still running.
   echo $$ > "${RUN_FILE}"
 
-  for dependency in "${RESTRICTED_CERTIFICATES_PATH}"; do
+  for dependency in "$(get_certificates_path)"; do
     if [ ! -x "${dependency}" ]; then
       lecho "Fatal: Crash sending disabled: ${dependency} not found."
       exit 1
diff --git a/crash_reporter/kernel_collector_test.cc b/crash_reporter/kernel_collector_test.cc
index cdb0ae7..015f624 100644
--- a/crash_reporter/kernel_collector_test.cc
+++ b/crash_reporter/kernel_collector_test.cc
@@ -253,15 +253,6 @@
   ASSERT_EQ(0, s_crashes);
 }
 
-TEST_F(KernelCollectorTest, CollectBadDirectory) {
-  WriteStringToFile(kcrash_file(), "====1.1\nsomething");
-  ASSERT_TRUE(collector_.Collect());
-  ASSERT_TRUE(FindLog("Unable to create appropriate crash directory"))
-      << "Did not find expected error string in log: {\n"
-      << GetLog() << "}";
-  ASSERT_EQ(1, s_crashes);
-}
-
 void KernelCollectorTest::SetUpSuccessfulCollect() {
   collector_.ForceCrashDirectory(test_crash_directory());
   WriteStringToFile(kcrash_file(), "====1.1\nsomething");
diff --git a/crash_reporter/user_collector_test.cc b/crash_reporter/user_collector_test.cc
index 72e61e6..638ea34 100644
--- a/crash_reporter/user_collector_test.cc
+++ b/crash_reporter/user_collector_test.cc
@@ -37,11 +37,6 @@
 
 const char kFilePath[] = "/my/path";
 
-// Keep in sync with UserCollector::ShouldDump.
-const char kChromeIgnoreMsg[] =
-    "ignoring call by kernel - chrome crash; "
-    "waiting for chrome to call us directly";
-
 void CountCrash() {
   ++s_crashes;
 }
@@ -167,24 +162,6 @@
   ASSERT_EQ(s_crashes, 1);
 }
 
-TEST_F(UserCollectorTest, HandleChromeCrashWithConsent) {
-  s_metrics = true;
-  collector_.HandleCrash("5:2:ignored", "chrome");
-  EXPECT_TRUE(FindLog(
-      "Received crash notification for chrome[5] sig 2"));
-  EXPECT_TRUE(FindLog(kChromeIgnoreMsg));
-  ASSERT_EQ(s_crashes, 0);
-}
-
-TEST_F(UserCollectorTest, HandleSuppliedChromeCrashWithConsent) {
-  s_metrics = true;
-  collector_.HandleCrash("0:2:chrome", nullptr);
-  EXPECT_TRUE(FindLog(
-      "Received crash notification for supplied_chrome[0] sig 2"));
-  EXPECT_TRUE(FindLog(kChromeIgnoreMsg));
-  ASSERT_EQ(s_crashes, 0);
-}
-
 TEST_F(UserCollectorTest, GetProcessPath) {
   FilePath path = collector_.GetProcessPath(100);
   ASSERT_EQ("/proc/100", path.value());
@@ -226,7 +203,7 @@
   pid_t my_pid = getpid();
   EXPECT_TRUE(collector_.GetExecutableBaseNameFromPid(my_pid, &base_name));
   EXPECT_FALSE(FindLog("Readlink failed"));
-  EXPECT_EQ("crash_reporter_test", base_name);
+  EXPECT_EQ("crash_reporter_tests", base_name);
 }
 
 TEST_F(UserCollectorTest, GetFirstLineWithPrefix) {
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 884d4d5..0afa895 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -518,11 +518,12 @@
   ALOGI("debuggerd: starting\n");
 
   for (;;) {
-    sockaddr addr;
-    socklen_t alen = sizeof(addr);
+    sockaddr_storage ss;
+    sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
+    socklen_t alen = sizeof(ss);
 
     ALOGV("waiting for connection\n");
-    int fd = accept(s, &addr, &alen);
+    int fd = accept(s, addrp, &alen);
     if (fd < 0) {
       ALOGV("accept failed: %s\n", strerror(errno));
       continue;
diff --git a/debuggerd/elf_utils.cpp b/debuggerd/elf_utils.cpp
index 65c1904..9959f2e 100644
--- a/debuggerd/elf_utils.cpp
+++ b/debuggerd/elf_utils.cpp
@@ -24,7 +24,7 @@
 #include <string>
 
 #include <backtrace/Backtrace.h>
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 #include <log/log.h>
 
 #include "elf_utils.h"
diff --git a/debuggerd/test/dump_memory_test.cpp b/debuggerd/test/dump_memory_test.cpp
index 75e7028..2addd5d 100644
--- a/debuggerd/test/dump_memory_test.cpp
+++ b/debuggerd/test/dump_memory_test.cpp
@@ -20,7 +20,7 @@
 #include <string>
 
 #include <gtest/gtest.h>
-#include <base/file.h>
+#include <android-base/file.h>
 
 #include "BacktraceMock.h"
 #include "log_fake.h"
diff --git a/debuggerd/test/log_fake.cpp b/debuggerd/test/log_fake.cpp
index d584a5e..e27e9f6 100644
--- a/debuggerd/test/log_fake.cpp
+++ b/debuggerd/test/log_fake.cpp
@@ -19,7 +19,7 @@
 
 #include <string>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 #include <log/log.h>
 #include <log/logger.h>
 
diff --git a/debuggerd/test/tombstone_test.cpp b/debuggerd/test/tombstone_test.cpp
index d945d27..96b3a7a 100644
--- a/debuggerd/test/tombstone_test.cpp
+++ b/debuggerd/test/tombstone_test.cpp
@@ -20,7 +20,7 @@
 #include <string>
 
 #include <gtest/gtest.h>
-#include <base/file.h>
+#include <android-base/file.h>
 
 #include "utility.h"
 
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index e283923..5f422e3 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -37,7 +37,7 @@
 
 #include <private/android_filesystem_config.h>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 #include <cutils/properties.h>
 #include <log/log.h>
 #include <log/logger.h>
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index f5d6ec1..ce214f9 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -25,9 +25,9 @@
 #include <sys/ptrace.h>
 #include <sys/wait.h>
 
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
 #include <backtrace/Backtrace.h>
-#include <base/file.h>
-#include <base/stringprintf.h>
 #include <log/log.h>
 
 const int SLEEP_TIME_USEC = 50000;         // 0.05 seconds
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 5ca88cb..8cbc79b 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -18,9 +18,12 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
+LOCAL_C_INCLUDES := \
+  $(LOCAL_PATH)/../adb \
+  $(LOCAL_PATH)/../mkbootimg \
   $(LOCAL_PATH)/../../extras/ext4_utils \
-  $(LOCAL_PATH)/../../extras/f2fs_utils
+  $(LOCAL_PATH)/../../extras/f2fs_utils \
+
 LOCAL_SRC_FILES := protocol.cpp engine.cpp bootimg_utils.cpp fastboot.cpp util.cpp fs.cpp
 LOCAL_MODULE := fastboot
 LOCAL_MODULE_TAGS := debug
@@ -30,13 +33,15 @@
 
 LOCAL_CFLAGS += -DFASTBOOT_REVISION='"$(fastboot_version)"'
 
-LOCAL_SRC_FILES_linux := usb_linux.cpp util_linux.cpp
+LOCAL_SRC_FILES_linux := socket_unix.cpp usb_linux.cpp util_linux.cpp
+LOCAL_STATIC_LIBRARIES_linux := libcutils libselinux
 
-LOCAL_SRC_FILES_darwin := usb_osx.cpp util_osx.cpp
+LOCAL_SRC_FILES_darwin := socket_unix.cpp usb_osx.cpp util_osx.cpp
+LOCAL_STATIC_LIBRARIES_darwin := libcutils libselinux
 LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
 LOCAL_CFLAGS_darwin := -Wno-unused-parameter
 
-LOCAL_SRC_FILES_windows := usb_windows.cpp util_windows.cpp
+LOCAL_SRC_FILES_windows := socket_windows.cpp usb_windows.cpp util_windows.cpp
 LOCAL_STATIC_LIBRARIES_windows := AdbWinApi
 LOCAL_REQUIRED_MODULES_windows := AdbWinApi
 LOCAL_LDLIBS_windows := -lws2_32
@@ -49,11 +54,9 @@
     libutils \
     liblog \
     libz \
+    libdiagnose_usb \
     libbase \
 
-LOCAL_STATIC_LIBRARIES_darwin := libselinux
-LOCAL_STATIC_LIBRARIES_linux := libselinux
-
 # libf2fs_dlutils_host will dlopen("libf2fs_fmt_host_dyn")
 LOCAL_CFLAGS_linux := -DUSE_F2FS
 LOCAL_LDFLAGS_linux := -ldl -rdynamic -Wl,-rpath,.
@@ -86,3 +89,28 @@
 LOCAL_STATIC_LIBRARIES := libbase
 include $(BUILD_HOST_EXECUTABLE)
 endif
+
+# fastboot_test
+# =========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := fastboot_test
+LOCAL_MODULE_HOST_OS := darwin linux windows
+
+LOCAL_SRC_FILES := socket_test.cpp
+LOCAL_STATIC_LIBRARIES := libbase
+
+LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
+
+LOCAL_SRC_FILES_linux := socket_unix.cpp
+LOCAL_STATIC_LIBRARIES_linux := libcutils
+
+LOCAL_SRC_FILES_darwin := socket_unix.cpp
+LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
+LOCAL_CFLAGS_darwin := -Wno-unused-parameter
+LOCAL_STATIC_LIBRARIES_darwin := libcutils
+
+LOCAL_SRC_FILES_windows := socket_windows.cpp
+LOCAL_LDLIBS_windows := -lws2_32
+
+include $(BUILD_HOST_NATIVE_TEST)
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index a16d7dd..d653746 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -44,15 +44,16 @@
 #include <unistd.h>
 #include <functional>
 
-#include <base/parseint.h>
-#include <base/strings.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
 #include <sparse/sparse.h>
 #include <ziparchive/zip_archive.h>
 
-#include <base/strings.h>
-#include <base/parseint.h>
+#include <android-base/strings.h>
+#include <android-base/parseint.h>
 
 #include "bootimg_utils.h"
+#include "diagnose_usb.h"
 #include "fastboot.h"
 #include "fs.h"
 #include "transport.h"
@@ -81,6 +82,8 @@
 static unsigned second_offset  = 0x00f00000;
 static unsigned tags_offset    = 0x00000100;
 
+static const std::string convert_fbe_marker_filename("convert_fbe");
+
 enum fb_buffer_type {
     FB_BUFFER,
     FB_BUFFER_SPARSE,
@@ -204,21 +207,21 @@
 
 static int list_devices_callback(usb_ifc_info* info) {
     if (match_fastboot_with_serial(info, nullptr) == 0) {
-        const char* serial = info->serial_number;
+        std::string serial = info->serial_number;
         if (!info->writable) {
-            serial = "no permissions"; // like "adb devices"
+            serial = UsbNoPermissionsShortHelpText();
         }
         if (!serial[0]) {
             serial = "????????????";
         }
         // output compatible with "adb devices"
         if (!long_listing) {
-            printf("%s\tfastboot\n", serial);
-        } else if (strcmp("", info->device_path) == 0) {
-            printf("%-22s fastboot\n", serial);
+            printf("%s\tfastboot", serial.c_str());
         } else {
-            printf("%-22s fastboot %s\n", serial, info->device_path);
+            printf("%-22s fastboot", serial.c_str());
+            if (strlen(info->device_path) > 0) printf(" %s", info->device_path);
         }
+        putchar('\n');
     }
 
     return -1;
@@ -279,6 +282,10 @@
             "                                           override the fs type and/or size\n"
             "                                           the bootloader reports.\n"
             "  getvar <variable>                        Display a bootloader variable.\n"
+            "  set_active <suffix>                      Sets the active slot. If slots are\n"
+            "                                           not supported, this does nothing.\n"
+            "                                           note: suffixes starting with a '-'\n"
+            "                                           must use set_active -- <suffix>\n"
             "  boot <kernel> [ <ramdisk> [ <second> ] ] Download and boot kernel.\n"
             "  flash:raw boot <kernel> [ <ramdisk> [ <second> ] ]\n"
             "                                           Create bootimage and flash it.\n"
@@ -321,12 +328,19 @@
             "  -a, --set-active[=<suffix>]              Sets the active slot. If no suffix is\n"
             "                                           provided, this will default to the value\n"
             "                                           given by --slot. If slots are not\n"
-            "                                           supported, this does nothing.\n"
+            "                                           supported, this does nothing. This will\n"
+            "                                           run after all non-reboot commands.\n"
+#if !defined(_WIN32)
+            "  --wipe-and-use-fbe                       On devices which support it,\n"
+            "                                           erase userdata and cache, and\n"
+            "                                           enable file-based encryption\n"
+#endif
             "  --unbuffered                             Do not buffer input or output.\n"
             "  --version                                Display version.\n"
             "  -h, --help                               show this message.\n"
         );
 }
+
 static void* load_bootable_image(const char* kernel, const char* ramdisk,
                                  const char* secondstage, int64_t* sz,
                                  const char* cmdline) {
@@ -446,8 +460,60 @@
 
 #define tmpfile win32_tmpfile
 
+static std::string make_temporary_directory() {
+    fprintf(stderr, "make_temporary_directory not supported under Windows, sorry!");
+    return "";
+}
+
+#else
+
+static std::string make_temporary_directory() {
+    const char *tmpdir = getenv("TMPDIR");
+    if (tmpdir == nullptr) {
+        tmpdir = P_tmpdir;
+    }
+    std::string result = std::string(tmpdir) + "/fastboot_userdata_XXXXXX";
+    if (mkdtemp(&result[0]) == NULL) {
+        fprintf(stderr, "Unable to create temporary directory: %s\n",
+            strerror(errno));
+        return "";
+    }
+    return result;
+}
+
 #endif
 
+static std::string create_fbemarker_tmpdir() {
+    std::string dir = make_temporary_directory();
+    if (dir.empty()) {
+        fprintf(stderr, "Unable to create local temp directory for FBE marker\n");
+        return "";
+    }
+    std::string marker_file = dir + "/" + convert_fbe_marker_filename;
+    int fd = open(marker_file.c_str(), O_CREAT | O_WRONLY | O_CLOEXEC, 0666);
+    if (fd == -1) {
+        fprintf(stderr, "Unable to create FBE marker file %s locally: %d, %s\n",
+            marker_file.c_str(), errno, strerror(errno));
+        return "";
+    }
+    close(fd);
+    return dir;
+}
+
+static void delete_fbemarker_tmpdir(const std::string& dir) {
+    std::string marker_file = dir + "/" + convert_fbe_marker_filename;
+    if (unlink(marker_file.c_str()) == -1) {
+        fprintf(stderr, "Unable to delete FBE marker file %s locally: %d, %s\n",
+            marker_file.c_str(), errno, strerror(errno));
+        return;
+    }
+    if (rmdir(dir.c_str()) == -1) {
+        fprintf(stderr, "Unable to delete FBE marker directory %s locally: %d, %s\n",
+            dir.c_str(), errno, strerror(errno));
+        return;
+    }
+}
+
 static int unzip_to_file(ZipArchiveHandle zip, char* entry_name) {
     FILE* fp = tmpfile();
     if (fp == nullptr) {
@@ -724,9 +790,19 @@
     return android::base::Split(suffix_list, ",");
 }
 
-static std::string verify_slot(Transport* transport, const char *slot) {
+static std::string verify_slot(Transport* transport, const char *slot, bool allow_all) {
     if (strcmp(slot, "all") == 0) {
-        return "all";
+        if (allow_all) {
+            return "all";
+        } else {
+            std::vector<std::string> suffixes = get_suffixes(transport);
+            if (!suffixes.empty()) {
+                return suffixes[0];
+            } else {
+                fprintf(stderr, "No known slots.\n");
+                exit(1);
+            }
+        }
     }
     std::vector<std::string> suffixes = get_suffixes(transport);
     for (const std::string &suffix : suffixes) {
@@ -740,6 +816,10 @@
     exit(1);
 }
 
+static std::string verify_slot(Transport* transport, const char *slot) {
+   return verify_slot(transport, slot, true);
+}
+
 static void do_for_partition(Transport* transport, const char *part, const char *slot,
                              std::function<void(const std::string&)> func, bool force_slot) {
     std::string has_slot;
@@ -994,7 +1074,8 @@
 
 static void fb_perform_format(Transport* transport,
                               const char* partition, int skip_if_not_supported,
-                              const char* type_override, const char* size_override) {
+                              const char* type_override, const char* size_override,
+                              const std::string& initial_dir) {
     std::string partition_type, partition_size;
 
     struct fastboot_buffer buf;
@@ -1058,7 +1139,7 @@
     }
 
     fd = fileno(tmpfile());
-    if (fs_generator_generate(gen, fd, size)) {
+    if (fs_generator_generate(gen, fd, size, initial_dir)) {
         fprintf(stderr, "Cannot generate image: %s\n", strerror(errno));
         close(fd);
         return;
@@ -1087,6 +1168,7 @@
     bool wants_reboot_bootloader = false;
     bool wants_set_active = false;
     bool erase_first = true;
+    bool set_fbe_marker = false;
     void *data;
     int64_t sz;
     int longindex;
@@ -1109,6 +1191,9 @@
         {"slot", required_argument, 0, 0},
         {"set_active", optional_argument, 0, 'a'},
         {"set-active", optional_argument, 0, 'a'},
+#if !defined(_WIN32)
+        {"wipe-and-use-fbe", no_argument, 0, 0},
+#endif
         {0, 0, 0, 0}
     };
 
@@ -1190,6 +1275,15 @@
                 return 0;
             } else if (strcmp("slot", longopts[longindex].name) == 0) {
                 slot_override = std::string(optarg);
+#if !defined(_WIN32)
+            } else if (strcmp("wipe-and-use-fbe", longopts[longindex].name) == 0) {
+                wants_wipe = true;
+                set_fbe_marker = true;
+#endif
+            } else {
+                fprintf(stderr, "Internal error in options processing for %s\n",
+                    longopts[longindex].name);
+                return 1;
             }
             break;
         default:
@@ -1220,14 +1314,14 @@
     if (slot_override != "")
         slot_override = verify_slot(transport, slot_override.c_str());
     if (next_active != "")
-        next_active = verify_slot(transport, next_active.c_str());
+        next_active = verify_slot(transport, next_active.c_str(), false);
 
     if (wants_set_active) {
         if (next_active == "") {
             if (slot_override == "") {
                 wants_set_active = false;
             } else {
-                next_active = slot_override;
+                next_active = verify_slot(transport, slot_override.c_str(), false);
             }
         }
     }
@@ -1283,7 +1377,8 @@
                 if (erase_first && needs_erase(transport, partition.c_str())) {
                     fb_queue_erase(partition.c_str());
                 }
-                fb_perform_format(transport, partition.c_str(), 0, type_override, size_override);
+                fb_perform_format(transport, partition.c_str(), 0,
+                    type_override, size_override, "");
             };
             do_for_partitions(transport, argv[1], slot_override.c_str(), format, true);
             skip(2);
@@ -1385,6 +1480,12 @@
                 do_update(transport, "update.zip", slot_override.c_str(), erase_first);
                 skip(1);
             }
+            wants_reboot = 1;
+        } else if(!strcmp(*argv, "set_active")) {
+            require(2);
+            std::string slot = verify_slot(transport, argv[1], false);
+            fb_set_active(slot.c_str());
+            skip(2);
             wants_reboot = true;
         } else if(!strcmp(*argv, "oem")) {
             argc = do_oem_command(argc, argv);
@@ -1413,13 +1514,23 @@
     if (wants_wipe) {
         fprintf(stderr, "wiping userdata...\n");
         fb_queue_erase("userdata");
-        fb_perform_format(transport, "userdata", 1, nullptr, nullptr);
+        if (set_fbe_marker) {
+            fprintf(stderr, "setting FBE marker...\n");
+            std::string initial_userdata_dir = create_fbemarker_tmpdir();
+            if (initial_userdata_dir.empty()) {
+                return 1;
+            }
+            fb_perform_format(transport, "userdata", 1, nullptr, nullptr, initial_userdata_dir);
+            delete_fbemarker_tmpdir(initial_userdata_dir);
+        } else {
+            fb_perform_format(transport, "userdata", 1, nullptr, nullptr, "");
+        }
 
         std::string cache_type;
         if (fb_getvar(transport, "partition-type:cache", &cache_type) && !cache_type.empty()) {
             fprintf(stderr, "wiping cache...\n");
             fb_queue_erase("cache");
-            fb_perform_format(transport, "cache", 1, nullptr, nullptr);
+            fb_perform_format(transport, "cache", 1, nullptr, nullptr, "");
         }
     }
     if (wants_set_active) {
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 90d8474..8539e23 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -1,7 +1,8 @@
+#include "fs.h"
+
 #include "fastboot.h"
 #include "make_ext4fs.h"
 #include "make_f2fs.h"
-#include "fs.h"
 
 #include <errno.h>
 #include <stdio.h>
@@ -13,24 +14,32 @@
 
 #include <sparse/sparse.h>
 
-static int generate_ext4_image(int fd, long long partSize)
+static int generate_ext4_image(int fd, long long partSize, const std::string& initial_dir)
 {
-    make_ext4fs_sparse_fd(fd, partSize, NULL, NULL);
-
+    if (initial_dir.empty()) {
+        make_ext4fs_sparse_fd(fd, partSize, NULL, NULL);
+    } else {
+        make_ext4fs_sparse_fd_directory(fd, partSize, NULL, NULL, initial_dir.c_str());
+    }
     return 0;
 }
 
 #ifdef USE_F2FS
-static int generate_f2fs_image(int fd, long long partSize)
+static int generate_f2fs_image(int fd, long long partSize, const std::string& initial_dir)
 {
+    if (!initial_dir.empty()) {
+        fprintf(stderr, "Unable to set initial directory on F2FS filesystem\n");
+        return -1;
+    }
     return make_f2fs_sparse_fd(fd, partSize, NULL, NULL);
 }
 #endif
 
 static const struct fs_generator {
-
     const char* fs_type;  //must match what fastboot reports for partition type
-    int (*generate)(int fd, long long partSize); //returns 0 or error value
+
+    //returns 0 or error value
+    int (*generate)(int fd, long long partSize, const std::string& initial_dir);
 
 } generators[] = {
     { "ext4", generate_ext4_image},
@@ -48,7 +57,8 @@
     return nullptr;
 }
 
-int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize)
+int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize,
+    const std::string& initial_dir)
 {
-    return gen->generate(tmpFileNo, partSize);
+    return gen->generate(tmpFileNo, partSize, initial_dir);
 }
diff --git a/fastboot/fs.h b/fastboot/fs.h
index 289488b..0a68507 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -1,11 +1,13 @@
 #ifndef _FS_H_
 #define _FS_H_
 
+#include <string>
 #include <stdint.h>
 
 struct fs_generator;
 
 const struct fs_generator* fs_get_generator(const std::string& fs_type);
-int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize);
+int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize,
+    const std::string& initial_dir);
 
 #endif
diff --git a/fastboot/genkey.sh b/fastboot/genkey.sh
deleted file mode 100755
index 011e902..0000000
--- a/fastboot/genkey.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/bash
-
-if [ $# -ne 2 ]
-then
- echo "Usage: $0 alias \"pass phrase\""
- exit -1
-fi
-
-# Generate a 2048 bit RSA key with public exponent 3.
-# Encrypt private key with provided password.
-openssl genrsa -3 -out $1.pem -passout pass:"$2" 2048
-
-# Create a self-signed cert for this key.
-openssl req -new -x509 -key $1.pem -passin pass:"$2" \
-        -out $1-cert.pem \
-        -batch -days 10000
-
-# Create a PKCS12 store containing the generated private key.
-# Protect the keystore and the private key with the provided password.
-openssl pkcs12 -export -in $1-cert.pem -inkey $1.pem -passin pass:"$2" \
-        -out $1.p12 -name $1 -passout pass:"$2"
-
-rm $1.pem
-rm $1-cert.pem
-
diff --git a/fastboot/socket.h b/fastboot/socket.h
new file mode 100644
index 0000000..888b530
--- /dev/null
+++ b/fastboot/socket.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 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.
+ */
+
+// This file provides a class interface for cross-platform UDP functionality. The main fastboot
+// engine should not be using this interface directly, but instead should use a higher-level
+// interface that enforces the fastboot UDP protocol.
+
+#ifndef SOCKET_H_
+#define SOCKET_H_
+
+#include "android-base/macros.h"
+
+#include <memory>
+#include <string>
+
+// UdpSocket interface to be implemented for each platform.
+class UdpSocket {
+  public:
+    // Creates a new client connection. Clients are connected to a specific hostname/port and can
+    // only send to that destination.
+    // On failure, |error| is filled (if non-null) and nullptr is returned.
+    static std::unique_ptr<UdpSocket> NewUdpClient(const std::string& hostname, int port,
+                                                   std::string* error);
+
+    // Creates a new server bound to local |port|. This is only meant for testing, during normal
+    // fastboot operation the device acts as the server.
+    // The server saves sender addresses in Receive(), and uses the most recent address during
+    // calls to Send().
+    static std::unique_ptr<UdpSocket> NewUdpServer(int port);
+
+    virtual ~UdpSocket() = default;
+
+    // Sends |length| bytes of |data|. Returns the number of bytes actually sent or -1 on error.
+    virtual ssize_t Send(const void* data, size_t length) = 0;
+
+    // Waits up to |timeout_ms| to receive up to |length| bytes of data. |timout_ms| of 0 will
+    // block forever. Returns the number of bytes received or -1 on error/timeout. On timeout
+    // errno will be set to EAGAIN or EWOULDBLOCK.
+    virtual ssize_t Receive(void* data, size_t length, int timeout_ms) = 0;
+
+    // Closes the socket. Returns 0 on success, -1 on error.
+    virtual int Close() = 0;
+
+  protected:
+    // Protected constructor to force factory function use.
+    UdpSocket() = default;
+
+    DISALLOW_COPY_AND_ASSIGN(UdpSocket);
+};
+
+#endif  // SOCKET_H_
diff --git a/fastboot/socket_test.cpp b/fastboot/socket_test.cpp
new file mode 100644
index 0000000..6ada964
--- /dev/null
+++ b/fastboot/socket_test.cpp
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+// Tests UDP functionality using loopback connections. Requires that kDefaultPort is available
+// for loopback communication on the host. These tests also assume that no UDP packets are lost,
+// which should be the case for loopback communication, but is not guaranteed.
+
+#include "socket.h"
+
+#include <errno.h>
+#include <time.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+enum {
+    // This port must be available for loopback communication.
+    kDefaultPort = 54321,
+
+    // Don't wait forever in a unit test.
+    kDefaultTimeoutMs = 3000,
+};
+
+static const char kReceiveStringError[] = "Error receiving string";
+
+// Test fixture to provide some helper functions. Makes each test a little simpler since we can
+// just check a bool for socket creation and don't have to pass hostname or port information.
+class SocketTest : public ::testing::Test {
+  protected:
+    bool StartServer(int port = kDefaultPort) {
+        server_ = UdpSocket::NewUdpServer(port);
+        return server_ != nullptr;
+    }
+
+    bool StartClient(const std::string hostname = "localhost", int port = kDefaultPort) {
+        client_ = UdpSocket::NewUdpClient(hostname, port, nullptr);
+        return client_ != nullptr;
+    }
+
+    bool StartClient2(const std::string hostname = "localhost", int port = kDefaultPort) {
+        client2_ = UdpSocket::NewUdpClient(hostname, port, nullptr);
+        return client2_ != nullptr;
+    }
+
+    std::unique_ptr<UdpSocket> server_, client_, client2_;
+};
+
+// Sends a string over a UdpSocket. Returns true if the full string (without terminating char)
+// was sent.
+static bool SendString(UdpSocket* udp, const std::string& message) {
+    return udp->Send(message.c_str(), message.length()) == static_cast<ssize_t>(message.length());
+}
+
+// Receives a string from a UdpSocket. Returns the string, or kReceiveStringError on failure.
+static std::string ReceiveString(UdpSocket* udp, size_t receive_size = 128) {
+    std::vector<char> buffer(receive_size);
+
+    ssize_t result = udp->Receive(buffer.data(), buffer.size(), kDefaultTimeoutMs);
+    if (result >= 0) {
+        return std::string(buffer.data(), result);
+    }
+    return kReceiveStringError;
+}
+
+// Calls Receive() on the UdpSocket with the given timeout. Returns true if the call timed out.
+static bool ReceiveTimeout(UdpSocket* udp, int timeout_ms) {
+    char buffer[1];
+
+    errno = 0;
+    return udp->Receive(buffer, 1, timeout_ms) == -1 && (errno == EAGAIN || errno == EWOULDBLOCK);
+}
+
+// Tests sending packets client -> server, then server -> client.
+TEST_F(SocketTest, SendAndReceive) {
+    ASSERT_TRUE(StartServer());
+    ASSERT_TRUE(StartClient());
+
+    EXPECT_TRUE(SendString(client_.get(), "foo"));
+    EXPECT_EQ("foo", ReceiveString(server_.get()));
+
+    EXPECT_TRUE(SendString(server_.get(), "bar baz"));
+    EXPECT_EQ("bar baz", ReceiveString(client_.get()));
+}
+
+// Tests sending and receiving large packets.
+TEST_F(SocketTest, LargePackets) {
+    std::string message(512, '\0');
+
+    ASSERT_TRUE(StartServer());
+    ASSERT_TRUE(StartClient());
+
+    // Run through the test a few times.
+    for (int i = 0; i < 10; ++i) {
+        // Use a different message each iteration to prevent false positives.
+        for (size_t j = 0; j < message.length(); ++j) {
+            message[j] = static_cast<char>(i + j);
+        }
+
+        EXPECT_TRUE(SendString(client_.get(), message));
+        EXPECT_EQ(message, ReceiveString(server_.get(), message.length()));
+    }
+}
+
+// Tests IPv4 client/server.
+TEST_F(SocketTest, IPv4) {
+    ASSERT_TRUE(StartServer());
+    ASSERT_TRUE(StartClient("127.0.0.1"));
+
+    EXPECT_TRUE(SendString(client_.get(), "foo"));
+    EXPECT_EQ("foo", ReceiveString(server_.get()));
+
+    EXPECT_TRUE(SendString(server_.get(), "bar"));
+    EXPECT_EQ("bar", ReceiveString(client_.get()));
+}
+
+// Tests IPv6 client/server.
+TEST_F(SocketTest, IPv6) {
+    ASSERT_TRUE(StartServer());
+    ASSERT_TRUE(StartClient("::1"));
+
+    EXPECT_TRUE(SendString(client_.get(), "foo"));
+    EXPECT_EQ("foo", ReceiveString(server_.get()));
+
+    EXPECT_TRUE(SendString(server_.get(), "bar"));
+    EXPECT_EQ("bar", ReceiveString(client_.get()));
+}
+
+// Tests receive timeout. The timing verification logic must be very coarse to make sure different
+// systems running different loads can all pass these tests.
+TEST_F(SocketTest, ReceiveTimeout) {
+    time_t start_time;
+
+    ASSERT_TRUE(StartServer());
+
+    // Make sure a 20ms timeout completes in 1 second or less.
+    start_time = time(nullptr);
+    EXPECT_TRUE(ReceiveTimeout(server_.get(), 20));
+    EXPECT_LE(difftime(time(nullptr), start_time), 1.0);
+
+    // Make sure a 1250ms timeout takes 1 second or more.
+    start_time = time(nullptr);
+    EXPECT_TRUE(ReceiveTimeout(server_.get(), 1250));
+    EXPECT_LE(1.0, difftime(time(nullptr), start_time));
+}
+
+// Tests receive overflow (the UDP packet is larger than the receive buffer).
+TEST_F(SocketTest, ReceiveOverflow) {
+    ASSERT_TRUE(StartServer());
+    ASSERT_TRUE(StartClient());
+
+    EXPECT_TRUE(SendString(client_.get(), "1234567890"));
+
+    // This behaves differently on different systems; some give us a truncated UDP packet, others
+    // will error out and not return anything at all.
+    std::string rx_string = ReceiveString(server_.get(), 5);
+
+    // If we didn't get an error then the packet should have been truncated.
+    if (rx_string != kReceiveStringError) {
+        EXPECT_EQ("12345", rx_string);
+    }
+}
+
+// Tests multiple clients sending to the same server.
+TEST_F(SocketTest, MultipleClients) {
+    ASSERT_TRUE(StartServer());
+    ASSERT_TRUE(StartClient());
+    ASSERT_TRUE(StartClient2());
+
+    EXPECT_TRUE(SendString(client_.get(), "client"));
+    EXPECT_TRUE(SendString(client2_.get(), "client2"));
+
+    // Receive the packets and send a response for each (note that packets may be received
+    // out-of-order).
+    for (int i = 0; i < 2; ++i) {
+        std::string received = ReceiveString(server_.get());
+        EXPECT_TRUE(SendString(server_.get(), received + " response"));
+    }
+
+    EXPECT_EQ("client response", ReceiveString(client_.get()));
+    EXPECT_EQ("client2 response", ReceiveString(client2_.get()));
+}
diff --git a/fastboot/socket_unix.cpp b/fastboot/socket_unix.cpp
new file mode 100644
index 0000000..462256a
--- /dev/null
+++ b/fastboot/socket_unix.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "socket.h"
+
+#include <errno.h>
+#include <netdb.h>
+
+#include <android-base/stringprintf.h>
+#include <cutils/sockets.h>
+
+class UnixUdpSocket : public UdpSocket {
+  public:
+    enum class Type { kClient, kServer };
+
+    UnixUdpSocket(int fd, Type type);
+    ~UnixUdpSocket() override;
+
+    ssize_t Send(const void* data, size_t length) override;
+    ssize_t Receive(void* data, size_t length, int timeout_ms) override;
+    int Close() override;
+
+  private:
+    int fd_;
+    int receive_timeout_ms_ = 0;
+    std::unique_ptr<sockaddr_storage> addr_;
+    socklen_t addr_size_ = 0;
+
+    DISALLOW_COPY_AND_ASSIGN(UnixUdpSocket);
+};
+
+UnixUdpSocket::UnixUdpSocket(int fd, Type type) : fd_(fd) {
+    // Only servers need to remember addresses; clients are connected to a server in NewUdpClient()
+    // so will send to that server without needing to specify the address again.
+    if (type == Type::kServer) {
+        addr_.reset(new sockaddr_storage);
+        addr_size_ = sizeof(*addr_);
+        memset(addr_.get(), 0, addr_size_);
+    }
+}
+
+UnixUdpSocket::~UnixUdpSocket() {
+    Close();
+}
+
+ssize_t UnixUdpSocket::Send(const void* data, size_t length) {
+    return TEMP_FAILURE_RETRY(
+            sendto(fd_, data, length, 0, reinterpret_cast<sockaddr*>(addr_.get()), addr_size_));
+}
+
+ssize_t UnixUdpSocket::Receive(void* data, size_t length, int timeout_ms) {
+    // Only set socket timeout if it's changed.
+    if (receive_timeout_ms_ != timeout_ms) {
+        timeval tv;
+        tv.tv_sec = timeout_ms / 1000;
+        tv.tv_usec = (timeout_ms % 1000) * 1000;
+        if (setsockopt(fd_, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
+            return -1;
+        }
+        receive_timeout_ms_ = timeout_ms;
+    }
+
+    socklen_t* addr_size_ptr = nullptr;
+    if (addr_ != nullptr) {
+        // Reset addr_size as it may have been modified by previous recvfrom() calls.
+        addr_size_ = sizeof(*addr_);
+        addr_size_ptr = &addr_size_;
+    }
+    return TEMP_FAILURE_RETRY(recvfrom(fd_, data, length, 0,
+                                       reinterpret_cast<sockaddr*>(addr_.get()), addr_size_ptr));
+}
+
+int UnixUdpSocket::Close() {
+    int result = 0;
+    if (fd_ != -1) {
+        result = close(fd_);
+        fd_ = -1;
+    }
+    return result;
+}
+
+std::unique_ptr<UdpSocket> UdpSocket::NewUdpClient(const std::string& host, int port,
+                                                   std::string* error) {
+    int getaddrinfo_error = 0;
+    int fd = socket_network_client_timeout(host.c_str(), port, SOCK_DGRAM, 0, &getaddrinfo_error);
+    if (fd == -1) {
+        if (error) {
+            *error = android::base::StringPrintf(
+                    "Failed to connect to %s:%d: %s", host.c_str(), port,
+                    getaddrinfo_error ? gai_strerror(getaddrinfo_error) : strerror(errno));
+        }
+        return nullptr;
+    }
+
+    return std::unique_ptr<UdpSocket>(new UnixUdpSocket(fd, UnixUdpSocket::Type::kClient));
+}
+
+std::unique_ptr<UdpSocket> UdpSocket::NewUdpServer(int port) {
+    int fd = socket_inaddr_any_server(port, SOCK_DGRAM);
+    if (fd == -1) {
+        // This is just used in testing, no need for an error message.
+        return nullptr;
+    }
+
+    return std::unique_ptr<UdpSocket>(new UnixUdpSocket(fd, UnixUdpSocket::Type::kServer));
+}
diff --git a/fastboot/socket_windows.cpp b/fastboot/socket_windows.cpp
new file mode 100644
index 0000000..4ad379f
--- /dev/null
+++ b/fastboot/socket_windows.cpp
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "socket.h"
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include <memory>
+
+#include <android-base/stringprintf.h>
+
+// Windows UDP socket functionality.
+class WindowsUdpSocket : public UdpSocket {
+  public:
+    enum class Type { kClient, kServer };
+
+    WindowsUdpSocket(SOCKET sock, Type type);
+    ~WindowsUdpSocket() override;
+
+    ssize_t Send(const void* data, size_t len) override;
+    ssize_t Receive(void* data, size_t len, int timeout_ms) override;
+    int Close() override;
+
+  private:
+    SOCKET sock_;
+    int receive_timeout_ms_ = 0;
+    std::unique_ptr<sockaddr_storage> addr_;
+    int addr_size_ = 0;
+
+    DISALLOW_COPY_AND_ASSIGN(WindowsUdpSocket);
+};
+
+WindowsUdpSocket::WindowsUdpSocket(SOCKET sock, Type type) : sock_(sock) {
+    // Only servers need to remember addresses; clients are connected to a server in NewUdpClient()
+    // so will send to that server without needing to specify the address again.
+    if (type == Type::kServer) {
+        addr_.reset(new sockaddr_storage);
+        addr_size_ = sizeof(*addr_);
+        memset(addr_.get(), 0, addr_size_);
+    }
+}
+
+WindowsUdpSocket::~WindowsUdpSocket() {
+    Close();
+}
+
+ssize_t WindowsUdpSocket::Send(const void* data, size_t len) {
+    return sendto(sock_, reinterpret_cast<const char*>(data), len, 0,
+                  reinterpret_cast<sockaddr*>(addr_.get()), addr_size_);
+}
+
+ssize_t WindowsUdpSocket::Receive(void* data, size_t len, int timeout_ms) {
+    // Only set socket timeout if it's changed.
+    if (receive_timeout_ms_ != timeout_ms) {
+        if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const char*>(&timeout_ms),
+                       sizeof(timeout_ms)) < 0) {
+            return -1;
+        }
+        receive_timeout_ms_ = timeout_ms;
+    }
+
+    int* addr_size_ptr = nullptr;
+    if (addr_ != nullptr) {
+        // Reset addr_size as it may have been modified by previous recvfrom() calls.
+        addr_size_ = sizeof(*addr_);
+        addr_size_ptr = &addr_size_;
+    }
+    int result = recvfrom(sock_, reinterpret_cast<char*>(data), len, 0,
+                          reinterpret_cast<sockaddr*>(addr_.get()), addr_size_ptr);
+    if (result < 0 && WSAGetLastError() == WSAETIMEDOUT) {
+        errno = EAGAIN;
+    }
+    return result;
+}
+
+int WindowsUdpSocket::Close() {
+    int result = 0;
+    if (sock_ != INVALID_SOCKET) {
+        result = closesocket(sock_);
+        sock_ = INVALID_SOCKET;
+    }
+    return result;
+}
+
+static int GetProtocol(int sock_type) {
+    switch (sock_type) {
+        case SOCK_DGRAM:
+            return IPPROTO_UDP;
+        case SOCK_STREAM:
+            return IPPROTO_TCP;
+        default:
+            // 0 lets the system decide which protocol to use.
+            return 0;
+    }
+}
+
+// Windows implementation of this libcutils function. This function does not make any calls to
+// WSAStartup() or WSACleanup() so that must be handled by the caller.
+// TODO(dpursell): share this code with adb.
+static SOCKET socket_network_client(const std::string& host, int port, int type) {
+    // First resolve the host and port parameters into a usable network address.
+    addrinfo hints;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_socktype = type;
+    hints.ai_protocol = GetProtocol(type);
+
+    addrinfo* address = nullptr;
+    getaddrinfo(host.c_str(), android::base::StringPrintf("%d", port).c_str(), &hints, &address);
+    if (address == nullptr) {
+        return INVALID_SOCKET;
+    }
+
+    // Now create and connect the socket.
+    SOCKET sock = socket(address->ai_family, address->ai_socktype, address->ai_protocol);
+    if (sock == INVALID_SOCKET) {
+        freeaddrinfo(address);
+        return INVALID_SOCKET;
+    }
+
+    if (connect(sock, address->ai_addr, address->ai_addrlen) == SOCKET_ERROR) {
+        closesocket(sock);
+        freeaddrinfo(address);
+        return INVALID_SOCKET;
+    }
+
+    freeaddrinfo(address);
+    return sock;
+}
+
+// Windows implementation of this libcutils function. This implementation creates a dual-stack
+// server socket that can accept incoming IPv4 or IPv6 packets. This function does not make any
+// calls to WSAStartup() or WSACleanup() so that must be handled by the caller.
+// TODO(dpursell): share this code with adb.
+static SOCKET socket_inaddr_any_server(int port, int type) {
+    SOCKET sock = socket(AF_INET6, type, GetProtocol(type));
+    if (sock == INVALID_SOCKET) {
+        return INVALID_SOCKET;
+    }
+
+    // Enforce exclusive addresses (1), and enable dual-stack so both IPv4 and IPv6 work (2).
+    // (1) https://msdn.microsoft.com/en-us/library/windows/desktop/ms740621(v=vs.85).aspx.
+    // (2) https://msdn.microsoft.com/en-us/library/windows/desktop/bb513665(v=vs.85).aspx.
+    int exclusive = 1;
+    DWORD v6_only = 0;
+    if (setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, reinterpret_cast<const char*>(&exclusive),
+                   sizeof(exclusive)) == SOCKET_ERROR ||
+        setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<const char*>(&v6_only),
+                   sizeof(v6_only)) == SOCKET_ERROR) {
+        closesocket(sock);
+        return INVALID_SOCKET;
+    }
+
+    // Bind the socket to our local port.
+    sockaddr_in6 addr;
+    memset(&addr, 0, sizeof(addr));
+    addr.sin6_family = AF_INET6;
+    addr.sin6_port = htons(port);
+    addr.sin6_addr = in6addr_any;
+    if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == SOCKET_ERROR) {
+        closesocket(sock);
+        return INVALID_SOCKET;
+    }
+
+    return sock;
+}
+
+// Documentation at https://msdn.microsoft.com/en-us/library/windows/desktop/ms741549(v=vs.85).aspx
+// claims WSACleanup() should be called before program exit, but general consensus seems to be that
+// it hasn't actually been necessary for a long time, possibly since Windows 3.1.
+//
+// Both adb (1) and Chrome (2) purposefully avoid WSACleanup(), and since no adverse affects have
+// been found we may as well do the same here to keep this code simpler.
+// (1) https://android.googlesource.com/platform/system/core.git/+/master/adb/sysdeps_win32.cpp#816
+// (2) https://code.google.com/p/chromium/codesearch#chromium/src/net/base/winsock_init.cc&l=35
+static bool InitWinsock() {
+    static bool init_success = false;
+
+    if (!init_success) {
+        WSADATA wsaData;
+        init_success = (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0);
+    }
+
+    return init_success;
+}
+
+std::unique_ptr<UdpSocket> UdpSocket::NewUdpClient(const std::string& host, int port,
+                                                   std::string* error) {
+    if (!InitWinsock()) {
+        if (error) {
+            *error = android::base::StringPrintf("Failed to initialize Winsock (error %d)",
+                                                 WSAGetLastError());
+        }
+        return nullptr;
+    }
+
+    SOCKET sock = socket_network_client(host, port, SOCK_DGRAM);
+    if (sock == INVALID_SOCKET) {
+        if (error) {
+            *error = android::base::StringPrintf("Failed to connect to %s:%d (error %d)",
+                                                 host.c_str(), port, WSAGetLastError());
+        }
+        return nullptr;
+    }
+
+    return std::unique_ptr<UdpSocket>(new WindowsUdpSocket(sock, WindowsUdpSocket::Type::kClient));
+}
+
+// This functionality is currently only used by tests so we don't need any error messages.
+std::unique_ptr<UdpSocket> UdpSocket::NewUdpServer(int port) {
+    if (!InitWinsock()) {
+        return nullptr;
+    }
+
+    SOCKET sock = socket_inaddr_any_server(port, SOCK_DGRAM);
+    if (sock == INVALID_SOCKET) {
+        return nullptr;
+    }
+
+    return std::unique_ptr<UdpSocket>(new WindowsUdpSocket(sock, WindowsUdpSocket::Type::kServer));
+}
diff --git a/fastboot/transport.h b/fastboot/transport.h
index 55a5abb..67d01f9 100644
--- a/fastboot/transport.h
+++ b/fastboot/transport.h
@@ -17,7 +17,7 @@
 #ifndef TRANSPORT_H_
 #define TRANSPORT_H_
 
-#include <base/macros.h>
+#include <android-base/macros.h>
 
 // General interface to allow the fastboot protocol to be used over different
 // types of transports.
diff --git a/fingerprintd/FingerprintDaemonProxy.cpp b/fingerprintd/FingerprintDaemonProxy.cpp
index beb95de..1c7da30 100644
--- a/fingerprintd/FingerprintDaemonProxy.cpp
+++ b/fingerprintd/FingerprintDaemonProxy.cpp
@@ -88,6 +88,16 @@
                     msg->data.removed.finger.fid,
                     msg->data.removed.finger.gid);
             break;
+        case FINGERPRINT_TEMPLATE_ENUMERATING:
+            ALOGD("onEnumerate(fid=%d, gid=%d, rem=%d)",
+                    msg->data.enumerated.finger.fid,
+                    msg->data.enumerated.finger.gid,
+                    msg->data.enumerated.remaining_templates);
+            callback->onEnumerate(device,
+                    msg->data.enumerated.finger.fid,
+                    msg->data.enumerated.finger.gid,
+                    msg->data.enumerated.remaining_templates);
+            break;
         default:
             ALOGE("invalid msg type: %d", msg->type);
             return;
@@ -158,6 +168,11 @@
     return mDevice->remove(mDevice, groupId, fingerId);
 }
 
+int32_t FingerprintDaemonProxy::enumerate() {
+    ALOG(LOG_VERBOSE, LOG_TAG, "enumerate()\n");
+    return mDevice->enumerate(mDevice);
+}
+
 uint64_t FingerprintDaemonProxy::getAuthenticatorId() {
     return mDevice->get_authenticator_id(mDevice);
 }
diff --git a/fingerprintd/FingerprintDaemonProxy.h b/fingerprintd/FingerprintDaemonProxy.h
index 871c0e6..145b4c9 100644
--- a/fingerprintd/FingerprintDaemonProxy.h
+++ b/fingerprintd/FingerprintDaemonProxy.h
@@ -40,6 +40,7 @@
         virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId);
         virtual int32_t stopAuthentication();
         virtual int32_t remove(int32_t fingerId, int32_t groupId);
+        virtual int32_t enumerate();
         virtual uint64_t getAuthenticatorId();
         virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen);
         virtual int64_t openHal();
diff --git a/fingerprintd/IFingerprintDaemon.cpp b/fingerprintd/IFingerprintDaemon.cpp
index 7131793..bc4af56 100644
--- a/fingerprintd/IFingerprintDaemon.cpp
+++ b/fingerprintd/IFingerprintDaemon.cpp
@@ -125,6 +125,16 @@
             reply->writeInt32(ret);
             return NO_ERROR;
         }
+        case ENUMERATE: {
+            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+                return PERMISSION_DENIED;
+            }
+            const int32_t ret = enumerate();
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
         case GET_AUTHENTICATOR_ID: {
             CHECK_INTERFACE(IFingerprintDaemon, data, reply);
             if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
diff --git a/fingerprintd/IFingerprintDaemon.h b/fingerprintd/IFingerprintDaemon.h
index 1eb4ac1..23c36ff 100644
--- a/fingerprintd/IFingerprintDaemon.h
+++ b/fingerprintd/IFingerprintDaemon.h
@@ -44,6 +44,7 @@
            CLOSE_HAL = IBinder::FIRST_CALL_TRANSACTION + 9,
            INIT = IBinder::FIRST_CALL_TRANSACTION + 10,
            POST_ENROLL = IBinder::FIRST_CALL_TRANSACTION + 11,
+           ENUMERATE = IBinder::FIRST_CALL_TRANSACTION + 12,
         };
 
         IFingerprintDaemon() { }
@@ -60,6 +61,7 @@
         virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId) = 0;
         virtual int32_t stopAuthentication() = 0;
         virtual int32_t remove(int32_t fingerId, int32_t groupId) = 0;
+        virtual int32_t enumerate() = 0;
         virtual uint64_t getAuthenticatorId() = 0;
         virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen) = 0;
         virtual int64_t openHal() = 0;
diff --git a/fingerprintd/IFingerprintDaemonCallback.cpp b/fingerprintd/IFingerprintDaemonCallback.cpp
index 44d8020..19838c9 100644
--- a/fingerprintd/IFingerprintDaemonCallback.cpp
+++ b/fingerprintd/IFingerprintDaemonCallback.cpp
@@ -74,13 +74,13 @@
         return remote()->transact(ON_REMOVED, data, &reply, IBinder::FLAG_ONEWAY);
     }
 
-    virtual status_t onEnumerate(int64_t devId, const int32_t* fpIds, const int32_t* gpIds,
-            int32_t sz) {
+    virtual status_t onEnumerate(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) {
         Parcel data, reply;
         data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
         data.writeInt64(devId);
-        data.writeInt32Array(sz, fpIds);
-        data.writeInt32Array(sz, gpIds);
+        data.writeInt32(fpId);
+        data.writeInt32(gpId);
+        data.writeInt32(rem);
         return remote()->transact(ON_ENUMERATE, data, &reply, IBinder::FLAG_ONEWAY);
     }
 };
diff --git a/fingerprintd/IFingerprintDaemonCallback.h b/fingerprintd/IFingerprintDaemonCallback.h
index 6e32213..e343cb4 100644
--- a/fingerprintd/IFingerprintDaemonCallback.h
+++ b/fingerprintd/IFingerprintDaemonCallback.h
@@ -44,8 +44,7 @@
         virtual status_t onAuthenticated(int64_t devId, int32_t fingerId, int32_t groupId) = 0;
         virtual status_t onError(int64_t devId, int32_t error) = 0;
         virtual status_t onRemoved(int64_t devId, int32_t fingerId, int32_t groupId) = 0;
-        virtual status_t onEnumerate(int64_t devId, const int32_t* fpIds, const int32_t* gpIds,
-                int32_t sz) = 0;
+        virtual status_t onEnumerate(int64_t devId, int32_t fingerId, int32_t groupId, int32_t rem) = 0;
 
         DECLARE_META_INTERFACE(FingerprintDaemonCallback);
 };
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index c47a585..2ff6273 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -101,6 +101,7 @@
     char tmpmnt_opts[64] = "errors=remount-ro";
     char *e2fsck_argv[] = {
         E2FSCK_BIN,
+        "-f",
         "-y",
         blk_device
     };
@@ -442,8 +443,22 @@
 // Check to see if a mountable volume has encryption requirements
 static int handle_encryptable(struct fstab *fstab, const struct fstab_rec* rec)
 {
+    /* Check for existence of convert_fbe breadcrumb file */
+    char convert_fbe_name[PATH_MAX];
+    snprintf(convert_fbe_name, sizeof(convert_fbe_name),
+             "%s/convert_fbe", rec->mount_point);
+    bool convert_fbe = (access(convert_fbe_name, F_OK) == 0);
+
+    /* Check for existence of convert_fbe breadcrumb file */
+    char convert_fde_name[PATH_MAX];
+    snprintf(convert_fde_name, sizeof(convert_fbe_name),
+             "%s/misc/vold/convert_fde", rec->mount_point);
+    bool convert_fde = (access(convert_fde_name, F_OK) == 0);
+
     /* If this is block encryptable, need to trigger encryption */
     if (   (rec->fs_mgr_flags & MF_FORCECRYPT)
+        || ((rec->fs_mgr_flags & MF_CRYPT) && convert_fde)
+        || ((rec->fs_mgr_flags & MF_FORCEFDEORFBE) && !convert_fbe)
         || (device_is_force_encrypted() && fs_mgr_is_encryptable(rec))) {
         if (umount(rec->mount_point) == 0) {
             return FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION;
@@ -455,7 +470,8 @@
     }
 
     // Deal with file level encryption
-    if (rec->fs_mgr_flags & MF_FILEENCRYPTION) {
+    if (   (rec->fs_mgr_flags & MF_FILEENCRYPTION)
+        || ((rec->fs_mgr_flags & MF_FORCEFDEORFBE) && convert_fbe)) {
         // Default or not yet initialized encryption requires no more work here
         if (!e4crypt_non_default_key(rec->mount_point)) {
             INFO("%s is default file encrypted\n", rec->mount_point);
@@ -881,7 +897,8 @@
         if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
             continue;
         }
-        if (!(fstab->recs[i].fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT))) {
+        if (!(fstab->recs[i].fs_mgr_flags
+              & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE))) {
             continue;
         }
 
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index cf35b3f..c8c624d 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -64,6 +64,7 @@
     { "encryptable=",MF_CRYPT },
     { "forceencrypt=",MF_FORCECRYPT },
     { "fileencryption",MF_FILEENCRYPTION },
+    { "forcefdeorfbe=",MF_FORCEFDEORFBE },
     { "nonremovable",MF_NONREMOVABLE },
     { "voldmanaged=",MF_VOLDMANAGED},
     { "length=",     MF_LENGTH },
@@ -140,6 +141,11 @@
                      * location of the keys.  Get it and return it.
                      */
                     flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+                } else if ((fl[i].flag == MF_FORCEFDEORFBE) && flag_vals) {
+                    /* The forcefdeorfbe flag is followed by an = and the
+                     * location of the keys.  Get it and return it.
+                     */
+                    flag_vals->key_loc = strdup(strchr(p, '=') + 1);
                 } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
                     /* The length flag is followed by an = and the
                      * size of the partition.  Get it and return it.
@@ -464,7 +470,7 @@
 
 int fs_mgr_is_encryptable(const struct fstab_rec *fstab)
 {
-    return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT);
+    return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE);
 }
 
 int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab)
@@ -472,6 +478,11 @@
     return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
 }
 
+int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_FORCEFDEORFBE;
+}
+
 int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index ba0e097..181b6cd 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -82,6 +82,7 @@
 #define MF_FILEENCRYPTION 0x2000
 #define MF_FORMATTABLE  0x4000
 #define MF_SLOTSELECT   0x8000
+#define MF_FORCEFDEORFBE 0x10000
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 6983b72..b5141c9 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -29,7 +29,7 @@
 #include <libgen.h>
 #include <time.h>
 
-#include <base/file.h>
+#include <android-base/file.h>
 #include <private/android_filesystem_config.h>
 #include <cutils/properties.h>
 #include <logwrap/logwrap.h>
@@ -254,7 +254,7 @@
         res = snprintf(buf, bufsize, "%s 2 " VERITY_TABLE_OPT_IGNZERO " %s", params->table,
                     mode_flag);
     } else {
-        res = strlcpy(buf, params->table, bufsize);
+        res = snprintf(buf, bufsize, "%s 1 " VERITY_TABLE_OPT_IGNZERO, params->table);
     }
 
     if (res < 0 || (size_t)res >= bufsize) {
@@ -695,31 +695,27 @@
     int match = 0;
     off64_t offset = 0;
 
+    /* unless otherwise specified, use EIO mode */
+    *mode = VERITY_MODE_EIO;
+
     /* use the kernel parameter if set */
     property_get("ro.boot.veritymode", propbuf, "");
 
     if (*propbuf != '\0') {
         if (!strcmp(propbuf, "enforcing")) {
             *mode = VERITY_MODE_DEFAULT;
-            return 0;
-        } else if (!strcmp(propbuf, "logging")) {
-            *mode = VERITY_MODE_LOGGING;
-            return 0;
-        } else {
-            INFO("Unknown value %s for veritymode; ignoring", propbuf);
         }
+        return 0;
     }
 
     if (get_verity_state_offset(fstab, &offset) < 0) {
         /* fall back to stateless behavior */
-        *mode = VERITY_MODE_EIO;
         return 0;
     }
 
     if (was_verity_restart()) {
         /* device was restarted after dm-verity detected a corrupted
-         * block, so switch to logging mode */
-        *mode = VERITY_MODE_LOGGING;
+         * block, so use EIO mode */
         return write_verity_state(fstab->verity_loc, offset, *mode);
     }
 
@@ -784,7 +780,6 @@
 int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback)
 {
     alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
-    bool use_state = true;
     char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
     char *mount_point;
     char propbuf[PROPERTY_VALUE_MAX];
@@ -793,15 +788,11 @@
     int i;
     int mode;
     int rc = -1;
-    off64_t offset = 0;
     struct dm_ioctl *io = (struct dm_ioctl *) buffer;
     struct fstab *fstab = NULL;
 
-    /* check if we need to store the state */
-    property_get("ro.boot.veritymode", propbuf, "");
-
-    if (*propbuf != '\0') {
-        use_state = false; /* state is kept by the bootloader */
+    if (!callback) {
+        return -1;
     }
 
     if (fs_mgr_load_verity_state(&mode) == -1) {
@@ -841,16 +832,7 @@
 
         status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
 
-        if (use_state && *status == 'C') {
-            if (write_verity_state(fstab->recs[i].verity_loc, offset,
-                    VERITY_MODE_LOGGING) < 0) {
-                continue;
-            }
-        }
-
-        if (callback) {
-            callback(&fstab->recs[i], mount_point, mode, *status);
-        }
+        callback(&fstab->recs[i], mount_point, mode, *status);
     }
 
     rc = 0;
@@ -962,13 +944,43 @@
 
     // load the verity mapping table
     if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
-            format_verity_table) < 0 &&
-        // try the legacy format for backwards compatibility
-        load_verity_table(io, mount_point, verity.data_size, fd, &params,
-            format_legacy_verity_table) < 0) {
-        goto out;
+            format_verity_table) == 0) {
+        goto loaded;
     }
 
+    if (params.ecc.valid) {
+        // kernel may not support error correction, try without
+        INFO("Disabling error correction for %s\n", mount_point);
+        params.ecc.valid = false;
+
+        if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
+                format_verity_table) == 0) {
+            goto loaded;
+        }
+    }
+
+    // try the legacy format for backwards compatibility
+    if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
+            format_legacy_verity_table) == 0) {
+        goto loaded;
+    }
+
+    if (params.mode != VERITY_MODE_EIO) {
+        // as a last resort, EIO mode should always be supported
+        INFO("Falling back to EIO mode for %s\n", mount_point);
+        params.mode = VERITY_MODE_EIO;
+
+        if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
+                format_legacy_verity_table) == 0) {
+            goto loaded;
+        }
+    }
+
+    ERROR("Failed to load verity table for %s\n", mount_point);
+    goto out;
+
+loaded:
+
     // activate the device
     if (resume_verity_table(io, mount_point, fd) < 0) {
         goto out;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 27fccf7..eb0a7fc 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -102,6 +102,7 @@
 int fs_mgr_is_verified(const struct fstab_rec *fstab);
 int fs_mgr_is_encryptable(const struct fstab_rec *fstab);
 int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab);
+int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab);
 int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
 int fs_mgr_is_notrim(struct fstab_rec *fstab);
 int fs_mgr_is_formattable(struct fstab_rec *fstab);
diff --git a/gatekeeperd/SoftGateKeeper.h b/gatekeeperd/SoftGateKeeper.h
index c8010ca..8b15d72 100644
--- a/gatekeeperd/SoftGateKeeper.h
+++ b/gatekeeperd/SoftGateKeeper.h
@@ -25,7 +25,7 @@
 #include <crypto_scrypt.h>
 }
 
-#include <base/memory.h>
+#include <android-base/memory.h>
 #include <UniquePtr.h>
 #include <gatekeeper/gatekeeper.h>
 
@@ -180,4 +180,3 @@
 }
 
 #endif // SOFT_GATEKEEPER_H_
-
diff --git a/gatekeeperd/tests/gatekeeper_test.cpp b/gatekeeperd/tests/gatekeeper_test.cpp
index c504f92..47a8bfa 100644
--- a/gatekeeperd/tests/gatekeeper_test.cpp
+++ b/gatekeeperd/tests/gatekeeper_test.cpp
@@ -18,9 +18,8 @@
 #include <iostream>
 
 #include <gtest/gtest.h>
-#include <UniquePtr.h>
-
 #include <hardware/hw_auth_token.h>
+#include <UniquePtr.h>
 
 #include "../SoftGateKeeper.h"
 
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 0085a07..3e618c0 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -631,7 +631,7 @@
             KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
         if (mHealthdConfig->batteryTechnologyPath.isEmpty())
             KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
-	if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
+        if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
             KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n");
         if (mHealthdConfig->batteryFullChargePath.isEmpty())
             KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n");
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 6800ad2..46bad4e 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -699,7 +699,10 @@
 
     GRSurface** scale_frames;
     int scale_count;
-    ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames);
+    int scale_fps;  // Not in use (charger/battery_scale doesn't have FPS text
+                    // chunk). We are using hard-coded frame.disp_time instead.
+    ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_fps,
+                                           &scale_frames);
     if (ret < 0) {
         LOGE("Cannot load battery_scale image\n");
         charger->batt_anim->num_frames = 0;
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index 087a0c4..c9790ad 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -69,7 +69,8 @@
 #define ATRACE_TAG_POWER            (1<<17)
 #define ATRACE_TAG_PACKAGE_MANAGER  (1<<18)
 #define ATRACE_TAG_SYSTEM_SERVER    (1<<19)
-#define ATRACE_TAG_LAST             ATRACE_TAG_SYSTEM_SERVER
+#define ATRACE_TAG_DATABASE         (1<<20)
+#define ATRACE_TAG_LAST             ATRACE_TAG_DATABASE
 
 // Reserved for initialization.
 #define ATRACE_TAG_NOT_READY        (1ULL<<63)
diff --git a/include/log/log.h b/include/log/log.h
index 086d742..3d9240d 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -604,7 +604,8 @@
     LOG_ID_EVENTS = 2,
     LOG_ID_SYSTEM = 3,
     LOG_ID_CRASH = 4,
-    LOG_ID_KERNEL = 5,
+    LOG_ID_SECURITY = 5,
+    LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
 #endif
 
     LOG_ID_MAX
@@ -620,6 +621,8 @@
  */
 int __android_log_is_loggable(int prio, const char *tag, int default_prio);
 
+int __android_log_security(); /* Device Owner is present */
+
 int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data,
                               uint32_t dataLen);
 
diff --git a/include/log/logd.h b/include/log/logd.h
index 0fe515f..b7aedaf 100644
--- a/include/log/logd.h
+++ b/include/log/logd.h
@@ -44,6 +44,8 @@
     size_t len);
 int __android_log_bswrite(int32_t tag, const char *payload);
 
+int __android_log_security_bwrite(int32_t tag, const void *payload, size_t len);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/log/logger.h b/include/log/logger.h
index c795253..60d47a2 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -11,6 +11,10 @@
 #define _LIBS_LOG_LOGGER_H
 
 #include <stdint.h>
+#ifdef __linux__
+#include <time.h> /* clockid_t definition */
+#endif
+
 #include <log/log.h>
 #include <log/log_read.h>
 
@@ -60,12 +64,24 @@
     char        msg[0];    /* the entry's payload */
 } __attribute__((__packed__));
 
+struct logger_entry_v4 {
+    uint16_t    len;       /* length of the payload */
+    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v4) */
+    int32_t     pid;       /* generating process's pid */
+    uint32_t    tid;       /* generating process's tid */
+    uint32_t    sec;       /* seconds since Epoch */
+    uint32_t    nsec;      /* nanoseconds */
+    uint32_t    lid;       /* log id of the payload, bottom 4 bits currently */
+    uint32_t    uid;       /* generating process's uid */
+    char        msg[0];    /* the entry's payload */
+} __attribute__((__packed__));
+
 /*
  * The maximum size of the log entry payload that can be
  * written to the logger. An attempt to write more than
  * this amount will result in a truncated log entry.
  */
-#define LOGGER_ENTRY_MAX_PAYLOAD	4076
+#define LOGGER_ENTRY_MAX_PAYLOAD	4068
 
 /*
  * The maximum size of a log entry which can be read from the
@@ -79,7 +95,8 @@
 struct log_msg {
     union {
         unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
-        struct logger_entry_v3 entry;
+        struct logger_entry_v4 entry;
+        struct logger_entry_v4 entry_v4;
         struct logger_entry_v3 entry_v3;
         struct logger_entry_v2 entry_v2;
         struct logger_entry    entry_v1;
@@ -159,6 +176,8 @@
 #define ANDROID_LOG_RDWR     O_RDWR
 #define ANDROID_LOG_ACCMODE  O_ACCMODE
 #define ANDROID_LOG_NONBLOCK O_NONBLOCK
+#define ANDROID_LOG_WRAP     0x40000000 /* Block until buffer about to wrap */
+#define ANDROID_LOG_WRAP_DEFAULT_TIMEOUT 7200 /* 2 hour default */
 #define ANDROID_LOG_PSTORE   0x80000000
 
 struct logger_list *android_logger_list_alloc(int mode,
@@ -183,7 +202,9 @@
                                              pid_t pid);
 #define android_logger_list_close android_logger_list_free
 
-char android_log_timestamp();
+#ifdef __linux__
+clockid_t android_log_clockid();
+#endif
 
 /*
  * log_id_t helpers
diff --git a/include/log/logprint.h b/include/log/logprint.h
index 204b3f2..539d1dc 100644
--- a/include/log/logprint.h
+++ b/include/log/logprint.h
@@ -44,6 +44,7 @@
     FORMAT_MODIFIER_ZONE,      /* Adds zone to date */
     FORMAT_MODIFIER_EPOCH,     /* Print time as seconds since Jan 1 1970 */
     FORMAT_MODIFIER_MONOTONIC, /* Print cpu time as seconds since start */
+    FORMAT_MODIFIER_UID,       /* Adds uid */
 } AndroidLogPrintFormat;
 
 typedef struct AndroidLogFormat_t AndroidLogFormat;
@@ -52,6 +53,7 @@
     time_t tv_sec;
     long tv_nsec;
     android_LogPriority priority;
+    int32_t uid;
     int32_t pid;
     int32_t tid;
     const char * tag;
diff --git a/include/nativeloader/native_loader.h b/include/nativeloader/native_loader.h
new file mode 100644
index 0000000..da07253
--- /dev/null
+++ b/include/nativeloader/native_loader.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NATIVE_LOADER_H_
+#define NATIVE_LOADER_H_
+
+#include "jni.h"
+#include <stdint.h>
+
+namespace android {
+
+__attribute__((visibility("default")))
+void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
+                        jobject class_loader, bool is_shared, jstring library_path,
+                        jstring permitted_path);
+
+};  // namespace android
+
+#endif  // NATIVE_BRIDGE_H_
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index e2133e9..d236938 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -81,6 +81,8 @@
 #define AID_SHARED_RELRO  1037  /* creator of shared GNU RELRO files */
 #define AID_DBUS          1038  /* dbus-daemon IPC broker process */
 #define AID_TLSDATE       1039  /* tlsdate unprivileged user */
+#define AID_MEDIA_EX      1040  /* mediaextractor process */
+#define AID_AUDIOSERVER   1041  /* audioserver process */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
 #define AID_CACHE         2001  /* cache access */
@@ -179,6 +181,8 @@
     { "shared_relro",  AID_SHARED_RELRO, },
     { "dbus",          AID_DBUS, },
     { "tlsdate",       AID_TLSDATE, },
+    { "mediaex",       AID_MEDIA_EX, },
+    { "audioserver",   AID_AUDIOSERVER, },
 
     { "shell",         AID_SHELL, },
     { "cache",         AID_CACHE, },
diff --git a/include/system/radio.h b/include/system/radio.h
index a088526..9e291c8 100644
--- a/include/system/radio.h
+++ b/include/system/radio.h
@@ -94,6 +94,7 @@
     radio_rds_t         rds;        /* RDS variants supported */
     bool                ta;         /* Traffic Announcement supported */
     bool                af;         /* Alternate Frequency supported */
+    bool                ea;         /* Emergency announcements supported */
 } radio_hal_fm_band_config_t;
 
 /* Additional attributes for an AM band configuration */
@@ -184,6 +185,7 @@
     RADIO_EVENT_METADATA    = 4,  /* New meta data received */
     RADIO_EVENT_TA          = 5,  /* Traffic announcement start or stop */
     RADIO_EVENT_AF_SWITCH   = 6,  /* Switch to Alternate Frequency */
+    RADIO_EVENT_EA          = 7,  /* Emergency announcement start or stop */
     // begin framework only events
     RADIO_EVENT_CONTROL     = 100, /* loss/gain of tuner control */
     RADIO_EVENT_SERVER_DIED = 101, /* radio service died */
@@ -195,7 +197,8 @@
     radio_event_type_t  type;       /* event type */
     int                 status;     /* used by RADIO_EVENT_CONFIG, RADIO_EVENT_TUNED */
     union {
-        bool                    on;     /* RADIO_EVENT_ANTENNA, RADIO_EVENT_TA */
+        /* RADIO_EVENT_ANTENNA, RADIO_EVENT_TA, RADIO_EVENT_EA */
+        bool                    on;
         radio_hal_band_config_t config; /* RADIO_EVENT_CONFIG */
         radio_program_info_t    info;   /* RADIO_EVENT_TUNED, RADIO_EVENT_AF_SWITCH */
         radio_metadata_t        *metadata; /* RADIO_EVENT_METADATA */
diff --git a/include/system/window.h b/include/system/window.h
index 508ce00..14cce27 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -25,6 +25,7 @@
 #include <sys/cdefs.h>
 #include <system/graphics.h>
 #include <unistd.h>
+#include <stdbool.h>
 
 #ifndef __UNUSED
 #define __UNUSED __attribute__((__unused__))
@@ -311,6 +312,7 @@
     NATIVE_WINDOW_SET_SIDEBAND_STREAM       = 18,
     NATIVE_WINDOW_SET_BUFFERS_DATASPACE     = 19,
     NATIVE_WINDOW_SET_SURFACE_DAMAGE        = 20,   /* private */
+    NATIVE_WINDOW_SET_SINGLE_BUFFER_MODE    = 21,
 };
 
 /* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
@@ -351,7 +353,8 @@
     NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY = 0x08
 };
 
-/* parameter for NATIVE_WINDOW_SET_SCALING_MODE */
+/* parameter for NATIVE_WINDOW_SET_SCALING_MODE
+ * keep in sync with Surface.java in frameworks/base */
 enum {
     /* the window content is not updated (frozen) until a buffer of
      * the window size is received (enqueued)
@@ -949,6 +952,18 @@
             rects, numRects);
 }
 
+/*
+ * native_window_set_single_buffer_mode(..., bool singleBufferMode)
+ * Enable/disable single buffer mode
+ */
+static inline int native_window_set_single_buffer_mode(
+        struct ANativeWindow* window,
+        bool singleBufferMode)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_SINGLE_BUFFER_MODE,
+            singleBufferMode);
+}
+
 __END_DECLS
 
 #endif /* SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H */
diff --git a/include/ziparchive/zip_writer.h b/include/ziparchive/zip_writer.h
index d996c4a..0efade8 100644
--- a/include/ziparchive/zip_writer.h
+++ b/include/ziparchive/zip_writer.h
@@ -17,7 +17,7 @@
 #ifndef LIBZIPARCHIVE_ZIPWRITER_H_
 #define LIBZIPARCHIVE_ZIPWRITER_H_
 
-#include "base/macros.h"
+#include "android-base/macros.h"
 #include <utils/Compat.h>
 
 #include <cstdio>
diff --git a/init/action.cpp b/init/action.cpp
index c6cbc2e..510ea89 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -18,8 +18,8 @@
 
 #include <errno.h>
 
-#include <base/strings.h>
-#include <base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/stringprintf.h>
 
 #include "builtins.h"
 #include "error.h"
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index e1e0c48..5704d28 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -33,7 +33,7 @@
 #include <string>
 #include <vector>
 
-#include <base/file.h>
+#include <android-base/file.h>
 
 #define LOG_ROOT        "/data/bootchart"
 #define LOG_STAT        LOG_ROOT"/proc_stat.log"
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 36ecbb8..dddd6e4 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -39,7 +39,7 @@
 #include <selinux/label.h>
 
 #include <fs_mgr.h>
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 #include <cutils/partition_utils.h>
 #include <cutils/android_reboot.h>
 #include <logwrap/logwrap.h>
@@ -642,7 +642,7 @@
 static int do_verity_load_state(const std::vector<std::string>& args) {
     int mode = -1;
     int rc = fs_mgr_load_verity_state(&mode);
-    if (rc == 0 && mode == VERITY_MODE_LOGGING) {
+    if (rc == 0 && mode != VERITY_MODE_DEFAULT) {
         ActionManager::GetInstance().QueueEventTrigger("verity-logging");
     }
     return rc;
@@ -838,6 +838,15 @@
     return e4crypt_set_user_crypto_policies(args[1].c_str());
 }
 
+static int do_createuserkey(const std::vector<std::string>& args) {
+    if (!is_file_crypto()) {
+        return 0;
+    }
+    return e4crypt_create_user_key(atoi(args[1].c_str()),
+                                   atoi(args[2].c_str()),
+                                   atoi(args[3].c_str()));
+}
+
 BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
     static const Map builtin_functions = {
@@ -848,6 +857,7 @@
         {"class_start",             {1,     1,    do_class_start}},
         {"class_stop",              {1,     1,    do_class_stop}},
         {"copy",                    {2,     2,    do_copy}},
+        {"createuserkey",           {3,     3,    do_createuserkey}},
         {"domainname",              {1,     1,    do_domainname}},
         {"enable",                  {1,     1,    do_enable}},
         {"exec",                    {1,     kMax, do_exec}},
diff --git a/init/init.cpp b/init/init.cpp
index 86aed9a..4aef823 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -40,9 +40,9 @@
 #include <selinux/label.h>
 #include <selinux/android.h>
 
-#include <base/file.h>
-#include <base/stringprintf.h>
-#include <base/strings.h>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <cutils/android_reboot.h>
 #include <cutils/fs.h>
 #include <cutils/iosched_policy.h>
@@ -350,6 +350,18 @@
     }
 }
 
+static void export_oem_lock_status() {
+    if (property_get("ro.oem_unlock_supported") != "1") {
+        return;
+    }
+
+    std::string value = property_get("ro.boot.verifiedbootstate");
+
+    if (!value.empty()) {
+        property_set("ro.boot.flash.locked", value == "orange" ? "0" : "1");
+    }
+}
+
 static void export_kernel_boot_props() {
     struct {
         const char *src_prop;
@@ -602,6 +614,7 @@
     restorecon("/dev");
     restorecon("/dev/socket");
     restorecon("/dev/__properties__");
+    restorecon("/property_contexts");
     restorecon_recursive("/sys");
 
     epoll_fd = epoll_create1(EPOLL_CLOEXEC);
@@ -613,6 +626,7 @@
     signal_handler_init();
 
     property_load_boot_defaults();
+    export_oem_lock_status();
     start_property_service();
 
     const BuiltinFunctionMap function_map;
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 5b8e27b..b44ca59 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -25,7 +25,7 @@
 #include "service.h"
 #include "util.h"
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 
 Parser::Parser() {
 }
diff --git a/init/keyword_map.h b/init/keyword_map.h
index dc2357b..693d82a 100644
--- a/init/keyword_map.h
+++ b/init/keyword_map.h
@@ -20,7 +20,7 @@
 #include <map>
 #include <string>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 
 template <typename Function>
 class KeywordMap {
diff --git a/init/log.cpp b/init/log.cpp
index eb5ec42..a72906b 100644
--- a/init/log.cpp
+++ b/init/log.cpp
@@ -22,7 +22,7 @@
 
 #include <selinux/selinux.h>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 
 static void init_klog_vwrite(int level, const char* fmt, va_list ap) {
     static const char* tag = basename(getprogname());
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 96b4a37..806608e 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -47,7 +47,7 @@
 #include <selinux/label.h>
 
 #include <fs_mgr.h>
-#include <base/file.h>
+#include <android-base/file.h>
 #include "bootimg.h"
 
 #include "property_service.h"
@@ -60,33 +60,13 @@
 #define RECOVERY_MOUNT_POINT "/recovery"
 
 static int persistent_properties_loaded = 0;
-static bool property_area_initialized = false;
 
 static int property_set_fd = -1;
 
-struct workspace {
-    size_t size;
-    int fd;
-};
-
-static workspace pa_workspace;
-
 void property_init() {
-    if (property_area_initialized) {
-        return;
-    }
-
-    property_area_initialized = true;
-
     if (__system_property_area_init()) {
-        return;
-    }
-
-    pa_workspace.size = 0;
-    pa_workspace.fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
-    if (pa_workspace.fd == -1) {
-        ERROR("Failed to open %s: %s\n", PROP_FILENAME, strerror(errno));
-        return;
+        ERROR("Failed to initialize property area\n");
+        exit(1);
     }
 }
 
@@ -353,12 +333,6 @@
     }
 }
 
-void get_property_workspace(int *fd, int *sz)
-{
-    *fd = pa_workspace.fd;
-    *sz = pa_workspace.size;
-}
-
 static void load_properties_from_file(const char *, const char *);
 
 /*
@@ -497,10 +471,6 @@
     load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL);
 }
 
-bool properties_initialized() {
-    return property_area_initialized;
-}
-
 static void load_override_properties() {
     if (ALLOW_LOCAL_PROP_OVERRIDE) {
         std::string debuggable = property_get("ro.debuggable");
diff --git a/init/property_service.h b/init/property_service.h
index 8b76d2b..dbaed34 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -32,10 +32,8 @@
 extern void load_persist_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);
 extern int property_set(const char *name, const char *value);
-extern bool properties_initialized();
 
 
-#endif	/* _INIT_PROPERTY_H */
+#endif  /* _INIT_PROPERTY_H */
diff --git a/init/readme.txt b/init/readme.txt
index bf440c2..bacd6bd 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -109,9 +109,16 @@
 user <username>
   Change to username before exec'ing this service.
   Currently defaults to root.  (??? probably should default to nobody)
-  Currently, if your process requires linux capabilities then you cannot use
-  this command. You must instead request the capabilities in-process while
-  still root, and then drop to your desired uid.
+  As of Android M, processes should use this option even if they
+  require linux capabilities.  Previously, to acquire linux
+  capabilities, a process would need to run as root, request the
+  capabilities, then drop to its desired uid.  There is a new
+  mechanism through fs_config that allows device manufacturers to add
+  linux capabilities to specific binaries on a file system that should
+  be used instead. This mechanism is described on
+  http://source.android.com/devices/tech/config/filesystem.html.  When
+  using this new mechanism, processes can use the user option to
+  select their desired uid without ever running as root.
 
 group <groupname> [ <groupname> ]*
   Change to groupname before exec'ing this service.  Additional
diff --git a/init/service.cpp b/init/service.cpp
index a3c5ca4..40a4bc7 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -24,8 +24,8 @@
 
 #include <selinux/selinux.h>
 
-#include <base/file.h>
-#include <base/stringprintf.h>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
 #include <cutils/android_reboot.h>
 #include <cutils/sockets.h>
 
@@ -76,11 +76,6 @@
 }
 
 void Service::NotifyStateChange(const std::string& new_state) const {
-    if (!properties_initialized()) {
-        // If properties aren't available yet, we can't set them.
-        return;
-    }
-
     if ((flags_ & SVC_EXEC) != 0) {
         // 'exec' commands don't have properties tracking their state.
         return;
@@ -400,14 +395,7 @@
 
     pid_t pid = fork();
     if (pid == 0) {
-        int fd, sz;
-
         umask(077);
-        if (properties_initialized()) {
-            get_property_workspace(&fd, &sz);
-            std::string tmp = StringPrintf("%d,%d", dup(fd), sz);
-            add_environment("ANDROID_PROPERTY_WORKSPACE", tmp.c_str());
-        }
 
         for (const auto& ei : envvars_) {
             add_environment(ei.name.c_str(), ei.value.c_str());
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index 867abbc..e7d42cb 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -23,7 +23,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 #include <cutils/android_reboot.h>
 #include <cutils/list.h>
 #include <cutils/sockets.h>
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 75924cb..249739b 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -22,7 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 #include <private/android_filesystem_config.h>
 #include <selinux/selinux.h>
 
diff --git a/init/util.cpp b/init/util.cpp
index b316d6e..aefdf8f 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -32,12 +32,12 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
-#include <base/file.h>
-#include <base/strings.h>
+#include <android-base/file.h>
+#include <android-base/strings.h>
 
 /* for ANDROID_SOCKET_* */
 #include <cutils/sockets.h>
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 
 #include <private/android_filesystem_config.h>
 
@@ -105,8 +105,12 @@
     int fd, ret;
     char *filecon;
 
-    if (socketcon)
-        setsockcreatecon(socketcon);
+    if (socketcon) {
+        if (setsockcreatecon(socketcon) == -1) {
+            ERROR("setsockcreatecon(\"%s\") failed: %s\n", socketcon, strerror(errno));
+            return -1;
+        }
+    }
 
     fd = socket(PF_UNIX, type, 0);
     if (fd < 0) {
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index 9c6742e..5d3dd86 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -68,6 +68,7 @@
 # Use static llvm libraries on host to remove dependency on 32-bit llvm shared library
 # which is not included in the prebuilt.
 libbacktrace_static_libraries_host := \
+	libcutils \
 	libLLVMObject \
 	libLLVMBitReader \
 	libLLVMMC \
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 9ead452..3c8f879 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -22,13 +22,11 @@
 
 #include <string>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
-#include <cutils/threads.h>
-
 #include "BacktraceLog.h"
 #include "BacktraceOffline.h"
 #include "thread_utils.h"
@@ -93,16 +91,26 @@
 }
 
 std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) {
-  const char* map_name;
-  if (BacktraceMap::IsValid(frame->map) && !frame->map.name.empty()) {
-    map_name = frame->map.name.c_str();
+  uintptr_t relative_pc;
+  std::string map_name;
+  if (BacktraceMap::IsValid(frame->map)) {
+    relative_pc = BacktraceMap::GetRelativePc(frame->map, frame->pc);
+    if (!frame->map.name.empty()) {
+      map_name = frame->map.name.c_str();
+      if (map_name[0] == '[' && map_name[map_name.size() - 1] == ']') {
+        map_name.resize(map_name.size() - 1);
+        map_name += StringPrintf(":%" PRIPTR "]", frame->map.start);
+      }
+    } else {
+      map_name = StringPrintf("<anonymous:%" PRIPTR ">", frame->map.start);
+    }
   } else {
     map_name = "<unknown>";
+    relative_pc = frame->pc;
   }
 
-  uintptr_t relative_pc = BacktraceMap::GetRelativePc(frame->map, frame->pc);
-
-  std::string line(StringPrintf("#%02zu pc %" PRIPTR "  %s", frame->num, relative_pc, map_name));
+  std::string line(StringPrintf("#%02zu pc %" PRIPTR "  ", frame->num, relative_pc));
+  line += map_name;
   // Special handling for non-zero offset maps, we need to print that
   // information.
   if (frame->map.offset != 0) {
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index d339550..8e22366 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -29,8 +29,6 @@
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
-#include <cutils/threads.h>
-
 #include "BacktraceCurrent.h"
 #include "BacktraceLog.h"
 #include "ThreadEntry.h"
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index 27dfb83..abc186b 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -22,7 +22,9 @@
 }
 
 #include <stdint.h>
+#include <stdio.h>
 #include <string.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <ucontext.h>
 #include <unistd.h>
@@ -616,7 +618,30 @@
   return debug_frame;
 }
 
+static bool IsValidElfPath(const std::string& filename) {
+  static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
+
+  struct stat st;
+  if (stat(filename.c_str(), &st) != 0 || !S_ISREG(st.st_mode)) {
+    return false;
+  }
+  FILE* fp = fopen(filename.c_str(), "reb");
+  if (fp == nullptr) {
+    return false;
+  }
+  char buf[4];
+  if (fread(buf, 4, 1, fp) != 1) {
+    fclose(fp);
+    return false;
+  }
+  fclose(fp);
+  return memcmp(buf, elf_magic, 4) == 0;
+}
+
 static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename) {
+  if (!IsValidElfPath(filename)) {
+    return nullptr;
+  }
   auto owning_binary = llvm::object::createBinary(llvm::StringRef(filename));
   if (owning_binary.getError()) {
     return nullptr;
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 9ebd639..23636db 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -42,7 +42,7 @@
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 #include <cutils/atomic.h>
 #include <cutils/threads.h>
 
@@ -775,16 +775,29 @@
             backtrace->FormatFrameData(&frame));
 
   // Check map name empty, but exists.
-  frame.map.start = 1;
-  frame.map.end = 1;
+  frame.pc = 0xb0020;
+  frame.map.start = 0xb0000;
+  frame.map.end = 0xbffff;
   frame.map.load_base = 0;
 #if defined(__LP64__)
-  EXPECT_EQ("#01 pc 0000000000000001  <unknown>",
+  EXPECT_EQ("#01 pc 0000000000000020  <anonymous:00000000000b0000>",
 #else
-  EXPECT_EQ("#01 pc 00000001  <unknown>",
+  EXPECT_EQ("#01 pc 00000020  <anonymous:000b0000>",
 #endif
             backtrace->FormatFrameData(&frame));
 
+  // Check map name begins with a [.
+  frame.pc = 0xc0020;
+  frame.map.start = 0xc0000;
+  frame.map.end = 0xcffff;
+  frame.map.load_base = 0;
+  frame.map.name = "[anon:thread signal stack]";
+#if defined(__LP64__)
+  EXPECT_EQ("#01 pc 0000000000000020  [anon:thread signal stack:00000000000c0000]",
+#else
+  EXPECT_EQ("#01 pc 00000020  [anon:thread signal stack:000c0000]",
+#endif
+            backtrace->FormatFrameData(&frame));
 
   // Check relative pc is set and map name is set.
   frame.pc = 0x12345679;
@@ -1448,4 +1461,3 @@
   ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
 }
 #endif
-
diff --git a/libbacktrace/thread_utils.h b/libbacktrace/thread_utils.h
index df83581..9590657 100644
--- a/libbacktrace/thread_utils.h
+++ b/libbacktrace/thread_utils.h
@@ -19,6 +19,10 @@
 
 #include <unistd.h>
 
+#if !defined(__ANDROID__)
+#include <cutils/threads.h>
+#endif
+
 __BEGIN_DECLS
 
 int tgkill(int tgid, int tid, int sig);
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 3ca544f..1f68290 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -16,28 +16,27 @@
 LOCAL_PATH := $(my-dir)
 include $(CLEAR_VARS)
 
-commonSources := \
-	hashmap.c \
-	atomic.c.arm \
-	native_handle.c \
-	config_utils.c \
-	load_file.c \
-	strlcpy.c \
-	open_memstream.c \
-	strdup16to8.c \
-	strdup8to16.c \
-	record_stream.c \
-	process_name.c \
-	threads.c \
-	sched_policy.c \
-	iosched_policy.c \
-	str_parms.c \
-	fs_config.c
+libcutils_common_sources := \
+        hashmap.c \
+        atomic.c.arm \
+        native_handle.c \
+        config_utils.c \
+        load_file.c \
+        strlcpy.c \
+        open_memstream.c \
+        strdup16to8.c \
+        strdup8to16.c \
+        record_stream.c \
+        process_name.c \
+        threads.c \
+        sched_policy.c \
+        iosched_policy.c \
+        fs_config.c
 
 # some files must not be compiled when building against Mingw
 # they correspond to features not used by our host development tools
 # which are also hard or even impossible to port to native Win32
-nonWindowsSources := \
+libcutils_nonwindows_sources := \
         fs.c \
         multiuser.c \
         socket_inaddr_any_server.c \
@@ -47,8 +46,9 @@
         socket_loopback_server.c \
         socket_network_client.c \
         sockets.c \
+        str_parms.c \
 
-nonWindowsHostSources := \
+libcutils_nonwindows_host_sources := \
         ashmem-host.c \
         trace-host.c
 
@@ -56,24 +56,22 @@
 # Shared and static library for host
 # ========================================================
 LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(commonSources) dlmalloc_stubs.c
-LOCAL_SRC_FILES_darwin := $(nonWindowsSources) $(nonWindowsHostSources)
-LOCAL_SRC_FILES_linux := $(nonWindowsSources) $(nonWindowsHostSources)
+LOCAL_SRC_FILES := $(libcutils_common_sources) dlmalloc_stubs.c
+LOCAL_SRC_FILES_darwin := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
+LOCAL_SRC_FILES_linux := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
 LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS_darwin := -Werror -Wall -Wextra
-LOCAL_CFLAGS_linux := -Werror -Wall -Wextra
+LOCAL_CFLAGS := -Werror -Wall -Wextra
 LOCAL_MULTILIB := both
 LOCAL_MODULE_HOST_OS := darwin linux windows
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(commonSources) dlmalloc_stubs.c
-LOCAL_SRC_FILES_darwin := $(nonWindowsSources) $(nonWindowsHostSources)
-LOCAL_SRC_FILES_linux := $(nonWindowsSources) $(nonWindowsHostSources)
+LOCAL_SRC_FILES := $(libcutils_common_sources) dlmalloc_stubs.c
+LOCAL_SRC_FILES_darwin := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
+LOCAL_SRC_FILES_linux := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
 LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_CFLAGS_darwin := -Werror -Wall -Wextra
-LOCAL_CFLAGS_linux := -Werror -Wall -Wextra
+LOCAL_CFLAGS := -Werror -Wall -Wextra
 LOCAL_MULTILIB := both
 include $(BUILD_HOST_SHARED_LIBRARY)
 
@@ -84,8 +82,8 @@
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(commonSources) \
-        $(nonWindowsSources) \
+LOCAL_SRC_FILES := $(libcutils_common_sources) \
+        $(libcutils_nonwindows_sources) \
         android_reboot.c \
         ashmem-dev.c \
         debugger.c \
@@ -115,6 +113,9 @@
 ifneq ($(ENABLE_CPUSETS),)
 LOCAL_CFLAGS += -DUSE_CPUSETS
 endif
+ifneq ($(ENABLE_SCHEDBOOST),)
+LOCAL_CFLAGS += -DUSE_SCHEDBOOST
+endif
 LOCAL_CFLAGS += -Werror -Wall -Wextra -std=gnu90
 LOCAL_CLANG := true
 LOCAL_SANITIZE := integer
@@ -129,6 +130,9 @@
 ifneq ($(ENABLE_CPUSETS),)
 LOCAL_CFLAGS += -DUSE_CPUSETS
 endif
+ifneq ($(ENABLE_SCHEDBOOST),)
+LOCAL_CFLAGS += -DUSE_SCHEDBOOST
+endif
 LOCAL_CFLAGS += -Werror -Wall -Wextra
 LOCAL_C_INCLUDES := $(libcutils_c_includes)
 LOCAL_CLANG := true
diff --git a/libcutils/ashmem-host.c b/libcutils/ashmem-host.c
index abc4f94..15dd43e 100644
--- a/libcutils/ashmem-host.c
+++ b/libcutils/ashmem-host.c
@@ -43,11 +43,16 @@
     char template[PATH_MAX];
     snprintf(template, sizeof(template), "/tmp/android-ashmem-%d-XXXXXXXXX", getpid());
     int fd = mkstemp(template);
-    if (fd != -1 && TEMP_FAILURE_RETRY(ftruncate(fd, size)) != -1 && unlink(template) != -1) {
-        return fd;
+    if (fd == -1) return -1;
+
+    unlink(template);
+
+    if (TEMP_FAILURE_RETRY(ftruncate(fd, size)) == -1) {
+      close(fd);
+      return -1;
     }
-    close(fd);
-    return -1;
+
+    return fd;
 }
 
 int ashmem_set_prot_region(int fd __unused, int prot __unused)
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index f4454bb..645edd1 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -79,6 +79,7 @@
     { 00500, AID_ROOT,   AID_ROOT,   0, "config" },
     { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
     { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-ephemeral" },
     { 00771, AID_ROOT,   AID_ROOT,   0, "data/dalvik-cache" },
     { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
     { 00771, AID_SHELL,  AID_SHELL,  0, "data/local/tmp" },
@@ -126,18 +127,17 @@
     { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app/*" },
     { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  0, "data/media/*" },
     { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-private/*" },
+    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-ephemeral/*" },
     { 00644, AID_APP,       AID_APP,       0, "data/data/*" },
     { 00640, AID_ROOT,      AID_SHELL,     0, "data/nativetest/tests.txt" },
     { 00640, AID_ROOT,      AID_SHELL,     0, "data/nativetest64/tests.txt" },
     { 00750, AID_ROOT,      AID_SHELL,     0, "data/nativetest/*" },
     { 00750, AID_ROOT,      AID_SHELL,     0, "data/nativetest64/*" },
 
-    /* the following four files are INTENTIONALLY set-uid, but they
+    /* the following two files are INTENTIONALLY set-uid, but they
      * are NOT included on user builds. */
     { 04750, AID_ROOT,      AID_SHELL,     0, "system/xbin/su" },
-    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/librank" },
     { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procmem" },
-    { 04770, AID_ROOT,      AID_RADIO,     0, "system/bin/pppd-ril" },
 
     /* the following files have enhanced capabilities and ARE included in user builds. */
     { 00750, AID_ROOT,      AID_SHELL,     CAP_MASK_LONG(CAP_SETUID) | CAP_MASK_LONG(CAP_SETGID), "system/bin/run-as" },
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 298e3da..6bba3a7 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -64,6 +64,8 @@
 // File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
 static int bg_cpuset_fd = -1;
 static int fg_cpuset_fd = -1;
+static int bg_schedboost_fd = -1;
+static int fg_schedboost_fd = -1;
 #endif
 
 /* Add tid to the scheduling group defined by the policy */
@@ -128,6 +130,12 @@
         fg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
         filename = "/dev/cpuset/background/tasks";
         bg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+#ifdef USE_SCHEDBOOST
+        filename = "/sys/fs/cgroup/stune/foreground/tasks";
+        fg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
+        filename = "/sys/fs/cgroup/stune/tasks";
+        bg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
+#endif
     }
 #endif
 
@@ -253,17 +261,20 @@
     pthread_once(&the_once, __initialize);
 
     int fd;
+    int boost_fd;
     switch (policy) {
     case SP_BACKGROUND:
         fd = bg_cpuset_fd;
+        boost_fd = bg_schedboost_fd;
         break;
     case SP_FOREGROUND:
     case SP_AUDIO_APP:
     case SP_AUDIO_SYS:
         fd = fg_cpuset_fd;
+        boost_fd = fg_schedboost_fd;
         break;
     default:
-        fd = -1;
+        boost_fd = fd = -1;
         break;
     }
 
@@ -272,6 +283,11 @@
             return -errno;
     }
 
+    if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
+        if (errno != ESRCH && errno != ENOENT)
+            return -errno;
+    }
+
     return 0;
 #endif
 }
diff --git a/libcutils/socket_inaddr_any_server.c b/libcutils/socket_inaddr_any_server.c
index 7f0ccb8..e1b7d84 100644
--- a/libcutils/socket_inaddr_any_server.c
+++ b/libcutils/socket_inaddr_any_server.c
@@ -34,21 +34,21 @@
 /* open listen() port on any interface */
 int socket_inaddr_any_server(int port, int type)
 {
-    struct sockaddr_in addr;
+    struct sockaddr_in6 addr;
     int s, n;
 
     memset(&addr, 0, sizeof(addr));
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    addr.sin6_family = AF_INET6;
+    addr.sin6_port = htons(port);
+    addr.sin6_addr = in6addr_any;
 
-    s = socket(AF_INET, type, 0);
-    if(s < 0) return -1;
+    s = socket(AF_INET6, type, 0);
+    if (s < 0) return -1;
 
     n = 1;
     setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof(n));
 
-    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+    if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
         close(s);
         return -1;
     }
diff --git a/libcutils/trace-dev.c b/libcutils/trace-dev.c
index a06987e..f025256 100644
--- a/libcutils/trace-dev.c
+++ b/libcutils/trace-dev.c
@@ -104,7 +104,7 @@
 
     if (sys_debuggable || atrace_is_debuggable) {
         // Check whether tracing is enabled for this process.
-        FILE * file = fopen("/proc/self/cmdline", "r");
+        FILE * file = fopen("/proc/self/cmdline", "re");
         if (file) {
             char cmdline[4096];
             if (fgets(cmdline, sizeof(cmdline), file)) {
@@ -173,7 +173,7 @@
 
 static void atrace_init_once()
 {
-    atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY);
+    atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
     if (atrace_marker_fd == -1) {
         ALOGE("Error opening trace file: %s (%d)", strerror(errno), errno);
         atrace_enabled_tags = 0;
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 34e7f92..878feb8 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -52,6 +52,7 @@
         },
         windows: {
             srcs: ["uio.c"],
+            enabled: true,
         },
         not_windows: {
             srcs: ["event_tag_map.c"],
diff --git a/liblog/README b/liblog/README
index f29ac04..df1e68c 100644
--- a/liblog/README
+++ b/liblog/README
@@ -116,6 +116,10 @@
        code,  otherwise the  android_logger_list_read  call will block for new
        entries.
 
+       The  ANDROID_LOG_WRAP  mode flag to the  android_logger_list_alloc_time
+       signals  logd to quiesce  the reader until the buffer is about to prune
+       at the start time then proceed to dumping content.
+
        The  ANDROID_LOG_PSTORE mode flag to the android_logger_open is used to
        switch from the active logs to the persistent logs from before the last
        reboot.
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index e128edb..0f81efc 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -25,13 +25,18 @@
 
 static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
 
-static void lock()
+static int lock()
 {
     /*
      * If we trigger a signal handler in the middle of locked activity and the
      * signal handler logs a message, we could get into a deadlock state.
      */
-    pthread_mutex_lock(&lock_loggable);
+    /*
+     *  Any contention, and we can turn around and use the non-cached method
+     * in less time than the system call associated with a mutex to deal with
+     * the contention.
+     */
+    return pthread_mutex_trylock(&lock_loggable);
 }
 
 static void unlock()
@@ -42,9 +47,18 @@
 struct cache {
     const prop_info *pinfo;
     uint32_t serial;
-    char c;
+    unsigned char c;
 };
 
+static int check_cache(struct cache *cache)
+{
+    return cache->pinfo
+        && __system_property_serial(cache->pinfo) != cache->serial;
+}
+
+#define BOOLEAN_TRUE 0xFF
+#define BOOLEAN_FALSE 0xFE
+
 static void refresh_cache(struct cache *cache, const char *key)
 {
     uint32_t serial;
@@ -55,6 +69,7 @@
         if (!cache->pinfo) {
             return;
         }
+        cache->serial = -1;
     }
     serial = __system_property_serial(cache->pinfo);
     if (serial == cache->serial) {
@@ -62,7 +77,16 @@
     }
     cache->serial = serial;
     __system_property_read(cache->pinfo, 0, buf);
-    cache->c = buf[0];
+    switch(buf[0]) {
+    case 't': case 'T':
+        cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE;
+        break;
+    case 'f': case 'F':
+        cache->c = strcasecmp(buf + 1, "alse") ? buf[0] : BOOLEAN_FALSE;
+        break;
+    default:
+        cache->c = buf[0];
+    }
 }
 
 static int __android_log_level(const char *tag, int default_prio)
@@ -73,7 +97,7 @@
     /* calculate the size of our key temporary buffer */
     const size_t taglen = (tag && *tag) ? strlen(tag) : 0;
     /* sizeof(log_namespace) = strlen(log_namespace) + 1 */
-    char key[sizeof(log_namespace) + taglen];
+    char key[sizeof(log_namespace) + taglen]; /* may be > PROPERTY_KEY_MAX */
     char *kp;
     size_t i;
     char c = 0;
@@ -88,49 +112,77 @@
      */
     static char *last_tag;
     static uint32_t global_serial;
-    uint32_t current_global_serial;
-    static struct cache tag_cache[2] = {
-        { NULL, -1, 0 },
-        { NULL, -1, 0 }
-    };
-    static struct cache global_cache[2] = {
-        { NULL, -1, 0 },
-        { NULL, -1, 0 }
-    };
+    /* some compilers erroneously see uninitialized use. !not_locked */
+    uint32_t current_global_serial = 0;
+    static struct cache tag_cache[2];
+    static struct cache global_cache[2];
+    int change_detected;
+    int global_change_detected;
+    int not_locked;
 
     strcpy(key, log_namespace);
 
-    lock();
+    global_change_detected = change_detected = not_locked = lock();
 
-    current_global_serial = __system_property_area_serial();
+    if (!not_locked) {
+        /*
+         *  check all known serial numbers to changes.
+         */
+        for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
+            if (check_cache(&tag_cache[i])) {
+                change_detected = 1;
+            }
+        }
+        for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
+            if (check_cache(&global_cache[i])) {
+                global_change_detected = 1;
+            }
+        }
+
+        current_global_serial = __system_property_area_serial();
+        if (current_global_serial != global_serial) {
+            change_detected = 1;
+            global_change_detected = 1;
+        }
+    }
 
     if (taglen) {
-        uint32_t current_local_serial = current_global_serial;
-
-        if (!last_tag || (last_tag[0] != tag[0]) || strcmp(last_tag + 1, tag + 1)) {
-            /* invalidate log.tag.<tag> cache */
-            for(i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
-                tag_cache[i].pinfo = NULL;
-                tag_cache[i].serial = -1;
-                tag_cache[i].c = '\0';
+        int local_change_detected = change_detected;
+        if (!not_locked) {
+            if (!last_tag
+                    || (last_tag[0] != tag[0])
+                    || strcmp(last_tag + 1, tag + 1)) {
+                /* invalidate log.tag.<tag> cache */
+                for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
+                    tag_cache[i].pinfo = NULL;
+                    tag_cache[i].c = '\0';
+                }
+                free(last_tag);
+                last_tag = NULL;
+                local_change_detected = 1;
             }
-            free(last_tag);
-            last_tag = NULL;
-            current_global_serial = -1;
-        }
-        if (!last_tag) {
-            last_tag = strdup(tag);
+            if (!last_tag) {
+                last_tag = strdup(tag);
+            }
         }
         strcpy(key + sizeof(log_namespace) - 1, tag);
 
         kp = key;
-        for(i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
-            if (current_local_serial != global_serial) {
-                refresh_cache(&tag_cache[i], kp);
+        for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
+            struct cache *cache = &tag_cache[i];
+            struct cache temp_cache;
+
+            if (not_locked) {
+                temp_cache.pinfo = NULL;
+                temp_cache.c = '\0';
+                cache = &temp_cache;
+            }
+            if (local_change_detected) {
+                refresh_cache(cache, kp);
             }
 
-            if (tag_cache[i].c) {
-                c = tag_cache[i].c;
+            if (cache->c) {
+                c = cache->c;
                 break;
             }
 
@@ -147,19 +199,31 @@
     case 'F': /* Not officially supported */
     case 'A':
     case 'S':
+    case BOOLEAN_FALSE: /* Not officially supported */
         break;
     default:
         /* clear '.' after log.tag */
         key[sizeof(log_namespace) - 2] = '\0';
 
         kp = key;
-        for(i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
-            if (current_global_serial != global_serial) {
-                refresh_cache(&global_cache[i], kp);
+        for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
+            struct cache *cache = &global_cache[i];
+            struct cache temp_cache;
+
+            if (not_locked) {
+                temp_cache = *cache;
+                if (temp_cache.pinfo != cache->pinfo) { /* check atomic */
+                    temp_cache.pinfo = NULL;
+                    temp_cache.c = '\0';
+                }
+                cache = &temp_cache;
+            }
+            if (global_change_detected) {
+                refresh_cache(cache, kp);
             }
 
-            if (global_cache[i].c) {
-                c = global_cache[i].c;
+            if (cache->c) {
+                c = cache->c;
                 break;
             }
 
@@ -168,9 +232,10 @@
         break;
     }
 
-    global_serial = current_global_serial;
-
-    unlock();
+    if (!not_locked) {
+        global_serial = current_global_serial;
+        unlock();
+    }
 
     switch (toupper(c)) {
     case 'V': return ANDROID_LOG_VERBOSE;
@@ -180,6 +245,7 @@
     case 'E': return ANDROID_LOG_ERROR;
     case 'F': /* FALLTHRU */ /* Not officially supported */
     case 'A': return ANDROID_LOG_FATAL;
+    case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */
     case 'S': return -1; /* ANDROID_LOG_SUPPRESS */
     }
     return default_prio;
@@ -192,37 +258,103 @@
 }
 
 /*
- * Timestamp state generally remains constant, since a change is
- * rare, we can accept a trylock failure gracefully. Use a separate
- * lock from is_loggable to keep contention down b/25563384.
+ * For properties that are read often, but generally remain constant.
+ * Since a change is rare, we will accept a trylock failure gracefully.
+ * Use a separate lock from is_loggable to keep contention down b/25563384.
  */
-static pthread_mutex_t lock_timestamp = PTHREAD_MUTEX_INITIALIZER;
+struct cache2 {
+    pthread_mutex_t lock;
+    uint32_t serial;
+    const char *key_persist;
+    struct cache cache_persist;
+    const char *key_ro;
+    struct cache cache_ro;
+    unsigned char (*const evaluate)(const struct cache2 *self);
+};
 
-char android_log_timestamp()
+static inline unsigned char do_cache2(struct cache2 *self)
 {
-    static struct cache r_time_cache = { NULL, -1, 0 };
-    static struct cache p_time_cache = { NULL, -1, 0 };
-    char retval;
+    uint32_t current_serial;
+    int change_detected;
+    unsigned char c;
 
-    if (pthread_mutex_trylock(&lock_timestamp)) {
+    if (pthread_mutex_trylock(&self->lock)) {
         /* We are willing to accept some race in this context */
-        if (!(retval = p_time_cache.c)) {
-            retval = r_time_cache.c;
-        }
-    } else {
-        static uint32_t serial;
-        uint32_t current_serial = __system_property_area_serial();
-        if (current_serial != serial) {
-            refresh_cache(&r_time_cache, "ro.logd.timestamp");
-            refresh_cache(&p_time_cache, "persist.logd.timestamp");
-            serial = current_serial;
-        }
-        if (!(retval = p_time_cache.c)) {
-            retval = r_time_cache.c;
-        }
-
-        pthread_mutex_unlock(&lock_timestamp);
+        return self->evaluate(self);
     }
 
-    return tolower(retval ?: 'r');
+    change_detected = check_cache(&self->cache_persist)
+                   || check_cache(&self->cache_ro);
+    current_serial = __system_property_area_serial();
+    if (current_serial != self->serial) {
+        change_detected = 1;
+    }
+    if (change_detected) {
+        refresh_cache(&self->cache_persist, self->key_persist);
+        refresh_cache(&self->cache_ro, self->key_ro);
+        self->serial = current_serial;
+    }
+    c = self->evaluate(self);
+
+    pthread_mutex_unlock(&self->lock);
+
+    return c;
+}
+
+static unsigned char evaluate_persist_ro(const struct cache2 *self)
+{
+    unsigned char c = self->cache_persist.c;
+
+    if (c) {
+        return c;
+    }
+
+    return self->cache_ro.c;
+}
+
+/*
+ * Timestamp state generally remains constant, but can change at any time
+ * to handle developer requirements.
+ */
+clockid_t android_log_clockid()
+{
+    static struct cache2 clockid = {
+        PTHREAD_MUTEX_INITIALIZER,
+        0,
+        "persist.logd.timestamp",
+        { NULL, -1, '\0' },
+        "ro.logd.timestamp",
+        { NULL, -1, '\0' },
+        evaluate_persist_ro
+    };
+
+    return (tolower(do_cache2(&clockid)) == 'm')
+        ? CLOCK_MONOTONIC
+        : CLOCK_REALTIME;
+}
+
+/*
+ * Security state generally remains constant, but the DO must be able
+ * to turn off logging should it become spammy after an attack is detected.
+ */
+static unsigned char evaluate_security(const struct cache2 *self)
+{
+    unsigned char c = self->cache_ro.c;
+
+    return (c != BOOLEAN_FALSE) && c && (self->cache_persist.c == BOOLEAN_TRUE);
+}
+
+int __android_log_security()
+{
+    static struct cache2 security = {
+        PTHREAD_MUTEX_INITIALIZER,
+        0,
+        "persist.logd.security",
+        { NULL, -1, BOOLEAN_FALSE },
+        "ro.device_owner",
+        { NULL, -1, BOOLEAN_FALSE },
+        evaluate_security
+    };
+
+    return do_cache2(&security);
 }
diff --git a/liblog/log_read.c b/liblog/log_read.c
index cfc8a7a..1aff272 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -208,6 +208,7 @@
     [LOG_ID_EVENTS] = "events",
     [LOG_ID_SYSTEM] = "system",
     [LOG_ID_CRASH] = "crash",
+    [LOG_ID_SECURITY] = "security",
     [LOG_ID_KERNEL] = "kernel",
 };
 
@@ -500,6 +501,14 @@
         remaining -= n;
         cp += n;
     }
+
+    if (logger_list->pid) {
+        n = snprintf(cp, remaining, " pid=%u", logger_list->pid);
+        n = min(n, remaining);
+        remaining -= n;
+        cp += n;
+    }
+
     return send_log_msg(NULL, NULL, buf, len);
 }
 
@@ -634,6 +643,7 @@
         android_log_header_t l;
     } buf;
     static uint8_t preread_count;
+    bool is_system;
 
     memset(log_msg, 0, sizeof(*log_msg));
 
@@ -690,12 +700,15 @@
             }
 
             uid = get_best_effective_uid();
-            if (!uid_has_log_permission(uid) && (uid != buf.p.uid)) {
+            is_system = uid_has_log_permission(uid);
+            if (!is_system && (uid != buf.p.uid)) {
                 break;
             }
 
             ret = TEMP_FAILURE_RETRY(read(logger_list->sock,
-                                          log_msg->entry_v3.msg,
+                                          is_system ?
+                                              log_msg->entry_v4.msg :
+                                              log_msg->entry_v3.msg,
                                           buf.p.len - sizeof(buf)));
             if (ret < 0) {
                 return -errno;
@@ -704,13 +717,18 @@
                 return -EIO;
             }
 
-            log_msg->entry_v3.len = buf.p.len - sizeof(buf);
-            log_msg->entry_v3.hdr_size = sizeof(log_msg->entry_v3);
-            log_msg->entry_v3.pid = buf.p.pid;
-            log_msg->entry_v3.tid = buf.l.tid;
-            log_msg->entry_v3.sec = buf.l.realtime.tv_sec;
-            log_msg->entry_v3.nsec = buf.l.realtime.tv_nsec;
-            log_msg->entry_v3.lid = buf.l.id;
+            log_msg->entry_v4.len = buf.p.len - sizeof(buf);
+            log_msg->entry_v4.hdr_size = is_system ?
+                sizeof(log_msg->entry_v4) :
+                sizeof(log_msg->entry_v3);
+            log_msg->entry_v4.pid = buf.p.pid;
+            log_msg->entry_v4.tid = buf.l.tid;
+            log_msg->entry_v4.sec = buf.l.realtime.tv_sec;
+            log_msg->entry_v4.nsec = buf.l.realtime.tv_nsec;
+            log_msg->entry_v4.lid = buf.l.id;
+            if (is_system) {
+                log_msg->entry_v4.uid = buf.p.uid;
+            }
 
             return ret;
         }
@@ -797,6 +815,14 @@
         }
 
         if (logger_list->start.tv_sec || logger_list->start.tv_nsec) {
+            if (logger_list->mode & ANDROID_LOG_WRAP) {
+                // ToDo: alternate API to allow timeout to be adjusted.
+                ret = snprintf(cp, remaining, " timeout=%u",
+                               ANDROID_LOG_WRAP_DEFAULT_TIMEOUT);
+                ret = min(ret, remaining);
+                remaining -= ret;
+                cp += ret;
+            }
             ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32,
                            logger_list->start.tv_sec,
                            logger_list->start.tv_nsec);
@@ -862,18 +888,10 @@
             sigaction(SIGALRM, &old_sigaction, NULL);
         }
 
-        if (ret <= 0) {
-            if ((ret == -1) && e) {
-                return -e;
-            }
-            return ret;
+        if ((ret == -1) && e) {
+            return -e;
         }
-
-        logger_for_each(logger, logger_list) {
-            if (log_msg->entry.lid == logger->id) {
-                return ret;
-            }
-        }
+        return ret;
     }
     /* NOTREACH */
     return ret;
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 83c6dc2..c2b0ec2 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -84,7 +84,7 @@
 #endif  /* !defined(_WIN32) */
 
 #if FAKE_LOG_DEVICE
-static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 };
+static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1, -1 };
 #else
 static int logd_fd = -1;
 static int pstore_fd = -1;
@@ -181,6 +181,7 @@
     static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
     static pid_t last_pid = (pid_t) -1;
     static atomic_int_fast32_t dropped;
+    static atomic_int_fast32_t dropped_security;
 
     if (!nr) {
         return -EINVAL;
@@ -192,6 +193,23 @@
     if (last_pid == (pid_t) -1) {
         last_pid = getpid();
     }
+    if (log_id == LOG_ID_SECURITY) {
+        if ((last_uid != AID_SYSTEM) && (last_uid != AID_ROOT)) {
+            uid_t uid = geteuid();
+            if ((uid != AID_SYSTEM) && (uid != AID_ROOT)) {
+                gid_t gid = getgid();
+                if ((gid != AID_SYSTEM) && (gid != AID_ROOT)) {
+                    gid = getegid();
+                    if ((gid != AID_SYSTEM) && (gid != AID_ROOT)) {
+                        return -EPERM;
+                    }
+                }
+            }
+        }
+        if (!__android_log_security()) {
+            return -EPERM;
+        }
+    }
     /*
      *  struct {
      *      // what we provide to pstore
@@ -212,11 +230,7 @@
      *  };
      */
 
-    if (android_log_timestamp() == 'm') {
-        clock_gettime(CLOCK_MONOTONIC, &ts);
-    } else {
-        clock_gettime(CLOCK_REALTIME, &ts);
-    }
+    clock_gettime(android_log_clockid(), &ts);
 
     pmsg_header.magic = LOGGER_MAGIC;
     pmsg_header.len = sizeof(pmsg_header) + sizeof(header);
@@ -233,7 +247,26 @@
     newVec[1].iov_len    = sizeof(header);
 
     if (logd_fd > 0) {
-        int32_t snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
+        int32_t snapshot = atomic_exchange_explicit(&dropped_security, 0,
+                                                    memory_order_relaxed);
+        if (snapshot) {
+            android_log_event_int_t buffer;
+
+            header.id = LOG_ID_SECURITY;
+            buffer.header.tag = htole32(LIBLOG_LOG_TAG);
+            buffer.payload.type = EVENT_TYPE_INT;
+            buffer.payload.data = htole32(snapshot);
+
+            newVec[2].iov_base = &buffer;
+            newVec[2].iov_len  = sizeof(buffer);
+
+            ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
+            if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+                atomic_fetch_add_explicit(&dropped_security, snapshot,
+                                          memory_order_relaxed);
+            }
+        }
+        snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
         if (snapshot) {
             android_log_event_int_t buffer;
 
@@ -247,7 +280,8 @@
 
             ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
             if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
-                atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
+                atomic_fetch_add_explicit(&dropped, snapshot,
+                                          memory_order_relaxed);
             }
         }
     }
@@ -319,6 +353,10 @@
         ret -= sizeof(header);
     } else if (ret == -EAGAIN) {
         atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
+        if (log_id == LOG_ID_SECURITY) {
+            atomic_fetch_add_explicit(&dropped_security, 1,
+                                      memory_order_relaxed);
+        }
     }
 #endif
 
@@ -332,6 +370,7 @@
     [LOG_ID_EVENTS] = "events",
     [LOG_ID_SYSTEM] = "system",
     [LOG_ID_CRASH] = "crash",
+    [LOG_ID_SECURITY] = "security",
     [LOG_ID_KERNEL] = "kernel",
 };
 
@@ -487,6 +526,18 @@
     return write_to_log(LOG_ID_EVENTS, vec, 2);
 }
 
+int __android_log_security_bwrite(int32_t tag, const void *payload, size_t len)
+{
+    struct iovec vec[2];
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = (void*)payload;
+    vec[1].iov_len = len;
+
+    return write_to_log(LOG_ID_SECURITY, vec, 2);
+}
+
 /*
  * Like __android_log_bwrite, but takes the type as well.  Doesn't work
  * for the general case where we're generating lists of stuff, but very
diff --git a/liblog/logprint.c b/liblog/logprint.c
index ebf9786..bd36cdd 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -32,6 +32,7 @@
 #include <cutils/list.h>
 #include <log/logd.h>
 #include <log/logprint.h>
+#include <private/android_filesystem_config.h>
 
 #define MS_PER_NSEC 1000000
 #define US_PER_NSEC 1000
@@ -56,6 +57,7 @@
     bool zone_output;
     bool epoch_output;
     bool monotonic_output;
+    bool uid_output;
 };
 
 /*
@@ -203,7 +205,8 @@
     p_ret->year_output = false;
     p_ret->zone_output = false;
     p_ret->epoch_output = false;
-    p_ret->monotonic_output = android_log_timestamp() == 'm';
+    p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC;
+    p_ret->uid_output = false;
 
     return p_ret;
 }
@@ -258,6 +261,9 @@
     case FORMAT_MODIFIER_MONOTONIC:
         p_format->monotonic_output = true;
         return 0;
+    case FORMAT_MODIFIER_UID:
+        p_format->uid_output = true;
+        return 0;
     default:
         break;
     }
@@ -290,6 +296,7 @@
     else if (strcmp(formatString, "zone") == 0) format = FORMAT_MODIFIER_ZONE;
     else if (strcmp(formatString, "epoch") == 0) format = FORMAT_MODIFIER_EPOCH;
     else if (strcmp(formatString, "monotonic") == 0) format = FORMAT_MODIFIER_MONOTONIC;
+    else if (strcmp(formatString, "uid") == 0) format = FORMAT_MODIFIER_UID;
     else {
         extern char *tzname[2];
         static const char gmt[] = "GMT";
@@ -451,6 +458,7 @@
 {
     entry->tv_sec = buf->sec;
     entry->tv_nsec = buf->nsec;
+    entry->uid = -1;
     entry->pid = buf->pid;
     entry->tid = buf->tid;
 
@@ -482,6 +490,9 @@
     struct logger_entry_v2 *buf2 = (struct logger_entry_v2 *)buf;
     if (buf2->hdr_size) {
         msg = ((char *)buf2) + buf2->hdr_size;
+        if (buf2->hdr_size >= sizeof(struct logger_entry_v4)) {
+            entry->uid = ((struct logger_entry_v4 *)buf)->uid;
+        }
     }
     for (i = 1; i < buf->len; i++) {
         if (msg[i] == '\0') {
@@ -500,14 +511,14 @@
     }
     if (msgEnd == -1) {
         /* incoming message not null-terminated; force it */
-        msgEnd = buf->len - 1;
+        msgEnd = buf->len - 1; /* may result in msgEnd < msgStart */
         msg[msgEnd] = '\0';
     }
 
     entry->priority = msg[0];
     entry->tag = msg + 1;
     entry->message = msg + msgStart;
-    entry->messageLen = msgEnd - msgStart;
+    entry->messageLen = (msgEnd < msgStart) ? 0 : (msgEnd - msgStart);
 
     return 0;
 }
@@ -734,16 +745,25 @@
     entry->tv_sec = buf->sec;
     entry->tv_nsec = buf->nsec;
     entry->priority = ANDROID_LOG_INFO;
+    entry->uid = -1;
     entry->pid = buf->pid;
     entry->tid = buf->tid;
 
     /*
-     * Pull the tag out.
+     * Pull the tag out, fill in some additional details based on incoming
+     * buffer version (v3 adds lid, v4 adds uid).
      */
     eventData = (const unsigned char*) buf->msg;
     struct logger_entry_v2 *buf2 = (struct logger_entry_v2 *)buf;
     if (buf2->hdr_size) {
         eventData = ((unsigned char *)buf2) + buf2->hdr_size;
+        if ((buf2->hdr_size >= sizeof(struct logger_entry_v3)) &&
+                (((struct logger_entry_v3 *)buf)->lid == LOG_ID_SECURITY)) {
+            entry->priority = ANDROID_LOG_WARN;
+        }
+        if (buf2->hdr_size >= sizeof(struct logger_entry_v4)) {
+            entry->uid = ((struct logger_entry_v4 *)buf)->uid;
+        }
     }
     inCount = buf->len;
     if (inCount < 4)
@@ -1238,7 +1258,7 @@
     char prefixBuf[128], suffixBuf[128];
     char priChar;
     int prefixSuffixIsHeaderFooter = 0;
-    char *ret = NULL;
+    char *ret;
     time_t now;
     unsigned long nsec;
 
@@ -1262,7 +1282,7 @@
     nsec = entry->tv_nsec;
     if (p_format->monotonic_output) {
         // prevent convertMonotonic from being called if logd is monotonic
-        if (android_log_timestamp() != 'm') {
+        if (android_log_clockid() != CLOCK_MONOTONIC) {
             struct timespec time;
             convertMonotonic(&time, entry);
             now = time.tv_sec;
@@ -1310,6 +1330,30 @@
         suffixLen = MIN(suffixLen, sizeof(suffixBuf));
     }
 
+    char uid[16];
+    uid[0] = '\0';
+    if (p_format->uid_output) {
+        if (entry->uid >= 0) {
+            const struct android_id_info *info = android_ids;
+            size_t i;
+
+            for (i = 0; i < android_id_count; ++i) {
+                if (info->aid == (unsigned int)entry->uid) {
+                    break;
+                }
+                ++info;
+            }
+            if ((i < android_id_count) && (strlen(info->name) <= 5)) {
+                 snprintf(uid, sizeof(uid), "%5s:", info->name);
+            } else {
+                 // Not worth parsing package list, names all longer than 5
+                 snprintf(uid, sizeof(uid), "%5d:", entry->uid);
+            }
+        } else {
+            snprintf(uid, sizeof(uid), "      ");
+        }
+    }
+
     switch (p_format->format) {
         case FORMAT_TAG:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
@@ -1322,11 +1366,11 @@
                 "  (%s)\n", entry->tag);
             suffixLen += MIN(len, sizeof(suffixBuf) - suffixLen);
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%c(%5d) ", priChar, entry->pid);
+                "%c(%s%5d) ", priChar, uid, entry->pid);
             break;
         case FORMAT_THREAD:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%c(%5d:%5d) ", priChar, entry->pid, entry->tid);
+                "%c(%s%5d:%5d) ", priChar, uid, entry->pid, entry->tid);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
@@ -1338,21 +1382,26 @@
             break;
         case FORMAT_TIME:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%s %c/%-8s(%5d): ", timeBuf, priChar, entry->tag, entry->pid);
+                "%s %c/%-8s(%s%5d): ", timeBuf, priChar, entry->tag,
+                uid, entry->pid);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
         case FORMAT_THREADTIME:
+            ret = strchr(uid, ':');
+            if (ret) {
+                *ret = ' ';
+            }
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%s %5d %5d %c %-8s: ", timeBuf,
-                entry->pid, entry->tid, priChar, entry->tag);
+                "%s %s%5d %5d %c %-8s: ", timeBuf,
+                uid, entry->pid, entry->tid, priChar, entry->tag);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
         case FORMAT_LONG:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "[ %s %5d:%5d %c/%-8s ]\n",
-                timeBuf, entry->pid, entry->tid, priChar, entry->tag);
+                "[ %s %s%5d:%5d %c/%-8s ]\n",
+                timeBuf, uid, entry->pid, entry->tid, priChar, entry->tag);
             strcpy(suffixBuf + suffixLen, "\n\n");
             suffixLen += 2;
             prefixSuffixIsHeaderFooter = 1;
@@ -1360,7 +1409,7 @@
         case FORMAT_BRIEF:
         default:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%c/%-8s(%5d): ", priChar, entry->tag, entry->pid);
+                "%c/%-8s(%s%5d): ", priChar, entry->tag, uid, entry->pid);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index b594634..01fb50f 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -14,11 +14,17 @@
  * limitations under the License.
  */
 
+#include <fcntl.h>
+#include <sys/endian.h>
 #include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
 #include <cutils/sockets.h>
 #include <log/log.h>
 #include <log/logger.h>
 #include <log/log_read.h>
+#include <private/android_logger.h>
 
 #include "benchmark.h"
 
@@ -85,6 +91,380 @@
 BENCHMARK(BM_clock_overhead);
 
 /*
+ * Measure the time it takes to submit the android logging data to pstore
+ */
+static void BM_pmsg_short(int iters) {
+
+    int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+    if (pstore_fd < 0) {
+        return;
+    }
+
+    /*
+     *  struct {
+     *      // what we provide to pstore
+     *      android_pmsg_log_header_t pmsg_header;
+     *      // what we provide to socket
+     *      android_log_header_t header;
+     *      // caller provides
+     *      union {
+     *          struct {
+     *              char     prio;
+     *              char     payload[];
+     *          } string;
+     *          struct {
+     *              uint32_t tag
+     *              char     payload[];
+     *          } binary;
+     *      };
+     *  };
+     */
+
+    struct timespec ts;
+    clock_gettime(android_log_clockid(), &ts);
+
+    android_pmsg_log_header_t pmsg_header;
+    pmsg_header.magic = LOGGER_MAGIC;
+    pmsg_header.len = sizeof(android_pmsg_log_header_t)
+                    + sizeof(android_log_header_t);
+    pmsg_header.uid = getuid();
+    pmsg_header.pid = getpid();
+
+    android_log_header_t header;
+    header.tid = gettid();
+    header.realtime.tv_sec = ts.tv_sec;
+    header.realtime.tv_nsec = ts.tv_nsec;
+
+    static const unsigned nr = 1;
+    static const unsigned header_length = 2;
+    struct iovec newVec[nr + header_length];
+
+    newVec[0].iov_base   = (unsigned char *) &pmsg_header;
+    newVec[0].iov_len    = sizeof(pmsg_header);
+    newVec[1].iov_base   = (unsigned char *) &header;
+    newVec[1].iov_len    = sizeof(header);
+
+    android_log_event_int_t buffer;
+
+    header.id = LOG_ID_EVENTS;
+    buffer.header.tag = 0;
+    buffer.payload.type = EVENT_TYPE_INT;
+    uint32_t snapshot = 0;
+    buffer.payload.data = htole32(snapshot);
+
+    newVec[2].iov_base = &buffer;
+    newVec[2].iov_len  = sizeof(buffer);
+
+    StartBenchmarkTiming();
+    for (int i = 0; i < iters; ++i) {
+        ++snapshot;
+        buffer.payload.data = htole32(snapshot);
+        writev(pstore_fd, newVec, nr);
+    }
+    StopBenchmarkTiming();
+    close(pstore_fd);
+}
+BENCHMARK(BM_pmsg_short);
+
+/*
+ * Measure the time it takes to submit the android logging data to pstore
+ * best case aligned single block.
+ */
+static void BM_pmsg_short_aligned(int iters) {
+
+    int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+    if (pstore_fd < 0) {
+        return;
+    }
+
+    /*
+     *  struct {
+     *      // what we provide to pstore
+     *      android_pmsg_log_header_t pmsg_header;
+     *      // what we provide to socket
+     *      android_log_header_t header;
+     *      // caller provides
+     *      union {
+     *          struct {
+     *              char     prio;
+     *              char     payload[];
+     *          } string;
+     *          struct {
+     *              uint32_t tag
+     *              char     payload[];
+     *          } binary;
+     *      };
+     *  };
+     */
+
+    struct timespec ts;
+    clock_gettime(android_log_clockid(), &ts);
+
+    struct packet {
+        android_pmsg_log_header_t pmsg_header;
+        android_log_header_t header;
+        android_log_event_int_t payload;
+    };
+    char buf[sizeof(struct packet) + 8] __aligned(8);
+    memset(buf, 0, sizeof(buf));
+    struct packet *buffer = (struct packet*)(((uintptr_t)buf + 7) & ~7);
+    if (((uintptr_t)&buffer->pmsg_header) & 7) {
+        fprintf (stderr, "&buffer=0x%p iters=%d\n", &buffer->pmsg_header, iters);
+    }
+
+    buffer->pmsg_header.magic = LOGGER_MAGIC;
+    buffer->pmsg_header.len = sizeof(android_pmsg_log_header_t)
+                            + sizeof(android_log_header_t);
+    buffer->pmsg_header.uid = getuid();
+    buffer->pmsg_header.pid = getpid();
+
+    buffer->header.tid = gettid();
+    buffer->header.realtime.tv_sec = ts.tv_sec;
+    buffer->header.realtime.tv_nsec = ts.tv_nsec;
+
+    buffer->header.id = LOG_ID_EVENTS;
+    buffer->payload.header.tag = 0;
+    buffer->payload.payload.type = EVENT_TYPE_INT;
+    uint32_t snapshot = 0;
+    buffer->payload.payload.data = htole32(snapshot);
+
+    StartBenchmarkTiming();
+    for (int i = 0; i < iters; ++i) {
+        ++snapshot;
+        buffer->payload.payload.data = htole32(snapshot);
+        write(pstore_fd, &buffer->pmsg_header,
+            sizeof(android_pmsg_log_header_t) +
+            sizeof(android_log_header_t) +
+            sizeof(android_log_event_int_t));
+    }
+    StopBenchmarkTiming();
+    close(pstore_fd);
+}
+BENCHMARK(BM_pmsg_short_aligned);
+
+/*
+ * Measure the time it takes to submit the android logging data to pstore
+ * best case aligned single block.
+ */
+static void BM_pmsg_short_unaligned1(int iters) {
+
+    int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+    if (pstore_fd < 0) {
+        return;
+    }
+
+    /*
+     *  struct {
+     *      // what we provide to pstore
+     *      android_pmsg_log_header_t pmsg_header;
+     *      // what we provide to socket
+     *      android_log_header_t header;
+     *      // caller provides
+     *      union {
+     *          struct {
+     *              char     prio;
+     *              char     payload[];
+     *          } string;
+     *          struct {
+     *              uint32_t tag
+     *              char     payload[];
+     *          } binary;
+     *      };
+     *  };
+     */
+
+    struct timespec ts;
+    clock_gettime(android_log_clockid(), &ts);
+
+    struct packet {
+        android_pmsg_log_header_t pmsg_header;
+        android_log_header_t header;
+        android_log_event_int_t payload;
+    };
+    char buf[sizeof(struct packet) + 8] __aligned(8);
+    memset(buf, 0, sizeof(buf));
+    struct packet *buffer = (struct packet*)((((uintptr_t)buf + 7) & ~7) + 1);
+    if ((((uintptr_t)&buffer->pmsg_header) & 7) != 1) {
+        fprintf (stderr, "&buffer=0x%p iters=%d\n", &buffer->pmsg_header, iters);
+    }
+
+    buffer->pmsg_header.magic = LOGGER_MAGIC;
+    buffer->pmsg_header.len = sizeof(android_pmsg_log_header_t)
+                            + sizeof(android_log_header_t);
+    buffer->pmsg_header.uid = getuid();
+    buffer->pmsg_header.pid = getpid();
+
+    buffer->header.tid = gettid();
+    buffer->header.realtime.tv_sec = ts.tv_sec;
+    buffer->header.realtime.tv_nsec = ts.tv_nsec;
+
+    buffer->header.id = LOG_ID_EVENTS;
+    buffer->payload.header.tag = 0;
+    buffer->payload.payload.type = EVENT_TYPE_INT;
+    uint32_t snapshot = 0;
+    buffer->payload.payload.data = htole32(snapshot);
+
+    StartBenchmarkTiming();
+    for (int i = 0; i < iters; ++i) {
+        ++snapshot;
+        buffer->payload.payload.data = htole32(snapshot);
+        write(pstore_fd, &buffer->pmsg_header,
+            sizeof(android_pmsg_log_header_t) +
+            sizeof(android_log_header_t) +
+            sizeof(android_log_event_int_t));
+    }
+    StopBenchmarkTiming();
+    close(pstore_fd);
+}
+BENCHMARK(BM_pmsg_short_unaligned1);
+
+/*
+ * Measure the time it takes to submit the android logging data to pstore
+ * best case aligned single block.
+ */
+static void BM_pmsg_long_aligned(int iters) {
+
+    int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+    if (pstore_fd < 0) {
+        return;
+    }
+
+    /*
+     *  struct {
+     *      // what we provide to pstore
+     *      android_pmsg_log_header_t pmsg_header;
+     *      // what we provide to socket
+     *      android_log_header_t header;
+     *      // caller provides
+     *      union {
+     *          struct {
+     *              char     prio;
+     *              char     payload[];
+     *          } string;
+     *          struct {
+     *              uint32_t tag
+     *              char     payload[];
+     *          } binary;
+     *      };
+     *  };
+     */
+
+    struct timespec ts;
+    clock_gettime(android_log_clockid(), &ts);
+
+    struct packet {
+        android_pmsg_log_header_t pmsg_header;
+        android_log_header_t header;
+        android_log_event_int_t payload;
+    };
+    char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD] __aligned(8);
+    memset(buf, 0, sizeof(buf));
+    struct packet *buffer = (struct packet*)(((uintptr_t)buf + 7) & ~7);
+    if (((uintptr_t)&buffer->pmsg_header) & 7) {
+        fprintf (stderr, "&buffer=0x%p iters=%d\n", &buffer->pmsg_header, iters);
+    }
+
+    buffer->pmsg_header.magic = LOGGER_MAGIC;
+    buffer->pmsg_header.len = sizeof(android_pmsg_log_header_t)
+                            + sizeof(android_log_header_t);
+    buffer->pmsg_header.uid = getuid();
+    buffer->pmsg_header.pid = getpid();
+
+    buffer->header.tid = gettid();
+    buffer->header.realtime.tv_sec = ts.tv_sec;
+    buffer->header.realtime.tv_nsec = ts.tv_nsec;
+
+    buffer->header.id = LOG_ID_EVENTS;
+    buffer->payload.header.tag = 0;
+    buffer->payload.payload.type = EVENT_TYPE_INT;
+    uint32_t snapshot = 0;
+    buffer->payload.payload.data = htole32(snapshot);
+
+    StartBenchmarkTiming();
+    for (int i = 0; i < iters; ++i) {
+        ++snapshot;
+        buffer->payload.payload.data = htole32(snapshot);
+        write(pstore_fd, &buffer->pmsg_header, LOGGER_ENTRY_MAX_PAYLOAD);
+    }
+    StopBenchmarkTiming();
+    close(pstore_fd);
+}
+BENCHMARK(BM_pmsg_long_aligned);
+
+/*
+ * Measure the time it takes to submit the android logging data to pstore
+ * best case aligned single block.
+ */
+static void BM_pmsg_long_unaligned1(int iters) {
+
+    int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+    if (pstore_fd < 0) {
+        return;
+    }
+
+    /*
+     *  struct {
+     *      // what we provide to pstore
+     *      android_pmsg_log_header_t pmsg_header;
+     *      // what we provide to socket
+     *      android_log_header_t header;
+     *      // caller provides
+     *      union {
+     *          struct {
+     *              char     prio;
+     *              char     payload[];
+     *          } string;
+     *          struct {
+     *              uint32_t tag
+     *              char     payload[];
+     *          } binary;
+     *      };
+     *  };
+     */
+
+    struct timespec ts;
+    clock_gettime(android_log_clockid(), &ts);
+
+    struct packet {
+        android_pmsg_log_header_t pmsg_header;
+        android_log_header_t header;
+        android_log_event_int_t payload;
+    };
+    char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD] __aligned(8);
+    memset(buf, 0, sizeof(buf));
+    struct packet *buffer = (struct packet*)((((uintptr_t)buf + 7) & ~7) + 1);
+    if ((((uintptr_t)&buffer->pmsg_header) & 7) != 1) {
+        fprintf (stderr, "&buffer=0x%p iters=%d\n", &buffer->pmsg_header, iters);
+    }
+
+    buffer->pmsg_header.magic = LOGGER_MAGIC;
+    buffer->pmsg_header.len = sizeof(android_pmsg_log_header_t)
+                            + sizeof(android_log_header_t);
+    buffer->pmsg_header.uid = getuid();
+    buffer->pmsg_header.pid = getpid();
+
+    buffer->header.tid = gettid();
+    buffer->header.realtime.tv_sec = ts.tv_sec;
+    buffer->header.realtime.tv_nsec = ts.tv_nsec;
+
+    buffer->header.id = LOG_ID_EVENTS;
+    buffer->payload.header.tag = 0;
+    buffer->payload.payload.type = EVENT_TYPE_INT;
+    uint32_t snapshot = 0;
+    buffer->payload.payload.data = htole32(snapshot);
+
+    StartBenchmarkTiming();
+    for (int i = 0; i < iters; ++i) {
+        ++snapshot;
+        buffer->payload.payload.data = htole32(snapshot);
+        write(pstore_fd, &buffer->pmsg_header, LOGGER_ENTRY_MAX_PAYLOAD);
+    }
+    StopBenchmarkTiming();
+    close(pstore_fd);
+}
+BENCHMARK(BM_pmsg_long_unaligned1);
+
+/*
  *	Measure the time it takes to submit the android logging call using
  * discrete acquisition under light load. Expect this to be a dozen or so
  * syscall periods (40us).
@@ -280,3 +660,31 @@
     StopBenchmarkTiming();
 }
 BENCHMARK(BM_is_loggable);
+
+/*
+ *	Measure the time it takes for android_log_clockid.
+ */
+static void BM_clockid(int iters) {
+    StartBenchmarkTiming();
+
+    for (int i = 0; i < iters; ++i) {
+        android_log_clockid();
+    }
+
+    StopBenchmarkTiming();
+}
+BENCHMARK(BM_clockid);
+
+/*
+ *	Measure the time it takes for __android_log_security.
+ */
+static void BM_security(int iters) {
+    StartBenchmarkTiming();
+
+    for (int i = 0; i < iters; ++i) {
+        __android_log_security();
+    }
+
+    StopBenchmarkTiming();
+}
+BENCHMARK(BM_security);
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index c987041..50afc5f 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -25,6 +25,7 @@
 #include <log/logger.h>
 #include <log/log_read.h>
 #include <log/logprint.h>
+#include <private/android_logger.h>
 
 // enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
 // non-syscall libs. Since we are only using this in the emergency of
@@ -164,6 +165,133 @@
     android_logger_list_close(logger_list);
 }
 
+TEST(liblog, __security) {
+    static const char persist_key[] = "persist.logd.security";
+    static const char readonly_key[] = "ro.device_owner";
+    static const char nothing_val[] = "_NOTHING_TO_SEE_HERE_";
+    char persist[PROP_VALUE_MAX];
+    char readonly[PROP_VALUE_MAX];
+
+    property_get(persist_key, persist, "");
+    property_get(readonly_key, readonly, nothing_val);
+
+    if (!strcmp(readonly, nothing_val)) {
+        EXPECT_FALSE(__android_log_security());
+        fprintf(stderr, "Warning, setting ro.device_owner to a domain\n");
+        property_set(readonly_key, "com.google.android.SecOps.DeviceOwner");
+    } else if (!strcasecmp(readonly, "false") || !readonly[0]) {
+        EXPECT_FALSE(__android_log_security());
+        return;
+    }
+
+    if (!strcasecmp(persist, "true")) {
+        EXPECT_TRUE(__android_log_security());
+    } else {
+        EXPECT_FALSE(__android_log_security());
+    }
+    property_set(persist_key, "TRUE");
+    EXPECT_TRUE(__android_log_security());
+    property_set(persist_key, "FALSE");
+    EXPECT_FALSE(__android_log_security());
+    property_set(persist_key, "true");
+    EXPECT_TRUE(__android_log_security());
+    property_set(persist_key, "false");
+    EXPECT_FALSE(__android_log_security());
+    property_set(persist_key, "");
+    EXPECT_FALSE(__android_log_security());
+    property_set(persist_key, persist);
+}
+
+TEST(liblog, __security_buffer) {
+    struct logger_list *logger_list;
+    android_event_long_t buffer;
+
+    static const char persist_key[] = "persist.logd.security";
+    char persist[PROP_VALUE_MAX];
+    bool set_persist = false;
+    bool allow_security = false;
+
+    if (__android_log_security()) {
+        allow_security = true;
+    } else {
+        property_get(persist_key, persist, "");
+        if (strcasecmp(persist, "true")) {
+            property_set(persist_key, "TRUE");
+            if (__android_log_security()) {
+                allow_security = true;
+                set_persist = true;
+            } else {
+                property_set(persist_key, persist);
+            }
+        }
+    }
+
+    if (!allow_security) {
+        fprintf(stderr, "WARNING: "
+                "security buffer disabled, bypassing end-to-end test\n");
+
+        log_time ts(CLOCK_MONOTONIC);
+
+        buffer.type = EVENT_TYPE_LONG;
+        buffer.data = *(static_cast<uint64_t *>((void *)&ts));
+
+        // expect failure!
+        ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
+
+        return;
+    }
+
+    pid_t pid = getpid();
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_SECURITY, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+        1000, pid)));
+
+    log_time ts(CLOCK_MONOTONIC);
+
+    buffer.type = EVENT_TYPE_LONG;
+    buffer.data = *(static_cast<uint64_t *>((void *)&ts));
+
+    ASSERT_LT(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
+    usleep(1000000);
+
+    int count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        ASSERT_EQ(log_msg.entry.pid, pid);
+
+        if ((log_msg.entry.len != (4 + 1 + 8))
+         || (log_msg.id() != LOG_ID_SECURITY)) {
+            continue;
+        }
+
+        char *eventData = log_msg.msg();
+
+        if (eventData[4] != EVENT_TYPE_LONG) {
+            continue;
+        }
+
+        log_time tx(eventData + 4 + 1);
+        if (ts == tx) {
+            ++count;
+        }
+    }
+
+    if (set_persist) {
+        property_set(persist_key, persist);
+    }
+
+    android_logger_list_close(logger_list);
+
+    EXPECT_EQ(1, count);
+
+}
+
 static unsigned signaled;
 log_time signal_time;
 
@@ -305,8 +433,9 @@
 }
 
 static const char max_payload_tag[] = "TEST_max_payload_XXXX";
-static const char max_payload_buf[LOGGER_ENTRY_MAX_PAYLOAD
-    - sizeof(max_payload_tag) - 1] = "LEONATO\n\
+#define SIZEOF_MAX_PAYLOAD_BUF (LOGGER_ENTRY_MAX_PAYLOAD - \
+                                sizeof(max_payload_tag) - 1)
+static const char max_payload_buf[] = "LEONATO\n\
 I learn in this letter that Don Peter of Arragon\n\
 comes this night to Messina\n\
 MESSENGER\n\
@@ -432,7 +561,7 @@
 trouble: the fashion of the world is to avoid\n\
 cost, and you encounter it\n\
 LEONATO\n\
-Never came trouble to my house in the likeness";
+Never came trouble to my house in the likeness of your grace";
 
 TEST(liblog, max_payload) {
     pid_t pid = getpid();
@@ -491,7 +620,7 @@
 
     EXPECT_EQ(true, matches);
 
-    EXPECT_LE(sizeof(max_payload_buf), static_cast<size_t>(max_len));
+    EXPECT_LE(SIZEOF_MAX_PAYLOAD_BUF, static_cast<size_t>(max_len));
 }
 
 TEST(liblog, too_big_payload) {
@@ -611,11 +740,12 @@
         struct logger * logger;
         EXPECT_TRUE(NULL != (logger = android_logger_open(logger_list, id)));
         EXPECT_EQ(id, android_logger_get_id(logger));
+        EXPECT_LT(0, android_logger_get_log_size(logger));
         /* crash buffer is allowed to be empty, that is actually healthy! */
-        if (android_logger_get_log_size(logger) || strcmp("crash", name)) {
-            EXPECT_LT(0, android_logger_get_log_size(logger));
+        if (android_logger_get_log_readable_size(logger) ||
+                (strcmp("crash", name) && strcmp("security", name))) {
+            EXPECT_LT(0, android_logger_get_log_readable_size(logger));
         }
-        EXPECT_LT(0, android_logger_get_log_readable_size(logger));
         EXPECT_LT(0, android_logger_get_log_version(logger));
     }
 
@@ -736,13 +866,27 @@
                 continue;
             }
             fprintf(stderr, "i=%zu j=%zu\r", i, j);
+            bool android_log_is_loggable = __android_log_is_loggable(
+                levels[i].level, tag, levels[j].level);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)) {
-                EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
-                                                       levels[j].level));
+                if (android_log_is_loggable) {
+                    fprintf(stderr, "\n");
+                }
+                EXPECT_FALSE(android_log_is_loggable);
+                for(size_t k = 1000; k; --k) {
+                    EXPECT_FALSE(__android_log_is_loggable(
+                        levels[i].level, tag, levels[j].level));
+                }
             } else {
-                EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
-                                                      levels[j].level));
+                if (!android_log_is_loggable) {
+                    fprintf(stderr, "\n");
+                }
+                EXPECT_TRUE(android_log_is_loggable);
+                for(size_t k = 1000; k; --k) {
+                    EXPECT_TRUE(__android_log_is_loggable(
+                        levels[i].level, tag, levels[j].level));
+                }
             }
         }
     }
@@ -761,30 +905,58 @@
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key, buf);
             property_set(key, buf);
+            bool android_log_is_loggable = __android_log_is_loggable(
+                levels[i].level, tag, ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_DEBUG)
                         && (levels[j].level == -2))) {
-                EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
-                                                       ANDROID_LOG_DEBUG));
+                if (android_log_is_loggable) {
+                    fprintf(stderr, "\n");
+                }
+                EXPECT_FALSE(android_log_is_loggable);
+                for(size_t k = 1000; k; --k) {
+                    EXPECT_FALSE(__android_log_is_loggable(
+                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                }
             } else {
-                EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
-                                                      ANDROID_LOG_DEBUG));
+                if (!android_log_is_loggable) {
+                    fprintf(stderr, "\n");
+                }
+                EXPECT_TRUE(android_log_is_loggable);
+                for(size_t k = 1000; k; --k) {
+                    EXPECT_TRUE(__android_log_is_loggable(
+                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                }
             }
             property_set(key, "");
 
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key + base_offset, buf);
             property_set(key + base_offset, buf);
+            android_log_is_loggable = __android_log_is_loggable(
+                levels[i].level, tag, ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_DEBUG)
                         && (levels[j].level == -2))) {
-                EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
-                                                       ANDROID_LOG_DEBUG));
+                if (android_log_is_loggable) {
+                    fprintf(stderr, "\n");
+                }
+                EXPECT_FALSE(android_log_is_loggable);
+                for(size_t k = 1000; k; --k) {
+                    EXPECT_FALSE(__android_log_is_loggable(
+                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                }
             } else {
-                EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
-                                                      ANDROID_LOG_DEBUG));
+                if (!android_log_is_loggable) {
+                    fprintf(stderr, "\n");
+                }
+                EXPECT_TRUE(android_log_is_loggable);
+                for(size_t k = 1000; k; --k) {
+                    EXPECT_TRUE(__android_log_is_loggable(
+                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                }
             }
             property_set(key + base_offset, "");
 
@@ -793,30 +965,58 @@
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key, buf);
             property_set(key, buf);
+            android_log_is_loggable = __android_log_is_loggable(
+                levels[i].level, tag, ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_DEBUG)
                         && (levels[j].level == -2))) {
-                EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
-                                                       ANDROID_LOG_DEBUG));
+                if (android_log_is_loggable) {
+                    fprintf(stderr, "\n");
+                }
+                EXPECT_FALSE(android_log_is_loggable);
+                for(size_t k = 1000; k; --k) {
+                    EXPECT_FALSE(__android_log_is_loggable(
+                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                }
             } else {
-                EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
-                                                      ANDROID_LOG_DEBUG));
+                if (!android_log_is_loggable) {
+                    fprintf(stderr, "\n");
+                }
+                EXPECT_TRUE(android_log_is_loggable);
+                for(size_t k = 1000; k; --k) {
+                    EXPECT_TRUE(__android_log_is_loggable(
+                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                }
             }
             property_set(key, "");
 
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key + base_offset, buf);
             property_set(key + base_offset, buf);
+            android_log_is_loggable = __android_log_is_loggable(
+                levels[i].level, tag, ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_DEBUG)
                         && (levels[j].level == -2))) {
-                EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
-                                                       ANDROID_LOG_DEBUG));
+                if (android_log_is_loggable) {
+                    fprintf(stderr, "\n");
+                }
+                EXPECT_FALSE(android_log_is_loggable);
+                for(size_t k = 1000; k; --k) {
+                    EXPECT_FALSE(__android_log_is_loggable(
+                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                }
             } else {
-                EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
-                                                      ANDROID_LOG_DEBUG));
+                if (!android_log_is_loggable) {
+                    fprintf(stderr, "\n");
+                }
+                EXPECT_TRUE(android_log_is_loggable);
+                for(size_t k = 1000; k; --k) {
+                    EXPECT_TRUE(__android_log_is_loggable(
+                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                }
             }
             property_set(key + base_offset, "");
         }
@@ -839,30 +1039,58 @@
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key, buf);
             property_set(key, buf);
+            bool android_log_is_loggable = __android_log_is_loggable(
+                levels[i].level, tag, ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
                         && (levels[j].level == -2))) {
-                EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
-                                                       ANDROID_LOG_DEBUG));
+                if (android_log_is_loggable) {
+                    fprintf(stderr, "\n");
+                }
+                EXPECT_FALSE(android_log_is_loggable);
+                for(size_t k = 1000; k; --k) {
+                    EXPECT_FALSE(__android_log_is_loggable(
+                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                }
             } else {
-                EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
-                                                      ANDROID_LOG_DEBUG));
+                if (!android_log_is_loggable) {
+                    fprintf(stderr, "\n");
+                }
+                EXPECT_TRUE(android_log_is_loggable);
+                for(size_t k = 1000; k; --k) {
+                    EXPECT_TRUE(__android_log_is_loggable(
+                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                }
             }
             property_set(key, "");
 
             fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
                     i, j, key + base_offset, buf);
             property_set(key + base_offset, buf);
+            android_log_is_loggable = __android_log_is_loggable(
+                levels[i].level, tag, ANDROID_LOG_DEBUG);
             if ((levels[i].level < levels[j].level)
                     || (levels[j].level == -1)
                     || ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
                         && (levels[j].level == -2))) {
-                EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
-                                                       ANDROID_LOG_DEBUG));
+                if (android_log_is_loggable) {
+                    fprintf(stderr, "\n");
+                }
+                EXPECT_FALSE(android_log_is_loggable);
+                for(size_t k = 1000; k; --k) {
+                    EXPECT_FALSE(__android_log_is_loggable(
+                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                }
             } else {
-                EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
-                                                      ANDROID_LOG_DEBUG));
+                if (!android_log_is_loggable) {
+                    fprintf(stderr, "\n");
+                }
+                EXPECT_TRUE(android_log_is_loggable);
+                for(size_t k = 1000; k; --k) {
+                    EXPECT_TRUE(__android_log_is_loggable(
+                        levels[i].level, tag, ANDROID_LOG_DEBUG));
+                }
             }
             property_set(key + base_offset, "");
         }
@@ -968,7 +1196,7 @@
     const int TAG = 123456782;
     const char SUBTAG[] = "test-subtag";
     const int UID = -1;
-    const int DATA_LEN = sizeof(max_payload_buf);
+    const int DATA_LEN = SIZEOF_MAX_PAYLOAD_BUF;
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -1039,8 +1267,8 @@
         }
         eventData += dataLen;
 
-        // 4 bytes for the tag, and 512 bytes for the log since the max_payload_buf should be
-        // truncated.
+        // 4 bytes for the tag, and 512 bytes for the log since the
+        // max_payload_buf should be truncated.
         ASSERT_EQ(4 + 512, eventData - original);
 
         ++count;
diff --git a/libnativeloader/Android.mk b/libnativeloader/Android.mk
new file mode 100644
index 0000000..5e65c4c
--- /dev/null
+++ b/libnativeloader/Android.mk
@@ -0,0 +1,54 @@
+LOCAL_PATH:= $(call my-dir)
+
+NATIVE_LOADER_COMMON_SRC_FILES := \
+  native_loader.cpp
+
+# Shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativeloader
+
+LOCAL_SRC_FILES:= $(NATIVE_LOADER_COMMON_SRC_FILES)
+LOCAL_SHARED_LIBRARIES := libnativehelper liblog libcutils
+LOCAL_STATIC_LIBRARIES := libbase
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Shared library for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativeloader
+
+LOCAL_SRC_FILES:= $(NATIVE_LOADER_COMMON_SRC_FILES)
+LOCAL_SHARED_LIBRARIES := libnativehelper liblog libcutils
+LOCAL_STATIC_LIBRARIES := libbase
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+# Static library for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativeloader
+
+LOCAL_SRC_FILES:= $(NATIVE_LOADER_COMMON_SRC_FILES)
+LOCAL_STATIC_LIBRARIES := libnativehelper libcutils liblog libbase
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
new file mode 100644
index 0000000..8020b41
--- /dev/null
+++ b/libnativeloader/native_loader.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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 "nativeloader/native_loader.h"
+#include "ScopedUtfChars.h"
+
+#include <dlfcn.h>
+#ifdef __ANDROID__
+#include <android/dlext.h>
+#include "cutils/properties.h"
+#endif
+
+#include <algorithm>
+#include <vector>
+#include <string>
+#include <mutex>
+
+#include "android-base/macros.h"
+#include "android-base/strings.h"
+
+namespace android {
+
+#ifdef __ANDROID__
+// TODO(dimitry): move this to system properties.
+static const char* kPublicNativeLibraries = "libandroid.so:"
+                                            "libc.so:"
+                                            "libdl.so:"
+                                            "libEGL.so:"
+                                            "libGLESv1_CM.so:"
+                                            "libGLESv2.so:"
+                                            "libGLESv3.so:"
+                                            "libjnigraphics.so:"
+                                            "liblog.so:"
+                                            "libmediandk.so:"
+                                            "libm.so:"
+                                            "libOpenMAXAL.so:"
+                                            "libOpenSLES.so:"
+                                            "libstdc++.so:"
+                                            "libz.so";
+
+class LibraryNamespaces {
+ public:
+  LibraryNamespaces() : initialized_(false) { }
+
+  android_namespace_t* GetOrCreate(JNIEnv* env, jobject class_loader,
+                                   bool is_shared,
+                                   jstring java_library_path,
+                                   jstring java_permitted_path) {
+    ScopedUtfChars library_path(env, java_library_path);
+
+    std::string permitted_path;
+    if (java_permitted_path != nullptr) {
+      ScopedUtfChars path(env, java_permitted_path);
+      permitted_path = path.c_str();
+    }
+
+    if (!initialized_ && !InitPublicNamespace(library_path.c_str())) {
+      return nullptr;
+    }
+
+    std::lock_guard<std::mutex> guard(mutex_);
+
+    auto it = FindNamespaceByClassLoader(env, class_loader);
+
+    if (it != namespaces_.end()) {
+      return it->second;
+    }
+
+    uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED;
+    if (is_shared) {
+      namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
+    }
+
+    android_namespace_t* ns =
+            android_create_namespace("classloader-namespace",
+                                     nullptr,
+                                     library_path.c_str(),
+                                     namespace_type,
+                                     java_permitted_path != nullptr ?
+                                        permitted_path.c_str() :
+                                        nullptr);
+
+    namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));
+
+    return ns;
+  }
+
+ private:
+  bool InitPublicNamespace(const char* library_path) {
+    // Make sure all the public libraries are loaded
+    std::vector<std::string> sonames = android::base::Split(kPublicNativeLibraries, ":");
+    for (const auto& soname : sonames) {
+      if (dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr) {
+        return false;
+      }
+    }
+
+    // Some apps call dlopen from generated code unknown to linker in which
+    // case linker uses anonymous namespace. See b/25844435 for details.
+    initialized_ = android_init_namespaces(kPublicNativeLibraries, library_path);
+
+    return initialized_;
+  }
+
+  std::vector<std::pair<jweak, android_namespace_t*>>::const_iterator
+  FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+    return std::find_if(namespaces_.begin(), namespaces_.end(),
+            [&](const std::pair<jweak, android_namespace_t*>& value) {
+              return env->IsSameObject(value.first, class_loader);
+            });
+  }
+
+  bool initialized_;
+  std::mutex mutex_;
+  std::vector<std::pair<jweak, android_namespace_t*>> namespaces_;
+
+  DISALLOW_COPY_AND_ASSIGN(LibraryNamespaces);
+};
+
+static LibraryNamespaces* g_namespaces = new LibraryNamespaces;
+#endif
+
+
+void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
+                        jobject class_loader, bool is_shared, jstring java_library_path,
+                        jstring java_permitted_path) {
+#if defined(__ANDROID__)
+  if (target_sdk_version <= INT_MAX || class_loader == nullptr) {
+    return dlopen(path, RTLD_NOW);
+  }
+
+  android_namespace_t* ns =
+      g_namespaces->GetOrCreate(env, class_loader, is_shared,
+                                java_library_path, java_permitted_path);
+
+  if (ns == nullptr) {
+    return nullptr;
+  }
+
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+  extinfo.library_namespace = ns;
+
+  return android_dlopen_ext(path, RTLD_NOW, &extinfo);
+#else
+  UNUSED(env, target_sdk_version, class_loader, is_shared,
+         java_library_path, java_permitted_path);
+  return dlopen(path, RTLD_NOW);
+#endif
+}
+
+}; //  android namespace
diff --git a/libnetutils/dhcptool.c b/libnetutils/dhcptool.c
index 352ac5e..a2d3869 100644
--- a/libnetutils/dhcptool.c
+++ b/libnetutils/dhcptool.c
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <err.h>
 #include <errno.h>
 #include <error.h>
 #include <stdbool.h>
@@ -29,12 +30,14 @@
 
   char* interface = argv[1];
   if (ifc_init()) {
-    error(EXIT_FAILURE, errno, "dhcptool %s: ifc_init failed", interface);
+    err(errno, "dhcptool %s: ifc_init failed", interface);
+    ifc_close();
+    return EXIT_FAILURE;
   }
 
   int rc = do_dhcp(interface);
   if (rc) {
-    error(0, errno, "dhcptool %s: do_dhcp failed", interface);
+    err(errno, "dhcptool %s: do_dhcp failed", interface);
   }
 
   ifc_close();
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index 956ed30..aa18bc1 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
+#include <pthread.h>
 
 #include <sys/socket.h>
 #include <sys/select.h>
@@ -57,6 +58,8 @@
 
 static int ifc_ctl_sock = -1;
 static int ifc_ctl_sock6 = -1;
+static pthread_mutex_t ifc_sock_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+static pthread_mutex_t ifc_sock6_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
 void printerr(char *fmt, ...);
 
 #define DBG 0
@@ -122,6 +125,8 @@
 int ifc_init(void)
 {
     int ret;
+
+    pthread_mutex_lock(&ifc_sock_mutex);
     if (ifc_ctl_sock == -1) {
         ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
         if (ifc_ctl_sock < 0) {
@@ -136,6 +141,7 @@
 
 int ifc_init6(void)
 {
+    pthread_mutex_lock(&ifc_sock6_mutex);
     if (ifc_ctl_sock6 == -1) {
         ifc_ctl_sock6 = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
         if (ifc_ctl_sock6 < 0) {
@@ -152,6 +158,7 @@
         (void)close(ifc_ctl_sock);
         ifc_ctl_sock = -1;
     }
+    pthread_mutex_unlock(&ifc_sock_mutex);
 }
 
 void ifc_close6(void)
@@ -160,6 +167,7 @@
         (void)close(ifc_ctl_sock6);
         ifc_ctl_sock6 = -1;
     }
+    pthread_mutex_unlock(&ifc_sock6_mutex);
 }
 
 static void ifc_init_ifr(const char *name, struct ifreq *ifr)
@@ -534,6 +542,7 @@
     ifc_init();
 
     if (ifc_ctl_sock < 0) {
+        ifc_close();
         return -errno;
     }
 
diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.cpp b/libpixelflinger/codeflinger/MIPS64Assembler.cpp
index a5305cc..672040b 100644
--- a/libpixelflinger/codeflinger/MIPS64Assembler.cpp
+++ b/libpixelflinger/codeflinger/MIPS64Assembler.cpp
@@ -1304,9 +1304,8 @@
 
 MIPS64Assembler::MIPS64Assembler(void* assembly, ArmToMips64Assembler *parent)
     : mParent(parent),
-    MIPSAssembler::MIPSAssembler(NULL, NULL)
+    MIPSAssembler::MIPSAssembler(assembly)
 {
-    mBase = mPC = (uint32_t *)assembly;
 }
 
 MIPS64Assembler::~MIPS64Assembler()
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.cpp b/libpixelflinger/codeflinger/MIPSAssembler.cpp
index daa231f..5497fae 100644
--- a/libpixelflinger/codeflinger/MIPSAssembler.cpp
+++ b/libpixelflinger/codeflinger/MIPSAssembler.cpp
@@ -1256,6 +1256,12 @@
     mDuration = ggl_system_time();
 }
 
+MIPSAssembler::MIPSAssembler(void* assembly)
+    : mParent(NULL), mAssembly(NULL)
+{
+    mBase = mPC = (uint32_t *)assembly;
+}
+
 MIPSAssembler::~MIPSAssembler()
 {
 }
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.h b/libpixelflinger/codeflinger/MIPSAssembler.h
index 06cb0d0..b53fefb 100644
--- a/libpixelflinger/codeflinger/MIPSAssembler.h
+++ b/libpixelflinger/codeflinger/MIPSAssembler.h
@@ -242,6 +242,7 @@
 {
 public:
                 MIPSAssembler(const sp<Assembly>& assembly, ArmToMipsAssembler *parent);
+                MIPSAssembler(void* assembly);
     virtual     ~MIPSAssembler();
 
     virtual uint32_t*   base() const;
diff --git a/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp b/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp
index 2b25223..b680b60 100644
--- a/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp
+++ b/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp
@@ -228,26 +228,26 @@
      {0xA039,INSTR_SUB,{1,R_a5,R_a6,2,7},GE,0,2,NA,1,1,NA,NA,NA,2,1,2},
      {0xA040,INSTR_SUB,{1,R_a5,R_a6,1,1},HS,0,2,NA,1,1,NA,NA,NA,2,1,1},
      {0xA041,INSTR_SUB,{1,R_a5,R_a6,0,1},HS,0,2,NA,1,1,NA,NA,NA,2,1,2},
-     {0xA042,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,1,1<< 16,0,0,0,NA,1,(uint64_t)(1 -(1<<16))},
+     {0xA042,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,1,1<< 16,0,0,0,NA,1,UINT64_C(1) -(1<<16)},
      {0xA043,INSTR_SUB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,1,1,0,0,0,NA,1,MAX_64BIT-1},
      {0xA044,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,1,1,0,0,0,NA,1,0},
-     {0xA045,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,1<<16,0,0,NA,1,(uint64_t)(1 -(1<<16))},
+     {0xA045,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,1<<16,0,0,NA,1,UINT64_C(1) -(1<<16)},
      {0xA046,INSTR_SUB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,0,NA,1,0,0,NA,1,MAX_64BIT-1},
      {0xA047,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,0,0,NA,1,0},
-     {0xA048,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,SHIFT_LSL,16,NA,1,(uint64_t)(1 -(1<<16))},
+     {0xA048,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,SHIFT_LSL,16,NA,1,UINT64_C(1) -(1<<16)},
      {0xA049,INSTR_SUB,{0,0,0,0,0},AL,0,0x80000001,NA,0,NA,MAX_32BIT,SHIFT_LSL,31,NA,1,1},
      {0xA050,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,3,SHIFT_LSR,1,NA,1,0},
      {0xA051,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,MAX_32BIT,SHIFT_LSR,31,NA,1,0},
-     {0xA052,INSTR_RSB,{1,R_a5,R_a6,4,1},GE,0,2,NA,1,0,NA,NA,NA,2,1,(uint64_t)-2},
-     {0xA053,INSTR_RSB,{1,R_a5,R_a6,-1,1},GE,0,2,NA,1,0,NA,NA,NA,2,1,2},
+     {0xA052,INSTR_RSB,{1,R_a5,R_a6,4,1},GE,0,2,NA,1,0,NA,NA,NA,2,1,UINT64_C(-2)},
+     {0xA053,INSTR_RSB,{1,R_a5,R_a6,UINT64_C(-1),1},GE,0,2,NA,1,0,NA,NA,NA,2,1,2},
      {0xA054,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,1,1<<16,NA,NA,NA,NA,1,(1<<16)-1},
-     {0xA055,INSTR_RSB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,1,1,NA,NA,NA,NA,1,(uint64_t)(1-MAX_64BIT)},
+     {0xA055,INSTR_RSB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,1,1,NA,NA,NA,NA,1,UINT64_C(1)-MAX_64BIT},
      {0xA056,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,1,1,NA,NA,NA,NA,1,0},
      {0xA057,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,1<<16,0,0,NA,1,(1<<16)-1},
-     {0xA058,INSTR_RSB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,0,NA,1,0,0,NA,1,(uint64_t)(1-MAX_64BIT)},
+     {0xA058,INSTR_RSB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,0,NA,1,0,0,NA,1,UINT64_C(1)-MAX_64BIT},
      {0xA059,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,0,0,NA,1,0},
      {0xA060,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,SHIFT_LSL,16,NA,1,(1<<16)-1},
-     {0xA061,INSTR_RSB,{0,0,0,0,0},AL,0,0x80000001,NA,0,NA,MAX_32BIT ,SHIFT_LSL,31,NA,1,(uint64_t)(-1)},
+     {0xA061,INSTR_RSB,{0,0,0,0,0},AL,0,0x80000001,NA,0,NA,MAX_32BIT ,SHIFT_LSL,31,NA,1,UINT64_C(-1)},
      {0xA062,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,3,SHIFT_LSR,1,NA,1,0},
      {0xA063,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,MAX_32BIT,SHIFT_LSR,31,NA,1,0},
      {0xA064,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,1,0x80000001,NA,NA,NA,NA,1,0xFFFFFFFF80000001},
@@ -263,28 +263,28 @@
      {0xA074,INSTR_MOV,{0,0,0,0,0},AL,1,NA,NA,0,0,MAX_64BIT -1,SHIFT_ASR,1,NA,1,MAX_64BIT},
      {0xA075,INSTR_MOV,{0,0,0,0,0},AL,1,NA,NA,0,0,3,SHIFT_ASR,1,NA,1,1},
      {0xA076,INSTR_MOV,{2,R_a5,R_a6,6,8},MI,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
-     {0xA077,INSTR_MOV,{2,R_a5,R_a6,-4,-8},MI,0,NA,NA,0,0,0x80000001,0,0,2,1,0xFFFFFFFF80000001},
-     {0xA078,INSTR_MOV,{1,R_a5,R_a6,-1,-1},LT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
-     {0xA079,INSTR_MOV,{1,R_a5,R_a6,-1,1},LT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
-     {0xA080,INSTR_MOV,{1,R_a5,R_a6,-1,-5},GE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,MAX_64BIT-1},
+     {0xA077,INSTR_MOV,{2,R_a5,R_a6,UINT64_C(-4),UINT64_C(-8)},MI,0,NA,NA,0,0,0x80000001,0,0,2,1,0xFFFFFFFF80000001},
+     {0xA078,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),UINT64_C(-1)},LT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
+     {0xA079,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},LT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
+     {0xA080,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),UINT64_C(-5)},GE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,MAX_64BIT-1},
      {0xA081,INSTR_MOV,{1,R_a5,R_a6,5,5},GE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,2,1,0xFFFFFFFF80000000},
-     {0xA082,INSTR_MOV,{1,R_a5,R_a6,-1,1},GE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,2,1,2},
+     {0xA082,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},GE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,2,1,2},
      {0xA083,INSTR_MOV,{1,R_a5,R_a6,4,1},LE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,2},
-     {0xA084,INSTR_MOV,{1,R_a5,R_a6,-1,-1},LE,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
-     {0xA085,INSTR_MOV,{1,R_a5,R_a6,-1,1},LE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,2,1,0xFFFFFFFF80000000},
+     {0xA084,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),UINT64_C(-1)},LE,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
+     {0xA085,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},LE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,2,1,0xFFFFFFFF80000000},
      {0xA086,INSTR_MOV,{1,R_a5,R_a6,1,1},GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
-     {0xA087,INSTR_MOV,{1,R_a5,R_a6,-1,-3},GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
-     {0xA088,INSTR_MOV,{1,R_a5,R_a6,-1,0},GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
-     {0xA089,INSTR_MOV,{1,R_a5,R_a6,-1,-1},GT,0,NA,NA,0,0,0x80000001,0,0,2,1,2},
+     {0xA087,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),UINT64_C(-3)},GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
+     {0xA088,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),0},GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
+     {0xA089,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),UINT64_C(-1)},GT,0,NA,NA,0,0,0x80000001,0,0,2,1,2},
      {0xA090,INSTR_MOV,{1,R_a5,R_a6,6,1},GT,0,NA,NA,0,0,0x80000001,0,0,2,1,0xFFFFFFFF80000001},
-     {0xA091,INSTR_MOV,{1,R_a5,R_a6,-1,1},GT,0,NA,NA,0,0,0x80000001,0,0,2,1,2},
+     {0xA091,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},GT,0,NA,NA,0,0,0x80000001,0,0,2,1,2},
      {0xA092,INSTR_MOV,{1,R_a5,R_a6,1,1},GT,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,2},
      {0xA093,INSTR_MOV,{1,R_a5,R_a6,4,1},GT,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,MAX_64BIT-1},
-     {0xA094,INSTR_MOV,{1,R_a5,R_a6,-1,1},GT,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,2,1,2},
-     {0xA095,INSTR_MOV,{1,R_a5,R_a6,1,-1},HS,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
-     {0xA096,INSTR_MOV,{1,R_a5,R_a6,-1,1},HS,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
+     {0xA094,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},GT,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,2,1,2},
+     {0xA095,INSTR_MOV,{1,R_a5,R_a6,1,UINT64_C(-1)},HS,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
+     {0xA096,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},HS,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
      {0xA097,INSTR_MVN,{1,R_a5,R_a6,1,4},HS,0,NA,NA,1,MAX_32BIT-1,NA,NA,NA,2,1,2},
-     {0xA098,INSTR_MVN,{1,R_a5,R_a6,-1,1},HS,0,NA,NA,1,MAX_32BIT-1,NA,NA,NA,2,1,1},
+     {0xA098,INSTR_MVN,{1,R_a5,R_a6,UINT64_C(-1),1},HS,0,NA,NA,1,MAX_32BIT-1,NA,NA,NA,2,1,1},
      {0xA099,INSTR_MVN,{0,0,0,0,0},AL,0,NA,NA,1,0,NA,NA,NA,2,1,MAX_64BIT},
      {0xA100,INSTR_MVN,{0,0,0,0,0},AL,0,NA,NA,0,NA,MAX_32BIT-1,NA,0,2,1,1},
      {0xA101,INSTR_MVN,{0,0,0,0,0},AL,0,NA,NA,0,NA,0x80000001,NA,0,2,1,0x7FFFFFFE},
diff --git a/libsparse/append2simg.c b/libsparse/append2simg.c
index 1cf827c..eef8764 100644
--- a/libsparse/append2simg.c
+++ b/libsparse/append2simg.c
@@ -82,7 +82,7 @@
         exit(-1);
     }
 
-    sparse_output = sparse_file_import_auto(output, true, true);
+    sparse_output = sparse_file_import_auto(output, false, true);
     if (!sparse_output) {
         fprintf(stderr, "Couldn't import output file\n");
         exit(-1);
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 3011ed7..168899c 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -199,13 +199,14 @@
             continue;
         }
         if (mListen && FD_ISSET(mSock, &read_fds)) {
-            struct sockaddr addr;
+            sockaddr_storage ss;
+            sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
             socklen_t alen;
             int c;
 
             do {
-                alen = sizeof(addr);
-                c = accept(mSock, &addr, &alen);
+                alen = sizeof(ss);
+                c = accept(mSock, addrp, &alen);
                 SLOGV("%s got %d from accept", mSocketName, c);
             } while (c < 0 && errno == EINTR);
             if (c < 0) {
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 631b5a3..8c4fd15 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -106,19 +106,16 @@
 LOCAL_SANITIZE := integer
 include $(BUILD_SHARED_LIBRARY)
 
-# Include subdirectory makefiles
-# ============================================================
-
 include $(CLEAR_VARS)
 LOCAL_MODULE := SharedBufferTest
-LOCAL_STATIC_LIBRARIES := libutils libcutils
+LOCAL_STATIC_LIBRARIES := libutils
 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_STATIC_LIBRARIES := libutils
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_SRC_FILES := SharedBufferTest.cpp
 include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index b14884b..952c992 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -74,7 +74,7 @@
         mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
         mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
         mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
-    mWakeEventFd = eventfd(0, EFD_NONBLOCK);
+    mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
     LOG_ALWAYS_FATAL_IF(mWakeEventFd < 0, "Could not make wake event fd: %s",
                         strerror(errno));
 
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index c7dd1ab..34d75ee 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#define __STDC_LIMIT_MACROS
-#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
diff --git a/libutils/SharedBufferTest.cpp b/libutils/SharedBufferTest.cpp
index a0484ff..33a4e0c 100644
--- a/libutils/SharedBufferTest.cpp
+++ b/libutils/SharedBufferTest.cpp
@@ -31,10 +31,10 @@
   // 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);
+  ASSERT_EQ(nullptr, buf);
 
   buf = android::SharedBuffer::alloc(0);
-  ASSERT_FALSE(NULL == buf);
+  ASSERT_NE(nullptr, buf);
   ASSERT_EQ(0U, buf->size());
   buf->release();
 }
@@ -49,7 +49,7 @@
   // 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);
+  ASSERT_EQ(nullptr, buf);
 
   buf = android::SharedBuffer::alloc(10);
   buf = buf->editResize(0);
diff --git a/libutils/tests/String8_test.cpp b/libutils/tests/String8_test.cpp
index c42c68d..01e64f6 100644
--- a/libutils/tests/String8_test.cpp
+++ b/libutils/tests/String8_test.cpp
@@ -72,4 +72,9 @@
     EXPECT_STREQ(src3, " Verify me.");
 }
 
+TEST_F(String8Test, SetToSizeMaxReturnsNoMemory) {
+    const char *in = "some string";
+    EXPECT_EQ(NO_MEMORY, String8("").setTo(in, SIZE_MAX));
+}
+
 }
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 3d18f7c..07ef6cd 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -30,9 +30,9 @@
 #include <memory>
 #include <vector>
 
-#include "base/file.h"
-#include "base/macros.h"  // TEMP_FAILURE_RETRY may or may not be in unistd
-#include "base/memory.h"
+#include "android-base/file.h"
+#include "android-base/macros.h"  // TEMP_FAILURE_RETRY may or may not be in unistd
+#include "android-base/memory.h"
 #include "log/log.h"
 #include "utils/Compat.h"
 #include "utils/FileMap.h"
diff --git a/libziparchive/zip_archive_common.h b/libziparchive/zip_archive_common.h
index 7f20d51..ca42509 100644
--- a/libziparchive/zip_archive_common.h
+++ b/libziparchive/zip_archive_common.h
@@ -17,7 +17,7 @@
 #ifndef LIBZIPARCHIVE_ZIPARCHIVECOMMON_H_
 #define LIBZIPARCHIVE_ZIPARCHIVECOMMON_H_
 
-#include "base/macros.h"
+#include "android-base/macros.h"
 
 #include <inttypes.h>
 
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 32b1a38..cb0f410 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -23,7 +23,7 @@
 #include <unistd.h>
 #include <vector>
 
-#include <base/file.h>
+#include <android-base/file.h>
 #include <gtest/gtest.h>
 
 static std::string test_data_dir;
diff --git a/libziparchive/zip_writer_test.cc b/libziparchive/zip_writer_test.cc
index f752b7e..b7d1458 100644
--- a/libziparchive/zip_writer_test.cc
+++ b/libziparchive/zip_writer_test.cc
@@ -17,7 +17,7 @@
 #include "ziparchive/zip_archive.h"
 #include "ziparchive/zip_writer.h"
 
-#include <base/test_utils.h>
+#include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 #include <memory>
 #include <vector>
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 7bbc811..511bf68 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -77,12 +77,7 @@
 static int epollfd;
 static int maxevents;
 
-#define OOM_DISABLE (-17)
-/* inclusive */
-#define OOM_ADJUST_MIN (-16)
-#define OOM_ADJUST_MAX 15
-
-/* kernel OOM score values */
+/* OOM score values used by both kernel and framework */
 #define OOM_SCORE_ADJ_MIN       (-1000)
 #define OOM_SCORE_ADJ_MAX       1000
 
@@ -114,8 +109,8 @@
 static struct proc *pidhash[PIDHASH_SZ];
 #define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
 
-#define ADJTOSLOT(adj) (adj + -OOM_ADJUST_MIN)
-static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_ADJUST_MAX) + 1];
+#define ADJTOSLOT(adj) (adj + -OOM_SCORE_ADJ_MIN)
+static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_SCORE_ADJ_MAX) + 1];
 
 /*
  * Wait 1-2 seconds for the death report of a killed process prior to
@@ -148,14 +143,6 @@
     return ret;
 }
 
-static int lowmem_oom_adj_to_oom_score_adj(int oom_adj)
-{
-    if (oom_adj == OOM_ADJUST_MAX)
-        return OOM_SCORE_ADJ_MAX;
-    else
-        return (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
-}
-
 static struct proc *pid_lookup(int pid) {
     struct proc *procp;
 
@@ -230,7 +217,7 @@
 }
 
 static void writefilestring(char *path, char *s) {
-    int fd = open(path, O_WRONLY);
+    int fd = open(path, O_WRONLY | O_CLOEXEC);
     int len = strlen(s);
     int ret;
 
@@ -254,13 +241,13 @@
     char path[80];
     char val[20];
 
-    if (oomadj < OOM_DISABLE || oomadj > OOM_ADJUST_MAX) {
+    if (oomadj < OOM_SCORE_ADJ_MIN || oomadj > OOM_SCORE_ADJ_MAX) {
         ALOGE("Invalid PROCPRIO oomadj argument %d", oomadj);
         return;
     }
 
     snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", pid);
-    snprintf(val, sizeof(val), "%d", lowmem_oom_adj_to_oom_score_adj(oomadj));
+    snprintf(val, sizeof(val), "%d", oomadj);
     writefilestring(path, val);
 
     if (use_inkernel_interface)
@@ -410,7 +397,8 @@
 }
 
 static void ctrl_connect_handler(uint32_t events __unused) {
-    struct sockaddr addr;
+    struct sockaddr_storage ss;
+    struct sockaddr *addrp = (struct sockaddr *)&ss;
     socklen_t alen;
     struct epoll_event epev;
 
@@ -419,8 +407,8 @@
         ctrl_dfd_reopened = 1;
     }
 
-    alen = sizeof(addr);
-    ctrl_dfd = accept(ctrl_lfd, &addr, &alen);
+    alen = sizeof(ss);
+    ctrl_dfd = accept(ctrl_lfd, addrp, &alen);
 
     if (ctrl_dfd < 0) {
         ALOGE("lmkd control socket accept failed; errno=%d", errno);
@@ -486,7 +474,7 @@
 
     memset(mip, 0, sizeof(struct sysmeminfo));
 
-    fd = open(ZONEINFO_PATH, O_RDONLY);
+    fd = open(ZONEINFO_PATH, O_RDONLY | O_CLOEXEC);
     if (fd == -1) {
         ALOGE("%s open: errno=%d", ZONEINFO_PATH, errno);
         return -1;
@@ -517,7 +505,7 @@
     ssize_t ret;
 
     snprintf(path, PATH_MAX, "/proc/%d/statm", pid);
-    fd = open(path, O_RDONLY);
+    fd = open(path, O_RDONLY | O_CLOEXEC);
     if (fd == -1)
         return -1;
 
@@ -540,7 +528,7 @@
     ssize_t ret;
 
     snprintf(path, PATH_MAX, "/proc/%d/cmdline", pid);
-    fd = open(path, O_RDONLY);
+    fd = open(path, O_RDONLY | O_CLOEXEC);
     if (fd == -1)
         return NULL;
     ret = read_all(fd, line, sizeof(line) - 1);
@@ -607,7 +595,7 @@
 static int find_and_kill_process(int other_free, int other_file, bool first)
 {
     int i;
-    int min_score_adj = OOM_ADJUST_MAX + 1;
+    int min_score_adj = OOM_SCORE_ADJ_MAX + 1;
     int minfree = 0;
     int killed_size = 0;
 
@@ -619,10 +607,10 @@
         }
     }
 
-    if (min_score_adj == OOM_ADJUST_MAX + 1)
+    if (min_score_adj == OOM_SCORE_ADJ_MAX + 1)
         return 0;
 
-    for (i = OOM_ADJUST_MAX; i >= min_score_adj; i--) {
+    for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
         struct proc *procp;
 
 retry:
@@ -685,19 +673,19 @@
     struct epoll_event epev;
     int ret;
 
-    mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY);
+    mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY | O_CLOEXEC);
     if (mpfd < 0) {
         ALOGI("No kernel memory.pressure_level support (errno=%d)", errno);
         goto err_open_mpfd;
     }
 
-    evctlfd = open(MEMCG_SYSFS_PATH "cgroup.event_control", O_WRONLY);
+    evctlfd = open(MEMCG_SYSFS_PATH "cgroup.event_control", O_WRONLY | O_CLOEXEC);
     if (evctlfd < 0) {
         ALOGI("No kernel memory cgroup event control (errno=%d)", errno);
         goto err_open_evctlfd;
     }
 
-    evfd = eventfd(0, EFD_NONBLOCK);
+    evfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
     if (evfd < 0) {
         ALOGE("eventfd failed for level %s; errno=%d", levelstr, errno);
         goto err_eventfd;
@@ -783,7 +771,7 @@
             ALOGE("Kernel does not support memory pressure events or in-kernel low memory killer");
     }
 
-    for (i = 0; i <= ADJTOSLOT(OOM_ADJUST_MAX); i++) {
+    for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) {
         procadjslot_list[i].next = &procadjslot_list[i];
         procadjslot_list[i].prev = &procadjslot_list[i];
     }
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 4d7adf1..ddc91ca 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -6,6 +6,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <getopt.h>
 #include <math.h>
 #include <sched.h>
 #include <signal.h>
@@ -24,8 +25,8 @@
 #include <memory>
 #include <string>
 
-#include <base/file.h>
-#include <base/strings.h>
+#include <android-base/file.h>
+#include <android-base/strings.h>
 #include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
 #include <log/event_tag_map.h>
@@ -256,13 +257,19 @@
                     "  -s              Set default filter to silent.\n"
                     "                  Like specifying filterspec '*:S'\n"
                     "  -f <filename>   Log to file. Default is stdout\n"
+                    "  --file=<filename>\n"
                     "  -r <kbytes>     Rotate log every kbytes. Requires -f\n"
+                    "  --rotate_kbytes=<kbytes>\n"
                     "  -n <count>      Sets max number of rotated logs to <count>, default 4\n"
-                    "  -v <format>     Sets the log print format, where <format> is:\n\n"
+                    "  --rotate_count=<count>\n"
+                    "  -v <format>     Sets the log print format, where <format> is:\n"
+                    "  --format=<format>\n"
                     "                      brief color epoch long monotonic printable process raw\n"
-                    "                      tag thread threadtime time usec UTC year zone\n\n"
+                    "                      tag thread threadtime time uid usec UTC year zone\n\n"
                     "  -D              print dividers between each log buffer\n"
+                    "  --dividers\n"
                     "  -c              clear (flush) the entire log and exit\n"
+                    "  --clear\n"
                     "  -d              dump the log and then exit (don't block)\n"
                     "  -t <count>      print only the most recent <count> lines (implies -d)\n"
                     "  -t '<time>'     print most recent lines since specified time (implies -d)\n"
@@ -271,22 +278,34 @@
                     "                  count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'\n"
                     "                  'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format\n"
                     "  -g              get the size of the log's ring buffer and exit\n"
-                    "  -L              dump logs from prior to last reboot\n"
-                    "  -b <buffer>     Request alternate ring buffer, 'main', 'system', 'radio',\n"
-                    "                  'events', 'crash' or 'all'. Multiple -b parameters are\n"
-                    "                  allowed and results are interleaved. The default is\n"
-                    "                  -b main -b system -b crash.\n"
-                    "  -B              output the log in binary.\n"
-                    "  -S              output statistics.\n"
+                    "  --buffer_size\n"
                     "  -G <size>       set size of log ring buffer, may suffix with K or M.\n"
+                    "  --buffer_size=<size>\n"
+                    "  -L              dump logs from prior to last reboot\n"
+                    "  --last\n"
+                    // Leave security (Device Owner only installations) and
+                    // kernel (userdebug and eng) buffers undocumented.
+                    "  -b <buffer>     Request alternate ring buffer, 'main', 'system', 'radio',\n"
+                    "  --buffer=<buffer> 'events', 'crash', 'default' or 'all'. Multiple -b\n"
+                    "                  parameters are allowed and results are interleaved. The\n"
+                    "                  default is -b main -b system -b crash.\n"
+                    "  -B              output the log in binary.\n"
+                    "  --binary\n"
+                    "  -S              output statistics.\n"
+                    "  --statistics\n"
                     "  -p              print prune white and ~black list. Service is specified as\n"
-                    "                  UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
+                    "  --prune         UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
                     "                  with ~, otherwise weighed for longevity if unadorned. All\n"
                     "                  other pruning activity is oldest first. Special case ~!\n"
                     "                  represents an automatic quicker pruning for the noisiest\n"
                     "                  UID as determined by the current statistics.\n"
                     "  -P '<list> ...' set prune white and ~black list, using same format as\n"
-                    "                  printed above. Must be quoted.\n");
+                    "  --prune='<list> ...'  printed above. Must be quoted.\n"
+                    "  --pid=<pid>     Only prints logs from the given pid.\n"
+                    // Check ANDROID_LOG_WRAP_DEFAULT_TIMEOUT value
+                    "  --wrap          Sleep for 2 hours or when buffer about to wrap whichever\n"
+                    "                  comes first. Improves efficiency of polling by providing\n"
+                    "                  an about-to-wrap wakeup.\n");
 
     fprintf(stderr,"\nfilterspecs are a series of \n"
                    "  <tag>[:priority]\n\n"
@@ -348,15 +367,19 @@
 static bool getSizeTArg(char *ptr, size_t *val, size_t min = 0,
                         size_t max = SIZE_MAX)
 {
-    char *endp;
-    errno = 0;
-    size_t ret = (size_t) strtoll(ptr, &endp, 0);
-
-    if (endp[0] != '\0' || errno != 0 ) {
+    if (!ptr) {
         return false;
     }
 
-    if (ret >  max || ret <  min) {
+    char *endp;
+    errno = 0;
+    size_t ret = (size_t)strtoll(ptr, &endp, 0);
+
+    if (endp[0] || errno) {
+        return false;
+    }
+
+    if ((ret > max) || (ret < min)) {
         return false;
     }
 
@@ -398,11 +421,9 @@
         return retval;
     }
 
-    log_time now(CLOCK_REALTIME);
-    bool monotonic = android_log_timestamp() == 'm';
-    if (monotonic) {
-        now = log_time(CLOCK_MONOTONIC);
-    }
+    clockid_t clock_type = android_log_clockid();
+    log_time now(clock_type);
+    bool monotonic = clock_type == CLOCK_MONOTONIC;
 
     std::string directory;
     char *file = strrchr(outputFileName, '/');
@@ -499,6 +520,7 @@
     struct logger_list *logger_list;
     size_t tail_lines = 0;
     log_time tail_time(log_time::EPOCH);
+    size_t pid = 0;
 
     signal(SIGPIPE, exit);
 
@@ -512,13 +534,66 @@
     for (;;) {
         int ret;
 
-        ret = getopt(argc, argv, ":cdDLt:T:gG:sQf:r:n:v:b:BSpP:");
+        int option_index = 0;
+        static const char pid_str[] = "pid";
+        static const char wrap_str[] = "wrap";
+        static const struct option long_options[] = {
+          { "binary",        no_argument,       NULL,   'B' },
+          { "buffer",        required_argument, NULL,   'b' },
+          { "buffer_size",   optional_argument, NULL,   'g' },
+          { "clear",         no_argument,       NULL,   'c' },
+          { "dividers",      no_argument,       NULL,   'D' },
+          { "file",          required_argument, NULL,   'f' },
+          { "format",        required_argument, NULL,   'v' },
+          { "last",          no_argument,       NULL,   'L' },
+          { pid_str,         required_argument, NULL,   0 },
+          { "prune",         optional_argument, NULL,   'p' },
+          { "rotate_count",  required_argument, NULL,   'n' },
+          { "rotate_kbytes", required_argument, NULL,   'r' },
+          { "statistics",    no_argument,       NULL,   'S' },
+          // support, but ignore and do not document, the optional argument
+          { wrap_str,        optional_argument, NULL,   0 },
+          { NULL,            0,                 NULL,   0 }
+        };
+
+        ret = getopt_long(argc, argv, ":cdDLt:T:gG:sQf:r:n:v:b:BSpP:",
+                          long_options, &option_index);
 
         if (ret < 0) {
             break;
         }
 
-        switch(ret) {
+        switch (ret) {
+            case 0:
+                // One of the long options
+                if (long_options[option_index].name == pid_str) {
+                    // ToDo: determine runtime PID_MAX?
+                    if (!getSizeTArg(optarg, &pid, 1)) {
+                        logcat_panic(true, "%s %s out of range\n",
+                                     long_options[option_index].name, optarg);
+                    }
+                    break;
+                }
+                if (long_options[option_index].name == wrap_str) {
+                    mode |= ANDROID_LOG_WRAP |
+                            ANDROID_LOG_RDONLY |
+                            ANDROID_LOG_NONBLOCK;
+                    // ToDo: implement API that supports setting a wrap timeout
+                    size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
+                    if (optarg && !getSizeTArg(optarg, &dummy, 1)) {
+                        logcat_panic(true, "%s %s out of range\n",
+                                     long_options[option_index].name, optarg);
+                    }
+                    if (dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
+                        fprintf(stderr,
+                                "WARNING: %s %u seconds, ignoring %zu\n",
+                                long_options[option_index].name,
+                                ANDROID_LOG_WRAP_DEFAULT_TIMEOUT, dummy);
+                    }
+                    break;
+                }
+            break;
+
             case 's':
                 // default to all silent
                 android_log_addFilterRule(g_logformat, "*:s");
@@ -570,8 +645,11 @@
             break;
 
             case 'g':
-                getLogSize = 1;
-            break;
+                if (!optarg) {
+                    getLogSize = 1;
+                    break;
+                }
+                // FALLTHRU
 
             case 'G': {
                 char *cp;
@@ -609,24 +687,31 @@
             break;
 
             case 'p':
-                getPruneList = 1;
-            break;
+                if (!optarg) {
+                    getPruneList = 1;
+                    break;
+                }
+                // FALLTHRU
 
             case 'P':
                 setPruneList = optarg;
             break;
 
             case 'b': {
-                if (strcmp(optarg, "all") == 0) {
-                    while (devices) {
-                        dev = devices;
-                        devices = dev->next;
-                        delete dev;
-                    }
+                if (strcmp(optarg, "default") == 0) {
+                    for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+                        switch (i) {
+                        case LOG_ID_SECURITY:
+                        case LOG_ID_EVENTS:
+                            continue;
+                        case LOG_ID_MAIN:
+                        case LOG_ID_SYSTEM:
+                        case LOG_ID_CRASH:
+                            break;
+                        default:
+                            continue;
+                        }
 
-                    devices = dev = NULL;
-                    g_devCount = 0;
-                    for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
                         const char *name = android_log_id_to_name((log_id_t)i);
                         log_id_t log_id = android_name_to_log_id(name);
 
@@ -634,7 +719,58 @@
                             continue;
                         }
 
-                        bool binary = strcmp(name, "events") == 0;
+                        bool found = false;
+                        for (dev = devices; dev; dev = dev->next) {
+                            if (!strcmp(optarg, dev->device)) {
+                                found = true;
+                                break;
+                            }
+                            if (!dev->next) {
+                                break;
+                            }
+                        }
+                        if (found) {
+                            break;
+                        }
+
+                        log_device_t* d = new log_device_t(name, false);
+
+                        if (dev) {
+                            dev->next = d;
+                            dev = d;
+                        } else {
+                            devices = dev = d;
+                        }
+                        g_devCount++;
+                    }
+                    break;
+                }
+
+                if (strcmp(optarg, "all") == 0) {
+                    for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+                        const char *name = android_log_id_to_name((log_id_t)i);
+                        log_id_t log_id = android_name_to_log_id(name);
+
+                        if (log_id != (log_id_t)i) {
+                            continue;
+                        }
+
+                        bool found = false;
+                        for (dev = devices; dev; dev = dev->next) {
+                            if (!strcmp(optarg, dev->device)) {
+                                found = true;
+                                break;
+                            }
+                            if (!dev->next) {
+                                break;
+                            }
+                        }
+                        if (found) {
+                            break;
+                        }
+
+                        bool binary = !strcmp(name, "events") ||
+                                      !strcmp(name, "security");
                         log_device_t* d = new log_device_t(name, binary);
 
                         if (dev) {
@@ -648,14 +784,21 @@
                     break;
                 }
 
-                bool binary = strcmp(optarg, "events") == 0;
+                bool binary = !(strcmp(optarg, "events") &&
+                                strcmp(optarg, "security"));
 
                 if (devices) {
                     dev = devices;
                     while (dev->next) {
+                        if (!strcmp(optarg, dev->device)) {
+                            dev = NULL;
+                            break;
+                        }
                         dev = dev->next;
                     }
-                    dev->next = new log_device_t(optarg, binary);
+                    if (dev) {
+                        dev->next = new log_device_t(optarg, binary);
+                    }
                 } else {
                     devices = new log_device_t(optarg, binary);
                 }
@@ -840,9 +983,9 @@
 
     dev = devices;
     if (tail_time != log_time::EPOCH) {
-        logger_list = android_logger_list_alloc_time(mode, tail_time, 0);
+        logger_list = android_logger_list_alloc_time(mode, tail_time, pid);
     } else {
-        logger_list = android_logger_list_alloc(mode, tail_lines, 0);
+        logger_list = android_logger_list_alloc(mode, tail_lines, pid);
     }
     const char *openDeviceFail = NULL;
     const char *clearFail = NULL;
@@ -925,7 +1068,7 @@
         size_t len = 8192;
         char *buf;
 
-        for(int retry = 32;
+        for (int retry = 32;
                 (retry >= 0) && ((buf = new char [len]));
                 delete [] buf, buf = NULL, --retry) {
             if (getPruneList) {
@@ -1015,7 +1158,7 @@
             logcat_panic(false, "logcat read failure");
         }
 
-        for(d = devices; d; d = d->next) {
+        for (d = devices; d; d = d->next) {
             if (android_name_to_log_id(d->device) == log_msg.id()) {
                 break;
             }
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 153a3fd..4f517bb 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -76,7 +76,7 @@
 
 TEST(logcat, year) {
 
-    if (android_log_timestamp() == 'm') {
+    if (android_log_clockid() == CLOCK_MONOTONIC) {
         fprintf(stderr, "Skipping test, logd is monotonic time\n");
         return;
     }
@@ -147,7 +147,7 @@
 
 TEST(logcat, tz) {
 
-    if (android_log_timestamp() == 'm') {
+    if (android_log_clockid() == CLOCK_MONOTONIC) {
         fprintf(stderr, "Skipping test, logd is monotonic time\n");
         return;
     }
@@ -605,7 +605,7 @@
                 char c;
 
                 if ((2 == sscanf(buffer, "%d log.tx%c", &num, &c)) &&
-                        (num <= 24)) {
+                        (num <= 40)) {
                     ++count;
                 } else if (strncmp(buffer, total, sizeof(total) - 1)) {
                     fprintf(stderr, "WARNING: Parse error: %s", buffer);
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index eafa28f..7394f11 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -27,13 +27,14 @@
 
 #include <string>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 #include <cutils/sockets.h>
 #include <private/android_filesystem_config.h>
 #include <sysutils/SocketClient.h>
 
 #include "CommandListener.h"
 #include "LogCommand.h"
+#include "LogUtils.h"
 
 CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
                                  LogListener * /*swl*/) :
@@ -209,9 +210,20 @@
     }
 
     unsigned int logMask = -1;
+    pid_t pid = 0;
     if (argc > 1) {
         logMask = 0;
         for (int i = 1; i < argc; ++i) {
+            static const char _pid[] = "pid=";
+            if (!strncmp(argv[i], _pid, sizeof(_pid) - 1)) {
+                pid = atol(argv[i] + sizeof(_pid) - 1);
+                if (pid == 0) {
+                    cli->sendMsg("PID Error");
+                    return 0;
+                }
+                continue;
+            }
+
             int id = atoi(argv[i]);
             if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
                 cli->sendMsg("Range Error");
@@ -221,7 +233,8 @@
         }
     }
 
-    cli->sendMsg(package_string(mBuf.formatStatistics(uid, logMask)).c_str());
+    cli->sendMsg(package_string(mBuf.formatStatistics(uid, pid,
+                                                      logMask)).c_str());
     return 0;
 }
 
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index 823a842..cb3d1c2 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -21,19 +21,22 @@
 #include "LogCommand.h"
 #include "LogReader.h"
 #include "LogTimes.h"
+#include "LogUtils.h"
 
 FlushCommand::FlushCommand(LogReader &reader,
                            bool nonBlock,
                            unsigned long tail,
                            unsigned int logMask,
                            pid_t pid,
-                           uint64_t start) :
+                           uint64_t start,
+                           uint64_t timeout) :
         mReader(reader),
         mNonBlock(nonBlock),
         mTail(tail),
         mLogMask(logMask),
         mPid(pid),
-        mStart(start) {
+        mStart(start),
+        mTimeout(timeout) {
 }
 
 // runSocketCommand is called once for every open client on the
@@ -54,6 +57,10 @@
     while(it != times.end()) {
         entry = (*it);
         if (entry->mClient == client) {
+            if (entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec) {
+                LogTimeEntry::unlock();
+                return;
+            }
             entry->triggerReader_Locked();
             if (entry->runningReader_Locked()) {
                 LogTimeEntry::unlock();
@@ -71,7 +78,8 @@
             LogTimeEntry::unlock();
             return;
         }
-        entry = new LogTimeEntry(mReader, client, mNonBlock, mTail, mLogMask, mPid, mStart);
+        entry = new LogTimeEntry(mReader, client, mNonBlock, mTail, mLogMask,
+                                 mPid, mStart, mTimeout);
         times.push_front(entry);
     }
 
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
index 61c6858..e0f2212 100644
--- a/logd/FlushCommand.h
+++ b/logd/FlushCommand.h
@@ -32,6 +32,7 @@
     unsigned int mLogMask;
     pid_t mPid;
     uint64_t mStart;
+    uint64_t mTimeout;
 
 public:
     FlushCommand(LogReader &mReader,
@@ -39,7 +40,8 @@
                  unsigned long tail = -1,
                  unsigned int logMask = -1,
                  pid_t pid = 0,
-                 uint64_t start = 1);
+                 uint64_t start = 1,
+                 uint64_t timeout = 0);
     virtual void runSocketCommand(SocketClient *client);
 
     static bool hasReadLogs(SocketClient *client);
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index fd5c066..110395c 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -100,6 +100,12 @@
     unsigned long default_size = property_get_size(global_tuneable);
     if (!default_size) {
         default_size = property_get_size(global_default);
+        if (!default_size) {
+            default_size = property_get_bool("ro.config.low_ram",
+                                             BOOL_DEFAULT_FALSE)
+                ? LOG_BUFFER_MIN_SIZE // 64K
+                : LOG_BUFFER_SIZE;    // 256K
+        }
     }
 
     log_id_for_each(i) {
@@ -128,46 +134,62 @@
         }
     }
     bool lastMonotonic = monotonic;
-    monotonic = android_log_timestamp() == 'm';
-    if (lastMonotonic == monotonic) {
-        return;
+    monotonic = android_log_clockid() == CLOCK_MONOTONIC;
+    if (lastMonotonic != monotonic) {
+        //
+        // Fixup all timestamps, may not be 100% accurate, but better than
+        // throwing what we have away when we get 'surprised' by a change.
+        // In-place element fixup so no need to check reader-lock. Entries
+        // should already be in timestamp order, but we could end up with a
+        // few out-of-order entries if new monotonics come in before we
+        // are notified of the reinit change in status. A Typical example would
+        // be:
+        //  --------- beginning of system
+        //      10.494082   184   201 D Cryptfs : Just triggered post_fs_data
+        //  --------- beginning of kernel
+        //       0.000000     0     0 I         : Initializing cgroup subsys
+        // as the act of mounting /data would trigger persist.logd.timestamp to
+        // be corrected. 1/30 corner case YMMV.
+        //
+        pthread_mutex_lock(&mLogElementsLock);
+        LogBufferElementCollection::iterator it = mLogElements.begin();
+        while((it != mLogElements.end())) {
+            LogBufferElement *e = *it;
+            if (monotonic) {
+                if (!android::isMonotonic(e->mRealTime)) {
+                    LogKlog::convertRealToMonotonic(e->mRealTime);
+                }
+            } else {
+                if (android::isMonotonic(e->mRealTime)) {
+                    LogKlog::convertMonotonicToReal(e->mRealTime);
+                }
+            }
+            ++it;
+        }
+        pthread_mutex_unlock(&mLogElementsLock);
     }
 
+    // We may have been triggered by a SIGHUP. Release any sleeping reader
+    // threads to dump their current content.
     //
-    // Fixup all timestamps, may not be 100% accurate, but better than
-    // throwing what we have away when we get 'surprised' by a change.
-    // In-place element fixup so no need to check reader-lock. Entries
-    // should already be in timestamp order, but we could end up with a
-    // few out-of-order entries if new monotonics come in before we
-    // are notified of the reinit change in status. A Typical example would
-    // be:
-    //  --------- beginning of system
-    //      10.494082   184   201 D Cryptfs : Just triggered post_fs_data
-    //  --------- beginning of kernel
-    //       0.000000     0     0 I         : Initializing cgroup subsys cpuacct
-    // as the act of mounting /data would trigger persist.logd.timestamp to
-    // be corrected. 1/30 corner case YMMV.
-    //
-    pthread_mutex_lock(&mLogElementsLock);
-    LogBufferElementCollection::iterator it = mLogElements.begin();
-    while((it != mLogElements.end())) {
-        LogBufferElement *e = *it;
-        if (monotonic) {
-            if (!android::isMonotonic(e->mRealTime)) {
-                LogKlog::convertRealToMonotonic(e->mRealTime);
-            }
-        } else {
-            if (android::isMonotonic(e->mRealTime)) {
-                LogKlog::convertMonotonicToReal(e->mRealTime);
-            }
+    // NB: this is _not_ performed in the context of a SIGHUP, it is
+    // performed during startup, and in context of reinit administrative thread
+    LogTimeEntry::lock();
+
+    LastLogTimes::iterator times = mTimes.begin();
+    while(times != mTimes.end()) {
+        LogTimeEntry *entry = (*times);
+        if (entry->owned_Locked()) {
+            entry->triggerReader_Locked();
         }
-        ++it;
+        times++;
     }
-    pthread_mutex_unlock(&mLogElementsLock);
+
+    LogTimeEntry::unlock();
 }
 
 LogBuffer::LogBuffer(LastLogTimes *times):
-        monotonic(android_log_timestamp() == 'm'),
+        monotonic(android_log_clockid() == CLOCK_MONOTONIC),
         mTimes(*times) {
     pthread_mutex_init(&mLogElementsLock, NULL);
 
@@ -183,22 +205,24 @@
 
     LogBufferElement *elem = new LogBufferElement(log_id, realtime,
                                                   uid, pid, tid, msg, len);
-    int prio = ANDROID_LOG_INFO;
-    const char *tag = NULL;
-    if (log_id == LOG_ID_EVENTS) {
-        tag = android::tagToName(elem->getTag());
-    } else {
-        prio = *msg;
-        tag = msg + 1;
-    }
-    if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
-        // Log traffic received to total
-        pthread_mutex_lock(&mLogElementsLock);
-        stats.add(elem);
-        stats.subtract(elem);
-        pthread_mutex_unlock(&mLogElementsLock);
-        delete elem;
-        return -EACCES;
+    if (log_id != LOG_ID_SECURITY) {
+        int prio = ANDROID_LOG_INFO;
+        const char *tag = NULL;
+        if (log_id == LOG_ID_EVENTS) {
+            tag = android::tagToName(elem->getTag());
+        } else {
+            prio = *msg;
+            tag = msg + 1;
+        }
+        if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
+            // Log traffic received to total
+            pthread_mutex_lock(&mLogElementsLock);
+            stats.add(elem);
+            stats.subtract(elem);
+            pthread_mutex_unlock(&mLogElementsLock);
+            delete elem;
+            return -EACCES;
+        }
     }
 
     pthread_mutex_lock(&mLogElementsLock);
@@ -429,7 +453,10 @@
     while(t != mTimes.end()) {
         LogTimeEntry *entry = (*t);
         if (entry->owned_Locked() && entry->isWatching(id)
-                && (!oldest || (oldest->mStart > entry->mStart))) {
+                && (!oldest ||
+                    (oldest->mStart > entry->mStart) ||
+                    ((oldest->mStart == entry->mStart) &&
+                     (entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec)))) {
             oldest = entry;
         }
         t++;
@@ -448,8 +475,12 @@
             }
 
             if (oldest && (oldest->mStart <= e->getSequence())) {
-                oldest->triggerSkip_Locked(id, pruneRows);
                 busy = true;
+                if (oldest->mTimeout.tv_sec || oldest->mTimeout.tv_nsec) {
+                    oldest->triggerReader_Locked();
+                } else {
+                    oldest->triggerSkip_Locked(id, pruneRows);
+                }
                 break;
             }
 
@@ -461,7 +492,7 @@
     }
 
     // prune by worst offender by uid
-    bool hasBlacklist = mPrune.naughty();
+    bool hasBlacklist = (id != LOG_ID_SECURITY) && mPrune.naughty();
     while (!clearAll && (pruneRows > 0)) {
         // recalculate the worst offender on every batched pass
         uid_t worst = (uid_t) -1;
@@ -469,7 +500,8 @@
         size_t second_worst_sizes = 0;
 
         if (worstUidEnabledForLogid(id) && mPrune.worstUidEnabled()) {
-            std::unique_ptr<const UidEntry *[]> sorted = stats.sort(2, id);
+            std::unique_ptr<const UidEntry *[]> sorted = stats.sort(
+                AID_ROOT, (pid_t)0, 2, id);
 
             if (sorted.get()) {
                 if (sorted[0] && sorted[1]) {
@@ -523,6 +555,9 @@
 
             if (oldest && (oldest->mStart <= e->getSequence())) {
                 busy = true;
+                if (oldest->mTimeout.tv_sec || oldest->mTimeout.tv_nsec) {
+                    oldest->triggerReader_Locked();
+                }
                 break;
             }
 
@@ -628,7 +663,7 @@
     }
 
     bool whitelist = false;
-    bool hasWhitelist = mPrune.nice() && !clearAll;
+    bool hasWhitelist = (id != LOG_ID_SECURITY) && mPrune.nice() && !clearAll;
     it = mLogElements.begin();
     while((pruneRows > 0) && (it != mLogElements.end())) {
         LogBufferElement *e = *it;
@@ -648,6 +683,8 @@
             if (stats.sizes(id) > (2 * log_buffer_size(id))) {
                 // kick a misbehaving log reader client off the island
                 oldest->release_Locked();
+            } else if (oldest->mTimeout.tv_sec || oldest->mTimeout.tv_nsec) {
+                oldest->triggerReader_Locked();
             } else {
                 oldest->triggerSkip_Locked(id, pruneRows);
             }
@@ -680,6 +717,8 @@
                 if (stats.sizes(id) > (2 * log_buffer_size(id))) {
                     // kick a misbehaving log reader client off the island
                     oldest->release_Locked();
+                } else if (oldest->mTimeout.tv_sec || oldest->mTimeout.tv_nsec) {
+                    oldest->triggerReader_Locked();
                 } else {
                     oldest->triggerSkip_Locked(id, pruneRows);
                 }
@@ -816,7 +855,7 @@
         pthread_mutex_unlock(&mLogElementsLock);
 
         // range locking in LastLogTimes looks after us
-        max = element->flushTo(reader, this);
+        max = element->flushTo(reader, this, privileged);
 
         if (max == element->FLUSH_ERROR) {
             return max;
@@ -829,10 +868,11 @@
     return max;
 }
 
-std::string LogBuffer::formatStatistics(uid_t uid, unsigned int logMask) {
+std::string LogBuffer::formatStatistics(uid_t uid, pid_t pid,
+                                        unsigned int logMask) {
     pthread_mutex_lock(&mLogElementsLock);
 
-    std::string ret = stats.format(uid, logMask);
+    std::string ret = stats.format(uid, pid, logMask);
 
     pthread_mutex_unlock(&mLogElementsLock);
 
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index c1fec73..c1614e8 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -86,7 +86,7 @@
     int setSize(log_id_t id, unsigned long size);
     unsigned long getSizeUsed(log_id_t id);
     // *strp uses malloc, use free to release.
-    std::string formatStatistics(uid_t uid, unsigned int logMask);
+    std::string formatStatistics(uid_t uid, pid_t pid, unsigned int logMask);
 
     void enableStatistics() {
         stats.enableStatistics();
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index c4c302b..fde9ad7 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -51,7 +51,8 @@
 }
 
 uint32_t LogBufferElement::getTag() const {
-    if ((mLogId != LOG_ID_EVENTS) || !mMsg || (mMsgLen < sizeof(uint32_t))) {
+    if (((mLogId != LOG_ID_EVENTS) && (mLogId != LOG_ID_SECURITY)) ||
+            !mMsg || (mMsgLen < sizeof(uint32_t))) {
         return 0;
     }
     return le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag);
@@ -158,7 +159,9 @@
                           mDropped, (mDropped > 1) ? "s" : "");
 
     size_t hdrLen;
-    if (mLogId == LOG_ID_EVENTS) {
+    // LOG_ID_SECURITY not strictly needed since spam filter not activated,
+    // but required for accuracy.
+    if ((mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY)) {
         hdrLen = sizeof(android_log_event_string_t);
     } else {
         hdrLen = 1 + sizeof(tag);
@@ -172,7 +175,7 @@
     }
 
     size_t retval = hdrLen + len;
-    if (mLogId == LOG_ID_EVENTS) {
+    if ((mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY)) {
         android_log_event_string_t *event =
             reinterpret_cast<android_log_event_string_t *>(buffer);
 
@@ -194,21 +197,25 @@
     return retval;
 }
 
-uint64_t LogBufferElement::flushTo(SocketClient *reader, LogBuffer *parent) {
-    struct logger_entry_v3 entry;
+uint64_t LogBufferElement::flushTo(SocketClient *reader, LogBuffer *parent,
+                                   bool privileged) {
+    struct logger_entry_v4 entry;
 
-    memset(&entry, 0, sizeof(struct logger_entry_v3));
+    memset(&entry, 0, sizeof(struct logger_entry_v4));
 
-    entry.hdr_size = sizeof(struct logger_entry_v3);
+    entry.hdr_size = privileged ?
+                         sizeof(struct logger_entry_v4) :
+                         sizeof(struct logger_entry_v3);
     entry.lid = mLogId;
     entry.pid = mPid;
     entry.tid = mTid;
+    entry.uid = mUid;
     entry.sec = mRealTime.tv_sec;
     entry.nsec = mRealTime.tv_nsec;
 
     struct iovec iovec[2];
     iovec[0].iov_base = &entry;
-    iovec[0].iov_len = sizeof(struct logger_entry_v3);
+    iovec[0].iov_len = entry.hdr_size;
 
     char *buffer = NULL;
 
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 09987ea..e7f88b9 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -80,7 +80,7 @@
     uint32_t getTag(void) const;
 
     static const uint64_t FLUSH_ERROR;
-    uint64_t flushTo(SocketClient *writer, LogBuffer *parent);
+    uint64_t flushTo(SocketClient *writer, LogBuffer *parent, bool privileged);
 };
 
 #endif
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
index 6d0e92e..3b17576 100644
--- a/logd/LogCommand.cpp
+++ b/logd/LogCommand.cpp
@@ -22,6 +22,7 @@
 #include <private/android_filesystem_config.h>
 
 #include "LogCommand.h"
+#include "LogUtils.h"
 
 LogCommand::LogCommand(const char *cmd) : FrameworkCommand(cmd) {
 }
@@ -56,20 +57,18 @@
     return false;
 }
 
-bool clientHasLogCredentials(SocketClient * cli) {
-    uid_t uid = cli->getUid();
-    if (uid == AID_ROOT) {
+bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid) {
+    if ((uid == AID_ROOT) || (uid == AID_SYSTEM) || (uid == AID_LOG)) {
         return true;
     }
 
-    gid_t gid = cli->getGid();
     if ((gid == AID_ROOT) || (gid == AID_SYSTEM) || (gid == AID_LOG)) {
         return true;
     }
 
     // FYI We will typically be here for 'adb logcat'
     char filename[256];
-    snprintf(filename, sizeof(filename), "/proc/%u/status", cli->getPid());
+    snprintf(filename, sizeof(filename), "/proc/%u/status", pid);
 
     bool ret;
     bool foundLog = false;
@@ -145,3 +144,7 @@
 
     return ret;
 }
+
+bool clientHasLogCredentials(SocketClient *cli) {
+    return clientHasLogCredentials(cli->getUid(), cli->getGid(), cli->getPid());
+}
diff --git a/logd/LogCommand.h b/logd/LogCommand.h
index e3b96a2..c944478 100644
--- a/logd/LogCommand.h
+++ b/logd/LogCommand.h
@@ -26,6 +26,4 @@
     virtual ~LogCommand() {}
 };
 
-bool clientHasLogCredentials(SocketClient * cli);
-
 #endif
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index 2a3f52f..db7e682 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -778,6 +778,31 @@
     memcpy(np, p, b);
     np[b] = '\0';
 
+    if (!isMonotonic()) {
+        // Watch out for singular race conditions with timezone causing near
+        // integer quarter-hour jumps in the time and compensate accordingly.
+        // Entries will be temporal within near_seconds * 2. b/21868540
+        static uint32_t vote_time[3];
+        vote_time[2] = vote_time[1];
+        vote_time[1] = vote_time[0];
+        vote_time[0] = now.tv_sec;
+
+        if (vote_time[1] && vote_time[2]) {
+            static const unsigned near_seconds = 10;
+            static const unsigned timezones_seconds = 900;
+            int diff0 = (vote_time[0] - vote_time[1]) / near_seconds;
+            unsigned abs0 = (diff0 < 0) ? -diff0 : diff0;
+            int diff1 = (vote_time[1] - vote_time[2]) / near_seconds;
+            unsigned abs1 = (diff1 < 0) ? -diff1 : diff1;
+            if ((abs1 <= 1) && // last two were in agreement on timezone
+                    ((abs0 + 1) % (timezones_seconds / near_seconds)) <= 2) {
+                abs0 = (abs0 + 1) / (timezones_seconds / near_seconds) *
+                                     timezones_seconds;
+                now.tv_sec -= (diff0 < 0) ? -abs0 : abs0;
+            }
+        }
+    }
+
     // Log message
     int rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr,
                          (unsigned short) n);
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index b29f5ab..5348a2d 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -27,6 +27,7 @@
 #include <private/android_logger.h>
 
 #include "LogListener.h"
+#include "LogUtils.h"
 
 LogListener::LogListener(LogBuffer *buf, LogReader *reader) :
         SocketListener(getLogSocket(), false),
@@ -44,7 +45,6 @@
     char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time)
         + LOGGER_ENTRY_MAX_PAYLOAD];
     struct iovec iov = { buffer, sizeof(buffer) };
-    memset(buffer, 0, sizeof(buffer));
 
     char control[CMSG_SPACE(sizeof(struct ucred))];
     struct msghdr hdr = {
@@ -59,6 +59,9 @@
 
     int socket = cli->getSocket();
 
+    // To clear the entire buffer is secure/safe, but this contributes to 1.68%
+    // overhead under logging load. We are safe because we check counts.
+    // memset(buffer, 0, sizeof(buffer));
     ssize_t n = recvmsg(socket, &hdr, 0);
     if (n <= (ssize_t)(sizeof(android_log_header_t))) {
         return false;
@@ -92,6 +95,12 @@
         return false;
     }
 
+    if ((header->id == LOG_ID_SECURITY) &&
+            (!__android_log_security() ||
+             !clientHasLogCredentials(cred->uid, cred->gid, cred->pid))) {
+        return false;
+    }
+
     char *msg = ((char *)buffer) + sizeof(android_log_header_t);
     n -= sizeof(android_log_header_t);
 
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 06135dd..c2d65b6 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -67,6 +67,14 @@
         start.strptime(cp + sizeof(_start) - 1, "%s.%q");
     }
 
+    uint64_t timeout = 0;
+    static const char _timeout[] = " timeout=";
+    cp = strstr(buffer, _timeout);
+    if (cp) {
+        timeout = atol(cp + sizeof(_timeout) - 1) * NS_PER_SEC +
+                  log_time(CLOCK_REALTIME).nsec();
+    }
+
     unsigned int logMask = -1;
     static const char _logIds[] = " lids=";
     cp = strstr(buffer, _logIds);
@@ -166,7 +174,7 @@
         }
     }
 
-    FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence);
+    FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence, timeout);
     command.runSocketCommand(cli);
     return true;
 }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 416edd8..afaefc2 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -85,7 +85,11 @@
 
     uint32_t tag = element->getTag();
     if (tag) {
-        tagTable.add(tag, element);
+        if (log_id == LOG_ID_SECURITY) {
+            securityTagTable.add(tag, element);
+        } else {
+            tagTable.add(tag, element);
+        }
     }
 }
 
@@ -113,7 +117,11 @@
 
     uint32_t tag = element->getTag();
     if (tag) {
-        tagTable.subtract(tag, element);
+        if (log_id == LOG_ID_SECURITY) {
+            securityTagTable.subtract(tag, element);
+        } else {
+            tagTable.subtract(tag, element);
+        }
     }
 }
 
@@ -197,7 +205,7 @@
 }
 
 std::string UidEntry::format(const LogStatistics &stat, log_id_t id) const {
-    uid_t uid = getKey();
+    uid_t uid = getUid();
     std::string name = android::base::StringPrintf("%u", uid);
     const char *nameTmp = stat.uidToName(uid);
     if (nameTmp) {
@@ -279,8 +287,8 @@
 
 std::string PidEntry::format(const LogStatistics &stat, log_id_t /* id */) const {
     uid_t uid = getUid();
-    std::string name = android::base::StringPrintf("%5u/%u",
-                                                   getKey(), uid);
+    pid_t pid = getPid();
+    std::string name = android::base::StringPrintf("%5u/%u", pid, uid);
     const char *nameTmp = getName();
     if (nameTmp) {
         name += android::base::StringPrintf(
@@ -317,7 +325,7 @@
 std::string TidEntry::format(const LogStatistics &stat, log_id_t /* id */) const {
     uid_t uid = getUid();
     std::string name = android::base::StringPrintf("%5u/%u",
-                                                   getKey(), uid);
+                                                   getTid(), uid);
     const char *nameTmp = getName();
     if (nameTmp) {
         name += android::base::StringPrintf(
@@ -380,7 +388,8 @@
     return formatLine(name, size, pruned);
 }
 
-std::string LogStatistics::format(uid_t uid, unsigned int logMask) const {
+std::string LogStatistics::format(uid_t uid, pid_t pid,
+                                  unsigned int logMask) const {
     static const unsigned short spaces_total = 19;
 
     // Report on total logging, current and for all time
@@ -453,19 +462,38 @@
         name = (uid == AID_ROOT)
             ? "Chattiest UIDs in %s log buffer:"
             : "Logging for your UID in %s log buffer:";
-        output += uidTable[id].format(*this, uid, name, id);
+        output += uidTable[id].format(*this, uid, pid, name, id);
     }
 
     if (enable) {
-        name = (uid == AID_ROOT) ? "Chattiest PIDs:" : "Logging for this PID:";
-        output += pidTable.format(*this, uid, name);
-        name = "Chattiest TIDs:";
-        output += tidTable.format(*this, uid, name);
+        name = ((uid == AID_ROOT) && !pid)
+            ? "Chattiest PIDs:"
+            : "Logging for this PID:";
+        output += pidTable.format(*this, uid, pid, name);
+        name = "Chattiest TIDs";
+        if (pid) {
+            name += android::base::StringPrintf(" for PID %d", pid);
+        }
+        name += ":";
+        output += tidTable.format(*this, uid, pid, name);
     }
 
     if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
-        name = "Chattiest events log buffer TAGs:";
-        output += tagTable.format(*this, uid, name, LOG_ID_EVENTS);
+        name = "Chattiest events log buffer TAGs";
+        if (pid) {
+            name += android::base::StringPrintf(" for PID %d", pid);
+        }
+        name += ":";
+        output += tagTable.format(*this, uid, pid, name, LOG_ID_EVENTS);
+    }
+
+    if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
+        name = "Chattiest security log buffer TAGs";
+        if (pid) {
+            name += android::base::StringPrintf(" for PID %d", pid);
+        }
+        name += ":";
+        output += securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
     }
 
     return output;
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 41f8b95..6d999d2 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -25,7 +25,7 @@
 #include <string>    // std::string
 #include <unordered_map>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 
@@ -47,7 +47,8 @@
     typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
     typedef typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
 
-    std::unique_ptr<const TEntry *[]> sort(size_t len) const {
+    std::unique_ptr<const TEntry *[]> sort(uid_t uid, pid_t pid,
+                                           size_t len) const {
         if (!len) {
             std::unique_ptr<const TEntry *[]> sorted(NULL);
             return sorted;
@@ -58,6 +59,14 @@
 
         for(const_iterator it = map.begin(); it != map.end(); ++it) {
             const TEntry &entry = it->second;
+
+            if ((uid != AID_ROOT) && (uid != entry.getUid())) {
+                continue;
+            }
+            if (pid && entry.getPid() && (pid != entry.getPid())) {
+                continue;
+            }
+
             size_t sizes = entry.getSizes();
             ssize_t index = len - 1;
             while ((!retval[index] || (sizes > retval[index]->getSizes()))
@@ -118,12 +127,13 @@
     std::string format(
             const LogStatistics &stat,
             uid_t uid,
+            pid_t pid,
             const std::string &name = std::string(""),
             log_id_t id = LOG_ID_MAX) const {
         static const size_t maximum_sorted_entries = 32;
         std::string output;
-        std::unique_ptr<const TEntry *[]> sorted = sort(maximum_sorted_entries);
-
+        std::unique_ptr<const TEntry *[]> sorted = sort(uid, pid,
+                                                        maximum_sorted_entries);
         if (!sorted.get()) {
             return output;
         }
@@ -136,9 +146,6 @@
             if (entry->getSizes() <= (sorted[0]->getSizes() / 100)) {
                 break;
             }
-            if ((uid != AID_ROOT) && (uid != entry->getUid())) {
-                continue;
-            }
             if (!headerPrinted) {
                 output += "\n\n";
                 output += entry->formatHeader(name, id);
@@ -217,14 +224,24 @@
 
 struct UidEntry : public EntryBaseDropped {
     const uid_t uid;
+    pid_t pid;
 
     UidEntry(LogBufferElement *element):
             EntryBaseDropped(element),
-            uid(element->getUid()) {
+            uid(element->getUid()),
+            pid(element->getPid()) {
     }
 
     inline const uid_t&getKey() const { return uid; }
-    inline const uid_t&getUid() const { return uid; }
+    inline const uid_t&getUid() const { return getKey(); }
+    inline const pid_t&getPid() const { return pid; }
+
+    inline void add(LogBufferElement *element) {
+        if (pid != element->getPid()) {
+            pid = -1;
+        }
+        EntryBase::add(element);
+    }
 
     std::string formatHeader(const std::string &name, log_id_t id) const;
     std::string format(const LogStatistics &stat, log_id_t id) const;
@@ -260,6 +277,7 @@
     ~PidEntry() { free(name); }
 
     const pid_t&getKey() const { return pid; }
+    const pid_t&getPid() const { return getKey(); }
     const uid_t&getUid() const { return uid; }
     const char*getName() const { return name; }
 
@@ -291,30 +309,36 @@
 
 struct TidEntry : public EntryBaseDropped {
     const pid_t tid;
+    pid_t pid;
     uid_t uid;
     char *name;
 
-    TidEntry(pid_t tid):
+    TidEntry(pid_t tid, pid_t pid):
             EntryBaseDropped(),
             tid(tid),
+            pid(pid),
             uid(android::pidToUid(tid)),
             name(android::tidToName(tid)) {
     }
     TidEntry(LogBufferElement *element):
             EntryBaseDropped(element),
             tid(element->getTid()),
+            pid(element->getPid()),
             uid(element->getUid()),
             name(android::tidToName(tid)) {
     }
     TidEntry(const TidEntry &element):
             EntryBaseDropped(element),
             tid(element.tid),
+            pid(element.pid),
             uid(element.uid),
             name(element.name ? strdup(element.name) : NULL) {
     }
     ~TidEntry() { free(name); }
 
     const pid_t&getKey() const { return tid; }
+    const pid_t&getTid() const { return getKey(); }
+    const pid_t&getPid() const { return pid; }
     const uid_t&getUid() const { return uid; }
     const char*getName() const { return name; }
 
@@ -330,8 +354,10 @@
 
     inline void add(LogBufferElement *element) {
         uid_t incomingUid = element->getUid();
-        if (getUid() != incomingUid) {
+        pid_t incomingPid = element->getPid();
+        if ((getUid() != incomingUid) || (getPid() != incomingPid)) {
             uid = incomingUid;
+            pid = incomingPid;
             free(name);
             name = android::tidToName(element->getTid());
         } else {
@@ -346,23 +372,28 @@
 
 struct TagEntry : public EntryBase {
     const uint32_t tag;
+    pid_t pid;
     uid_t uid;
 
     TagEntry(LogBufferElement *element):
             EntryBase(element),
             tag(element->getTag()),
+            pid(element->getPid()),
             uid(element->getUid()) {
     }
 
     const uint32_t&getKey() const { return tag; }
+    const pid_t&getPid() const { return pid; }
     const uid_t&getUid() const { return uid; }
     const char*getName() const { return android::tagToName(tag); }
 
     inline void add(LogBufferElement *element) {
-        uid_t incomingUid = element->getUid();
-        if (uid != incomingUid) {
+        if (uid != element->getUid()) {
             uid = -1;
         }
+        if (pid != element->getPid()) {
+            pid = -1;
+        }
         EntryBase::add(element);
     }
 
@@ -397,6 +428,9 @@
     typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
     tagTable_t tagTable;
 
+    // security tag list
+    tagTable_t securityTagTable;
+
 public:
     LogStatistics();
 
@@ -413,8 +447,9 @@
         --mDroppedElements[log_id];
     }
 
-    std::unique_ptr<const UidEntry *[]> sort(size_t len, log_id id) {
-        return uidTable[id].sort(len);
+    std::unique_ptr<const UidEntry *[]> sort(uid_t uid, pid_t pid,
+                                             size_t len, log_id id) {
+        return uidTable[id].sort(uid, pid, len);
     }
 
     // fast track current value by id only
@@ -426,7 +461,7 @@
     size_t sizesTotal(log_id_t id) const { return mSizesTotal[id]; }
     size_t elementsTotal(log_id_t id) const { return mElementsTotal[id]; }
 
-    std::string format(uid_t uid, unsigned int logMask) const;
+    std::string format(uid_t uid, pid_t pid, unsigned int logMask) const;
 
     // helper (must be locked directly or implicitly by mLogElementsLock)
     const char *pidToName(pid_t pid) const;
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 229be3c..b4c97a9 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <errno.h>
 #include <sys/prctl.h>
 
 #include "FlushCommand.h"
@@ -26,7 +27,7 @@
 LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client,
                            bool nonBlock, unsigned long tail,
                            unsigned int logMask, pid_t pid,
-                           uint64_t start) :
+                           uint64_t start, uint64_t timeout) :
         mRefCount(1),
         mRelease(false),
         mError(false),
@@ -42,6 +43,8 @@
         mStart(start),
         mNonBlock(nonBlock),
         mEnd(LogBufferElement::getCurrentSequence()) {
+    mTimeout.tv_sec = timeout / NS_PER_SEC;
+    mTimeout.tv_nsec = timeout % NS_PER_SEC;
     pthread_cond_init(&threadTriggeredCondition, NULL);
     cleanSkip_Locked();
 }
@@ -131,6 +134,19 @@
     uint64_t start = me->mStart;
 
     while (me->threadRunning && !me->isError_Locked()) {
+
+        if (me->mTimeout.tv_sec || me->mTimeout.tv_nsec) {
+            if (pthread_cond_timedwait(&me->threadTriggeredCondition,
+                                       &timesLock,
+                                       &me->mTimeout) == ETIMEDOUT) {
+                me->mTimeout.tv_sec = 0;
+                me->mTimeout.tv_nsec = 0;
+            }
+            if (!me->threadRunning || me->isError_Locked()) {
+                break;
+            }
+        }
+
         unlock();
 
         if (me->mTail) {
@@ -154,7 +170,9 @@
 
         me->cleanSkip_Locked();
 
-        pthread_cond_wait(&me->threadTriggeredCondition, &timesLock);
+        if (!me->mTimeout.tv_sec && !me->mTimeout.tv_nsec) {
+            pthread_cond_wait(&me->threadTriggeredCondition, &timesLock);
+        }
     }
 
     unlock();
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index 39bcdd4..1117088 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -50,10 +50,11 @@
 public:
     LogTimeEntry(LogReader &reader, SocketClient *client, bool nonBlock,
                  unsigned long tail, unsigned int logMask, pid_t pid,
-                 uint64_t start);
+                 uint64_t start, uint64_t timeout);
 
     SocketClient *mClient;
     uint64_t mStart;
+    struct timespec mTimeout;
     const bool mNonBlock;
     const uint64_t mEnd; // only relevant if mNonBlock
 
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index 533eb1c..fd4800e 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 
 #include <log/log.h>
+#include <sysutils/SocketClient.h>
 
 // Hijack this header as a common include file used by most all sources
 // to report some utilities defined here and there.
@@ -38,8 +39,22 @@
 
 }
 
+// Furnished in LogCommand.cpp
+bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid);
+bool clientHasLogCredentials(SocketClient *cli);
+
+// Furnished in main.cpp
+#define BOOL_DEFAULT_FLAG_TRUE_FALSE 0x1
+#define BOOL_DEFAULT_FALSE       0x0     // false if property not present
+#define BOOL_DEFAULT_TRUE        0x1     // true if property not present
+#define BOOL_DEFAULT_FLAG_PERSIST    0x2 // <key>, persist.<key>, ro.<key>
+#define BOOL_DEFAULT_FLAG_ENG        0x4 // off for user
+#define BOOL_DEFAULT_FLAG_SVELTE     0x8 // off for low_ram
+
+bool property_get_bool(const char *key, int def);
+
 static inline bool worstUidEnabledForLogid(log_id_t id) {
-    return (id != LOG_ID_CRASH) && (id != LOG_ID_KERNEL) && (id != LOG_ID_EVENTS);
+    return (id == LOG_ID_MAIN) || (id == LOG_ID_SYSTEM) || (id == LOG_ID_RADIO);
 }
 
 template <int (*cmp)(const char *l, const char *r, const size_t s)>
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index c71beb5..29e637e 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -16,7 +16,7 @@
 
 #include <ctype.h>
 
-#include <base/stringprintf.h>
+#include <android-base/stringprintf.h>
 #include <cutils/properties.h>
 
 #include "LogWhiteBlackList.h"
diff --git a/logd/README.property b/logd/README.property
index e4b23a9..019bd40 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -1,37 +1,53 @@
 The properties that logd responds to are:
 
 name                       type default  description
-logd.auditd                 bool  true   Enable selinux audit daemon
-logd.auditd.dmesg           bool  true   selinux audit messages duplicated and
+ro.logd.auditd             bool   true   Enable selinux audit daemon
+ro.logd.auditd.dmesg       bool   true   selinux audit messages duplicated and
                                          sent on to dmesg log
-logd.klogd                  bool depends Enable klogd daemon
-logd.statistics             bool depends Enable logcat -S statistics.
-ro.config.low_ram           bool  false  if true, logd.statistics & logd.klogd
-                                         default false
-ro.build.type               string       if user, logd.statistics & logd.klogd
-                                         default false
-persist.logd.logpersistd    string       Enable logpersist daemon, "logcatd"
+persist.logd.security      bool   false  Enable security buffer.
+ro.device_owner            bool   false  Override persist.logd.security to false
+ro.logd.kernel             bool+ svelte+ Enable klogd daemon
+ro.logd.statistics         bool+ svelte+ Enable logcat -S statistics.
+ro.build.type              string        if user, logd.statistics &
+                                         ro.logd.kernel default false.
+persist.logd.logpersistd   string        Enable logpersist daemon, "logcatd"
                                          turns on logcat -f in logd context
-persist.logd.size          number 256K   Global default size of the buffer for
+persist.logd.size          number  ro    Global default size of the buffer for
                                          all log ids at initial startup, at
                                          runtime use: logcat -b all -G <value>
-persist.logd.size.main     number 256K   Size of the buffer for the main log
-persist.logd.size.system   number 256K   Size of the buffer for the system log
-persist.logd.size.radio    number 256K   Size of the buffer for the radio log
-persist.logd.size.event    number 256K   Size of the buffer for the event log
-persist.logd.size.crash    number 256K   Size of the buffer for the crash log
-persist.logd.filter         string       Pruning filter to optimize content,
-                                         default is ro.logd.filter or
-                                         "~!" which means to prune the oldest
-                                         entries of chattiest UID. At runtime
-                                         use: logcat -P "<string>"
-persist.logd.timestamp      string       The recording timestamp source. Default
-                                         is ro.logd.timestamp. "m[onotonic]" is
-                                         the only supported key character,
-                                         otherwise assumes realtime.
+ro.logd.size               number svelte default for persist.logd.size
+persist.logd.size.<buffer> number  ro    Size of the buffer for <buffer> log
+ro.logd.size.<buffer>      number svelte default for persist.logd.size.<buffer>
+ro.config.low_ram          bool   false  if true, logd.statistics, logd.kernel
+                                         default false, logd.size 64K instead
+                                         of 256K.
+persist.logd.filter        string        Pruning filter to optimize content.
+                                         At runtime use: logcat -P "<string>"
+ro.logd.filter             string "~!"   default for persist.logd.filter.
+                                         This default means to prune the
+                                         oldest entries of chattiest UID.
+persist.logd.timestamp     string  ro    The recording timestamp source.
+                                         "m[onotonic]" is the only supported
+                                         key character, otherwise realtime.
+ro.logd.timestamp        string realtime default for persist.logd.timestamp
+log.tag                   string persist The global logging level, VERBOSE,
+                                         DEBUG, INFO, WARN, ERROR, ASSERT or
+                                         SILENT. Only the first character is
+                                         the key character.
+persist.log.tag            string build  default for log.tag
+log.tag.<tag>             string persist The <tag> specific logging level.
+persist.log.tag.<tag>      string build  default for log.tag.<tag>
 
 NB:
-- Number support multipliers (K or M) for convenience. Range is limited
+- bool+ - "true", "false" and comma separated list of "eng" (forced false if
+  ro.build.type is "user") or "svelte" (forced false if ro.config.low_ram is
+  true).
+- svelte - see ro.config.low_ram for details.
+- svelte+ - see ro.config.low_ram and ro.build.type for details.
+- ro - <base property> temporary override, ro.<base property> platform default.
+- persist - <base property> override, persist.<base property> platform default.
+- build - VERBOSE for native, DEBUG for jvm isLoggable, or developer option.
+- number - support multipliers (K or M) for convenience. Range is limited
   to between 64K and 256M for log buffer sizes. Individual log buffer ids
   such as main, system, ... override global default.
 - Pruning filter is of form of a space-separated list of [~][UID][/PID]
diff --git a/logd/main.cpp b/logd/main.cpp
index 8e75b37..ba56e57 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -143,18 +143,72 @@
 }
 
 // Property helper
-static bool property_get_bool(const char *key, bool def) {
-    char property[PROPERTY_VALUE_MAX];
-    property_get(key, property, "");
-
-    if (!strcasecmp(property, "true")) {
-        return true;
-    }
-    if (!strcasecmp(property, "false")) {
+static bool check_flag(const char *prop, const char *flag) {
+    const char *cp = strcasestr(prop, flag);
+    if (!cp) {
         return false;
     }
+    // We only will document comma (,)
+    static const char sep[] = ",:;|+ \t\f";
+    if ((cp != prop) && !strchr(sep, cp[-1])) {
+        return false;
+    }
+    cp += strlen(flag);
+    return !*cp || !!strchr(sep, *cp);
+}
 
-    return def;
+bool property_get_bool(const char *key, int flag) {
+    char def[PROPERTY_VALUE_MAX];
+    char property[PROPERTY_VALUE_MAX];
+    def[0] = '\0';
+    if (flag & BOOL_DEFAULT_FLAG_PERSIST) {
+        char newkey[PROPERTY_KEY_MAX];
+        snprintf(newkey, sizeof(newkey), "ro.%s", key);
+        property_get(newkey, property, "");
+        // persist properties set by /data require innoculation with
+        // logd-reinit. They may be set in init.rc early and function, but
+        // otherwise are defunct unless reset. Do not rely on persist
+        // properties for startup-only keys unless you are willing to restart
+        // logd daemon (not advised).
+        snprintf(newkey, sizeof(newkey), "persist.%s", key);
+        property_get(newkey, def, property);
+    }
+
+    property_get(key, property, def);
+
+    if (check_flag(property, "true")) {
+        return true;
+    }
+    if (check_flag(property, "false")) {
+        return false;
+    }
+    if (check_flag(property, "eng")) {
+       flag |= BOOL_DEFAULT_FLAG_ENG;
+    }
+    // this is really a "not" flag
+    if (check_flag(property, "svelte")) {
+       flag |= BOOL_DEFAULT_FLAG_SVELTE;
+    }
+
+    // Sanity Check
+    if (flag & (BOOL_DEFAULT_FLAG_SVELTE | BOOL_DEFAULT_FLAG_ENG)) {
+        flag &= ~BOOL_DEFAULT_FLAG_TRUE_FALSE;
+        flag |= BOOL_DEFAULT_TRUE;
+    }
+
+    if ((flag & BOOL_DEFAULT_FLAG_SVELTE)
+            && property_get_bool("ro.config.low_ram",
+                                 BOOL_DEFAULT_FALSE)) {
+        return false;
+    }
+    if (flag & BOOL_DEFAULT_FLAG_ENG) {
+        property_get("ro.build.type", property, "");
+        if (!strcmp(property, "user")) {
+            return false;
+        }
+    }
+
+    return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE;
 }
 
 // Remove the static, and use this variable
@@ -266,17 +320,6 @@
     return android_lookupEventTag(map, tag);
 }
 
-static bool property_get_bool_svelte(const char *key) {
-    bool not_user;
-    {
-        char property[PROPERTY_VALUE_MAX];
-        property_get("ro.build.type", property, "");
-        not_user = !!strcmp(property, "user");
-    }
-    return property_get_bool(key, not_user
-            && !property_get_bool("ro.config.low_ram", false));
-}
-
 static void readDmesg(LogAudit *al, LogKlog *kl) {
     if (!al && !kl) {
         return;
@@ -325,7 +368,11 @@
 // transitory per-client threads are created for each reader.
 int main(int argc, char *argv[]) {
     int fdPmesg = -1;
-    bool klogd = property_get_bool_svelte("logd.klogd");
+    bool klogd = property_get_bool("logd.kernel",
+                                   BOOL_DEFAULT_TRUE |
+                                   BOOL_DEFAULT_FLAG_PERSIST |
+                                   BOOL_DEFAULT_FLAG_ENG |
+                                   BOOL_DEFAULT_FLAG_SVELTE);
     if (klogd) {
         fdPmesg = open("/proc/kmsg", O_RDONLY | O_NDELAY);
     }
@@ -349,7 +396,7 @@
         memset(&p, 0, sizeof(p));
         p.fd = sock;
         p.events = POLLIN;
-        ret = TEMP_FAILURE_RETRY(poll(&p, 1, 100));
+        ret = TEMP_FAILURE_RETRY(poll(&p, 1, 1000));
         if (ret < 0) {
             return -errno;
         }
@@ -405,7 +452,11 @@
 
     signal(SIGHUP, reinit_signal_handler);
 
-    if (property_get_bool_svelte("logd.statistics")) {
+    if (property_get_bool("logd.statistics",
+                          BOOL_DEFAULT_TRUE |
+                          BOOL_DEFAULT_FLAG_PERSIST |
+                          BOOL_DEFAULT_FLAG_ENG |
+                          BOOL_DEFAULT_FLAG_SVELTE)) {
         logBuf->enableStatistics();
     }
 
@@ -439,12 +490,17 @@
     // initiated log messages. New log entries are added to LogBuffer
     // and LogReader is notified to send updates to connected clients.
 
-    bool auditd = property_get_bool("logd.auditd", true);
-
+    bool auditd = property_get_bool("logd.auditd",
+                                    BOOL_DEFAULT_TRUE |
+                                    BOOL_DEFAULT_FLAG_PERSIST);
     LogAudit *al = NULL;
     if (auditd) {
-        bool dmesg = property_get_bool("logd.auditd.dmesg", true);
-        al = new LogAudit(logBuf, reader, dmesg ? fdDmesg : -1);
+        al = new LogAudit(logBuf, reader,
+                          property_get_bool("logd.auditd.dmesg",
+                                            BOOL_DEFAULT_TRUE |
+                                            BOOL_DEFAULT_FLAG_PERSIST)
+                              ? fdDmesg
+                              : -1);
     }
 
     LogKlog *kl = NULL;
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 44fa95c..7d0dd44 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -26,8 +26,6 @@
 #include "log/log.h"
 #include "log/logger.h"
 
-#define __unused __attribute__((__unused__))
-
 /*
  * returns statistics
  */
@@ -112,18 +110,38 @@
             ++cp;
         }
         benchmark = cp;
+#ifdef DEBUG
+        char *end = strstr(benchmark, "\n");
+        if (end == NULL) {
+            end = benchmark + strlen(benchmark);
+        }
+        fprintf(stderr, "parse for spam counter in \"%.*s\"\n",
+                (int)(end - benchmark), benchmark);
+#endif
+        // content
         while (isdigit(*cp)) {
             ++cp;
         }
         while (isspace(*cp)) {
             ++cp;
         }
+        // optional +/- field?
+        if ((*cp == '-') || (*cp == '+')) {
+            while (isdigit(*++cp) ||
+                   (*cp == '.') || (*cp == '%') || (*cp == 'X')) {
+                ;
+            }
+            while (isspace(*cp)) {
+                ++cp;
+            }
+        }
+        // number of entries pruned
         unsigned long value = 0;
         while (isdigit(*cp)) {
             value = value * 10ULL + *cp - '0';
             ++cp;
         }
-        if (value > 100000UL) {
+        if (value > 10UL) {
             break;
         }
         benchmark = NULL;
@@ -176,7 +194,7 @@
     delete [] buf;
 }
 
-static void caught_signal(int signum __unused) { }
+static void caught_signal(int /* signum */) { }
 
 static void dump_log_msg(const char *prefix,
                          log_msg *msg, unsigned int version, int lid) {
@@ -223,6 +241,12 @@
     case 3:
         fprintf(stderr, "lid=system ");
         break;
+    case 4:
+        fprintf(stderr, "lid=crash ");
+        break;
+    case 5:
+        fprintf(stderr, "lid=kernel ");
+        break;
     default:
         if (lid >= 0) {
             fprintf(stderr, "lid=%d ", lid);
@@ -419,7 +443,7 @@
 
     EXPECT_GE(250000UL, ns[log_overhead]); // 126886 user
 
-    EXPECT_GE(10000UL, ns[log_latency]); // 5669 user space
+    EXPECT_GE(10000000UL, ns[log_latency]); // 1453559 user space (background cgroup)
 
     EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user
 
@@ -499,3 +523,68 @@
     // 50% threshold for SPAM filter (<20% typical, lots of engineering margin)
     ASSERT_GT(totalSize, nowSpamSize * 2);
 }
+
+TEST(logd, timeout) {
+    log_msg msg_wrap, msg_timeout;
+    bool content_wrap = false, content_timeout = false, written = false;
+    unsigned int alarm_wrap = 0, alarm_timeout = 0;
+    // A few tries to get it right just in case wrap kicks in due to
+    // content providers being active during the test.
+    int i = 3;
+
+    while (--i) {
+        int fd = socket_local_client("logdr",
+                                     ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                     SOCK_SEQPACKET);
+        ASSERT_LT(0, fd);
+
+        struct sigaction ignore, old_sigaction;
+        memset(&ignore, 0, sizeof(ignore));
+        ignore.sa_handler = caught_signal;
+        sigemptyset(&ignore.sa_mask);
+        sigaction(SIGALRM, &ignore, &old_sigaction);
+        unsigned int old_alarm = alarm(3);
+
+        static const char ask[] = "dumpAndClose lids=0,1,2,3,4,5 timeout=6";
+        written = write(fd, ask, sizeof(ask)) == sizeof(ask);
+        if (!written) {
+            alarm(old_alarm);
+            sigaction(SIGALRM, &old_sigaction, NULL);
+            close(fd);
+            continue;
+        }
+
+        content_wrap = recv(fd, msg_wrap.buf, sizeof(msg_wrap), 0) > 0;
+
+        alarm_wrap = alarm(5);
+
+        content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
+
+        alarm_timeout = alarm((old_alarm <= 0)
+            ? old_alarm
+            : (old_alarm > (1 + 3 - alarm_wrap))
+                ? old_alarm - 3 + alarm_wrap
+                : 2);
+        sigaction(SIGALRM, &old_sigaction, NULL);
+
+        close(fd);
+
+        if (!content_wrap && !alarm_wrap && content_timeout && !alarm_timeout) {
+            break;
+        }
+    }
+
+    if (content_wrap) {
+        dump_log_msg("wrap", &msg_wrap, 3, -1);
+    }
+
+    if (content_timeout) {
+        dump_log_msg("timeout", &msg_timeout, 3, -1);
+    }
+
+    EXPECT_TRUE(written);
+    EXPECT_FALSE(content_wrap);
+    EXPECT_EQ(0U, alarm_wrap);
+    EXPECT_TRUE(content_timeout);
+    EXPECT_NE(0U, alarm_timeout);
+}
diff --git a/metricsd/.clang-format b/metricsd/.clang-format
new file mode 100644
index 0000000..65d8277
--- /dev/null
+++ b/metricsd/.clang-format
@@ -0,0 +1,9 @@
+BasedOnStyle: Google
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+BinPackParameters: false
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+PointerAlignment: Left
+TabWidth: 2
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
index 97c0d28..2149a4b 100644
--- a/metricsd/Android.mk
+++ b/metricsd/Android.mk
@@ -18,8 +18,6 @@
 libmetrics_sources := \
   c_metrics_library.cc \
   metrics_library.cc \
-  serialization/metric_sample.cc \
-  serialization/serialization_utils.cc \
   timer.cc
 
 metrics_client_sources := \
@@ -30,18 +28,19 @@
   collectors/cpu_usage_collector.cc \
   collectors/disk_usage_collector.cc \
   metrics_collector.cc \
-  persistent_integer.cc \
+  metrics_collector_service_trampoline.cc \
+  persistent_integer.cc
 
 metricsd_common := \
   persistent_integer.cc \
-  serialization/metric_sample.cc \
-  serialization/serialization_utils.cc \
+  uploader/bn_metricsd_impl.cc \
+  uploader/crash_counters.cc \
   uploader/metrics_hashes.cc \
   uploader/metrics_log_base.cc \
   uploader/metrics_log.cc \
   uploader/sender_http.cc \
   uploader/system_profile_cache.cc \
-  uploader/upload_service.cc \
+  uploader/upload_service.cc
 
 metrics_collector_tests_sources := \
   collectors/averaged_statistics_collector_test.cc \
@@ -49,14 +48,13 @@
   metrics_collector_test.cc \
   metrics_library_test.cc \
   persistent_integer_test.cc \
-  serialization/serialization_utils_unittest.cc \
-  timer_test.cc \
+  timer_test.cc
 
 metricsd_tests_sources := \
   uploader/metrics_hashes_unittest.cc \
   uploader/metrics_log_base_unittest.cc \
   uploader/mock/sender_mock.cc \
-  uploader/upload_service_test.cc \
+  uploader/upload_service_test.cc
 
 metrics_CFLAGS := -Wall \
   -Wno-char-subscripts \
@@ -70,22 +68,50 @@
   -fvisibility=default
 metrics_includes := external/gtest/include \
   $(LOCAL_PATH)/include
-libmetrics_shared_libraries := libchrome libbrillo
+libmetrics_shared_libraries := libchrome libbinder libbrillo libutils
 metrics_collector_shared_libraries := $(libmetrics_shared_libraries) \
+  libbrillo-binder \
   libbrillo-dbus \
   libbrillo-http \
   libchrome-dbus \
   libdbus \
   libmetrics \
   librootdev \
-  libweaved \
+  libweaved
+
+metrics_collector_static_libraries := libmetricscollectorservice
 
 metricsd_shared_libraries := \
+  libbinder \
   libbrillo \
   libbrillo-http \
   libchrome \
   libprotobuf-cpp-lite \
   libupdate_engine_client \
+  libutils
+
+# Static proxy library for the metricsd binder interface.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := metricsd_binder_proxy
+LOCAL_SHARED_LIBRARIES := libbinder libutils
+LOCAL_SRC_FILES := aidl/android/brillo/metrics/IMetricsd.aidl
+include $(BUILD_STATIC_LIBRARY)
+
+# Static library for the metrics_collector binder interface.
+# ==========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libmetricscollectorservice
+LOCAL_SHARED_LIBRARIES := libbinder libbrillo-binder libchrome libutils
+LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_SRC_FILES := \
+  aidl/android/brillo/metrics/IMetricsCollectorService.aidl \
+  metrics_collector_service_impl.cc \
+  metrics_collector_service_client.cc
+LOCAL_RTTI_FLAG := -fno-rtti
+include $(BUILD_STATIC_LIBRARY)
 
 # Shared library for metrics.
 # ========================================================
@@ -100,6 +126,7 @@
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_SHARED_LIBRARIES := $(libmetrics_shared_libraries)
 LOCAL_SRC_FILES := $(libmetrics_sources)
+LOCAL_STATIC_LIBRARIES := metricsd_binder_proxy
 include $(BUILD_SHARED_LIBRARY)
 
 # CLI client for metrics.
@@ -114,6 +141,7 @@
 LOCAL_SHARED_LIBRARIES := $(libmetrics_shared_libraries) \
   libmetrics
 LOCAL_SRC_FILES := $(metrics_client_sources)
+LOCAL_STATIC_LIBRARIES := metricsd_binder_proxy
 include $(BUILD_EXECUTABLE)
 
 # Protobuf library for metricsd.
@@ -137,13 +165,13 @@
 LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
 LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
 LOCAL_INIT_RC := metrics_collector.rc
-LOCAL_REQUIRED_MODULES := \
-  metrics.json \
-  metrics.schema.json
+LOCAL_REQUIRED_MODULES := metrics.json
 LOCAL_RTTI_FLAG := -frtti
 LOCAL_SHARED_LIBRARIES := $(metrics_collector_shared_libraries)
 LOCAL_SRC_FILES := $(metrics_collector_common) \
   metrics_collector_main.cc
+LOCAL_STATIC_LIBRARIES := metricsd_binder_proxy \
+  $(metrics_collector_static_libraries)
 include $(BUILD_EXECUTABLE)
 
 # metricsd daemon.
@@ -158,9 +186,8 @@
 LOCAL_INIT_RC := metricsd.rc
 LOCAL_REQUIRED_MODULES := \
   metrics_collector
-LOCAL_RTTI_FLAG := -frtti
 LOCAL_SHARED_LIBRARIES := $(metricsd_shared_libraries)
-LOCAL_STATIC_LIBRARIES := metricsd_protos
+LOCAL_STATIC_LIBRARIES := metricsd_protos metricsd_binder_proxy
 LOCAL_SRC_FILES := $(metricsd_common) \
   metricsd_main.cc
 include $(BUILD_EXECUTABLE)
@@ -173,10 +200,9 @@
 LOCAL_CLANG := true
 LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
 LOCAL_CPPFLAGS := $(metrics_CPPFLAGS) -Wno-sign-compare
-LOCAL_RTTI_FLAG := -frtti
-LOCAL_SHARED_LIBRARIES := $(metricsd_shared_libraries) libmetrics
+LOCAL_SHARED_LIBRARIES := $(metricsd_shared_libraries)
 LOCAL_SRC_FILES := $(metricsd_tests_sources) $(metricsd_common)
-LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock metricsd_protos
+LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock metricsd_protos metricsd_binder_proxy
 include $(BUILD_NATIVE_TEST)
 
 # Unit tests for metrics_collector.
@@ -191,7 +217,8 @@
 LOCAL_SHARED_LIBRARIES := $(metrics_collector_shared_libraries)
 LOCAL_SRC_FILES := $(metrics_collector_tests_sources) \
   $(metrics_collector_common)
-LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock
+LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock metricsd_binder_proxy \
+  $(metrics_collector_static_libraries)
 include $(BUILD_NATIVE_TEST)
 
 # Weave schema files
@@ -199,13 +226,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := metrics.json
 LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/weaved/commands
-LOCAL_SRC_FILES := etc/weaved/commands/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := metrics.schema.json
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/weaved/states
-LOCAL_SRC_FILES := etc/weaved/states/$(LOCAL_MODULE)
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/weaved/traits
+LOCAL_SRC_FILES := etc/weaved/traits/$(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
diff --git a/metricsd/aidl/android/brillo/metrics/IMetricsCollectorService.aidl b/metricsd/aidl/android/brillo/metrics/IMetricsCollectorService.aidl
new file mode 100644
index 0000000..49f484f
--- /dev/null
+++ b/metricsd/aidl/android/brillo/metrics/IMetricsCollectorService.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+package android.brillo.metrics;
+
+interface IMetricsCollectorService {
+  oneway void notifyUserCrash();
+}
diff --git a/metricsd/aidl/android/brillo/metrics/IMetricsd.aidl b/metricsd/aidl/android/brillo/metrics/IMetricsd.aidl
new file mode 100644
index 0000000..aa3cb34
--- /dev/null
+++ b/metricsd/aidl/android/brillo/metrics/IMetricsd.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+package android.brillo.metrics;
+
+interface IMetricsd {
+  oneway void recordHistogram(String name, int sample, int min, int max,
+                              int nbuckets);
+  oneway void recordLinearHistogram(String name, int sample, int max);
+  oneway void recordSparseHistogram(String name, int sample);
+  oneway void recordCrash(String type);
+  String getHistogramsDump();
+}
diff --git a/metricsd/c_metrics_library.cc b/metricsd/c_metrics_library.cc
index 0503876..47a543e 100644
--- a/metricsd/c_metrics_library.cc
+++ b/metricsd/c_metrics_library.cc
@@ -66,14 +66,6 @@
   return lib->SendSparseToUMA(std::string(name), sample);
 }
 
-extern "C" int CMetricsLibrarySendUserActionToUMA(CMetricsLibrary handle,
-                                                  const char* action) {
-  MetricsLibrary* lib = reinterpret_cast<MetricsLibrary*>(handle);
-  if (lib == NULL)
-    return 0;
-  return lib->SendUserActionToUMA(std::string(action));
-}
-
 extern "C" int CMetricsLibrarySendCrashToUMA(CMetricsLibrary handle,
                                             const char* crash_kind) {
   MetricsLibrary* lib = reinterpret_cast<MetricsLibrary*>(handle);
diff --git a/metricsd/collectors/averaged_statistics_collector_test.cc b/metricsd/collectors/averaged_statistics_collector_test.cc
index 9c97f00..68f9f2f 100644
--- a/metricsd/collectors/averaged_statistics_collector_test.cc
+++ b/metricsd/collectors/averaged_statistics_collector_test.cc
@@ -16,11 +16,12 @@
 
 #include "averaged_statistics_collector.h"
 
+#include <memory>
+
 #include <inttypes.h>
 
 #include <base/files/file_util.h>
 #include <base/files/scoped_temp_dir.h>
-#include <base/memory/scoped_ptr.h>
 #include <base/strings/stringprintf.h>
 #include <gtest/gtest.h>
 
@@ -62,7 +63,7 @@
   }
 
   // Collector used for tests.
-  scoped_ptr<AveragedStatisticsCollector> collector_;
+  std::unique_ptr<AveragedStatisticsCollector> collector_;
 
   // Temporary directory used for tests.
   base::ScopedTempDir temp_dir_;
diff --git a/metricsd/constants.h b/metricsd/constants.h
index 3a7569b..4815888 100644
--- a/metricsd/constants.h
+++ b/metricsd/constants.h
@@ -18,8 +18,10 @@
 #define METRICS_CONSTANTS_H_
 
 namespace metrics {
-static const char kMetricsDirectory[] = "/data/misc/metrics/";
-static const char kMetricsEventsFileName[] = "uma-events";
+static const char kSharedMetricsDirectory[] = "/data/misc/metrics/";
+static const char kMetricsdDirectory[] = "/data/misc/metricsd/";
+static const char kMetricsCollectorDirectory[] =
+    "/data/misc/metrics_collector/";
 static const char kMetricsGUIDFileName[] = "Sysinfo.GUID";
 static const char kMetricsServer[] = "https://clients4.google.com/uma/v2";
 static const char kConsentFileName[] = "enabled";
diff --git a/metricsd/etc/weaved/commands/metrics.json b/metricsd/etc/weaved/commands/metrics.json
deleted file mode 100644
index b7f32d5..0000000
--- a/metricsd/etc/weaved/commands/metrics.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "_metrics": {
-    "_enableAnalyticsReporting": {
-      "minimalRole": "manager"
-    },
-    "_disableAnalyticsReporting": {
-      "minimalRole": "manager"
-    }
-  }
-}
diff --git a/metricsd/etc/weaved/states/metrics.schema.json b/metricsd/etc/weaved/states/metrics.schema.json
deleted file mode 100644
index 130ac46..0000000
--- a/metricsd/etc/weaved/states/metrics.schema.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "_metrics": {
-    "_AnalyticsReportingState": {
-      "enum": ["enabled", "disabled"],
-      "default": "disabled"
-    }
-  }
-}
diff --git a/metricsd/etc/weaved/traits/metrics.json b/metricsd/etc/weaved/traits/metrics.json
new file mode 100644
index 0000000..7583270
--- /dev/null
+++ b/metricsd/etc/weaved/traits/metrics.json
@@ -0,0 +1,20 @@
+{
+  "_metrics": {
+    "commands": {
+      "enableAnalyticsReporting": {
+        "minimalRole": "manager",
+        "parameters": {}
+      },
+      "disableAnalyticsReporting": {
+        "minimalRole": "manager",
+        "parameters": {}
+      }
+    },
+    "state": {
+      "analyticsReportingState": {
+        "type": "string",
+        "enum": [ "enabled", "disabled" ]
+      }
+    }
+  }
+}
diff --git a/metricsd/include/metrics/c_metrics_library.h b/metricsd/include/metrics/c_metrics_library.h
index 4e7e666..1e597c2 100644
--- a/metricsd/include/metrics/c_metrics_library.h
+++ b/metricsd/include/metrics/c_metrics_library.h
@@ -44,10 +44,6 @@
 int CMetricsLibrarySendSparseToUMA(CMetricsLibrary handle,
                                    const char* name, int sample);
 
-// C wrapper for MetricsLibrary::SendUserActionToUMA.
-int CMetricsLibrarySendUserActionToUMA(CMetricsLibrary handle,
-                                       const char* action);
-
 // C wrapper for MetricsLibrary::SendCrashToUMA.
 int CMetricsLibrarySendCrashToUMA(CMetricsLibrary handle,
                                   const char* crash_kind);
diff --git a/metricsd/include/metrics/metrics_collector_service_client.h b/metricsd/include/metrics/metrics_collector_service_client.h
new file mode 100644
index 0000000..c800eae
--- /dev/null
+++ b/metricsd/include/metrics/metrics_collector_service_client.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Client interface to IMetricsCollectorService.
+
+#ifndef METRICS_METRICS_COLLECTOR_SERVICE_CLIENT_H_
+#define METRICS_METRICS_COLLECTOR_SERVICE_CLIENT_H_
+
+#include "android/brillo/metrics/IMetricsCollectorService.h"
+
+class MetricsCollectorServiceClient {
+ public:
+  MetricsCollectorServiceClient() = default;
+  ~MetricsCollectorServiceClient() = default;
+
+  // Initialize.  Returns true if OK, or false if IMetricsCollectorService
+  // is not registered.
+  bool Init();
+
+  // Called by crash_reporter to report a userspace crash event.  Returns
+  // true if successfully called the IMetricsCollectorService method of the
+  // same name, or false if the service was not registered at Init() time.
+  bool notifyUserCrash();
+
+ private:
+  // IMetricsCollectorService binder proxy
+  android::sp<android::brillo::metrics::IMetricsCollectorService>
+      metrics_collector_service_;
+};
+
+#endif  // METRICS_METRICS_COLLECTOR_SERVICE_CLIENT_H_
diff --git a/metricsd/include/metrics/metrics_library.h b/metricsd/include/metrics/metrics_library.h
index d2e98c8..a1bb926 100644
--- a/metricsd/include/metrics/metrics_library.h
+++ b/metricsd/include/metrics/metrics_library.h
@@ -24,9 +24,17 @@
 #include <base/compiler_specific.h>
 #include <base/files/file_path.h>
 #include <base/macros.h>
-#include <base/memory/scoped_ptr.h>
+#include <binder/IServiceManager.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
+namespace android {
+namespace brillo {
+namespace metrics {
+class IMetricsd;
+}  // namespace metrics
+}  // namespace brillo
+}  // namespace android
+
 class MetricsLibraryInterface {
  public:
   virtual void Init() = 0;
@@ -36,7 +44,6 @@
   virtual bool SendEnumToUMA(const std::string& name, int sample, int max) = 0;
   virtual bool SendBoolToUMA(const std::string& name, bool sample) = 0;
   virtual bool SendSparseToUMA(const std::string& name, int sample) = 0;
-  virtual bool SendUserActionToUMA(const std::string& action) = 0;
   virtual ~MetricsLibraryInterface() {}
 };
 
@@ -106,18 +113,6 @@
   // |sample| is the 32-bit integer value to be recorded.
   bool SendSparseToUMA(const std::string& name, int sample) override;
 
-  // Sends a user action to Chrome for transport to UMA and returns true on
-  // success. This method results in the equivalent of an asynchronous
-  // non-blocking RPC to UserMetrics::RecordAction.  The new metric must be
-  // added to chrome/tools/extract_actions.py in the Chromium repository, which
-  // should then be run to generate a hash for the new action.
-  //
-  // Until http://crosbug.com/11125 is fixed, the metric must also be added to
-  // chrome/browser/chromeos/external_metrics.cc.
-  //
-  // |action| is the user-generated event (e.g., "MuteKeyPressed").
-  bool SendUserActionToUMA(const std::string& action) override;
-
   // Sends a signal to UMA that a crash of the given |crash_kind|
   // has occurred.  Used by UMA to generate stability statistics.
   bool SendCrashToUMA(const char *crash_kind);
@@ -130,6 +125,11 @@
   // number in the histograms dashboard).
   bool SendCrosEventToUMA(const std::string& event);
 
+  // Debugging only.
+  // Dumps the histograms aggregated since metricsd started into |dump|.
+  // Returns true iff the dump succeeds.
+  bool GetHistogramsDump(std::string* dump);
+
  private:
   friend class CMetricsLibraryTest;
   friend class MetricsLibraryTest;
@@ -152,6 +152,10 @@
                        char* buffer, int buffer_size,
                        bool* result);
 
+  // Connects to IMetricsd if the proxy does not exist or is not alive.
+  // Don't block if we fail to get the proxy for any reason.
+  bool CheckService();
+
   // Time at which we last checked if metrics were enabled.
   time_t cached_enabled_time_;
 
@@ -161,7 +165,8 @@
   // True iff we should cache the enabled/disabled status.
   bool use_caching_;
 
-  base::FilePath uma_events_file_;
+  android::sp<android::IServiceManager> manager_;
+  android::sp<android::brillo::metrics::IMetricsd> metricsd_proxy_;
   base::FilePath consent_file_;
 
   DISALLOW_COPY_AND_ASSIGN(MetricsLibrary);
diff --git a/metricsd/include/metrics/metrics_library_mock.h b/metricsd/include/metrics/metrics_library_mock.h
index db56f9e..3b0b24d 100644
--- a/metricsd/include/metrics/metrics_library_mock.h
+++ b/metricsd/include/metrics/metrics_library_mock.h
@@ -34,7 +34,6 @@
                                    int max));
   MOCK_METHOD2(SendBoolToUMA, bool(const std::string& name, bool sample));
   MOCK_METHOD2(SendSparseToUMA, bool(const std::string& name, int sample));
-  MOCK_METHOD1(SendUserActionToUMA, bool(const std::string& action));
 
   bool AreMetricsEnabled() override {return metrics_enabled_;};
 };
diff --git a/metricsd/include/metrics/timer.h b/metricsd/include/metrics/timer.h
index b36ffff..c1b8ede 100644
--- a/metricsd/include/metrics/timer.h
+++ b/metricsd/include/metrics/timer.h
@@ -19,10 +19,10 @@
 #ifndef METRICS_TIMER_H_
 #define METRICS_TIMER_H_
 
+#include <memory>
 #include <string>
 
 #include <base/macros.h>
-#include <base/memory/scoped_ptr.h>
 #include <base/time/time.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
@@ -121,7 +121,7 @@
   TimerState timer_state_;
 
   // Wrapper for the calls to the system clock.
-  scoped_ptr<ClockWrapper> clock_wrapper_;
+  std::unique_ptr<ClockWrapper> clock_wrapper_;
 
   DISALLOW_COPY_AND_ASSIGN(Timer);
 };
diff --git a/metricsd/metrics_client.cc b/metricsd/metrics_client.cc
index 78174ef..c66b975 100644
--- a/metricsd/metrics_client.cc
+++ b/metricsd/metrics_client.cc
@@ -17,19 +17,14 @@
 #include <cstdio>
 #include <cstdlib>
 
-#include <base/memory/scoped_vector.h>
-
 #include "constants.h"
 #include "metrics/metrics_library.h"
-#include "serialization/metric_sample.h"
-#include "serialization/serialization_utils.h"
 
 enum Mode {
-    kModeDumpLogs,
+    kModeDumpHistograms,
     kModeSendSample,
     kModeSendEnumSample,
     kModeSendSparseSample,
-    kModeSendUserAction,
     kModeSendCrosEvent,
     kModeHasConsent,
     kModeIsGuestMode,
@@ -41,19 +36,17 @@
           "        metrics_client -e   name sample max\n"
           "        metrics_client -s   name sample\n"
           "        metrics_client -v   event\n"
-          "        metrics_client -u action\n"
           "        metrics_client [-cdg]\n"
           "\n"
           "  default: send metric with integer values \n"
           "           |min| > 0, |min| <= sample < |max|\n"
           "  -c: return exit status 0 if user consents to stats, 1 otherwise,\n"
           "      in guest mode always return 1\n"
-          "  -d: dump cached logs to the console\n"
+          "  -d: dump the histograms recorded by metricsd to stdout\n"
           "  -e: send linear/enumeration histogram data\n"
           "  -g: return exit status 0 if machine in guest mode, 1 otherwise\n"
           "  -s: send a sparse histogram sample\n"
           "  -t: convert sample from double seconds to int milliseconds\n"
-          "  -u: send a user action to Chrome\n"
           "  -v: send a Platform.CrOSEvent enum histogram sample\n");
   exit(1);
 }
@@ -78,6 +71,20 @@
   return value;
 }
 
+static int DumpHistograms() {
+  MetricsLibrary metrics_lib;
+  metrics_lib.Init();
+
+  std::string dump;
+  if (!metrics_lib.GetHistogramsDump(&dump)) {
+    printf("Failed to dump the histograms.");
+    return 1;
+  }
+
+  printf("%s\n", dump.c_str());
+  return 0;
+}
+
 static int SendStats(char* argv[],
                      int name_index,
                      enum Mode mode,
@@ -106,14 +113,6 @@
   return 0;
 }
 
-static int SendUserAction(char* argv[], int action_index) {
-  const char* action = argv[action_index];
-  MetricsLibrary metrics_lib;
-  metrics_lib.Init();
-  metrics_lib.SendUserActionToUMA(action);
-  return 0;
-}
-
 static int SendCrosEvent(char* argv[], int action_index) {
   const char* event = argv[action_index];
   bool result;
@@ -139,58 +138,19 @@
   return metrics_lib.IsGuestMode() ? 0 : 1;
 }
 
-static int DumpLogs() {
-  base::FilePath events_file = base::FilePath(
-      metrics::kMetricsDirectory).Append(metrics::kMetricsEventsFileName);
-  printf("Metrics from %s\n\n", events_file.value().data());
-
-  ScopedVector<metrics::MetricSample> metrics;
-  metrics::SerializationUtils::ReadMetricsFromFile(events_file.value(),
-                                                   &metrics);
-
-  for (ScopedVector<metrics::MetricSample>::const_iterator i = metrics.begin();
-       i != metrics.end(); ++i) {
-    const metrics::MetricSample* sample = *i;
-    printf("name: %s\t", sample->name().c_str());
-    printf("type: ");
-
-    switch (sample->type()) {
-      case metrics::MetricSample::CRASH:
-        printf("CRASH");
-        break;
-      case metrics::MetricSample::HISTOGRAM:
-        printf("HISTOGRAM");
-        break;
-      case metrics::MetricSample::LINEAR_HISTOGRAM:
-        printf("LINEAR_HISTOGRAM");
-        break;
-      case metrics::MetricSample::SPARSE_HISTOGRAM:
-        printf("SPARSE_HISTOGRAM");
-        break;
-      case metrics::MetricSample::USER_ACTION:
-        printf("USER_ACTION");
-        break;
-    }
-
-    printf("\n");
-  }
-
-  return 0;
-}
-
 int main(int argc, char** argv) {
   enum Mode mode = kModeSendSample;
   bool secs_to_msecs = false;
 
   // Parse arguments
   int flag;
-  while ((flag = getopt(argc, argv, "abcdegstuv")) != -1) {
+  while ((flag = getopt(argc, argv, "abcdegstv")) != -1) {
     switch (flag) {
       case 'c':
         mode = kModeHasConsent;
         break;
       case 'd':
-        mode = kModeDumpLogs;
+        mode = kModeDumpHistograms;
         break;
       case 'e':
         mode = kModeSendEnumSample;
@@ -204,9 +164,6 @@
       case 't':
         secs_to_msecs = true;
         break;
-      case 'u':
-        mode = kModeSendUserAction;
-        break;
       case 'v':
         mode = kModeSendCrosEvent;
         break;
@@ -224,8 +181,6 @@
     expected_args = 3;
   else if (mode == kModeSendSparseSample)
     expected_args = 2;
-  else if (mode == kModeSendUserAction)
-    expected_args = 1;
   else if (mode == kModeSendCrosEvent)
     expected_args = 1;
 
@@ -234,6 +189,8 @@
   }
 
   switch (mode) {
+    case kModeDumpHistograms:
+      return DumpHistograms();
     case kModeSendSample:
     case kModeSendEnumSample:
     case kModeSendSparseSample:
@@ -244,16 +201,12 @@
                        arg_index,
                        mode,
                        secs_to_msecs);
-    case kModeSendUserAction:
-      return SendUserAction(argv, arg_index);
     case kModeSendCrosEvent:
       return SendCrosEvent(argv, arg_index);
     case kModeHasConsent:
       return HasConsent();
     case kModeIsGuestMode:
       return IsGuestMode();
-    case kModeDumpLogs:
-      return DumpLogs();
     default:
       ShowUsage();
       return 0;
diff --git a/metricsd/metrics_collector.cc b/metricsd/metrics_collector.cc
index 28194a1..a5daab5 100644
--- a/metricsd/metrics_collector.cc
+++ b/metricsd/metrics_collector.cc
@@ -19,6 +19,8 @@
 #include <sysexits.h>
 #include <time.h>
 
+#include <memory>
+
 #include <base/bind.h>
 #include <base/files/file_path.h>
 #include <base/files/file_util.h>
@@ -33,6 +35,7 @@
 #include <dbus/message.h>
 
 #include "constants.h"
+#include "metrics_collector_service_trampoline.h"
 
 using base::FilePath;
 using base::StringPrintf;
@@ -40,19 +43,12 @@
 using base::TimeDelta;
 using base::TimeTicks;
 using chromeos_metrics::PersistentInteger;
-using com::android::Weave::CommandProxy;
-using com::android::Weave::ManagerProxy;
 using std::map;
 using std::string;
 using std::vector;
 
 namespace {
 
-const char kCrashReporterInterface[] = "org.chromium.CrashReporter";
-const char kCrashReporterUserCrashSignal[] = "UserCrash";
-const char kCrashReporterMatchRule[] =
-    "type='signal',interface='%s',path='/',member='%s'";
-
 const int kSecondsPerMinute = 60;
 const int kMinutesPerHour = 60;
 const int kHoursPerDay = 24;
@@ -73,6 +69,8 @@
 const char kMeminfoFileName[] = "/proc/meminfo";
 const char kVmStatFileName[] = "/proc/vmstat";
 
+const char kWeaveComponent[] = "metrics";
+
 }  // namespace
 
 // Zram sysfs entries.
@@ -130,6 +128,10 @@
     version_cumulative_cpu_use_->Set(0);
   }
 
+  // Start metricscollectorservice via trampoline
+  MetricsCollectorServiceTrampoline metricscollectorservice_trampoline(this);
+  metricscollectorservice_trampoline.Run();
+
   return brillo::DBusDaemon::Run();
 }
 
@@ -149,51 +151,54 @@
   return version_hash;
 }
 
-void MetricsCollector::Init(bool testing,
-                         MetricsLibraryInterface* metrics_lib,
-                         const string& diskstats_path,
-                         const base::FilePath& metrics_directory) {
+void MetricsCollector::Init(bool testing, MetricsLibraryInterface* metrics_lib,
+                            const string& diskstats_path,
+                            const base::FilePath& private_metrics_directory,
+                            const base::FilePath& shared_metrics_directory) {
   CHECK(metrics_lib);
   testing_ = testing;
-  metrics_directory_ = metrics_directory;
+  shared_metrics_directory_ = shared_metrics_directory;
   metrics_lib_ = metrics_lib;
 
-  daily_active_use_.reset(
-      new PersistentInteger("Platform.UseTime.PerDay"));
-  version_cumulative_active_use_.reset(
-      new PersistentInteger("Platform.CumulativeUseTime"));
-  version_cumulative_cpu_use_.reset(
-      new PersistentInteger("Platform.CumulativeCpuTime"));
+  daily_active_use_.reset(new PersistentInteger("Platform.UseTime.PerDay",
+                                                private_metrics_directory));
+  version_cumulative_active_use_.reset(new PersistentInteger(
+      "Platform.CumulativeUseTime", private_metrics_directory));
+  version_cumulative_cpu_use_.reset(new PersistentInteger(
+      "Platform.CumulativeCpuTime", private_metrics_directory));
 
-  kernel_crash_interval_.reset(
-      new PersistentInteger("Platform.KernelCrashInterval"));
-  unclean_shutdown_interval_.reset(
-      new PersistentInteger("Platform.UncleanShutdownInterval"));
-  user_crash_interval_.reset(
-      new PersistentInteger("Platform.UserCrashInterval"));
+  kernel_crash_interval_.reset(new PersistentInteger(
+      "Platform.KernelCrashInterval", private_metrics_directory));
+  unclean_shutdown_interval_.reset(new PersistentInteger(
+      "Platform.UncleanShutdownInterval", private_metrics_directory));
+  user_crash_interval_.reset(new PersistentInteger("Platform.UserCrashInterval",
+                                                   private_metrics_directory));
 
-  any_crashes_daily_count_.reset(
-      new PersistentInteger("Platform.AnyCrashes.PerDay"));
-  any_crashes_weekly_count_.reset(
-      new PersistentInteger("Platform.AnyCrashes.PerWeek"));
-  user_crashes_daily_count_.reset(
-      new PersistentInteger("Platform.UserCrashes.PerDay"));
-  user_crashes_weekly_count_.reset(
-      new PersistentInteger("Platform.UserCrashes.PerWeek"));
-  kernel_crashes_daily_count_.reset(
-      new PersistentInteger("Platform.KernelCrashes.PerDay"));
-  kernel_crashes_weekly_count_.reset(
-      new PersistentInteger("Platform.KernelCrashes.PerWeek"));
-  kernel_crashes_version_count_.reset(
-      new PersistentInteger("Platform.KernelCrashesSinceUpdate"));
-  unclean_shutdowns_daily_count_.reset(
-      new PersistentInteger("Platform.UncleanShutdown.PerDay"));
-  unclean_shutdowns_weekly_count_.reset(
-      new PersistentInteger("Platform.UncleanShutdowns.PerWeek"));
+  any_crashes_daily_count_.reset(new PersistentInteger(
+      "Platform.AnyCrashes.PerDay", private_metrics_directory));
+  any_crashes_weekly_count_.reset(new PersistentInteger(
+      "Platform.AnyCrashes.PerWeek", private_metrics_directory));
+  user_crashes_daily_count_.reset(new PersistentInteger(
+      "Platform.UserCrashes.PerDay", private_metrics_directory));
+  user_crashes_weekly_count_.reset(new PersistentInteger(
+      "Platform.UserCrashes.PerWeek", private_metrics_directory));
+  kernel_crashes_daily_count_.reset(new PersistentInteger(
+      "Platform.KernelCrashes.PerDay", private_metrics_directory));
+  kernel_crashes_weekly_count_.reset(new PersistentInteger(
+      "Platform.KernelCrashes.PerWeek", private_metrics_directory));
+  kernel_crashes_version_count_.reset(new PersistentInteger(
+      "Platform.KernelCrashesSinceUpdate", private_metrics_directory));
+  unclean_shutdowns_daily_count_.reset(new PersistentInteger(
+      "Platform.UncleanShutdown.PerDay", private_metrics_directory));
+  unclean_shutdowns_weekly_count_.reset(new PersistentInteger(
+      "Platform.UncleanShutdowns.PerWeek", private_metrics_directory));
 
-  daily_cycle_.reset(new PersistentInteger("daily.cycle"));
-  weekly_cycle_.reset(new PersistentInteger("weekly.cycle"));
-  version_cycle_.reset(new PersistentInteger("version.cycle"));
+  daily_cycle_.reset(
+      new PersistentInteger("daily.cycle", private_metrics_directory));
+  weekly_cycle_.reset(
+      new PersistentInteger("weekly.cycle", private_metrics_directory));
+  version_cycle_.reset(
+      new PersistentInteger("version.cycle", private_metrics_directory));
 
   disk_usage_collector_.reset(new DiskUsageCollector(metrics_lib_));
   averaged_stats_collector_.reset(
@@ -220,36 +225,17 @@
   bus_->AssertOnDBusThread();
   CHECK(bus_->SetUpAsyncOperations());
 
-  if (bus_->is_connected()) {
-    const std::string match_rule =
-        base::StringPrintf(kCrashReporterMatchRule,
-                           kCrashReporterInterface,
-                           kCrashReporterUserCrashSignal);
-
-    bus_->AddFilterFunction(&MetricsCollector::MessageFilter, this);
-
-    DBusError error;
-    dbus_error_init(&error);
-    bus_->AddMatch(match_rule, &error);
-
-    if (dbus_error_is_set(&error)) {
-      LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
-          << error.name << ": " << error.message;
-      return EX_SOFTWARE;
-    }
-  } else {
-    LOG(ERROR) << "DBus isn't connected.";
-    return EX_UNAVAILABLE;
-  }
-
   device_ = weaved::Device::CreateInstance(
       bus_,
       base::Bind(&MetricsCollector::UpdateWeaveState, base::Unretained(this)));
+  device_->AddComponent(kWeaveComponent, {"_metrics"});
   device_->AddCommandHandler(
-      "_metrics._enableAnalyticsReporting",
+      kWeaveComponent,
+      "_metrics.enableAnalyticsReporting",
       base::Bind(&MetricsCollector::OnEnableMetrics, base::Unretained(this)));
   device_->AddCommandHandler(
-      "_metrics._disableAnalyticsReporting",
+      kWeaveComponent,
+      "_metrics.disableAnalyticsReporting",
       base::Bind(&MetricsCollector::OnDisableMetrics, base::Unretained(this)));
 
   latest_cpu_use_microseconds_ = cpu_usage_collector_->GetCumulativeCpuUse();
@@ -262,23 +248,6 @@
 }
 
 void MetricsCollector::OnShutdown(int* return_code) {
-  if (!testing_ && bus_->is_connected()) {
-    const std::string match_rule =
-        base::StringPrintf(kCrashReporterMatchRule,
-                           kCrashReporterInterface,
-                           kCrashReporterUserCrashSignal);
-
-    bus_->RemoveFilterFunction(&MetricsCollector::MessageFilter, this);
-
-    DBusError error;
-    dbus_error_init(&error);
-    bus_->RemoveMatch(match_rule, &error);
-
-    if (dbus_error_is_set(&error)) {
-      LOG(ERROR) << "Failed to remove match rule \"" << match_rule << "\". Got "
-          << error.name << ": " << error.message;
-    }
-  }
   brillo::DBusDaemon::OnShutdown(return_code);
 }
 
@@ -288,8 +257,9 @@
   if (!command)
     return;
 
-  if (base::WriteFile(metrics_directory_.Append(metrics::kConsentFileName),
-                      "", 0) != 0) {
+  if (base::WriteFile(
+          shared_metrics_directory_.Append(metrics::kConsentFileName), "", 0) !=
+      0) {
     PLOG(ERROR) << "Could not create the consent file.";
     command->Abort("metrics_error", "Could not create the consent file",
                    nullptr);
@@ -306,8 +276,8 @@
   if (!command)
     return;
 
-  if (!base::DeleteFile(metrics_directory_.Append(metrics::kConsentFileName),
-                        false)) {
+  if (!base::DeleteFile(
+          shared_metrics_directory_.Append(metrics::kConsentFileName), false)) {
     PLOG(ERROR) << "Could not delete the consent file.";
     command->Abort("metrics_error", "Could not delete the consent file",
                    nullptr);
@@ -322,46 +292,17 @@
   if (!device_)
     return;
 
-  brillo::VariantDictionary state_change{
-    { "_metrics._AnalyticsReportingState",
-      metrics_lib_->AreMetricsEnabled() ? "enabled" : "disabled" }
-  };
+  std::string enabled =
+      metrics_lib_->AreMetricsEnabled() ? "enabled" : "disabled";
 
-  if (!device_->SetStateProperties(state_change, nullptr)) {
+  if (!device_->SetStateProperty(kWeaveComponent,
+                                 "_metrics.analyticsReportingState",
+                                 enabled,
+                                 nullptr)) {
     LOG(ERROR) << "failed to update weave's state";
   }
 }
 
-// static
-DBusHandlerResult MetricsCollector::MessageFilter(DBusConnection* connection,
-                                                   DBusMessage* message,
-                                                   void* user_data) {
-  int message_type = dbus_message_get_type(message);
-  if (message_type != DBUS_MESSAGE_TYPE_SIGNAL) {
-    DLOG(WARNING) << "unexpected message type " << message_type;
-    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-  }
-
-  // Signal messages always have interfaces.
-  const std::string interface(dbus_message_get_interface(message));
-  const std::string member(dbus_message_get_member(message));
-  DLOG(INFO) << "Got " << interface << "." << member << " D-Bus signal";
-
-  MetricsCollector* daemon = static_cast<MetricsCollector*>(user_data);
-
-  DBusMessageIter iter;
-  dbus_message_iter_init(message, &iter);
-  if (interface == kCrashReporterInterface) {
-    CHECK_EQ(member, kCrashReporterUserCrashSignal);
-    daemon->ProcessUserCrash();
-  } else {
-    // Ignore messages from the bus itself.
-    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-  }
-
-  return DBUS_HANDLER_RESULT_HANDLED;
-}
-
 void MetricsCollector::ProcessUserCrash() {
   // Counts the active time up to now.
   UpdateStats(TimeTicks::Now(), Time::Now());
@@ -726,7 +667,7 @@
 }
 
 void MetricsCollector::SendAndResetDailyUseSample(
-    const scoped_ptr<PersistentInteger>& use) {
+    const unique_ptr<PersistentInteger>& use) {
   SendSample(use->Name(),
              use->GetAndClear(),
              1,                        // value of first bucket
@@ -735,7 +676,7 @@
 }
 
 void MetricsCollector::SendAndResetCrashIntervalSample(
-    const scoped_ptr<PersistentInteger>& interval) {
+    const unique_ptr<PersistentInteger>& interval) {
   SendSample(interval->Name(),
              interval->GetAndClear(),
              1,                        // value of first bucket
@@ -744,7 +685,7 @@
 }
 
 void MetricsCollector::SendAndResetCrashFrequencySample(
-    const scoped_ptr<PersistentInteger>& frequency) {
+    const unique_ptr<PersistentInteger>& frequency) {
   SendSample(frequency->Name(),
              frequency->GetAndClear(),
              1,                        // value of first bucket
diff --git a/metricsd/metrics_collector.h b/metricsd/metrics_collector.h
index e080ac0..45ef63d 100644
--- a/metricsd/metrics_collector.h
+++ b/metricsd/metrics_collector.h
@@ -20,11 +20,11 @@
 #include <stdint.h>
 
 #include <map>
+#include <memory>
 #include <string>
 #include <vector>
 
 #include <base/files/file_path.h>
-#include <base/memory/scoped_ptr.h>
 #include <base/time/time.h>
 #include <brillo/daemons/dbus_daemon.h>
 #include <libweaved/command.h>
@@ -38,6 +38,7 @@
 #include "persistent_integer.h"
 
 using chromeos_metrics::PersistentInteger;
+using std::unique_ptr;
 
 class MetricsCollector : public brillo::DBusDaemon {
  public:
@@ -48,7 +49,8 @@
   void Init(bool testing,
             MetricsLibraryInterface* metrics_lib,
             const std::string& diskstats_path,
-            const base::FilePath& metrics_directory);
+            const base::FilePath& private_metrics_directory,
+            const base::FilePath& shared_metrics_directory);
 
   // Initializes DBus and MessageLoop variables before running the MessageLoop.
   int OnInit() override;
@@ -62,6 +64,10 @@
   // Returns the active time since boot (uptime minus sleep time) in seconds.
   static double GetActiveTime();
 
+  // Updates the active use time and logs time between user-space
+  // process crashes.  Called via MetricsCollectorServiceTrampoline.
+  void ProcessUserCrash();
+
  protected:
   // Used also by the unit tests.
   static const char kComprDataSizeName[];
@@ -107,11 +113,6 @@
     int value;               // value from /proc/meminfo
   };
 
-  // D-Bus filter callback.
-  static DBusHandlerResult MessageFilter(DBusConnection* connection,
-                                         DBusMessage* message,
-                                         void* user_data);
-
   // Enables metrics reporting.
   void OnEnableMetrics(const std::weak_ptr<weaved::Command>& cmd);
 
@@ -121,10 +122,6 @@
   // Updates the weave device state.
   void UpdateWeaveState();
 
-  // Updates the active use time and logs time between user-space
-  // process crashes.
-  void ProcessUserCrash();
-
   // Updates the active use time and logs time between kernel crashes.
   void ProcessKernelCrash();
 
@@ -155,18 +152,17 @@
 
   // Sends a sample representing the number of seconds of active use
   // for a 24-hour period and reset |use|.
-  void SendAndResetDailyUseSample(
-      const scoped_ptr<PersistentInteger>& use);
+  void SendAndResetDailyUseSample(const unique_ptr<PersistentInteger>& use);
 
   // Sends a sample representing a time interval between two crashes of the
   // same type and reset |interval|.
   void SendAndResetCrashIntervalSample(
-      const scoped_ptr<PersistentInteger>& interval);
+      const unique_ptr<PersistentInteger>& interval);
 
   // Sends a sample representing a frequency of crashes of some type and reset
   // |frequency|.
   void SendAndResetCrashFrequencySample(
-      const scoped_ptr<PersistentInteger>& frequency);
+      const unique_ptr<PersistentInteger>& frequency);
 
   // Initializes vm and disk stats reporting.
   void StatsReporterInit();
@@ -225,8 +221,8 @@
   // Test mode.
   bool testing_;
 
-  // Root of the configuration files to use.
-  base::FilePath metrics_directory_;
+  // Publicly readable metrics directory.
+  base::FilePath shared_metrics_directory_;
 
   // The metrics library handle.
   MetricsLibraryInterface* metrics_lib_;
@@ -245,36 +241,36 @@
   base::TimeDelta latest_cpu_use_microseconds_;
 
   // Persistent values and accumulators for crash statistics.
-  scoped_ptr<PersistentInteger> daily_cycle_;
-  scoped_ptr<PersistentInteger> weekly_cycle_;
-  scoped_ptr<PersistentInteger> version_cycle_;
+  unique_ptr<PersistentInteger> daily_cycle_;
+  unique_ptr<PersistentInteger> weekly_cycle_;
+  unique_ptr<PersistentInteger> version_cycle_;
 
   // Active use accumulated in a day.
-  scoped_ptr<PersistentInteger> daily_active_use_;
+  unique_ptr<PersistentInteger> daily_active_use_;
   // Active use accumulated since the latest version update.
-  scoped_ptr<PersistentInteger> version_cumulative_active_use_;
+  unique_ptr<PersistentInteger> version_cumulative_active_use_;
 
   // The CPU time accumulator.  This contains the CPU time, in milliseconds,
   // used by the system since the most recent OS version update.
-  scoped_ptr<PersistentInteger> version_cumulative_cpu_use_;
+  unique_ptr<PersistentInteger> version_cumulative_cpu_use_;
 
-  scoped_ptr<PersistentInteger> user_crash_interval_;
-  scoped_ptr<PersistentInteger> kernel_crash_interval_;
-  scoped_ptr<PersistentInteger> unclean_shutdown_interval_;
+  unique_ptr<PersistentInteger> user_crash_interval_;
+  unique_ptr<PersistentInteger> kernel_crash_interval_;
+  unique_ptr<PersistentInteger> unclean_shutdown_interval_;
 
-  scoped_ptr<PersistentInteger> any_crashes_daily_count_;
-  scoped_ptr<PersistentInteger> any_crashes_weekly_count_;
-  scoped_ptr<PersistentInteger> user_crashes_daily_count_;
-  scoped_ptr<PersistentInteger> user_crashes_weekly_count_;
-  scoped_ptr<PersistentInteger> kernel_crashes_daily_count_;
-  scoped_ptr<PersistentInteger> kernel_crashes_weekly_count_;
-  scoped_ptr<PersistentInteger> kernel_crashes_version_count_;
-  scoped_ptr<PersistentInteger> unclean_shutdowns_daily_count_;
-  scoped_ptr<PersistentInteger> unclean_shutdowns_weekly_count_;
+  unique_ptr<PersistentInteger> any_crashes_daily_count_;
+  unique_ptr<PersistentInteger> any_crashes_weekly_count_;
+  unique_ptr<PersistentInteger> user_crashes_daily_count_;
+  unique_ptr<PersistentInteger> user_crashes_weekly_count_;
+  unique_ptr<PersistentInteger> kernel_crashes_daily_count_;
+  unique_ptr<PersistentInteger> kernel_crashes_weekly_count_;
+  unique_ptr<PersistentInteger> kernel_crashes_version_count_;
+  unique_ptr<PersistentInteger> unclean_shutdowns_daily_count_;
+  unique_ptr<PersistentInteger> unclean_shutdowns_weekly_count_;
 
-  scoped_ptr<CpuUsageCollector> cpu_usage_collector_;
-  scoped_ptr<DiskUsageCollector> disk_usage_collector_;
-  scoped_ptr<AveragedStatisticsCollector> averaged_stats_collector_;
+  unique_ptr<CpuUsageCollector> cpu_usage_collector_;
+  unique_ptr<DiskUsageCollector> disk_usage_collector_;
+  unique_ptr<AveragedStatisticsCollector> averaged_stats_collector_;
 
   std::unique_ptr<weaved::Device> device_;
 };
diff --git a/metricsd/metrics_collector_main.cc b/metricsd/metrics_collector_main.cc
index 117426e..d7aaaf5 100644
--- a/metricsd/metrics_collector_main.cc
+++ b/metricsd/metrics_collector_main.cc
@@ -51,9 +51,13 @@
 int main(int argc, char** argv) {
   DEFINE_bool(foreground, false, "Don't daemonize");
 
-  DEFINE_string(metrics_directory,
-                metrics::kMetricsDirectory,
-                "Root of the configuration files (testing only)");
+  DEFINE_string(private_directory, metrics::kMetricsCollectorDirectory,
+                "Path to the private directory used by metrics_collector "
+                "(testing only)");
+  DEFINE_string(shared_directory, metrics::kSharedMetricsDirectory,
+                "Path to the shared metrics directory, used by "
+                "metrics_collector, metricsd and all metrics clients "
+                "(testing only)");
 
   DEFINE_bool(logtostderr, false, "Log to standard error");
   DEFINE_bool(logtosyslog, false, "Log to syslog");
@@ -86,7 +90,8 @@
   daemon.Init(false,
               &metrics_lib,
               MetricsMainDiskStatsPath(),
-              base::FilePath(FLAGS_metrics_directory));
+              base::FilePath(FLAGS_private_directory),
+              base::FilePath(FLAGS_shared_directory));
 
   daemon.Run();
 }
diff --git a/metricsd/metrics_collector_service_client.cc b/metricsd/metrics_collector_service_client.cc
new file mode 100644
index 0000000..08aaa4a
--- /dev/null
+++ b/metricsd/metrics_collector_service_client.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Client interface to IMetricsCollectorService.
+
+#include "metrics/metrics_collector_service_client.h"
+
+#include <base/logging.h>
+#include <binder/IServiceManager.h>
+#include <utils/String16.h>
+
+#include "android/brillo/metrics/IMetricsCollectorService.h"
+
+namespace {
+const char kMetricsCollectorServiceName[] =
+    "android.brillo.metrics.IMetricsCollectorService";
+}
+
+bool MetricsCollectorServiceClient::Init() {
+  const android::String16 name(kMetricsCollectorServiceName);
+  metrics_collector_service_ = android::interface_cast<
+      android::brillo::metrics::IMetricsCollectorService>(
+      android::defaultServiceManager()->checkService(name));
+
+  if (metrics_collector_service_ == nullptr)
+    LOG(ERROR) << "Unable to lookup service " << kMetricsCollectorServiceName;
+
+  return metrics_collector_service_ != nullptr;
+}
+
+bool MetricsCollectorServiceClient::notifyUserCrash() {
+  if (metrics_collector_service_ == nullptr)
+    return false;
+
+  metrics_collector_service_->notifyUserCrash();
+  return true;
+}
diff --git a/metricsd/metrics_collector_service_impl.cc b/metricsd/metrics_collector_service_impl.cc
new file mode 100644
index 0000000..dbb0578
--- /dev/null
+++ b/metricsd/metrics_collector_service_impl.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "metrics_collector_service_impl.h"
+
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+#include <brillo/binder_watcher.h>
+#include <utils/Errors.h>
+
+#include "metrics_collector_service_trampoline.h"
+
+using namespace android;
+
+BnMetricsCollectorServiceImpl::BnMetricsCollectorServiceImpl(
+    MetricsCollectorServiceTrampoline* metrics_collector_service_trampoline) {
+  metrics_collector_service_trampoline_ = metrics_collector_service_trampoline;
+}
+
+void BnMetricsCollectorServiceImpl::Run() {
+  status_t status =
+      defaultServiceManager()->addService(getInterfaceDescriptor(), this);
+  CHECK(status == OK) << "libmetricscollectorservice: failed to add service";
+  binder_watcher_.reset(new ::brillo::BinderWatcher);
+  CHECK(binder_watcher_->Init()) << "Binder FD watcher init failed";
+}
+
+android::binder::Status BnMetricsCollectorServiceImpl::notifyUserCrash() {
+  metrics_collector_service_trampoline_->ProcessUserCrash();
+  return android::binder::Status::ok();
+}
diff --git a/metricsd/metrics_collector_service_impl.h b/metricsd/metrics_collector_service_impl.h
new file mode 100644
index 0000000..bdcab50
--- /dev/null
+++ b/metricsd/metrics_collector_service_impl.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef METRICSD_METRICS_COLLECTOR_SERVICE_IMPL_H_
+#define METRICSD_METRICS_COLLECTOR_SERVICE_IMPL_H_
+
+// metrics_collector binder service implementation.  Constructed by
+// MetricsCollectorServiceTrampoline, which we use to call back into
+// MetricsCollector.  The trampoline isolates us from the -frtti code of
+// metrics_collector / libbrillo.
+
+#include "android/brillo/metrics/BnMetricsCollectorService.h"
+
+#include <memory>
+
+#include <binder/Status.h>
+#include <brillo/binder_watcher.h>
+
+class MetricsCollectorServiceTrampoline;
+
+//#include "metrics_collector_service_trampoline.h"
+
+class BnMetricsCollectorServiceImpl
+    : public android::brillo::metrics::BnMetricsCollectorService {
+ public:
+  // Passed a this pointer from the MetricsCollectorServiceTrampoline
+  // object that constructs us.
+  explicit BnMetricsCollectorServiceImpl(
+      MetricsCollectorServiceTrampoline* metrics_collector_service_trampoline);
+
+  virtual ~BnMetricsCollectorServiceImpl() = default;
+
+  // Starts the binder main loop.
+  void Run();
+
+  // Called by crash_reporter to report a userspace crash event.  We relay
+  // this to MetricsCollector using the trampoline.
+  android::binder::Status notifyUserCrash();
+
+ private:
+  // Trampoline object that constructs us, we use this to call MetricsCollector
+  // methods via the trampoline.
+  MetricsCollectorServiceTrampoline* metrics_collector_service_trampoline_;
+
+  // BinderWatcher object we construct for handling Binder traffic
+  std::unique_ptr<brillo::BinderWatcher> binder_watcher_;
+};
+
+#endif  // METRICSD_METRICS_COLLECTOR_SERVICE_IMPL_H_
diff --git a/metricsd/metrics_collector_service_trampoline.cc b/metricsd/metrics_collector_service_trampoline.cc
new file mode 100644
index 0000000..12b80a1
--- /dev/null
+++ b/metricsd/metrics_collector_service_trampoline.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "metrics_collector_service_trampoline.h"
+#include "metrics_collector.h"
+#include "metrics_collector_service_impl.h"
+
+MetricsCollectorServiceTrampoline::MetricsCollectorServiceTrampoline(
+    MetricsCollector* metrics_collector) {
+  metrics_collector_ = metrics_collector;
+}
+
+void MetricsCollectorServiceTrampoline::Run() {
+  // Start metricscollectorservice binder service
+  metrics_collector_service.reset(new BnMetricsCollectorServiceImpl(this));
+  metrics_collector_service->Run();
+}
+
+void MetricsCollectorServiceTrampoline::ProcessUserCrash() {
+  metrics_collector_->ProcessUserCrash();
+}
diff --git a/metricsd/metrics_collector_service_trampoline.h b/metricsd/metrics_collector_service_trampoline.h
new file mode 100644
index 0000000..5da9fa5
--- /dev/null
+++ b/metricsd/metrics_collector_service_trampoline.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef METRICSD_METRICS_COLLECTOR_SERVICE_TRAMPOLINE_H_
+#define METRICSD_METRICS_COLLECTOR_SERVICE_TRAMPOLINE_H_
+
+// Trampoline between the -fno-rtti compile of libmetricsservice and the
+// -frtti compile of metrics_collector.  MetricsCollectorServiceTrampoline
+// is called from MetricsCollector to run the IMetricsCollectorService
+// server, and acts as a go-between for calls from server back to
+// MetricsCollector.
+
+#include <memory>
+
+#include "metrics_collector_service_impl.h"
+
+// Forward declaration of MetricsCollector.  Don't include the header file
+// for the class here, as it pulls in -frtti stuff.
+class MetricsCollector;
+
+class MetricsCollectorServiceTrampoline {
+ public:
+  // Constructor take a this pointer from the MetricsCollector class that
+  // constructs these objects.
+  explicit MetricsCollectorServiceTrampoline(
+      MetricsCollector* metrics_collector);
+
+  // Initialize and run the IMetricsCollectorService
+  void Run();
+
+  // Called from IMetricsCollectorService to trampoline into the
+  // MetricsCollector method of the same name.
+  void ProcessUserCrash();
+
+ private:
+  // The MetricsCollector object that constructs us, for which we act as
+  // the go-between for MetricsCollectorServiceImpl use.
+  MetricsCollector* metrics_collector_;
+
+  // The IMetricsCollectorService implementation we construct.
+  std::unique_ptr<BnMetricsCollectorServiceImpl> metrics_collector_service;
+};
+
+#endif  // METRICSD_METRICS_COLLECTOR_SERVICE_TRAMPOLINE_H_
diff --git a/metricsd/metrics_collector_test.cc b/metricsd/metrics_collector_test.cc
index a0e7087..5fb3ac8 100644
--- a/metricsd/metrics_collector_test.cc
+++ b/metricsd/metrics_collector_test.cc
@@ -46,9 +46,13 @@
     brillo::FlagHelper::Init(0, nullptr, "");
     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
 
-    chromeos_metrics::PersistentInteger::SetMetricsDirectory(
-        temp_dir_.path().value());
-    daemon_.Init(true, &metrics_lib_, "", temp_dir_.path());
+    base::FilePath private_dir = temp_dir_.path().Append("private");
+    base::FilePath shared_dir = temp_dir_.path().Append("shared");
+
+    EXPECT_TRUE(base::CreateDirectory(private_dir));
+    EXPECT_TRUE(base::CreateDirectory(shared_dir));
+
+    daemon_.Init(true, &metrics_lib_, "", private_dir, shared_dir);
   }
 
   // Adds a metrics library mock expectation that the specified metric
@@ -111,37 +115,6 @@
   StrictMock<MetricsLibraryMock> metrics_lib_;
 };
 
-TEST_F(MetricsCollectorTest, MessageFilter) {
-  // Ignore calls to SendToUMA.
-  EXPECT_CALL(metrics_lib_, SendToUMA(_, _, _, _, _)).Times(AnyNumber());
-
-  DBusMessage* msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL);
-  DBusHandlerResult res =
-      MetricsCollector::MessageFilter(/* connection */ nullptr, msg, &daemon_);
-  EXPECT_EQ(DBUS_HANDLER_RESULT_NOT_YET_HANDLED, res);
-  DeleteDBusMessage(msg);
-
-  vector<string> signal_args;
-  msg = NewDBusSignalString("/",
-                            "org.chromium.CrashReporter",
-                            "UserCrash",
-                            signal_args);
-  res = MetricsCollector::MessageFilter(/* connection */ nullptr, msg, &daemon_);
-  EXPECT_EQ(DBUS_HANDLER_RESULT_HANDLED, res);
-  DeleteDBusMessage(msg);
-
-  signal_args.clear();
-  signal_args.push_back("randomstate");
-  signal_args.push_back("bob");  // arbitrary username
-  msg = NewDBusSignalString("/",
-                            "org.chromium.UnknownService.Manager",
-                            "StateChanged",
-                            signal_args);
-  res = MetricsCollector::MessageFilter(/* connection */ nullptr, msg, &daemon_);
-  EXPECT_EQ(DBUS_HANDLER_RESULT_NOT_YET_HANDLED, res);
-  DeleteDBusMessage(msg);
-}
-
 TEST_F(MetricsCollectorTest, SendSample) {
   ExpectSample("Dummy.Metric", 3);
   daemon_.SendSample("Dummy.Metric", /* sample */ 3,
diff --git a/metricsd/metrics_library.cc b/metricsd/metrics_library.cc
index 735d39f..d211ab4 100644
--- a/metricsd/metrics_library.cc
+++ b/metricsd/metrics_library.cc
@@ -18,19 +18,21 @@
 
 #include <base/logging.h>
 #include <base/strings/stringprintf.h>
+#include <binder/IServiceManager.h>
 #include <errno.h>
 #include <sys/file.h>
 #include <sys/stat.h>
+#include <utils/String16.h>
 
 #include <cstdio>
 #include <cstring>
 
+#include "android/brillo/metrics/IMetricsd.h"
 #include "constants.h"
-#include "serialization/metric_sample.h"
-#include "serialization/serialization_utils.h"
 
 static const char kCrosEventHistogramName[] = "Platform.CrOSEvent";
 static const int kCrosEventHistogramMax = 100;
+static const char kMetricsServiceName[] = "android.brillo.metrics.IMetricsd";
 
 /* Add new cros events here.
  *
@@ -53,6 +55,10 @@
   "TPM.EarlyResetDuringCommand",  // 12
 };
 
+using android::binder::Status;
+using android::brillo::metrics::IMetricsd;
+using android::String16;
+
 MetricsLibrary::MetricsLibrary() {}
 MetricsLibrary::~MetricsLibrary() {}
 
@@ -123,6 +129,17 @@
   return result && (access("/var/run/state/logged-in", F_OK) == 0);
 }
 
+bool MetricsLibrary::CheckService() {
+  if (metricsd_proxy_.get() &&
+      android::IInterface::asBinder(metricsd_proxy_)->isBinderAlive())
+    return true;
+
+  const String16 name(kMetricsServiceName);
+  metricsd_proxy_ = android::interface_cast<IMetricsd>(
+      android::defaultServiceManager()->checkService(name));
+  return metricsd_proxy_.get();
+}
+
 bool MetricsLibrary::AreMetricsEnabled() {
   static struct stat stat_buffer;
   time_t this_check_time = time(nullptr);
@@ -134,8 +151,7 @@
 }
 
 void MetricsLibrary::Init() {
-  base::FilePath dir = base::FilePath(metrics::kMetricsDirectory);
-  uma_events_file_ = dir.Append(metrics::kMetricsEventsFileName);
+  base::FilePath dir = base::FilePath(metrics::kSharedMetricsDirectory);
   consent_file_ = dir.Append(metrics::kConsentFileName);
   cached_enabled_ = false;
   cached_enabled_time_ = 0;
@@ -148,54 +164,45 @@
 }
 
 void MetricsLibrary::InitForTest(const base::FilePath& metrics_directory) {
-  uma_events_file_ = metrics_directory.Append(metrics::kMetricsEventsFileName);
   consent_file_ = metrics_directory.Append(metrics::kConsentFileName);
   cached_enabled_ = false;
   cached_enabled_time_ = 0;
   use_caching_ = true;
 }
 
-bool MetricsLibrary::SendToUMA(const std::string& name,
-                               int sample,
-                               int min,
-                               int max,
-                               int nbuckets) {
-  return metrics::SerializationUtils::WriteMetricToFile(
-      *metrics::MetricSample::HistogramSample(name, sample, min, max, nbuckets)
-           .get(),
-      uma_events_file_.value());
+bool MetricsLibrary::SendToUMA(
+    const std::string& name, int sample, int min, int max, int nbuckets) {
+  return CheckService() &&
+         metricsd_proxy_->recordHistogram(String16(name.c_str()), sample, min,
+                                          max, nbuckets)
+             .isOk();
 }
 
-bool MetricsLibrary::SendEnumToUMA(const std::string& name, int sample,
+bool MetricsLibrary::SendEnumToUMA(const std::string& name,
+                                   int sample,
                                    int max) {
-  return metrics::SerializationUtils::WriteMetricToFile(
-      *metrics::MetricSample::LinearHistogramSample(name, sample, max).get(),
-      uma_events_file_.value());
+  return CheckService() &&
+         metricsd_proxy_->recordLinearHistogram(String16(name.c_str()), sample,
+                                                max)
+             .isOk();
 }
 
 bool MetricsLibrary::SendBoolToUMA(const std::string& name, bool sample) {
-  return metrics::SerializationUtils::WriteMetricToFile(
-      *metrics::MetricSample::LinearHistogramSample(name,
-                                                    sample ? 1 : 0, 2).get(),
-      uma_events_file_.value());
+  return CheckService() &&
+         metricsd_proxy_->recordLinearHistogram(String16(name.c_str()),
+                                                sample ? 1 : 0, 2)
+             .isOk();
 }
 
 bool MetricsLibrary::SendSparseToUMA(const std::string& name, int sample) {
-  return metrics::SerializationUtils::WriteMetricToFile(
-      *metrics::MetricSample::SparseHistogramSample(name, sample).get(),
-      uma_events_file_.value());
+  return CheckService() &&
+         metricsd_proxy_->recordSparseHistogram(String16(name.c_str()), sample)
+             .isOk();
 }
 
-bool MetricsLibrary::SendUserActionToUMA(const std::string& action) {
-  return metrics::SerializationUtils::WriteMetricToFile(
-      *metrics::MetricSample::UserActionSample(action).get(),
-      uma_events_file_.value());
-}
-
-bool MetricsLibrary::SendCrashToUMA(const char *crash_kind) {
-  return metrics::SerializationUtils::WriteMetricToFile(
-      *metrics::MetricSample::CrashSample(crash_kind).get(),
-      uma_events_file_.value());
+bool MetricsLibrary::SendCrashToUMA(const char* crash_kind) {
+  return CheckService() &&
+         metricsd_proxy_->recordCrash(String16(crash_kind)).isOk();
 }
 
 bool MetricsLibrary::SendCrosEventToUMA(const std::string& event) {
@@ -206,3 +213,14 @@
   }
   return false;
 }
+
+bool MetricsLibrary::GetHistogramsDump(std::string* dump) {
+  android::String16 temp_dump;
+  if (!CheckService() ||
+      !metricsd_proxy_->getHistogramsDump(&temp_dump).isOk()) {
+    return false;
+  }
+
+  *dump = android::String8(temp_dump).string();
+  return true;
+}
diff --git a/metricsd/metrics_library_test.cc b/metricsd/metrics_library_test.cc
index be8a4bb..52fcce3 100644
--- a/metricsd/metrics_library_test.cc
+++ b/metricsd/metrics_library_test.cc
@@ -29,7 +29,6 @@
   virtual void SetUp() {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     lib_.InitForTest(temp_dir_.path());
-    EXPECT_EQ(0, WriteFile(lib_.uma_events_file_, "", 0));
     // Defeat metrics enabled caching between tests.
     lib_.cached_enabled_time_ = 0;
   }
diff --git a/metricsd/metricsd.rc b/metricsd/metricsd.rc
index b5e7b82..359d0d1 100644
--- a/metricsd/metricsd.rc
+++ b/metricsd/metricsd.rc
@@ -1,5 +1,7 @@
 on post-fs-data
     mkdir /data/misc/metrics 0770 system system
+    mkdir /data/misc/metricsd 0700 system system
+    mkdir /data/misc/metrics_collector 0700 system system
 
 service metricsd /system/bin/metricsd --foreground --logtosyslog
     class late_start
diff --git a/metricsd/metricsd_main.cc b/metricsd/metricsd_main.cc
index ab71e6b..f460268 100644
--- a/metricsd/metricsd_main.cc
+++ b/metricsd/metricsd_main.cc
@@ -14,46 +14,50 @@
  * limitations under the License.
  */
 
+#include <thread>
+
 #include <base/at_exit.h>
 #include <base/command_line.h>
 #include <base/files/file_path.h>
 #include <base/logging.h>
+#include <base/metrics/statistics_recorder.h>
 #include <base/strings/string_util.h>
 #include <base/time/time.h>
 #include <brillo/flag_helper.h>
 #include <brillo/syslog_logging.h>
 
 #include "constants.h"
+#include "uploader/bn_metricsd_impl.h"
+#include "uploader/crash_counters.h"
 #include "uploader/upload_service.h"
 
-
 int main(int argc, char** argv) {
   DEFINE_bool(foreground, false, "Don't daemonize");
 
   // Upload the metrics once and exit. (used for testing)
-  DEFINE_bool(uploader_test,
-              false,
-              "run the uploader once and exit");
+  DEFINE_bool(uploader_test, false, "run the uploader once and exit");
 
   // Upload Service flags.
-  DEFINE_int32(upload_interval_secs,
-               1800,
+  DEFINE_int32(upload_interval_secs, 1800,
                "Interval at which metrics_daemon sends the metrics. (needs "
                "-uploader)");
-  DEFINE_string(server,
-                metrics::kMetricsServer,
+  DEFINE_string(server, metrics::kMetricsServer,
                 "Server to upload the metrics to. (needs -uploader)");
-  DEFINE_string(metrics_directory,
-                metrics::kMetricsDirectory,
-                "Root of the configuration files (testing only)");
+  DEFINE_string(private_directory, metrics::kMetricsdDirectory,
+                "Path to the private directory used by metricsd "
+                "(testing only)");
+  DEFINE_string(shared_directory, metrics::kSharedMetricsDirectory,
+                "Path to the shared metrics directory, used by "
+                "metrics_collector, metricsd and all metrics clients "
+                "(testing only)");
 
   DEFINE_bool(logtostderr, false, "Log to standard error");
   DEFINE_bool(logtosyslog, false, "Log to syslog");
 
   brillo::FlagHelper::Init(argc, argv, "Brillo metrics daemon.");
 
-  int logging_location = (FLAGS_foreground ? brillo::kLogToStderr
-                          : brillo::kLogToSyslog);
+  int logging_location =
+      (FLAGS_foreground ? brillo::kLogToStderr : brillo::kLogToSyslog);
   if (FLAGS_logtosyslog)
     logging_location = brillo::kLogToSyslog;
 
@@ -72,9 +76,18 @@
     return errno;
   }
 
-  UploadService service(FLAGS_server,
-                        base::TimeDelta::FromSeconds(FLAGS_upload_interval_secs),
-                        base::FilePath(FLAGS_metrics_directory));
+  std::shared_ptr<CrashCounters> counters(new CrashCounters);
 
-  service.Run();
+  UploadService upload_service(
+      FLAGS_server, base::TimeDelta::FromSeconds(FLAGS_upload_interval_secs),
+      base::FilePath(FLAGS_private_directory),
+      base::FilePath(FLAGS_shared_directory), counters);
+
+  base::StatisticsRecorder::Initialize();
+
+  // Create and start the binder thread.
+  BnMetricsdImpl binder_service(counters);
+  std::thread binder_thread(&BnMetricsdImpl::Run, &binder_service);
+
+  upload_service.Run();
 }
diff --git a/metricsd/persistent_integer.cc b/metricsd/persistent_integer.cc
index ddc4b50..7fe355e 100644
--- a/metricsd/persistent_integer.cc
+++ b/metricsd/persistent_integer.cc
@@ -23,19 +23,15 @@
 
 #include "constants.h"
 
-
 namespace chromeos_metrics {
 
-// Static class member instantiation.
-std::string PersistentInteger::metrics_directory_ = metrics::kMetricsDirectory;
-
-PersistentInteger::PersistentInteger(const std::string& name) :
-      value_(0),
+PersistentInteger::PersistentInteger(const std::string& name,
+                                     const base::FilePath& directory)
+    : value_(0),
       version_(kVersion),
       name_(name),
-      synced_(false) {
-  backing_file_name_ = metrics_directory_ + name_;
-}
+      backing_file_path_(directory.Append(name_)),
+      synced_(false) {}
 
 PersistentInteger::~PersistentInteger() {}
 
@@ -62,23 +58,25 @@
 }
 
 void PersistentInteger::Write() {
-  int fd = HANDLE_EINTR(open(backing_file_name_.c_str(),
+  int fd = HANDLE_EINTR(open(backing_file_path_.value().c_str(),
                              O_WRONLY | O_CREAT | O_TRUNC,
                              S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH));
-  PCHECK(fd >= 0) << "cannot open " << backing_file_name_ << " for writing";
+  PCHECK(fd >= 0) << "cannot open " << backing_file_path_.value()
+                  << " for writing";
   PCHECK((HANDLE_EINTR(write(fd, &version_, sizeof(version_))) ==
           sizeof(version_)) &&
          (HANDLE_EINTR(write(fd, &value_, sizeof(value_))) ==
           sizeof(value_)))
-      << "cannot write to " << backing_file_name_;
+      << "cannot write to " << backing_file_path_.value();
   close(fd);
   synced_ = true;
 }
 
 bool PersistentInteger::Read() {
-  int fd = HANDLE_EINTR(open(backing_file_name_.c_str(), O_RDONLY));
+  int fd = HANDLE_EINTR(open(backing_file_path_.value().c_str(), O_RDONLY));
   if (fd < 0) {
-    PLOG(WARNING) << "cannot open " << backing_file_name_ << " for reading";
+    PLOG(WARNING) << "cannot open " << backing_file_path_.value()
+                  << " for reading";
     return false;
   }
   int32_t version;
@@ -95,9 +93,4 @@
   return read_succeeded;
 }
 
-void PersistentInteger::SetMetricsDirectory(const std::string& directory) {
-  metrics_directory_ = directory;
-}
-
-
 }  // namespace chromeos_metrics
diff --git a/metricsd/persistent_integer.h b/metricsd/persistent_integer.h
index ecef3d1..96d9fc0 100644
--- a/metricsd/persistent_integer.h
+++ b/metricsd/persistent_integer.h
@@ -21,6 +21,8 @@
 
 #include <string>
 
+#include <base/files/file_path.h>
+
 namespace chromeos_metrics {
 
 // PersistentIntegers is a named 64-bit integer value backed by a file.
@@ -29,7 +31,7 @@
 
 class PersistentInteger {
  public:
-  explicit PersistentInteger(const std::string& name);
+  PersistentInteger(const std::string& name, const base::FilePath& directory);
 
   // Virtual only because of mock.
   virtual ~PersistentInteger();
@@ -50,10 +52,6 @@
   // Virtual only because of mock.
   virtual void Add(int64_t x);
 
-  // Sets the directory path for all persistent integers.
-  // This is used in unittests to change where the counters are stored.
-  static void SetMetricsDirectory(const std::string& directory);
-
  private:
   static const int kVersion = 1001;
 
@@ -68,8 +66,7 @@
   int64_t value_;
   int32_t version_;
   std::string name_;
-  std::string backing_file_name_;
-  static std::string metrics_directory_;
+  base::FilePath backing_file_path_;
   bool synced_;
 };
 
diff --git a/metricsd/persistent_integer_mock.h b/metricsd/persistent_integer_mock.h
index acc5389..0be54d4 100644
--- a/metricsd/persistent_integer_mock.h
+++ b/metricsd/persistent_integer_mock.h
@@ -27,9 +27,10 @@
 
 class PersistentIntegerMock : public PersistentInteger {
  public:
-  explicit PersistentIntegerMock(const std::string& name)
-      : PersistentInteger(name) {}
-    MOCK_METHOD1(Add, void(int64_t count));
+  explicit PersistentIntegerMock(const std::string& name,
+                                 const base::FilePath& directory)
+      : PersistentInteger(name, directory) {}
+  MOCK_METHOD1(Add, void(int64_t count));
 };
 
 }  // namespace chromeos_metrics
diff --git a/metricsd/persistent_integer_test.cc b/metricsd/persistent_integer_test.cc
index 5e2067f..bf76261 100644
--- a/metricsd/persistent_integer_test.cc
+++ b/metricsd/persistent_integer_test.cc
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
+#include <memory>
 
 #include <base/compiler_specific.h>
 #include <base/files/file_enumerator.h>
 #include <base/files/file_util.h>
 #include <base/files/scoped_temp_dir.h>
+#include <gtest/gtest.h>
 
 #include "persistent_integer.h"
 
 const char kBackingFileName[] = "1.pibakf";
-const char kBackingFilePattern[] = "*.pibakf";
 
 using chromeos_metrics::PersistentInteger;
 
@@ -32,28 +32,15 @@
   void SetUp() override {
     // Set testing mode.
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    chromeos_metrics::PersistentInteger::SetMetricsDirectory(
-        temp_dir_.path().value());
   }
 
-  void TearDown() override {
-    // Remove backing files.  The convention is that they all end in ".pibakf".
-    base::FileEnumerator f_enum(base::FilePath("."),
-                                false,
-                                base::FileEnumerator::FILES,
-                                FILE_PATH_LITERAL(kBackingFilePattern));
-    for (base::FilePath name = f_enum.Next();
-         !name.empty();
-         name = f_enum.Next()) {
-      base::DeleteFile(name, false);
-    }
-  }
-
+ protected:
   base::ScopedTempDir temp_dir_;
 };
 
 TEST_F(PersistentIntegerTest, BasicChecks) {
-  scoped_ptr<PersistentInteger> pi(new PersistentInteger(kBackingFileName));
+  std::unique_ptr<PersistentInteger> pi(
+      new PersistentInteger(kBackingFileName, temp_dir_.path()));
 
   // Test initialization.
   EXPECT_EQ(0, pi->Get());
@@ -65,7 +52,7 @@
   EXPECT_EQ(5, pi->Get());
 
   // Test persistence.
-  pi.reset(new PersistentInteger(kBackingFileName));
+  pi.reset(new PersistentInteger(kBackingFileName, temp_dir_.path()));
   EXPECT_EQ(5, pi->Get());
 
   // Test GetAndClear.
@@ -73,6 +60,6 @@
   EXPECT_EQ(pi->Get(), 0);
 
   // Another persistence test.
-  pi.reset(new PersistentInteger(kBackingFileName));
+  pi.reset(new PersistentInteger(kBackingFileName, temp_dir_.path()));
   EXPECT_EQ(0, pi->Get());
 }
diff --git a/metricsd/serialization/metric_sample.cc b/metricsd/serialization/metric_sample.cc
deleted file mode 100644
index 76a47c0..0000000
--- a/metricsd/serialization/metric_sample.cc
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "serialization/metric_sample.h"
-
-#include <string>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/stringprintf.h"
-
-namespace metrics {
-
-MetricSample::MetricSample(MetricSample::SampleType sample_type,
-                           const std::string& metric_name,
-                           int sample,
-                           int min,
-                           int max,
-                           int bucket_count)
-    : type_(sample_type),
-      name_(metric_name),
-      sample_(sample),
-      min_(min),
-      max_(max),
-      bucket_count_(bucket_count) {
-}
-
-MetricSample::~MetricSample() {
-}
-
-bool MetricSample::IsValid() const {
-  return name().find(' ') == std::string::npos &&
-         name().find('\0') == std::string::npos && !name().empty();
-}
-
-std::string MetricSample::ToString() const {
-  if (type_ == CRASH) {
-    return base::StringPrintf("crash%c%s%c",
-                              '\0',
-                              name().c_str(),
-                              '\0');
-  } else if (type_ == SPARSE_HISTOGRAM) {
-    return base::StringPrintf("sparsehistogram%c%s %d%c",
-                              '\0',
-                              name().c_str(),
-                              sample_,
-                              '\0');
-  } else if (type_ == LINEAR_HISTOGRAM) {
-    return base::StringPrintf("linearhistogram%c%s %d %d%c",
-                              '\0',
-                              name().c_str(),
-                              sample_,
-                              max_,
-                              '\0');
-  } else if (type_ == HISTOGRAM) {
-    return base::StringPrintf("histogram%c%s %d %d %d %d%c",
-                              '\0',
-                              name().c_str(),
-                              sample_,
-                              min_,
-                              max_,
-                              bucket_count_,
-                              '\0');
-  } else {
-    // The type can only be USER_ACTION.
-    CHECK_EQ(type_, USER_ACTION);
-    return base::StringPrintf("useraction%c%s%c",
-                              '\0',
-                              name().c_str(),
-                              '\0');
-  }
-}
-
-int MetricSample::sample() const {
-  CHECK_NE(type_, USER_ACTION);
-  CHECK_NE(type_, CRASH);
-  return sample_;
-}
-
-int MetricSample::min() const {
-  CHECK_EQ(type_, HISTOGRAM);
-  return min_;
-}
-
-int MetricSample::max() const {
-  CHECK_NE(type_, CRASH);
-  CHECK_NE(type_, USER_ACTION);
-  CHECK_NE(type_, SPARSE_HISTOGRAM);
-  return max_;
-}
-
-int MetricSample::bucket_count() const {
-  CHECK_EQ(type_, HISTOGRAM);
-  return bucket_count_;
-}
-
-// static
-scoped_ptr<MetricSample> MetricSample::CrashSample(
-    const std::string& crash_name) {
-  return scoped_ptr<MetricSample>(
-      new MetricSample(CRASH, crash_name, 0, 0, 0, 0));
-}
-
-// static
-scoped_ptr<MetricSample> MetricSample::HistogramSample(
-    const std::string& histogram_name,
-    int sample,
-    int min,
-    int max,
-    int bucket_count) {
-  return scoped_ptr<MetricSample>(new MetricSample(
-      HISTOGRAM, histogram_name, sample, min, max, bucket_count));
-}
-
-// static
-scoped_ptr<MetricSample> MetricSample::ParseHistogram(
-    const std::string& serialized_histogram) {
-  std::vector<std::string> parts;
-  base::SplitString(serialized_histogram, ' ', &parts);
-
-  if (parts.size() != 5)
-    return scoped_ptr<MetricSample>();
-  int sample, min, max, bucket_count;
-  if (parts[0].empty() || !base::StringToInt(parts[1], &sample) ||
-      !base::StringToInt(parts[2], &min) ||
-      !base::StringToInt(parts[3], &max) ||
-      !base::StringToInt(parts[4], &bucket_count)) {
-    return scoped_ptr<MetricSample>();
-  }
-
-  return HistogramSample(parts[0], sample, min, max, bucket_count);
-}
-
-// static
-scoped_ptr<MetricSample> MetricSample::SparseHistogramSample(
-    const std::string& histogram_name,
-    int sample) {
-  return scoped_ptr<MetricSample>(
-      new MetricSample(SPARSE_HISTOGRAM, histogram_name, sample, 0, 0, 0));
-}
-
-// static
-scoped_ptr<MetricSample> MetricSample::ParseSparseHistogram(
-    const std::string& serialized_histogram) {
-  std::vector<std::string> parts;
-  base::SplitString(serialized_histogram, ' ', &parts);
-  if (parts.size() != 2)
-    return scoped_ptr<MetricSample>();
-  int sample;
-  if (parts[0].empty() || !base::StringToInt(parts[1], &sample))
-    return scoped_ptr<MetricSample>();
-
-  return SparseHistogramSample(parts[0], sample);
-}
-
-// static
-scoped_ptr<MetricSample> MetricSample::LinearHistogramSample(
-    const std::string& histogram_name,
-    int sample,
-    int max) {
-  return scoped_ptr<MetricSample>(
-      new MetricSample(LINEAR_HISTOGRAM, histogram_name, sample, 0, max, 0));
-}
-
-// static
-scoped_ptr<MetricSample> MetricSample::ParseLinearHistogram(
-    const std::string& serialized_histogram) {
-  std::vector<std::string> parts;
-  int sample, max;
-  base::SplitString(serialized_histogram, ' ', &parts);
-  if (parts.size() != 3)
-    return scoped_ptr<MetricSample>();
-  if (parts[0].empty() || !base::StringToInt(parts[1], &sample) ||
-      !base::StringToInt(parts[2], &max)) {
-    return scoped_ptr<MetricSample>();
-  }
-
-  return LinearHistogramSample(parts[0], sample, max);
-}
-
-// static
-scoped_ptr<MetricSample> MetricSample::UserActionSample(
-    const std::string& action_name) {
-  return scoped_ptr<MetricSample>(
-      new MetricSample(USER_ACTION, action_name, 0, 0, 0, 0));
-}
-
-bool MetricSample::IsEqual(const MetricSample& metric) {
-  return type_ == metric.type_ && name_ == metric.name_ &&
-         sample_ == metric.sample_ && min_ == metric.min_ &&
-         max_ == metric.max_ && bucket_count_ == metric.bucket_count_;
-}
-
-}  // namespace metrics
diff --git a/metricsd/serialization/metric_sample.h b/metricsd/serialization/metric_sample.h
deleted file mode 100644
index 5a4e4ae..0000000
--- a/metricsd/serialization/metric_sample.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_SERIALIZATION_METRIC_SAMPLE_H_
-#define METRICS_SERIALIZATION_METRIC_SAMPLE_H_
-
-#include <string>
-
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-
-namespace metrics {
-
-// This class is used by libmetrics (ChromeOS) to serialize
-// and deserialize measurements to send them to a metrics sending service.
-// It is meant to be a simple container with serialization functions.
-class MetricSample {
- public:
-  // Types of metric sample used.
-  enum SampleType {
-    CRASH,
-    HISTOGRAM,
-    LINEAR_HISTOGRAM,
-    SPARSE_HISTOGRAM,
-    USER_ACTION
-  };
-
-  ~MetricSample();
-
-  // Returns true if the sample is valid (can be serialized without ambiguity).
-  //
-  // This function should be used to filter bad samples before serializing them.
-  bool IsValid() const;
-
-  // Getters for type and name. All types of metrics have these so we do not
-  // need to check the type.
-  SampleType type() const { return type_; }
-  const std::string& name() const { return name_; }
-
-  // Getters for sample, min, max, bucket_count.
-  // Check the metric type to make sure the request make sense. (ex: a crash
-  // sample does not have a bucket_count so we crash if we call bucket_count()
-  // on it.)
-  int sample() const;
-  int min() const;
-  int max() const;
-  int bucket_count() const;
-
-  // Returns a serialized version of the sample.
-  //
-  // The serialized message for each type is:
-  // crash: crash\0|name_|\0
-  // user action: useraction\0|name_|\0
-  // histogram: histogram\0|name_| |sample_| |min_| |max_| |bucket_count_|\0
-  // sparsehistogram: sparsehistogram\0|name_| |sample_|\0
-  // linearhistogram: linearhistogram\0|name_| |sample_| |max_|\0
-  std::string ToString() const;
-
-  // Builds a crash sample.
-  static scoped_ptr<MetricSample> CrashSample(const std::string& crash_name);
-
-  // Builds a histogram sample.
-  static scoped_ptr<MetricSample> HistogramSample(
-      const std::string& histogram_name,
-      int sample,
-      int min,
-      int max,
-      int bucket_count);
-  // Deserializes a histogram sample.
-  static scoped_ptr<MetricSample> ParseHistogram(const std::string& serialized);
-
-  // Builds a sparse histogram sample.
-  static scoped_ptr<MetricSample> SparseHistogramSample(
-      const std::string& histogram_name,
-      int sample);
-  // Deserializes a sparse histogram sample.
-  static scoped_ptr<MetricSample> ParseSparseHistogram(
-      const std::string& serialized);
-
-  // Builds a linear histogram sample.
-  static scoped_ptr<MetricSample> LinearHistogramSample(
-      const std::string& histogram_name,
-      int sample,
-      int max);
-  // Deserializes a linear histogram sample.
-  static scoped_ptr<MetricSample> ParseLinearHistogram(
-      const std::string& serialized);
-
-  // Builds a user action sample.
-  static scoped_ptr<MetricSample> UserActionSample(
-      const std::string& action_name);
-
-  // Returns true if sample and this object represent the same sample (type,
-  // name, sample, min, max, bucket_count match).
-  bool IsEqual(const MetricSample& sample);
-
- private:
-  MetricSample(SampleType sample_type,
-               const std::string& metric_name,
-               const int sample,
-               const int min,
-               const int max,
-               const int bucket_count);
-
-  const SampleType type_;
-  const std::string name_;
-  const int sample_;
-  const int min_;
-  const int max_;
-  const int bucket_count_;
-
-  DISALLOW_COPY_AND_ASSIGN(MetricSample);
-};
-
-}  // namespace metrics
-
-#endif  // METRICS_SERIALIZATION_METRIC_SAMPLE_H_
diff --git a/metricsd/serialization/serialization_utils.cc b/metricsd/serialization/serialization_utils.cc
deleted file mode 100644
index 102c940..0000000
--- a/metricsd/serialization/serialization_utils.cc
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "serialization/serialization_utils.h"
-
-#include <sys/file.h>
-
-#include <string>
-#include <vector>
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "serialization/metric_sample.h"
-
-#define READ_WRITE_ALL_FILE_FLAGS \
-  (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
-
-namespace metrics {
-namespace {
-
-// Reads the next message from |file_descriptor| into |message|.
-//
-// |message| will be set to the empty string if no message could be read (EOF)
-// or the message was badly constructed.
-//
-// Returns false if no message can be read from this file anymore (EOF or
-// unrecoverable error).
-bool ReadMessage(int fd, std::string* message) {
-  CHECK(message);
-
-  int result;
-  int32_t message_size;
-  const int32_t message_hdr_size = sizeof(message_size);
-  // The file containing the metrics do not leave the device so the writer and
-  // the reader will always have the same endianness.
-  result = HANDLE_EINTR(read(fd, &message_size, sizeof(message_size)));
-  if (result < 0) {
-    DPLOG(ERROR) << "reading metrics message header";
-    return false;
-  }
-  if (result == 0) {
-    // This indicates a normal EOF.
-    return false;
-  }
-  if (result < message_hdr_size) {
-    DLOG(ERROR) << "bad read size " << result << ", expecting "
-                << sizeof(message_size);
-    return false;
-  }
-
-  // kMessageMaxLength applies to the entire message: the 4-byte
-  // length field and the content.
-  if (message_size > SerializationUtils::kMessageMaxLength) {
-    DLOG(ERROR) << "message too long : " << message_size;
-    if (HANDLE_EINTR(lseek(fd, message_size - 4, SEEK_CUR)) == -1) {
-      DLOG(ERROR) << "error while skipping message. abort";
-      return false;
-    }
-    // Badly formatted message was skipped. Treat the badly formatted sample as
-    // an empty sample.
-    message->clear();
-    return true;
-  }
-
-  if (message_size < message_hdr_size) {
-    DLOG(ERROR) << "message too short : " << message_size;
-    return false;
-  }
-
-  message_size -= message_hdr_size;  // The message size includes itself.
-  char buffer[SerializationUtils::kMessageMaxLength];
-  if (!base::ReadFromFD(fd, buffer, message_size)) {
-    DPLOG(ERROR) << "reading metrics message body";
-    return false;
-  }
-  *message = std::string(buffer, message_size);
-  return true;
-}
-
-
-// Opens the metrics log file at |filename| in the given |mode|.
-//
-// Returns the file descriptor wrapped in a valid ScopedFD on success.
-base::ScopedFD OpenMetricsFile(const std::string& filename, mode_t mode) {
-  struct stat stat_buf;
-  int result;
-
-  result = stat(filename.c_str(), &stat_buf);
-  if (result < 0) {
-    if (errno != ENOENT)
-      DPLOG(ERROR) << filename << ": bad metrics file stat";
-
-    // Nothing to collect---try later.
-    return base::ScopedFD();
-  }
-  if (stat_buf.st_size == 0) {
-    // Also nothing to collect.
-    return base::ScopedFD();
-  }
-  base::ScopedFD fd(open(filename.c_str(), mode));
-  if (fd.get() < 0) {
-    DPLOG(ERROR) << filename << ": cannot open";
-    return base::ScopedFD();
-  }
-
-  return fd.Pass();
-}
-
-
-// Parses the contents of the metrics log file descriptor |fd| into |metrics|.
-void ReadAllMetricsFromFd(int fd, ScopedVector<MetricSample>* metrics) {
-  for (;;) {
-    std::string message;
-
-    if (!ReadMessage(fd, &message))
-      break;
-
-    scoped_ptr<MetricSample> sample = SerializationUtils::ParseSample(message);
-    if (sample)
-      metrics->push_back(sample.release());
-  }
-}
-
-}  // namespace
-
-scoped_ptr<MetricSample> SerializationUtils::ParseSample(
-    const std::string& sample) {
-  if (sample.empty())
-    return scoped_ptr<MetricSample>();
-
-  std::vector<std::string> parts;
-  base::SplitString(sample, '\0', &parts);
-  // We should have two null terminated strings so split should produce
-  // three chunks.
-  if (parts.size() != 3) {
-    DLOG(ERROR) << "splitting message on \\0 produced " << parts.size()
-                << " parts (expected 3)";
-    return scoped_ptr<MetricSample>();
-  }
-  const std::string& name = parts[0];
-  const std::string& value = parts[1];
-
-  if (base::LowerCaseEqualsASCII(name, "crash")) {
-    return MetricSample::CrashSample(value);
-  } else if (base::LowerCaseEqualsASCII(name, "histogram")) {
-    return MetricSample::ParseHistogram(value);
-  } else if (base::LowerCaseEqualsASCII(name, "linearhistogram")) {
-    return MetricSample::ParseLinearHistogram(value);
-  } else if (base::LowerCaseEqualsASCII(name, "sparsehistogram")) {
-    return MetricSample::ParseSparseHistogram(value);
-  } else if (base::LowerCaseEqualsASCII(name, "useraction")) {
-    return MetricSample::UserActionSample(value);
-  } else {
-    DLOG(ERROR) << "invalid event type: " << name << ", value: " << value;
-  }
-  return scoped_ptr<MetricSample>();
-}
-
-void SerializationUtils::ReadMetricsFromFile(
-    const std::string& filename,
-    ScopedVector<MetricSample>* metrics) {
-  base::ScopedFD fd(OpenMetricsFile(filename, O_RDONLY));
-  if (!fd.is_valid()) {
-    return;
-  }
-
-  // This processes all messages in the log.
-  ReadAllMetricsFromFd(fd.get(), metrics);
-}
-
-void SerializationUtils::ReadAndTruncateMetricsFromFile(
-    const std::string& filename,
-    ScopedVector<MetricSample>* metrics) {
-  base::ScopedFD fd(OpenMetricsFile(filename, O_RDWR));
-  if (!fd.is_valid()) {
-    return;
-  }
-
-  int result = flock(fd.get(), LOCK_EX);
-  if (result < 0) {
-    DPLOG(ERROR) << filename << ": cannot lock";
-    return;
-  }
-
-  // This processes all messages in the log. When all messages are
-  // read and processed, or an error occurs, truncate the file to zero size.
-  ReadAllMetricsFromFd(fd.get(), metrics);
-
-  result = ftruncate(fd.get(), 0);
-  if (result < 0)
-    DPLOG(ERROR) << "truncate metrics log";
-
-  result = flock(fd.get(), LOCK_UN);
-  if (result < 0)
-    DPLOG(ERROR) << "unlock metrics log";
-}
-
-bool SerializationUtils::WriteMetricToFile(const MetricSample& sample,
-                                           const std::string& filename) {
-  if (!sample.IsValid())
-    return false;
-
-  base::ScopedFD file_descriptor(open(filename.c_str(),
-                                      O_WRONLY | O_APPEND | O_CREAT,
-                                      READ_WRITE_ALL_FILE_FLAGS));
-
-  if (file_descriptor.get() < 0) {
-    DPLOG(ERROR) << filename << ": cannot open";
-    return false;
-  }
-
-  fchmod(file_descriptor.get(), READ_WRITE_ALL_FILE_FLAGS);
-  // Grab a lock to avoid chrome truncating the file
-  // underneath us. Keep the file locked as briefly as possible.
-  // Freeing file_descriptor will close the file and and remove the lock.
-  if (HANDLE_EINTR(flock(file_descriptor.get(), LOCK_EX)) < 0) {
-    DPLOG(ERROR) << filename << ": cannot lock";
-    return false;
-  }
-
-  std::string msg = sample.ToString();
-  int32 size = msg.length() + sizeof(int32);
-  if (size > kMessageMaxLength) {
-    DLOG(ERROR) << "cannot write message: too long";
-    return false;
-  }
-
-  // The file containing the metrics samples will only be read by programs on
-  // the same device so we do not check endianness.
-  if (!base::WriteFileDescriptor(file_descriptor.get(),
-                                 reinterpret_cast<char*>(&size),
-                                 sizeof(size))) {
-    DPLOG(ERROR) << "error writing message length";
-    return false;
-  }
-
-  if (!base::WriteFileDescriptor(
-          file_descriptor.get(), msg.c_str(), msg.size())) {
-    DPLOG(ERROR) << "error writing message";
-    return false;
-  }
-
-  return true;
-}
-
-}  // namespace metrics
diff --git a/metricsd/serialization/serialization_utils.h b/metricsd/serialization/serialization_utils.h
deleted file mode 100644
index 655652d..0000000
--- a/metricsd/serialization/serialization_utils.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICS_SERIALIZATION_SERIALIZATION_UTILS_H_
-#define METRICS_SERIALIZATION_SERIALIZATION_UTILS_H_
-
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-
-namespace metrics {
-
-class MetricSample;
-
-// Metrics helpers to serialize and deserialize metrics collected by
-// ChromeOS.
-namespace SerializationUtils {
-
-// Deserializes a sample passed as a string and return a sample.
-// The return value will either be a scoped_ptr to a Metric sample (if the
-// deserialization was successful) or a NULL scoped_ptr.
-scoped_ptr<MetricSample> ParseSample(const std::string& sample);
-
-// Reads all samples from a file. The file contents remain unchanged.
-void ReadMetricsFromFile(const std::string& filename,
-                         ScopedVector<MetricSample>* metrics);
-
-// Reads all samples from a file and truncates the file when done.
-void ReadAndTruncateMetricsFromFile(const std::string& filename,
-                                    ScopedVector<MetricSample>* metrics);
-
-// Serializes a sample and write it to filename.
-// The format for the message is:
-//  message_size, serialized_message
-// where
-//  * message_size is the total length of the message (message_size +
-//    serialized_message) on 4 bytes
-//  * serialized_message is the serialized version of sample (using ToString)
-//
-//  NB: the file will never leave the device so message_size will be written
-//  with the architecture's endianness.
-bool WriteMetricToFile(const MetricSample& sample, const std::string& filename);
-
-// Maximum length of a serialized message
-static const int kMessageMaxLength = 1024;
-
-}  // namespace SerializationUtils
-}  // namespace metrics
-
-#endif  // METRICS_SERIALIZATION_SERIALIZATION_UTILS_H_
diff --git a/metricsd/serialization/serialization_utils_unittest.cc b/metricsd/serialization/serialization_utils_unittest.cc
deleted file mode 100644
index 7a572de..0000000
--- a/metricsd/serialization/serialization_utils_unittest.cc
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "serialization/serialization_utils.h"
-
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <base/logging.h>
-#include <base/strings/stringprintf.h>
-#include <gtest/gtest.h>
-
-#include "serialization/metric_sample.h"
-
-namespace metrics {
-namespace {
-
-class SerializationUtilsTest : public testing::Test {
- protected:
-  SerializationUtilsTest() {
-    bool success = temporary_dir.CreateUniqueTempDir();
-    if (success) {
-      base::FilePath dir_path = temporary_dir.path();
-      filename = dir_path.value() + "chromeossampletest";
-      filepath = base::FilePath(filename);
-    }
-  }
-
-  void SetUp() override { base::DeleteFile(filepath, false); }
-
-  void TestSerialization(MetricSample* sample) {
-    std::string serialized(sample->ToString());
-    ASSERT_EQ('\0', serialized[serialized.length() - 1]);
-    scoped_ptr<MetricSample> deserialized =
-        SerializationUtils::ParseSample(serialized);
-    ASSERT_TRUE(deserialized);
-    EXPECT_TRUE(sample->IsEqual(*deserialized.get()));
-  }
-
-  std::string filename;
-  base::ScopedTempDir temporary_dir;
-  base::FilePath filepath;
-};
-
-TEST_F(SerializationUtilsTest, CrashSerializeTest) {
-  TestSerialization(MetricSample::CrashSample("test").get());
-}
-
-TEST_F(SerializationUtilsTest, HistogramSerializeTest) {
-  TestSerialization(
-      MetricSample::HistogramSample("myhist", 13, 1, 100, 10).get());
-}
-
-TEST_F(SerializationUtilsTest, LinearSerializeTest) {
-  TestSerialization(
-      MetricSample::LinearHistogramSample("linearhist", 12, 30).get());
-}
-
-TEST_F(SerializationUtilsTest, SparseSerializeTest) {
-  TestSerialization(MetricSample::SparseHistogramSample("mysparse", 30).get());
-}
-
-TEST_F(SerializationUtilsTest, UserActionSerializeTest) {
-  TestSerialization(MetricSample::UserActionSample("myaction").get());
-}
-
-TEST_F(SerializationUtilsTest, IllegalNameAreFilteredTest) {
-  scoped_ptr<MetricSample> sample1 =
-      MetricSample::SparseHistogramSample("no space", 10);
-  scoped_ptr<MetricSample> sample2 = MetricSample::LinearHistogramSample(
-      base::StringPrintf("here%cbhe", '\0'), 1, 3);
-
-  EXPECT_FALSE(SerializationUtils::WriteMetricToFile(*sample1.get(), filename));
-  EXPECT_FALSE(SerializationUtils::WriteMetricToFile(*sample2.get(), filename));
-  int64 size = 0;
-
-  ASSERT_TRUE(!PathExists(filepath) || base::GetFileSize(filepath, &size));
-
-  EXPECT_EQ(0, size);
-}
-
-TEST_F(SerializationUtilsTest, BadInputIsCaughtTest) {
-  std::string input(
-      base::StringPrintf("sparsehistogram%cname foo%c", '\0', '\0'));
-  EXPECT_EQ(NULL, MetricSample::ParseSparseHistogram(input).get());
-}
-
-TEST_F(SerializationUtilsTest, MessageSeparatedByZero) {
-  scoped_ptr<MetricSample> crash = MetricSample::CrashSample("mycrash");
-
-  SerializationUtils::WriteMetricToFile(*crash.get(), filename);
-  int64 size = 0;
-  ASSERT_TRUE(base::GetFileSize(filepath, &size));
-  // 4 bytes for the size
-  // 5 bytes for crash
-  // 7 bytes for mycrash
-  // 2 bytes for the \0
-  // -> total of 18
-  EXPECT_EQ(size, 18);
-}
-
-TEST_F(SerializationUtilsTest, MessagesTooLongAreDiscardedTest) {
-  // Creates a message that is bigger than the maximum allowed size.
-  // As we are adding extra character (crash, \0s, etc), if the name is
-  // kMessageMaxLength long, it will be too long.
-  std::string name(SerializationUtils::kMessageMaxLength, 'c');
-
-  scoped_ptr<MetricSample> crash = MetricSample::CrashSample(name);
-  EXPECT_FALSE(SerializationUtils::WriteMetricToFile(*crash.get(), filename));
-  int64 size = 0;
-  ASSERT_TRUE(base::GetFileSize(filepath, &size));
-  EXPECT_EQ(0, size);
-}
-
-TEST_F(SerializationUtilsTest, ReadLongMessageTest) {
-  base::File test_file(filepath,
-                       base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND);
-  std::string message(SerializationUtils::kMessageMaxLength + 1, 'c');
-
-  int32 message_size = message.length() + sizeof(int32);
-  test_file.WriteAtCurrentPos(reinterpret_cast<const char*>(&message_size),
-                              sizeof(message_size));
-  test_file.WriteAtCurrentPos(message.c_str(), message.length());
-  test_file.Close();
-
-  scoped_ptr<MetricSample> crash = MetricSample::CrashSample("test");
-  SerializationUtils::WriteMetricToFile(*crash.get(), filename);
-
-  ScopedVector<MetricSample> samples;
-  SerializationUtils::ReadAndTruncateMetricsFromFile(filename, &samples);
-  ASSERT_EQ(size_t(1), samples.size());
-  ASSERT_TRUE(samples[0] != NULL);
-  EXPECT_TRUE(crash->IsEqual(*samples[0]));
-}
-
-TEST_F(SerializationUtilsTest, WriteReadTest) {
-  scoped_ptr<MetricSample> hist =
-      MetricSample::HistogramSample("myhist", 1, 2, 3, 4);
-  scoped_ptr<MetricSample> crash = MetricSample::CrashSample("mycrash");
-  scoped_ptr<MetricSample> lhist =
-      MetricSample::LinearHistogramSample("linear", 1, 10);
-  scoped_ptr<MetricSample> shist =
-      MetricSample::SparseHistogramSample("mysparse", 30);
-  scoped_ptr<MetricSample> action = MetricSample::UserActionSample("myaction");
-
-  SerializationUtils::WriteMetricToFile(*hist.get(), filename);
-  SerializationUtils::WriteMetricToFile(*crash.get(), filename);
-  SerializationUtils::WriteMetricToFile(*lhist.get(), filename);
-  SerializationUtils::WriteMetricToFile(*shist.get(), filename);
-  SerializationUtils::WriteMetricToFile(*action.get(), filename);
-  ScopedVector<MetricSample> vect;
-  SerializationUtils::ReadAndTruncateMetricsFromFile(filename, &vect);
-  ASSERT_EQ(vect.size(), size_t(5));
-  for (int i = 0; i < 5; i++) {
-    ASSERT_TRUE(vect[0] != NULL);
-  }
-  EXPECT_TRUE(hist->IsEqual(*vect[0]));
-  EXPECT_TRUE(crash->IsEqual(*vect[1]));
-  EXPECT_TRUE(lhist->IsEqual(*vect[2]));
-  EXPECT_TRUE(shist->IsEqual(*vect[3]));
-  EXPECT_TRUE(action->IsEqual(*vect[4]));
-
-  int64 size = 0;
-  ASSERT_TRUE(base::GetFileSize(filepath, &size));
-  ASSERT_EQ(0, size);
-}
-
-}  // namespace
-}  // namespace metrics
diff --git a/metricsd/timer.cc b/metricsd/timer.cc
index 0c2c119..06fc336 100644
--- a/metricsd/timer.cc
+++ b/metricsd/timer.cc
@@ -18,8 +18,6 @@
 
 #include <string>
 
-#include <base/memory/scoped_ptr.h>
-
 #include "metrics/metrics_library.h"
 
 namespace chromeos_metrics {
diff --git a/metricsd/timer_test.cc b/metricsd/timer_test.cc
index bc7a2a1..7a67e11 100644
--- a/metricsd/timer_test.cc
+++ b/metricsd/timer_test.cc
@@ -16,9 +16,9 @@
 
 #include <stdint.h>
 
-#include <base/memory/scoped_ptr.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <memory>
 
 #include "metrics/metrics_library_mock.h"
 #include "metrics/timer.h"
@@ -61,7 +61,7 @@
   virtual void TearDown() {}
 
   Timer timer_;
-  scoped_ptr<ClockWrapperMock> clock_wrapper_mock_;
+  std::unique_ptr<ClockWrapperMock> clock_wrapper_mock_;
   base::TimeTicks stime, etime, stime2, etime2, stime3, etime3;
 };
 
@@ -436,7 +436,7 @@
 
   TimerReporter timer_reporter_;
   MetricsLibraryMock lib_;
-  scoped_ptr<ClockWrapperMock> clock_wrapper_mock_;
+  std::unique_ptr<ClockWrapperMock> clock_wrapper_mock_;
   base::TimeTicks stime, etime;
 };
 
diff --git a/metricsd/uploader/bn_metricsd_impl.cc b/metricsd/uploader/bn_metricsd_impl.cc
new file mode 100644
index 0000000..2cbc2da
--- /dev/null
+++ b/metricsd/uploader/bn_metricsd_impl.cc
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "uploader/bn_metricsd_impl.h"
+
+#include <base/metrics/histogram.h>
+#include <base/metrics/sparse_histogram.h>
+#include <base/metrics/statistics_recorder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Errors.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::binder::Status;
+using android::String16;
+
+static const char16_t kCrashTypeKernel[] = u"kernel";
+static const char16_t kCrashTypeUncleanShutdown[] = u"uncleanshutdown";
+static const char16_t kCrashTypeUser[] = u"user";
+
+BnMetricsdImpl::BnMetricsdImpl(const std::shared_ptr<CrashCounters>& counters)
+    : counters_(counters) {
+  CHECK(counters_) << "Invalid counters argument to constructor";
+}
+
+void BnMetricsdImpl::Run() {
+  android::status_t status =
+      android::defaultServiceManager()->addService(getInterfaceDescriptor(),
+                                                   this);
+  CHECK(status == android::OK) << "Metricsd service registration failed";
+  android::ProcessState::self()->setThreadPoolMaxThreadCount(0);
+  android::IPCThreadState::self()->disableBackgroundScheduling(true);
+  android::IPCThreadState::self()->joinThreadPool();
+}
+
+Status BnMetricsdImpl::recordHistogram(
+    const String16& name, int sample, int min, int max, int nbuckets) {
+  base::HistogramBase* histogram = base::Histogram::FactoryGet(
+      android::String8(name).string(), min, max, nbuckets,
+      base::Histogram::kUmaTargetedHistogramFlag);
+  // |histogram| may be null if a client reports two contradicting histograms
+  // with the same name but different limits.
+  // FactoryGet will print a useful message if that is the case.
+  if (histogram) {
+    histogram->Add(sample);
+  }
+  return Status::ok();
+}
+
+Status BnMetricsdImpl::recordLinearHistogram(const String16& name,
+                                             int sample,
+                                             int max) {
+  base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
+      android::String8(name).string(), 1, max, max + 1,
+      base::Histogram::kUmaTargetedHistogramFlag);
+  // |histogram| may be null if a client reports two contradicting histograms
+  // with the same name but different limits.
+  // FactoryGet will print a useful message if that is the case.
+  if (histogram) {
+    histogram->Add(sample);
+  }
+  return Status::ok();
+}
+
+Status BnMetricsdImpl::recordSparseHistogram(const String16& name, int sample) {
+  base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
+      android::String8(name).string(),
+      base::Histogram::kUmaTargetedHistogramFlag);
+  // |histogram| may be null if a client reports two contradicting histograms
+  // with the same name but different limits.
+  // FactoryGet will print a useful message if that is the case.
+  if (histogram) {
+    histogram->Add(sample);
+  }
+  return Status::ok();
+}
+
+Status BnMetricsdImpl::recordCrash(const String16& type) {
+  if (type == kCrashTypeUser) {
+    counters_->IncrementUserCrashCount();
+  } else if (type == kCrashTypeKernel) {
+    counters_->IncrementKernelCrashCount();
+  } else if (type == kCrashTypeUncleanShutdown) {
+    counters_->IncrementUncleanShutdownCount();
+  } else {
+    LOG(ERROR) << "Unknown crash type received: " << type;
+  }
+  return Status::ok();
+}
+
+Status BnMetricsdImpl::getHistogramsDump(String16* dump) {
+  std::string str_dump;
+  base::StatisticsRecorder::WriteGraph(std::string(), &str_dump);
+  *dump = String16(str_dump.c_str());
+  return Status::ok();
+}
diff --git a/metricsd/uploader/bn_metricsd_impl.h b/metricsd/uploader/bn_metricsd_impl.h
new file mode 100644
index 0000000..016ccb6
--- /dev/null
+++ b/metricsd/uploader/bn_metricsd_impl.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef METRICSD_UPLOADER_BN_METRICSD_IMPL_H_
+#define METRICSD_UPLOADER_BN_METRICSD_IMPL_H_
+
+#include "android/brillo/metrics/BnMetricsd.h"
+#include "uploader/crash_counters.h"
+
+class BnMetricsdImpl : public android::brillo::metrics::BnMetricsd {
+ public:
+  explicit BnMetricsdImpl(const std::shared_ptr<CrashCounters>& counters);
+  virtual ~BnMetricsdImpl() = default;
+
+  // Starts the binder main loop.
+  void Run();
+
+  // Records a histogram.
+  android::binder::Status recordHistogram(const android::String16& name,
+                                          int sample,
+                                          int min,
+                                          int max,
+                                          int nbuckets) override;
+
+  // Records a linear histogram.
+  android::binder::Status recordLinearHistogram(const android::String16& name,
+                                                int sample,
+                                                int max) override;
+
+  // Records a sparse histogram.
+  android::binder::Status recordSparseHistogram(const android::String16& name,
+                                                int sample) override;
+
+  // Records a crash.
+  android::binder::Status recordCrash(const android::String16& type) override;
+
+  // Returns a dump of the histograms aggregated in memory.
+  android::binder::Status getHistogramsDump(android::String16* dump) override;
+
+ private:
+  std::shared_ptr<CrashCounters> counters_;
+};
+
+#endif  // METRICSD_UPLOADER_BN_METRICSD_IMPL_H_
diff --git a/metricsd/uploader/crash_counters.cc b/metricsd/uploader/crash_counters.cc
new file mode 100644
index 0000000..1478b9a
--- /dev/null
+++ b/metricsd/uploader/crash_counters.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "uploader/crash_counters.h"
+
+CrashCounters::CrashCounters()
+    : kernel_crashes_(0), unclean_shutdowns_(0), user_crashes_(0) {}
+
+void CrashCounters::IncrementKernelCrashCount() {
+  kernel_crashes_++;
+}
+
+unsigned int CrashCounters::GetAndResetKernelCrashCount() {
+  return kernel_crashes_.exchange(0);
+}
+
+void CrashCounters::IncrementUncleanShutdownCount() {
+  unclean_shutdowns_++;
+}
+
+unsigned int CrashCounters::GetAndResetUncleanShutdownCount() {
+  return unclean_shutdowns_.exchange(0);
+}
+
+void CrashCounters::IncrementUserCrashCount() {
+  user_crashes_++;
+}
+
+unsigned int CrashCounters::GetAndResetUserCrashCount() {
+  return user_crashes_.exchange(0);
+}
diff --git a/metricsd/uploader/crash_counters.h b/metricsd/uploader/crash_counters.h
new file mode 100644
index 0000000..3fdbf3f
--- /dev/null
+++ b/metricsd/uploader/crash_counters.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef METRICSD_UPLOADER_CRASH_COUNTERS_H_
+#define METRICSD_UPLOADER_CRASH_COUNTERS_H_
+
+#include <atomic>
+
+// This class is used to keep track of the crash counters.
+// An instance of it will be used by both the binder thread (to increment the
+// counters) and the uploader thread (to gather and reset the counters).
+// As such, the internal counters are atomic uints to allow concurrent access.
+class CrashCounters {
+ public:
+  CrashCounters();
+
+  void IncrementKernelCrashCount();
+  unsigned int GetAndResetKernelCrashCount();
+
+  void IncrementUserCrashCount();
+  unsigned int GetAndResetUserCrashCount();
+
+  void IncrementUncleanShutdownCount();
+  unsigned int GetAndResetUncleanShutdownCount();
+
+ private:
+  std::atomic_uint kernel_crashes_;
+  std::atomic_uint unclean_shutdowns_;
+  std::atomic_uint user_crashes_;
+};
+
+#endif  // METRICSD_UPLOADER_CRASH_COUNTERS_H_
diff --git a/metricsd/uploader/metrics_log.cc b/metricsd/uploader/metrics_log.cc
index 1f16ca1..a01b5da 100644
--- a/metricsd/uploader/metrics_log.cc
+++ b/metricsd/uploader/metrics_log.cc
@@ -27,25 +27,25 @@
     : MetricsLogBase("", 0, metrics::MetricsLogBase::ONGOING_LOG, "") {
 }
 
-void MetricsLog::IncrementUserCrashCount() {
+void MetricsLog::IncrementUserCrashCount(unsigned int count) {
   metrics::SystemProfileProto::Stability* stability(
       uma_proto()->mutable_system_profile()->mutable_stability());
   int current = stability->other_user_crash_count();
-  stability->set_other_user_crash_count(current + 1);
+  stability->set_other_user_crash_count(current + count);
 }
 
-void MetricsLog::IncrementKernelCrashCount() {
+void MetricsLog::IncrementKernelCrashCount(unsigned int count) {
   metrics::SystemProfileProto::Stability* stability(
       uma_proto()->mutable_system_profile()->mutable_stability());
   int current = stability->kernel_crash_count();
-  stability->set_kernel_crash_count(current + 1);
+  stability->set_kernel_crash_count(current + count);
 }
 
-void MetricsLog::IncrementUncleanShutdownCount() {
+void MetricsLog::IncrementUncleanShutdownCount(unsigned int count) {
   metrics::SystemProfileProto::Stability* stability(
       uma_proto()->mutable_system_profile()->mutable_stability());
   int current = stability->unclean_system_shutdown_count();
-  stability->set_unclean_system_shutdown_count(current + 1);
+  stability->set_unclean_system_shutdown_count(current + count);
 }
 
 bool MetricsLog::PopulateSystemProfile(SystemProfileSetter* profile_setter) {
diff --git a/metricsd/uploader/metrics_log.h b/metricsd/uploader/metrics_log.h
index 5e09070..b76cd72 100644
--- a/metricsd/uploader/metrics_log.h
+++ b/metricsd/uploader/metrics_log.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef METRICS_UPLOADER_METRICS_LOG_H_
-#define METRICS_UPLOADER_METRICS_LOG_H_
+#ifndef METRICSD_UPLOADER_METRICS_LOG_H_
+#define METRICSD_UPLOADER_METRICS_LOG_H_
 
 #include <string>
 
@@ -34,15 +34,20 @@
   // SystemProfileSetter.
   MetricsLog();
 
-  void IncrementUserCrashCount();
-  void IncrementKernelCrashCount();
-  void IncrementUncleanShutdownCount();
+  // Increment the crash counters in the protobuf.
+  // These methods don't have to be thread safe as metrics logs are only
+  // accessed by the uploader thread.
+  void IncrementUserCrashCount(unsigned int count);
+  void IncrementKernelCrashCount(unsigned int count);
+  void IncrementUncleanShutdownCount(unsigned int count);
 
   // Populate the system profile with system information using setter.
   bool PopulateSystemProfile(SystemProfileSetter* setter);
 
  private:
+  friend class UploadServiceTest;
   FRIEND_TEST(UploadServiceTest, LogContainsAggregatedValues);
+  FRIEND_TEST(UploadServiceTest, LogContainsCrashCounts);
   FRIEND_TEST(UploadServiceTest, LogKernelCrash);
   FRIEND_TEST(UploadServiceTest, LogUncleanShutdown);
   FRIEND_TEST(UploadServiceTest, LogUserCrash);
@@ -51,4 +56,4 @@
   DISALLOW_COPY_AND_ASSIGN(MetricsLog);
 };
 
-#endif  // METRICS_UPLOADER_METRICS_LOG_H_
+#endif  // METRICSD_UPLOADER_METRICS_LOG_H_
diff --git a/metricsd/uploader/system_profile_cache.cc b/metricsd/uploader/system_profile_cache.cc
index 8928a0d..70f6afd 100644
--- a/metricsd/uploader/system_profile_cache.cc
+++ b/metricsd/uploader/system_profile_cache.cc
@@ -55,11 +55,10 @@
 
 SystemProfileCache::SystemProfileCache()
     : initialized_(false),
-    testing_(false),
-    metrics_directory_(metrics::kMetricsDirectory),
-    session_id_(new chromeos_metrics::PersistentInteger(
-        kPersistentSessionIdFilename)) {
-}
+      testing_(false),
+      metrics_directory_(metrics::kMetricsdDirectory),
+      session_id_(new chromeos_metrics::PersistentInteger(
+          kPersistentSessionIdFilename, metrics_directory_)) {}
 
 SystemProfileCache::SystemProfileCache(bool testing,
                                        const base::FilePath& metrics_directory)
@@ -67,8 +66,7 @@
       testing_(testing),
       metrics_directory_(metrics_directory),
       session_id_(new chromeos_metrics::PersistentInteger(
-          kPersistentSessionIdFilename)) {
-}
+          kPersistentSessionIdFilename, metrics_directory)) {}
 
 bool SystemProfileCache::Initialize() {
   CHECK(!initialized_)
diff --git a/metricsd/uploader/system_profile_cache.h b/metricsd/uploader/system_profile_cache.h
index 0a21ad4..f9c484c 100644
--- a/metricsd/uploader/system_profile_cache.h
+++ b/metricsd/uploader/system_profile_cache.h
@@ -19,12 +19,12 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <string>
 
 #include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
-#include "base/memory/scoped_ptr.h"
 #include "persistent_integer.h"
 #include "uploader/proto/system_profile.pb.h"
 #include "uploader/system_profile_setter.h"
@@ -80,7 +80,7 @@
   bool initialized_;
   bool testing_;
   base::FilePath metrics_directory_;
-  scoped_ptr<chromeos_metrics::PersistentInteger> session_id_;
+  std::unique_ptr<chromeos_metrics::PersistentInteger> session_id_;
   SystemProfile profile_;
 };
 
diff --git a/metricsd/uploader/upload_service.cc b/metricsd/uploader/upload_service.cc
index ca5024e..2fb30c3 100644
--- a/metricsd/uploader/upload_service.cc
+++ b/metricsd/uploader/upload_service.cc
@@ -18,6 +18,7 @@
 
 #include <sysexits.h>
 
+#include <memory>
 #include <string>
 
 #include <base/bind.h>
@@ -33,8 +34,6 @@
 #include <base/sha1.h>
 
 #include "constants.h"
-#include "serialization/metric_sample.h"
-#include "serialization/serialization_utils.h"
 #include "uploader/metrics_log.h"
 #include "uploader/sender_http.h"
 #include "uploader/system_profile_setter.h"
@@ -43,19 +42,20 @@
 
 UploadService::UploadService(const std::string& server,
                              const base::TimeDelta& upload_interval,
-                             const base::FilePath& metrics_directory)
+                             const base::FilePath& private_metrics_directory,
+                             const base::FilePath& shared_metrics_directory,
+                             const std::shared_ptr<CrashCounters> counters)
     : histogram_snapshot_manager_(this),
       sender_(new HttpSender(server)),
-      failed_upload_count_(metrics::kFailedUploadCountName),
+      failed_upload_count_(metrics::kFailedUploadCountName,
+                           private_metrics_directory),
+      counters_(counters),
       upload_interval_(upload_interval) {
-  metrics_file_ = metrics_directory.Append(metrics::kMetricsEventsFileName);
-  staged_log_path_ = metrics_directory.Append(metrics::kStagedLogName);
-  consent_file_ = metrics_directory.Append(metrics::kConsentFileName);
+  staged_log_path_ = private_metrics_directory.Append(metrics::kStagedLogName);
+  consent_file_ = shared_metrics_directory.Append(metrics::kConsentFileName);
 }
 
 int UploadService::OnInit() {
-  base::StatisticsRecorder::Initialize();
-
   system_profile_setter_.reset(new SystemProfileCache());
 
   base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
@@ -67,7 +67,6 @@
 }
 
 void UploadService::InitForTest(SystemProfileSetter* setter) {
-  base::StatisticsRecorder::Initialize();
   system_profile_setter_.reset(setter);
 }
 
@@ -99,8 +98,7 @@
     return;
   }
 
-  // Previous upload successful, reading metrics sample from the file.
-  ReadMetrics();
+  // Previous upload successful, stage another log.
   GatherHistograms();
   StageCurrentLog();
 
@@ -140,76 +138,24 @@
   failed_upload_count_.Set(0);
 }
 
-void UploadService::ReadMetrics() {
-  CHECK(!HasStagedLog()) << "cannot read metrics until the old logs have been "
-                         << "discarded";
-
-  ScopedVector<metrics::MetricSample> vector;
-  metrics::SerializationUtils::ReadAndTruncateMetricsFromFile(
-      metrics_file_.value(), &vector);
-
-  int i = 0;
-  for (ScopedVector<metrics::MetricSample>::iterator it = vector.begin();
-       it != vector.end(); it++) {
-    metrics::MetricSample* sample = *it;
-    AddSample(*sample);
-    i++;
-  }
-  VLOG(1) << i << " samples read";
-}
-
-void UploadService::AddSample(const metrics::MetricSample& sample) {
-  base::HistogramBase* counter;
-  switch (sample.type()) {
-    case metrics::MetricSample::CRASH:
-      AddCrash(sample.name());
-      break;
-    case metrics::MetricSample::HISTOGRAM:
-      counter = base::Histogram::FactoryGet(
-          sample.name(), sample.min(), sample.max(), sample.bucket_count(),
-          base::Histogram::kUmaTargetedHistogramFlag);
-      counter->Add(sample.sample());
-      break;
-    case metrics::MetricSample::SPARSE_HISTOGRAM:
-      counter = base::SparseHistogram::FactoryGet(
-          sample.name(), base::HistogramBase::kUmaTargetedHistogramFlag);
-      counter->Add(sample.sample());
-      break;
-    case metrics::MetricSample::LINEAR_HISTOGRAM:
-      counter = base::LinearHistogram::FactoryGet(
-          sample.name(),
-          1,
-          sample.max(),
-          sample.max() + 1,
-          base::Histogram::kUmaTargetedHistogramFlag);
-      counter->Add(sample.sample());
-      break;
-    case metrics::MetricSample::USER_ACTION:
-      GetOrCreateCurrentLog()->RecordUserAction(sample.name());
-      break;
-    default:
-      break;
-  }
-}
-
-void UploadService::AddCrash(const std::string& crash_name) {
-  if (crash_name == "user") {
-    GetOrCreateCurrentLog()->IncrementUserCrashCount();
-  } else if (crash_name == "kernel") {
-    GetOrCreateCurrentLog()->IncrementKernelCrashCount();
-  } else if (crash_name == "uncleanshutdown") {
-    GetOrCreateCurrentLog()->IncrementUncleanShutdownCount();
-  } else {
-    DLOG(ERROR) << "crash name unknown" << crash_name;
-  }
-}
-
 void UploadService::GatherHistograms() {
   base::StatisticsRecorder::Histograms histograms;
   base::StatisticsRecorder::GetHistograms(&histograms);
 
   histogram_snapshot_manager_.PrepareDeltas(
       base::Histogram::kNoFlags, base::Histogram::kUmaTargetedHistogramFlag);
+
+  // Gather and reset the crash counters, shared with the binder threads.
+  unsigned int kernel_crashes = counters_->GetAndResetKernelCrashCount();
+  unsigned int unclean_shutdowns = counters_->GetAndResetUncleanShutdownCount();
+  unsigned int user_crashes = counters_->GetAndResetUserCrashCount();
+
+  // Only create a log if the counters have changed.
+  if (kernel_crashes > 0 || unclean_shutdowns > 0 || user_crashes > 0) {
+    GetOrCreateCurrentLog()->IncrementKernelCrashCount(kernel_crashes);
+    GetOrCreateCurrentLog()->IncrementUncleanShutdownCount(unclean_shutdowns);
+    GetOrCreateCurrentLog()->IncrementUserCrashCount(user_crashes);
+  }
 }
 
 void UploadService::RecordDelta(const base::HistogramBase& histogram,
@@ -224,7 +170,7 @@
   if (!current_log_)
     return;
 
-  scoped_ptr<MetricsLog> staged_log;
+  std::unique_ptr<MetricsLog> staged_log;
   staged_log.swap(current_log_);
   staged_log->CloseLog();
   if (!staged_log->PopulateSystemProfile(system_profile_setter_.get())) {
@@ -265,4 +211,3 @@
 bool UploadService::AreMetricsEnabled() {
   return base::PathExists(consent_file_);
 }
-
diff --git a/metricsd/uploader/upload_service.h b/metricsd/uploader/upload_service.h
index 7faf357..1d36121 100644
--- a/metricsd/uploader/upload_service.h
+++ b/metricsd/uploader/upload_service.h
@@ -17,6 +17,7 @@
 #ifndef METRICS_UPLOADER_UPLOAD_SERVICE_H_
 #define METRICS_UPLOADER_UPLOAD_SERVICE_H_
 
+#include <memory>
 #include <string>
 
 #include <base/metrics/histogram_base.h>
@@ -25,20 +26,12 @@
 #include <brillo/daemons/daemon.h>
 
 #include "persistent_integer.h"
+#include "uploader/crash_counters.h"
 #include "uploader/metrics_log.h"
+#include "uploader/proto/chrome_user_metrics_extension.pb.h"
 #include "uploader/sender.h"
 #include "uploader/system_profile_cache.h"
 
-namespace metrics {
-class ChromeUserMetricsExtension;
-class CrashSample;
-class HistogramSample;
-class LinearHistogramSample;
-class MetricSample;
-class SparseHistogramSample;
-class UserActionSample;
-}
-
 class SystemProfileSetter;
 
 // Service responsible for uploading the metrics periodically to the server.
@@ -57,21 +50,21 @@
 //    - if the upload is successful, we discard the log (therefore
 //      transitioning back to no staged log)
 //    - if the upload fails, we keep the log to try again later.
-//    We do not try to read the metrics that are stored on
-//    the disk as we want to avoid storing the metrics in memory.
 //
 // * if no staged logs are present:
-//    Read all metrics from the disk, aggregate them and try to send them.
+//    Take a snapshot of the aggregated metrics, save it to disk and try to send
+//    it:
 //    - if the upload succeeds, we discard the staged log (transitioning back
 //      to the no staged log state)
-//    - if the upload fails, we keep the staged log in memory to retry
-//      uploading later.
+//    - if the upload fails, we continue and will retry to upload later.
 //
 class UploadService : public base::HistogramFlattener, public brillo::Daemon {
  public:
   UploadService(const std::string& server,
                 const base::TimeDelta& upload_interval,
-                const base::FilePath& metrics_directory);
+                const base::FilePath& private_metrics_directory,
+                const base::FilePath& shared_metrics_directory,
+                const std::shared_ptr<CrashCounters> counters);
 
   // Initializes the upload service.
   int OnInit();
@@ -105,6 +98,7 @@
   FRIEND_TEST(UploadServiceTest, EmptyLogsAreNotSent);
   FRIEND_TEST(UploadServiceTest, FailedSendAreRetried);
   FRIEND_TEST(UploadServiceTest, LogContainsAggregatedValues);
+  FRIEND_TEST(UploadServiceTest, LogContainsCrashCounts);
   FRIEND_TEST(UploadServiceTest, LogEmptyAfterUpload);
   FRIEND_TEST(UploadServiceTest, LogEmptyByDefault);
   FRIEND_TEST(UploadServiceTest, LogFromTheMetricsLibrary);
@@ -124,15 +118,6 @@
   // Resets the internal state.
   void Reset();
 
-  // Reads all the metrics from the disk.
-  void ReadMetrics();
-
-  // Adds a generic sample to the current log.
-  void AddSample(const metrics::MetricSample& sample);
-
-  // Adds a crash to the current log.
-  void AddCrash(const std::string& crash_name);
-
   // Returns true iff metrics reporting is enabled.
   bool AreMetricsEnabled();
 
@@ -157,16 +142,16 @@
   // Returns the current log. If there is no current log, creates it first.
   MetricsLog* GetOrCreateCurrentLog();
 
-  scoped_ptr<SystemProfileSetter> system_profile_setter_;
+  std::unique_ptr<SystemProfileSetter> system_profile_setter_;
   base::HistogramSnapshotManager histogram_snapshot_manager_;
-  scoped_ptr<Sender> sender_;
+  std::unique_ptr<Sender> sender_;
   chromeos_metrics::PersistentInteger failed_upload_count_;
-  scoped_ptr<MetricsLog> current_log_;
-  
+  std::unique_ptr<MetricsLog> current_log_;
+  std::shared_ptr<CrashCounters> counters_;
+
   base::TimeDelta upload_interval_;
 
   base::FilePath consent_file_;
-  base::FilePath metrics_file_;
   base::FilePath staged_log_path_;
 
   bool testing_;
diff --git a/metricsd/uploader/upload_service_test.cc b/metricsd/uploader/upload_service_test.cc
index 24e3127..ec507e8 100644
--- a/metricsd/uploader/upload_service_test.cc
+++ b/metricsd/uploader/upload_service_test.cc
@@ -14,18 +14,19 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
+#include <memory>
 
 #include <base/at_exit.h>
 #include <base/files/file_util.h>
 #include <base/files/scoped_temp_dir.h>
 #include <base/logging.h>
+#include <base/metrics/sparse_histogram.h>
+#include <base/metrics/statistics_recorder.h>
 #include <base/sys_info.h>
+#include <gtest/gtest.h>
 
 #include "constants.h"
-#include "metrics/metrics_library_mock.h"
 #include "persistent_integer.h"
-#include "serialization/metric_sample.h"
 #include "uploader/metrics_log.h"
 #include "uploader/mock/mock_system_profile_setter.h"
 #include "uploader/mock/sender_mock.h"
@@ -39,13 +40,23 @@
  protected:
   virtual void SetUp() {
     CHECK(dir_.CreateUniqueTempDir());
-    chromeos_metrics::PersistentInteger::SetMetricsDirectory(
-        dir_.path().value());
-    metrics_lib_.InitForTest(dir_.path());
-    ASSERT_EQ(0, base::WriteFile(
-        dir_.path().Append(metrics::kConsentFileName), "", 0));
-    upload_service_.reset(new UploadService("", base::TimeDelta(),
-                                            dir_.path()));
+    // Make sure the statistics recorder is inactive (contains no metrics) then
+    // initialize it.
+    ASSERT_FALSE(base::StatisticsRecorder::IsActive());
+    base::StatisticsRecorder::Initialize();
+
+    base::FilePath private_dir = dir_.path().Append("private");
+    base::FilePath shared_dir = dir_.path().Append("shared");
+
+    EXPECT_TRUE(base::CreateDirectory(private_dir));
+    EXPECT_TRUE(base::CreateDirectory(shared_dir));
+
+    ASSERT_EQ(0, base::WriteFile(shared_dir.Append(metrics::kConsentFileName),
+                                 "", 0));
+    counters_.reset(new CrashCounters);
+
+    upload_service_.reset(new UploadService("", base::TimeDelta(), private_dir,
+                                            shared_dir, counters_));
 
     upload_service_->sender_.reset(new SenderMock);
     upload_service_->InitForTest(new MockSystemProfileSetter);
@@ -53,8 +64,17 @@
     upload_service_->Reset();
   }
 
-  scoped_ptr<metrics::MetricSample> Crash(const std::string& name) {
-    return metrics::MetricSample::CrashSample(name);
+  void SendSparseHistogram(const std::string& name, int sample) {
+    base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
+        name, base::Histogram::kUmaTargetedHistogramFlag);
+    histogram->Add(sample);
+  }
+
+  void SendHistogram(
+      const std::string& name, int sample, int min, int max, int nbuckets) {
+    base::HistogramBase* histogram = base::Histogram::FactoryGet(
+        name, min, max, nbuckets, base::Histogram::kUmaTargetedHistogramFlag);
+    histogram->Add(sample);
   }
 
   void SetTestingProperty(const std::string& name, const std::string& value) {
@@ -66,57 +86,26 @@
         base::WriteFile(filepath, value.data(), value.size()));
   }
 
+  const metrics::SystemProfileProto_Stability GetCurrentStability() {
+    EXPECT_TRUE(upload_service_->current_log_.get());
+
+    return upload_service_->current_log_->uma_proto()->system_profile().stability();
+  }
+
   base::ScopedTempDir dir_;
-  scoped_ptr<UploadService> upload_service_;
-  MetricsLibrary metrics_lib_;
+  std::unique_ptr<UploadService> upload_service_;
 
-  scoped_ptr<base::AtExitManager> exit_manager_;
+  std::unique_ptr<base::AtExitManager> exit_manager_;
+  std::shared_ptr<CrashCounters> counters_;
 };
 
-// Tests that the right crash increments a values.
-TEST_F(UploadServiceTest, LogUserCrash) {
-  upload_service_->AddSample(*Crash("user").get());
-
-  MetricsLog* log = upload_service_->current_log_.get();
-  metrics::ChromeUserMetricsExtension* proto = log->uma_proto();
-
-  EXPECT_EQ(1, proto->system_profile().stability().other_user_crash_count());
-}
-
-TEST_F(UploadServiceTest, LogUncleanShutdown) {
-  upload_service_->AddSample(*Crash("uncleanshutdown"));
-
-  EXPECT_EQ(1, upload_service_->current_log_
-                   ->uma_proto()
-                   ->system_profile()
-                   .stability()
-                   .unclean_system_shutdown_count());
-}
-
-TEST_F(UploadServiceTest, LogKernelCrash) {
-  upload_service_->AddSample(*Crash("kernel"));
-
-  EXPECT_EQ(1, upload_service_->current_log_
-                   ->uma_proto()
-                   ->system_profile()
-                   .stability()
-                   .kernel_crash_count());
-}
-
-TEST_F(UploadServiceTest, UnknownCrashIgnored) {
-  upload_service_->AddSample(*Crash("foo"));
-
-  // The log should be empty.
-  EXPECT_FALSE(upload_service_->current_log_);
-}
-
 TEST_F(UploadServiceTest, FailedSendAreRetried) {
   SenderMock* sender = new SenderMock();
   upload_service_->sender_.reset(sender);
 
   sender->set_should_succeed(false);
 
-  upload_service_->AddSample(*Crash("user"));
+  SendSparseHistogram("hello", 1);
   upload_service_->UploadEvent();
   EXPECT_EQ(1, sender->send_call_count());
   std::string sent_string = sender->last_message();
@@ -132,7 +121,7 @@
 
   sender->set_should_succeed(false);
 
-  upload_service_->AddSample(*Crash("user"));
+  SendSparseHistogram("hello", 1);
 
   for (int i = 0; i < UploadService::kMaxFailedUpload; i++) {
     upload_service_->UploadEvent();
@@ -143,7 +132,7 @@
   EXPECT_FALSE(upload_service_->HasStagedLog());
 
   // Log a new sample. The failed upload counter should be reset.
-  upload_service_->AddSample(*Crash("user"));
+  SendSparseHistogram("hello", 1);
   for (int i = 0; i < UploadService::kMaxFailedUpload; i++) {
     upload_service_->UploadEvent();
   }
@@ -160,7 +149,8 @@
 }
 
 TEST_F(UploadServiceTest, LogEmptyByDefault) {
-  UploadService upload_service("", base::TimeDelta(), dir_.path());
+  UploadService upload_service("", base::TimeDelta(), dir_.path(), dir_.path(),
+                               std::make_shared<CrashCounters>());
 
   // current_log_ should be initialized later as it needs AtExitManager to exit
   // in order to gather system information from SysInfo.
@@ -171,35 +161,28 @@
   SenderMock* sender = new SenderMock();
   upload_service_->sender_.reset(sender);
 
-  upload_service_->AddSample(*Crash("user"));
+  SendSparseHistogram("hello", 1);
+
   upload_service_->UploadEvent();
 
   std::string first_message = sender->last_message();
+  SendSparseHistogram("hello", 2);
 
-  upload_service_->AddSample(*Crash("kernel"));
   upload_service_->UploadEvent();
 
   EXPECT_NE(first_message, sender->last_message());
 }
 
 TEST_F(UploadServiceTest, LogEmptyAfterUpload) {
-  upload_service_->AddSample(*Crash("user"));
-
-  EXPECT_TRUE(upload_service_->current_log_);
+  SendSparseHistogram("hello", 2);
 
   upload_service_->UploadEvent();
   EXPECT_FALSE(upload_service_->current_log_);
 }
 
 TEST_F(UploadServiceTest, LogContainsAggregatedValues) {
-  scoped_ptr<metrics::MetricSample> histogram =
-      metrics::MetricSample::HistogramSample("foo", 10, 0, 42, 10);
-  upload_service_->AddSample(*histogram.get());
-
-
-  scoped_ptr<metrics::MetricSample> histogram2 =
-      metrics::MetricSample::HistogramSample("foo", 11, 0, 42, 10);
-  upload_service_->AddSample(*histogram2.get());
+  SendHistogram("foo", 11, 0, 42, 10);
+  SendHistogram("foo", 12, 0, 42, 10);
 
   upload_service_->GatherHistograms();
   metrics::ChromeUserMetricsExtension* proto =
@@ -207,6 +190,37 @@
   EXPECT_EQ(1, proto->histogram_event().size());
 }
 
+TEST_F(UploadServiceTest, LogContainsCrashCounts) {
+  // By default, there is no current log.
+  upload_service_->GatherHistograms();
+  EXPECT_FALSE(upload_service_->current_log_);
+
+  // If the user crash counter is incremented, we add the count to the current
+  // log.
+  counters_->IncrementUserCrashCount();
+  upload_service_->GatherHistograms();
+  EXPECT_EQ(1, GetCurrentStability().other_user_crash_count());
+
+  // If the kernel crash counter is incremented, we add the count to the current
+  // log.
+  counters_->IncrementKernelCrashCount();
+  upload_service_->GatherHistograms();
+  EXPECT_EQ(1, GetCurrentStability().kernel_crash_count());
+
+  // If the kernel crash counter is incremented, we add the count to the current
+  // log.
+  counters_->IncrementUncleanShutdownCount();
+  counters_->IncrementUncleanShutdownCount();
+  upload_service_->GatherHistograms();
+  EXPECT_EQ(2, GetCurrentStability().unclean_system_shutdown_count());
+
+  // If no counter is incremented, the reported numbers don't change.
+  upload_service_->GatherHistograms();
+  EXPECT_EQ(1, GetCurrentStability().other_user_crash_count());
+  EXPECT_EQ(1, GetCurrentStability().kernel_crash_count());
+  EXPECT_EQ(2, GetCurrentStability().unclean_system_shutdown_count());
+}
+
 TEST_F(UploadServiceTest, ExtractChannelFromString) {
   EXPECT_EQ(
       SystemProfileCache::ProtoChannelFromString(
@@ -230,13 +244,12 @@
   SetTestingProperty(metrics::kProductId, "hello");
   SetTestingProperty(metrics::kProductVersion, "1.2.3.4");
 
-  scoped_ptr<metrics::MetricSample> histogram =
-      metrics::MetricSample::SparseHistogramSample("myhistogram", 1);
+  SendSparseHistogram("hello", 1);
+
   // Reset to create the new log with the profile setter.
   upload_service_->system_profile_setter_.reset(
       new SystemProfileCache(true, dir_.path()));
   upload_service_->Reset();
-  upload_service_->AddSample(*histogram.get());
   upload_service_->UploadEvent();
 
   EXPECT_EQ(1, sender->send_call_count());
@@ -277,21 +290,6 @@
   EXPECT_EQ(cache.profile_.session_id, session_id + 1);
 }
 
-// Test that we can log metrics from the metrics library and have the uploader
-// upload them.
-TEST_F(UploadServiceTest, LogFromTheMetricsLibrary) {
-  SenderMock* sender = new SenderMock();
-  upload_service_->sender_.reset(sender);
-
-  upload_service_->UploadEvent();
-  EXPECT_EQ(0, sender->send_call_count());
-
-  metrics_lib_.SendEnumToUMA("testname", 2, 10);
-  upload_service_->UploadEvent();
-
-  EXPECT_EQ(1, sender->send_call_count());
-}
-
 // The product id must be set for metrics to be uploaded.
 // If it is not set, the system profile cache should fail to initialize.
 TEST_F(UploadServiceTest, ProductIdMandatory) {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 91d6697..ab6afa2 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -52,6 +52,17 @@
     chown root system /sys/fs/cgroup/memory/sw/tasks
     chmod 0660 /sys/fs/cgroup/memory/sw/tasks
 
+    # Create energy-aware scheduler tuning nodes
+    mkdir /sys/fs/cgroup/stune
+    mount cgroup none /sys/fs/cgroup/stune schedtune
+    mkdir /sys/fs/cgroup/stune/foreground
+    chown system system /sys/fs/cgroup/stune
+    chown system system /sys/fs/cgroup/stune/foreground
+    chown system system /sys/fs/cgroup/stune/tasks
+    chown system system /sys/fs/cgroup/stune/foreground/tasks
+    chmod 0664 /sys/fs/cgroup/stune/tasks
+    chmod 0664 /sys/fs/cgroup/stune/foreground/tasks
+
     # Mount staging areas for devices managed by vold
     # See storage config details at http://source.android.com/tech/storage/
     mount tmpfs tmpfs /mnt mode=0755,uid=0,gid=1000
@@ -65,9 +76,9 @@
     mkdir /mnt/user 0755 root root
     mkdir /mnt/user/0 0755 root root
     mkdir /mnt/expand 0771 system system
+    mkdir /mnt/appfuse 0711 root root
 
     # Storage views to support runtime permissions
-    mkdir /storage 0755 root root
     mkdir /mnt/runtime 0700 root root
     mkdir /mnt/runtime/default 0755 root root
     mkdir /mnt/runtime/default/self 0755 root root
@@ -163,13 +174,16 @@
     chown system system /dev/cpuset/foreground
     chown system system /dev/cpuset/foreground/boost
     chown system system /dev/cpuset/background
+    chown system system /dev/cpuset/system-background
     chown system system /dev/cpuset/tasks
     chown system system /dev/cpuset/foreground/tasks
     chown system system /dev/cpuset/foreground/boost/tasks
     chown system system /dev/cpuset/background/tasks
+    chown system system /dev/cpuset/system-background/tasks
     chmod 0664 /dev/cpuset/foreground/tasks
     chmod 0664 /dev/cpuset/foreground/boost/tasks
     chmod 0664 /dev/cpuset/background/tasks
+    chmod 0664 /dev/cpuset/system-background/tasks
     chmod 0664 /dev/cpuset/tasks
 
 
@@ -248,6 +262,9 @@
     # Mount default storage into root namespace
     mount none /mnt/runtime/default /storage slave bind rec
 
+    # Make sure /sys/kernel/debug (if present) is labeled properly
+    restorecon_recursive /sys/kernel/debug
+
     # We chown/chmod /cache again so because mount is run as root + defaults
     chown system cache /cache
     chmod 0770 /cache
@@ -293,6 +310,7 @@
 
     # Emulated internal storage area
     mkdir /data/media 0770 media_rw media_rw
+
     # Start bootcharting as soon as possible after the data partition is
     # mounted to collect more data.
     mkdir /data/bootchart 0755 shell shell
@@ -329,6 +347,7 @@
     chmod 0660 /data/misc/wifi/wpa_supplicant.conf
     mkdir /data/local 0751 root root
     mkdir /data/misc/media 0700 media media
+    mkdir /data/misc/vold 0700 root root
     mkdir /data/misc/boottrace 0771 system shell
     mkdir /data/misc/update_engine 0700 root root
     mkdir /data/misc/trace 0700 root root
@@ -338,6 +357,7 @@
     mkdir /data/local/tmp 0771 shell shell
     mkdir /data/data 0771 system system
     mkdir /data/app-private 0771 system system
+    mkdir /data/app-ephemeral 0771 system system
     mkdir /data/app-asec 0700 root root
     mkdir /data/app-lib 0771 system system
     mkdir /data/app 0771 system system
@@ -376,11 +396,18 @@
     mkdir /data/backup 0700 system system
     mkdir /data/media 0770 media_rw media_rw
     mkdir /data/ss 0700 system system
+
     mkdir /data/system 0775 system system
     mkdir /data/system/heapdump 0700 system system
+    mkdir /data/system_ce 0770 system system
+    mkdir /data/system_ce/0 0770 system system
+
     mkdir /data/user 0711 system system
+    mkdir /data/user_de 0711 system system
+    mkdir /data/user_de/0 0771 system system
 
     setusercryptopolicies /data/user
+    createuserkey 0 0 0
 
     # Reload policy from /data/security if present.
     setprop selinux.reload_policy 1
@@ -490,6 +517,8 @@
     class_start core
 
 on nonencrypted
+    # A/B update verifier that marks a successful boot.
+    exec - root -- /system/bin/update_verifier nonencrypted
     class_start main
     class_start late_start
 
@@ -518,9 +547,13 @@
     trigger post-fs-data
 
 on property:vold.decrypt=trigger_restart_min_framework
+    # A/B update verifier that marks a successful boot.
+    exec - root -- /system/bin/update_verifier trigger_restart_min_framework
     class_start main
 
 on property:vold.decrypt=trigger_restart_framework
+    # A/B update verifier that marks a successful boot.
+    exec - root -- /system/bin/update_verifier trigger_restart_framework
     class_start main
     class_start late_start
 
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index ff25ac2..53cfcc2 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -3,6 +3,7 @@
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
+    onrestart restart audioserver
     onrestart restart media
     onrestart restart netd
-    writepid /dev/cpuset/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 29bb1cf..a9a94d7 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -3,12 +3,13 @@
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
+    onrestart restart audioserver
     onrestart restart media
     onrestart restart netd
-    writepid /dev/cpuset/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
 
 service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
     class main
     socket zygote_secondary stream 660 root system
     onrestart restart zygote
-    writepid /dev/cpuset/foreground/tasks
\ No newline at end of file
+    writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 5497524..8f47174 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -3,6 +3,7 @@
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
+    onrestart restart audioserver
     onrestart restart media
     onrestart restart netd
-    writepid /dev/cpuset/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 8ed5e9e..70a9678 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -3,12 +3,13 @@
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
+    onrestart restart audioserver
     onrestart restart media
     onrestart restart netd
-    writepid /dev/cpuset/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
 
 service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
     class main
     socket zygote_secondary stream 660 root system
     onrestart restart zygote
-    writepid /dev/cpuset/foreground/tasks
\ No newline at end of file
+    writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index b6bbe7e..45efe36 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -507,6 +507,16 @@
     }
 }
 
+static void derive_permissions_recursive_locked(struct fuse* fuse, struct node *parent) {
+    struct node *node;
+    for (node = parent->child; node; node = node->next) {
+        derive_permissions_locked(fuse, parent, node);
+        if (node->child) {
+            derive_permissions_recursive_locked(fuse, node);
+        }
+    }
+}
+
 /* Kernel has already enforced everything we returned through
  * derive_permissions_locked(), so this is used to lock down access
  * even further, such as enforcing that apps hold sdcard_rw. */
@@ -1145,6 +1155,8 @@
     res = rename_node_locked(child_node, new_name, new_actual_name);
     if (!res) {
         remove_node_from_parent_locked(child_node);
+        derive_permissions_locked(fuse, new_parent_node, child_node);
+        derive_permissions_recursive_locked(fuse, child_node);
         add_node_to_parent_locked(child_node, new_parent_node);
     }
     goto done;
@@ -1654,6 +1666,9 @@
     TRACE("read_package_list: found %zu packages\n",
             hashmapSize(global->package_to_appid));
 
+    /* Regenerate ownership details using newly loaded mapping */
+    derive_permissions_recursive_locked(global->fuse_default, &global->root);
+
     pthread_mutex_unlock(&global->lock);
 
     return rc;
diff --git a/trusty/gatekeeper/Android.mk b/trusty/gatekeeper/Android.mk
new file mode 100644
index 0000000..13e9a09
--- /dev/null
+++ b/trusty/gatekeeper/Android.mk
@@ -0,0 +1,50 @@
+#
+# Copyright (C) 2015 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# WARNING: Everything listed here will be built on ALL platforms,
+# including x86, the emulator, and the SDK.  Modules must be uniquely
+# named (liblights.panda), and must build everywhere, or limit themselves
+# to only building on ARM if they include assembly. Individual makefiles
+# are responsible for having their own logic, for fine-grained control.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := gatekeeper.trusty
+
+LOCAL_MODULE_RELATIVE_PATH := hw
+
+LOCAL_SRC_FILES := \
+	module.cpp \
+	trusty_gatekeeper_ipc.c \
+	trusty_gatekeeper.cpp
+
+LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
+
+LOCAL_SHARED_LIBRARIES := \
+	libgatekeeper \
+	liblog \
+	libcutils \
+	libtrusty
+
+LOCAL_MODULE_TAGS := optional
+
+# Symlink gatekeeper.trusty.so -> gatekeeper.<device>.so so libhardware can find it.
+LOCAL_POST_INSTALL_CMD = \
+    $(hide) ln -sf $(notdir $(LOCAL_INSTALLED_MODULE)) $(dir $(LOCAL_INSTALLED_MODULE))gatekeeper.$(TARGET_DEVICE).so
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/trusty/gatekeeper/gatekeeper_ipc.h b/trusty/gatekeeper/gatekeeper_ipc.h
new file mode 100644
index 0000000..b05dcd8
--- /dev/null
+++ b/trusty/gatekeeper/gatekeeper_ipc.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#define GATEKEEPER_PORT "com.android.trusty.gatekeeper"
+#define GATEKEEPER_MAX_BUFFER_LENGTH 1024
+
+enum gatekeeper_command {
+	GK_REQ_SHIFT = 1,
+	GK_RESP_BIT  = 1,
+
+	GK_ENROLL       = (0 << GK_REQ_SHIFT),
+	GK_VERIFY       = (1 << GK_REQ_SHIFT),
+};
+
+/**
+ * gatekeeper_message - Serial header for communicating with GK server
+ * @cmd: the command, one of ENROLL, VERIFY. Payload must be a serialized
+ *       buffer of the corresponding request object.
+ * @payload: start of the serialized command specific payload
+ */
+struct gatekeeper_message {
+    uint32_t cmd;
+    uint8_t payload[0];
+};
+
diff --git a/trusty/gatekeeper/module.cpp b/trusty/gatekeeper/module.cpp
new file mode 100644
index 0000000..0ee3c2f
--- /dev/null
+++ b/trusty/gatekeeper/module.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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 <hardware/hardware.h>
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "trusty_gatekeeper.h"
+
+using gatekeeper::TrustyGateKeeperDevice;
+
+static int trusty_gatekeeper_open(const hw_module_t *module, const char *name,
+        hw_device_t **device) {
+
+    if (strcmp(name, HARDWARE_GATEKEEPER) != 0) {
+        return -EINVAL;
+    }
+
+    TrustyGateKeeperDevice *gatekeeper = new TrustyGateKeeperDevice(module);
+    if (gatekeeper == NULL) return -ENOMEM;
+    *device = gatekeeper->hw_device();
+
+    return 0;
+}
+
+static struct hw_module_methods_t gatekeeper_module_methods = {
+    .open = trusty_gatekeeper_open,
+};
+
+struct gatekeeper_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
+    .common = {
+        .tag = HARDWARE_MODULE_TAG,
+        .module_api_version = GATEKEEPER_MODULE_API_VERSION_0_1,
+        .hal_api_version = HARDWARE_HAL_API_VERSION,
+        .id = GATEKEEPER_HARDWARE_MODULE_ID,
+        .name = "Trusty GateKeeper HAL",
+        .author = "The Android Open Source Project",
+        .methods = &gatekeeper_module_methods,
+        .dso = 0,
+        .reserved = {}
+    },
+};
diff --git a/trusty/gatekeeper/trusty_gatekeeper.cpp b/trusty/gatekeeper/trusty_gatekeeper.cpp
new file mode 100644
index 0000000..d24f44f
--- /dev/null
+++ b/trusty/gatekeeper/trusty_gatekeeper.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <assert.h>
+#include <type_traits>
+
+#include "trusty_gatekeeper.h"
+#include "trusty_gatekeeper_ipc.h"
+#include "gatekeeper_ipc.h"
+
+#define LOG_TAG "TrustyGateKeeper"
+#include <cutils/log.h>
+
+namespace gatekeeper {
+
+const uint32_t SEND_BUF_SIZE = 8192;
+const uint32_t RECV_BUF_SIZE = 8192;
+
+TrustyGateKeeperDevice::TrustyGateKeeperDevice(const hw_module_t *module) {
+#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
+    static_assert(std::is_standard_layout<TrustyGateKeeperDevice>::value,
+                  "TrustyGateKeeperDevice must be standard layout");
+    static_assert(offsetof(TrustyGateKeeperDevice, device_) == 0,
+                  "device_ must be the first member of TrustyGateKeeperDevice");
+    static_assert(offsetof(TrustyGateKeeperDevice, device_.common) == 0,
+                  "common must be the first member of gatekeeper_device");
+#else
+    assert(reinterpret_cast<gatekeeper_device_t *>(this) == &device_);
+    assert(reinterpret_cast<hw_device_t *>(this) == &(device_.common));
+#endif
+
+    memset(&device_, 0, sizeof(device_));
+    device_.common.tag = HARDWARE_DEVICE_TAG;
+    device_.common.version = 1;
+    device_.common.module = const_cast<hw_module_t *>(module);
+    device_.common.close = close_device;
+
+    device_.enroll = enroll;
+    device_.verify = verify;
+    device_.delete_user = nullptr;
+    device_.delete_all_users = nullptr;
+
+    int rc = trusty_gatekeeper_connect();
+    if (rc < 0) {
+        ALOGE("Error initializing trusty session: %d", rc);
+    }
+
+    error_ = rc;
+
+}
+
+hw_device_t* TrustyGateKeeperDevice::hw_device() {
+    return &device_.common;
+}
+
+int TrustyGateKeeperDevice::close_device(hw_device_t* dev) {
+    delete reinterpret_cast<TrustyGateKeeperDevice *>(dev);
+    return 0;
+}
+
+TrustyGateKeeperDevice::~TrustyGateKeeperDevice() {
+    trusty_gatekeeper_disconnect();
+}
+
+int TrustyGateKeeperDevice::Enroll(uint32_t uid, const uint8_t *current_password_handle,
+        uint32_t current_password_handle_length, const uint8_t *current_password,
+        uint32_t current_password_length, const uint8_t *desired_password,
+        uint32_t desired_password_length, uint8_t **enrolled_password_handle,
+        uint32_t *enrolled_password_handle_length) {
+
+    if (error_ != 0) {
+        return error_;
+    }
+
+    SizedBuffer desired_password_buffer(desired_password_length);
+    memcpy(desired_password_buffer.buffer.get(), desired_password, desired_password_length);
+
+    SizedBuffer current_password_handle_buffer(current_password_handle_length);
+    if (current_password_handle) {
+        memcpy(current_password_handle_buffer.buffer.get(), current_password_handle,
+                current_password_handle_length);
+    }
+
+    SizedBuffer current_password_buffer(current_password_length);
+    if (current_password) {
+        memcpy(current_password_buffer.buffer.get(), current_password, current_password_length);
+    }
+
+    EnrollRequest request(uid, &current_password_handle_buffer, &desired_password_buffer,
+            &current_password_buffer);
+    EnrollResponse response;
+
+    gatekeeper_error_t error = Send(request, &response);
+
+    if (error == ERROR_RETRY) {
+        return response.retry_timeout;
+    } else if (error != ERROR_NONE) {
+        return -EINVAL;
+    }
+
+    *enrolled_password_handle = response.enrolled_password_handle.buffer.release();
+    *enrolled_password_handle_length = response.enrolled_password_handle.length;
+
+
+    return 0;
+}
+
+int TrustyGateKeeperDevice::Verify(uint32_t uid, uint64_t challenge,
+        const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+        const uint8_t *provided_password, uint32_t provided_password_length,
+        uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll) {
+    if (error_ != 0) {
+        return error_;
+    }
+
+    SizedBuffer password_handle_buffer(enrolled_password_handle_length);
+    memcpy(password_handle_buffer.buffer.get(), enrolled_password_handle,
+            enrolled_password_handle_length);
+    SizedBuffer provided_password_buffer(provided_password_length);
+    memcpy(provided_password_buffer.buffer.get(), provided_password, provided_password_length);
+
+    VerifyRequest request(uid, challenge, &password_handle_buffer, &provided_password_buffer);
+    VerifyResponse response;
+
+    gatekeeper_error_t error = Send(request, &response);
+
+    if (error == ERROR_RETRY) {
+        return response.retry_timeout;
+    } else if (error != ERROR_NONE) {
+        return -EINVAL;
+    }
+
+    if (auth_token != NULL && auth_token_length != NULL) {
+       *auth_token = response.auth_token.buffer.release();
+       *auth_token_length = response.auth_token.length;
+    }
+
+    if (request_reenroll != NULL) {
+        *request_reenroll = response.request_reenroll;
+    }
+
+    return 0;
+}
+
+gatekeeper_error_t TrustyGateKeeperDevice::Send(uint32_t command, const GateKeeperMessage& request,
+        GateKeeperMessage *response) {
+    uint32_t request_size = request.GetSerializedSize();
+    if (request_size > SEND_BUF_SIZE)
+        return ERROR_INVALID;
+    uint8_t send_buf[SEND_BUF_SIZE];
+    request.Serialize(send_buf, send_buf + request_size);
+
+    // Send it
+    uint8_t recv_buf[RECV_BUF_SIZE];
+    uint32_t response_size = RECV_BUF_SIZE;
+    int rc = trusty_gatekeeper_call(command, send_buf, request_size, recv_buf, &response_size);
+    if (rc < 0) {
+        ALOGE("error (%d) calling gatekeeper TA", rc);
+        return ERROR_INVALID;
+    }
+
+    const gatekeeper_message *msg = reinterpret_cast<gatekeeper_message *>(recv_buf);
+    const uint8_t *payload = msg->payload;
+
+    return response->Deserialize(payload, payload + response_size);
+}
+
+static inline TrustyGateKeeperDevice *convert_device(const gatekeeper_device *dev) {
+    return reinterpret_cast<TrustyGateKeeperDevice *>(const_cast<gatekeeper_device *>(dev));
+}
+
+/* static */
+int TrustyGateKeeperDevice::enroll(const struct gatekeeper_device *dev, uint32_t uid,
+            const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+            const uint8_t *current_password, uint32_t current_password_length,
+            const uint8_t *desired_password, uint32_t desired_password_length,
+            uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length) {
+
+    if (dev == NULL ||
+            enrolled_password_handle == NULL || enrolled_password_handle_length == NULL ||
+            desired_password == NULL || desired_password_length == 0)
+        return -EINVAL;
+
+    // Current password and current password handle go together
+    if (current_password_handle == NULL || current_password_handle_length == 0 ||
+            current_password == NULL || current_password_length == 0) {
+        current_password_handle = NULL;
+        current_password_handle_length = 0;
+        current_password = NULL;
+        current_password_length = 0;
+    }
+
+    return convert_device(dev)->Enroll(uid, current_password_handle, current_password_handle_length,
+            current_password, current_password_length, desired_password, desired_password_length,
+            enrolled_password_handle, enrolled_password_handle_length);
+
+}
+
+/* static */
+int TrustyGateKeeperDevice::verify(const struct gatekeeper_device *dev, uint32_t uid,
+        uint64_t challenge, const uint8_t *enrolled_password_handle,
+        uint32_t enrolled_password_handle_length, const uint8_t *provided_password,
+        uint32_t provided_password_length, uint8_t **auth_token, uint32_t *auth_token_length,
+        bool *request_reenroll) {
+
+    if (dev == NULL || enrolled_password_handle == NULL ||
+            provided_password == NULL) {
+        return -EINVAL;
+    }
+
+    return convert_device(dev)->Verify(uid, challenge, enrolled_password_handle,
+            enrolled_password_handle_length, provided_password, provided_password_length,
+            auth_token, auth_token_length, request_reenroll);
+}
+};
diff --git a/trusty/gatekeeper/trusty_gatekeeper.h b/trusty/gatekeeper/trusty_gatekeeper.h
new file mode 100644
index 0000000..82108dc
--- /dev/null
+++ b/trusty/gatekeeper/trusty_gatekeeper.h
@@ -0,0 +1,126 @@
+/*
+ * 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 TRUSTY_GATEKEEPER_H
+#define TRUSTY_GATEKEEPER_H
+
+#include <hardware/gatekeeper.h>
+#include <gatekeeper/gatekeeper_messages.h>
+
+#include "gatekeeper_ipc.h"
+
+namespace gatekeeper {
+
+class TrustyGateKeeperDevice {
+    public:
+
+    TrustyGateKeeperDevice(const hw_module_t* module);
+    ~TrustyGateKeeperDevice();
+
+    hw_device_t* hw_device();
+
+    /**
+     * Enrolls password_payload, which should be derived from a user selected pin or password,
+     * with the authentication factor private key used only for enrolling authentication
+     * factor data.
+     *
+     * Returns: 0 on success or an error code less than 0 on error.
+     * On error, enrolled_password will not be allocated.
+     */
+    int Enroll(uint32_t uid, const uint8_t *current_password_handle,
+            uint32_t current_password_handle_length, const uint8_t *current_password,
+            uint32_t current_password_length, const uint8_t *desired_password,
+            uint32_t desired_password_length, uint8_t **enrolled_password_handle,
+            uint32_t *enrolled_password_handle_length);
+
+    /**
+     * Verifies provided_password matches expected_password after enrolling
+     * with the authentication factor private key.
+     *
+     * Implementations of this module may retain the result of this call
+     * to attest to the recency of authentication.
+     *
+     * On success, writes the address of a verification token to verification_token,
+     *
+     * Returns: 0 on success or an error code less than 0 on error
+     * On error, verification token will not be allocated
+     */
+    int Verify(uint32_t uid, uint64_t challenge, const uint8_t *enrolled_password_handle,
+            uint32_t enrolled_password_handle_length, const uint8_t *provided_password,
+            uint32_t provided_password_length, uint8_t **auth_token, uint32_t *auth_token_length,
+            bool *request_reenroll);
+
+    private:
+
+    gatekeeper_error_t Send(uint32_t command, const GateKeeperMessage& request,
+                           GateKeeperMessage* response);
+
+    gatekeeper_error_t Send(const EnrollRequest& request, EnrollResponse *response) {
+        return Send(GK_ENROLL, request, response);
+    }
+
+    gatekeeper_error_t Send(const VerifyRequest& request, VerifyResponse *response) {
+        return Send(GK_VERIFY, request, response);
+    }
+
+    // Static methods interfacing the HAL API with the TrustyGateKeeper device
+
+    /**
+     * Enrolls desired_password, which should be derived from a user selected pin or password,
+     * with the authentication factor private key used only for enrolling authentication
+     * factor data.
+     *
+     * If there was already a password enrolled, it should be provided in
+     * current_password_handle, along with the current password in current_password
+     * that should validate against current_password_handle.
+     *
+     * Returns: 0 on success or an error code less than 0 on error.
+     * On error, enrolled_password_handle will not be allocated.
+     */
+    static int enroll(const struct gatekeeper_device *dev, uint32_t uid,
+            const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+            const uint8_t *current_password, uint32_t current_password_length,
+            const uint8_t *desired_password, uint32_t desired_password_length,
+            uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length);
+
+    /**
+     * Verifies provided_password matches enrolled_password_handle.
+     *
+     * Implementations of this module may retain the result of this call
+     * to attest to the recency of authentication.
+     *
+     * On success, writes the address of a verification token to auth_token,
+     * usable to attest password verification to other trusted services. Clients
+     * may pass NULL for this value.
+     *
+     * Returns: 0 on success or an error code less than 0 on error
+     * On error, verification token will not be allocated
+     */
+    static int verify(const struct gatekeeper_device *dev, uint32_t uid, uint64_t challenge,
+            const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+            const uint8_t *provided_password, uint32_t provided_password_length,
+            uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll);
+
+    static int close_device(hw_device_t* dev);
+
+    gatekeeper_device device_;
+    int error_;
+
+};
+}
+
+#endif
+
diff --git a/trusty/gatekeeper/trusty_gatekeeper_ipc.c b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
new file mode 100644
index 0000000..a1c319e
--- /dev/null
+++ b/trusty/gatekeeper/trusty_gatekeeper_ipc.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_TAG "TrustyGateKeeper"
+#include <cutils/log.h>
+#include <trusty/tipc.h>
+
+#include "trusty_gatekeeper_ipc.h"
+#include "gatekeeper_ipc.h"
+
+#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
+
+static int handle_ = 0;
+
+int trusty_gatekeeper_connect() {
+    int rc = tipc_connect(TRUSTY_DEVICE_NAME, GATEKEEPER_PORT);
+    if (rc < 0) {
+        return rc;
+    }
+
+    handle_ = rc;
+    return 0;
+}
+
+int trusty_gatekeeper_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
+                           uint32_t *out_size) {
+    if (handle_ == 0) {
+        ALOGE("not connected\n");
+        return -EINVAL;
+    }
+
+    size_t msg_size = in_size + sizeof(struct gatekeeper_message);
+    struct gatekeeper_message *msg = malloc(msg_size);
+    msg->cmd = cmd;
+    memcpy(msg->payload, in, in_size);
+
+    ssize_t rc = write(handle_, msg, msg_size);
+    free(msg);
+
+    if (rc < 0) {
+        ALOGE("failed to send cmd (%d) to %s: %s\n", cmd,
+                GATEKEEPER_PORT, strerror(errno));
+        return -errno;
+    }
+
+    rc = read(handle_, out, *out_size);
+    if (rc < 0) {
+        ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n",
+                cmd, GATEKEEPER_PORT, strerror(errno));
+        return -errno;
+    }
+
+    if ((size_t) rc < sizeof(struct gatekeeper_message)) {
+        ALOGE("invalid response size (%d)\n", (int) rc);
+        return -EINVAL;
+    }
+
+    msg = (struct gatekeeper_message *) out;
+
+    if ((cmd | GK_RESP_BIT) != msg->cmd) {
+        ALOGE("invalid command (%d)\n", msg->cmd);
+        return -EINVAL;
+    }
+
+    *out_size = ((size_t) rc) - sizeof(struct gatekeeper_message);
+    return rc;
+}
+
+void trusty_gatekeeper_disconnect() {
+    if (handle_ != 0) {
+        tipc_close(handle_);
+    }
+}
+
diff --git a/trusty/gatekeeper/trusty_gatekeeper_ipc.h b/trusty/gatekeeper/trusty_gatekeeper_ipc.h
new file mode 100644
index 0000000..f8de7f8
--- /dev/null
+++ b/trusty/gatekeeper/trusty_gatekeeper_ipc.h
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+__BEGIN_DECLS
+
+int trusty_gatekeeper_connect();
+int trusty_gatekeeper_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
+                           uint32_t *out_size);
+void trusty_gatekeeper_disconnect();
+
+__END_DECLS
diff --git a/tzdatacheck/tzdatacheck.cpp b/tzdatacheck/tzdatacheck.cpp
index 31f7b55..c1ab2ac 100644
--- a/tzdatacheck/tzdatacheck.cpp
+++ b/tzdatacheck/tzdatacheck.cpp
@@ -27,7 +27,7 @@
 #include <string>
 #include <vector>
 
-#include "base/logging.h"
+#include "android-base/logging.h"
 
 static const char* TZDATA_FILENAME = "/tzdata";
 // tzdata file header (as much as we need for the version):