Merge "Show install path in "adb --version" and "fastboot --version"."
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index f195b4e..f95a855 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -268,10 +268,6 @@
 #undef   accept
 #define  accept  ___xxx_accept
 
-int adb_getsockname(int fd, struct sockaddr* sockaddr, socklen_t* optlen);
-#undef getsockname
-#define getsockname(...) ___xxx_getsockname(__VA__ARGS__)
-
 // Returns the local port number of a bound socket, or -1 on failure.
 int adb_socket_get_local_port(int fd);
 
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index f997e6b..5873b2b 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -984,7 +984,7 @@
         return -1;
     }
 
-    int result = (getsockname)(fh->fh_socket, sockaddr, optlen);
+    int result = getsockname(fh->fh_socket, sockaddr, optlen);
     if (result == SOCKET_ERROR) {
         const DWORD err = WSAGetLastError();
         D("adb_getsockname: setsockopt on fd %d failed: %s\n", fd,
@@ -1042,11 +1042,6 @@
     int local_port = -1;
     std::string error;
 
-    struct sockaddr_storage peer_addr = {};
-    struct sockaddr_storage client_addr = {};
-    socklen_t peer_socklen = sizeof(peer_addr);
-    socklen_t client_socklen = sizeof(client_addr);
-
     server = network_loopback_server(0, SOCK_STREAM, &error);
     if (server < 0) {
         D("adb_socketpair: failed to create server: %s", error.c_str());
@@ -1066,32 +1061,12 @@
         goto fail;
     }
 
-    // Make sure that the peer that connected to us and the client are the same.
-    accepted = adb_socket_accept(server, reinterpret_cast<sockaddr*>(&peer_addr), &peer_socklen);
+    accepted = adb_socket_accept(server, nullptr, nullptr);
     if (accepted < 0) {
         D("adb_socketpair: failed to accept: %s", strerror(errno));
         goto fail;
     }
-
-    if (adb_getsockname(client, reinterpret_cast<sockaddr*>(&client_addr), &client_socklen) != 0) {
-        D("adb_socketpair: failed to getpeername: %s", strerror(errno));
-        goto fail;
-    }
-
-    if (peer_socklen != client_socklen) {
-        D("adb_socketpair: client and peer sockaddrs have different lengths");
-        errno = EIO;
-        goto fail;
-    }
-
-    if (memcmp(&peer_addr, &client_addr, peer_socklen) != 0) {
-        D("adb_socketpair: client and peer sockaddrs don't match");
-        errno = EIO;
-        goto fail;
-    }
-
     adb_close(server);
-
     sv[0] = client;
     sv[1] = accepted;
     return 0;
diff --git a/base/Android.bp b/base/Android.bp
index 7b1dc8e..121da42 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -42,24 +42,36 @@
             srcs: [
                 "errors_unix.cpp",
                 "properties.cpp",
+                "chrono_utils.cpp",
             ],
             cppflags: ["-Wexit-time-destructors"],
             sanitize: {
                 misc_undefined: ["integer"],
             },
+
         },
         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: [
@@ -92,11 +104,18 @@
     ],
     target: {
         android: {
-            srcs: ["properties_test.cpp"],
+            srcs: [
+                "chrono_utils_test.cpp",
+                "properties_test.cpp"
+            ],
             sanitize: {
                 misc_undefined: ["integer"],
             },
         },
+        linux: {
+            srcs: ["chrono_utils_test.cpp"],
+            host_ldlibs: ["-lrt"],
+        },
         windows: {
             srcs: ["utf8_test.cpp"],
             enabled: true,
diff --git a/base/chrono_utils.cpp b/base/chrono_utils.cpp
new file mode 100644
index 0000000..5eedf3b
--- /dev/null
+++ b/base/chrono_utils.cpp
@@ -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.
+ */
+
+#include "android-base/chrono_utils.h"
+
+#include <time.h>
+
+namespace android {
+namespace base {
+
+boot_clock::time_point boot_clock::now() {
+#ifdef __ANDROID__
+  timespec ts;
+  clock_gettime(CLOCK_BOOTTIME, &ts);
+  return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) +
+                                std::chrono::nanoseconds(ts.tv_nsec));
+#else
+  // Darwin does not support clock_gettime.
+  return boot_clock::time_point();
+#endif  // __ANDROID__
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/chrono_utils_test.cpp b/base/chrono_utils_test.cpp
new file mode 100644
index 0000000..057132d
--- /dev/null
+++ b/base/chrono_utils_test.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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/bootstat/Android.bp b/bootstat/Android.bp
index f744ad1..95c9af5 100644
--- a/bootstat/Android.bp
+++ b/bootstat/Android.bp
@@ -16,7 +16,6 @@
 
 bootstat_lib_src_files = [
     "boot_event_record_store.cpp",
-    "uptime_parser.cpp",
 ]
 
 cc_defaults {
diff --git a/bootstat/boot_event_record_store.cpp b/bootstat/boot_event_record_store.cpp
index 2648594..99d9405 100644
--- a/bootstat/boot_event_record_store.cpp
+++ b/bootstat/boot_event_record_store.cpp
@@ -20,13 +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 "uptime_parser.h"
 
 namespace {
 
@@ -55,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..d98169b 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"
+#include <gtest/gtest.h>
 
 using testing::UnorderedElementsAreArray;
 
@@ -89,6 +92,13 @@
   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 +136,7 @@
   BootEventRecordStore store;
   store.SetStorePath(GetStorePathForTesting());
 
-  time_t uptime = bootstat::ParseUptime();
+  time_t uptime = GetUptimeSeconds();
   ASSERT_NE(-1, uptime);
 
   store.AddBootEvent("cenozoic");
@@ -141,7 +151,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 a4cc5f2..6f25d96 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>
@@ -30,15 +31,15 @@
 #include <string>
 #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 <android/log.h>
 #include <cutils/properties.h>
 #include <metricslogger/metrics_logger.h>
 
 #include "boot_event_record_store.h"
-#include "uptime_parser.h"
 
 namespace {
 
@@ -255,7 +256,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)) {
@@ -282,22 +284,21 @@
     // 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);
+      boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption",
+                                             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");
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/bootstat/uptime_parser.h b/bootstat/uptime_parser.h
deleted file mode 100644
index 756ae9b..0000000
--- a/bootstat/uptime_parser.h
+++ /dev/null
@@ -1,29 +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.
- */
-
-#ifndef UPTIME_PARSER_H_
-#define UPTIME_PARSER_H_
-
-#include <time.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
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 024bc3d..4783d6e 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -163,6 +163,7 @@
             srcs: [
                 "client/debuggerd_client_test.cpp",
                 "debuggerd_test.cpp",
+                "tombstoned_client.cpp",
                 "util.cpp"
             ],
         },
@@ -176,7 +177,8 @@
     ],
 
     static_libs: [
-        "libdebuggerd"
+        "libdebuggerd",
+        "libc_logging",
     ],
 
     local_include_dirs: [
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index b9fb512..224444f 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -65,24 +65,25 @@
   auto time_left = [timeout_ms, &end]() { return end - std::chrono::steady_clock::now(); };
   auto set_timeout = [timeout_ms, &time_left](int sockfd) {
     if (timeout_ms <= 0) {
-      return true;
+      return -1;
     }
 
     auto remaining = time_left();
     if (remaining < decltype(remaining)::zero()) {
-      return false;
+      LOG(ERROR) << "timeout expired";
+      return -1;
     }
     struct timeval timeout;
     populate_timeval(&timeout, remaining);
 
     if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) != 0) {
-      return false;
+      return -1;
     }
     if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) != 0) {
-      return false;
+      return -1;
     }
 
-    return true;
+    return sockfd;
   };
 
   sockfd.reset(socket(AF_LOCAL, SOCK_SEQPACKET, 0));
@@ -91,12 +92,7 @@
     return false;
   }
 
-  if (!set_timeout(sockfd)) {
-    PLOG(ERROR) << "libdebugger_client: failed to set timeout";
-    return false;
-  }
-
-  if (socket_local_client_connect(sockfd.get(), kTombstonedInterceptSocketName,
+  if (socket_local_client_connect(set_timeout(sockfd.get()), kTombstonedInterceptSocketName,
                                   ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET) == -1) {
     PLOG(ERROR) << "libdebuggerd_client: failed to connect to tombstoned";
     return false;
@@ -115,21 +111,35 @@
     return false;
   }
 
-  if (send_fd(sockfd.get(), &req, sizeof(req), std::move(pipe_write)) != sizeof(req)) {
+  if (send_fd(set_timeout(sockfd), &req, sizeof(req), std::move(pipe_write)) != sizeof(req)) {
     PLOG(ERROR) << "libdebuggerd_client: failed to send output fd to tombstoned";
     return false;
   }
 
+  // Check to make sure we've successfully registered.
+  InterceptResponse response;
+  ssize_t rc =
+      TEMP_FAILURE_RETRY(recv(set_timeout(sockfd.get()), &response, sizeof(response), MSG_TRUNC));
+  if (rc == 0) {
+    LOG(ERROR) << "libdebuggerd_client: failed to read response from tombstoned: timeout reached?";
+    return false;
+  } else if (rc != sizeof(response)) {
+    LOG(ERROR)
+        << "libdebuggerd_client: received packet of unexpected length from tombstoned: expected "
+        << sizeof(response) << ", received " << rc;
+    return false;
+  }
+
+  if (response.status != InterceptStatus::kRegistered) {
+    LOG(ERROR) << "libdebuggerd_client: unexpected registration response: "
+               << static_cast<int>(response.status);
+    return false;
+  }
+
   bool backtrace = dump_type == kDebuggerdBacktrace;
   send_signal(pid, backtrace);
 
-  if (!set_timeout(sockfd)) {
-    PLOG(ERROR) << "libdebuggerd_client: failed to set timeout";
-    return false;
-  }
-
-  InterceptResponse response;
-  ssize_t rc = TEMP_FAILURE_RETRY(recv(sockfd.get(), &response, sizeof(response), MSG_TRUNC));
+  rc = TEMP_FAILURE_RETRY(recv(set_timeout(sockfd.get()), &response, sizeof(response), MSG_TRUNC));
   if (rc == 0) {
     LOG(ERROR) << "libdebuggerd_client: failed to read response from tombstoned: timeout reached?";
     return false;
@@ -140,7 +150,7 @@
     return false;
   }
 
-  if (response.success != 1) {
+  if (response.status != InterceptStatus::kStarted) {
     response.error_message[sizeof(response.error_message) - 1] = '\0';
     LOG(ERROR) << "libdebuggerd_client: tombstoned reported failure: " << response.error_message;
     return false;
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 1a27f3f..fa2838e 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -36,6 +36,7 @@
 #include <cutils/sockets.h>
 #include <debuggerd/handler.h>
 #include <debuggerd/protocol.h>
+#include <debuggerd/tombstoned.h>
 #include <debuggerd/util.h>
 #include <gtest/gtest.h>
 
@@ -77,6 +78,54 @@
     }                                                                           \
   } while (0)
 
+static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd) {
+  intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
+                                          ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
+  if (intercept_fd->get() == -1) {
+    FAIL() << "failed to contact tombstoned: " << strerror(errno);
+  }
+
+  InterceptRequest req = {.pid = target_pid};
+
+  unique_fd output_pipe_write;
+  if (!Pipe(output_fd, &output_pipe_write)) {
+    FAIL() << "failed to create output pipe: " << strerror(errno);
+  }
+
+  std::string pipe_size_str;
+  int pipe_buffer_size;
+  if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
+    FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
+  }
+
+  pipe_size_str = android::base::Trim(pipe_size_str);
+
+  if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
+    FAIL() << "failed to parse pipe max size";
+  }
+
+  if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
+    FAIL() << "failed to set pipe size: " << strerror(errno);
+  }
+
+  if (send_fd(intercept_fd->get(), &req, sizeof(req), std::move(output_pipe_write)) != sizeof(req)) {
+    FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
+  }
+
+  InterceptResponse response;
+  ssize_t rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), &response, sizeof(response)));
+  if (rc == -1) {
+    FAIL() << "failed to read response from tombstoned: " << strerror(errno);
+  } else if (rc == 0) {
+    FAIL() << "failed to read response from tombstoned (EOF)";
+  } else if (rc != sizeof(response)) {
+    FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
+           << ", received " << rc;
+  }
+
+  ASSERT_EQ(InterceptStatus::kRegistered, response.status);
+}
+
 class CrasherTest : public ::testing::Test {
  public:
   pid_t crasher_pid = -1;
@@ -118,38 +167,7 @@
     FAIL() << "crasher hasn't been started";
   }
 
