Merge "Add native_window_get_next_frame_id."
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 5a3b401..7afa616 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -313,3 +313,15 @@
 void AdbCloser::Close(int fd) {
     adb_close(fd);
 }
+
+int usage(const char* fmt, ...) {
+    fprintf(stderr, "adb: ");
+
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+
+    fprintf(stderr, "\n");
+    return 1;
+}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 16317e0..2b59034 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -21,6 +21,8 @@
 
 #include <android-base/macros.h>
 
+int usage(const char*, ...);
+
 void close_stdin();
 
 bool getcwd(std::string* cwd);
diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
index 9b59d05..b7e76a6 100644
--- a/adb/bugreport.cpp
+++ b/adb/bugreport.cpp
@@ -182,11 +182,8 @@
     DISALLOW_COPY_AND_ASSIGN(BugreportStandardStreamsCallback);
 };
 
-// Implemented in commandline.cpp
-int usage();
-
 int Bugreport::DoIt(TransportType transport_type, const char* serial, int argc, const char** argv) {
-    if (argc > 2) return usage();
+    if (argc > 2) return usage("usage: adb bugreport [PATH]");
 
     // Gets bugreportz version.
     std::string bugz_stdout, bugz_stderr;
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 2befa0c..3b2df2e 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -231,11 +231,6 @@
     // clang-format on
 }
 
-int usage() {
-    help();
-    return 1;
-}
-
 #if defined(_WIN32)
 
 // Implemented in sysdeps_win32.cpp.
@@ -1235,7 +1230,7 @@
 }
 
 static int restore(int argc, const char** argv) {
-    if (argc != 2) return usage();
+    if (argc != 2) return usage("restore requires an argument");
 
     const char* filename = argv[1];
     int tarFd = adb_open(filename, O_RDONLY);
@@ -1443,19 +1438,19 @@
             /* this is a special flag used only when the ADB client launches the ADB Server */
             is_daemon = 1;
         } else if (!strcmp(argv[0], "--reply-fd")) {
-            if (argc < 2) return usage();
+            if (argc < 2) return usage("--reply-fd requires an argument");
             const char* reply_fd_str = argv[1];
             argc--;
             argv++;
             ack_reply_fd = strtol(reply_fd_str, nullptr, 10);
             if (!_is_valid_ack_reply_fd(ack_reply_fd)) {
                 fprintf(stderr, "adb: invalid reply fd \"%s\"\n", reply_fd_str);
-                return usage();
+                return 1;
             }
         } else if (!strncmp(argv[0], "-p", 2)) {
             const char* product = nullptr;
             if (argv[0][2] == '\0') {
-                if (argc < 2) return usage();
+                if (argc < 2) return usage("-p requires an argument");
                 product = argv[1];
                 argc--;
                 argv++;
@@ -1465,13 +1460,13 @@
             gProductOutPath = find_product_out_path(product);
             if (gProductOutPath.empty()) {
                 fprintf(stderr, "adb: could not resolve \"-p %s\"\n", product);
-                return usage();
+                return 1;
             }
         } else if (argv[0][0]=='-' && argv[0][1]=='s') {
             if (isdigit(argv[0][2])) {
                 serial = argv[0] + 2;
             } else {
-                if (argc < 2 || argv[0][2] != '\0') return usage();
+                if (argc < 2 || argv[0][2] != '\0') return usage("-s requires an argument");
                 serial = argv[1];
                 argc--;
                 argv++;
@@ -1484,7 +1479,7 @@
             gListenAll = 1;
         } else if (!strncmp(argv[0], "-H", 2)) {
             if (argv[0][2] == '\0') {
-                if (argc < 2) return usage();
+                if (argc < 2) return usage("-H requires an argument");
                 server_host_str = argv[1];
                 argc--;
                 argv++;
@@ -1493,7 +1488,7 @@
             }
         } else if (!strncmp(argv[0], "-P", 2)) {
             if (argv[0][2] == '\0') {
-                if (argc < 2) return usage();
+                if (argc < 2) return usage("-P requires an argument");
                 server_port_str = argv[1];
                 argc--;
                 argv++;
@@ -1501,7 +1496,7 @@
                 server_port_str = argv[0] + 2;
             }
         } else if (!strcmp(argv[0], "-L")) {
-            if (argc < 2) return usage();
+            if (argc < 2) return usage("-L requires an argument");
             server_socket_str = argv[1];
             argc--;
             argv++;
@@ -1566,7 +1561,7 @@
         if (no_daemon || is_daemon) {
             if (is_daemon && (ack_reply_fd == -1)) {
                 fprintf(stderr, "reply fd for adb server to client communication not specified.\n");
-                return usage();
+                return 1;
             }
             r = adb_server_main(is_daemon, server_socket_str, ack_reply_fd);
         } else {
@@ -1579,7 +1574,8 @@
     }
 
     if (argc == 0) {
-        return usage();
+        help();
+        return 1;
     }
 
     /* handle wait-for-* prefix */
@@ -1696,7 +1692,7 @@
         }
     }
     else if (!strcmp(argv[0], "sideload")) {
-        if (argc != 2) return usage();
+        if (argc != 2) return usage("sideload requires an argument");
         if (adb_sideload_host(argv[1])) {
             return 1;
         } else {
@@ -1730,7 +1726,7 @@
         bool reverse = !strcmp(argv[0], "reverse");
         ++argv;
         --argc;
-        if (argc < 1) return usage();
+        if (argc < 1) return usage("%s requires an argument", argv[0]);
 
         // Determine the <host-prefix> for this command.
         std::string host_prefix;
@@ -1750,24 +1746,24 @@
 
         std::string cmd, error;
         if (strcmp(argv[0], "--list") == 0) {
-            if (argc != 1) return usage();
+            if (argc != 1) return usage("--list doesn't take any arguments");
             return adb_query_command(host_prefix + ":list-forward");
         } else if (strcmp(argv[0], "--remove-all") == 0) {
-            if (argc != 1) return usage();
+            if (argc != 1) return usage("--remove-all doesn't take any arguments");
             cmd = host_prefix + ":killforward-all";
         } else if (strcmp(argv[0], "--remove") == 0) {
             // forward --remove <local>
-            if (argc != 2) return usage();
+            if (argc != 2) return usage("--remove requires an argument");
             cmd = host_prefix + ":killforward:" + argv[1];
         } else if (strcmp(argv[0], "--no-rebind") == 0) {
             // forward --no-rebind <local> <remote>
-            if (argc != 3) return usage();
+            if (argc != 3) return usage("--no-rebind takes two arguments");
             if (forward_targets_are_valid(argv[1], argv[2], &error)) {
                 cmd = host_prefix + ":forward:norebind:" + argv[1] + ";" + argv[2];
             }
         } else {
             // forward <local> <remote>
-            if (argc != 2) return usage();
+            if (argc != 2) return usage("forward takes two arguments");
             if (forward_targets_are_valid(argv[0], argv[1], &error)) {
                 cmd = host_prefix + ":forward:" + argv[0] + ";" + argv[1];
             }
@@ -1796,7 +1792,7 @@
     }
     /* do_sync_*() commands */
     else if (!strcmp(argv[0], "ls")) {
-        if (argc != 2) return usage();
+        if (argc != 2) return usage("ls requires an argument");
         return do_sync_ls(argv[1]) ? 0 : 1;
     }
     else if (!strcmp(argv[0], "push")) {
@@ -1805,7 +1801,7 @@
         const char* dst = nullptr;
 
         parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, &copy_attrs);
-        if (srcs.empty() || !dst) return usage();
+        if (srcs.empty() || !dst) return usage("push requires an argument");
         return do_sync_push(srcs, dst) ? 0 : 1;
     }
     else if (!strcmp(argv[0], "pull")) {
@@ -1814,22 +1810,22 @@
         const char* dst = ".";
 
         parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, &copy_attrs);
-        if (srcs.empty()) return usage();
+        if (srcs.empty()) return usage("pull requires an argument");
         return do_sync_pull(srcs, dst, copy_attrs) ? 0 : 1;
     }
     else if (!strcmp(argv[0], "install")) {
-        if (argc < 2) return usage();
+        if (argc < 2) return usage("install requires an argument");
         if (_use_legacy_install()) {
             return install_app_legacy(transport_type, serial, argc, argv);
         }
         return install_app(transport_type, serial, argc, argv);
     }
     else if (!strcmp(argv[0], "install-multiple")) {
-        if (argc < 2) return usage();
+        if (argc < 2) return usage("install-multiple requires an argument");
         return install_multiple_app(transport_type, serial, argc, argv);
     }
     else if (!strcmp(argv[0], "uninstall")) {
-        if (argc < 2) return usage();
+        if (argc < 2) return usage("uninstall requires an argument");
         if (_use_legacy_install()) {
             return uninstall_app_legacy(transport_type, serial, argc, argv);
         }
@@ -1852,12 +1848,12 @@
             // A local path or "android"/"data" arg was specified.
             src = argv[1];
         } else {
-            return usage();
+            return usage("usage: adb sync [-l] [PARTITION]");
         }
 
         if (src != "" &&
             src != "system" && src != "data" && src != "vendor" && src != "oem") {
-            return usage();
+            return usage("don't know how to sync %s partition", src.c_str());
         }
 
         std::string system_src_path = product_file("system");
@@ -1909,7 +1905,7 @@
         return restore(argc, argv);
     }
     else if (!strcmp(argv[0], "keygen")) {
-        if (argc < 2) return usage();
+        if (argc != 2) return usage("keygen requires an argument");
         // Always print key generation information for keygen command.
         adb_trace_enable(AUTH);
         return adb_auth_keygen(argv[1]);
@@ -1926,11 +1922,11 @@
 
 
     /* "adb /?" is a common idiom under Windows */
-    else if (!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
+    else if (!strcmp(argv[0], "--help") || !strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
         help();
         return 0;
     }
-    else if (!strcmp(argv[0], "version")) {
+    else if (!strcmp(argv[0], "--version") || !strcmp(argv[0], "version")) {
         fprintf(stdout, "%s", adb_version().c_str());
         return 0;
     }
@@ -1961,12 +1957,12 @@
                 std::string err;
                 return adb_query_command("host:reconnect-offline");
             } else {
-                return usage();
+                return usage("usage: adb reconnect [device|offline]");
             }
         }
     }
 
-    usage();
+    usage("unknown command %s", argv[0]);
     return 1;
 }
 
diff --git a/base/Android.bp b/base/Android.bp
index b9a6e0b..df09784 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -37,26 +37,40 @@
     cppflags: libbase_cppflags,
     export_include_dirs: ["include"],
     shared_libs: ["liblog"],
+    sanitize: {
+        misc_undefined: ["integer"],
+    },
     target: {
         android: {
             srcs: [
                 "errors_unix.cpp",
                 "properties.cpp",
+                "chrono_utils.cpp",
             ],
             cppflags: ["-Wexit-time-destructors"],
         },
         darwin: {
-            srcs: ["errors_unix.cpp"],
+            srcs: [
+                "chrono_utils.cpp",
+                "errors_unix.cpp",
+            ],
             cppflags: ["-Wexit-time-destructors"],
         },
         linux_bionic: {
-            srcs: ["errors_unix.cpp"],
+            srcs: [
+                "chrono_utils.cpp",
+                "errors_unix.cpp",
+            ],
             cppflags: ["-Wexit-time-destructors"],
             enabled: true,
         },
         linux: {
-            srcs: ["errors_unix.cpp"],
+            srcs: [
+                "chrono_utils.cpp",
+                "errors_unix.cpp",
+            ],
             cppflags: ["-Wexit-time-destructors"],
+            host_ldlibs: ["-lrt"],
         },
         windows: {
             srcs: [
@@ -86,9 +100,19 @@
         "strings_test.cpp",
         "test_main.cpp",
     ],
+    sanitize: {
+        misc_undefined: ["integer"],
+    },
     target: {
         android: {
-            srcs: ["properties_test.cpp"],
+            srcs: [
+                "chrono_utils_test.cpp",
+                "properties_test.cpp"
+            ],
+        },
+        linux: {
+            srcs: ["chrono_utils_test.cpp"],
+            host_ldlibs: ["-lrt"],
         },
         windows: {
             srcs: ["utf8_test.cpp"],
diff --git a/base/chrono_utils.cpp b/base/chrono_utils.cpp
new file mode 100644
index 0000000..644fd28
--- /dev/null
+++ b/base/chrono_utils.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 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 "android-base/chrono_utils.h"
+
+#include <time.h>
+
+namespace android {
+namespace base {
+
+boot_clock::time_point boot_clock::now() {
+  timespec ts;
+  clockid_t clk_id;
+
+#ifdef __ANDROID__
+  clk_id = CLOCK_BOOTTIME;
+#else
+  // Darwin does not support CLOCK_BOOTTIME.  CLOCK_MONOTONIC is a sufficient
+  // fallback; the only loss of precision is the time duration when the system
+  // is suspended.
+  clk_id = CLOCK_MONOTONIC;
+#endif  // __ANDROID__
+
+  clock_gettime(clk_id, &ts);
+  return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) +
+                                std::chrono::nanoseconds(ts.tv_nsec));
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/chrono_utils_test.cpp b/base/chrono_utils_test.cpp
new file mode 100644
index 0000000..bc6df4b
--- /dev/null
+++ b/base/chrono_utils_test.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 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 "android-base/chrono_utils.h"
+
+#include <time.h>
+
+#include <chrono>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace base {
+
+std::chrono::seconds GetBootTimeSeconds() {
+  struct timespec now;
+  clock_gettime(CLOCK_BOOTTIME, &now);
+
+  auto now_tp = boot_clock::time_point(
+      std::chrono::seconds(now.tv_sec) + std::chrono::nanoseconds(now.tv_nsec));
+  return std::chrono::duration_cast<std::chrono::seconds>(
+      now_tp.time_since_epoch());
+}
+
+// Tests (at least) the seconds accuracy of the boot_clock::now() method.
+TEST(ChronoUtilsTest, BootClockNowSeconds) {
+  auto now = GetBootTimeSeconds();
+  auto boot_seconds = std::chrono::duration_cast<std::chrono::seconds>(
+      boot_clock::now().time_since_epoch());
+  EXPECT_EQ(now, boot_seconds);
+}
+
+}  // namespace base
+}  // namespace android
\ No newline at end of file
diff --git a/base/include/android-base/chrono_utils.h b/base/include/android-base/chrono_utils.h
new file mode 100644
index 0000000..0086425
--- /dev/null
+++ b/base/include/android-base/chrono_utils.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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 ANDROID_BASE_CHRONO_UTILS_H
+#define ANDROID_BASE_CHRONO_UTILS_H
+
+#include <chrono>
+
+namespace android {
+namespace base {
+
+// A std::chrono clock based on CLOCK_BOOTTIME.
+class boot_clock {
+ public:
+  typedef std::chrono::nanoseconds duration;
+  typedef std::chrono::time_point<boot_clock, duration> time_point;
+
+  static time_point now();
+};
+
+}  // namespace base
+}  // namespace android
+
+#endif  // ANDROID_BASE_CHRONO_UTILS_H
diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h
index 4d7082a..e275fa2 100644
--- a/base/include/android-base/properties.h
+++ b/base/include/android-base/properties.h
@@ -58,6 +58,9 @@
 // tell you whether or not your call succeeded. A `false` return value definitely means failure.
 bool SetProperty(const std::string& key, const std::string& value);
 
+// Waits for the system property `key` to have the value `expected_value`, .
+void WaitForProperty(const std::string& key, const std::string& expected_value);
+
 } // namespace base
 } // namespace android
 
diff --git a/base/properties.cpp b/base/properties.cpp
index 37daf9a..0f0f638 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -14,9 +14,12 @@
  * limitations under the License.
  */
 
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+
 #include "android-base/properties.h"
 
 #include <sys/system_properties.h>
+#include <sys/_system_properties.h>
 
 #include <string>
 
@@ -78,5 +81,43 @@
   return (__system_property_set(key.c_str(), value.c_str()) == 0);
 }
 
+struct WaitForPropertyData {
+  bool done;
+  const std::string* expected_value;
+  unsigned last_read_serial;
+};
+
+static void WaitForPropertyCallback(void* data_ptr, const char*, const char* value, unsigned serial) {
+  WaitForPropertyData* data = reinterpret_cast<WaitForPropertyData*>(data_ptr);
+  if (*data->expected_value == value) {
+    data->done = true;
+  } else {
+    data->last_read_serial = serial;
+  }
+}
+
+void WaitForProperty(const std::string& key, const std::string& expected_value) {
+  // Find the property's prop_info*.
+  const prop_info* pi;
+  unsigned global_serial = 0;
+  while ((pi = __system_property_find(key.c_str())) == nullptr) {
+    // The property doesn't even exist yet.
+    // Wait for a global change and then look again.
+    global_serial = __system_property_wait_any(global_serial);
+  }
+
+  WaitForPropertyData data;
+  data.expected_value = &expected_value;
+  data.done = false;
+  while (true) {
+    // Check whether the property has the value we're looking for?
+    __system_property_read_callback(pi, WaitForPropertyCallback, &data);
+    if (data.done) return;
+
+    // It didn't so wait for it to change before checking again.
+    __system_property_wait(pi, data.last_read_serial);
+  }
+}
+
 }  // namespace base
 }  // namespace android
diff --git a/base/properties_test.cpp b/base/properties_test.cpp
index da89ec5..d8186be 100644
--- a/base/properties_test.cpp
+++ b/base/properties_test.cpp
@@ -18,7 +18,12 @@
 
 #include <gtest/gtest.h>
 
+#include <atomic>
+#include <chrono>
 #include <string>
+#include <thread>
+
+using namespace std::chrono_literals;
 
 TEST(properties, smoke) {
   android::base::SetProperty("debug.libbase.property_test", "hello");
@@ -119,3 +124,18 @@
 TEST(properties, GetUintProperty_uint16_t) { CheckGetUintProperty<uint16_t>(); }
 TEST(properties, GetUintProperty_uint32_t) { CheckGetUintProperty<uint32_t>(); }
 TEST(properties, GetUintProperty_uint64_t) { CheckGetUintProperty<uint64_t>(); }
+
+TEST(properties, WaitForProperty) {
+  std::atomic<bool> flag{false};
+  std::thread thread([&]() {
+    std::this_thread::sleep_for(100ms);
+    android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
+    while (!flag) std::this_thread::yield();
+    android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
+  });
+
+  android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a");
+  flag = true;
+  android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b");
+  thread.join();
+}
diff --git a/base/strings.cpp b/base/strings.cpp
index 46fe939..bfdaf12 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -36,11 +36,12 @@
 
   size_t base = 0;
   size_t found;
-  do {
+  while (true) {
     found = s.find_first_of(delimiters, base);
     result.push_back(s.substr(base, found - base));
+    if (found == s.npos) break;
     base = found + 1;
-  } while (found != s.npos);
+  }
 
   return result;
 }
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 7a65a00..7ed5b2b 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -251,3 +251,7 @@
   ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "bar"));
   ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "fool"));
 }
+
+TEST(strings, ubsan_28729303) {
+  android::base::Split("/dev/null", ":");
+}
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 3b3d698..636477d 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -57,7 +57,13 @@
 
 static std::string GetSystemTempDir() {
 #if defined(__ANDROID__)
-  return "/data/local/tmp";
+  const char* tmpdir = "/data/local/tmp";
+  if (access(tmpdir, R_OK | W_OK | X_OK) == 0) {
+    return tmpdir;
+  }
+  // Tests running in app context can't access /data/local/tmp,
+  // so try current directory if /data/local/tmp is not accessible.
+  return ".";
 #elif defined(_WIN32)
   char tmp_dir[MAX_PATH];
   DWORD result = GetTempPathA(sizeof(tmp_dir), tmp_dir);
diff --git a/bootstat/Android.bp b/bootstat/Android.bp
index d98a9d7..95c9af5 100644
--- a/bootstat/Android.bp
+++ b/bootstat/Android.bp
@@ -16,8 +16,6 @@
 
 bootstat_lib_src_files = [
     "boot_event_record_store.cpp",
-    "histogram_logger.cpp",
-    "uptime_parser.cpp",
 ]
 
 cc_defaults {
@@ -27,15 +25,12 @@
         "-Wall",
         "-Wextra",
         "-Werror",
-
-        // 524291 corresponds to sysui_histogram, from
-        // frameworks/base/core/java/com/android/internal/logging/EventLogTags.logtags
-        "-DHISTOGRAM_LOG_TAG=524291",
     ],
     shared_libs: [
         "libbase",
         "libcutils",
         "liblog",
+        "libmetricslogger",
     ],
     whole_static_libs: ["libgtest_prod"],
     // Clang is required because of C++14
diff --git a/bootstat/boot_event_record_store.cpp b/bootstat/boot_event_record_store.cpp
index f902af3..3243676 100644
--- a/bootstat/boot_event_record_store.cpp
+++ b/bootstat/boot_event_record_store.cpp
@@ -20,14 +20,16 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <utime.h>
+
+#include <chrono>
 #include <cstdlib>
 #include <string>
 #include <utility>
+
+#include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
-#include "histogram_logger.h"
-#include "uptime_parser.h"
 
 namespace {
 
@@ -56,7 +58,9 @@
 }
 
 void BootEventRecordStore::AddBootEvent(const std::string& event) {
-  AddBootEventWithValue(event, bootstat::ParseUptime());
+  auto uptime = std::chrono::duration_cast<std::chrono::seconds>(
+      android::base::boot_clock::now().time_since_epoch());
+  AddBootEventWithValue(event, uptime.count());
 }
 
 // The implementation of AddBootEventValue makes use of the mtime file
diff --git a/bootstat/boot_event_record_store_test.cpp b/bootstat/boot_event_record_store_test.cpp
index 90f6513..0df6706 100644
--- a/bootstat/boot_event_record_store_test.cpp
+++ b/bootstat/boot_event_record_store_test.cpp
@@ -21,15 +21,18 @@
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <unistd.h>
+
+#include <chrono>
 #include <cstdint>
 #include <cstdlib>
+
+#include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/test_utils.h>
 #include <android-base/unique_fd.h>
 #include <gtest/gtest.h>
 #include <gmock/gmock.h>
-#include "uptime_parser.h"
 
 using testing::UnorderedElementsAreArray;
 
@@ -89,6 +92,12 @@
   rmdir(path.c_str());
 }
 
+// Returns the time in seconds since boot.
+time_t GetUptimeSeconds() {
+  return std::chrono::duration_cast<std::chrono::seconds>(
+      android::base::boot_clock::now().time_since_epoch()).count();
+}
+
 class BootEventRecordStoreTest : public ::testing::Test {
  public:
   BootEventRecordStoreTest() {
@@ -126,7 +135,7 @@
   BootEventRecordStore store;
   store.SetStorePath(GetStorePathForTesting());
 
-  time_t uptime = bootstat::ParseUptime();
+  time_t uptime = GetUptimeSeconds();
   ASSERT_NE(-1, uptime);
 
   store.AddBootEvent("cenozoic");
@@ -141,7 +150,7 @@
   BootEventRecordStore store;
   store.SetStorePath(GetStorePathForTesting());
 
-  time_t uptime = bootstat::ParseUptime();
+  time_t uptime = GetUptimeSeconds();
   ASSERT_NE(-1, uptime);
 
   store.AddBootEvent("cretaceous");
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index c85667e..d594cdb 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -21,6 +21,7 @@
 #include <getopt.h>
 #include <unistd.h>
 
+#include <chrono>
 #include <cmath>
 #include <cstddef>
 #include <cstdio>
@@ -31,14 +32,14 @@
 #include <vector>
 
 #include <android/log.h>
+#include <android-base/chrono_utils.h>
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
 #include <cutils/properties.h>
+#include <metricslogger/metrics_logger.h>
 
 #include "boot_event_record_store.h"
-#include "histogram_logger.h"
-#include "uptime_parser.h"
 
 namespace {
 
@@ -49,7 +50,7 @@
 
   auto events = boot_event_store.GetAllBootEvents();
   for (auto i = events.cbegin(); i != events.cend(); ++i) {
-    bootstat::LogHistogram(i->first, i->second);
+    android::metricslogger::LogHistogram(i->first, i->second);
   }
 }
 
@@ -247,7 +248,8 @@
   BootEventRecordStore boot_event_store;
   BootEventRecordStore::BootEventRecord record;
 
-  time_t uptime = bootstat::ParseUptime();
+  auto uptime = std::chrono::duration_cast<std::chrono::seconds>(
+      android::base::boot_clock::now().time_since_epoch());
   time_t current_time_utc = time(nullptr);
 
   if (boot_event_store.GetBootEvent("last_boot_time_utc", &record)) {
@@ -274,22 +276,22 @@
     // Log the amount of time elapsed until the device is decrypted, which
     // includes the variable amount of time the user takes to enter the
     // decryption password.
-    boot_event_store.AddBootEventWithValue("boot_decryption_complete", uptime);
+    boot_event_store.AddBootEventWithValue("boot_decryption_complete", uptime.count());
 
     // Subtract the decryption time to normalize the boot cycle timing.
-    time_t boot_complete = uptime - record.second;
+    std::chrono::seconds boot_complete = std::chrono::seconds(uptime.count() - record.second);
     boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_post_decrypt",
-                                           boot_complete);
+                                           boot_complete.count());
 
 
   } else {
     boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption",
-                                           uptime);
+                                           uptime.count());
   }
 
   // Record the total time from device startup to boot complete, regardless of
   // encryption state.
-  boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime);
+  boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime.count());
 
   RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init");
   RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.selinux");
@@ -317,18 +319,18 @@
 
   if (current_time_utc < 0) {
     // UMA does not display negative values in buckets, so convert to positive.
-    bootstat::LogHistogram(
+    android::metricslogger::LogHistogram(
         "factory_reset_current_time_failure", std::abs(current_time_utc));
 
-    // Logging via BootEventRecordStore to see if using bootstat::LogHistogram
+    // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
     // is losing records somehow.
     boot_event_store.AddBootEventWithValue(
         "factory_reset_current_time_failure", std::abs(current_time_utc));
     return;
   } else {
-    bootstat::LogHistogram("factory_reset_current_time", current_time_utc);
+    android::metricslogger::LogHistogram("factory_reset_current_time", current_time_utc);
 
-    // Logging via BootEventRecordStore to see if using bootstat::LogHistogram
+    // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
     // is losing records somehow.
     boot_event_store.AddBootEventWithValue(
         "factory_reset_current_time", current_time_utc);
@@ -347,9 +349,9 @@
   // Calculate and record the difference in time between now and the
   // factory_reset time.
   time_t factory_reset_utc = record.second;
-  bootstat::LogHistogram("factory_reset_record_value", factory_reset_utc);
+  android::metricslogger::LogHistogram("factory_reset_record_value", factory_reset_utc);
 
-  // Logging via BootEventRecordStore to see if using bootstat::LogHistogram
+  // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
   // is losing records somehow.
   boot_event_store.AddBootEventWithValue(
       "factory_reset_record_value", factory_reset_utc);
diff --git a/bootstat/bootstat.rc b/bootstat/bootstat.rc
index b072412..f4756d5 100644
--- a/bootstat/bootstat.rc
+++ b/bootstat/bootstat.rc
@@ -8,7 +8,8 @@
 #
 # post-fs-data: /data is writable
 # property:init.svc.bootanim=running: The boot animation is running
-on post-fs-data && property:init.svc.bootanim=running
+# property:ro.crypto.type=block: FDE device
+on post-fs-data && property:init.svc.bootanim=running && property:ro.crypto.type=block
     exec - root root -- /system/bin/bootstat -r post_decrypt_time_elapsed
 
 # sys.logbootcomplete is a signal to enable the bootstat logging mechanism.
diff --git a/bootstat/uptime_parser.cpp b/bootstat/uptime_parser.cpp
deleted file mode 100644
index 7c2034c..0000000
--- a/bootstat/uptime_parser.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2016 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 "uptime_parser.h"
-
-#include <time.h>
-#include <cstdlib>
-#include <string>
-#include <android-base/file.h>
-#include <android-base/logging.h>
-
-namespace bootstat {
-
-time_t ParseUptime() {
-  std::string uptime_str;
-  if (!android::base::ReadFileToString("/proc/uptime", &uptime_str)) {
-    PLOG(ERROR) << "Failed to read /proc/uptime";
-    return -1;
-  }
-
-  // Cast intentionally rounds down.
-  return static_cast<time_t>(strtod(uptime_str.c_str(), NULL));
-}
-
-}  // namespace bootstat
\ No newline at end of file
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 58eaed7..2889356 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -18,10 +18,12 @@
 #include <dirent.h>
 #include <fcntl.h>
 #include <stdlib.h>
-#include <syscall.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
 #include <sys/ptrace.h>
 #include <sys/types.h>
 #include <sys/un.h>
+#include <syscall.h>
 #include <unistd.h>
 
 #include <limits>
@@ -51,24 +53,25 @@
 using android::base::unique_fd;
 using android::base::StringPrintf;
 
-static bool pid_contains_tid(pid_t pid, pid_t tid) {
-  std::string task_path = StringPrintf("/proc/%d/task/%d", pid, tid);
-  return access(task_path.c_str(), F_OK) == 0;
+static bool pid_contains_tid(int pid_proc_fd, pid_t tid) {
+  struct stat st;
+  std::string task_path = StringPrintf("task/%d", tid);
+  return fstatat(pid_proc_fd, task_path.c_str(), &st, 0) == 0;
 }
 
 // Attach to a thread, and verify that it's still a member of the given process
-static bool ptrace_seize_thread(pid_t pid, pid_t tid, std::string* error) {
+static bool ptrace_seize_thread(int pid_proc_fd, pid_t tid, std::string* error) {
   if (ptrace(PTRACE_SEIZE, tid, 0, 0) != 0) {
     *error = StringPrintf("failed to attach to thread %d: %s", tid, strerror(errno));
     return false;
   }
 
   // Make sure that the task we attached to is actually part of the pid we're dumping.
-  if (!pid_contains_tid(pid, tid)) {
+  if (!pid_contains_tid(pid_proc_fd, tid)) {
     if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
       PLOG(FATAL) << "failed to detach from thread " << tid;
     }
-    *error = StringPrintf("thread %d is not in process %d", tid, pid);
+    *error = StringPrintf("thread %d is not in process", tid);
     return false;
   }
 
@@ -190,6 +193,24 @@
   _exit(1);
 }
 
+static void drop_capabilities() {
+  __user_cap_header_struct capheader;
+  memset(&capheader, 0, sizeof(capheader));
+  capheader.version = _LINUX_CAPABILITY_VERSION_3;
+  capheader.pid = 0;
+
+  __user_cap_data_struct capdata[2];
+  memset(&capdata, 0, sizeof(capdata));
+
+  if (capset(&capheader, &capdata[0]) == -1) {
+    PLOG(FATAL) << "failed to drop capabilities";
+  }
+
+  if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) {
+    PLOG(FATAL) << "failed to set PR_SET_NO_NEW_PRIVS";
+  }
+}
+
 static void check_process(int proc_fd, pid_t expected_pid) {
   android::procinfo::ProcessInfo proc_info;
   if (!android::procinfo::GetProcessInfoFromProcPidFd(proc_fd, &proc_info)) {
@@ -263,7 +284,7 @@
   check_process(target_proc_fd, target);
 
   std::string attach_error;
-  if (!ptrace_seize_thread(target, main_tid, &attach_error)) {
+  if (!ptrace_seize_thread(target_proc_fd, main_tid, &attach_error)) {
     LOG(FATAL) << attach_error;
   }
 
@@ -304,6 +325,7 @@
   }
 
   int signo = siginfo.si_signo;
+  bool fatal_signal = signo != DEBUGGER_SIGNAL;
   bool backtrace = false;
   uintptr_t abort_address = 0;
 
@@ -319,17 +341,16 @@
 
   // Now that we have the signal that kicked things off, attach all of the
   // sibling threads, and then proceed.
-  bool fatal_signal = signo != DEBUGGER_SIGNAL;
-  std::set<pid_t> siblings;
   std::set<pid_t> attached_siblings;
-  if (fatal_signal || backtrace) {
+  {
+    std::set<pid_t> siblings;
     if (!android::procinfo::GetProcessTids(target, &siblings)) {
       PLOG(FATAL) << "failed to get process siblings";
     }
     siblings.erase(main_tid);
 
     for (pid_t sibling_tid : siblings) {
-      if (!ptrace_seize_thread(target, sibling_tid, &attach_error)) {
+      if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) {
         LOG(WARNING) << attach_error;
       } else {
         attached_siblings.insert(sibling_tid);
@@ -337,20 +358,29 @@
     }
   }
 
+  std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(main_tid));
+  if (!backtrace_map) {
+    LOG(FATAL) << "failed to create backtrace map";
+  }
+
+  // Collect the list of open files.
+  OpenFilesList open_files;
+  if (!backtrace) {
+    populate_open_files_list(target, &open_files);
+  }
+
+  // Drop our capabilities now that we've attached to the threads we care about.
+  drop_capabilities();
+
   check_process(target_proc_fd, target);
 
   // TODO: Use seccomp to lock ourselves down.
 
-  std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(main_tid));
   std::string amfd_data;
 
   if (backtrace) {
     dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, attached_siblings, 0);
   } else {
-    // Collect the list of open files.
-    OpenFilesList open_files;
-    populate_open_files_list(target, &open_files);
-
     engrave_tombstone(output_fd.get(), backtrace_map.get(), open_files, target, main_tid,
                       attached_siblings, abort_address, fatal_signal ? &amfd_data : nullptr);
   }
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index e7503e9..e22d6a9 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -40,10 +40,10 @@
 using android::base::unique_fd;
 
 #if defined(__LP64__)
-#define CRASHER_PATH  "/system/xbin/crasher64"
+#define CRASHER_PATH  "/system/bin/crasher64"
 #define ARCH_SUFFIX "64"
 #else
-#define CRASHER_PATH "/system/xbin/crasher"
+#define CRASHER_PATH "/system/bin/crasher"
 #define ARCH_SUFFIX ""
 #endif
 
@@ -192,7 +192,7 @@
   std::string type = "wait-" + crash_type;
   StartProcess([type]() {
     execl(CRASHER_PATH, CRASHER_PATH, type.c_str(), nullptr);
-    err(1, "exec failed");
+    exit(errno);
   });
 }
 
@@ -216,7 +216,9 @@
     FAIL() << "failed to wait for crasher: " << strerror(errno);
   }
 
-  if (!WIFSIGNALED(status)) {
+  if (WIFEXITED(status)) {
+    FAIL() << "crasher failed to exec: " << strerror(WEXITSTATUS(status));
+  } else if (!WIFSIGNALED(status)) {
     FAIL() << "crasher didn't terminate via a signal";
   }
   ASSERT_EQ(signo, WTERMSIG(status));
@@ -405,3 +407,35 @@
   });
   AssertDeath(SIGUSR1);
 }
