Merge "fs_mgr: removing fs_mgr_read_fstab_with_dt()"
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..1befcb1 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;
   }
 }
 
@@ -508,3 +526,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/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/init/Android.mk b/init/Android.mk
index b52c949..1ca88d7 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -16,6 +16,14 @@
     -DREBOOT_BOOTLOADER_ON_PANIC=0
 endif
 
+ifneq (,$(filter eng,$(TARGET_BUILD_VARIANT)))
+init_options += \
+    -DSHUTDOWN_ZERO_TIMEOUT=1
+else
+init_options += \
+    -DSHUTDOWN_ZERO_TIMEOUT=0
+endif
+
 init_options += -DLOG_UEVENTS=0
 
 init_cflags += \
diff --git a/init/README.md b/init/README.md
index 024d559..e66ade2 100644
--- a/init/README.md
+++ b/init/README.md
@@ -286,11 +286,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.
@@ -311,6 +306,12 @@
   groups can be provided. No other commands will be run until this one
   finishes. _seclabel_ can be a - to denote default. Properties are expanded
   within _argument_.
+  Init halts executing commands until the forked process exits.
+
+`exec_start <service>`
+> Start service a given service and halt processing of additional init commands
+  until it returns.  It functions similarly to the `exec` command, but uses an
+  existing service definition instead of providing them as arguments.
 
 `export <name> <value>`
 > Set the environment variable _name_ equal to _value_ in the
diff --git a/init/action.cpp b/init/action.cpp
index 1bba0f2..2ccf0bc 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -18,14 +18,14 @@
 
 #include <errno.h>
 
-#include <android-base/strings.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 
 #include "builtins.h"
 #include "error.h"
 #include "init_parser.h"
 #include "log.h"
-#include "property_service.h"
 #include "util.h"
 
 using android::base::Join;
@@ -219,9 +219,8 @@
                 found = true;
             }
         } else {
-            std::string prop_val = property_get(trigger_name.c_str());
-            if (prop_val.empty() || (trigger_value != "*" &&
-                                     trigger_value != prop_val)) {
+            std::string prop_val = android::base::GetProperty(trigger_name, "");
+            if (prop_val.empty() || (trigger_value != "*" && trigger_value != prop_val)) {
                 return false;
             }
         }
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index 4a9c32e..beabea1 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -16,8 +16,6 @@
 
 #include "bootchart.h"
 
-#include "property_service.h"
-
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -39,6 +37,7 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 
 using android::base::StringPrintf;
@@ -72,7 +71,7 @@
   utsname uts;
   if (uname(&uts) == -1) return;
 
-  std::string fingerprint = property_get("ro.build.fingerprint");
+  std::string fingerprint = android::base::GetProperty("ro.build.fingerprint", "");
   if (fingerprint.empty()) return;
 
   std::string kernel_cmdline;
diff --git a/init/builtins.cpp b/init/builtins.cpp
index ec55b03..dc2bda6 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -45,15 +45,16 @@
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 
-#include <fs_mgr.h>
 #include <android-base/file.h>
 #include <android-base/parseint.h>
-#include <android-base/strings.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <bootloader_message/bootloader_message.h>
 #include <cutils/android_reboot.h>
 #include <ext4_utils/ext4_crypt.h>
 #include <ext4_utils/ext4_crypt_init_extensions.h>
+#include <fs_mgr.h>
 #include <logwrap/logwrap.h>
 
 #include "action.h"
@@ -166,19 +167,11 @@
 }
 
 static int do_exec(const std::vector<std::string>& args) {
-    Service* svc = ServiceManager::GetInstance().MakeExecOneshotService(args);
-    if (!svc) {
-        return -1;
-    }
-    if (!start_waiting_for_exec()) {
-        return -1;
-    }
-    if (!svc->Start()) {
-        stop_waiting_for_exec();
-        ServiceManager::GetInstance().RemoveService(*svc);
-        return -1;
-    }
-    return 0;
+    return ServiceManager::GetInstance().Exec(args) ? 0 : -1;
+}
+
+static int do_exec_start(const std::vector<std::string>& args) {
+    return ServiceManager::GetInstance().ExecStart(args[1]) ? 0 : -1;
 }
 
 static int do_export(const std::vector<std::string>& args) {
@@ -709,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,16 +922,21 @@
 }
 
 static bool is_file_crypto() {
-    std::string value = property_get("ro.crypto.type");
-    return value == "file";
+    return android::base::GetProperty("ro.crypto.type", "") == "file";
 }
 
 static int do_installkey(const std::vector<std::string>& args) {
     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) {
@@ -897,6 +945,7 @@
 
 BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
+    // clang-format off
     static const Map builtin_functions = {
         {"bootchart",               {1,     1,    do_bootchart}},
         {"chmod",                   {2,     2,    do_chmod}},
@@ -909,6 +958,7 @@
         {"domainname",              {1,     1,    do_domainname}},
         {"enable",                  {1,     1,    do_enable}},
         {"exec",                    {1,     kMax, do_exec}},
+        {"exec_start",              {1,     1,    do_exec_start}},
         {"export",                  {2,     2,    do_export}},
         {"hostname",                {1,     1,    do_hostname}},
         {"ifup",                    {1,     1,    do_ifup}},
@@ -942,5 +992,6 @@
         {"wait_for_prop",           {2,     2,    do_wait_for_prop}},
         {"write",                   {2,     2,    do_write}},
     };
+    // clang-format on
     return builtin_functions;
 }
