Merge "libnetutils: Check socket() return value"
diff --git a/adb/Android.mk b/adb/Android.mk
index 9c8ab6d..d629223 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -349,8 +349,6 @@
     libcutils \
     libbase \
     libcrypto_static \
-    libminijail \
-    libminijail_generated \
-    libcap
+    libminijail
 
 include $(BUILD_EXECUTABLE)
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 78db69d..4721e2f 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -124,12 +124,9 @@
                       AID_INET,     AID_NET_BT,    AID_NET_BT_ADMIN,
                       AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS,
                       AID_READPROC};
-    if (minijail_set_supplementary_gids(
-            jail.get(),
-            sizeof(groups) / sizeof(groups[0]),
-            groups) != 0) {
-        LOG(FATAL) << "Could not configure supplementary groups";
-    }
+    minijail_set_supplementary_gids(jail.get(),
+                                    sizeof(groups) / sizeof(groups[0]),
+                                    groups);
 
     // Don't listen on a port (default 5037) if running in secure mode.
     // Don't run as root if running in secure mode.
diff --git a/adb/line_printer.cpp b/adb/line_printer.cpp
index e8fe6c9..4ec8979 100644
--- a/adb/line_printer.cpp
+++ b/adb/line_printer.cpp
@@ -67,7 +67,7 @@
 
 void LinePrinter::Print(string to_print, LineType type) {
   if (!smart_terminal_) {
-    Out(to_print);
+    Out(to_print + "\n");
     return;
   }
 
diff --git a/adb/services.cpp b/adb/services.cpp
index 20166ce..cd33e7b 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -368,8 +368,9 @@
     while (true) {
         bool is_ambiguous = false;
         std::string error = "unknown error";
-        atransport* t = acquire_one_transport(sinfo->transport_type, sinfo->serial.c_str(),
-                                              &is_ambiguous, &error);
+        const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : NULL;
+        atransport* t = acquire_one_transport(sinfo->transport_type, serial, &is_ambiguous, &error);
+
         if (t != nullptr && t->connection_state == sinfo->state) {
             SendOkay(fd);
             break;
diff --git a/crash_reporter/Android.mk b/crash_reporter/Android.mk
index 565963c..bc023b0 100644
--- a/crash_reporter/Android.mk
+++ b/crash_reporter/Android.mk
@@ -41,7 +41,6 @@
 LOCAL_MODULE := libcrash
 LOCAL_CPP_EXTENSION := $(crash_reporter_cpp_extension)
 LOCAL_C_INCLUDES := $(crash_reporter_includes)
-LOCAL_RTTI_FLAG := -frtti
 LOCAL_SHARED_LIBRARIES := libchrome \
     libbinder \
     libbrillo \
@@ -63,7 +62,6 @@
     crash_sender \
     crash_server
 LOCAL_INIT_RC := crash_reporter.rc
-LOCAL_RTTI_FLAG := -frtti
 LOCAL_SHARED_LIBRARIES := libchrome \
     libbinder \
     libbrillo \
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index de0f943..9e4f1f7 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -62,7 +62,7 @@
 LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -fstack-protector-all -Werror -Wno-free-nonheap-object
+LOCAL_CFLAGS += -fstack-protector-all -Werror -Wno-free-nonheap-object -Wno-date-time
 #LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_SHARED_LIBRARIES := libcutils liblog libc
 
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 0afa895..58b629b 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -24,11 +24,12 @@
 #include <dirent.h>
 #include <time.h>
 
-#include <sys/ptrace.h>
-#include <sys/wait.h>
 #include <elf.h>
-#include <sys/stat.h>
 #include <sys/poll.h>
+#include <sys/prctl.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
 
 #include <selinux/android.h>
 
@@ -363,6 +364,37 @@
   }
 #endif
 
+  // Fork a child to handle the rest of the request.
+  pid_t fork_pid = fork();
+  if (fork_pid == -1) {
+    ALOGE("debuggerd: failed to fork: %s\n", strerror(errno));
+    return;
+  } else if (fork_pid != 0) {
+    waitpid(fork_pid, nullptr, 0);
+    return;
+  }
+
+  // Open the tombstone file if we need it.
+  std::string tombstone_path;
+  int tombstone_fd = -1;
+  switch (request.action) {
+    case DEBUGGER_ACTION_DUMP_TOMBSTONE:
+    case DEBUGGER_ACTION_CRASH:
+      tombstone_fd = open_tombstone(&tombstone_path);
+      if (tombstone_fd == -1) {
+        ALOGE("debuggerd: failed to open tombstone file: %s\n", strerror(errno));
+        exit(1);
+      }
+      break;
+
+    case DEBUGGER_ACTION_DUMP_BACKTRACE:
+      break;
+
+    default:
+      ALOGE("debuggerd: unexpected request action: %d", request.action);
+      exit(1);
+  }
+
   // At this point, the thread that made the request is blocked in
   // a read() call.  If the thread has crashed, then this gives us
   // time to PTRACE_ATTACH to it before it has a chance to really fault.
@@ -374,19 +406,32 @@
   // See details in bionic/libc/linker/debugger.c, in function
   // debugger_signal_handler().
   if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) {
-    ALOGE("ptrace attach failed: %s\n", strerror(errno));
-    return;
+    ALOGE("debuggerd: ptrace attach failed: %s\n", strerror(errno));
+    exit(1);
+  }
+
+  // Generate the backtrace map before dropping privileges.
+  std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(request.pid));
+
+  // Now that we've done everything that requires privileges, we can drop them.
+  if (setresgid(AID_DEBUGGERD, AID_DEBUGGERD, AID_DEBUGGERD) != 0) {
+    ALOGE("debuggerd: failed to setresgid");
+    exit(1);
+  }
+
+  if (setresuid(AID_DEBUGGERD, AID_DEBUGGERD, AID_DEBUGGERD) != 0) {
+    ALOGE("debuggerd: failed to setresuid");
+    exit(1);
   }
 
   bool detach_failed = false;
   bool tid_unresponsive = false;
   bool attach_gdb = should_attach_gdb(&request);
   if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
-    ALOGE("failed responding to client: %s\n", strerror(errno));
-    return;
+    ALOGE("debuggerd: failed to respond to client: %s\n", strerror(errno));
+    exit(1);
   }
 
-  std::unique_ptr<char> tombstone_path;
   int total_sleep_time_usec = 0;
   while (true) {
     int signal = wait_for_sigstop(request.tid, &total_sleep_time_usec, &detach_failed);
@@ -399,9 +444,9 @@
       case SIGSTOP:
         if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
           ALOGV("stopped -- dumping to tombstone\n");
-          tombstone_path.reset(engrave_tombstone(
-            request.pid, request.tid, signal, request.original_si_code, request.abort_msg_address,
-            true, &detach_failed, &total_sleep_time_usec));
+          engrave_tombstone(tombstone_fd, backtrace_map.get(), request.pid, request.tid, signal,
+                            request.original_si_code, request.abort_msg_address, true,
+                            &detach_failed, &total_sleep_time_usec);
         } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
           ALOGV("stopped -- dumping to fd\n");
           dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed, &total_sleep_time_usec);
@@ -409,7 +454,7 @@
           ALOGV("stopped -- continuing\n");
           status = ptrace(PTRACE_CONT, request.tid, 0, 0);
           if (status) {
-            ALOGE("ptrace continue failed: %s\n", strerror(errno));
+            ALOGE("debuggerd: ptrace continue failed: %s\n", strerror(errno));
           }
           continue;  // loop again
         }
@@ -432,21 +477,21 @@
         kill(request.pid, SIGSTOP);
         // don't dump sibling threads when attaching to GDB because it
         // makes the process less reliable, apparently...
-        tombstone_path.reset(engrave_tombstone(
-          request.pid, request.tid, signal, request.original_si_code, request.abort_msg_address,
-          !attach_gdb, &detach_failed, &total_sleep_time_usec));
+        engrave_tombstone(tombstone_fd, backtrace_map.get(), request.pid, request.tid, signal,
+                          request.original_si_code, request.abort_msg_address, !attach_gdb,
+                          &detach_failed, &total_sleep_time_usec);
         break;
 
       default:
-        ALOGE("process stopped due to unexpected signal %d\n", signal);
+        ALOGE("debuggerd: process stopped due to unexpected signal %d\n", signal);
         break;
     }
     break;
   }
 
   if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
-    if (tombstone_path) {
-      write(fd, tombstone_path.get(), strlen(tombstone_path.get()));
+    if (!tombstone_path.empty()) {
+      write(fd, tombstone_path.c_str(), tombstone_path.length());
     }
   }
 
@@ -457,7 +502,7 @@
       kill(request.pid, SIGSTOP);
     }
     if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
-      ALOGE("ptrace detach from %d failed: %s", request.tid, strerror(errno));
+      ALOGE("debuggerd: ptrace detach from %d failed: %s", request.tid, strerror(errno));
       detach_failed = true;
     } else if (attach_gdb) {
       // if debug.db.uid is set, its value indicates if we should wait
@@ -468,16 +513,9 @@
     }
   }
 
-  // resume stopped process (so it can crash in peace).
+  // Resume the stopped process so it can crash in peace, and exit.
   kill(request.pid, SIGCONT);
-
-  // If we didn't successfully detach, we're still the parent, and the
-  // actual parent won't receive a death notification via wait(2).  At this point
-  // there's not much we can do about that.
-  if (detach_failed) {
-    ALOGE("debuggerd committing suicide to free the zombie!\n");
-    kill(getpid(), SIGKILL);
-  }
+  exit(0);
 }
 
 static int do_server() {
diff --git a/debuggerd/test/selinux/android.h b/debuggerd/test/selinux/android.h
new file mode 100644
index 0000000..abed087
--- /dev/null
+++ b/debuggerd/test/selinux/android.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+extern "C" int selinux_android_restorecon(const char*, unsigned int);
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 5f422e3..b2f203d 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -632,7 +632,7 @@
 }
 
 // Dumps all information about the specified pid to the tombstone.
-static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, int si_code,
+static bool dump_crash(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid, int signal, int si_code,
                        uintptr_t abort_msg_address, bool dump_sibling_threads,
                        int* total_sleep_time_usec) {
   // don't copy log messages to tombstone unless this is a dev device
@@ -659,8 +659,7 @@
     dump_signal_info(log, tid, signal, si_code);
   }
 
-  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
-  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map));
   dump_abort_message(backtrace.get(), log, abort_msg_address);
   dump_registers(log, tid);
   if (backtrace->Unwind(0)) {
@@ -669,8 +668,8 @@
     ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
   }
   dump_memory_and_code(log, backtrace.get());