+
+TEST(crash_dump, zombie) {
+  pid_t forkpid = fork();
+
+  int pipefd[2];
+  ASSERT_EQ(0, pipe2(pipefd, O_CLOEXEC));
+
+  pid_t rc;
+  int status;
+
+  if (forkpid == 0) {
+    errno = 0;
+    rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
+    if (rc != -1 || errno != ECHILD) {
+      errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
+    }
+
+    raise(DEBUGGER_SIGNAL);
+
+    errno = 0;
+    rc = waitpid(-1, &status, __WALL | __WNOTHREAD);
+    if (rc != -1 || errno != ECHILD) {
+      errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
+    }
+    _exit(0);
+  } else {
+    rc = waitpid(forkpid, &status, 0);
+    ASSERT_EQ(forkpid, rc);
+    ASSERT_TRUE(WIFEXITED(status));
+    ASSERT_EQ(0, WEXITSTATUS(status));
+  }
+}
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 9469bbd..353f642 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -39,6 +39,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/capability.h>
 #include <sys/mman.h>
 #include <sys/prctl.h>
 #include <sys/socket.h>
@@ -207,7 +208,7 @@
   }
 
   // Don't use fork(2) to avoid calling pthread_atfork handlers.
-  int forkpid = clone(nullptr, nullptr, SIGCHLD, nullptr);
+  int forkpid = clone(nullptr, nullptr, 0, nullptr);
   if (forkpid == -1) {
     __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to fork in debuggerd signal handler: %s",
                       strerror(errno));
@@ -216,6 +217,11 @@
     close(pipefds[0]);
     close(pipefds[1]);
 
+    // Set all of the ambient capability bits we can, so that crash_dump can ptrace us.
+    for (unsigned long i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) != -1; ++i) {
+      prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0);
+    }
+
     char buf[10];
     snprintf(buf, sizeof(buf), "%d", thread_info->crashing_tid);
     execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, buf, nullptr);
@@ -242,10 +248,12 @@
     close(pipefds[0]);
 
     // Don't leave a zombie child.
-    siginfo_t child_siginfo;
-    if (TEMP_FAILURE_RETRY(waitid(P_PID, forkpid, &child_siginfo, WEXITED)) != 0) {
+    int status;
+    if (TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0)) == -1) {
       __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s",
                         strerror(errno));
+    } else if (WIFSTOPPED(status) || WIFSIGNALED(status)) {
+      __libc_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper crashed or stopped");
       thread_info->crash_dump_started = false;
     }
   }
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e7f1a07..a4a0b52 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1303,6 +1303,36 @@
     return num;
 }
 
+static std::string fb_fix_numeric_var(std::string var) {
+    // Some bootloaders (angler, for example), send spurious leading whitespace.
+    var = android::base::Trim(var);
+    // Some bootloaders (hammerhead, for example) use implicit hex.
+    // This code used to use strtol with base 16.
+    if (!android::base::StartsWith(var, "0x")) var = "0x" + var;
+    return var;
+}
+
+static unsigned fb_get_flash_block_size(Transport* transport, std::string name) {
+    std::string sizeString;
+    if (!fb_getvar(transport, name.c_str(), &sizeString)) {
+        /* This device does not report flash block sizes, so return 0 */
+        return 0;
+    }
+    sizeString = fb_fix_numeric_var(sizeString);
+
+    unsigned size;
+    if (!android::base::ParseUint(sizeString, &size)) {
+        fprintf(stderr, "Couldn't parse %s '%s'.\n", name.c_str(), sizeString.c_str());
+        return 0;
+    }
+    if (size < 4096 || (size & (size - 1)) != 0) {
+        fprintf(stderr, "Invalid %s %u: must be a power of 2 and at least 4096.\n",
+                name.c_str(), size);
+        return 0;
+    }
+    return size;
+}
+
 static void fb_perform_format(Transport* transport,
                               const char* partition, int skip_if_not_supported,
                               const char* type_override, const char* size_override,
@@ -1345,11 +1375,7 @@
         }
         partition_size = size_override;
     }
-    // Some bootloaders (angler, for example), send spurious leading whitespace.
-    partition_size = android::base::Trim(partition_size);
-    // Some bootloaders (hammerhead, for example) use implicit hex.
-    // This code used to use strtol with base 16.
-    if (!android::base::StartsWith(partition_size, "0x")) partition_size = "0x" + partition_size;
+    partition_size = fb_fix_numeric_var(partition_size);
 
     gen = fs_get_generator(partition_type);
     if (!gen) {
@@ -1370,7 +1396,12 @@
     }
 
     fd = fileno(tmpfile());
-    if (fs_generator_generate(gen, fd, size, initial_dir)) {
+
+    unsigned eraseBlkSize, logicalBlkSize;
+    eraseBlkSize = fb_get_flash_block_size(transport, "erase-block-size");
+    logicalBlkSize = fb_get_flash_block_size(transport, "logical-block-size");
+
+    if (fs_generator_generate(gen, fd, size, initial_dir, eraseBlkSize, logicalBlkSize)) {
         fprintf(stderr, "Cannot generate image: %s\n", strerror(errno));
         close(fd);
         return;
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 9b73165..5d9ccfe 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -14,18 +14,21 @@
 #include <ext4_utils/make_ext4fs.h>
 #include <sparse/sparse.h>
 
-static int generate_ext4_image(int fd, long long partSize, const std::string& initial_dir)
+static int generate_ext4_image(int fd, long long partSize, const std::string& initial_dir,
+                                       unsigned eraseBlkSize, unsigned logicalBlkSize)
 {
     if (initial_dir.empty()) {
-        make_ext4fs_sparse_fd(fd, partSize, NULL, NULL);
+        make_ext4fs_sparse_fd_align(fd, partSize, NULL, NULL, eraseBlkSize, logicalBlkSize);
     } else {
-        make_ext4fs_sparse_fd_directory(fd, partSize, NULL, NULL, initial_dir.c_str());
+        make_ext4fs_sparse_fd_directory_align(fd, partSize, NULL, NULL, initial_dir.c_str(),
+                                              eraseBlkSize, logicalBlkSize);
     }
     return 0;
 }
 
 #ifdef USE_F2FS
-static int generate_f2fs_image(int fd, long long partSize, const std::string& initial_dir)
+static int generate_f2fs_image(int fd, long long partSize, const std::string& initial_dir,
+                               unsigned /* unused */, unsigned /* unused */)
 {
     if (!initial_dir.empty()) {
         fprintf(stderr, "Unable to set initial directory on F2FS filesystem\n");
@@ -39,7 +42,8 @@
     const char* fs_type;  //must match what fastboot reports for partition type
 
     //returns 0 or error value
-    int (*generate)(int fd, long long partSize, const std::string& initial_dir);
+    int (*generate)(int fd, long long partSize, const std::string& initial_dir,
+                    unsigned eraseBlkSize, unsigned logicalBlkSize);
 
 } generators[] = {
     { "ext4", generate_ext4_image},
@@ -58,7 +62,7 @@
 }
 
 int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize,
-    const std::string& initial_dir)
+    const std::string& initial_dir, unsigned eraseBlkSize, unsigned logicalBlkSize)
 {
-    return gen->generate(tmpFileNo, partSize, initial_dir);
+    return gen->generate(tmpFileNo, partSize, initial_dir, eraseBlkSize, logicalBlkSize);
 }
diff --git a/fastboot/fs.h b/fastboot/fs.h
index 0a68507..0a5f5a4 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -8,6 +8,6 @@
 
 const struct fs_generator* fs_get_generator(const std::string& fs_type);
 int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize,
-    const std::string& initial_dir);
+    const std::string& initial_dir, unsigned eraseBlkSize = 0, unsigned logicalBlkSize = 0);
 
 #endif
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 70140d8..dd08271 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -215,8 +215,8 @@
 
     // Reads digest.
     if (digest.size() != expected_digest_size) {
-        LERROR << "Unexpected digest size: " << digest.size() << " (expected: "
-               << expected_digest_size << ")";
+        LERROR << "Unexpected digest size: " << digest.size()
+               << " (expected: " << expected_digest_size << ")";
         return false;
     }
 
@@ -482,22 +482,6 @@
     return true;
 }
 
-static inline bool polling_vbmeta_blk_device(struct fstab *fstab)
-{
-    // It needs the block device symlink: fstab_rec->blk_device to read
-    // /vbmeta partition. However, the symlink created by ueventd might
-    // not be ready at this point. Use test_access() to poll it before
-    // trying to read the partition.
-    struct fstab_rec *fstab_entry =
-        fs_mgr_get_entry_for_mount_point(fstab, "/vbmeta");
-
-    // Makes sure /vbmeta block device is ready to access.
-    if (fs_mgr_test_access(fstab_entry->blk_device) < 0) {
-        return false;
-    }
-    return true;
-}
-
 static bool init_is_avb_used()
 {
     // When AVB is used, boot loader should set androidboot.vbmeta.{hash_alg,
@@ -529,11 +513,6 @@
 {
     FS_MGR_CHECK(fstab != nullptr);
 
-    if (!polling_vbmeta_blk_device(fstab)) {
-        LERROR << "Failed to find block device of /vbmeta";
-        return FS_MGR_SETUP_AVB_FAIL;
-    }
-
     // Gets the expected hash value of vbmeta images from
     // kernel cmdline.
     if (!load_vbmeta_prop(&fs_mgr_vbmeta_prop)) {
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
index 7683166..f96f124 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -66,7 +66,7 @@
         fs_mgr_get_entry_for_mount_point(fs_mgr_fstab, "/misc");
 
     if (fstab_entry == nullptr) {
-        LERROR << "Partition (" << partition << ") not found in fstab";
+        LERROR << "/misc mount point not found in fstab";
         return AVB_IO_RESULT_ERROR_IO;
     }
 
@@ -79,6 +79,13 @@
         path = by_name_prefix + partition_name;
     }
 
+    // Ensures the device path (a symlink created by init) is ready to
+    // access. fs_mgr_test_access() will test a few iterations if the
+    // path doesn't exist yet.
+    if (fs_mgr_test_access(path.c_str()) < 0) {
+        return AVB_IO_RESULT_ERROR_IO;
+    }
+
     android::base::unique_fd fd(
         TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
 
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 48ddf29..44789cc 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -34,7 +34,8 @@
     int max_comp_streams;
     unsigned int zram_size;
     uint64_t reserved_size;
-    unsigned int file_encryption_mode;
+    unsigned int file_contents_mode;
+    unsigned int file_names_mode;
     unsigned int erase_blk_size;
     unsigned int logical_blk_size;
 };
@@ -94,15 +95,51 @@
     { 0,                    0 },
 };
 
-#define EM_SOFTWARE 1
-#define EM_ICE      2
+#define EM_AES_256_XTS  1
+#define EM_ICE          2
+#define EM_AES_256_CTS  3
+#define EM_AES_256_HEH  4
 
-static struct flag_list encryption_modes[] = {
-    {"software", EM_SOFTWARE},
-    {"ice", EM_ICE},
-    {0, 0}
+static const struct flag_list file_contents_encryption_modes[] = {
+    {"aes-256-xts", EM_AES_256_XTS},
+    {"software", EM_AES_256_XTS}, /* alias for backwards compatibility */
+    {"ice", EM_ICE}, /* hardware-specific inline cryptographic engine */
+    {0, 0},
 };
 
+static const struct flag_list file_names_encryption_modes[] = {
+    {"aes-256-cts", EM_AES_256_CTS},
+    {"aes-256-heh", EM_AES_256_HEH},
+    {0, 0},
+};
+
+static unsigned int encryption_mode_to_flag(const struct flag_list *list,
+                                            const char *mode, const char *type)
+{
+    const struct flag_list *j;
+
+    for (j = list; j->name; ++j) {
+        if (!strcmp(mode, j->name)) {
+            return j->flag;
+        }
+    }
+    LERROR << "Unknown " << type << " encryption mode: " << mode;
+    return 0;
+}
+
+static const char *flag_to_encryption_mode(const struct flag_list *list,
+                                           unsigned int flag)
+{
+    const struct flag_list *j;
+
+    for (j = list; j->name; ++j) {
+        if (flag == j->flag) {
+            return j->name;
+        }
+    }
+    return nullptr;
+}
+
 static uint64_t calculate_zram_size(unsigned int percentage)
 {
     uint64_t total;
@@ -183,20 +220,28 @@
                      * location of the keys.  Get it and return it.
                      */
                     flag_vals->key_loc = strdup(strchr(p, '=') + 1);
-                    flag_vals->file_encryption_mode = EM_SOFTWARE;
+                    flag_vals->file_contents_mode = EM_AES_256_XTS;
+                    flag_vals->file_names_mode = EM_AES_256_CTS;
                 } else if ((fl[i].flag == MF_FILEENCRYPTION) && flag_vals) {
-                    /* The fileencryption flag is followed by an = and the
-                     * type of the encryption.  Get it and return it.
+                    /* The fileencryption flag is followed by an = and
+                     * the mode of contents encryption, then optionally a
+                     * : and the mode of filenames encryption (defaults
+                     * to aes-256-cts).  Get it and return it.
                      */
-                    const struct flag_list *j;
-                    const char *mode = strchr(p, '=') + 1;
-                    for (j = encryption_modes; j->name; ++j) {
-                        if (!strcmp(mode, j->name)) {
-                            flag_vals->file_encryption_mode = j->flag;
-                        }
+                    char *mode = strchr(p, '=') + 1;
+                    char *colon = strchr(mode, ':');
+                    if (colon) {
+                        *colon = '\0';
                     }
-                    if (flag_vals->file_encryption_mode == 0) {
-                        LERROR << "Unknown file encryption mode: " << mode;
+                    flag_vals->file_contents_mode =
+                        encryption_mode_to_flag(file_contents_encryption_modes,
+                                                mode, "file contents");
+                    if (colon) {
+                        flag_vals->file_names_mode =
+                            encryption_mode_to_flag(file_names_encryption_modes,
+                                                    colon + 1, "file names");
+                    } else {
+                        flag_vals->file_names_mode = EM_AES_256_CTS;
                     }
                 } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
                     /* The length flag is followed by an = and the
@@ -406,7 +451,8 @@
         fstab->recs[cnt].max_comp_streams = flag_vals.max_comp_streams;
         fstab->recs[cnt].zram_size = flag_vals.zram_size;
         fstab->recs[cnt].reserved_size = flag_vals.reserved_size;
-        fstab->recs[cnt].file_encryption_mode = flag_vals.file_encryption_mode;
+        fstab->recs[cnt].file_contents_mode = flag_vals.file_contents_mode;
+        fstab->recs[cnt].file_names_mode = flag_vals.file_names_mode;
         fstab->recs[cnt].erase_blk_size = flag_vals.erase_blk_size;
         fstab->recs[cnt].logical_blk_size = flag_vals.logical_blk_size;
         cnt++;
@@ -567,15 +613,14 @@
     return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
 }
 
-const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab)
+void fs_mgr_get_file_encryption_modes(const struct fstab_rec *fstab,
+                                      const char **contents_mode_ret,
+                                      const char **filenames_mode_ret)
 {
-    const struct flag_list *j;
-    for (j = encryption_modes; j->name; ++j) {
-        if (fstab->file_encryption_mode == j->flag) {
-            return j->name;
-        }
-    }
-    return NULL;
+    *contents_mode_ret = flag_to_encryption_mode(file_contents_encryption_modes,
+                                                 fstab->file_contents_mode);
+    *filenames_mode_ret = flag_to_encryption_mode(file_names_encryption_modes,
+                                                  fstab->file_names_mode);
 }
 
 int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab)
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index d959798..e8321b9 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -76,7 +76,8 @@
     int max_comp_streams;
     unsigned int zram_size;
     uint64_t reserved_size;
-    unsigned int file_encryption_mode;
+    unsigned int file_contents_mode;
+    unsigned int file_names_mode;
     unsigned int erase_blk_size;
     unsigned int logical_blk_size;
 };
@@ -118,7 +119,9 @@
 int fs_mgr_is_verified(const struct fstab_rec *fstab);
 int fs_mgr_is_encryptable(const struct fstab_rec *fstab);
 int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab);
-const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab);
+void fs_mgr_get_file_encryption_modes(const struct fstab_rec *fstab,
+                                      const char **contents_mode_ret,
+                                      const char **filenames_mode_ret);
 int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab);
 int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
 int fs_mgr_is_notrim(struct fstab_rec *fstab);
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 369a022..4007203 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -348,6 +348,7 @@
 
 status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
     status_t ret = BAD_VALUE;
+    std::string buf;
 
     val->valueInt64 = LONG_MIN;
 
@@ -400,6 +401,15 @@
         }
         break;
 
+    case BATTERY_PROP_BATTERY_STATUS:
+        if (mAlwaysPluggedDevice) {
+            val->valueInt64 = BATTERY_STATUS_CHARGING;
+        } else {
+            val->valueInt64 = getChargeStatus();
+        }
+        ret = NO_ERROR;
+        break;
+
     default:
         break;
     }
diff --git a/init/.clang-format b/init/.clang-format
new file mode 100644
index 0000000..48d423f
--- /dev/null
+++ b/init/.clang-format
@@ -0,0 +1,14 @@
+---
+Language:        Cpp
+BasedOnStyle:  Google
+BinPackArguments: true
+BinPackParameters: true
+ColumnLimit:     100
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+IndentWidth:     4
+Standard:        Auto
+TabWidth:        8
+UseTab:          Never
+DerivePointerAlignment: false
+PointerAlignment: Left
+...
diff --git a/init/Android.mk b/init/Android.mk
index 9e61fb2..f9c6f94 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -36,7 +36,7 @@
 LOCAL_SRC_FILES := \
     parser/tokenizer_test.cpp \
 
-LOCAL_STATIC_LIBRARIES := libinit_parser
+LOCAL_STATIC_LIBRARIES := libbase libinit_parser
 LOCAL_CLANG := true
 include $(BUILD_HOST_NATIVE_TEST)
 endif
@@ -134,3 +134,8 @@
 LOCAL_CLANG := true
 LOCAL_CPPFLAGS := -Wall -Wextra -Werror
 include $(BUILD_NATIVE_TEST)
+
+
+# Include targets in subdirs.
+# =========================================================
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/init/init.cpp b/init/init.cpp
index 43f601f..4af0656 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -40,6 +40,7 @@
 #include <selinux/label.h>
 #include <selinux/android.h>
 
+#include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
@@ -68,6 +69,7 @@
 #include "util.h"
 #include "watchdogd.h"
 
+using android::base::boot_clock;
 using android::base::StringPrintf;
 
 struct selabel_handle *sehandle;
@@ -750,7 +752,7 @@
         return watchdogd_main(argc, argv);
     }
 
-    boot_clock::time_point start_time = boot_clock::now();
+    boot_clock::time_point start_time = android::base::boot_clock::now();
 
     // Clear the umask.
     umask(0);
diff --git a/init/service.cpp b/init/service.cpp
index e186f27..cbdc4a8 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -32,6 +32,7 @@
 
 #include <selinux/selinux.h>
 
+#include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
@@ -47,6 +48,7 @@
 #include "property_service.h"
 #include "util.h"
 
+using android::base::boot_clock;
 using android::base::ParseInt;
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
diff --git a/init/service.h b/init/service.h
index 013e65f..3dc0e53 100644
--- a/init/service.h
+++ b/init/service.h
@@ -25,6 +25,8 @@
 #include <string>
 #include <vector>
 
+#include <android-base/chrono_utils.h>
+
 #include "action.h"
 #include "capabilities.h"
 #include "descriptors.h"
@@ -135,8 +137,8 @@
 
     unsigned flags_;
     pid_t pid_;
-    boot_clock::time_point time_started_; // time of last start
-    boot_clock::time_point time_crashed_; // first crash within inspection window
+    android::base::boot_clock::time_point time_started_; // time of last start
+    android::base::boot_clock::time_point time_crashed_; // first crash within inspection window
     int crash_count_;                     // number of times crashed within window
 
     uid_t uid_;
diff --git a/init/test_service/Android.mk b/init/test_service/Android.mk
new file mode 100644
index 0000000..30c9e9d
--- /dev/null
+++ b/init/test_service/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+# Sample service for testing.
+# =========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := test_service
+LOCAL_SRC_FILES := test_service.cpp
+
+LOCAL_SHARED_LIBRARIES += libbase
+
+LOCAL_INIT_RC := test_service.rc
+
+include $(BUILD_EXECUTABLE)
diff --git a/init/test_service/README.md b/init/test_service/README.md
new file mode 100644
index 0000000..6773235
--- /dev/null
+++ b/init/test_service/README.md
@@ -0,0 +1,43 @@
+# Sample service for testing
+This is a sample service that can be used for testing init.
+
+## Design
+The service includes a `.rc` file that allows starting it from init.
+
+    service test_service /system/bin/test_service CapAmb 0000000000003000
+        class main
+        user system
+        group system
+        capabilities NET_ADMIN NET_RAW
+        disabled
+        oneshot
+
+The service accepts any even number of arguments on the command line
+(i.e. any number of pairs of arguments.)
+It will attempt to find the first element of each pair of arguments in
+`/proc/self/status`, and attempt to exactly match the second element of the pair
+to the relevant line of `proc/self/status`.
+
+### Example
+In the above case, the service will look for lines containing `CapAmb`:
+
+    cat /proc/self/status
+    ...
+    CapAmb:	0000000000003000
+
+And then attempt to exactly match the token after `:`, `0000000000003000`,
+with the command-line argument.
+If they match, the service exits successfully. If not, the service will exit
+with an error.
+
+## Usage
+	mmma -j <jobs> system/core/init/testservice
+	adb root
+	adb remount
+	adb sync
+	adb reboot
+	adb root
+	adb shell start test_service
+	adb logcat -b all -d | grep test_service
+
+Look for an exit status of 0.
diff --git a/init/test_service/test_service.cpp b/init/test_service/test_service.cpp
new file mode 100644
index 0000000..e7206f8
--- /dev/null
+++ b/init/test_service/test_service.cpp
@@ -0,0 +1,78 @@
+// Copyright (C) 2016 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 <unistd.h>
+
+#include <map>
+#include <sstream>
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+void Usage(char* argv[]) {
+    printf("Usage: %s <status field> <value> [<status field> <value>]*\n", argv[0]);
+    printf("E.g.: $ %s Uid \"1000 1000 1000 1000\"\n", argv[0]);
+}
+
+int main(int argc, char* argv[]) {
+    if (argc < 3) {
+        Usage(argv);
+        LOG(FATAL) << "no status field requested";
+    }
+    if (argc % 2 == 0) {
+        // Since |argc| counts argv[0], if |argc| is odd, then the number of
+        // command-line arguments is even.
+        Usage(argv);
+        LOG(FATAL) << "need even number of command-line arguments";
+    }
+
+    std::string status;
+    bool res = android::base::ReadFileToString("/proc/self/status", &status, true);
+    if (!res) {
+        PLOG(FATAL) << "could not read /proc/self/status";
+    }
+
+    std::map<std::string, std::string> fields;
+    std::vector<std::string> lines = android::base::Split(status, "\n");
+    for (const auto& line : lines) {
+        std::vector<std::string> tokens = android::base::Split(line, ":");
+        if (tokens.size() >= 2) {
+            std::string field = tokens[0];
+            std::string value = android::base::Trim(tokens[1]);
+            if (field.length() > 0) {
+                fields[field] = value;
+            }
+        }
+    }
+
+    bool test_fails = false;
+    size_t uargc = static_cast<size_t>(argc);  // |argc| >= 3.
+    for (size_t i = 1; i < static_cast<size_t>(argc); i = i + 2) {
+        std::string expected_value = argv[i + 1];
+        auto f = fields.find(argv[i]);
+        if (f != fields.end()) {
+            if (f->second != expected_value) {
+                LOG(ERROR) << "field '" << argv[i] << "' expected '" << expected_value
+                           << "', actual '" << f->second << "'";
+                test_fails = true;
+            }
+        } else {
+            LOG(WARNING) << "could not find field '" << argv[i] << "'";
+        }
+    }
+
+    return test_fails ? 1 : 0;
+}
diff --git a/init/test_service/test_service.rc b/init/test_service/test_service.rc
new file mode 100644
index 0000000..91e1a0f
--- /dev/null
+++ b/init/test_service/test_service.rc
@@ -0,0 +1,7 @@
+service test_service /system/bin/test_service CapAmb 0000000000003000
+    class main
+    user system
+    group system
+    capabilities NET_ADMIN NET_RAW
+    disabled
+    oneshot
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 361b925..915afbd 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -60,9 +60,18 @@
     cb.func_log = selinux_klog_callback;
     selinux_set_callback(SELINUX_CB_LOG, cb);
 
-    std::string hardware = property_get("ro.hardware");
-
     ueventd_parse_config_file("/ueventd.rc");
+    ueventd_parse_config_file("/vendor/ueventd.rc");
+    ueventd_parse_config_file("/odm/ueventd.rc");
+
+    /*
+     * keep the current product name base configuration so
+     * we remain backwards compatible and allow it to override
+     * everything
+     * TODO: cleanup platform ueventd.rc to remove vendor specific
+     * device node entries (b/34968103)
+     */
+    std::string hardware = property_get("ro.hardware");
     ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware.c_str()).c_str());
 
     device_init();
diff --git a/init/util.cpp b/init/util.cpp
index 888a366..f59ba82 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -51,6 +51,8 @@
 #include "property_service.h"
 #include "util.h"
 
+using android::base::boot_clock;
+
 static unsigned int do_decode_uid(const char *s)
 {
     unsigned int v;
@@ -199,11 +201,16 @@
     return success;
 }
 
-boot_clock::time_point boot_clock::now() {
-  timespec ts;
-  clock_gettime(CLOCK_BOOTTIME, &ts);
-  return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) +
-                                std::chrono::nanoseconds(ts.tv_nsec));
+Timer::Timer() : start_(boot_clock::now()) {
+}
+
+double Timer::duration_s() const {
+  typedef std::chrono::duration<double> double_duration;
+  return std::chrono::duration_cast<double_duration>(boot_clock::now() - start_).count();
+}
+
+int64_t Timer::duration_ms() const {
+  return std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() - start_).count();
 }
 
 int mkdir_recursive(const char *pathname, mode_t mode)