diff --git a/init/init.cpp b/init/init.cpp
index b337c64..e14034f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -40,7 +40,9 @@
 #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>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
@@ -68,6 +70,8 @@
 #include "util.h"
 #include "watchdogd.h"
 
+using android::base::boot_clock;
+using android::base::GetProperty;
 using android::base::StringPrintf;
 
 struct selabel_handle *sehandle;
@@ -82,8 +86,6 @@
 
 const char *ENV[32];
 
-static std::unique_ptr<Timer> waiting_for_exec(nullptr);
-
 static int epoll_fd = -1;
 
 static std::unique_ptr<Timer> waiting_for_prop(nullptr);
@@ -131,29 +133,12 @@
     return -1;
 }
 
-bool start_waiting_for_exec()
-{
-    if (waiting_for_exec) {
-        return false;
-    }
-    waiting_for_exec.reset(new Timer());
-    return true;
-}
-
-void stop_waiting_for_exec()
-{
-    if (waiting_for_exec) {
-        LOG(INFO) << "Wait for exec took " << *waiting_for_exec;
-        waiting_for_exec.reset();
-    }
-}
-
 bool start_waiting_for_property(const char *name, const char *value)
 {
     if (waiting_for_prop) {
         return false;
     }
-    if (property_get(name) != value) {
+    if (GetProperty(name, "") != value) {
         // Current property value is not equal to expected value
         wait_prop_name = name;
         wait_prop_value = value;
@@ -441,7 +426,7 @@
 
 static int console_init_action(const std::vector<std::string>& args)
 {
-    std::string console = property_get("ro.boot.console");
+    std::string console = GetProperty("ro.boot.console", "");
     if (!console.empty()) {
         default_console = "/dev/" + console;
     }
@@ -465,11 +450,11 @@
 }
 
 static void export_oem_lock_status() {
-    if (property_get("ro.oem_unlock_supported") != "1") {
+    if (!android::base::GetBoolProperty("ro.oem_unlock_supported", false)) {
         return;
     }
 
-    std::string value = property_get("ro.boot.verifiedbootstate");
+    std::string value = GetProperty("ro.boot.verifiedbootstate", "");
 
     if (!value.empty()) {
         property_set("ro.boot.flash.locked", value == "orange" ? "0" : "1");
@@ -490,7 +475,7 @@
         { "ro.boot.revision",   "ro.revision",   "0", },
     };
     for (size_t i = 0; i < arraysize(prop_map); i++) {
-        std::string value = property_get(prop_map[i].src_prop);
+        std::string value = GetProperty(prop_map[i].src_prop, "");
         property_set(prop_map[i].dst_prop, (!value.empty()) ? value.c_str() : prop_map[i].default_value);
     }
 }
@@ -892,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.
@@ -1230,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) {
@@ -1267,7 +1255,7 @@
     parser.AddSectionParser("service",std::make_unique<ServiceParser>());
     parser.AddSectionParser("on", std::make_unique<ActionParser>());
     parser.AddSectionParser("import", std::make_unique<ImportParser>());
-    std::string bootscript = property_get("ro.boot.init_rc");
+    std::string bootscript = GetProperty("ro.boot.init_rc", "");
     if (bootscript.empty()) {
         parser.ParseConfig("/init.rc");
         parser.set_is_system_etc_init_loaded(
@@ -1307,7 +1295,7 @@
     am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
 
     // Don't mount filesystems or start core system services in charger mode.
-    std::string bootmode = property_get("ro.bootmode");
+    std::string bootmode = GetProperty("ro.bootmode", "");
     if (bootmode == "charger") {
         am.QueueEventTrigger("charger");
     } else {
@@ -1321,10 +1309,10 @@
         // By default, sleep until something happens.
         int epoll_timeout_ms = -1;
 
-        if (!(waiting_for_exec || waiting_for_prop)) {
+        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
             am.ExecuteOneCommand();
         }
-        if (!(waiting_for_exec || waiting_for_prop)) {
+        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
             restart_processes();
 
             // If there's a process that needs restarting, wake up in time for that.
diff --git a/init/init.h b/init/init.h
index b4d25fb..fe850ef 100644
--- a/init/init.h
+++ b/init/init.h
@@ -32,10 +32,6 @@
 
 int add_environment(const char* key, const char* val);
 
-bool start_waiting_for_exec();
-
-void stop_waiting_for_exec();
-
 bool start_waiting_for_property(const char *name, const char *value);
 
 #endif  /* _INIT_INIT_H */
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 3dbb2f0..5801ea8 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -23,9 +23,10 @@
 #include <linux/keychord.h>
 #include <unistd.h>
 
+#include <android-base/properties.h>
+
 #include "init.h"
 #include "log.h"
-#include "property_service.h"
 #include "service.h"
 
 static struct input_keychord *keychords = 0;
@@ -74,7 +75,7 @@
     }
 
     // Only handle keychords if adb is enabled.
-    std::string adb_enabled = property_get("init.svc.adbd");
+    std::string adb_enabled = android::base::GetProperty("init.svc.adbd", "");
     if (adb_enabled == "running") {
         Service* svc = ServiceManager::GetInstance().FindServiceByKeychord(id);
         if (svc) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 6960279..a4d8b5f 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -114,12 +114,6 @@
     return check_mac_perms(ctl_name, sctx, cr);
 }
 
-std::string property_get(const char* name) {
-    char value[PROP_VALUE_MAX] = {0};
-    __system_property_get(name, value);
-    return value;
-}
-
 static void write_persistent_property(const char *name, const char *value)
 {
     char tempPath[PATH_MAX];
@@ -588,10 +582,7 @@
 
 static void load_override_properties() {
     if (ALLOW_LOCAL_PROP_OVERRIDE) {
-        std::string debuggable = property_get("ro.debuggable");
-        if (debuggable == "1") {
-            load_properties_from_file("/data/local.prop", NULL);
-        }
+        load_properties_from_file("/data/local.prop", NULL);
     }
 }
 
diff --git a/init/property_service.h b/init/property_service.h
index 5d59473..994da63 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -32,7 +32,6 @@
 void load_persist_props(void);
 void load_system_props(void);
 void start_property_service(void);
-std::string property_get(const char* name);
 uint32_t property_set(const std::string& name, const std::string& value);
 bool is_legal_property_name(const std::string& name);
 
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 0b49ba1..e34abdb 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -32,7 +32,7 @@
 
 #include <android-base/file.h>
 #include <android-base/macros.h>
-#include <android-base/parseint.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <bootloader_message/bootloader_message.h>
@@ -41,7 +41,6 @@
 #include <logwrap/logwrap.h>
 
 #include "log.h"
-#include "property_service.h"
 #include "reboot.h"
 #include "service.h"
 #include "util.h"
@@ -341,12 +340,16 @@
         abort();
     }
 
-    std::string timeout = property_get("ro.build.shutdown_timeout");
     /* TODO update default waiting time based on usage data */
-    unsigned int shutdownTimeout = 10;  // default value
-    if (android::base::ParseUint(timeout, &shutdownTimeout)) {
-        LOG(INFO) << "ro.build.shutdown_timeout set:" << shutdownTimeout;
+    constexpr unsigned int shutdownTimeoutDefault = 10;
+    unsigned int shutdownTimeout = shutdownTimeoutDefault;
+    if (SHUTDOWN_ZERO_TIMEOUT) {  // eng build
+        shutdownTimeout = 0;
+    } else {
+        shutdownTimeout =
+            android::base::GetUintProperty("ro.build.shutdown_timeout", shutdownTimeoutDefault);
     }
+    LOG(INFO) << "Shutdown timeout: " << shutdownTimeout;
 
     static const constexpr char* shutdown_critical_services[] = {"vold", "watchdogd"};
     for (const char* name : shutdown_critical_services) {
diff --git a/init/service.cpp b/init/service.cpp
index c6ef838..e89de9a 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -32,8 +32,10 @@
 
 #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>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <system/thread_defs.h>
@@ -47,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;
@@ -191,8 +194,8 @@
 }
 
 void Service::NotifyStateChange(const std::string& new_state) const {
-    if ((flags_ & SVC_EXEC) != 0) {
-        // 'exec' commands don't have properties tracking their state.
+    if ((flags_ & SVC_TEMPORARY) != 0) {
+        // Services created by 'exec' are temporary and don't have properties tracking their state.
         return;
     }
 
@@ -210,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) {
@@ -259,7 +268,7 @@
     }
 }
 
-bool Service::Reap() {
+void Service::Reap() {
     if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) {
         KillProcessGroup(SIGKILL);
     }
@@ -270,7 +279,10 @@
 
     if (flags_ & SVC_EXEC) {
         LOG(INFO) << "SVC_EXEC pid " << pid_ << " finished...";
-        return true;
+    }
+
+    if (flags_ & SVC_TEMPORARY) {
+        return;
     }
 
     pid_ = 0;
@@ -285,7 +297,7 @@
     // Disabled and reset processes do not get restarted automatically.
     if (flags_ & (SVC_DISABLED | SVC_RESET))  {
         NotifyStateChange("stopped");
-        return false;
+        return;
     }
 
     // If we crash > 4 times in 4 minutes, reboot into recovery.
@@ -309,7 +321,7 @@
     onrestart_.ExecuteAllCommands();
 
     NotifyStateChange("restarting");
-    return false;
+    return;
 }
 
 void Service::DumpState() const {
@@ -577,6 +589,18 @@
     return (this->*parser)(args, err);
 }
 
+bool Service::ExecStart(std::unique_ptr<Timer>* exec_waiter) {
+    flags_ |= SVC_EXEC | SVC_ONESHOT;
+
+    exec_waiter->reset(new Timer);
+
+    if (!Start()) {
+        exec_waiter->reset();
+        return false;
+    }
+    return true;
+}
+
 bool Service::Start() {
     // Starting a service removes it from the disabled or reset state and
     // immediately takes it out of the restarting state if it was in there.
@@ -657,7 +681,7 @@
         if (iter == writepid_files_.end()) {
             // There were no "writepid" instructions for cpusets, check if the system default
             // cpuset is specified to be used for the process.
-            std::string default_cpuset = property_get("ro.cpuset.default");
+            std::string default_cpuset = android::base::GetProperty("ro.cpuset.default", "");
             if (!default_cpuset.empty()) {
                 // Make sure the cpuset name starts and ends with '/'.
                 // A single '/' means the 'root' cpuset.
@@ -863,6 +887,35 @@
     services_.emplace_back(std::move(service));
 }
 
+bool ServiceManager::Exec(const std::vector<std::string>& args) {
+    Service* svc = MakeExecOneshotService(args);
+    if (!svc) {
+        LOG(ERROR) << "Could not create exec service";
+        return false;
+    }
+    if (!svc->ExecStart(&exec_waiter_)) {
+        LOG(ERROR) << "Could not start exec service";
+        ServiceManager::GetInstance().RemoveService(*svc);
+        return false;
+    }
+    return true;
+}
+
+bool ServiceManager::ExecStart(const std::string& name) {
+    Service* svc = FindServiceByName(name);
+    if (!svc) {
+        LOG(ERROR) << "ExecStart(" << name << "): Service not found";
+        return false;
+    }
+    if (!svc->ExecStart(&exec_waiter_)) {
+        LOG(ERROR) << "ExecStart(" << name << "): Could not start Service";
+        return false;
+    }
+    return true;
+}
+
+bool ServiceManager::IsWaitingForExec() const { return exec_waiter_ != nullptr; }
+
 Service* ServiceManager::MakeExecOneshotService(const std::vector<std::string>& args) {
     // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
     // SECLABEL can be a - to denote default
@@ -886,7 +939,7 @@
 
     exec_count_++;
     std::string name = StringPrintf("exec %d (%s)", exec_count_, str_args[0].c_str());
-    unsigned flags = SVC_EXEC | SVC_ONESHOT;
+    unsigned flags = SVC_EXEC | SVC_ONESHOT | SVC_TEMPORARY;
     CapSet no_capabilities;
     unsigned namespace_flags = 0;
 
@@ -1026,8 +1079,13 @@
         return true;
     }
 
-    if (svc->Reap()) {
-        stop_waiting_for_exec();
+    svc->Reap();
+
+    if (svc->flags() & SVC_EXEC) {
+        LOG(INFO) << "Wait for exec took " << *exec_waiter_;
+        exec_waiter_.reset();
+    }
+    if (svc->flags() & SVC_TEMPORARY) {
         RemoveService(*svc);
     }
 
diff --git a/init/service.h b/init/service.h
index 9a9046b..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"
@@ -44,10 +46,13 @@
 #define SVC_RC_DISABLED 0x080     // Remember if the disabled flag was set in the rc script.
 #define SVC_RESTART 0x100         // Use to safely restart (stop, wait, start) a service.
 #define SVC_DISABLED_START 0x200  // A start was requested but it was disabled at the time.
-#define SVC_EXEC 0x400            // This synthetic service corresponds to an 'exec'.
+#define SVC_EXEC 0x400  // This service was started by either 'exec' or 'exec_start' and stops
+                        // init from processing more commands until it completes
 
 #define SVC_SHUTDOWN_CRITICAL 0x800  // This service is critical for shutdown and
                                      // should not be killed during shutdown
+#define SVC_TEMPORARY 0x1000  // This service was started by 'exec' and should be removed from the
+                              // service list once it is reaped.
 
 #define NR_SVC_SUPP_GIDS 12    // twelve supplementary groups
 
@@ -72,6 +77,7 @@
 
     bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
     bool ParseLine(const std::vector<std::string>& args, std::string* err);
+    bool ExecStart(std::unique_ptr<Timer>* exec_waiter);
     bool Start();
     bool StartIfNotDisabled();
     bool Enable();
@@ -80,7 +86,7 @@
     void Terminate();
     void Restart();
     void RestartIfNeeded(time_t* process_needs_restart_at);
-    bool Reap();
+    void Reap();
     void DumpState() const;
     void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
     bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
@@ -140,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_;
@@ -178,6 +184,9 @@
 
     void AddService(std::unique_ptr<Service> service);
     Service* MakeExecOneshotService(const std::vector<std::string>& args);
+    bool Exec(const std::vector<std::string>& args);
+    bool ExecStart(const std::string& name);
+    bool IsWaitingForExec() const;
     Service* FindServiceByName(const std::string& name) const;
     Service* FindServiceByPid(pid_t pid) const;
     Service* FindServiceByKeychord(int keychord_id) const;
@@ -198,6 +207,8 @@
     bool ReapOneProcess();
 
     static int exec_count_; // Every service needs a unique name.
+    std::unique_ptr<Timer> exec_waiter_;
+
     std::vector<std::unique_ptr<Service>> services_;
 };
 
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 915afbd..f27be64 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -26,6 +26,7 @@
 
 #include <sys/types.h>
 
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <selinux/selinux.h>
 
@@ -34,7 +35,6 @@
 #include "util.h"
 #include "devices.h"
 #include "ueventd_parser.h"
-#include "property_service.h"
 
 int ueventd_main(int argc, char **argv)
 {
@@ -71,7 +71,7 @@
      * TODO: cleanup platform ueventd.rc to remove vendor specific
      * device node entries (b/34968103)
      */
-    std::string hardware = property_get("ro.hardware");
+    std::string hardware = android::base::GetProperty("ro.hardware", "");
     ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware.c_str()).c_str());
 
     device_init();
diff --git a/init/util.cpp b/init/util.cpp
index 0ba9800..3f8f244 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -38,6 +38,7 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
@@ -48,10 +49,11 @@
 
 #include "init.h"
 #include "log.h"
-#include "property_service.h"
 #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];
@@ -395,7 +390,7 @@
             return false;
         }
 
-        std::string prop_val = property_get(prop_name.c_str());
+        std::string prop_val = android::base::GetProperty(prop_name, "");
         if (prop_val.empty()) {
             if (def_val.empty()) {
                 LOG(ERROR) << "property '" << prop_name << "' doesn't exist while expanding '" << src << "'";
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/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 0037f15..3eeb9dc 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -130,6 +130,7 @@
 #define AID_MEDIA_OBB 1059       /* GID for OBB files on internal media storage */
 #define AID_ESE 1060             /* embedded secure element (eSE) subsystem */
 #define AID_OTA_UPDATE 1061      /* resource tracking UID for OTA updates */
+#define AID_DISK_RESERVED 1062   /* GID that has access to reserved disk space */
 /* Changes to this file must be made in AOSP, *not* in internal branches. */
 
 #define AID_SHELL 2000 /* adb and debug shell user */
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/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/rootdir/init.rc b/rootdir/init.rc
index 7091ab9..d48b892 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -598,7 +598,7 @@
 
 on nonencrypted
     # A/B update verifier that marks a successful boot.
-    exec - root cache -- /system/bin/update_verifier nonencrypted
+    exec_start update_verifier_nonencrypted
     class_start main
     class_start late_start
 
@@ -621,12 +621,12 @@
 
 on property:vold.decrypt=trigger_restart_min_framework
     # A/B update verifier that marks a successful boot.
-    exec - root cache -- /system/bin/update_verifier trigger_restart_min_framework
+    exec_start update_verifier
     class_start main
 
 on property:vold.decrypt=trigger_restart_framework
     # A/B update verifier that marks a successful boot.
-    exec - root cache -- /system/bin/update_verifier trigger_restart_framework
+    exec_start update_verifier
     class_start main
     class_start late_start
 
diff --git a/tzdatacheck/tzdatacheck.cpp b/tzdatacheck/tzdatacheck.cpp
index 381df5a..8fcd17f 100644
--- a/tzdatacheck/tzdatacheck.cpp
+++ b/tzdatacheck/tzdatacheck.cpp
@@ -30,6 +30,19 @@
 
 #include "android-base/logging.h"
 
+// The name of the directory that holds a staged time zone update distro. If this exists it should
+// replace the one in CURRENT_DIR_NAME.
+// See also libcore.tzdata.update2.TimeZoneDistroInstaller.
+static const char* STAGED_DIR_NAME = "/staged";
+
+// The name of the directory that holds the (optional) installed time zone update distro.
+// See also libcore.tzdata.update2.TimeZoneDistroInstaller.
+static const char* CURRENT_DIR_NAME = "/current";
+
+// The name of a file in the staged dir that indicates the staged operation is an "uninstall".
+// See also libcore.tzdata.update2.TimeZoneDistroInstaller.
+static const char* UNINSTALL_TOMBSTONE_FILE_NAME = "/STAGED_UNINSTALL_TOMBSTONE";
+
 // The name of the file containing the distro version information.
 // See also libcore.tzdata.shared2.TimeZoneDistro / libcore.tzdata.shared2.DistroVersion.
 static const char* DISTRO_VERSION_FILENAME = "/distro_version";
@@ -75,7 +88,6 @@
 static const char TZ_DATA_HEADER_PREFIX[] = "tzdata";
 static const size_t TZ_DATA_HEADER_PREFIX_LEN = sizeof(TZ_DATA_HEADER_PREFIX) - 1; // exclude \0
 
-
 static void usage() {
     std::cerr << "Usage: tzdatacheck SYSTEM_TZ_DIR DATA_TZ_DIR\n"
             "\n"
@@ -184,7 +196,7 @@
     return 0;
 }
 
-enum PathStatus { ERR, NONE, IS_DIR, NOT_DIR };
+enum PathStatus { ERR, NONE, IS_DIR, IS_REG, UNKNOWN };
 
 static PathStatus checkPath(const std::string& path) {
     struct stat buf;
@@ -195,7 +207,31 @@
         }
         return NONE;
     }
-    return S_ISDIR(buf.st_mode) ? IS_DIR : NOT_DIR;
+    return S_ISDIR(buf.st_mode) ? IS_DIR : S_ISREG(buf.st_mode) ? IS_REG : UNKNOWN;
+}
+
+/*
+ * Deletes fileToDelete and returns true if it is successful. If fileToDelete is not a file or
+ * cannot be accessed this method returns false.
+ */
+static bool deleteFile(const std::string& fileToDelete) {
+    // Check whether the file exists.
+    PathStatus pathStatus = checkPath(fileToDelete);
+    if (pathStatus == NONE) {
+        LOG(INFO) << "Path " << fileToDelete << " does not exist";
+        return true;
+    }
+    if (pathStatus != IS_REG) {
+        LOG(WARNING) << "Path " << fileToDelete << " failed to stat() or is not a file.";
+        return false;
+    }
+
+    // Attempt the deletion.
+    int rc = unlink(fileToDelete.c_str());
+    if (rc != 0) {
+        PLOG(WARNING) << "unlink() failed for " << fileToDelete;
+    }
+    return rc == 0;
 }
 
 /*
@@ -260,8 +296,7 @@
     std::string dataUpdatesDirName(dataZoneInfoDir);
     dataUpdatesDirName += "/updates";
     LOG(INFO) << "Removing: " << dataUpdatesDirName;
-    bool deleted = deleteDir(dataUpdatesDirName);
-    if (!deleted) {
+    if (!deleteDir(dataUpdatesDirName)) {
         LOG(WARNING) << "Deletion of install metadata " << dataUpdatesDirName
                 << " was not successful";
     }
@@ -270,14 +305,151 @@
 /*
  * Deletes the timezone update distro directory.
  */
-static void deleteUpdateDistroDir(std::string& distroDirName) {
+static void deleteUpdateDistroDir(const std::string& distroDirName) {
     LOG(INFO) << "Removing: " << distroDirName;
-    bool deleted = deleteDir(distroDirName);
-    if (!deleted) {
+    if (!deleteDir(distroDirName)) {
         LOG(WARNING) << "Deletion of distro dir " << distroDirName << " was not successful";
     }
 }
 
+static void handleStagedUninstall(const std::string& dataStagedDirName,
+                                  const std::string& dataCurrentDirName,
+                                  const PathStatus dataCurrentDirStatus) {
+    LOG(INFO) << "Staged operation is an uninstall.";
+
+    // Delete the current install directory.
+    switch (dataCurrentDirStatus) {
+        case NONE:
+            // This is unexpected: No uninstall should be staged if there is nothing to
+            // uninstall. Carry on anyway.
+            LOG(WARNING) << "No current install to delete.";
+            break;
+        case IS_DIR:
+            // This is normal. Delete the current install dir.
+            if (!deleteDir(dataCurrentDirName)) {
+                LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
+                             << " was not successful";
+                // If this happens we don't know whether we were able to delete or not. We don't
+                // delete the staged operation so it will be retried next boot unless overridden.
+                return;
+            }
+            break;
+        case IS_REG:
+        default:
+            // This is unexpected: We can try to delete the unexpected file and carry on.
+            LOG(WARNING) << "Current distro dir " << dataCurrentDirName
+                         << " is not actually a directory. Attempting deletion.";
+            if (!deleteFile(dataCurrentDirName)) {
+                LOG(WARNING) << "Could not delete " << dataCurrentDirName;
+                return;
+            }
+            break;
+    }
+
+    // Delete the staged uninstall dir.
+    if (!deleteDir(dataStagedDirName)) {
+        LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
+                     << " was not successful";
+        // If this happens we don't know whether we were able to delete the staged operation
+        // or not.
+        return;
+    }
+    LOG(INFO) << "Staged uninstall complete.";
+}
+
+static void handleStagedInstall(const std::string& dataStagedDirName,
+                                const std::string& dataCurrentDirName,
+                                const PathStatus dataCurrentDirStatus) {
+    LOG(INFO) << "Staged operation is an install.";
+
+    switch (dataCurrentDirStatus) {
+        case NONE:
+            // This is expected: This is the first install.
+            LOG(INFO) << "No current install to replace.";
+            break;
+        case IS_DIR:
+            // This is expected: We are replacing an existing install.
+            // Delete the current dir so we can replace it.
+            if (!deleteDir(dataCurrentDirName)) {
+                LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
+                             << " was not successful";
+                // If this happens, we cannot proceed.
+                return;
+            }
+            break;
+        case IS_REG:
+        default:
+            // This is unexpected: We can try to delete the unexpected file and carry on.
+            LOG(WARNING) << "Current distro dir " << dataCurrentDirName
+                         << " is not actually a directory. Attempting deletion.";
+            if (!deleteFile(dataCurrentDirName)) {
+                LOG(WARNING) << "Could not delete " << dataCurrentDirName;
+                return;
+            }
+            break;
+    }
+
+    // Move the staged dir so it is the new current dir, completing the install.
+    LOG(INFO) << "Moving " << dataStagedDirName << " to " << dataCurrentDirName;
+    int rc = rename(dataStagedDirName.c_str(), dataCurrentDirName.c_str());
+    if (rc == -1) {
+        PLOG(WARNING) << "Unable to rename directory from " << dataStagedDirName << " to "
+                      << &dataCurrentDirName[0];
+        return;
+    }
+
+    LOG(INFO) << "Staged install complete.";
+}
+/*
+ * Process a staged operation if there is one.
+ */
+static void processStagedOperation(const std::string& dataStagedDirName,
+                                   const std::string& dataCurrentDirName) {
+    PathStatus dataStagedDirStatus = checkPath(dataStagedDirName);
+
+    // Exit early for the common case.
+    if (dataStagedDirStatus == NONE) {
+        LOG(DEBUG) << "No staged time zone operation.";
+        return;
+    }
+
+    // Check known directory names are in a good starting state.
+    if (dataStagedDirStatus != IS_DIR) {
+        LOG(WARNING) << "Staged distro dir " << dataStagedDirName
+                     << " could not be accessed or is not a directory."
+                     << " stagedDirStatus=" << dataStagedDirStatus;
+        return;
+    }
+
+    // dataStagedDirStatus == IS_DIR.
+
+    // Work out whether there is anything currently installed.
+    PathStatus dataCurrentDirStatus = checkPath(dataCurrentDirName);
+    if (dataCurrentDirStatus == ERR) {
+        LOG(WARNING) << "Current install dir " << dataCurrentDirName << " could not be accessed"
+                     << " dataCurrentDirStatus=" << dataCurrentDirStatus;
+        return;
+    }
+
+    // We must perform the staged operation.
+
+    // Check to see if the staged directory contains an uninstall or an install operation.
+    std::string uninstallTombStoneFile(dataStagedDirName);
+    uninstallTombStoneFile += UNINSTALL_TOMBSTONE_FILE_NAME;
+    int uninstallTombStoneFileStatus = checkPath(uninstallTombStoneFile);
+    if (uninstallTombStoneFileStatus != IS_REG && uninstallTombStoneFileStatus != NONE) {
+        // Error case.
+        LOG(WARNING) << "Unable to determine if the staged operation is an uninstall.";
+        return;
+    }
+    if (uninstallTombStoneFileStatus == IS_REG) {
+        handleStagedUninstall(dataStagedDirName, dataCurrentDirName, dataCurrentDirStatus);
+    } else {
+        // uninstallTombStoneFileStatus == NONE meaning this is a staged install.
+        handleStagedInstall(dataStagedDirName, dataCurrentDirName, dataCurrentDirStatus);
+    }
+}
+
 /*
  * After a platform update it is likely that timezone data found on the system partition will be
  * newer than the version found in the data partition. This tool detects this case and removes the
@@ -300,15 +472,25 @@
     const char* systemZoneInfoDir = argv[1];
     const char* dataZoneInfoDir = argv[2];
 
-    // Check the distro directory exists. If it does not, exit quickly: nothing to do.
+    std::string dataStagedDirName(dataZoneInfoDir);
+    dataStagedDirName += STAGED_DIR_NAME;
+
     std::string dataCurrentDirName(dataZoneInfoDir);
-    dataCurrentDirName += "/current";
-    int dataCurrentDirStatus = checkPath(dataCurrentDirName);
+    dataCurrentDirName += CURRENT_DIR_NAME;
+
+    // Check for an process any staged operation.
+    // If the staged operation could not be handled we still have to validate the current installed
+    // directory so we do not check for errors and do not quit early.
+    processStagedOperation(dataStagedDirName, dataCurrentDirName);
+
+    // Check the distro directory exists. If it does not, exit quickly: nothing to do.
+    PathStatus dataCurrentDirStatus = checkPath(dataCurrentDirName);
     if (dataCurrentDirStatus == NONE) {
         LOG(INFO) << "timezone distro dir " << dataCurrentDirName
                 << " does not exist. No action required.";
         return 0;
     }
+
     // If the distro directory path is not a directory or we can't stat() the path, exit with a
     // warning: either there's a problem accessing storage or the world is not as it should be;
     // nothing to do.