-  if (map.get() != nullptr) {
-    dump_all_maps(backtrace.get(), map.get(), log, tid);
+  if (map) {
+    dump_all_maps(backtrace.get(), map, log, tid);
   }
 
   if (want_logs) {
@@ -679,7 +678,7 @@
 
   bool detach_failed = false;
   if (dump_sibling_threads) {
-    detach_failed = dump_sibling_thread_report(log, pid, tid, total_sleep_time_usec, map.get());
+    detach_failed = dump_sibling_thread_report(log, pid, tid, total_sleep_time_usec, map);
   }
 
   if (want_logs) {
@@ -698,53 +697,57 @@
   return detach_failed;
 }
 
-// find_and_open_tombstone - find an available tombstone slot, if any, of the
+// open_tombstone - find an available tombstone slot, if any, of the
 // form tombstone_XX where XX is 00 to MAX_TOMBSTONES-1, inclusive. If no
 // file is available, we reuse the least-recently-modified file.
-//
-// Returns the path of the tombstone file, allocated using malloc().  Caller must free() it.
-static char* find_and_open_tombstone(int* fd) {
+int open_tombstone(std::string* out_path) {
   // In a single pass, find an available slot and, in case none
   // exist, find and record the least-recently-modified file.
   char path[128];
+  int fd = -1;
   int oldest = -1;
   struct stat oldest_sb;
   for (int i = 0; i < MAX_TOMBSTONES; i++) {
     snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, i);
 
     struct stat sb;
-    if (!stat(path, &sb)) {
+    if (stat(path, &sb) == 0) {
       if (oldest < 0 || sb.st_mtime < oldest_sb.st_mtime) {
         oldest = i;
         oldest_sb.st_mtime = sb.st_mtime;
       }
       continue;
     }
-    if (errno != ENOENT)
-      continue;
+    if (errno != ENOENT) continue;
 
-    *fd = open(path, O_CREAT | O_EXCL | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
-    if (*fd < 0)
-      continue;   // raced ?
+    fd = open(path, O_CREAT | O_EXCL | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
+    if (fd < 0) continue;  // raced ?
 
-    fchown(*fd, AID_SYSTEM, AID_SYSTEM);
-    return strdup(path);
+    if (out_path) {
+      *out_path = path;
+    }
+    fchown(fd, AID_SYSTEM, AID_SYSTEM);
+    return fd;
   }
 
   if (oldest < 0) {
-    ALOGE("Failed to find a valid tombstone, default to using tombstone 0.\n");
+    ALOGE("debuggerd: failed to find a valid tombstone, default to using tombstone 0.\n");
     oldest = 0;
   }
 
   // we didn't find an available file, so we clobber the oldest one
   snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest);
-  *fd = open(path, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
-  if (*fd < 0) {
-    ALOGE("failed to open tombstone file '%s': %s\n", path, strerror(errno));
-    return NULL;
+  fd = open(path, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
+  if (fd < 0) {
+    ALOGE("debuggerd: failed to open tombstone file '%s': %s\n", path, strerror(errno));
+    return -1;
   }
-  fchown(*fd, AID_SYSTEM, AID_SYSTEM);
-  return strdup(path);
+
+  if (out_path) {
+    *out_path = path;
+  }
+  fchown(fd, AID_SYSTEM, AID_SYSTEM);
+  return fd;
 }
 
 static int activity_manager_connect() {
@@ -777,49 +780,27 @@
   return amfd;
 }
 
-char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
-                        uintptr_t abort_msg_address, bool dump_sibling_threads,
-                        bool* detach_failed, int* total_sleep_time_usec) {
-
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid, int signal,
+                       int original_si_code, uintptr_t abort_msg_address, bool dump_sibling_threads,
+                       bool* detach_failed, int* total_sleep_time_usec) {
   log_t log;
   log.current_tid = tid;
   log.crashed_tid = tid;
 
-  if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) {
-    ALOGE("failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
-  }
-
-  if (chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM) == -1) {
-    ALOGE("failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno));
-  }
-
-  int fd = -1;
-  char* path = NULL;
-  if (selinux_android_restorecon(TOMBSTONE_DIR, 0) == 0) {
-    path = find_and_open_tombstone(&fd);
-  } else {
-    ALOGE("Failed to restore security context, not writing tombstone.\n");
-  }
-
-  if (fd < 0) {
-    ALOGE("Skipping tombstone write, nothing to do.\n");
+  if (tombstone_fd < 0) {
+    ALOGE("debuggerd: skipping tombstone write, nothing to do.\n");
     *detach_failed = false;
-    return NULL;
+    return;
   }
 
-  log.tfd = fd;
+  log.tfd = tombstone_fd;
   // Preserve amfd since it can be modified through the calls below without
   // being closed.
   int amfd = activity_manager_connect();
   log.amfd = amfd;
-  *detach_failed = dump_crash(&log, pid, tid, signal, original_si_code, abort_msg_address,
+  *detach_failed = dump_crash(&log, map, pid, tid, signal, original_si_code, abort_msg_address,
                               dump_sibling_threads, total_sleep_time_usec);
 
-  _LOG(&log, logtype::BACKTRACE, "\nTombstone written to: %s\n", path);
-
-  // Either of these file descriptors can be -1, any error is ignored.
+  // This file descriptor can be -1, any error is ignored.
   close(amfd);
-  close(fd);
-
-  return path;
 }
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index 7e2b2fe..5f2d239 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -17,15 +17,23 @@
 #ifndef _DEBUGGERD_TOMBSTONE_H
 #define _DEBUGGERD_TOMBSTONE_H
 
-#include <stddef.h>
 #include <stdbool.h>
+#include <stddef.h>
 #include <sys/types.h>
+#include <string>
+
+class BacktraceMap;
+
+/* Create and open a tombstone file for writing.
+ * Returns a writable file descriptor, or -1 with errno set appropriately.
+ * If out_path is non-null, *out_path is set to the path of the tombstone file.
+ */
+int open_tombstone(std::string* path);
 
 /* Creates a tombstone file and writes the crash dump to it.
  * Returns the path of the tombstone, which must be freed using free(). */
-char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
-                        uintptr_t abort_msg_address,
-                        bool dump_sibling_threads, bool* detach_failed,
-                        int* total_sleep_time_usec);
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid, int signal,
+                       int original_si_code, uintptr_t abort_msg_address, bool dump_sibling_threads,
+                       bool* detach_failed, int* total_sleep_time_usec);
 
 #endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 5b66366..bd17485 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -282,8 +282,6 @@
             "  getvar <variable>                        Display a bootloader variable.\n"
             "  set_active <suffix>                      Sets the active slot. If slots are\n"
             "                                           not supported, this does nothing.\n"
-            "                                           note: suffixes starting with a '-'\n"
-            "                                           must use set_active -- <suffix>\n"
             "  boot <kernel> [ <ramdisk> [ <second> ] ] Download and boot kernel.\n"
             "  flash:raw boot <kernel> [ <ramdisk> [ <second> ] ]\n"
             "                                           Create bootimage and flash it.\n"
@@ -320,9 +318,10 @@
             "                                           device supports slots. This will be\n"
             "                                           added to all partition names that use\n"
             "                                           slots. 'all' can be given to refer\n"
-            "                                           to all slots. If this is not given,\n"
-            "                                           slotted partitions will default to\n"
-            "                                           the current active slot.\n"
+            "                                           to all slots. 'other' can be given to\n"
+            "                                           refer to a non-current slot. If this\n"
+            "                                           flag is not used, slotted partitions\n"
+            "                                           will default to the current active slot.\n"
             "  -a, --set-active[=<suffix>]              Sets the active slot. If no suffix is\n"
             "                                           provided, this will default to the value\n"
             "                                           given by --slot. If slots are not\n"
@@ -739,12 +738,28 @@
             if (!suffixes.empty()) {
                 return suffixes[0];
             } else {
-                fprintf(stderr, "No known slots.\n");
-                exit(1);
+                die("No known slots.");
             }
         }
     }
+
     std::vector<std::string> suffixes = get_suffixes(transport);
+
+    if (strcmp(slot, "other") == 0) {
+        std::string current_slot;
+        if (!fb_getvar(transport, "current-slot", &current_slot)) {
+            die("Failed to identify current slot.");
+        }
+        if (!suffixes.empty()) {
+            for (size_t i = 0; i < suffixes.size(); i++) {
+                if (current_slot == suffixes[i])
+                    return suffixes[(i+1)%suffixes.size()];
+            }
+        } else {
+            die("No known slots.");
+        }
+    }
+
     for (const std::string &suffix : suffixes) {
         if (suffix == slot)
             return slot;
@@ -1411,7 +1426,6 @@
             std::string slot = verify_slot(transport, argv[1], false);
             fb_set_active(slot.c_str());
             skip(2);
-            wants_reboot = true;
         } else if(!strcmp(*argv, "oem")) {
             argc = do_oem_command(argc, argv);
         } else if(!strcmp(*argv, "flashing")) {
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 0085a07..cdfe9c5 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -30,7 +30,6 @@
 #include <batteryservice/BatteryService.h>
 #include <cutils/klog.h>
 #include <cutils/properties.h>
-#include <log/log_read.h>
 #include <utils/Errors.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
@@ -313,25 +312,6 @@
                  props.chargerUsbOnline ? "u" : "",
                  props.chargerWirelessOnline ? "w" : "");
 
-        log_time realtime(CLOCK_REALTIME);
-        time_t t = realtime.tv_sec;
-        struct tm *tmp = gmtime(&t);
-        if (tmp) {
-            static const char fmt[] = " %Y-%m-%d %H:%M:%S.XXXXXXXXX UTC";
-            len = strlen(dmesgline);
-            if ((len < (sizeof(dmesgline) - sizeof(fmt) - 8)) // margin
-                    && strftime(dmesgline + len, sizeof(dmesgline) - len,
-                                fmt, tmp)) {
-                char *usec = strchr(dmesgline + len, 'X');
-                if (usec) {
-                    len = usec - dmesgline;
-                    snprintf(dmesgline + len, sizeof(dmesgline) - len,
-                             "%09u", realtime.tv_nsec);
-                    usec[9] = ' ';
-                }
-            }
-        }
-
         KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);
     }
 
diff --git a/include/binderwrapper/binder_wrapper.h b/include/binderwrapper/binder_wrapper.h
index 921c4ed..ccda825 100644
--- a/include/binderwrapper/binder_wrapper.h
+++ b/include/binderwrapper/binder_wrapper.h
@@ -30,6 +30,7 @@
 class IBinder;
 
 // Wraps libbinder to make it testable.
+// NOTE: Static methods of this class are not thread-safe.
 class BinderWrapper {
  public:
   virtual ~BinderWrapper() {}
@@ -50,6 +51,10 @@
   // InitForTesting().
   static BinderWrapper* Get();
 
+  // Returns the singleton instance if it was previously created by Create() or
+  // set by InitForTesting(), or creates a new one by calling Create().
+  static BinderWrapper* GetOrCreateInstance();
+
   // Gets the binder for communicating with the service identified by
   // |service_name|, returning null immediately if it doesn't exist.
   virtual sp<IBinder> GetService(const std::string& service_name) = 0;
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index bbe4486..9876e34 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -83,6 +83,10 @@
 #define AID_TLSDATE       1039  /* tlsdate unprivileged user */
 #define AID_MEDIA_EX      1040  /* mediaextractor process */
 #define AID_AUDIOSERVER   1041  /* audioserver process */
+#define AID_METRICS_COLL  1042  /* metrics_collector process */
+#define AID_METRICSD      1043  /* metricsd process */
+#define AID_WEBSERV       1044  /* webservd process */
+#define AID_DEBUGGERD     1045  /* debuggerd unprivileged user */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
 #define AID_CACHE         2001  /* cache access */
@@ -184,6 +188,10 @@
     { "tlsdate",       AID_TLSDATE, },
     { "mediaex",       AID_MEDIA_EX, },
     { "audioserver",   AID_AUDIOSERVER, },
+    { "metrics_coll",  AID_METRICS_COLL },
+    { "metricsd",      AID_METRICSD },
+    { "webserv",       AID_WEBSERV },
+    { "debuggerd",     AID_DEBUGGERD, },
 
     { "shell",         AID_SHELL, },
     { "cache",         AID_CACHE, },
diff --git a/init/Android.mk b/init/Android.mk
index d6cb4e5..66ce8a8 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -52,7 +52,7 @@
     service.cpp \
     util.cpp \
 
-LOCAL_STATIC_LIBRARIES := libbase
+LOCAL_STATIC_LIBRARIES := libbase libselinux
 LOCAL_MODULE := libinit
 LOCAL_SANITIZE := integer
 LOCAL_CLANG := true
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 10f9d81..d2291bb 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -39,6 +39,7 @@
 #include <selinux/label.h>
 
 #include <fs_mgr.h>
+#include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 #include <cutils/partition_utils.h>
 #include <cutils/android_reboot.h>
@@ -53,6 +54,7 @@
 #include "log.h"
 #include "property_service.h"
 #include "service.h"
+#include "signal_handler.h"
 #include "util.h"
 
 #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
@@ -62,6 +64,8 @@
 // System call provided by bionic but not in any header file.
 extern "C" int init_module(void *, unsigned long, const char *);
 
+static const int kTerminateServiceDelayMicroSeconds = 50000;
+
 static int insmod(const char *filename, const char *options) {
     std::string module;
     if (!read_file(filename, &module)) {
@@ -608,6 +612,42 @@
         return -EINVAL;
     }
 
+    std::string timeout = property_get("ro.build.shutdown_timeout");
+    unsigned int delay = 0;
+
+    if (android::base::ParseUint(timeout.c_str(), &delay) && delay > 0) {
+        Timer t;
+        // Ask all services to terminate.
+        ServiceManager::GetInstance().ForEachService(
+            [] (Service* s) { s->Terminate(); });
+
+        while (t.duration() < delay) {
+            ServiceManager::GetInstance().ReapAnyOutstandingChildren();
+
+            int service_count = 0;
+            ServiceManager::GetInstance().ForEachService(
+                [&service_count] (Service* s) {
+                    // Count the number of services running.
+                    // Exclude the console as it will ignore the SIGTERM signal
+                    // and not exit.
+                    // Note: SVC_CONSOLE actually means "requires console" but
+                    // it is only used by the shell.
+                    if (s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
+                        service_count++;
+                    }
+                });
+
+            if (service_count == 0) {
+                // All terminable services terminated. We can exit early.
+                break;
+            }
+
+            // Wait a bit before recounting the number or running services.
+            usleep(kTerminateServiceDelayMicroSeconds);
+        }
+        NOTICE("Terminating running services took %.02f seconds", t.duration());
+    }
+
     return android_reboot_with_callback(cmd, 0, reboot_target,
                                         callback_on_ro_remount);
 }
diff --git a/init/service.cpp b/init/service.cpp
index 40a4bc7..0ddc484 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -19,6 +19,7 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/wait.h>
 #include <termios.h>
 #include <unistd.h>
 
@@ -531,6 +532,17 @@
     StopOrReset(SVC_DISABLED);
 }
 
+void Service::Terminate() {
+    flags_ &= ~(SVC_RESTARTING | SVC_DISABLED_START);
+    flags_ |= SVC_DISABLED;
+    if (pid_) {
+        NOTICE("Sending SIGTERM to service '%s' (pid %d)...\n", name_.c_str(),
+               pid_);
+        kill(-pid_, SIGTERM);
+        NotifyStateChange("stopping");
+    }
+}
+
 void Service::Restart() {
     if (flags_ & SVC_RUNNING) {
         /* Stop, wait, then start the service. */
@@ -724,9 +736,9 @@
     return nullptr;
 }
 
-void ServiceManager::ForEachService(void (*func)(Service* svc)) const {
+void ServiceManager::ForEachService(std::function<void(Service*)> callback) const {
     for (const auto& s : services_) {
-        func(s.get());
+        callback(s.get());
     }
 }
 
@@ -767,6 +779,53 @@
     INFO("\n");
 }
 
+bool ServiceManager::ReapOneProcess() {
+    int status;
+    pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
+    if (pid == 0) {
+        return false;
+    } else if (pid == -1) {
+        ERROR("waitpid failed: %s\n", strerror(errno));
+        return false;
+    }
+
+    Service* svc = FindServiceByPid(pid);
+
+    std::string name;
+    if (svc) {
+        name = android::base::StringPrintf("Service '%s' (pid %d)",
+                                           svc->name().c_str(), pid);
+    } else {
+        name = android::base::StringPrintf("Untracked pid %d", pid);
+    }
+
+    if (WIFEXITED(status)) {
+        NOTICE("%s exited with status %d\n", name.c_str(), WEXITSTATUS(status));
+    } else if (WIFSIGNALED(status)) {
+        NOTICE("%s killed by signal %d\n", name.c_str(), WTERMSIG(status));
+    } else if (WIFSTOPPED(status)) {
+        NOTICE("%s stopped by signal %d\n", name.c_str(), WSTOPSIG(status));
+    } else {
+        NOTICE("%s state changed", name.c_str());
+    }
+
+    if (!svc) {
+        return true;
+    }
+
+    if (svc->Reap()) {
+        waiting_for_exec = false;
+        RemoveService(*svc);
+    }
+
+    return true;
+}
+
+void ServiceManager::ReapAnyOutstandingChildren() {
+    while (ReapOneProcess()) {
+    }
+}
+
 bool ServiceParser::ParseSection(const std::vector<std::string>& args,
                                  std::string* err) {
     if (args.size() < 3) {
diff --git a/init/service.h b/init/service.h
index 10eb736..35abde9 100644
--- a/init/service.h
+++ b/init/service.h
@@ -82,6 +82,7 @@
     bool Enable();
     void Reset();
     void Stop();
+    void Terminate();
     void Restart();
     void RestartIfNeeded(time_t& process_needs_restart);
     bool Reap();
@@ -167,17 +168,22 @@
     Service* FindServiceByName(const std::string& name) const;
     Service* FindServiceByPid(pid_t pid) const;
     Service* FindServiceByKeychord(int keychord_id) const;
-    void ForEachService(void (*func)(Service* svc)) const;
+    void ForEachService(std::function<void(Service*)> callback) const;
     void ForEachServiceInClass(const std::string& classname,
                                void (*func)(Service* svc)) const;
     void ForEachServiceWithFlags(unsigned matchflags,
                              void (*func)(Service* svc)) const;
+    void ReapAnyOutstandingChildren();
     void RemoveService(const Service& svc);
     void DumpState() const;
 
 private:
     ServiceManager();
 
+    // Cleans up a child process that exited.
+    // Returns true iff a children was cleaned up.
+    bool ReapOneProcess();
+
     static int exec_count_; // Every service needs a unique name.
     std::vector<std::unique_ptr<Service>> services_;
 };
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index e7d42cb..ea483d4 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -37,62 +37,12 @@
 static int signal_write_fd = -1;
 static int signal_read_fd = -1;
 
-static std::string DescribeStatus(int status) {
-    if (WIFEXITED(status)) {
-        return android::base::StringPrintf("exited with status %d", WEXITSTATUS(status));
-    } else if (WIFSIGNALED(status)) {
-        return android::base::StringPrintf("killed by signal %d", WTERMSIG(status));
-    } else if (WIFSTOPPED(status)) {
-        return android::base::StringPrintf("stopped by signal %d", WSTOPSIG(status));
-    } else {
-        return "state changed";
-    }
-}
-
-static bool wait_for_one_process() {
-    int status;
-    pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
-    if (pid == 0) {
-        return false;
-    } else if (pid == -1) {
-        ERROR("waitpid failed: %s\n", strerror(errno));
-        return false;
-    }
-
-    Service* svc = ServiceManager::GetInstance().FindServiceByPid(pid);
-
-    std::string name;
-    if (svc) {
-        name = android::base::StringPrintf("Service '%s' (pid %d)", svc->name().c_str(), pid);
-    } else {
-        name = android::base::StringPrintf("Untracked pid %d", pid);
-    }
-
-    NOTICE("%s %s\n", name.c_str(), DescribeStatus(status).c_str());
-
-    if (!svc) {
-        return true;
-    }
-
-    if (svc->Reap()) {
-        waiting_for_exec = false;
-        ServiceManager::GetInstance().RemoveService(*svc);
-    }
-
-    return true;
-}
-
-static void reap_any_outstanding_children() {
-    while (wait_for_one_process()) {
-    }
-}
-
 static void handle_signal() {
     // Clear outstanding requests.
     char buf[32];
     read(signal_read_fd, buf, sizeof(buf));
 
-    reap_any_outstanding_children();
+    ServiceManager::GetInstance().ReapAnyOutstandingChildren();
 }
 
 static void SIGCHLD_handler(int) {
@@ -119,7 +69,7 @@
     act.sa_flags = SA_NOCLDSTOP;
     sigaction(SIGCHLD, &act, 0);
 
-    reap_any_outstanding_children();
+    ServiceManager::GetInstance().ReapAnyOutstandingChildren();
 
     register_epoll_handler(signal_read_fd, handle_signal);
 }
diff --git a/libbinderwrapper/binder_wrapper.cc b/libbinderwrapper/binder_wrapper.cc
index 0b5ff96..ca9c1df 100644
--- a/libbinderwrapper/binder_wrapper.cc
+++ b/libbinderwrapper/binder_wrapper.cc
@@ -50,4 +50,11 @@
   return instance_;
 }
 
+// static
+BinderWrapper* BinderWrapper::GetOrCreateInstance() {
+  if (!instance_)
+    instance_ = new RealBinderWrapper();
+  return instance_;
+}
+
 }  // namespace android
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 878feb8..ee883f0 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -71,6 +71,7 @@
         //       $(LOCAL_PATH)/event.logtags)
         // so make sure we do not regret hard-coding it as follows:
         "-DLIBLOG_LOG_TAG=1005",
+        "-DSNET_EVENT_LOG_TAG=1397638484",
     ],
     compile_multilib: "both",
     stl: "none",
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index c2b0ec2..5406c50 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -39,6 +39,7 @@
 #include <android/set_abort_message.h>
 #endif
 
+#include <log/event_tag_map.h>
 #include <log/logd.h>
 #include <log/logger.h>
 #include <log/log_read.h>
@@ -71,6 +72,11 @@
     pthread_mutex_lock(&log_init_lock);
 }
 