diff --git a/init/util.h b/init/util.h
index 5c38dc3..4444427 100644
--- a/init/util.h
+++ b/init/util.h
@@ -25,6 +25,8 @@
 #include <ostream>
 #include <string>
 
+#include <android-base/chrono_utils.h>
+
 #define COLDBOOT_DONE "/dev/.coldboot_done"
 
 using namespace std::chrono_literals;
@@ -35,32 +37,16 @@
 bool read_file(const char* path, std::string* content);
 bool write_file(const char* path, const char* content);
 
-// A std::chrono clock based on CLOCK_BOOTTIME.
-class boot_clock {
- public:
-  typedef std::chrono::nanoseconds duration;
-  typedef std::chrono::time_point<boot_clock, duration> time_point;
-  static constexpr bool is_steady = true;
-
-  static time_point now();
-};
-
 class Timer {
  public:
-  Timer() : start_(boot_clock::now()) {
-  }
+  Timer();
 
-  double duration_s() const {
-    typedef std::chrono::duration<double> double_duration;
-    return std::chrono::duration_cast<double_duration>(boot_clock::now() - start_).count();
-  }
+  double duration_s() const;
 
-  int64_t duration_ms() const {
-    return std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() - start_).count();
-  }
+  int64_t duration_ms() const;
 
  private:
-  boot_clock::time_point start_;
+  android::base::boot_clock::time_point start_;
 };
 
 std::ostream& operator<<(std::ostream& os, const Timer& t);
diff --git a/libappfuse/tests/FuseBufferTest.cc b/libappfuse/tests/FuseBufferTest.cc
index db35d33..1a1abd5 100644
--- a/libappfuse/tests/FuseBufferTest.cc
+++ b/libappfuse/tests/FuseBufferTest.cc
@@ -31,7 +31,7 @@
 constexpr char kTempFile[] = "/data/local/tmp/appfuse_test_dump";
 
 void OpenTempFile(android::base::unique_fd* fd) {
-  fd->reset(open(kTempFile, O_CREAT | O_RDWR));
+  fd->reset(open(kTempFile, O_CREAT | O_RDWR, 0600));
   ASSERT_NE(-1, *fd) << strerror(errno);
   unlink(kTempFile);
   ASSERT_NE(-1, *fd) << strerror(errno);
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index 5e54328..0a2f5a3 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -21,6 +21,7 @@
 #include <dwarf.h>
 }
 
+#include <pthread.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
@@ -30,6 +31,7 @@
 #include <unistd.h>
 
 #include <memory>
+#include <mutex>
 #include <string>
 #include <vector>
 
@@ -90,9 +92,6 @@
       has_debug_frame(false), has_gnu_debugdata(false) { }
 };
 
-static std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>& g_debug_frames =
-    *new std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>;
-
 void Space::Clear() {
   start = 0;
   end = 0;
@@ -282,39 +281,14 @@
 
   // vaddr in the elf file.
   uint64_t ip_vaddr = ip - map.start + debug_frame->min_vaddr;
-  if (debug_frame->has_arm_exidx) {
-    auto& func_vaddrs = debug_frame->arm_exidx.func_vaddr_array;
-    if (ip_vaddr >= func_vaddrs[0] && ip_vaddr < debug_frame->text_end_vaddr) {
-      // Use binary search to find the correct function.
-      auto it = std::upper_bound(func_vaddrs.begin(), func_vaddrs.end(),
-                                 static_cast<uint32_t>(ip_vaddr));
-      if (it != func_vaddrs.begin()) {
-        --it;
-        // Found the exidx entry.
-        size_t index = it - func_vaddrs.begin();
 
-        proc_info->format = UNW_INFO_FORMAT_ARM_EXIDX;
-        proc_info->unwind_info = reinterpret_cast<void*>(
-            static_cast<uintptr_t>(index * sizeof(ArmIdxEntry) +
-                                   debug_frame->arm_exidx.exidx_vaddr +
-                                   debug_frame->min_vaddr));
-
-        // Prepare arm_exidx space and arm_extab space.
-        arm_exidx_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.exidx_vaddr;
-        arm_exidx_space_.end = arm_exidx_space_.start +
-            debug_frame->arm_exidx.exidx_data.size() * sizeof(ArmIdxEntry);
-        arm_exidx_space_.data = reinterpret_cast<const uint8_t*>(
-            debug_frame->arm_exidx.exidx_data.data());
-
-        arm_extab_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.extab_vaddr;
-        arm_extab_space_.end = arm_extab_space_.start +
-            debug_frame->arm_exidx.extab_data.size();
-        arm_extab_space_.data = debug_frame->arm_exidx.extab_data.data();
-        return true;
-      }
-    }
-  }
-
+  // The unwind info can come from .ARM.exidx or .eh_frame, or .debug_frame/.gnu_debugdata.
+  // First check .eh_frame/.debug_frame, then check .ARM.exidx. Because .eh_frame/.debug_frame has
+  // function range for each entry, by matching ip address with the function range, we know exactly
+  // whether the ip address hits an entry. But .ARM.exidx doesn't have function range for each
+  // entry, it thinks that an ip address hits an entry when (entry.addr <= ip < next_entry.addr).
+  // To prevent ip addresses hit in .eh_frame/.debug_frame being regarded as addresses hit in
+  // .ARM.exidx, we need to check .eh_frame/.debug_frame first.
   if (debug_frame->has_eh_frame) {
     if (ip_vaddr >= debug_frame->eh_frame.min_func_vaddr &&
         ip_vaddr < debug_frame->text_end_vaddr) {
@@ -323,7 +297,6 @@
       eh_frame_hdr_space_.end =
           eh_frame_hdr_space_.start + debug_frame->eh_frame.hdr_data.size();
       eh_frame_hdr_space_.data = debug_frame->eh_frame.hdr_data.data();
-
       eh_frame_space_.start = ip - ip_vaddr + debug_frame->eh_frame.vaddr;
       eh_frame_space_.end = eh_frame_space_.start + debug_frame->eh_frame.data.size();
       eh_frame_space_.data = debug_frame->eh_frame.data.data();
@@ -345,7 +318,6 @@
       }
     }
   }
-
   if (debug_frame->has_debug_frame || debug_frame->has_gnu_debugdata) {
     unw_dyn_info_t di;
     unw_word_t segbase = map.start - map.offset;
@@ -359,6 +331,40 @@
       }
     }
   }
+
+  if (debug_frame->has_arm_exidx) {
+    auto& func_vaddrs = debug_frame->arm_exidx.func_vaddr_array;
+    if (ip_vaddr >= func_vaddrs[0] && ip_vaddr < debug_frame->text_end_vaddr) {
+      // Use binary search to find the correct function.
+      auto it = std::upper_bound(func_vaddrs.begin(), func_vaddrs.end(),
+                                 static_cast<uint32_t>(ip_vaddr));
+      if (it != func_vaddrs.begin()) {
+        --it;
+        // Found the exidx entry.
+        size_t index = it - func_vaddrs.begin();
+        proc_info->start_ip = *it;
+        proc_info->format = UNW_INFO_FORMAT_ARM_EXIDX;
+        proc_info->unwind_info = reinterpret_cast<void*>(
+            static_cast<uintptr_t>(index * sizeof(ArmIdxEntry) +
+                                   debug_frame->arm_exidx.exidx_vaddr +
+                                   debug_frame->min_vaddr));
+        eh_frame_hdr_space_.Clear();
+        eh_frame_space_.Clear();
+        // Prepare arm_exidx space and arm_extab space.
+        arm_exidx_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.exidx_vaddr;
+        arm_exidx_space_.end = arm_exidx_space_.start +
+            debug_frame->arm_exidx.exidx_data.size() * sizeof(ArmIdxEntry);
+        arm_exidx_space_.data = reinterpret_cast<const uint8_t*>(
+            debug_frame->arm_exidx.exidx_data.data());
+
+        arm_extab_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.extab_vaddr;
+        arm_extab_space_.end = arm_extab_space_.start +
+            debug_frame->arm_exidx.extab_data.size();
+        arm_extab_space_.data = debug_frame->arm_exidx.extab_data.data();
+        return true;
+      }
+    }
+  }
   return false;
 }
 
@@ -549,18 +555,31 @@
   return "";
 }
 
+static std::mutex g_lock;
+static std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>* g_debug_frames = nullptr;
+
 static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename);
 
 DebugFrameInfo* BacktraceOffline::GetDebugFrameInFile(const std::string& filename) {
   if (cache_file_) {
-    auto it = g_debug_frames.find(filename);
-    if (it != g_debug_frames.end()) {
-      return it->second.get();
+    std::lock_guard<std::mutex> lock(g_lock);
+    if (g_debug_frames != nullptr) {
+      auto it = g_debug_frames->find(filename);
+      if (it != g_debug_frames->end()) {
+        return it->second.get();
+      }
     }
   }
   DebugFrameInfo* debug_frame = ReadDebugFrameFromFile(filename);
   if (cache_file_) {
-      g_debug_frames.emplace(filename, std::unique_ptr<DebugFrameInfo>(debug_frame));
+    std::lock_guard<std::mutex> lock(g_lock);
+    if (g_debug_frames == nullptr) {
+      g_debug_frames = new std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>;
+    }
+    auto pair = g_debug_frames->emplace(filename, std::unique_ptr<DebugFrameInfo>(debug_frame));
+    if (!pair.second) {
+      debug_frame = pair.first->second.get();
+    }
   }
   return debug_frame;
 }
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 49fcb29..465b3f9 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -220,25 +220,7 @@
 #endif
 }
 
-static void BacktraceOfflineTest(const std::string& testlib_name) {
-  const std::string arch = GetArch();
-  if (arch.empty()) {
-    GTEST_LOG_(INFO) << "This test does nothing on current arch.";
-    return;
-  }
-  const std::string offline_testdata_path = "testdata/" + arch + "/offline_testdata";
-  std::string testdata;
-  ASSERT_TRUE(android::base::ReadFileToString(offline_testdata_path, &testdata));
-
-  const std::string testlib_path = "testdata/" + arch + "/" + testlib_name;
-  struct stat st;
-  if (stat(testlib_path.c_str(), &st) == -1) {
-    GTEST_LOG_(INFO) << "This test is skipped as " << testlib_path << " doesn't exist.";
-    return;
-  }
-
-  // Parse offline_testdata.
-  std::vector<std::string> lines = android::base::Split(testdata, "\n");
+struct OfflineTestData {
   int pid;
   int tid;
   std::vector<backtrace_map_t> maps;
@@ -246,63 +228,93 @@
   backtrace_stackinfo_t stack_info;
   std::vector<uint8_t> stack;
   std::vector<FunctionSymbol> symbols;
+};
+
+bool ReadOfflineTestData(const std::string offline_testdata_path, OfflineTestData* testdata) {
+  std::string s;
+  if (!android::base::ReadFileToString(offline_testdata_path, &s)) {
+    return false;
+  }
+  // Parse offline_testdata.
+  std::vector<std::string> lines = android::base::Split(s, "\n");
+  memset(&testdata->unw_context, 0, sizeof(testdata->unw_context));
   for (const auto& line : lines) {
     if (android::base::StartsWith(line, "pid:")) {
-      sscanf(line.c_str(), "pid: %d tid: %d", &pid, &tid);
+      sscanf(line.c_str(), "pid: %d tid: %d", &testdata->pid, &testdata->tid);
     } else if (android::base::StartsWith(line, "map:")) {
-      maps.resize(maps.size() + 1);
+      testdata->maps.resize(testdata->maps.size() + 1);
+      backtrace_map_t& map = testdata->maps.back();
       int pos;
       sscanf(line.c_str(),
              "map: start: %" SCNxPTR " end: %" SCNxPTR " offset: %" SCNxPTR
              " load_base: %" SCNxPTR " flags: %d name: %n",
-             &maps.back().start, &maps.back().end, &maps.back().offset,
-             &maps.back().load_base, &maps.back().flags, &pos);
-      maps.back().name = android::base::Trim(line.substr(pos));
+             &map.start, &map.end, &map.offset, &map.load_base, &map.flags, &pos);
+      map.name = android::base::Trim(line.substr(pos));
     } else if (android::base::StartsWith(line, "registers:")) {
       size_t size;
       int pos;
       sscanf(line.c_str(), "registers: %zu %n", &size, &pos);
-      ASSERT_EQ(sizeof(unw_context), size);
-      HexStringToRawData(&line[pos], &unw_context, size);
+      if (sizeof(testdata->unw_context) != size) {
+        return false;
+      }
+      HexStringToRawData(&line[pos], &testdata->unw_context, size);
     } else if (android::base::StartsWith(line, "stack:")) {
       size_t size;
       int pos;
       sscanf(line.c_str(),
              "stack: start: %" SCNx64 " end: %" SCNx64 " size: %zu %n",
-             &stack_info.start, &stack_info.end, &size, &pos);
-      stack.resize(size);
-      HexStringToRawData(&line[pos], &stack[0], size);
-      stack_info.data = stack.data();
+             &testdata->stack_info.start, &testdata->stack_info.end, &size, &pos);
+      testdata->stack.resize(size);
+      HexStringToRawData(&line[pos], &testdata->stack[0], size);
+      testdata->stack_info.data = testdata->stack.data();
     } else if (android::base::StartsWith(line, "function:")) {
-      symbols.resize(symbols.size() + 1);
+      testdata->symbols.resize(testdata->symbols.size() + 1);
+      FunctionSymbol& symbol = testdata->symbols.back();
       int pos;
       sscanf(line.c_str(),
              "function: start: %" SCNxPTR " end: %" SCNxPTR " name: %n",
-             &symbols.back().start, &symbols.back().end,
-             &pos);
-      symbols.back().name = line.substr(pos);
+             &symbol.start, &symbol.end, &pos);
+      symbol.name = line.substr(pos);
     }
   }
+  return true;
+}
+
+static void BacktraceOfflineTest(const std::string& testlib_name) {
+  const std::string arch = GetArch();
+  if (arch.empty()) {
+    GTEST_LOG_(INFO) << "This test does nothing on current arch.";
+    return;
+  }
+  const std::string testlib_path = "testdata/" + arch + "/" + testlib_name;
+  struct stat st;
+  if (stat(testlib_path.c_str(), &st) == -1) {
+    GTEST_LOG_(INFO) << "This test is skipped as " << testlib_path << " doesn't exist.";
+    return;
+  }
+
+  const std::string offline_testdata_path = "testdata/" + arch + "/offline_testdata";
+  OfflineTestData testdata;
+  ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
 
   // Fix path of libbacktrace_testlib.so.
-  for (auto& map : maps) {
+  for (auto& map : testdata.maps) {
     if (map.name.find("libbacktrace_test.so") != std::string::npos) {
       map.name = testlib_path;
     }
   }
 
   // Do offline backtrace.
-  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid, maps));
+  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(testdata.pid, testdata.maps));
   ASSERT_TRUE(map != nullptr);
 
   std::unique_ptr<Backtrace> backtrace(
-      Backtrace::CreateOffline(pid, tid, map.get(), stack_info));
+      Backtrace::CreateOffline(testdata.pid, testdata.tid, map.get(), testdata.stack_info));
   ASSERT_TRUE(backtrace != nullptr);
 
-  ucontext_t ucontext = GetUContextFromUnwContext(unw_context);
+  ucontext_t ucontext = GetUContextFromUnwContext(testdata.unw_context);
   ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
 
-
   // Collect pc values of the call stack frames.
   std::vector<uintptr_t> pc_values;
   for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
@@ -311,17 +323,20 @@
 
   size_t test_one_index = 0;
   for (size_t i = 0; i < pc_values.size(); ++i) {
-    if (FunctionNameForAddress(pc_values[i], symbols) == "test_level_one") {
+    if (FunctionNameForAddress(pc_values[i], testdata.symbols) == "test_level_one") {
       test_one_index = i;
       break;
     }
   }
 
   ASSERT_GE(test_one_index, 3u);
-  ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index], symbols));
-  ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1], symbols));
-  ASSERT_EQ("test_level_three", FunctionNameForAddress(pc_values[test_one_index - 2], symbols));
-  ASSERT_EQ("test_level_four", FunctionNameForAddress(pc_values[test_one_index - 3], symbols));
+  ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index], testdata.symbols));
+  ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1],
+                                                     testdata.symbols));
+  ASSERT_EQ("test_level_three", FunctionNameForAddress(pc_values[test_one_index - 2],
+                                                       testdata.symbols));
+  ASSERT_EQ("test_level_four", FunctionNameForAddress(pc_values[test_one_index - 3],
+                                                      testdata.symbols));
 }
 
 TEST(libbacktrace, offline_eh_frame) {
@@ -339,3 +354,47 @@
 TEST(libbacktrace, offline_arm_exidx) {
   BacktraceOfflineTest("libbacktrace_test_arm_exidx.so");
 }
+
+// This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx
+// overlap with each other, which appears in /system/lib/libart.so.
+TEST(libbacktrace, offline_unwind_mix_eh_frame_and_arm_exidx) {
+  const std::string arch = GetArch();
+  if (arch.empty() || arch != "arm") {
+    GTEST_LOG_(INFO) << "This test does nothing on current arch.";
+    return;
+  }
+  const std::string testlib_path = "testdata/" + arch + "/libart.so";
+  struct stat st;
+  ASSERT_EQ(0, stat(testlib_path.c_str(), &st)) << "can't find testlib " << testlib_path;
+
+  const std::string offline_testdata_path = "testdata/" + arch + "/offline_testdata_for_libart";
+  OfflineTestData testdata;
+  ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
+
+  // Fix path of /system/lib/libart.so.
+  for (auto& map : testdata.maps) {
+    if (map.name.find("libart.so") != std::string::npos) {
+      map.name = testlib_path;
+    }
+  }
+
+  // Do offline backtrace.
+  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(testdata.pid, testdata.maps));
+  ASSERT_TRUE(map != nullptr);
+
+  std::unique_ptr<Backtrace> backtrace(
+      Backtrace::CreateOffline(testdata.pid, testdata.tid, map.get(), testdata.stack_info));
+  ASSERT_TRUE(backtrace != nullptr);
+
+  ucontext_t ucontext = GetUContextFromUnwContext(testdata.unw_context);
+  ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
+
+  // The last frame is outside of libart.so
+  ASSERT_EQ(testdata.symbols.size() + 1, backtrace->NumFrames());
+  for (size_t i = 0; i + 1 < backtrace->NumFrames(); ++i) {
+    uintptr_t vaddr_in_file = backtrace->GetFrame(i)->pc - testdata.maps[0].start +
+        testdata.maps[0].load_base;
+    std::string name = FunctionNameForAddress(vaddr_in_file, testdata.symbols);
+    ASSERT_EQ(name, testdata.symbols[i].name);
+  }
+}
diff --git a/libbacktrace/testdata/arm/libart.so b/libbacktrace/testdata/arm/libart.so
new file mode 100644
index 0000000..bed8e35
--- /dev/null
+++ b/libbacktrace/testdata/arm/libart.so
Binary files differ
diff --git a/libbacktrace/testdata/arm/offline_testdata_for_libart b/libbacktrace/testdata/arm/offline_testdata_for_libart
new file mode 100644
index 0000000..63f6a07
--- /dev/null
+++ b/libbacktrace/testdata/arm/offline_testdata_for_libart
@@ -0,0 +1,10 @@
+pid: 32232 tid: 32233
+registers: 64 000000000000000000000000000000006473602451b3e2e700000000d82fd1ff5600000000908eec00000000d42dd1ff00000000c02dd1ff617171e9617171e9
+map: start: e9380000 end: e9766000 offset: 0 load_base: b000 flags: 5 name: /system/lib/libart.so
+stack: start: ffd12dc0 end: ffd16000 size: 12864 00000000000c5024070000000300000005070a0a0100000051b3e2e700000000d82fd1ff560000004c2ed1ff000000000000000081b771e9d82fd1ff000000004c2ed1ff0c2ed1ff40a8d27024bf76e900908eec000000000834d1ff0000000000000000000000000d000000050000000000000000000000080000000101d1ff44b8bfeb4b0000000000000000000000e8b8952400000000fc2ed1ff4fb3e2e7bc49ac6f00908eecb02ed1ffd82fd1ff040000008c908eec942fd1ffd5c141e9d82fd1ff4fb3e2e7542fd1ff336c68e940000000400000007030d1fff031d1ff00000000bc49ac6f5c30d1ff942fd1ff842fd1ffd82fd1ff00000000b8f1786f4fb3e2e7610d67e9d82fd1ff4fb3e2e77880adeb7980adeb7a80adeb7b80adeb7c80adeb7d80adeb7e80adeb7f80adeb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007430d1ff02000000e8b89524e8d895240200000000908eec5c30d1ffbc49ac6f4fb3e2e74030d1ffe8d8952400000000b8f1786fbc49ac6f332367e94fb3e2e701000000637171e9637171e9000000005c30d1ff8430d1ffe0c08bec882fd1ff4fb3e2e70200000004000000942fd1ffe8b8952400908eec58d8952458d895247fbd69e90500000000400fe40100000000908eec58d89524060000009c86bd6f6b876fe900908eece0c08bec00008eec0000000000000000000000000000000044b8bfeb4b000000009be86f040000000038d1ff01000000c8e7446f060000000000000000908eec30d89524e8b895249c86bd6f7893476f00908eec00000000358c6fe970400fe4116e71e9a0285a6fa4d49c6f4489bd6f30d8952458d89524e8d8952400908eeca431d1ff2c31d1ffb75861e90100000000908eec30528bec409181e958d8952431abed6fac33576fb438d1ff030000007800502400000000a0005024060000007893476f00908eec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004489bd6f78005024d00c5024a0005024a431d1ff2c31d1ff9b99aa71a4d49c6f30d8952400000000e8d895244489bd6fa8e5bc6fc8b895240100000000000000b033d1ff56000000637171e900000000d00c5024c8b89524000000000100000000000000b033d1ff560000006431d1ffa431d1ff000000009fb671e9b033d1ff00000000a431d1ff6431d1ffc431d1ff000000000000000081b771e9b033d1ff00000000c431d1ff8431d1ff01000000020000002429000001000000dc501b002033d1ff0100000018f9736f0100000000908eec58d8952440f180e9a8ec01245b215ce8a4d49c6f00908eec0832d1ffb033d1ff040000008c908eeca832d1ffabc141e9b033d1ff5b215ce82832d1ffb033d1ff080000008c908eec000000000035d1ff0834d1ffa832d1ffa4d49c6f04000000cca312e800908eec6832d1ffb033d1ff0834d1ff6bc354e9b033d1ff5b215ce8cca312e800908eec8832d1ffb033d1ff0834d1ff6bc354e900908eeca4d49c6f44b8bfeb1833d1ff000000006832d1ffb033d1ff478054e9b033d1ff1b8054e90834d1ffa4d49c6f0000000000000000000000000000000008000000000000000834d1ff0000000000000000000000000000000000000000000000000000000058d895240000000000000000000000000000000000000000000000000000000058d89524b17e54e98c56af6f00000000a4d49c6f288944e800908eec00000000d032d1ff0000000000000000000000000000000000000000000000007e8ea6c358a58cec00f580e90834d1ffa4d49c6f58d8952400908eecb033d1ffe9100000da8844e8833c70e9e9100000b033d1ff0200000058d8952408b1796f0200000000908eecda8844e82c34d1ff00908eece9100000005d70e9070000007d1300006034d1ff98d170e9b033d1ff0834d1ff148844e800908eecb033d1ffa034d1ffa833d1ff0100000044b8bfeb41f252e9e91fdeeaa491deea000000004700000001000000d9c4ddea0000000000000000b834d1ff00b051ff0834d1ff00908eecf833d1ffa034d1ff148844e800000000020000004d4c53e900000000000000000000000000908eec44b8bfeb0834d1ff3835d1ff148844e85035d1ffbb936fe90000000044b8bfebb033d1ffda8844e8148844e8000000000d0000005a0000007d137d13d00c502400000000600480240400000070048024f80c5024170000000100000002000000000000000040000000000000d0018024d00c502400000000600480240000000070048024f80c5024000000000000000000000000000000000000000000000000d001802465906fe97b2e5ce8000000000300000000000000881388131a00000001000000000000004cdd76e9010000007b2e5ce8020000009835d1ff5835d1ffc435d1ff010000000000000000000000010000000000000000dd76e90834d1ff0d0000000100000000000000000000005035d1ff9036d1ff00000000a435d1ff7e8ea6c3080000000000000000000000000000000000000038cb7e7044b8bfeb7d2e5ce800000000c037d1ff5600000000908eec00000000cc35d1ff55af71e9e0285a6f040000000800000001000000a437d1ff010000001c73d870000000000000000043000000339768e9040000006c36d1ff0e000000b436d1ff8cc97e706c36d1ff0e00000018eb01243173d870040000007d2e5ce800000000c037d1ff5600000000000000cc35d1ff637171e90000000018eb012402000000010000007d2e5ce800000000c037d1ff560000004436d1ff000000000000000081b771e9c037d1ff000000004436d1ff0436d1ff00e68dec0800000001000000a437d1ff010000001c73d870000000000000000043000000339768e9040000006c36d1ff0e000000b436d1ff8cc97e706c36d1ff0e000000adf861e918eb01243173d870040000007b2e5ce844b8bfeb00908eeca836d1ffc037d1ff040000008c908eec7c37d1ffd5c141e9c037d1ff7b2e5ce80000000000908eecd036d1ff00000000b038d1ff183ad1ff0000000044b8bfeb1038d1ff7c37d1ff6c37d1ffc037d1ff7b2e5ce8000000007b2e5ce8610d67e9c037d1ff7b2e5ce8280477e99835456f960300009a35456f10aa5e6f9a35456f9835456f68b85e6f881e77e9b30a47e9e81382e94c95b4ec7100000000908eec9c908eec30528bec1038d1ff7b2e5ce800000000c78469e91038d1ff0aeb3b52208989ec150645e9010000001038d1ff6c37d1ff44b8bfeb6c37d1ff00000000d837d1ff1038d1ff7b2e5ce8000000006c38d1ff8f0b67e97b2e5ce818eb012400000000000000000838d1ff7b2e5ce802000000040000007c37d1ff18eb01249835456f00000000901e77e9180000000300000000908eec480000004800000043000000640477e97669747954687265070000001a00000060eb0124000000000000000000000000a500000044b8bfeb1038d1ff00908eeceeac73e943000000640477e9901e77e9e6ac73e961705ce96c38d1ff18eb012400908eeceeac73e943000000640477e9000059008bc95ce900908eec30528bec409181e900908eec430000005900000000528bec409181e900004300710000000300000030528bec89c75ce944b8bfebe2050000103dd1ff03000000a3f6a7eb89c75ce96c38d1ff7e8ea6c389c75ce997f5a7eb710000000000000030528bec7e8ea6c3e83cd1ff2079002488beba6ff0ca726f5600000000908eec000000005439d1ff8b1db8aa803a89ec7e8ea6c3000000009173d870ec55af6f00000000010000004892796f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003801802488beba6ff0ca726f56000000000000005439d1ff9d3daa71cc55af6f7039d1ff0b0000006839d1ff7d2e5ce800000000483bd1ff637171e900000000207900240b00000058a58cec40f180e9010000007d2e5ce800000000483bd1ff56000000cc39d1ff000000000000000081b771e9483bd1ff00000000cc39d1ff8c39d1ff05000000050000000c000000040000000100000012000000958c00000100000074d73500483bd1ff01000000e880746f0100000000908eec903ad1ff40f180e97e02000000908eec2079002400000000383ad1ff7b2e5ce8cc55af6f00908eec303ad1ff483bd1ff040000008c908eec043bd1ffd5c141e9483bd1ff7b2e5ce840f180e900908eec583ad1ff00000000000000000000000000000000cc55af6f983bd1ff043bd1fff43ad1ff483bd1ff7b2e5ce8000000007b2e5ce8610d67e9483bd1ff7b2e5ce8280477e94892796f860100004e92796f00a088ec4e92796f4892796f18a688ec881e77e9b30a47e978e388ec4c95b4ec2100000000908eec9c908eec30528bec983bd1ff7b2e5ce800000000c78469e9983bd1ff06b005fdf0298aec150645e901000000983bd1fff43ad1ffcc55af6ff43ad1ff00000000603bd1ff983bd1ff7b2e5ce800000000f43bd1ff8f0b67e97b2e5ce8e00864e80000000000000000903bd1ff7b2e5ce80200000004000000043bd1ff207900249c908eec04000000583bd1ff603bd1ff4892796f04000000ac3bd1ff01000000901e77e917885ee9010000004d5cb1eb485cb1eb00908eec4892796f00000000000000000000000000004300cc55af6f983bd1ff00908eeceeac73e943000000640477e9901e77e9e6ac73e961705ce9f43bd1ff55000000ac3bd1ffeeac73e943000000640477e900005900e3225ce900908eec30528bec409181e900908eec430000005900000000528bec409181e9000043005500000078e388ec2100000009215ce901000000ce3fb8aae83cd1ff40420f00a3f6a7eb09215ce9f43bd1ff7e8ea6c309215ce9ed0ea8eb2100000075270000003289ec0000000030528becef665c74db0e42e911ac58e99daf58e9103dd1ff010000007e8ea6c31b000000385cd1ff385cd1ff02000000103dd1ff0300000087e26deae43cd1ff0200000001000000a31eb8aa020000007c3cd1ff18ac89ec1dac89ec0f000000fc94b4ec7c3cd1ff18ac89ec7e8ea6c3e83cd1ff884dd1ff741ab8aaa81ab8aa000000000700000004000000e43cd1ff3b19b8aa000000000000000000000000000000000000000000000000884dd1ff0000000001000000844dd1ff7e8ea6c3f065b4ec00fd0000205db8aa308789ec010000000000000004000000b8e78aec18ac89ec005db8aa2ceab2eb101082e935000000000000000800000001100000ba5bd1ff99000000b8e78aec205db8aa508789ec030000000000000004000000e2050000108789ec00000000d991aeece583aeec10d0acec10d0acec50d0acec6170705f70726f63657373333200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080a4ec00000000001000009dfe6feb00000000975673eb000000002516b8aa844dd1ff08000000a84dd1ff0000000000000000000000007c4dd1ff3b996feb00000000000000000000000000000000000000005015b8aad45cb8aadc5cb8aae85cb8aa804dd1ff0000000015b8aeec08000000ba5bd1ffd45bd1ffe05bd1ffee5bd1ff0f5cd1ff335cd1ff355cd1ff385cd1ff00000000535cd1ff6f5cd1ff825cd1ff9d5cd1ffbf5cd1ffd45cd1ffee5cd1ff015dd1ff1c5dd1ffe35ed1fffc5ed1ff465fd1ffc55fd1ff0000000010000000d6b0270006000000001000001100000064000000030000003400b8aa040000002000000005000000090000000700000000d0adec080000000000000009000000ec14b8aa0b000000752700000c000000752700000d000000752700000e000000752700001700000000000000190000007c4ed1ff1a0000001f0000001f000000de5fd1ff0f0000008c4ed1ff00000000000000000000000086da76325883c1a6b44d586d68c7843576386c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000636f6d2e6578616d706c652e7375646f67616d65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f3d2f73797374656d2f62696e2f6170705f70726f63657373333200414e44524f49445f444154413d2f6461746100444f574e4c4f41445f43414348453d2f646174612f636163686500414e44524f49445f534f434b45545f7a79676f74655f7365636f6e646172793d3900414e44524f49445f524f4f543d2f73797374656d00415345435f4d4f554e54504f494e543d2f6d6e742f6173656300414e44524f49445f424f4f544c4f474f3d3100414e44524f49445f4153534554533d2f73797374656d2f61707000424f4f54434c415353504154483d2f73797374656d2f6672616d65776f726b2f636f72652d6f6a2e6a61723a2f73797374656d2f6672616d65776f726b2f636f72652d6c69626172742e6a61723a2f73797374656d2f6672616d65776f726b2f636f6e7363727970742e6a61723a2f73797374656d2f6672616d65776f726b2f6f6b687474702e6a61723a2f73797374656d2f6672616d65776f726b2f6c65676163792d746573742e6a61723a2f73797374656d2f6672616d65776f726b2f626f756e6379636173746c652e6a61723a2f73797374656d2f6672616d65776f726b2f6578742e6a61723a2f73797374656d2f6672616d65776f726b2f6672616d65776f726b2e6a61723a2f73797374656d2f6672616d65776f726b2f74656c6570686f6e792d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f766f69702d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f696d732d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f6170616368652d786d6c2e6a61723a2f73797374656d2f6672616d65776f726b2f6f72672e6170616368652e687474702e6c65676163792e626f6f742e6a617200414e44524f49445f53544f524147453d2f73746f7261676500504154483d2f7362696e3a2f73797374656d2f7362696e3a2f73797374656d2f62696e3a2f73797374656d2f7862696e3a2f76656e646f722f62696e3a2f76656e646f722f7862696e0053595354454d534552564552434c415353504154483d2f73797374656d2f6672616d65776f726b2f73657276696365732e6a61723a2f73797374656d2f6672616d65776f726b2f65746865726e65742d736572766963652e6a61723a2f73797374656d2f6672616d65776f726b2f776966692d736572766963652e6a61720045585445524e414c5f53544f524147453d2f736463617264002f73797374656d2f62696e2f6170705f70726f636573733332000000000000000000
+function: start: 3a2121 end: 3a217a name: art_quick_invoke_stub_internal
+function: start: 3a66a5 end: 3a6787 name: art_quick_invoke_static_stub
+function: start: a7129 end: a72f1 name: art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)
+function: start: 2fbd35 end: 2fc789 name: art::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::ArgArray*, art::JValue*, char const*)
+function: start: 2fcf75 end: 2fd88d name: art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned int)
+function: start: 2a089d end: 2a08bb name: art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobject*)
\ No newline at end of file
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 3d686ce..394a897 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -166,7 +166,7 @@
     /* Support wifi_hal_legacy administering a network interface. */
     { 00755, AID_WIFI,      AID_WIFI,      CAP_MASK_LONG(CAP_NET_ADMIN) |
                                            CAP_MASK_LONG(CAP_NET_RAW),
-                                              "system/bin/hw/android.hardware.wifi@1.0-service" },
+                                              "vendor/bin/hw/android.hardware.wifi@1.0-service" },
 
     /* Support Bluetooth legacy hal accessing /sys/class/rfkill */
     { 00700, AID_BLUETOOTH, AID_BLUETOOTH, CAP_MASK_LONG(CAP_NET_ADMIN),
@@ -182,11 +182,8 @@
                                            CAP_MASK_LONG(CAP_SETPCAP),
                                               "system/bin/webview_zygote64" },
 