-  intercept_fd.reset(socket_local_client(kTombstonedInterceptSocketName,
-                                         ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
-  if (intercept_fd == -1) {
-    FAIL() << "failed to contact tombstoned: " << strerror(errno);
-  }
-
-  InterceptRequest req = {.pid = crasher_pid };
-
-  unique_fd output_pipe_write;
-  if (!Pipe(output_fd, &output_pipe_write)) {
-    FAIL() << "failed to create output pipe: " << strerror(errno);
-  }
-
-  std::string pipe_size_str;
-  int pipe_buffer_size;
-  if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
-    FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
-  }
-
-  pipe_size_str = android::base::Trim(pipe_size_str);
-
-  if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
-    FAIL() << "failed to parse pipe max size";
-  }
-
-  if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
-    FAIL() << "failed to set pipe size: " << strerror(errno);
-  }
-
-  if (send_fd(intercept_fd.get(), &req, sizeof(req), std::move(output_pipe_write)) != sizeof(req)) {
-    FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
-  }
+  tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd);
 }
 
 void CrasherTest::FinishIntercept(int* result) {
@@ -165,7 +183,7 @@
     FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
            << ", received " << rc;
   } else {
-    *result = response.success;
+    *result = response.status == InterceptStatus::kStarted ? 1 : 0;
   }
 }
 
@@ -461,6 +479,7 @@
       err(1, "failed to drop ambient capabilities");
     }
 
+    pthread_setname_np(pthread_self(), "thread_name");
     raise(SIGSYS);
   });
 
@@ -474,6 +493,7 @@
   FinishIntercept(&intercept_result);
   ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
   ConsumeFd(std::move(output_fd), &result);
+  ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
   ASSERT_MATCH(result, R"(#00 pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX R"(/libc.so \(tgkill)");
 }
 
@@ -508,3 +528,97 @@
     ASSERT_EQ(0, WEXITSTATUS(status));
   }
 }
+
+TEST(tombstoned, no_notify) {
+  // Do this a few times.
+  for (int i = 0; i < 3; ++i) {
+    pid_t pid = 123'456'789 + i;
+
+    unique_fd intercept_fd, output_fd;
+    tombstoned_intercept(pid, &intercept_fd, &output_fd);
+
+    {
+      unique_fd tombstoned_socket, input_fd;
+      ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd));
+      ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
+    }
+
+    pid_t read_pid;
+    ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
+    ASSERT_EQ(read_pid, pid);
+  }
+}
+
+TEST(tombstoned, stress) {
+  // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
+  static constexpr int kDumpCount = 100;
+
+  std::atomic<bool> start(false);
+  std::vector<std::thread> threads;
+  threads.emplace_back([&start]() {
+    while (!start) {
+      continue;
+    }
+
+    // Use a way out of range pid, to avoid stomping on an actual process.
+    pid_t pid_base = 1'000'000;
+
+    for (int dump = 0; dump < kDumpCount; ++dump) {
+      pid_t pid = pid_base + dump;
+
+      unique_fd intercept_fd, output_fd;
+      tombstoned_intercept(pid, &intercept_fd, &output_fd);
+
+      // Pretend to crash, and then immediately close the socket.
+      unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
+                                           ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
+      if (sockfd == -1) {
+        FAIL() << "failed to connect to tombstoned: " << strerror(errno);
+      }
+      TombstonedCrashPacket packet = {};
+      packet.packet_type = CrashPacketType::kDumpRequest;
+      packet.packet.dump_request.pid = pid;
+      if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
+        FAIL() << "failed to write to tombstoned: " << strerror(errno);
+      }
+
+      continue;
+    }
+  });
+
+  threads.emplace_back([&start]() {
+    while (!start) {
+      continue;
+    }
+
+    // Use a way out of range pid, to avoid stomping on an actual process.
+    pid_t pid_base = 2'000'000;
+
+    for (int dump = 0; dump < kDumpCount; ++dump) {
+      pid_t pid = pid_base + dump;
+
+      unique_fd intercept_fd, output_fd;
+      tombstoned_intercept(pid, &intercept_fd, &output_fd);
+
+      {
+        unique_fd tombstoned_socket, input_fd;
+        ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd));
+        ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
+        tombstoned_notify_completion(tombstoned_socket.get());
+      }
+
+      // TODO: Fix the race that requires this sleep.
+      std::this_thread::sleep_for(50ms);
+
+      pid_t read_pid;
+      ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
+      ASSERT_EQ(read_pid, pid);
+    }
+  });
+
+  start = true;
+
+  for (std::thread& thread : threads) {
+    thread.join();
+  }
+}
diff --git a/debuggerd/include/debuggerd/protocol.h b/debuggerd/include/debuggerd/protocol.h
index bb2ab0d..0756876 100644
--- a/debuggerd/include/debuggerd/protocol.h
+++ b/debuggerd/include/debuggerd/protocol.h
@@ -56,8 +56,14 @@
   int32_t pid;
 };
 
+enum class InterceptStatus : uint8_t {
+  kFailed,
+  kStarted,
+  kRegistered,
+};
+
 // Sent either immediately upon failure, or when the intercept has been used.
 struct InterceptResponse {
-  uint8_t success;          // 0 or 1
+  InterceptStatus status;
   char error_message[127];  // always null-terminated
 };
diff --git a/debuggerd/tombstoned/intercept_manager.cpp b/debuggerd/tombstoned/intercept_manager.cpp
index 789260d..dff942c 100644
--- a/debuggerd/tombstoned/intercept_manager.cpp
+++ b/debuggerd/tombstoned/intercept_manager.cpp
@@ -105,6 +105,7 @@
     // We trust the other side, so only do minimal validity checking.
     if (intercept_request.pid <= 0 || intercept_request.pid > std::numeric_limits<pid_t>::max()) {
       InterceptResponse response = {};
+      response.status = InterceptStatus::kFailed;
       snprintf(response.error_message, sizeof(response.error_message), "invalid pid %" PRId32,
                intercept_request.pid);
       TEMP_FAILURE_RETRY(write(sockfd, &response, sizeof(response)));
@@ -113,9 +114,10 @@
 
     intercept->intercept_pid = intercept_request.pid;
 
-    // Register the intercept with the InterceptManager.
+    // Check if it's already registered.
     if (intercept_manager->intercepts.count(intercept_request.pid) > 0) {
       InterceptResponse response = {};
+      response.status = InterceptStatus::kFailed;
       snprintf(response.error_message, sizeof(response.error_message),
                "pid %" PRId32 " already intercepted", intercept_request.pid);
       TEMP_FAILURE_RETRY(write(sockfd, &response, sizeof(response)));
@@ -123,6 +125,15 @@
       goto fail;
     }
 
+    // Let the other side know that the intercept has been registered, now that we know we can't
+    // fail. tombstoned is single threaded, so this isn't racy.
+    InterceptResponse response = {};
+    response.status = InterceptStatus::kRegistered;
+    if (TEMP_FAILURE_RETRY(write(sockfd, &response, sizeof(response))) == -1) {
+      PLOG(WARNING) << "failed to notify interceptor of registration";
+      goto fail;
+    }
+
     intercept->output_fd = std::move(rcv_fd);
     intercept_manager->intercepts[intercept_request.pid] = std::unique_ptr<Intercept>(intercept);
     intercept->registered = true;
@@ -174,7 +185,7 @@
 
   LOG(INFO) << "found intercept fd " << intercept->output_fd.get() << " for pid " << pid;
   InterceptResponse response = {};
-  response.success = 1;
+  response.status = InterceptStatus::kStarted;
   TEMP_FAILURE_RETRY(write(intercept->sockfd, &response, sizeof(response)));
   *out_fd = std::move(intercept->output_fd);
 
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index 6754508..2248a21 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -126,9 +126,7 @@
   return result;
 }
 
-static void dequeue_request(Crash* crash) {
-  ++num_concurrent_dumps;
-
+static void perform_request(Crash* crash) {
   unique_fd output_fd;
   if (!intercept_manager->GetIntercept(crash->crash_pid, &output_fd)) {
     output_fd = get_tombstone_fd();
@@ -153,12 +151,22 @@
                  crash_completed_cb, crash);
     event_add(crash->crash_event, &timeout);
   }
+
+  ++num_concurrent_dumps;
   return;
 
 fail:
   delete crash;
 }
 
+static void dequeue_requests() {
+  while (!queued_requests.empty() && num_concurrent_dumps < kMaxConcurrentDumps) {
+    Crash* next_crash = queued_requests.front();
+    queued_requests.pop_front();
+    perform_request(next_crash);
+  }
+}
+
 static void crash_accept_cb(evconnlistener* listener, evutil_socket_t sockfd, sockaddr*, int,
                             void*) {
   event_base* base = evconnlistener_get_base(listener);
@@ -207,7 +215,7 @@
     LOG(INFO) << "enqueueing crash request for pid " << crash->crash_pid;
     queued_requests.push_back(crash);
   } else {
-    dequeue_request(crash);
+    perform_request(crash);
   }
 
   return;
@@ -247,11 +255,7 @@
   delete crash;
 
   // If there's something queued up, let them proceed.
-  if (!queued_requests.empty()) {
-    Crash* next_crash = queued_requests.front();
-    queued_requests.pop_front();
-    dequeue_request(next_crash);
-  }
+  dequeue_requests();
 }
 
 int main(int, char* []) {
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index a99ba23..704dc43 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -115,6 +115,7 @@
     {"system_other.img", "system.sig", "system", true, true},
     {"vendor.img", "vendor.sig", "vendor", true, false},
     {"vendor_other.img", "vendor.sig", "vendor", true, true},
+    {"vbmeta.img", "vbmeta.sig", "vbmeta", true, false},
 };
 
 static std::string find_item_given_name(const char* img_name, const char* product) {
@@ -144,6 +145,8 @@
         fn = "system.img";
     } else if(!strcmp(item,"vendor")) {
         fn = "vendor.img";
+    } else if(!strcmp(item,"vbmeta")) {
+        fn = "vbmeta.img";
     } else if(!strcmp(item,"userdata")) {
         fn = "userdata.img";
     } else if(!strcmp(item,"cache")) {
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index a762038..7512eb9 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -390,10 +390,12 @@
             continue;
         }
 
-        // Ensures that hashtree descriptor is either in /vbmeta or in
+        // Ensures that hashtree descriptor is in /vbmeta or /boot or in
         // the same partition for verity setup.
         std::string vbmeta_partition_name(verify_data.vbmeta_images[i].partition_name);