+static int trylock()
+{
+    return pthread_mutex_trylock(&log_init_lock);
+}
+
 static void unlock()
 {
     pthread_mutex_unlock(&log_init_lock);
@@ -79,6 +85,7 @@
 #else   /* !defined(_WIN32) */
 
 #define lock() ((void)0)
+#define trylock() (0) /* success */
 #define unlock() ((void)0)
 
 #endif  /* !defined(_WIN32) */
@@ -194,6 +201,9 @@
         last_pid = getpid();
     }
     if (log_id == LOG_ID_SECURITY) {
+        if (vec[0].iov_len < 4) {
+            return -EINVAL;
+        }
         if ((last_uid != AID_SYSTEM) && (last_uid != AID_ROOT)) {
             uid_t uid = geteuid();
             if ((uid != AID_SYSTEM) && (uid != AID_ROOT)) {
@@ -207,9 +217,86 @@
             }
         }
         if (!__android_log_security()) {
+            atomic_store(&dropped_security, 0);
+            return -EPERM;
+        }
+    } else if (log_id == LOG_ID_EVENTS) {
+        static atomic_uintptr_t map;
+        int ret;
+        const char *tag;
+        EventTagMap *m, *f;
+
+        if (vec[0].iov_len < 4) {
+            return -EINVAL;
+        }
+
+        tag = NULL;
+        f = NULL;
+        m = (EventTagMap *)atomic_load(&map);
+
+        if (!m) {
+            ret = trylock();
+            m = (EventTagMap *)atomic_load(&map); /* trylock flush cache */
+            if (!m) {
+                m = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+                if (ret) { /* trylock failed, use local copy, mark for close */
+                    f = m;
+                } else {
+                    if (!m) { /* One chance to open map file */
+                        m = (EventTagMap *)(uintptr_t)-1LL;
+                    }
+                    atomic_store(&map, (uintptr_t)m);
+                }
+            }
+            if (!ret) { /* trylock succeeded, unlock */
+                unlock();
+            }
+        }
+        if (m && (m != (EventTagMap *)(uintptr_t)-1LL)) {
+            tag = android_lookupEventTag(
+                                    m,
+                                    htole32(((uint32_t *)vec[0].iov_base)[0]));
+        }
+        ret = __android_log_is_loggable(ANDROID_LOG_INFO,
+                                        tag,
+                                        ANDROID_LOG_VERBOSE);
+        if (f) { /* local copy marked for close */
+            android_closeEventTagMap(f);
+        }
+        if (!ret) {
+            return -EPERM;
+        }
+    } else {
+        /* Validate the incoming tag, tag content can not split across iovec */
+        char prio = ANDROID_LOG_VERBOSE;
+        const char *tag = vec[0].iov_base;
+        size_t len = vec[0].iov_len;
+        if (!tag) {
+            len = 0;
+        }
+        if (len > 0) {
+            prio = *tag;
+            if (len > 1) {
+                --len;
+                ++tag;
+            } else {
+                len = vec[1].iov_len;
+                tag = ((const char *)vec[1].iov_base);
+                if (!tag) {
+                    len = 0;
+                }
+            }
+        }
+        /* tag must be nul terminated */
+        if (strnlen(tag, len) >= len) {
+            tag = NULL;
+        }
+
+        if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
             return -EPERM;
         }
     }