-    { 00755, AID_ROOT,      AID_SHELL,     CAP_MASK_LONG(CAP_SYS_PTRACE),
-                                              "system/bin/crash_dump32" },
-    { 00755, AID_ROOT,      AID_SHELL,     CAP_MASK_LONG(CAP_SYS_PTRACE),
-                                              "system/bin/crash_dump64" },
-
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/crash_dump32" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/crash_dump64" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/debuggerd" },
     { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/uncrypt" },
     { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/install-recovery.sh" },
diff --git a/libcutils/include/cutils/android_reboot.h b/libcutils/include/cutils/android_reboot.h
index 1bbb9b9..2e3b429 100644
--- a/libcutils/include/cutils/android_reboot.h
+++ b/libcutils/include/cutils/android_reboot.h
@@ -31,7 +31,7 @@
 #define ANDROID_RB_PROPERTY "sys.powerctl"
 
 /* Android reboot reason stored in this file */
-#define LAST_REBOOT_REASON_FILE "/data/misc/recovery/last_reboot_reason"
+#define LAST_REBOOT_REASON_FILE "/data/misc/reboot/last_reboot_reason"
 
 int android_reboot(int cmd, int flags, const char *arg);
 int android_reboot_with_callback(
diff --git a/libcutils/include/cutils/properties.h b/libcutils/include/cutils/properties.h
index adf670b..b45f58f 100644
--- a/libcutils/include/cutils/properties.h
+++ b/libcutils/include/cutils/properties.h
@@ -43,7 +43,12 @@
 ** If the property read fails or returns an empty value, the default
 ** value is used (if nonnull).
 */
-int property_get(const char *key, char *value, const char *default_value);
+int property_get(const char *key, char *value, const char *default_value)
+/* Sometimes we use not-Bionic with this, so we need this check. */
+#if defined(__BIONIC_FORTIFY)
+        __overloadable __RENAME_CLANG(property_get)
+#endif
+        ;
 
 /* property_get_bool: returns the value of key coerced into a
 ** boolean. If the property is not set, then the default value is returned.
@@ -106,14 +111,40 @@
 /* property_set: returns 0 on success, < 0 on failure
 */
 int property_set(const char *key, const char *value);
-    
-int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);    
 
-#if defined(__BIONIC_FORTIFY) && !defined(__clang__)
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);
+
+#if defined(__BIONIC_FORTIFY)
+#define __property_get_err_str "property_get() called with too small of a buffer"
+
+#if defined(__clang__)
+
+/* Some projects use -Weverything; enable_if is clang-specific.
+** FIXME: This is marked used because we'll otherwise get complaints about an
+** unused static function. This is more robust than marking it unused, since
+** -Wused-but-marked-unused is a thing that will complain if this function is
+** actually used, thus making FORTIFY noisier when an error happens. It's going
+** to go away anyway during our FORTIFY cleanup.
+**/
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgcc-compat"
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+int property_get(const char *key, char *value, const char *default_value)
+        __overloadable
+        __enable_if(__bos(value) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+                    __bos(value) < PROPERTY_VALUE_MAX, __property_get_err_str)
+        __errorattr(__property_get_err_str)
+        __attribute__((used));
+#pragma clang diagnostic pop
+
+/* No object size? No FORTIFY.
+*/
+
+#else /* defined(__clang__) */
 
 extern int __property_get_real(const char *, char *, const char *)
     __asm__(__USER_LABEL_PREFIX__ "property_get");
-__errordecl(__property_get_too_small_error, "property_get() called with too small of a buffer");
+__errordecl(__property_get_too_small_error, __property_get_err_str);
 
 __BIONIC_FORTIFY_INLINE
 int property_get(const char *key, char *value, const char *default_value) {
@@ -124,7 +155,10 @@
     return __property_get_real(key, value, default_value);
 }
 
-#endif
+#endif /* defined(__clang__) */
+
+#undef __property_get_err_str
+#endif /* defined(__BIONIC_FORTIFY) */
 
 #ifdef __cplusplus
 }
diff --git a/libcutils/properties.cpp b/libcutils/properties.cpp
index 43ad574..d2645e6 100644
--- a/libcutils/properties.cpp
+++ b/libcutils/properties.cpp
@@ -129,7 +129,7 @@
     void* cookie;
 };
 
-static void trampoline(void* raw_data, const char* name, const char* value) {
+static void trampoline(void* raw_data, const char* name, const char* value, unsigned /*serial*/) {
     callback_data* data = reinterpret_cast<callback_data*>(raw_data);
     data->callback(name, value, data->cookie);
 }
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 747fcc8..310dbf4 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -15,13 +15,17 @@
 //
 
 liblog_sources = [
+    "config_read.c",
+    "config_write.c",
+    "local_logger.c",
     "log_event_list.c",
     "log_event_write.c",
-    "logger_write.c",
-    "config_write.c",
-    "logger_name.c",
-    "logger_lock.c",
     "log_ratelimit.cpp",
+    "logger_lock.c",
+    "logger_name.c",
+    "logger_read.c",
+    "logger_write.c",
+    "logprint.c",
 ]
 liblog_host_sources = [
     "fake_log_device.c",
@@ -29,15 +33,12 @@
 ]
 liblog_target_sources = [
     "event_tag_map.cpp",
-    "config_read.c",
     "log_time.cpp",
     "properties.c",
-    "logprint.c",
     "pmsg_reader.c",
     "pmsg_writer.c",
     "logd_reader.c",
     "logd_writer.c",
-    "logger_read.c",
 ]
 
 // Shared and static library for host and device
diff --git a/liblog/README b/liblog/README
index 610338c..40a39ad 100644
--- a/liblog/README
+++ b/liblog/README
@@ -108,6 +108,11 @@
 
        int android_log_destroy(android_log_context *ctx)
 
+       #include <log/log_frontend.h>
+
+       int android_set_log_frontend(int frontend_flag)
+       int android_get_log_frontend()
+
        Link with -llog
 
 DESCRIPTION
@@ -162,6 +167,13 @@
        when  opening  the  sub-log.    It  is  recommended  to  open  the  log
        ANDROID_LOG_RDONLY in these cases.
 
+       android_set_log_frontend() selects frontend filters. Argument is either
+       LOGGER_DEFAULT, LOGGER_LOGD, LOGGER_NULL or LOGGER_LOCAL. Log to logger
+       daemon for default or logd,  drop contents on floor,  or log into local
+       memory   respectively.          Both   android_set_log_frontend()   and
+       android_get_log_frontend()  return  the  current  frontend mask,   or a
+       negative errno for any problems.
+
 ERRORS
        If messages fail, a negative error code will be returned to the caller.
 
@@ -194,4 +206,4 @@
 
 
 
-                                  17 Oct 2016                        LIBLOG(3)
+                                  08 Feb 2017                        LIBLOG(3)
diff --git a/liblog/config_read.c b/liblog/config_read.c
index 1f54152..b9a281b 100644
--- a/liblog/config_read.c
+++ b/liblog/config_read.c
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <log/log_frontend.h>
+
 #include "config_read.h"
 #include "logger.h"
 
@@ -52,11 +54,35 @@
 }
 
 LIBLOG_HIDDEN void __android_log_config_read() {
-#if (FAKE_LOG_DEVICE == 0)
-    extern struct android_log_transport_read logdLoggerRead;
-    extern struct android_log_transport_read pmsgLoggerRead;
+    if (__android_log_frontend & LOGGER_LOCAL) {
+        extern struct android_log_transport_read localLoggerRead;
 
-    __android_log_add_transport(&__android_log_transport_read, &logdLoggerRead);
-    __android_log_add_transport(&__android_log_persist_read, &pmsgLoggerRead);
+        __android_log_add_transport(&__android_log_transport_read,
+                                    &localLoggerRead);
+    }
+
+#if (FAKE_LOG_DEVICE == 0)
+    if ((__android_log_frontend == LOGGER_DEFAULT) ||
+        (__android_log_frontend & LOGGER_LOGD)) {
+        extern struct android_log_transport_read logdLoggerRead;
+        extern struct android_log_transport_read pmsgLoggerRead;
+
+        __android_log_add_transport(&__android_log_transport_read,
+                                    &logdLoggerRead);
+        __android_log_add_transport(&__android_log_persist_read,
+                                    &pmsgLoggerRead);
+    }
 #endif
 }
+
+LIBLOG_HIDDEN void __android_log_config_read_close() {
+    struct android_log_transport_read *transport;
+    struct listnode *n;
+
+    read_transport_for_each_safe(transport, n, &__android_log_transport_read) {
+        list_remove(&transport->node);
+    }
+    read_transport_for_each_safe(transport, n, &__android_log_persist_read) {
+        list_remove(&transport->node);
+    }
+}
diff --git a/liblog/config_read.h b/liblog/config_read.h
index 49a3b75..892e80d 100644
--- a/liblog/config_read.h
+++ b/liblog/config_read.h
@@ -28,22 +28,31 @@
 
 #define read_transport_for_each(transp, transports)                         \
     for ((transp) = node_to_item((transports)->next,                        \
-                               struct android_log_transport_read, node);    \
-         ((transp) != node_to_item(transports,                              \
-                                 struct android_log_transport_read, node)); \
+                                 struct android_log_transport_read, node);  \
+         ((transp) != node_to_item((transports),                            \
+                                   struct android_log_transport_read,       \
+                                   node)) &&                                \
+         ((transp) != node_to_item((transp)->node.next,                     \
+                                   struct android_log_transport_read,       \
+                                   node));                                  \
          (transp) = node_to_item((transp)->node.next,                       \
-                               struct android_log_transport_read, node))    \
+                                 struct android_log_transport_read, node))
 
 #define read_transport_for_each_safe(transp, n, transports)                 \
     for ((transp) = node_to_item((transports)->next,                        \
-                               struct android_log_transport_read, node),    \
+                                 struct android_log_transport_read, node),  \
          (n) = (transp)->node.next;                                         \
-         ((transp) != node_to_item(transports,                              \
-                                 struct android_log_transport_read, node)); \
-         (transp) = node_to_item(n, struct android_log_transport_read, node), \
+         ((transp) != node_to_item((transports),                            \
+                                   struct android_log_transport_read,       \
+                                   node)) &&                                \
+         ((transp) != node_to_item((n), struct android_log_transport_read,  \
+                                   node));                                  \
+         (transp) = node_to_item((n), struct android_log_transport_read,    \
+                                 node),                                     \
          (n) = (transp)->node.next)
 
 LIBLOG_HIDDEN void __android_log_config_read();
+LIBLOG_HIDDEN void __android_log_config_read_close();
 
 __END_DECLS
 
diff --git a/liblog/config_write.c b/liblog/config_write.c
index d689f63..583dcff 100644
--- a/liblog/config_write.c
+++ b/liblog/config_write.c
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <log/log_frontend.h>
+
 #include "config_write.h"
 #include "logger.h"
 
@@ -52,15 +54,42 @@
 }
 
 LIBLOG_HIDDEN void __android_log_config_write() {
+    if (__android_log_frontend & LOGGER_LOCAL) {
+        extern struct android_log_transport_write localLoggerWrite;
+
+        __android_log_add_transport(&__android_log_transport_write,
+                                    &localLoggerWrite);
+    }
+
+    if ((__android_log_frontend == LOGGER_DEFAULT) ||
+        (__android_log_frontend & LOGGER_LOGD)) {
 #if (FAKE_LOG_DEVICE == 0)
-    extern struct android_log_transport_write logdLoggerWrite;
-    extern struct android_log_transport_write pmsgLoggerWrite;
+        extern struct android_log_transport_write logdLoggerWrite;
+        extern struct android_log_transport_write pmsgLoggerWrite;
 
-    __android_log_add_transport(&__android_log_transport_write, &logdLoggerWrite);
-    __android_log_add_transport(&__android_log_persist_write, &pmsgLoggerWrite);
+        __android_log_add_transport(&__android_log_transport_write,
+                                    &logdLoggerWrite);
+        __android_log_add_transport(&__android_log_persist_write,
+                                    &pmsgLoggerWrite);
 #else
-    extern struct android_log_transport_write fakeLoggerWrite;
+        extern struct android_log_transport_write fakeLoggerWrite;
 
-    __android_log_add_transport(&__android_log_transport_write, &fakeLoggerWrite);
+        __android_log_add_transport(&__android_log_transport_write,
+                                    &fakeLoggerWrite);
 #endif
+    }
+}
+
+LIBLOG_HIDDEN void __android_log_config_write_close() {
+    struct android_log_transport_write *transport;
+    struct listnode *n;
+
+    write_transport_for_each_safe(transport, n, &__android_log_transport_write) {
+        transport->logMask = 0;
+        list_remove(&transport->node);
+    }
+    write_transport_for_each_safe(transport, n, &__android_log_persist_write) {
+        transport->logMask = 0;
+        list_remove(&transport->node);
+    }
 }
diff --git a/liblog/config_write.h b/liblog/config_write.h
index 3b01a9a..8825411 100644
--- a/liblog/config_write.h
+++ b/liblog/config_write.h
@@ -29,21 +29,30 @@
 #define write_transport_for_each(transp, transports)                         \
     for ((transp) = node_to_item((transports)->next,                         \
                                  struct android_log_transport_write, node);  \
-         ((transp) != node_to_item(transports,                               \
-                                 struct android_log_transport_write, node)); \
+         ((transp) != node_to_item((transports),                             \
+                                   struct android_log_transport_write,       \
+                                   node)) &&                                 \
+         ((transp) != node_to_item((transp)->node.next,                      \
+                                   struct android_log_transport_write,       \
+                                   node));                                   \
          (transp) = node_to_item((transp)->node.next,                        \
-                                 struct android_log_transport_write, node))  \
+                                 struct android_log_transport_write, node))
 
 #define write_transport_for_each_safe(transp, n, transports)                 \
     for ((transp) = node_to_item((transports)->next,                         \
                                  struct android_log_transport_write, node),  \
          (n) = (transp)->node.next;                                          \
-         ((transp) != node_to_item(transports,                               \
-                                   struct android_log_transport_write, node)); \
-         (transp) = node_to_item(n, struct android_log_transport_write, node), \
+         ((transp) != node_to_item((transports),                             \
+                                   struct android_log_transport_write,       \
+                                   node)) &&                                 \
+         ((transp) != node_to_item((n), struct android_log_transport_write,  \
+                                   node));                                   \
+         (transp) = node_to_item((n), struct android_log_transport_write,    \
+                                 node),                                      \
          (n) = (transp)->node.next)
 
 LIBLOG_HIDDEN void __android_log_config_write();
+LIBLOG_HIDDEN void __android_log_config_write_close();
 
 __END_DECLS
 
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index 957129e..1d7a157 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -612,7 +612,12 @@
 
 bail:
     unlock();
-    return vector[0].iov_len + vector[1].iov_len + vector[2].iov_len;
+    int len = 0;
+    for (i = 0; i < count; ++i) {
+       len += vector[i].iov_len;
+    }
+    return len;
+
 error:
     unlock();
     return -1;
diff --git a/liblog/fake_writer.c b/liblog/fake_writer.c
index dab8bc5..2350673 100644
--- a/liblog/fake_writer.c
+++ b/liblog/fake_writer.c
@@ -46,9 +46,19 @@
     int i;
 
     for (i = 0; i < LOG_ID_MAX; i++) {
-        char buf[sizeof("/dev/log_security")];
+        /*
+         * Known maximum size string, plus an 8 character margin to deal with
+         * possible independent changes to android_log_id_to_name().
+         */
+        char buf[sizeof("/dev/log_security") + 8];
+        if (logFds[i] >= 0) {
+            continue;
+        }
         snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
         logFds[i] = fakeLogOpen(buf, O_WRONLY);
+        if (logFds[i] < 0) {
+            fprintf(stderr, "fakeLogOpen(%s, O_WRONLY) failed\n", buf);
+        }
     }
     return 0;
 }
