Merge "adbd: Add os descriptor support for adb."
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 1c1683e..1eb3a3c 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -245,7 +245,7 @@
 
     if (pieces.size() > 2) {
         const std::string& props = pieces[2];
-        for (auto& prop : android::base::Split(props, ";")) {
+        for (const auto& prop : android::base::Split(props, ";")) {
             // The list of properties was traditionally ;-terminated rather than ;-separated.
             if (prop.empty()) continue;
 
@@ -904,7 +904,7 @@
         }
 
         std::string error_msg;
-        atransport* transport = acquire_one_transport(kCsAny, type, serial, &error_msg);
+        atransport* transport = acquire_one_transport(type, serial, nullptr, &error_msg);
         if (!transport) {
             SendFail(reply_fd, error_msg);
             return 1;
@@ -990,13 +990,13 @@
             serial = service;
         }
 
-        std::string error_msg;
-        atransport* t = acquire_one_transport(kCsAny, type, serial, &error_msg);
+        std::string error;
+        atransport* t = acquire_one_transport(type, serial, nullptr, &error);
         if (t != nullptr) {
             s->transport = t;
             SendOkay(reply_fd);
         } else {
-            SendFail(reply_fd, error_msg);
+            SendFail(reply_fd, error);
         }
         return 1;
     }
@@ -1014,12 +1014,12 @@
     }
 
     if (!strcmp(service, "features")) {
-        std::string error_msg;
-        atransport* t = acquire_one_transport(kCsAny, type, serial, &error_msg);
+        std::string error;
+        atransport* t = acquire_one_transport(type, serial, nullptr, &error);
         if (t != nullptr) {
             SendOkay(reply_fd, FeatureSetToString(t->features()));
         } else {
-            SendFail(reply_fd, error_msg);
+            SendFail(reply_fd, error);
         }
         return 0;
     }
@@ -1049,29 +1049,41 @@
         return SendOkay(reply_fd, android::base::StringPrintf("disconnected %s", address.c_str()));
     }
 
-    // returns our value for ADB_SERVER_VERSION
+    // Returns our value for ADB_SERVER_VERSION.
     if (!strcmp(service, "version")) {
         return SendOkay(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION));
     }
 
     // These always report "unknown" rather than the actual error, for scripts.
     if (!strcmp(service, "get-serialno")) {
-        std::string ignored;
-        atransport* t = acquire_one_transport(kCsAny, type, serial, &ignored);
-        return SendOkay(reply_fd, (t && t->serial) ? t->serial : "unknown");
+        std::string error;
+        atransport* t = acquire_one_transport(type, serial, nullptr, &error);
+        if (t) {
+            return SendOkay(reply_fd, t->serial ? t->serial : "unknown");
+        } else {
+            return SendFail(reply_fd, error);
+        }
     }
     if (!strcmp(service, "get-devpath")) {
-        std::string ignored;
-        atransport* t = acquire_one_transport(kCsAny, type, serial, &ignored);
-        return SendOkay(reply_fd, (t && t->devpath) ? t->devpath : "unknown");
+        std::string error;
+        atransport* t = acquire_one_transport(type, serial, nullptr, &error);
+        if (t) {
+            return SendOkay(reply_fd, t->devpath ? t->devpath : "unknown");
+        } else {
+            return SendFail(reply_fd, error);
+        }
     }
     if (!strcmp(service, "get-state")) {
-        std::string ignored;
-        atransport* t = acquire_one_transport(kCsAny, type, serial, &ignored);
-        return SendOkay(reply_fd, t ? t->connection_state_name() : "unknown");
+        std::string error;
+        atransport* t = acquire_one_transport(type, serial, nullptr, &error);
+        if (t) {
+            return SendOkay(reply_fd, t->connection_state_name());
+        } else {
+            return SendFail(reply_fd, error);
+        }
     }
 
-    // indicates a new emulator instance has started
+    // Indicates a new emulator instance has started.
     if (!strncmp(service, "emulator:", 9)) {
         int  port = atoi(service+9);
         local_connect(port);
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 7b314c3..5309519 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -368,7 +368,7 @@
         return;
     }
 
-    for (auto& path : android::base::Split(adb_keys_path, ENV_PATH_SEPARATOR_STR)) {
+    for (const auto& path : android::base::Split(adb_keys_path, ENV_PATH_SEPARATOR_STR)) {
         if (!read_key(path.c_str(), key_list)) {
             D("Failed to read '%s'", path.c_str());
         }
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index 984910d..fa8ce9e 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -209,9 +209,8 @@
             adb_close(fd);
 
             if (sscanf(&version_string[0], "%04x", &version) != 1) {
-                *error = android::base::StringPrintf(
-                        "cannot parse version string: %s",
-                        version_string.c_str());
+                *error = android::base::StringPrintf("cannot parse version string: %s",
+                                                     version_string.c_str());
                 return -1;
             }
         } else {
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 5e5ca7f..0531cf9 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1093,8 +1093,6 @@
     }
     // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
 
-    const char* serial = getenv("ANDROID_SERIAL");
-
     /* Validate and assign the server port */
     const char* server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
     int server_port = DEFAULT_ADB_PORT;
@@ -1108,7 +1106,9 @@
         }
     }
 