+
     /*
      *  struct {
      *      // what we provide to pstore
@@ -267,7 +354,9 @@
             }
         }
         snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
-        if (snapshot) {
+        if (snapshot && __android_log_is_loggable(ANDROID_LOG_INFO,
+                                                  "liblog",
+                                                  ANDROID_LOG_VERBOSE)) {
             android_log_event_int_t buffer;
 
             header.id = LOG_ID_EVENTS;
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 8020b41..3153319 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -49,6 +49,7 @@
                                             "libOpenMAXAL.so:"
                                             "libOpenSLES.so:"
                                             "libstdc++.so:"
+                                            "libwebviewchromium_plat_support.so:"
                                             "libz.so";
 
 class LibraryNamespaces {
@@ -138,7 +139,7 @@
                         jobject class_loader, bool is_shared, jstring java_library_path,
                         jstring java_permitted_path) {
 #if defined(__ANDROID__)
-  if (target_sdk_version <= INT_MAX || class_loader == nullptr) {
+  if (target_sdk_version == 0 || class_loader == nullptr) {
     return dlopen(path, RTLD_NOW);
   }
 
diff --git a/logcat/logpersist b/logcat/logpersist
index 6f666f6..dab466d 100755
--- a/logcat/logpersist
+++ b/logcat/logpersist
@@ -10,7 +10,7 @@
 data=/data/misc/logd
 property=persist.logd.logpersistd
 service=logcatd
-if [ X"${1}" = "-h" -o X"${1}" = X"--help" ]; then
+if [ X"${1}" = X"-h" -o X"${1}" = X"--help" ]; then
   echo "${progname%.*}.cat            - dump current ${service%d} logs"
   echo "${progname%.*}.start          - start ${service} service"
   echo "${progname%.*}.stop [--clear] - stop ${service} service"
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 110395c..707527b 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -32,7 +32,7 @@
 #include "LogReader.h"
 
 // Default
-#define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
+#define LOG_BUFFER_SIZE (256 * 1024) // Tuned with ro.logd.size per-platform
 #define log_buffer_size(id) mMaxSize[id]
 #define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
 #define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
@@ -248,9 +248,9 @@
 
         LogTimeEntry::lock();
 
-        LastLogTimes::iterator t = mTimes.begin();
-        while(t != mTimes.end()) {
-            LogTimeEntry *entry = (*t);
+        LastLogTimes::iterator times = mTimes.begin();
+        while(times != mTimes.end()) {
+            LogTimeEntry *entry = (*times);
             if (entry->owned_Locked()) {
                 if (!entry->mNonBlock) {
                     end_always = true;
@@ -261,7 +261,7 @@
                     end_set = true;
                 }
             }
-            t++;
+            times++;
         }
 
         if (end_always
@@ -307,20 +307,35 @@
 
 LogBufferElementCollection::iterator LogBuffer::erase(
         LogBufferElementCollection::iterator it, bool coalesce) {
-    LogBufferElement *e = *it;
-    log_id_t id = e->getLogId();
+    LogBufferElement *element = *it;
+    log_id_t id = element->getLogId();
 
-    LogBufferIteratorMap::iterator f = mLastWorstUid[id].find(e->getUid());
-    if ((f != mLastWorstUid[id].end()) && (it == f->second)) {
-        mLastWorstUid[id].erase(f);
+    {   // start of scope for uid found iterator
+        LogBufferIteratorMap::iterator found =
+            mLastWorstUid[id].find(element->getUid());
+        if ((found != mLastWorstUid[id].end())
+                && (it == found->second)) {
+            mLastWorstUid[id].erase(found);
+        }
     }
+
+    if (element->getUid() == AID_SYSTEM) {
+        // start of scope for pid found iterator
+        LogBufferPidIteratorMap::iterator found =
+            mLastWorstPidOfSystem[id].find(element->getPid());
+        if ((found != mLastWorstPidOfSystem[id].end())
+                && (it == found->second)) {
+            mLastWorstPidOfSystem[id].erase(found);
+        }
+    }
+
     it = mLogElements.erase(it);
     if (coalesce) {
-        stats.erase(e);
+        stats.erase(element);
     } else {
-        stats.subtract(e);
+        stats.subtract(element);
     }
-    delete e;
+    delete element;
 
     return it;
 }
@@ -340,8 +355,13 @@
     } __packed;
 
 public:
-    LogBufferElementKey(uid_t u, pid_t p, pid_t t):uid(u),pid(p),tid(t),padding(0) { }
-    LogBufferElementKey(uint64_t k):value(k) { }
+    LogBufferElementKey(uid_t uid, pid_t pid, pid_t tid):
+            uid(uid),
+            pid(pid),
+            tid(tid),
+            padding(0) {
+    }
+    LogBufferElementKey(uint64_t key):value(key) { }
 
     uint64_t getKey() { return value; }
 };
@@ -353,38 +373,42 @@
 
 public:
 
-    bool coalesce(LogBufferElement *e, unsigned short dropped) {
-        LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid());
+    bool coalesce(LogBufferElement *element, unsigned short dropped) {
+        LogBufferElementKey key(element->getUid(),
+                                element->getPid(),
+                                element->getTid());
         LogBufferElementMap::iterator it = map.find(key.getKey());
         if (it != map.end()) {
-            LogBufferElement *l = it->second;
-            unsigned short d = l->getDropped();
-            if ((dropped + d) > USHRT_MAX) {
+            LogBufferElement *found = it->second;
+            unsigned short moreDropped = found->getDropped();
+            if ((dropped + moreDropped) > USHRT_MAX) {
                 map.erase(it);
             } else {
-                l->setDropped(dropped + d);
+                found->setDropped(dropped + moreDropped);
                 return true;
             }
         }
         return false;
     }
 
-    void add(LogBufferElement *e) {
-        LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid());
-        map[key.getKey()] = e;
+    void add(LogBufferElement *element) {
+        LogBufferElementKey key(element->getUid(),
+                                element->getPid(),
+                                element->getTid());
+        map[key.getKey()] = element;
     }
 
     inline void clear() {
         map.clear();
     }
 
-    void clear(LogBufferElement *e) {
-        uint64_t current = e->getRealTime().nsec()
+    void clear(LogBufferElement *element) {
+        uint64_t current = element->getRealTime().nsec()
                          - (EXPIRE_RATELIMIT * NS_PER_SEC);
         for(LogBufferElementMap::iterator it = map.begin(); it != map.end();) {
-            LogBufferElement *l = it->second;
-            if ((l->getDropped() >= EXPIRE_THRESHOLD)
-                    && (current > l->getRealTime().nsec())) {
+            LogBufferElement *mapElement = it->second;
+            if ((mapElement->getDropped() >= EXPIRE_THRESHOLD)
+                    && (current > mapElement->getRealTime().nsec())) {
                 it = map.erase(it);
             } else {
                 ++it;
@@ -449,9 +473,9 @@
     LogTimeEntry::lock();
 
     // Region locked?
-    LastLogTimes::iterator t = mTimes.begin();
-    while(t != mTimes.end()) {
-        LogTimeEntry *entry = (*t);
+    LastLogTimes::iterator times = mTimes.begin();
+    while(times != mTimes.end()) {
+        LogTimeEntry *entry = (*times);
         if (entry->owned_Locked() && entry->isWatching(id)
                 && (!oldest ||
                     (oldest->mStart > entry->mStart) ||
@@ -459,7 +483,7 @@
                      (entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec)))) {
             oldest = entry;
         }
-        t++;
+        times++;
     }
 
     LogBufferElementCollection::iterator it;
@@ -467,14 +491,14 @@
     if (caller_uid != AID_ROOT) {
         // Only here if clearAll condition (pruneRows == ULONG_MAX)
         for(it = mLogElements.begin(); it != mLogElements.end();) {
-            LogBufferElement *e = *it;
+            LogBufferElement *element = *it;
 
-            if ((e->getLogId() != id) || (e->getUid() != caller_uid)) {
+            if ((element->getLogId() != id) || (element->getUid() != caller_uid)) {
                 ++it;
                 continue;
             }
 
-            if (oldest && (oldest->mStart <= e->getSequence())) {
+            if (oldest && (oldest->mStart <= element->getSequence())) {
                 busy = true;
                 if (oldest->mTimeout.tv_sec || oldest->mTimeout.tv_nsec) {
                     oldest->triggerReader_Locked();
@@ -491,20 +515,21 @@
         return busy;
     }
 
-    // prune by worst offender by uid
+    // prune by worst offenders; by blacklist, UID, and by PID of system UID
     bool hasBlacklist = (id != LOG_ID_SECURITY) && mPrune.naughty();
     while (!clearAll && (pruneRows > 0)) {
         // recalculate the worst offender on every batched pass
         uid_t worst = (uid_t) -1;
         size_t worst_sizes = 0;
         size_t second_worst_sizes = 0;
+        pid_t worstPid = 0; // POSIX guarantees PID != 0
 
         if (worstUidEnabledForLogid(id) && mPrune.worstUidEnabled()) {
-            std::unique_ptr<const UidEntry *[]> sorted = stats.sort(
-                AID_ROOT, (pid_t)0, 2, id);
+            {   // begin scope for UID sorted list
+                std::unique_ptr<const UidEntry *[]> sorted = stats.sort(
+                    AID_ROOT, (pid_t)0, 2, id);
 
-            if (sorted.get()) {
-                if (sorted[0] && sorted[1]) {
+                if (sorted.get() && sorted[0] && sorted[1]) {
                     worst_sizes = sorted[0]->getSizes();
                     // Calculate threshold as 12.5% of available storage
                     size_t threshold = log_buffer_size(id) / 8;
@@ -520,6 +545,18 @@
                     }
                 }
             }
+
+            if ((worst == AID_SYSTEM) && mPrune.worstPidOfSystemEnabled()) {
+                // begin scope of PID sorted list
+                std::unique_ptr<const PidEntry *[]> sorted = stats.sort(
+                    worst, (pid_t)0, 2, id, worst);
+                if (sorted.get() && sorted[0] && sorted[1]) {
+                    worstPid = sorted[0]->getKey();
+                    second_worst_sizes = worst_sizes
+                                       - sorted[0]->getSizes()
+                                       + sorted[1]->getSizes();
+                }
+            }
         }
 
         // skip if we have neither worst nor naughty filters
@@ -536,11 +573,23 @@
         // - check age-out of preserved logs
         bool gc = pruneRows <= 1;
         if (!gc && (worst != (uid_t) -1)) {
-            LogBufferIteratorMap::iterator f = mLastWorstUid[id].find(worst);
-            if ((f != mLastWorstUid[id].end())
-                    && (f->second != mLogElements.end())) {
-                leading = false;
-                it = f->second;
+            {   // begin scope for uid worst found iterator
+                LogBufferIteratorMap::iterator found = mLastWorstUid[id].find(worst);
+                if ((found != mLastWorstUid[id].end())
+                        && (found->second != mLogElements.end())) {
+                    leading = false;
+                    it = found->second;
+                }
+            }
+            if (worstPid) {
+                // begin scope for pid worst found iterator
+                LogBufferPidIteratorMap::iterator found
+                    = mLastWorstPidOfSystem[id].find(worstPid);
+                if ((found != mLastWorstPidOfSystem[id].end())
+                        && (found->second != mLogElements.end())) {
+                    leading = false;
+                    it = found->second;
+                }
             }
         }
         static const timespec too_old = {
@@ -551,9 +600,9 @@
         --lastt;
         LogBufferElementLast last;
         while (it != mLogElements.end()) {
-            LogBufferElement *e = *it;
+            LogBufferElement *element = *it;
 
-            if (oldest && (oldest->mStart <= e->getSequence())) {
+            if (oldest && (oldest->mStart <= element->getSequence())) {
                 busy = true;
                 if (oldest->mTimeout.tv_sec || oldest->mTimeout.tv_nsec) {
                     oldest->triggerReader_Locked();
@@ -561,12 +610,12 @@
                 break;
             }
 
-            if (e->getLogId() != id) {
+            if (element->getLogId() != id) {
                 ++it;
                 continue;
             }
 
-            unsigned short dropped = e->getDropped();
+            unsigned short dropped = element->getDropped();
 
             // remove any leading drops
             if (leading && dropped) {
@@ -574,13 +623,13 @@
                 continue;
             }
 
-            if (dropped && last.coalesce(e, dropped)) {
+            if (dropped && last.coalesce(element, dropped)) {
                 it = erase(it, true);
                 continue;
             }
 
-            if (hasBlacklist && mPrune.naughty(e)) {
-                last.clear(e);
+            if (hasBlacklist && mPrune.naughty(element)) {
+                last.clear(element);
                 it = erase(it);
                 if (dropped) {
                     continue;
@@ -591,35 +640,42 @@
                     break;
                 }
 
-                if (e->getUid() == worst) {
+                if (element->getUid() == worst) {
                     kick = true;
                     if (worst_sizes < second_worst_sizes) {
                         break;
                     }
-                    worst_sizes -= e->getMsgLen();
+                    worst_sizes -= element->getMsgLen();
                 }
                 continue;
             }
 
-            if ((e->getRealTime() < ((*lastt)->getRealTime() - too_old))
-                    || (e->getRealTime() > (*lastt)->getRealTime())) {
+            if ((element->getRealTime() < ((*lastt)->getRealTime() - too_old))
+                    || (element->getRealTime() > (*lastt)->getRealTime())) {
                 break;
             }
 
             if (dropped) {
-                last.add(e);
-                if ((!gc && (e->getUid() == worst))
-                        || (mLastWorstUid[id].find(e->getUid())
+                last.add(element);
+                if (worstPid
+                        && ((!gc && (element->getPid() == worstPid))
+                            || (mLastWorstPidOfSystem[id].find(element->getPid())
+                                == mLastWorstPidOfSystem[id].end()))) {
+                    mLastWorstPidOfSystem[id][element->getUid()] = it;
+                }
+                if ((!gc && !worstPid && (element->getUid() == worst))
+                        || (mLastWorstUid[id].find(element->getUid())
                             == mLastWorstUid[id].end())) {
-                    mLastWorstUid[id][e->getUid()] = it;
+                    mLastWorstUid[id][element->getUid()] = it;
                 }
                 ++it;
                 continue;
             }
 
-            if (e->getUid() != worst) {
+            if ((element->getUid() != worst)
+                    || (worstPid && (element->getPid() != worstPid))) {
                 leading = false;
-                last.clear(e);
+                last.clear(element);
                 ++it;
                 continue;
             }
@@ -631,19 +687,24 @@
 
             kick = true;
 
-            unsigned short len = e->getMsgLen();
+            unsigned short len = element->getMsgLen();
 
             // do not create any leading drops
             if (leading) {
                 it = erase(it);
             } else {
-                stats.drop(e);
-                e->setDropped(1);
-                if (last.coalesce(e, 1)) {
+                stats.drop(element);
+                element->setDropped(1);
+                if (last.coalesce(element, 1)) {
                     it = erase(it, true);
                 } else {
-                    last.add(e);
-                    if (!gc || (mLastWorstUid[id].find(worst)
+                    last.add(element);
+                    if (worstPid && (!gc
+                                || (mLastWorstPidOfSystem[id].find(worstPid)
+                                    == mLastWorstPidOfSystem[id].end()))) {
+                        mLastWorstPidOfSystem[id][worstPid] = it;
+                    }
+                    if ((!gc && !worstPid) || (mLastWorstUid[id].find(worst)
                                 == mLastWorstUid[id].end())) {
                         mLastWorstUid[id][worst] = it;
                     }
@@ -666,16 +727,15 @@
     bool hasWhitelist = (id != LOG_ID_SECURITY) && mPrune.nice() && !clearAll;
     it = mLogElements.begin();
     while((pruneRows > 0) && (it != mLogElements.end())) {
-        LogBufferElement *e = *it;
+        LogBufferElement *element = *it;
 
-        if (e->getLogId() != id) {
+        if (element->getLogId() != id) {
             it++;
             continue;
         }
 
-        if (oldest && (oldest->mStart <= e->getSequence())) {
+        if (oldest && (oldest->mStart <= element->getSequence())) {
             busy = true;
-
             if (whitelist) {
                 break;
             }
@@ -691,7 +751,8 @@
             break;
         }
 
-        if (hasWhitelist && !e->getDropped() && mPrune.nice(e)) { // WhiteListed
+        if (hasWhitelist && !element->getDropped() && mPrune.nice(element)) {
+            // WhiteListed
             whitelist = true;
             it++;
             continue;
@@ -705,14 +766,14 @@
     if (whitelist && (pruneRows > 0)) {
         it = mLogElements.begin();
         while((it != mLogElements.end()) && (pruneRows > 0)) {
-            LogBufferElement *e = *it;
+            LogBufferElement *element = *it;
 
-            if (e->getLogId() != id) {
+            if (element->getLogId() != id) {
                 ++it;
                 continue;
             }
 
-            if (oldest && (oldest->mStart <= e->getSequence())) {
+            if (oldest && (oldest->mStart <= element->getSequence())) {
                 busy = true;
                 if (stats.sizes(id) > (2 * log_buffer_size(id))) {
                     // kick a misbehaving log reader client off the island
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index c1614e8..2667e78 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -33,16 +33,42 @@
 #include "LogWhiteBlackList.h"
 
 //
-// We are either in 1970ish (MONOTONIC) or 2015+ish (REALTIME) so to
-// differentiate without prejudice, we use 1980 to delineate, earlier
-// is monotonic, later is real.
+// We are either in 1970ish (MONOTONIC) or 2016+ish (REALTIME) so to
+// differentiate without prejudice, we use 1972 to delineate, earlier
+// is likely monotonic, later is real. Otherwise we start using a
+// dividing line between monotonic and realtime if more than a minute
+// difference between them.
 //
 namespace android {
 
 static bool isMonotonic(const log_time &mono) {
-    static const uint32_t EPOCH_PLUS_10_YEARS = 10 * 1461 / 4 * 24 * 60 * 60;
+    static const uint32_t EPOCH_PLUS_2_YEARS = 2 * 24 * 60 * 60 * 1461 / 4;
+    static const uint32_t EPOCH_PLUS_MINUTE = 60;
 
-    return mono.tv_sec < EPOCH_PLUS_10_YEARS;
+    if (mono.tv_sec >= EPOCH_PLUS_2_YEARS) {
+        return false;
+    }
+
+    log_time now(CLOCK_REALTIME);
+
+    /* Timezone and ntp time setup? */
+    if (now.tv_sec >= EPOCH_PLUS_2_YEARS) {
+        return true;
+    }
+
+    /* no way to differentiate realtime from monotonic time */
+    if (now.tv_sec < EPOCH_PLUS_MINUTE) {
+        return false;
+    }
+
+    log_time cpu(CLOCK_MONOTONIC);
+    /* too close to call to differentiate monotonic times from realtime */
+    if ((cpu.tv_sec + EPOCH_PLUS_MINUTE) >= now.tv_sec) {
+        return false;
+    }
+
+    /* dividing line half way between monotonic and realtime */
+    return mono.tv_sec < ((cpu.tv_sec + now.tv_sec) / 2);
 }
 
 }