@@ -66,16 +76,28 @@
                       struct iovec *vec, size_t nr)
 {
     ssize_t ret;
-    int logFd;
+    size_t i;
+    int logFd, len;
 
     if (/*(int)log_id >= 0 &&*/ (int)log_id >= (int)LOG_ID_MAX) {
-        return -EBADF;
+        return -EINVAL;
+    }
+
+    len = 0;
+    for (i = 0; i < nr; ++i) {
+        len += vec[i].iov_len;
+    }
+
+    if (len > LOGGER_ENTRY_MAX_PAYLOAD) {
+        len = LOGGER_ENTRY_MAX_PAYLOAD;
     }
 
     logFd = logFds[(int)log_id];
     ret = TEMP_FAILURE_RETRY(fakeLogWritev(logFd, vec, nr));
     if (ret < 0) {
         ret = -errno;
+    } else if (ret > len) {
+        ret = len;
     }
 
     return ret;
diff --git a/liblog/include/log/log_frontend.h b/liblog/include/log/log_frontend.h
new file mode 100644
index 0000000..9527779
--- /dev/null
+++ b/liblog/include/log/log_frontend.h
@@ -0,0 +1,34 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** This file is dual licensed.  It may be redistributed and/or modified
+** under the terms of the Apache 2.0 License OR version 2 of the GNU
+** General Public License.
+*/
+
+#ifndef _LIBS_LOG_FRONTEND_H
+#define _LIBS_LOG_FRONTEND_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Logging frontends, bit mask to select features. Function returns selection.
+ */
+#define LOGGER_DEFAULT 0x0
+#define LOGGER_LOGD    0x1
+#define LOGGER_KERNEL  0x2 /* Reserved/Deprecated */
+#define LOGGER_NULL    0x4 /* Does not release resources of other selections */
+#define LOGGER_LOCAL   0x8 /* logs sent to local memory */
+
+/* Both return the selected frontend flag mask, or negative errno */
+int android_set_log_frontend(int frontend_flag);
+int android_get_log_frontend();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_LOG_FRONTEND_H */
diff --git a/liblog/include/log/log_radio.h b/liblog/include/log/log_radio.h
index 30a73f2..430e522 100644
--- a/liblog/include/log/log_radio.h
+++ b/liblog/include/log/log_radio.h
@@ -38,6 +38,10 @@
 
 /* --------------------------------------------------------------------- */
 
+#ifndef __predict_false
+#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
+#endif
+
 /*
  * Simplified macro to send a verbose radio log message using current LOG_TAG.
  */
diff --git a/liblog/include/log/log_read.h b/liblog/include/log/log_read.h
index 5b5eebc..6a44b56 100644
--- a/liblog/include/log/log_read.h
+++ b/liblog/include/log/log_read.h
@@ -251,7 +251,11 @@
 #define ANDROID_LOG_WRONLY   O_WRONLY
 #define ANDROID_LOG_RDWR     O_RDWR
 #define ANDROID_LOG_ACCMODE  O_ACCMODE
+#ifndef O_NONBLOCK
+#define ANDROID_LOG_NONBLOCK 0x00000800
+#else
 #define ANDROID_LOG_NONBLOCK O_NONBLOCK
+#endif
 #if __ANDROID_USE_LIBLOG_READER_INTERFACE > 2
 #define ANDROID_LOG_WRAP     0x40000000 /* Block until buffer about to wrap */
 #define ANDROID_LOG_WRAP_DEFAULT_TIMEOUT 7200 /* 2 hour default */
diff --git a/liblog/include/log/log_system.h b/liblog/include/log/log_system.h
index 8c1ec96..394a106 100644
--- a/liblog/include/log/log_system.h
+++ b/liblog/include/log/log_system.h
@@ -36,6 +36,10 @@
 #endif
 #endif
 
+#ifndef __predict_false
+#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
+#endif
+
 /*
  * Simplified macro to send a verbose system log message using current LOG_TAG.
  */
diff --git a/liblog/local_logger.c b/liblog/local_logger.c
new file mode 100644
index 0000000..d504342
--- /dev/null
+++ b/liblog/local_logger.c
@@ -0,0 +1,556 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#if !defined(__MINGW32__)
+#include <pwd.h>
+#endif
+#include <sched.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <log/uio.h>
+
+#include <cutils/list.h> /* template, no library dependency */
+#include <log/log_frontend.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
+#include <system/thread_defs.h>
+
+#include "config_read.h"
+#include "config_write.h"
+#include "log_portability.h"
+#include "logger.h"
+
+static const char baseServiceName[] = "android.logd";
+
+static int writeToLocalInit();
+static int writeToLocalAvailable(log_id_t logId);
+static void writeToLocalReset();
+static int writeToLocalWrite(log_id_t logId, struct timespec *ts,
+                             struct iovec *vec, size_t nr);
+
+LIBLOG_HIDDEN struct android_log_transport_write localLoggerWrite = {
+    .node = { &localLoggerWrite.node, &localLoggerWrite.node },
+    .context.private = NULL,
+    .name = "local",
+    .available = writeToLocalAvailable,
+    .open = writeToLocalInit,
+    .close = writeToLocalReset,
+    .write = writeToLocalWrite,
+};
+
+static int writeToLocalVersion(struct android_log_logger *logger,
+                               struct android_log_transport_context *transp);
+static int writeToLocalRead(struct android_log_logger_list *logger_list,
+                            struct android_log_transport_context *transp,
+                            struct log_msg *log_msg);
+static int writeToLocalPoll(struct android_log_logger_list *logger_list,
+                            struct android_log_transport_context *transp);
+static void writeToLocalClose(struct android_log_logger_list *logger_list,
+                              struct android_log_transport_context *transp);
+static int writeToLocalClear(struct android_log_logger *logger,
+                             struct android_log_transport_context *transp);
+static ssize_t writeToLocalGetSize(
+        struct android_log_logger *logger,
+        struct android_log_transport_context *transp);
+static ssize_t writeToLocalSetSize(
+        struct android_log_logger *logger,
+        struct android_log_transport_context *transp __unused,
+        size_t size);
+static ssize_t writeToLocalGetReadbleSize(
+        struct android_log_logger *logger,
+        struct android_log_transport_context *transp);
+
+struct android_log_transport_read localLoggerRead = {
+    .node = { &localLoggerRead.node, &localLoggerRead.node },
+    .name = "local",
+    .available = writeToLocalAvailable,
+    .version = writeToLocalVersion,
+    .read = writeToLocalRead,
+    .poll = writeToLocalPoll,
+    .close = writeToLocalClose,
+    .clear = writeToLocalClear,
+    .getSize = writeToLocalGetSize,
+    .setSize = writeToLocalSetSize,
+    .getReadableSize = writeToLocalGetReadbleSize,
+    .getPrune = NULL,
+    .setPrune = NULL,
+    .getStats = NULL,
+};
+
+struct LogBufferElement {
+  struct listnode node;
+  log_id_t logId;
+  pid_t tid;
+  log_time timestamp;
+  unsigned short len;
+  char msg[];
+};
+
+static const size_t MAX_SIZE_DEFAULT = 32768;
+
+/*
+ * Number of log buffers we support with the following assumption:
+ *  . . .
+ *   LOG_ID_SECURITY = 5, // security logs go to the system logs only
+ *   LOG_ID_KERNEL = 6,   // place last, third-parties can not use it
+ *   LOG_ID_MAX
+ * } log_id_t;
+ *
+ * Confirm the following should <log/log_id.h> be adjusted in the future.
+ */
+#define NUMBER_OF_LOG_BUFFERS ((LOG_ID_SECURITY == (LOG_ID_MAX - 2)) ? \
+                                  LOG_ID_SECURITY : \
+                                  LOG_ID_KERNEL)
+#define BLOCK_LOG_BUFFERS(id) (((id) == LOG_ID_SECURITY) || \
+                               ((id) == LOG_ID_KERNEL))
+
+static struct LogBuffer {
+  struct listnode head;
+  pthread_rwlock_t listLock;
+  char *serviceName; /* Also indicates ready by having a value */
+  /* Order and proximity important for memset */
+  size_t number[NUMBER_OF_LOG_BUFFERS];         /* clear memset          */
+  size_t size[NUMBER_OF_LOG_BUFFERS];           /* clear memset          */
+  size_t totalSize[NUMBER_OF_LOG_BUFFERS];      /* init memset           */
+  size_t maxSize[NUMBER_OF_LOG_BUFFERS];        /* init MAX_SIZE_DEFAULT */
+  struct listnode *last[NUMBER_OF_LOG_BUFFERS]; /* init &head            */
+} logbuf = {
+  .head = { &logbuf.head, &logbuf.head },
+  .listLock = PTHREAD_RWLOCK_INITIALIZER,
+};
+
+static void LogBufferInit(struct LogBuffer *log) {
+  size_t i;
+
+  pthread_rwlock_wrlock(&log->listLock);
+  list_init(&log->head);
+  memset(log->number, 0,
+    sizeof(log->number) + sizeof(log->size) + sizeof(log->totalSize));
+  for (i = 0; i < NUMBER_OF_LOG_BUFFERS; ++i) {
+    log->maxSize[i] = MAX_SIZE_DEFAULT;
+    log->last[i] = &log->head;
+  }
+#ifdef __BIONIC__
+  asprintf(&log->serviceName, "%s@%d:%d", baseServiceName,
+           __android_log_uid(), getpid());
+#else
+  char buffer[sizeof(baseServiceName) + 1 + 5 + 1 + 5 + 8];
+  snprintf(buffer, sizeof(buffer), "%s@%d:%d", baseServiceName,
+                                   __android_log_uid(), getpid());
+  log->serviceName = strdup(buffer);
+#endif
+  pthread_rwlock_unlock(&log->listLock);
+}
+
+static void LogBufferClear(struct LogBuffer *log) {
+  size_t i;
+  struct listnode *node;
+
+  pthread_rwlock_wrlock(&log->listLock);
+  memset(log->number, 0, sizeof(log->number) + sizeof(log->size));
+  for (i = 0; i < NUMBER_OF_LOG_BUFFERS; ++i) {
+    log->last[i] = &log->head;
+  }
+  while ((node = list_head(&log->head)) != &log->head) {
+    struct LogBufferElement *element;
+
+    element = node_to_item(node, struct LogBufferElement, node);
+    list_remove(node);
+    free(element);
+  }
+  pthread_rwlock_unlock(&log->listLock);
+}
+
+static inline void LogBufferFree(struct LogBuffer *log) {
+  pthread_rwlock_wrlock(&log->listLock);
+  free(log->serviceName);
+  log->serviceName = NULL;
+  pthread_rwlock_unlock(&log->listLock);
+  LogBufferClear(log);
+}
+
+static int LogBufferLog(struct LogBuffer *log,
+                        struct LogBufferElement *element) {
+  log_id_t logId = element->logId;
+
+  pthread_rwlock_wrlock(&log->listLock);
+  log->number[logId]++;
+  log->size[logId] += element->len;
+  log->totalSize[logId] += element->len;
+  /* prune entry(s) until enough space is available */
+  if (log->last[logId] == &log->head) {
+    log->last[logId] = list_tail(&log->head);
+  }
+  while (log->size[logId] > log->maxSize[logId]) {
+    struct listnode *node = log->last[logId];
+    struct LogBufferElement *e;
+    struct android_log_logger_list *logger_list;
+
+    e = node_to_item(node, struct LogBufferElement, node);
+    log->number[logId]--;
+    log->size[logId] -= e->len;
+    logger_list_rdlock();
+    logger_list_for_each(logger_list) {
+      struct android_log_transport_context *transp;
+
+      transport_context_for_each(transp, logger_list) {
+        if ((transp->transport == &localLoggerRead) &&
+            (transp->context.node == node)) {
+          if (node == &log->head) {
+            transp->context.node = &log->head;
+          } else {
+            transp->context.node = node->next;
+          }
+        }
+      }
+    }
+    logger_list_unlock();
+    if (node != &log->head) {
+      log->last[logId] = node->prev;
+    }
+    list_remove(node);
+    free(e);
+  }
+  /* add entry to list */
+  list_add_head(&log->head, &element->node);
+  /* ToDo: wake up all readers */
+  pthread_rwlock_unlock(&log->listLock);
+
+  return element->len;
+}
+
+/*
+ * return zero if permitted to log directly to logd,
+ * return 1 if binder server started and
+ * return negative error number if failed to start binder server.
+ */
+static int writeToLocalInit() {
+  pthread_attr_t attr;
+  struct LogBuffer *log;
+
+  if (writeToLocalAvailable(LOG_ID_MAIN) < 0) {
+    return -EPERM;
+  }
+
+  log = &logbuf;
+  if (!log->serviceName) {
+      LogBufferInit(log);
+  }
+
+  if (!log->serviceName) {
+    LogBufferFree(log);
+    return -ENOMEM;
+  }
+
+  return EPERM; /* successful local-only logging */
+}
+
+static void writeToLocalReset() {
+  LogBufferFree(&logbuf);
+}
+
+static int writeToLocalAvailable(log_id_t logId) {
+#if !defined(__MINGW32__)
+  uid_t uid;
+#endif
+
+  if ((logId >= NUMBER_OF_LOG_BUFFERS) || BLOCK_LOG_BUFFERS(logId)) {
+    return -EINVAL;
+  }
+
+  /* Android hard coded permitted, system goes to logd */
+#if !defined(__MINGW32__)
+  if (__android_log_frontend == LOGGER_DEFAULT) {
+    uid = __android_log_uid();
+    if ((uid < AID_APP) && (getpwuid(uid) != NULL)) {
+      return -EPERM;
+    }
+  }
+#endif
+
+  /* ToDo: Ask package manager for LOGD permissions */
+  /* Assume we do _not_ have permissions to go to LOGD, so must go local */
+  return 0;
+}
+
+static int writeToLocalWrite(log_id_t logId, struct timespec *ts,
+                             struct iovec *vec, size_t nr) {
+  size_t len, i;
+  struct LogBufferElement *element;
+
+  if ((logId >= NUMBER_OF_LOG_BUFFERS) || BLOCK_LOG_BUFFERS(logId)) {
+    return -EINVAL;
+  }
+
+  len = 0;
+  for (i = 0; i < nr; ++i) {
+    len += vec[i].iov_len;
+  }
+
+  if (len > LOGGER_ENTRY_MAX_PAYLOAD) {
+    len = LOGGER_ENTRY_MAX_PAYLOAD;
+  }
+  element = (struct LogBufferElement *)calloc(1,
+      sizeof(struct LogBufferElement) + len + 1);
+  if (!element) {
+    return errno ? -errno : -ENOMEM;
+  }
+  element->timestamp.tv_sec = ts->tv_sec;
+  element->timestamp.tv_nsec = ts->tv_nsec;
+#ifdef __BIONIC__
+  element->tid = gettid();
+#else
+  element->tid = getpid();
+#endif
+  element->logId = logId;
+  element->len = len;
+
+  char *cp = element->msg;
+  for (i = 0; i < nr; ++i) {
+    size_t iov_len = vec[i].iov_len;
+    if (iov_len > len) {
+      iov_len = len;
+    }
+    memcpy(cp, vec[i].iov_base, iov_len);
+    len -= iov_len;
+    if (len == 0) {
+      break;
+    }
+    cp += iov_len;
+  }
+
+  return LogBufferLog(&logbuf, element);
+}
+
+static int writeToLocalVersion(
+        struct android_log_logger *logger __unused,
+        struct android_log_transport_context *transp __unused) {
+  return 3;
+}
+
+/* within reader lock, serviceName already validated */
+static struct listnode *writeToLocalNode(
+        struct android_log_logger_list *logger_list,
+        struct android_log_transport_context *transp) {
+  struct listnode *node;
+  unsigned logMask;
+  unsigned int tail;
+
+  node = transp->context.node;
+  if (node) {
+    return node;
+  }
+
+  if (!logger_list->tail) {
+    return transp->context.node = &logbuf.head;
+  }
+
+  logMask = transp->logMask;
+  tail = logger_list->tail;
+
+  for (node = list_head(&logbuf.head); node != &logbuf.head; node = node->next) {
+    struct LogBufferElement *element;
+    log_id_t logId;
+
+    element = node_to_item(node, struct LogBufferElement, node);
+    logId = element->logId;
+
+    if ((logMask & (1 << logId)) && !--tail) {
+      node = node->next;
+      break;
+    }
+  }
+  return transp->context.node = node;
+}
+
+static int writeToLocalRead(
+        struct android_log_logger_list *logger_list,
+        struct android_log_transport_context *transp,
+        struct log_msg *log_msg) {
+  int ret;
+  struct listnode *node;
+  unsigned logMask;
+
+  pthread_rwlock_rdlock(&logbuf.listLock);
+  if (!logbuf.serviceName) {
+    pthread_rwlock_unlock(&logbuf.listLock);
+    return (logger_list->mode & ANDROID_LOG_NONBLOCK) ? -ENODEV : 0;
+  }
+
+  logMask = transp->logMask;
+
+  node = writeToLocalNode(logger_list, transp);
+
+  ret = 0;
+
+  while (node != list_head(&logbuf.head)) {
+    struct LogBufferElement *element;
+    log_id_t logId;
+
+    node = node->prev;
+    element = node_to_item(node, struct LogBufferElement, node);
+    logId = element->logId;
+
+    if (logMask & (1 << logId)) {
+      ret = log_msg->entry_v3.len = element->len;
+      log_msg->entry_v3.hdr_size = sizeof(log_msg->entry_v3);
+      log_msg->entry_v3.pid = getpid();
+      log_msg->entry_v3.tid = element->tid;
+      log_msg->entry_v3.sec = element->timestamp.tv_sec;
+      log_msg->entry_v3.nsec = element->timestamp.tv_nsec;
+      log_msg->entry_v3.lid = logId;
+      memcpy(log_msg->entry_v3.msg, element->msg, ret);
+      ret += log_msg->entry_v3.hdr_size;
+      break;
+    }
+  }
+
+  transp->context.node = node;
+
+  /* ToDo: if blocking, and no entry, put reader to sleep */
+  pthread_rwlock_unlock(&logbuf.listLock);
+  return ret;
+}
+
+static int writeToLocalPoll(
+        struct android_log_logger_list *logger_list,
+        struct android_log_transport_context *transp) {
+  int ret = (logger_list->mode & ANDROID_LOG_NONBLOCK) ? -ENODEV : 0;
+
+  pthread_rwlock_rdlock(&logbuf.listLock);
+
+  if (logbuf.serviceName) {
+    unsigned logMask = transp->logMask;
+    struct listnode *node = writeToLocalNode(logger_list, transp);
+
+    ret = (node != list_head(&logbuf.head));
+    if (ret) {
+      do {
+        ret = !!(logMask & (1 << (node_to_item(node->prev,
+                                               struct LogBufferElement,
+                                               node))->logId));
+      } while (!ret && ((node = node->prev) != list_head(&logbuf.head)));
+    }
+
+    transp->context.node = node;
+  }
+
+  pthread_rwlock_unlock(&logbuf.listLock);
+
+  return ret;
+}
+
+static void writeToLocalClose(
+        struct android_log_logger_list *logger_list __unused,
+        struct android_log_transport_context *transp) {
+  pthread_rwlock_wrlock(&logbuf.listLock);
+  transp->context.node = list_head(&logbuf.head);
+  pthread_rwlock_unlock(&logbuf.listLock);
+}
+
+static int writeToLocalClear(
+        struct android_log_logger *logger,
+        struct android_log_transport_context *unused __unused) {
+  log_id_t logId = logger->logId;
+  struct listnode *node, *n;
+
+  if ((logId >= NUMBER_OF_LOG_BUFFERS) || BLOCK_LOG_BUFFERS(logId)) {
+    return -EINVAL;
+  }
+
+  pthread_rwlock_wrlock(&logbuf.listLock);
+  logbuf.number[logId] = 0;
+  logbuf.last[logId] = &logbuf.head;
+  list_for_each_safe(node, n, &logbuf.head) {
+    struct LogBufferElement *element;
+    element = node_to_item(node, struct LogBufferElement, node);
+
+    if (logId == element->logId) {
+      struct android_log_logger_list *logger_list;
+
+      logger_list_rdlock();
+      logger_list_for_each(logger_list) {
+        struct android_log_transport_context *transp;
+
+        transport_context_for_each(transp, logger_list) {
+          if ((transp->transport == &localLoggerRead) &&
+              (transp->context.node == node)) {
+            transp->context.node = node->next;
+          }
+        }
+      }
+      logger_list_unlock();
+      list_remove(node);
+      free(element);
+    }
+  }
+
+  pthread_rwlock_unlock(&logbuf.listLock);
+
+  return 0;
+}
+
+static ssize_t writeToLocalGetSize(
+        struct android_log_logger *logger,
+        struct android_log_transport_context *transp __unused) {
+  ssize_t ret = -EINVAL;
+  log_id_t logId = logger->logId;
+
+  if ((logId < NUMBER_OF_LOG_BUFFERS) && !BLOCK_LOG_BUFFERS(logId)) {
+    pthread_rwlock_rdlock(&logbuf.listLock);
+    ret = logbuf.maxSize[logId];
+    pthread_rwlock_unlock(&logbuf.listLock);
+  }
+
+  return ret;
+}
+
+static ssize_t writeToLocalSetSize(
+        struct android_log_logger *logger,
+        struct android_log_transport_context *transp __unused,
+        size_t size) {
+  ssize_t ret = -EINVAL;
+
+  if ((size > LOGGER_ENTRY_MAX_LEN) || (size < (4 * 1024 * 1024))) {
+    log_id_t logId = logger->logId;
+    if ((logId < NUMBER_OF_LOG_BUFFERS) || !BLOCK_LOG_BUFFERS(logId)) {
+      pthread_rwlock_wrlock(&logbuf.listLock);
+      ret = logbuf.maxSize[logId] = size;
+      pthread_rwlock_unlock(&logbuf.listLock);
+    }
+  }
+
+  return ret;
+}
+
+static ssize_t writeToLocalGetReadbleSize(
+        struct android_log_logger *logger,
+        struct android_log_transport_context *transp __unused) {
+  ssize_t ret = -EINVAL;
+  log_id_t logId = logger->logId;
+
+  if ((logId < NUMBER_OF_LOG_BUFFERS) && !BLOCK_LOG_BUFFERS(logId)) {
+    pthread_rwlock_rdlock(&logbuf.listLock);
+    ret = logbuf.serviceName ? (ssize_t)logbuf.size[logId] : -EBADF;
+    pthread_rwlock_unlock(&logbuf.listLock);
+  }
+
+  return ret;
+}
diff --git a/liblog/logd_reader.c b/liblog/logd_reader.c
index ccc7da8..9411f36 100644
--- a/liblog/logd_reader.c
+++ b/liblog/logd_reader.c
@@ -91,7 +91,7 @@
 
 static int logdAvailable(log_id_t logId)
 {
-    if (logId > LOG_ID_KERNEL) {
+    if (logId >= LOG_ID_MAX || logId == LOG_ID_KERNEL) {
         return -EINVAL;
     }
     if (logId == LOG_ID_SECURITY) {
diff --git a/liblog/logger.h b/liblog/logger.h
index 50d1cb4..d94cd14 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -39,14 +39,16 @@
 
 struct android_log_transport_write {
   struct listnode node;
-  const char *name;
-  unsigned logMask; /* cache of available success */
+  const char *name; /* human name to describe the transport */
+  unsigned logMask; /* mask cache of available() success */
   union android_log_context context; /* Initialized by static allocation */
 
-  int (*available)(log_id_t logId);
-  int (*open)();
-  void (*close)();
-  int (*write)(log_id_t logId, struct timespec *ts, struct iovec *vec, size_t nr);
+  int (*available)(log_id_t logId); /* Does not cause resources to be taken */
+  int (*open)();   /* can be called multiple times, reusing current resources */
+  void (*close)(); /* free up resources */
+  /* write log to transport, returns number of bytes propagated, or -errno */
+  int (*write)(log_id_t logId, struct timespec *ts,
+               struct iovec *vec, size_t nr);
 };
 
 struct android_log_logger_list;
@@ -55,22 +57,23 @@
 
 struct android_log_transport_read {
   struct listnode node;
-  const char *name;
+  const char *name; /* human name to describe the transport */
 
+  /* Does not cause resources to be taken */
   int (*available)(log_id_t logId);
   int (*version)(struct android_log_logger *logger,
                  struct android_log_transport_context *transp);
+  /* Release resources taken by the following interfaces */
   void (*close)(struct android_log_logger_list *logger_list,
                 struct android_log_transport_context *transp);
-
   /*
-   * Expect all to instantiate open on any call, so we do not have
-   * an expicit open call
+   * Expect all to instantiate open automagically on any call,
+   * so we do not have an explicit open call.
    */
   int (*read)(struct android_log_logger_list *logger_list,
               struct android_log_transport_context *transp,
               struct log_msg *log_msg);
-  /* Assumption is only called if not ANDROID_LOG_NONBLOCK */
+  /* Must only be called if not ANDROID_LOG_NONBLOCK (blocking) */
   int (*poll)(struct android_log_logger_list *logger_list,
               struct android_log_transport_context *transp);
 
@@ -96,6 +99,7 @@
 };
 
 struct android_log_logger_list {
+  struct listnode node;
   struct listnode logger;
   struct listnode transport;
   int mode;
@@ -117,9 +121,9 @@
   struct android_log_logger_list *parent;
 
   struct android_log_transport_read *transport;
-  unsigned logMask;
-  int ret;
-  struct log_msg logMsg; /* valid is logMsg.len != 0 */
+  unsigned logMask;      /* mask of requested log buffers */
+  int ret;               /* return value associated with following data */
+  struct log_msg logMsg; /* peek at upcoming data, valid if logMsg.len != 0 */
 };
 
 /* assumes caller has structures read-locked, single threaded, or fenced */
@@ -143,6 +147,41 @@
          (logp) = node_to_item((logp)->node.next,                   \
                              struct android_log_logger, node))
 
+/*
+ *    Global list of log readers.
+ *
+ * Usage case: search out transport contexts for all readers
+ */
+
+LIBLOG_HIDDEN struct listnode __android_log_readers;
+
+#if defined(_WIN32)
+#define logger_list_rdlock()
+#define logger_list_wrlock()
+#define logger_list_unlock()
+#else
+LIBLOG_HIDDEN pthread_rwlock_t __android_log_readers_lock;
+
+#define logger_list_rdlock() pthread_rwlock_rdlock(&__android_log_readers_lock)
+#define logger_list_wrlock() pthread_rwlock_wrlock(&__android_log_readers_lock)
+#define logger_list_unlock() pthread_rwlock_unlock(&__android_log_readers_lock)
+#endif
+
+/* Must be called with logger_list_rdlock() or logger_list_wrlock() held */
+#define logger_list_for_each(logger_list)                              \
+    for ((logger_list) = node_to_item(&__android_log_readers,          \
+                                      struct android_log_logger_list,  \
+                                      node);                           \
+         (logger_list) != node_to_item(&__android_log_readers,         \
+                                       struct android_log_logger_list, \
+                                       node) &&                        \
+         (logger_list) != node_to_item((logger_list)->node.next,       \
+                                       struct android_log_logger_list, \
+                                       node);                          \
+         (logger_list) = node_to_item((logger_list)->node.next,        \
+                                      struct android_log_logger_list,  \
+                                      node))
+
 /* OS specific dribs and drabs */
 
 #if defined(_WIN32)
@@ -157,6 +196,8 @@
 LIBLOG_HIDDEN int __android_log_trylock();
 LIBLOG_HIDDEN void __android_log_unlock();
 
+LIBLOG_HIDDEN int __android_log_frontend;
+
 __END_DECLS
 
 #endif /* _LIBLOG_LOGGER_H__ */
diff --git a/liblog/logger_read.c b/liblog/logger_read.c
index c3cb7ad..7e50a23 100644
--- a/liblog/logger_read.c
+++ b/liblog/logger_read.c
@@ -228,6 +228,13 @@
     LOGGER_LIST_FUNCTION(logger_list, -ENODEV, setPrune, buf, len);
 }
 
+LIBLOG_HIDDEN struct listnode __android_log_readers =
+    { &__android_log_readers, &__android_log_readers };
+#if !defined(_WIN32)
+LIBLOG_HIDDEN pthread_rwlock_t __android_log_readers_lock =
+    PTHREAD_RWLOCK_INITIALIZER;
+#endif
+
 LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc(
         int mode,
         unsigned int tail,
@@ -246,6 +253,10 @@
     logger_list->tail = tail;
     logger_list->pid = pid;
 
+    logger_list_wrlock();
+    list_add_tail(&__android_log_readers, &logger_list->node);
+    logger_list_unlock();
+
     return (struct logger_list *)logger_list;
 }
 
@@ -267,6 +278,10 @@
     logger_list->start = start;
     logger_list->pid = pid;
 
+    logger_list_wrlock();
+    list_add_tail(&__android_log_readers, &logger_list->node);
+    logger_list_unlock();
+
     return (struct logger_list *)logger_list;
 }
 
@@ -502,6 +517,10 @@
         return;
     }
 
+    logger_list_wrlock();
+    list_remove(&logger_list_internal->node);
+    logger_list_unlock();
+
     while (!list_empty(&logger_list_internal->transport)) {
         struct listnode *node = list_head(&logger_list_internal->transport);
         struct android_log_transport_context *transp =
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index 1a2d506..e149e68 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -25,9 +25,11 @@
 #endif
 
 #include <log/event_tag_map.h>
+#include <log/log_frontend.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
+#include "config_read.h" /* __android_log_config_read_close() definition */
 #include "config_write.h"
 #include "log_portability.h"
 #include "logger.h"
@@ -170,6 +172,8 @@
         }
     }
 
+    __android_log_config_write_close();
+
 #if defined(__ANDROID__)
     /*
      * Additional risk here somewhat mitigated by immediately unlock flushing
@@ -343,7 +347,7 @@
             }
         }
         /* tag must be nul terminated */
-        if (strnlen(tag, len) >= len) {
+        if (tag && strnlen(tag, len) >= len) {
             tag = NULL;
         }
 
@@ -514,6 +518,14 @@
             strcpy(buf, "Unspecified assertion failed");
     }
 
+    // Log assertion failures to stderr for the benefit of "adb shell" users
+    // and gtests (http://b/23675822).
+    struct iovec iov[2] = {
+        { buf, strlen(buf) },
+        { (char*) "\n", 1 },
+    };
+    TEMP_FAILURE_RETRY(writev(2, iov, 2));
+
     __android_log_write(ANDROID_LOG_FATAL, tag, buf);
     abort(); /* abort so we have a chance to debug the situation */
     /* NOTREACHED */
@@ -610,3 +622,87 @@
 
     return write_to_log(LOG_ID_SECURITY, vec, 4);
 }
+
+static int __write_to_log_null(log_id_t log_id, struct iovec* vec, size_t nr)
+{
+    size_t len, i;
+
+    if ((log_id < LOG_ID_MIN) || (log_id >= LOG_ID_MAX)) {
+        return -EINVAL;
+    }
+
+    for (len = i = 0; i < nr; ++i) {
+        len += vec[i].iov_len;
+    }
+    if (!len) {
+        return -EINVAL;
+    }
+    return len;
+}
+
+/* Following functions need access to our internal write_to_log status */
+
+LIBLOG_HIDDEN int __android_log_frontend;
+
+LIBLOG_ABI_PUBLIC int android_set_log_frontend(int frontend_flag)
+{
+    int retval;
+
+    if (frontend_flag < 0) {
+        return -EINVAL;
+    }
+
+    retval = LOGGER_NULL;
+
+    __android_log_lock();
+
+    if (frontend_flag & LOGGER_NULL) {
+        write_to_log = __write_to_log_null;
+
+        __android_log_unlock();
+
+        return retval;
+    }
+
+    __android_log_frontend &= LOGGER_LOCAL | LOGGER_LOGD;
+
+    frontend_flag &= LOGGER_LOCAL | LOGGER_LOGD;
+
+    if (__android_log_frontend != frontend_flag) {
+        __android_log_frontend = frontend_flag;
+        __android_log_config_write_close();
+        __android_log_config_read_close();
+
+        write_to_log = __write_to_log_init;
+    /* generically we only expect these two values for write_to_log */
+    } else if ((write_to_log != __write_to_log_init) &&
+               (write_to_log != __write_to_log_daemon)) {
+        write_to_log = __write_to_log_init;
+    }
+
+    retval = __android_log_frontend;
+
+    __android_log_unlock();
+
+    return retval;
+}
+
+LIBLOG_ABI_PUBLIC int android_get_log_frontend()
+{
+    int ret = LOGGER_DEFAULT;
+
+    __android_log_lock();
+    if (write_to_log == __write_to_log_null) {
+        ret = LOGGER_NULL;
+    } else {
+        __android_log_frontend &= LOGGER_LOCAL | LOGGER_LOGD;
+        ret = __android_log_frontend;
+        if ((write_to_log != __write_to_log_init) &&
+            (write_to_log != __write_to_log_daemon)) {
+            ret = -EINVAL;
+        }
+    }
+    __android_log_unlock();
+
+    return ret;
+}
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 18af9de..e61850d 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -16,13 +16,20 @@
 */
 
 #define _GNU_SOURCE /* for asprintf */
+#ifndef __MINGW32__
+#define HAVE_STRSEP
+#endif
 
-#include <arpa/inet.h>
+//#ifndef __MINGW32__
+//#include <arpa/inet.h>
+//#endif
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
 #include <inttypes.h>
+#ifndef __MINGW32__
 #include <pwd.h>
+#endif
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -40,6 +47,10 @@
 #define MS_PER_NSEC 1000000
 #define US_PER_NSEC 1000
 
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
 typedef struct FilterInfo_t {
     char *mTag;
     android_LogPriority mPri;
@@ -216,7 +227,11 @@
     p_ret->year_output = false;
     p_ret->zone_output = false;
     p_ret->epoch_output = false;
+#ifdef __ANDROID__
     p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC;
+#else
+    p_ret->monotonic_output = false;
+#endif
     p_ret->uid_output = false;
     p_ret->descriptive_output = false;
     descriptive_output = false;
@@ -322,6 +337,7 @@
     else if (strcmp(formatString, "monotonic") == 0) format = FORMAT_MODIFIER_MONOTONIC;
     else if (strcmp(formatString, "uid") == 0) format = FORMAT_MODIFIER_UID;
     else if (strcmp(formatString, "descriptive") == 0) format = FORMAT_MODIFIER_DESCRIPT;
+#ifndef __MINGW32__
     else {
         extern char *tzname[2];
         static const char gmt[] = "GMT";
@@ -353,6 +369,7 @@
         }
         free(cp);
     }
+#endif
 
     return format;
 }
@@ -411,7 +428,7 @@
 
 /*
  * Presently HAVE_STRNDUP is never defined, so the second case is always taken
- * Darwin doesn't have strnup, everything else does
+ * Darwin doesn't have strndup, everything else does
  */
 #ifdef HAVE_STRNDUP
         tagName = strndup(filterExpression, tagNameLength);
@@ -433,6 +450,27 @@
     return -1;
 }
 
+#ifndef HAVE_STRSEP
+/* KISS replacement helper for below */
+static char* strsep(char** stringp, const char* delim)
+{
+    char* token;
+    char* ret = *stringp;
+
+    if (!ret || !*ret) {
+        return NULL;
+    }
+    token = strpbrk(ret, delim);
+    if (token) {
+        *token = '\0';
+        ++token;
+    } else {
+        token = ret + strlen(ret);
+    }
+    *stringp = token;
+    return ret;
+}
+#endif
 
 /**
  * filterString: a comma/whitespace-separated set of filter expressions
@@ -444,7 +482,6 @@
  * Assumes single threaded execution
  *
  */
-
 LIBLOG_ABI_PUBLIC int android_log_addFilterString(
         AndroidLogFormat *p_format,
         const char *filterString)
@@ -728,6 +765,7 @@
             }
         }
     }
+    outCount = 0;
     lval = 0;
     switch (type) {
     case EVENT_TYPE_INT:
@@ -953,7 +991,7 @@
 LIBLOG_ABI_PUBLIC int android_log_processBinaryLogBuffer(
         struct logger_entry *buf,
         AndroidLogEntry *entry,
-        const EventTagMap *map,
+        const EventTagMap *map __unused,
         char *messageBuf, int messageBufLen)
 {
     size_t inCount;
@@ -995,11 +1033,12 @@
     inCount -= 4;
 
     entry->tagLen = 0;
+    entry->tag = NULL;
+#ifdef __ANDROID__
     if (map != NULL) {
         entry->tag = android_lookupEventTag_len(map, &entry->tagLen, tagIndex);
-    } else {
-        entry->tag = NULL;
     }
+#endif
 
     /*
      * If we don't have a map, or didn't find the tag number in the map,
@@ -1024,9 +1063,11 @@
      */
     const char* fmtStr = NULL;
     size_t fmtLen = 0;
+#ifdef __ANDROID__
     if (descriptive_output && map) {
         fmtStr = android_lookupEventFormat_len(map, &fmtLen, tagIndex);
     }
+#endif
 
     char* outBuf = messageBuf;
     size_t outRemaining = messageBufLen - 1; /* leave one for nul byte */
@@ -1250,6 +1291,7 @@
     return (long long)now->tv_sec * NS_PER_SEC + now->tv_nsec;
 }
 
+#ifdef __ANDROID__
 static void convertMonotonic(struct timespec *result,
                              const AndroidLogEntry *entry)
 {
@@ -1482,6 +1524,7 @@
     result->tv_nsec = entry->tv_nsec;
     subTimespec(result, result, &convert);
 }
+#endif
 
 /**
  * Formats a log message into a buffer
@@ -1529,6 +1572,7 @@
      */
     now = entry->tv_sec;
     nsec = entry->tv_nsec;
+#if __ANDROID__
     if (p_format->monotonic_output) {
         // prevent convertMonotonic from being called if logd is monotonic
         if (android_log_clockid() != CLOCK_MONOTONIC) {
@@ -1538,6 +1582,7 @@
             nsec = time.tv_nsec;
         }
     }
+#endif
     if (now < 0) {
         nsec = NS_PER_SEC - nsec;
     }
@@ -1591,13 +1636,18 @@
              * This code is Android specific, bionic guarantees that
              * calls to non-reentrant getpwuid() are thread safe.
              */
+#if !defined(__MINGW32__)
+#if (FAKE_LOG_DEVICE == 0)
 #ifndef __BIONIC__
 #warning "This code assumes that getpwuid is thread safe, only true with Bionic!"
 #endif
+#endif
             struct passwd* pwd = getpwuid(entry->uid);
             if (pwd && (strlen(pwd->pw_name) <= 5)) {
                  snprintf(uid, sizeof(uid), "%5s:", pwd->pw_name);
-            } else {
+            } else
+#endif
+            {
                  // Not worth parsing package list, names all longer than 5
                  snprintf(uid, sizeof(uid), "%5d:", entry->uid);
             }
diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c
index c1c068e..5e4ff98 100644
--- a/liblog/pmsg_writer.c
+++ b/liblog/pmsg_writer.c
@@ -285,6 +285,7 @@
                 __android_log_unlock();
             } else if (pmsgOpen() < 0) {
                 __android_log_unlock();
+                free(cp);
                 return -EBADF;
             }
         }
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index 097befc..cfea452 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -55,7 +55,8 @@
     -fno-builtin \
 
 test_src_files := \
-    liblog_test.cpp \
+    liblog_test_default.cpp \
+    liblog_test_local.cpp \
     log_id_test.cpp \
     log_radio_test.cpp \
     log_read_test.cpp \
@@ -111,6 +112,7 @@
 LOCAL_CXX_STL := libc++
 LOCAL_SHARED_LIBRARIES := liblog libcutils libbase
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_LDLIBS_linux := -lrt
 include $(BUILD_HOST_NATIVE_TEST)
 
 endif  # ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index dc411c3..dac84eb 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -27,6 +27,7 @@
 #include <android-base/file.h>
 #include <cutils/sockets.h>
 #include <log/event_tag_map.h>
+#include <log/log_frontend.h>
 #include <private/android_logger.h>
 
 #include "benchmark.h"
@@ -80,10 +81,29 @@
 }
 BENCHMARK(BM_log_maximum);
 