-        if (vbmeta_partition_name != "vbmeta" && vbmeta_partition_name != partition_name) {
+        if (vbmeta_partition_name != "vbmeta" &&
+            vbmeta_partition_name != "boot" &&  // for legacy device to append top-level vbmeta
+            vbmeta_partition_name != partition_name) {
             LWARNING << "Skip vbmeta image at " << verify_data.vbmeta_images[i].partition_name
                      << " for partition: " << partition_name.c_str();
             continue;
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
index 2c14c9b..8e49663 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -39,7 +39,28 @@
 #include "fs_mgr_avb_ops.h"
 #include "fs_mgr_priv.h"
 
-static struct fstab* fs_mgr_fstab = nullptr;
+static std::string fstab_by_name_prefix;
+
+static std::string extract_by_name_prefix(struct fstab* fstab) {
+    // In AVB, we can assume that there's an entry for the /misc mount
+    // point in the fstab file and use that to get the device file for
+    // the misc partition. The device needs not to have an actual /misc
+    // partition. Then returns the prefix by removing the trailing "misc":
+    //
+    //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
+    //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/
+
+    struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
+    if (fstab_entry == nullptr) {
+        LERROR << "/misc mount point not found in fstab";
+        return "";
+    }
+
+    std::string full_path(fstab_entry->blk_device);
+    size_t end_slash = full_path.find_last_of("/");
+
+    return full_path.substr(0, end_slash + 1);
+}
 
 static AvbIOResult read_from_partition(AvbOps* ops ATTRIBUTE_UNUSED, const char* partition,
                                        int64_t offset, size_t num_bytes, void* buffer,
@@ -49,30 +70,14 @@
     // for partitions having 'slotselect' optin in fstab file, but it
     // won't be appended to the mount point.
     //
-    // In AVB, we can assume that there's an entry for the /misc mount
-    // point and use that to get the device file for the misc partition.
-    // From there we'll assume that a by-name scheme is used
-    // so we can just replace the trailing "misc" by the given
-    // |partition|, e.g.
+    // Appends |partition| to the fstab_by_name_prefix, which is obtained
+    // by removing the trailing "misc" from the device file of /misc mount
+    // point. e.g.,
     //
-    //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
+    //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/ ->
     //    - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a
 
-    struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fs_mgr_fstab, "/misc");
-
-    if (fstab_entry == nullptr) {
-        LERROR << "/misc mount point not found in fstab";
-        return AVB_IO_RESULT_ERROR_IO;
-    }
-
-    std::string partition_name(partition);
-    std::string path(fstab_entry->blk_device);
-    // Replaces the last field of device file if it's not misc.
-    if (!android::base::StartsWith(partition_name, "misc")) {
-        size_t end_slash = path.find_last_of("/");
-        std::string by_name_prefix(path.substr(0, end_slash + 1));
-        path = by_name_prefix + partition_name;
-    }
+    std::string path = fstab_by_name_prefix + partition;
 
     // Ensures the device path (a symlink created by init) is ready to
     // access. fs_mgr_test_access() will test a few iterations if the
@@ -168,8 +173,8 @@
 AvbOps* fs_mgr_dummy_avb_ops_new(struct fstab* fstab) {
     AvbOps* ops;
 
-    // Assigns the fstab to the static variable for later use.
-    fs_mgr_fstab = fstab;
+    fstab_by_name_prefix = extract_by_name_prefix(fstab);
+    if (fstab_by_name_prefix.empty()) return nullptr;
 
     ops = (AvbOps*)calloc(1, sizeof(AvbOps));
     if (ops == nullptr) {
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 720ec03..0406efd 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -625,17 +625,6 @@
     return fstab;
 }
 
-/* combines fstab entries passed in from device tree with
- * the ones found from fstab_path
- */
-struct fstab *fs_mgr_read_fstab_with_dt(const char *fstab_path)
-{
-    struct fstab *fstab_dt = fs_mgr_read_fstab_dt();
-    struct fstab *fstab = fs_mgr_read_fstab(fstab_path);
-
-    return in_place_merge(fstab_dt, fstab);
-}
-
 /*
  * tries to load default fstab.<hardware> file from /odm/etc, /vendor/etc
  * or /. loads the first one found and also combines fstab entries passed
@@ -658,7 +647,12 @@
         LWARNING << __FUNCTION__ << "(): failed to find device hardware name";
     }
 
-    return fs_mgr_read_fstab_with_dt(default_fstab.c_str());
+    // combines fstab entries passed in from device tree with
+    // the ones found from default_fstab file
+    struct fstab *fstab_dt = fs_mgr_read_fstab_dt();
+    struct fstab *fstab = fs_mgr_read_fstab(default_fstab.c_str());
+
+    return in_place_merge(fstab_dt, fstab);
 }
 
 void fs_mgr_free_fstab(struct fstab *fstab)
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index e4aeb48..4b626de 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -88,7 +88,6 @@
 struct fstab *fs_mgr_read_fstab_default();
 struct fstab *fs_mgr_read_fstab_dt();
 struct fstab *fs_mgr_read_fstab(const char *fstab_path);
-struct fstab *fs_mgr_read_fstab_with_dt(const char *fstab_path);
 void fs_mgr_free_fstab(struct fstab *fstab);
 
 #define FS_MGR_MNTALL_DEV_FILE_ENCRYPTED 5
diff --git a/init/README.md b/init/README.md
index 0d8f495..822d81e 100644
--- a/init/README.md
+++ b/init/README.md
@@ -198,6 +198,13 @@
   is in the class "default" if one is not specified via the
   class option. Additional classnames beyond the (required) first
   one are used to group services.
+`animation class`
+> 'animation' class should include all services necessary for both
+  boot animation and shutdown animation. As these services can be
+  launched very early during bootup and can run until the last stage
+  of shutdown, access to /data partition is not guaranteed. These
+  services can check files under /data but it should not keep files opened
+  and should work when /data is not available.
 
 `onrestart`
 > Execute a Command (see below) when service restarts.
@@ -286,11 +293,6 @@
 `copy <src> <dst>`
 > Copies a file. Similar to write, but useful for binary/large
   amounts of data.
-  Regarding to the src file, copying from symbol link file and world-writable
-  or group-writable files are not allowed.
-  Regarding to the dst file, the default mode created is 0600 if it does not
-  exist. And it will be truncated if dst file is a normal regular file and
-  already exists.
 
 `domainname <name>`
 > Set the domain name.
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 02e314f..dc2bda6 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -702,11 +702,61 @@
 }
 
 static int do_copy(const std::vector<std::string>& args) {
-    std::string data;
-    if (read_file(args[1].c_str(), &data)) {
-        return write_file(args[2].c_str(), data.data()) ? 0 : 1;
+    char *buffer = NULL;
+    int rc = 0;
+    int fd1 = -1, fd2 = -1;
+    struct stat info;
+    int brtw, brtr;
+    char *p;
+
+    if (stat(args[1].c_str(), &info) < 0)
+        return -1;
+
+    if ((fd1 = open(args[1].c_str(), O_RDONLY|O_CLOEXEC)) < 0)
+        goto out_err;
+
+    if ((fd2 = open(args[2].c_str(), O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0660)) < 0)
+        goto out_err;
+
+    if (!(buffer = (char*) malloc(info.st_size)))
+        goto out_err;
+
+    p = buffer;
+    brtr = info.st_size;
+    while(brtr) {
+        rc = read(fd1, p, brtr);
+        if (rc < 0)
+            goto out_err;
+        if (rc == 0)
+            break;
+        p += rc;
+        brtr -= rc;
     }
-    return 1;
+
+    p = buffer;
+    brtw = info.st_size;
+    while(brtw) {
+        rc = write(fd2, p, brtw);
+        if (rc < 0)
+            goto out_err;
+        if (rc == 0)
+            break;
+        p += rc;
+        brtw -= rc;
+    }
+
+    rc = 0;
+    goto out;
+out_err:
+    rc = -1;
+out:
+    if (buffer)
+        free(buffer);
+    if (fd1 >= 0)
+        close(fd1);
+    if (fd2 >= 0)
+        close(fd2);
+    return rc;
 }
 
 static int do_chown(const std::vector<std::string>& args) {
@@ -879,8 +929,14 @@
     if (!is_file_crypto()) {
         return 0;
     }
-    return e4crypt_create_device_key(args[1].c_str(),
-                                     do_installkeys_ensure_dir_exists);
+    auto unencrypted_dir = args[1] + e4crypt_unencrypted_folder;
+    if (do_installkeys_ensure_dir_exists(unencrypted_dir.c_str())) {
+        PLOG(ERROR) << "Failed to create " << unencrypted_dir;
+        return -1;
+    }
+    std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
+                                          "enablefilecrypto"};
+    return do_exec(exec_args);
 }
 
 static int do_init_user0(const std::vector<std::string>& args) {
diff --git a/init/init.cpp b/init/init.cpp
index 4249115..e14034f 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/properties.h>
 #include <android-base/stringprintf.h>
@@ -69,6 +70,7 @@
 #include "util.h"
 #include "watchdogd.h"
 
+using android::base::boot_clock;
 using android::base::GetProperty;
 using android::base::StringPrintf;
 
@@ -875,6 +877,24 @@
     }
 }
 
+// The files and directories that were created before initial sepolicy load
+// need to have their security context restored to the proper value.
+// This must happen before /dev is populated by ueventd.
+static void selinux_restore_context() {
+    LOG(INFO) << "Running restorecon...";
+    restorecon("/dev");
+    restorecon("/dev/kmsg");
+    restorecon("/dev/socket");
+    restorecon("/dev/random");
+    restorecon("/dev/urandom");
+    restorecon("/dev/__properties__");
+    restorecon("/plat_property_contexts");
+    restorecon("/nonplat_property_contexts");
+    restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
+    restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
+    restorecon("/dev/device-mapper");
+}
+
 // Set the UDC controller for the ConfigFS USB Gadgets.
 // Read the UDC controller in use from "/sys/class/udc".
 // In case of multiple UDC controllers select the first one.
@@ -1213,22 +1233,7 @@
 
     // Now set up SELinux for second stage.
     selinux_initialize(false);
-
-    // These directories were necessarily created before initial policy load
-    // and therefore need their security context restored to the proper value.
-    // This must happen before /dev is populated by ueventd.
-    LOG(INFO) << "Running restorecon...";
-    restorecon("/dev");
-    restorecon("/dev/kmsg");
-    restorecon("/dev/socket");
-    restorecon("/dev/random");
-    restorecon("/dev/urandom");
-    restorecon("/dev/__properties__");
-    restorecon("/plat_property_contexts");
-    restorecon("/nonplat_property_contexts");
-    restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
-    restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
-    restorecon("/dev/device-mapper");
+    selinux_restore_context();
 
     epoll_fd = epoll_create1(EPOLL_CLOEXEC);
     if (epoll_fd == -1) {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index e34abdb..62e5c85 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -26,6 +26,7 @@
 #include <sys/wait.h>
 
 #include <memory>
+#include <set>
 #include <string>
 #include <thread>
 #include <vector>
@@ -41,6 +42,7 @@
 #include <logwrap/logwrap.h>
 
 #include "log.h"
+#include "property_service.h"
 #include "reboot.h"
 #include "service.h"
 #include "util.h"
@@ -248,8 +250,9 @@
                                               flags);
                 } else {
                     umountDone = false;
-                    PLOG(WARNING) << StringPrintf("cannot umount %s, flags:0x%x",
-                                                  entry.mnt_fsname().c_str(), flags);
+                    PLOG(WARNING) << StringPrintf("cannot umount %s, mnt_dir %s, flags:0x%x",
+                                                  entry.mnt_fsname().c_str(),
+                                                  entry.mnt_dir().c_str(), flags);
                 }
             }
         }
@@ -351,26 +354,40 @@
     }
     LOG(INFO) << "Shutdown timeout: " << shutdownTimeout;
 
-    static const constexpr char* shutdown_critical_services[] = {"vold", "watchdogd"};
-    for (const char* name : shutdown_critical_services) {
-        Service* s = ServiceManager::GetInstance().FindServiceByName(name);
-        if (s == nullptr) {
-            LOG(WARNING) << "Shutdown critical service not found:" << name;
-            continue;
+    // keep debugging tools until non critical ones are all gone.
+    const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
+    // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
+    const std::set<std::string> to_starts{"watchdogd", "vold"};
+    ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) {
+        if (kill_after_apps.count(s->name())) {
+            s->SetShutdownCritical();
+        } else if (to_starts.count(s->name())) {
+            s->Start();
+            s->SetShutdownCritical();
         }
-        s->Start();  // make sure that it is running.
-        s->SetShutdownCritical();
+    });
+
+    Service* bootAnim = ServiceManager::GetInstance().FindServiceByName("bootanim");
+    Service* surfaceFlinger = ServiceManager::GetInstance().FindServiceByName("surfaceflinger");
+    if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
+        property_set("service.bootanim.exit", "0");
+        // Could be in the middle of animation. Stop and start so that it can pick
+        // up the right mode.
+        bootAnim->Stop();
+        // start all animation classes if stopped.
+        ServiceManager::GetInstance().ForEachServiceInClass("animation", [](Service* s) {
+            s->Start();
+            s->SetShutdownCritical();  // will not check animation class separately
+        });
+        bootAnim->Start();
+        surfaceFlinger->SetShutdownCritical();
+        bootAnim->SetShutdownCritical();
     }
+
     // optional shutdown step
     // 1. terminate all services except shutdown critical ones. wait for delay to finish
     if (shutdownTimeout > 0) {
         LOG(INFO) << "terminating init services";
-        // tombstoned can write to data when other services are killed. so finish it first.
-        static const constexpr char* first_to_kill[] = {"tombstoned"};
-        for (const char* name : first_to_kill) {
-            Service* s = ServiceManager::GetInstance().FindServiceByName(name);
-            if (s != nullptr) s->Stop();
-        }
 
         // Ask all services to terminate except shutdown critical ones.
         ServiceManager::GetInstance().ForEachService([](Service* s) {
@@ -409,8 +426,8 @@
 
     // minimum safety steps before restarting
     // 2. kill all services except ones that are necessary for the shutdown sequence.
-    ServiceManager::GetInstance().ForEachService([](Service* s) {
-        if (!s->IsShutdownCritical()) s->Stop();
+    ServiceManager::GetInstance().ForEachService([&kill_after_apps](Service* s) {
+        if (!s->IsShutdownCritical() || kill_after_apps.count(s->name())) s->Stop();
     });
     ServiceManager::GetInstance().ReapAnyOutstandingChildren();
 
diff --git a/init/service.cpp b/init/service.cpp
index ede6364..e89de9a 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/properties.h>
@@ -48,6 +49,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;
@@ -211,7 +213,13 @@
     LOG(INFO) << "Sending signal " << signal
               << " to service '" << name_
               << "' (pid " << pid_ << ") process group...";
-    if (killProcessGroup(uid_, pid_, signal) == -1) {
+    int r;
+    if (signal == SIGTERM) {
+        r = killProcessGroupOnce(uid_, pid_, signal);
+    } else {
+        r = killProcessGroup(uid_, pid_, signal);
+    }
+    if (r == -1) {
         PLOG(ERROR) << "killProcessGroup(" << uid_ << ", " << pid_ << ", " << signal << ") failed";
     }
     if (kill(-pid_, signal) == -1) {
diff --git a/init/service.h b/init/service.h
index f08a03f..d84ce02 100644
--- a/init/service.h
+++ b/init/service.h
@@ -26,6 +26,8 @@
 #include <string>
 #include <vector>
 
+#include <android-base/chrono_utils.h>
+
 #include "action.h"
 #include "capabilities.h"
 #include "descriptors.h"
@@ -144,8 +146,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/ueventd.cpp b/init/ueventd.cpp
index f27be64..ba53e47 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -94,7 +94,7 @@
     return 0;
 }
 
-void set_device_permission(int nargs, char **args)
+void set_device_permission(const char* fn, int line, int nargs, char **args)
 {
     char *name;
     char *attr = 0;
@@ -121,7 +121,7 @@
     }
 
     if (nargs != 4) {
-        LOG(ERROR) << "invalid line ueventd.rc line for '" << args[0] << "'";
+        LOG(ERROR) << "invalid line (" << fn << ":" << line << ") line for '" << args[0] << "'";
         return;
     }
 
@@ -136,20 +136,20 @@
 
     perm = strtol(args[1], &endptr, 8);
     if (!endptr || *endptr != '\0') {
-        LOG(ERROR) << "invalid mode '" << args[1] << "'";
+        LOG(ERROR) << "invalid mode (" << fn << ":" << line << ") '" << args[1] << "'";
         return;
     }
 
     struct passwd* pwd = getpwnam(args[2]);
     if (!pwd) {
-        LOG(ERROR) << "invalid uid '" << args[2] << "'";
+        LOG(ERROR) << "invalid uid (" << fn << ":" << line << ") '" << args[2] << "'";
         return;
     }
     uid = pwd->pw_uid;
 
     struct group* grp = getgrnam(args[3]);
     if (!grp) {
-        LOG(ERROR) << "invalid gid '" << args[3] << "'";
+        LOG(ERROR) << "invalid gid (" << fn << ":" << line << ") '" << args[3] << "'";
         return;
     }
     gid = grp->gr_gid;
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index baff58c..554c1e3 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -236,6 +236,6 @@
     return 0;
 }
 
-static void parse_line_device(parse_state*, int nargs, char** args) {
-    set_device_permission(nargs, args);
+static void parse_line_device(parse_state* state, int nargs, char** args) {
+    set_device_permission(state->filename, state->line, nargs, args);
 }
diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h
index 907cc49..4d69897 100644
--- a/init/ueventd_parser.h
+++ b/init/ueventd_parser.h
@@ -22,7 +22,7 @@
 #define UEVENTD_PARSER_MAXARGS 5
 
 int ueventd_parse_config_file(const char *fn);
-void set_device_permission(int nargs, char **args);
+void set_device_permission(const char* fn, int line, int nargs, char **args);
 struct ueventd_subsystem *ueventd_subsystem_find_by_name(const char *name);
 
 #endif
diff --git a/init/util.cpp b/init/util.cpp
index 8a19939..3f8f244 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -52,6 +52,8 @@
 #include "reboot.h"
 #include "util.h"
 
+using android::base::boot_clock;
+
 static unsigned int do_decode_uid(const char *s)
 {
     unsigned int v;
@@ -185,8 +187,8 @@
 }
 
 bool write_file(const char* path, const char* content) {
-    android::base::unique_fd fd(TEMP_FAILURE_RETRY(
-        open(path, O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0600)));
+    android::base::unique_fd fd(
+        TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC, 0600)));
     if (fd == -1) {
         PLOG(ERROR) << "write_file: Unable to open '" << path << "'";
         return false;
@@ -198,13 +200,6 @@
     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));
-}
-
 int mkdir_recursive(const char *pathname, mode_t mode)
 {
     char buf[128];
diff --git a/init/util.h b/init/util.h
index 81c64d7..23509d3 100644
--- a/init/util.h
+++ b/init/util.h
@@ -25,8 +25,11 @@
 #include <ostream>
 #include <string>
 
+#include <android-base/chrono_utils.h>
+
 #define COLDBOOT_DONE "/dev/.coldboot_done"
 
+using android::base::boot_clock;
 using namespace std::chrono_literals;
 
 int create_socket(const char *name, int type, mode_t perm,
@@ -35,32 +38,22 @@
 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()) {
-  }
+  public:
+    Timer() : start_(boot_clock::now()) {}
 
-  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 {
+        typedef std::chrono::duration<double> double_duration;
+        return std::chrono::duration_cast<double_duration>(boot_clock::now() - start_).count();
+    }
 
-  int64_t duration_ms() const {
-    return std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() - start_).count();
-  }
+    int64_t duration_ms() const {
+        return std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() - start_)
+            .count();
+    }
 
- private:
-  boot_clock::time_point start_;
+  private:
+    android::base::boot_clock::time_point start_;
 };
 
 std::ostream& operator<<(std::ostream& os, const Timer& t);
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 4e82e76..24c75c4 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -17,15 +17,9 @@
 #include "util.h"
 
 #include <errno.h>
-#include <fcntl.h>
-
-#include <sys/stat.h>
 
 #include <gtest/gtest.h>
 
-#include <android-base/stringprintf.h>
-#include <android-base/test_utils.h>
-
 TEST(util, read_file_ENOENT) {
   std::string s("hello");
   errno = 0;
@@ -34,35 +28,6 @@
   EXPECT_EQ("", s); // s was cleared.
 }
 
-TEST(util, read_file_group_writeable) {
-    std::string s("hello");
-    TemporaryFile tf;
-    ASSERT_TRUE(tf.fd != -1);
-    EXPECT_TRUE(write_file(tf.path, s.c_str())) << strerror(errno);
-    EXPECT_NE(-1, fchmodat(AT_FDCWD, tf.path, 0620, AT_SYMLINK_NOFOLLOW)) << strerror(errno);
-    EXPECT_FALSE(read_file(tf.path, &s)) << strerror(errno);
-    EXPECT_EQ("", s);  // s was cleared.
-}
-
-TEST(util, read_file_world_writeable) {
-    std::string s("hello");
-    TemporaryFile tf;
-    ASSERT_TRUE(tf.fd != -1);
-    EXPECT_TRUE(write_file(tf.path, s.c_str())) << strerror(errno);
-    EXPECT_NE(-1, fchmodat(AT_FDCWD, tf.path, 0602, AT_SYMLINK_NOFOLLOW)) << strerror(errno);
-    EXPECT_FALSE(read_file(tf.path, &s)) << strerror(errno);
-    EXPECT_EQ("", s);  // s was cleared.
-}
-
-TEST(util, read_file_symbol_link) {
-    std::string s("hello");
-    errno = 0;
-    // lrwxrwxrwx 1 root root 13 1970-01-01 00:00 charger -> /sbin/healthd
-    EXPECT_FALSE(read_file("/charger", &s));
-    EXPECT_EQ(ELOOP, errno);
-    EXPECT_EQ("", s);  // s was cleared.
-}
-
 TEST(util, read_file_success) {
   std::string s("hello");
   EXPECT_TRUE(read_file("/proc/version", &s));
@@ -72,42 +37,6 @@
   EXPECT_STREQ("Linux", s.c_str());
 }
 
-TEST(util, write_file_not_exist) {
-    std::string s("hello");
-    std::string s2("hello");
-    TemporaryDir test_dir;
-    std::string path = android::base::StringPrintf("%s/does-not-exist", test_dir.path);
-    EXPECT_TRUE(write_file(path.c_str(), s.c_str()));
-    EXPECT_TRUE(read_file(path.c_str(), &s2));
-    EXPECT_EQ(s, s2);
-    struct stat sb;
-    int fd = open(path.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
-    EXPECT_NE(-1, fd);
-    EXPECT_EQ(0, fstat(fd, &sb));
-    EXPECT_NE(0u, sb.st_mode & S_IRUSR);
-    EXPECT_NE(0u, sb.st_mode & S_IWUSR);
-    EXPECT_EQ(0u, sb.st_mode & S_IXUSR);
-    EXPECT_EQ(0u, sb.st_mode & S_IRGRP);
-    EXPECT_EQ(0u, sb.st_mode & S_IWGRP);
-    EXPECT_EQ(0u, sb.st_mode & S_IXGRP);
-    EXPECT_EQ(0u, sb.st_mode & S_IROTH);
-    EXPECT_EQ(0u, sb.st_mode & S_IWOTH);
-    EXPECT_EQ(0u, sb.st_mode & S_IXOTH);
-    EXPECT_EQ(0, unlink(path.c_str()));
-}
-
-TEST(util, write_file_exist) {
-    std::string s2("");
-    TemporaryFile tf;
-    ASSERT_TRUE(tf.fd != -1);
-    EXPECT_TRUE(write_file(tf.path, "1hello1")) << strerror(errno);
-    EXPECT_TRUE(read_file(tf.path, &s2));
-    EXPECT_STREQ("1hello1", s2.c_str());
-    EXPECT_TRUE(write_file(tf.path, "2hello2"));
-    EXPECT_TRUE(read_file(tf.path, &s2));
-    EXPECT_STREQ("2hello2", s2.c_str());
-}
-
 TEST(util, decode_uid) {
   EXPECT_EQ(0U, decode_uid("root"));
   EXPECT_EQ(UINT_MAX, decode_uid("toot"));
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index 718d76b..c663a5d 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -69,6 +69,7 @@
 
 cc_test {
     name: "libcutils_test_static",
+    test_suites: ["device-tests"],
     defaults: ["libcutils_test_default"],
     static_libs: ["libc"] + test_libraries,
     stl: "libc++_static",
diff --git a/libcutils/tests/AndroidTest.xml b/libcutils/tests/AndroidTest.xml
new file mode 100644
index 0000000..c945f4d
--- /dev/null
+++ b/libcutils/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config for libcutils_test_static">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="libcutils_test_static->/data/local/tmp/libcutils_test_static" />
+    </target_preparer>
+    <option name="test-suite-tag" value="apct" />
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="libcutils_test_static" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index d322c0f..84feb20 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -410,16 +410,46 @@
   if (!tag) tag = "";
 
   /* XXX: This needs to go! */
-  if ((bufID != LOG_ID_RADIO) &&
-      (!strcmp(tag, "HTC_RIL") ||
-       !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
-       !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
-       !strcmp(tag, "AT") || !strcmp(tag, "GSM") || !strcmp(tag, "STK") ||
-       !strcmp(tag, "CDMA") || !strcmp(tag, "PHONE") || !strcmp(tag, "SMS"))) {
-    bufID = LOG_ID_RADIO;
-    /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
-    snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
-    tag = tmp_tag;
+  if (bufID != LOG_ID_RADIO) {
+    switch (tag[0]) {
+      case 'H':
+        if (strcmp(tag + 1, "HTC_RIL" + 1)) break;
+        goto inform;
+      case 'R':
+        /* Any log tag with "RIL" as the prefix */
+        if (strncmp(tag + 1, "RIL" + 1, strlen("RIL") - 1)) break;
+        goto inform;
+      case 'Q':
+        /* Any log tag with "QC_RIL" as the prefix */
+        if (strncmp(tag + 1, "QC_RIL" + 1, strlen("QC_RIL") - 1)) break;
+        goto inform;
+      case 'I':
+        /* Any log tag with "IMS" as the prefix */
+        if (strncmp(tag + 1, "IMS" + 1, strlen("IMS") - 1)) break;
+        goto inform;
+      case 'A':
+        if (strcmp(tag + 1, "AT" + 1)) break;
+        goto inform;
+      case 'G':
+        if (strcmp(tag + 1, "GSM" + 1)) break;
+        goto inform;
+      case 'S':
+        if (strcmp(tag + 1, "STK" + 1) && strcmp(tag + 1, "SMS" + 1)) break;
+        goto inform;
+      case 'C':
+        if (strcmp(tag + 1, "CDMA" + 1)) break;
+        goto inform;
+      case 'P':
+        if (strcmp(tag + 1, "PHONE" + 1)) break;
+      /* FALLTHRU */
+      inform:
+        bufID = LOG_ID_RADIO;
+        snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
+        tag = tmp_tag;
+      /* FALLTHRU */
+      default:
+        break;
+    }
   }
 
 #if __BIONIC__
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 3f79552..c4bf959 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -527,11 +527,13 @@
 /*
  *	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)
+ * under light load. Expect this to be a long path to logger to convert the
+ * unknown tag (0) into a tagname (less than 200us).
  */
 static void BM_log_event_overhead(int iters) {
   for (unsigned long long i = 0; i < (unsigned)iters; ++i) {
     StartBenchmarkTiming();
+    // log tag number 0 is not known, nor shall it ever be known
     __android_log_btwrite(0, EVENT_TYPE_LONG, &i, sizeof(i));
     StopBenchmarkTiming();
     logd_yield();
@@ -539,6 +541,28 @@
 }
 BENCHMARK(BM_log_event_overhead);
 
+/*
+ *	Measure the time it takes to submit the android event logging call
+ * using discrete acquisition (StartBenchmarkTiming() -> StopBenchmarkTiming())
+ * under light load with a known logtag.  Expect this to be a dozen or so
+ * syscall periods (less than 40us)
+ */
+static void BM_log_event_overhead_42(int iters) {
+  for (unsigned long long i = 0; i < (unsigned)iters; ++i) {
+    StartBenchmarkTiming();
+    // In system/core/logcat/event.logtags:
+    // # These are used for testing, do not modify without updating
+    // # tests/framework-tests/src/android/util/EventLogFunctionalTest.java.
+    // # system/core/liblog/tests/liblog_benchmark.cpp
+    // # system/core/liblog/tests/liblog_test.cpp
+    // 42    answer (to life the universe etc|3)
+    __android_log_btwrite(42, EVENT_TYPE_LONG, &i, sizeof(i));
+    StopBenchmarkTiming();
+    logd_yield();
+  }
+}
+BENCHMARK(BM_log_event_overhead_42);
+
 static void BM_log_event_overhead_null(int iters) {
   set_log_null();
   BM_log_event_overhead(iters);
diff --git a/libnativebridge/.clang-format b/libnativebridge/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/libnativebridge/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/libnativeloader/.clang-format b/libnativeloader/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/libnativeloader/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 11bd8cc..47f6ff3 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -24,6 +24,8 @@
 
 int killProcessGroup(uid_t uid, int initialPid, int signal);
 
+int killProcessGroupOnce(uid_t uid, int initialPid, int signal);
+
 int createProcessGroup(uid_t uid, int initialPid);
 
 void removeAllProcessGroups(void);
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index eb66727..1572cb3 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -252,8 +252,7 @@
     }
 }
 
-static int killProcessGroupOnce(uid_t uid, int initialPid, int signal)
-{
+static int doKillProcessGroupOnce(uid_t uid, int initialPid, int signal) {
     int processes = 0;
     struct ctx ctx;
     pid_t pid;
@@ -282,13 +281,11 @@
     return processes;
 }
 
-int killProcessGroup(uid_t uid, int initialPid, int signal)
-{
+static int killProcessGroup(uid_t uid, int initialPid, int signal, int retry) {
     std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
 
-    int retry = 40;
     int processes;
-    while ((processes = killProcessGroupOnce(uid, initialPid, signal)) > 0) {
+    while ((processes = doKillProcessGroupOnce(uid, initialPid, signal)) > 0) {
         LOG(VERBOSE) << "killed " << processes << " processes for processgroup " << initialPid;
         if (retry > 0) {
             std::this_thread::sleep_for(5ms);
@@ -313,6 +310,14 @@
     }
 }
 
+int killProcessGroup(uid_t uid, int initialPid, int signal) {
+    return killProcessGroup(uid, initialPid, signal, 40 /*maxRetry*/);
+}
+
+int killProcessGroupOnce(uid_t uid, int initialPid, int signal) {
+    return killProcessGroup(uid, initialPid, signal, 0 /*maxRetry*/);
+}
+
 static bool mkdirAndChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
 {
     if (mkdir(path, mode) == -1 && errno != EEXIST) {
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index ece623b..dabeac1 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -47,6 +47,7 @@
 
     srcs: [
         "ArmExidx.cpp",
+        "DwarfMemory.cpp",
         "Elf.cpp",
         "ElfInterface.cpp",
         "ElfInterfaceArm.cpp",
@@ -87,6 +88,7 @@
     srcs: [
         "tests/ArmExidxDecodeTest.cpp",
         "tests/ArmExidxExtractTest.cpp",
+        "tests/DwarfMemoryTest.cpp",
         "tests/ElfInterfaceArmTest.cpp",
         "tests/ElfInterfaceTest.cpp",
         "tests/ElfTest.cpp",
diff --git a/libunwindstack/DwarfEncoding.h b/libunwindstack/DwarfEncoding.h
new file mode 100644
index 0000000..0ff3b8c
--- /dev/null
+++ b/libunwindstack/DwarfEncoding.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_DWARF_ENCODING_H
+#define _LIBUNWINDSTACK_DWARF_ENCODING_H
+
+#include <stdint.h>
+
+enum DwarfEncoding : uint8_t {
+  DW_EH_PE_omit = 0xff,
+
+  DW_EH_PE_absptr = 0x00,
+  DW_EH_PE_uleb128 = 0x01,
+  DW_EH_PE_udata2 = 0x02,
+  DW_EH_PE_udata4 = 0x03,
+  DW_EH_PE_udata8 = 0x04,
+  DW_EH_PE_sleb128 = 0x09,
+  DW_EH_PE_sdata2 = 0x0a,
+  DW_EH_PE_sdata4 = 0x0b,
+  DW_EH_PE_sdata8 = 0x0c,
+
+  DW_EH_PE_pcrel = 0x10,
+  DW_EH_PE_textrel = 0x20,
+  DW_EH_PE_datarel = 0x30,
+  DW_EH_PE_funcrel = 0x40,
+  DW_EH_PE_aligned = 0x50,
+
+  // The following are special values used to encode CFA and OP operands.
+  DW_EH_PE_udata1 = 0x0d,
+  DW_EH_PE_sdata1 = 0x0e,
+  DW_EH_PE_block = 0x0f,
+};
+
+#endif  // _LIBUNWINDSTACK_DWARF_ENCODING_H
diff --git a/libunwindstack/DwarfMemory.cpp b/libunwindstack/DwarfMemory.cpp
new file mode 100644
index 0000000..11806ea
--- /dev/null
+++ b/libunwindstack/DwarfMemory.cpp
@@ -0,0 +1,248 @@
+/*
+ * 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 <assert.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "DwarfEncoding.h"
+#include "DwarfMemory.h"
+#include "Memory.h"
+
+bool DwarfMemory::ReadBytes(void* dst, size_t num_bytes) {
+  if (!memory_->Read(cur_offset_, dst, num_bytes)) {
+    return false;
+  }
+  cur_offset_ += num_bytes;
+  return true;
+}
+
+template <typename SignedType>
+bool DwarfMemory::ReadSigned(uint64_t* value) {
+  SignedType signed_value;
+  if (!ReadBytes(&signed_value, sizeof(SignedType))) {
+    return false;
+  }
+  *value = static_cast<int64_t>(signed_value);
+  return true;
+}
+
+bool DwarfMemory::ReadULEB128(uint64_t* value) {
+  uint64_t cur_value = 0;
+  uint64_t shift = 0;
+  uint8_t byte;
+  do {
+    if (!ReadBytes(&byte, 1)) {
+      return false;
+    }
+    cur_value += static_cast<uint64_t>(byte & 0x7f) << shift;
+    shift += 7;
+  } while (byte & 0x80);
+  *value = cur_value;
+  return true;
+}
+
+bool DwarfMemory::ReadSLEB128(int64_t* value) {
+  uint64_t cur_value = 0;
+  uint64_t shift = 0;
+  uint8_t byte;
+  do {
+    if (!ReadBytes(&byte, 1)) {
+      return false;
+    }
+    cur_value += static_cast<uint64_t>(byte & 0x7f) << shift;
+    shift += 7;
+  } while (byte & 0x80);
+  if (byte & 0x40) {
+    // Negative value, need to sign extend.
+    cur_value |= static_cast<uint64_t>(-1) << shift;
+  }
+  *value = static_cast<int64_t>(cur_value);
+  return true;
+}
+
+template <typename AddressType>
+size_t DwarfMemory::GetEncodedSize(uint8_t encoding) {
+  switch (encoding & 0x0f) {
+    case DW_EH_PE_absptr:
+      return sizeof(AddressType);
+    case DW_EH_PE_udata1:
+    case DW_EH_PE_sdata1:
+      return 1;
+    case DW_EH_PE_udata2:
+    case DW_EH_PE_sdata2:
+      return 2;
+    case DW_EH_PE_udata4:
+    case DW_EH_PE_sdata4:
+      return 4;
+    case DW_EH_PE_udata8:
+    case DW_EH_PE_sdata8:
+      return 8;
+    case DW_EH_PE_uleb128:
+    case DW_EH_PE_sleb128:
+    default:
+      return 0;
+  }
+}
+
+bool DwarfMemory::AdjustEncodedValue(uint8_t encoding, uint64_t* value) {
+  assert((encoding & 0x0f) == 0);
+  assert(encoding != DW_EH_PE_aligned);
+
+  // Handle the encoding.
+  switch (encoding) {
+    case DW_EH_PE_absptr:
+      // Nothing to do.
+      break;
+    case DW_EH_PE_pcrel:
+      if (pc_offset_ == static_cast<uint64_t>(-1)) {
+        // Unsupported encoding.
+        return false;
+      }
+      *value += pc_offset_;
+      break;
+    case DW_EH_PE_textrel:
+      if (text_offset_ == static_cast<uint64_t>(-1)) {
+        // Unsupported encoding.
+        return false;
+      }
+      *value += text_offset_;
+      break;
+    case DW_EH_PE_datarel:
+      if (data_offset_ == static_cast<uint64_t>(-1)) {
+        // Unsupported encoding.
+        return false;
+      }
+      *value += data_offset_;
+      break;
+    case DW_EH_PE_funcrel:
+      if (func_offset_ == static_cast<uint64_t>(-1)) {
+        // Unsupported encoding.
+        return false;
+      }
+      *value += func_offset_;
+      break;
+    default:
+      return false;
+  }
+
+  return true;
+}
+
+template <typename AddressType>
+bool DwarfMemory::ReadEncodedValue(uint8_t encoding, uint64_t* value) {
+  if (encoding == DW_EH_PE_omit) {
+    *value = 0;
+    return true;
+  } else if (encoding == DW_EH_PE_aligned) {
+    if (__builtin_add_overflow(cur_offset_, sizeof(AddressType) - 1, &cur_offset_)) {
+      return false;
+    }
+    cur_offset_ &= -sizeof(AddressType);
+
+    if (sizeof(AddressType) != sizeof(uint64_t)) {
+      *value = 0;
+    }
+    return ReadBytes(value, sizeof(AddressType));
+  }
+
+  // Get the data.
+  switch (encoding & 0x0f) {
+    case DW_EH_PE_absptr:
+      if (sizeof(AddressType) != sizeof(uint64_t)) {
+        *value = 0;
+      }
+      if (!ReadBytes(value, sizeof(AddressType))) {
+        return false;
+      }
+      break;
+    case DW_EH_PE_uleb128:
+      if (!ReadULEB128(value)) {
+        return false;
+      }
+      break;
+    case DW_EH_PE_sleb128:
+      int64_t signed_value;
+      if (!ReadSLEB128(&signed_value)) {
+        return false;
+      }
+      *value = static_cast<uint64_t>(signed_value);
+      break;
+    case DW_EH_PE_udata1: {
+      uint8_t value8;
+      if (!ReadBytes(&value8, 1)) {
+        return false;
+      }
+      *value = value8;
+    } break;
+    case DW_EH_PE_sdata1:
+      if (!ReadSigned<int8_t>(value)) {
+        return false;
+      }
+      break;
+    case DW_EH_PE_udata2: {
+      uint16_t value16;
+      if (!ReadBytes(&value16, 2)) {
+        return false;
+      }
+      *value = value16;
+    } break;
+    case DW_EH_PE_sdata2:
+      if (!ReadSigned<int16_t>(value)) {
+        return false;
+      }
+      break;
+    case DW_EH_PE_udata4: {
+      uint32_t value32;
+      if (!ReadBytes(&value32, 4)) {
+        return false;
+      }
+      *value = value32;
+    } break;
+    case DW_EH_PE_sdata4:
+      if (!ReadSigned<int32_t>(value)) {
+        return false;
+      }
+      break;
+    case DW_EH_PE_udata8:
+      if (!ReadBytes(value, sizeof(uint64_t))) {
+        return false;
+      }
+      break;
+    case DW_EH_PE_sdata8:
+      if (!ReadSigned<int64_t>(value)) {
+        return false;
+      }
+      break;
+    default:
+      return false;
+  }
+
+  return AdjustEncodedValue(encoding & 0xf0, value);
+}
+
+// Instantiate all of the needed template functions.
+template bool DwarfMemory::ReadSigned<int8_t>(uint64_t*);
+template bool DwarfMemory::ReadSigned<int16_t>(uint64_t*);
+template bool DwarfMemory::ReadSigned<int32_t>(uint64_t*);
+template bool DwarfMemory::ReadSigned<int64_t>(uint64_t*);
+
+template size_t DwarfMemory::GetEncodedSize<uint32_t>(uint8_t);
+template size_t DwarfMemory::GetEncodedSize<uint64_t>(uint8_t);
+
+template bool DwarfMemory::ReadEncodedValue<uint32_t>(uint8_t, uint64_t*);
+template bool DwarfMemory::ReadEncodedValue<uint64_t>(uint8_t, uint64_t*);
diff --git a/libunwindstack/DwarfMemory.h b/libunwindstack/DwarfMemory.h
new file mode 100644
index 0000000..a304dd9
--- /dev/null
+++ b/libunwindstack/DwarfMemory.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_DWARF_MEMORY_H
+#define _LIBUNWINDSTACK_DWARF_MEMORY_H
+
+#include <stdint.h>
+
+// Forward declarations.
+class Memory;
+
+class DwarfMemory {
+ public:
+  DwarfMemory(Memory* memory) : memory_(memory) {}
+  virtual ~DwarfMemory() = default;
+
+  bool ReadBytes(void* dst, size_t num_bytes);
+
+  template <typename SignedType>
+  bool ReadSigned(uint64_t* value);
+
+  bool ReadULEB128(uint64_t* value);
+
+  bool ReadSLEB128(int64_t* value);
+
+  template <typename AddressType>
+  size_t GetEncodedSize(uint8_t encoding);
+
+  bool AdjustEncodedValue(uint8_t encoding, uint64_t* value);
+
+  template <typename AddressType>
+  bool ReadEncodedValue(uint8_t encoding, uint64_t* value);
+
+  uint64_t cur_offset() { return cur_offset_; }
+  void set_cur_offset(uint64_t cur_offset) { cur_offset_ = cur_offset; }
+
+  void set_pc_offset(uint64_t offset) { pc_offset_ = offset; }
+  void clear_pc_offset() { pc_offset_ = static_cast<uint64_t>(-1); }
+
+  void set_data_offset(uint64_t offset) { data_offset_ = offset; }
+  void clear_data_offset() { data_offset_ = static_cast<uint64_t>(-1); }
+
+  void set_func_offset(uint64_t offset) { func_offset_ = offset; }
+  void clear_func_offset() { func_offset_ = static_cast<uint64_t>(-1); }
+
+  void set_text_offset(uint64_t offset) { text_offset_ = offset; }
+  void clear_text_offset() { text_offset_ = static_cast<uint64_t>(-1); }
+
+ private:
+  Memory* memory_;
+  uint64_t cur_offset_ = 0;
+
+  uint64_t pc_offset_ = static_cast<uint64_t>(-1);
+  uint64_t data_offset_ = static_cast<uint64_t>(-1);
+  uint64_t func_offset_ = static_cast<uint64_t>(-1);
+  uint64_t text_offset_ = static_cast<uint64_t>(-1);
+};
+
+#endif  // _LIBUNWINDSTACK_DWARF_MEMORY_H
diff --git a/libunwindstack/tests/DwarfMemoryTest.cpp b/libunwindstack/tests/DwarfMemoryTest.cpp
new file mode 100644
index 0000000..4877f36
--- /dev/null
+++ b/libunwindstack/tests/DwarfMemoryTest.cpp
@@ -0,0 +1,472 @@
+/*
+ * 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 <stdint.h>
+
+#include <ios>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "DwarfMemory.h"
+
+#include "MemoryFake.h"
+
+class DwarfMemoryTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    memory_.Clear();
+    dwarf_mem_.reset(new DwarfMemory(&memory_));
+  }
+
+  template <typename AddressType>
+  void GetEncodedSizeTest(uint8_t value, size_t expected);
+  template <typename AddressType>
+  void ReadEncodedValue_omit();
+  template <typename AddressType>
+  void ReadEncodedValue_leb128();
+  template <typename AddressType>
+  void ReadEncodedValue_data1();
+  template <typename AddressType>
+  void ReadEncodedValue_data2();
+  template <typename AddressType>
+  void ReadEncodedValue_data4();
+  template <typename AddressType>
+  void ReadEncodedValue_data8();
+  template <typename AddressType>
+  void ReadEncodedValue_non_zero_adjust();
+  template <typename AddressType>
+  void ReadEncodedValue_overflow();
+
+  MemoryFake memory_;
+  std::unique_ptr<DwarfMemory> dwarf_mem_;
+};
+
+TEST_F(DwarfMemoryTest, ReadBytes) {
+  memory_.SetMemory(0, std::vector<uint8_t>{0x10, 0x18, 0xff, 0xfe});
+
+  uint8_t byte;
+  ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
+  ASSERT_EQ(0x10U, byte);
+  ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
+  ASSERT_EQ(0x18U, byte);
+  ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
+  ASSERT_EQ(0xffU, byte);
+  ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
+  ASSERT_EQ(0xfeU, byte);
+  ASSERT_EQ(4U, dwarf_mem_->cur_offset());
+
+  dwarf_mem_->set_cur_offset(2);
+  ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
+  ASSERT_EQ(0xffU, byte);
+  ASSERT_EQ(3U, dwarf_mem_->cur_offset());
+}
+
+TEST_F(DwarfMemoryTest, ReadSigned_check) {
+  uint64_t value;
+
+  // Signed 8 byte reads.
+  memory_.SetData8(0, static_cast<uint8_t>(-10));
+  memory_.SetData8(1, 200);
+  ASSERT_TRUE(dwarf_mem_->ReadSigned<int8_t>(&value));
+  ASSERT_EQ(static_cast<int8_t>(-10), static_cast<int8_t>(value));
+  ASSERT_TRUE(dwarf_mem_->ReadSigned<int8_t>(&value));
+  ASSERT_EQ(static_cast<int8_t>(200), static_cast<int8_t>(value));
+
+  // Signed 16 byte reads.
+  memory_.SetData16(0x10, static_cast<uint16_t>(-1000));
+  memory_.SetData16(0x12, 50100);
+  dwarf_mem_->set_cur_offset(0x10);
+  ASSERT_TRUE(dwarf_mem_->ReadSigned<int16_t>(&value));
+  ASSERT_EQ(static_cast<int16_t>(-1000), static_cast<int16_t>(value));
+  ASSERT_TRUE(dwarf_mem_->ReadSigned<int16_t>(&value));
+  ASSERT_EQ(static_cast<int16_t>(50100), static_cast<int16_t>(value));
+
+  // Signed 32 byte reads.
+  memory_.SetData32(0x100, static_cast<uint32_t>(-1000000000));
+  memory_.SetData32(0x104, 3000000000);
+  dwarf_mem_->set_cur_offset(0x100);
+  ASSERT_TRUE(dwarf_mem_->ReadSigned<int32_t>(&value));
+  ASSERT_EQ(static_cast<int32_t>(-1000000000), static_cast<int32_t>(value));
+  ASSERT_TRUE(dwarf_mem_->ReadSigned<int32_t>(&value));
+  ASSERT_EQ(static_cast<int32_t>(3000000000), static_cast<int32_t>(value));
+
+  // Signed 64 byte reads.
+  memory_.SetData64(0x200, static_cast<uint64_t>(-2000000000000LL));
+  memory_.SetData64(0x208, 5000000000000LL);
+  dwarf_mem_->set_cur_offset(0x200);
+  ASSERT_TRUE(dwarf_mem_->ReadSigned<int64_t>(&value));
+  ASSERT_EQ(static_cast<int64_t>(-2000000000000), static_cast<int64_t>(value));
+  ASSERT_TRUE(dwarf_mem_->ReadSigned<int64_t>(&value));
+  ASSERT_EQ(static_cast<int64_t>(5000000000000), static_cast<int64_t>(value));
+}
+
+TEST_F(DwarfMemoryTest, ReadULEB128) {
+  memory_.SetMemory(0, std::vector<uint8_t>{0x01, 0x80, 0x24, 0xff, 0xc3, 0xff, 0x7f});
+
+  uint64_t value;
+  ASSERT_TRUE(dwarf_mem_->ReadULEB128(&value));
+  ASSERT_EQ(1U, dwarf_mem_->cur_offset());
+  ASSERT_EQ(1U, value);
+
+  ASSERT_TRUE(dwarf_mem_->ReadULEB128(&value));
+  ASSERT_EQ(3U, dwarf_mem_->cur_offset());
+  ASSERT_EQ(0x1200U, value);
+
+  ASSERT_TRUE(dwarf_mem_->ReadULEB128(&value));
+  ASSERT_EQ(7U, dwarf_mem_->cur_offset());
+  ASSERT_EQ(0xfffe1ffU, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadSLEB128) {
+  memory_.SetMemory(0, std::vector<uint8_t>{0x06, 0x40, 0x82, 0x34, 0x89, 0x64, 0xf9, 0xc3, 0x8f,
+                                            0x2f, 0xbf, 0xc3, 0xf7, 0x5f});
+
+  int64_t value;
+  ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
+  ASSERT_EQ(1U, dwarf_mem_->cur_offset());
+  ASSERT_EQ(6U, value);
+
+  ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
+  ASSERT_EQ(2U, dwarf_mem_->cur_offset());
+  ASSERT_EQ(0xffffffffffffffc0ULL, static_cast<uint64_t>(value));
+
+  ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
+  ASSERT_EQ(4U, dwarf_mem_->cur_offset());
+  ASSERT_EQ(0x1a02U, value);
+
+  ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
+  ASSERT_EQ(6U, dwarf_mem_->cur_offset());
+  ASSERT_EQ(0xfffffffffffff209ULL, static_cast<uint64_t>(value));
+
+  ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
+  ASSERT_EQ(10U, dwarf_mem_->cur_offset());
+  ASSERT_EQ(0x5e3e1f9U, value);
+
+  ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
+  ASSERT_EQ(14U, dwarf_mem_->cur_offset());
+  ASSERT_EQ(0xfffffffffbfde1bfULL, static_cast<uint64_t>(value));
+}
+
+template <typename AddressType>
+void DwarfMemoryTest::GetEncodedSizeTest(uint8_t value, size_t expected) {
+  for (size_t i = 0; i < 16; i++) {
+    uint8_t encoding = (i << 4) | value;
+    ASSERT_EQ(expected, dwarf_mem_->GetEncodedSize<AddressType>(encoding))
+        << "encoding 0x" << std::hex << static_cast<uint32_t>(encoding) << " test value 0x"
+        << static_cast<size_t>(value);
+  }
+}
+
+TEST_F(DwarfMemoryTest, GetEncodedSize_absptr_uint32_t) {
+  GetEncodedSizeTest<uint32_t>(0, sizeof(uint32_t));
+}
+
+TEST_F(DwarfMemoryTest, GetEncodedSize_absptr_uint64_t) {
+  GetEncodedSizeTest<uint64_t>(0, sizeof(uint64_t));
+}
+
+TEST_F(DwarfMemoryTest, GetEncodedSize_data1) {
+  // udata1
+  GetEncodedSizeTest<uint32_t>(0x0d, 1);
+  GetEncodedSizeTest<uint64_t>(0x0d, 1);
+
+  // sdata1
+  GetEncodedSizeTest<uint32_t>(0x0e, 1);
+  GetEncodedSizeTest<uint64_t>(0x0e, 1);
+}
+
+TEST_F(DwarfMemoryTest, GetEncodedSize_data2) {
+  // udata2
+  GetEncodedSizeTest<uint32_t>(0x02, 2);
+  GetEncodedSizeTest<uint64_t>(0x02, 2);
+
+  // sdata2
+  GetEncodedSizeTest<uint32_t>(0x0a, 2);
+  GetEncodedSizeTest<uint64_t>(0x0a, 2);
+}
+
+TEST_F(DwarfMemoryTest, GetEncodedSize_data4) {
+  // udata4
+  GetEncodedSizeTest<uint32_t>(0x03, 4);
+  GetEncodedSizeTest<uint64_t>(0x03, 4);
+
+  // sdata4
+  GetEncodedSizeTest<uint32_t>(0x0b, 4);
+  GetEncodedSizeTest<uint64_t>(0x0b, 4);
+}
+
+TEST_F(DwarfMemoryTest, GetEncodedSize_data8) {
+  // udata8
+  GetEncodedSizeTest<uint32_t>(0x04, 8);
+  GetEncodedSizeTest<uint64_t>(0x04, 8);
+
+  // sdata8
+  GetEncodedSizeTest<uint32_t>(0x0c, 8);
+  GetEncodedSizeTest<uint64_t>(0x0c, 8);
+}
+
+TEST_F(DwarfMemoryTest, GetEncodedSize_unknown) {
+  GetEncodedSizeTest<uint32_t>(0x01, 0);
+  GetEncodedSizeTest<uint64_t>(0x01, 0);
+
+  GetEncodedSizeTest<uint32_t>(0x09, 0);
+  GetEncodedSizeTest<uint64_t>(0x09, 0);
+
+  GetEncodedSizeTest<uint32_t>(0x0f, 0);
+  GetEncodedSizeTest<uint64_t>(0x0f, 0);
+}
+
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_omit() {
+  uint64_t value = 123;
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0xff, &value));
+  ASSERT_EQ(0U, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_omit_uint32_t) { ReadEncodedValue_omit<uint32_t>(); }
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_omit_uint64_t) { ReadEncodedValue_omit<uint64_t>(); }
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_absptr_uint32_t) {
+  uint64_t value = 100;
+  ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<uint32_t>(0x00, &value));
+
+  memory_.SetData32(0, 0x12345678);
+
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<uint32_t>(0x00, &value));
+  ASSERT_EQ(4U, dwarf_mem_->cur_offset());
+  ASSERT_EQ(0x12345678U, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_absptr_uint64_t) {
+  uint64_t value = 100;
+  ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<uint64_t>(0x00, &value));
+
+  memory_.SetData64(0, 0x12345678f1f2f3f4ULL);
+
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<uint64_t>(0x00, &value));
+  ASSERT_EQ(8U, dwarf_mem_->cur_offset());
+  ASSERT_EQ(0x12345678f1f2f3f4ULL, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_aligned_uint32_t) {
+  uint64_t value = 100;
+  dwarf_mem_->set_cur_offset(1);
+  ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<uint32_t>(0x50, &value));
+
+  memory_.SetData32(4, 0x12345678);
+
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<uint32_t>(0x50, &value));
+  ASSERT_EQ(8U, dwarf_mem_->cur_offset());
+  ASSERT_EQ(0x12345678U, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_aligned_uint64_t) {
+  uint64_t value = 100;
+  dwarf_mem_->set_cur_offset(1);
+  ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<uint64_t>(0x50, &value));
+
+  memory_.SetData64(8, 0x12345678f1f2f3f4ULL);
+
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<uint64_t>(0x50, &value));
+  ASSERT_EQ(16U, dwarf_mem_->cur_offset());
+  ASSERT_EQ(0x12345678f1f2f3f4ULL, value);
+}
+
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_leb128() {
+  memory_.SetMemory(0, std::vector<uint8_t>{0x80, 0x42});
+
+  uint64_t value = 100;
+  // uleb128
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x01, &value));
+  ASSERT_EQ(0x2100U, value);
+
+  dwarf_mem_->set_cur_offset(0);
+  // sleb128
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x09, &value));
+  ASSERT_EQ(0xffffffffffffe100ULL, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_leb128_uint32_t) { ReadEncodedValue_leb128<uint32_t>(); }
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_leb128_uint64_t) { ReadEncodedValue_leb128<uint64_t>(); }
+
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_data1() {
+  memory_.SetData8(0, 0xe0);
+
+  uint64_t value = 0;
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0d, &value));
+  ASSERT_EQ(0xe0U, value);
+
+  dwarf_mem_->set_cur_offset(0);
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0e, &value));
+  ASSERT_EQ(0xffffffffffffffe0ULL, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data1_uint32_t) { ReadEncodedValue_data1<uint32_t>(); }
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data1_uint64_t) { ReadEncodedValue_data1<uint64_t>(); }
+
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_data2() {
+  memory_.SetData16(0, 0xe000);
+
+  uint64_t value = 0;
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x02, &value));
+  ASSERT_EQ(0xe000U, value);
+
+  dwarf_mem_->set_cur_offset(0);
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0a, &value));
+  ASSERT_EQ(0xffffffffffffe000ULL, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data2_uint32_t) { ReadEncodedValue_data2<uint32_t>(); }
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data2_uint64_t) { ReadEncodedValue_data2<uint64_t>(); }
+
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_data4() {
+  memory_.SetData32(0, 0xe0000000);
+
+  uint64_t value = 0;
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x03, &value));
+  ASSERT_EQ(0xe0000000U, value);
+
+  dwarf_mem_->set_cur_offset(0);
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0b, &value));
+  ASSERT_EQ(0xffffffffe0000000ULL, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data4_uint32_t) { ReadEncodedValue_data4<uint32_t>(); }
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data4_uint64_t) { ReadEncodedValue_data4<uint64_t>(); }
+
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_data8() {
+  memory_.SetData64(0, 0xe000000000000000ULL);
+
+  uint64_t value = 0;
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x04, &value));
+  ASSERT_EQ(0xe000000000000000ULL, value);
+
+  dwarf_mem_->set_cur_offset(0);
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0c, &value));
+  ASSERT_EQ(0xe000000000000000ULL, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data8_uint32_t) { ReadEncodedValue_data8<uint32_t>(); }
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data8_uint64_t) { ReadEncodedValue_data8<uint64_t>(); }
+
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_non_zero_adjust() {
+  memory_.SetData64(0, 0xe000000000000000ULL);
+
+  uint64_t value = 0;
+  dwarf_mem_->set_pc_offset(0x2000);
+  ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x14, &value));
+  ASSERT_EQ(0xe000000000002000ULL, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_non_zero_adjust_uint32_t) {
+  ReadEncodedValue_non_zero_adjust<uint32_t>();
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_non_zero_adjust_uint64_t) {
+  ReadEncodedValue_non_zero_adjust<uint64_t>();
+}
+
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_overflow() {
+  memory_.SetData64(0, 0);
+
+  uint64_t value = 0;
+  dwarf_mem_->set_cur_offset(UINT64_MAX);
+  ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<AddressType>(0x50, &value));
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_overflow_uint32_t) {
+  ReadEncodedValue_overflow<uint32_t>();
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_overflow_uint64_t) {
+  ReadEncodedValue_overflow<uint64_t>();
+}
+
+TEST_F(DwarfMemoryTest, AdjustEncodedValue_absptr) {
+  uint64_t value = 0x1234;
+  ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x00, &value));
+  ASSERT_EQ(0x1234U, value);
+}
+
+TEST_F(DwarfMemoryTest, AdjustEncodedValue_pcrel) {
+  uint64_t value = 0x1234;
+  ASSERT_FALSE(dwarf_mem_->AdjustEncodedValue(0x10, &value));
+
+  dwarf_mem_->set_pc_offset(0x2000);
+  ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x10, &value));
+  ASSERT_EQ(0x3234U, value);
+
+  dwarf_mem_->set_pc_offset(static_cast<uint64_t>(-4));
+  value = 0x1234;
+  ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x10, &value));
+  ASSERT_EQ(0x1230U, value);
+}
+
+TEST_F(DwarfMemoryTest, AdjustEncodedValue_textrel) {
+  uint64_t value = 0x8234;
+  ASSERT_FALSE(dwarf_mem_->AdjustEncodedValue(0x20, &value));
+
+  dwarf_mem_->set_text_offset(0x1000);
+  ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x20, &value));
+  ASSERT_EQ(0x9234U, value);
+
+  dwarf_mem_->set_text_offset(static_cast<uint64_t>(-16));
+  value = 0x8234;
+  ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x20, &value));
+  ASSERT_EQ(0x8224U, value);
+}
+
+TEST_F(DwarfMemoryTest, AdjustEncodedValue_datarel) {
+  uint64_t value = 0xb234;
+  ASSERT_FALSE(dwarf_mem_->AdjustEncodedValue(0x30, &value));
+
+  dwarf_mem_->set_data_offset(0x1200);
+  ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x30, &value));
+  ASSERT_EQ(0xc434U, value);
+
+  dwarf_mem_->set_data_offset(static_cast<uint64_t>(-256));
+  value = 0xb234;
+  ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x30, &value));
+  ASSERT_EQ(0xb134U, value);
+}
+
+TEST_F(DwarfMemoryTest, AdjustEncodedValue_funcrel) {
+  uint64_t value = 0x15234;
+  ASSERT_FALSE(dwarf_mem_->AdjustEncodedValue(0x40, &value));
+
+  dwarf_mem_->set_func_offset(0x60000);
+  ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x40, &value));
+  ASSERT_EQ(0x75234U, value);
+
+  dwarf_mem_->set_func_offset(static_cast<uint64_t>(-4096));
+  value = 0x15234;
+  ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x40, &value));
+  ASSERT_EQ(0x14234U, value);
+}
diff --git a/logcat/event.logtags b/logcat/event.logtags
index 909f8e2..9f05351 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -36,6 +36,8 @@
 
 # These are used for testing, do not modify without updating
 # tests/framework-tests/src/android/util/EventLogFunctionalTest.java.
+# system/core/liblog/tests/liblog_benchmark.cpp
+# system/core/liblog/tests/liblog_test.cpp
 42    answer (to life the universe etc|3)
 314   pi
 2718  e
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 86ea6b4..0984e81 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -109,11 +109,11 @@
 
 LogBuffer::LogBuffer(LastLogTimes* times)
     : monotonic(android_log_clockid() == CLOCK_MONOTONIC), mTimes(*times) {
-    pthread_mutex_init(&mLogElementsLock, NULL);
+    pthread_mutex_init(&mLogElementsLock, nullptr);
 
     log_id_for_each(i) {
-        lastLoggedElements[i] = NULL;
-        droppedElements[i] = NULL;
+        lastLoggedElements[i] = nullptr;
+        droppedElements[i] = nullptr;
     }
 
     init();
@@ -196,7 +196,7 @@
         new LogBufferElement(log_id, realtime, uid, pid, tid, msg, len);
     if (log_id != LOG_ID_SECURITY) {
         int prio = ANDROID_LOG_INFO;
-        const char* tag = NULL;
+        const char* tag = nullptr;
         if (log_id == LOG_ID_EVENTS) {
             tag = tagToName(elem->getTag());
         } else {
@@ -222,24 +222,24 @@
         //
         // State Init
         //     incoming:
-        //         dropped = NULL
-        //         currentLast = NULL;
+        //         dropped = nullptr
+        //         currentLast = nullptr;
         //         elem = incoming message
         //     outgoing:
-        //         dropped = NULL -> State 0
+        //         dropped = nullptr -> State 0
         //         currentLast = copy of elem
         //         log elem
         // State 0
         //     incoming:
         //         count = 0
-        //         dropped = NULL
+        //         dropped = nullptr
         //         currentLast = copy of last message
         //         elem = incoming message
         //     outgoing: if match != DIFFERENT
         //         dropped = copy of first identical message -> State 1
         //         currentLast = reference to elem
         //     break: if match == DIFFERENT
-        //         dropped = NULL -> State 0
+        //         dropped = nullptr -> State 0
         //         delete copy of last message (incoming currentLast)
         //         currentLast = copy of elem
         //         log elem
@@ -266,7 +266,7 @@
         //             currentLast = reference to elem, sum liblog.
         //     break: if match == DIFFERENT
         //         delete dropped
-        //         dropped = NULL -> State 0
+        //         dropped = nullptr -> State 0
         //         log reference to last held-back (currentLast)
         //         currentLast = copy of elem
         //         log elem
@@ -285,7 +285,7 @@
         //         currentLast = reference to elem
         //     break: if match == DIFFERENT
         //         log dropped (chatty message)
-        //         dropped = NULL -> State 0
+        //         dropped = nullptr -> State 0
         //         log reference to last held-back (currentLast)
         //         currentLast = copy of elem
         //         log elem
@@ -350,7 +350,7 @@
             } else {           // State 1
                 delete dropped;
             }
-            droppedElements[log_id] = NULL;
+            droppedElements[log_id] = nullptr;
             log(currentLast);  // report last message in the series
         } else {               // State 0
             delete currentLast;
@@ -654,7 +654,7 @@
 // mLogElementsLock must be held when this function is called.
 //
 bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
-    LogTimeEntry* oldest = NULL;
+    LogTimeEntry* oldest = nullptr;
     bool busy = false;
     bool clearAll = pruneRows == ULONG_MAX;
 
@@ -1076,9 +1076,11 @@
     return retval;
 }
 
-log_time LogBuffer::flushTo(
-    SocketClient* reader, const log_time& start, bool privileged, bool security,
-    int (*filter)(const LogBufferElement* element, void* arg), void* arg) {
+log_time LogBuffer::flushTo(SocketClient* reader, const log_time& start,
+                            pid_t* lastTid, bool privileged, bool security,
+                            int (*filter)(const LogBufferElement* element,
+                                          void* arg),
+                            void* arg) {
     LogBufferElementCollection::iterator it;
     uid_t uid = reader->getUid();
 
@@ -1107,9 +1109,6 @@
     }
 
     log_time max = start;
-    // Help detect if the valid message before is from the same source so
-    // we can differentiate chatty filter types.
-    pid_t lastTid[LOG_ID_MAX] = { 0 };
 
     for (; it != mLogElements.end(); ++it) {
         LogBufferElement* element = *it;
@@ -1137,14 +1136,17 @@
             }
         }
 
-        bool sameTid = lastTid[element->getLogId()] == element->getTid();
-        // Dropped (chatty) immediately following a valid log from the
-        // same source in the same log buffer indicates we have a
-        // multiple identical squash.  chatty that differs source
-        // is due to spam filter.  chatty to chatty of different
-        // source is also due to spam filter.
-        lastTid[element->getLogId()] =
-            (element->getDropped() && !sameTid) ? 0 : element->getTid();
+        bool sameTid = false;
+        if (lastTid) {
+            sameTid = lastTid[element->getLogId()] == element->getTid();
+            // Dropped (chatty) immediately following a valid log from the
+            // same source in the same log buffer indicates we have a
+            // multiple identical squash.  chatty that differs source
+            // is due to spam filter.  chatty to chatty of different
+            // source is also due to spam filter.
+            lastTid[element->getLogId()] =
+                (element->getDropped() && !sameTid) ? 0 : element->getTid();
+        }
 
         pthread_mutex_unlock(&mLogElementsLock);
 
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index fcf6b9a..19d11cb 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -115,11 +115,15 @@
 
     int log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
             const char* msg, unsigned short len);
+    // lastTid is an optional context to help detect if the last previous
+    // valid message was from the same source so we can differentiate chatty
+    // filter types (identical or expired)
     log_time flushTo(SocketClient* writer, const log_time& start,
+                     pid_t* lastTid,  // &lastTid[LOG_ID_MAX] or nullptr
                      bool privileged, bool security,
                      int (*filter)(const LogBufferElement* element,
-                                   void* arg) = NULL,
-                     void* arg = NULL);
+                                   void* arg) = nullptr,
+                     void* arg = nullptr);
 
     bool clear(log_id_t id, uid_t uid = AID_ROOT);
     unsigned long getSize(log_id_t id);
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 620d4d0..af19279 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -182,7 +182,7 @@
         } logFindStart(pid, logMask, sequence,
                        logbuf().isMonotonic() && android::isMonotonic(start));
 
-        logbuf().flushTo(cli, sequence, FlushCommand::hasReadLogs(cli),
+        logbuf().flushTo(cli, sequence, nullptr, FlushCommand::hasReadLogs(cli),
                          FlushCommand::hasSecurityLogs(cli),
                          logFindStart.callback, &logFindStart);
 
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 04e531f..ccc550a 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <errno.h>
+#include <string.h>
 #include <sys/prctl.h>
 
 #include <private/android_logger.h>
@@ -47,7 +48,8 @@
       mEnd(log_time(android_log_clockid())) {
     mTimeout.tv_sec = timeout / NS_PER_SEC;
     mTimeout.tv_nsec = timeout % NS_PER_SEC;
-    pthread_cond_init(&threadTriggeredCondition, NULL);
+    memset(mLastTid, 0, sizeof(mLastTid));
+    pthread_cond_init(&threadTriggeredCondition, nullptr);
     cleanSkip_Locked();
 }
 
@@ -98,7 +100,7 @@
             it++;
         }
 
-        me->mClient = NULL;
+        me->mClient = nullptr;
         reader.release(client);
     }
 
@@ -122,7 +124,7 @@
     SocketClient* client = me->mClient;
     if (!client) {
         me->error();
-        return NULL;
+        return nullptr;
     }
 
     LogBuffer& logbuf = me->mReader.logbuf();
@@ -151,12 +153,12 @@
         unlock();
 
         if (me->mTail) {
-            logbuf.flushTo(client, start, privileged, security, FilterFirstPass,
-                           me);
+            logbuf.flushTo(client, start, nullptr, privileged, security,
+                           FilterFirstPass, me);
             me->leadingDropped = true;
         }
-        start = logbuf.flushTo(client, start, privileged, security,
-                               FilterSecondPass, me);
+        start = logbuf.flushTo(client, start, me->mLastTid, privileged,
+                               security, FilterSecondPass, me);
 
         lock();
 
@@ -182,7 +184,7 @@
 
     pthread_cleanup_pop(true);
 
-    return NULL;
+    return nullptr;
 }
 
 // A first pass to count the number of elements
@@ -281,7 +283,5 @@
 }
 
 void LogTimeEntry::cleanSkip_Locked(void) {
-    for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t)(i + 1)) {
-        skipAhead[i] = 0;
-    }
+    memset(skipAhead, 0, sizeof(skipAhead));
 }
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index 9a3ddab..ec8252e 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -44,6 +44,7 @@
     const unsigned int mLogMask;
     const pid_t mPid;
     unsigned int skipAhead[LOG_ID_MAX];
+    pid_t mLastTid[LOG_ID_MAX];
     unsigned long mCount;
     unsigned long mTail;
     unsigned long mIndex;
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index ddff393..d0101ed 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -426,7 +426,7 @@
                     " BM_log_maximum_retry"
                     " BM_log_maximum"
                     " BM_clock_overhead"
-                    " BM_log_overhead"
+                    " BM_log_print_overhead"
                     " BM_log_latency"
                     " BM_log_delay",
                     "r")));
@@ -434,13 +434,13 @@
     char buffer[5120];
 
     static const char* benchmarks[] = {
-        "BM_log_maximum_retry ", "BM_log_maximum ", "BM_clock_overhead ",
-        "BM_log_overhead ",      "BM_log_latency ", "BM_log_delay "
+        "BM_log_maximum_retry ",  "BM_log_maximum ", "BM_clock_overhead ",
+        "BM_log_print_overhead ", "BM_log_latency ", "BM_log_delay "
     };
     static const unsigned int log_maximum_retry = 0;
     static const unsigned int log_maximum = 1;
     static const unsigned int clock_overhead = 2;
-    static const unsigned int log_overhead = 3;
+    static const unsigned int log_print_overhead = 3;
     static const unsigned int log_latency = 4;
     static const unsigned int log_delay = 5;
 
@@ -469,21 +469,23 @@
     }
 
     EXPECT_GE(200000UL, ns[log_maximum_retry]);  // 104734 user
+    EXPECT_NE(0UL, ns[log_maximum_retry]);       // failure to parse
 
     EXPECT_GE(90000UL, ns[log_maximum]);  // 46913 user
+    EXPECT_NE(0UL, ns[log_maximum]);      // failure to parse
 
     EXPECT_GE(4096UL, ns[clock_overhead]);  // 4095
+    EXPECT_NE(0UL, ns[clock_overhead]);     // failure to parse
 
-    EXPECT_GE(250000UL, ns[log_overhead]);  // 126886 user
+    EXPECT_GE(250000UL, ns[log_print_overhead]);  // 126886 user
+    EXPECT_NE(0UL, ns[log_print_overhead]);       // failure to parse
 
     EXPECT_GE(10000000UL,
               ns[log_latency]);  // 1453559 user space (background cgroup)
+    EXPECT_NE(0UL, ns[log_latency]);  // failure to parse
 
     EXPECT_GE(20000000UL, ns[log_delay]);  // 10500289 user
-
-    for (unsigned i = 0; i < arraysize(ns); ++i) {
-        EXPECT_NE(0UL, ns[i]);
-    }
+    EXPECT_NE(0UL, ns[log_delay]);         // failure to parse
 
     alloc_statistics(&buf, &len);
 
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
new file mode 100644
index 0000000..81cf315
--- /dev/null
+++ b/shell_and_utilities/Android.bp
@@ -0,0 +1,13 @@
+phony {
+    name: "shell_and_utilities",
+    required: [
+        "bzip2",
+        "grep",
+        "gzip",
+        "mkshrc",
+        "reboot",
+        "sh",
+        "toolbox",
+        "toybox",
+    ],
+}