@@ -61,6 +87,11 @@
                                LogBufferElementCollection::iterator>
                 LogBufferIteratorMap;
     LogBufferIteratorMap mLastWorstUid[LOG_ID_MAX];
+    // watermark of any worst/chatty pid of system processing
+    typedef std::unordered_map<pid_t,
+                               LogBufferElementCollection::iterator>
+                LogBufferPidIteratorMap;
+    LogBufferPidIteratorMap mLastWorstPidOfSystem[LOG_ID_MAX];
 
     unsigned long mMaxSize[LOG_ID_MAX];
 
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index db7e682..9690489 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -206,7 +206,10 @@
     // NOTREACHED
 }
 
-log_time LogKlog::correction = log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC);
+log_time LogKlog::correction =
+    (log_time(CLOCK_REALTIME) < log_time(CLOCK_MONOTONIC))
+        ? log_time::EPOCH
+        : (log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC));
 
 LogKlog::LogKlog(LogBuffer *buf, LogReader *reader, int fdWrite, int fdRead, bool auditd) :
         SocketListener(fdRead, false),
@@ -272,7 +275,7 @@
                                   size_t len) {
     log_time real;
     const char *ep = real.strptime(real_string, "%Y-%m-%d %H:%M:%S.%09q UTC");
-    if (!ep || (ep > &real_string[len])) {
+    if (!ep || (ep > &real_string[len]) || (real > log_time(CLOCK_REALTIME))) {
         return;
     }
     // kernel report UTC, log_time::strptime is localtime from calendar.
@@ -283,8 +286,16 @@
     memset(&tm, 0, sizeof(tm));
     tm.tm_isdst = -1;
     localtime_r(&now, &tm);
-    real.tv_sec += tm.tm_gmtoff;
-    correction = real - monotonic;
+    if ((tm.tm_gmtoff < 0) && ((-tm.tm_gmtoff) > (long)real.tv_sec)) {
+        real = log_time::EPOCH;
+    } else {
+        real.tv_sec += tm.tm_gmtoff;
+    }
+    if (monotonic > real) {
+        correction = log_time::EPOCH;
+    } else {
+        correction = real - monotonic;
+    }
 }
 
 static const char suspendStr[] = "PM: suspend entry ";
@@ -319,11 +330,11 @@
     if (cp && (cp >= &(*buf)[len])) {
         cp = NULL;
     }
-    len -= cp - *buf;
     if (cp) {
         static const char healthd[] = "healthd";
         static const char battery[] = ": battery ";
 
+        len -= cp - *buf;
         if (len && isspace(*cp)) {
             ++cp;
             --len;
@@ -347,16 +358,11 @@
                 && ((size_t)((b += sizeof(healthd) - 1) - cp) < len)
                 && ((b = strnstr(b, len -= b - cp, battery)))
                 && ((size_t)((b += sizeof(battery) - 1) - cp) < len)) {
-            len -= b - cp;
-            // NB: healthd is roughly 150us late, worth the price to deal with
-            //     ntp-induced or hardware clock drift.
-            // look for " 2???-??-?? ??:??:??.????????? ???"
-            for (; len && *b && (*b != '\n'); ++b, --len) {
-                if ((b[0] == ' ') && (b[1] == '2') && (b[5] == '-')) {
-                    calculateCorrection(now, b + 1, len - 1);
-                    break;
-                }
-            }
+            // NB: healthd is roughly 150us late, so we use it instead to
+            //     trigger a check for ntp-induced or hardware clock drift.
+            log_time real(CLOCK_REALTIME);
+            log_time mono(CLOCK_MONOTONIC);
+            correction = (real < mono) ? log_time::EPOCH : (real - mono);
         } else if (((b = strnstr(cp, len, suspendedStr)))
                 && ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
             len -= b - cp;
@@ -371,7 +377,11 @@
                     real.tv_nsec += (*endp - '0') * multiplier;
                 }
                 if (reverse) {
-                    correction -= real;
+                    if (real > correction) {
+                        correction = log_time::EPOCH;
+                    } else {
+                        correction -= real;
+                    }
                 } else {
                     correction += real;
                 }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index afaefc2..2b02bc1 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -75,6 +75,9 @@
     }
 
     uidTable[log_id].add(element->getUid(), element);
+    if (element->getUid() == AID_SYSTEM) {
+        pidSystemTable[log_id].add(element->getPid(), element);
+    }
 
     if (!enable) {
         return;
@@ -107,6 +110,9 @@
     }
 
     uidTable[log_id].subtract(element->getUid(), element);
+    if (element->getUid() == AID_SYSTEM) {
+        pidSystemTable[log_id].subtract(element->getPid(), element);
+    }
 
     if (!enable) {
         return;
@@ -134,6 +140,9 @@
     ++mDroppedElements[log_id];
 
     uidTable[log_id].drop(element->getUid(), element);
+    if (element->getUid() == AID_SYSTEM) {
+        pidSystemTable[log_id].drop(element->getPid(), element);
+    }
 
     if (!enable) {
         return;
@@ -273,7 +282,43 @@
         }
     }
 
-    return formatLine(name, size, pruned);
+    std::string output = formatLine(name, size, pruned);
+
+    if (uid != AID_SYSTEM) {
+        return output;
+    }
+
+    static const size_t maximum_sorted_entries = 32;
+    std::unique_ptr<const PidEntry *[]> sorted
+        = stat.pidSystemTable[id].sort(uid, (pid_t)0, maximum_sorted_entries);
+
+    if (!sorted.get()) {
+        return output;
+    }
+    std::string byPid;
+    size_t index;
+    bool hasDropped = false;
+    for (index = 0; index < maximum_sorted_entries; ++index) {
+        const PidEntry *entry = sorted[index];
+        if (!entry) {
+            break;
+        }
+        if (entry->getSizes() <= (getSizes() / 100)) {
+            break;
+        }
+        if (entry->getDropped()) {
+            hasDropped = true;
+        }
+        byPid += entry->format(stat, id);
+    }
+    if (index > 1) { // print this only if interesting
+        std::string ditto("\" ");
+        output += formatLine(std::string("  PID/UID   COMMAND LINE"),
+                             ditto, hasDropped ? ditto : std::string(""));
+        output += byPid;
+    }
+
+    return output;
 }
 
 std::string PidEntry::formatHeader(const std::string &name, log_id_t /* id */) const {
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 6d999d2..6f7d264 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -416,6 +416,10 @@
     typedef LogHashtable<uid_t, UidEntry> uidTable_t;
     uidTable_t uidTable[LOG_ID_MAX];
 
+    // pid of system to size list
+    typedef LogHashtable<pid_t, PidEntry> pidSystemTable_t;
+    pidSystemTable_t pidSystemTable[LOG_ID_MAX];
+
     // pid to uid list
     typedef LogHashtable<pid_t, PidEntry> pidTable_t;
     pidTable_t pidTable;
@@ -451,6 +455,10 @@
                                              size_t len, log_id id) {
         return uidTable[id].sort(uid, pid, len);
     }