+static void set_log_null() {
+    android_set_log_frontend(LOGGER_NULL);
+}
+
+static void set_log_default() {
+    android_set_log_frontend(LOGGER_DEFAULT);
+}
+
+static void BM_log_maximum_null(int iters) {
+    set_log_null();
+    BM_log_maximum(iters);
+    set_log_default();
+}
+BENCHMARK(BM_log_maximum_null);
+
 /*
- *	Measure the time it takes to submit the android logging call using
- * discrete acquisition under light load. Expect this to be a pair of
- * syscall periods (2us).
+ *	Measure the time it takes to collect the time using
+ * discrete acquisition (StartBenchmarkTiming() -> StopBenchmarkTiming())
+ * under light load. Expect this to be a syscall period (2us) or
+ * data read time if zero-syscall.
+ *
+ * vdso support in the kernel and the library can allow
+ * clock_gettime to be zero-syscall.
  */
 static void BM_clock_overhead(int iters) {
     for (int i = 0; i < iters; ++i) {
@@ -468,19 +488,94 @@
 BENCHMARK(BM_pmsg_long_unaligned1);
 
 /*
- *	Measure the time it takes to submit the android logging call using
- * discrete acquisition under light load. Expect this to be a dozen or so
- * syscall periods (40us).
+ *	Measure the time it takes to form sprintf plus time using
+ * discrete acquisition (StartBenchmarkTiming() -> StopBenchmarkTiming())
+ * under light load. Expect this to be a syscall period (2us) or sprintf
+ * time if zero-syscall time.
  */
-static void BM_log_overhead(int iters) {
+/* helper function */
+static void test_print(const char *fmt, ...) {
+    va_list ap;
+    char buf[1024];
+
+    va_start(ap, fmt);
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+    va_end(ap);
+}
+
+#define logd_yield() sched_yield() // allow logd to catch up
+#define logd_sleep() usleep(50)    // really allow logd to catch up
+
+/* performance test */
+static void BM_sprintf_overhead(int iters) {
+    for (int i = 0; i < iters; ++i) {
+       StartBenchmarkTiming();
+       test_print("BM_sprintf_overhead:%d", i);
+       StopBenchmarkTiming();
+       logd_yield();
+    }
+}
+BENCHMARK(BM_sprintf_overhead);
+
+/*
+ *	Measure the time it takes to submit the android printing logging call
+ * using discrete acquisition discrete acquisition (StartBenchmarkTiming() ->
+ * StopBenchmarkTiming()) under light load. Expect this to be a dozen or so
+ * syscall periods (40us) plus time to run *printf
+ */
+static void BM_log_print_overhead(int iters) {
     for (int i = 0; i < iters; ++i) {
        StartBenchmarkTiming();
        __android_log_print(ANDROID_LOG_INFO, "BM_log_overhead", "%d", i);
        StopBenchmarkTiming();
-       usleep(1000);
+       logd_yield();
     }
 }
-BENCHMARK(BM_log_overhead);
+BENCHMARK(BM_log_print_overhead);
+
+/*
+ *	Measure the time it takes to submit the android event logging call
+ * using discrete acquisition (StartBenchmarkTiming() -> StopBenchmarkTiming())
+ * under light load. Expect this to be a dozen or so syscall periods (40us)
+ */
+static void BM_log_event_overhead(int iters) {
+    for (unsigned long long i = 0; i < (unsigned)iters; ++i) {
+       StartBenchmarkTiming();
+       __android_log_btwrite(0, EVENT_TYPE_LONG, &i, sizeof(i));
+       StopBenchmarkTiming();
+       logd_yield();
+    }
+}
+BENCHMARK(BM_log_event_overhead);
+
+static void BM_log_event_overhead_null(int iters) {
+    set_log_null();
+    BM_log_event_overhead(iters);
+    set_log_default();
+}
+BENCHMARK(BM_log_event_overhead_null);
+
+/*
+ *	Measure the time it takes to submit the android event logging call
+ * using discrete acquisition (StartBenchmarkTiming() -> StopBenchmarkTiming())
+ * under very-light load (<1% CPU utilization).
+ */
+static void BM_log_light_overhead(int iters) {
+    for (unsigned long long i = 0; i < (unsigned)iters; ++i) {
+       StartBenchmarkTiming();
+       __android_log_btwrite(0, EVENT_TYPE_LONG, &i, sizeof(i));
+       StopBenchmarkTiming();
+       usleep(10000);
+    }
+}
+BENCHMARK(BM_log_light_overhead);
+
+static void BM_log_light_overhead_null(int iters) {
+    set_log_null();
+    BM_log_light_overhead(iters);
+    set_log_default();
+}
+BENCHMARK(BM_log_light_overhead_null);
 
 static void caught_latency(int /*signum*/)
 {
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 5faf8e1..bc0ea4c 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -37,9 +37,32 @@
 #include <gtest/gtest.h>
 #include <log/logprint.h>
 #include <log/log_event_list.h>
+#include <log/log_frontend.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
+#ifndef TEST_PREFIX
+#ifdef __ANDROID__ // make sure we always run code if compiled for android
+#define TEST_PREFIX
+#endif
+#endif
+
+#if (!defined(USING_LOGGER_DEFAULT) || !defined(USING_LOGGER_LOCAL))
+#ifdef liblog // a binary clue that we are overriding the test names
+// Does not support log reading blocking feature yet
+// Does not support LOG_ID_SECURITY (unless we set LOGGER_LOCAL | LOGGER_LOGD)
+// Assume some common aspects are tested by USING_LOGGER_DEFAULT:
+// Does not need to _retest_ pmsg functionality
+// Does not need to _retest_ property handling as it is a higher function
+// Does not need to _retest_ event mapping functionality
+// Does not need to _retest_ ratelimit
+// Does not need to _retest_ logprint
+#define USING_LOGGER_LOCAL
+#else
+#define USING_LOGGER_DEFAULT
+#endif
+#endif
+
 // enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
 // non-syscall libs. Since we are only using this in the emergency of
 // a signal to stuff a terminating code into the logs, we will spin rather
@@ -56,7 +79,9 @@
     _rc; })
 
 TEST(liblog, __android_log_btwrite) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+    TEST_PREFIX
+#endif
     int intBuf = 0xDEADBEEF;
     EXPECT_LT(0, __android_log_btwrite(0,
                                       EVENT_TYPE_INT,
@@ -71,13 +96,10 @@
                                       EVENT_TYPE_STRING,
                                       Buf, sizeof(Buf) - 1));
     usleep(1000);
-#else
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
 }
 
-#ifdef __ANDROID__
-std::string popenToString(std::string command) {
+#if (defined(__ANDROID__) && !defined(USING_LOGGER_LOCAL))
+static std::string popenToString(std::string command) {
     std::string ret;
 
     FILE* fp = popen(command.c_str(), "r");
@@ -141,11 +163,11 @@
     return false;
 }
 
-bool tested__android_log_close;
+static bool tested__android_log_close;
 #endif
 
 TEST(liblog, __android_log_btwrite__android_logger_list_read) {
-#ifdef __ANDROID__
+#if (defined(__ANDROID__) || defined(USING_LOGGER_LOCAL))
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -153,9 +175,10 @@
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
         LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
-    // Check that we can close and reopen the logger
     log_time ts(CLOCK_MONOTONIC);
     ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+#ifndef USING_LOGGER_LOCAL
+    // Check that we can close and reopen the logger
     bool pmsgActiveAfter__android_log_btwrite;
     bool logdwActiveAfter__android_log_btwrite;
     if (getuid() == AID_ROOT) {
@@ -174,15 +197,18 @@
         EXPECT_FALSE(pmsgActiveAfter__android_log_close);
         EXPECT_FALSE(logdwActiveAfter__android_log_close);
     }
+#endif
 
     log_time ts1(CLOCK_MONOTONIC);
     ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
+#ifndef USING_LOGGER_LOCAL
     if (getuid() == AID_ROOT) {
         pmsgActiveAfter__android_log_btwrite = isPmsgActive();
         logdwActiveAfter__android_log_btwrite = isLogdwActive();
         EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
         EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
     }
+#endif
     usleep(1000000);
 
     int count = 0;
@@ -225,15 +251,92 @@
 #endif
 }
 
-#ifdef __ANDROID__
-static inline int32_t get4LE(const char* src)
-{
+// This test makes little sense standalone, and requires the tests ahead
+// and behind us, to make us whole.  We could incorporate a prefix and
+// suffix test to make this standalone, but opted to not complicate this.
+TEST(liblog, android_set_log_frontend) {
+#if (defined(__ANDROID__) || defined(USING_LOGGER_LOCAL))
+#ifdef TEST_PREFIX
+    TEST_PREFIX
+#endif
+
+    int logger = android_get_log_frontend();
+    EXPECT_NE(LOGGER_NULL, logger);
+
+    EXPECT_EQ(LOGGER_NULL, android_set_log_frontend(LOGGER_NULL));
+    EXPECT_EQ(LOGGER_NULL, android_get_log_frontend());
+
+    pid_t pid = getpid();
+
+    struct logger_list *logger_list;
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+    log_time ts(CLOCK_MONOTONIC);
+    ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+
+    usleep(1000000);
+
+    int count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        ASSERT_EQ(log_msg.entry.pid, pid);
+
+        if ((log_msg.entry.len != sizeof(android_log_event_long_t))
+         || (log_msg.id() != LOG_ID_EVENTS)) {
+            continue;
+        }
+
+        android_log_event_long_t* eventData;
+        eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
+
+        if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
+            continue;
+        }
+
+        log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
+        if (ts == tx) {
+            ++count;
+        }
+    }
+
+    android_logger_list_close(logger_list);
+
+    EXPECT_EQ(logger, android_set_log_frontend(logger));
+    EXPECT_EQ(logger, android_get_log_frontend());
+
+    // False negative if liblog.__android_log_btwrite__android_logger_list_read
+    // fails above, so we will likely succeed. But we will have so many
+    // failures elsewhere that it is probably not worthwhile for us to
+    // highlight yet another disappointment.
+    EXPECT_EQ(0, count);
+    // We also expect failures in the following tests if the set does not
+    // react in an appropriate manner internally, yet passes, so we depend
+    // on this test being in the middle of a series of tests performed in
+    // the same process.
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
+#ifdef TEST_PREFIX
+static inline uint32_t get4LE(const uint8_t* src) {
     return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
 }
+
+static inline uint32_t get4LE(const char* src) {
+    return get4LE(reinterpret_cast<const uint8_t*>(src));
+}
 #endif
 
 static void bswrite_test(const char *message) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+    TEST_PREFIX
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -241,7 +344,11 @@
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
         LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
+#ifdef __ANDROID__
     log_time ts(android_log_clockid());
+#else
+    log_time ts(CLOCK_REALTIME);
+#endif
 
     ASSERT_LT(0, __android_log_bswrite(0, message));
     size_t num_lines = 1, size = 0, length = 0, total = 0;
@@ -307,8 +414,11 @@
                 &log_msg.entry_v1, &entry, NULL, msgBuf, sizeof(msgBuf));
             EXPECT_EQ((length == total) ? 0 : -1, processBinaryLogBuffer);
             if (processBinaryLogBuffer == 0) {
+                size_t line_overhead = 20;
+                if (pid > 99999) ++line_overhead;
+                if (pid > 999999) ++line_overhead;
                 fflush(stderr);
-                EXPECT_EQ((int)((20 * num_lines) + size),
+                EXPECT_EQ((int)((line_overhead * num_lines) + size),
                     android_log_printLogLine(logformat, fileno(stderr), &entry));
             }
             android_log_format_free(logformat);
@@ -345,7 +455,8 @@
 }
 
 static void buf_write_test(const char *message) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+    TEST_PREFIX
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -354,7 +465,11 @@
         LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
     static const char tag[] = "TEST__android_log_buf_write";
+#ifdef __ANDROID__
     log_time ts(android_log_clockid());
+#else
+    log_time ts(CLOCK_REALTIME);
+#endif
 
     EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
                                          tag, message));
@@ -402,8 +517,11 @@
                                                             &entry);
         EXPECT_EQ(0, processLogBuffer);
         if (processLogBuffer == 0) {
+            size_t line_overhead = 11;
+            if (pid > 99999) ++line_overhead;
+            if (pid > 999999) ++line_overhead;
             fflush(stderr);
-            EXPECT_EQ((int)(((11 + sizeof(tag)) * num_lines) + size),
+            EXPECT_EQ((int)(((line_overhead + sizeof(tag)) * num_lines) + size),
                 android_log_printLogLine(logformat, fileno(stderr), &entry));
         }
         android_log_format_free(logformat);
@@ -430,7 +548,8 @@
     buf_write_test("\n Hello World \n");
 }
 
-#ifdef __ANDROID__
+#ifndef USING_LOGGER_LOCAL // requires blocking reader functionality
+#ifdef TEST_PREFIX
 static unsigned signaled;
 static log_time signal_time;
 
@@ -492,7 +611,8 @@
 #endif
 
 TEST(liblog, android_logger_list_read__cpu_signal) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+    TEST_PREFIX
     struct logger_list *logger_list;
     unsigned long long v = 0xDEADBEEFA55A0000ULL;
 
@@ -584,7 +704,7 @@
 #endif
 }
 
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
 /*
  *  Strictly, we are not allowed to log messages in a signal context, the
  * correct way to handle this is to ensure the messages are constructed in
@@ -618,7 +738,7 @@
     return NULL;
 }
 
-int start_thread()
+static int start_thread()
 {
     sem_init(&thread_trigger, 0, 0);
 
@@ -650,7 +770,8 @@
 #endif
 
 TEST(liblog, android_logger_list_read__cpu_thread) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+    TEST_PREFIX
     struct logger_list *logger_list;
     unsigned long long v = 0xDEADBEAFA55A0000ULL;
 
@@ -742,8 +863,9 @@
     GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
+#endif // !USING_LOGGER_LOCAL
 
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
 static const char max_payload_tag[] = "TEST_max_payload_and_longish_tag_XXXX";
 #define SIZEOF_MAX_PAYLOAD_BUF (LOGGER_ENTRY_MAX_PAYLOAD - \
                                 sizeof(max_payload_tag) - 1)
@@ -880,7 +1002,8 @@
 takes his leave.";
 
 TEST(liblog, max_payload) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+    TEST_PREFIX
     pid_t pid = getpid();
     char tag[sizeof(max_payload_tag)];
     memcpy(tag, max_payload_tag, sizeof(tag));
@@ -944,7 +1067,8 @@
 }
 
 TEST(liblog, __android_log_buf_print__maxtag) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+    TEST_PREFIX
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -952,7 +1076,11 @@
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
         LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
+#ifdef __ANDROID__
     log_time ts(android_log_clockid());
+#else
+    log_time ts(CLOCK_REALTIME);
+#endif
 
     EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
                                          max_payload_buf, max_payload_buf));
@@ -1004,7 +1132,8 @@
 }
 
 TEST(liblog, too_big_payload) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+    TEST_PREFIX
     pid_t pid = getpid();
     static const char big_payload_tag[] = "TEST_big_payload_XXXX";
     char tag[sizeof(big_payload_tag)];
@@ -1058,6 +1187,12 @@
     EXPECT_LE(LOGGER_ENTRY_MAX_PAYLOAD - sizeof(big_payload_tag),
               static_cast<size_t>(max_len));
 
+    // SLOP: Allow the underlying interface to optionally place a
+    // terminating nul at the LOGGER_ENTRY_MAX_PAYLOAD's last byte
+    // or not.
+    if (ret == (max_len + static_cast<ssize_t>(sizeof(big_payload_tag)) - 1)) {
+        --max_len;
+    }
     EXPECT_EQ(ret, max_len + static_cast<ssize_t>(sizeof(big_payload_tag)));
 #else
     GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -1065,17 +1200,29 @@
 }
 
 TEST(liblog, dual_reader) {
-#ifdef __ANDROID__
-    struct logger_list *logger_list1;
+#ifdef TEST_PREFIX
+    TEST_PREFIX
 
-    // >25 messages due to liblog.__android_log_buf_print__concurrentXX above.
+    static const int num = 25;
+
+    for (int i = 25; i > 0; --i) {
+        static const char fmt[] = "dual_reader %02d";
+        char buffer[sizeof(fmt) + 8];
+        snprintf(buffer, sizeof(buffer), fmt, i);
+        LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_MAIN,
+                                                  ANDROID_LOG_INFO,
+                                                  "liblog", buffer));
+    }
+    usleep(1000000);
+
+    struct logger_list *logger_list1;
     ASSERT_TRUE(NULL != (logger_list1 = android_logger_list_open(
-        LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 25, 0)));
+        LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, num, 0)));
 
     struct logger_list *logger_list2;
 
     if (NULL == (logger_list2 = android_logger_list_open(
-            LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 15, 0))) {
+            LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, num - 10, 0))) {
         android_logger_list_close(logger_list1);
         ASSERT_TRUE(NULL != logger_list2);
     }
@@ -1108,22 +1255,20 @@
     android_logger_list_close(logger_list1);
     android_logger_list_close(logger_list2);
 
-    EXPECT_EQ(25, count1);
-    EXPECT_EQ(15, count2);
+    EXPECT_EQ(num, count1);
+    EXPECT_EQ(num - 10, count2);
 #else
     GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
 
-#ifdef __ANDROID__
+#ifndef USING_LOGGER_LOCAL // Do not retest logprint
 static bool checkPriForTag(AndroidLogFormat *p_format, const char *tag, android_LogPriority pri) {
     return android_log_shouldPrintLine(p_format, tag, pri)
         && !android_log_shouldPrintLine(p_format, tag, (android_LogPriority)(pri - 1));
 }
-#endif
 
 TEST(liblog, filterRule) {
-#ifdef __ANDROID__
     static const char tag[] = "random";
 
     AndroidLogFormat *p_format = android_log_format_new();
@@ -1185,11 +1330,10 @@
 #endif
 
     android_log_format_free(p_format);
-#else
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
 }
+#endif // !USING_LOGGER_LOCAL
 
+#ifndef USING_LOGGER_LOCAL // Do not retest property handling
 TEST(liblog, is_loggable) {
 #ifdef __ANDROID__
     static const char tag[] = "is_loggable";
@@ -1488,8 +1632,13 @@
     GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
+#endif // !USING_LOGGER_LOCAL
 
-#ifdef __ANDROID__
+// Following tests the specific issues surrounding error handling wrt logd.
+// Kills logd and toss all collected data, equivalent to logcat -b all -c,
+// except we also return errors to the logging callers.
+#ifndef USING_LOGGER_LOCAL
+#ifdef TEST_PREFIX
 // helper to liblog.enoent to count end-to-end matching logging messages.
 static int count_matching_ts(log_time ts) {
     usleep(1000000);
@@ -1531,10 +1680,11 @@
         testing::AssertionSuccess() :
         (testing::AssertionFailure() << message);
 }
-#endif
+#endif // TEST_PREFIX
 
 TEST(liblog, enoent) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
+    TEST_PREFIX
     log_time ts(CLOCK_MONOTONIC);
     EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
     EXPECT_EQ(1, count_matching_ts(ts));
@@ -1588,9 +1738,12 @@
     GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
+#endif // !USING_LOCAL_LOGGER
 
 // Below this point we run risks of setuid(AID_SYSTEM) which may affect others.
 
+// Do not retest properties, and cannot log into LOG_ID_SECURITY
+#ifndef USING_LOGGER_LOCAL
 TEST(liblog, __security) {
 #ifdef __ANDROID__
     static const char persist_key[] = "persist.logd.security";
@@ -1776,15 +1929,19 @@
     GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
+#endif // !USING_LOGGER_LOCAL
 
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
 static void android_errorWriteWithInfoLog_helper(int TAG, const char* SUBTAG,
                                                  int UID, const char* payload,
                                                  int DATA_LEN, int& count) {
+    TEST_PREFIX
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
 
+    count = 0;
+
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
         LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
@@ -1798,8 +1955,6 @@
 
     sleep(2);
 
-    count = 0;
-
     for (;;) {
         log_msg log_msg;
         if (android_logger_list_read(logger_list, &log_msg) <= 0) {
@@ -1839,7 +1994,7 @@
         ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
         eventData++;
 
-        int subtag_len = strlen(SUBTAG);
+        unsigned subtag_len = strlen(SUBTAG);
         if (subtag_len > 32) subtag_len = 32;
         ASSERT_EQ(subtag_len, get4LE(eventData));
         eventData += 4;
@@ -1853,7 +2008,7 @@
         ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
         eventData++;
 
-        ASSERT_EQ(UID, get4LE(eventData));
+        ASSERT_EQ(UID, (int)get4LE(eventData));
         eventData += 4;
 
         // Element #3: string type for data
@@ -1883,7 +2038,7 @@
 #endif
 
 TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__typical) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
     int count;
     android_errorWriteWithInfoLog_helper(
             123456781,
@@ -1899,7 +2054,7 @@
 }
 
 TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__data_too_large) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
     int count;
     android_errorWriteWithInfoLog_helper(
             123456782,
@@ -1915,7 +2070,7 @@
 }
 
 TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__null_data) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
     int count;
     android_errorWriteWithInfoLog_helper(
             123456783,
@@ -1931,7 +2086,7 @@
 }
 
 TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__subtag_too_long) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
     int count;
     android_errorWriteWithInfoLog_helper(
             123456784,
@@ -1954,12 +2109,15 @@
     buf_write_test(max_payload_buf);
 }
 
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
 static void android_errorWriteLog_helper(int TAG, const char *SUBTAG, int& count) {
+    TEST_PREFIX
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
 
+    count = 0;
+
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
         LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
@@ -1972,8 +2130,6 @@
 
     sleep(2);
 
-    count = 0;
-
     for (;;) {
         log_msg log_msg;
         if (android_logger_list_read(logger_list, &log_msg) <= 0) {
@@ -2011,7 +2167,7 @@
         ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
         eventData++;
 
-        ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
+        ASSERT_EQ(strlen(SUBTAG), get4LE(eventData));
         eventData +=4;
 
         if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
@@ -2025,7 +2181,7 @@
 #endif
 
 TEST(liblog, android_errorWriteLog__android_logger_list_read__success) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
     int count;
     android_errorWriteLog_helper(123456785, "test-subtag", count);
     EXPECT_EQ(1, count);
@@ -2035,7 +2191,7 @@
 }
 
 TEST(liblog, android_errorWriteLog__android_logger_list_read__null_subtag) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
     int count;
     android_errorWriteLog_helper(123456786, NULL, count);
     EXPECT_EQ(0, count);
@@ -2044,7 +2200,8 @@
 #endif
 }
 
-#ifdef __ANDROID__
+// Do not retest logger list handling
+#if (defined(TEST_PREFIX) || !defined(USING_LOGGER_LOCAL))
 static int is_real_element(int type) {
     return ((type == EVENT_TYPE_INT) ||
             (type == EVENT_TYPE_LONG) ||
@@ -2052,8 +2209,8 @@
             (type == EVENT_TYPE_FLOAT));
 }
 
-int android_log_buffer_to_string(const char *msg, size_t len,
-                                 char *strOut, size_t strOutLen) {
+static int android_log_buffer_to_string(const char *msg, size_t len,
+                                        char *strOut, size_t strOutLen) {
     android_log_context context = create_android_log_parser(msg, len);
     android_log_list_element elem;
     bool overflow = false;
@@ -2203,7 +2360,9 @@
 
     return 0;
 }
+#endif // TEST_PREFIX || !USING_LOGGER_LOCAL
 
+#ifdef TEST_PREFIX
 static const char *event_test_int32(uint32_t tag, size_t &expected_len) {
     android_log_context ctx;
 
@@ -2459,6 +2618,7 @@
 }
 
 static void create_android_logger(const char *(*fn)(uint32_t tag, size_t &expected_len)) {
+    TEST_PREFIX
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -2466,7 +2626,11 @@
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
         LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
 
+#ifdef __ANDROID__
     log_time ts(android_log_clockid());
+#else
+    log_time ts(CLOCK_REALTIME);
+#endif
 
     size_t expected_len;
     const char *expected_string = (*fn)(1005, expected_len);
@@ -2507,18 +2671,23 @@
             &log_msg.entry_v1, &entry, NULL, msgBuf, sizeof(msgBuf));
         EXPECT_EQ(0, processBinaryLogBuffer);
         if (processBinaryLogBuffer == 0) {
+            int line_overhead = 20;
+            if (pid > 99999) ++line_overhead;
+            if (pid > 999999) ++line_overhead;
             print_barrier();
             int printLogLine = android_log_printLogLine(
                 logformat, fileno(stderr), &entry);
             print_barrier();
-            EXPECT_EQ(20 + (int)strlen(expected_string), printLogLine);
+            EXPECT_EQ(line_overhead + (int)strlen(expected_string),
+                      printLogLine);
         }
         android_log_format_free(logformat);
 
         // test buffer reading API
         int buffer_to_string = -1;
         if (eventData) {
-            snprintf(msgBuf, sizeof(msgBuf), "I/[%d]", get4LE(eventData));
+            snprintf(msgBuf, sizeof(msgBuf),
+                     "I/[%" PRIu32 "]", get4LE(eventData));
             print_barrier();
             fprintf(stderr, "%-10s(%5u): ", msgBuf, pid);
             memset(msgBuf, 0, sizeof(msgBuf));
@@ -2541,7 +2710,7 @@
 #endif
 
 TEST(liblog, create_android_logger_int32) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
     create_android_logger(event_test_int32);
 #else
     GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2549,7 +2718,7 @@
 }
 
 TEST(liblog, create_android_logger_int64) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
     create_android_logger(event_test_int64);
 #else
     GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2557,7 +2726,7 @@
 }
 
 TEST(liblog, create_android_logger_list_int64) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
     create_android_logger(event_test_list_int64);
 #else
     GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2565,7 +2734,7 @@
 }
 
 TEST(liblog, create_android_logger_simple_automagic_list) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
     create_android_logger(event_test_simple_automagic_list);
 #else
     GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2573,7 +2742,7 @@
 }
 
 TEST(liblog, create_android_logger_list_empty) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
     create_android_logger(event_test_list_empty);
 #else
     GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2581,7 +2750,7 @@
 }
 
 TEST(liblog, create_android_logger_complex_nested_list) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
     create_android_logger(event_test_complex_nested_list);
 #else
     GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2589,7 +2758,7 @@
 }
 
 TEST(liblog, create_android_logger_7_level_prefix) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
     create_android_logger(event_test_7_level_prefix);
 #else
     GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2597,7 +2766,7 @@
 }
 
 TEST(liblog, create_android_logger_7_level_suffix) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
     create_android_logger(event_test_7_level_suffix);
 #else
     GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2605,7 +2774,7 @@
 }
 
 TEST(liblog, create_android_logger_android_log_error_write) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
     create_android_logger(event_test_android_log_error_write);
 #else
     GTEST_LOG_(INFO) << "This test does nothing.\n";
@@ -2613,15 +2782,15 @@
 }
 
 TEST(liblog, create_android_logger_android_log_error_write_null) {
-#ifdef __ANDROID__
+#ifdef TEST_PREFIX
     create_android_logger(event_test_android_log_error_write_null);
 #else
     GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
 
+#ifndef USING_LOGGER_LOCAL // Do not retest logger list handling
 TEST(liblog, create_android_logger_overflow) {
-#ifdef __ANDROID__
     android_log_context ctx;
 
     EXPECT_TRUE(NULL != (ctx = create_android_logger(1005)));
@@ -2646,13 +2815,9 @@
     EXPECT_GT(0, android_log_write_list_begin(ctx));
     EXPECT_LE(0, android_log_destroy(&ctx));
     ASSERT_TRUE(NULL == ctx);
-#else
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
 }
 
 TEST(liblog, android_log_write_list_buffer) {
-#ifdef __ANDROID__
     __android_log_event_list ctx(1005);
     ctx << 1005 << "tag_def" << "(tag|1),(name|3),(format|3)";
     std::string buffer(ctx);
@@ -2663,11 +2828,10 @@
     EXPECT_EQ(android_log_buffer_to_string(buffer.data(), buffer.length(),
                                            msgBuf, sizeof(msgBuf)), 0);
     EXPECT_STREQ(msgBuf, "[1005,tag_def,(tag|1),(name|3),(format|3)]");
-#else
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
 }
+#endif // !USING_LOGGER_LOCAL
 
+#ifndef USING_LOGGER_LOCAL // Do not retest pmsg functionality
 #ifdef __ANDROID__
 static const char __pmsg_file[] =
         "/data/william-shakespeare/MuchAdoAboutNothing.txt";
@@ -2730,8 +2894,8 @@
 }
 
 #ifdef __ANDROID__
-ssize_t __pmsg_fn(log_id_t logId, char prio, const char *filename,
-                  const char *buf, size_t len, void *arg) {
+static ssize_t __pmsg_fn(log_id_t logId, char prio, const char *filename,
+                         const char *buf, size_t len, void *arg) {
     EXPECT_TRUE(NULL == arg);
     EXPECT_EQ(LOG_ID_CRASH, logId);
     EXPECT_EQ(ANDROID_LOG_VERBOSE, prio);
@@ -2793,7 +2957,9 @@
     GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
+#endif // !USING_LOGGER_LOCAL
 
+#ifndef USING_LOGGER_LOCAL // Do not retest event mapping functionality
 #ifdef __ANDROID__
 // must be: '<needle:> 0 kB'
 static bool isZero(const std::string &content, std::string::size_type pos,
@@ -2876,7 +3042,7 @@
     EXPECT_TRUE(IsOk(private_ok, content));
     EXPECT_TRUE(IsOk(anonymous_ok, content));
 }
-#endif
+#endif // __ANDROID__
 
 TEST(liblog, event_log_tags) {
 #ifdef __ANDROID__
@@ -2897,7 +3063,9 @@
     GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
+#endif // !USING_LOGGER_LOCAL
 
+#ifndef USING_LOGGER_LOCAL // Do not retest ratelimit
 TEST(liblog, __android_log_ratelimit) {
     time_t state = 0;
 
@@ -2929,7 +3097,9 @@
     }
     // Do not test default seconds, to allow liblog to tune freely
 }
+#endif // !USING_LOGGER_LOCAL
 
+#ifndef USING_LOGGER_LOCAL // Do not retest event mapping functionality
 TEST(liblog, android_lookupEventTagNum) {
 #ifdef __ANDROID__
     EventTagMap* map = android_openEventTagMap(NULL);
@@ -2945,3 +3115,4 @@
     GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
+#endif // !USING_LOGGER_LOCAL
diff --git a/liblog/tests/liblog_test_default.cpp b/liblog/tests/liblog_test_default.cpp
new file mode 100644
index 0000000..079ba07
--- /dev/null
+++ b/liblog/tests/liblog_test_default.cpp
@@ -0,0 +1,5 @@
+#ifdef __ANDROID__
+#include <log/log_frontend.h>
+#define TEST_PREFIX android_set_log_frontend(LOGGER_DEFAULT);
+#endif
+#include "liblog_test.cpp"
diff --git a/liblog/tests/liblog_test_local.cpp b/liblog/tests/liblog_test_local.cpp
new file mode 100644
index 0000000..5f7f645
--- /dev/null
+++ b/liblog/tests/liblog_test_local.cpp
@@ -0,0 +1,4 @@
+#include <log/log_frontend.h>
+#define liblog liblog_local
+#define TEST_PREFIX android_set_log_frontend(LOGGER_LOCAL);
+#include "liblog_test.cpp"
diff --git a/liblog/tests/log_id_test.cpp b/liblog/tests/log_id_test.cpp
index 3241534..b8223f1 100644
--- a/liblog/tests/log_id_test.cpp
+++ b/liblog/tests/log_id_test.cpp
@@ -31,7 +31,6 @@
 #endif
 
 TEST(liblog, log_id) {
-#ifdef __ANDROID__
     int count = 0;
 
     for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
@@ -44,13 +43,9 @@
         fprintf(stderr, "log buffer %s\r", name);
     }
     ASSERT_EQ(LOG_ID_MAX, count);
-#else
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
 }
 
 TEST(liblog, __android_log_buf_print) {
-#ifdef __ANDROID__
     EXPECT_LT(0, __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO,
                                          "TEST__android_log_buf_print",
                                          "radio"));
@@ -63,13 +58,9 @@
                                          "TEST__android_log_buf_print",
                                          "main"));
     usleep(1000);
-#else
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
 }
 
 TEST(liblog, __android_log_buf_write) {
-#ifdef __ANDROID__
     EXPECT_LT(0, __android_log_buf_write(LOG_ID_RADIO, ANDROID_LOG_INFO,
                                          "TEST__android_log_buf_write",
                                          "radio"));
@@ -82,26 +73,20 @@
                                          "TEST__android_log_buf_write",
                                          "main"));
     usleep(1000);
-#else
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
 }
 
-#ifdef __ANDROID__
 static void* ConcurrentPrintFn(void *arg) {
     int ret = __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
                                   "TEST__android_log_print", "Concurrent %" PRIuPTR,
                                   reinterpret_cast<uintptr_t>(arg));
     return reinterpret_cast<void*>(ret);
 }
-#endif
 
 #define NUM_CONCURRENT 64
 #define _concurrent_name(a,n) a##__concurrent##n
 #define concurrent_name(a,n) _concurrent_name(a,n)
 
 TEST(liblog, concurrent_name(__android_log_buf_print, NUM_CONCURRENT)) {
-#ifdef __ANDROID__
     pthread_t t[NUM_CONCURRENT];
     int i;
     for (i=0; i < NUM_CONCURRENT; i++) {
@@ -119,7 +104,4 @@
         }
     }
     ASSERT_LT(0, ret);
-#else
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
 }
diff --git a/liblog/tests/log_radio_test.cpp b/liblog/tests/log_radio_test.cpp
index 591748a..ecba777 100644
--- a/liblog/tests/log_radio_test.cpp
+++ b/liblog/tests/log_radio_test.cpp
@@ -27,7 +27,6 @@
 #include <log/log_radio.h>
 
 TEST(liblog, RLOG) {
-#ifdef __ANDROID__
     static const char content[] = "log_radio.h";
     static const char content_false[] = "log_radio.h false";
 
@@ -84,6 +83,7 @@
     usleep(100000);
     RLOGE_IF(false, content_false);
 
+#ifdef __ANDROID__
     // give time for content to long-path through logger
     sleep(1);
 
@@ -112,6 +112,6 @@
 #endif
 
 #else
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
+    GTEST_LOG_(INFO) << "This test does not test end-to-end.\n";
 #endif
 }
diff --git a/liblog/tests/log_system_test.cpp b/liblog/tests/log_system_test.cpp
index b62832e..40e3a63 100644
--- a/liblog/tests/log_system_test.cpp
+++ b/liblog/tests/log_system_test.cpp
@@ -27,7 +27,6 @@
 #include <log/log_system.h>
 
 TEST(liblog, SLOG) {
-#ifdef __ANDROID__
     static const char content[] = "log_system.h";
     static const char content_false[] = "log_system.h false";
 
@@ -84,6 +83,7 @@
     usleep(100000);
     SLOGE_IF(false, content_false);
 
+#ifdef __ANDROID__
     // give time for content to long-path through logger
     sleep(1);
 
@@ -112,6 +112,6 @@
 #endif
 
 #else
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
+    GTEST_LOG_(INFO) << "This test does not test end-to-end.\n";
 #endif
 }
diff --git a/liblog/tests/log_time_test.cpp b/liblog/tests/log_time_test.cpp
index f2601b6..59655ba 100644
--- a/liblog/tests/log_time_test.cpp
+++ b/liblog/tests/log_time_test.cpp
@@ -21,8 +21,6 @@
 #include <log/log_time.h>
 
 TEST(liblog, log_time) {
-#ifdef __ANDROID__
-
 #ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
     log_time(CLOCK_MONOTONIC);
 
@@ -36,8 +34,4 @@
     EXPECT_EQ(tl, ts);
     EXPECT_GE(tl, ts);
     EXPECT_LE(tl, ts);
-
-#else
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
 }
diff --git a/libmetricslogger/Android.bp b/libmetricslogger/Android.bp
new file mode 100644
index 0000000..75eab66
--- /dev/null
+++ b/libmetricslogger/Android.bp
@@ -0,0 +1,64 @@
+// Copyright 2017 The Android Open Source Project
+
+metricslogger_lib_src_files = [
+    "metrics_logger.cpp",
+]
+
+cc_defaults {
+    name: "metricslogger_defaults",
+
+    clang: true,
+    host_supported: true,
+
+    export_include_dirs: ["include"],
+    local_include_dirs: ["include"],
+    shared_libs: ["liblog"],
+    whole_static_libs: ["libgtest_prod"],
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+
+        // 524291 corresponds to sysui_histogram, from
+        // frameworks/base/core/java/com/android/internal/logging/EventLogTags.logtags
+        "-DHISTOGRAM_LOG_TAG=524291",
+    ],
+}
+
+// metricslogger shared library
+// -----------------------------------------------------------------------------
+cc_library_shared {
+    name: "libmetricslogger",
+    srcs: metricslogger_lib_src_files,
+    defaults: ["metricslogger_defaults"],
+}
+
+// metricslogger shared library, debug
+// -----------------------------------------------------------------------------
+cc_library_shared {
+    name: "libmetricslogger_debug",
+    srcs: metricslogger_lib_src_files,
+    defaults: ["metricslogger_defaults"],
+
+    target: {
+        host: {
+            cflags: ["-UNDEBUG"],
+        },
+    },
+}
+
+// Native tests
+// -----------------------------------------------------------------------------
+cc_test {
+    name: "metricslogger_tests",
+    defaults: ["metricslogger_defaults"],
+    shared_libs: [
+        "libbase",
+        "libmetricslogger_debug",
+    ],
+    static_libs: ["libBionicGtestMain"],
+    srcs: [
+        "metrics_logger_test.cpp",
+    ],
+}
diff --git a/bootstat/histogram_logger.h b/libmetricslogger/include/metricslogger/metrics_logger.h
similarity index 72%
rename from bootstat/histogram_logger.h
rename to libmetricslogger/include/metricslogger/metrics_logger.h
index 60c7776..d30e56c 100644
--- a/bootstat/histogram_logger.h
+++ b/libmetricslogger/include/metricslogger/metrics_logger.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -17,10 +17,12 @@
 #include <cstdint>
 #include <string>
 
-namespace bootstat {
+namespace android {
+namespace metricslogger {
 
-// Builds an EventLog buffer named |event| containing |data| and writes
-// the log into the Tron histogram logs.
+// Logs a Tron histogram metric named |event| containing |data| to the Tron log
+// buffer.
 void LogHistogram(const std::string& event, int32_t data);
 
-}  // namespace bootstat
\ No newline at end of file
+}  // namespace metricslogger
+}  // namespace android
diff --git a/bootstat/histogram_logger.cpp b/libmetricslogger/metrics_logger.cpp
similarity index 76%
rename from bootstat/histogram_logger.cpp
rename to libmetricslogger/metrics_logger.cpp
index 73f3295..f8e0174 100644
--- a/bootstat/histogram_logger.cpp
+++ b/libmetricslogger/metrics_logger.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -14,19 +14,19 @@
  * limitations under the License.
  */
 