-    /* modifiers and flags */
+    // We need to check for -d and -e before we look at $ANDROID_SERIAL.
+    const char* serial = nullptr;
+
     while (argc > 0) {
         if (!strcmp(argv[0],"server")) {
             is_server = 1;
@@ -1199,6 +1199,11 @@
         argv++;
     }
 
+    // If none of -d, -e, or -s were specified, try $ANDROID_SERIAL.
+    if (transport_type == kTransportAny && serial == nullptr) {
+        serial = getenv("ANDROID_SERIAL");
+    }
+
     adb_set_transport(transport_type, serial);
     adb_set_tcp_specifics(server_port);
 
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 18b64f6..ddd15a2 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -199,7 +199,7 @@
 
 static std::string dump_pollfds(const std::vector<pollfd>& pollfds) {
     std::string result;
-    for (auto& pollfd : pollfds) {
+    for (const auto& pollfd : pollfds) {
         std::string op;
         if (pollfd.events & POLLIN) {
             op += "R";
@@ -214,8 +214,8 @@
 
 static void fdevent_process() {
     std::vector<pollfd> pollfds;
-    for (auto it = g_poll_node_map.begin(); it != g_poll_node_map.end(); ++it) {
-        pollfds.push_back(it->second.pollfd);
+    for (const auto& pair : g_poll_node_map) {
+        pollfds.push_back(pair.second.pollfd);
     }
     CHECK_GT(pollfds.size(), 0u);
     D("poll(), pollfds = %s", dump_pollfds(pollfds).c_str());
@@ -224,7 +224,7 @@
         PLOG(ERROR) << "poll(), ret = " << ret;
         return;
     }
-    for (auto& pollfd : pollfds) {
+    for (const auto& pollfd : pollfds) {
         if (pollfd.revents != 0) {
             D("for fd %d, revents = %x", pollfd.fd, pollfd.revents);
         }
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 9b56392..298ed82 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -56,7 +56,7 @@
     path_components.pop_back(); // For "/system/bin/sh", only create "/system/bin".
 
     std::string partial_path;
-    for (auto& path_component : path_components) {
+    for (const auto& path_component : path_components) {
         if (partial_path.back() != OS_PATH_SEPARATOR) partial_path += OS_PATH_SEPARATOR;
         partial_path += path_component;
 
diff --git a/adb/services.cpp b/adb/services.cpp
index e832b1e..e24b470 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -363,23 +363,31 @@
     ConnectionState state;
 };
 
-static void wait_for_state(int fd, void* cookie)
-{
+static void wait_for_state(int fd, void* cookie) {
     state_info* sinfo = reinterpret_cast<state_info*>(cookie);
 
     D("wait_for_state %d", sinfo->state);
 
-    std::string error_msg = "unknown error";
-    atransport* t = acquire_one_transport(sinfo->state, sinfo->transport_type, sinfo->serial,
-                                          &error_msg);
-    if (t != nullptr) {
-        SendOkay(fd);
-    } else {
-        SendFail(fd, error_msg);
+    while (true) {
+        bool is_ambiguous = false;
+        std::string error = "unknown error";
+        atransport* t = acquire_one_transport(sinfo->transport_type, sinfo->serial,
+                                              &is_ambiguous, &error);
+        if (t != nullptr && t->connection_state == sinfo->state) {
+            SendOkay(fd);
+            break;
+        } else if (!is_ambiguous) {
+            adb_sleep_ms(1000);
+            // Try again...
+        } else {
+            SendFail(fd, error);
+            break;
+        }
     }
 
-    if (sinfo->serial)
+    if (sinfo->serial) {
         free(sinfo->serial);
+    }
     free(sinfo);
     adb_close(fd);
     D("wait_for_state is done");
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 8562496..f8c2f64 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -671,8 +671,8 @@
 {
     unsigned len;
 #if ADB_HOST
-    char *service = NULL;
-    char* serial = NULL;
+    char *service = nullptr;
+    char* serial = nullptr;
     TransportType type = kTransportAny;
 #endif
 
@@ -739,7 +739,7 @@
         type = kTransportAny;
         service += strlen("host:");
     } else {
-        service = NULL;
+        service = nullptr;
     }
 
     if (service) {
@@ -782,7 +782,7 @@
         SendOkay(s->peer->fd);
 
         s->peer->ready = local_socket_ready;
-        s->peer->shutdown = NULL;
+        s->peer->shutdown = nullptr;
         s->peer->close = local_socket_close;
         s->peer->peer = s2;
         s2->peer = s->peer;
@@ -795,12 +795,10 @@
         return 0;
     }
 #else /* !ADB_HOST */
-    if (s->transport == NULL) {
+    if (s->transport == nullptr) {
         std::string error_msg = "unknown failure";
-        s->transport =
-            acquire_one_transport(kCsAny, kTransportAny, NULL, &error_msg);
-
-        if (s->transport == NULL) {
+        s->transport = acquire_one_transport(kTransportAny, nullptr, nullptr, &error_msg);
+        if (s->transport == nullptr) {
             SendFail(s->peer->fd, error_msg);
             goto fail;
         }
@@ -822,7 +820,7 @@
         ** tear down
         */
     s->peer->ready = local_socket_ready_notify;
-    s->peer->shutdown = NULL;
+    s->peer->shutdown = nullptr;
     s->peer->close = local_socket_close_notify;
     s->peer->peer = 0;
         /* give him our transport and upref it */
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 501a39a..e9e774f 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -653,22 +653,28 @@
     return !*to_test;
 }
 
-atransport* acquire_one_transport(ConnectionState state, TransportType type,
-                                  const char* serial, std::string* error_out) {
-    atransport *result = NULL;
-    int ambiguous = 0;
+atransport* acquire_one_transport(TransportType type, const char* serial,
+                                  bool* is_ambiguous, std::string* error_out) {
+    atransport* result = nullptr;
 
-retry:
-    *error_out = serial ? android::base::StringPrintf("device '%s' not found", serial) : "no devices found";
+    if (serial) {
+        *error_out = android::base::StringPrintf("device '%s' not found", serial);
+    } else if (type == kTransportLocal) {
+        *error_out = "no emulators found";
+    } else if (type == kTransportAny) {
+        *error_out = "no devices/emulators found";
+    } else {
+        *error_out = "no devices found";
+    }
 
     adb_mutex_lock(&transport_lock);
-    for (auto t : transport_list) {
+    for (const auto& t : transport_list) {
         if (t->connection_state == kCsNoPerm) {
             *error_out = "insufficient permissions for device";
             continue;
         }
 
-        /* check for matching serial number */
+        // Check for matching serial number.
         if (serial) {
             if ((t->serial && !strcmp(serial, t->serial)) ||
                 (t->devpath && !strcmp(serial, t->devpath)) ||
@@ -677,8 +683,8 @@
                 qual_match(serial, "device:", t->device, false)) {
                 if (result) {
                     *error_out = "more than one device";
-                    ambiguous = 1;
-                    result = NULL;
+                    if (is_ambiguous) *is_ambiguous = true;
+                    result = nullptr;
                     break;
                 }
                 result = t;
@@ -687,24 +693,24 @@
             if (type == kTransportUsb && t->type == kTransportUsb) {
                 if (result) {
                     *error_out = "more than one device";
-                    ambiguous = 1;
-                    result = NULL;
+                    if (is_ambiguous) *is_ambiguous = true;
+                    result = nullptr;
                     break;
                 }
                 result = t;
             } else if (type == kTransportLocal && t->type == kTransportLocal) {
                 if (result) {
                     *error_out = "more than one emulator";
-                    ambiguous = 1;
-                    result = NULL;
+                    if (is_ambiguous) *is_ambiguous = true;
+                    result = nullptr;
                     break;
                 }
                 result = t;
             } else if (type == kTransportAny) {
                 if (result) {
                     *error_out = "more than one device/emulator";
-                    ambiguous = 1;
-                    result = NULL;
+                    if (is_ambiguous) *is_ambiguous = true;
+                    result = nullptr;
                     break;
                 }
                 result = t;
@@ -713,37 +719,26 @@
     }
     adb_mutex_unlock(&transport_lock);
 
-    if (result) {
-        if (result->connection_state == kCsUnauthorized) {
-            *error_out = "device unauthorized.\n";
-            char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
-            *error_out += "This adb server's $ADB_VENDOR_KEYS is ";
-            *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
-            *error_out += "\n";
-            *error_out += "Try 'adb kill-server' if that seems wrong.\n";
-            *error_out += "Otherwise check for a confirmation dialog on your device.";
-            result = NULL;
-        }
+    // Don't return unauthorized devices; the caller can't do anything with them.
+    if (result && result->connection_state == kCsUnauthorized) {
+        *error_out = "device unauthorized.\n";
+        char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
+        *error_out += "This adb server's $ADB_VENDOR_KEYS is ";
+        *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
+        *error_out += "\n";
+        *error_out += "Try 'adb kill-server' if that seems wrong.\n";
+        *error_out += "Otherwise check for a confirmation dialog on your device.";
+        result = nullptr;
+    }
 
-        /* offline devices are ignored -- they are either being born or dying */
-        if (result && result->connection_state == kCsOffline) {
-            *error_out = "device offline";
-            result = NULL;
-        }
-
-        /* check for required connection state */
-        if (result && state != kCsAny && result->connection_state != state) {
-            *error_out = "invalid device state";
-            result = NULL;
-        }
+    // Don't return offline devices; the caller can't do anything with them.
+    if (result && result->connection_state == kCsOffline) {
+        *error_out = "device offline";
+        result = nullptr;
     }
 
     if (result) {
-        /* found one that we can take */
         *error_out = "success";
-    } else if (state != kCsAny && (serial || !ambiguous)) {
-        adb_sleep_ms(1000);
-        goto retry;
     }
 
     return result;
@@ -830,7 +825,7 @@
 }
 
 void atransport::RunDisconnects() {
-    for (auto& disconnect : disconnects_) {
+    for (const auto& disconnect : disconnects_) {
         disconnect->func(disconnect->opaque, this);
     }
     disconnects_.clear();
@@ -877,7 +872,7 @@
 std::string list_transports(bool long_listing) {
     std::string result;
     adb_mutex_lock(&transport_lock);
-    for (const auto t : transport_list) {
+    for (const auto& t : transport_list) {
         append_transport(t, &result, long_listing);
     }
     adb_mutex_unlock(&transport_lock);
@@ -887,7 +882,7 @@
 /* hack for osx */
 void close_usb_devices() {
     adb_mutex_lock(&transport_lock);
-    for (auto t : transport_list) {
+    for (const auto& t : transport_list) {
         if (!t->kicked) {
             t->kicked = 1;
             t->kick(t);
@@ -913,7 +908,7 @@
     }
 
     adb_mutex_lock(&transport_lock);
-    for (auto transport : pending_list) {
+    for (const auto& transport : pending_list) {
         if (transport->serial && strcmp(serial, transport->serial) == 0) {
             adb_mutex_unlock(&transport_lock);
             delete t;
@@ -921,7 +916,7 @@
         }
     }
 
-    for (auto transport : transport_list) {
+    for (const auto& transport : transport_list) {
         if (transport->serial && strcmp(serial, transport->serial) == 0) {
             adb_mutex_unlock(&transport_lock);
             delete t;
diff --git a/adb/transport.h b/adb/transport.h
index dfe8875..f41a8d4 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -122,12 +122,13 @@
 
 /*
  * Obtain a transport from the available transports.
- * If state is != kCsAny, only transports in that state are considered.
- * If serial is non-NULL then only the device with that serial will be chosen.
- * If no suitable transport is found, error is set.
+ * If serial is non-null then only the device with that serial will be chosen.
+ * If multiple devices/emulators would match, *is_ambiguous (if non-null)
+ * is set to true and nullptr returned.
+ * If no suitable transport is found, error is set and nullptr returned.
  */
-atransport* acquire_one_transport(ConnectionState state, TransportType type,
-                                  const char* serial, std::string* error_out);
+atransport* acquire_one_transport(TransportType type, const char* serial,
+                                  bool* is_ambiguous, std::string* error_out);
 void kick_transport(atransport* t);
 void update_transports(void);
 
diff --git a/crash_reporter/crash_collector.cc b/crash_reporter/crash_collector.cc
index ae56b4c..2a9d1d3 100644
--- a/crash_reporter/crash_collector.cc
+++ b/crash_reporter/crash_collector.cc
@@ -35,8 +35,8 @@
 #include <base/strings/string_split.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
-#include <chromeos/key_value_store.h>
-#include <chromeos/process.h>
+#include <brillo/key_value_store.h>
+#include <brillo/process.h>
 
 namespace {
 
@@ -340,7 +340,7 @@
 bool CrashCollector::GetLogContents(const FilePath &config_path,
                                     const std::string &exec_name,
                                     const FilePath &output_file) {
-  chromeos::KeyValueStore store;
+  brillo::KeyValueStore store;
   if (!store.Load(config_path)) {
     LOG(INFO) << "Unable to read log configuration file "
               << config_path.value();
@@ -351,7 +351,7 @@
   if (!store.GetString(exec_name, &command))
     return false;
 
-  chromeos::ProcessImpl diag_process;
+  brillo::ProcessImpl diag_process;
   diag_process.AddArg(kShellPath);
   diag_process.AddStringOption("-c", command);
   diag_process.RedirectOutput(output_file.value());
diff --git a/crash_reporter/crash_collector_test.cc b/crash_reporter/crash_collector_test.cc
index 32cbe9f..d00a5b5 100644
--- a/crash_reporter/crash_collector_test.cc
+++ b/crash_reporter/crash_collector_test.cc
@@ -22,14 +22,14 @@
 #include <base/files/file_util.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
-#include <chromeos/syslog_logging.h>
+#include <brillo/syslog_logging.h>
 #include <gtest/gtest.h>
 
 #include "crash_collector.h"
 
 using base::FilePath;
 using base::StringPrintf;
-using chromeos::FindLog;
+using brillo::FindLog;
 using ::testing::Invoke;
 using ::testing::Return;
 
@@ -54,7 +54,7 @@
     collector_.Initialize(CountCrash, IsMetrics);
     test_dir_ = FilePath("test");
     base::CreateDirectory(test_dir_);
-    chromeos::ClearLog();
+    brillo::ClearLog();
   }
 
   void TearDown() {
@@ -208,7 +208,7 @@
             symlink(kMetaFileBasename,
                     meta_symlink_path.value().c_str()));
   ASSERT_TRUE(base::PathExists(meta_symlink_path));
-  chromeos::ClearLog();
+  brillo::ClearLog();
   collector_.WriteCrashMetaData(meta_symlink_path,
                                 "kernel",
                                 payload_file.value());
@@ -221,7 +221,7 @@
   // Test target of dangling symlink is not created.
   base::DeleteFile(meta_file, false);
   ASSERT_FALSE(base::PathExists(meta_file));
-  chromeos::ClearLog();
+  brillo::ClearLog();
   collector_.WriteCrashMetaData(meta_symlink_path, "kernel",
                                 payload_file.value());
   EXPECT_FALSE(base::PathExists(meta_file));
diff --git a/crash_reporter/crash_reporter.cc b/crash_reporter/crash_reporter.cc
index 7872f7b..3955fe5 100644
--- a/crash_reporter/crash_reporter.cc
+++ b/crash_reporter/crash_reporter.cc
@@ -25,9 +25,9 @@
 #include <base/strings/string_split.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
-#include <chromeos/flag_helper.h>
-#include <chromeos/process.h>
-#include <chromeos/syslog_logging.h>
+#include <brillo/flag_helper.h>
+#include <brillo/process.h>
+#include <brillo/syslog_logging.h>
 #include <metrics/metrics_library.h>
 
 #include "kernel_collector.h"
@@ -102,7 +102,7 @@
   // 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.
 
-  chromeos::ProcessImpl dbus_send;
+  brillo::ProcessImpl dbus_send;
   dbus_send.AddArg("/system/bin/dbus-send");
   dbus_send.AddArg("--type=signal");
   dbus_send.AddArg("--system");
@@ -183,10 +183,10 @@
   }
 
   // Accumulate logs to help in diagnosing failures during user collection.
-  chromeos::LogToString(true);
+  brillo::LogToString(true);
   // Handle the crash, get the name of the process from procfs.
   bool handled = user_collector->HandleCrash(user, nullptr);
-  chromeos::LogToString(false);
+  brillo::LogToString(false);
   if (!handled)
     return 1;
   return 0;
@@ -198,9 +198,9 @@
   CHECK(!udev_event.empty()) << "--udev= must be set";
 
   // Accumulate logs to help in diagnosing failures during user collection.
-  chromeos::LogToString(true);
+  brillo::LogToString(true);
   bool handled = udev_collector->HandleCrash(udev_event);
-  chromeos::LogToString(false);
+  brillo::LogToString(false);
   if (!handled)
     return 1;
   return 0;
@@ -209,9 +209,9 @@
 static int HandleKernelWarning(KernelWarningCollector
                                *kernel_warning_collector) {
   // Accumulate logs to help in diagnosing failures during collection.
-  chromeos::LogToString(true);
+  brillo::LogToString(true);
   bool handled = kernel_warning_collector->Collect();
-  chromeos::LogToString(false);
+  brillo::LogToString(false);
   if (!handled)
     return 1;
   return 0;
@@ -278,9 +278,9 @@
   OpenStandardFileDescriptors();
   FilePath my_path = base::MakeAbsoluteFilePath(FilePath(argv[0]));
   s_metrics_lib.Init();
-  chromeos::FlagHelper::Init(argc, argv, "Chromium OS Crash Reporter");
-  chromeos::OpenLog(my_path.BaseName().value().c_str(), true);
-  chromeos::InitLog(chromeos::kLogToSyslog);
+  brillo::FlagHelper::Init(argc, argv, "Chromium OS Crash Reporter");
+  brillo::OpenLog(my_path.BaseName().value().c_str(), true);
+  brillo::InitLog(brillo::kLogToSyslog);
 
   KernelCollector kernel_collector;
   kernel_collector.Initialize(CountKernelCrash, IsFeedbackAllowed);
diff --git a/crash_reporter/crash_reporter.rc b/crash_reporter/crash_reporter.rc
index 30e87f5..7bfe0c2 100644
--- a/crash_reporter/crash_reporter.rc
+++ b/crash_reporter/crash_reporter.rc
@@ -1,6 +1,6 @@
 on property:crash_reporter.coredump.enabled=1
     write /proc/sys/kernel/core_pattern \
-          "|/system/bin/crash_reporter --user=%P:%s:%u:%e"
+          "|/system/bin/crash_reporter --user=%P:%s:%u:%g:%e"
 
 on property:crash_reporter.coredump.enabled=0
     write /proc/sys/kernel/core_pattern "core"
@@ -14,11 +14,14 @@
     rmdir /data/misc/crash_reporter/lock/crash_sender
 
     # Create crash directories.
-    mkdir /data/misc/crash_reporter 0700 root root
+    # These directories are group-writable by root so that crash_reporter can
+    # still access them when it switches users.
+    mkdir /data/misc/crash_reporter 0770 root root
+    mkdir /data/misc/crash_reporter/crash 0770 root root
     mkdir /data/misc/crash_reporter/lock 0700 root root
     mkdir /data/misc/crash_reporter/log 0700 root root
     mkdir /data/misc/crash_reporter/run 0700 root root
-    mkdir /data/misc/crash_reporter/tmp 0700 root root
+    mkdir /data/misc/crash_reporter/tmp 0770 root root
 
 service crash_reporter /system/bin/crash_reporter --init
     class late_start
diff --git a/crash_reporter/crash_reporter_logs_test.cc b/crash_reporter/crash_reporter_logs_test.cc
index c9ca02d..e778002 100644
--- a/crash_reporter/crash_reporter_logs_test.cc
+++ b/crash_reporter/crash_reporter_logs_test.cc
@@ -17,7 +17,7 @@
 #include <string>
 
 #include <base/files/file_path.h>
-#include <chromeos/key_value_store.h>
+#include <brillo/key_value_store.h>
 #include <gtest/gtest.h>
 
 namespace {
@@ -32,7 +32,7 @@
 
 // Tests that the config file is parsable and that Chrome is listed.
 TEST(CrashReporterLogsTest, ReadConfig) {
-  chromeos::KeyValueStore store;
+  brillo::KeyValueStore store;
   ASSERT_TRUE(store.Load(base::FilePath(kConfigFile)));
   std::string command;
   EXPECT_TRUE(store.GetString(kChromeExecName, &command));
diff --git a/crash_reporter/crash_sender b/crash_reporter/crash_sender
index 8a422dd..e38d410 100755
--- a/crash_reporter/crash_sender
+++ b/crash_reporter/crash_sender
@@ -292,7 +292,7 @@
   local kind="$(get_kind "${meta_path}")"
   local exec_name="$(get_key_value "${meta_path}" "exec_name")"
   local url="$(getprop crash_reporter.server)"
-  local brillo_version="$(get_key_value "${meta_path}" "ver")"
+  local bdk_version="$(get_key_value "${meta_path}" "bdk_version")"
   local hwclass="$(get_hardware_class)"
   local write_payload_size="$(get_key_value "${meta_path}" "payload_size")"
   local log="$(get_key_value "${meta_path}" "log")"
@@ -370,12 +370,12 @@
   fi
 
   # If ID or VERSION_ID is undefined, we use the default product name
-  # and CHROMEOS_RELEASE_VERSION from /etc/lsb-release.
+  # and bdk_version from /etc/os-release.d.
   if [ "${product}" = "undefined" ]; then
     product="${BRILLO_PRODUCT}"
   fi
   if [ "${version}" = "undefined" ]; then
-    version="${brillo_version}"
+    version="${bdk_version}"
   fi
 
   local image_type
@@ -460,6 +460,7 @@
     --capath "${RESTRICTED_CERTIFICATES_PATH}" --ciphers HIGH \
     -F "prod=${product}" \
     -F "ver=${version}" \
+    -F "bdk_version=${bdk_version}" \
     -F "hwclass=${hwclass}" \
     -F "exec_name=${exec_name}" \
     -F "model_manifest_id=${model_manifest_id}" \
diff --git a/crash_reporter/kernel_collector_test.cc b/crash_reporter/kernel_collector_test.cc
index e690b77..cdb0ae7 100644
--- a/crash_reporter/kernel_collector_test.cc
+++ b/crash_reporter/kernel_collector_test.cc
@@ -22,13 +22,13 @@
 #include <base/files/scoped_temp_dir.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
-#include <chromeos/syslog_logging.h>
+#include <brillo/syslog_logging.h>
 #include <gtest/gtest.h>
 
 using base::FilePath;
 using base::StringPrintf;
-using chromeos::FindLog;
-using chromeos::GetLog;
+using brillo::FindLog;
+using brillo::GetLog;
 
 namespace {
 
@@ -78,7 +78,7 @@
 
     test_crash_directory_ = scoped_temp_dir_.path().Append("crash_directory");
     ASSERT_TRUE(base::CreateDirectory(test_crash_directory_));
-    chromeos::ClearLog();
+    brillo::ClearLog();
   }
 
   FilePath test_kcrash_;
@@ -282,7 +282,7 @@
   ASSERT_EQ(1, s_crashes);
   ASSERT_TRUE(FindLog("(handling)"));
   static const char kNamePrefix[] = "Stored kcrash to ";
-  std::string log = chromeos::GetLog();
+  std::string log = brillo::GetLog();
   size_t pos = log.find(kNamePrefix);
   ASSERT_NE(std::string::npos, pos)
       << "Did not find string \"" << kNamePrefix << "\" in log: {\n"
diff --git a/crash_reporter/list_proxies.cc b/crash_reporter/list_proxies.cc
index a39441d..d445557 100644
--- a/crash_reporter/list_proxies.cc
+++ b/crash_reporter/list_proxies.cc
@@ -28,8 +28,8 @@
 #include <base/strings/string_tokenizer.h>
 #include <base/strings/string_util.h>
 #include <base/values.h>
-#include <chromeos/daemons/dbus_daemon.h>
-#include <chromeos/syslog_logging.h>
+#include <brillo/daemons/dbus_daemon.h>
+#include <brillo/syslog_logging.h>
 
 #include "libcrosservice/dbus-proxies.h"
 
@@ -111,7 +111,7 @@
 // must be called, which blocks on the D-Bus call to Chrome.  The call returns
 // after either the timeout or the proxy has been resolved.  The resolved
 // proxies can then be accessed through the proxies() function.
-class ProxyResolver : public chromeos::DBusDaemon {
+class ProxyResolver : public brillo::DBusDaemon {
  public:
   ProxyResolver(const std::string& source_url,
                 const std::string& signal_interface,
@@ -138,7 +138,7 @@
         timeout_callback_.callback(),
         timeout_);
 
-    return chromeos::DBusDaemon::Run();
+    return brillo::DBusDaemon::Run();
   }
 
  protected:
@@ -162,7 +162,7 @@
       return;
     }
 
-    chromeos::ErrorPtr error;
+    brillo::ErrorPtr error;
     call_proxy_->ResolveNetworkProxy(source_url_,
                                      signal_interface_,
                                      signal_name_,
@@ -189,7 +189,7 @@
   }
 
   int OnInit() override {
-    int return_code = chromeos::DBusDaemon::OnInit();
+    int return_code = brillo::DBusDaemon::OnInit();
     if (return_code != EX_OK)
       return return_code;
 
@@ -276,13 +276,13 @@
   }
 
   // Default to logging to syslog.
-  int init_flags = chromeos::kLogToSyslog;
+  int init_flags = brillo::kLogToSyslog;
   // Log to stderr if a TTY (and "-quiet" wasn't passed), or if "-verbose"
   // was passed.
 
   if ((!quiet && isatty(STDERR_FILENO)) || verbose)
-    init_flags |= chromeos::kLogToStderr;
-  chromeos::InitLog(init_flags);
+    init_flags |= brillo::kLogToStderr;
+  brillo::InitLog(init_flags);
 
   std::string url;
   base::CommandLine::StringVector urls = cl->GetArgs();
diff --git a/crash_reporter/testrunner.cc b/crash_reporter/testrunner.cc
index a8c717e..744cf10 100644
--- a/crash_reporter/testrunner.cc
+++ b/crash_reporter/testrunner.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <chromeos/test_helpers.h>
+#include <brillo/test_helpers.h>
 #include <gtest/gtest.h>
 
 int main(int argc, char** argv) {
diff --git a/crash_reporter/udev_collector.cc b/crash_reporter/udev_collector.cc
index 576fdbd..1e018db 100644
--- a/crash_reporter/udev_collector.cc
+++ b/crash_reporter/udev_collector.cc
@@ -27,7 +27,7 @@
 #include <base/strings/string_split.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
-#include <chromeos/process.h>
+#include <brillo/process.h>
 
 using base::FilePath;
 
@@ -120,7 +120,7 @@
   }
 
   // Compress the output using gzip.
-  chromeos::ProcessImpl gzip_process;
+  brillo::ProcessImpl gzip_process;
   gzip_process.AddArg(kGzipPath);
   gzip_process.AddArg(crash_path.value());
   int process_result = gzip_process.Run();
diff --git a/crash_reporter/udev_collector_test.cc b/crash_reporter/udev_collector_test.cc
index a6643fb..5474f48 100644
--- a/crash_reporter/udev_collector_test.cc
+++ b/crash_reporter/udev_collector_test.cc
@@ -18,7 +18,7 @@
 #include <base/files/file_util.h>
 #include <base/files/scoped_temp_dir.h>
 #include <base/strings/stringprintf.h>
-#include <chromeos/syslog_logging.h>
+#include <brillo/syslog_logging.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
@@ -141,7 +141,7 @@
                               kLogConfigFileContents,
                               strlen(kLogConfigFileContents)));
 
-    chromeos::ClearLog();
+    brillo::ClearLog();
   }
 
   UdevCollectorMock collector_;
diff --git a/crash_reporter/unclean_shutdown_collector_test.cc b/crash_reporter/unclean_shutdown_collector_test.cc
index c5c0662..3bdeca1 100644
--- a/crash_reporter/unclean_shutdown_collector_test.cc
+++ b/crash_reporter/unclean_shutdown_collector_test.cc
@@ -20,12 +20,12 @@
 
 #include <base/files/file_util.h>
 #include <base/strings/string_util.h>
-#include <chromeos/syslog_logging.h>
+#include <brillo/syslog_logging.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 using base::FilePath;
-using ::chromeos::FindLog;
+using ::brillo::FindLog;
 
 namespace {
 
@@ -65,7 +65,7 @@
     base::DeleteFile(test_unclean_, true);
     // Set up an alternate power manager state file as well
     collector_.powerd_suspended_file_ = FilePath(kTestSuspended);
-    chromeos::ClearLog();
+    brillo::ClearLog();
   }
 
  protected:
diff --git a/crash_reporter/user_collector.cc b/crash_reporter/user_collector.cc
index a9522cc..53fbb14 100644
--- a/crash_reporter/user_collector.cc
+++ b/crash_reporter/user_collector.cc
@@ -23,9 +23,11 @@
 #include <pwd.h>  // For struct passwd.
 #include <stdint.h>
 #include <sys/cdefs.h>  // For __WORDSIZE
+#include <sys/fsuid.h>
 #include <sys/types.h>  // For getpwuid_r, getgrnam_r, WEXITSTATUS.
 #include <unistd.h>  // For setgroups
 
+#include <iostream>  // For std::oct
 #include <string>
 #include <vector>
 
@@ -35,8 +37,9 @@
 #include <base/strings/string_split.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
-#include <chromeos/process.h>
-#include <chromeos/syslog_logging.h>
+#include <brillo/osrelease_reader.h>
+#include <brillo/process.h>
+#include <brillo/syslog_logging.h>
 #include <cutils/properties.h>
 #include <private/android_filesystem_config.h>
 
@@ -49,8 +52,9 @@
 
 static const char kCoreTempFolder[] = "/data/misc/crash_reporter/tmp";
 
-// Define an otherwise invalid value that represents an unknown UID.
+// Define an otherwise invalid value that represents an unknown UID and GID.
 static const uid_t kUnknownUid = -1;
+static const gid_t kUnknownGid = -1;
 
 const char *UserCollector::kUserId = "Uid:\t";
 const char *UserCollector::kGroupId = "Gid:\t";
@@ -61,6 +65,8 @@
 // The property containing the product id.
 const char kProductIDProperty[] = "ro.product.product_id";
 
+static const char kBdkVersionKey[] = "bdk_version";
+
 
 using base::FilePath;
 using base::StringPrintf;
@@ -87,9 +93,9 @@
   directory_failure_ = directory_failure;
   filter_in_ = filter_in;
 
-  gid_t groups[] = { AID_SYSTEM, AID_DBUS };
+  gid_t groups[] = { AID_ROOT, AID_SYSTEM, AID_DBUS };
   if (setgroups(arraysize(groups), groups) != 0) {
-    PLOG(FATAL) << "Unable to set groups to system and dbus";
+    PLOG(FATAL) << "Unable to set groups to root, system, and dbus";
   }
 }
 
@@ -115,22 +121,6 @@
   }
 }
 
-// Return the string that should be used for the kernel's core_pattern file.
-// Note that if you change the format of the enabled pattern, you'll probably
-// also need to change the ParseCrashAttributes() function below, the
-// user_collector_test.cc unittest, and the logging_UserCrash.py autotest.
-std::string UserCollector::GetPattern(bool enabled) const {
-  if (enabled) {
-    // Combine the four crash attributes into one parameter to try to reduce
-    // the size of the invocation line for crash_reporter, since the kernel
-    // has a fixed-sized (128B) buffer for it (before parameter expansion).
-    // Note that the kernel does not support quoted arguments in core_pattern.
-    return StringPrintf("|%s --user=%%P:%%s:%%u:%%e", our_path_.c_str());
-  } else {
-    return "core";
-  }
-}
-
 bool UserCollector::SetUpInternal(bool enabled) {
   CHECK(initialized_);
   LOG(INFO) << (enabled ? "Enabling" : "Disabling") << " user crash handling";
@@ -200,7 +190,7 @@
   AddCrashMetaData("sig", kCollectionErrorSignature);
   AddCrashMetaData("error_type", GetErrorTypeSignature(error_type));
   std::string dump_basename = FormatDumpBasename(exec, time(nullptr), pid);
-  std::string error_log = chromeos::GetLog();
+  std::string error_log = brillo::GetLog();
   FilePath diag_log_path = GetCrashPath(crash_path, dump_basename, "diaglog");
   if (GetLogContents(FilePath(log_config_path_), kCollectionErrorSignature,
                      diag_log_path)) {
@@ -227,7 +217,19 @@
 bool UserCollector::CopyOffProcFiles(pid_t pid,
                                      const FilePath &container_dir) {
   if (!base::CreateDirectory(container_dir)) {
-    PLOG(ERROR) << "Could not create " << container_dir.value().c_str();
+    PLOG(ERROR) << "Could not create " << container_dir.value();
+    return false;
+  }
+  int dir_mask = base::FILE_PERMISSION_READ_BY_USER
+                 | base::FILE_PERMISSION_WRITE_BY_USER
+                 | base::FILE_PERMISSION_EXECUTE_BY_USER
+                 | base::FILE_PERMISSION_READ_BY_GROUP
+                 | base::FILE_PERMISSION_WRITE_BY_GROUP;
+  if (!base::SetPosixFilePermissions(container_dir,
+                                     base::FILE_PERMISSION_MASK & dir_mask)) {
+    PLOG(ERROR) << "Could not set permissions for " << container_dir.value()
+                << " to " << std::oct
+                << (base::FILE_PERMISSION_MASK & dir_mask);
     return false;
   }
   FilePath process_path = GetProcessPath(pid);
@@ -368,7 +370,7 @@
                                       const FilePath &minidump_path,
                                       const FilePath &temp_directory) {
   FilePath output_path = temp_directory.Append("output");
-  chromeos::ProcessImpl core2md;
+  brillo::ProcessImpl core2md;
   core2md.RedirectOutput(output_path.value());
   core2md.AddArg(kCoreToMinidumpConverterPath);
   core2md.AddArg(core_path.value());
@@ -410,6 +412,43 @@
   bool proc_files_usable =
       CopyOffProcFiles(pid, container_dir) && ValidateProcFiles(container_dir);
 
+  // Switch back to the original UID/GID.
+  gid_t rgid, egid, sgid;
+  if (getresgid(&rgid, &egid, &sgid) != 0) {
+    PLOG(FATAL) << "Unable to read saved gid";
+  }
+  if (setresgid(sgid, sgid, -1) != 0) {
+    PLOG(FATAL) << "Unable to set real group ID back to saved gid";
+  } else {
+    if (getresgid(&rgid, &egid, &sgid) != 0) {
+      // If the groups cannot be read at this point, the rgid variable will
+      // contain the previously read group ID from before changing it.  This
+      // will cause the chown call below to set the incorrect group for
+      // non-root crashes.  But do not treat this as a fatal error, so that
+      // the rest of the collection will continue for potential manual
+      // collection by a developer.
+      PLOG(ERROR) << "Unable to read real group ID after setting it";
+    }
+  }
+
+  uid_t ruid, euid, suid;
+  if (getresuid(&ruid, &euid, &suid) != 0) {
+    PLOG(FATAL) << "Unable to read saved uid";
+  }
+  if (setresuid(suid, suid, -1) != 0) {
+    PLOG(FATAL) << "Unable to set real user ID back to saved uid";
+  } else {
+    if (getresuid(&ruid, &euid, &suid) != 0) {
+      // If the user ID cannot be read at this point, the ruid variable will
+      // contain the previously read user ID from before changing it.  This
+      // will cause the chown call below to set the incorrect user for
+      // non-root crashes.  But do not treat this as a fatal error, so that
+      // the rest of the collection will continue for potential manual
+      // collection by a developer.
+      PLOG(ERROR) << "Unable to read real user ID after setting it";
+    }
+  }
+
   if (!CopyStdinToCoreFile(core_path)) {
     return kErrorReadCoreData;
   }
@@ -425,6 +464,13 @@
     return error;
   }
 
+  // Chown the temp container directory back to the original user/group that
+  // crash_reporter is run as, so that additional files can be written to
+  // the temp folder.
+  if (chown(container_dir.value().c_str(), ruid, rgid) < 0) {
+    PLOG(ERROR) << "Could not set owner for " << container_dir.value();
+  }
+
   if (!RunCoreToMinidump(core_path,
                          container_dir,  // procfs directory
                          minidump_path,
@@ -468,6 +514,15 @@
   property_get(kProductIDProperty, value, "undefined");
   AddCrashMetaUploadData("prod", value);
 
+  brillo::OsReleaseReader reader;
+  reader.Load();
+  std::string bdk_version = "undefined";
+  if (!reader.GetString(kBdkVersionKey, &bdk_version)) {
+    LOG(ERROR) << "Could not read " << kBdkVersionKey
+               << " from /etc/os-release.d/";
+  }
+  AddCrashMetaData(kBdkVersionKey, bdk_version);
+
   ErrorType error_type =
       ConvertCoreToMinidump(pid, container_dir, core_path, minidump_path);
   if (error_type != kErrorNone) {
@@ -496,15 +551,18 @@
 
 bool UserCollector::ParseCrashAttributes(const std::string &crash_attributes,
                                          pid_t *pid, int *signal, uid_t *uid,
+                                         gid_t *gid,
                                          std::string *kernel_supplied_name) {
-  pcrecpp::RE re("(\\d+):(\\d+):(\\d+):(.*)");
-  if (re.FullMatch(crash_attributes, pid, signal, uid, kernel_supplied_name))
+  pcrecpp::RE re("(\\d+):(\\d+):(\\d+):(\\d+):(.*)");
+  if (re.FullMatch(crash_attributes, pid, signal, uid, gid,
+                   kernel_supplied_name))
     return true;
 
   LOG(INFO) << "Falling back to parsing crash attributes '"
-            << crash_attributes << "' without UID";
+            << crash_attributes << "' without UID and GID";
   pcrecpp::RE re_without_uid("(\\d+):(\\d+):(.*)");
   *uid = kUnknownUid;
+  *gid = kUnknownGid;
   return re_without_uid.FullMatch(crash_attributes, pid, signal,
       kernel_supplied_name);
 }
@@ -537,14 +595,25 @@
   pid_t pid = 0;
   int signal = 0;
   uid_t supplied_ruid = kUnknownUid;
+  gid_t supplied_rgid = kUnknownGid;
   std::string kernel_supplied_name;
 
   if (!ParseCrashAttributes(crash_attributes, &pid, &signal, &supplied_ruid,
-                            &kernel_supplied_name)) {
+                            &supplied_rgid, &kernel_supplied_name)) {
     LOG(ERROR) << "Invalid parameter: --user=" <<  crash_attributes;
     return false;
   }
 
+  // Switch to the group and user that ran the crashing binary in order to
+  // access their /proc files.  Do not set suid/sgid, so that we can switch
+  // back after copying the necessary files.
+  if (setresgid(supplied_rgid, supplied_rgid, -1) != 0) {
+    PLOG(FATAL) << "Unable to set real group ID to access process files";
+  }
+  if (setresuid(supplied_ruid, supplied_ruid, -1) != 0) {
+    PLOG(FATAL) << "Unable to set real user ID to access process files";
+  }
+
   std::string exec;
   if (force_exec) {
     exec.assign(force_exec);
diff --git a/crash_reporter/user_collector.h b/crash_reporter/user_collector.h
index 8c38aa2..7261ed4 100644
--- a/crash_reporter/user_collector.h
+++ b/crash_reporter/user_collector.h
@@ -105,7 +105,6 @@
   // crash_reporter-user-collection signature.
   std::string GetErrorTypeSignature(ErrorType error_type) const;
 
-  std::string GetPattern(bool enabled) const;
   bool SetUpInternal(bool enabled);
 
   // Returns, via |line|, the first line in |lines| that starts with |prefix|.
@@ -166,7 +165,7 @@
   ErrorType ConvertAndEnqueueCrash(pid_t pid, const std::string &exec_name,
                                    uid_t supplied_ruid, bool *out_of_capacity);
   bool ParseCrashAttributes(const std::string &crash_attributes,
-                            pid_t *pid, int *signal, uid_t *uid,
+                            pid_t *pid, int *signal, uid_t *uid, gid_t *gid,
                             std::string *kernel_supplied_name);
 
   bool ShouldDump(bool has_owner_consent,
diff --git a/crash_reporter/user_collector_test.cc b/crash_reporter/user_collector_test.cc
index 4419e7c..72e61e6 100644
--- a/crash_reporter/user_collector_test.cc
+++ b/crash_reporter/user_collector_test.cc
@@ -23,12 +23,12 @@
 #include <base/files/file_util.h>
 #include <base/files/scoped_temp_dir.h>
 #include <base/strings/string_split.h>
-#include <chromeos/syslog_logging.h>
+#include <brillo/syslog_logging.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 using base::FilePath;
-using chromeos::FindLog;
+using brillo::FindLog;
 
 namespace {
 
@@ -73,7 +73,7 @@
     base::DeleteFile(FilePath("test"), true);
     mkdir("test", 0777);
     pid_ = getpid();
-    chromeos::ClearLog();
+    brillo::ClearLog();
   }
 
  protected:
@@ -98,35 +98,38 @@
   pid_t pid;
   int signal;
   uid_t uid;
+  gid_t gid;
   std::string exec_name;
-  EXPECT_TRUE(collector_.ParseCrashAttributes("123456:11:1000:foobar",
-      &pid, &signal, &uid, &exec_name));
+  EXPECT_TRUE(collector_.ParseCrashAttributes("123456:11:1000:2000:foobar",
+      &pid, &signal, &uid, &gid, &exec_name));
   EXPECT_EQ(123456, pid);
   EXPECT_EQ(11, signal);
   EXPECT_EQ(1000, uid);
+  EXPECT_EQ(2000, gid);
   EXPECT_EQ("foobar", exec_name);
   EXPECT_TRUE(collector_.ParseCrashAttributes("4321:6:barfoo",
-      &pid, &signal, &uid, &exec_name));
+      &pid, &signal, &uid, &gid, &exec_name));
   EXPECT_EQ(4321, pid);
   EXPECT_EQ(6, signal);
   EXPECT_EQ(-1, uid);
+  EXPECT_EQ(-1, gid);
   EXPECT_EQ("barfoo", exec_name);
 
   EXPECT_FALSE(collector_.ParseCrashAttributes("123456:11",
-      &pid, &signal, &uid, &exec_name));
+      &pid, &signal, &uid, &gid, &exec_name));
 
   EXPECT_TRUE(collector_.ParseCrashAttributes("123456:11:exec:extra",
-      &pid, &signal, &uid, &exec_name));
+      &pid, &signal, &uid, &gid, &exec_name));
   EXPECT_EQ("exec:extra", exec_name);
 
   EXPECT_FALSE(collector_.ParseCrashAttributes("12345p:11:foobar",
-      &pid, &signal, &uid, &exec_name));
+      &pid, &signal, &uid, &gid, &exec_name));
 
   EXPECT_FALSE(collector_.ParseCrashAttributes("123456:1 :foobar",
-      &pid, &signal, &uid, &exec_name));
+      &pid, &signal, &uid, &gid, &exec_name));
 
   EXPECT_FALSE(collector_.ParseCrashAttributes("123456::foobar",
-      &pid, &signal, &uid, &exec_name));
+      &pid, &signal, &uid, &gid, &exec_name));
 }
 
 TEST_F(UserCollectorTest, ShouldDumpDeveloperImageOverridesConsent) {
@@ -219,7 +222,7 @@
       "GetSymlinkTarget failed - Path /proc/0 DirectoryExists: 0"));
   EXPECT_TRUE(FindLog("stat /proc/0/exe failed: -1 2"));
 
-  chromeos::ClearLog();
+  brillo::ClearLog();
   pid_t my_pid = getpid();
   EXPECT_TRUE(collector_.GetExecutableBaseNameFromPid(my_pid, &base_name));
   EXPECT_FALSE(FindLog("Readlink failed"));
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 599995c..713638d 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -130,31 +130,44 @@
   "dump_backtrace"
 };
 
-static bool selinux_action_allowed(int s, pid_t tid, debugger_action_t action)
+static int audit_callback(void* data, security_class_t /* cls */, char* buf, size_t len)
+{
+    struct debugger_request_t* req = reinterpret_cast<debugger_request_t*>(data);
+
+    if (!req) {
+        ALOGE("No debuggerd request audit data");
+        return 0;
+    }
+
+    snprintf(buf, len, "pid=%d uid=%d gid=%d", req->pid, req->uid, req->gid);
+    return 0;
+}
+
+static bool selinux_action_allowed(int s, debugger_request_t* request)
 {
   char *scon = NULL, *tcon = NULL;
   const char *tclass = "debuggerd";
   const char *perm;
   bool allowed = false;
 
-  if (action <= 0 || action >= (sizeof(debuggerd_perms)/sizeof(debuggerd_perms[0]))) {
-    ALOGE("SELinux:  No permission defined for debugger action %d", action);
+  if (request->action <= 0 || request->action >= (sizeof(debuggerd_perms)/sizeof(debuggerd_perms[0]))) {
+    ALOGE("SELinux:  No permission defined for debugger action %d", request->action);
     return false;
   }
 
-  perm = debuggerd_perms[action];
+  perm = debuggerd_perms[request->action];
 
   if (getpeercon(s, &scon) < 0) {
     ALOGE("Cannot get peer context from socket\n");
     goto out;
   }
 
-  if (getpidcon(tid, &tcon) < 0) {
-    ALOGE("Cannot get context for tid %d\n", tid);
+  if (getpidcon(request->tid, &tcon) < 0) {
+    ALOGE("Cannot get context for tid %d\n", request->tid);
     goto out;
   }
 
-  allowed = (selinux_check_access(scon, tcon, tclass, perm, NULL) == 0);
+  allowed = (selinux_check_access(scon, tcon, tclass, perm, reinterpret_cast<void*>(request)) == 0);
 
 out:
    freecon(scon);
@@ -225,7 +238,7 @@
       return -1;
     }
 
-    if (!selinux_action_allowed(fd, out_request->tid, out_request->action))
+    if (!selinux_action_allowed(fd, out_request))
       return -1;
   } else {
     // No one else is allowed to dump arbitrary processes.
@@ -566,6 +579,8 @@
 int main(int argc, char** argv) {
   union selinux_callback cb;
   if (argc == 1) {
+    cb.func_audit = audit_callback;
+    selinux_set_callback(SELINUX_CB_AUDIT, cb);
     cb.func_log = selinux_log_callback;
     selinux_set_callback(SELINUX_CB_LOG, cb);
     return do_server();
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 5e6c6f9..b45703a 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -1,49 +1,59 @@
 # Copyright 2011 The Android Open Source Project
 
 LOCAL_PATH:= $(call my-dir)
+
+common_static_libraries := \
+    liblogwrap \
+    libfec \
+    libfec_rs \
+    libbase \
+    libmincrypt \
+    libcrypto_static \
+    libext4_utils_static \
+    libsquashfs_utils
+
 include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= fs_mgr.c fs_mgr_verity.c fs_mgr_fstab.c
-LOCAL_SRC_FILES += fs_mgr_format.c fs_mgr_slotselect.c
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include \
+LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
+LOCAL_SRC_FILES:= \
+    fs_mgr.c \
+    fs_mgr_format.c \
+    fs_mgr_fstab.c \
+    fs_mgr_slotselect.c \
+    fs_mgr_verity.cpp
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/include \
     system/vold \
     system/extras/ext4_utils \
-    external/openssl/include
-
+    external/openssl/include \
+    bootable/recovery
 LOCAL_MODULE:= libfs_mgr
-LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static libsquashfs_utils
-LOCAL_C_INCLUDES += system/extras/ext4_utils system/extras/squashfs_utils \
-	bootable/recovery
+LOCAL_STATIC_LIBRARIES := $(common_static_libraries)
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_CFLAGS := -Werror
-
 ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT)))
 LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
 endif
-
 include $(BUILD_STATIC_LIBRARY)
 
-
-
 include $(CLEAR_VARS)
-
+LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
 LOCAL_SRC_FILES:= fs_mgr_main.c
-
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-
 LOCAL_MODULE:= fs_mgr
-
 LOCAL_MODULE_TAGS := optional
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
-
-LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static libsquashfs_utils
-LOCAL_STATIC_LIBRARIES += libsparse_static libz libselinux
+LOCAL_STATIC_LIBRARIES := $(common_static_libraries) \
+    libfs_mgr \
+    libcutils \
+    liblog \
+    libc \
+    libsparse_static \
+    libz \
+    libselinux
 LOCAL_CXX_STL := libc++_static
-
 LOCAL_CFLAGS := -Werror
-
 include $(BUILD_EXECUTABLE)
-
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 367ab6e..ba0e097 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -20,6 +20,8 @@
 #include <cutils/klog.h>
 #include <fs_mgr.h>
 
+__BEGIN_DECLS
+
 #define INFO(x...)    KLOG_INFO("fs_mgr", x)
 #define WARNING(x...) KLOG_WARNING("fs_mgr", x)
 #define ERROR(x...)   KLOG_ERROR("fs_mgr", x)
@@ -86,4 +88,6 @@
 int fs_mgr_set_blk_ro(const char *blockdev);
 int fs_mgr_update_for_slotselect(struct fstab *fstab);
 
+__END_DECLS
+
 #endif /* __CORE_FS_MGR_PRIV_H */
diff --git a/fs_mgr/fs_mgr_priv_verity.h b/fs_mgr/fs_mgr_priv_verity.h
index f90e596..cd673f3 100644
--- a/fs_mgr/fs_mgr_priv_verity.h
+++ b/fs_mgr/fs_mgr_priv_verity.h
@@ -14,7 +14,14 @@
  * limitations under the License.
  */
 
+#include <sys/cdefs.h>
+
 #define FS_MGR_SETUP_VERITY_DISABLED -2
 #define FS_MGR_SETUP_VERITY_FAIL -1
 #define FS_MGR_SETUP_VERITY_SUCCESS 0
+
+__BEGIN_DECLS
+
 int fs_mgr_setup_verity(struct fstab_rec *fstab);
+
+__END_DECLS
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.cpp
similarity index 70%
rename from fs_mgr/fs_mgr_verity.c
rename to fs_mgr/fs_mgr_verity.cpp
index eddc3e4..c358982 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -29,6 +29,7 @@
 #include <libgen.h>
 #include <time.h>
 
+#include <base/file.h>
 #include <private/android_filesystem_config.h>
 #include <cutils/properties.h>
 #include <logwrap/logwrap.h>
@@ -37,19 +38,27 @@
 #include "mincrypt/sha.h"
 #include "mincrypt/sha256.h"
 
-#include "ext4_sb.h"
-#include "squashfs_utils.h"
+#include "fec/io.h"
 
+#include "fs_mgr.h"
 #include "fs_mgr_priv.h"
 #include "fs_mgr_priv_verity.h"
 
 #define FSTAB_PREFIX "/fstab."
 
-#define VERITY_METADATA_SIZE 32768
 #define VERITY_TABLE_RSA_KEY "/verity_key"
 #define VERITY_TABLE_HASH_IDX 8
 #define VERITY_TABLE_SALT_IDX 9
 
+#define VERITY_TABLE_OPT_RESTART "restart_on_corruption"
+#define VERITY_TABLE_OPT_LOGGING "ignore_corruption"
+#define VERITY_TABLE_OPT_IGNZERO "ignore_zero_blocks"
+
+#define VERITY_TABLE_OPT_FEC_FORMAT \
+    "use_fec_from_device %s fec_start %" PRIu64 " fec_blocks %" PRIu64 \
+    " fec_roots %u " VERITY_TABLE_OPT_IGNZERO
+#define VERITY_TABLE_OPT_FEC_ARGS 9
+
 #define METADATA_MAGIC 0x01564c54
 #define METADATA_TAG_MAX_LENGTH 63
 #define METADATA_EOD "eod"
@@ -74,18 +83,15 @@
 
 extern struct fs_info info;
 
-static RSAPublicKey *load_key(char *path)
+static RSAPublicKey *load_key(const char *path)
 {
-    FILE *f;
-    RSAPublicKey *key;
-
-    key = malloc(sizeof(RSAPublicKey));
+    RSAPublicKey* key = static_cast<RSAPublicKey*>(malloc(sizeof(RSAPublicKey)));
     if (!key) {
         ERROR("Can't malloc key\n");
         return NULL;
     }
 
-    f = fopen(path, "r");
+    FILE* f = fopen(path, "r");
     if (!f) {
         ERROR("Can't open '%s'\n", path);
         free(key);
@@ -93,7 +99,7 @@
     }
 
     if (!fread(key, sizeof(*key), 1, f)) {
-        ERROR("Could not read key!");
+        ERROR("Could not read key!\n");
         fclose(f);
         free(key);
         return NULL;
@@ -110,7 +116,8 @@
     return key;
 }
 
-static int verify_table(char *signature, char *table, int table_length)
+static int verify_table(const uint8_t *signature, const char *table,
+        uint32_t table_length)
 {
     RSAPublicKey *key;
     uint8_t hash_buf[SHA256_DIGEST_SIZE];
@@ -122,17 +129,17 @@
     // Now get the public key from the keyfile
     key = load_key(VERITY_TABLE_RSA_KEY);
     if (!key) {
-        ERROR("Couldn't load verity keys");
+        ERROR("Couldn't load verity keys\n");
         goto out;
     }
 
     // verify the result
     if (!RSA_verify(key,
-                    (uint8_t*) signature,
+                    signature,
                     RSANUMBYTES,
                     (uint8_t*) hash_buf,
                     SHA256_DIGEST_SIZE)) {
-        ERROR("Couldn't verify table.");
+        ERROR("Couldn't verify table\n");
         goto out;
     }
 
@@ -143,11 +150,11 @@
     return retval;
 }
 
-static int invalidate_table(char *table, int table_length)
+static int invalidate_table(char *table, size_t table_length)
 {
-    int n = 0;
-    int idx = 0;
-    int cleared = 0;
+    size_t n = 0;
+    size_t idx = 0;
+    size_t cleared = 0;
 
     while (n < table_length) {
         if (table[n++] == ' ') {
@@ -170,181 +177,6 @@
     return -1;
 }
 
-static int squashfs_get_target_device_size(char *blk_device, uint64_t *device_size)
-{
-    struct squashfs_info sq_info;
-
-    if (squashfs_parse_sb(blk_device, &sq_info) >= 0) {
-        *device_size = sq_info.bytes_used_4K_padded;
-        return 0;
-    } else {
-        return -1;
-    }
-}
-
-static int ext4_get_target_device_size(char *blk_device, uint64_t *device_size)
-{
-    int data_device;
-    struct ext4_super_block sb;
-    struct fs_info info;
-
-    info.len = 0;  /* Only len is set to 0 to ask the device for real size. */
-
-    data_device = TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC));
-    if (data_device == -1) {
-        ERROR("Error opening block device (%s)", strerror(errno));
-        return -1;
-    }
-
-    if (TEMP_FAILURE_RETRY(lseek64(data_device, 1024, SEEK_SET)) < 0) {
-        ERROR("Error seeking to superblock");
-        close(data_device);
-        return -1;
-    }
-
-    if (TEMP_FAILURE_RETRY(read(data_device, &sb, sizeof(sb))) != sizeof(sb)) {
-        ERROR("Error reading superblock");
-        close(data_device);
-        return -1;
-    }
-
-    ext4_parse_sb(&sb, &info);
-    *device_size = info.len;
-
-    close(data_device);
-    return 0;
-}
-
-static int get_fs_size(char *fs_type, char *blk_device, uint64_t *device_size) {
-    if (!strcmp(fs_type, "ext4")) {
-        if (ext4_get_target_device_size(blk_device, device_size) < 0) {
-            ERROR("Failed to get ext4 fs size on %s.", blk_device);
-            return -1;
-        }
-    } else if (!strcmp(fs_type, "squashfs")) {
-        if (squashfs_get_target_device_size(blk_device, device_size) < 0) {
-            ERROR("Failed to get squashfs fs size on %s.", blk_device);
-            return -1;
-        }
-    } else {
-        ERROR("%s: Unsupported filesystem for verity.", fs_type);
-        return -1;
-    }
-    return 0;
-}
-
-static int read_verity_metadata(uint64_t device_size, char *block_device, char **signature,
-        char **table)
-{
-    unsigned magic_number;
-    unsigned table_length;
-    int protocol_version;
-    int device;
-    int retval = FS_MGR_SETUP_VERITY_FAIL;
-
-    *signature = NULL;
-
-    if (table) {
-        *table = NULL;
-    }
-
-    device = TEMP_FAILURE_RETRY(open(block_device, O_RDONLY | O_CLOEXEC));
-    if (device == -1) {
-        ERROR("Could not open block device %s (%s).\n", block_device, strerror(errno));
-        goto out;
-    }
-
-    if (TEMP_FAILURE_RETRY(lseek64(device, device_size, SEEK_SET)) < 0) {
-        ERROR("Could not seek to start of verity metadata block.\n");
-        goto out;
-    }
-
-    // check the magic number
-    if (TEMP_FAILURE_RETRY(read(device, &magic_number, sizeof(magic_number))) !=
-            sizeof(magic_number)) {
-        ERROR("Couldn't read magic number!\n");
-        goto out;
-    }
-
-#ifdef ALLOW_ADBD_DISABLE_VERITY
-    if (magic_number == VERITY_METADATA_MAGIC_DISABLE) {
-        retval = FS_MGR_SETUP_VERITY_DISABLED;
-        INFO("Attempt to cleanly disable verity - only works in USERDEBUG");
-        goto out;
-    }
-#endif
-
-    if (magic_number != VERITY_METADATA_MAGIC_NUMBER) {
-        ERROR("Couldn't find verity metadata at offset %"PRIu64"!\n", device_size);
-        goto out;
-    }
-
-    // check the protocol version
-    if (TEMP_FAILURE_RETRY(read(device, &protocol_version,
-            sizeof(protocol_version))) != sizeof(protocol_version)) {
-        ERROR("Couldn't read verity metadata protocol version!\n");
-        goto out;
-    }
-    if (protocol_version != 0) {
-        ERROR("Got unknown verity metadata protocol version %d!\n", protocol_version);
-        goto out;
-    }
-
-    // get the signature
-    *signature = (char*) malloc(RSANUMBYTES);
-    if (!*signature) {
-        ERROR("Couldn't allocate memory for signature!\n");
-        goto out;
-    }
-    if (TEMP_FAILURE_RETRY(read(device, *signature, RSANUMBYTES)) != RSANUMBYTES) {
-        ERROR("Couldn't read signature from verity metadata!\n");
-        goto out;
-    }
-
-    if (!table) {
-        retval = FS_MGR_SETUP_VERITY_SUCCESS;
-        goto out;
-    }
-
-    // get the size of the table
-    if (TEMP_FAILURE_RETRY(read(device, &table_length, sizeof(table_length))) !=
-            sizeof(table_length)) {
-        ERROR("Couldn't get the size of the verity table from metadata!\n");
-        goto out;
-    }
-
-    // get the table + null terminator
-    *table = malloc(table_length + 1);
-    if (!*table) {
-        ERROR("Couldn't allocate memory for verity table!\n");
-        goto out;
-    }
-    if (TEMP_FAILURE_RETRY(read(device, *table, table_length)) !=
-            (ssize_t)table_length) {
-        ERROR("Couldn't read the verity table from metadata!\n");
-        goto out;
-    }
-
-    (*table)[table_length] = 0;
-    retval = FS_MGR_SETUP_VERITY_SUCCESS;
-
-out:
-    if (device != -1)
-        close(device);
-
-    if (retval != FS_MGR_SETUP_VERITY_SUCCESS) {
-        free(*signature);
-        *signature = NULL;
-
-        if (table) {
-            free(*table);
-            *table = NULL;
-        }
-    }
-
-    return retval;
-}
-
 static void verity_ioctl_init(struct dm_ioctl *io, char *name, unsigned flags)
 {
     memset(io, 0, DM_BUF_SIZE);
@@ -384,8 +216,76 @@
     return 0;
 }
 
-static int load_verity_table(struct dm_ioctl *io, char *name, uint64_t device_size, int fd, char *table,
-        int mode)
+struct verity_table_params {
+    const char *table;
+    int mode;
+    struct fec_ecc_metadata ecc;
+    const char *ecc_dev;
+};
+
+typedef bool (*format_verity_table_func)(char *buf, const size_t bufsize,
+        const struct verity_table_params *params);
+
+static bool format_verity_table(char *buf, const size_t bufsize,
+        const struct verity_table_params *params)
+{
+    const char *mode_flag = NULL;
+    int res = -1;
+
+    if (params->mode == VERITY_MODE_RESTART) {
+        mode_flag = VERITY_TABLE_OPT_RESTART;
+    } else if (params->mode == VERITY_MODE_LOGGING) {
+        mode_flag = VERITY_TABLE_OPT_LOGGING;
+    }
+
+    if (params->ecc.valid) {
+        if (mode_flag) {
+            res = snprintf(buf, bufsize,
+                    "%s %u %s " VERITY_TABLE_OPT_FEC_FORMAT,
+                    params->table, 1 + VERITY_TABLE_OPT_FEC_ARGS, mode_flag, params->ecc_dev,
+                    params->ecc.start / FEC_BLOCKSIZE, params->ecc.blocks, params->ecc.roots);
+        } else {
+            res = snprintf(buf, bufsize,
+                    "%s %u " VERITY_TABLE_OPT_FEC_FORMAT,
+                    params->table, VERITY_TABLE_OPT_FEC_ARGS, params->ecc_dev,
+                    params->ecc.start / FEC_BLOCKSIZE, params->ecc.blocks, params->ecc.roots);
+        }
+    } else if (mode_flag) {
+        res = snprintf(buf, bufsize, "%s 2 " VERITY_TABLE_OPT_IGNZERO " %s", params->table,
+                    mode_flag);
+    } else {
+        res = strlcpy(buf, params->table, bufsize);
+    }
+
+    if (res < 0 || (size_t)res >= bufsize) {
+        ERROR("Error building verity table; insufficient buffer size?\n");
+        return false;
+    }
+
+    return true;
+}
+
+static bool format_legacy_verity_table(char *buf, const size_t bufsize,
+        const struct verity_table_params *params)
+{
+    int res;
+
+    if (params->mode == VERITY_MODE_EIO) {
+        res = strlcpy(buf, params->table, bufsize);
+    } else {
+        res = snprintf(buf, bufsize, "%s %d", params->table, params->mode);
+    }
+
+    if (res < 0 || (size_t)res >= bufsize) {
+        ERROR("Error building verity table; insufficient buffer size?\n");
+        return false;
+    }
+
+    return true;
+}
+
+static int load_verity_table(struct dm_ioctl *io, char *name, uint64_t device_size, int fd,
+        const struct verity_table_params *params, format_verity_table_func format)
 {
     char *verity_params;
     char *buffer = (char*) io;
@@ -395,35 +295,32 @@
 
     struct dm_target_spec *tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
 
-    // set tgt arguments here
+    // set tgt arguments
     io->target_count = 1;
-    tgt->status=0;
-    tgt->sector_start=0;
-    tgt->length=device_size/512;
+    tgt->status = 0;
+    tgt->sector_start = 0;
+    tgt->length = device_size / 512;
     strcpy(tgt->target_type, "verity");
 
-    // build the verity params here
+    // build the verity params
     verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
     bufsize = DM_BUF_SIZE - (verity_params - buffer);
 
-    if (mode == VERITY_MODE_EIO) {
-        // allow operation with older dm-verity drivers that are unaware
-        // of the mode parameter by omitting it; this also means that we
-        // cannot use logging mode with these drivers, they always cause
-        // an I/O error for corrupted blocks
-        strcpy(verity_params, table);
-    } else if (snprintf(verity_params, bufsize, "%s %d", table, mode) < 0) {
+    if (!format(verity_params, bufsize, params)) {
+        ERROR("Failed to format verity parameters\n");
         return -1;
     }
 
+    INFO("loading verity table: '%s'", verity_params);
+
     // set next target boundary
     verity_params += strlen(verity_params) + 1;
-    verity_params = (char*) (((unsigned long)verity_params + 7) & ~8);
+    verity_params = (char*)(((unsigned long)verity_params + 7) & ~8);
     tgt->next = verity_params - buffer;
 
     // send the ioctl to load the verity table
     if (ioctl(fd, DM_TABLE_LOAD, io)) {
-        ERROR("Error loading verity table (%s)", strerror(errno));
+        ERROR("Error loading verity table (%s)\n", strerror(errno));
         return -1;
     }
 
@@ -485,7 +382,7 @@
         goto out;
     }
 
-    if (TEMP_FAILURE_RETRY(read(fd, buffer, size)) != size) {
+    if (!android::base::ReadFully(fd, buffer, size)) {
         ERROR("Failed to read %zd bytes from %s (%s)\n", size, fname,
             strerror(errno));
         goto out;
@@ -708,28 +605,31 @@
 static int compare_last_signature(struct fstab_rec *fstab, int *match)
 {
     char tag[METADATA_TAG_MAX_LENGTH + 1];
-    char *signature = NULL;
     int fd = -1;
     int rc = -1;
+    off64_t offset = 0;
+    struct fec_handle *f = NULL;
+    struct fec_verity_metadata verity;
     uint8_t curr[SHA256_DIGEST_SIZE];
     uint8_t prev[SHA256_DIGEST_SIZE];
-    off64_t offset = 0;
-    uint64_t device_size;
 
     *match = 1;
 
-    // get verity filesystem size
-    if (get_fs_size(fstab->fs_type, fstab->blk_device, &device_size) < 0) {
-        ERROR("Failed to get filesystem size\n");
+    if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
+            FEC_DEFAULT_ROOTS) == -1) {
+        ERROR("Failed to open '%s' (%s)\n", fstab->blk_device,
+            strerror(errno));
+        return rc;
+    }
+
+    // read verity metadata
+    if (fec_verity_get_metadata(f, &verity) == -1) {
+        ERROR("Failed to get verity metadata '%s' (%s)\n", fstab->blk_device,
+            strerror(errno));
         goto out;
     }
 
-    if (read_verity_metadata(device_size, fstab->blk_device, &signature, NULL) < 0) {
-        ERROR("Failed to read verity signature from %s\n", fstab->mount_point);
-        goto out;
-    }
-
-    SHA256_hash(signature, RSANUMBYTES, curr);
+    SHA256_hash(verity.signature, RSANUMBYTES, curr);
 
     if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s",
             basename(fstab->mount_point)) >= (int)sizeof(tag)) {
@@ -771,12 +671,7 @@
     rc = 0;
 
 out:
-    free(signature);
-
-    if (fd != -1) {
-        close(fd);
-    }
-
+    fec_close(f);
     return rc;
 }
 
@@ -887,8 +782,9 @@
 
 int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback)
 {
-    _Alignas(struct dm_ioctl) char buffer[DM_BUF_SIZE];
+    alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
     bool use_state = true;
+    bool use_state_for_device = true;
     char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
     char *mount_point;
     char propbuf[PROPERTY_VALUE_MAX];
@@ -933,10 +829,12 @@
             continue;
         }
 
+        use_state_for_device = use_state;
+
         if (use_state) {
             if (get_verity_state_offset(&fstab->recs[i], &offset) < 0 ||
                 read_verity_state(fstab->recs[i].verity_loc, offset, &mode) < 0) {
-                continue;
+                use_state_for_device = false;
             }
         }
 
@@ -951,7 +849,7 @@
 
         status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
 
-        if (use_state && *status == 'C') {
+        if (use_state_for_device && *status == 'C') {
             if (write_verity_state(fstab->recs[i].verity_loc, offset,
                     VERITY_MODE_LOGGING) < 0) {
                 continue;
@@ -977,87 +875,105 @@
     return rc;
 }
 
-int fs_mgr_setup_verity(struct fstab_rec *fstab) {
-
+int fs_mgr_setup_verity(struct fstab_rec *fstab)
+{
     int retval = FS_MGR_SETUP_VERITY_FAIL;
     int fd = -1;
-    int mode;
+    char *invalid_table = NULL;
+    char *verity_blk_name = NULL;
+    struct fec_handle *f = NULL;
+    struct fec_verity_metadata verity;
+    struct verity_table_params params;
 
-    char *verity_blk_name = 0;
-    char *verity_table = 0;
-    char *verity_table_signature = 0;
-    int verity_table_length = 0;
-    uint64_t device_size = 0;
-
-    _Alignas(struct dm_ioctl) char buffer[DM_BUF_SIZE];
+    alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
     struct dm_ioctl *io = (struct dm_ioctl *) buffer;
     char *mount_point = basename(fstab->mount_point);
 
-    // get verity filesystem size
-    if (get_fs_size(fstab->fs_type, fstab->blk_device, &device_size) < 0) {
+    if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
+            FEC_DEFAULT_ROOTS) < 0) {
+        ERROR("Failed to open '%s' (%s)\n", fstab->blk_device,
+            strerror(errno));
         return retval;
     }
 
-    // read the verity block at the end of the block device
-    // send error code up the chain so we can detect attempts to disable verity
-    retval = read_verity_metadata(device_size,
-                                  fstab->blk_device,
-                                  &verity_table_signature,
-                                  &verity_table);
-    if (retval < 0) {
+    // read verity metadata
+    if (fec_verity_get_metadata(f, &verity) < 0) {
+        ERROR("Failed to get verity metadata '%s' (%s)\n", fstab->blk_device,
+            strerror(errno));
         goto out;
     }
 
-    retval = FS_MGR_SETUP_VERITY_FAIL;
-    verity_table_length = strlen(verity_table);
+#ifdef ALLOW_ADBD_DISABLE_VERITY
+    if (verity.disabled) {
+        retval = FS_MGR_SETUP_VERITY_DISABLED;
+        INFO("Attempt to cleanly disable verity - only works in USERDEBUG\n");
+        goto out;
+    }
+#endif
+
+    // read ecc metadata
+    if (fec_ecc_get_metadata(f, &params.ecc) < 0) {
+        params.ecc.valid = false;
+    }
+
+    params.ecc_dev = fstab->blk_device;
 
     // get the device mapper fd
     if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
-        ERROR("Error opening device mapper (%s)", strerror(errno));
+        ERROR("Error opening device mapper (%s)\n", strerror(errno));
         goto out;
     }
 
     // create the device
     if (create_verity_device(io, mount_point, fd) < 0) {
-        ERROR("Couldn't create verity device!");
+        ERROR("Couldn't create verity device!\n");
         goto out;
     }
 
     // get the name of the device file
     if (get_verity_device_name(io, mount_point, fd, &verity_blk_name) < 0) {
-        ERROR("Couldn't get verity device number!");
+        ERROR("Couldn't get verity device number!\n");
         goto out;
     }
 
-    if (load_verity_state(fstab, &mode) < 0) {
+    if (load_verity_state(fstab, &params.mode) < 0) {
         /* if accessing or updating the state failed, switch to the default
          * safe mode. This makes sure the device won't end up in an endless
          * restart loop, and no corrupted data will be exposed to userspace
          * without a warning. */
-        mode = VERITY_MODE_EIO;
+        params.mode = VERITY_MODE_EIO;
     }
 
     // verify the signature on the table
-    if (verify_table(verity_table_signature,
-                            verity_table,
-                            verity_table_length) < 0) {
-        if (mode == VERITY_MODE_LOGGING) {
+    if (verify_table(verity.signature, verity.table,
+            verity.table_length) < 0) {
+        if (params.mode == VERITY_MODE_LOGGING) {
             // the user has been warned, allow mounting without dm-verity
             retval = FS_MGR_SETUP_VERITY_SUCCESS;
             goto out;
         }
 
         // invalidate root hash and salt to trigger device-specific recovery
-        if (invalidate_table(verity_table, verity_table_length) < 0) {
+        invalid_table = strdup(verity.table);
+
+        if (!invalid_table ||
+                invalidate_table(invalid_table, verity.table_length) < 0) {
             goto out;
         }
+
+        params.table = invalid_table;
+    } else {
+        params.table = verity.table;
     }
 
-    INFO("Enabling dm-verity for %s (mode %d)\n",  mount_point, mode);
+    INFO("Enabling dm-verity for %s (mode %d)\n", mount_point, params.mode);
 
     // load the verity mapping table
-    if (load_verity_table(io, mount_point, device_size, fd, verity_table,
-            mode) < 0) {
+    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;
     }
 
@@ -1086,8 +1002,8 @@
         close(fd);
     }
 
-    free(verity_table);
-    free(verity_table_signature);
+    fec_close(f);
+    free(invalid_table);
     free(verity_blk_name);
 
     return retval;
diff --git a/include/utils/LruCache.h b/include/utils/LruCache.h
index 7818b4e..20a379e 100644
--- a/include/utils/LruCache.h
+++ b/include/utils/LruCache.h
@@ -99,17 +99,29 @@
     TValue mNullValue;
 
 public:
+    // To be used like:
+    // while (it.next()) {
+    //   it.value(); it.key();
+    // }
     class Iterator {
     public:
-        Iterator(const LruCache<TKey, TValue>& cache): mCache(cache), mIterator(mCache.mSet->begin()) {
+        Iterator(const LruCache<TKey, TValue>& cache):
+                mCache(cache), mIterator(mCache.mSet->begin()), mBeginReturned(false) {
         }
 
         bool next() {
             if (mIterator == mCache.mSet->end()) {
                 return false;
             }
-            std::advance(mIterator, 1);
-            return mIterator != mCache.mSet->end();
+            if (!mBeginReturned) {
+                // mIterator has been initialized to the beginning and
+                // hasn't been returned. Do not advance:
+                mBeginReturned = true;
+            } else {
+                std::advance(mIterator, 1);
+            }
+            bool ret = (mIterator != mCache.mSet->end());
+            return ret;
         }
 
         const TValue& value() const {
@@ -122,6 +134,7 @@
     private:
         const LruCache<TKey, TValue>& mCache;
         typename LruCacheSet::iterator mIterator;
+        bool mBeginReturned;
     };
 };
 
diff --git a/init/Android.mk b/init/Android.mk
index c1cdc1a..8e45a7a 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -84,6 +84,8 @@
 LOCAL_STATIC_LIBRARIES := \
     libinit \
     libfs_mgr \
+    libfec \
+    libfec_rs \
     libsquashfs_utils \
     liblogwrap \
     libcutils \
@@ -94,6 +96,7 @@
     libc \
     libselinux \
     libmincrypt \
+    libcrypto_static \
     libc++_static \
     libdl \
     libsparse_static \
diff --git a/init/init.cpp b/init/init.cpp
index ee1351d..a898b03 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -467,7 +467,16 @@
 }
 
 static int audit_callback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
-    snprintf(buf, len, "property=%s", !data ? "NULL" : (char *)data);
+
+    property_audit_data *d = reinterpret_cast<property_audit_data*>(data);
+
+    if (!d || !d->name || !d->cr) {
+        ERROR("audit_callback invoked with null data arguments!");
+        return 0;
+    }
+
+    snprintf(buf, len, "property=%s pid=%d uid=%d gid=%d", d->name,
+            d->cr->pid, d->cr->uid, d->cr->gid);
     return 0;
 }
 
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 02b3985..5b8e27b 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -105,7 +105,10 @@
     for (const auto& sp : section_parsers_) {
         sp.second->EndFile(path);
     }
-    DumpState();
+
+    // Turning this on and letting the INFO logging be discarded adds 0.2s to
+    // Nexus 9 boot time, so it's disabled by default.
+    if (false) DumpState();
 
     NOTICE("(Parsing %s took %.2fs.)\n", path.c_str(), t.duration());
     return true;
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 7194820..ebf768e 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -90,10 +90,11 @@
     }
 }
 
-static int check_mac_perms(const char *name, char *sctx)
+static int check_mac_perms(const char *name, char *sctx, struct ucred *cr)
 {
     char *tctx = NULL;
     int result = 0;
+    property_audit_data audit_data;
 
     if (!sctx)
         goto err;
@@ -104,7 +105,10 @@
     if (selabel_lookup(sehandle_prop, &tctx, name, 1) != 0)
         goto err;
 
-    if (selinux_check_access(sctx, tctx, "property_service", "set", (void*) name) == 0)
+    audit_data.name = name;
+    audit_data.cr = cr;
+
+    if (selinux_check_access(sctx, tctx, "property_service", "set", reinterpret_cast<void*>(&audit_data)) == 0)
         result = 1;
 
     freecon(tctx);
@@ -112,7 +116,7 @@
     return result;
 }
 
-static int check_control_mac_perms(const char *name, char *sctx)
+static int check_control_mac_perms(const char *name, char *sctx, struct ucred *cr)
 {
     /*
      *  Create a name prefix out of ctl.<service name>
@@ -126,19 +130,19 @@
     if (ret < 0 || (size_t) ret >= sizeof(ctl_name))
         return 0;
 
-    return check_mac_perms(ctl_name, sctx);
+    return check_mac_perms(ctl_name, sctx, cr);
 }
 
 /*
  * Checks permissions for setting system properties.
  * Returns 1 if uid allowed, 0 otherwise.
  */
-static int check_perms(const char *name, char *sctx)
+static int check_perms(const char *name, char *sctx, struct ucred *cr)
 {
     if(!strncmp(name, "ro.", 3))
         name +=3;
 
-    return check_mac_perms(name, sctx);
+    return check_mac_perms(name, sctx, cr);
 }
 
 std::string property_get(const char* name) {
@@ -321,14 +325,14 @@
             // Keep the old close-socket-early behavior when handling
             // ctl.* properties.
             close(s);
-            if (check_control_mac_perms(msg.value, source_ctx)) {
+            if (check_control_mac_perms(msg.value, source_ctx, &cr)) {
                 handle_control_message((char*) msg.name + 4, (char*) msg.value);
             } else {
                 ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
                         msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
             }
         } else {
-            if (check_perms(msg.name, source_ctx)) {
+            if (check_perms(msg.name, source_ctx, &cr)) {
                 property_set((char*) msg.name, (char*) msg.value);
             } else {
                 ERROR("sys_prop: permission denied uid:%d  name:%s\n",
diff --git a/init/property_service.h b/init/property_service.h
index 51d7404..1a48fb1 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -18,9 +18,15 @@
 #define _INIT_PROPERTY_H
 
 #include <stddef.h>
+#include <sys/socket.h>
 #include <sys/system_properties.h>
 #include <string>
 
+struct property_audit_data {
+    ucred *cr;
+    const char* name;
+};
+
 extern void property_init(void);
 extern void property_load_boot_defaults(void);
 extern void load_persist_props(void);
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 681c57f..970b386 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -126,11 +126,10 @@
     { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-private/*" },
     { 00644, AID_APP,       AID_APP,       0, "data/data/*" },
 
-    /* the following five files are INTENTIONALLY set-uid, but they
+    /* the following four 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/procrank" },
     { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procmem" },
     { 04770, AID_ROOT,      AID_RADIO,     0, "system/bin/pppd-ril" },
 
diff --git a/libutils/tests/LruCache_test.cpp b/libutils/tests/LruCache_test.cpp
index 2ed84d7..580b980 100644
--- a/libutils/tests/LruCache_test.cpp
+++ b/libutils/tests/LruCache_test.cpp
@@ -293,4 +293,110 @@
     EXPECT_EQ(3, callback.callbackCount);
 }
 
+TEST_F(LruCacheTest, IteratorCheck) {
+    LruCache<int, int> cache(100);
+
+    cache.put(1, 4);
+    cache.put(2, 5);
+    cache.put(3, 6);
+    EXPECT_EQ(3U, cache.size());
+
+    LruCache<int, int>::Iterator it(cache);
+    std::unordered_set<int> returnedValues;
+    while (it.next()) {
+        int v = it.value();
+        // Check we haven't seen the value before.
+        EXPECT_TRUE(returnedValues.find(v) == returnedValues.end());
+        returnedValues.insert(v);
+    }
+    EXPECT_EQ(std::unordered_set<int>({4, 5, 6}), returnedValues);
+}
+
+TEST_F(LruCacheTest, EmptyCacheIterator) {
+    // Check that nothing crashes...
+    LruCache<int, int> cache(100);
+
+    LruCache<int, int>::Iterator it(cache);
+    std::unordered_set<int> returnedValues;
+    while (it.next()) {
+        returnedValues.insert(it.value());
+    }
+    EXPECT_EQ(std::unordered_set<int>(), returnedValues);
+}
+
+TEST_F(LruCacheTest, OneElementCacheIterator) {
+    // Check that nothing crashes...
+    LruCache<int, int> cache(100);
+    cache.put(1, 2);
+
+    LruCache<int, int>::Iterator it(cache);
+    std::unordered_set<int> returnedValues;
+    while (it.next()) {
+        returnedValues.insert(it.value());
+    }
+    EXPECT_EQ(std::unordered_set<int>({ 2 }), returnedValues);
+}
+
+TEST_F(LruCacheTest, OneElementCacheRemove) {
+    LruCache<int, int> cache(100);
+    cache.put(1, 2);
+
+    cache.remove(1);
+
+    LruCache<int, int>::Iterator it(cache);
+    std::unordered_set<int> returnedValues;
+    while (it.next()) {
+        returnedValues.insert(it.value());
+    }
+    EXPECT_EQ(std::unordered_set<int>({ }), returnedValues);
+}
+
+TEST_F(LruCacheTest, Remove) {
+    LruCache<int, int> cache(100);
+    cache.put(1, 4);
+    cache.put(2, 5);
+    cache.put(3, 6);
+
+    cache.remove(2);
+
+    LruCache<int, int>::Iterator it(cache);
+    std::unordered_set<int> returnedValues;
+    while (it.next()) {
+        returnedValues.insert(it.value());
+    }
+    EXPECT_EQ(std::unordered_set<int>({ 4, 6 }), returnedValues);
+}
+
+TEST_F(LruCacheTest, RemoveYoungest) {
+    LruCache<int, int> cache(100);
+    cache.put(1, 4);
+    cache.put(2, 5);
+    cache.put(3, 6);
+
+    cache.remove(3);
+
+    LruCache<int, int>::Iterator it(cache);
+    std::unordered_set<int> returnedValues;
+    while (it.next()) {
+        returnedValues.insert(it.value());
+    }
+    EXPECT_EQ(std::unordered_set<int>({ 4, 5 }), returnedValues);
+}
+
+TEST_F(LruCacheTest, RemoveNonMember) {
+    LruCache<int, int> cache(100);
+    cache.put(1, 4);
+    cache.put(2, 5);
+    cache.put(3, 6);
+
+    cache.remove(7);
+
+    LruCache<int, int>::Iterator it(cache);
+    std::unordered_set<int> returnedValues;
+    while (it.next()) {
+        returnedValues.insert(it.value());
+    }
+    EXPECT_EQ(std::unordered_set<int>({ 4, 5, 6 }), returnedValues);
+}
+
 }
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 9440b68..ddbfb3e 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -656,7 +656,7 @@
             break;
 
             case 'f':
-                if ((tail_time == log_time::EPOCH) && (tail_lines != 0)) {
+                if ((tail_time == log_time::EPOCH) && (tail_lines == 0)) {
                     tail_time = lastLogTime(optarg);
                 }
                 // redirect output to a file
@@ -832,49 +832,66 @@
     } else {
         logger_list = android_logger_list_alloc(mode, tail_lines, 0);
     }
+    const char *openDeviceFail = NULL;
+    const char *clearFail = NULL;
+    const char *setSizeFail = NULL;
+    const char *getSizeFail = NULL;
+    // We have three orthogonal actions below to clear, set log size and
+    // get log size. All sharing the same iteration loop.
     while (dev) {
         dev->logger_list = logger_list;
         dev->logger = android_logger_open(logger_list,
                                           android_name_to_log_id(dev->device));
         if (!dev->logger) {
-            logcat_panic(false, "Unable to open log device '%s'\n",
-                         dev->device);
+            openDeviceFail = openDeviceFail ?: dev->device;
+            dev = dev->next;
+            continue;
         }
 
         if (clearLog) {
-            int ret;
-            ret = android_logger_clear(dev->logger);
-            if (ret) {
-                logcat_panic(false, "failed to clear the log");
+            if (android_logger_clear(dev->logger)) {
+                clearFail = clearFail ?: dev->device;
             }
         }
 
-        if (setLogSize && android_logger_set_log_size(dev->logger, setLogSize)) {
-            logcat_panic(false, "failed to set the log size");
+        if (setLogSize) {
+            if (android_logger_set_log_size(dev->logger, setLogSize)) {
+                setSizeFail = setSizeFail ?: dev->device;
+            }
         }
 
         if (getLogSize) {
-            long size, readable;
+            long size = android_logger_get_log_size(dev->logger);
+            long readable = android_logger_get_log_readable_size(dev->logger);
 
-            size = android_logger_get_log_size(dev->logger);
-            if (size < 0) {
-                logcat_panic(false, "failed to get the log size");
+            if ((size < 0) || (readable < 0)) {
+                getSizeFail = getSizeFail ?: dev->device;
+            } else {
+                printf("%s: ring buffer is %ld%sb (%ld%sb consumed), "
+                       "max entry is %db, max payload is %db\n", dev->device,
+                       value_of_size(size), multiplier_of_size(size),
+                       value_of_size(readable), multiplier_of_size(readable),
+                       (int) LOGGER_ENTRY_MAX_LEN,
+                       (int) LOGGER_ENTRY_MAX_PAYLOAD);
             }
-
-            readable = android_logger_get_log_readable_size(dev->logger);
-            if (readable < 0) {
-                logcat_panic(false, "failed to get the readable log size");
-            }
-
-            printf("%s: ring buffer is %ld%sb (%ld%sb consumed), "
-                   "max entry is %db, max payload is %db\n", dev->device,
-                   value_of_size(size), multiplier_of_size(size),
-                   value_of_size(readable), multiplier_of_size(readable),
-                   (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
         }
 
         dev = dev->next;
     }
+    // report any errors in the above loop and exit
+    if (openDeviceFail) {
+        logcat_panic(false, "Unable to open log device '%s'\n", openDeviceFail);
+    }
+    if (clearFail) {
+        logcat_panic(false, "failed to clear the '%s' log\n", clearFail);
+    }
+    if (setSizeFail) {
+        logcat_panic(false, "failed to set the '%s' log size\n", setSizeFail);
+    }
+    if (getSizeFail) {
+        logcat_panic(false, "failed to get the readable '%s' log size",
+                     getSizeFail);
+    }
 
     if (setPruneList) {
         size_t len = strlen(setPruneList);
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index bcf8d82..610a6ec 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -15,10 +15,12 @@
  */
 
 #include <ctype.h>
+#include <dirent.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/types.h>
 
 #include <gtest/gtest.h>
 #include <log/log.h>
@@ -368,7 +370,7 @@
 
     while (fgets(buffer, sizeof(buffer), fp)) {
         int size, consumed, max, payload;
-        char size_mult[2], consumed_mult[2];
+        char size_mult[3], consumed_mult[3];
         long full_size, full_consumed;
 
         size = consumed = max = payload = 0;
@@ -573,12 +575,12 @@
     static const char comm[] = "logcat -b radio -b events -b system -b main"
                                      " -d -f %s/log.txt -n 7 -r 1";
     char command[sizeof(buf) + sizeof(comm)];
-    sprintf(command, comm, buf);
+    snprintf(command, sizeof(command), comm, buf);
 
     int ret;
     EXPECT_FALSE((ret = system(command)));
     if (!ret) {
-        sprintf(command, "ls -s %s 2>/dev/null", buf);
+        snprintf(command, sizeof(command), "ls -s %s 2>/dev/null", buf);
 
         FILE *fp;
         EXPECT_TRUE(NULL != (fp = popen(command, "r")));
@@ -587,16 +589,12 @@
             int count = 0;
 
             while (fgets(buffer, sizeof(buffer), fp)) {
-                static const char match_1[] = "4 log.txt";
-                static const char match_2[] = "8 log.txt";
-                static const char match_3[] = "12 log.txt";
-                static const char match_4[] = "16 log.txt";
                 static const char total[] = "total ";
+                int num;
+                char c;
 
-                if (!strncmp(buffer, match_1, sizeof(match_1) - 1)
-                 || !strncmp(buffer, match_2, sizeof(match_2) - 1)
-                 || !strncmp(buffer, match_3, sizeof(match_3) - 1)
-                 || !strncmp(buffer, match_4, sizeof(match_4) - 1)) {
+                if ((2 == sscanf(buffer, "%d log.tx%c", &num, &c)) &&
+                        (num <= 24)) {
                     ++count;
                 } else if (strncmp(buffer, total, sizeof(total) - 1)) {
                     fprintf(stderr, "WARNING: Parse error: %s", buffer);
@@ -606,7 +604,7 @@
             EXPECT_TRUE(count == 7 || count == 8);
         }
     }
-    sprintf(command, "rm -rf %s", buf);
+    snprintf(command, sizeof(command), "rm -rf %s", buf);
     EXPECT_FALSE(system(command));
 }
 
@@ -618,12 +616,12 @@
     static const char logcat_cmd[] = "logcat -b radio -b events -b system -b main"
                                      " -d -f %s/log.txt -n 10 -r 1";
     char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd)];
-    sprintf(command, logcat_cmd, tmp_out_dir);
+    snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir);
 
     int ret;
     EXPECT_FALSE((ret = system(command)));
     if (!ret) {
-        sprintf(command, "ls %s 2>/dev/null", tmp_out_dir);
+        snprintf(command, sizeof(command), "ls %s 2>/dev/null", tmp_out_dir);
 
         FILE *fp;
         EXPECT_TRUE(NULL != (fp = popen(command, "r")));
@@ -659,7 +657,113 @@
         pclose(fp);
         EXPECT_EQ(11, log_file_count);
     }
-    sprintf(command, "rm -rf %s", tmp_out_dir);
+    snprintf(command, sizeof(command), "rm -rf %s", tmp_out_dir);
+    EXPECT_FALSE(system(command));
+}
+
+TEST(logcat, logrotate_continue) {
+    static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
+    char tmp_out_dir[sizeof(tmp_out_dir_form)];
+    ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
+
+    static const char log_filename[] = "log.txt";
+    static const char logcat_cmd[] = "logcat -b all -d -f %s/%s -n 256 -r 1024";
+    static const char cleanup_cmd[] = "rm -rf %s";
+    char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd) + sizeof(log_filename)];
+    snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
+
+    int ret;
+    EXPECT_FALSE((ret = system(command)));
+    if (ret) {
+        snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+        EXPECT_FALSE(system(command));
+        return;
+    }
+    FILE *fp;
+    snprintf(command, sizeof(command), "%s/%s", tmp_out_dir, log_filename);
+    EXPECT_TRUE(NULL != ((fp = fopen(command, "r"))));
+    if (!fp) {
+        snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+        EXPECT_FALSE(system(command));
+        return;
+    }
+    char *line = NULL;
+    char *last_line = NULL; // this line is allowed to stutter, one-line overlap
+    char *second_last_line = NULL;
+    size_t len = 0;
+    while (getline(&line, &len, fp) != -1) {
+        free(second_last_line);
+        second_last_line = last_line;
+        last_line = line;
+        line = NULL;
+    }
+    fclose(fp);
+    free(line);
+    if (second_last_line == NULL) {
+        fprintf(stderr, "No second to last line, using last, test may fail\n");
+        second_last_line = last_line;
+        last_line = NULL;
+    }
+    free(last_line);
+    EXPECT_TRUE(NULL != second_last_line);
+    if (!second_last_line) {
+        snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+        EXPECT_FALSE(system(command));
+        return;
+    }
+    // re-run the command, it should only add a few lines more content if it
+    // continues where it left off.
+    snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
+    EXPECT_FALSE((ret = system(command)));
+    if (ret) {
+        snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+        EXPECT_FALSE(system(command));
+        return;
+    }
+    DIR *dir;
+    EXPECT_TRUE(NULL != (dir = opendir(tmp_out_dir)));
+    if (!dir) {
+        snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+        EXPECT_FALSE(system(command));
+        return;
+    }
+    struct dirent *entry;
+    unsigned count = 0;
+    while ((entry = readdir(dir))) {
+        if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
+            continue;
+        }
+        snprintf(command, sizeof(command), "%s/%s", tmp_out_dir, entry->d_name);
+        EXPECT_TRUE(NULL != ((fp = fopen(command, "r"))));
+        if (!fp) {
+            fprintf(stderr, "%s ?\n", command);
+            continue;
+        }
+        line = NULL;
+        size_t number = 0;
+        while (getline(&line, &len, fp) != -1) {
+            ++number;
+            if (!strcmp(line, second_last_line)) {
+                EXPECT_TRUE(++count <= 1);
+                fprintf(stderr, "%s(%zu):\n", entry->d_name, number);
+            }
+        }
+        fclose(fp);
+        free(line);
+        unlink(command);
+    }
+    closedir(dir);
+    if (count > 1) {
+        char *brk = strpbrk(second_last_line, "\r\n");
+        if (!brk) {
+            brk = second_last_line + strlen(second_last_line);
+        }
+        fprintf(stderr, "\"%.*s\" occured %u times\n",
+            (int)(brk - second_last_line), second_last_line, count);
+    }
+    free(second_last_line);
+
+    snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
     EXPECT_FALSE(system(command));
 }
 
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 031c740..eafa28f 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -96,8 +96,7 @@
         return 0;
     }
 
-    mBuf.clear((log_id_t) id, uid);
-    cli->sendMsg("success");
+    cli->sendMsg(mBuf.clear((log_id_t) id, uid) ? "busy" : "success");
     return 0;
 }
 
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 808d17a..2f7cbfb 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -183,7 +183,7 @@
     static const char comm_str[] = " comm=\"";
     const char *comm = strstr(str, comm_str);
     const char *estr = str + strlen(str);
-    char *commfree = NULL;
+    const char *commfree = NULL;
     if (comm) {
         estr = comm;
         comm += sizeof(comm_str) - 1;
@@ -231,7 +231,7 @@
         // end scope for main buffer
     }
 
-    free(commfree);
+    free(const_cast<char *>(commfree));
     free(str);
 
     if (notify) {
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index c2f846e..1de8e64 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -217,7 +217,7 @@
     return len;
 }
 
-// Prune at most 10% of the log entries or 256, whichever is less.
+// Prune at most 10% of the log entries or maxPrune, whichever is less.
 //
 // mLogElementsLock must be held when this function is called.
 void LogBuffer::maybePrune(log_id_t id) {
@@ -225,21 +225,24 @@
     unsigned long maxSize = log_buffer_size(id);
     if (sizes > maxSize) {
         size_t sizeOver = sizes - ((maxSize * 9) / 10);
-        size_t elements = stats.elements(id);
-        size_t minElements = elements / 10;
+        size_t elements = stats.realElements(id);
+        size_t minElements = elements / 100;
+        if (minElements < minPrune) {
+            minElements = minPrune;
+        }
         unsigned long pruneRows = elements * sizeOver / sizes;
-        if (pruneRows <= minElements) {
+        if (pruneRows < minElements) {
             pruneRows = minElements;
         }
-        if (pruneRows > 256) {
-            pruneRows = 256;
+        if (pruneRows > maxPrune) {
+            pruneRows = maxPrune;
         }
         prune(id, pruneRows);
     }
 }
 
 LogBufferElementCollection::iterator LogBuffer::erase(
-        LogBufferElementCollection::iterator it, bool engageStats) {
+        LogBufferElementCollection::iterator it, bool coalesce) {
     LogBufferElement *e = *it;
     log_id_t id = e->getLogId();
 
@@ -248,10 +251,10 @@
         mLastWorstUid[id].erase(f);
     }
     it = mLogElements.erase(it);
-    if (engageStats) {
-        stats.subtract(e);
-    } else {
+    if (coalesce) {
         stats.erase(e);
+    } else {
+        stats.subtract(e);
     }
     delete e;
 
@@ -286,7 +289,7 @@
 
 public:
 
-    bool merge(LogBufferElement *e, unsigned short dropped) {
+    bool coalesce(LogBufferElement *e, unsigned short dropped) {
         LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid());
         LogBufferElementMap::iterator it = map.find(key.getKey());
         if (it != map.end()) {
@@ -374,8 +377,10 @@
 //
 // mLogElementsLock must be held when this function is called.
 //
-void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
+bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
     LogTimeEntry *oldest = NULL;
+    bool busy = false;
+    bool clearAll = pruneRows == ULONG_MAX;
 
     LogTimeEntry::lock();
 
@@ -393,35 +398,31 @@
     LogBufferElementCollection::iterator it;
 
     if (caller_uid != AID_ROOT) {
+        // Only here if clearAll condition (pruneRows == ULONG_MAX)
         for(it = mLogElements.begin(); it != mLogElements.end();) {
             LogBufferElement *e = *it;
 
-            if (oldest && (oldest->mStart <= e->getSequence())) {
-                break;
-            }
-
-            if (e->getLogId() != id) {
+            if ((e->getLogId() != id) || (e->getUid() != caller_uid)) {
                 ++it;
                 continue;
             }
 
-            if (e->getUid() == caller_uid) {
-                it = erase(it);
-                pruneRows--;
-                if (pruneRows == 0) {
-                    break;
-                }
-            } else {
-                ++it;
+            if (oldest && (oldest->mStart <= e->getSequence())) {
+                oldest->triggerSkip_Locked(id, pruneRows);
+                busy = true;
+                break;
             }
+
+            it = erase(it);
+            pruneRows--;
         }
         LogTimeEntry::unlock();
-        return;
+        return busy;
     }
 
     // prune by worst offender by uid
     bool hasBlacklist = mPrune.naughty();
-    while (pruneRows > 0) {
+    while (!clearAll && (pruneRows > 0)) {
         // recalculate the worst offender on every batched pass
         uid_t worst = (uid_t) -1;
         size_t worst_sizes = 0;
@@ -456,7 +457,7 @@
         it = mLogElements.begin();
         // Perform at least one mandatory garbage collection cycle in following
         // - clear leading chatty tags
-        // - merge chatty tags
+        // - coalesce chatty tags
         // - check age-out of preserved logs
         bool gc = pruneRows <= 1;
         if (!gc && (worst != (uid_t) -1)) {
@@ -478,6 +479,7 @@
             LogBufferElement *e = *it;
 
             if (oldest && (oldest->mStart <= e->getSequence())) {
+                busy = true;
                 break;
             }
 
@@ -494,9 +496,8 @@
                 continue;
             }
 
-            // merge any drops
-            if (dropped && last.merge(e, dropped)) {
-                it = erase(it, false);
+            if (dropped && last.coalesce(e, dropped)) {
+                it = erase(it, true);
                 continue;
             }
 
@@ -527,7 +528,6 @@
                 break;
             }
 
-            // unmerged drop message
             if (dropped) {
                 last.add(e);
                 if ((!gc && (e->getUid() == worst))
@@ -561,8 +561,8 @@
             } else {
                 stats.drop(e);
                 e->setDropped(1);
-                if (last.merge(e, 1)) {
-                    it = erase(it, false);
+                if (last.coalesce(e, 1)) {
+                    it = erase(it, true);
                 } else {
                     last.add(e);
                     if (!gc || (mLastWorstUid[id].find(worst)
@@ -585,7 +585,7 @@
     }
 
     bool whitelist = false;
-    bool hasWhitelist = mPrune.nice();
+    bool hasWhitelist = mPrune.nice() && !clearAll;
     it = mLogElements.begin();
     while((pruneRows > 0) && (it != mLogElements.end())) {
         LogBufferElement *e = *it;
@@ -596,6 +596,8 @@
         }
 
         if (oldest && (oldest->mStart <= e->getSequence())) {
+            busy = true;
+
             if (whitelist) {
                 break;
             }
@@ -631,6 +633,7 @@
             }
 
             if (oldest && (oldest->mStart <= e->getSequence())) {
+                busy = true;
                 if (stats.sizes(id) > (2 * log_buffer_size(id))) {
                     // kick a misbehaving log reader client off the island
                     oldest->release_Locked();
@@ -646,13 +649,50 @@
     }
 
     LogTimeEntry::unlock();
+
+    return (pruneRows > 0) && busy;
 }
 
 // clear all rows of type "id" from the buffer.
-void LogBuffer::clear(log_id_t id, uid_t uid) {
-    pthread_mutex_lock(&mLogElementsLock);
-    prune(id, ULONG_MAX, uid);
-    pthread_mutex_unlock(&mLogElementsLock);
+bool LogBuffer::clear(log_id_t id, uid_t uid) {
+    bool busy = true;
+    // If it takes more than 4 tries (seconds) to clear, then kill reader(s)
+    for (int retry = 4;;) {
+        if (retry == 1) { // last pass
+            // Check if it is still busy after the sleep, we say prune
+            // one entry, not another clear run, so we are looking for
+            // the quick side effect of the return value to tell us if
+            // we have a _blocked_ reader.
+            pthread_mutex_lock(&mLogElementsLock);
+            busy = prune(id, 1, uid);
+            pthread_mutex_unlock(&mLogElementsLock);
+            // It is still busy, blocked reader(s), lets kill them all!
+            // otherwise, lets be a good citizen and preserve the slow
+            // readers and let the clear run (below) deal with determining
+            // if we are still blocked and return an error code to caller.
+            if (busy) {
+                LogTimeEntry::lock();
+                LastLogTimes::iterator times = mTimes.begin();
+                while (times != mTimes.end()) {
+                    LogTimeEntry *entry = (*times);
+                    // Killer punch
+                    if (entry->owned_Locked() && entry->isWatching(id)) {
+                        entry->release_Locked();
+                    }
+                    times++;
+                }
+                LogTimeEntry::unlock();
+            }
+        }
+        pthread_mutex_lock(&mLogElementsLock);
+        busy = prune(id, ULONG_MAX, uid);
+        pthread_mutex_unlock(&mLogElementsLock);
+        if (!busy || !--retry) {
+            break;
+        }
+        sleep (1); // Let reader(s) catch up after notification
+    }
+    return busy;
 }
 
 // get the used space associated with "id".
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index de76693..7ed92e9 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -63,7 +63,7 @@
                      int (*filter)(const LogBufferElement *element, void *arg) = NULL,
                      void *arg = NULL);
 
-    void clear(log_id_t id, uid_t uid = AID_ROOT);
+    bool clear(log_id_t id, uid_t uid = AID_ROOT);
     unsigned long getSize(log_id_t id);
     int setSize(log_id_t id, unsigned long size);
     unsigned long getSizeUsed(log_id_t id);
@@ -78,17 +78,21 @@
     std::string formatPrune() { return mPrune.format(); }
 
     // helper must be protected directly or implicitly by lock()/unlock()
-    char *pidToName(pid_t pid) { return stats.pidToName(pid); }
+    const char *pidToName(pid_t pid) { return stats.pidToName(pid); }
     uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); }
-    char *uidToName(uid_t uid) { return stats.uidToName(uid); }
+    const char *uidToName(uid_t uid) { return stats.uidToName(uid); }
     void lock() { pthread_mutex_lock(&mLogElementsLock); }
     void unlock() { pthread_mutex_unlock(&mLogElementsLock); }
 
 private:
+
+    static constexpr size_t minPrune = 4;
+    static constexpr size_t maxPrune = 256;
+
     void maybePrune(log_id_t id);
-    void prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT);
+    bool prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT);
     LogBufferElementCollection::iterator erase(
-        LogBufferElementCollection::iterator it, bool engageStats = true);
+        LogBufferElementCollection::iterator it, bool coalesce = false);
 };
 
 #endif // _LOGD_LOG_BUFFER_H__
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 150ce22..c4c302b 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -113,9 +113,9 @@
 
     static const char format_uid[] = "uid=%u%s%s expire %u line%s";
     parent->lock();
-    char *name = parent->uidToName(mUid);
+    const char *name = parent->uidToName(mUid);
     parent->unlock();
-    char *commName = android::tidToName(mTid);
+    const char *commName = android::tidToName(mTid);
     if (!commName && (mTid != mPid)) {
         commName = android::tidToName(mPid);
     }
@@ -128,28 +128,28 @@
         size_t len = strlen(name + 1);
         if (!strncmp(name + 1, commName + 1, len)) {
             if (commName[len + 1] == '\0') {
-                free(commName);
+                free(const_cast<char *>(commName));
                 commName = NULL;
             } else {
-                free(name);
+                free(const_cast<char *>(name));
                 name = NULL;
             }
         }
     }
     if (name) {
-        char *p = NULL;
-        asprintf(&p, "(%s)", name);
-        if (p) {
-            free(name);
-            name = p;
+        char *buf = NULL;
+        asprintf(&buf, "(%s)", name);
+        if (buf) {
+            free(const_cast<char *>(name));
+            name = buf;
         }
     }
     if (commName) {
-        char *p = NULL;
-        asprintf(&p, " %s", commName);
-        if (p) {
-            free(commName);
-            commName = p;
+        char *buf = NULL;
+        asprintf(&buf, " %s", commName);
+        if (buf) {
+            free(const_cast<char *>(commName));
+            commName = buf;
         }
     }
     // identical to below to calculate the buffer size required
@@ -166,18 +166,19 @@
 
     buffer = static_cast<char *>(calloc(1, hdrLen + len + 1));
     if (!buffer) {
-        free(name);
-        free(commName);
+        free(const_cast<char *>(name));
+        free(const_cast<char *>(commName));
         return 0;
     }
 
     size_t retval = hdrLen + len;
     if (mLogId == LOG_ID_EVENTS) {
-        android_log_event_string_t *e = reinterpret_cast<android_log_event_string_t *>(buffer);
+        android_log_event_string_t *event =
+            reinterpret_cast<android_log_event_string_t *>(buffer);
 
-        e->header.tag = htole32(LOGD_LOG_TAG);
-        e->type = EVENT_TYPE_STRING;
-        e->length = htole32(len);
+        event->header.tag = htole32(LOGD_LOG_TAG);
+        event->type = EVENT_TYPE_STRING;
+        event->length = htole32(len);
     } else {
         ++retval;
         buffer[0] = ANDROID_LOG_INFO;
@@ -187,8 +188,8 @@
     snprintf(buffer + hdrLen, len + 1, format_uid, mUid, name ? name : "",
              commName ? commName : "",
              mDropped, (mDropped > 1) ? "s" : "");
-    free(name);
-    free(commName);
+    free(const_cast<char *>(name));
+    free(const_cast<char *>(commName));
 
     return retval;
 }
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
index 06d865c..6d0e92e 100644
--- a/logd/LogCommand.cpp
+++ b/logd/LogCommand.cpp
@@ -42,7 +42,6 @@
 static bool groupIsLog(char *buf) {
     char *ptr;
     static const char ws[] = " \n";
-    bool ret = false;
 
     for (buf = strtok_r(buf, ws, &ptr); buf; buf = strtok_r(NULL, ws, &ptr)) {
         errno = 0;
@@ -51,10 +50,10 @@
             return false;
         }
         if (Gid == AID_LOG) {
-            ret = true;
+            return true;
         }
     }
-    return ret;
+    return false;
 }
 
 bool clientHasLogCredentials(SocketClient * cli) {
@@ -69,61 +68,79 @@
     }
 
     // FYI We will typically be here for 'adb logcat'
-    bool ret = false;
+    char filename[256];
+    snprintf(filename, sizeof(filename), "/proc/%u/status", cli->getPid());
 
-    char filename[1024];
-    snprintf(filename, sizeof(filename), "/proc/%d/status", cli->getPid());
-
-    FILE *file = fopen(filename, "r");
-    if (!file) {
-        return ret;
-    }
-
+    bool ret;
+    bool foundLog = false;
     bool foundGid = false;
     bool foundUid = false;
 
-    char line[1024];
-    while (fgets(line, sizeof(line), file)) {
-        static const char groups_string[] = "Groups:\t";
-        static const char uid_string[] = "Uid:\t";
-        static const char gid_string[] = "Gid:\t";
-
-        if (strncmp(groups_string, line, strlen(groups_string)) == 0) {
-            ret = groupIsLog(line + strlen(groups_string));
-            if (!ret) {
-                break;
-            }
-        } else if (strncmp(uid_string, line, strlen(uid_string)) == 0) {
-            uid_t u[4] = { (uid_t) -1, (uid_t) -1, (uid_t) -1, (uid_t) -1};
-
-            sscanf(line + strlen(uid_string), "%u\t%u\t%u\t%u",
-                   &u[0], &u[1], &u[2], &u[3]);
-
-            // Protect against PID reuse by checking that the UID is the same
-            if ((uid != u[0]) || (uid != u[1]) || (uid != u[2]) || (uid != u[3])) {
-                ret = false;
-                break;
-            }
-            foundUid = true;
-        } else if (strncmp(gid_string, line, strlen(gid_string)) == 0) {
-            gid_t g[4] = { (gid_t) -1, (gid_t) -1, (gid_t) -1, (gid_t) -1};
-
-            sscanf(line + strlen(gid_string), "%u\t%u\t%u\t%u",
-                   &g[0], &g[1], &g[2], &g[3]);
-
-            // Protect against PID reuse by checking that the GID is the same
-            if ((gid != g[0]) || (gid != g[1]) || (gid != g[2]) || (gid != g[3])) {
-                ret = false;
-                break;
-            }
-            foundGid = true;
+    //
+    // Reading /proc/<pid>/status is rife with race conditions. All of /proc
+    // suffers from this and its use should be minimized. However, we have no
+    // choice.
+    //
+    // Notably the content from one 4KB page to the next 4KB page can be from a
+    // change in shape even if we are gracious enough to attempt to read
+    // atomically. getline can not even guarantee a page read is not split up
+    // and in effect can read from different vintages of the content.
+    //
+    // We are finding out in the field that a 'logcat -c' via adb occasionally
+    // is returned with permission denied when we did only one pass and thus
+    // breaking scripts. For security we still err on denying access if in
+    // doubt, but we expect the falses  should be reduced significantly as
+    // three times is a charm.
+    //
+    for (int retry = 3;
+            !(ret = foundGid && foundUid && foundLog) && retry;
+            --retry) {
+        FILE *file = fopen(filename, "r");
+        if (!file) {
+            continue;
         }
-    }
 
-    fclose(file);
+        char *line = NULL;
+        size_t len = 0;
+        while (getline(&line, &len, file) > 0) {
+            static const char groups_string[] = "Groups:\t";
+            static const char uid_string[] = "Uid:\t";
+            static const char gid_string[] = "Gid:\t";
 
-    if (!foundGid || !foundUid) {
-        ret = false;
+            if (strncmp(groups_string, line, sizeof(groups_string) - 1) == 0) {
+                if (groupIsLog(line + sizeof(groups_string) - 1)) {
+                    foundLog = true;
+                }
+            } else if (strncmp(uid_string, line, sizeof(uid_string) - 1) == 0) {
+                uid_t u[4] = { (uid_t) -1, (uid_t) -1, (uid_t) -1, (uid_t) -1};
+
+                sscanf(line + sizeof(uid_string) - 1, "%u\t%u\t%u\t%u",
+                       &u[0], &u[1], &u[2], &u[3]);
+
+                // Protect against PID reuse by checking that UID is the same
+                if ((uid == u[0])
+                        && (uid == u[1])
+                        && (uid == u[2])
+                        && (uid == u[3])) {
+                    foundUid = true;
+                }
+            } else if (strncmp(gid_string, line, sizeof(gid_string) - 1) == 0) {
+                gid_t g[4] = { (gid_t) -1, (gid_t) -1, (gid_t) -1, (gid_t) -1};
+
+                sscanf(line + sizeof(gid_string) - 1, "%u\t%u\t%u\t%u",
+                       &g[0], &g[1], &g[2], &g[3]);
+
+                // Protect against PID reuse by checking that GID is the same
+                if ((gid == g[0])
+                        && (gid == g[1])
+                        && (gid == g[2])
+                        && (gid == g[3])) {
+                    foundGid = true;
+                }
+            }
+        }
+        free(line);
+        fclose(file);
     }
 
     return ret;
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index a9c3086..fdb2576 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -14,15 +14,12 @@
  * limitations under the License.
  */
 
-#include <algorithm> // std::max
 #include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 
-#include <base/stringprintf.h>
 #include <log/logger.h>
-#include <private/android_filesystem_config.h>
 
 #include "LogStatistics.h"
 
@@ -30,6 +27,7 @@
     log_id_for_each(id) {
         mSizes[id] = 0;
         mElements[id] = 0;
+        mDroppedElements[id] = 0;
         mSizesTotal[id] = 0;
         mElementsTotal[id] = 0;
     }
@@ -63,9 +61,9 @@
 
 }
 
-void LogStatistics::add(LogBufferElement *e) {
-    log_id_t log_id = e->getLogId();
-    unsigned short size = e->getMsgLen();
+void LogStatistics::add(LogBufferElement *element) {
+    log_id_t log_id = element->getLogId();
+    unsigned short size = element->getMsgLen();
     mSizes[log_id] += size;
     ++mElements[log_id];
 
@@ -76,65 +74,69 @@
         return;
     }
 
-    uidTable[log_id].add(e->getUid(), e);
+    uidTable[log_id].add(element->getUid(), element);
 
     if (!enable) {
         return;
     }
 
-    pidTable.add(e->getPid(), e);
-    tidTable.add(e->getTid(), e);
+    pidTable.add(element->getPid(), element);
+    tidTable.add(element->getTid(), element);
 
-    uint32_t tag = e->getTag();
+    uint32_t tag = element->getTag();
     if (tag) {
-        tagTable.add(tag, e);
+        tagTable.add(tag, element);
     }
 }
 
-void LogStatistics::subtract(LogBufferElement *e) {
-    log_id_t log_id = e->getLogId();
-    unsigned short size = e->getMsgLen();
+void LogStatistics::subtract(LogBufferElement *element) {
+    log_id_t log_id = element->getLogId();
+    unsigned short size = element->getMsgLen();
     mSizes[log_id] -= size;
     --mElements[log_id];
+    if (element->getDropped()) {
+        --mDroppedElements[log_id];
+    }
 
     if (log_id == LOG_ID_KERNEL) {
         return;
     }
 
-    uidTable[log_id].subtract(e->getUid(), e);
+    uidTable[log_id].subtract(element->getUid(), element);
 
     if (!enable) {
         return;
     }
 
-    pidTable.subtract(e->getPid(), e);
-    tidTable.subtract(e->getTid(), e);
+    pidTable.subtract(element->getPid(), element);
+    tidTable.subtract(element->getTid(), element);
 
-    uint32_t tag = e->getTag();
+    uint32_t tag = element->getTag();
     if (tag) {
-        tagTable.subtract(tag, e);
+        tagTable.subtract(tag, element);
     }
 }
 
 // Atomically set an entry to drop
 // entry->setDropped(1) must follow this call, caller should do this explicitly.
-void LogStatistics::drop(LogBufferElement *e) {
-    log_id_t log_id = e->getLogId();
-    unsigned short size = e->getMsgLen();
+void LogStatistics::drop(LogBufferElement *element) {
+    log_id_t log_id = element->getLogId();
+    unsigned short size = element->getMsgLen();
     mSizes[log_id] -= size;
+    ++mDroppedElements[log_id];
 
-    uidTable[log_id].drop(e->getUid(), e);
+    uidTable[log_id].drop(element->getUid(), element);
 
     if (!enable) {
         return;
     }
 
-    pidTable.drop(e->getPid(), e);
-    tidTable.drop(e->getTid(), e);
+    pidTable.drop(element->getPid(), element);
+    tidTable.drop(element->getTid(), element);
 }
 
 // caller must own and free character string
-char *LogStatistics::uidToName(uid_t uid) {
+const char *LogStatistics::uidToName(uid_t uid) const {
     // Local hard coded favourites
     if (uid == AID_LOGD) {
         return strdup("auditd");
@@ -152,7 +154,7 @@
 
     // Parse /data/system/packages.list
     uid_t userId = uid % AID_USER;
-    char *name = android::uidToName(userId);
+    const char *name = android::uidToName(userId);
     if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
         name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
     }
@@ -161,17 +163,17 @@
     }
 
     // report uid -> pid(s) -> pidToName if unique
-    for(pidTable_t::iterator it = pidTable.begin(); it != pidTable.end(); ++it) {
+    for(pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end(); ++it) {
         const PidEntry &entry = it->second;
 
         if (entry.getUid() == uid) {
-            const char *n = entry.getName();
+            const char *nameTmp = entry.getName();
 
-            if (n) {
+            if (nameTmp) {
                 if (!name) {
-                    name = strdup(n);
-                } else if (fast<strcmp>(name, n)) {
-                    free(name);
+                    name = strdup(nameTmp);
+                } else if (fast<strcmp>(name, nameTmp)) {
+                    free(const_cast<char *>(name));
                     name = NULL;
                     break;
                 }
@@ -183,28 +185,152 @@
     return name;
 }
 
-static std::string format_line(
-        const std::string &name,
-        const std::string &size,
-        const std::string &pruned) {
-    static const size_t pruned_len = 6;
-    static const size_t total_len = 70 + pruned_len;
-
-    ssize_t drop_len = std::max(pruned.length() + 1, pruned_len);
-    ssize_t size_len = std::max(size.length() + 1,
-                                total_len - name.length() - drop_len - 1);
-
-    if (pruned.length()) {
-        return android::base::StringPrintf("%s%*s%*s\n", name.c_str(),
-                                           (int)size_len, size.c_str(),
-                                           (int)drop_len, pruned.c_str());
-    } else {
-        return android::base::StringPrintf("%s%*s\n", name.c_str(),
-                                           (int)size_len, size.c_str());
-    }
+std::string UidEntry::formatHeader(const std::string &name, log_id_t id) const {
+    bool isprune = worstUidEnabledForLogid(id);
+    return formatLine(android::base::StringPrintf(
+                          name.c_str(), android_log_id_to_name(id)),
+                      std::string("Size"),
+                      std::string(isprune ? "Pruned" : ""))
+         + formatLine(std::string("UID   PACKAGE"),
+                      std::string("BYTES"),
+                      std::string(isprune ? "NUM" : ""));
 }
 
-std::string LogStatistics::format(uid_t uid, unsigned int logMask) {
+std::string UidEntry::format(const LogStatistics &stat, log_id_t /* id */) const {
+    uid_t uid = getKey();
+    std::string name = android::base::StringPrintf("%u", uid);
+    const char *nameTmp = stat.uidToName(uid);
+    if (nameTmp) {
+        name += android::base::StringPrintf(
+            "%*s%s", (int)std::max(6 - name.length(), (size_t)1),
+            "", nameTmp);
+        free(const_cast<char *>(nameTmp));
+    }
+
+    std::string size = android::base::StringPrintf("%zu", getSizes());
+
+    std::string pruned = "";
+    size_t dropped = getDropped();
+    if (dropped) {
+        pruned = android::base::StringPrintf("%zu", dropped);
+    }
+
+    return formatLine(name, size, pruned);
+}
+
+std::string PidEntry::formatHeader(const std::string &name, log_id_t /* id */) const {
+    return formatLine(name,
+                      std::string("Size"),
+                      std::string("Pruned"))
+         + formatLine(std::string("  PID/UID   COMMAND LINE"),
+                      std::string("BYTES"),
+                      std::string("NUM"));
+}
+
+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);
+    const char *nameTmp = getName();
+    if (nameTmp) {
+        name += android::base::StringPrintf(
+            "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
+            "", nameTmp);
+    } else if ((nameTmp = stat.uidToName(uid))) {
+        name += android::base::StringPrintf(
+            "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
+            "", nameTmp);
+        free(const_cast<char *>(nameTmp));
+    }
+
+    std::string size = android::base::StringPrintf("%zu",
+                                                   getSizes());
+
+    std::string pruned = "";
+    size_t dropped = getDropped();
+    if (dropped) {
+        pruned = android::base::StringPrintf("%zu", dropped);
+    }
+
+    return formatLine(name, size, pruned);
+}
+
+std::string TidEntry::formatHeader(const std::string &name, log_id_t /* id */) const {
+    return formatLine(name,
+                      std::string("Size"),
+                      std::string("Pruned"))
+         + formatLine(std::string("  TID/UID   COMM"),
+                      std::string("BYTES"),
+                      std::string("NUM"));
+}
+
+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);
+    const char *nameTmp = getName();
+    if (nameTmp) {
+        name += android::base::StringPrintf(
+            "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
+            "", nameTmp);
+    } else if ((nameTmp = stat.uidToName(uid))) {
+        // if we do not have a PID name, lets punt to try UID name?
+        name += android::base::StringPrintf(
+            "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
+            "", nameTmp);
+        free(const_cast<char *>(nameTmp));
+        // We tried, better to not have a name at all, we still
+        // have TID/UID by number to report in any case.
+    }
+
+    std::string size = android::base::StringPrintf("%zu",
+                                                   getSizes());
+
+    std::string pruned = "";
+    size_t dropped = getDropped();
+    if (dropped) {
+        pruned = android::base::StringPrintf("%zu", dropped);
+    }
+
+    return formatLine(name, size, pruned);
+}
+
+std::string TagEntry::formatHeader(const std::string &name, log_id_t id) const {
+    bool isprune = worstUidEnabledForLogid(id);
+    return formatLine(name,
+                      std::string("Size"),
+                      std::string(isprune ? "Prune" : ""))
+         + formatLine(std::string("    TAG/UID   TAGNAME"),
+                      std::string("BYTES"),
+                      std::string(isprune ? "NUM" : ""));
+}
+
+std::string TagEntry::format(const LogStatistics & /* stat */, log_id_t /* id */) const {
+    std::string name;
+    uid_t uid = getUid();
+    if (uid == (uid_t)-1) {
+        name = android::base::StringPrintf("%7u",
+                                           getKey());
+    } else {
+        name = android::base::StringPrintf("%7u/%u",
+                                           getKey(), uid);
+    }
+    const char *nameTmp = getName();
+    if (nameTmp) {
+        name += android::base::StringPrintf(
+            "%*s%s", (int)std::max(14 - name.length(), (size_t)1),
+            "", nameTmp);
+    }
+
+    std::string size = android::base::StringPrintf("%zu",
+                                                   getSizes());
+
+    std::string pruned = "";
+
+    return formatLine(name, size, pruned);
+}
+
+std::string LogStatistics::format(uid_t uid, unsigned int logMask) const {
     static const unsigned short spaces_total = 19;
 
     // Report on total logging, current and for all time
@@ -227,7 +353,7 @@
     }
 
     spaces = 4;
-    output += android::base::StringPrintf("\nTotal");
+    output += "\nTotal";
 
     log_id_for_each(id) {
         if (!(logMask & (1 << id))) {
@@ -244,7 +370,7 @@
     }
 
     spaces = 6;
-    output += android::base::StringPrintf("\nNow");
+    output += "\nNow";
 
     log_id_for_each(id) {
         if (!(logMask & (1 << id))) {
@@ -266,245 +392,30 @@
 
     // Report on Chattiest
 
+    std::string name;
+
     // Chattiest by application (UID)
-    static const size_t maximum_sorted_entries = 32;
     log_id_for_each(id) {
         if (!(logMask & (1 << id))) {
             continue;
         }
 
-        bool headerPrinted = false;
-        std::unique_ptr<const UidEntry *[]> sorted = sort(maximum_sorted_entries, id);
-        ssize_t index = -1;
-        while ((index = uidTable_t::next(index, sorted, maximum_sorted_entries)) >= 0) {
-            const UidEntry *entry = sorted[index];
-            uid_t u = entry->getKey();
-            if ((uid != AID_ROOT) && (u != uid)) {
-                continue;
-            }
-
-            if (!headerPrinted) {
-                output += android::base::StringPrintf("\n\n");
-                std::string name;
-                if (uid == AID_ROOT) {
-                    name = android::base::StringPrintf(
-                        "Chattiest UIDs in %s log buffer:",
-                        android_log_id_to_name(id));
-                } else {
-                    name = android::base::StringPrintf(
-                        "Logging for your UID in %s log buffer:",
-                        android_log_id_to_name(id));
-                }
-                std::string size = "Size";
-                std::string pruned = "Pruned";
-                if (!worstUidEnabledForLogid(id)) {
-                    pruned = "";
-                }
-                output += format_line(name, size, pruned);
-
-                name = "UID   PACKAGE";
-                size = "BYTES";
-                pruned = "LINES";
-                if (!worstUidEnabledForLogid(id)) {
-                    pruned = "";
-                }
-                output += format_line(name, size, pruned);
-
-                headerPrinted = true;
-            }
-
-            std::string name = android::base::StringPrintf("%u", u);
-            char *n = uidToName(u);
-            if (n) {
-                name += android::base::StringPrintf(
-                    "%*s%s", (int)std::max(6 - name.length(), (size_t)1),
-                    "", n);
-                free(n);
-            }
-
-            std::string size = android::base::StringPrintf("%zu",
-                                                           entry->getSizes());
-
-            std::string pruned = "";
-            size_t dropped = entry->getDropped();
-            if (dropped) {
-                pruned = android::base::StringPrintf("%zu", dropped);
-            }
-
-            output += format_line(name, size, pruned);
-        }
+        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);
     }
 
     if (enable) {
-        // Pid table
-        bool headerPrinted = false;
-        std::unique_ptr<const PidEntry *[]> sorted = pidTable.sort(maximum_sorted_entries);
-        ssize_t index = -1;
-        while ((index = pidTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
-            const PidEntry *entry = sorted[index];
-            uid_t u = entry->getUid();
-            if ((uid != AID_ROOT) && (u != uid)) {
-                continue;
-            }
-
-            if (!headerPrinted) {
-                output += android::base::StringPrintf("\n\n");
-                std::string name;
-                if (uid == AID_ROOT) {
-                    name = android::base::StringPrintf("Chattiest PIDs:");
-                } else {
-                    name = android::base::StringPrintf("Logging for this PID:");
-                }
-                std::string size = "Size";
-                std::string pruned = "Pruned";
-                output += format_line(name, size, pruned);
-
-                name = "  PID/UID   COMMAND LINE";
-                size = "BYTES";
-                pruned = "LINES";
-                output += format_line(name, size, pruned);
-
-                headerPrinted = true;
-            }
-
-            std::string name = android::base::StringPrintf("%5u/%u",
-                                                           entry->getKey(), u);
-            const char *n = entry->getName();
-            if (n) {
-                name += android::base::StringPrintf(
-                    "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
-                    "", n);
-            } else {
-                char *un = uidToName(u);
-                if (un) {
-                    name += android::base::StringPrintf(
-                        "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
-                        "", un);
-                    free(un);
-                }
-            }
-
-            std::string size = android::base::StringPrintf("%zu",
-                                                           entry->getSizes());
-
-            std::string pruned = "";
-            size_t dropped = entry->getDropped();
-            if (dropped) {
-                pruned = android::base::StringPrintf("%zu", dropped);
-            }
-
-            output += format_line(name, size, pruned);
-        }
-    }
-
-    if (enable) {
-        // Tid table
-        bool headerPrinted = false;
-        // sort() returns list of references, unique_ptr makes sure self-delete
-        std::unique_ptr<const TidEntry *[]> sorted = tidTable.sort(maximum_sorted_entries);
-        ssize_t index = -1;
-        while ((index = tidTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
-            const TidEntry *entry = sorted[index];
-            uid_t u = entry->getUid();
-            if ((uid != AID_ROOT) && (u != uid)) {
-                continue;
-            }
-
-            if (!headerPrinted) { // Only print header if we have table to print
-                output += android::base::StringPrintf("\n\n");
-                std::string name = "Chattiest TIDs:";
-                std::string size = "Size";
-                std::string pruned = "Pruned";
-                output += format_line(name, size, pruned);
-
-                name = "  TID/UID   COMM";
-                size = "BYTES";
-                pruned = "LINES";
-                output += format_line(name, size, pruned);
-
-                headerPrinted = true;
-            }
-
-            std::string name = android::base::StringPrintf("%5u/%u",
-                                                           entry->getKey(), u);
-            const char *n = entry->getName();
-            if (n) {
-                name += android::base::StringPrintf(
-                    "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
-                    "", n);
-            } else {
-                // if we do not have a PID name, lets punt to try UID name?
-                char *un = uidToName(u);
-                if (un) {
-                    name += android::base::StringPrintf(
-                        "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
-                        "", un);
-                    free(un);
-                }
-                // We tried, better to not have a name at all, we still
-                // have TID/UID by number to report in any case.
-            }
-
-            std::string size = android::base::StringPrintf("%zu",
-                                                           entry->getSizes());
-
-            std::string pruned = "";
-            size_t dropped = entry->getDropped();
-            if (dropped) {
-                pruned = android::base::StringPrintf("%zu", dropped);
-            }
-
-            output += format_line(name, size, pruned);
-        }
+        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);
     }
 
     if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
-        // Tag table
-        bool headerPrinted = false;
-        std::unique_ptr<const TagEntry *[]> sorted = tagTable.sort(maximum_sorted_entries);
-        ssize_t index = -1;
-        while ((index = tagTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
-            const TagEntry *entry = sorted[index];
-            uid_t u = entry->getUid();
-            if ((uid != AID_ROOT) && (u != uid)) {
-                continue;
-            }
-
-            std::string pruned = "";
-
-            if (!headerPrinted) {
-                output += android::base::StringPrintf("\n\n");
-                std::string name = "Chattiest events log buffer TAGs:";
-                std::string size = "Size";
-                output += format_line(name, size, pruned);
-
-                name = "    TAG/UID   TAGNAME";
-                size = "BYTES";
-                output += format_line(name, size, pruned);
-
-                headerPrinted = true;
-            }
-
-            std::string name;
-            if (u == (uid_t)-1) {
-                name = android::base::StringPrintf("%7u",
-                                                   entry->getKey());
-            } else {
-                name = android::base::StringPrintf("%7u/%u",
-                                                   entry->getKey(), u);
-            }
-            const char *n = entry->getName();
-            if (n) {
-                name += android::base::StringPrintf(
-                    "%*s%s", (int)std::max(14 - name.length(), (size_t)1),
-                    "", n);
-            }
-
-            std::string size = android::base::StringPrintf("%zu",
-                                                           entry->getSizes());
-
-            output += format_line(name, size, pruned);
-        }
+        name = "Chattiest events log buffer TAGs:";
+        output += tagTable.format(*this, uid, name, LOG_ID_EVENTS);
     }
 
     return output;
@@ -536,8 +447,10 @@
 }
 
 // caller must free character string
-char *LogStatistics::pidToName(pid_t pid) {
-    const char *name = pidTable.add(pid)->second.getName();
+const char *LogStatistics::pidToName(pid_t pid) const {
+    // An inconvenient truth ... getName() can alter the object
+    pidTable_t &writablePidTable = const_cast<pidTable_t &>(pidTable);
+    const char *name = writablePidTable.add(pid)->second.getName();
     if (!name) {
         return NULL;
     }
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 5a44d59..6943820 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -21,9 +21,13 @@
 #include <stdlib.h>
 #include <sys/types.h>
 
+#include <algorithm> // std::max
+#include <string>    // std::string
 #include <unordered_map>
 
+#include <base/stringprintf.h>
 #include <log/log.h>
+#include <private/android_filesystem_config.h>
 
 #include "LogBufferElement.h"
 #include "LogUtils.h"
@@ -31,6 +35,8 @@
 #define log_id_for_each(i) \
     for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1))
 
+class LogStatistics;
+
 template <typename TKey, typename TEntry>
 class LogHashtable {
 
@@ -39,50 +45,43 @@
 public:
 
     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 n) {
-        if (!n) {
+    std::unique_ptr<const TEntry *[]> sort(size_t len) const {
+        if (!len) {
             std::unique_ptr<const TEntry *[]> sorted(NULL);
             return sorted;
         }
 
-        const TEntry **retval = new const TEntry* [n];
-        memset(retval, 0, sizeof(*retval) * n);
+        const TEntry **retval = new const TEntry* [len];
+        memset(retval, 0, sizeof(*retval) * len);
 
-        for(iterator it = map.begin(); it != map.end(); ++it) {
+        for(const_iterator it = map.begin(); it != map.end(); ++it) {
             const TEntry &entry = it->second;
-            size_t s = entry.getSizes();
-            ssize_t i = n - 1;
-            while ((!retval[i] || (s > retval[i]->getSizes())) && (--i >= 0))
+            size_t sizes = entry.getSizes();
+            ssize_t index = len - 1;
+            while ((!retval[index] || (sizes > retval[index]->getSizes()))
+                    && (--index >= 0))
                 ;
-            if (++i < (ssize_t)n) {
-                size_t b = n - i - 1;
-                if (b) {
-                    memmove(&retval[i+1], &retval[i], b * sizeof(retval[0]));
+            if (++index < (ssize_t)len) {
+                size_t num = len - index - 1;
+                if (num) {
+                    memmove(&retval[index + 1], &retval[index],
+                            num * sizeof(retval[0]));
                 }
-                retval[i] = &entry;
+                retval[index] = &entry;
             }
         }
         std::unique_ptr<const TEntry *[]> sorted(retval);
         return sorted;
     }
 
-    // Iteration handler for the sort method output
-    static ssize_t next(ssize_t index, std::unique_ptr<const TEntry *[]> &sorted, size_t n) {
-        ++index;
-        if (!sorted.get() || (index < 0) || (n <= (size_t)index) || !sorted[index]
-         || (sorted[index]->getSizes() <= (sorted[0]->getSizes() / 100))) {
-            return -1;
-        }
-        return index;
-    }
-
-    inline iterator add(TKey key, LogBufferElement *e) {
+    inline iterator add(TKey key, LogBufferElement *element) {
         iterator it = map.find(key);
         if (it == map.end()) {
-            it = map.insert(std::make_pair(key, TEntry(e))).first;
+            it = map.insert(std::make_pair(key, TEntry(element))).first;
         } else {
-            it->second.add(e);
+            it->second.add(element);
         }
         return it;
     }
@@ -97,65 +96,138 @@
         return it;
     }
 
-    void subtract(TKey key, LogBufferElement *e) {
+    void subtract(TKey key, LogBufferElement *element) {
         iterator it = map.find(key);
-        if ((it != map.end()) && it->second.subtract(e)) {
+        if ((it != map.end()) && it->second.subtract(element)) {
             map.erase(it);
         }
     }
 
-    inline void drop(TKey key, LogBufferElement *e) {
+    inline void drop(TKey key, LogBufferElement *element) {
         iterator it = map.find(key);
         if (it != map.end()) {
-            it->second.drop(e);
+            it->second.drop(element);
         }
     }
 
     inline iterator begin() { return map.begin(); }
+    inline const_iterator begin() const { return map.begin(); }
     inline iterator end() { return map.end(); }
+    inline const_iterator end() const { return map.end(); }
 
+    std::string format(
+            const LogStatistics &stat,
+            uid_t uid,
+            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);
+
+        if (!sorted.get()) {
+            return output;
+        }
+        bool headerPrinted = false;
+        for (size_t index = 0; index < maximum_sorted_entries; ++index) {
+            const TEntry *entry = sorted[index];
+            if (!entry) {
+                break;
+            }
+            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);
+                headerPrinted = true;
+            }
+            output += entry->format(stat, id);
+        }
+        return output;
+    }
 };
 
+namespace EntryBaseConstants {
+    static constexpr size_t pruned_len = 14;
+    static constexpr size_t total_len = 80;
+}
+
 struct EntryBase {
     size_t size;
 
     EntryBase():size(0) { }
-    EntryBase(LogBufferElement *e):size(e->getMsgLen()) { }
+    EntryBase(LogBufferElement *element):size(element->getMsgLen()) { }
 
     size_t getSizes() const { return size; }
 
-    inline void add(LogBufferElement *e) { size += e->getMsgLen(); }
-    inline bool subtract(LogBufferElement *e) { size -= e->getMsgLen(); return !size; }
+    inline void add(LogBufferElement *element) { size += element->getMsgLen(); }
+    inline bool subtract(LogBufferElement *element) {
+        size -= element->getMsgLen();
+        return !size;
+    }
+
+    static std::string formatLine(
+            const std::string &name,
+            const std::string &size,
+            const std::string &pruned) {
+        ssize_t drop_len = std::max(pruned.length() + 1,
+                                    EntryBaseConstants::pruned_len);
+        ssize_t size_len = std::max(size.length() + 1,
+                                    EntryBaseConstants::total_len
+                                        - name.length() - drop_len - 1);
+
+        if (pruned.length()) {
+            return android::base::StringPrintf("%s%*s%*s\n", name.c_str(),
+                                               (int)size_len, size.c_str(),
+                                               (int)drop_len, pruned.c_str());
+        } else {
+            return android::base::StringPrintf("%s%*s\n", name.c_str(),
+                                               (int)size_len, size.c_str());
+        }
+    }
 };
 
 struct EntryBaseDropped : public EntryBase {
     size_t dropped;
 
     EntryBaseDropped():dropped(0) { }
-    EntryBaseDropped(LogBufferElement *e):EntryBase(e),dropped(e->getDropped()){ }
+    EntryBaseDropped(LogBufferElement *element):
+            EntryBase(element),
+            dropped(element->getDropped()){
+    }
 
     size_t getDropped() const { return dropped; }
 
-    inline void add(LogBufferElement *e) {
-        dropped += e->getDropped();
-        EntryBase::add(e);
+    inline void add(LogBufferElement *element) {
+        dropped += element->getDropped();
+        EntryBase::add(element);
     }
-    inline bool subtract(LogBufferElement *e) {
-        dropped -= e->getDropped();
-        return EntryBase::subtract(e) && !dropped;
+    inline bool subtract(LogBufferElement *element) {
+        dropped -= element->getDropped();
+        return EntryBase::subtract(element) && !dropped;
     }
-    inline void drop(LogBufferElement *e) {
+    inline void drop(LogBufferElement *element) {
         dropped += 1;
-        EntryBase::subtract(e);
+        EntryBase::subtract(element);
     }
 };
 
 struct UidEntry : public EntryBaseDropped {
     const uid_t uid;
 
-    UidEntry(LogBufferElement *e):EntryBaseDropped(e),uid(e->getUid()) { }
+    UidEntry(LogBufferElement *element):
+            EntryBaseDropped(element),
+            uid(element->getUid()) {
+    }
 
     inline const uid_t&getKey() const { return uid; }
+    inline const uid_t&getUid() const { return uid; }
+
+    std::string formatHeader(const std::string &name, log_id_t id) const;
+    std::string format(const LogStatistics &stat, log_id_t id) const;
 };
 
 namespace android {
@@ -167,51 +239,54 @@
     uid_t uid;
     char *name;
 
-    PidEntry(pid_t p):
-        EntryBaseDropped(),
-        pid(p),
-        uid(android::pidToUid(p)),
-        name(android::pidToName(pid)) { }
-    PidEntry(LogBufferElement *e):
-        EntryBaseDropped(e),
-        pid(e->getPid()),
-        uid(e->getUid()),
-        name(android::pidToName(e->getPid())) { }
-    PidEntry(const PidEntry &c):
-        EntryBaseDropped(c),
-        pid(c.pid),
-        uid(c.uid),
-        name(c.name ? strdup(c.name) : NULL) { }
+    PidEntry(pid_t pid):
+            EntryBaseDropped(),
+            pid(pid),
+            uid(android::pidToUid(pid)),
+            name(android::pidToName(pid)) {
+    }
+    PidEntry(LogBufferElement *element):
+            EntryBaseDropped(element),
+            pid(element->getPid()),
+            uid(element->getUid()),
+            name(android::pidToName(pid)) {
+    }
+    PidEntry(const PidEntry &element):
+            EntryBaseDropped(element),
+            pid(element.pid),
+            uid(element.uid),
+            name(element.name ? strdup(element.name) : NULL) {
+    }
     ~PidEntry() { free(name); }
 
     const pid_t&getKey() const { return pid; }
     const uid_t&getUid() const { return uid; }
     const char*getName() const { return name; }
 
-    inline void add(pid_t p) {
+    inline void add(pid_t newPid) {
         if (name && !fast<strncmp>(name, "zygote", 6)) {
             free(name);
             name = NULL;
         }
         if (!name) {
-            char *n = android::pidToName(p);
-            if (n) {
-                name = n;
-            }
+            name = android::pidToName(newPid);
         }
     }
 
-    inline void add(LogBufferElement *e) {
-        uid_t u = e->getUid();
-        if (getUid() != u) {
-            uid = u;
+    inline void add(LogBufferElement *element) {
+        uid_t incomingUid = element->getUid();
+        if (getUid() != incomingUid) {
+            uid = incomingUid;
             free(name);
-            name = android::pidToName(e->getPid());
+            name = android::pidToName(element->getPid());
         } else {
-            add(e->getPid());
+            add(element->getPid());
         }
-        EntryBaseDropped::add(e);
+        EntryBaseDropped::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;
 };
 
 struct TidEntry : public EntryBaseDropped {
@@ -219,79 +294,87 @@
     uid_t uid;
     char *name;
 
-    TidEntry(pid_t t):
-        EntryBaseDropped(),
-        tid(t),
-        uid(android::pidToUid(t)),
-        name(android::tidToName(tid)) { }
-    TidEntry(LogBufferElement *e):
-        EntryBaseDropped(e),
-        tid(e->getTid()),
-        uid(e->getUid()),
-        name(android::tidToName(e->getTid())) { }
-    TidEntry(const TidEntry &c):
-        EntryBaseDropped(c),
-        tid(c.tid),
-        uid(c.uid),
-        name(c.name ? strdup(c.name) : NULL) { }
+    TidEntry(pid_t tid):
+            EntryBaseDropped(),
+            tid(tid),
+            uid(android::pidToUid(tid)),
+            name(android::tidToName(tid)) {
+    }
+    TidEntry(LogBufferElement *element):
+            EntryBaseDropped(element),
+            tid(element->getTid()),
+            uid(element->getUid()),
+            name(android::tidToName(tid)) {
+    }
+    TidEntry(const TidEntry &element):
+            EntryBaseDropped(element),
+            tid(element.tid),
+            uid(element.uid),
+            name(element.name ? strdup(element.name) : NULL) {
+    }
     ~TidEntry() { free(name); }
 
     const pid_t&getKey() const { return tid; }
     const uid_t&getUid() const { return uid; }
     const char*getName() const { return name; }
 
-    inline void add(pid_t t) {
+    inline void add(pid_t incomingTid) {
         if (name && !fast<strncmp>(name, "zygote", 6)) {
             free(name);
             name = NULL;
         }
         if (!name) {
-            char *n = android::tidToName(t);
-            if (n) {
-                name = n;
-            }
+            name = android::tidToName(incomingTid);
         }
     }
 
-    inline void add(LogBufferElement *e) {
-        uid_t u = e->getUid();
-        if (getUid() != u) {
-            uid = u;
+    inline void add(LogBufferElement *element) {
+        uid_t incomingUid = element->getUid();
+        if (getUid() != incomingUid) {
+            uid = incomingUid;
             free(name);
-            name = android::tidToName(e->getTid());
+            name = android::tidToName(element->getTid());
         } else {
-            add(e->getTid());
+            add(element->getTid());
         }
-        EntryBaseDropped::add(e);
+        EntryBaseDropped::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;
 };
 
 struct TagEntry : public EntryBase {
     const uint32_t tag;
     uid_t uid;
 
-    TagEntry(LogBufferElement *e):
-        EntryBase(e),
-        tag(e->getTag()),
-        uid(e->getUid()) { }
+    TagEntry(LogBufferElement *element):
+            EntryBase(element),
+            tag(element->getTag()),
+            uid(element->getUid()) {
+    }
 
     const uint32_t&getKey() const { return tag; }
     const uid_t&getUid() const { return uid; }
     const char*getName() const { return android::tagToName(tag); }
 
-    inline void add(LogBufferElement *e) {
-        uid_t u = e->getUid();
-        if (uid != u) {
+    inline void add(LogBufferElement *element) {
+        uid_t incomingUid = element->getUid();
+        if (uid != incomingUid) {
             uid = -1;
         }
-        EntryBase::add(e);
+        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;
 };
 
 // Log Statistics
 class LogStatistics {
     size_t mSizes[LOG_ID_MAX];
     size_t mElements[LOG_ID_MAX];
+    size_t mDroppedElements[LOG_ID_MAX];
     size_t mSizesTotal[LOG_ID_MAX];
     size_t mElementsTotal[LOG_ID_MAX];
     bool enable;
@@ -321,23 +404,32 @@
     void subtract(LogBufferElement *entry);
     // entry->setDropped(1) must follow this call
     void drop(LogBufferElement *entry);
-    // Correct for merging two entries referencing dropped content
-    void erase(LogBufferElement *e) { --mElements[e->getLogId()]; }
+    // Correct for coalescing two entries referencing dropped content
+    void erase(LogBufferElement *element) {
+        log_id_t log_id = element->getLogId();
+        --mElements[log_id];
+        --mDroppedElements[log_id];
+    }
 
-    std::unique_ptr<const UidEntry *[]> sort(size_t n, log_id i) { return uidTable[i].sort(n); }
+    std::unique_ptr<const UidEntry *[]> sort(size_t len, log_id id) {
+        return uidTable[id].sort(len);
+    }
 
     // fast track current value by id only
     size_t sizes(log_id_t id) const { return mSizes[id]; }
     size_t elements(log_id_t id) const { return mElements[id]; }
+    size_t realElements(log_id_t id) const {
+        return mElements[id] - mDroppedElements[id];
+    }
     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);
+    std::string format(uid_t uid, unsigned int logMask) const;
 
     // helper (must be locked directly or implicitly by mLogElementsLock)
-    char *pidToName(pid_t pid);
+    const char *pidToName(pid_t pid) const;
     uid_t pidToUid(pid_t pid);
-    char *uidToName(uid_t uid);
+    const char *uidToName(uid_t uid) const;
 };
 
 #endif // _LOGD_LOG_STATISTICS_H__
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 68a0680..229be3c 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -128,9 +128,9 @@
 
     lock();
 
-    while (me->threadRunning && !me->isError_Locked()) {
-        uint64_t start = me->mStart;
+    uint64_t start = me->mStart;
 
+    while (me->threadRunning && !me->isError_Locked()) {
         unlock();
 
         if (me->mTail) {
@@ -143,8 +143,11 @@
 
         if (start == LogBufferElement::FLUSH_ERROR) {
             me->error_Locked();
+            break;
         }
 
+        me->mStart = start + 1;
+
         if (me->mNonBlock || !me->threadRunning || me->isError_Locked()) {
             break;
         }
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
index afb45da..3deb7d3 100644
--- a/metricsd/Android.mk
+++ b/metricsd/Android.mk
@@ -74,7 +74,7 @@
   libmetrics \
   libprotobuf-cpp-lite \
   librootdev \
-  libweaved-client \
+  libweaved \
 
 # Shared library for metrics.
 # ========================================================
diff --git a/metricsd/metrics_daemon.cc b/metricsd/metrics_daemon.cc
index 5b80b05..2b7e98c 100644
--- a/metricsd/metrics_daemon.cc
+++ b/metricsd/metrics_daemon.cc
@@ -140,7 +140,7 @@
     version_cumulative_cpu_use_->Set(0);
   }
 
-  return chromeos::DBusDaemon::Run();
+  return brillo::DBusDaemon::Run();
 }
 
 void MetricsDaemon::RunUploaderTest() {
@@ -242,8 +242,8 @@
 }
 
 int MetricsDaemon::OnInit() {
-  int return_code = dbus_enabled_ ? chromeos::DBusDaemon::OnInit() :
-      chromeos::Daemon::OnInit();
+  int return_code = dbus_enabled_ ? brillo::DBusDaemon::OnInit() :
+      brillo::Daemon::OnInit();
   if (return_code != EX_OK)
     return return_code;
 
@@ -283,11 +283,15 @@
       return EX_UNAVAILABLE;
     }
 
-    weaved_object_mgr_.reset(new com::android::Weave::ObjectManagerProxy{bus_});
-    weaved_object_mgr_->SetCommandAddedCallback(
-        base::Bind(&MetricsDaemon::OnWeaveCommand, base::Unretained(this)));
-    weaved_object_mgr_->SetManagerAddedCallback(
+    device_ = weaved::Device::CreateInstance(
+        bus_,
         base::Bind(&MetricsDaemon::UpdateWeaveState, base::Unretained(this)));
+    device_->AddCommandHandler(
+        "_metrics._enableAnalyticsReporting",
+        base::Bind(&MetricsDaemon::OnEnableMetrics, base::Unretained(this)));
+    device_->AddCommandHandler(
+        "_metrics._disableAnalyticsReporting",
+        base::Bind(&MetricsDaemon::OnDisableMetrics, base::Unretained(this)));
   }
 
   base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
@@ -322,59 +326,54 @@
           << error.name << ": " << error.message;
     }
   }
-  chromeos::DBusDaemon::OnShutdown(return_code);
+  brillo::DBusDaemon::OnShutdown(return_code);
 }
 
-void MetricsDaemon::OnWeaveCommand(CommandProxy* command) {
-  if (command->category() != "metrics" || command->status() != "queued") {
+void MetricsDaemon::OnEnableMetrics(const std::weak_ptr<weaved::Command>& cmd) {
+  auto command = cmd.lock();
+  if (!command)
     return;
-  }
 
-  VLOG(1) << "received weave command: " << command->name();
-  if (command->name() == "_metrics._enableAnalyticsReporting") {
-    OnEnableMetrics(command);
-  } else if (command->name() == "_metrics._disableAnalyticsReporting") {
-    OnDisableMetrics(command);
-  }
-}
-
-void MetricsDaemon::OnEnableMetrics(CommandProxy* command) {
   if (base::WriteFile(metrics_directory_.Append(metrics::kConsentFileName),
                       "", 0) != 0) {
     PLOG(ERROR) << "Could not create the consent file.";
-    command->Abort(nullptr);
+    command->Abort("metrics_error", "Could not create the consent file",
+                   nullptr);
     return;
   }
 
-  NotifyStateChanged();
-  command->Done(nullptr);
+  UpdateWeaveState();
+  command->Complete({}, nullptr);
 }
 
-void MetricsDaemon::OnDisableMetrics(CommandProxy* command) {
+void MetricsDaemon::OnDisableMetrics(
+    const std::weak_ptr<weaved::Command>& cmd) {
+  auto command = cmd.lock();
+  if (!command)
+    return;
+
   if (!base::DeleteFile(metrics_directory_.Append(metrics::kConsentFileName),
                         false)) {
-    PLOG(ERROR) << "Cound not delete the consent file.";
-    command->Abort(nullptr);
+    PLOG(ERROR) << "Could not delete the consent file.";
+    command->Abort("metrics_error", "Could not delete the consent file",
+                   nullptr);
     return;
   }
 
-  NotifyStateChanged();
-  command->Done(nullptr);
+  UpdateWeaveState();
+  command->Complete({}, nullptr);
 }
 
-void MetricsDaemon::NotifyStateChanged() {
-  ManagerProxy* manager = weaved_object_mgr_->GetManagerProxy();
-  if (manager)
-    UpdateWeaveState(manager);
-}
+void MetricsDaemon::UpdateWeaveState() {
+  if (!device_)
+    return;
 
-void MetricsDaemon::UpdateWeaveState(ManagerProxy* manager) {
-  chromeos::VariantDictionary state_change{
+  brillo::VariantDictionary state_change{
     { "_metrics._AnalyticsReportingState",
       metrics_lib_->AreMetricsEnabled() ? "enabled" : "disabled" }
   };
 
-  if (!manager->UpdateState(state_change, nullptr)) {
+  if (!device_->SetStateProperties(state_change, nullptr)) {
     LOG(ERROR) << "failed to update weave's state";
   }
 }
diff --git a/metricsd/metrics_daemon.h b/metricsd/metrics_daemon.h
index 0a8f6a5..3d691c5 100644
--- a/metricsd/metrics_daemon.h
+++ b/metricsd/metrics_daemon.h
@@ -26,8 +26,9 @@
 #include <base/files/file_path.h>
 #include <base/memory/scoped_ptr.h>
 #include <base/time/time.h>
-#include <buffet/dbus-proxies.h>
-#include <chromeos/daemons/dbus_daemon.h>
+#include <brillo/daemons/dbus_daemon.h>
+#include <libweaved/command.h>
+#include <libweaved/device.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
 #include "collectors/averaged_statistics_collector.h"
@@ -38,7 +39,7 @@
 
 using chromeos_metrics::PersistentInteger;
 
-class MetricsDaemon : public chromeos::DBusDaemon {
+class MetricsDaemon : public brillo::DBusDaemon {
  public:
   MetricsDaemon();
   ~MetricsDaemon();
@@ -122,20 +123,14 @@
                                          DBusMessage* message,
                                          void* user_data);
 
-  // Callback for Weave commands.
-  void OnWeaveCommand(com::android::Weave::CommandProxy* command);
-
   // Enables metrics reporting.
-  void OnEnableMetrics(com::android::Weave::CommandProxy* command);
+  void OnEnableMetrics(const std::weak_ptr<weaved::Command>& cmd);
 
   // Disables metrics reporting.
-  void OnDisableMetrics(com::android::Weave::CommandProxy* command);
+  void OnDisableMetrics(const std::weak_ptr<weaved::Command>& cmd);
 
   // Updates the weave device state.
-  void UpdateWeaveState(com::android::Weave::ManagerProxy* manager);
-
-  // Tells Weave that the state has changed.
-  void NotifyStateChanged();
+  void UpdateWeaveState();
 
   // Updates the active use time and logs time between user-space
   // process crashes.
@@ -317,7 +312,7 @@
   std::string server_;
 
   scoped_ptr<UploadService> upload_service_;
-  scoped_ptr<com::android::Weave::ObjectManagerProxy> weaved_object_mgr_;
+  std::unique_ptr<weaved::Device> device_;
 };
 
 #endif  // METRICS_METRICS_DAEMON_H_
diff --git a/metricsd/metrics_daemon_main.cc b/metricsd/metrics_daemon_main.cc
index df13944..50c279d 100644
--- a/metricsd/metrics_daemon_main.cc
+++ b/metricsd/metrics_daemon_main.cc
@@ -18,8 +18,8 @@
 #include <base/command_line.h>
 #include <base/logging.h>
 #include <base/strings/string_util.h>
-#include <chromeos/flag_helper.h>
-#include <chromeos/syslog_logging.h>
+#include <brillo/flag_helper.h>
+#include <brillo/syslog_logging.h>
 #include <rootdev.h>
 
 #include "constants.h"
@@ -79,11 +79,11 @@
                 metrics::kMetricsDirectory,
                 "Root of the configuration files (testing only)");
 
-  chromeos::FlagHelper::Init(argc, argv, "Chromium OS Metrics Daemon");
+  brillo::FlagHelper::Init(argc, argv, "Chromium OS Metrics Daemon");
 
   // Also log to stderr when not running as daemon.
-  chromeos::InitLog(chromeos::kLogToSyslog | chromeos::kLogHeader |
-                    (FLAGS_daemon ? 0 : chromeos::kLogToStderr));
+  brillo::InitLog(brillo::kLogToSyslog | brillo::kLogHeader |
+                  (FLAGS_daemon ? 0 : brillo::kLogToStderr));
 
   if (FLAGS_daemon && daemon(0, 0) != 0) {
     return errno;
diff --git a/metricsd/metrics_daemon_test.cc b/metricsd/metrics_daemon_test.cc
index 3a8fc3a..d3c9a23 100644
--- a/metricsd/metrics_daemon_test.cc
+++ b/metricsd/metrics_daemon_test.cc
@@ -20,7 +20,7 @@
 #include <base/files/file_util.h>
 #include <base/files/scoped_temp_dir.h>
 #include <base/strings/string_number_conversions.h>
-#include <chromeos/flag_helper.h>
+#include <brillo/flag_helper.h>
 #include <gtest/gtest.h>
 
 #include "constants.h"
@@ -43,7 +43,7 @@
 class MetricsDaemonTest : public testing::Test {
  protected:
   virtual void SetUp() {
-    chromeos::FlagHelper::Init(0, nullptr, "");
+    brillo::FlagHelper::Init(0, nullptr, "");
     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
     scaling_max_freq_path_ = temp_dir_.path().Append("scaling_max");
     cpu_max_freq_path_ = temp_dir_.path().Append("cpu_freq_max");
diff --git a/metricsd/uploader/proto/system_profile.proto b/metricsd/uploader/proto/system_profile.proto
index 4cab0d9..bac828b 100644
--- a/metricsd/uploader/proto/system_profile.proto
+++ b/metricsd/uploader/proto/system_profile.proto
@@ -88,7 +88,7 @@
   optional string application_locale = 4;
 
   message BrilloDeviceData {
-    optional string build_target_id = 1;
+    optional string product_id = 1;
   }
   optional BrilloDeviceData brillo = 21;
 
diff --git a/metricsd/uploader/sender_http.cc b/metricsd/uploader/sender_http.cc
index 953afc1..4b572a6 100644
--- a/metricsd/uploader/sender_http.cc
+++ b/metricsd/uploader/sender_http.cc
@@ -20,8 +20,8 @@
 
 #include <base/logging.h>
 #include <base/strings/string_number_conversions.h>
-#include <chromeos/http/http_utils.h>
-#include <chromeos/mime_utils.h>
+#include <brillo/http/http_utils.h>
+#include <brillo/mime_utils.h>
 
 HttpSender::HttpSender(const std::string server_url)
     : server_url_(server_url) {}
@@ -31,14 +31,14 @@
   const std::string hash =
       base::HexEncode(content_hash.data(), content_hash.size());
 
-  chromeos::http::HeaderList headers = {{"X-Chrome-UMA-Log-SHA1", hash}};
-  chromeos::ErrorPtr error;
-  auto response = chromeos::http::PostTextAndBlock(
+  brillo::http::HeaderList headers = {{"X-Chrome-UMA-Log-SHA1", hash}};
+  brillo::ErrorPtr error;
+  auto response = brillo::http::PostTextAndBlock(
       server_url_,
       content,
-      chromeos::mime::application::kWwwFormUrlEncoded,
+      brillo::mime::application::kWwwFormUrlEncoded,
       headers,
-      chromeos::http::Transport::CreateDefault(),
+      brillo::http::Transport::CreateDefault(),
       &error);
   if (!response || response->ExtractDataAsString() != "OK") {
     if (error) {
diff --git a/metricsd/uploader/system_profile_cache.cc b/metricsd/uploader/system_profile_cache.cc
index 2437b56..1d87be5 100644
--- a/metricsd/uploader/system_profile_cache.cc
+++ b/metricsd/uploader/system_profile_cache.cc
@@ -136,7 +136,7 @@
   profile_proto->set_channel(profile_.channel);
   metrics::SystemProfileProto_BrilloDeviceData* device_data =
       profile_proto->mutable_brillo();
-  device_data->set_build_target_id(profile_.product_id);
+  device_data->set_product_id(profile_.product_id);
 
   return true;
 }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 10635d3..38c686d 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -13,6 +13,9 @@
     # Set init and its forked children's oom_adj.
     write /proc/1/oom_score_adj -1000
 
+    # Disable sysrq from keyboard
+    write /proc/sys/kernel/sysrq 0
+
     # Set the security context of /adb_keys if present.
     restorecon /adb_keys
 
@@ -296,6 +299,7 @@
     mkdir /data/local 0751 root root
     mkdir /data/misc/media 0700 media media
     mkdir /data/misc/boottrace 0771 system shell
+    mkdir /data/misc/update_engine 0700 root root
 
     # For security reasons, /data/local/tmp should always be empty.
     # Do not place files or directories in /data/local/tmp