+    std::unique_ptr<const PidEntry *[]> sort(uid_t uid, pid_t pid,
+                                             size_t len, log_id id, uid_t) {
+        return pidSystemTable[id].sort(uid, pid, len);
+    }
 
     // fast track current value by id only
     size_t sizes(log_id_t id) const { return mSizes[id]; }
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index 29e637e..ae933b5 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -66,6 +66,7 @@
 
 int PruneList::init(const char *str) {
     mWorstUidEnabled = true;
+    mWorstPidOfSystemEnabled = true;
     PruneCollection::iterator it;
     for (it = mNice.begin(); it != mNice.end();) {
         it = mNice.erase(it);
@@ -103,13 +104,14 @@
     // default here means take internal default.
     if (filter == _default) {
         // See README.property for description of filter format
-        filter = "~!";
+        filter = "~! ~1000/!";
     }
     if (filter == _disable) {
         filter = "";
     }
 
     mWorstUidEnabled = false;
+    mWorstPidOfSystemEnabled = false;
 
     for(str = filter.c_str(); *str; ++str) {
         if (isspace(*str)) {
@@ -131,6 +133,19 @@
                 }
                 continue;
             }
+            // special case, translated to worst PID of System at priority
+            static const char worstPid[] = "1000/!";
+            if (!strncmp(str, worstPid, sizeof(worstPid) - 1)) {
+                mWorstPidOfSystemEnabled = true;
+                str += sizeof(worstPid) - 1;
+                if (!*str) {
+                    break;
+                }
+                if (!isspace(*str)) {
+                    return 1;
+                }
+                continue;
+            }
             if (!*str) {
                 return 1;
             }
@@ -209,6 +224,9 @@
     if (mWorstUidEnabled) {
         string = "~!";
         fmt = nice_format;
+        if (mWorstPidOfSystemEnabled) {
+            string += " ~1000/!";
+        }
     }
 
     PruneCollection::iterator it;
diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h
index 6f17402..8b8e02f 100644
--- a/logd/LogWhiteBlackList.h
+++ b/logd/LogWhiteBlackList.h
@@ -53,6 +53,7 @@
     PruneCollection mNaughty;
     PruneCollection mNice;
     bool mWorstUidEnabled;
+    bool mWorstPidOfSystemEnabled;
 
 public:
     PruneList();
@@ -65,6 +66,7 @@
     bool nice(LogBufferElement *element);
     bool nice(void) { return !mNice.empty(); }
     bool worstUidEnabled() const { return mWorstUidEnabled; }
+    bool worstPidOfSystemEnabled() const { return mWorstPidOfSystemEnabled; }
 
     std::string format();
 };
diff --git a/logd/README.property b/logd/README.property
index 019bd40..22f86b9 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -15,7 +15,11 @@
 persist.logd.size          number  ro    Global default size of the buffer for
                                          all log ids at initial startup, at
                                          runtime use: logcat -b all -G <value>
-ro.logd.size               number svelte default for persist.logd.size
+ro.logd.size               number svelte default for persist.logd.size. Larger
+                                         platform default sizes than 256KB are
+                                         known to not scale well under log spam
+                                         pressure. Address the spam first,
+                                         resist increasing the log buffer.
 persist.logd.size.<buffer> number  ro    Size of the buffer for <buffer> log
 ro.logd.size.<buffer>      number svelte default for persist.logd.size.<buffer>
 ro.config.low_ram          bool   false  if true, logd.statistics, logd.kernel
@@ -23,9 +27,11 @@
                                          of 256K.
 persist.logd.filter        string        Pruning filter to optimize content.
                                          At runtime use: logcat -P "<string>"
-ro.logd.filter             string "~!"   default for persist.logd.filter.
+ro.logd.filter       string "~! ~1000/!" default for persist.logd.filter.
                                          This default means to prune the
-                                         oldest entries of chattiest UID.
+                                         oldest entries of chattiest UID, and
+                                         the chattiest PID of system
+                                         (1000, or AID_SYSTEM).
 persist.logd.timestamp     string  ro    The recording timestamp source.
                                          "m[onotonic]" is the only supported
                                          key character, otherwise realtime.
@@ -52,4 +58,6 @@
   such as main, system, ... override global default.
 - Pruning filter is of form of a space-separated list of [~][UID][/PID]
   references, where '~' prefix means to blacklist otherwise whitelist. For
-  blacklisting, UID may be a '!' to instead reference the chattiest client.
+  blacklisting, UID or PID may be a '!' to instead reference the chattiest
+  client, with the restriction that the PID must be in the UID group 1000
+  (system or AID_SYSTEM).
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
index 2149a4b..7381703 100644
--- a/metricsd/Android.mk
+++ b/metricsd/Android.mk
@@ -28,7 +28,7 @@
   collectors/cpu_usage_collector.cc \
   collectors/disk_usage_collector.cc \
   metrics_collector.cc \
-  metrics_collector_service_trampoline.cc \
+  metrics_collector_service_impl.cc \
   persistent_integer.cc
 
 metricsd_common := \
@@ -102,15 +102,14 @@
 # ==========================================================
 include $(CLEAR_VARS)
 LOCAL_MODULE := libmetricscollectorservice
+LOCAL_CLANG := true
 LOCAL_SHARED_LIBRARIES := libbinder libbrillo-binder libchrome libutils
 LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_SRC_FILES := \
   aidl/android/brillo/metrics/IMetricsCollectorService.aidl \
-  metrics_collector_service_impl.cc \
   metrics_collector_service_client.cc
-LOCAL_RTTI_FLAG := -fno-rtti
 include $(BUILD_STATIC_LIBRARY)
 
 # Shared library for metrics.
@@ -122,7 +121,6 @@
 LOCAL_CLANG := true
 LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
 LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
-LOCAL_RTTI_FLAG := -frtti
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_SHARED_LIBRARIES := $(libmetrics_shared_libraries)
 LOCAL_SRC_FILES := $(libmetrics_sources)
@@ -166,7 +164,6 @@
 LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
 LOCAL_INIT_RC := metrics_collector.rc
 LOCAL_REQUIRED_MODULES := metrics.json
-LOCAL_RTTI_FLAG := -frtti
 LOCAL_SHARED_LIBRARIES := $(metrics_collector_shared_libraries)
 LOCAL_SRC_FILES := $(metrics_collector_common) \
   metrics_collector_main.cc
@@ -213,7 +210,6 @@
 LOCAL_CLANG := true
 LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
 LOCAL_CPPFLAGS := $(metrics_CPPFLAGS) -Wno-sign-compare
-LOCAL_RTTI_FLAG := -frtti
 LOCAL_SHARED_LIBRARIES := $(metrics_collector_shared_libraries)
 LOCAL_SRC_FILES := $(metrics_collector_tests_sources) \
   $(metrics_collector_common)
diff --git a/metricsd/README b/metricsd/README
deleted file mode 100644
index d4c9a0e..0000000
--- a/metricsd/README
+++ /dev/null
@@ -1,150 +0,0 @@
-Copyright (C) 2015 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-================================================================================
-
-The Chrome OS "metrics" package contains utilities for client-side user metric
-collection.
-When Chrome is installed, Chrome will take care of aggregating and uploading the
-metrics to the UMA server.
-When Chrome is not installed (embedded build) and the metrics_uploader USE flag
-is set, metrics_daemon will aggregate and upload the metrics itself.
-
-
-================================================================================
-The Metrics Library: libmetrics
-================================================================================
-
-libmetrics is a small library that implements the basic C and C++ API for
-metrics collection. All metrics collection is funneled through this library. The
-easiest and recommended way for a client-side module to collect user metrics is
-to link libmetrics and use its APIs to send metrics to Chrome for transport to
-UMA. In order to use the library in a module, you need to do the following:
-
-- Add a dependence (DEPEND and RDEPEND) on chromeos-base/metrics to the module's
-  ebuild.
-
-- Link the module with libmetrics (for example, by passing -lmetrics to the
-  module's link command). Both libmetrics.so and libmetrics.a are built and
-  installed under $SYSROOT/usr/lib/. Note that by default -lmetrics will link
-  against libmetrics.so, which is preferred.
-
-- To access the metrics library API in the module, include the
-  <metrics/metrics_library.h> header file. The file is installed in
-  $SYSROOT/usr/include/ when the metrics library is built and installed.
-
-- The API is documented in metrics_library.h under src/platform/metrics/. Before
-  using the API methods, a MetricsLibrary object needs to be constructed and
-  initialized through its Init method.
-
-  For more information on the C API see c_metrics_library.h.
-
-- Samples are sent to Chrome only if the "/home/chronos/Consent To Send Stats"
-  file exists or the metrics are declared enabled in the policy file (see the
-  AreMetricsEnabled API method).
-
-- On the target platform, shortly after the sample is sent, it should be visible
-  in Chrome through "about:histograms".
-
-
-================================================================================
-Histogram Naming Convention
-================================================================================
-
-Use TrackerArea.MetricName. For example:
-
-Platform.DailyUseTime
-Network.TimeToDrop
-
-
-================================================================================
-Server Side
-================================================================================
-
-If the histogram data is visible in about:histograms, it will be sent by an
-official Chrome build to UMA, assuming the user has opted into metrics
-collection. To make the histogram visible on "chromedashboard", the histogram
-description XML file needs to be updated (steps 2 and 3 after following the
-"Details on how to add your own histograms" link under the Histograms tab).
-Include the string "Chrome OS" in the histogram description so that it's easier
-to distinguish Chrome OS specific metrics from general Chrome histograms.
-
-The UMA server logs and keeps the collected field data even if the metric's name
-is not added to the histogram XML. However, the dashboard histogram for that
-metric will show field data as of the histogram XML update date; it will not
-include data for older dates. If past data needs to be displayed, manual
-server-side intervention is required. In other words, one should assume that
-field data collection starts only after the histogram XML has been updated.
-
-
-================================================================================
-The Metrics Client: metrics_client
-================================================================================
-
-metrics_client is a simple shell command-line utility for sending histogram
-samples and user actions. It's installed under /usr/bin on the target platform
-and uses libmetrics to send the data to Chrome. The utility is useful for
-generating metrics from shell scripts.
-
-For usage information and command-line options, run "metrics_client" on the
-target platform or look for "Usage:" in metrics_client.cc.
-
-
-================================================================================
-The Metrics Daemon: metrics_daemon
-================================================================================
-
-metrics_daemon is a daemon that runs in the background on the target platform
-and is intended for passive or ongoing metrics collection, or metrics collection
-requiring feedback from multiple modules. For example, it listens to D-Bus
-signals related to the user session and screen saver states to determine if the
-user is actively using the device or not and generates the corresponding
-data. The metrics daemon uses libmetrics to send the data to Chrome.
-
-The recommended way to generate metrics data from a module is to link and use
-libmetrics directly. However, the module could instead send signals to or
-communicate in some alternative way with the metrics daemon. Then the metrics
-daemon needs to monitor for the relevant events and take appropriate action --
-for example, aggregate data and send the histogram samples.
-
-
-================================================================================
-FAQ
-================================================================================
-
-Q. What should my histogram's |min| and |max| values be set at?
-
-A. You should set the values to a range that covers the vast majority of samples
-   that would appear in the field. Note that samples below the |min| will still
-   be collected in the underflow bucket and samples above the |max| will end up
-   in the overflow bucket. Also, the reported mean of the data will be correct
-   regardless of the range.
-
-Q. How many buckets should I use in my histogram?
-
-A. You should allocate as many buckets as necessary to perform proper analysis
-   on the collected data. Note, however, that the memory allocated in Chrome for
-   each histogram is proportional to the number of buckets. Therefore, it is
-   strongly recommended to keep this number low (e.g., 50 is normal, while 100
-   is probably high).
-
-Q. When should I use an enumeration (linear) histogram vs. a regular
-   (exponential) histogram?
-
-A. Enumeration histograms should really be used only for sampling enumerated
-   events and, in some cases, percentages. Normally, you should use a regular
-   histogram with exponential bucket layout that provides higher resolution at
-   the low end of the range and lower resolution at the high end. Regular
-   histograms are generally used for collecting performance data (e.g., timing,
-   memory usage, power) as well as aggregated event counts.
diff --git a/metricsd/README.md b/metricsd/README.md
new file mode 100644
index 0000000..8d4828c
--- /dev/null
+++ b/metricsd/README.md
@@ -0,0 +1,124 @@
+Metricsd
+========
+
+The metricsd daemon is used to gather metrics from the platform and application,
+aggregate them and upload them periodically to a server.
+The metrics will then be available in their aggregated form to the developer
+for analysis.
+
+Three components are provided to interact with `metricsd`: `libmetrics`,
+`metrics_collector` and `metrics_client`.
+
+The Metrics Library: libmetrics
+-------------------------------
+
+`libmetrics` is a small library that implements the basic C++ API for
+metrics collection. All metrics collection is funneled through this library. The
+easiest and recommended way for a client-side module to collect user metrics is
+to link `libmetrics` and use its APIs to send metrics to `metricsd` for transport to
+UMA. In order to use the library in a module, you need to do the following:
+
+- Add a dependency on the shared library in your Android.mk file:
+  `LOCAL_SHARED_LIBRARIES += libmetrics`
+
+- To access the metrics library API in the module, include the
+  <metrics/metrics_library.h> header file.
+
+- The API is documented in `metrics_library.h`. Before using the API methods, a
+  MetricsLibrary object needs to be constructed and initialized through its
+  Init method.
+
+- Samples are uploaded only if the `/data/misc/metrics/enabled` file exists.
+
+
+Server Side
+-----------
+
+You will be able to see all uploaded metrics on the metrics dashboard,
+accessible via the developer console.
+
+*** note
+It usually takes a day for metrics to be available on the dashboard.
+***
+
+
+The Metrics Client: metrics_client
+----------------------------------
+
+`metrics_client` is a simple shell command-line utility for sending histogram
+samples and querying `metricsd`. It's installed under `/system/bin` on the target
+platform and uses `libmetrics`.
+
+For usage information and command-line options, run `metrics_client` on the
+target platform or look for "Usage:" in `metrics_client.cc`.
+
+
+The Metrics Daemon: metricsd
+----------------------------
+
+`metricsd` is the daemon that listens for metrics logging calls (via Binder),
+aggregates the metrics and uploads them periodically. This daemon should start as
+early as possible so that depending daemons can log at any time.
+
+`metricsd` is made of two threads that work as follows:
+
+* The binder thread listens for one-way Binder calls, aggregates the metrics in
+  memory (via `base::StatisticsRecorder`) and increments the crash counters when a
+  crash is reported. This thread is kept as simple as possible to ensure the
+  maximum throughput possible.
+* The uploader thread takes care of backing up the metrics to disk periodically
+  (to avoid losing metrics on crashes), collecting metadata about the client
+  (version number, channel, etc..) and uploading the metrics periodically to the
+  server.
+
+
+The Metrics Collector: metrics_collector
+----------------------------------------
+
+metrics_collector is a daemon that runs in the background on the target platform,
+gathers health information about the system and maintains long running counters
+(ex: number of crashes per week).
+
+The recommended way to generate metrics data from a module is to link and use
+libmetrics directly. However, we may not want to add a dependency on libmetrics
+to some modules (ex: kernel). In this case, we can add a collector to
+metrics_collector that will, for example, take measurements and report them
+periodically to metricsd (this is the case for the disk utilization histogram).
+
+
+FAQ
+---
+
+### What should my histogram's |min| and |max| values be set at?
+
+You should set the values to a range that covers the vast majority of samples
+that would appear in the field. Note that samples below the |min| will still
+be collected in the underflow bucket and samples above the |max| will end up
+in the overflow bucket. Also, the reported mean of the data will be correct
+regardless of the range.
+
+### How many buckets should I use in my histogram?
+
+You should allocate as many buckets as necessary to perform proper analysis
+on the collected data. Note, however, that the memory allocated in metricsd
+for each histogram is proportional to the number of buckets. Therefore, it is
+strongly recommended to keep this number low (e.g., 50 is normal, while 100
+is probably high).
+
+### When should I use an enumeration (linear) histogram vs. a regular (exponential) histogram?
+
+Enumeration histograms should really be used only for sampling enumerated
+events and, in some cases, percentages. Normally, you should use a regular
+histogram with exponential bucket layout that provides higher resolution at
+the low end of the range and lower resolution at the high end. Regular
+histograms are generally used for collecting performance data (e.g., timing,
+memory usage, power) as well as aggregated event counts.
+
+### How can I test that my histogram was reported correctly?
+
+* Make sure no error messages appear in logcat when you log a sample.
+* Run `metrics_client -d` to dump the currently aggregated metrics. Your
+  histogram should appear in the list.
+* Make sure that the aggregated metrics were uploaded to the server successfully
+  (check for an OK message from `metricsd` in logcat).
+* After a day, your histogram should be available on the dashboard.
diff --git a/metricsd/metrics_collector.cc b/metricsd/metrics_collector.cc
index a5daab5..2cf2338 100644
--- a/metricsd/metrics_collector.cc
+++ b/metricsd/metrics_collector.cc
@@ -30,12 +30,13 @@
 #include <base/strings/string_split.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
+#include <brillo/binder_watcher.h>
 #include <brillo/osrelease_reader.h>
 #include <dbus/dbus.h>
 #include <dbus/message.h>
 
 #include "constants.h"
-#include "metrics_collector_service_trampoline.h"
+#include "metrics_collector_service_impl.h"
 
 using base::FilePath;
 using base::StringPrintf;
@@ -70,6 +71,7 @@
 const char kVmStatFileName[] = "/proc/vmstat";
 
 const char kWeaveComponent[] = "metrics";
+const char kWeaveTrait[] = "_metrics";
 
 }  // namespace
 
@@ -128,10 +130,18 @@
     version_cumulative_cpu_use_->Set(0);
   }
 