-#include "histogram_logger.h"
+#include "metricslogger/metrics_logger.h"
 
 #include <cstdlib>
 
-#include <android-base/logging.h>
 #include <log/log_event_list.h>
 
-namespace bootstat {
+namespace android {
+namespace metricslogger {
 
 void LogHistogram(const std::string& event, int32_t data) {
-  LOG(INFO) << "Logging histogram: " << event << " " << data;
   android_log_event_list log(HISTOGRAM_LOG_TAG);
   log << event << data << LOG_ID_EVENTS;
 }
 
-}  // namespace bootstat
+}  // namespace metricslogger
+}  // namespace android
diff --git a/bootstat/uptime_parser.h b/libmetricslogger/metrics_logger_test.cpp
similarity index 71%
rename from bootstat/uptime_parser.h
rename to libmetricslogger/metrics_logger_test.cpp
index 756ae9b..5a30ad7 100644
--- a/bootstat/uptime_parser.h
+++ b/libmetricslogger/metrics_logger_test.cpp
@@ -14,16 +14,11 @@
  * limitations under the License.
  */
 
-#ifndef UPTIME_PARSER_H_
-#define UPTIME_PARSER_H_
+#include "metricslogger/metrics_logger.h"
 
-#include <time.h>
+#include <gtest/gtest.h>
 
-namespace bootstat {
-
-// Returns the number of seconds the system has been on since reboot.
-time_t ParseUptime();
-
-}  // namespace bootstat
-
-#endif  // UPTIME_PARSER_H_
\ No newline at end of file
+TEST(MetricsLoggerTest, AddSingleBootEvent) {
+  android::metricslogger::LogHistogram("test_event", 42);
+  // TODO(jhawkins): Verify the EventLog is updated.
+}
diff --git a/libnativeloader/include/nativeloader/dlext_namespaces.h b/libnativeloader/include/nativeloader/dlext_namespaces.h
index 02e7075..ac64f71 100644
--- a/libnativeloader/include/nativeloader/dlext_namespaces.h
+++ b/libnativeloader/include/nativeloader/dlext_namespaces.h
@@ -22,16 +22,15 @@
 __BEGIN_DECLS
 
 /*
- * Initializes public and anonymous namespaces. The public_ns_sonames is the list of sonames
- * to be included into public namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
- * The libraries in this list should be loaded prior to this call.
+ * Initializes anonymous namespaces. The shared_libs_sonames is the list of sonames
+ * to be shared by default namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
  *
- * The anon_ns_library_path is the search path for anonymous namespace. The anonymous namespace
+ * The library_search_path is the search path for anonymous namespace. The anonymous namespace
  * is used in the case when linker cannot identify the caller of dlopen/dlsym. This happens
  * for the code not loaded by dynamic linker; for example calls from the mono-compiled code.
  */
-extern bool android_init_namespaces(const char* public_ns_sonames,
-                                    const char* anon_ns_library_path);
+extern bool android_init_anonymous_namespace(const char* shared_libs_sonames,
+                                             const char* library_search_path);
 
 
 enum {
@@ -87,6 +86,26 @@
                                                             android_namespace_t* parent);
 
 /*
+ * Creates a link between namespaces. Every link has list of sonames of
+ * shared libraries. These are the libraries which are accessible from
+ * namespace 'from' but loaded within namespace 'to' context.
+ * When to namespace is nullptr this function establishes a link between
+ * 'from' namespace and the default namespace.
+ *
+ * The lookup order of the libraries in namespaces with links is following:
+ * 1. Look inside current namespace using 'this' namespace search path.
+ * 2. Look in linked namespaces
+ * 2.1. Perform soname check - if library soname is not in the list of shared
+ *      libraries sonames skip this link, otherwise
+ * 2.2. Search library using linked namespace search path. Note that this
+ *      step will not go deeper into linked namespaces for this library but
+ *      will do so for DT_NEEDED libraries.
+ */
+extern bool android_link_namespaces(android_namespace_t* from,
+                                    android_namespace_t* to,
+                                    const char* shared_libs_sonames);
+
+/*
  * Get the default library search path.
  * The path will be copied into buffer, which must have space for at least
  * buffer_size chars. Elements are separated with ':', and the path will always
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index d7b5cb5..74f2f1d 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -165,6 +165,11 @@
         return false;
       }
 
+      if (!android_link_namespaces(ns, nullptr, public_libraries_.c_str())) {
+        *error_msg = dlerror();
+        return false;
+      }
+
       native_loader_ns = NativeLoaderNamespace(ns);
     } else {
       native_bridge_namespace_t* ns = NativeBridgeCreateNamespace("classloader-namespace",
@@ -246,7 +251,9 @@
     // For now we rely on CTS test to catch things like this but
     // it should probably be addressed in the future.
     for (const auto& soname : sonames) {
-      dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE);
+      LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
+                          "Error preloading public library %s: %s",
+                          soname.c_str(), dlerror());
     }
 
     public_libraries_ = base::Join(sonames, ':');
@@ -308,8 +315,8 @@
     // code is one example) unknown to linker in which  case linker uses anonymous
     // namespace. The second argument specifies the search path for the anonymous
     // namespace which is the library_path of the classloader.
-    initialized_ = android_init_namespaces(public_libraries_.c_str(),
-                                           is_native_bridge ? nullptr : library_path);
+    initialized_ = android_init_anonymous_namespace(public_libraries_.c_str(),
+                                                    is_native_bridge ? nullptr : library_path);
     if (!initialized_) {
       *error_msg = dlerror();
       return false;
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index fef801a..79bc888 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -561,10 +561,12 @@
 static const char*
 has_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen)
 {
-    if ((end-str) >= (ptrdiff_t)prefixlen && !memcmp(str, prefix, prefixlen))
+    if ((end - str) >= (ptrdiff_t)prefixlen &&
+        (prefixlen == 0 || !memcmp(str, prefix, prefixlen))) {
         return str + prefixlen;
-    else
+    } else {
         return NULL;
+    }
 }
 
 /* Same as strlen(x) for constant string literals ONLY */
diff --git a/libutils/tests/Vector_test.cpp b/libutils/tests/Vector_test.cpp
index 671200f..e074a92 100644
--- a/libutils/tests/Vector_test.cpp
+++ b/libutils/tests/Vector_test.cpp
@@ -74,12 +74,9 @@
     EXPECT_EQ(other[3], 5);
 }
 
-// TODO: gtest isn't capable of parsing Abort messages formatted by
-// Android (fails differently on host and target), so we always need to
-// use an empty error message for death tests.
 TEST_F(VectorTest, SetCapacity_Overflow) {
   Vector<int> vector;
-  EXPECT_DEATH(vector.setCapacity(SIZE_MAX / sizeof(int) + 1), "");
+  EXPECT_DEATH(vector.setCapacity(SIZE_MAX / sizeof(int) + 1), "Assertion failed");
 }
 
 TEST_F(VectorTest, SetCapacity_ShrinkBelowSize) {
@@ -95,20 +92,13 @@
   ASSERT_EQ(8U, vector.capacity());
 }
 
-// NOTE: All of the tests below are useless because of the "TODO" above.
-// We have no way of knowing *why* the process crashed. Given that we're
-// inserting a NULL array, we'll fail with a SIGSEGV eventually. We need
-// the ability to make assertions on the abort message to make sure we're
-// failing for the right reasons.
 TEST_F(VectorTest, _grow_OverflowSize) {
   Vector<int> vector;
   vector.add(1);
 
   // Checks that the size calculation (not the capacity calculation) doesn't
   // overflow : the size here will be (1 + SIZE_MAX).
-  //
-  // EXPECT_DEATH(vector.insertArrayAt(NULL, 0, SIZE_MAX), "new_size_overflow");
-  EXPECT_DEATH(vector.insertArrayAt(NULL, 0, SIZE_MAX), "");
+  EXPECT_DEATH(vector.insertArrayAt(NULL, 0, SIZE_MAX), "new_size overflow");
 }
 
 TEST_F(VectorTest, _grow_OverflowCapacityDoubling) {
@@ -116,18 +106,14 @@
 
   // This should fail because the calculated capacity will overflow even though
   // the size of the vector doesn't.
-  //
-  // EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX - 1)), "new_capacity_overflow");
-  EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX - 1)), "");
+  EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX - 1)), "new_capacity overflow");
 }
 
 TEST_F(VectorTest, _grow_OverflowBufferAlloc) {
   Vector<int> vector;
   // This should fail because the capacity * sizeof(int) overflows, even
   // though the capacity itself doesn't.
-  //
-  // EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX / 2)), "new_alloc_size overflow");
-  EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX / 2)), "");
+  EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX / 2)), "new_alloc_size overflow");
 }
 
 TEST_F(VectorTest, editArray_Shared) {
diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt
index 2fe90d9..4081982 100644
--- a/rootdir/etc/public.libraries.android.txt
+++ b/rootdir/etc/public.libraries.android.txt
@@ -1,4 +1,5 @@
 libandroid.so
+libaaudio.so
 libc.so
 libcamera2ndk.so
 libdl.so
@@ -12,7 +13,6 @@
 liblog.so
 libmediandk.so
 libm.so
-liboboe.so
 libOpenMAXAL.so
 libOpenSLES.so
 libRS.so
diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt
index b35d463..9f0cde1 100644
--- a/rootdir/etc/public.libraries.wear.txt
+++ b/rootdir/etc/public.libraries.wear.txt
@@ -1,4 +1,5 @@
 libandroid.so
+libaaudio.so
 libc.so
 libcamera2ndk.so
 libdl.so
@@ -12,7 +13,6 @@
 liblog.so
 libmediandk.so
 libm.so
-liboboe.so
 libOpenMAXAL.so
 libOpenSLES.so
 libRS.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index c300c1c..fe7e3d0 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -403,6 +403,7 @@
     mkdir /data/misc/boottrace 0771 system shell
     mkdir /data/misc/update_engine 0700 root root
     mkdir /data/misc/trace 0700 root root
+    mkdir /data/misc/reboot 0700 root root
     # profile file layout
     mkdir /data/misc/profiles 0771 system system
     mkdir /data/misc/profiles/cur 0771 system system
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index ed11164..80bb673 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -11,7 +11,7 @@
     onrestart restart media
     onrestart restart netd
     onrestart restart wificond
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks
 
 service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
     class main
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 7084355..36bb443 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -11,9 +11,9 @@
     onrestart restart media
     onrestart restart netd
     onrestart restart wificond
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks
 
-service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
+service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
     class main
     priority -20
     user root
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 0633a68..3b64f6d 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -46,7 +46,7 @@
 /dev/tty0                 0660   root       system
 /dev/graphics/*           0660   root       graphics
 /dev/msm_hw3dm            0660   system     graphics
-/dev/input/*              0660   root       input
+/dev/input/*              0640   system     input
 /dev/eac                  0660   root       audio
 /dev/cam                  0660   root       camera
 /dev/pmem                 0660   system     graphics
diff --git a/storaged/Android.mk b/storaged/Android.mk
index 0e8b574..2adb14d 100644
--- a/storaged/Android.mk
+++ b/storaged/Android.mk
@@ -2,22 +2,30 @@
 
 LOCAL_PATH := $(call my-dir)
 
-LIBSTORAGED_SHARED_LIBRARIES := libbinder libbase libutils libcutils liblog libsysutils libcap libpackagelistparser
+LIBSTORAGED_SHARED_LIBRARIES := \
+    libbinder \
+    libbase \
+    libutils \
+    libcutils \
+    liblog \
+    libsysutils \
+    libpackagelistparser \
+    libbatteryservice \
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := storaged.cpp \
-                  storaged_service.cpp \
-                  storaged_utils.cpp \
-                  storaged_uid_monitor.cpp \
-                  EventLogTags.logtags
+LOCAL_SRC_FILES := \
+    storaged.cpp \
+    storaged_service.cpp \
+    storaged_utils.cpp \
+    storaged_uid_monitor.cpp \
+    EventLogTags.logtags
 
 LOCAL_MODULE := libstoraged
 LOCAL_CFLAGS := -Werror
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include external/googletest/googletest/include
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_SHARED_LIBRARIES := $(LIBSTORAGED_SHARED_LIBRARIES)
-
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h
index 41bdf97..591719e 100644
--- a/storaged/include/storaged.h
+++ b/storaged/include/storaged.h
@@ -26,8 +26,12 @@
 #include <unordered_map>
 #include <vector>
 
+#include <batteryservice/IBatteryPropertiesListener.h>
+
 #include "storaged_uid_monitor.h"
 
+using namespace android;
+
 #define FRIEND_TEST(test_case_name, test_name) \
 friend class test_case_name##_##test_name##_Test
 
@@ -45,6 +49,8 @@
 #define MSEC_TO_USEC ( 1000 )
 #define USEC_TO_NSEC ( 1000 )
 #define SEC_TO_USEC ( 1000000 )
+#define HOUR_TO_SEC ( 3600 )
+#define DAY_TO_SEC ( 3600 * 24 )
 
 // number of attributes diskstats has
 #define DISK_STATS_SIZE ( 11 )
@@ -250,7 +256,8 @@
 #define DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT ( 60 )
 #define DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH ( 3600 )
 #define DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH ( 86400 )
-#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO ( 86400 )
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO ( 3600 )
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT (300)
 
 // UID IO threshold in bytes
 #define DEFAULT_PERIODIC_CHORES_UID_IO_THRESHOLD ( 1024 * 1024 * 1024ULL )
@@ -266,7 +273,7 @@
     int event_time_check_usec;  // check how much cputime spent in event loop
 };
 
-class storaged_t {
+class storaged_t : public BnBatteryPropertiesListener {
 private:
     time_t mTimer;
     storaged_config mConfig;
@@ -292,11 +299,20 @@
     }
 
     std::unordered_map<uint32_t, struct uid_info> get_uids(void) {
-        return mUidm.get_uids();
+        return mUidm.get_uid_io_stats();
     }
-    std::vector<struct uid_event> get_uid_events(void) {
-        return mUidm.dump_events();
+    std::map<uint64_t, std::vector<struct uid_record>> get_uid_records(
+            double hours, uint64_t threshold, bool force_report) {
+        return mUidm.dump(hours, threshold, force_report);
     }
+    void update_uid_io_interval(int interval) {
+        if (interval >= DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT) {
+            mConfig.periodic_chores_interval_uid_io = interval;
+        }
+    }
+
+    void init_battery_service();
+    virtual void batteryPropertiesChanged(struct BatteryProperties props);
 };
 
 // Eventlog tag
diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h
index 9101767..031b7c4 100644
--- a/storaged/include/storaged_uid_monitor.h
+++ b/storaged/include/storaged_uid_monitor.h
@@ -23,10 +23,22 @@
 #include <unordered_map>
 #include <vector>
 
-enum {
-    UID_FOREGROUND = 0,
-    UID_BACKGROUND = 1,
-    UID_STATS_SIZE = 2
+enum uid_stat_t {
+    FOREGROUND = 0,
+    BACKGROUND = 1,
+    UID_STATS = 2
+};
+
+enum charger_stat_t {
+    CHARGER_OFF = 0,
+    CHARGER_ON = 1,
+    CHARGER_STATS = 2
+};
+
+enum io_type_t {
+    READ = 0,
+    WRITE = 1,
+    IO_TYPES = 2
 };
 
 struct uid_io_stats {
@@ -39,36 +51,52 @@
 struct uid_info {
     uint32_t uid;                   // user id
     std::string name;               // package name
-    struct uid_io_stats io[UID_STATS_SIZE];      // [0]:foreground [1]:background
+    struct uid_io_stats io[UID_STATS];    // [0]:foreground [1]:background
 };
 
-struct uid_event {
+struct uid_io_usage {
+    uint64_t bytes[IO_TYPES][UID_STATS][CHARGER_STATS];
+};
+
+struct uid_record {
     std::string name;
-    uint64_t fg_read_bytes;
-    uint64_t fg_write_bytes;
-    uint64_t bg_read_bytes;
-    uint64_t bg_write_bytes;
-    uint64_t interval;
+    struct uid_io_usage ios;
 };
 
 class uid_monitor {
 private:
-    std::unordered_map<uint32_t, struct uid_info> last_uids;
-    std::vector<struct uid_event> events;
-    sem_t events_lock;
-    void set_last_uids(std::unordered_map<uint32_t, struct uid_info>&& uids, uint64_t ts);
-    int interval;  // monitor interval in seconds
-    int threshold; // monitor threshold in bytes
-    uint64_t last_report_ts; // timestamp of last report in nsec
+    // last dump from /proc/uid_io/stats, uid -> uid_info
+    std::unordered_map<uint32_t, struct uid_info> last_uid_io_stats;
+    // current io usage for next report, app name -> uid_io_usage
+    std::unordered_map<std::string, struct uid_io_usage> curr_io_stats;
+    // io usage records, timestamp -> vector of events
+    std::map<uint64_t, std::vector<struct uid_record>> records;
+    // charger ON/OFF
+    charger_stat_t charger_stat;
+    // protects curr_io_stats, last_uid_io_stats, records and charger_stat
+    sem_t um_lock;
+
+    // reads from /proc/uid_io/stats
+    std::unordered_map<uint32_t, struct uid_info> get_uid_io_stats_locked();
+    // flushes curr_io_stats to records
+    void add_records_locked(uint64_t curr_ts);
+    // updates curr_io_stats and set last_uid_io_stats
+    void update_curr_io_stats_locked();
+
 public:
     uid_monitor();
     ~uid_monitor();
-    void set_periodic_chores_params(int intvl, int thold) { interval = intvl; threshold = thold; }
-    int get_periodic_chores_interval() { return interval; }
-    std::unordered_map<uint32_t, struct uid_info> get_uids();
+    // called by storaged main thread
+    void init(charger_stat_t stat);
+    // called by storaged -u
+    std::unordered_map<uint32_t, struct uid_info> get_uid_io_stats();
+    // called by dumpsys
+    std::map<uint64_t, std::vector<struct uid_record>> dump(
+        double hours, uint64_t threshold, bool force_report);
+    // called by battery properties listener
+    void set_charger_state(charger_stat_t stat);
+    // called by storaged periodic_chore or dump with force_report
     void report();
-    void add_event(const struct uid_event& event);
-    std::vector<struct uid_event> dump_events();
 };
 
 #endif /* _STORAGED_UID_MONITOR_H_ */
diff --git a/storaged/main.cpp b/storaged/main.cpp
index 9ad420e..f5a8f39 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -55,32 +55,6 @@
 
     if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) return -1;
 
-    if (prctl(PR_SET_KEEPCAPS, 1) < 0) return -1;
-
-    std::unique_ptr<struct _cap_struct, int(*)(void *)> caps(cap_init(), cap_free);
-    if (cap_clear(caps.get()) < 0) return -1;
-    cap_value_t cap_value[] = {
-        CAP_SETGID,
-        CAP_SETUID
-    };
-    if (cap_set_flag(caps.get(), CAP_PERMITTED,
-                     arraysize(cap_value), cap_value,
-                     CAP_SET) < 0) return -1;
-    if (cap_set_flag(caps.get(), CAP_EFFECTIVE,
-                     arraysize(cap_value), cap_value,
-                     CAP_SET) < 0) return -1;
-    if (cap_set_proc(caps.get()) < 0)
-        return -1;
-
-    if (setgid(AID_SYSTEM) != 0) return -1;
-
-    if (setuid(AID_SYSTEM) != 0) return -1;
-
-    if (cap_set_flag(caps.get(), CAP_PERMITTED, 2, cap_value, CAP_CLEAR) < 0) return -1;
-    if (cap_set_flag(caps.get(), CAP_EFFECTIVE, 2, cap_value, CAP_CLEAR) < 0) return -1;
-    if (cap_set_proc(caps.get()) < 0)
-        return -1;
-
     return 0;
 }
 
@@ -88,6 +62,8 @@
 void* storaged_main(void* s) {
     storaged_t* storaged = (storaged_t*)s;
 
+    storaged->init_battery_service();
+
     LOG_TO(SYSTEM, INFO) << "storaged: Start";
 
     for (;;) {
@@ -104,9 +80,6 @@
     fflush(stdout);
 }
 
-#define HOUR_TO_SEC ( 3600 )
-#define DAY_TO_SEC ( 3600 * 24 )
-
 int main(int argc, char** argv) {
     int flag_main_service = 0;
     int flag_dump_uid = 0;
diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp
index 73df6d0..2f02074 100644
--- a/storaged/storaged.cpp
+++ b/storaged/storaged.cpp
@@ -21,6 +21,9 @@
 #include <unistd.h>
 
 #include <android-base/logging.h>
+#include <batteryservice/BatteryServiceConstants.h>
+#include <batteryservice/IBatteryPropertiesRegistrar.h>
+#include <binder/IServiceManager.h>
 #include <cutils/properties.h>
 #include <log/log.h>
 
@@ -157,6 +160,43 @@
     }
 }
 
+static sp<IBatteryPropertiesRegistrar> get_battery_properties_service() {
+    sp<IServiceManager> sm = defaultServiceManager();
+    if (sm == NULL) return NULL;
+
+    sp<IBinder> binder = sm->getService(String16("batteryproperties"));
+    if (binder == NULL) return NULL;
+
+    sp<IBatteryPropertiesRegistrar> battery_properties =
+        interface_cast<IBatteryPropertiesRegistrar>(binder);
+
+    return battery_properties;
+}
+
+static inline charger_stat_t is_charger_on(int64_t prop) {
+    return (prop == BATTERY_STATUS_CHARGING || prop == BATTERY_STATUS_FULL) ?
+        CHARGER_ON : CHARGER_OFF;
+}
+
+void storaged_t::batteryPropertiesChanged(struct BatteryProperties props) {
+    mUidm.set_charger_state(is_charger_on(props.batteryStatus));
+}
+
+void storaged_t::init_battery_service() {
+    sp<IBatteryPropertiesRegistrar> battery_properties = get_battery_properties_service();
+    if (battery_properties == NULL) {
+        LOG_TO(SYSTEM, WARNING) << "failed to find batteryproperties service";
+        return;
+    }
+
+    struct BatteryProperty val;
+    battery_properties->getProperty(BATTERY_PROP_BATTERY_STATUS, &val);
+    mUidm.init(is_charger_on(val.valueInt64));
+
+    // register listener after init uid_monitor
+    battery_properties->registerListener(this);
+}
+
 /* storaged_t */
 storaged_t::storaged_t(void) {
     mConfig.emmc_available = (access(EMMC_ECSD_PATH, R_OK) >= 0);
@@ -181,9 +221,8 @@
     mConfig.periodic_chores_interval_emmc_info_publish =
         property_get_int32("ro.storaged.emmc_info_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH);
 
-    mUidm.set_periodic_chores_params(
-        property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO),
-        property_get_int32("ro.storaged.uid_io.threshold", DEFAULT_PERIODIC_CHORES_UID_IO_THRESHOLD));
+    mConfig.periodic_chores_interval_uid_io =
+        property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO);
 
     mStarttime = time(NULL);
 }
@@ -204,7 +243,7 @@
     }
 
     if (mConfig.proc_uid_io_available && mTimer &&
-            (mTimer % mUidm.get_periodic_chores_interval()) == 0) {
+            (mTimer % mConfig.periodic_chores_interval_uid_io) == 0) {
          mUidm.report();
     }
 
diff --git a/storaged/storaged.rc b/storaged/storaged.rc
index 53fdb85..bb7c623 100644
--- a/storaged/storaged.rc
+++ b/storaged/storaged.rc
@@ -2,3 +2,5 @@
     class main
     file /d/mmc0/mmc0:0001/ext_csd r
     writepid /dev/cpuset/system-background/tasks
+    user root
+    group system package_info
\ No newline at end of file
diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp
index 86a2b21..9c8cbf0 100644
--- a/storaged/storaged_service.cpp
+++ b/storaged/storaged_service.cpp
@@ -78,7 +78,7 @@
     return uids_v;
 }
 
-status_t Storaged::dump(int fd, const Vector<String16>& /* args */) {
+status_t Storaged::dump(int fd, const Vector<String16>& args) {
     IPCThreadState* self = IPCThreadState::self();
     const int pid = self->getCallingPid();
     const int uid = self->getCallingUid();
@@ -88,19 +88,61 @@
         return PERMISSION_DENIED;
     }
 
-    const std::vector<struct uid_event>& events = storaged.get_uid_events();
-    for (const auto& event : events) {
-        dprintf(fd, "%s %llu %llu %llu %llu %llu\n", event.name.c_str(),
-            (unsigned long long)event.fg_read_bytes,
-            (unsigned long long)event.fg_write_bytes,
-            (unsigned long long)event.bg_read_bytes,
-            (unsigned long long)event.bg_write_bytes,
-            (unsigned long long)event.interval);
+    double hours = 0;
+    int time_window = 0;
+    uint64_t threshold = 0;
+    bool force_report = false;
+    for (size_t i = 0; i < args.size(); i++) {
+        const auto& arg = args[i];
+        if (arg == String16("--hours")) {
+            if (++i >= args.size())
+                break;
+            hours = stod(String16::std_string(args[i]));
+            continue;
+        }
+        if (arg == String16("--time_window")) {
+            if (++i >= args.size())
+                break;
+            time_window = stoi(String16::std_string(args[i]));
+            continue;
+        }
+        if (arg == String16("--threshold")) {
+            if (++i >= args.size())
+                break;
+            threshold = stoll(String16::std_string(args[i]));
+            continue;
+        }
+        if (arg == String16("--force")) {
+            force_report = true;
+            continue;
+        }
     }
+
+    const std::map<uint64_t, std::vector<struct uid_record>>& records =
+                storaged.get_uid_records(hours, threshold, force_report);
+    for (const auto& it : records) {
+        dprintf(fd, "%llu\n", (unsigned long long)it.first);
+        for (const auto& record : it.second) {
+            dprintf(fd, "%s %llu %llu %llu %llu %llu %llu %llu %llu\n",
+                record.name.c_str(),
+                (unsigned long long)record.ios.bytes[READ][FOREGROUND][CHARGER_OFF],
+                (unsigned long long)record.ios.bytes[WRITE][FOREGROUND][CHARGER_OFF],
+                (unsigned long long)record.ios.bytes[READ][BACKGROUND][CHARGER_OFF],
+                (unsigned long long)record.ios.bytes[WRITE][BACKGROUND][CHARGER_OFF],
+                (unsigned long long)record.ios.bytes[READ][FOREGROUND][CHARGER_ON],
+                (unsigned long long)record.ios.bytes[WRITE][FOREGROUND][CHARGER_ON],
+                (unsigned long long)record.ios.bytes[READ][BACKGROUND][CHARGER_ON],
+                (unsigned long long)record.ios.bytes[WRITE][BACKGROUND][CHARGER_ON]);
+        }
+    }
+
+    if (time_window) {
+        storaged.update_uid_io_interval(time_window);
+    }
+
     return NO_ERROR;
 }
 
-
 sp<IStoraged> get_storaged_service() {
     sp<IServiceManager> sm = defaultServiceManager();
     if (sm == NULL) return NULL;
diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp
index 5f664e4..3b893b5 100644
--- a/storaged/storaged_uid_monitor.cpp
+++ b/storaged/storaged_uid_monitor.cpp
@@ -49,20 +49,19 @@
     return true;
 }
 
-void uid_monitor::set_last_uids(std::unordered_map<uint32_t, struct uid_info>&& uids,
-            uint64_t ts)
+std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats()
 {
-    last_uids = uids;
-    last_report_ts = ts;
-}
+    std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
+    return get_uid_io_stats_locked();
+};
 
-std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uids()
+std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats_locked()
 {
-    std::unordered_map<uint32_t, struct uid_info> uids;
+    std::unordered_map<uint32_t, struct uid_info> uid_io_stats;
     std::string buffer;
     if (!android::base::ReadFileToString(UID_IO_STATS_PATH, &buffer)) {
         PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed";
-        return uids;
+        return uid_io_stats;
     }
 
     std::stringstream ss(buffer);
@@ -70,114 +69,190 @@
     bool refresh_uid = false;
 
     while (ss >> u.uid) {
-        ss >> u.io[UID_FOREGROUND].rchar >> u.io[UID_FOREGROUND].wchar
-           >> u.io[UID_FOREGROUND].read_bytes >> u.io[UID_FOREGROUND].write_bytes
-           >> u.io[UID_BACKGROUND].rchar >> u.io[UID_BACKGROUND].wchar
-           >> u.io[UID_BACKGROUND].read_bytes >> u.io[UID_BACKGROUND].write_bytes;
+        ss >> u.io[FOREGROUND].rchar >> u.io[FOREGROUND].wchar
+           >> u.io[FOREGROUND].read_bytes >> u.io[FOREGROUND].write_bytes
+           >> u.io[BACKGROUND].rchar >> u.io[BACKGROUND].wchar
+           >> u.io[BACKGROUND].read_bytes >> u.io[BACKGROUND].write_bytes;
 
         if (!ss.good()) {
             ss.clear(std::ios_base::badbit);
             break;
         }
 
-        if (last_uids.find(u.uid) == last_uids.end()) {
+        if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) {
             refresh_uid = true;
             u.name = std::to_string(u.uid);
         } else {
-            u.name = last_uids[u.uid].name;
+            u.name = last_uid_io_stats[u.uid].name;
         }
-        uids[u.uid] = u;
+        uid_io_stats[u.uid] = u;
     }
 
     if (!ss.eof() || ss.bad()) {
-        uids.clear();
+        uid_io_stats.clear();
         LOG_TO(SYSTEM, ERROR) << "read UID IO stats failed";
     }
 
     if (refresh_uid) {
-        packagelist_parse(packagelist_parse_cb, &uids);
+        packagelist_parse(packagelist_parse_cb, &uid_io_stats);
     }
 
-    return uids;
+    return uid_io_stats;
 }
 
-static const int MAX_UID_EVENTS = 1000;
+static const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours
 
-void uid_monitor::add_event(const struct uid_event& event)
+static inline int records_size(
+    const std::map<uint64_t, std::vector<struct uid_record>>& records)
 {
-    std::unique_ptr<lock_t> lock(new lock_t(&events_lock));
+    int count = 0;
+    for (auto const& it : records) {
+        count += it.second.size();
+    }
+    return count;
+}
 
-    if (events.size() > MAX_UID_EVENTS) {
-        LOG_TO(SYSTEM, ERROR) << "event buffer full";
+static struct uid_io_usage zero_io_usage;
+
+void uid_monitor::add_records_locked(uint64_t curr_ts)
+{
+    // remove records more than 5 days old
+    if (curr_ts > 5 * DAY_TO_SEC) {
+        auto it = records.lower_bound(curr_ts - 5 * DAY_TO_SEC);
+        records.erase(records.begin(), it);
+    }
+
+    std::vector<struct uid_record> new_records;
+    for (const auto& p : curr_io_stats) {
+        struct uid_record record = {};
+        record.name = p.first;
+        record.ios = p.second;
+        if (memcmp(&record.ios, &zero_io_usage, sizeof(struct uid_io_usage))) {
+            new_records.push_back(record);
+        }
+    }
+
+    curr_io_stats.clear();
+
+    if (new_records.empty())
+      return;
+
+    // make some room for new records
+    int overflow = records_size(records) +
+        new_records.size() - MAX_UID_RECORDS_SIZE;
+    while (overflow > 0 && records.size() > 0) {
+        overflow -= records[0].size();
+        records.erase(records.begin());
+    }
+
+    records[curr_ts].insert(records[curr_ts].end(),
+        new_records.begin(), new_records.end());
+}
+
+std::map<uint64_t, std::vector<struct uid_record>> uid_monitor::dump(
+    double hours, uint64_t threshold, bool force_report)
+{
+    if (force_report) {
+        report();
+    }
+
+    std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
+
+    std::map<uint64_t, std::vector<struct uid_record>> dump_records;
+    uint64_t first_ts = 0;
+
+    if (hours != 0) {
+        first_ts = time(NULL) - hours * HOUR_TO_SEC;
+    }
+
+    for (auto it = records.lower_bound(first_ts); it != records.end(); ++it) {
+        const std::vector<struct uid_record>& recs = it->second;
+        std::vector<struct uid_record> filtered;
+
+        for (const auto& rec : recs) {
+            if (rec.ios.bytes[READ][FOREGROUND][CHARGER_ON] +
+                rec.ios.bytes[READ][FOREGROUND][CHARGER_OFF] +
+                rec.ios.bytes[READ][BACKGROUND][CHARGER_ON] +
+                rec.ios.bytes[READ][BACKGROUND][CHARGER_OFF] +
+                rec.ios.bytes[WRITE][FOREGROUND][CHARGER_ON] +
+                rec.ios.bytes[WRITE][FOREGROUND][CHARGER_OFF] +
+                rec.ios.bytes[WRITE][BACKGROUND][CHARGER_ON] +
+                rec.ios.bytes[WRITE][BACKGROUND][CHARGER_OFF] > threshold) {
+                filtered.push_back(rec);
+            }
+        }
+        dump_records.insert(
+            std::pair<uint64_t, std::vector<struct uid_record>>(it->first, filtered));
+    }
+
+    return dump_records;
+}
+
+void uid_monitor::update_curr_io_stats_locked()
+{
+    std::unordered_map<uint32_t, struct uid_info> uid_io_stats =
+        get_uid_io_stats_locked();
+    if (uid_io_stats.empty()) {
         return;
     }
-    events.push_back(event);
-}
 
-std::vector<struct uid_event> uid_monitor::dump_events()
-{
-    std::unique_ptr<lock_t> lock(new lock_t(&events_lock));
-    std::vector<struct uid_event> dump_events = events;
+    for (const auto& it : uid_io_stats) {
+        const struct uid_info& uid = it.second;
 
-    events.clear();
-    return dump_events;
+        if (curr_io_stats.find(uid.name) == curr_io_stats.end()) {
+          curr_io_stats[uid.name] = {};
+        }
+
+        struct uid_io_usage& usage = curr_io_stats[uid.name];
+        usage.bytes[READ][FOREGROUND][charger_stat] +=
+            uid.io[FOREGROUND].read_bytes -
+            last_uid_io_stats[uid.uid].io[FOREGROUND].read_bytes;
+        usage.bytes[READ][BACKGROUND][charger_stat] +=
+            uid.io[BACKGROUND].read_bytes -
+            last_uid_io_stats[uid.uid].io[BACKGROUND].read_bytes;
+        usage.bytes[WRITE][FOREGROUND][charger_stat] +=
+            uid.io[FOREGROUND].write_bytes -
+            last_uid_io_stats[uid.uid].io[FOREGROUND].write_bytes;
+        usage.bytes[WRITE][BACKGROUND][charger_stat] +=
+            uid.io[BACKGROUND].write_bytes -
+            last_uid_io_stats[uid.uid].io[BACKGROUND].write_bytes;;
+    }
+
+    last_uid_io_stats = uid_io_stats;
 }
 
 void uid_monitor::report()
 {
-    struct timespec ts;
+    std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
 
-    // Use monotonic to exclude suspend time so that we measure IO bytes/sec
-    // when system is running.
-    if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
-        PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
+    update_curr_io_stats_locked();
+    add_records_locked(time(NULL));
+}
+
+void uid_monitor::set_charger_state(charger_stat_t stat)
+{
+    std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
+
+    if (charger_stat == stat) {
         return;
     }
 
-    uint64_t curr_ts = ts.tv_sec * NS_PER_SEC + ts.tv_nsec;
-    uint64_t ts_delta = curr_ts - last_report_ts;
-    uint64_t adjusted_threshold = threshold * ((double)ts_delta / interval / NS_PER_SEC);
+    update_curr_io_stats_locked();
+    charger_stat = stat;
+}
 
-    std::unordered_map<uint32_t, struct uid_info> uids = get_uids();
-    if (uids.empty()) {
-        return;
-    }
-
-    for (const auto& it : uids) {
-        const struct uid_info& uid = it.second;
-        struct uid_event event;
-
-        event.name = uid.name;
-        event.fg_read_bytes = uid.io[UID_FOREGROUND].read_bytes -
-            last_uids[uid.uid].io[UID_FOREGROUND].read_bytes;;
-        event.fg_write_bytes = uid.io[UID_FOREGROUND].write_bytes -
-            last_uids[uid.uid].io[UID_FOREGROUND].write_bytes;;
-        event.bg_read_bytes = uid.io[UID_BACKGROUND].read_bytes -
-            last_uids[uid.uid].io[UID_BACKGROUND].read_bytes;;
-        event.bg_write_bytes = uid.io[UID_BACKGROUND].write_bytes -
-            last_uids[uid.uid].io[UID_BACKGROUND].write_bytes;;
-        event.interval = uint64_t(ts_delta / NS_PER_SEC);
-
-        add_event(event);
-    }
-
-    set_last_uids(std::move(uids), curr_ts);
+void uid_monitor::init(charger_stat_t stat)
+{
+    charger_stat = stat;
+    last_uid_io_stats = get_uid_io_stats();
 }
 
 uid_monitor::uid_monitor()
 {
-    struct timespec ts;
-
-    if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
-        PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
-        return;
-    }
-    last_report_ts = ts.tv_sec * NS_PER_SEC + ts.tv_nsec;
-
-    sem_init(&events_lock, 0, 1);
+    sem_init(&um_lock, 0, 1);
 }
 
 uid_monitor::~uid_monitor()
 {
-    sem_destroy(&events_lock);
+    sem_destroy(&um_lock);
 }
diff --git a/storaged/storaged_utils.cpp b/storaged/storaged_utils.cpp
index 51ea64f..1ef89af 100644
--- a/storaged/storaged_utils.cpp
+++ b/storaged/storaged_utils.cpp
@@ -247,7 +247,7 @@
 
 static bool cmp_uid_info(struct uid_info l, struct uid_info r) {
     // Compare background I/O first.
-    for (int i = UID_STATS_SIZE - 1; i >= 0; i--) {
+    for (int i = UID_STATS - 1; i >= 0; i--) {
         uint64_t l_bytes = l.io[i].read_bytes + l.io[i].write_bytes;
         uint64_t r_bytes = r.io[i].read_bytes + r.io[i].write_bytes;
         uint64_t l_chars = l.io[i].rchar + l.io[i].wchar;
diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp
index 5395b9a..9e03c50 100644
--- a/storaged/tests/storaged_test.cpp
+++ b/storaged/tests/storaged_test.cpp
@@ -33,7 +33,7 @@
 
 static void pause(uint32_t sec) {
     const char* path = "/cache/test";
-    int fd = open(path, O_WRONLY | O_CREAT);
+    int fd = open(path, O_WRONLY | O_CREAT, 0600);
     ASSERT_LT(-1, fd);
     char buffer[2048];
     memset(buffer, 1, sizeof(buffer));
diff --git a/toolbox/getevent.c b/toolbox/getevent.c
index e6def6b..1fb315c 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -321,7 +321,7 @@
     char idstr[80];
     struct input_id id;
 
-    fd = open(device, O_RDWR);
+    fd = open(device, O_RDONLY);
     if(fd < 0) {
         if(print_flags & PRINT_DEVICE_ERRORS)
             fprintf(stderr, "could not open %s, %s\n", device, strerror(errno));
diff --git a/tzdatacheck/tzdatacheck.cpp b/tzdatacheck/tzdatacheck.cpp
index fb5c84b..769f0f5 100644
--- a/tzdatacheck/tzdatacheck.cpp
+++ b/tzdatacheck/tzdatacheck.cpp
@@ -30,26 +30,48 @@
 
 #include "android-base/logging.h"
 
-static const char* BUNDLE_VERSION_FILENAME = "/bundle_version";
-// bundle_version is an ASCII file consisting of 17 bytes in the form: AAA.BBB|CCCCC|DDD
-// AAA.BBB is the major/minor version of the bundle format (e.g. 001.001),
+// The name of the file containing the distro version information.
+// See also libcore.tzdata.update2.TimeZoneDistro / libcore.tzdata.update2.DistroVersion.
+static const char* DISTRO_VERSION_FILENAME = "/distro_version";
+
+// distro_version is an ASCII file consisting of 17 bytes in the form: AAA.BBB|CCCCC|DDD
+// AAA.BBB is the major/minor version of the distro format (e.g. 001.001),
 // CCCCC is the rules version (e.g. 2016g)
-// DDD is the android revision for this rules version to allow for bundle corrections (e.g. 001)
+// DDD is the android revision for this rules version to allow for distro corrections (e.g. 001)
 // We only need the first 13 to determine if it is suitable for the device.
-static const int BUNDLE_VERSION_LENGTH = 13;
-// The major version of the bundle format supported by this code as a null-terminated char[].
-static const char REQUIRED_BUNDLE_VERSION[] = "001";
-static const size_t REQUIRED_BUNDLE_VERSION_LEN = sizeof(REQUIRED_BUNDLE_VERSION) - 1; // exclude \0
+static const int DISTRO_VERSION_LENGTH = 13;
+
+// The major version of the distro format supported by this code as a null-terminated char[].
+// See also libcore.tzdata.update2.TimeZoneDistro / libcore.tzdata.update2.DistroVersion.
+static const char SUPPORTED_DISTRO_MAJOR_VERSION[] = "001";
+
+// The length of the distro format major version excluding the \0
+static const size_t SUPPORTED_DISTRO_MAJOR_VERSION_LEN = sizeof(SUPPORTED_DISTRO_MAJOR_VERSION) - 1;
+
+// The minor version of the distro format supported by this code as a null-terminated char[].
+// See also libcore.tzdata.update2.TimeZoneDistro / libcore.tzdata.update2.DistroVersion.
+static const char SUPPORTED_DISTRO_MINOR_VERSION[] = "001";
+
+// The length of the distro format minor version excluding the \0
+static const size_t SUPPORTED_DISTRO_MINOR_VERSION_LEN = sizeof(SUPPORTED_DISTRO_MINOR_VERSION) - 1;
+
+// The length of the distro format version. e.g. 001.001
+static const size_t SUPPORTED_DISTRO_VERSION_LEN =
+        SUPPORTED_DISTRO_MAJOR_VERSION_LEN + SUPPORTED_DISTRO_MINOR_VERSION_LEN + 1;
+
 // The length of the IANA rules version bytes. e.g. 2016a
 static const size_t RULES_VERSION_LEN = 5;
-// Bundle version bytes are: AAA.BBB|CCCCC - the rules version is CCCCC
-static const size_t BUNDLE_VERSION_RULES_IDX = 8;
 
+// Distro version bytes are: AAA.BBB|CCCCC - the rules version is CCCCC
+static const size_t DISTRO_VERSION_RULES_IDX = 8;
+
+// See also libcore.tzdata.update2.TimeZoneDistro.
 static const char* TZDATA_FILENAME = "/tzdata";
+
 // tzdata file header (as much as we need for the version):
 // byte[11] tzdata_version  -- e.g. "tzdata2012f"
 static const int TZ_HEADER_LENGTH = 11;
-// The major version of the bundle format supported by this code as a null-terminated char[].
+
 static const char TZ_DATA_HEADER_PREFIX[] = "tzdata";
 static const size_t TZ_DATA_HEADER_PREFIX_LEN = sizeof(TZ_DATA_HEADER_PREFIX) - 1; // exclude \0
 
@@ -57,7 +79,7 @@
 static void usage() {
     std::cerr << "Usage: tzdatacheck SYSTEM_TZ_DIR DATA_TZ_DIR\n"
             "\n"
-            "Checks whether any timezone update bundle in DATA_TZ_DIR is compatible with the\n"
+            "Checks whether any timezone update distro in DATA_TZ_DIR is compatible with the\n"
             "current Android release and better than or the same as base system timezone rules in\n"
             "SYSTEM_TZ_DIR. If the timezone rules in SYSTEM_TZ_DIR are a higher version than the\n"
             "one in DATA_TZ_DIR the DATA_TZ_DIR is renamed and then deleted.\n";
@@ -108,8 +130,8 @@
     return true;
 }
 
-static bool checkValidBundleVersion(const char* buffer) {
-    // See BUNDLE_VERSION_LENGTH comments above for a description of the format.
+static bool checkValidDistroVersion(const char* buffer) {
+    // See DISTRO_VERSION_LENGTH comments above for a description of the format.
     size_t i = 0;
     if (!checkDigits(buffer, 3, &i)) {
       return false;
@@ -246,13 +268,13 @@
 }
 
 /*
- * Deletes the timezone update bundle directory.
+ * Deletes the timezone update distro directory.
  */
-static void deleteUpdateBundleDir(std::string& bundleDirName) {
-    LOG(INFO) << "Removing: " << bundleDirName;
-    bool deleted = deleteDir(bundleDirName);
+static void deleteUpdateDistroDir(std::string& distroDirName) {
+    LOG(INFO) << "Removing: " << distroDirName;
+    bool deleted = deleteDir(distroDirName);
     if (!deleted) {
-        LOG(WARNING) << "Deletion of bundle dir " << bundleDirName << " was not successful";
+        LOG(WARNING) << "Deletion of distro dir " << distroDirName << " was not successful";
     }
 }
 
@@ -278,60 +300,83 @@
     const char* systemZoneInfoDir = argv[1];
     const char* dataZoneInfoDir = argv[2];
 
-    // Check the bundle directory exists. If it does not, exit quickly: nothing to do.
+    // Check the distro directory exists. If it does not, exit quickly: nothing to do.
     std::string dataCurrentDirName(dataZoneInfoDir);
     dataCurrentDirName += "/current";
     int dataCurrentDirStatus = checkPath(dataCurrentDirName);
     if (dataCurrentDirStatus == NONE) {
-        LOG(INFO) << "timezone bundle dir " << dataCurrentDirName
+        LOG(INFO) << "timezone distro dir " << dataCurrentDirName
                 << " does not exist. No action required.";
         return 0;
     }
-    // If the bundle directory path is not a directory or we can't stat() the path, exit with a
+    // If the distro directory path is not a directory or we can't stat() the path, exit with a
     // warning: either there's a problem accessing storage or the world is not as it should be;
     // nothing to do.
     if (dataCurrentDirStatus != IS_DIR) {
-        LOG(WARNING) << "Current bundle dir " << dataCurrentDirName
+        LOG(WARNING) << "Current distro dir " << dataCurrentDirName
                 << " could not be accessed or is not a directory. result=" << dataCurrentDirStatus;
         return 2;
     }
 
-    // Check the installed bundle version.
-    std::string bundleVersionFileName(dataCurrentDirName);
-    bundleVersionFileName += BUNDLE_VERSION_FILENAME;
-    std::vector<char> bundleVersion;
-    bundleVersion.reserve(BUNDLE_VERSION_LENGTH);
-    bool bundleVersionReadOk =
-            readBytes(bundleVersionFileName, bundleVersion.data(), BUNDLE_VERSION_LENGTH);
-    if (!bundleVersionReadOk) {
-        LOG(WARNING) << "bundle version file " << bundleVersionFileName
-                << " does not exist or is too short. Deleting bundle dir.";
+    // Check the installed distro version.
+    std::string distroVersionFileName(dataCurrentDirName);
+    distroVersionFileName += DISTRO_VERSION_FILENAME;
+    std::vector<char> distroVersion;
+    distroVersion.reserve(DISTRO_VERSION_LENGTH);
+    bool distroVersionReadOk =
+            readBytes(distroVersionFileName, distroVersion.data(), DISTRO_VERSION_LENGTH);
+    if (!distroVersionReadOk) {
+        LOG(WARNING) << "distro version file " << distroVersionFileName
+                << " does not exist or is too short. Deleting distro dir.";
         // Implies the contents of the data partition is corrupt in some way. Try to clean up.
         deleteConfigUpdaterMetadataDir(dataZoneInfoDir);
-        deleteUpdateBundleDir(dataCurrentDirName);
+        deleteUpdateDistroDir(dataCurrentDirName);
         return 3;
     }
 
-    if (!checkValidBundleVersion(bundleVersion.data())) {
-        LOG(WARNING) << "bundle version file " << bundleVersionFileName
-                << " is not valid. Deleting bundle dir.";
+    if (!checkValidDistroVersion(distroVersion.data())) {
+        LOG(WARNING) << "distro version file " << distroVersionFileName
+                << " is not valid. Deleting distro dir.";
         // Implies the contents of the data partition is corrupt in some way. Try to clean up.
         deleteConfigUpdaterMetadataDir(dataZoneInfoDir);
-        deleteUpdateBundleDir(dataCurrentDirName);
+        deleteUpdateDistroDir(dataCurrentDirName);
         return 4;
     }
 
-    // Check the first 3 bytes of the bundleVersionHeader: these are the major version (e.g. 001).
-    // It must match exactly to be ok. The minor version is currently ignored.
-    if (strncmp(&bundleVersion[0], REQUIRED_BUNDLE_VERSION, REQUIRED_BUNDLE_VERSION_LEN) != 0) {
-        LOG(INFO) << "bundle version file " << bundleVersionFileName
-                << " is not the required version " << REQUIRED_BUNDLE_VERSION
-                << ". Deleting bundle dir.";
-        // This shouldn't happen with 001, but it in future, this will imply there has been an OTA
-        // and the installed bundle is not compatible with the new version of Android. Remove the
-        // installed bundle.
+    std::string actualDistroVersion =
+            std::string(distroVersion.data(), SUPPORTED_DISTRO_VERSION_LEN);
+    // Check the first 3 bytes of the distro version: these are the major version (e.g. 001).
+    // It must match the one we support exactly to be ok.
+    if (strncmp(
+            &distroVersion[0],
+            SUPPORTED_DISTRO_MAJOR_VERSION,
+            SUPPORTED_DISTRO_MAJOR_VERSION_LEN) != 0) {
+
+        LOG(INFO) << "distro version file " << distroVersionFileName
+                << " major version is not the required version " << SUPPORTED_DISTRO_MAJOR_VERSION
+                << ", was \"" << actualDistroVersion << "\". Deleting distro dir.";
+        // This implies there has been an OTA and the installed distro is not compatible with the
+        // new version of Android. Remove the installed distro.
         deleteConfigUpdaterMetadataDir(dataZoneInfoDir);
-        deleteUpdateBundleDir(dataCurrentDirName);
+        deleteUpdateDistroDir(dataCurrentDirName);
+        return 5;
+    }
+
+    // Check the last 3 bytes of the distro version: these are the minor version (e.g. 001).
+    // If the version in the distro is < the minor version required by this device it cannot be
+    // used.
+    if (strncmp(
+            &distroVersion[4],
+            SUPPORTED_DISTRO_MINOR_VERSION,
+            SUPPORTED_DISTRO_MINOR_VERSION_LEN) < 0) {
+
+        LOG(INFO) << "distro version file " << distroVersionFileName
+                << " minor version is not the required version " << SUPPORTED_DISTRO_MINOR_VERSION
+                << ", was \"" << actualDistroVersion << "\". Deleting distro dir.";
+        // This implies there has been an OTA and the installed distro is not compatible with the
+        // new version of Android. Remove the installed distro.
+        deleteConfigUpdaterMetadataDir(dataZoneInfoDir);
+        deleteUpdateDistroDir(dataCurrentDirName);
         return 5;
     }
 
@@ -353,22 +398,22 @@
         return 7;
     }
 
-    // Compare the bundle rules version against the system rules version.
+    // Compare the distro rules version against the system rules version.
     if (strncmp(
             &systemTzDataHeader[TZ_DATA_HEADER_PREFIX_LEN],
-            &bundleVersion[BUNDLE_VERSION_RULES_IDX],
+            &distroVersion[DISTRO_VERSION_RULES_IDX],
             RULES_VERSION_LEN) <= 0) {
-        LOG(INFO) << "Found an installed bundle but it is valid. No action taken.";
+        LOG(INFO) << "Found an installed distro but it is valid. No action taken.";
         // Implies there is an installed update, but it is good.
         return 0;
     }
 
     // Implies there has been an OTA and the system version of the timezone rules is now newer
-    // than the version installed in /data. Remove the installed bundle.
-    LOG(INFO) << "timezone bundle in " << dataCurrentDirName << " is older than data in "
+    // than the version installed in /data. Remove the installed distro.
+    LOG(INFO) << "timezone distro in " << dataCurrentDirName << " is older than data in "
             << systemTzDataFileName << "; fixing...";
 
     deleteConfigUpdaterMetadataDir(dataZoneInfoDir);
-    deleteUpdateBundleDir(dataCurrentDirName);
+    deleteUpdateDistroDir(dataCurrentDirName);
     return 0;
 }