-  // Start metricscollectorservice via trampoline
-  MetricsCollectorServiceTrampoline metricscollectorservice_trampoline(this);
-  metricscollectorservice_trampoline.Run();
+  // Start metricscollectorservice
+  android::sp<BnMetricsCollectorServiceImpl> metrics_collector_service =
+      new BnMetricsCollectorServiceImpl(this);
+  android::status_t status = android::defaultServiceManager()->addService(
+      metrics_collector_service->getInterfaceDescriptor(),
+      metrics_collector_service);
+  CHECK(status == android::OK)
+      << "failed to register service metricscollectorservice";
 
+  // Watch Binder events in the main loop
+  brillo::BinderWatcher binder_watcher;
+  CHECK(binder_watcher.Init()) << "Binder FD watcher init failed";
   return brillo::DBusDaemon::Run();
 }
 
@@ -225,23 +235,15 @@
   bus_->AssertOnDBusThread();
   CHECK(bus_->SetUpAsyncOperations());
 
-  device_ = weaved::Device::CreateInstance(
-      bus_,
-      base::Bind(&MetricsCollector::UpdateWeaveState, base::Unretained(this)));
-  device_->AddComponent(kWeaveComponent, {"_metrics"});
-  device_->AddCommandHandler(
-      kWeaveComponent,
-      "_metrics.enableAnalyticsReporting",
-      base::Bind(&MetricsCollector::OnEnableMetrics, base::Unretained(this)));
-  device_->AddCommandHandler(
-      kWeaveComponent,
-      "_metrics.disableAnalyticsReporting",
-      base::Bind(&MetricsCollector::OnDisableMetrics, base::Unretained(this)));
+  weave_service_subscription_ = weaved::Service::Connect(
+      brillo::MessageLoop::current(),
+      base::Bind(&MetricsCollector::OnWeaveServiceConnected,
+                 weak_ptr_factory_.GetWeakPtr()));
 
   latest_cpu_use_microseconds_ = cpu_usage_collector_->GetCumulativeCpuUse();
   base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
       base::Bind(&MetricsCollector::HandleUpdateStatsTimeout,
-                 base::Unretained(this)),
+                 weak_ptr_factory_.GetWeakPtr()),
       base::TimeDelta::FromMilliseconds(kUpdateStatsIntervalMs));
 
   return EX_OK;
@@ -251,12 +253,28 @@
   brillo::DBusDaemon::OnShutdown(return_code);
 }
 
-void MetricsCollector::OnEnableMetrics(
-    const std::weak_ptr<weaved::Command>& cmd) {
-  auto command = cmd.lock();
-  if (!command)
+void MetricsCollector::OnWeaveServiceConnected(
+    const std::weak_ptr<weaved::Service>& service) {
+  service_ = service;
+  auto weave_service = service_.lock();
+  if (!weave_service)
     return;
 
+  weave_service->AddComponent(kWeaveComponent, {kWeaveTrait}, nullptr);
+  weave_service->AddCommandHandler(
+      kWeaveComponent, kWeaveTrait, "enableAnalyticsReporting",
+      base::Bind(&MetricsCollector::OnEnableMetrics,
+                 weak_ptr_factory_.GetWeakPtr()));
+  weave_service->AddCommandHandler(
+      kWeaveComponent, kWeaveTrait, "disableAnalyticsReporting",
+      base::Bind(&MetricsCollector::OnDisableMetrics,
+                 weak_ptr_factory_.GetWeakPtr()));
+
+  UpdateWeaveState();
+}
+
+void MetricsCollector::OnEnableMetrics(
+    std::unique_ptr<weaved::Command> command) {
   if (base::WriteFile(
           shared_metrics_directory_.Append(metrics::kConsentFileName), "", 0) !=
       0) {
@@ -271,11 +289,7 @@
 }
 
 void MetricsCollector::OnDisableMetrics(
-    const std::weak_ptr<weaved::Command>& cmd) {
-  auto command = cmd.lock();
-  if (!command)
-    return;
-
+    std::unique_ptr<weaved::Command> command) {
   if (!base::DeleteFile(
           shared_metrics_directory_.Append(metrics::kConsentFileName), false)) {
     PLOG(ERROR) << "Could not delete the consent file.";
@@ -289,16 +303,16 @@
 }
 
 void MetricsCollector::UpdateWeaveState() {
-  if (!device_)
+  auto weave_service = service_.lock();
+  if (!weave_service)
     return;
 
   std::string enabled =
       metrics_lib_->AreMetricsEnabled() ? "enabled" : "disabled";
 
-  if (!device_->SetStateProperty(kWeaveComponent,
-                                 "_metrics.analyticsReportingState",
-                                 enabled,
-                                 nullptr)) {
+  if (!weave_service->SetStateProperty(kWeaveComponent, kWeaveTrait,
+                                       "analyticsReportingState", enabled,
+                                       nullptr)) {
     LOG(ERROR) << "failed to update weave's state";
   }
 }
@@ -372,8 +386,8 @@
   }
   base::TimeDelta waitDelta = base::TimeDelta::FromSeconds(wait);
   base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::Bind(&MetricsCollector::MeminfoCallback, base::Unretained(this),
-                 waitDelta),
+      base::Bind(&MetricsCollector::MeminfoCallback,
+                 weak_ptr_factory_.GetWeakPtr(), waitDelta),
       waitDelta);
 }
 
@@ -387,8 +401,8 @@
   // Make both calls even if the first one fails.
   if (ProcessMeminfo(meminfo_raw)) {
     base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-        base::Bind(&MetricsCollector::MeminfoCallback, base::Unretained(this),
-                   wait),
+        base::Bind(&MetricsCollector::MeminfoCallback,
+                   weak_ptr_factory_.GetWeakPtr(), wait),
         wait);
   }
 }
@@ -555,7 +569,8 @@
     return;
   }
   base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::Bind(&MetricsCollector::MemuseCallback, base::Unretained(this)),
+      base::Bind(&MetricsCollector::MemuseCallback,
+                 weak_ptr_factory_.GetWeakPtr()),
       base::TimeDelta::FromSeconds(interval));
 }
 
@@ -741,6 +756,6 @@
   UpdateStats(TimeTicks::Now(), Time::Now());
   base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
       base::Bind(&MetricsCollector::HandleUpdateStatsTimeout,
-                 base::Unretained(this)),
+                 weak_ptr_factory_.GetWeakPtr()),
       base::TimeDelta::FromMilliseconds(kUpdateStatsIntervalMs));
 }
diff --git a/metricsd/metrics_collector.h b/metricsd/metrics_collector.h
index 45ef63d..ca4ae52 100644
--- a/metricsd/metrics_collector.h
+++ b/metricsd/metrics_collector.h
@@ -25,10 +25,12 @@
 #include <vector>
 
 #include <base/files/file_path.h>
+#include <base/memory/weak_ptr.h>
 #include <base/time/time.h>
+#include <brillo/binder_watcher.h>
 #include <brillo/daemons/dbus_daemon.h>
 #include <libweaved/command.h>
-#include <libweaved/device.h>
+#include <libweaved/service.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
 #include "collectors/averaged_statistics_collector.h"
@@ -114,10 +116,10 @@
   };
 
   // Enables metrics reporting.
-  void OnEnableMetrics(const std::weak_ptr<weaved::Command>& cmd);
+  void OnEnableMetrics(std::unique_ptr<weaved::Command> command);
 
   // Disables metrics reporting.
-  void OnDisableMetrics(const std::weak_ptr<weaved::Command>& cmd);
+  void OnDisableMetrics(std::unique_ptr<weaved::Command> command);
 
   // Updates the weave device state.
   void UpdateWeaveState();
@@ -216,6 +218,10 @@
   // Reads a string from a file and converts it to uint64_t.
   static bool ReadFileToUint64(const base::FilePath& path, uint64_t* value);
 
+  // Callback invoked when a connection to weaved's service is established
+  // over Binder interface.
+  void OnWeaveServiceConnected(const std::weak_ptr<weaved::Service>& service);
+
   // VARIABLES
 
   // Test mode.
@@ -272,7 +278,10 @@
   unique_ptr<DiskUsageCollector> disk_usage_collector_;
   unique_ptr<AveragedStatisticsCollector> averaged_stats_collector_;
 
-  std::unique_ptr<weaved::Device> device_;
+  unique_ptr<weaved::Service::Subscription> weave_service_subscription_;
+  std::weak_ptr<weaved::Service> service_;
+
+  base::WeakPtrFactory<MetricsCollector> weak_ptr_factory_{this};
 };
 
 #endif  // METRICS_METRICS_COLLECTOR_H_
diff --git a/metricsd/metrics_collector.rc b/metricsd/metrics_collector.rc
index 2e7e0ae..3dcb2d7 100644
--- a/metricsd/metrics_collector.rc
+++ b/metricsd/metrics_collector.rc
@@ -1,4 +1,4 @@
 service metricscollector /system/bin/metrics_collector --foreground --logtosyslog
     class late_start
-    user system
-    group system dbus
+    user metrics_coll
+    group metrics_coll dbus
diff --git a/metricsd/metrics_collector_service_impl.cc b/metricsd/metrics_collector_service_impl.cc
index dbb0578..4d9a05a 100644
--- a/metricsd/metrics_collector_service_impl.cc
+++ b/metricsd/metrics_collector_service_impl.cc
@@ -18,27 +18,18 @@
 
 #include <binder/IServiceManager.h>
 #include <binder/Status.h>
-#include <brillo/binder_watcher.h>
 #include <utils/Errors.h>
 
-#include "metrics_collector_service_trampoline.h"
+#include "metrics_collector.h"
 
 using namespace android;
 
 BnMetricsCollectorServiceImpl::BnMetricsCollectorServiceImpl(
-    MetricsCollectorServiceTrampoline* metrics_collector_service_trampoline) {
-  metrics_collector_service_trampoline_ = metrics_collector_service_trampoline;
-}
-
-void BnMetricsCollectorServiceImpl::Run() {
-  status_t status =
-      defaultServiceManager()->addService(getInterfaceDescriptor(), this);
-  CHECK(status == OK) << "libmetricscollectorservice: failed to add service";
-  binder_watcher_.reset(new ::brillo::BinderWatcher);
-  CHECK(binder_watcher_->Init()) << "Binder FD watcher init failed";
+    MetricsCollector* metrics_collector)
+    : metrics_collector_(metrics_collector) {
 }
 
 android::binder::Status BnMetricsCollectorServiceImpl::notifyUserCrash() {
-  metrics_collector_service_trampoline_->ProcessUserCrash();
+  metrics_collector_->ProcessUserCrash();
   return android::binder::Status::ok();
 }
diff --git a/metricsd/metrics_collector_service_impl.h b/metricsd/metrics_collector_service_impl.h
index bdcab50..8db418a 100644
--- a/metricsd/metrics_collector_service_impl.h
+++ b/metricsd/metrics_collector_service_impl.h
@@ -18,45 +18,31 @@
 #define METRICSD_METRICS_COLLECTOR_SERVICE_IMPL_H_
 
 // metrics_collector binder service implementation.  Constructed by
-// MetricsCollectorServiceTrampoline, which we use to call back into
-// MetricsCollector.  The trampoline isolates us from the -frtti code of
-// metrics_collector / libbrillo.
+// MetricsCollector.
 
 #include "android/brillo/metrics/BnMetricsCollectorService.h"
 
-#include <memory>
-
 #include <binder/Status.h>
-#include <brillo/binder_watcher.h>
 
-class MetricsCollectorServiceTrampoline;
-
-//#include "metrics_collector_service_trampoline.h"
+class MetricsCollector;
 
 class BnMetricsCollectorServiceImpl
     : public android::brillo::metrics::BnMetricsCollectorService {
  public:
-  // Passed a this pointer from the MetricsCollectorServiceTrampoline
-  // object that constructs us.
+  // Passed a this pointer from the MetricsCollector object that constructs us.
   explicit BnMetricsCollectorServiceImpl(
-      MetricsCollectorServiceTrampoline* metrics_collector_service_trampoline);
+      MetricsCollector* metrics_collector_service);
 
   virtual ~BnMetricsCollectorServiceImpl() = default;
 
-  // Starts the binder main loop.
-  void Run();
-
   // Called by crash_reporter to report a userspace crash event.  We relay
-  // this to MetricsCollector using the trampoline.
+  // this to MetricsCollector.
   android::binder::Status notifyUserCrash();
 
  private:
-  // Trampoline object that constructs us, we use this to call MetricsCollector
-  // methods via the trampoline.
-  MetricsCollectorServiceTrampoline* metrics_collector_service_trampoline_;
-
-  // BinderWatcher object we construct for handling Binder traffic
-  std::unique_ptr<brillo::BinderWatcher> binder_watcher_;
+  // MetricsCollector object that constructs us, we use this to call back
+  // to it.
+  MetricsCollector* metrics_collector_;
 };
 
 #endif  // METRICSD_METRICS_COLLECTOR_SERVICE_IMPL_H_
diff --git a/metricsd/metrics_collector_service_trampoline.cc b/metricsd/metrics_collector_service_trampoline.cc
deleted file mode 100644
index 12b80a1..0000000
--- a/metricsd/metrics_collector_service_trampoline.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "metrics_collector_service_trampoline.h"
-#include "metrics_collector.h"
-#include "metrics_collector_service_impl.h"
-
-MetricsCollectorServiceTrampoline::MetricsCollectorServiceTrampoline(
-    MetricsCollector* metrics_collector) {
-  metrics_collector_ = metrics_collector;
-}
-
-void MetricsCollectorServiceTrampoline::Run() {
-  // Start metricscollectorservice binder service
-  metrics_collector_service.reset(new BnMetricsCollectorServiceImpl(this));
-  metrics_collector_service->Run();
-}
-
-void MetricsCollectorServiceTrampoline::ProcessUserCrash() {
-  metrics_collector_->ProcessUserCrash();
-}
diff --git a/metricsd/metrics_collector_service_trampoline.h b/metricsd/metrics_collector_service_trampoline.h
deleted file mode 100644
index 5da9fa5..0000000
--- a/metricsd/metrics_collector_service_trampoline.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRICSD_METRICS_COLLECTOR_SERVICE_TRAMPOLINE_H_
-#define METRICSD_METRICS_COLLECTOR_SERVICE_TRAMPOLINE_H_
-
-// Trampoline between the -fno-rtti compile of libmetricsservice and the
-// -frtti compile of metrics_collector.  MetricsCollectorServiceTrampoline
-// is called from MetricsCollector to run the IMetricsCollectorService
-// server, and acts as a go-between for calls from server back to
-// MetricsCollector.
-
-#include <memory>
-
-#include "metrics_collector_service_impl.h"
-
-// Forward declaration of MetricsCollector.  Don't include the header file
-// for the class here, as it pulls in -frtti stuff.
-class MetricsCollector;
-
-class MetricsCollectorServiceTrampoline {
- public:
-  // Constructor take a this pointer from the MetricsCollector class that
-  // constructs these objects.
-  explicit MetricsCollectorServiceTrampoline(
-      MetricsCollector* metrics_collector);
-
-  // Initialize and run the IMetricsCollectorService
-  void Run();
-
-  // Called from IMetricsCollectorService to trampoline into the
-  // MetricsCollector method of the same name.
-  void ProcessUserCrash();
-
- private:
-  // The MetricsCollector object that constructs us, for which we act as
-  // the go-between for MetricsCollectorServiceImpl use.
-  MetricsCollector* metrics_collector_;
-
-  // The IMetricsCollectorService implementation we construct.
-  std::unique_ptr<BnMetricsCollectorServiceImpl> metrics_collector_service;
-};
-
-#endif  // METRICSD_METRICS_COLLECTOR_SERVICE_TRAMPOLINE_H_
diff --git a/metricsd/metricsd.rc b/metricsd/metricsd.rc
index 359d0d1..825c87f 100644
--- a/metricsd/metricsd.rc
+++ b/metricsd/metricsd.rc
@@ -1,9 +1,9 @@
 on post-fs-data
-    mkdir /data/misc/metrics 0770 system system
-    mkdir /data/misc/metricsd 0700 system system
-    mkdir /data/misc/metrics_collector 0700 system system
+    mkdir /data/misc/metrics 0750 metrics_coll system
+    mkdir /data/misc/metricsd 0700 metricsd metricsd
+    mkdir /data/misc/metrics_collector 0700 metrics_coll metrics_coll
 
 service metricsd /system/bin/metricsd --foreground --logtosyslog
     class late_start
-    user system
+    user metricsd
     group system dbus inet
diff --git a/metricsd/uploader/upload_service.h b/metricsd/uploader/upload_service.h
index 1d36121..420653e 100644
--- a/metricsd/uploader/upload_service.h
+++ b/metricsd/uploader/upload_service.h
@@ -34,30 +34,33 @@
 
 class SystemProfileSetter;
 
-// Service responsible for uploading the metrics periodically to the server.
-// This service works as a simple 2-state state-machine.
+// Service responsible for backing up the currently aggregated metrics to disk
+// and uploading them periodically to the server.
 //
-// The two states are the presence or not of a staged log.
-// A staged log is a compressed protobuffer containing both the aggregated
-// metrics and event and information about the client. (product,
-// model_manifest_id, etc...).
+// A given metrics sample can be in one of three locations.
+// * in-memory metrics: in memory aggregated metrics, waiting to be staged for
+//   upload.
+// * saved log: protobuf message, written to disk periodically and on shutdown
+//   to make a backup of metrics data for uploading later.
+// * staged log: protobuf message waiting to be uploaded.
 //
-// At regular intervals, the upload event will be triggered and the following
-// will happen:
-// * if a staged log is present:
-//    The previous upload may have failed for various reason. We then retry to
-//    upload the same log.
-//    - if the upload is successful, we discard the log (therefore
-//      transitioning back to no staged log)
-//    - if the upload fails, we keep the log to try again later.
+// The service works as follows:
+// On startup, we create the in-memory metrics from the saved log if it exists.
 //
-// * if no staged logs are present:
-//    Take a snapshot of the aggregated metrics, save it to disk and try to send
-//    it:
-//    - if the upload succeeds, we discard the staged log (transitioning back
-//      to the no staged log state)
-//    - if the upload fails, we continue and will retry to upload later.
+// Periodically (every |disk_persistence_interval_| seconds), we take a snapshot
+// of the in-memory metrics and save them to disk.
 //
+// Periodically (every |upload_interval| seconds), we:
+// * take a snapshot of the in-memory metrics and create the staged log
+// * save the staged log to disk to avoid losing it if metricsd or the system
+//   crashes between two uploads.
+// * delete the last saved log: all the metrics contained in it are also in the
+//   newly created staged log.
+//
+// On shutdown (SIGINT or SIGTERM), we save the in-memory metrics to disk.
+//
+// Note: the in-memory metrics can be stored in |current_log_| or
+// base::StatisticsRecorder.
 class UploadService : public base::HistogramFlattener, public brillo::Daemon {
  public:
   UploadService(const std::string& server,
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a52d87d..d322402 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -332,6 +332,7 @@
     chmod 0660 /data/misc/wifi/wpa_supplicant.conf
     mkdir /data/local 0751 root root
     mkdir /data/misc/media 0700 media media
+    mkdir /data/misc/vold 0700 root root
     mkdir /data/misc/boottrace 0771 system shell
     mkdir /data/misc/update_engine 0700 root root
     mkdir /data/misc/trace 0700 root root