Merge "storaged: add task io to dump service"
diff --git a/adb/Android.mk b/adb/Android.mk
index 6ed01fa..5d6c418 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -108,7 +108,6 @@
     sysdeps_win32_test.cpp \
 
 include $(CLEAR_VARS)
-LOCAL_CLANG := true
 LOCAL_MODULE := libadbd_usb
 LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
 LOCAL_SRC_FILES := daemon/usb.cpp
@@ -122,7 +121,6 @@
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
-LOCAL_CLANG := true
 LOCAL_MODULE := libadbd
 LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
 LOCAL_SRC_FILES := \
@@ -171,7 +169,6 @@
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
-LOCAL_CLANG := true
 LOCAL_MODULE := adbd_test
 LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS)
 LOCAL_SRC_FILES := \
@@ -330,8 +327,6 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_CLANG := true
-
 LOCAL_SRC_FILES := \
     daemon/main.cpp \
     daemon/mdns.cpp \
@@ -350,11 +345,11 @@
     -D_GNU_SOURCE \
     -Wno-deprecated-declarations \
 
+LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)
 LOCAL_CFLAGS += -DALLOW_ADBD_NO_AUTH=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
 LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
-LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1
 endif
 
 LOCAL_MODULE := adbd
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 1c94298..e0629ab 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -49,17 +49,23 @@
 
 static const char* root_seclabel = nullptr;
 
+static inline bool is_device_unlocked() {
+    return "orange" == android::base::GetProperty("ro.boot.verifiedbootstate", "");
+}
+
 static void drop_capabilities_bounding_set_if_needed(struct minijail *j) {
-#if defined(ALLOW_ADBD_ROOT)
-    if (__android_log_is_debuggable()) {
-        return;
+    if (ALLOW_ADBD_ROOT || is_device_unlocked()) {
+        if (__android_log_is_debuggable()) {
+            return;
+        }
     }
-#endif
     minijail_capbset_drop(j, CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SETGID));
 }
 
 static bool should_drop_privileges() {
-#if defined(ALLOW_ADBD_ROOT)
+    // "adb root" not allowed, always drop privileges.
+    if (!ALLOW_ADBD_ROOT && !is_device_unlocked()) return true;
+
     // The properties that affect `adb root` and `adb unroot` are ro.secure and
     // ro.debuggable. In this context the names don't make the expected behavior
     // particularly obvious.
@@ -89,9 +95,6 @@
     }
 
     return drop;
-#else
-    return true; // "adb root" not allowed, always drop privileges.
-#endif // ALLOW_ADBD_ROOT
 }
 
 static void drop_privileges(int server_port) {
@@ -158,7 +161,10 @@
     // descriptor will always be open.
     adbd_cloexec_auth_socket();
 
-    if (ALLOW_ADBD_NO_AUTH && !android::base::GetBoolProperty("ro.adb.secure", false)) {
+    // Respect ro.adb.secure in userdebug/eng builds (ALLOW_ADBD_NO_AUTH), or when the
+    // device is unlocked.
+    if ((ALLOW_ADBD_NO_AUTH || is_device_unlocked()) &&
+        !android::base::GetBoolProperty("ro.adb.secure", false)) {
         auth_required = false;
     }
 
diff --git a/base/Android.bp b/base/Android.bp
index b636dc3..1395756 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -39,7 +39,6 @@
 cc_library {
     name: "libbase",
     vendor_available: true,
-    clang: true,
     host_supported: true,
     srcs: [
         "file.cpp",
@@ -109,7 +108,6 @@
 cc_test {
     name: "libbase_test",
     host_supported: true,
-    clang: true,
     srcs: [
         "endian_test.cpp",
         "errors_test.cpp",
diff --git a/base/chrono_utils.cpp b/base/chrono_utils.cpp
index 5eedf3b..b6bf701 100644
--- a/base/chrono_utils.cpp
+++ b/base/chrono_utils.cpp
@@ -33,5 +33,10 @@
 #endif  // __ANDROID__
 }
 
+std::ostream& operator<<(std::ostream& os, const Timer& t) {
+  os << t.duration().count() << "ms";
+  return os;
+}
+
 }  // namespace base
 }  // namespace android
diff --git a/base/chrono_utils_test.cpp b/base/chrono_utils_test.cpp
index 057132d..da442f4 100644
--- a/base/chrono_utils_test.cpp
+++ b/base/chrono_utils_test.cpp
@@ -19,6 +19,9 @@
 #include <time.h>
 
 #include <chrono>
+#include <sstream>
+#include <string>
+#include <thread>
 
 #include <gtest/gtest.h>
 
@@ -42,5 +45,36 @@
   EXPECT_EQ(now, boot_seconds);
 }
 
+template <typename T>
+void ExpectAboutEqual(T expected, T actual) {
+  auto expected_upper_bound = expected * 1.05f;
+  auto expected_lower_bound = expected * .95;
+  EXPECT_GT(expected_upper_bound, actual);
+  EXPECT_LT(expected_lower_bound, actual);
+}
+
+TEST(ChronoUtilsTest, TimerDurationIsSane) {
+  auto start = boot_clock::now();
+  Timer t;
+  std::this_thread::sleep_for(50ms);
+  auto stop = boot_clock::now();
+  auto stop_timer = t.duration();
+
+  auto expected = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
+  ExpectAboutEqual(expected, stop_timer);
+}
+
+TEST(ChronoUtilsTest, TimerOstream) {
+  Timer t;
+  std::this_thread::sleep_for(50ms);
+  auto stop_timer = t.duration().count();
+  std::stringstream os;
+  os << t;
+  decltype(stop_timer) stop_timer_from_stream;
+  os >> stop_timer_from_stream;
+  EXPECT_NE(0, stop_timer);
+  ExpectAboutEqual(stop_timer, stop_timer_from_stream);
+}
+
 }  // namespace base
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/base/file.cpp b/base/file.cpp
index a2f2887..2f697a1 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -153,6 +153,37 @@
   return true;
 }
 
+#if defined(_WIN32)
+// Windows implementation of pread. Note that this DOES move the file descriptors read position,
+// but it does so atomically.
+static ssize_t pread(int fd, void* data, size_t byte_count, off64_t offset) {
+  DWORD bytes_read;
+  OVERLAPPED overlapped;
+  memset(&overlapped, 0, sizeof(OVERLAPPED));
+  overlapped.Offset = static_cast<DWORD>(offset);
+  overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
+  if (!ReadFile(reinterpret_cast<HANDLE>(_get_osfhandle(fd)), data, static_cast<DWORD>(byte_count),
+                &bytes_read, &overlapped)) {
+    // In case someone tries to read errno (since this is masquerading as a POSIX call)
+    errno = EIO;
+    return -1;
+  }
+  return static_cast<ssize_t>(bytes_read);
+}
+#endif
+
+bool ReadFullyAtOffset(int fd, void* data, size_t byte_count, off64_t offset) {
+  uint8_t* p = reinterpret_cast<uint8_t*>(data);
+  while (byte_count > 0) {
+    ssize_t n = TEMP_FAILURE_RETRY(pread(fd, p, byte_count, offset));
+    if (n <= 0) return false;
+    p += n;
+    byte_count -= n;
+    offset += n;
+  }
+  return true;
+}
+
 bool WriteFully(int fd, const void* data, size_t byte_count) {
   const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
   size_t remaining = byte_count;
diff --git a/base/include/android-base/chrono_utils.h b/base/include/android-base/chrono_utils.h
index 0086425..7679d4c 100644
--- a/base/include/android-base/chrono_utils.h
+++ b/base/include/android-base/chrono_utils.h
@@ -18,6 +18,9 @@
 #define ANDROID_BASE_CHRONO_UTILS_H
 
 #include <chrono>
+#include <sstream>
+
+using namespace std::chrono_literals;
 
 namespace android {
 namespace base {
@@ -31,6 +34,20 @@
   static time_point now();
 };
 
+class Timer {
+ public:
+  Timer() : start_(boot_clock::now()) {}
+
+  std::chrono::milliseconds duration() const {
+    return std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() - start_);
+  }
+
+ private:
+  boot_clock::time_point start_;
+};
+
+std::ostream& operator<<(std::ostream& os, const Timer& t);
+
 }  // namespace base
 }  // namespace android
 
diff --git a/base/include/android-base/file.h b/base/include/android-base/file.h
index 651f529..667d6fb 100644
--- a/base/include/android-base/file.h
+++ b/base/include/android-base/file.h
@@ -18,12 +18,18 @@
 #define ANDROID_BASE_FILE_H
 
 #include <sys/stat.h>
+#include <sys/types.h>
 #include <string>
 
 #if !defined(_WIN32) && !defined(O_BINARY)
 #define O_BINARY 0
 #endif
 
+#if defined(__APPLE__)
+/* Mac OS has always had a 64-bit off_t, so it doesn't have off64_t. */
+typedef off_t off64_t;
+#endif
+
 namespace android {
 namespace base {
 
@@ -42,6 +48,17 @@
 #endif
 
 bool ReadFully(int fd, void* data, size_t byte_count);
+
+// Reads `byte_count` bytes from the file descriptor at the specified offset.
+// Returns false if there was an IO error or EOF was reached before reading `byte_count` bytes.
+//
+// NOTE: On Linux/Mac, this function wraps pread, which provides atomic read support without
+// modifying the read pointer of the file descriptor. On Windows, however, the read pointer does
+// get modified. This means that ReadFullyAtOffset can be used concurrently with other calls to the
+// same function, but concurrently seeking or reading incrementally can lead to unexpected
+// behavior.
+bool ReadFullyAtOffset(int fd, void* data, size_t byte_count, off64_t offset);
+
 bool WriteFully(int fd, const void* data, size_t byte_count);
 
 bool RemoveFileIfExists(const std::string& path, std::string* err = nullptr);
diff --git a/bootstat/Android.bp b/bootstat/Android.bp
index bc90a6e..dd357ed 100644
--- a/bootstat/Android.bp
+++ b/bootstat/Android.bp
@@ -32,9 +32,6 @@
         "liblog",
         "libmetricslogger",
     ],
-    whole_static_libs: ["libgtest_prod"],
-    // Clang is required because of C++14
-    clang: true,
 }
 
 // bootstat static library
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index a4c2160..344fa9a 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -85,12 +85,13 @@
   fprintf(stderr, "Usage: %s [options]\n", cmd);
   fprintf(stderr,
           "options include:\n"
-          "  -h, --help            Show this help\n"
-          "  -l, --log             Log all metrics to logstorage\n"
-          "  -p, --print           Dump the boot event records to the console\n"
-          "  -r, --record          Record the timestamp of a named boot event\n"
-          "  --value               Optional value to associate with the boot event\n"
-          "  --record_boot_reason  Record the reason why the device booted\n"
+          "  -h, --help              Show this help\n"
+          "  -l, --log               Log all metrics to logstorage\n"
+          "  -p, --print             Dump the boot event records to the console\n"
+          "  -r, --record            Record the timestamp of a named boot event\n"
+          "  --value                 Optional value to associate with the boot event\n"
+          "  --record_boot_complete  Record metrics related to the time for the device boot\n"
+          "  --record_boot_reason    Record the reason why the device booted\n"
           "  --record_time_since_factory_reset Record the time since the device was reset\n");
 }
 
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index 6970201..f57349b 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -134,6 +134,14 @@
     free(buf); // GCC is smart enough to warn about this, but we're doing it deliberately.
 }
 
+noinline void leak() {
+    while (true) {
+        void* mapping =
+            mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+        static_cast<volatile char*>(mapping)[0] = 'a';
+    }
+}
+
 noinline void sigsegv_non_null() {
     int* a = (int *)(&do_action);
     *a = 42;
@@ -160,8 +168,8 @@
     fprintf(stderr, "  stack-overflow        recurse until the stack overflows\n");
     fprintf(stderr, "  nostack               crash with a NULL stack pointer\n");
     fprintf(stderr, "\n");
-    fprintf(stderr, "  heap-corruption       cause a libc abort by corrupting the heap\n");
     fprintf(stderr, "  heap-usage            cause a libc abort by abusing a heap function\n");
+    fprintf(stderr, "  leak                  leak memory until we get OOM-killed\n");
     fprintf(stderr, "\n");
     fprintf(stderr, "  abort                 call abort()\n");
     fprintf(stderr, "  assert                call assert() without a function\n");
@@ -265,6 +273,8 @@
         return pthread_join(0, nullptr);
     } else if (!strcasecmp(arg, "heap-usage")) {
         abuse_heap();
+    } else if (!strcasecmp(arg, "leak")) {
+        leak();
     } else if (!strcasecmp(arg, "SIGSEGV-unmapped")) {
         char* map = reinterpret_cast<char*>(mmap(nullptr, sizeof(int), PROT_READ | PROT_WRITE,
                                                  MAP_SHARED | MAP_ANONYMOUS, -1, 0));
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index 325210d..6be59e7 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -220,21 +220,21 @@
   map.start = 0xa434000;
   map.end = 0xa435000;
   map.offset = 0x1000;
-  map.load_base = 0xd000;
+  map.load_bias = 0xd000;
   map.flags = PROT_WRITE;
   map_mock_->AddMap(map);
 
   map.start = 0xa534000;
   map.end = 0xa535000;
   map.offset = 0x3000;
-  map.load_base = 0x2000;
+  map.load_bias = 0x2000;
   map.flags = PROT_EXEC;
   map_mock_->AddMap(map);
 
   map.start = 0xa634000;
   map.end = 0xa635000;
   map.offset = 0;
-  map.load_base = 0;
+  map.load_bias = 0;
   map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
   map.name = "/system/lib/fake.so";
   map_mock_->AddMap(map);
@@ -244,20 +244,20 @@
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
-  const char* expected_dump = \
-"\nmemory map:\n"
+  const char* expected_dump =
+      "\nmemory map:\n"
 #if defined(__LP64__)
-"    00000000'0a234000-00000000'0a234fff ---         0      1000\n"
-"    00000000'0a334000-00000000'0a334fff r--      f000      1000\n"
-"    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load base 0xd000)\n"
-"    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load base 0x2000)\n"
-"    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
+      "    00000000'0a234000-00000000'0a234fff ---         0      1000\n"
+      "    00000000'0a334000-00000000'0a334fff r--      f000      1000\n"
+      "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
+      "    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 0x2000)\n"
+      "    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
 #else
-"    0a234000-0a234fff ---         0      1000\n"
-"    0a334000-0a334fff r--      f000      1000\n"
-"    0a434000-0a434fff -w-      1000      1000  (load base 0xd000)\n"
-"    0a534000-0a534fff --x      3000      1000  (load base 0x2000)\n"
-"    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
+      "    0a234000-0a234fff ---         0      1000\n"
+      "    0a334000-0a334fff r--      f000      1000\n"
+      "    0a434000-0a434fff -w-      1000      1000  (load bias 0xd000)\n"
+      "    0a534000-0a534fff --x      3000      1000  (load bias 0x2000)\n"
+      "    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
@@ -274,21 +274,21 @@
   map.start = 0xa434000;
   map.end = 0xa435000;
   map.offset = 0x1000;
-  map.load_base = 0xd000;
+  map.load_bias = 0xd000;
   map.flags = PROT_WRITE;
   map_mock_->AddMap(map);
 
   map.start = 0xa534000;
   map.end = 0xa535000;
   map.offset = 0x3000;
-  map.load_base = 0x2000;
+  map.load_bias = 0x2000;
   map.flags = PROT_EXEC;
   map_mock_->AddMap(map);
 
   map.start = 0xa634000;
   map.end = 0xa635000;
   map.offset = 0;
-  map.load_base = 0;
+  map.load_bias = 0;
   map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
   map.name = "/system/lib/fake.so";
   map_mock_->AddMap(map);
@@ -304,18 +304,18 @@
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
-  const char* expected_dump = \
-"\nmemory map: (fault address prefixed with --->)\n"
+  const char* expected_dump =
+      "\nmemory map: (fault address prefixed with --->)\n"
 #if defined(__LP64__)
-"--->Fault address falls at 00000000'00001000 before any mapped regions\n"
-"    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load base 0xd000)\n"
-"    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load base 0x2000)\n"
-"    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
+      "--->Fault address falls at 00000000'00001000 before any mapped regions\n"
+      "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
+      "    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 0x2000)\n"
+      "    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
 #else
-"--->Fault address falls at 00001000 before any mapped regions\n"
-"    0a434000-0a434fff -w-      1000      1000  (load base 0xd000)\n"
-"    0a534000-0a534fff --x      3000      1000  (load base 0x2000)\n"
-"    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
+      "--->Fault address falls at 00001000 before any mapped regions\n"
+      "    0a434000-0a434fff -w-      1000      1000  (load bias 0xd000)\n"
+      "    0a534000-0a534fff --x      3000      1000  (load bias 0x2000)\n"
+      "    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
@@ -332,21 +332,21 @@
   map.start = 0xa434000;
   map.end = 0xa435000;
   map.offset = 0x1000;
-  map.load_base = 0xd000;
+  map.load_bias = 0xd000;
   map.flags = PROT_WRITE;
   map_mock_->AddMap(map);
 
   map.start = 0xa534000;
   map.end = 0xa535000;
   map.offset = 0x3000;
-  map.load_base = 0x2000;
+  map.load_bias = 0x2000;
   map.flags = PROT_EXEC;
   map_mock_->AddMap(map);
 
   map.start = 0xa634000;
   map.end = 0xa635000;
   map.offset = 0;
-  map.load_base = 0;
+  map.load_bias = 0;
   map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
   map.name = "/system/lib/fake.so";
   map_mock_->AddMap(map);
@@ -362,18 +362,18 @@
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
-  const char* expected_dump = \
-"\nmemory map: (fault address prefixed with --->)\n"
+  const char* expected_dump =
+      "\nmemory map: (fault address prefixed with --->)\n"
 #if defined(__LP64__)
-"    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load base 0xd000)\n"
-"--->Fault address falls at 00000000'0a533000 between mapped regions\n"
-"    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load base 0x2000)\n"
-"    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
+      "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
+      "--->Fault address falls at 00000000'0a533000 between mapped regions\n"
+      "    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 0x2000)\n"
+      "    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
 #else
-"    0a434000-0a434fff -w-      1000      1000  (load base 0xd000)\n"
-"--->Fault address falls at 0a533000 between mapped regions\n"
-"    0a534000-0a534fff --x      3000      1000  (load base 0x2000)\n"
-"    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
+      "    0a434000-0a434fff -w-      1000      1000  (load bias 0xd000)\n"
+      "--->Fault address falls at 0a533000 between mapped regions\n"
+      "    0a534000-0a534fff --x      3000      1000  (load bias 0x2000)\n"
+      "    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
@@ -390,21 +390,21 @@
   map.start = 0xa434000;
   map.end = 0xa435000;
   map.offset = 0x1000;
-  map.load_base = 0xd000;
+  map.load_bias = 0xd000;
   map.flags = PROT_WRITE;
   map_mock_->AddMap(map);
 
   map.start = 0xa534000;
   map.end = 0xa535000;
   map.offset = 0x3000;
-  map.load_base = 0x2000;
+  map.load_bias = 0x2000;
   map.flags = PROT_EXEC;
   map_mock_->AddMap(map);
 
   map.start = 0xa634000;
   map.end = 0xa635000;
   map.offset = 0;
-  map.load_base = 0;
+  map.load_bias = 0;
   map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
   map.name = "/system/lib/fake.so";
   map_mock_->AddMap(map);
@@ -420,16 +420,16 @@
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
-  const char* expected_dump = \
-"\nmemory map: (fault address prefixed with --->)\n"
+  const char* expected_dump =
+      "\nmemory map: (fault address prefixed with --->)\n"
 #if defined(__LP64__)
-"    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load base 0xd000)\n"
-"--->00000000'0a534000-00000000'0a534fff --x      3000      1000  (load base 0x2000)\n"
-"    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
+      "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
+      "--->00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 0x2000)\n"
+      "    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n";
 #else
-"    0a434000-0a434fff -w-      1000      1000  (load base 0xd000)\n"
-"--->0a534000-0a534fff --x      3000      1000  (load base 0x2000)\n"
-"    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
+      "    0a434000-0a434fff -w-      1000      1000  (load bias 0xd000)\n"
+      "--->0a534000-0a534fff --x      3000      1000  (load bias 0x2000)\n"
+      "    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n";
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
@@ -446,21 +446,21 @@
   map.start = 0xa434000;
   map.end = 0xa435000;
   map.offset = 0x1000;
-  map.load_base = 0xd000;
+  map.load_bias = 0xd000;
   map.flags = PROT_WRITE;
   map_mock_->AddMap(map);
 
   map.start = 0xa534000;
   map.end = 0xa535000;
   map.offset = 0x3000;
-  map.load_base = 0x2000;
+  map.load_bias = 0x2000;
   map.flags = PROT_EXEC;
   map_mock_->AddMap(map);
 
   map.start = 0xa634000;
   map.end = 0xa635000;
   map.offset = 0;
-  map.load_base = 0;
+  map.load_bias = 0;
   map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
   map.name = "/system/lib/fake.so";
   map_mock_->AddMap(map);
@@ -480,18 +480,18 @@
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
-  const char* expected_dump = \
-"\nmemory map: (fault address prefixed with --->)\n"
+  const char* expected_dump =
+      "\nmemory map: (fault address prefixed with --->)\n"
 #if defined(__LP64__)
-"    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load base 0xd000)\n"
-"    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load base 0x2000)\n"
-"    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n"
-"--->Fault address falls at 00001234'5a534040 after any mapped regions\n";
+      "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n"
+      "    00000000'0a534000-00000000'0a534fff --x      3000      1000  (load bias 0x2000)\n"
+      "    00000000'0a634000-00000000'0a634fff rwx         0      1000  /system/lib/fake.so\n"
+      "--->Fault address falls at 00001234'5a534040 after any mapped regions\n";
 #else
-"    0a434000-0a434fff -w-      1000      1000  (load base 0xd000)\n"
-"    0a534000-0a534fff --x      3000      1000  (load base 0x2000)\n"
-"    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n"
-"--->Fault address falls at 0f534040 after any mapped regions\n";
+      "    0a434000-0a434fff -w-      1000      1000  (load bias 0xd000)\n"
+      "    0a534000-0a534fff --x      3000      1000  (load bias 0x2000)\n"
+      "    0a634000-0a634fff rwx         0      1000  /system/lib/fake.so\n"
+      "--->Fault address falls at 0f534040 after any mapped regions\n";
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
@@ -508,7 +508,7 @@
   map.start = 0xa434000;
   map.end = 0xa435000;
   map.offset = 0x1000;
-  map.load_base = 0xd000;
+  map.load_bias = 0xd000;
   map.flags = PROT_WRITE;
   map_mock_->AddMap(map);
 
@@ -520,12 +520,12 @@
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
-  const char* expected_dump = \
-"\nmemory map:\n"
+  const char* expected_dump =
+      "\nmemory map:\n"
 #if defined(__LP64__)
-"    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load base 0xd000)\n";
+      "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load bias 0xd000)\n";
 #else
-"    0a434000-0a434fff -w-      1000      1000  (load base 0xd000)\n";
+      "    0a434000-0a434fff -w-      1000      1000  (load bias 0xd000)\n";
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 996d714..0113131 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -466,11 +466,11 @@
         line += " (BuildId: " + build_id + ")";
       }
     }
-    if (it->load_base != 0) {
+    if (it->load_bias != 0) {
       if (space_needed) {
         line += ' ';
       }
-      line += StringPrintf(" (load base 0x%" PRIxPTR ")", it->load_base);
+      line += StringPrintf(" (load bias 0x%" PRIxPTR ")", it->load_bias);
     }
     _LOG(log, logtype::MAPS, "%s\n", line.c_str());
   }
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 80def73..dd8bad9 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -40,6 +40,7 @@
 LOCAL_MODULE_TAGS := debug
 LOCAL_MODULE_HOST_OS := darwin linux windows
 LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
+LOCAL_REQUIRED_MODULES := mke2fs e2fsdroid
 
 LOCAL_SRC_FILES_linux := usb_linux.cpp
 LOCAL_STATIC_LIBRARIES_linux := libselinux
@@ -85,6 +86,8 @@
 include $(BUILD_HOST_EXECUTABLE)
 
 my_dist_files := $(LOCAL_BUILT_MODULE)
+my_dist_files += $(HOST_OUT_EXECUTABLES)/mke2fs$(HOST_EXECUTABLE_SUFFIX)
+my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid$(HOST_EXECUTABLE_SUFFIX)
 ifeq ($(HOST_OS),linux)
 my_dist_files += $(HOST_LIBRARY_PATH)/libf2fs_fmt_host_dyn$(HOST_SHLIB_SUFFIX)
 endif
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 99ca7dd..f3c000e 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -10,14 +10,22 @@
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#ifndef WIN32
+#include <sys/wait.h>
+#endif
 #include <unistd.h>
+#include <vector>
 
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
 #include <ext4_utils/make_ext4fs.h>
 #include <sparse/sparse.h>
 
+using android::base::StringPrintf;
 using android::base::unique_fd;
 
+#ifdef WIN32
 static int generate_ext4_image(const char* fileName, long long partSize, const std::string& initial_dir,
                                        unsigned eraseBlkSize, unsigned logicalBlkSize)
 {
@@ -34,6 +42,84 @@
     }
     return 0;
 }
+#else
+static int exec_e2fs_cmd(const char* path, char* const argv[]) {
+    int status;
+    pid_t child;
+    if ((child = fork()) == 0) {
+        setenv("MKE2FS_CONFIG", "", 1);
+        execvp(path, argv);
+        _exit(EXIT_FAILURE);
+    }
+    if (child < 0) {
+        fprintf(stderr, "%s failed with fork %s\n", path, strerror(errno));
+        return -1;
+    }
+    if (TEMP_FAILURE_RETRY(waitpid(child, &status, 0)) == -1) {
+        fprintf(stderr, "%s failed with waitpid %s\n", path, strerror(errno));
+        return -1;
+    }
+    int ret = -1;
+    if (WIFEXITED(status)) {
+        ret = WEXITSTATUS(status);
+        if (ret != 0) {
+            fprintf(stderr, "%s failed with status %d\n", path, ret);
+        }
+    }
+    return ret;
+}
+
+static int generate_ext4_image(const char* fileName, long long partSize,
+                               const std::string& initial_dir, unsigned eraseBlkSize,
+                               unsigned logicalBlkSize) {
+    static constexpr int block_size = 4096;
+    const std::string exec_dir = android::base::GetExecutableDirectory();
+
+    const std::string mke2fs_path = exec_dir + "/mke2fs";
+    std::vector<const char*> mke2fs_args = {mke2fs_path.c_str(), "-t", "ext4", "-b"};
+
+    std::string block_size_str = std::to_string(block_size);
+    mke2fs_args.push_back(block_size_str.c_str());
+
+    std::string ext_attr = "android_sparse";
+    if (eraseBlkSize != 0 && logicalBlkSize != 0) {
+        int raid_stride = logicalBlkSize / block_size;
+        int raid_stripe_width = eraseBlkSize / block_size;
+        // stride should be the max of 8kb and logical block size
+        if (logicalBlkSize != 0 && logicalBlkSize < 8192) raid_stride = 8192 / block_size;
+        ext_attr += StringPrintf(",stride=%d,stripe-width=%d", raid_stride, raid_stripe_width);
+    }
+    mke2fs_args.push_back("-E");
+    mke2fs_args.push_back(ext_attr.c_str());
+    mke2fs_args.push_back(fileName);
+
+    std::string size_str = std::to_string(partSize / block_size);
+    mke2fs_args.push_back(size_str.c_str());
+    mke2fs_args.push_back(nullptr);
+
+    int ret = exec_e2fs_cmd(mke2fs_args[0], const_cast<char**>(mke2fs_args.data()));
+    if (ret != 0) {
+        fprintf(stderr, "mke2fs failed: %d\n", ret);
+        return -1;
+    }
+
+    if (initial_dir.empty()) {
+        return 0;
+    }
+
+    const std::string e2fsdroid_path = exec_dir + "/e2fsdroid";
+    std::vector<const char*> e2fsdroid_args = {e2fsdroid_path.c_str(), "-f", initial_dir.c_str(),
+                                               fileName, nullptr};
+
+    ret = exec_e2fs_cmd(e2fsdroid_args[0], const_cast<char**>(e2fsdroid_args.data()));
+    if (ret != 0) {
+        fprintf(stderr, "e2fsdroid failed: %d\n", ret);
+        return -1;
+    }
+
+    return 0;
+}
+#endif
 
 #ifdef USE_F2FS
 static int generate_f2fs_image(const char* fileName, long long partSize, const std::string& initial_dir,
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 9249343..007189d 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -15,7 +15,6 @@
     libavb
 
 include $(CLEAR_VARS)
-LOCAL_CLANG := true
 LOCAL_SANITIZE := integer
 LOCAL_SRC_FILES:= fs_mgr_main.cpp
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index e009383..c9af421 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -32,6 +32,7 @@
 #include <unistd.h>
 
 #include <memory>
+#include <thread>
 
 #include <android-base/file.h>
 #include <android-base/properties.h>
@@ -78,43 +79,33 @@
     FS_STAT_E2FSCK_F_ALWAYS = 0x0004,
     FS_STAT_UNCLEAN_SHUTDOWN = 0x0008,
     FS_STAT_QUOTA_ENABLED = 0x0010,
-    FS_STAT_TUNE2FS_FAILED = 0x0020,
     FS_STAT_RO_MOUNT_FAILED = 0x0040,
     FS_STAT_RO_UNMOUNT_FAILED = 0x0080,
     FS_STAT_FULL_MOUNT_FAILED = 0x0100,
     FS_STAT_E2FSCK_FAILED = 0x0200,
     FS_STAT_E2FSCK_FS_FIXED = 0x0400,
     FS_STAT_EXT4_INVALID_MAGIC = 0x0800,
+    FS_STAT_TOGGLE_QUOTAS_FAILED = 0x10000,
+    FS_STAT_SET_RESERVED_BLOCKS_FAILED = 0x20000,
+    FS_STAT_ENABLE_ENCRYPTION_FAILED = 0x40000,
 };
 
-/*
- * gettime() - returns the time in seconds of the system's monotonic clock or
- * zero on error.
- */
-static time_t gettime(void)
-{
-    struct timespec ts;
-    int ret;
+// TODO: switch to inotify()
+bool fs_mgr_wait_for_file(const std::string& filename,
+                          const std::chrono::milliseconds relative_timeout) {
+    auto start_time = std::chrono::steady_clock::now();
 
-    ret = clock_gettime(CLOCK_MONOTONIC, &ts);
-    if (ret < 0) {
-        PERROR << "clock_gettime(CLOCK_MONOTONIC) failed";
-        return 0;
+    while (true) {
+        if (!access(filename.c_str(), F_OK) || errno != ENOENT) {
+            return true;
+        }
+
+        std::this_thread::sleep_for(50ms);
+
+        auto now = std::chrono::steady_clock::now();
+        auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
+        if (time_elapsed > relative_timeout) return false;
     }
-
-    return ts.tv_sec;
-}
-
-static int wait_for_file(const char *filename, int timeout)
-{
-    struct stat info;
-    time_t timeout_time = gettime() + timeout;
-    int ret = -1;
-
-    while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0))
-        usleep(10000);
-
-    return ret;
 }
 
 static void log_fs_stat(const char* blk_device, int fs_stat)
@@ -128,10 +119,16 @@
     }
 }
 
+static bool is_extfs(const std::string& fs_type) {
+    return fs_type == "ext4" || fs_type == "ext3" || fs_type == "ext2";
+}
+
 static bool should_force_check(int fs_stat) {
-    return fs_stat & (FS_STAT_E2FSCK_F_ALWAYS | FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED |
-                      FS_STAT_TUNE2FS_FAILED | FS_STAT_RO_MOUNT_FAILED | FS_STAT_RO_UNMOUNT_FAILED |
-                      FS_STAT_FULL_MOUNT_FAILED | FS_STAT_E2FSCK_FAILED);
+    return fs_stat &
+           (FS_STAT_E2FSCK_F_ALWAYS | FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED |
+            FS_STAT_RO_MOUNT_FAILED | FS_STAT_RO_UNMOUNT_FAILED | FS_STAT_FULL_MOUNT_FAILED |
+            FS_STAT_E2FSCK_FAILED | FS_STAT_TOGGLE_QUOTAS_FAILED |
+            FS_STAT_SET_RESERVED_BLOCKS_FAILED | FS_STAT_ENABLE_ENCRYPTION_FAILED);
 }
 
 static void check_fs(const char *blk_device, char *fs_type, char *target, int *fs_stat)
@@ -144,7 +141,7 @@
     const char* e2fsck_forced_argv[] = {E2FSCK_BIN, "-f", "-y", blk_device};
 
     /* Check for the types of filesystems we know how to check */
-    if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
+    if (is_extfs(fs_type)) {
         if (*fs_stat & FS_STAT_EXT4_INVALID_MAGIC) {  // will fail, so do not try
             return;
         }
@@ -242,186 +239,214 @@
     return;
 }
 
-/* Function to read the primary superblock */
-static int read_super_block(int fd, struct ext4_super_block *sb)
-{
-    off64_t ret;
-
-    ret = lseek64(fd, 1024, SEEK_SET);
-    if (ret < 0)
-        return ret;
-
-    ret = read(fd, sb, sizeof(*sb));
-    if (ret < 0)
-        return ret;
-    if (ret != sizeof(*sb))
-        return ret;
-
-    return 0;
-}
-
-static ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es)
-{
+static ext4_fsblk_t ext4_blocks_count(const struct ext4_super_block* es) {
     return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) |
-            le32_to_cpu(es->s_blocks_count_lo);
+           le32_to_cpu(es->s_blocks_count_lo);
 }
 
-static ext4_fsblk_t ext4_r_blocks_count(struct ext4_super_block *es)
-{
+static ext4_fsblk_t ext4_r_blocks_count(const struct ext4_super_block* es) {
     return ((ext4_fsblk_t)le32_to_cpu(es->s_r_blocks_count_hi) << 32) |
-            le32_to_cpu(es->s_r_blocks_count_lo);
+           le32_to_cpu(es->s_r_blocks_count_lo);
 }
 
-static int do_quota_with_shutdown_check(char *blk_device, char *fs_type,
-                                        struct fstab_rec *rec, int *fs_stat)
-{
-    int force_check = 0;
-    if (!strcmp(fs_type, "ext4")) {
-        /*
-         * Some system images do not have tune2fs for licensing reasons
-         * Detect these and skip reserve blocks.
-         */
-        if (access(TUNE2FS_BIN, X_OK)) {
-            LERROR << "Not running " << TUNE2FS_BIN << " on "
-                   << blk_device << " (executable not in system image)";
-        } else {
-            const char* arg1 = nullptr;
-            const char* arg2 = nullptr;
-            int status = 0;
-            int ret = 0;
-            android::base::unique_fd fd(
-                TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC)));
-            if (fd >= 0) {
-                struct ext4_super_block sb;
-                ret = read_super_block(fd, &sb);
-                if (ret < 0) {
-                    PERROR << "Can't read '" << blk_device << "' super block";
-                    return force_check;
-                }
-                if (sb.s_magic != EXT4_SUPER_MAGIC) {
-                    LINFO << "Invalid ext4 magic:0x" << std::hex << sb.s_magic << "," << blk_device;
-                    *fs_stat |= FS_STAT_EXT4_INVALID_MAGIC;
-                    return 0;  // not a valid fs, tune2fs, fsck, and mount  will all fail.
-                }
-                *fs_stat |= FS_STAT_IS_EXT4;
-                LINFO << "superblock s_max_mnt_count:" << sb.s_max_mnt_count << "," << blk_device;
-                if (sb.s_max_mnt_count == 0xffff) {  // -1 (int16) in ext2, but uint16 in ext4
-                    *fs_stat |= FS_STAT_NEW_IMAGE_VERSION;
-                }
-                if ((sb.s_feature_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) != 0 ||
-                    (sb.s_state & EXT4_VALID_FS) == 0) {
-                    LINFO << __FUNCTION__ << "(): was not clealy shutdown, state flag:"
-                          << std::hex << sb.s_state
-                          << "incompat flag:" << std::hex << sb.s_feature_incompat;
-                    force_check = 1;
-                    *fs_stat |= FS_STAT_UNCLEAN_SHUTDOWN;
-                }
-                int has_quota = (sb.s_feature_ro_compat
-                        & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_QUOTA)) != 0;
-                int want_quota = fs_mgr_is_quota(rec) != 0;
-
-                if (has_quota == want_quota) {
-                    LINFO << "Requested quota status is match on " << blk_device;
-                    return force_check;
-                } else if (want_quota) {
-                    LINFO << "Enabling quota on " << blk_device;
-                    arg1 = "-Oquota";
-                    arg2 = "-Qusrquota,grpquota";
-                    force_check = 1;
-                    *fs_stat |= FS_STAT_QUOTA_ENABLED;
-                } else {
-                    LINFO << "Disabling quota on " << blk_device;
-                    arg1 = "-Q^usrquota,^grpquota";
-                    arg2 = "-O^quota";
-                }
-            } else {
-                PERROR << "Failed to open '" << blk_device << "'";
-                return force_check;
-            }
-
-            const char *tune2fs_argv[] = {
-                TUNE2FS_BIN,
-                arg1,
-                arg2,
-                blk_device,
-            };
-            ret = android_fork_execvp_ext(ARRAY_SIZE(tune2fs_argv),
-                                          const_cast<char **>(tune2fs_argv),
-                                          &status, true, LOG_KLOG | LOG_FILE,
-                                          true, NULL, NULL, 0);
-            if (ret < 0) {
-                /* No need to check for error in fork, we can't really handle it now */
-                LERROR << "Failed trying to run " << TUNE2FS_BIN;
-                *fs_stat |= FS_STAT_TUNE2FS_FAILED;
-            }
-        }
-    }
-    return force_check;
+static bool is_ext4_superblock_valid(const struct ext4_super_block* es) {
+    if (es->s_magic != EXT4_SUPER_MAGIC) return false;
+    if (es->s_rev_level != EXT4_DYNAMIC_REV && es->s_rev_level != EXT4_GOOD_OLD_REV) return false;
+    if (EXT4_INODES_PER_GROUP(es) == 0) return false;
+    return true;
 }
 
-static void do_reserved_size(char *blk_device, char *fs_type, struct fstab_rec *rec, int *fs_stat)
-{
-    /* Check for the types of filesystems we know how to check */
-    if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
-        /*
-         * Some system images do not have tune2fs for licensing reasons
-         * Detect these and skip reserve blocks.
-         */
-        if (access(TUNE2FS_BIN, X_OK)) {
-            LERROR << "Not running " << TUNE2FS_BIN << " on "
-                   << blk_device << " (executable not in system image)";
+// Read the primary superblock from an ext4 filesystem.  On failure return
+// false.  If it's not an ext4 filesystem, also set FS_STAT_EXT4_INVALID_MAGIC.
+static bool read_ext4_superblock(const char* blk_device, struct ext4_super_block* sb, int* fs_stat) {
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC)));
+
+    if (fd < 0) {
+        PERROR << "Failed to open '" << blk_device << "'";
+        return false;
+    }
+
+    if (pread(fd, sb, sizeof(*sb), 1024) != sizeof(*sb)) {
+        PERROR << "Can't read '" << blk_device << "' superblock";
+        return false;
+    }
+
+    if (!is_ext4_superblock_valid(sb)) {
+        LINFO << "Invalid ext4 superblock on '" << blk_device << "'";
+        // not a valid fs, tune2fs, fsck, and mount  will all fail.
+        *fs_stat |= FS_STAT_EXT4_INVALID_MAGIC;
+        return false;
+    }
+    *fs_stat |= FS_STAT_IS_EXT4;
+    LINFO << "superblock s_max_mnt_count:" << sb->s_max_mnt_count << "," << blk_device;
+    if (sb->s_max_mnt_count == 0xffff) {  // -1 (int16) in ext2, but uint16 in ext4
+        *fs_stat |= FS_STAT_NEW_IMAGE_VERSION;
+    }
+    return true;
+}
+
+// Some system images do not have tune2fs for licensing reasons.
+// Detect these and skip running it.
+static bool tune2fs_available(void) {
+    return access(TUNE2FS_BIN, X_OK) == 0;
+}
+
+static bool run_tune2fs(const char* argv[], int argc) {
+    int ret;
+
+    ret = android_fork_execvp_ext(argc, const_cast<char**>(argv), nullptr, true,
+                                  LOG_KLOG | LOG_FILE, true, nullptr, nullptr, 0);
+    return ret == 0;
+}
+
+// Enable/disable quota support on the filesystem if needed.
+static void tune_quota(const char* blk_device, const struct fstab_rec* rec,
+                       const struct ext4_super_block* sb, int* fs_stat) {
+    bool has_quota = (sb->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_QUOTA)) != 0;
+    bool want_quota = fs_mgr_is_quota(rec) != 0;
+
+    if (has_quota == want_quota) {
+        return;
+    }
+
+    if (!tune2fs_available()) {
+        LERROR << "Unable to " << (want_quota ? "enable" : "disable") << " quotas on " << blk_device
+               << " because " TUNE2FS_BIN " is missing";
+        return;
+    }
+
+    const char* argv[] = {TUNE2FS_BIN, nullptr, nullptr, blk_device};
+
+    if (want_quota) {
+        LINFO << "Enabling quotas on " << blk_device;
+        argv[1] = "-Oquota";
+        argv[2] = "-Qusrquota,grpquota";
+        *fs_stat |= FS_STAT_QUOTA_ENABLED;
+    } else {
+        LINFO << "Disabling quotas on " << blk_device;
+        argv[1] = "-O^quota";
+        argv[2] = "-Q^usrquota,^grpquota";
+    }
+
+    if (!run_tune2fs(argv, ARRAY_SIZE(argv))) {
+        LERROR << "Failed to run " TUNE2FS_BIN " to " << (want_quota ? "enable" : "disable")
+               << " quotas on " << blk_device;
+        *fs_stat |= FS_STAT_TOGGLE_QUOTAS_FAILED;
+    }
+}
+
+// Set the number of reserved filesystem blocks if needed.
+static void tune_reserved_size(const char* blk_device, const struct fstab_rec* rec,
+                               const struct ext4_super_block* sb, int* fs_stat) {
+    if (!(rec->fs_mgr_flags & MF_RESERVEDSIZE)) {
+        return;
+    }
+
+    // The size to reserve is given in the fstab, but we won't reserve more
+    // than 2% of the filesystem.
+    const uint64_t max_reserved_blocks = ext4_blocks_count(sb) * 0.02;
+    uint64_t reserved_blocks = rec->reserved_size / EXT4_BLOCK_SIZE(sb);
+
+    if (reserved_blocks > max_reserved_blocks) {
+        LWARNING << "Reserved blocks " << reserved_blocks << " is too large; "
+                 << "capping to " << max_reserved_blocks;
+        reserved_blocks = max_reserved_blocks;
+    }
+
+    if (ext4_r_blocks_count(sb) == reserved_blocks) {
+        return;
+    }
+
+    if (!tune2fs_available()) {
+        LERROR << "Unable to set the number of reserved blocks on " << blk_device
+               << " because " TUNE2FS_BIN " is missing";
+        return;
+    }
+
+    char buf[32];
+    const char* argv[] = {TUNE2FS_BIN, "-r", buf, blk_device};
+
+    snprintf(buf, sizeof(buf), "%" PRIu64, reserved_blocks);
+    LINFO << "Setting reserved block count on " << blk_device << " to " << reserved_blocks;
+    if (!run_tune2fs(argv, ARRAY_SIZE(argv))) {
+        LERROR << "Failed to run " TUNE2FS_BIN " to set the number of reserved blocks on "
+               << blk_device;
+        *fs_stat |= FS_STAT_SET_RESERVED_BLOCKS_FAILED;
+    }
+}
+
+// Enable file-based encryption if needed.
+static void tune_encrypt(const char* blk_device, const struct fstab_rec* rec,
+                         const struct ext4_super_block* sb, int* fs_stat) {
+    bool has_encrypt = (sb->s_feature_incompat & cpu_to_le32(EXT4_FEATURE_INCOMPAT_ENCRYPT)) != 0;
+    bool want_encrypt = fs_mgr_is_file_encrypted(rec) != 0;
+
+    if (has_encrypt || !want_encrypt) {
+        return;
+    }
+
+    if (!tune2fs_available()) {
+        LERROR << "Unable to enable ext4 encryption on " << blk_device
+               << " because " TUNE2FS_BIN " is missing";
+        return;
+    }
+
+    const char* argv[] = {TUNE2FS_BIN, "-Oencrypt", blk_device};
+
+    LINFO << "Enabling ext4 encryption on " << blk_device;
+    if (!run_tune2fs(argv, ARRAY_SIZE(argv))) {
+        LERROR << "Failed to run " TUNE2FS_BIN " to enable "
+               << "ext4 encryption on " << blk_device;
+        *fs_stat |= FS_STAT_ENABLE_ENCRYPTION_FAILED;
+    }
+}
+
+//
+// Prepare the filesystem on the given block device to be mounted.
+//
+// If the "check" option was given in the fstab record, or it seems that the
+// filesystem was uncleanly shut down, we'll run fsck on the filesystem.
+//
+// If needed, we'll also enable (or disable) filesystem features as specified by
+// the fstab record.
+//
+static int prepare_fs_for_mount(const char* blk_device, const struct fstab_rec* rec) {
+    int fs_stat = 0;
+
+    if (is_extfs(rec->fs_type)) {
+        struct ext4_super_block sb;
+
+        if (read_ext4_superblock(blk_device, &sb, &fs_stat)) {
+            if ((sb.s_feature_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) != 0 ||
+                (sb.s_state & EXT4_VALID_FS) == 0) {
+                LINFO << "Filesystem on " << blk_device << " was not cleanly shutdown; "
+                      << "state flags: 0x" << std::hex << sb.s_state << ", "
+                      << "incompat feature flags: 0x" << std::hex << sb.s_feature_incompat;
+                fs_stat |= FS_STAT_UNCLEAN_SHUTDOWN;
+            }
+
+            // Note: quotas should be enabled before running fsck.
+            tune_quota(blk_device, rec, &sb, &fs_stat);
         } else {
-            LINFO << "Running " << TUNE2FS_BIN << " on " << blk_device;
-
-            int status = 0;
-            int ret = 0;
-            unsigned long reserved_blocks = 0;
-            android::base::unique_fd fd(
-                TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC)));
-            if (fd >= 0) {
-                struct ext4_super_block sb;
-                ret = read_super_block(fd, &sb);
-                if (ret < 0) {
-                    PERROR << "Can't read '" << blk_device << "' super block";
-                    return;
-                }
-                reserved_blocks = rec->reserved_size / EXT4_BLOCK_SIZE(&sb);
-                unsigned long reserved_threshold = ext4_blocks_count(&sb) * 0.02;
-                if (reserved_threshold < reserved_blocks) {
-                    LWARNING << "Reserved blocks " << reserved_blocks
-                             << " is too large";
-                    reserved_blocks = reserved_threshold;
-                }
-
-                if (ext4_r_blocks_count(&sb) == reserved_blocks) {
-                    LINFO << "Have reserved same blocks";
-                    return;
-                }
-            } else {
-                PERROR << "Failed to open '" << blk_device << "'";
-                return;
-            }
-
-            char buf[16] = {0};
-            snprintf(buf, sizeof (buf), "-r %lu", reserved_blocks);
-            const char *tune2fs_argv[] = {
-                TUNE2FS_BIN,
-                buf,
-                blk_device,
-            };
-
-            ret = android_fork_execvp_ext(ARRAY_SIZE(tune2fs_argv),
-                                          const_cast<char **>(tune2fs_argv),
-                                          &status, true, LOG_KLOG | LOG_FILE,
-                                          true, NULL, NULL, 0);
-
-            if (ret < 0) {
-                /* No need to check for error in fork, we can't really handle it now */
-                LERROR << "Failed trying to run " << TUNE2FS_BIN;
-                *fs_stat |= FS_STAT_TUNE2FS_FAILED;
-            }
+            return fs_stat;
         }
     }
+
+    if ((rec->fs_mgr_flags & MF_CHECK) ||
+        (fs_stat & (FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED))) {
+        check_fs(blk_device, rec->fs_type, rec->mount_point, &fs_stat);
+    }
+
+    if (is_extfs(rec->fs_type) && (rec->fs_mgr_flags & (MF_RESERVEDSIZE | MF_FILEENCRYPTION))) {
+        struct ext4_super_block sb;
+
+        if (read_ext4_superblock(blk_device, &sb, &fs_stat)) {
+            tune_reserved_size(blk_device, rec, &sb, &fs_stat);
+            tune_encrypt(blk_device, rec, &sb, &fs_stat);
+        }
+    }
+
+    return fs_stat;
 }
 
 static void remove_trailing_slashes(char *n)
@@ -457,6 +482,16 @@
     return rc;
 }
 
+// Orange state means the device is unlocked, see the following link for details.
+// https://source.android.com/security/verifiedboot/verified-boot#device_state
+bool fs_mgr_is_device_unlocked() {
+    std::string verified_boot_state;
+    if (fs_mgr_get_boot_config("verifiedbootstate", &verified_boot_state)) {
+        return verified_boot_state == "orange";
+    }
+    return false;
+}
+
 /*
  * __mount(): wrapper around the mount() system call which also
  * sets the underlying block device to read-only if the mount is read-only.
@@ -476,10 +511,11 @@
         if ((info.st_mode & S_IFMT) == S_IFLNK)
             unlink(target);
     mkdir(target, 0755);
+    errno = 0;
     ret = mount(source, target, rec->fs_type, mountflags, rec->fs_options);
     save_errno = errno;
-    LINFO << __FUNCTION__ << "(source=" << source << ",target="
-          << target << ",type=" << rec->fs_type << ")=" << ret;
+    PINFO << __FUNCTION__ << "(source=" << source << ",target=" << target
+          << ",type=" << rec->fs_type << ")=" << ret;
     if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
         fs_mgr_set_blk_ro(source);
     }
@@ -559,10 +595,7 @@
                 continue;
             }
 
-            int fs_stat = 0;
-            int force_check = do_quota_with_shutdown_check(fstab->recs[i].blk_device,
-                                                           fstab->recs[i].fs_type,
-                                                           &fstab->recs[i], &fs_stat);
+            int fs_stat = prepare_fs_for_mount(fstab->recs[i].blk_device, &fstab->recs[i]);
             if (fs_stat & FS_STAT_EXT4_INVALID_MAGIC) {
                 LERROR << __FUNCTION__ << "(): skipping mount, invalid ext4, mountpoint="
                        << fstab->recs[i].mount_point << " rec[" << i
@@ -570,15 +603,6 @@
                 mount_errno = EINVAL;  // continue bootup for FDE
                 continue;
             }
-            if ((fstab->recs[i].fs_mgr_flags & MF_CHECK) || force_check) {
-                check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
-                         fstab->recs[i].mount_point, &fs_stat);
-            }
-
-            if (fstab->recs[i].fs_mgr_flags & MF_RESERVEDSIZE) {
-                do_reserved_size(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
-                                 &fstab->recs[i], &fs_stat);
-            }
 
             int retry_count = 2;
             while (retry_count-- > 0) {
@@ -756,19 +780,6 @@
     }
 }
 
-// TODO: add ueventd notifiers if they don't exist.
-// This is just doing a wait_for_device for maximum of 1s
-int fs_mgr_test_access(const char *device) {
-    int tries = 25;
-    while (tries--) {
-        if (!access(device, F_OK) || errno != ENOENT) {
-            return 0;
-        }
-        usleep(40 * 1000);
-    }
-    return -1;
-}
-
 bool is_device_secure() {
     int ret = -1;
     char value[PROP_VALUE_MAX];
@@ -829,9 +840,7 @@
         }
 
         /* Translate LABEL= file system labels into block devices */
-        if (!strcmp(fstab->recs[i].fs_type, "ext2") ||
-            !strcmp(fstab->recs[i].fs_type, "ext3") ||
-            !strcmp(fstab->recs[i].fs_type, "ext4")) {
+        if (is_extfs(fstab->recs[i].fs_type)) {
             int tret = translate_ext_labels(&fstab->recs[i]);
             if (tret < 0) {
                 LERROR << "Could not translate label to block device";
@@ -839,8 +848,10 @@
             }
         }
 
-        if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
-            wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
+        if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
+            !fs_mgr_wait_for_file(fstab->recs[i].blk_device, 20s)) {
+            LERROR << "Skipping '" << fstab->recs[i].blk_device << "' during mount_all";
+            continue;
         }
 
         if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
@@ -1047,22 +1058,12 @@
         }
 
         /* First check the filesystem if requested */
-        if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
-            wait_for_file(n_blk_device, WAIT_TIMEOUT);
+        if (fstab->recs[i].fs_mgr_flags & MF_WAIT && !fs_mgr_wait_for_file(n_blk_device, 20s)) {
+            LERROR << "Skipping mounting '" << n_blk_device << "'";
+            continue;
         }
 
-        int fs_stat = 0;
-        int force_check = do_quota_with_shutdown_check(n_blk_device, fstab->recs[i].fs_type,
-                                                       &fstab->recs[i], &fs_stat);
-
-        if ((fstab->recs[i].fs_mgr_flags & MF_CHECK) || force_check) {
-            check_fs(n_blk_device, fstab->recs[i].fs_type,
-                     fstab->recs[i].mount_point, &fs_stat);
-        }
-
-        if (fstab->recs[i].fs_mgr_flags & MF_RESERVEDSIZE) {
-            do_reserved_size(n_blk_device, fstab->recs[i].fs_type, &fstab->recs[i], &fs_stat);
-        }
+        int fs_stat = prepare_fs_for_mount(n_blk_device, &fstab->recs[i]);
 
         if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
             if (!avb_handle) {
@@ -1221,8 +1222,11 @@
             fclose(zram_fp);
         }
 
-        if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
-            wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
+        if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
+            !fs_mgr_wait_for_file(fstab->recs[i].blk_device, 20s)) {
+            LERROR << "Skipping mkswap for '" << fstab->recs[i].blk_device << "'";
+            ret = -1;
+            continue;
         }
 
         /* Initialize the swap area */
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 2c99aa7..7824cfa 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -397,7 +397,7 @@
     fstab_entry->blk_device = strdup(verity_blk_name.c_str());
 
     // Makes sure we've set everything up properly.
-    if (wait_for_verity_dev && fs_mgr_test_access(verity_blk_name.c_str()) < 0) {
+    if (wait_for_verity_dev && !fs_mgr_wait_for_file(verity_blk_name, 1s)) {
         return false;
     }
 
@@ -473,16 +473,6 @@
     return true;
 }
 
-// Orange state means the device is unlocked, see the following link for details.
-// https://source.android.com/security/verifiedboot/verified-boot#device_state
-static inline bool IsDeviceUnlocked() {
-    std::string verified_boot_state;
-    if (fs_mgr_get_boot_config("verifiedbootstate", &verified_boot_state)) {
-        return verified_boot_state == "orange";
-    }
-    return false;
-}
-
 FsManagerAvbUniquePtr FsManagerAvbHandle::Open(const fstab& fstab) {
     FsManagerAvbOps avb_ops(fstab);
     return DoOpen(&avb_ops);
@@ -498,7 +488,7 @@
 }
 
 FsManagerAvbUniquePtr FsManagerAvbHandle::DoOpen(FsManagerAvbOps* avb_ops) {
-    bool is_device_unlocked = IsDeviceUnlocked();
+    bool is_device_unlocked = fs_mgr_is_device_unlocked();
 
     FsManagerAvbUniquePtr avb_handle(new FsManagerAvbHandle());
     if (!avb_handle) {
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
index ba1262f..43879fe 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -142,10 +142,8 @@
     }
     std::string path = iter->second;
 
-    // Ensures the device path (a symlink created by init) is ready to
-    // access. fs_mgr_test_access() will test a few iterations if the
-    // path doesn't exist yet.
-    if (fs_mgr_test_access(path.c_str()) < 0) {
+    // Ensures the device path (a symlink created by init) is ready to access.
+    if (!fs_mgr_wait_for_file(path, 1s)) {
         return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
     }
 
diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/fs_mgr_boot_config.cpp
index ab5beed..9117667 100644
--- a/fs_mgr/fs_mgr_boot_config.cpp
+++ b/fs_mgr/fs_mgr_boot_config.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <string>
+
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
@@ -51,9 +53,11 @@
     // lastly, check the device tree
     if (is_dt_compatible()) {
         std::string file_name = kAndroidDtDir + "/" + key;
-        // DT entries terminate with '\0' but so do the properties
         if (android::base::ReadFileToString(file_name, out_val)) {
-            return true;
+            if (!out_val->empty()) {
+                out_val->pop_back();  // Trims the trailing '\0' out.
+                return true;
+            }
         }
     }
 
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index fc88217..85a593f 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -34,23 +34,35 @@
 #include "fs_mgr_priv.h"
 #include "cryptfs.h"
 
-static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer)
+static int get_dev_sz(char *fs_blkdev, uint64_t *dev_sz)
 {
-    uint64_t dev_sz;
-    int fd, rc = 0;
+    int fd;
 
-    if ((fd = open(fs_blkdev, O_WRONLY)) < 0) {
+    if ((fd = open(fs_blkdev, O_RDONLY)) < 0) {
         PERROR << "Cannot open block device";
         return -1;
     }
 
-    if ((ioctl(fd, BLKGETSIZE64, &dev_sz)) == -1) {
+    if ((ioctl(fd, BLKGETSIZE64, dev_sz)) == -1) {
         PERROR << "Cannot get block device size";
         close(fd);
         return -1;
     }
 
     close(fd);
+    return 0;
+}
+
+static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer)
+{
+    uint64_t dev_sz;
+    int rc = 0;
+    int status;
+
+    rc = get_dev_sz(fs_blkdev, &dev_sz);
+    if (rc) {
+        return rc;
+    }
 
     /* Format the partition using the calculated length */
     if (crypt_footer) {
@@ -85,9 +97,25 @@
     return rc;
 }
 
-static int format_f2fs(char *fs_blkdev)
+static int format_f2fs(char *fs_blkdev, uint64_t dev_sz, bool crypt_footer)
 {
-    const char* const args[] = {"/system/bin/make_f2fs", "-f", "-O encrypt", fs_blkdev, nullptr};
+    int status;
+
+    if (!dev_sz) {
+        int rc = get_dev_sz(fs_blkdev, &dev_sz);
+        if (rc) {
+            return rc;
+        }
+    }
+
+    /* Format the partition using the calculated length */
+    if (crypt_footer) {
+        dev_sz -= CRYPT_FOOTER_OFFSET;
+    }
+
+    std::string size_str = std::to_string(dev_sz / 4096);
+    const char* const args[] = {
+        "/system/bin/make_f2fs", "-f", "-O", "encrypt", fs_blkdev, size_str.c_str(), nullptr};
 
     return android_fork_execvp_ext(arraysize(args), const_cast<char**>(args), NULL, true,
                                    LOG_KLOG, true, nullptr, nullptr, 0);
@@ -101,7 +129,7 @@
            << " as '" << fstab->fs_type << "'";
 
     if (!strncmp(fstab->fs_type, "f2fs", 4)) {
-        rc = format_f2fs(fstab->blk_device);
+        rc = format_f2fs(fstab->blk_device, fstab->length, crypt_footer);
     } else if (!strncmp(fstab->fs_type, "ext4", 4)) {
         rc = format_ext4(fstab->blk_device, fstab->mount_point, crypt_footer);
     } else {
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 6c527c5..6dcbded 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -864,32 +864,26 @@
     return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
 }
 
-int fs_mgr_is_notrim(struct fstab_rec *fstab)
-{
+int fs_mgr_is_notrim(const struct fstab_rec* fstab) {
     return fstab->fs_mgr_flags & MF_NOTRIM;
 }
 
-int fs_mgr_is_formattable(struct fstab_rec *fstab)
-{
+int fs_mgr_is_formattable(const struct fstab_rec* fstab) {
     return fstab->fs_mgr_flags & (MF_FORMATTABLE);
 }
 
-int fs_mgr_is_slotselect(struct fstab_rec *fstab)
-{
+int fs_mgr_is_slotselect(const struct fstab_rec* fstab) {
     return fstab->fs_mgr_flags & MF_SLOTSELECT;
 }
 
-int fs_mgr_is_nofail(struct fstab_rec *fstab)
-{
+int fs_mgr_is_nofail(const struct fstab_rec* fstab) {
     return fstab->fs_mgr_flags & MF_NOFAIL;
 }
 
-int fs_mgr_is_latemount(struct fstab_rec *fstab)
-{
+int fs_mgr_is_latemount(const struct fstab_rec* fstab) {
     return fstab->fs_mgr_flags & MF_LATEMOUNT;
 }
 
-int fs_mgr_is_quota(struct fstab_rec *fstab)
-{
+int fs_mgr_is_quota(const struct fstab_rec* fstab) {
     return fstab->fs_mgr_flags & MF_QUOTA;
 }
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 3ca507b..a5d172b 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -17,8 +17,12 @@
 #ifndef __CORE_FS_MGR_PRIV_H
 #define __CORE_FS_MGR_PRIV_H
 
+#include <chrono>
+#include <string>
+
 #include <android-base/logging.h>
-#include <fs_mgr.h>
+
+#include "fs_mgr.h"
 #include "fs_mgr_priv_boot_config.h"
 
 /* The CHECK() in logging.h will use program invocation name as the tag.
@@ -43,8 +47,6 @@
 
 #define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000"
 
-#define WAIT_TIMEOUT 20
-
 /* fstab has the following format:
  *
  * Any line starting with a # is a comment and ignored
@@ -111,9 +113,13 @@
 
 #define DM_BUF_SIZE 4096
 
+using namespace std::chrono_literals;
+
 int fs_mgr_set_blk_ro(const char *blockdev);
-int fs_mgr_test_access(const char *device);
+bool fs_mgr_wait_for_file(const std::string& filename,
+                          const std::chrono::milliseconds relative_timeout);
 bool fs_mgr_update_for_slotselect(struct fstab *fstab);
+bool fs_mgr_is_device_unlocked();
 bool is_dt_compatible();
 bool is_device_secure();
 int load_verity_state(struct fstab_rec* fstab, int* mode);
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 8fa9370..7f8e1e2 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -782,8 +782,8 @@
     if (fec_verity_get_metadata(f, &verity) < 0) {
         PERROR << "Failed to get verity metadata '" << fstab->blk_device << "'";
         // Allow verity disabled when the device is unlocked without metadata
-        if ("0" == android::base::GetProperty("ro.boot.flash.locked", "")) {
-            retval = FS_MGR_SETUP_VERITY_DISABLED;
+        if (fs_mgr_is_device_unlocked()) {
+            retval = FS_MGR_SETUP_VERITY_SKIPPED;
             LWARNING << "Allow invalid metadata when the device is unlocked";
         }
         goto out;
@@ -841,9 +841,15 @@
 
     // verify the signature on the table
     if (verify_verity_signature(verity) < 0) {
+        // Allow signature verification error when the device is unlocked
+        if (fs_mgr_is_device_unlocked()) {
+            retval = FS_MGR_SETUP_VERITY_SKIPPED;
+            LWARNING << "Allow signature verification error when the device is unlocked";
+            goto out;
+        }
         if (params.mode == VERITY_MODE_LOGGING) {
             // the user has been warned, allow mounting without dm-verity
-            retval = FS_MGR_SETUP_VERITY_SUCCESS;
+            retval = FS_MGR_SETUP_VERITY_SKIPPED;
             goto out;
         }
 
@@ -929,7 +935,7 @@
     }
 
     // make sure we've set everything up properly
-    if (wait_for_verity_dev && fs_mgr_test_access(fstab->blk_device) < 0) {
+    if (wait_for_verity_dev && !fs_mgr_wait_for_file(fstab->blk_device, 1s)) {
         goto out;
     }
 
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index d7cbfe1..15c8caf 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -83,12 +83,12 @@
                                       const char** filenames_mode_ret);
 int fs_mgr_is_convertible_to_fbe(const struct fstab_rec* fstab);
 int fs_mgr_is_noemulatedsd(const struct fstab_rec* fstab);
-int fs_mgr_is_notrim(struct fstab_rec* fstab);
-int fs_mgr_is_formattable(struct fstab_rec* fstab);
-int fs_mgr_is_slotselect(struct fstab_rec* fstab);
-int fs_mgr_is_nofail(struct fstab_rec* fstab);
-int fs_mgr_is_latemount(struct fstab_rec* fstab);
-int fs_mgr_is_quota(struct fstab_rec* fstab);
+int fs_mgr_is_notrim(const struct fstab_rec* fstab);
+int fs_mgr_is_formattable(const struct fstab_rec* fstab);
+int fs_mgr_is_slotselect(const struct fstab_rec* fstab);
+int fs_mgr_is_nofail(const struct fstab_rec* fstab);
+int fs_mgr_is_latemount(const struct fstab_rec* fstab);
+int fs_mgr_is_quota(const struct fstab_rec* fstab);
 
 __END_DECLS
 
diff --git a/gatekeeperd/SoftGateKeeper.h b/gatekeeperd/SoftGateKeeper.h
index cb02a6f..92d1752 100644
--- a/gatekeeperd/SoftGateKeeper.h
+++ b/gatekeeperd/SoftGateKeeper.h
@@ -26,8 +26,8 @@
 }
 
 #include <android-base/memory.h>
-#include <UniquePtr.h>
 #include <gatekeeper/gatekeeper.h>
+#include <nativehelper/UniquePtr.h>
 
 #include <iostream>
 #include <unordered_map>
diff --git a/gatekeeperd/SoftGateKeeperDevice.h b/gatekeeperd/SoftGateKeeperDevice.h
index 3463c29..229f9a9 100644
--- a/gatekeeperd/SoftGateKeeperDevice.h
+++ b/gatekeeperd/SoftGateKeeperDevice.h
@@ -19,7 +19,7 @@
 
 #include "SoftGateKeeper.h"
 
-#include <UniquePtr.h>
+#include <nativehelper/UniquePtr.h>
 
 using namespace gatekeeper;
 
diff --git a/gatekeeperd/tests/gatekeeper_test.cpp b/gatekeeperd/tests/gatekeeper_test.cpp
index 47a8bfa..b3aea7b 100644
--- a/gatekeeperd/tests/gatekeeper_test.cpp
+++ b/gatekeeperd/tests/gatekeeper_test.cpp
@@ -19,7 +19,7 @@
 
 #include <gtest/gtest.h>
 #include <hardware/hw_auth_token.h>
-#include <UniquePtr.h>
+#include <nativehelper/UniquePtr.h>
 
 #include "../SoftGateKeeper.h"
 
diff --git a/healthd/Android.bp b/healthd/Android.bp
new file mode 100644
index 0000000..56f5148
--- /dev/null
+++ b/healthd/Android.bp
@@ -0,0 +1,7 @@
+cc_library_headers {
+    name: "libhealthd_headers",
+    vendor_available: true,
+    export_include_dirs: ["include"],
+    header_libs: ["libbatteryservice_headers"],
+    export_header_lib_headers: ["libbatteryservice_headers"],
+}
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 8b59964..6b14289 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -33,6 +33,30 @@
 
 include $(CLEAR_VARS)
 
+LOCAL_MODULE := libhealthd_draw
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+LOCAL_STATIC_LIBRARIES := \
+	libminui \
+	libbase
+LOCAL_SRC_FILES := healthd_draw.cpp
+
+ifneq ($(TARGET_HEALTHD_DRAW_SPLIT_SCREEN),)
+LOCAL_CFLAGS += -DHEALTHD_DRAW_SPLIT_SCREEN=$(TARGET_HEALTHD_DRAW_SPLIT_SCREEN)
+else
+LOCAL_CFLAGS += -DHEALTHD_DRAW_SPLIT_SCREEN=0
+endif
+
+ifneq ($(TARGET_HEALTHD_DRAW_SPLIT_OFFSET),)
+LOCAL_CFLAGS += -DHEALTHD_DRAW_SPLIT_OFFSET=$(TARGET_HEALTHD_DRAW_SPLIT_OFFSET)
+else
+LOCAL_CFLAGS += -DHEALTHD_DRAW_SPLIT_OFFSET=0
+endif
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
 LOCAL_CFLAGS := -Werror
 ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
 LOCAL_CFLAGS += -DCHARGER_DISABLE_INIT_BLANK
@@ -58,6 +82,7 @@
     libutils \
     libbase \
     libcutils \
+    libhealthd_draw \
     liblog \
     libm \
     libc \
@@ -101,6 +126,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
     libhealthd_charger \
+    libhealthd_draw \
     libbatterymonitor \
     libbase \
     libutils \
diff --git a/healthd/healthd_draw.cpp b/healthd/healthd_draw.cpp
new file mode 100644
index 0000000..ea3d991
--- /dev/null
+++ b/healthd/healthd_draw.cpp
@@ -0,0 +1,195 @@
+/*
+ * 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/stringprintf.h>
+#include <batteryservice/BatteryService.h>
+#include <cutils/klog.h>
+
+#include "healthd_draw.h"
+
+#define LOGE(x...) KLOG_ERROR("charger", x);
+#define LOGV(x...) KLOG_DEBUG("charger", x);
+
+HealthdDraw::HealthdDraw(animation* anim)
+  : kSplitScreen(HEALTHD_DRAW_SPLIT_SCREEN),
+    kSplitOffset(HEALTHD_DRAW_SPLIT_OFFSET) {
+  gr_init();
+  gr_font_size(gr_sys_font(), &char_width_, &char_height_);
+
+  screen_width_ = gr_fb_width() / (kSplitScreen ? 2 : 1);
+  screen_height_ = gr_fb_height();
+
+  int res;
+  if (!anim->text_clock.font_file.empty() &&
+      (res = gr_init_font(anim->text_clock.font_file.c_str(),
+                          &anim->text_clock.font)) < 0) {
+    LOGE("Could not load time font (%d)\n", res);
+  }
+  if (!anim->text_percent.font_file.empty() &&
+      (res = gr_init_font(anim->text_percent.font_file.c_str(),
+                          &anim->text_percent.font)) < 0) {
+    LOGE("Could not load percent font (%d)\n", res);
+  }
+}
+
+HealthdDraw::~HealthdDraw() {}
+
+void HealthdDraw::redraw_screen(const animation* batt_anim, GRSurface* surf_unknown) {
+  clear_screen();
+
+  /* try to display *something* */
+  if (batt_anim->cur_level < 0 || batt_anim->num_frames == 0)
+    draw_unknown(surf_unknown);
+  else
+    draw_battery(batt_anim);
+  gr_flip();
+}
+
+void HealthdDraw::blank_screen(bool blank) { gr_fb_blank(blank); }
+
+void HealthdDraw::clear_screen(void) {
+  gr_color(0, 0, 0, 255);
+  gr_clear();
+}
+
+int HealthdDraw::draw_surface_centered(GRSurface* surface) {
+  int w = gr_get_width(surface);
+  int h = gr_get_height(surface);
+  int x = (screen_width_ - w) / 2 + kSplitOffset;
+  int y = (screen_height_ - h) / 2;
+
+  LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
+  gr_blit(surface, 0, 0, w, h, x, y);
+  if (kSplitScreen) {
+    x += screen_width_ - 2 * kSplitOffset;
+    LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
+    gr_blit(surface, 0, 0, w, h, x, y);
+  }
+
+  return y + h;
+}
+
+int HealthdDraw::draw_text(const GRFont* font, int x, int y, const char* str) {
+  int str_len_px = gr_measure(font, str);
+
+  if (x < 0) x = (screen_width_ - str_len_px) / 2;
+  if (y < 0) y = (screen_height_ - char_height_) / 2;
+  gr_text(font, x + kSplitOffset, y, str, false /* bold */);
+  if (kSplitScreen)
+    gr_text(font, x - kSplitOffset + screen_width_, y, str, false /* bold */);
+
+  return y + char_height_;
+}
+
+void HealthdDraw::determine_xy(const animation::text_field& field,
+                               const int length, int* x, int* y) {
+  *x = field.pos_x;
+
+  int str_len_px = length * field.font->char_width;
+  if (field.pos_x == CENTER_VAL) {
+    *x = (screen_width_ - str_len_px) / 2;
+  } else if (field.pos_x >= 0) {
+    *x = field.pos_x;
+  } else {  // position from max edge
+    *x = screen_width_ + field.pos_x - str_len_px - kSplitOffset;
+  }
+
+  *y = field.pos_y;
+
+  if (field.pos_y == CENTER_VAL) {
+    *y = (screen_height_ - field.font->char_height) / 2;
+  } else if (field.pos_y >= 0) {
+    *y = field.pos_y;
+  } else {  // position from max edge
+    *y = screen_height_ + field.pos_y - field.font->char_height;
+  }
+}
+
+void HealthdDraw::draw_clock(const animation* anim) {
+  static constexpr char CLOCK_FORMAT[] = "%H:%M";
+  static constexpr int CLOCK_LENGTH = 6;
+
+  const animation::text_field& field = anim->text_clock;
+
+  if (field.font == nullptr || field.font->char_width == 0 ||
+      field.font->char_height == 0)
+    return;
+
+  time_t rawtime;
+  time(&rawtime);
+  tm* time_info = localtime(&rawtime);
+
+  char clock_str[CLOCK_LENGTH];
+  size_t length = strftime(clock_str, CLOCK_LENGTH, CLOCK_FORMAT, time_info);
+  if (length != CLOCK_LENGTH - 1) {
+    LOGE("Could not format time\n");
+    return;
+  }
+
+  int x, y;
+  determine_xy(field, length, &x, &y);
+
+  LOGV("drawing clock %s %d %d\n", clock_str, x, y);
+  gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
+  draw_text(field.font, x, y, clock_str);
+}
+
+void HealthdDraw::draw_percent(const animation* anim) {
+  int cur_level = anim->cur_level;
+  if (anim->cur_status == BATTERY_STATUS_FULL) {
+    cur_level = 100;
+  }
+
+  if (cur_level <= 0) return;
+
+  const animation::text_field& field = anim->text_percent;
+  if (field.font == nullptr || field.font->char_width == 0 ||
+      field.font->char_height == 0) {
+    return;
+  }
+
+  std::string str = base::StringPrintf("%d%%", cur_level);
+
+  int x, y;
+  determine_xy(field, str.size(), &x, &y);
+
+  LOGV("drawing percent %s %d %d\n", str.c_str(), x, y);
+  gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
+  draw_text(field.font, x, y, str.c_str());
+}
+
+void HealthdDraw::draw_battery(const animation* anim) {
+  const animation::frame& frame = anim->frames[anim->cur_frame];
+
+  if (anim->num_frames != 0) {
+    draw_surface_centered(frame.surface);
+    LOGV("drawing frame #%d min_cap=%d time=%d\n", anim->cur_frame,
+         frame.min_level, frame.disp_time);
+  }
+  draw_clock(anim);
+  draw_percent(anim);
+}
+
+void HealthdDraw::draw_unknown(GRSurface* surf_unknown) {
+  int y;
+  if (surf_unknown) {
+    draw_surface_centered(surf_unknown);
+  } else {
+    gr_color(0xa4, 0xc6, 0x39, 255);
+    y = draw_text(gr_sys_font(), -1, -1, "Charging!");
+    draw_text(gr_sys_font(), -1, y + 25, "?\?/100");
+  }
+}
diff --git a/healthd/healthd_draw.h b/healthd/healthd_draw.h
new file mode 100644
index 0000000..6a6ba76
--- /dev/null
+++ b/healthd/healthd_draw.h
@@ -0,0 +1,75 @@
+/*
+ * 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 HEALTHD_DRAW_H
+#define HEALTHD_DRAW_H
+
+#include <linux/input.h>
+#include <minui/minui.h>
+
+#include "animation.h"
+
+using namespace android;
+
+class HealthdDraw {
+ public:
+  // Configures font using given animation.
+  HealthdDraw(animation* anim);
+  virtual ~HealthdDraw();
+
+  // Redraws screen.
+  void redraw_screen(const animation* batt_anim, GRSurface* surf_unknown);
+
+  // Blanks screen if true, unblanks if false.
+  virtual void blank_screen(bool blank);
+
+ protected:
+  virtual void clear_screen();
+
+  // returns the last y-offset of where the surface ends.
+  virtual int draw_surface_centered(GRSurface* surface);
+  // Negative x or y coordinates center text.
+  virtual int draw_text(const GRFont* font, int x, int y, const char* str);
+
+  // Negative x or y coordinates position the text away from the opposite edge
+  // that positive ones do.
+  virtual void determine_xy(const animation::text_field& field,
+                            const int length, int* x, int* y);
+
+  // Draws battery animation, if it exists.
+  virtual void draw_battery(const animation* anim);
+  // Draws clock text, if animation contains text_field data.
+  virtual void draw_clock(const animation* anim);
+  // Draws battery percentage text if animation contains text_field data.
+  virtual void draw_percent(const animation* anim);
+  // Draws charger->surf_unknown or basic text.
+  virtual void draw_unknown(GRSurface* surf_unknown);
+
+  // Pixel sizes of characters for default font.
+  int char_width_;
+  int char_height_;
+
+  // Width and height of screen in pixels.
+  int screen_width_;
+  int screen_height_;
+
+  // Device screen is split vertically.
+  const bool kSplitScreen;
+  // Pixels to offset graphics towards center split.
+  const int kSplitOffset;
+};
+
+#endif  // HEALTHD_DRAW_H
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index c76762d..6c6d738 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2013 The Android Open Source Project
+ * Copyright (C) 2011-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.
@@ -18,7 +18,6 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
-#include <linux/input.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -34,56 +33,54 @@
 
 #include <android-base/file.h>
 #include <android-base/macros.h>
-#include <android-base/stringprintf.h>
 
-#include <sys/socket.h>
 #include <linux/netlink.h>
+#include <sys/socket.h>
 
-#include <batteryservice/BatteryService.h>
 #include <cutils/klog.h>
 #include <cutils/misc.h>
-#include <cutils/uevent.h>
 #include <cutils/properties.h>
-#include <minui/minui.h>
+#include <cutils/uevent.h>
 #include <sys/reboot.h>
 
 #ifdef CHARGER_ENABLE_SUSPEND
 #include <suspend/autosuspend.h>
 #endif
 
-#include "animation.h"
 #include "AnimationParser.h"
+#include "healthd_draw.h"
 
 #include <healthd/healthd.h>
 
 using namespace android;
 
-char *locale;
+char* locale;
 
 #ifndef max
-#define max(a,b) ((a) > (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
 #endif
 
 #ifndef min
-#define min(a,b) ((a) < (b) ? (a) : (b))
+#define min(a, b) ((a) < (b) ? (a) : (b))
 #endif
 
-#define ARRAY_SIZE(x)           (sizeof(x)/sizeof((x)[0]))
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
-#define MSEC_PER_SEC            (1000LL)
-#define NSEC_PER_MSEC           (1000000LL)
+#define MSEC_PER_SEC (1000LL)
+#define NSEC_PER_MSEC (1000000LL)
 
-#define BATTERY_UNKNOWN_TIME    (2 * MSEC_PER_SEC)
-#define POWER_ON_KEY_TIME       (2 * MSEC_PER_SEC)
+#define BATTERY_UNKNOWN_TIME (2 * MSEC_PER_SEC)
+#define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC)
 #define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
 
-#define LAST_KMSG_MAX_SZ        (32 * 1024)
+#define LAST_KMSG_MAX_SZ (32 * 1024)
 
-#define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0)
-#define LOGW(x...) do { KLOG_WARNING("charger", x); } while (0)
-#define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
+#define LOGE(x...) KLOG_ERROR("charger", x);
+#define LOGW(x...) KLOG_WARNING("charger", x);
+#define LOGV(x...) KLOG_DEBUG("charger", x);
 
-static constexpr const char* animation_desc_path = "/res/values/charger/animation.txt";
+static constexpr const char* animation_desc_path =
+    "/res/values/charger/animation.txt";
 
 struct key_state {
     bool pending;
@@ -98,34 +95,36 @@
     int64_t next_key_check;
     int64_t next_pwr_check;
 
-    struct key_state keys[KEY_MAX + 1];
+    key_state keys[KEY_MAX + 1];
 
-    struct animation *batt_anim;
+    animation* batt_anim;
     GRSurface* surf_unknown;
     int boot_min_cap;
 };
 
-static const struct animation BASE_ANIMATION = {
-    .text_clock = {
-        .pos_x = 0,
-        .pos_y = 0,
+static const animation BASE_ANIMATION = {
+    .text_clock =
+        {
+            .pos_x = 0,
+            .pos_y = 0,
 
-        .color_r = 255,
-        .color_g = 255,
-        .color_b = 255,
-        .color_a = 255,
+            .color_r = 255,
+            .color_g = 255,
+            .color_b = 255,
+            .color_a = 255,
 
-        .font = nullptr,
-    },
-    .text_percent = {
-        .pos_x = 0,
-        .pos_y = 0,
+            .font = nullptr,
+        },
+    .text_percent =
+        {
+            .pos_x = 0,
+            .pos_y = 0,
 
-        .color_r = 255,
-        .color_g = 255,
-        .color_b = 255,
-        .color_a = 255,
-    },
+            .color_r = 255,
+            .color_g = 255,
+            .color_b = 255,
+            .color_a = 255,
+        },
 
     .run = false,
 
@@ -141,8 +140,7 @@
     .cur_status = BATTERY_STATUS_UNKNOWN,
 };
 
-
-static struct animation::frame default_animation_frames[] = {
+static animation::frame default_animation_frames[] = {
     {
         .disp_time = 750,
         .min_level = 0,
@@ -181,35 +179,25 @@
     },
 };
 
-static struct animation battery_animation = BASE_ANIMATION;
+static animation battery_animation = BASE_ANIMATION;
 
-static struct charger charger_state;
-static struct healthd_config *healthd_config;
-static struct android::BatteryProperties *batt_prop;
-static int char_width;
-static int char_height;
-static bool minui_inited;
+static charger charger_state;
+static healthd_config* healthd_config;
+static android::BatteryProperties* batt_prop;
+static std::unique_ptr<HealthdDraw> healthd_draw;
 
 /* current time in milliseconds */
-static int64_t curr_time_ms(void)
-{
-    struct timespec tm;
+static int64_t curr_time_ms() {
+    timespec tm;
     clock_gettime(CLOCK_MONOTONIC, &tm);
     return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC);
 }
 
-static void clear_screen(void)
-{
-    gr_color(0, 0, 0, 255);
-    gr_clear();
-}
-
 #define MAX_KLOG_WRITE_BUF_SZ 256
 
-static void dump_last_kmsg(void)
-{
-    char *buf;
-    char *ptr;
+static void dump_last_kmsg(void) {
+    char* buf;
+    char* ptr;
     unsigned sz = 0;
     int len;
 
@@ -239,11 +227,10 @@
     while (len > 0) {
         int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
         char yoink;
-        char *nl;
+        char* nl;
 
-        nl = (char *)memrchr(ptr, '\n', cnt - 1);
-        if (nl)
-            cnt = nl - ptr + 1;
+        nl = (char*)memrchr(ptr, '\n', cnt - 1);
+        if (nl) cnt = nl - ptr + 1;
 
         yoink = ptr[cnt];
         ptr[cnt] = '\0';
@@ -263,241 +250,59 @@
 }
 
 #ifdef CHARGER_ENABLE_SUSPEND
-static int request_suspend(bool enable)
-{
+static int request_suspend(bool enable) {
     if (enable)
         return autosuspend_enable();
     else
         return autosuspend_disable();
 }
 #else
-static int request_suspend(bool /*enable*/)
-{
+static int request_suspend(bool /*enable*/) {
     return 0;
 }
 #endif
 
-static int draw_text(const char *str, int x, int y)
-{
-    int str_len_px = gr_measure(gr_sys_font(), str);
-
-    if (x < 0)
-        x = (gr_fb_width() - str_len_px) / 2;
-    if (y < 0)
-        y = (gr_fb_height() - char_height) / 2;
-    gr_text(gr_sys_font(), x, y, str, 0);
-
-    return y + char_height;
-}
-
-static void android_green(void)
-{
-    gr_color(0xa4, 0xc6, 0x39, 255);
-}
-
-// Negative x or y coordinates position the text away from the opposite edge that positive ones do.
-void determine_xy(const animation::text_field& field, const int length, int* x, int* y)
-{
-    *x = field.pos_x;
-    *y = field.pos_y;
-
-    int str_len_px = length * field.font->char_width;
-    if (field.pos_x == CENTER_VAL) {
-        *x = (gr_fb_width() - str_len_px) / 2;
-    } else if (field.pos_x >= 0) {
-        *x = field.pos_x;
-    } else {  // position from max edge
-        *x = gr_fb_width() + field.pos_x - str_len_px;
-    }
-
-    if (field.pos_y == CENTER_VAL) {
-        *y = (gr_fb_height() - field.font->char_height) / 2;
-    } else if (field.pos_y >= 0) {
-        *y = field.pos_y;
-    } else {  // position from max edge
-        *y = gr_fb_height() + field.pos_y - field.font->char_height;
-    }
-}
-
-static void draw_clock(const animation& anim)
-{
-    static constexpr char CLOCK_FORMAT[] = "%H:%M";
-    static constexpr int CLOCK_LENGTH = 6;
-
-    const animation::text_field& field = anim.text_clock;
-
-    if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) return;
-
-    time_t rawtime;
-    time(&rawtime);
-    struct tm* time_info = localtime(&rawtime);
-
-    char clock_str[CLOCK_LENGTH];
-    size_t length = strftime(clock_str, CLOCK_LENGTH, CLOCK_FORMAT, time_info);
-    if (length != CLOCK_LENGTH - 1) {
-        LOGE("Could not format time\n");
-        return;
-    }
-
-    int x, y;
-    determine_xy(field, length, &x, &y);
-
-    LOGV("drawing clock %s %d %d\n", clock_str, x, y);
-    gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
-    gr_text(field.font, x, y, clock_str, false);
-}
-
-static void draw_percent(const animation& anim)
-{
-    int cur_level = anim.cur_level;
-    if (anim.cur_status == BATTERY_STATUS_FULL) {
-        cur_level = 100;
-    }
-
-    if (cur_level <= 0) return;
-
-    const animation::text_field& field = anim.text_percent;
-    if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) {
-        return;
-    }
-
-    std::string str = base::StringPrintf("%d%%", cur_level);
-
-    int x, y;
-    determine_xy(field, str.size(), &x, &y);
-
-    LOGV("drawing percent %s %d %d\n", str.c_str(), x, y);
-    gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
-    gr_text(field.font, x, y, str.c_str(), false);
-}
-
-/* returns the last y-offset of where the surface ends */
-static int draw_surface_centered(GRSurface* surface)
-{
-    int w;
-    int h;
-    int x;
-    int y;
-
-    w = gr_get_width(surface);
-    h = gr_get_height(surface);
-    x = (gr_fb_width() - w) / 2 ;
-    y = (gr_fb_height() - h) / 2 ;
-
-    LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
-    gr_blit(surface, 0, 0, w, h, x, y);
-    return y + h;
-}
-
-static void draw_unknown(struct charger *charger)
-{
-    int y;
-    if (charger->surf_unknown) {
-        draw_surface_centered(charger->surf_unknown);
-    } else {
-        android_green();
-        y = draw_text("Charging!", -1, -1);
-        draw_text("?\?/100", -1, y + 25);
-    }
-}
-
-static void draw_battery(const struct charger* charger)
-{
-    const struct animation& anim = *charger->batt_anim;
-    const struct animation::frame& frame = anim.frames[anim.cur_frame];
-
-    if (anim.num_frames != 0) {
-        draw_surface_centered(frame.surface);
-        LOGV("drawing frame #%d min_cap=%d time=%d\n",
-             anim.cur_frame, frame.min_level,
-             frame.disp_time);
-    }
-    draw_clock(anim);
-    draw_percent(anim);
-}
-
-static void redraw_screen(struct charger *charger)
-{
-    struct animation *batt_anim = charger->batt_anim;
-
-    clear_screen();
-
-    /* try to display *something* */
-    if (batt_anim->cur_level < 0 || batt_anim->num_frames == 0)
-        draw_unknown(charger);
-    else
-        draw_battery(charger);
-    gr_flip();
-}
-
-static void kick_animation(struct animation *anim)
-{
+static void kick_animation(animation* anim) {
     anim->run = true;
 }
 
-static void reset_animation(struct animation *anim)
-{
+static void reset_animation(animation* anim) {
     anim->cur_cycle = 0;
     anim->cur_frame = 0;
     anim->run = false;
 }
 
-static void init_status_display(struct animation* anim)
-{
-    int res;
-
-    if (!anim->text_clock.font_file.empty()) {
-        if ((res =
-                gr_init_font(anim->text_clock.font_file.c_str(), &anim->text_clock.font)) < 0) {
-            LOGE("Could not load time font (%d)\n", res);
-        }
-    }
-
-    if (!anim->text_percent.font_file.empty()) {
-        if ((res =
-                gr_init_font(anim->text_percent.font_file.c_str(), &anim->text_percent.font)) < 0) {
-            LOGE("Could not load percent font (%d)\n", res);
-        }
-    }
-}
-
-static void update_screen_state(struct charger *charger, int64_t now)
-{
-    struct animation *batt_anim = charger->batt_anim;
+static void update_screen_state(charger* charger, int64_t now) {
+    animation* batt_anim = charger->batt_anim;
     int disp_time;
 
     if (!batt_anim->run || now < charger->next_screen_transition) return;
 
-    if (!minui_inited) {
+    if (healthd_draw == nullptr) {
         if (healthd_config && healthd_config->screen_on) {
             if (!healthd_config->screen_on(batt_prop)) {
                 LOGV("[%" PRId64 "] leave screen off\n", now);
                 batt_anim->run = false;
                 charger->next_screen_transition = -1;
-                if (charger->charger_connected)
-                    request_suspend(true);
+                if (charger->charger_connected) request_suspend(true);
                 return;
             }
         }
 
-        gr_init();
-        gr_font_size(gr_sys_font(), &char_width, &char_height);
-        init_status_display(batt_anim);
+        healthd_draw.reset(new HealthdDraw(batt_anim));
 
 #ifndef CHARGER_DISABLE_INIT_BLANK
-        gr_fb_blank(true);
+        healthd_draw->blank_screen(true);
 #endif
-        minui_inited = true;
     }
 
     /* animation is over, blank screen and leave */
     if (batt_anim->num_cycles > 0 && batt_anim->cur_cycle == batt_anim->num_cycles) {
         reset_animation(batt_anim);
         charger->next_screen_transition = -1;
-        gr_fb_blank(true);
+        healthd_draw->blank_screen(true);
         LOGV("[%" PRId64 "] animation done\n", now);
-        if (charger->charger_connected)
-            request_suspend(true);
+        if (charger->charger_connected) request_suspend(true);
         return;
     }
 
@@ -505,7 +310,6 @@
 
     /* animation starting, set up the animation */
     if (batt_anim->cur_frame == 0) {
-
         LOGV("[%" PRId64 "] animation starting\n", now);
         if (batt_prop) {
             batt_anim->cur_level = batt_prop->batteryLevel;
@@ -522,17 +326,16 @@
 
                 // repeat the first frame first_frame_repeats times
                 disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time *
-                    batt_anim->first_frame_repeats;
+                            batt_anim->first_frame_repeats;
             }
         }
     }
 
     /* unblank the screen  on first cycle */
-    if (batt_anim->cur_cycle == 0)
-        gr_fb_blank(false);
+    if (batt_anim->cur_cycle == 0) healthd_draw->blank_screen(false);
 
     /* draw the new frame (@ cur_frame) */
-    redraw_screen(charger);
+    healthd_draw->redraw_screen(charger->batt_anim, charger->surf_unknown);
 
     /* if we don't have anim frames, we only have one image, so just bump
      * the cycle counter and exit
@@ -576,22 +379,18 @@
     }
 }
 
-static int set_key_callback(struct charger *charger, int code, int value)
-{
+static int set_key_callback(charger* charger, int code, int value) {
     int64_t now = curr_time_ms();
     int down = !!value;
 
-    if (code > KEY_MAX)
-        return -1;
+    if (code > KEY_MAX) return -1;
 
     /* ignore events that don't modify our state */
-    if (charger->keys[code].down == down)
-        return 0;
+    if (charger->keys[code].down == down) return 0;
 
     /* only record the down even timestamp, as the amount
      * of time the key spent not being pressed is not useful */
-    if (down)
-        charger->keys[code].timestamp = now;
+    if (down) charger->keys[code].timestamp = now;
     charger->keys[code].down = down;
     charger->keys[code].pending = true;
     if (down) {
@@ -600,34 +399,27 @@
         int64_t duration = now - charger->keys[code].timestamp;
         int64_t secs = duration / 1000;
         int64_t msecs = duration - secs * 1000;
-        LOGV("[%" PRId64 "] key[%d] up (was down for %" PRId64 ".%" PRId64 "sec)\n",
-             now, code, secs, msecs);
+        LOGV("[%" PRId64 "] key[%d] up (was down for %" PRId64 ".%" PRId64 "sec)\n", now, code,
+             secs, msecs);
     }
 
     return 0;
 }
 
-static void update_input_state(struct charger *charger,
-                               struct input_event *ev)
-{
-    if (ev->type != EV_KEY)
-        return;
+static void update_input_state(charger* charger, input_event* ev) {
+    if (ev->type != EV_KEY) return;
     set_key_callback(charger, ev->code, ev->value);
 }
 
-static void set_next_key_check(struct charger *charger,
-                               struct key_state *key,
-                               int64_t timeout)
-{
+static void set_next_key_check(charger* charger, key_state* key, int64_t timeout) {
     int64_t then = key->timestamp + timeout;
 
     if (charger->next_key_check == -1 || then < charger->next_key_check)
         charger->next_key_check = then;
 }
 
-static void process_key(struct charger *charger, int code, int64_t now)
-{
-    struct key_state *key = &charger->keys[code];
+static void process_key(charger* charger, int code, int64_t now) {
+    key_state* key = &charger->keys[code];
 
     if (code == KEY_POWER) {
         if (key->down) {
@@ -644,8 +436,10 @@
                         LOGW("[%" PRId64 "] rebooting\n", now);
                         reboot(RB_AUTOBOOT);
                     } else {
-                        LOGV("[%" PRId64 "] ignore power-button press, battery level "
-                            "less than minimum\n", now);
+                        LOGV("[%" PRId64
+                             "] ignore power-button press, battery level "
+                             "less than minimum\n",
+                             now);
                     }
                 }
             } else {
@@ -654,9 +448,9 @@
                  */
                 set_next_key_check(charger, key, POWER_ON_KEY_TIME);
 
-               /* Turn on the display and kick animation on power-key press
-                * rather than on key release
-                */
+                /* Turn on the display and kick animation on power-key press
+                 * rather than on key release
+                 */
                 kick_animation(charger->batt_anim);
                 request_suspend(false);
             }
@@ -671,21 +465,17 @@
     key->pending = false;
 }
 
-static void handle_input_state(struct charger *charger, int64_t now)
-{
+static void handle_input_state(charger* charger, int64_t now) {
     process_key(charger, KEY_POWER, now);
 
     if (charger->next_key_check != -1 && now > charger->next_key_check)
         charger->next_key_check = -1;
 }
 
-static void handle_power_supply_state(struct charger *charger, int64_t now)
-{
-    if (!charger->have_battery_state)
-        return;
+static void handle_power_supply_state(charger* charger, int64_t now) {
+    if (!charger->have_battery_state) return;
 
     if (!charger->charger_connected) {
-
         /* Last cycle would have stopped at the extreme top of battery-icon
          * Need to show the correct level corresponding to capacity.
          */
@@ -711,9 +501,8 @@
     }
 }
 
-void healthd_mode_charger_heartbeat()
-{
-    struct charger *charger = &charger_state;
+void healthd_mode_charger_heartbeat() {
+    charger* charger = &charger_state;
     int64_t now = curr_time_ms();
 
     handle_input_state(charger, now);
@@ -725,14 +514,11 @@
     update_screen_state(charger, now);
 }
 
-void healthd_mode_charger_battery_update(
-    struct android::BatteryProperties *props)
-{
-    struct charger *charger = &charger_state;
+void healthd_mode_charger_battery_update(android::BatteryProperties* props) {
+    charger* charger = &charger_state;
 
     charger->charger_connected =
-        props->chargerAcOnline || props->chargerUsbOnline ||
-        props->chargerWirelessOnline;
+        props->chargerAcOnline || props->chargerUsbOnline || props->chargerWirelessOnline;
 
     if (!charger->have_battery_state) {
         charger->have_battery_state = true;
@@ -743,19 +529,16 @@
     batt_prop = props;
 }
 
-int healthd_mode_charger_preparetowait(void)
-{
-    struct charger *charger = &charger_state;
+int healthd_mode_charger_preparetowait(void) {
+    charger* charger = &charger_state;
     int64_t now = curr_time_ms();
     int64_t next_event = INT64_MAX;
     int64_t timeout;
 
-    LOGV("[%" PRId64 "] next screen: %" PRId64 " next key: %" PRId64 " next pwr: %" PRId64 "\n", now,
-         charger->next_screen_transition, charger->next_key_check,
-         charger->next_pwr_check);
+    LOGV("[%" PRId64 "] next screen: %" PRId64 " next key: %" PRId64 " next pwr: %" PRId64 "\n",
+         now, charger->next_screen_transition, charger->next_key_check, charger->next_pwr_check);
 
-    if (charger->next_screen_transition != -1)
-        next_event = charger->next_screen_transition;
+    if (charger->next_screen_transition != -1) next_event = charger->next_screen_transition;
     if (charger->next_key_check != -1 && charger->next_key_check < next_event)
         next_event = charger->next_key_check;
     if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event)
@@ -766,32 +549,27 @@
     else
         timeout = -1;
 
-   return (int)timeout;
+    return (int)timeout;
 }
 
-static int input_callback(struct charger *charger, int fd, unsigned int epevents)
-{
-    struct input_event ev;
+static int input_callback(charger* charger, int fd, unsigned int epevents) {
+    input_event ev;
     int ret;
 
     ret = ev_get_input(fd, epevents, &ev);
-    if (ret)
-        return -1;
+    if (ret) return -1;
     update_input_state(charger, &ev);
     return 0;
 }
 
-static void charger_event_handler(uint32_t /*epevents*/)
-{
+static void charger_event_handler(uint32_t /*epevents*/) {
     int ret;
 
     ret = ev_wait(-1);
-    if (!ret)
-        ev_dispatch();
+    if (!ret) ev_dispatch();
 }
 
-animation* init_animation()
-{
+animation* init_animation() {
     bool parse_success;
 
     std::string content;
@@ -814,32 +592,29 @@
     }
 
     LOGV("Animation Description:\n");
-    LOGV("  animation: %d %d '%s' (%d)\n",
-        battery_animation.num_cycles, battery_animation.first_frame_repeats,
-        battery_animation.animation_file.c_str(), battery_animation.num_frames);
+    LOGV("  animation: %d %d '%s' (%d)\n", battery_animation.num_cycles,
+         battery_animation.first_frame_repeats, battery_animation.animation_file.c_str(),
+         battery_animation.num_frames);
     LOGV("  fail_file: '%s'\n", battery_animation.fail_file.c_str());
-    LOGV("  clock: %d %d %d %d %d %d '%s'\n",
-        battery_animation.text_clock.pos_x, battery_animation.text_clock.pos_y,
-        battery_animation.text_clock.color_r, battery_animation.text_clock.color_g,
-        battery_animation.text_clock.color_b, battery_animation.text_clock.color_a,
-        battery_animation.text_clock.font_file.c_str());
-    LOGV("  percent: %d %d %d %d %d %d '%s'\n",
-        battery_animation.text_percent.pos_x, battery_animation.text_percent.pos_y,
-        battery_animation.text_percent.color_r, battery_animation.text_percent.color_g,
-        battery_animation.text_percent.color_b, battery_animation.text_percent.color_a,
-        battery_animation.text_percent.font_file.c_str());
+    LOGV("  clock: %d %d %d %d %d %d '%s'\n", battery_animation.text_clock.pos_x,
+         battery_animation.text_clock.pos_y, battery_animation.text_clock.color_r,
+         battery_animation.text_clock.color_g, battery_animation.text_clock.color_b,
+         battery_animation.text_clock.color_a, battery_animation.text_clock.font_file.c_str());
+    LOGV("  percent: %d %d %d %d %d %d '%s'\n", battery_animation.text_percent.pos_x,
+         battery_animation.text_percent.pos_y, battery_animation.text_percent.color_r,
+         battery_animation.text_percent.color_g, battery_animation.text_percent.color_b,
+         battery_animation.text_percent.color_a, battery_animation.text_percent.font_file.c_str());
     for (int i = 0; i < battery_animation.num_frames; i++) {
         LOGV("  frame %.2d: %d %d %d\n", i, battery_animation.frames[i].disp_time,
-            battery_animation.frames[i].min_level, battery_animation.frames[i].max_level);
+             battery_animation.frames[i].min_level, battery_animation.frames[i].max_level);
     }
 
     return &battery_animation;
 }
 
-void healthd_mode_charger_init(struct healthd_config* config)
-{
+void healthd_mode_charger_init(struct healthd_config* config) {
     int ret;
-    struct charger *charger = &charger_state;
+    charger* charger = &charger_state;
     int i;
     int epollfd;
 
@@ -847,14 +622,13 @@
 
     LOGW("--------------- STARTING CHARGER MODE ---------------\n");
 
-    ret = ev_init(std::bind(&input_callback, charger, std::placeholders::_1,
-                            std::placeholders::_2));
+    ret = ev_init(std::bind(&input_callback, charger, std::placeholders::_1, std::placeholders::_2));
     if (!ret) {
         epollfd = ev_get_epollfd();
         healthd_register_event(epollfd, charger_event_handler, EVENT_WAKEUP_FD);
     }
 
-    struct animation* anim = init_animation();
+    animation* anim = init_animation();
     charger->batt_anim = anim;
 
     ret = res_create_display_surface(anim->fail_file.c_str(), &charger->surf_unknown);
@@ -871,15 +645,15 @@
     int scale_count;
     int scale_fps;  // Not in use (charger/battery_scale doesn't have FPS text
                     // chunk). We are using hard-coded frame.disp_time instead.
-    ret = res_create_multi_display_surface(anim->animation_file.c_str(),
-        &scale_count, &scale_fps, &scale_frames);
+    ret = res_create_multi_display_surface(anim->animation_file.c_str(), &scale_count, &scale_fps,
+                                           &scale_frames);
     if (ret < 0) {
         LOGE("Cannot load battery_scale image\n");
         anim->num_frames = 0;
         anim->num_cycles = 1;
     } else if (scale_count != anim->num_frames) {
-        LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
-             scale_count, anim->num_frames);
+        LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n", scale_count,
+             anim->num_frames);
         anim->num_frames = 0;
         anim->num_cycles = 1;
     } else {
@@ -887,8 +661,8 @@
             anim->frames[i].surface = scale_frames[i];
         }
     }
-    ev_sync_key_state(std::bind(&set_key_callback, charger, std::placeholders::_1,
-                                std::placeholders::_2));
+    ev_sync_key_state(
+        std::bind(&set_key_callback, charger, std::placeholders::_1, std::placeholders::_2));
 
     charger->next_screen_transition = -1;
     charger->next_key_check = -1;
diff --git a/include/ziparchive b/include/ziparchive
deleted file mode 120000
index d8fa424..0000000
--- a/include/ziparchive
+++ /dev/null
@@ -1 +0,0 @@
-../libziparchive/include/ziparchive
\ No newline at end of file
diff --git a/init/Android.bp b/init/Android.bp
index fce424e..8294598 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -94,6 +94,10 @@
 
     name: "init",
     defaults: ["init_defaults"],
+    required: [
+        "e2fsdroid",
+        "mke2fs",
+    ],
     static_executable: true,
     srcs: [
         "bootchart.cpp",
@@ -153,6 +157,7 @@
         "init_test.cpp",
         "property_service_test.cpp",
         "service_test.cpp",
+        "ueventd_test.cpp",
         "util_test.cpp",
     ],
     shared_libs: [
diff --git a/init/Android.mk b/init/Android.mk
index 8fc354a..9eb7649 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -28,6 +28,10 @@
 
 init_options += -DLOG_UEVENTS=0
 
+ifeq ($(TARGET_USER_MODE_LINUX), true)
+    init_cflags += -DUSER_MODE_LINUX
+endif
+
 init_cflags += \
     $(init_options) \
     -Wall -Wextra \
@@ -71,6 +75,7 @@
     libcutils \
     libbase \
     libc \
+    libseccomp_policy \
     libselinux \
     liblog \
     libcrypto_utils \
@@ -83,11 +88,14 @@
     libavb \
     libkeyutils \
 
+LOCAL_REQUIRED_MODULES := \
+    e2fsdroid \
+    mke2fs \
+
 # Create symlinks.
 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
     ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
     ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd
 
 LOCAL_SANITIZE := integer
-LOCAL_CLANG := true
 include $(BUILD_EXECUTABLE)
diff --git a/init/README.md b/init/README.md
index 72b6c6b..f3b57bc 100644
--- a/init/README.md
+++ b/init/README.md
@@ -260,6 +260,26 @@
 > Sets the child's /proc/self/oom\_score\_adj to the specified value,
   which must range from -1000 to 1000.
 
+`memcg.swappiness <value>`
+> Sets the child's memory.swappiness to the specified value (only if memcg is mounted),
+  which must be equal or greater than 0.
+
+`memcg.soft_limit_in_bytes <value>`
+> Sets the child's memory.soft_limit_in_bytes to the specified value (only if memcg is mounted),
+  which must be equal or greater than 0.
+
+`memcg.limit_in_bytes <value>`
+> Sets the child's memory.limit_in_bytes to the specified value (only if memcg is mounted),
+  which must be equal or greater than 0.
+
+`shutdown <shutdown_behavior>`
+> Set shutdown behavior of the service process. When this is not specified,
+  the service is killed during shutdown process by using SIGTERM and SIGKILL.
+  The service with shutdown_behavior of "critical" is not killed during shutdown
+  until shutdown times out. When shutdown times out, even services tagged with
+  "shutdown critical" will be killed. When the service tagged with "shutdown critical"
+  is not running when shut down starts, it will be started.
+
 
 Triggers
 --------
diff --git a/init/action.cpp b/init/action.cpp
index 6900391..4ec5f17 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -16,6 +16,7 @@
 
 #include "action.h"
 
+#include <android-base/chrono_utils.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android-base/strings.h>
@@ -90,19 +91,18 @@
 }
 
 void Action::ExecuteCommand(const Command& command) const {
-    Timer t;
+    android::base::Timer t;
     int result = command.InvokeFunc();
 
-    double duration_ms = t.duration_s() * 1000;
+    auto duration = t.duration();
     // Any action longer than 50ms will be warned to user as slow operation
-    if (duration_ms > 50.0 ||
-        android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
+    if (duration > 50ms || android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
         std::string trigger_name = BuildTriggersString();
         std::string cmd_str = command.BuildCommandString();
 
         LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << " (" << filename_
-                  << ":" << command.line() << ") returned " << result << " took " << duration_ms
-                  << "ms.";
+                  << ":" << command.line() << ") returned " << result << " took "
+                  << duration.count() << "ms.";
     }
 }
 
@@ -326,6 +326,13 @@
     }
 }
 
+void ActionManager::ClearQueue() {
+    // We are shutting down so don't claim the oneshot builtin actions back
+    current_executing_actions_ = {};
+    event_queue_ = {};
+    current_command_ = 0;
+}
+
 bool ActionParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,
                                 int line, std::string* err) {
     std::vector<std::string> triggers(args.begin() + 1, args.end());
diff --git a/init/action.h b/init/action.h
index 5cb50a7..ad15f3f 100644
--- a/init/action.h
+++ b/init/action.h
@@ -104,6 +104,7 @@
     void ExecuteOneCommand();
     bool HasMoreCommands() const;
     void DumpState() const;
+    void ClearQueue();
 
   private:
     ActionManager(ActionManager const&) = delete;
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 921ea94..56d0ae2 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -39,6 +39,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
@@ -119,7 +120,7 @@
         LOG(ERROR) << "failed to set bootloader message: " << err;
         return -1;
     }
-    DoReboot(ANDROID_RB_RESTART2, "reboot", "recovery", false);
+    property_set("sys.powerctl", "reboot,recovery");
     return 0;
 }
 
@@ -555,9 +556,9 @@
     }
 
     std::string prop_name = "ro.boottime.init.mount_all."s + prop_post_fix;
-    Timer t;
+    android::base::Timer t;
     int ret =  mount_fstab(fstabfile, mount_mode);
-    property_set(prop_name, std::to_string(t.duration_ms()));
+    property_set(prop_name, std::to_string(t.duration().count()));
 
     if (import_rc) {
         /* Paths of .rc files are specified at the 2nd argument and beyond */
diff --git a/init/devices.cpp b/init/devices.cpp
index 215d2ea..13cf991 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -219,7 +219,7 @@
     return {0600, 0, 0};
 }
 
-void DeviceHandler::MakeDevice(const std::string& path, int block, int major, int minor,
+void DeviceHandler::MakeDevice(const std::string& path, bool block, int major, int minor,
                                const std::vector<std::string>& links) const {
     auto[mode, uid, gid] = GetDevicePermissions(path, links);
     mode |= (block ? S_IFBLK : S_IFCHR);
@@ -279,45 +279,6 @@
     }
 }
 
-std::vector<std::string> DeviceHandler::GetCharacterDeviceSymlinks(const Uevent& uevent) const {
-    std::string parent_device;
-    if (!FindPlatformDevice(uevent.path, &parent_device)) return {};
-
-    // skip path to the parent driver
-    std::string path = uevent.path.substr(parent_device.length());
-
-    if (!StartsWith(path, "/usb")) return {};
-
-    // skip root hub name and device. use device interface
-    // skip 3 slashes, including the first / by starting the search at the 1st character, not 0th.
-    // then extract what comes between the 3rd and 4th slash
-    // e.g. "/usb/usb_device/name/tty2-1:1.0" -> "name"
-
-    std::string::size_type start = 0;
-    start = path.find('/', start + 1);
-    if (start == std::string::npos) return {};
-
-    start = path.find('/', start + 1);
-    if (start == std::string::npos) return {};
-
-    auto end = path.find('/', start + 1);
-    if (end == std::string::npos) return {};
-
-    start++;  // Skip the first '/'
-
-    auto length = end - start;
-    if (length == 0) return {};
-
-    auto name_string = path.substr(start, length);
-
-    std::vector<std::string> links;
-    links.emplace_back("/dev/usb/" + uevent.subsystem + name_string);
-
-    mkdir("/dev/usb", 0755);
-
-    return links;
-}
-
 // replaces any unacceptable characters with '_', the
 // length of the resulting string is equal to the input string
 void SanitizePartitionName(std::string* string) {
@@ -385,7 +346,7 @@
     return links;
 }
 
-void DeviceHandler::HandleDevice(const std::string& action, const std::string& devpath, int block,
+void DeviceHandler::HandleDevice(const std::string& action, const std::string& devpath, bool block,
                                  int major, int minor, const std::vector<std::string>& links) const {
     if (action == "add") {
         MakeDevice(devpath, block, major, minor, links);
@@ -411,31 +372,26 @@
     }
 }
 
-void DeviceHandler::HandleBlockDeviceEvent(const Uevent& uevent) const {
-    // if it's not a /dev device, nothing to do
-    if (uevent.major < 0 || uevent.minor < 0) return;
-
-    const char* base = "/dev/block/";
-    make_dir(base, 0755, sehandle_);
-
-    std::string name = Basename(uevent.path);
-    std::string devpath = base + name;
-
-    std::vector<std::string> links;
-    if (StartsWith(uevent.path, "/devices")) {
-        links = GetBlockDeviceSymlinks(uevent);
+void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) {
+    if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
+        FixupSysPermissions(uevent.path, uevent.subsystem);
     }
 
-    HandleDevice(uevent.action, devpath, 1, uevent.major, uevent.minor, links);
-}
-
-void DeviceHandler::HandleGenericDeviceEvent(const Uevent& uevent) const {
     // if it's not a /dev device, nothing to do
     if (uevent.major < 0 || uevent.minor < 0) return;
 
     std::string devpath;
+    std::vector<std::string> links;
+    bool block = false;
 
-    if (StartsWith(uevent.subsystem, "usb")) {
+    if (uevent.subsystem == "block") {
+        block = true;
+        devpath = "/dev/block/" + Basename(uevent.path);
+
+        if (StartsWith(uevent.path, "/devices")) {
+            links = GetBlockDeviceSymlinks(uevent);
+        }
+    } else if (StartsWith(uevent.subsystem, "usb")) {
         if (uevent.subsystem == "usb") {
             if (!uevent.device_name.empty()) {
                 devpath = "/dev/" + uevent.device_name;
@@ -461,21 +417,7 @@
 
     mkdir_recursive(Dirname(devpath), 0755, sehandle_);
 
-    auto links = GetCharacterDeviceSymlinks(uevent);
-
-    HandleDevice(uevent.action, devpath, 0, uevent.major, uevent.minor, links);
-}
-
-void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) {
-    if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
-        FixupSysPermissions(uevent.path, uevent.subsystem);
-    }
-
-    if (uevent.subsystem == "block") {
-        HandleBlockDeviceEvent(uevent);
-    } else {
-        HandleGenericDeviceEvent(uevent);
-    }
+    HandleDevice(uevent.action, devpath, block, uevent.major, uevent.minor, links);
 }
 
 DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions,
diff --git a/init/devices.h b/init/devices.h
index 5105ad7..c64f5fb 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -115,16 +115,12 @@
     bool FindPlatformDevice(std::string path, std::string* platform_device_path) const;
     std::tuple<mode_t, uid_t, gid_t> GetDevicePermissions(
         const std::string& path, const std::vector<std::string>& links) const;
-    void MakeDevice(const std::string& path, int block, int major, int minor,
+    void MakeDevice(const std::string& path, bool block, int major, int minor,
                     const std::vector<std::string>& links) const;
-    std::vector<std::string> GetCharacterDeviceSymlinks(const Uevent& uevent) const;
-    void HandleDevice(const std::string& action, const std::string& devpath, int block, int major,
+    void HandleDevice(const std::string& action, const std::string& devpath, bool block, int major,
                       int minor, const std::vector<std::string>& links) const;
     void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const;
 
-    void HandleBlockDeviceEvent(const Uevent& uevent) const;
-    void HandleGenericDeviceEvent(const Uevent& uevent) const;
-
     std::vector<Permissions> dev_permissions_;
     std::vector<SysfsPermissions> sysfs_permissions_;
     std::vector<Subsystem> subsystems_;
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
index 57d8e0f..ac4ab9b 100644
--- a/init/devices_test.cpp
+++ b/init/devices_test.cpp
@@ -30,7 +30,7 @@
 class DeviceHandlerTester {
   public:
     void TestGetSymlinks(const std::string& platform_device, const Uevent& uevent,
-                         const std::vector<std::string> expected_links, bool block) {
+                         const std::vector<std::string> expected_links) {
         TemporaryDir fake_sys_root;
         device_handler_.sysfs_mount_point_ = fake_sys_root.path;
 
@@ -44,11 +44,7 @@
         mkdir_recursive(android::base::Dirname(fake_sys_root.path + uevent.path), 0777, nullptr);
 
         std::vector<std::string> result;
-        if (block) {
-            result = device_handler_.GetBlockDeviceSymlinks(uevent);
-        } else {
-            result = device_handler_.GetCharacterDeviceSymlinks(uevent);
-        }
+        result = device_handler_.GetBlockDeviceSymlinks(uevent);
 
         auto expected_size = expected_links.size();
         ASSERT_EQ(expected_size, result.size());
@@ -64,95 +60,6 @@
     DeviceHandler device_handler_;
 };
 
-TEST(device_handler, get_character_device_symlinks_success) {
-    const char* platform_device = "/devices/platform/some_device_name";
-    Uevent uevent = {
-        .path = "/devices/platform/some_device_name/usb/usb_device/name/tty2-1:1.0",
-        .subsystem = "tty",
-    };
-    std::vector<std::string> expected_result{"/dev/usb/ttyname"};
-
-    DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_pdev_match) {
-    const char* platform_device = "/devices/platform/some_device_name";
-    Uevent uevent = {
-        .path = "/device/name/tty2-1:1.0", .subsystem = "tty",
-    };
-    std::vector<std::string> expected_result;
-
-    DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_nothing_after_platform_device) {
-    const char* platform_device = "/devices/platform/some_device_name";
-    Uevent uevent = {
-        .path = "/devices/platform/some_device_name", .subsystem = "tty",
-    };
-    std::vector<std::string> expected_result;
-
-    DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_usb_found) {
-    const char* platform_device = "/devices/platform/some_device_name";
-    Uevent uevent = {
-        .path = "/devices/platform/some_device_name/bad/bad/", .subsystem = "tty",
-    };
-    std::vector<std::string> expected_result;
-
-    DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_roothub) {
-    const char* platform_device = "/devices/platform/some_device_name";
-    Uevent uevent = {
-        .path = "/devices/platform/some_device_name/usb/", .subsystem = "tty",
-    };
-    std::vector<std::string> expected_result;
-
-    DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_usb_device) {
-    const char* platform_device = "/devices/platform/some_device_name";
-    Uevent uevent = {
-        .path = "/devices/platform/some_device_name/usb/usb_device/", .subsystem = "tty",
-    };
-    std::vector<std::string> expected_result;
-
-    DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_final_slash) {
-    const char* platform_device = "/devices/platform/some_device_name";
-    Uevent uevent = {
-        .path = "/devices/platform/some_device_name/usb/usb_device/name", .subsystem = "tty",
-    };
-    std::vector<std::string> expected_result;
-
-    DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_final_name) {
-    const char* platform_device = "/devices/platform/some_device_name";
-    Uevent uevent = {
-        .path = "/devices/platform/some_device_name/usb/usb_device//", .subsystem = "tty",
-    };
-    std::vector<std::string> expected_result;
-
-    DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
 TEST(device_handler, get_block_device_symlinks_success_platform) {
     // These are actual paths from bullhead
     const char* platform_device = "/devices/soc.0/f9824900.sdhci";
@@ -164,7 +71,7 @@
     std::vector<std::string> expected_result{"/dev/block/platform/soc.0/f9824900.sdhci/mmcblk0"};
 
     DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
 }
 
 TEST(device_handler, get_block_device_symlinks_success_platform_with_partition) {
@@ -182,7 +89,7 @@
     };
 
     DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
 }
 
 TEST(device_handler, get_block_device_symlinks_success_platform_with_partition_only_num) {
@@ -198,7 +105,7 @@
     };
 
     DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
 }
 
 TEST(device_handler, get_block_device_symlinks_success_platform_with_partition_only_name) {
@@ -214,7 +121,7 @@
     };
 
     DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
 }
 
 TEST(device_handler, get_block_device_symlinks_success_pci) {
@@ -225,7 +132,7 @@
     std::vector<std::string> expected_result{"/dev/block/pci/pci0000:00/0000:00:1f.2/mmcblk0"};
 
     DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
 }
 
 TEST(device_handler, get_block_device_symlinks_pci_bad_format) {
@@ -236,7 +143,7 @@
     std::vector<std::string> expected_result{};
 
     DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
 }
 
 TEST(device_handler, get_block_device_symlinks_success_vbd) {
@@ -247,7 +154,7 @@
     std::vector<std::string> expected_result{"/dev/block/vbd/1234/mmcblk0"};
 
     DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
 }
 
 TEST(device_handler, get_block_device_symlinks_vbd_bad_format) {
@@ -258,7 +165,7 @@
     std::vector<std::string> expected_result{};
 
     DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
 }
 
 TEST(device_handler, get_block_device_symlinks_no_matches) {
@@ -271,7 +178,7 @@
     std::vector<std::string> expected_result;
 
     DeviceHandlerTester device_handler_tester_;
-    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+    device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
 }
 
 TEST(device_handler, sanitize_null) {
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index 8cd5cc5..b686885 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -24,12 +24,12 @@
 #include <string>
 #include <thread>
 
+#include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 
-#include "util.h"
-
+using android::base::Timer;
 using android::base::unique_fd;
 using android::base::WriteFully;
 
@@ -110,31 +110,16 @@
     if (uevent.subsystem != "firmware" || uevent.action != "add") return;
 
     // Loading the firmware in a child means we can do that in parallel...
-    // We double fork instead of waiting for these processes.
-    pid_t pid = fork();
+    auto pid = fork();
     if (pid == -1) {
         PLOG(ERROR) << "could not fork to process firmware event for " << uevent.firmware;
-        return;
     }
-
     if (pid == 0) {
-        pid = fork();
-        if (pid == -1) {
-            PLOG(ERROR) << "could not fork a sceond time to process firmware event for "
-                        << uevent.firmware;
-            _exit(EXIT_FAILURE);
-        }
-        if (pid == 0) {
-            Timer t;
-            ProcessFirmwareEvent(uevent);
-            LOG(INFO) << "loading " << uevent.path << " took " << t;
-            _exit(EXIT_SUCCESS);
-        }
-
+        Timer t;
+        ProcessFirmwareEvent(uevent);
+        LOG(INFO) << "loading " << uevent.path << " took " << t;
         _exit(EXIT_SUCCESS);
     }
-
-    waitpid(pid, nullptr, 0);
 }
 
 }  // namespace init
diff --git a/init/init.cpp b/init/init.cpp
index ae878de..24f863c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -23,6 +23,7 @@
 #include <inttypes.h>
 #include <libgen.h>
 #include <paths.h>
+#include <seccomp_policy.h>
 #include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -73,6 +74,7 @@
 
 using android::base::boot_clock;
 using android::base::GetProperty;
+using android::base::Timer;
 
 namespace android {
 namespace init {
@@ -94,6 +96,7 @@
 static std::unique_ptr<Timer> waiting_for_prop(nullptr);
 static std::string wait_prop_name;
 static std::string wait_prop_value;
+static bool shutting_down;
 
 void DumpState() {
     ServiceManager::GetInstance().DumpState();
@@ -158,21 +161,31 @@
     return true;
 }
 
+void ResetWaitForProp() {
+    wait_prop_name.clear();
+    wait_prop_value.clear();
+    waiting_for_prop.reset();
+}
+
 void property_changed(const std::string& name, const std::string& value) {
     // If the property is sys.powerctl, we bypass the event queue and immediately handle it.
     // This is to ensure that init will always and immediately shutdown/reboot, regardless of
     // if there are other pending events to process or if init is waiting on an exec service or
     // waiting on a property.
-    if (name == "sys.powerctl") HandlePowerctlMessage(value);
+    // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
+    // commands to be executed.
+    if (name == "sys.powerctl") {
+        if (HandlePowerctlMessage(value)) {
+            shutting_down = true;
+        }
+    }
 
     if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);
 
     if (waiting_for_prop) {
         if (wait_prop_name == name && wait_prop_value == value) {
-            wait_prop_name.clear();
-            wait_prop_value.clear();
             LOG(INFO) << "Wait for property took " << *waiting_for_prop;
-            waiting_for_prop.reset();
+            ResetWaitForProp();
         }
     }
 }
@@ -221,7 +234,7 @@
         panic();
     }
 
-    property_set("ro.boottime.init.cold_boot_wait", std::to_string(t.duration_ms()));
+    property_set("ro.boottime.init.cold_boot_wait", std::to_string(t.duration().count()));
     return 0;
 }
 
@@ -379,7 +392,10 @@
     int ret = -1;
 
     /* values are arch-dependent */
-#if defined(__aarch64__)
+#if defined(USER_MODE_LINUX)
+    /* uml does not support mmap_rnd_bits */
+    ret = 0;
+#elif defined(__aarch64__)
     /* arm64 supports 18 - 33 bits depending on pagesize and VA_SIZE */
     if (set_mmap_rnd_bits_min(33, 24, false)
             && set_mmap_rnd_bits_min(16, 16, true)) {
@@ -539,6 +555,15 @@
     return 0;
 }
 
+static void global_seccomp() {
+    import_kernel_cmdline(false, [](const std::string& key, const std::string& value, bool in_qemu) {
+        if (key == "androidboot.seccomp" && value == "global" && !set_global_seccomp_filter()) {
+            LOG(ERROR) << "Failed to globally enable seccomp!";
+            panic();
+        }
+    });
+}
+
 static void selinux_init_all_handles(void)
 {
     sehandle = selinux_android_file_context_handle();
@@ -877,7 +902,7 @@
         }
 
         // init's first stage can't set properties, so pass the time to the second stage.
-        setenv("INIT_SELINUX_TOOK", std::to_string(t.duration_ms()).c_str(), 1);
+        setenv("INIT_SELINUX_TOOK", std::to_string(t.duration().count()).c_str(), 1);
     } else {
         selinux_init_all_handles();
     }
@@ -1010,6 +1035,9 @@
 
         SetInitAvbVersionInRecovery();
 
+        // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
+        global_seccomp();
+
         // Set up SELinux, loading the SELinux policy.
         selinux_initialize(true);
 
@@ -1156,7 +1184,7 @@
             am.ExecuteOneCommand();
         }
         if (!(waiting_for_prop || sm.IsWaitingForExec())) {
-            restart_processes();
+            if (!shutting_down) restart_processes();
 
             // If there's a process that needs restarting, wake up in time for that.
             if (process_needs_restart_at != 0) {
diff --git a/init/init.h b/init/init.h
index 479b771..aaab523 100644
--- a/init/init.h
+++ b/init/init.h
@@ -44,6 +44,8 @@
 
 void DumpState();
 
+void ResetWaitForProp();
+
 }  // namespace init
 }  // namespace android
 
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index e10c3b2..0f7e38f 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -25,6 +25,7 @@
 #include <string>
 #include <vector>
 
+#include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/strings.h>
@@ -36,7 +37,7 @@
 #include "uevent_listener.h"
 #include "util.h"
 
-using namespace std::chrono_literals;
+using android::base::Timer;
 
 namespace android {
 namespace init {
@@ -171,10 +172,13 @@
         };
         uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
         if (!found) {
+            LOG(INFO) << "device-mapper device not found in /sys, waiting for its uevent";
+            Timer t;
             uevent_listener_.Poll(dm_callback, 10s);
+            LOG(INFO) << "Wait for device-mapper returned after " << t;
         }
         if (!found) {
-            LOG(ERROR) << "device-mapper device not found";
+            LOG(ERROR) << "device-mapper device not found after polling timeout";
             return false;
         }
     }
@@ -185,11 +189,16 @@
     // UeventCallback() will remove found partitions from required_devices_partition_names_.
     // So if it isn't empty here, it means some partitions are not found.
     if (!required_devices_partition_names_.empty()) {
+        LOG(INFO) << __PRETTY_FUNCTION__
+                  << ": partition(s) not found in /sys, waiting for their uevent(s): "
+                  << android::base::Join(required_devices_partition_names_, ", ");
+        Timer t;
         uevent_listener_.Poll(uevent_callback, 10s);
+        LOG(INFO) << "Wait for partitions returned after " << t;
     }
 
     if (!required_devices_partition_names_.empty()) {
-        LOG(ERROR) << __PRETTY_FUNCTION__ << ": partition(s) not found: "
+        LOG(ERROR) << __PRETTY_FUNCTION__ << ": partition(s) not found after polling timeout: "
                    << android::base::Join(required_devices_partition_names_, ", ");
         return false;
     }
@@ -241,10 +250,13 @@
 
     uevent_listener_.RegenerateUeventsForPath(syspath, verity_callback);
     if (!found) {
+        LOG(INFO) << "dm-verity device not found in /sys, waiting for its uevent";
+        Timer t;
         uevent_listener_.Poll(verity_callback, 10s);
+        LOG(INFO) << "wait for dm-verity device returned after " << t;
     }
     if (!found) {
-        LOG(ERROR) << "dm-verity device not found";
+        LOG(ERROR) << "dm-verity device not found after polling timeout";
         return false;
     }
 
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index e76d589..9f7089b 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -18,6 +18,7 @@
 
 #include <dirent.h>
 
+#include <android-base/chrono_utils.h>
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
@@ -111,7 +112,7 @@
 
 bool Parser::ParseConfigFile(const std::string& path) {
     LOG(INFO) << "Parsing file " << path << "...";
-    Timer t;
+    android::base::Timer t;
     std::string data;
     std::string err;
     if (!ReadFile(path, &data, &err)) {
diff --git a/init/init_parser_test.cpp b/init/init_parser_test.cpp
index 38b8275..95f269a 100644
--- a/init/init_parser_test.cpp
+++ b/init/init_parser_test.cpp
@@ -16,13 +16,14 @@
 
 #include "init_parser.h"
 
-#include "init.h"
-#include "service.h"
+#include <string>
+#include <vector>
 
 #include <gtest/gtest.h>
 
-#include <string>
-#include <vector>
+#include "init.h"
+#include "service.h"
+#include "util.h"
 
 namespace android {
 namespace init {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index b7907e5..fd14bd6 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -42,6 +42,7 @@
 #include <queue>
 #include <vector>
 
+#include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
@@ -55,6 +56,8 @@
 #include "init.h"
 #include "util.h"
 
+using android::base::Timer;
+
 #define PERSISTENT_PROPERTY_DIR  "/data/property"
 #define RECOVERY_MOUNT_POINT "/recovery"
 
@@ -350,7 +353,7 @@
     while (*timeout_ms > 0) {
       Timer timer;
       int nr = poll(ufds, 1, *timeout_ms);
-      uint64_t millis = timer.duration_ms();
+      uint64_t millis = timer.duration().count();
       *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis;
 
       if (nr > 0) {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 34c98a7..17e3576 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -35,6 +35,7 @@
 #include <thread>
 #include <vector>
 
+#include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/macros.h>
@@ -49,10 +50,12 @@
 #include <private/android_filesystem_config.h>
 
 #include "capabilities.h"
+#include "init.h"
 #include "property_service.h"
 #include "service.h"
 
 using android::base::StringPrintf;
+using android::base::Timer;
 
 namespace android {
 namespace init {
@@ -160,7 +163,8 @@
 }
 
 static void LogShutdownTime(UmountStat stat, Timer* t) {
-    LOG(WARNING) << "powerctl_shutdown_time_ms:" << std::to_string(t->duration_ms()) << ":" << stat;
+    LOG(WARNING) << "powerctl_shutdown_time_ms:" << std::to_string(t->duration().count()) << ":"
+                 << stat;
 }
 
 // Determines whether the system is capable of rebooting. This is conservative,
@@ -230,7 +234,13 @@
             LOG(INFO) << "mount entry " << mentry->mnt_fsname << ":" << mentry->mnt_dir << " opts "
                       << mentry->mnt_opts << " type " << mentry->mnt_type;
         } else if (MountEntry::IsBlockDevice(*mentry) && hasmntopt(mentry, "rw")) {
-            blockDevPartitions->emplace(blockDevPartitions->begin(), *mentry);
+            std::string mount_dir(mentry->mnt_dir);
+            // These are R/O partitions changed to R/W after adb remount.
+            // Do not umount them as shutdown critical services may rely on them.
+            if (mount_dir != "/" && mount_dir != "/system" && mount_dir != "/vendor" &&
+                mount_dir != "/oem") {
+                blockDevPartitions->emplace(blockDevPartitions->begin(), *mentry);
+            }
         } else if (MountEntry::IsEmulatedDevice(*mentry)) {
             emulatedPartitions->emplace(emulatedPartitions->begin(), *mentry);
         }
@@ -253,7 +263,7 @@
     }
 }
 
-static UmountStat UmountPartitions(int timeoutMs) {
+static UmountStat UmountPartitions(std::chrono::milliseconds timeout) {
     Timer t;
     UmountStat stat = UMOUNT_STAT_TIMEOUT;
     int retry = 0;
@@ -271,7 +281,7 @@
             stat = UMOUNT_STAT_SUCCESS;
             break;
         }
-        if ((timeoutMs < t.duration_ms()) && retry > 0) {  // try umount at least once
+        if ((timeout < t.duration()) && retry > 0) {  // try umount at least once
             stat = UMOUNT_STAT_TIMEOUT;
             break;
         }
@@ -300,7 +310,7 @@
  *
  * return true when umount was successful. false when timed out.
  */
-static UmountStat TryUmountAndFsck(bool runFsck, int timeoutMs) {
+static UmountStat TryUmountAndFsck(bool runFsck, std::chrono::milliseconds timeout) {
     Timer t;
     std::vector<MountEntry> block_devices;
     std::vector<MountEntry> emulated_devices;
@@ -311,14 +321,14 @@
         return UMOUNT_STAT_ERROR;
     }
 
-    UmountStat stat = UmountPartitions(timeoutMs - t.duration_ms());
+    UmountStat stat = UmountPartitions(timeout - t.duration());
     if (stat != UMOUNT_STAT_SUCCESS) {
         LOG(INFO) << "umount timeout, last resort, kill all and try";
-        if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(false);
+        if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(true);
         KillAllProcesses();
         // even if it succeeds, still it is timeout and do not run fsck with all processes killed
-        UmountPartitions(0);
-        if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(true);
+        UmountStat st = UmountPartitions(0ms);
+        if ((st != UMOUNT_STAT_SUCCESS) && DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(false);
     }
 
     if (stat == UMOUNT_STAT_SUCCESS && runFsck) {
@@ -331,13 +341,6 @@
     return stat;
 }
 
-static void __attribute__((noreturn)) DoThermalOff() {
-    LOG(WARNING) << "Thermal system shutdown";
-    sync();
-    RebootSystem(ANDROID_RB_THERMOFF, "");
-    abort();
-}
-
 void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
               bool runFsck) {
     Timer t;
@@ -346,31 +349,38 @@
     android::base::WriteStringToFile(StringPrintf("%s\n", reason.c_str()), LAST_REBOOT_REASON_FILE,
                                      S_IRUSR | S_IWUSR, AID_SYSTEM, AID_SYSTEM);
 
-    if (cmd == ANDROID_RB_THERMOFF) {  // do not wait if it is thermal
-        DoThermalOff();
-        abort();
+    bool is_thermal_shutdown = false;
+    if (cmd == ANDROID_RB_THERMOFF) {
+        is_thermal_shutdown = true;
+        runFsck = false;
     }
 
-    constexpr unsigned int shutdownTimeoutDefault = 6;
-    unsigned int shutdownTimeout = shutdownTimeoutDefault;
-    if (SHUTDOWN_ZERO_TIMEOUT) {  // eng build
-        shutdownTimeout = 0;
-    } else {
-        shutdownTimeout =
-            android::base::GetUintProperty("ro.build.shutdown_timeout", shutdownTimeoutDefault);
+    auto shutdown_timeout = 0ms;
+    if (!SHUTDOWN_ZERO_TIMEOUT) {
+        if (is_thermal_shutdown) {
+            constexpr unsigned int thermal_shutdown_timeout = 1;
+            shutdown_timeout = std::chrono::seconds(thermal_shutdown_timeout);
+        } else {
+            constexpr unsigned int shutdown_timeout_default = 6;
+            auto shutdown_timeout_property = android::base::GetUintProperty(
+                "ro.build.shutdown_timeout", shutdown_timeout_default);
+            shutdown_timeout = std::chrono::seconds(shutdown_timeout_property);
+        }
     }
-    LOG(INFO) << "Shutdown timeout: " << shutdownTimeout;
+    LOG(INFO) << "Shutdown timeout: " << shutdown_timeout.count() << " ms";
 
     // keep debugging tools until non critical ones are all gone.
     const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
     // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
-    const std::set<std::string> to_starts{"watchdogd", "vold", "ueventd"};
+    const std::set<std::string> to_starts{"watchdogd"};
     ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) {
         if (kill_after_apps.count(s->name())) {
             s->SetShutdownCritical();
         } else if (to_starts.count(s->name())) {
             s->Start();
             s->SetShutdownCritical();
+        } else if (s->IsShutdownCritical()) {
+            s->Start();  // start shutdown critical service if not started
         }
     });
 
@@ -384,7 +394,7 @@
 
     // optional shutdown step
     // 1. terminate all services except shutdown critical ones. wait for delay to finish
-    if (shutdownTimeout > 0) {
+    if (shutdown_timeout > 0ms) {
         LOG(INFO) << "terminating init services";
 
         // Ask all services to terminate except shutdown critical ones.
@@ -393,9 +403,9 @@
         });
 
         int service_count = 0;
-        // Up to half as long as shutdownTimeout or 3 seconds, whichever is lower.
-        unsigned int terminationWaitTimeout = std::min<unsigned int>((shutdownTimeout + 1) / 2, 3);
-        while (t.duration_s() < terminationWaitTimeout) {
+        // Only wait up to half of timeout here
+        auto termination_wait_timeout = shutdown_timeout / 2;
+        while (t.duration() < termination_wait_timeout) {
             ServiceManager::GetInstance().ReapAnyOutstandingChildren();
 
             service_count = 0;
@@ -443,10 +453,10 @@
     });
     // 4. sync, try umount, and optionally run fsck for user shutdown
     sync();
-    UmountStat stat = TryUmountAndFsck(runFsck, shutdownTimeout * 1000 - t.duration_ms());
+    UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
     // Follow what linux shutdown is doing: one more sync with little bit delay
     sync();
-    std::this_thread::sleep_for(100ms);
+    if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms);
     LogShutdownTime(stat, &t);
     // Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
     RebootSystem(cmd, rebootTarget);
@@ -489,6 +499,7 @@
             }
         }
     } else if (command == "thermal-shutdown") {  // no additional parameter allowed
+        // run_fsck is false to avoid delay
         cmd = ANDROID_RB_THERMOFF;
     } else {
         command_invalid = true;
@@ -498,7 +509,26 @@
         return false;
     }
 
-    DoReboot(cmd, command, reboot_target, run_fsck);
+    LOG(INFO) << "Clear action queue and start shutdown trigger";
+    ActionManager::GetInstance().ClearQueue();
+    // Queue shutdown trigger first
+    ActionManager::GetInstance().QueueEventTrigger("shutdown");
+    // Queue built-in shutdown_done
+    auto shutdown_handler = [cmd, command, reboot_target,
+                             run_fsck](const std::vector<std::string>&) {
+        DoReboot(cmd, command, reboot_target, run_fsck);
+        return 0;
+    };
+    ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");
+
+    // Skip wait for prop if it is in progress
+    ResetWaitForProp();
+
+    // Skip wait for exec if it is in progress
+    if (ServiceManager::GetInstance().IsWaitingForExec()) {
+        ServiceManager::GetInstance().ClearExecWait();
+    }
+
     return true;
 }
 
diff --git a/init/service.cpp b/init/service.cpp
index f2e5d22..fc64db6 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -34,6 +34,7 @@
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/properties.h>
+#include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <processgroup/processgroup.h>
@@ -47,6 +48,7 @@
 using android::base::boot_clock;
 using android::base::GetProperty;
 using android::base::Join;
+using android::base::make_scope_guard;
 using android::base::ParseInt;
 using android::base::StartsWith;
 using android::base::StringPrintf;
@@ -154,24 +156,7 @@
 }
 
 Service::Service(const std::string& name, const std::vector<std::string>& args)
-    : name_(name),
-      classnames_({"default"}),
-      flags_(0),
-      pid_(0),
-      crash_count_(0),
-      uid_(0),
-      gid_(0),
-      namespace_flags_(0),
-      seclabel_(""),
-      onrestart_(false, "<Service '" + name + "' onrestart>", 0),
-      keychord_id_(0),
-      ioprio_class_(IoSchedClass_NONE),
-      ioprio_pri_(0),
-      priority_(0),
-      oom_score_adjust_(-1000),
-      args_(args) {
-    onrestart_.InitSingleTrigger("onrestart");
-}
+    : Service(name, 0, 0, 0, {}, 0, 0, "", args) {}
 
 Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
                  const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
@@ -194,6 +179,9 @@
       ioprio_pri_(0),
       priority_(0),
       oom_score_adjust_(-1000),
+      swappiness_(-1),
+      soft_limit_in_bytes_(-1),
+      limit_in_bytes_(-1),
       args_(args) {
     onrestart_.InitSingleTrigger("onrestart");
 }
@@ -489,6 +477,30 @@
     return true;
 }
 
+bool Service::ParseMemcgSwappiness(const std::vector<std::string>& args, std::string* err) {
+    if (!ParseInt(args[1], &swappiness_, 0)) {
+        *err = "swappiness value must be equal or greater than 0";
+        return false;
+    }
+    return true;
+}
+
+bool Service::ParseMemcgLimitInBytes(const std::vector<std::string>& args, std::string* err) {
+    if (!ParseInt(args[1], &limit_in_bytes_, 0)) {
+        *err = "limit_in_bytes value must be equal or greater than 0";
+        return false;
+    }
+    return true;
+}
+
+bool Service::ParseMemcgSoftLimitInBytes(const std::vector<std::string>& args, std::string* err) {
+    if (!ParseInt(args[1], &soft_limit_in_bytes_, 0)) {
+        *err = "soft_limit_in_bytes value must be equal or greater than 0";
+        return false;
+    }
+    return true;
+}
+
 bool Service::ParseSeclabel(const std::vector<std::string>& args, std::string* err) {
     seclabel_ = args[1];
     return true;
@@ -499,6 +511,14 @@
     return true;
 }
 
+bool Service::ParseShutdown(const std::vector<std::string>& args, std::string* err) {
+    if (args[1] == "critical") {
+        flags_ |= SVC_SHUTDOWN_CRITICAL;
+        return true;
+    }
+    return false;
+}
+
 template <typename T>
 bool Service::AddDescriptor(const std::vector<std::string>& args, std::string* err) {
     int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
@@ -599,9 +619,16 @@
         {"onrestart",   {1,     kMax, &Service::ParseOnrestart}},
         {"oom_score_adjust",
                         {1,     1,    &Service::ParseOomScoreAdjust}},
+        {"memcg.swappiness",
+                        {1,     1,    &Service::ParseMemcgSwappiness}},
+        {"memcg.soft_limit_in_bytes",
+                        {1,     1,    &Service::ParseMemcgSoftLimitInBytes}},
+        {"memcg.limit_in_bytes",
+                        {1,     1,    &Service::ParseMemcgLimitInBytes}},
         {"namespace",   {1,     2,    &Service::ParseNamespace}},
         {"seclabel",    {1,     1,    &Service::ParseSeclabel}},
         {"setenv",      {2,     2,    &Service::ParseSetenv}},
+        {"shutdown",    {1,     1,    &Service::ParseShutdown}},
         {"socket",      {3,     6,    &Service::ParseSocket}},
         {"file",        {2,     2,    &Service::ParseFile}},
         {"user",        {1,     1,    &Service::ParseUser}},
@@ -622,10 +649,10 @@
     return (this->*parser)(args, err);
 }
 
-bool Service::ExecStart(std::unique_ptr<Timer>* exec_waiter) {
+bool Service::ExecStart(std::unique_ptr<android::base::Timer>* exec_waiter) {
     flags_ |= SVC_EXEC | SVC_ONESHOT;
 
-    exec_waiter->reset(new Timer);
+    exec_waiter->reset(new android::base::Timer);
 
     if (!Start()) {
         exec_waiter->reset();
@@ -784,6 +811,24 @@
     if (errno != 0) {
         PLOG(ERROR) << "createProcessGroup(" << uid_ << ", " << pid_ << ") failed for service '"
                     << name_ << "'";
+    } else {
+        if (swappiness_ != -1) {
+            if (!setProcessGroupSwappiness(uid_, pid_, swappiness_)) {
+                PLOG(ERROR) << "setProcessGroupSwappiness failed";
+            }
+        }
+
+        if (soft_limit_in_bytes_ != -1) {
+            if (!setProcessGroupSoftLimit(uid_, pid_, soft_limit_in_bytes_)) {
+                PLOG(ERROR) << "setProcessGroupSoftLimit failed";
+            }
+        }
+
+        if (limit_in_bytes_ != -1) {
+            if (!setProcessGroupLimit(uid_, pid_, limit_in_bytes_)) {
+                PLOG(ERROR) << "setProcessGroupLimit failed";
+            }
+        }
     }
 
     if ((flags_ & SVC_EXEC) != 0) {
@@ -1088,14 +1133,24 @@
 }
 
 bool ServiceManager::ReapOneProcess() {
-    int status;
-    pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
-    if (pid == 0) {
+    siginfo_t siginfo = {};
+    // This returns a zombie pid or informs us that there are no zombies left to be reaped.
+    // It does NOT reap the pid; that is done below.
+    if (TEMP_FAILURE_RETRY(waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG | WNOWAIT)) != 0) {
+        PLOG(ERROR) << "waitid failed";
         return false;
-    } else if (pid == -1) {
-        PLOG(ERROR) << "waitpid failed";
-        return false;
-    } else if (PropertyChildReap(pid)) {
+    }
+
+    auto pid = siginfo.si_pid;
+    if (pid == 0) return false;
+
+    // At this point we know we have a zombie pid, so we use this scopeguard to reap the pid
+    // whenever the function returns from this point forward.
+    // We do NOT want to reap the zombie earlier as in Service::Reap(), we kill(-pid, ...) and we
+    // want the pid to remain valid throughout that (and potentially future) usages.
+    auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); });
+
+    if (PropertyChildReap(pid)) {
         return true;
     }
 
@@ -1106,20 +1161,18 @@
     if (svc) {
         name = StringPrintf("Service '%s' (pid %d)", svc->name().c_str(), pid);
         if (svc->flags() & SVC_EXEC) {
-            wait_string = StringPrintf(" waiting took %f seconds", exec_waiter_->duration_s());
+            wait_string = StringPrintf(" waiting took %f seconds",
+                                       exec_waiter_->duration().count() / 1000.0f);
         }
     } else {
         name = StringPrintf("Untracked pid %d", pid);
     }
 
+    auto status = siginfo.si_status;
     if (WIFEXITED(status)) {
         LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string;
     } else if (WIFSIGNALED(status)) {
         LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string;
-    } else if (WIFSTOPPED(status)) {
-        LOG(INFO) << name << " stopped by signal " << WSTOPSIG(status) << wait_string;
-    } else {
-        LOG(INFO) << name << " state changed" << wait_string;
     }
 
     if (!svc) {
@@ -1143,6 +1196,15 @@
     }
 }
 
+void ServiceManager::ClearExecWait() {
+    // Clear EXEC flag if there is one pending
+    // And clear the wait flag
+    for (const auto& s : services_) {
+        s->UnSetExec();
+    }
+    exec_waiter_.reset();
+}
+
 bool ServiceParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,
                                  int line, std::string* err) {
     if (args.size() < 3) {
diff --git a/init/service.h b/init/service.h
index 3c7dc74..62a3299 100644
--- a/init/service.h
+++ b/init/service.h
@@ -32,7 +32,6 @@
 #include "descriptors.h"
 #include "init_parser.h"
 #include "keyword_map.h"
-#include "util.h"
 
 #define SVC_DISABLED 0x001        // do not autostart with class
 #define SVC_ONESHOT 0x002         // do not restart on exit
@@ -76,7 +75,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 ExecStart(std::unique_ptr<android::base::Timer>* exec_waiter);
     bool Start();
     bool StartIfNotDisabled();
     bool Enable();
@@ -89,6 +88,7 @@
     void DumpState() const;
     void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
     bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
+    void UnSetExec() { flags_ &= ~SVC_EXEC; }
 
     const std::string& name() const { return name_; }
     const std::set<std::string>& classnames() const { return classnames_; }
@@ -134,9 +134,13 @@
     bool ParseOneshot(const std::vector<std::string>& args, std::string* err);
     bool ParseOnrestart(const std::vector<std::string>& args, std::string* err);
     bool ParseOomScoreAdjust(const std::vector<std::string>& args, std::string* err);
+    bool ParseMemcgLimitInBytes(const std::vector<std::string>& args, std::string* err);
+    bool ParseMemcgSoftLimitInBytes(const std::vector<std::string>& args, std::string* err);
+    bool ParseMemcgSwappiness(const std::vector<std::string>& args, std::string* err);
     bool ParseNamespace(const std::vector<std::string>& args, std::string* err);
     bool ParseSeclabel(const std::vector<std::string>& args, std::string* err);
     bool ParseSetenv(const std::vector<std::string>& args, std::string* err);
+    bool ParseShutdown(const std::vector<std::string>& args, std::string* err);
     bool ParseSocket(const std::vector<std::string>& args, std::string* err);
     bool ParseFile(const std::vector<std::string>& args, std::string* err);
     bool ParseUser(const std::vector<std::string>& args, std::string* err);
@@ -180,13 +184,17 @@
 
     int oom_score_adjust_;
 
+    int swappiness_;
+    int soft_limit_in_bytes_;
+    int limit_in_bytes_;
+
     bool process_cgroup_empty_ = false;
 
     std::vector<std::string> args_;
 };
 
 class ServiceManager {
-public:
+  public:
     static ServiceManager& GetInstance();
 
     // Exposed for testing
@@ -208,14 +216,15 @@
     void ReapAnyOutstandingChildren();
     void RemoveService(const Service& svc);
     void DumpState() const;
+    void ClearExecWait();
 
-private:
+  private:
     // Cleans up a child process that exited.
     // Returns true iff a children was cleaned up.
     bool ReapOneProcess();
 
     static int exec_count_; // Every service needs a unique name.
-    std::unique_ptr<Timer> exec_waiter_;
+    std::unique_ptr<android::base::Timer> exec_waiter_;
 
     std::vector<std::unique_ptr<Service>> services_;
 };
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 81a0572..c0eae1e 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -27,6 +27,7 @@
 #include <set>
 #include <thread>
 
+#include <android-base/chrono_utils.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <selinux/android.h>
@@ -198,7 +199,7 @@
 }
 
 void ColdBoot::Run() {
-    Timer cold_boot_timer;
+    android::base::Timer cold_boot_timer;
 
     RegenerateUevents();
 
@@ -209,7 +210,7 @@
     WaitForSubProcesses();
 
     close(open(COLDBOOT_DONE, O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
-    LOG(INFO) << "Coldboot took " << cold_boot_timer;
+    LOG(INFO) << "Coldboot took " << cold_boot_timer.duration().count() / 1000.0f << " seconds";
 }
 
 DeviceHandler CreateDeviceHandler() {
@@ -268,6 +269,13 @@
         cold_boot.Run();
     }
 
+    // We use waitpid() in ColdBoot, so we can't ignore SIGCHLD until now.
+    signal(SIGCHLD, SIG_IGN);
+    // Reap and pending children that exited between the last call to waitpid() and setting SIG_IGN
+    // for SIGCHLD above.
+    while (waitpid(-1, nullptr, WNOHANG) > 0) {
+    }
+
     uevent_listener.Poll([&device_handler](const Uevent& uevent) {
         HandleFirmwareEvent(uevent);
         device_handler.HandleDeviceEvent(uevent);
diff --git a/init/ueventd_test.cpp b/init/ueventd_test.cpp
new file mode 100644
index 0000000..4d9a1fa
--- /dev/null
+++ b/init/ueventd_test.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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 <linux/futex.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/scopeguard.h>
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+#include <selinux/selinux.h>
+
+using namespace std::string_literals;
+
+template <typename T, typename F>
+void WriteFromMultipleThreads(std::vector<std::pair<std::string, T>>& files_and_parameters,
+                              F function) {
+    auto num_threads = files_and_parameters.size();
+    pthread_barrier_t barrier;
+    pthread_barrier_init(&barrier, nullptr, num_threads);
+    auto barrier_destroy =
+        android::base::make_scope_guard([&barrier]() { pthread_barrier_destroy(&barrier); });
+
+    auto make_thread_function = [&function, &barrier](const auto& file, const auto& parameter) {
+        return [&]() {
+            function(parameter);
+            pthread_barrier_wait(&barrier);
+            android::base::WriteStringToFile("<empty>", file);
+        };
+    };
+
+    std::vector<std::thread> threads;
+    // TODO(b/63712782): Structured bindings + templated containers are broken in clang :(
+    // for (const auto& [file, parameter] : files_and_parameters) {
+    for (const auto& pair : files_and_parameters) {
+        const auto& file = pair.first;
+        const auto& parameter = pair.second;
+        threads.emplace_back(std::thread(make_thread_function(file, parameter)));
+    }
+
+    for (auto& thread : threads) {
+        thread.join();
+    }
+}
+
+TEST(ueventd, setegid_IsPerThread) {
+    if (getuid() != 0) {
+        GTEST_LOG_(INFO) << "Skipping test, must be run as root.";
+        return;
+    }
+
+    TemporaryDir dir;
+
+    gid_t gid = 0;
+    std::vector<std::pair<std::string, gid_t>> files_and_gids;
+    std::generate_n(std::back_inserter(files_and_gids), 100, [&gid, &dir]() {
+        gid++;
+        return std::pair(dir.path + "/gid_"s + std::to_string(gid), gid);
+    });
+
+    WriteFromMultipleThreads(files_and_gids, [](gid_t gid) { EXPECT_EQ(0, setegid(gid)); });
+
+    for (const auto& [file, expected_gid] : files_and_gids) {
+        struct stat info;
+        ASSERT_EQ(0, stat(file.c_str(), &info));
+        EXPECT_EQ(expected_gid, info.st_gid);
+    }
+}
+
+TEST(ueventd, setfscreatecon_IsPerThread) {
+    if (getuid() != 0) {
+        GTEST_LOG_(INFO) << "Skipping test, must be run as root.";
+        return;
+    }
+    if (!is_selinux_enabled() || security_getenforce() == 1) {
+        GTEST_LOG_(INFO) << "Skipping test, SELinux must be enabled and in permissive mode.";
+        return;
+    }
+
+    const char* const contexts[] = {
+        "u:object_r:audio_device:s0",
+        "u:object_r:sensors_device:s0",
+        "u:object_r:video_device:s0"
+        "u:object_r:zero_device:s0",
+    };
+
+    TemporaryDir dir;
+    std::vector<std::pair<std::string, std::string>> files_and_contexts;
+    for (const char* context : contexts) {
+        files_and_contexts.emplace_back(dir.path + "/context_"s + context, context);
+    }
+
+    WriteFromMultipleThreads(files_and_contexts, [](const std::string& context) {
+        EXPECT_EQ(0, setfscreatecon(context.c_str()));
+    });
+
+    for (const auto& [file, expected_context] : files_and_contexts) {
+        char* file_context;
+        ASSERT_GT(getfilecon(file.c_str(), &file_context), 0);
+        EXPECT_EQ(expected_context, file_context);
+        freecon(file_context);
+    }
+}
diff --git a/init/util.cpp b/init/util.cpp
index 4b1894f..2792794 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -370,14 +370,10 @@
 
 void panic() {
     LOG(ERROR) << "panic: rebooting to bootloader";
+    // Do not queue "shutdown" trigger since we want to shutdown immediately
     DoReboot(ANDROID_RB_RESTART2, "reboot", "bootloader", false);
 }
 
-std::ostream& operator<<(std::ostream& os, const Timer& t) {
-    os << t.duration_s() << " seconds";
-    return os;
-}
-
 // Reads the content of device tree file under kAndroidDtDir directory.
 // Returns true if the read is success, false otherwise.
 bool read_android_dt_file(const std::string& sub_path, std::string* dt_content) {
diff --git a/init/util.h b/init/util.h
index 346953f..452df2d 100644
--- a/init/util.h
+++ b/init/util.h
@@ -44,26 +44,6 @@
 bool ReadFile(const std::string& path, std::string* content, std::string* err);
 bool WriteFile(const std::string& path, const std::string& content, std::string* err);
 
-class Timer {
-  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();
-    }
-
-    int64_t duration_ms() const {
-        return std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() - start_)
-            .count();
-    }
-
-  private:
-    android::base::boot_clock::time_point start_;
-};
-
-std::ostream& operator<<(std::ostream& os, const Timer& t);
-
 bool DecodeUid(const std::string& name, uid_t* uid, std::string* err);
 
 int mkdir_recursive(const std::string& pathname, mode_t mode, selabel_handle* sehandle);
diff --git a/libappfuse/Android.bp b/libappfuse/Android.bp
index b0ac5c4..29ffe32 100644
--- a/libappfuse/Android.bp
+++ b/libappfuse/Android.bp
@@ -8,7 +8,6 @@
         "-Wall",
         "-Werror",
     ],
-    clang: true
 }
 
 cc_library_shared {
diff --git a/libappfuse/FuseBridgeLoop.cc b/libappfuse/FuseBridgeLoop.cc
index 5a897a4..8b0c53e 100644
--- a/libappfuse/FuseBridgeLoop.cc
+++ b/libappfuse/FuseBridgeLoop.cc
@@ -173,9 +173,6 @@
     }
 
     FuseBridgeState ReadFromDevice(FuseBridgeLoopCallback* callback) {
-        // To observe APCT failures.
-        base::ScopedLogSeverity log_severity(base::VERBOSE);
-
         LOG(VERBOSE) << "ReadFromDevice";
         if (!buffer_.request.Read(device_fd_)) {
             return FuseBridgeState::kClosing;
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index a643a29..e02aaf2 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -161,6 +161,7 @@
     shared_libs = [
         "libbase",
         "libunwind",
+        "libziparchive",
     ],
 }
 
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index e46d353..81f5e32 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -84,10 +84,8 @@
 }
 
 std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) {
-  uintptr_t relative_pc;
   std::string map_name;
   if (BacktraceMap::IsValid(frame->map)) {
-    relative_pc = BacktraceMap::GetRelativePc(frame->map, frame->pc);
     if (!frame->map.name.empty()) {
       map_name = frame->map.name.c_str();
       if (map_name[0] == '[' && map_name[map_name.size() - 1] == ']') {
@@ -99,10 +97,9 @@
     }
   } else {
     map_name = "<unknown>";
-    relative_pc = frame->pc;
   }
 
-  std::string line(StringPrintf("#%02zu pc %" PRIPTR "  ", frame->num, relative_pc));
+  std::string line(StringPrintf("#%02zu pc %" PRIPTR "  ", frame->num, frame->rel_pc));
   line += map_name;
   // Special handling for non-zero offset maps, we need to print that
   // information.
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
index 3c509e6..2c87fa8 100644
--- a/libbacktrace/UnwindCurrent.cpp
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -133,6 +133,11 @@
           backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
           prev->stack_size = frame->sp - prev->sp;
         }
+        if (BacktraceMap::IsValid(frame->map)) {
+          frame->rel_pc = frame->pc - frame->map.start + frame->map.load_bias;
+        } else {
+          frame->rel_pc = frame->pc;
+        }
         num_frames++;
       } else {
         num_ignore_frames--;
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index af79562..0b8232b 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -57,7 +57,7 @@
     map.start = unw_map.start;
     map.end = unw_map.end;
     map.offset = unw_map.offset;
-    map.load_base = unw_map.load_base;
+    map.load_bias = unw_map.load_base;
     map.flags = unw_map.flags;
     map.name = unw_map.path;
 
@@ -106,7 +106,7 @@
       map.start = unw_map.start;
       map.end = unw_map.end;
       map.offset = unw_map.offset;
-      map.load_base = unw_map.load_base;
+      map.load_bias = unw_map.load_base;
       map.flags = unw_map.flags;
       map.name = unw_map.path;
 
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
index 42ac1bc..87282ef 100644
--- a/libbacktrace/UnwindPtrace.cpp
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -135,6 +135,11 @@
       }
 
       FillInMap(frame->pc, &frame->map);
+      if (BacktraceMap::IsValid(frame->map)) {
+        frame->rel_pc = frame->pc - frame->map.start + frame->map.load_bias;
+      } else {
+        frame->rel_pc = frame->pc;
+      }
 
       frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map);
 
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 465b3f9..16b1d79 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -167,9 +167,9 @@
   // 2. Dump maps
   for (auto it = map->begin(); it != map->end(); ++it) {
     testdata += android::base::StringPrintf(
-        "map: start: %" PRIxPTR " end: %" PRIxPTR " offset: %" PRIxPTR
-        " load_base: %" PRIxPTR " flags: %d name: %s\n",
-        it->start, it->end, it->offset, it->load_base, it->flags, it->name.c_str());
+        "map: start: %" PRIxPTR " end: %" PRIxPTR " offset: %" PRIxPTR " load_bias: %" PRIxPTR
+        " flags: %d name: %s\n",
+        it->start, it->end, it->offset, it->load_bias, it->flags, it->name.c_str());
   }
   // 3. Dump registers
   testdata += android::base::StringPrintf("registers: %zu ", sizeof(arg.unw_context));
@@ -246,9 +246,9 @@
       backtrace_map_t& map = testdata->maps.back();
       int pos;
       sscanf(line.c_str(),
-             "map: start: %" SCNxPTR " end: %" SCNxPTR " offset: %" SCNxPTR
-             " load_base: %" SCNxPTR " flags: %d name: %n",
-             &map.start, &map.end, &map.offset, &map.load_base, &map.flags, &pos);
+             "map: start: %" SCNxPTR " end: %" SCNxPTR " offset: %" SCNxPTR " load_bias: %" SCNxPTR
+             " flags: %d name: %n",
+             &map.start, &map.end, &map.offset, &map.load_bias, &map.flags, &pos);
       map.name = android::base::Trim(line.substr(pos));
     } else if (android::base::StartsWith(line, "registers:")) {
       size_t size;
@@ -392,8 +392,8 @@
   // The last frame is outside of libart.so
   ASSERT_EQ(testdata.symbols.size() + 1, backtrace->NumFrames());
   for (size_t i = 0; i + 1 < backtrace->NumFrames(); ++i) {
-    uintptr_t vaddr_in_file = backtrace->GetFrame(i)->pc - testdata.maps[0].start +
-        testdata.maps[0].load_base;
+    uintptr_t vaddr_in_file =
+        backtrace->GetFrame(i)->pc - testdata.maps[0].start + testdata.maps[0].load_bias;
     std::string name = FunctionNameForAddress(vaddr_in_file, testdata.symbols);
     ASSERT_EQ(name, testdata.symbols[i].name);
   }
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index fb463b0..1ec6a45 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -784,6 +784,7 @@
   backtrace_frame_data_t frame;
   frame.num = 1;
   frame.pc = 2;
+  frame.rel_pc = 2;
   frame.sp = 0;
   frame.stack_size = 0;
   frame.func_offset = 0;
@@ -799,9 +800,10 @@
 
   // Check map name empty, but exists.
   frame.pc = 0xb0020;
+  frame.rel_pc = 0x20;
   frame.map.start = 0xb0000;
   frame.map.end = 0xbffff;
-  frame.map.load_base = 0;
+  frame.map.load_bias = 0;
 #if defined(__LP64__)
   EXPECT_EQ("#01 pc 0000000000000020  <anonymous:00000000000b0000>",
 #else
@@ -813,7 +815,7 @@
   frame.pc = 0xc0020;
   frame.map.start = 0xc0000;
   frame.map.end = 0xcffff;
-  frame.map.load_base = 0;
+  frame.map.load_bias = 0;
   frame.map.name = "[anon:thread signal stack]";
 #if defined(__LP64__)
   EXPECT_EQ("#01 pc 0000000000000020  [anon:thread signal stack:00000000000c0000]",
@@ -824,6 +826,7 @@
 
   // Check relative pc is set and map name is set.
   frame.pc = 0x12345679;
+  frame.rel_pc = 0x12345678;
   frame.map.name = "MapFake";
   frame.map.start =  1;
   frame.map.end =  1;
@@ -852,9 +855,10 @@
 #endif
             backtrace->FormatFrameData(&frame));
 
-  // Check func_name is set, func offset is non-zero, and load_base is non-zero.
+  // Check func_name is set, func offset is non-zero, and load_bias is non-zero.
+  frame.rel_pc = 0x123456dc;
   frame.func_offset = 645;
-  frame.map.load_base = 100;
+  frame.map.load_bias = 100;
 #if defined(__LP64__)
   EXPECT_EQ("#01 pc 00000000123456dc  MapFake (ProcFake+645)",
 #else
@@ -1737,9 +1741,13 @@
   FinishRemoteProcess(pid);
 }
 
-TEST(libbacktrace, unwind_remote_through_signal_using_handler) { UnwindThroughSignal(false); }
+TEST(libbacktrace, unwind_remote_through_signal_using_handler) {
+  UnwindThroughSignal(false);
+}
 
-TEST(libbacktrace, unwind_remote_through_signal_using_action) { UnwindThroughSignal(true); }
+TEST(libbacktrace, unwind_remote_through_signal_using_action) {
+  UnwindThroughSignal(true);
+}
 
 #if defined(ENABLE_PSS_TESTS)
 #include "GetPss.h"
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 4f73a65..b919e81 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -55,6 +55,7 @@
 struct backtrace_frame_data_t {
   size_t num;             // The current fame number.
   uintptr_t pc;           // The absolute pc.
+  uintptr_t rel_pc;       // The relative pc.
   uintptr_t sp;           // The top of the stack.
   size_t stack_size;      // The size of the stack, zero indicate an unknown stack size.
   backtrace_map_t map;    // The map associated with the given pc.
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index 8ab0dfa..02a50f7 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -41,7 +41,7 @@
   uintptr_t start = 0;
   uintptr_t end = 0;
   uintptr_t offset = 0;
-  uintptr_t load_base = 0;
+  uintptr_t load_bias = 0;
   int flags = 0;
   std::string name;
 };
@@ -95,14 +95,6 @@
     return map.end > 0;
   }
 
-  static uintptr_t GetRelativePc(const backtrace_map_t& map, uintptr_t pc) {
-    if (IsValid(map)) {
-      return pc - map.start + map.load_base;
-    } else {
-      return pc;
-    }
-  }
-
 protected:
   BacktraceMap(pid_t pid);
 
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 245deb1..85258cd 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -156,8 +156,6 @@
         "-Wall",
         "-Wextra",
     ],
-
-    clang: true,
 }
 
 subdirs = ["tests"]
diff --git a/libion/tests/Android.bp b/libion/tests/Android.bp
index 4428848..b3fcb3b 100644
--- a/libion/tests/Android.bp
+++ b/libion/tests/Android.bp
@@ -16,7 +16,6 @@
 
 cc_test {
     name: "ion-unit-tests",
-    clang: true,
     cflags: [
         "-g",
         "-Wall",
diff --git a/liblog/Android.bp b/liblog/Android.bp
index e74aa82..b98d18f 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -42,6 +42,24 @@
     "logd_writer.c",
 ]
 
+cc_library_headers {
+    name: "liblog_headers",
+    host_supported: true,
+    vendor_available: true,
+    export_include_dirs: ["include"],
+    target: {
+        windows: {
+            enabled: true,
+        },
+        linux_bionic: {
+            enabled: true,
+        },
+        vendor: {
+            export_include_dirs: ["include_vndk"],
+        },
+    },
+}
+
 // Shared and static library for host and device
 // ========================================================
 cc_library {
@@ -81,7 +99,8 @@
         },
     },
 
-    export_include_dirs: ["include"],
+    header_libs: ["liblog_headers"],
+    export_header_lib_headers: ["liblog_headers"],
 
     cflags: [
         "-Werror",
@@ -100,7 +119,7 @@
 }
 
 ndk_headers {
-    name: "liblog_headers",
+    name: "liblog_ndk_headers",
     from: "include/android",
     to: "android",
     srcs: ["include/android/log.h"],
diff --git a/liblog/include/log/log.h b/liblog/include/log/log.h
index 3a215e9..d01708d 100644
--- a/liblog/include/log/log.h
+++ b/liblog/include/log/log.h
@@ -161,7 +161,7 @@
 #endif
 
 #if __ANDROID_USE_LIBLOG_CLOCK_INTERFACE
-clockid_t android_log_clockid();
+clockid_t android_log_clockid(void);
 #endif
 
 #endif /* __linux__ */
@@ -185,7 +185,7 @@
  * May be used to clean up File descriptors after a Fork, the resources are
  * all O_CLOEXEC so wil self clean on exec().
  */
-void __android_log_close();
+void __android_log_close(void);
 #endif
 
 #ifndef __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h
index da16158..68c2e9a 100644
--- a/liblog/include/log/log_main.h
+++ b/liblog/include/log/log_main.h
@@ -18,10 +18,9 @@
 #define _LIBS_LOG_LOG_MAIN_H
 
 #include <android/log.h>
+#include <sys/cdefs.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+__BEGIN_DECLS
 
 /*
  * Normally we strip the effects of ALOGV (VERBOSE messages),
@@ -385,8 +384,6 @@
 #pragma clang diagnostic pop
 #endif
 
-#ifdef __cplusplus
-}
-#endif
+__END_DECLS
 
 #endif /* _LIBS_LOG_LOG_MAIN_H */
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index ab96429..91044ab 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -89,7 +89,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 LOCAL_SHARED_LIBRARIES := liblog libcutils libbase
 LOCAL_STATIC_LIBRARIES := libgtest libgtest_main
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 LOCAL_CTS_TEST_PACKAGE := android.core.liblog
 include $(BUILD_CTS_EXECUTABLE)
 
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index cdac76b..8b76a65 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -6,7 +6,6 @@
         "-Wextra",
         "-Werror",
     ],
-    clang: true,
     shared_libs: [
         "libbase",
     ],
@@ -26,6 +25,7 @@
     defaults: ["libmemunreachable_defaults"],
     srcs: [
         "Allocator.cpp",
+        "Binder.cpp",
         "HeapWalker.cpp",
         "LeakFolding.cpp",
         "LeakPipe.cpp",
@@ -84,3 +84,18 @@
         },
     },
 }
+
+cc_test {
+    name: "memunreachable_binder_test",
+    defaults: ["libmemunreachable_defaults"],
+    srcs: [
+        "tests/Binder_test.cpp",
+        "tests/MemUnreachable_test.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libhwbinder",
+        "libmemunreachable",
+        "libutils",
+    ],
+}
diff --git a/libmemunreachable/Binder.cpp b/libmemunreachable/Binder.cpp
new file mode 100644
index 0000000..60512a3
--- /dev/null
+++ b/libmemunreachable/Binder.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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 <sys/cdefs.h>
+#include <unistd.h>
+
+#include <functional>
+
+#include "Binder.h"
+#include "log.h"
+
+__BEGIN_DECLS
+
+// Weak undefined references to the symbols in libbinder and libhwbinder
+// so that libmemunreachable can call them in processes that have them
+// loaded without requiring libmemunreachable to have dependencies on them.
+ssize_t __attribute__((weak)) getBinderKernelReferences(size_t, uintptr_t*);
+ssize_t __attribute__((weak)) getHWBinderKernelReferences(size_t, uintptr_t*);
+
+__END_DECLS
+
+namespace android {
+
+static bool BinderReferencesToVector(allocator::vector<uintptr_t>& refs,
+                                     std::function<ssize_t(size_t, uintptr_t*)> fn) {
+  if (fn == nullptr) {
+    return true;
+  }
+
+  size_t size = refs.size();
+
+  do {
+    refs.resize(size);
+
+    ssize_t ret = fn(refs.size(), refs.data());
+    if (ret < 0) {
+      return false;
+    }
+
+    size = ret;
+  } while (size > refs.size());
+
+  refs.resize(size);
+  return true;
+}
+
+bool BinderReferences(allocator::vector<uintptr_t>& refs) {
+  refs.clear();
+
+  allocator::vector<uintptr_t> binder_refs{refs.get_allocator()};
+  if (BinderReferencesToVector(refs, getBinderKernelReferences)) {
+    refs.insert(refs.end(), binder_refs.begin(), binder_refs.end());
+  } else {
+    MEM_ALOGE("getBinderKernelReferences failed");
+  }
+
+  allocator::vector<uintptr_t> hwbinder_refs{refs.get_allocator()};
+  if (BinderReferencesToVector(hwbinder_refs, getHWBinderKernelReferences)) {
+    refs.insert(refs.end(), hwbinder_refs.begin(), hwbinder_refs.end());
+  } else {
+    MEM_ALOGE("getHWBinderKernelReferences failed");
+  }
+
+  return true;
+}
+
+}  // namespace android
diff --git a/libunwindstack/Log.h b/libmemunreachable/Binder.h
similarity index 65%
copy from libunwindstack/Log.h
copy to libmemunreachable/Binder.h
index 2d01aa8..bf4fd3e 100644
--- a/libunwindstack/Log.h
+++ b/libmemunreachable/Binder.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,12 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef _LIBUNWINDSTACK_LOG_H
-#define _LIBUNWINDSTACK_LOG_H
+#ifndef LIBMEMUNREACHABLE_BINDER_H_
+#define LIBMEMUNREACHABLE_BINDER_H_
 
-#include <stdint.h>
+#include "Allocator.h"
 
-void log_to_stdout(bool enable);
-void log(uint8_t indent, const char* format, ...);
+namespace android {
 
-#endif  // _LIBUNWINDSTACK_LOG_H
+bool BinderReferences(allocator::vector<uintptr_t>& refs);
+
+}  // namespace android
+
+#endif  // LIBMEMUNREACHABLE_BINDER_H_
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index a1f74c3..5e062fd 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -28,6 +28,7 @@
 #include <backtrace.h>
 
 #include "Allocator.h"
+#include "Binder.h"
 #include "HeapWalker.h"
 #include "Leak.h"
 #include "LeakFolding.h"
@@ -53,7 +54,8 @@
   MemUnreachable(pid_t pid, Allocator<void> allocator)
       : pid_(pid), allocator_(allocator), heap_walker_(allocator_) {}
   bool CollectAllocations(const allocator::vector<ThreadInfo>& threads,
-                          const allocator::vector<Mapping>& mappings);
+                          const allocator::vector<Mapping>& mappings,
+                          const allocator::vector<uintptr_t>& refs);
   bool GetUnreachableMemory(allocator::vector<Leak>& leaks, size_t limit, size_t* num_leaks,
                             size_t* leak_bytes);
   size_t Allocations() { return heap_walker_.Allocations(); }
@@ -82,7 +84,8 @@
 }
 
 bool MemUnreachable::CollectAllocations(const allocator::vector<ThreadInfo>& threads,
-                                        const allocator::vector<Mapping>& mappings) {
+                                        const allocator::vector<Mapping>& mappings,
+                                        const allocator::vector<uintptr_t>& refs) {
   MEM_ALOGI("searching process %d for allocations", pid_);
   allocator::vector<Mapping> heap_mappings{mappings};
   allocator::vector<Mapping> anon_mappings{mappings};
@@ -118,6 +121,8 @@
     heap_walker_.Root(thread_it->regs);
   }
 
+  heap_walker_.Root(refs);
+
   MEM_ALOGI("searching done");
 
   return true;
@@ -282,6 +287,7 @@
     ThreadCapture thread_capture(parent_pid, heap);
     allocator::vector<ThreadInfo> thread_info(heap);
     allocator::vector<Mapping> mappings(heap);
+    allocator::vector<uintptr_t> refs(heap);
 
     // ptrace all the threads
     if (!thread_capture.CaptureThreads()) {
@@ -301,6 +307,11 @@
       return 1;
     }
 
+    if (!BinderReferences(refs)) {
+      continue_parent_sem.Post();
+      return 1;
+    }
+
     // malloc must be enabled to call fork, at_fork handlers take the same
     // locks as ScopedDisableMalloc.  All threads are paused in ptrace, so
     // memory state is still consistent.  Unfreeze the original thread so it
@@ -326,7 +337,7 @@
 
       MemUnreachable unreachable{parent_pid, heap};
 
-      if (!unreachable.CollectAllocations(thread_info, mappings)) {
+      if (!unreachable.CollectAllocations(thread_info, mappings, refs)) {
         _exit(2);
       }
       size_t num_allocations = unreachable.Allocations();
diff --git a/libmemunreachable/tests/AndroidTest.xml b/libmemunreachable/tests/AndroidTest.xml
new file mode 100644
index 0000000..604c0ec
--- /dev/null
+++ b/libmemunreachable/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 memunreachable_test">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="memunreachable_test->/data/local/tmp/memunreachable_test" />
+    </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="memunreachable_test" />
+    </test>
+</configuration>
diff --git a/libmemunreachable/tests/Binder_test.cpp b/libmemunreachable/tests/Binder_test.cpp
new file mode 100644
index 0000000..6e85d5a
--- /dev/null
+++ b/libmemunreachable/tests/Binder_test.cpp
@@ -0,0 +1,156 @@
+/*
+ * 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 <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+
+#include <gtest/gtest.h>
+
+#include "Allocator.h"
+#include "Binder.h"
+
+namespace android {
+
+static const String16 service_name("test.libmemunreachable_binder");
+
+class BinderService : public BBinder {
+ public:
+  BinderService() = default;
+  virtual ~BinderService() = default;
+
+  virtual status_t onTransact(uint32_t /*code*/, const Parcel& data, Parcel* reply,
+                              uint32_t /*flags*/ = 0) {
+    reply->writeStrongBinder(ref);
+    ref = data.readStrongBinder();
+    return 0;
+  }
+
+ private:
+  sp<IBinder> ref;
+};
+
+class BinderObject : public BBinder {
+ public:
+  BinderObject() = default;
+  ~BinderObject() = default;
+};
+
+class ServiceProcess {
+ public:
+  ServiceProcess() : child_(0) {}
+  ~ServiceProcess() { Stop(); }
+
+  bool Run() {
+    pid_t ret = fork();
+    if (ret < 0) {
+      return false;
+    } else if (ret == 0) {
+      // child
+      _exit(Service());
+    } else {
+      // parent
+      child_ = ret;
+      return true;
+    }
+  }
+
+  bool Stop() {
+    if (child_ > 0) {
+      if (kill(child_, SIGTERM)) {
+        return false;
+      }
+      int status = 0;
+      if (TEMP_FAILURE_RETRY(waitpid(child_, &status, 0)) != child_) {
+        return false;
+      }
+      child_ = 0;
+      return WIFEXITED(status) && WEXITSTATUS(status) == 0;
+    }
+
+    return true;
+  }
+
+  int Service() {
+    sp<ProcessState> proc{ProcessState::self()};
+    sp<IServiceManager> sm = defaultServiceManager();
+    if (sm == nullptr) {
+      fprintf(stderr, "Failed to get service manager\n");
+      return 1;
+    }
+    if (sm->addService(service_name, new BinderService()) != OK) {
+      fprintf(stderr, "Failed to add test service\n");
+      return 1;
+    }
+    proc->startThreadPool();
+    pause();
+    return 0;
+  }
+
+ private:
+  pid_t child_;
+};
+
+class BinderTest : public ::testing::Test {
+ protected:
+  ServiceProcess service_process_;
+};
+
+TEST_F(BinderTest, binder) {
+  ServiceProcess service_process;
+  ASSERT_TRUE(service_process.Run());
+
+  sp<IServiceManager> sm = defaultServiceManager();
+  ASSERT_TRUE(sm != nullptr);
+
+  // A small sleep allows the service to start, which
+  // prevents a longer sleep in getService.
+  usleep(100000);
+
+  sp<IBinder> service = sm->getService(service_name);
+  ASSERT_TRUE(service != nullptr);
+
+  sp<IBinder> binder{new BinderObject()};
+
+  Parcel send;
+  Parcel reply;
+
+  send.writeStrongBinder(binder);
+  status_t rv = service->transact(0, send, &reply);
+  ASSERT_EQ(static_cast<status_t>(OK), rv);
+
+  Heap heap;
+  allocator::vector<uintptr_t> refs{heap};
+
+  ASSERT_TRUE(BinderReferences(refs));
+
+  bool found_ref = false;
+  for (auto ref : refs) {
+    if (ref == reinterpret_cast<uintptr_t>(binder.get())) {
+      found_ref = true;
+    }
+  }
+
+  ASSERT_TRUE(found_ref);
+}
+
+}  // namespace android
diff --git a/libmetricslogger/Android.bp b/libmetricslogger/Android.bp
index 38859d1..c692d1f 100644
--- a/libmetricslogger/Android.bp
+++ b/libmetricslogger/Android.bp
@@ -7,7 +7,6 @@
 cc_defaults {
     name: "metricslogger_defaults",
 
-    clang: true,
     host_supported: true,
 
     export_include_dirs: ["include"],
@@ -31,7 +30,6 @@
 // -----------------------------------------------------------------------------
 cc_library_shared {
     name: "libmetricslogger",
-    vendor_available: true,
     srcs: metricslogger_lib_src_files,
     defaults: ["metricslogger_defaults"],
 }
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
index 377b7dd..8b48a87 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -1,11 +1,19 @@
 
+cc_library_headers {
+    name: "libnativebridge-dummy-headers",
+
+    host_supported: true,
+    export_include_dirs=["include"],
+}
+
 cc_library {
     name: "libnativebridge",
 
     host_supported: true,
     srcs: ["native_bridge.cc"],
     shared_libs: ["liblog"],
-    clang: true,
+
+    export_include_dirs=["include"],
 
     cflags: [
         "-Werror",
@@ -23,4 +31,4 @@
     },
 }
 
-subdirs = ["tests"]
\ No newline at end of file
+subdirs = ["tests"]
diff --git a/include/nativebridge/native_bridge.h b/libnativebridge/include/nativebridge/native_bridge.h
similarity index 100%
rename from include/nativebridge/native_bridge.h
rename to libnativebridge/include/nativebridge/native_bridge.h
diff --git a/libnativebridge/tests/Android.bp b/libnativebridge/tests/Android.bp
index efd3978..e31dae0 100644
--- a/libnativebridge/tests/Android.bp
+++ b/libnativebridge/tests/Android.bp
@@ -23,6 +23,7 @@
         "-Wextra",
         "-Werror",
     ],
+    header_libs: ["libnativebridge-dummy-headers"],
     cppflags: ["-fvisibility=protected"],
     target: {
         android: {
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index 70b3fcc..c1e65ff 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -34,7 +34,6 @@
 
 $(foreach file,$(test_src_files), \
     $(eval include $(CLEAR_VARS)) \
-    $(eval LOCAL_CLANG := true) \
     $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
     $(eval LOCAL_SRC_FILES := $(file)) \
     $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
@@ -43,7 +42,6 @@
 
 $(foreach file,$(test_src_files), \
     $(eval include $(CLEAR_VARS)) \
-    $(eval LOCAL_CLANG := true) \
     $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
     $(eval LOCAL_SRC_FILES := $(file)) \
     $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index c1133fb..13f9744 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -19,7 +19,6 @@
             host_ldlibs: ["-ldl"],
         },
     },
-    clang: true,
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 36a2e44..7ccd7db 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -15,7 +15,7 @@
  */
 
 #include "nativeloader/native_loader.h"
-#include "ScopedUtfChars.h"
+#include <nativehelper/ScopedUtfChars.h>
 
 #include <dlfcn.h>
 #ifdef __ANDROID__
diff --git a/libpackagelistparser/Android.bp b/libpackagelistparser/Android.bp
index 70ff528..a9fec7d 100644
--- a/libpackagelistparser/Android.bp
+++ b/libpackagelistparser/Android.bp
@@ -6,7 +6,6 @@
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
 
-    clang: true,
     sanitize: {
         misc_undefined: ["integer"],
     },
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index f0c3795..9fa4154 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -33,6 +33,10 @@
 
 int createProcessGroup(uid_t uid, int initialPid);
 
+bool setProcessGroupSwappiness(uid_t uid, int initialPid, int swappiness);
+bool setProcessGroupSoftLimit(uid_t uid, int initialPid, int64_t softLimitInBytes);
+bool setProcessGroupLimit(uid_t uid, int initialPid, int64_t limitInBytes);
+
 void removeAllProcessGroups(void);
 
 __END_DECLS
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 9b8248e..8526b3a 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -35,12 +35,15 @@
 #include <set>
 #include <thread>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 #include <private/android_filesystem_config.h>
 
 #include <processgroup/processgroup.h>
 
+using android::base::WriteStringToFile;
+
 using namespace std::chrono_literals;
 
 #define MEM_CGROUP_PATH "/dev/memcg/apps"
@@ -402,22 +405,40 @@
 
     strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
 
-    int fd = open(path, O_WRONLY);
-    if (fd == -1) {
-        int ret = -errno;
-        PLOG(ERROR) << "Failed to open " << path;
-        return ret;
-    }
-
-    char pid[PROCESSGROUP_MAX_PID_LEN + 1] = {0};
-    int len = snprintf(pid, sizeof(pid), "%d", initialPid);
-
     int ret = 0;
-    if (write(fd, pid, len) < 0) {
+    if (!WriteStringToFile(std::to_string(initialPid), path)) {
         ret = -errno;
-        PLOG(ERROR) << "Failed to write '" << pid << "' to " << path;
+        PLOG(ERROR) << "Failed to write '" << initialPid << "' to " << path;
     }
 
-    close(fd);
     return ret;
 }
+
+static bool setProcessGroupValue(uid_t uid, int pid, const char* fileName, int64_t value) {
+    char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
+    if (strcmp(getCgroupRootPath(), MEM_CGROUP_PATH)) {
+        PLOG(ERROR) << "Memcg is not mounted." << path;
+        return false;
+    }
+
+    convertUidPidToPath(path, sizeof(path), uid, pid);
+    strlcat(path, fileName, sizeof(path));
+
+    if (!WriteStringToFile(std::to_string(value), path)) {
+        PLOG(ERROR) << "Failed to write '" << value << "' to " << path;
+        return false;
+    }
+    return true;
+}
+
+bool setProcessGroupSwappiness(uid_t uid, int pid, int swappiness) {
+    return setProcessGroupValue(uid, pid, "/memory.swappiness", swappiness);
+}
+
+bool setProcessGroupSoftLimit(uid_t uid, int pid, int64_t soft_limit_in_bytes) {
+    return setProcessGroupValue(uid, pid, "/memory.soft_limit_in_bytes", soft_limit_in_bytes);
+}
+
+bool setProcessGroupLimit(uid_t uid, int pid, int64_t limit_in_bytes) {
+    return setProcessGroupValue(uid, pid, "/memory.limit_in_bytes", limit_in_bytes);
+}
diff --git a/libsync/Android.bp b/libsync/Android.bp
index 257d42d..1646348 100644
--- a/libsync/Android.bp
+++ b/libsync/Android.bp
@@ -52,5 +52,4 @@
         "-Wno-missing-field-initializers",
         "-Wno-sign-compare",
     ],
-    clang: true,
 }
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index 6f76e76..87e2684 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -211,7 +211,6 @@
     return;
 
 overflow:
-    LOG_EVENT_INT(78001, cli->getUid());
     cli->sendMsg(500, "Command too long", false);
     goto out;
 }
diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp
index 896dad3..aad0394 100644
--- a/libsysutils/src/NetlinkListener.cpp
+++ b/libsysutils/src/NetlinkListener.cpp
@@ -57,8 +57,6 @@
     count = TEMP_FAILURE_RETRY(uevent_kernel_recv(socket,
             mBuffer, sizeof(mBuffer), require_group, &uid));
     if (count < 0) {
-        if (uid > 0)
-            LOG_EVENT_INT(65537, uid);
         SLOGE("recvmsg failed (%s)", strerror(errno));
         return false;
     }
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 8776db7..04c4cfa 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -31,19 +31,20 @@
         },
     },
 
-    multilib: {
-        lib32: {
-            suffix: "32",
+    arch: {
+        mips: {
+            enabled: false,
         },
-        lib64: {
-            suffix: "64",
+        mips64: {
+            enabled: false,
         },
     },
 }
 
-cc_defaults {
-    name: "libunwindstack_common",
+cc_library {
+    name: "libunwindstack",
     defaults: ["libunwindstack_flags"],
+    export_include_dirs: ["include"],
 
     srcs: [
         "ArmExidx.cpp",
@@ -64,6 +65,15 @@
         "Symbols.cpp",
     ],
 
+    arch: {
+        x86: {
+            srcs: ["AsmGetRegsX86.S"],
+        },
+        x86_64: {
+            srcs: ["AsmGetRegsX86_64.S"],
+        },
+    },
+
     shared_libs: [
         "libbase",
         "liblog",
@@ -71,16 +81,11 @@
     ],
 }
 
-cc_library {
-    name: "libunwindstack",
-    defaults: ["libunwindstack_common"],
-}
-
 //-------------------------------------------------------------------------
 // Unit Tests
 //-------------------------------------------------------------------------
-cc_defaults {
-    name: "libunwindstack_test_common",
+cc_test {
+    name: "libunwindstack_test",
     defaults: ["libunwindstack_flags"],
 
     srcs: [
@@ -98,16 +103,22 @@
         "tests/ElfInterfaceArmTest.cpp",
         "tests/ElfInterfaceTest.cpp",
         "tests/ElfTest.cpp",
+        "tests/ElfTestUtils.cpp",
         "tests/LogFake.cpp",
-        "tests/MapInfoTest.cpp",
+        "tests/MapInfoCreateMemoryTest.cpp",
+        "tests/MapInfoGetElfTest.cpp",
         "tests/MapsTest.cpp",
+        "tests/MemoryBufferTest.cpp",
         "tests/MemoryFake.cpp",
         "tests/MemoryFileTest.cpp",
         "tests/MemoryLocalTest.cpp",
         "tests/MemoryRangeTest.cpp",
         "tests/MemoryRemoteTest.cpp",
+        "tests/MemoryTest.cpp",
+        "tests/RegsStepIfSignalHandlerTest.cpp",
         "tests/RegsTest.cpp",
         "tests/SymbolsTest.cpp",
+        "tests/UnwindTest.cpp",
     ],
 
     cflags: [
@@ -119,6 +130,7 @@
         "libbase",
         "liblog",
         "liblzma",
+        "libunwindstack",
     ],
 
     static_libs: [
@@ -132,28 +144,18 @@
             ],
         },
     },
-}
-
-// These unit tests run against the shared library.
-cc_test {
-    name: "libunwindstack_test",
-    defaults: ["libunwindstack_test_common"],
-
-    shared_libs: [
-        "libunwindstack",
-    ],
 
     data: [
-        "tests/elf32.xz",
-        "tests/elf64.xz",
+        "tests/files/elf32.xz",
+        "tests/files/elf64.xz",
     ],
 }
 
 //-------------------------------------------------------------------------
-// Utility Executables
+// Tools
 //-------------------------------------------------------------------------
 cc_defaults {
-    name: "libunwindstack_executables",
+    name: "libunwindstack_tools",
     defaults: ["libunwindstack_flags"],
 
     shared_libs: [
@@ -161,20 +163,40 @@
         "libbase",
         "liblzma",
     ],
+}
 
-    static_libs: [
-        "liblog",
+cc_binary {
+    name: "unwind",
+    defaults: ["libunwindstack_tools"],
+
+    srcs: [
+        "tools/unwind.cpp",
     ],
 
-    compile_multilib: "both",
+    target: {
+        linux: {
+            host_ldlibs: [
+                "-lrt",
+            ],
+        },
+    },
 }
 
 cc_binary {
     name: "unwind_info",
-    defaults: ["libunwindstack_executables"],
+    defaults: ["libunwindstack_tools"],
 
     srcs: [
-        "unwind_info.cpp",
+        "tools/unwind_info.cpp",
+    ],
+}
+
+cc_binary {
+    name: "unwind_symbols",
+    defaults: ["libunwindstack_tools"],
+
+    srcs: [
+        "tools/unwind_symbols.cpp",
     ],
 }
 
@@ -182,20 +204,9 @@
 // Once these files are generated, use the xz command to compress the data.
 cc_binary_host {
     name: "gen_gnudebugdata",
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wextra",
-    ],
+    defaults: ["libunwindstack_flags"],
 
     srcs: [
         "tests/GenGnuDebugdata.cpp",
     ],
-
-    target: {
-        darwin: {
-            enabled: false,
-        },
-    },
 }
diff --git a/libunwindstack/ArmExidx.cpp b/libunwindstack/ArmExidx.cpp
index 5c7caca..fed3e0e 100644
--- a/libunwindstack/ArmExidx.cpp
+++ b/libunwindstack/ArmExidx.cpp
@@ -21,12 +21,15 @@
 
 #include <android-base/stringprintf.h>
 
+#include <unwindstack/Log.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
 #include "ArmExidx.h"
 #include "Check.h"
-#include "Log.h"
 #include "Machine.h"
-#include "Memory.h"
-#include "Regs.h"
+
+namespace unwindstack {
 
 void ArmExidx::LogRawData() {
   std::string log_str("Raw Data:");
@@ -684,3 +687,5 @@
   while (Decode());
   return status_ == ARM_STATUS_FINISH;
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/ArmExidx.h b/libunwindstack/ArmExidx.h
index 8c7f15a..f4361d4 100644
--- a/libunwindstack/ArmExidx.h
+++ b/libunwindstack/ArmExidx.h
@@ -21,6 +21,8 @@
 
 #include <deque>
 
+namespace unwindstack {
+
 // Forward declarations.
 class Memory;
 class RegsArm;
@@ -105,4 +107,6 @@
   bool pc_set_ = false;
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_ARM_EXIDX_H
diff --git a/libunwindstack/AsmGetRegsX86.S b/libunwindstack/AsmGetRegsX86.S
new file mode 100644
index 0000000..14927a3
--- /dev/null
+++ b/libunwindstack/AsmGetRegsX86.S
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+  .text
+  .global AsmGetRegs
+  .balign 16
+  .type AsmGetRegs, @function
+AsmGetRegs:
+  .cfi_startproc
+  mov 4(%esp), %eax
+  movl $0, (%eax)
+  movl %ecx, 4(%eax)
+  movl %edx, 8(%eax)
+  movl %ebx, 12(%eax)
+
+  /* ESP */
+  leal 4(%esp), %ecx
+  movl %ecx, 16(%eax)
+
+  movl %ebp, 20(%eax)
+  movl %esi, 24(%eax)
+  movl %edi, 28(%eax)
+
+  /* EIP */
+  movl (%esp), %ecx
+  movl %ecx, 32(%eax)
+
+  movl %cs, 36(%eax)
+  movl %ss, 40(%eax)
+  movl %ds, 44(%eax)
+  movl %es, 48(%eax)
+  movl %fs, 52(%eax)
+  movl %gs, 56(%eax)
+  ret
+
+  .cfi_endproc
+  .size AsmGetRegs, .-AsmGetRegs
diff --git a/libunwindstack/AsmGetRegsX86_64.S b/libunwindstack/AsmGetRegsX86_64.S
new file mode 100644
index 0000000..4cd3b6f
--- /dev/null
+++ b/libunwindstack/AsmGetRegsX86_64.S
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+  .text
+  .global AsmGetRegs
+  .balign 16
+  .type AsmGetRegs, @function
+AsmGetRegs:
+  .cfi_startproc
+  movq %rax, (%rdi)
+  movq %rdx, 8(%rdi)
+  movq %rcx, 16(%rdi)
+  movq %rbx, 24(%rdi)
+  movq %rsi, 32(%rdi)
+  movq %rdi, 40(%rdi)
+  movq %rbp, 48(%rdi)
+
+  /* RSP */
+  lea 8(%rsp), %rax
+  movq %rax, 56(%rdi)
+
+  movq %r8, 64(%rdi)
+  movq %r9, 72(%rdi)
+  movq %r10, 80(%rdi)
+  movq %r11, 88(%rdi)
+  movq %r12, 96(%rdi)
+  movq %r13, 104(%rdi)
+  movq %r14, 112(%rdi)
+  movq %r15, 120(%rdi)
+
+  /* RIP */
+  movq (%rsp), %rax
+  movq %rax, 128(%rdi)
+  ret
+
+  .cfi_endproc
+  .size AsmGetRegs, .-AsmGetRegs
diff --git a/libunwindstack/Check.h b/libunwindstack/Check.h
index e0c48c7..2d216d7 100644
--- a/libunwindstack/Check.h
+++ b/libunwindstack/Check.h
@@ -19,7 +19,9 @@
 
 #include <stdlib.h>
 
-#include "Log.h"
+#include <unwindstack/Log.h>
+
+namespace unwindstack {
 
 #define CHECK(assertion)                                   \
   if (__builtin_expect(!(assertion), false)) {             \
@@ -27,4 +29,6 @@
     abort();                                               \
   }
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_ERROR_H
diff --git a/libunwindstack/DwarfCfa.cpp b/libunwindstack/DwarfCfa.cpp
index 006f039..b1d55ba 100644
--- a/libunwindstack/DwarfCfa.cpp
+++ b/libunwindstack/DwarfCfa.cpp
@@ -23,12 +23,15 @@
 
 #include <android-base/stringprintf.h>
 
+#include <unwindstack/DwarfLocation.h>
+#include <unwindstack/Log.h>
+
 #include "DwarfCfa.h"
 #include "DwarfEncoding.h"
-#include "DwarfMemory.h"
+#include "DwarfError.h"
 #include "DwarfOp.h"
-#include "DwarfStructs.h"
-#include "Log.h"
+
+namespace unwindstack {
 
 template <typename AddressType>
 constexpr typename DwarfCfa<AddressType>::process_func DwarfCfa<AddressType>::kCallbackTable[64];
@@ -711,3 +714,5 @@
 // Explicitly instantiate DwarfCfa.
 template class DwarfCfa<uint32_t>;
 template class DwarfCfa<uint64_t>;
+
+}  // namespace unwindstack
diff --git a/libunwindstack/DwarfCfa.h b/libunwindstack/DwarfCfa.h
index 42ebae1..62b9b7a 100644
--- a/libunwindstack/DwarfCfa.h
+++ b/libunwindstack/DwarfCfa.h
@@ -24,10 +24,13 @@
 #include <type_traits>
 #include <vector>
 
+#include <unwindstack/DwarfLocation.h>
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/DwarfStructs.h>
+
 #include "DwarfError.h"
-#include "DwarfLocation.h"
-#include "DwarfMemory.h"
-#include "DwarfStructs.h"
+
+namespace unwindstack {
 
 // DWARF Standard home: http://dwarfstd.org/
 // This code is based on DWARF 4: http://http://dwarfstd.org/doc/DWARF4.pdf
@@ -252,4 +255,6 @@
   };
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_DWARF_CFA_H
diff --git a/libunwindstack/DwarfDebugFrame.cpp b/libunwindstack/DwarfDebugFrame.cpp
index 3ac02fc..5707596 100644
--- a/libunwindstack/DwarfDebugFrame.cpp
+++ b/libunwindstack/DwarfDebugFrame.cpp
@@ -19,11 +19,14 @@
 
 #include <algorithm>
 
+#include <unwindstack/DwarfStructs.h>
+#include <unwindstack/Memory.h>
+
 #include "DwarfDebugFrame.h"
-#include "DwarfMemory.h"
-#include "DwarfSection.h"
-#include "DwarfStructs.h"
-#include "Memory.h"
+#include "DwarfEncoding.h"
+#include "DwarfError.h"
+
+namespace unwindstack {
 
 template <typename AddressType>
 bool DwarfDebugFrame<AddressType>::Init(uint64_t offset, uint64_t size) {
@@ -309,3 +312,5 @@
 // Explicitly instantiate DwarfDebugFrame.
 template class DwarfDebugFrame<uint32_t>;
 template class DwarfDebugFrame<uint64_t>;
+
+}  // namespace unwindstack
diff --git a/libunwindstack/DwarfDebugFrame.h b/libunwindstack/DwarfDebugFrame.h
index 320368c..6a6178e 100644
--- a/libunwindstack/DwarfDebugFrame.h
+++ b/libunwindstack/DwarfDebugFrame.h
@@ -21,7 +21,9 @@
 
 #include <vector>
 
-#include "DwarfSection.h"
+#include <unwindstack/DwarfSection.h>
+
+namespace unwindstack {
 
 template <typename AddressType>
 class DwarfDebugFrame : public DwarfSectionImpl<AddressType> {
@@ -73,4 +75,6 @@
   std::vector<FdeInfo> fdes_;
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_DWARF_DEBUG_FRAME_H
diff --git a/libunwindstack/DwarfEhFrame.cpp b/libunwindstack/DwarfEhFrame.cpp
index 937b6bd..d0b35c3 100644
--- a/libunwindstack/DwarfEhFrame.cpp
+++ b/libunwindstack/DwarfEhFrame.cpp
@@ -16,12 +16,14 @@
 
 #include <stdint.h>
 
+#include <unwindstack/DwarfStructs.h>
+#include <unwindstack/Memory.h>
+
 #include "Check.h"
 #include "DwarfEhFrame.h"
-#include "DwarfMemory.h"
-#include "DwarfSection.h"
-#include "DwarfStructs.h"
-#include "Memory.h"
+#include "DwarfError.h"
+
+namespace unwindstack {
 
 template <typename AddressType>
 bool DwarfEhFrame<AddressType>::Init(uint64_t offset, uint64_t size) {
@@ -211,3 +213,5 @@
 // Explicitly instantiate DwarfEhFrame.
 template class DwarfEhFrame<uint32_t>;
 template class DwarfEhFrame<uint64_t>;
+
+}  // namespace unwindstack
diff --git a/libunwindstack/DwarfEhFrame.h b/libunwindstack/DwarfEhFrame.h
index e6909ed..4207b42 100644
--- a/libunwindstack/DwarfEhFrame.h
+++ b/libunwindstack/DwarfEhFrame.h
@@ -19,7 +19,9 @@
 
 #include <stdint.h>
 
-#include "DwarfSection.h"
+#include <unwindstack/DwarfSection.h>
+
+namespace unwindstack {
 
 // Forward declarations.
 class Memory;
@@ -86,4 +88,6 @@
   std::unordered_map<uint64_t, FdeInfo> fde_info_;
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_DWARF_EH_FRAME_H
diff --git a/libunwindstack/DwarfEncoding.h b/libunwindstack/DwarfEncoding.h
index 0ff3b8c..20db222 100644
--- a/libunwindstack/DwarfEncoding.h
+++ b/libunwindstack/DwarfEncoding.h
@@ -19,6 +19,8 @@
 
 #include <stdint.h>
 
+namespace unwindstack {
+
 enum DwarfEncoding : uint8_t {
   DW_EH_PE_omit = 0xff,
 
@@ -44,4 +46,6 @@
   DW_EH_PE_block = 0x0f,
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_DWARF_ENCODING_H
diff --git a/libunwindstack/DwarfError.h b/libunwindstack/DwarfError.h
index c00f17d..54199b8 100644
--- a/libunwindstack/DwarfError.h
+++ b/libunwindstack/DwarfError.h
@@ -19,6 +19,8 @@
 
 #include <stdint.h>
 
+namespace unwindstack {
+
 enum DwarfError : uint8_t {
   DWARF_ERROR_NONE,
   DWARF_ERROR_MEMORY_INVALID,
@@ -31,4 +33,6 @@
   DWARF_ERROR_UNSUPPORTED_VERSION,
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_DWARF_ERROR_H
diff --git a/libunwindstack/DwarfMemory.cpp b/libunwindstack/DwarfMemory.cpp
index a984fc6..b6e0412 100644
--- a/libunwindstack/DwarfMemory.cpp
+++ b/libunwindstack/DwarfMemory.cpp
@@ -18,10 +18,13 @@
 
 #include <string>
 
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/Memory.h>
+
 #include "Check.h"
 #include "DwarfEncoding.h"
-#include "DwarfMemory.h"
-#include "Memory.h"
+
+namespace unwindstack {
 
 bool DwarfMemory::ReadBytes(void* dst, size_t num_bytes) {
   if (!memory_->Read(cur_offset_, dst, num_bytes)) {
@@ -246,3 +249,5 @@
 
 template bool DwarfMemory::ReadEncodedValue<uint32_t>(uint8_t, uint64_t*);
 template bool DwarfMemory::ReadEncodedValue<uint64_t>(uint8_t, uint64_t*);
+
+}  // namespace unwindstack
diff --git a/libunwindstack/DwarfOp.cpp b/libunwindstack/DwarfOp.cpp
index 507ca08..b3fd0df 100644
--- a/libunwindstack/DwarfOp.cpp
+++ b/libunwindstack/DwarfOp.cpp
@@ -22,12 +22,15 @@
 
 #include <android-base/stringprintf.h>
 
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/Log.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
 #include "DwarfError.h"
-#include "DwarfMemory.h"
 #include "DwarfOp.h"
-#include "Log.h"
-#include "Memory.h"
-#include "Regs.h"
+
+namespace unwindstack {
 
 template <typename AddressType>
 constexpr typename DwarfOp<AddressType>::OpCallback DwarfOp<AddressType>::kCallbackTable[256];
@@ -460,3 +463,5 @@
 // Explicitly instantiate DwarfOp.
 template class DwarfOp<uint32_t>;
 template class DwarfOp<uint64_t>;
+
+}  // namespace unwindstack
diff --git a/libunwindstack/DwarfOp.h b/libunwindstack/DwarfOp.h
index 0f4b36d..c29bf35 100644
--- a/libunwindstack/DwarfOp.h
+++ b/libunwindstack/DwarfOp.h
@@ -25,6 +25,9 @@
 #include <vector>
 
 #include "DwarfEncoding.h"
+#include "DwarfError.h"
+
+namespace unwindstack {
 
 enum DwarfVersion : uint8_t {
   DWARF_VERSION_2 = 2,
@@ -1633,4 +1636,6 @@
   };
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_DWARF_OP_H
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 4c98aa3..1234eb1 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -16,16 +16,22 @@
 
 #include <stdint.h>
 
+#include <unwindstack/DwarfLocation.h>
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/DwarfSection.h>
+#include <unwindstack/DwarfStructs.h>
+#include <unwindstack/Log.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
 #include "DwarfCfa.h"
+#include "DwarfEncoding.h"
 #include "DwarfError.h"
-#include "DwarfLocation.h"
-#include "DwarfMemory.h"
 #include "DwarfOp.h"
-#include "DwarfSection.h"
-#include "DwarfStructs.h"
-#include "Log.h"
-#include "Memory.h"
-#include "Regs.h"
+
+namespace unwindstack {
+
+DwarfSection::DwarfSection(Memory* memory) : memory_(memory), last_error_(DWARF_ERROR_NONE) {}
 
 const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
   uint64_t fde_offset;
@@ -42,6 +48,7 @@
 }
 
 bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory) {
+  last_error_ = DWARF_ERROR_NONE;
   const DwarfFde* fde = GetFdeFromPc(pc);
   if (fde == nullptr || fde->cie == nullptr) {
     last_error_ = DWARF_ERROR_ILLEGAL_STATE;
@@ -248,6 +255,9 @@
     last_error_ = DWARF_ERROR_MEMORY_INVALID;
     return false;
   }
+  // Set the default for the lsda encoding.
+  cie->lsda_encoding = DW_EH_PE_omit;
+
   if (length32 == static_cast<uint32_t>(-1)) {
     // 64 bit Cie
     uint64_t length64;
@@ -541,3 +551,5 @@
 // Explicitly instantiate DwarfSectionImpl
 template class DwarfSectionImpl<uint32_t>;
 template class DwarfSectionImpl<uint64_t>;
+
+}  // namespace unwindstack
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index ad1447a..4fc7c67 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -23,12 +23,17 @@
 #define LOG_TAG "unwind"
 #include <log/log.h>
 
-#include "Elf.h"
-#include "ElfInterface.h"
+#include <unwindstack/Elf.h>
+#include <unwindstack/ElfInterface.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
 #include "ElfInterfaceArm.h"
 #include "Machine.h"
-#include "Memory.h"
-#include "Regs.h"
+#include "Symbols.h"
+
+namespace unwindstack {
 
 bool Elf::Init() {
   if (!memory_) {
@@ -71,6 +76,37 @@
   }
 }
 
+bool Elf::GetSoname(std::string* name) {
+  return valid_ && interface_->GetSoname(name);
+}
+
+uint64_t Elf::GetRelPc(uint64_t pc, const MapInfo* map_info) {
+  uint64_t load_bias = 0;
+  if (valid()) {
+    load_bias = interface_->load_bias();
+  }
+
+  return pc - map_info->start + load_bias + map_info->elf_offset;
+}
+
+bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
+  return valid_ && (interface_->GetFunctionName(addr, name, func_offset) ||
+                    (gnu_debugdata_interface_ &&
+                     gnu_debugdata_interface_->GetFunctionName(addr, name, func_offset)));
+}
+
+bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory) {
+  return valid_ && (regs->StepIfSignalHandler(rel_pc, this, process_memory) ||
+                    interface_->Step(rel_pc, regs, process_memory) ||
+                    (gnu_debugdata_interface_ &&
+                     gnu_debugdata_interface_->Step(rel_pc, regs, process_memory)));
+}
+
+uint64_t Elf::GetLoadBias() {
+  if (!valid_) return 0;
+  return interface_->load_bias();
+}
+
 bool Elf::IsValidElf(Memory* memory) {
   if (memory == nullptr) {
     return false;
@@ -112,24 +148,27 @@
     machine_type_ = e_machine;
     if (e_machine == EM_ARM) {
       interface.reset(new ElfInterfaceArm(memory));
-    } else {
+    } else if (e_machine == EM_386) {
       interface.reset(new ElfInterface32(memory));
+    } else {
+      ALOGI("32 bit elf that is neither arm nor x86: e_machine = %d\n", e_machine);
+      return nullptr;
     }
   } else if (class_type_ == ELFCLASS64) {
     Elf64_Half e_machine;
     if (!memory->Read(EI_NIDENT + sizeof(Elf64_Half), &e_machine, sizeof(e_machine))) {
       return nullptr;
     }
-
     if (e_machine != EM_AARCH64 && e_machine != EM_X86_64) {
       // Unsupported.
       ALOGI("64 bit elf that is neither aarch64 nor x86_64: e_machine = %d\n", e_machine);
       return nullptr;
     }
-
     machine_type_ = e_machine;
     interface.reset(new ElfInterface64(memory));
   }
 
   return interface.release();
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 7d38ee0..75abc85 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -24,15 +24,18 @@
 #include <Xz.h>
 #include <XzCrc64.h>
 
+#include <unwindstack/DwarfSection.h>
+#include <unwindstack/ElfInterface.h>
+#include <unwindstack/Log.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
 #include "DwarfDebugFrame.h"
 #include "DwarfEhFrame.h"
-#include "DwarfSection.h"
-#include "ElfInterface.h"
-#include "Log.h"
-#include "Memory.h"
-#include "Regs.h"
 #include "Symbols.h"
 
+namespace unwindstack {
+
 ElfInterface::~ElfInterface() {
   for (auto symbol : symbols_) {
     delete symbol;
@@ -387,3 +390,5 @@
                                                                    uint64_t*);
 template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*,
                                                                    uint64_t*);
+
+}  // namespace unwindstack
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index bab84cc..66bc51f 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -17,12 +17,14 @@
 #include <elf.h>
 #include <stdint.h>
 
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
 #include "ArmExidx.h"
-#include "ElfInterface.h"
 #include "ElfInterfaceArm.h"
 #include "Machine.h"
-#include "Memory.h"
-#include "Regs.h"
+
+namespace unwindstack {
 
 bool ElfInterfaceArm::FindEntry(uint32_t pc, uint64_t* entry_offset) {
   if (start_offset_ == 0 || total_entries_ == 0) {
@@ -127,3 +129,5 @@
   }
   return false;
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/ElfInterfaceArm.h b/libunwindstack/ElfInterfaceArm.h
index ece694f..1f4e8cb 100644
--- a/libunwindstack/ElfInterfaceArm.h
+++ b/libunwindstack/ElfInterfaceArm.h
@@ -23,8 +23,10 @@
 #include <iterator>
 #include <unordered_map>
 
-#include "ElfInterface.h"
-#include "Memory.h"
+#include <unwindstack/ElfInterface.h>
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
 
 class ElfInterfaceArm : public ElfInterface32 {
  public:
@@ -87,4 +89,6 @@
   std::unordered_map<size_t, uint32_t> addrs_;
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_ELF_INTERFACE_ARM_H
diff --git a/libunwindstack/Log.cpp b/libunwindstack/Log.cpp
index faeb66c..436e23c 100644
--- a/libunwindstack/Log.cpp
+++ b/libunwindstack/Log.cpp
@@ -25,7 +25,9 @@
 
 #include <android-base/stringprintf.h>
 
-#include "Log.h"
+#include <unwindstack/Log.h>
+
+namespace unwindstack {
 
 static bool g_print_to_stdout = false;
 
@@ -51,3 +53,5 @@
   }
   va_end(args);
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/Machine.h b/libunwindstack/Machine.h
index 323ce80..1fb9309 100644
--- a/libunwindstack/Machine.h
+++ b/libunwindstack/Machine.h
@@ -19,6 +19,8 @@
 
 #include <stdint.h>
 
+namespace unwindstack {
+
 enum ArmReg : uint16_t {
   ARM_REG_R0 = 0,
   ARM_REG_R1,
@@ -83,51 +85,57 @@
   ARM64_REG_LR = ARM64_REG_R30,
 };
 
+// Matches the numbers for the registers as generated by compilers.
+// If this is changed, then unwinding will fail.
 enum X86Reg : uint16_t {
   X86_REG_EAX = 0,
-  X86_REG_ECX,
-  X86_REG_EDX,
-  X86_REG_EBX,
-  X86_REG_ESP,
-  X86_REG_EBP,
-  X86_REG_ESI,
-  X86_REG_EDI,
-  X86_REG_EIP,
-  X86_REG_EFL,
-  X86_REG_CS,
-  X86_REG_SS,
-  X86_REG_DS,
-  X86_REG_ES,
-  X86_REG_FS,
-  X86_REG_GS,
+  X86_REG_ECX = 1,
+  X86_REG_EDX = 2,
+  X86_REG_EBX = 3,
+  X86_REG_ESP = 4,
+  X86_REG_EBP = 5,
+  X86_REG_ESI = 6,
+  X86_REG_EDI = 7,
+  X86_REG_EIP = 8,
+  X86_REG_EFL = 9,
+  X86_REG_CS = 10,
+  X86_REG_SS = 11,
+  X86_REG_DS = 12,
+  X86_REG_ES = 13,
+  X86_REG_FS = 14,
+  X86_REG_GS = 15,
   X86_REG_LAST,
 
   X86_REG_SP = X86_REG_ESP,
   X86_REG_PC = X86_REG_EIP,
 };
 
+// Matches the numbers for the registers as generated by compilers.
+// If this is changed, then unwinding will fail.
 enum X86_64Reg : uint16_t {
   X86_64_REG_RAX = 0,
-  X86_64_REG_RDX,
-  X86_64_REG_RCX,
-  X86_64_REG_RBX,
-  X86_64_REG_RSI,
-  X86_64_REG_RDI,
-  X86_64_REG_RBP,
-  X86_64_REG_RSP,
-  X86_64_REG_R8,
-  X86_64_REG_R9,
-  X86_64_REG_R10,
-  X86_64_REG_R11,
-  X86_64_REG_R12,
-  X86_64_REG_R13,
-  X86_64_REG_R14,
-  X86_64_REG_R15,
-  X86_64_REG_RIP,
+  X86_64_REG_RDX = 1,
+  X86_64_REG_RCX = 2,
+  X86_64_REG_RBX = 3,
+  X86_64_REG_RSI = 4,
+  X86_64_REG_RDI = 5,
+  X86_64_REG_RBP = 6,
+  X86_64_REG_RSP = 7,
+  X86_64_REG_R8 = 8,
+  X86_64_REG_R9 = 9,
+  X86_64_REG_R10 = 10,
+  X86_64_REG_R11 = 11,
+  X86_64_REG_R12 = 12,
+  X86_64_REG_R13 = 13,
+  X86_64_REG_R14 = 14,
+  X86_64_REG_R15 = 15,
+  X86_64_REG_RIP = 16,
   X86_64_REG_LAST,
 
   X86_64_REG_SP = X86_64_REG_RSP,
   X86_64_REG_PC = X86_64_REG_RIP,
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_MACHINE_H
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 051f700..d0e1216 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -20,10 +20,12 @@
 #include <memory>
 #include <string>
 
-#include "Elf.h"
-#include "MapInfo.h"
-#include "Maps.h"
-#include "Memory.h"
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
 
 Memory* MapInfo::CreateMemory(pid_t pid) {
   if (end <= start) {
@@ -73,14 +75,18 @@
   return new MemoryRange(memory, start, end);
 }
 
-Elf* MapInfo::GetElf(pid_t pid, bool) {
+Elf* MapInfo::GetElf(pid_t pid, bool init_gnu_debugdata) {
   if (elf) {
     return elf;
   }
 
   elf = new Elf(CreateMemory(pid));
-  elf->Init();
+  if (elf->Init() && init_gnu_debugdata) {
+    elf->InitGnuDebugdata();
+  }
   // If the init fails, keep the elf around as an invalid object so we
   // don't try to reinit the object.
   return elf;
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index b869918..8a90423 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -29,7 +29,11 @@
 #include <string>
 #include <vector>
 
-#include "Maps.h"
+#include <unwindstack/Elf.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
 
 MapInfo* Maps::Find(uint64_t pc) {
   if (maps_.empty()) {
@@ -196,3 +200,5 @@
   }
   return true;
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index 9e46509..8c36055 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -28,7 +28,11 @@
 
 #include <android-base/unique_fd.h>
 
-#include "Memory.h"
+#include <unwindstack/Memory.h>
+
+#include "Check.h"
+
+namespace unwindstack {
 
 bool Memory::ReadString(uint64_t addr, std::string* string, uint64_t max_read) {
   string->clear();
@@ -245,6 +249,11 @@
   return true;
 }
 
+MemoryRange::MemoryRange(Memory* memory, uint64_t begin, uint64_t end)
+    : memory_(memory), begin_(begin), length_(end - begin) {
+  CHECK(end > begin);
+}
+
 bool MemoryRange::Read(uint64_t addr, void* dst, size_t size) {
   uint64_t max_read;
   if (__builtin_add_overflow(addr, size, &max_read) || max_read > length_) {
@@ -253,3 +262,5 @@
   // The check above guarantees that addr + begin_ will not overflow.
   return memory_->Read(addr + begin_, dst, size);
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index da22b07..dea7b87 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -21,23 +21,17 @@
 
 #include <vector>
 
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
 #include "Check.h"
-#include "Elf.h"
-#include "ElfInterface.h"
 #include "Machine.h"
-#include "MapInfo.h"
-#include "Regs.h"
+#include "Ucontext.h"
 #include "User.h"
 
-template <typename AddressType>
-uint64_t RegsImpl<AddressType>::GetRelPc(Elf* elf, const MapInfo* map_info) {
-  uint64_t load_bias = 0;
-  if (elf->valid()) {
-    load_bias = elf->interface()->load_bias();
-  }
-
-  return pc_ - map_info->start + load_bias + map_info->elf_offset;
-}
+namespace unwindstack {
 
 template <typename AddressType>
 bool RegsImpl<AddressType>::GetReturnAddressFromDefault(Memory* memory, uint64_t* value) {
@@ -88,6 +82,11 @@
   return rel_pc - 4;
 }
 
+void RegsArm::SetFromRaw() {
+  set_pc(regs_[ARM_REG_PC]);
+  set_sp(regs_[ARM_REG_SP]);
+}
+
 RegsArm64::RegsArm64()
     : RegsImpl<uint64_t>(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {}
 
@@ -102,6 +101,11 @@
   return rel_pc - 4;
 }
 
+void RegsArm64::SetFromRaw() {
+  set_pc(regs_[ARM64_REG_PC]);
+  set_sp(regs_[ARM64_REG_SP]);
+}
+
 RegsX86::RegsX86()
     : RegsImpl<uint32_t>(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {}
 
@@ -116,6 +120,11 @@
   return rel_pc - 1;
 }
 
+void RegsX86::SetFromRaw() {
+  set_pc(regs_[X86_REG_PC]);
+  set_sp(regs_[X86_REG_SP]);
+}
+
 RegsX86_64::RegsX86_64()
     : RegsImpl<uint64_t>(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {}
 
@@ -131,15 +140,17 @@
   return rel_pc - 1;
 }
 
+void RegsX86_64::SetFromRaw() {
+  set_pc(regs_[X86_64_REG_PC]);
+  set_sp(regs_[X86_64_REG_SP]);
+}
+
 static Regs* ReadArm(void* remote_data) {
   arm_user_regs* user = reinterpret_cast<arm_user_regs*>(remote_data);
 
   RegsArm* regs = new RegsArm();
   memcpy(regs->RawData(), &user->regs[0], ARM_REG_LAST * sizeof(uint32_t));
-
-  regs->set_pc(user->regs[ARM_REG_PC]);
-  regs->set_sp(user->regs[ARM_REG_SP]);
-
+  regs->SetFromRaw();
   return regs;
 }
 
@@ -148,9 +159,10 @@
 
   RegsArm64* regs = new RegsArm64();
   memcpy(regs->RawData(), &user->regs[0], (ARM64_REG_R31 + 1) * sizeof(uint64_t));
-  regs->set_pc(user->pc);
-  regs->set_sp(user->sp);
-
+  uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
+  reg_data[ARM64_REG_PC] = user->pc;
+  reg_data[ARM64_REG_SP] = user->sp;
+  regs->SetFromRaw();
   return regs;
 }
 
@@ -168,9 +180,7 @@
   (*regs)[X86_REG_ESP] = user->esp;
   (*regs)[X86_REG_EIP] = user->eip;
 
-  regs->set_pc(user->eip);
-  regs->set_sp(user->esp);
-
+  regs->SetFromRaw();
   return regs;
 }
 
@@ -196,9 +206,7 @@
   (*regs)[X86_64_REG_RSP] = user->rsp;
   (*regs)[X86_64_REG_RIP] = user->rip;
 
-  regs->set_pc(user->rip);
-  regs->set_sp(user->rsp);
-
+  regs->SetFromRaw();
   return regs;
 }
 
@@ -231,3 +239,302 @@
   }
   return nullptr;
 }
+
+static Regs* CreateFromArmUcontext(void* ucontext) {
+  arm_ucontext_t* arm_ucontext = reinterpret_cast<arm_ucontext_t*>(ucontext);
+
+  RegsArm* regs = new RegsArm();
+  memcpy(regs->RawData(), &arm_ucontext->uc_mcontext.regs[0], ARM_REG_LAST * sizeof(uint32_t));
+  regs->SetFromRaw();
+  return regs;
+}
+
+static Regs* CreateFromArm64Ucontext(void* ucontext) {
+  arm64_ucontext_t* arm64_ucontext = reinterpret_cast<arm64_ucontext_t*>(ucontext);
+
+  RegsArm64* regs = new RegsArm64();
+  memcpy(regs->RawData(), &arm64_ucontext->uc_mcontext.regs[0], ARM64_REG_LAST * sizeof(uint64_t));
+  regs->SetFromRaw();
+  return regs;
+}
+
+void RegsX86::SetFromUcontext(x86_ucontext_t* ucontext) {
+  // Put the registers in the expected order.
+  regs_[X86_REG_EDI] = ucontext->uc_mcontext.edi;
+  regs_[X86_REG_ESI] = ucontext->uc_mcontext.esi;
+  regs_[X86_REG_EBP] = ucontext->uc_mcontext.ebp;
+  regs_[X86_REG_ESP] = ucontext->uc_mcontext.esp;
+  regs_[X86_REG_EBX] = ucontext->uc_mcontext.ebx;
+  regs_[X86_REG_EDX] = ucontext->uc_mcontext.edx;
+  regs_[X86_REG_ECX] = ucontext->uc_mcontext.ecx;
+  regs_[X86_REG_EAX] = ucontext->uc_mcontext.eax;
+  regs_[X86_REG_EIP] = ucontext->uc_mcontext.eip;
+  SetFromRaw();
+}
+
+static Regs* CreateFromX86Ucontext(void* ucontext) {
+  x86_ucontext_t* x86_ucontext = reinterpret_cast<x86_ucontext_t*>(ucontext);
+
+  RegsX86* regs = new RegsX86();
+  regs->SetFromUcontext(x86_ucontext);
+  return regs;
+}
+
+void RegsX86_64::SetFromUcontext(x86_64_ucontext_t* ucontext) {
+  // R8-R15
+  memcpy(&regs_[X86_64_REG_R8], &ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));
+
+  // Rest of the registers.
+  regs_[X86_64_REG_RDI] = ucontext->uc_mcontext.rdi;
+  regs_[X86_64_REG_RSI] = ucontext->uc_mcontext.rsi;
+  regs_[X86_64_REG_RBP] = ucontext->uc_mcontext.rbp;
+  regs_[X86_64_REG_RBX] = ucontext->uc_mcontext.rbx;
+  regs_[X86_64_REG_RDX] = ucontext->uc_mcontext.rdx;
+  regs_[X86_64_REG_RAX] = ucontext->uc_mcontext.rax;
+  regs_[X86_64_REG_RCX] = ucontext->uc_mcontext.rcx;
+  regs_[X86_64_REG_RSP] = ucontext->uc_mcontext.rsp;
+  regs_[X86_64_REG_RIP] = ucontext->uc_mcontext.rip;
+
+  SetFromRaw();
+}
+
+static Regs* CreateFromX86_64Ucontext(void* ucontext) {
+  x86_64_ucontext_t* x86_64_ucontext = reinterpret_cast<x86_64_ucontext_t*>(ucontext);
+
+  RegsX86_64* regs = new RegsX86_64();
+  regs->SetFromUcontext(x86_64_ucontext);
+  return regs;
+}
+
+Regs* Regs::CreateFromUcontext(uint32_t machine_type, void* ucontext) {
+  switch (machine_type) {
+    case EM_386:
+      return CreateFromX86Ucontext(ucontext);
+    case EM_X86_64:
+      return CreateFromX86_64Ucontext(ucontext);
+    case EM_ARM:
+      return CreateFromArmUcontext(ucontext);
+    case EM_AARCH64:
+      return CreateFromArm64Ucontext(ucontext);
+  }
+  return nullptr;
+}
+
+uint32_t Regs::GetMachineType() {
+#if defined(__arm__)
+  return EM_ARM;
+#elif defined(__aarch64__)
+  return EM_AARCH64;
+#elif defined(__i386__)
+  return EM_386;
+#elif defined(__x86_64__)
+  return EM_X86_64;
+#else
+  abort();
+#endif
+}
+
+Regs* Regs::CreateFromLocal() {
+  Regs* regs;
+#if defined(__arm__)
+  regs = new RegsArm();
+#elif defined(__aarch64__)
+  regs = new RegsArm64();
+#elif defined(__i386__)
+  regs = new RegsX86();
+#elif defined(__x86_64__)
+  regs = new RegsX86_64();
+#else
+  abort();
+#endif
+  return regs;
+}
+
+bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+  uint32_t data;
+  Memory* elf_memory = elf->memory();
+  // Read from elf memory since it is usually more expensive to read from
+  // process memory.
+  if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
+    return false;
+  }
+
+  uint64_t offset = 0;
+  if (data == 0xe3a07077 || data == 0xef900077 || data == 0xdf002777) {
+    // non-RT sigreturn call.
+    // __restore:
+    //
+    // Form 1 (arm):
+    // 0x77 0x70              mov r7, #0x77
+    // 0xa0 0xe3              svc 0x00000000
+    //
+    // Form 2 (arm):
+    // 0x77 0x00 0x90 0xef    svc 0x00900077
+    //
+    // Form 3 (thumb):
+    // 0x77 0x27              movs r7, #77
+    // 0x00 0xdf              svc 0
+    if (!process_memory->Read(sp(), &data, sizeof(data))) {
+      return false;
+    }
+    if (data == 0x5ac3c35a) {
+      // SP + uc_mcontext offset + r0 offset.
+      offset = sp() + 0x14 + 0xc;
+    } else {
+      // SP + r0 offset
+      offset = sp() + 0xc;
+    }
+  } else if (data == 0xe3a070ad || data == 0xef9000ad || data == 0xdf0027ad) {
+    // RT sigreturn call.
+    // __restore_rt:
+    //
+    // Form 1 (arm):
+    // 0xad 0x70      mov r7, #0xad
+    // 0xa0 0xe3      svc 0x00000000
+    //
+    // Form 2 (arm):
+    // 0xad 0x00 0x90 0xef    svc 0x009000ad
+    //
+    // Form 3 (thumb):
+    // 0xad 0x27              movs r7, #ad
+    // 0x00 0xdf              svc 0
+    if (!process_memory->Read(sp(), &data, sizeof(data))) {
+      return false;
+    }
+    if (data == sp() + 8) {
+      // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
+      offset = sp() + 8 + 0x80 + 0x14 + 0xc;
+    } else {
+      // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
+      offset = sp() + 0x80 + 0x14 + 0xc;
+    }
+  }
+  if (offset == 0) {
+    return false;
+  }
+
+  if (!process_memory->Read(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
+    return false;
+  }
+  SetFromRaw();
+  return true;
+}
+
+bool RegsArm64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+  uint64_t data;
+  Memory* elf_memory = elf->memory();
+  // Read from elf memory since it is usually more expensive to read from
+  // process memory.
+  if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
+    return false;
+  }
+
+  // Look for the kernel sigreturn function.
+  // __kernel_rt_sigreturn:
+  // 0xd2801168     mov x8, #0x8b
+  // 0xd4000001     svc #0x0
+  if (data != 0xd4000001d2801168ULL) {
+    return false;
+  }
+
+  // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
+  if (!process_memory->Read(sp() + 0x80 + 0xb0 + 0x08, regs_.data(),
+                            sizeof(uint64_t) * ARM64_REG_LAST)) {
+    return false;
+  }
+
+  SetFromRaw();
+  return true;
+}
+
+bool RegsX86::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+  uint64_t data;
+  Memory* elf_memory = elf->memory();
+  // Read from elf memory since it is usually more expensive to read from
+  // process memory.
+  if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
+    return false;
+  }
+
+  if (data == 0x80cd00000077b858ULL) {
+    // Without SA_SIGINFO set, the return sequence is:
+    //
+    //   __restore:
+    //   0x58                            pop %eax
+    //   0xb8 0x77 0x00 0x00 0x00        movl 0x77,%eax
+    //   0xcd 0x80                       int 0x80
+    //
+    // SP points at arguments:
+    //   int signum
+    //   struct sigcontext (same format as mcontext)
+    struct x86_mcontext_t context;
+    if (!process_memory->Read(sp() + 4, &context, sizeof(context))) {
+      return false;
+    }
+    regs_[X86_REG_EBP] = context.ebp;
+    regs_[X86_REG_ESP] = context.esp;
+    regs_[X86_REG_EBX] = context.ebx;
+    regs_[X86_REG_EDX] = context.edx;
+    regs_[X86_REG_ECX] = context.ecx;
+    regs_[X86_REG_EAX] = context.eax;
+    regs_[X86_REG_EIP] = context.eip;
+    SetFromRaw();
+    return true;
+  } else if ((data & 0x00ffffffffffffffULL) == 0x0080cd000000adb8ULL) {
+    // With SA_SIGINFO set, the return sequence is:
+    //
+    //   __restore_rt:
+    //   0xb8 0xad 0x00 0x00 0x00        movl 0xad,%eax
+    //   0xcd 0x80                       int 0x80
+    //
+    // SP points at arguments:
+    //   int signum
+    //   siginfo*
+    //   ucontext*
+
+    // Get the location of the sigcontext data.
+    uint32_t ptr;
+    if (!process_memory->Read(sp() + 8, &ptr, sizeof(ptr))) {
+      return false;
+    }
+    // Only read the portion of the data structure we care about.
+    x86_ucontext_t x86_ucontext;
+    if (!process_memory->Read(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
+      return false;
+    }
+    SetFromUcontext(&x86_ucontext);
+    return true;
+  }
+  return false;
+}
+
+bool RegsX86_64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+  uint64_t data;
+  Memory* elf_memory = elf->memory();
+  // Read from elf memory since it is usually more expensive to read from
+  // process memory.
+  if (!elf_memory->Read(rel_pc, &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
+    return false;
+  }
+
+  uint16_t data2;
+  if (!elf_memory->Read(rel_pc + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
+    return false;
+  }
+
+  // __restore_rt:
+  // 0x48 0xc7 0xc0 0x0f 0x00 0x00 0x00   mov $0xf,%rax
+  // 0x0f 0x05                            syscall
+  // 0x0f                                 nopl 0x0($rax)
+
+  // Read the mcontext data from the stack.
+  // sp points to the ucontext data structure, read only the mcontext part.
+  x86_64_ucontext_t x86_64_ucontext;
+  if (!process_memory->Read(sp() + 0x28, &x86_64_ucontext.uc_mcontext, sizeof(x86_64_mcontext_t))) {
+    return false;
+  }
+  SetFromUcontext(&x86_64_ucontext);
+  return true;
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/Symbols.cpp b/libunwindstack/Symbols.cpp
index edc2187..42d816a 100644
--- a/libunwindstack/Symbols.cpp
+++ b/libunwindstack/Symbols.cpp
@@ -19,10 +19,13 @@
 
 #include <string>
 
+#include <unwindstack/Memory.h>
+
 #include "Check.h"
-#include "Memory.h"
 #include "Symbols.h"
 
+namespace unwindstack {
+
 Symbols::Symbols(uint64_t offset, uint64_t size, uint64_t entry_size, uint64_t str_offset,
                  uint64_t str_size)
     : cur_offset_(offset),
@@ -108,3 +111,5 @@
 // Instantiate all of the needed template functions.
 template bool Symbols::GetName<Elf32_Sym>(uint64_t, uint64_t, Memory*, std::string*, uint64_t*);
 template bool Symbols::GetName<Elf64_Sym>(uint64_t, uint64_t, Memory*, std::string*, uint64_t*);
+
+}  // namespace unwindstack
diff --git a/libunwindstack/Symbols.h b/libunwindstack/Symbols.h
index 3c0d033..689144b 100644
--- a/libunwindstack/Symbols.h
+++ b/libunwindstack/Symbols.h
@@ -22,6 +22,8 @@
 #include <string>
 #include <vector>
 
+namespace unwindstack {
+
 // Forward declaration.
 class Memory;
 
@@ -61,4 +63,6 @@
   std::vector<Info> symbols_;
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_SYMBOLS_H
diff --git a/libunwindstack/Ucontext.h b/libunwindstack/Ucontext.h
new file mode 100644
index 0000000..22f6a89
--- /dev/null
+++ b/libunwindstack/Ucontext.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBUNWINDSTACK_UCONTEXT_H
+#define _LIBUNWINDSTACK_UCONTEXT_H
+
+#include <stdint.h>
+
+namespace unwindstack {
+
+//-------------------------------------------------------------------
+// ARM ucontext structures
+//-------------------------------------------------------------------
+struct arm_stack_t {
+  uint32_t ss_sp;    // void __user*
+  int32_t ss_flags;  // int
+  uint32_t ss_size;  // size_t
+};
+
+struct arm_mcontext_t {
+  uint32_t trap_no;             // unsigned long
+  uint32_t error_code;          // unsigned long
+  uint32_t oldmask;             // unsigned long
+  uint32_t regs[ARM_REG_LAST];  // unsigned long
+  uint32_t cpsr;                // unsigned long
+  uint32_t fault_address;       // unsigned long
+};
+
+struct arm_ucontext_t {
+  uint32_t uc_flags;  // unsigned long
+  uint32_t uc_link;   // struct ucontext*
+  arm_stack_t uc_stack;
+  arm_mcontext_t uc_mcontext;
+  // Nothing else is used, so don't define it.
+};
+//-------------------------------------------------------------------
+
+//-------------------------------------------------------------------
+// ARM64 ucontext structures
+//-------------------------------------------------------------------
+struct arm64_stack_t {
+  uint64_t ss_sp;    // void __user*
+  int32_t ss_flags;  // int
+  uint64_t ss_size;  // size_t
+};
+
+struct arm64_sigset_t {
+  uint64_t sig;  // unsigned long
+};
+
+struct arm64_mcontext_t {
+  uint64_t fault_address;         // __u64
+  uint64_t regs[ARM64_REG_LAST];  // __u64
+  uint64_t pstate;                // __u64
+  // Nothing else is used, so don't define it.
+};
+
+struct arm64_ucontext_t {
+  uint64_t uc_flags;  // unsigned long
+  uint64_t uc_link;   // struct ucontext*
+  arm64_stack_t uc_stack;
+  arm64_sigset_t uc_sigmask;
+  // The kernel adds extra padding after uc_sigmask to match glibc sigset_t on ARM64.
+  char __padding[128 - sizeof(arm64_sigset_t)];
+  // The full structure requires 16 byte alignment, but our partial structure
+  // doesn't, so force the alignment.
+  arm64_mcontext_t uc_mcontext __attribute__((aligned(16)));
+};
+//-------------------------------------------------------------------
+
+//-------------------------------------------------------------------
+// X86 ucontext structures
+//-------------------------------------------------------------------
+struct x86_stack_t {
+  uint32_t ss_sp;    // void __user*
+  int32_t ss_flags;  // int
+  uint32_t ss_size;  // size_t
+};
+
+struct x86_mcontext_t {
+  uint32_t gs;
+  uint32_t fs;
+  uint32_t es;
+  uint32_t ds;
+  uint32_t edi;
+  uint32_t esi;
+  uint32_t ebp;
+  uint32_t esp;
+  uint32_t ebx;
+  uint32_t edx;
+  uint32_t ecx;
+  uint32_t eax;
+  uint32_t trapno;
+  uint32_t err;
+  uint32_t eip;
+  uint32_t cs;
+  uint32_t efl;
+  uint32_t uesp;
+  uint32_t ss;
+  // Only care about the registers, skip everything else.
+};
+
+struct x86_ucontext_t {
+  uint32_t uc_flags;  // unsigned long
+  uint32_t uc_link;   // struct ucontext*
+  x86_stack_t uc_stack;
+  x86_mcontext_t uc_mcontext;
+  // Nothing else is used, so don't define it.
+};
+//-------------------------------------------------------------------
+
+//-------------------------------------------------------------------
+// X86_64 ucontext structures
+//-------------------------------------------------------------------
+struct x86_64_stack_t {
+  uint64_t ss_sp;    // void __user*
+  int32_t ss_flags;  // int
+  uint64_t ss_size;  // size_t
+};
+
+struct x86_64_mcontext_t {
+  uint64_t r8;
+  uint64_t r9;
+  uint64_t r10;
+  uint64_t r11;
+  uint64_t r12;
+  uint64_t r13;
+  uint64_t r14;
+  uint64_t r15;
+  uint64_t rdi;
+  uint64_t rsi;
+  uint64_t rbp;
+  uint64_t rbx;
+  uint64_t rdx;
+  uint64_t rax;
+  uint64_t rcx;
+  uint64_t rsp;
+  uint64_t rip;
+  uint64_t efl;
+  uint64_t csgsfs;
+  uint64_t err;
+  uint64_t trapno;
+  uint64_t oldmask;
+  uint64_t cr2;
+  // Only care about the registers, skip everything else.
+};
+
+struct x86_64_ucontext_t {
+  uint64_t uc_flags;  // unsigned long
+  uint64_t uc_link;   // struct ucontext*
+  x86_64_stack_t uc_stack;
+  x86_64_mcontext_t uc_mcontext;
+  // Nothing else is used, so don't define it.
+};
+//-------------------------------------------------------------------
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_UCONTEXT_H
diff --git a/libunwindstack/User.h b/libunwindstack/User.h
index a695467..53f7e50 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/User.h
@@ -29,6 +29,8 @@
 #ifndef _LIBUNWINDSTACK_USER_H
 #define _LIBUNWINDSTACK_USER_H
 
+namespace unwindstack {
+
 struct x86_user_regs {
   uint32_t ebx;
   uint32_t ecx;
@@ -93,4 +95,6 @@
 // The largest user structure.
 constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_USER_H
diff --git a/libunwindstack/DwarfLocation.h b/libunwindstack/include/unwindstack/DwarfLocation.h
similarity index 95%
rename from libunwindstack/DwarfLocation.h
rename to libunwindstack/include/unwindstack/DwarfLocation.h
index 062d125..3467e6a 100644
--- a/libunwindstack/DwarfLocation.h
+++ b/libunwindstack/include/unwindstack/DwarfLocation.h
@@ -21,6 +21,8 @@
 
 #include <unordered_map>
 
+namespace unwindstack {
+
 enum DwarfLocationEnum : uint8_t {
   DWARF_LOCATION_INVALID = 0,
   DWARF_LOCATION_UNDEFINED,
@@ -38,4 +40,6 @@
 
 typedef std::unordered_map<uint16_t, DwarfLocation> dwarf_loc_regs_t;
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_DWARF_LOCATION_H
diff --git a/libunwindstack/DwarfMemory.h b/libunwindstack/include/unwindstack/DwarfMemory.h
similarity index 97%
rename from libunwindstack/DwarfMemory.h
rename to libunwindstack/include/unwindstack/DwarfMemory.h
index a304dd9..8dd8d2b 100644
--- a/libunwindstack/DwarfMemory.h
+++ b/libunwindstack/include/unwindstack/DwarfMemory.h
@@ -19,6 +19,8 @@
 
 #include <stdint.h>
 
+namespace unwindstack {
+
 // Forward declarations.
 class Memory;
 
@@ -69,4 +71,6 @@
   uint64_t text_offset_ = static_cast<uint64_t>(-1);
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_DWARF_MEMORY_H
diff --git a/libunwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
similarity index 93%
rename from libunwindstack/DwarfSection.h
rename to libunwindstack/include/unwindstack/DwarfSection.h
index e617601..a97ca2b 100644
--- a/libunwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -22,18 +22,20 @@
 #include <iterator>
 #include <unordered_map>
 
-#include "DwarfError.h"
-#include "DwarfLocation.h"
-#include "DwarfMemory.h"
-#include "DwarfStructs.h"
+#include <unwindstack/DwarfLocation.h>
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/DwarfStructs.h>
+
+namespace unwindstack {
 
 // Forward declarations.
+enum DwarfError : uint8_t;
 class Memory;
 class Regs;
 
 class DwarfSection {
  public:
-  DwarfSection(Memory* memory) : memory_(memory) {}
+  DwarfSection(Memory* memory);
   virtual ~DwarfSection() = default;
 
   class iterator : public std::iterator<std::bidirectional_iterator_tag, DwarfFde*> {
@@ -102,7 +104,7 @@
 
  protected:
   DwarfMemory memory_;
-  DwarfError last_error_ = DWARF_ERROR_NONE;
+  DwarfError last_error_;
 
   uint64_t fde_count_;
   std::unordered_map<uint64_t, DwarfFde> fde_entries_;
@@ -134,4 +136,6 @@
                       AddressType* value);
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_DWARF_SECTION_H
diff --git a/libunwindstack/DwarfStructs.h b/libunwindstack/include/unwindstack/DwarfStructs.h
similarity index 92%
rename from libunwindstack/DwarfStructs.h
rename to libunwindstack/include/unwindstack/DwarfStructs.h
index 87182c9..4b481f0 100644
--- a/libunwindstack/DwarfStructs.h
+++ b/libunwindstack/include/unwindstack/DwarfStructs.h
@@ -21,12 +21,12 @@
 
 #include <vector>
 
-#include "DwarfEncoding.h"
+namespace unwindstack {
 
 struct DwarfCie {
   uint8_t version = 0;
-  uint8_t fde_address_encoding = DW_EH_PE_absptr;
-  uint8_t lsda_encoding = DW_EH_PE_omit;
+  uint8_t fde_address_encoding = 0;
+  uint8_t lsda_encoding = 0;
   uint8_t segment_size = 0;
   std::vector<char> augmentation_string;
   uint64_t personality_handler = 0;
@@ -49,4 +49,6 @@
 
 constexpr uint16_t CFA_REG = static_cast<uint16_t>(-1);
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_DWARF_STRUCTS_H
diff --git a/libunwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
similarity index 75%
rename from libunwindstack/Elf.h
rename to libunwindstack/include/unwindstack/Elf.h
index cff9dc4..d89a746 100644
--- a/libunwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -22,14 +22,17 @@
 #include <memory>
 #include <string>
 
-#include "ElfInterface.h"
-#include "Memory.h"
+#include <unwindstack/ElfInterface.h>
+#include <unwindstack/Memory.h>
 
 #if !defined(EM_AARCH64)
 #define EM_AARCH64 183
 #endif
 
+namespace unwindstack {
+
 // Forward declaration.
+struct MapInfo;
 class Regs;
 
 class Elf {
@@ -41,24 +44,18 @@
 
   void InitGnuDebugdata();
 
-  bool GetSoname(std::string* name) {
-    return valid_ && interface_->GetSoname(name);
-  }
+  bool GetSoname(std::string* name);
 
-  bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
-    return valid_ && (interface_->GetFunctionName(addr, name, func_offset) ||
-                      (gnu_debugdata_interface_ &&
-                       gnu_debugdata_interface_->GetFunctionName(addr, name, func_offset)));
-  }
+  bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset);
 
-  bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory) {
-    return valid_ && (interface_->Step(rel_pc, regs, process_memory) ||
-                      (gnu_debugdata_interface_ &&
-                       gnu_debugdata_interface_->Step(rel_pc, regs, process_memory)));
-  }
+  uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);
+
+  bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory);
 
   ElfInterface* CreateInterfaceFromMemory(Memory* memory);
 
+  uint64_t GetLoadBias();
+
   bool valid() { return valid_; }
 
   uint32_t machine_type() { return machine_type_; }
@@ -84,4 +81,6 @@
   std::unique_ptr<ElfInterface> gnu_debugdata_interface_;
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_ELF_H
diff --git a/libunwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
similarity index 97%
rename from libunwindstack/ElfInterface.h
rename to libunwindstack/include/unwindstack/ElfInterface.h
index d0d0d28..5cac0d3 100644
--- a/libunwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -25,7 +25,9 @@
 #include <unordered_map>
 #include <vector>
 
-#include "DwarfSection.h"
+#include <unwindstack/DwarfSection.h>
+
+namespace unwindstack {
 
 // Forward declarations.
 class Memory;
@@ -166,4 +168,6 @@
   }
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_ELF_INTERFACE_H
diff --git a/libunwindstack/Log.h b/libunwindstack/include/unwindstack/Log.h
similarity index 93%
rename from libunwindstack/Log.h
rename to libunwindstack/include/unwindstack/Log.h
index 2d01aa8..aa1219c 100644
--- a/libunwindstack/Log.h
+++ b/libunwindstack/include/unwindstack/Log.h
@@ -19,7 +19,11 @@
 
 #include <stdint.h>
 
+namespace unwindstack {
+
 void log_to_stdout(bool enable);
 void log(uint8_t indent, const char* format, ...);
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_LOG_H
diff --git a/libunwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
similarity index 95%
rename from libunwindstack/MapInfo.h
rename to libunwindstack/include/unwindstack/MapInfo.h
index 79a2ada..2a97dde 100644
--- a/libunwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -21,6 +21,8 @@
 
 #include <string>
 
+namespace unwindstack {
+
 // Forward declarations.
 class Elf;
 class Memory;
@@ -42,4 +44,6 @@
   Elf* GetElf(pid_t pid, bool init_gnu_debugdata = false);
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_MAP_INFO_H
diff --git a/libunwindstack/Maps.h b/libunwindstack/include/unwindstack/Maps.h
similarity index 96%
rename from libunwindstack/Maps.h
rename to libunwindstack/include/unwindstack/Maps.h
index 239b64a..0b02739 100644
--- a/libunwindstack/Maps.h
+++ b/libunwindstack/include/unwindstack/Maps.h
@@ -23,8 +23,9 @@
 #include <string>
 #include <vector>
 
-#include "Elf.h"
-#include "MapInfo.h"
+#include <unwindstack/MapInfo.h>
+
+namespace unwindstack {
 
 // Special flag to indicate a map is in /dev/. However, a map in
 // /dev/ashmem/... does not set this flag.
@@ -104,4 +105,6 @@
   bool Parse() override;
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_MAPS_H
diff --git a/libunwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
similarity index 89%
rename from libunwindstack/Memory.h
rename to libunwindstack/include/unwindstack/Memory.h
index e353cab..0c05266 100644
--- a/libunwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -24,7 +24,7 @@
 #include <string>
 #include <vector>
 
-#include "Check.h"
+namespace unwindstack {
 
 class Memory {
  public:
@@ -47,13 +47,9 @@
     return Read(offset, field, size);
   }
 
-  inline bool Read32(uint64_t addr, uint32_t* dst) {
-    return Read(addr, dst, sizeof(uint32_t));
-  }
+  inline bool Read32(uint64_t addr, uint32_t* dst) { return Read(addr, dst, sizeof(uint32_t)); }
 
-  inline bool Read64(uint64_t addr, uint64_t* dst) {
-    return Read(addr, dst, sizeof(uint64_t));
-  }
+  inline bool Read64(uint64_t addr, uint64_t* dst) { return Read(addr, dst, sizeof(uint64_t)); }
 };
 
 class MemoryBuffer : public Memory {
@@ -129,10 +125,7 @@
 
 class MemoryRange : public Memory {
  public:
-  MemoryRange(Memory* memory, uint64_t begin, uint64_t end)
-      : memory_(memory), begin_(begin), length_(end - begin) {
-    CHECK(end > begin);
-  }
+  MemoryRange(Memory* memory, uint64_t begin, uint64_t end);
   virtual ~MemoryRange() { delete memory_; }
 
   bool Read(uint64_t addr, void* dst, size_t size) override;
@@ -143,4 +136,6 @@
   uint64_t length_;
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_MEMORY_H
diff --git a/libunwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
similarity index 76%
rename from libunwindstack/Regs.h
rename to libunwindstack/include/unwindstack/Regs.h
index 8f5a721..78e2c0d 100644
--- a/libunwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -21,9 +21,14 @@
 
 #include <vector>
 
+namespace unwindstack {
+
 // Forward declarations.
 class Elf;
 struct MapInfo;
+class Memory;
+struct x86_ucontext_t;
+struct x86_64_ucontext_t;
 
 class Regs {
  public:
@@ -50,14 +55,19 @@
 
   virtual bool GetReturnAddressFromDefault(Memory* memory, uint64_t* value) = 0;
 
-  virtual uint64_t GetRelPc(Elf* elf, const MapInfo* map_info) = 0;
-
   virtual uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) = 0;
 
+  virtual bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) = 0;
+
+  virtual void SetFromRaw() = 0;
+
   uint16_t sp_reg() { return sp_reg_; }
   uint16_t total_regs() { return total_regs_; }
 
+  static uint32_t GetMachineType();
   static Regs* RemoteGet(pid_t pid, uint32_t* machine_type);
+  static Regs* CreateFromUcontext(uint32_t machine_type, void* ucontext);
+  static Regs* CreateFromLocal();
 
  protected:
   uint16_t total_regs_;
@@ -72,8 +82,6 @@
       : Regs(total_regs, sp_reg, return_loc), regs_(total_regs) {}
   virtual ~RegsImpl() = default;
 
-  uint64_t GetRelPc(Elf* elf, const MapInfo* map_info) override;
-
   bool GetReturnAddressFromDefault(Memory* memory, uint64_t* value) override;
 
   uint64_t pc() override { return pc_; }
@@ -98,6 +106,10 @@
   virtual ~RegsArm() = default;
 
   uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
+
+  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
 };
 
 class RegsArm64 : public RegsImpl<uint64_t> {
@@ -106,6 +118,10 @@
   virtual ~RegsArm64() = default;
 
   uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
+
+  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
 };
 
 class RegsX86 : public RegsImpl<uint32_t> {
@@ -114,6 +130,12 @@
   virtual ~RegsX86() = default;
 
   uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
+
+  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+  void SetFromUcontext(x86_ucontext_t* ucontext);
 };
 
 class RegsX86_64 : public RegsImpl<uint64_t> {
@@ -122,6 +144,14 @@
   virtual ~RegsX86_64() = default;
 
   uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
+
+  bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+  void SetFromUcontext(x86_64_ucontext_t* ucontext);
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_REGS_H
diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
new file mode 100644
index 0000000..ffec213
--- /dev/null
+++ b/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBUNWINDSTACK_REGS_GET_LOCAL_H
+#define _LIBUNWINDSTACK_REGS_GET_LOCAL_H
+
+namespace unwindstack {
+
+#if defined(__arm__)
+
+inline void RegsGetLocal(Regs* regs) {
+  void* reg_data = regs->RawData();
+  asm volatile(
+      ".align 2\n"
+      "bx pc\n"
+      "nop\n"
+      ".code 32\n"
+      "stmia %[base], {r0-r12}\n"
+      "add %[base], #52\n"
+      "mov r1, r13\n"
+      "mov r2, r14\n"
+      "mov r3, r15\n"
+      "stmia %[base], {r1-r3}\n"
+      "orr %[base], pc, #1\n"
+      "bx %[base]\n"
+      : [base] "+r"(reg_data)
+      :
+      : "memory");
+
+  regs->SetFromRaw();
+}
+
+#elif defined(__aarch64__)
+
+inline void RegsGetLocal(Regs* regs) {
+  void* reg_data = regs->RawData();
+  asm volatile(
+      "1:\n"
+      "stp x0, x1, [%[base], #0]\n"
+      "stp x2, x3, [%[base], #16]\n"
+      "stp x4, x5, [%[base], #32]\n"
+      "stp x6, x7, [%[base], #48]\n"
+      "stp x8, x9, [%[base], #64]\n"
+      "stp x10, x11, [%[base], #80]\n"
+      "stp x12, x13, [%[base], #96]\n"
+      "stp x14, x15, [%[base], #112]\n"
+      "stp x16, x17, [%[base], #128]\n"
+      "stp x18, x19, [%[base], #144]\n"
+      "stp x20, x21, [%[base], #160]\n"
+      "stp x22, x23, [%[base], #176]\n"
+      "stp x24, x25, [%[base], #192]\n"
+      "stp x26, x27, [%[base], #208]\n"
+      "stp x28, x29, [%[base], #224]\n"
+      "str x30, [%[base], #240]\n"
+      "mov x12, sp\n"
+      "adr x13, 1b\n"
+      "stp x12, x13, [%[base], #248]\n"
+      : [base] "+r"(reg_data)
+      :
+      : "x12", "x13", "memory");
+
+  regs->SetFromRaw();
+}
+
+#elif defined(__i386__) || defined(__x86_64__)
+
+extern "C" void AsmGetRegs(void* regs);
+
+inline void RegsGetLocal(Regs* regs) {
+  AsmGetRegs(regs->RawData());
+
+  regs->SetFromRaw();
+}
+
+#endif
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_REGS_GET_LOCAL_H
diff --git a/libunwindstack/tests/ArmExidxDecodeTest.cpp b/libunwindstack/tests/ArmExidxDecodeTest.cpp
index 4fff48e..94cb493 100644
--- a/libunwindstack/tests/ArmExidxDecodeTest.cpp
+++ b/libunwindstack/tests/ArmExidxDecodeTest.cpp
@@ -23,13 +23,16 @@
 
 #include <gtest/gtest.h>
 
+#include <unwindstack/Log.h>
+#include <unwindstack/Regs.h>
+
 #include "ArmExidx.h"
-#include "Regs.h"
-#include "Log.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
 
+namespace unwindstack {
+
 class ArmExidxDecodeTest : public ::testing::TestWithParam<std::string> {
  protected:
   void Init(Memory* process_memory = nullptr) {
@@ -1092,3 +1095,5 @@
 }
 
 INSTANTIATE_TEST_CASE_P(, ArmExidxDecodeTest, ::testing::Values("logging", "no_logging"));
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/ArmExidxExtractTest.cpp b/libunwindstack/tests/ArmExidxExtractTest.cpp
index aed75bf..caad131 100644
--- a/libunwindstack/tests/ArmExidxExtractTest.cpp
+++ b/libunwindstack/tests/ArmExidxExtractTest.cpp
@@ -21,12 +21,15 @@
 
 #include <gtest/gtest.h>
 
+#include <unwindstack/Log.h>
+
 #include "ArmExidx.h"
-#include "Log.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
 
+namespace unwindstack {
+
 class ArmExidxExtractTest : public ::testing::Test {
  protected:
   void SetUp() override {
@@ -329,3 +332,5 @@
   ASSERT_TRUE(exidx_->ExtractEntryData(0x5000));
   ASSERT_EQ("4 unwind Raw Data: 0x11 0x22 0x33 0xb0\n", GetFakeLogPrint());
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfCfaLogTest.cpp b/libunwindstack/tests/DwarfCfaLogTest.cpp
index 967c2c2..b17ca33 100644
--- a/libunwindstack/tests/DwarfCfaLogTest.cpp
+++ b/libunwindstack/tests/DwarfCfaLogTest.cpp
@@ -23,15 +23,18 @@
 #include <android-base/stringprintf.h>
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfLocation.h>
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/DwarfStructs.h>
+#include <unwindstack/Log.h>
+
 #include "DwarfCfa.h"
-#include "DwarfLocation.h"
-#include "DwarfMemory.h"
-#include "DwarfStructs.h"
-#include "Log.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
 
+namespace unwindstack {
+
 template <typename TypeParam>
 class DwarfCfaLogTest : public ::testing::Test {
  protected:
@@ -812,3 +815,5 @@
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfCfaLogTestTypes;
 INSTANTIATE_TYPED_TEST_CASE_P(, DwarfCfaLogTest, DwarfCfaLogTestTypes);
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfCfaTest.cpp b/libunwindstack/tests/DwarfCfaTest.cpp
index 687af7d..73a67ac 100644
--- a/libunwindstack/tests/DwarfCfaTest.cpp
+++ b/libunwindstack/tests/DwarfCfaTest.cpp
@@ -21,15 +21,19 @@
 
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfLocation.h>
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/DwarfStructs.h>
+#include <unwindstack/Log.h>
+
 #include "DwarfCfa.h"
-#include "DwarfLocation.h"
-#include "DwarfMemory.h"
-#include "DwarfStructs.h"
-#include "Log.h"
+#include "DwarfError.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
 
+namespace unwindstack {
+
 template <typename TypeParam>
 class DwarfCfaTest : public ::testing::Test {
  protected:
@@ -957,3 +961,5 @@
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfCfaTestTypes;
 INSTANTIATE_TYPED_TEST_CASE_P(, DwarfCfaTest, DwarfCfaTestTypes);
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp
index 94a9974..69813e5 100644
--- a/libunwindstack/tests/DwarfDebugFrameTest.cpp
+++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp
@@ -21,11 +21,14 @@
 
 #include "DwarfDebugFrame.h"
 #include "DwarfEncoding.h"
+#include "DwarfError.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
 #include "RegsFake.h"
 
+namespace unwindstack {
+
 template <typename TypeParam>
 class MockDwarfDebugFrame : public DwarfDebugFrame<TypeParam> {
  public:
@@ -454,3 +457,5 @@
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfDebugFrameTestTypes;
 INSTANTIATE_TYPED_TEST_CASE_P(, DwarfDebugFrameTest, DwarfDebugFrameTestTypes);
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp
index 4e538d4..e9501e3 100644
--- a/libunwindstack/tests/DwarfEhFrameTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameTest.cpp
@@ -21,11 +21,14 @@
 
 #include "DwarfEhFrame.h"
 #include "DwarfEncoding.h"
+#include "DwarfError.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
 #include "RegsFake.h"
 
+namespace unwindstack {
+
 template <typename TypeParam>
 class MockDwarfEhFrame : public DwarfEhFrame<TypeParam> {
  public:
@@ -407,3 +410,5 @@
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfEhFrameTestTypes;
 INSTANTIATE_TYPED_TEST_CASE_P(, DwarfEhFrameTest, DwarfEhFrameTestTypes);
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfMemoryTest.cpp b/libunwindstack/tests/DwarfMemoryTest.cpp
index 4877f36..08fe7cf 100644
--- a/libunwindstack/tests/DwarfMemoryTest.cpp
+++ b/libunwindstack/tests/DwarfMemoryTest.cpp
@@ -21,10 +21,12 @@
 
 #include <gtest/gtest.h>
 
-#include "DwarfMemory.h"
+#include <unwindstack/DwarfMemory.h>
 
 #include "MemoryFake.h"
 
+namespace unwindstack {
+
 class DwarfMemoryTest : public ::testing::Test {
  protected:
   void SetUp() override {
@@ -237,9 +239,13 @@
   ASSERT_EQ(0U, value);
 }
 
-TEST_F(DwarfMemoryTest, ReadEncodedValue_omit_uint32_t) { ReadEncodedValue_omit<uint32_t>(); }
+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_omit_uint64_t) {
+  ReadEncodedValue_omit<uint64_t>();
+}
 
 TEST_F(DwarfMemoryTest, ReadEncodedValue_absptr_uint32_t) {
   uint64_t value = 100;
@@ -302,9 +308,13 @@
   ASSERT_EQ(0xffffffffffffe100ULL, value);
 }
 
-TEST_F(DwarfMemoryTest, ReadEncodedValue_leb128_uint32_t) { ReadEncodedValue_leb128<uint32_t>(); }
+TEST_F(DwarfMemoryTest, ReadEncodedValue_leb128_uint32_t) {
+  ReadEncodedValue_leb128<uint32_t>();
+}
 
-TEST_F(DwarfMemoryTest, ReadEncodedValue_leb128_uint64_t) { ReadEncodedValue_leb128<uint64_t>(); }
+TEST_F(DwarfMemoryTest, ReadEncodedValue_leb128_uint64_t) {
+  ReadEncodedValue_leb128<uint64_t>();
+}
 
 template <typename AddressType>
 void DwarfMemoryTest::ReadEncodedValue_data1() {
@@ -319,9 +329,13 @@
   ASSERT_EQ(0xffffffffffffffe0ULL, value);
 }
 
-TEST_F(DwarfMemoryTest, ReadEncodedValue_data1_uint32_t) { ReadEncodedValue_data1<uint32_t>(); }
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data1_uint32_t) {
+  ReadEncodedValue_data1<uint32_t>();
+}
 
-TEST_F(DwarfMemoryTest, ReadEncodedValue_data1_uint64_t) { ReadEncodedValue_data1<uint64_t>(); }
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data1_uint64_t) {
+  ReadEncodedValue_data1<uint64_t>();
+}
 
 template <typename AddressType>
 void DwarfMemoryTest::ReadEncodedValue_data2() {
@@ -336,9 +350,13 @@
   ASSERT_EQ(0xffffffffffffe000ULL, value);
 }
 
-TEST_F(DwarfMemoryTest, ReadEncodedValue_data2_uint32_t) { ReadEncodedValue_data2<uint32_t>(); }
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data2_uint32_t) {
+  ReadEncodedValue_data2<uint32_t>();
+}
 
-TEST_F(DwarfMemoryTest, ReadEncodedValue_data2_uint64_t) { ReadEncodedValue_data2<uint64_t>(); }
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data2_uint64_t) {
+  ReadEncodedValue_data2<uint64_t>();
+}
 
 template <typename AddressType>
 void DwarfMemoryTest::ReadEncodedValue_data4() {
@@ -353,9 +371,13 @@
   ASSERT_EQ(0xffffffffe0000000ULL, value);
 }
 
-TEST_F(DwarfMemoryTest, ReadEncodedValue_data4_uint32_t) { ReadEncodedValue_data4<uint32_t>(); }
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data4_uint32_t) {
+  ReadEncodedValue_data4<uint32_t>();
+}
 
-TEST_F(DwarfMemoryTest, ReadEncodedValue_data4_uint64_t) { ReadEncodedValue_data4<uint64_t>(); }
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data4_uint64_t) {
+  ReadEncodedValue_data4<uint64_t>();
+}
 
 template <typename AddressType>
 void DwarfMemoryTest::ReadEncodedValue_data8() {
@@ -370,9 +392,13 @@
   ASSERT_EQ(0xe000000000000000ULL, value);
 }
 
-TEST_F(DwarfMemoryTest, ReadEncodedValue_data8_uint32_t) { ReadEncodedValue_data8<uint32_t>(); }
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data8_uint32_t) {
+  ReadEncodedValue_data8<uint32_t>();
+}
 
-TEST_F(DwarfMemoryTest, ReadEncodedValue_data8_uint64_t) { ReadEncodedValue_data8<uint64_t>(); }
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data8_uint64_t) {
+  ReadEncodedValue_data8<uint64_t>();
+}
 
 template <typename AddressType>
 void DwarfMemoryTest::ReadEncodedValue_non_zero_adjust() {
@@ -470,3 +496,5 @@
   ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x40, &value));
   ASSERT_EQ(0x14234U, value);
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfOpLogTest.cpp b/libunwindstack/tests/DwarfOpLogTest.cpp
index d18aad0..234d1c9 100644
--- a/libunwindstack/tests/DwarfOpLogTest.cpp
+++ b/libunwindstack/tests/DwarfOpLogTest.cpp
@@ -21,14 +21,17 @@
 
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/Log.h>
+#include <unwindstack/Regs.h>
+
 #include "DwarfError.h"
-#include "DwarfMemory.h"
 #include "DwarfOp.h"
-#include "Log.h"
-#include "Regs.h"
 
 #include "MemoryFake.h"
 
+namespace unwindstack {
+
 template <typename TypeParam>
 class DwarfOpLogTest : public ::testing::Test {
  protected:
@@ -66,3 +69,5 @@
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfOpLogTestTypes;
 INSTANTIATE_TYPED_TEST_CASE_P(, DwarfOpLogTest, DwarfOpLogTestTypes);
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfOpTest.cpp b/libunwindstack/tests/DwarfOpTest.cpp
index 20c488a..47a40cf 100644
--- a/libunwindstack/tests/DwarfOpTest.cpp
+++ b/libunwindstack/tests/DwarfOpTest.cpp
@@ -21,14 +21,17 @@
 
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/Log.h>
+
 #include "DwarfError.h"
-#include "DwarfMemory.h"
 #include "DwarfOp.h"
-#include "Log.h"
 
 #include "MemoryFake.h"
 #include "RegsFake.h"
 
+namespace unwindstack {
+
 template <typename TypeParam>
 class DwarfOpTest : public ::testing::Test {
  protected:
@@ -1579,3 +1582,5 @@
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfOpTestTypes;
 INSTANTIATE_TYPED_TEST_CASE_P(, DwarfOpTest, DwarfOpTestTypes);
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index 71b114a..b871539 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -19,12 +19,17 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
-#include "DwarfSection.h"
+#include <unwindstack/DwarfSection.h>
+
+#include "DwarfEncoding.h"
+#include "DwarfError.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
 #include "RegsFake.h"
 
+namespace unwindstack {
+
 template <typename TypeParam>
 class MockDwarfSectionImpl : public DwarfSectionImpl<TypeParam> {
  public:
@@ -830,3 +835,5 @@
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfSectionImplTestTypes;
 INSTANTIATE_TYPED_TEST_CASE_P(, DwarfSectionImplTest, DwarfSectionImplTestTypes);
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfSectionTest.cpp b/libunwindstack/tests/DwarfSectionTest.cpp
index 20f0e2a..fc67063 100644
--- a/libunwindstack/tests/DwarfSectionTest.cpp
+++ b/libunwindstack/tests/DwarfSectionTest.cpp
@@ -19,10 +19,12 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
-#include "DwarfSection.h"
+#include <unwindstack/DwarfSection.h>
 
 #include "MemoryFake.h"
 
+namespace unwindstack {
+
 class MockDwarfSection : public DwarfSection {
  public:
   MockDwarfSection(Memory* memory) : DwarfSection(memory) {}
@@ -158,3 +160,5 @@
 
   ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process));
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index 67c9a6b..c7ef4a1 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -20,12 +20,15 @@
 
 #include <vector>
 
+#include <unwindstack/Regs.h>
+
 #include "ElfInterfaceArm.h"
 #include "Machine.h"
-#include "Regs.h"
 
 #include "MemoryFake.h"
 
+namespace unwindstack {
+
 class ElfInterfaceArmTest : public ::testing::Test {
  protected:
   void SetUp() override {
@@ -370,3 +373,5 @@
   ASSERT_EQ(0x10U, regs.pc());
   ASSERT_EQ(0x10U, regs[ARM_REG_PC]);
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index 0f56ba8..acb7320 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -20,7 +20,9 @@
 
 #include <gtest/gtest.h>
 
-#include "ElfInterface.h"
+#include <unwindstack/ElfInterface.h>
+
+#include "DwarfEncoding.h"
 #include "ElfInterfaceArm.h"
 
 #include "MemoryFake.h"
@@ -33,6 +35,8 @@
 #define EM_AARCH64 183
 #endif
 
+namespace unwindstack {
+
 class ElfInterfaceTest : public ::testing::Test {
  protected:
   void SetUp() override {
@@ -921,3 +925,5 @@
 TEST_F(ElfInterfaceTest, init_section_headers_offsets64) {
   InitSectionHeadersOffsets<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>();
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 22cade2..ed1be3b 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -22,50 +22,35 @@
 
 #include <gtest/gtest.h>
 
-#include "Elf.h"
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
 
+#include "ElfTestUtils.h"
+#include "LogFake.h"
 #include "MemoryFake.h"
 
 #if !defined(PT_ARM_EXIDX)
 #define PT_ARM_EXIDX 0x70000001
 #endif
 
+namespace unwindstack {
+
 class ElfTest : public ::testing::Test {
  protected:
   void SetUp() override {
     memory_ = new MemoryFake;
   }
 
-  template <typename Ehdr>
-  void InitEhdr(Ehdr* ehdr) {
-    memset(ehdr, 0, sizeof(Ehdr));
-    memcpy(&ehdr->e_ident[0], ELFMAG, SELFMAG);
-    ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
-    ehdr->e_ident[EI_VERSION] = EV_CURRENT;
-    ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
-
-    ehdr->e_type = ET_DYN;
-    ehdr->e_version = EV_CURRENT;
-  }
-
-  void InitElf32(uint32_t machine) {
+  void InitElf32(uint32_t machine_type) {
     Elf32_Ehdr ehdr;
+    TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, machine_type);
 
-    InitEhdr<Elf32_Ehdr>(&ehdr);
-    ehdr.e_ident[EI_CLASS] = ELFCLASS32;
-
-    ehdr.e_machine = machine;
-    ehdr.e_entry = 0;
     ehdr.e_phoff = 0x100;
-    ehdr.e_shoff = 0;
-    ehdr.e_flags = 0;
     ehdr.e_ehsize = sizeof(ehdr);
     ehdr.e_phentsize = sizeof(Elf32_Phdr);
     ehdr.e_phnum = 1;
     ehdr.e_shentsize = sizeof(Elf32_Shdr);
-    ehdr.e_shnum = 0;
-    ehdr.e_shstrndx = 0;
-    if (machine == EM_ARM) {
+    if (machine_type == EM_ARM) {
       ehdr.e_flags = 0x5000200;
       ehdr.e_phnum = 2;
     }
@@ -74,16 +59,13 @@
     Elf32_Phdr phdr;
     memset(&phdr, 0, sizeof(phdr));
     phdr.p_type = PT_LOAD;
-    phdr.p_offset = 0;
-    phdr.p_vaddr = 0;
-    phdr.p_paddr = 0;
     phdr.p_filesz = 0x10000;
     phdr.p_memsz = 0x10000;
     phdr.p_flags = PF_R | PF_X;
     phdr.p_align = 0x1000;
     memory_->SetMemory(0x100, &phdr, sizeof(phdr));
 
-    if (machine == EM_ARM) {
+    if (machine_type == EM_ARM) {
       memset(&phdr, 0, sizeof(phdr));
       phdr.p_type = PT_ARM_EXIDX;
       phdr.p_offset = 0x30000;
@@ -97,31 +79,21 @@
     }
   }
 
-  void InitElf64(uint32_t machine) {
+  void InitElf64(uint32_t machine_type) {
     Elf64_Ehdr ehdr;
+    TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, machine_type);
 
-    InitEhdr<Elf64_Ehdr>(&ehdr);
-    ehdr.e_ident[EI_CLASS] = ELFCLASS64;
-
-    ehdr.e_machine = machine;
-    ehdr.e_entry = 0;
     ehdr.e_phoff = 0x100;
-    ehdr.e_shoff = 0;
     ehdr.e_flags = 0x5000200;
     ehdr.e_ehsize = sizeof(ehdr);
     ehdr.e_phentsize = sizeof(Elf64_Phdr);
     ehdr.e_phnum = 1;
     ehdr.e_shentsize = sizeof(Elf64_Shdr);
-    ehdr.e_shnum = 0;
-    ehdr.e_shstrndx = 0;
     memory_->SetMemory(0, &ehdr, sizeof(ehdr));
 
     Elf64_Phdr phdr;
     memset(&phdr, 0, sizeof(phdr));
     phdr.p_type = PT_LOAD;
-    phdr.p_offset = 0;
-    phdr.p_vaddr = 0;
-    phdr.p_paddr = 0;
     phdr.p_filesz = 0x10000;
     phdr.p_memsz = 0x10000;
     phdr.p_flags = PF_R | PF_X;
@@ -129,12 +101,6 @@
     memory_->SetMemory(0x100, &phdr, sizeof(phdr));
   }
 
-  template <typename Ehdr, typename Shdr>
-  void GnuDebugdataInitFail(Ehdr* ehdr);
-
-  template <typename Ehdr, typename Shdr>
-  void GnuDebugdataInit(Ehdr* ehdr);
-
   MemoryFake* memory_;
 };
 
@@ -166,6 +132,32 @@
   ASSERT_FALSE(elf.Step(0, nullptr, nullptr));
 }
 
+TEST_F(ElfTest, elf32_invalid_machine) {
+  Elf elf(memory_);
+
+  InitElf32(EM_PPC);
+
+  ResetLogs();
+  ASSERT_FALSE(elf.Init());
+
+  ASSERT_EQ("", GetFakeLogBuf());
+  ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86: e_machine = 20\n\n",
+            GetFakeLogPrint());
+}
+
+TEST_F(ElfTest, elf64_invalid_machine) {
+  Elf elf(memory_);
+
+  InitElf64(EM_PPC64);
+
+  ResetLogs();
+  ASSERT_FALSE(elf.Init());
+
+  ASSERT_EQ("", GetFakeLogBuf());
+  ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64: e_machine = 21\n\n",
+            GetFakeLogPrint());
+}
+
 TEST_F(ElfTest, elf_arm) {
   Elf elf(memory_);
 
@@ -214,153 +206,94 @@
   ASSERT_TRUE(elf.interface() != nullptr);
 }
 
-template <typename Ehdr, typename Shdr>
-void ElfTest::GnuDebugdataInitFail(Ehdr* ehdr) {
+TEST_F(ElfTest, gnu_debugdata_init_fail32) {
+  TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false,
+                                               [&](uint64_t offset, const void* ptr, size_t size) {
+                                                 memory_->SetMemory(offset, ptr, size);
+                                               });
+
   Elf elf(memory_);
-
-  uint64_t offset = 0x2000;
-
-  ehdr->e_shoff = offset;
-  ehdr->e_shnum = 3;
-  ehdr->e_shentsize = sizeof(Shdr);
-  ehdr->e_shstrndx = 2;
-  memory_->SetMemory(0, ehdr, sizeof(*ehdr));
-
-  Shdr shdr;
-  memset(&shdr, 0, sizeof(shdr));
-  shdr.sh_type = SHT_NULL;
-  memory_->SetMemory(offset, &shdr, sizeof(shdr));
-  offset += ehdr->e_shentsize;
-
-  memset(&shdr, 0, sizeof(shdr));
-  shdr.sh_type = SHT_PROGBITS;
-  shdr.sh_name = 0x100;
-  shdr.sh_addr = 0x5000;
-  shdr.sh_offset = 0x5000;
-  shdr.sh_entsize = 0x100;
-  shdr.sh_size = 0x800;
-  memory_->SetMemory(offset, &shdr, sizeof(shdr));
-  offset += ehdr->e_shentsize;
-
-  memset(&shdr, 0, sizeof(shdr));
-  shdr.sh_type = SHT_STRTAB;
-  shdr.sh_name = 0x200000;
-  shdr.sh_offset = 0xf000;
-  shdr.sh_size = 0x1000;
-  memory_->SetMemory(offset, &shdr, sizeof(shdr));
-  offset += ehdr->e_shentsize;
-
-  memory_->SetMemory(0xf100, ".gnu_debugdata", sizeof(".gnu_debugdata"));
-
   ASSERT_TRUE(elf.Init());
   ASSERT_TRUE(elf.interface() != nullptr);
   ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
-  EXPECT_EQ(0x5000U, elf.interface()->gnu_debugdata_offset());
-  EXPECT_EQ(0x800U, elf.interface()->gnu_debugdata_size());
-
-  elf.InitGnuDebugdata();
-}
-
-TEST_F(ElfTest, gnu_debugdata_init_fail32) {
-  Elf32_Ehdr ehdr;
-  InitEhdr<Elf32_Ehdr>(&ehdr);
-  ehdr.e_ident[EI_CLASS] = ELFCLASS32;
-  ehdr.e_machine = EM_ARM;
-
-  GnuDebugdataInitFail<Elf32_Ehdr, Elf32_Shdr>(&ehdr);
+  EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
+  EXPECT_EQ(0x100U, elf.interface()->gnu_debugdata_size());
 }
 
 TEST_F(ElfTest, gnu_debugdata_init_fail64) {
-  Elf64_Ehdr ehdr;
-  InitEhdr<Elf64_Ehdr>(&ehdr);
-  ehdr.e_ident[EI_CLASS] = ELFCLASS64;
-  ehdr.e_machine = EM_AARCH64;
+  TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false,
+                                               [&](uint64_t offset, const void* ptr, size_t size) {
+                                                 memory_->SetMemory(offset, ptr, size);
+                                               });
 
-  GnuDebugdataInitFail<Elf64_Ehdr, Elf64_Shdr>(&ehdr);
-}
-
-template <typename Ehdr, typename Shdr>
-void ElfTest::GnuDebugdataInit(Ehdr* ehdr) {
   Elf elf(memory_);
-
-  uint64_t offset = 0x2000;
-
-  ehdr->e_shoff = offset;
-  ehdr->e_shnum = 3;
-  ehdr->e_shentsize = sizeof(Shdr);
-  ehdr->e_shstrndx = 2;
-  memory_->SetMemory(0, ehdr, sizeof(*ehdr));
-
-  Shdr shdr;
-  memset(&shdr, 0, sizeof(shdr));
-  shdr.sh_type = SHT_NULL;
-  memory_->SetMemory(offset, &shdr, sizeof(shdr));
-  offset += ehdr->e_shentsize;
-
-  uint64_t gnu_offset = offset;
-  offset += ehdr->e_shentsize;
-
-  memset(&shdr, 0, sizeof(shdr));
-  shdr.sh_type = SHT_STRTAB;
-  shdr.sh_name = 0x200000;
-  shdr.sh_offset = 0xf000;
-  shdr.sh_size = 0x1000;
-  memory_->SetMemory(offset, &shdr, sizeof(shdr));
-  offset += ehdr->e_shentsize;
-
-  memory_->SetMemory(0xf100, ".gnu_debugdata", sizeof(".gnu_debugdata"));
-
-  // Read in the compressed elf data and put it in our fake memory.
-  std::string name("tests/");
-  if (sizeof(Ehdr) == sizeof(Elf32_Ehdr)) {
-    name += "elf32.xz";
-  } else {
-    name += "elf64.xz";
-  }
-  int fd = TEMP_FAILURE_RETRY(open(name.c_str(), O_RDONLY));
-  ASSERT_NE(-1, fd) << "Cannot open " + name;
-  // Assumes the file is less than 1024 bytes.
-  std::vector<uint8_t> buf(1024);
-  ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, buf.data(), buf.size()));
-  ASSERT_GT(bytes, 0);
-  // Make sure the file isn't too big.
-  ASSERT_NE(static_cast<size_t>(bytes), buf.size())
-      << "File " + name + " is too big, increase buffer size.";
-  close(fd);
-  buf.resize(bytes);
-  memory_->SetMemory(0x5000, buf);
-
-  memset(&shdr, 0, sizeof(shdr));
-  shdr.sh_type = SHT_PROGBITS;
-  shdr.sh_name = 0x100;
-  shdr.sh_addr = 0x5000;
-  shdr.sh_offset = 0x5000;
-  shdr.sh_size = bytes;
-  memory_->SetMemory(gnu_offset, &shdr, sizeof(shdr));
-
   ASSERT_TRUE(elf.Init());
   ASSERT_TRUE(elf.interface() != nullptr);
   ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
-  EXPECT_EQ(0x5000U, elf.interface()->gnu_debugdata_offset());
+  EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
+  EXPECT_EQ(0x100U, elf.interface()->gnu_debugdata_size());
+}
+
+TEST_F(ElfTest, gnu_debugdata_init32) {
+  TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
+                                               [&](uint64_t offset, const void* ptr, size_t size) {
+                                                 memory_->SetMemory(offset, ptr, size);
+                                               });
+
+  Elf elf(memory_);
+  ASSERT_TRUE(elf.Init());
+  ASSERT_TRUE(elf.interface() != nullptr);
+  ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
+  EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
+  EXPECT_EQ(0x8cU, elf.interface()->gnu_debugdata_size());
 
   elf.InitGnuDebugdata();
   ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
 }
 
-TEST_F(ElfTest, gnu_debugdata_init32) {
-  Elf32_Ehdr ehdr;
-  InitEhdr<Elf32_Ehdr>(&ehdr);
-  ehdr.e_ident[EI_CLASS] = ELFCLASS32;
-  ehdr.e_machine = EM_ARM;
-
-  GnuDebugdataInit<Elf32_Ehdr, Elf32_Shdr>(&ehdr);
-}
-
 TEST_F(ElfTest, gnu_debugdata_init64) {
-  Elf64_Ehdr ehdr;
-  InitEhdr<Elf64_Ehdr>(&ehdr);
-  ehdr.e_ident[EI_CLASS] = ELFCLASS64;
-  ehdr.e_machine = EM_AARCH64;
+  TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
+                                               [&](uint64_t offset, const void* ptr, size_t size) {
+                                                 memory_->SetMemory(offset, ptr, size);
+                                               });
 
-  GnuDebugdataInit<Elf64_Ehdr, Elf64_Shdr>(&ehdr);
+  Elf elf(memory_);
+  ASSERT_TRUE(elf.Init());
+  ASSERT_TRUE(elf.interface() != nullptr);
+  ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
+  EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
+  EXPECT_EQ(0x90U, elf.interface()->gnu_debugdata_size());
+
+  elf.InitGnuDebugdata();
+  ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
 }
+
+class MockElf : public Elf {
+ public:
+  MockElf(Memory* memory) : Elf(memory) {}
+  virtual ~MockElf() = default;
+
+  void set_valid(bool valid) { valid_ = valid; }
+  void set_elf_interface(ElfInterface* interface) { interface_.reset(interface); }
+};
+
+TEST_F(ElfTest, rel_pc) {
+  MockElf elf(memory_);
+
+  ElfInterface* interface = new ElfInterface32(memory_);
+  elf.set_elf_interface(interface);
+
+  elf.set_valid(true);
+  interface->set_load_bias(0);
+  MapInfo map_info{.start = 0x1000, .end = 0x2000};
+
+  ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
+
+  interface->set_load_bias(0x3000);
+  ASSERT_EQ(0x3101U, elf.GetRelPc(0x1101, &map_info));
+
+  elf.set_valid(false);
+  ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/ElfTestUtils.cpp b/libunwindstack/tests/ElfTestUtils.cpp
new file mode 100644
index 0000000..069386b
--- /dev/null
+++ b/libunwindstack/tests/ElfTestUtils.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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 <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "ElfTestUtils.h"
+
+namespace unwindstack {
+
+template <typename Ehdr>
+void TestInitEhdr(Ehdr* ehdr, uint32_t elf_class, uint32_t machine_type) {
+  memset(ehdr, 0, sizeof(Ehdr));
+  memcpy(&ehdr->e_ident[0], ELFMAG, SELFMAG);
+  ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+  ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+  ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
+  ehdr->e_ident[EI_CLASS] = elf_class;
+  ehdr->e_type = ET_DYN;
+  ehdr->e_machine = machine_type;
+  ehdr->e_version = EV_CURRENT;
+  ehdr->e_ehsize = sizeof(Ehdr);
+}
+
+static std::string GetTestFileDirectory() {
+  std::string exec(testing::internal::GetArgvs()[0]);
+  auto const value = exec.find_last_of('/');
+  if (value == std::string::npos) {
+    return "tests/files/";
+  }
+  return exec.substr(0, value + 1) + "tests/files/";
+}
+
+template <typename Ehdr, typename Shdr>
+void TestInitGnuDebugdata(uint32_t elf_class, uint32_t machine, bool init_gnu_debugdata,
+                          TestCopyFuncType copy_func) {
+  Ehdr ehdr;
+
+  TestInitEhdr(&ehdr, elf_class, machine);
+
+  uint64_t offset = sizeof(Ehdr);
+  ehdr.e_shoff = offset;
+  ehdr.e_shnum = 3;
+  ehdr.e_shentsize = sizeof(Shdr);
+  ehdr.e_shstrndx = 2;
+  copy_func(0, &ehdr, sizeof(ehdr));
+
+  Shdr shdr;
+  memset(&shdr, 0, sizeof(shdr));
+  shdr.sh_type = SHT_NULL;
+  copy_func(offset, &shdr, sizeof(shdr));
+  offset += ehdr.e_shentsize;
+
+  // Skip this header, it will contain the gnu_debugdata information.
+  uint64_t gnu_offset = offset;
+  offset += ehdr.e_shentsize;
+
+  uint64_t symtab_offset = sizeof(ehdr) + ehdr.e_shnum * ehdr.e_shentsize;
+  memset(&shdr, 0, sizeof(shdr));
+  shdr.sh_name = 1;
+  shdr.sh_type = SHT_STRTAB;
+  shdr.sh_offset = symtab_offset;
+  shdr.sh_size = 0x100;
+  copy_func(offset, &shdr, sizeof(shdr));
+
+  char value = '\0';
+  uint64_t symname_offset = symtab_offset;
+  copy_func(symname_offset, &value, 1);
+  symname_offset++;
+  std::string name(".shstrtab");
+  copy_func(symname_offset, name.c_str(), name.size() + 1);
+  symname_offset += name.size() + 1;
+  name = ".gnu_debugdata";
+  copy_func(symname_offset, name.c_str(), name.size() + 1);
+
+  ssize_t bytes = 0x100;
+  offset = symtab_offset + 0x100;
+  if (init_gnu_debugdata) {
+    // Read in the compressed elf data and copy it in.
+    name = GetTestFileDirectory();
+    if (elf_class == ELFCLASS32) {
+      name += "elf32.xz";
+    } else {
+      name += "elf64.xz";
+    }
+    int fd = TEMP_FAILURE_RETRY(open(name.c_str(), O_RDONLY));
+    ASSERT_NE(-1, fd) << "Cannot open " + name;
+    // Assumes the file is less than 1024 bytes.
+    std::vector<uint8_t> buf(1024);
+    bytes = TEMP_FAILURE_RETRY(read(fd, buf.data(), buf.size()));
+    ASSERT_GT(bytes, 0);
+    // Make sure the file isn't too big.
+    ASSERT_NE(static_cast<size_t>(bytes), buf.size())
+        << "File " + name + " is too big, increase buffer size.";
+    close(fd);
+    buf.resize(bytes);
+    copy_func(offset, buf.data(), buf.size());
+  }
+
+  memset(&shdr, 0, sizeof(shdr));
+  shdr.sh_type = SHT_PROGBITS;
+  shdr.sh_name = symname_offset - symtab_offset;
+  shdr.sh_addr = offset;
+  shdr.sh_offset = offset;
+  shdr.sh_size = bytes;
+  copy_func(gnu_offset, &shdr, sizeof(shdr));
+}
+
+template void TestInitEhdr<Elf32_Ehdr>(Elf32_Ehdr*, uint32_t, uint32_t);
+template void TestInitEhdr<Elf64_Ehdr>(Elf64_Ehdr*, uint32_t, uint32_t);
+
+template void TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(uint32_t, uint32_t, bool,
+                                                           TestCopyFuncType);
+template void TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(uint32_t, uint32_t, bool,
+                                                           TestCopyFuncType);
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/ElfTestUtils.h b/libunwindstack/tests/ElfTestUtils.h
new file mode 100644
index 0000000..6ef00e1
--- /dev/null
+++ b/libunwindstack/tests/ElfTestUtils.h
@@ -0,0 +1,35 @@
+/*
+ * 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 _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
+#define _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
+
+#include <functional>
+
+namespace unwindstack {
+
+typedef std::function<void(uint64_t, const void*, size_t)> TestCopyFuncType;
+
+template <typename Ehdr>
+void TestInitEhdr(Ehdr* ehdr, uint32_t elf_class, uint32_t machine_type);
+
+template <typename Ehdr, typename Shdr>
+void TestInitGnuDebugdata(uint32_t elf_class, uint32_t machine_type, bool init_gnu_debudata,
+                          TestCopyFuncType copy_func);
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
diff --git a/libunwindstack/tests/LogFake.cpp b/libunwindstack/tests/LogFake.cpp
index 411594a..537ccaf 100644
--- a/libunwindstack/tests/LogFake.cpp
+++ b/libunwindstack/tests/LogFake.cpp
@@ -25,7 +25,6 @@
 #include "LogFake.h"
 
 // Forward declarations.
-class Backtrace;
 struct EventTagMap;
 struct AndroidLogEntry;
 
@@ -33,6 +32,8 @@
 
 std::string g_fake_log_print;
 
+namespace unwindstack {
+
 void ResetLogs() {
   g_fake_log_buf = "";
   g_fake_log_print = "";
@@ -46,6 +47,8 @@
   return g_fake_log_print;
 }
 
+}  // namespace unwindstack
+
 extern "C" int __android_log_buf_write(int bufId, int prio, const char* tag, const char* msg) {
   g_fake_log_buf += std::to_string(bufId) + ' ' + std::to_string(prio) + ' ';
   g_fake_log_buf += tag;
diff --git a/libunwindstack/tests/LogFake.h b/libunwindstack/tests/LogFake.h
index 006d393..e1dc50d 100644
--- a/libunwindstack/tests/LogFake.h
+++ b/libunwindstack/tests/LogFake.h
@@ -19,8 +19,12 @@
 
 #include <string>
 
+namespace unwindstack {
+
 void ResetLogs();
 std::string GetFakeLogBuf();
 std::string GetFakeLogPrint();
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_TESTS_LOG_FAKE_H
diff --git a/libunwindstack/tests/MapInfoTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
similarity index 84%
rename from libunwindstack/tests/MapInfoTest.cpp
rename to libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 6e47dc0..9e45e78 100644
--- a/libunwindstack/tests/MapInfoTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -30,11 +30,13 @@
 #include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
-#include "Elf.h"
-#include "MapInfo.h"
-#include "Memory.h"
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
 
-class MapInfoTest : public ::testing::Test {
+namespace unwindstack {
+
+class MapInfoCreateMemoryTest : public ::testing::Test {
  protected:
   static void SetUpTestCase() {
     std::vector<uint8_t> buffer(1024);
@@ -58,10 +60,10 @@
 
   static TemporaryFile elf_at_100_;
 };
-TemporaryFile MapInfoTest::elf_;
-TemporaryFile MapInfoTest::elf_at_100_;
+TemporaryFile MapInfoCreateMemoryTest::elf_;
+TemporaryFile MapInfoCreateMemoryTest::elf_at_100_;
 
-TEST_F(MapInfoTest, end_le_start) {
+TEST_F(MapInfoCreateMemoryTest, end_le_start) {
   MapInfo info{.start = 0x100, .end = 0x100, .offset = 0, .name = elf_.path};
 
   std::unique_ptr<Memory> memory;
@@ -80,7 +82,7 @@
 
 // Verify that if the offset is non-zero but there is no elf at the offset,
 // that the full file is used.
-TEST_F(MapInfoTest, create_memory_file_backed_non_zero_offset_full_file) {
+TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
   MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_.path};
 
   std::unique_ptr<Memory> memory(info.CreateMemory(getpid()));
@@ -100,7 +102,7 @@
 
 // Verify that if the offset is non-zero and there is an elf at that
 // offset, that only part of the file is used.
-TEST_F(MapInfoTest, create_memory_file_backed_non_zero_offset_partial_file) {
+TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) {
   MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_at_100_.path};
 
   std::unique_ptr<Memory> memory(info.CreateMemory(getpid()));
@@ -119,7 +121,7 @@
 }
 
 // Verify that device file names will never result in Memory object creation.
-TEST_F(MapInfoTest, create_memory_check_device_maps) {
+TEST_F(MapInfoCreateMemoryTest, check_device_maps) {
   // Set up some memory so that a valid local memory object would
   // be returned if the file mapping fails, but the device check is incorrect.
   std::vector<uint8_t> buffer(1024);
@@ -135,7 +137,7 @@
   ASSERT_TRUE(memory.get() == nullptr);
 }
 
-TEST_F(MapInfoTest, create_memory_local_memory) {
+TEST_F(MapInfoCreateMemoryTest, local_memory) {
   // Set up some memory for a valid local memory object.
   std::vector<uint8_t> buffer(1024);
   for (size_t i = 0; i < buffer.size(); i++) {
@@ -160,7 +162,7 @@
   ASSERT_FALSE(memory->Read(read_buffer.size(), read_buffer.data(), 1));
 }
 
-TEST_F(MapInfoTest, create_memory_remote_memory) {
+TEST_F(MapInfoCreateMemoryTest, remote_memory) {
   std::vector<uint8_t> buffer(1024);
   memset(buffer.data(), 0xa, buffer.size());
 
@@ -201,20 +203,7 @@
   ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
 
   kill(pid, SIGKILL);
+  ASSERT_EQ(pid, wait(nullptr));
 }
 
-TEST_F(MapInfoTest, get_elf) {
-  // Create a map to use as initialization data.
-  void* map = mmap(nullptr, 1024, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-  ASSERT_NE(MAP_FAILED, map);
-
-  uint64_t start = reinterpret_cast<uint64_t>(map);
-  MapInfo info{.start = start, .end = start + 1024, .offset = 0, .name = ""};
-
-  // The map contains garbage, but this should still produce an elf object.
-  std::unique_ptr<Elf> elf(info.GetElf(getpid(), false));
-  ASSERT_TRUE(elf.get() != nullptr);
-  ASSERT_FALSE(elf->valid());
-
-  ASSERT_EQ(0, munmap(map, 1024));
-}
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
new file mode 100644
index 0000000..abfa172
--- /dev/null
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -0,0 +1,146 @@
+/*
+ * 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 <elf.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+
+#include "ElfTestUtils.h"
+
+namespace unwindstack {
+
+class MapInfoGetElfTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    map_ = mmap(nullptr, kMapSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+    ASSERT_NE(MAP_FAILED, map_);
+
+    uint64_t start = reinterpret_cast<uint64_t>(map_);
+    info_.reset(new MapInfo{.start = start, .end = start + 1024, .offset = 0, .name = ""});
+  }
+
+  void TearDown() override { munmap(map_, kMapSize); }
+
+  const size_t kMapSize = 4096;
+
+  void* map_ = nullptr;
+  std::unique_ptr<MapInfo> info_;
+};
+
+TEST_F(MapInfoGetElfTest, invalid) {
+  // The map is empty, but this should still create an invalid elf object.
+  std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+  ASSERT_TRUE(elf.get() != nullptr);
+  ASSERT_FALSE(elf->valid());
+}
+
+TEST_F(MapInfoGetElfTest, valid32) {
+  Elf32_Ehdr ehdr;
+  TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+  memcpy(map_, &ehdr, sizeof(ehdr));
+
+  std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+  ASSERT_TRUE(elf.get() != nullptr);
+  ASSERT_TRUE(elf->valid());
+  EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
+  EXPECT_EQ(ELFCLASS32, elf->class_type());
+}
+
+TEST_F(MapInfoGetElfTest, valid64) {
+  Elf64_Ehdr ehdr;
+  TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
+  memcpy(map_, &ehdr, sizeof(ehdr));
+
+  std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+  ASSERT_TRUE(elf.get() != nullptr);
+  ASSERT_TRUE(elf->valid());
+  EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
+  EXPECT_EQ(ELFCLASS64, elf->class_type());
+}
+
+TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init32) {
+  TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(
+      ELFCLASS32, EM_ARM, false, [&](uint64_t offset, const void* ptr, size_t size) {
+        memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
+      });
+
+  std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+  ASSERT_TRUE(elf.get() != nullptr);
+  ASSERT_TRUE(elf->valid());
+  EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
+  EXPECT_EQ(ELFCLASS32, elf->class_type());
+  EXPECT_TRUE(elf->gnu_debugdata_interface() == nullptr);
+}
+
+TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) {
+  TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(
+      ELFCLASS64, EM_AARCH64, false, [&](uint64_t offset, const void* ptr, size_t size) {
+        memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
+      });
+
+  std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+  ASSERT_TRUE(elf.get() != nullptr);
+  ASSERT_TRUE(elf->valid());
+  EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
+  EXPECT_EQ(ELFCLASS64, elf->class_type());
+  EXPECT_TRUE(elf->gnu_debugdata_interface() == nullptr);
+}
+
+TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
+  TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(
+      ELFCLASS32, EM_ARM, true, [&](uint64_t offset, const void* ptr, size_t size) {
+        memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
+      });
+
+  std::unique_ptr<Elf> elf(info_->GetElf(getpid(), true));
+  ASSERT_TRUE(elf.get() != nullptr);
+  ASSERT_TRUE(elf->valid());
+  EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
+  EXPECT_EQ(ELFCLASS32, elf->class_type());
+  EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
+}
+
+TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
+  TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(
+      ELFCLASS64, EM_AARCH64, true, [&](uint64_t offset, const void* ptr, size_t size) {
+        memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
+      });
+
+  std::unique_ptr<Elf> elf(info_->GetElf(getpid(), true));
+  ASSERT_TRUE(elf.get() != nullptr);
+  ASSERT_TRUE(elf->valid());
+  EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
+  EXPECT_EQ(ELFCLASS64, elf->class_type());
+  EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp
index 7eb9bae..9430cf3 100644
--- a/libunwindstack/tests/MapsTest.cpp
+++ b/libunwindstack/tests/MapsTest.cpp
@@ -20,7 +20,9 @@
 #include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
-#include "Maps.h"
+#include <unwindstack/Maps.h>
+
+namespace unwindstack {
 
 TEST(MapsTest, parse_permissions) {
   BufferMaps maps(
@@ -235,3 +237,5 @@
   ASSERT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags);
   ASSERT_EQ("/system/lib/fake5.so", info->name);
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryBuffer.cpp b/libunwindstack/tests/MemoryBufferTest.cpp
similarity index 96%
rename from libunwindstack/tests/MemoryBuffer.cpp
rename to libunwindstack/tests/MemoryBufferTest.cpp
index af3d6b9..50a8a1b 100644
--- a/libunwindstack/tests/MemoryBuffer.cpp
+++ b/libunwindstack/tests/MemoryBufferTest.cpp
@@ -18,10 +18,12 @@
 
 #include <gtest/gtest.h>
 
-#include "Memory.h"
+#include <unwindstack/Memory.h>
 
 #include "LogFake.h"
 
+namespace unwindstack {
+
 class MemoryBufferTest : public ::testing::Test {
  protected:
   void SetUp() override {
@@ -75,3 +77,5 @@
 
   ASSERT_FALSE(memory_->Read(UINT64_MAX - 100, buffer.data(), 200));
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryFake.cpp b/libunwindstack/tests/MemoryFake.cpp
index afb1029..2026acc 100644
--- a/libunwindstack/tests/MemoryFake.cpp
+++ b/libunwindstack/tests/MemoryFake.cpp
@@ -21,6 +21,8 @@
 
 #include "MemoryFake.h"
 
+namespace unwindstack {
+
 void MemoryFake::SetMemory(uint64_t addr, const void* memory, size_t length) {
   const uint8_t* src = reinterpret_cast<const uint8_t*>(memory);
   for (size_t i = 0; i < length; i++, addr++) {
@@ -44,3 +46,5 @@
   }
   return true;
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryFake.h b/libunwindstack/tests/MemoryFake.h
index 70ef30a..d374261 100644
--- a/libunwindstack/tests/MemoryFake.h
+++ b/libunwindstack/tests/MemoryFake.h
@@ -23,7 +23,9 @@
 #include <vector>
 #include <unordered_map>
 
-#include "Memory.h"
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
 
 class MemoryFake : public Memory {
  public:
@@ -87,4 +89,6 @@
   }
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_TESTS_MEMORY_FAKE_H
diff --git a/libunwindstack/tests/MemoryFileTest.cpp b/libunwindstack/tests/MemoryFileTest.cpp
index aa7a23a..a204bae 100644
--- a/libunwindstack/tests/MemoryFileTest.cpp
+++ b/libunwindstack/tests/MemoryFileTest.cpp
@@ -21,7 +21,9 @@
 #include <android-base/file.h>
 #include <gtest/gtest.h>
 
-#include "Memory.h"
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
 
 class MemoryFileTest : public ::testing::Test {
  protected:
@@ -269,3 +271,5 @@
     ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
   }
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryLocalTest.cpp b/libunwindstack/tests/MemoryLocalTest.cpp
index ab999da..73eebdd 100644
--- a/libunwindstack/tests/MemoryLocalTest.cpp
+++ b/libunwindstack/tests/MemoryLocalTest.cpp
@@ -21,7 +21,9 @@
 
 #include <gtest/gtest.h>
 
-#include "Memory.h"
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
 
 TEST(MemoryLocalTest, read) {
   std::vector<uint8_t> src(1024);
@@ -64,3 +66,5 @@
   uint64_t value;
   ASSERT_FALSE(local.Read(reinterpret_cast<uint64_t>(&value), dst.data(), SIZE_MAX));
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryRangeTest.cpp b/libunwindstack/tests/MemoryRangeTest.cpp
index 469afcc..6d1366c 100644
--- a/libunwindstack/tests/MemoryRangeTest.cpp
+++ b/libunwindstack/tests/MemoryRangeTest.cpp
@@ -22,10 +22,12 @@
 
 #include <gtest/gtest.h>
 
-#include "Memory.h"
+#include <unwindstack/Memory.h>
 
 #include "MemoryFake.h"
 
+namespace unwindstack {
+
 TEST(MemoryRangeTest, read) {
   std::vector<uint8_t> src(1024);
   memset(src.data(), 0x4c, 1024);
@@ -70,3 +72,5 @@
   std::unique_ptr<MemoryRange> overflow(new MemoryRange(new MemoryFakeAlwaysReadZero, 100, 200));
   ASSERT_FALSE(overflow->Read(UINT64_MAX - 10, buffer.data(), 100));
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index e48edf7..f8965b2 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -31,10 +31,12 @@
 #include <android-base/file.h>
 #include <gtest/gtest.h>
 
-#include "Memory.h"
+#include <unwindstack/Memory.h>
 
 #include "MemoryFake.h"
 
+namespace unwindstack {
+
 class MemoryRemoteTest : public ::testing::Test {
  protected:
   static uint64_t NanoTime() {
@@ -91,6 +93,7 @@
   ASSERT_TRUE(Detach(pid));
 
   kill(pid, SIGKILL);
+  ASSERT_EQ(pid, wait(nullptr));
 }
 
 TEST_F(MemoryRemoteTest, read_fail) {
@@ -131,6 +134,7 @@
   ASSERT_TRUE(Detach(pid));
 
   kill(pid, SIGKILL);
+  ASSERT_EQ(pid, wait(nullptr));
 }
 
 TEST_F(MemoryRemoteTest, read_overflow) {
@@ -160,4 +164,7 @@
   ASSERT_TRUE(Detach(pid));
 
   kill(pid, SIGKILL);
+  ASSERT_EQ(pid, wait(nullptr));
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryTest.cpp b/libunwindstack/tests/MemoryTest.cpp
index 51b5d7d..4a9ed9f 100644
--- a/libunwindstack/tests/MemoryTest.cpp
+++ b/libunwindstack/tests/MemoryTest.cpp
@@ -22,10 +22,12 @@
 
 #include <gtest/gtest.h>
 
-#include "Memory.h"
+#include <unwindstack/Memory.h>
 
 #include "MemoryFake.h"
 
+namespace unwindstack {
+
 TEST(MemoryTest, read32) {
   MemoryFakeAlwaysReadZero memory;
 
@@ -124,3 +126,5 @@
   ASSERT_TRUE(memory.ReadString(0, &dst_name));
   ASSERT_EQ("short", dst_name);
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index ff030c8..6669d7d 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -19,7 +19,10 @@
 
 #include <stdint.h>
 
-#include "Regs.h"
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
 
 template <typename TypeParam>
 class RegsFake : public RegsImpl<TypeParam> {
@@ -28,9 +31,12 @@
       : RegsImpl<TypeParam>(total_regs, sp_reg, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {}
   virtual ~RegsFake() = default;
 
-  uint64_t GetRelPc(Elf*, const MapInfo*) override { return 0; }
   uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; }
+  void SetFromRaw() override {}
+  bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
   bool GetReturnAddressFromDefault(Memory*, uint64_t*) { return false; }
 };
 
+}  // namespace unwindstack
+
 #endif  // _LIBUNWINDSTACK_TESTS_REGS_FAKE_H
diff --git a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
new file mode 100644
index 0000000..85192d5
--- /dev/null
+++ b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
@@ -0,0 +1,201 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+#include "Machine.h"
+
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+class RegsStepIfSignalHandlerTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    elf_memory_ = new MemoryFake;
+    elf_.reset(new Elf(elf_memory_));
+  }
+
+  void ArmStepIfSignalHandlerNonRt(uint32_t pc_data);
+  void ArmStepIfSignalHandlerRt(uint32_t pc_data);
+
+  MemoryFake* elf_memory_;
+  MemoryFake process_memory_;
+  std::unique_ptr<Elf> elf_;
+};
+
+void RegsStepIfSignalHandlerTest::ArmStepIfSignalHandlerNonRt(uint32_t pc_data) {
+  uint64_t addr = 0x1000;
+  RegsArm regs;
+  regs[ARM_REG_PC] = 0x5000;
+  regs[ARM_REG_SP] = addr;
+  regs.SetFromRaw();
+
+  elf_memory_->SetData32(0x5000, pc_data);
+
+  for (uint64_t index = 0; index <= 30; index++) {
+    process_memory_.SetData32(addr + index * 4, index * 0x10);
+  }
+
+  ASSERT_TRUE(regs.StepIfSignalHandler(0x5000, elf_.get(), &process_memory_));
+  EXPECT_EQ(0x100U, regs[ARM_REG_SP]);
+  EXPECT_EQ(0x120U, regs[ARM_REG_PC]);
+  EXPECT_EQ(0x100U, regs.sp());
+  EXPECT_EQ(0x120U, regs.pc());
+}
+
+TEST_F(RegsStepIfSignalHandlerTest, arm_step_if_signal_handler_non_rt) {
+  // Form 1
+  ArmStepIfSignalHandlerNonRt(0xe3a07077);
+
+  // Form 2
+  ArmStepIfSignalHandlerNonRt(0xef900077);
+
+  // Form 3
+  ArmStepIfSignalHandlerNonRt(0xdf002777);
+}
+
+void RegsStepIfSignalHandlerTest::ArmStepIfSignalHandlerRt(uint32_t pc_data) {
+  uint64_t addr = 0x1000;
+  RegsArm regs;
+  regs[ARM_REG_PC] = 0x5000;
+  regs[ARM_REG_SP] = addr;
+  regs.SetFromRaw();
+
+  elf_memory_->SetData32(0x5000, pc_data);
+
+  for (uint64_t index = 0; index <= 100; index++) {
+    process_memory_.SetData32(addr + index * 4, index * 0x10);
+  }
+
+  ASSERT_TRUE(regs.StepIfSignalHandler(0x5000, elf_.get(), &process_memory_));
+  EXPECT_EQ(0x350U, regs[ARM_REG_SP]);
+  EXPECT_EQ(0x370U, regs[ARM_REG_PC]);
+  EXPECT_EQ(0x350U, regs.sp());
+  EXPECT_EQ(0x370U, regs.pc());
+}
+
+TEST_F(RegsStepIfSignalHandlerTest, arm_step_if_signal_handler_rt) {
+  // Form 1
+  ArmStepIfSignalHandlerRt(0xe3a070ad);
+
+  // Form 2
+  ArmStepIfSignalHandlerRt(0xef9000ad);
+
+  // Form 3
+  ArmStepIfSignalHandlerRt(0xdf0027ad);
+}
+
+TEST_F(RegsStepIfSignalHandlerTest, arm64_step_if_signal_handler) {
+  uint64_t addr = 0x1000;
+  RegsArm64 regs;
+  regs[ARM64_REG_PC] = 0x8000;
+  regs[ARM64_REG_SP] = addr;
+  regs.SetFromRaw();
+
+  elf_memory_->SetData64(0x8000, 0xd4000001d2801168ULL);
+
+  for (uint64_t index = 0; index <= 100; index++) {
+    process_memory_.SetData64(addr + index * 8, index * 0x10);
+  }
+
+  ASSERT_TRUE(regs.StepIfSignalHandler(0x8000, elf_.get(), &process_memory_));
+  EXPECT_EQ(0x460U, regs[ARM64_REG_SP]);
+  EXPECT_EQ(0x470U, regs[ARM64_REG_PC]);
+  EXPECT_EQ(0x460U, regs.sp());
+  EXPECT_EQ(0x470U, regs.pc());
+}
+
+TEST_F(RegsStepIfSignalHandlerTest, x86_step_if_signal_handler_no_siginfo) {
+  uint64_t addr = 0xa00;
+  RegsX86 regs;
+  regs[X86_REG_EIP] = 0x4100;
+  regs[X86_REG_ESP] = addr;
+  regs.SetFromRaw();
+
+  elf_memory_->SetData64(0x4100, 0x80cd00000077b858ULL);
+  for (uint64_t index = 0; index <= 25; index++) {
+    process_memory_.SetData32(addr + index * 4, index * 0x10);
+  }
+
+  ASSERT_TRUE(regs.StepIfSignalHandler(0x4100, elf_.get(), &process_memory_));
+  EXPECT_EQ(0x70U, regs[X86_REG_EBP]);
+  EXPECT_EQ(0x80U, regs[X86_REG_ESP]);
+  EXPECT_EQ(0x90U, regs[X86_REG_EBX]);
+  EXPECT_EQ(0xa0U, regs[X86_REG_EDX]);
+  EXPECT_EQ(0xb0U, regs[X86_REG_ECX]);
+  EXPECT_EQ(0xc0U, regs[X86_REG_EAX]);
+  EXPECT_EQ(0xf0U, regs[X86_REG_EIP]);
+  EXPECT_EQ(0x80U, regs.sp());
+  EXPECT_EQ(0xf0U, regs.pc());
+}
+
+TEST_F(RegsStepIfSignalHandlerTest, x86_step_if_signal_handler_siginfo) {
+  uint64_t addr = 0xa00;
+  RegsX86 regs;
+  regs[X86_REG_EIP] = 0x4100;
+  regs[X86_REG_ESP] = addr;
+  regs.SetFromRaw();
+
+  elf_memory_->SetData64(0x4100, 0x0080cd000000adb8ULL);
+  addr += 8;
+  // Pointer to ucontext data.
+  process_memory_.SetData32(addr, 0x8100);
+
+  addr = 0x8100;
+  for (uint64_t index = 0; index <= 30; index++) {
+    process_memory_.SetData32(addr + index * 4, index * 0x10);
+  }
+
+  ASSERT_TRUE(regs.StepIfSignalHandler(0x4100, elf_.get(), &process_memory_));
+  EXPECT_EQ(0xb0U, regs[X86_REG_EBP]);
+  EXPECT_EQ(0xc0U, regs[X86_REG_ESP]);
+  EXPECT_EQ(0xd0U, regs[X86_REG_EBX]);
+  EXPECT_EQ(0xe0U, regs[X86_REG_EDX]);
+  EXPECT_EQ(0xf0U, regs[X86_REG_ECX]);
+  EXPECT_EQ(0x100U, regs[X86_REG_EAX]);
+  EXPECT_EQ(0x130U, regs[X86_REG_EIP]);
+  EXPECT_EQ(0xc0U, regs.sp());
+  EXPECT_EQ(0x130U, regs.pc());
+}
+
+TEST_F(RegsStepIfSignalHandlerTest, x86_64_step_if_signal_handler) {
+  uint64_t addr = 0x500;
+  RegsX86_64 regs;
+  regs[X86_64_REG_RIP] = 0x7000;
+  regs[X86_64_REG_RSP] = addr;
+  regs.SetFromRaw();
+
+  elf_memory_->SetData64(0x7000, 0x0f0000000fc0c748);
+  elf_memory_->SetData16(0x7008, 0x0f05);
+
+  for (uint64_t index = 0; index <= 30; index++) {
+    process_memory_.SetData64(addr + index * 8, index * 0x10);
+  }
+
+  ASSERT_TRUE(regs.StepIfSignalHandler(0x7000, elf_.get(), &process_memory_));
+  EXPECT_EQ(0x140U, regs[X86_64_REG_RSP]);
+  EXPECT_EQ(0x150U, regs[X86_64_REG_RIP]);
+  EXPECT_EQ(0x140U, regs.sp());
+  EXPECT_EQ(0x150U, regs.pc());
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 3056373..e6de56a 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -18,13 +18,15 @@
 
 #include <gtest/gtest.h>
 
-#include "Elf.h"
-#include "ElfInterface.h"
-#include "MapInfo.h"
-#include "Regs.h"
+#include <unwindstack/Elf.h>
+#include <unwindstack/ElfInterface.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Regs.h>
 
 #include "MemoryFake.h"
 
+namespace unwindstack {
+
 class ElfFake : public Elf {
  public:
   ElfFake(Memory* memory) : Elf(memory) { valid_ = true; }
@@ -56,7 +58,9 @@
       : RegsImpl<TypeParam>(total_regs, regs_sp, return_loc) {}
   virtual ~RegsTestImpl() = default;
 
-  uint64_t GetAdjustedPc(uint64_t, Elf*) { return 0; }
+  uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; }
+  void SetFromRaw() override {}
+  bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
 };
 
 class RegsTest : public ::testing::Test {
@@ -69,10 +73,7 @@
   }
 
   template <typename AddressType>
-  void regs_rel_pc();
-
-  template <typename AddressType>
-  void regs_return_address_register();
+  void RegsReturnAddressRegister();
 
   ElfInterfaceFake* elf_interface_;
   MemoryFake* memory_;
@@ -126,27 +127,7 @@
 }
 
 template <typename AddressType>
-void RegsTest::regs_rel_pc() {
-  RegsTestImpl<AddressType> regs(30, 12);
-
-  elf_interface_->set_load_bias(0);
-  MapInfo map_info{.start = 0x1000, .end = 0x2000};
-  regs.set_pc(0x1101);
-  ASSERT_EQ(0x101U, regs.GetRelPc(elf_.get(), &map_info));
-  elf_interface_->set_load_bias(0x3000);
-  ASSERT_EQ(0x3101U, regs.GetRelPc(elf_.get(), &map_info));
-}
-
-TEST_F(RegsTest, regs32_rel_pc) {
-  regs_rel_pc<uint32_t>();
-}
-
-TEST_F(RegsTest, regs64_rel_pc) {
-  regs_rel_pc<uint64_t>();
-}
-
-template <typename AddressType>
-void RegsTest::regs_return_address_register() {
+void RegsTest::RegsReturnAddressRegister() {
   RegsTestImpl<AddressType> regs(20, 10, Regs::Location(Regs::LOCATION_REGISTER, 5));
 
   regs[5] = 0x12345;
@@ -156,11 +137,11 @@
 }
 
 TEST_F(RegsTest, regs32_return_address_register) {
-  regs_return_address_register<uint32_t>();
+  RegsReturnAddressRegister<uint32_t>();
 }
 
 TEST_F(RegsTest, regs64_return_address_register) {
-  regs_return_address_register<uint64_t>();
+  RegsReturnAddressRegister<uint64_t>();
 }
 
 TEST_F(RegsTest, regs32_return_address_sp_offset) {
@@ -249,18 +230,60 @@
   MapInfo map_info{.start = 0x1000, .end = 0x2000};
 
   regs_arm.set_pc(0x1500);
-  ASSERT_EQ(0x500U, regs_arm.GetRelPc(&invalid_elf, &map_info));
+  ASSERT_EQ(0x500U, invalid_elf.GetRelPc(regs_arm.pc(), &map_info));
   ASSERT_EQ(0x500U, regs_arm.GetAdjustedPc(0x500U, &invalid_elf));
 
   regs_arm64.set_pc(0x1600);
-  ASSERT_EQ(0x600U, regs_arm64.GetRelPc(&invalid_elf, &map_info));
+  ASSERT_EQ(0x600U, invalid_elf.GetRelPc(regs_arm64.pc(), &map_info));
   ASSERT_EQ(0x600U, regs_arm64.GetAdjustedPc(0x600U, &invalid_elf));
 
   regs_x86.set_pc(0x1700);
-  ASSERT_EQ(0x700U, regs_x86.GetRelPc(&invalid_elf, &map_info));
+  ASSERT_EQ(0x700U, invalid_elf.GetRelPc(regs_x86.pc(), &map_info));
   ASSERT_EQ(0x700U, regs_x86.GetAdjustedPc(0x700U, &invalid_elf));
 
   regs_x86_64.set_pc(0x1800);
-  ASSERT_EQ(0x800U, regs_x86_64.GetRelPc(&invalid_elf, &map_info));
+  ASSERT_EQ(0x800U, invalid_elf.GetRelPc(regs_x86_64.pc(), &map_info));
   ASSERT_EQ(0x800U, regs_x86_64.GetAdjustedPc(0x800U, &invalid_elf));
 }
+
+TEST_F(RegsTest, arm_set_from_raw) {
+  RegsArm arm;
+  uint32_t* regs = reinterpret_cast<uint32_t*>(arm.RawData());
+  regs[13] = 0x100;
+  regs[15] = 0x200;
+  arm.SetFromRaw();
+  EXPECT_EQ(0x100U, arm.sp());
+  EXPECT_EQ(0x200U, arm.pc());
+}
+
+TEST_F(RegsTest, arm64_set_from_raw) {
+  RegsArm64 arm64;
+  uint64_t* regs = reinterpret_cast<uint64_t*>(arm64.RawData());
+  regs[31] = 0xb100000000ULL;
+  regs[32] = 0xc200000000ULL;
+  arm64.SetFromRaw();
+  EXPECT_EQ(0xb100000000U, arm64.sp());
+  EXPECT_EQ(0xc200000000U, arm64.pc());
+}
+
+TEST_F(RegsTest, x86_set_from_raw) {
+  RegsX86 x86;
+  uint32_t* regs = reinterpret_cast<uint32_t*>(x86.RawData());
+  regs[4] = 0x23450000;
+  regs[8] = 0xabcd0000;
+  x86.SetFromRaw();
+  EXPECT_EQ(0x23450000U, x86.sp());
+  EXPECT_EQ(0xabcd0000U, x86.pc());
+}
+
+TEST_F(RegsTest, x86_64_set_from_raw) {
+  RegsX86_64 x86_64;
+  uint64_t* regs = reinterpret_cast<uint64_t*>(x86_64.RawData());
+  regs[7] = 0x1200000000ULL;
+  regs[16] = 0x4900000000ULL;
+  x86_64.SetFromRaw();
+  EXPECT_EQ(0x1200000000U, x86_64.sp());
+  EXPECT_EQ(0x4900000000U, x86_64.pc());
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/SymbolsTest.cpp b/libunwindstack/tests/SymbolsTest.cpp
index a0a21e6..da258a6 100644
--- a/libunwindstack/tests/SymbolsTest.cpp
+++ b/libunwindstack/tests/SymbolsTest.cpp
@@ -32,10 +32,13 @@
 #include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
-#include "Memory.h"
+#include <unwindstack/Memory.h>
+
 #include "MemoryFake.h"
 #include "Symbols.h"
 
+namespace unwindstack {
+
 template <typename TypeParam>
 class SymbolsTest : public ::testing::Test {
  protected:
@@ -333,3 +336,5 @@
 
 typedef ::testing::Types<Elf32_Sym, Elf64_Sym> SymbolsTestTypes;
 INSTANTIATE_TYPED_TEST_CASE_P(, SymbolsTest, SymbolsTestTypes);
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
new file mode 100644
index 0000000..3c69e2a
--- /dev/null
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <signal.h>
+#include <stdint.h>
+#include <sys/ptrace.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+#include <atomic>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsGetLocal.h>
+
+namespace unwindstack {
+
+static std::atomic_bool g_ready(false);
+static volatile bool g_ready_for_remote = false;
+static volatile bool g_signal_ready_for_remote = false;
+static std::atomic_bool g_finish(false);
+static std::atomic_uintptr_t g_ucontext;
+
+static std::vector<const char*> kFunctionOrder{"InnerFunction", "MiddleFunction", "OuterFunction"};
+
+static std::vector<const char*> kFunctionSignalOrder{"SignalInnerFunction", "SignalMiddleFunction",
+                                                     "SignalOuterFunction", "InnerFunction",
+                                                     "MiddleFunction",      "OuterFunction"};
+
+static void SignalHandler(int, siginfo_t*, void* sigcontext) {
+  g_ucontext = reinterpret_cast<uintptr_t>(sigcontext);
+  while (!g_finish.load()) {
+  }
+}
+
+extern "C" void SignalInnerFunction() {
+  g_signal_ready_for_remote = true;
+  while (!g_finish.load()) {
+  }
+}
+
+extern "C" void SignalMiddleFunction() {
+  SignalInnerFunction();
+}
+
+extern "C" void SignalOuterFunction() {
+  SignalMiddleFunction();
+}
+
+static void SignalCallerHandler(int, siginfo_t*, void*) {
+  SignalOuterFunction();
+}
+
+static std::string ErrorMsg(const std::vector<const char*>& function_names, size_t index,
+                            std::stringstream& unwind_stream) {
+  return std::string(
+             "Unwind completed without finding all frames\n"
+             "  Looking for function: ") +
+         function_names[index] + "\n" + "Unwind data:\n" + unwind_stream.str();
+}
+
+static void VerifyUnwind(pid_t pid, Memory* memory, Maps* maps, Regs* regs,
+                         std::vector<const char*>& function_names) {
+  size_t function_name_index = 0;
+
+  std::stringstream unwind_stream;
+  unwind_stream << std::hex;
+  for (size_t frame_num = 0; frame_num < 64; frame_num++) {
+    ASSERT_NE(0U, regs->pc()) << ErrorMsg(function_names, function_name_index, unwind_stream);
+    MapInfo* map_info = maps->Find(regs->pc());
+    ASSERT_TRUE(map_info != nullptr) << ErrorMsg(function_names, function_name_index, unwind_stream);
+
+    Elf* elf = map_info->GetElf(pid, true);
+    uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
+    uint64_t adjusted_rel_pc = rel_pc;
+    if (frame_num != 0) {
+      adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf);
+    }
+    unwind_stream << "  PC: 0x" << regs->pc() << " Rel: 0x" << adjusted_rel_pc;
+    unwind_stream << " Map: ";
+    if (!map_info->name.empty()) {
+      unwind_stream << map_info->name;
+    } else {
+      unwind_stream << " anonymous";
+    }
+    unwind_stream << "<" << map_info->start << "-" << map_info->end << ">";
+
+    std::string name;
+    uint64_t func_offset;
+    if (elf->GetFunctionName(adjusted_rel_pc, &name, &func_offset)) {
+      if (name == function_names[function_name_index]) {
+        if (++function_name_index == function_names.size()) {
+          return;
+        }
+      }
+      unwind_stream << " " << name;
+    }
+    unwind_stream << "\n";
+    ASSERT_TRUE(elf->Step(rel_pc + map_info->elf_offset, regs, memory))
+        << ErrorMsg(function_names, function_name_index, unwind_stream);
+  }
+  ASSERT_TRUE(false) << ErrorMsg(function_names, function_name_index, unwind_stream);
+}
+
+// This test assumes that this code is compiled with optimizations turned
+// off. If this doesn't happen, then all of the calls will be optimized
+// away.
+extern "C" void InnerFunction(bool local) {
+  if (local) {
+    LocalMaps maps;
+    ASSERT_TRUE(maps.Parse());
+    std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
+    RegsGetLocal(regs.get());
+    MemoryLocal memory;
+
+    VerifyUnwind(getpid(), &memory, &maps, regs.get(), kFunctionOrder);
+  } else {
+    g_ready_for_remote = true;
+    g_ready = true;
+    while (!g_finish.load()) {
+    }
+  }
+}
+
+extern "C" void MiddleFunction(bool local) {
+  InnerFunction(local);
+}
+
+extern "C" void OuterFunction(bool local) {
+  MiddleFunction(local);
+}
+
+TEST(UnwindTest, local) {
+  OuterFunction(true);
+}
+
+void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) {
+  *completed = false;
+  // Need to sleep before attempting first ptrace. Without this, on the
+  // host it becomes impossible to attach and ptrace set errno to EPERM.
+  usleep(1000);
+  for (size_t i = 0; i < 100; i++) {
+    ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid, 0, 0));
+    for (size_t j = 0; j < 100; j++) {
+      siginfo_t si;
+      if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
+        MemoryRemote memory(pid);
+        // Read the remote value to see if we are ready.
+        bool value;
+        if (memory.Read(addr, &value, sizeof(value)) && value) {
+          *completed = true;
+          break;
+        }
+      }
+      usleep(1000);
+    }
+    if (leave_attached && *completed) {
+      break;
+    }
+    ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
+    if (*completed) {
+      break;
+    }
+    usleep(1000);
+  }
+}
+
+TEST(UnwindTest, remote) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    OuterFunction(false);
+    exit(0);
+  }
+  ASSERT_NE(-1, pid);
+
+  bool completed;
+  WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed);
+  ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
+
+  RemoteMaps maps(pid);
+  ASSERT_TRUE(maps.Parse());
+  MemoryRemote memory(pid);
+  uint32_t machine_type;
+  std::unique_ptr<Regs> regs(Regs::RemoteGet(pid, &machine_type));
+  ASSERT_TRUE(regs.get() != nullptr);
+
+  VerifyUnwind(pid, &memory, &maps, regs.get(), kFunctionOrder);
+
+  ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
+
+  kill(pid, SIGKILL);
+  ASSERT_EQ(pid, wait(nullptr));
+}
+
+TEST(UnwindTest, from_context) {
+  std::atomic_int tid(0);
+  std::thread thread([&]() {
+    tid = syscall(__NR_gettid);
+    OuterFunction(false);
+  });
+
+  struct sigaction act, oldact;
+  memset(&act, 0, sizeof(act));
+  act.sa_sigaction = SignalHandler;
+  act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+  ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact));
+  // Wait for the tid to get set.
+  for (size_t i = 0; i < 100; i++) {
+    if (tid.load() != 0) {
+      break;
+    }
+    usleep(1000);
+  }
+  ASSERT_NE(0, tid.load());
+  // Portable tgkill method.
+  ASSERT_EQ(0, syscall(__NR_tgkill, getpid(), tid.load(), SIGUSR1)) << "Error: " << strerror(errno);
+
+  // Wait for context data.
+  void* ucontext;
+  for (size_t i = 0; i < 2000; i++) {
+    ucontext = reinterpret_cast<void*>(g_ucontext.load());
+    if (ucontext != nullptr) {
+      break;
+    }
+    usleep(1000);
+  }
+  ASSERT_TRUE(ucontext != nullptr) << "Timed out waiting for thread to respond to signal.";
+
+  LocalMaps maps;
+  ASSERT_TRUE(maps.Parse());
+  std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::GetMachineType(), ucontext));
+  MemoryLocal memory;
+
+  VerifyUnwind(tid.load(), &memory, &maps, regs.get(), kFunctionOrder);
+
+  ASSERT_EQ(0, sigaction(SIGUSR1, &oldact, nullptr));
+
+  g_finish = true;
+  thread.join();
+}
+
+static void RemoteThroughSignal(unsigned int sa_flags) {
+  g_ready = false;
+  g_signal_ready_for_remote = false;
+  g_finish = false;
+
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    struct sigaction act, oldact;
+    memset(&act, 0, sizeof(act));
+    act.sa_sigaction = SignalCallerHandler;
+    act.sa_flags = SA_RESTART | SA_ONSTACK | sa_flags;
+    ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact));
+
+    OuterFunction(false);
+    exit(0);
+  }
+  ASSERT_NE(-1, pid);
+
+  bool completed;
+  WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), false, &completed);
+  ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
+  ASSERT_EQ(0, kill(pid, SIGUSR1));
+  WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_signal_ready_for_remote), true, &completed);
+  ASSERT_TRUE(completed) << "Timed out waiting for remote process to be in signal handler.";
+
+  RemoteMaps maps(pid);
+  ASSERT_TRUE(maps.Parse());
+  MemoryRemote memory(pid);
+  uint32_t machine_type;
+  std::unique_ptr<Regs> regs(Regs::RemoteGet(pid, &machine_type));
+  ASSERT_TRUE(regs.get() != nullptr);
+
+  VerifyUnwind(pid, &memory, &maps, regs.get(), kFunctionSignalOrder);
+
+  ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
+
+  kill(pid, SIGKILL);
+  ASSERT_EQ(pid, wait(nullptr));
+}
+
+TEST(UnwindTest, remote_through_signal) {
+  RemoteThroughSignal(0);
+}
+
+TEST(UnwindTest, remote_through_signal_sa_siginfo) {
+  RemoteThroughSignal(SA_SIGINFO);
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/elf32.xz b/libunwindstack/tests/files/elf32.xz
similarity index 100%
rename from libunwindstack/tests/elf32.xz
rename to libunwindstack/tests/files/elf32.xz
Binary files differ
diff --git a/libunwindstack/tests/elf64.xz b/libunwindstack/tests/files/elf64.xz
similarity index 100%
rename from libunwindstack/tests/elf64.xz
rename to libunwindstack/tests/files/elf64.xz
Binary files differ
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
new file mode 100644
index 0000000..642105a
--- /dev/null
+++ b/libunwindstack/tools/unwind.cpp
@@ -0,0 +1,162 @@
+/*
+ * 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 <elf.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
+static bool Attach(pid_t pid) {
+  if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
+    return false;
+  }
+
+  // Allow at least 1 second to attach properly.
+  for (size_t i = 0; i < 1000; i++) {
+    siginfo_t si;
+    if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
+      return true;
+    }
+    usleep(1000);
+  }
+  printf("%d: Failed to stop.\n", pid);
+  return false;
+}
+
+static bool Detach(pid_t pid) {
+  return ptrace(PTRACE_DETACH, pid, 0, 0) == 0;
+}
+
+void DoUnwind(pid_t pid) {
+  unwindstack::RemoteMaps remote_maps(pid);
+  if (!remote_maps.Parse()) {
+    printf("Failed to parse map data.\n");
+    return;
+  }
+
+  uint32_t machine_type;
+  unwindstack::Regs* regs = unwindstack::Regs::RemoteGet(pid, &machine_type);
+  if (regs == nullptr) {
+    printf("Unable to get remote reg data\n");
+    return;
+  }
+
+  bool bits32 = true;
+  printf("ABI: ");
+  switch (machine_type) {
+    case EM_ARM:
+      printf("arm");
+      break;
+    case EM_386:
+      printf("x86");
+      break;
+    case EM_AARCH64:
+      printf("arm64");
+      bits32 = false;
+      break;
+    case EM_X86_64:
+      printf("x86_64");
+      bits32 = false;
+      break;
+    default:
+      printf("unknown\n");
+      return;
+  }
+  printf("\n");
+
+  unwindstack::MemoryRemote remote_memory(pid);
+  for (size_t frame_num = 0; frame_num < 64; frame_num++) {
+    if (regs->pc() == 0) {
+      break;
+    }
+    unwindstack::MapInfo* map_info = remote_maps.Find(regs->pc());
+    if (map_info == nullptr) {
+      printf("Failed to find map data for the pc\n");
+      break;
+    }
+
+    unwindstack::Elf* elf = map_info->GetElf(pid, true);
+
+    uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
+    uint64_t adjusted_rel_pc = rel_pc;
+    // Don't need to adjust the first frame pc.
+    if (frame_num != 0) {
+      adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf);
+    }
+
+    std::string name;
+    if (bits32) {
+      printf("  #%02zu pc %08" PRIx64, frame_num, adjusted_rel_pc);
+    } else {
+      printf("  #%02zu pc %016" PRIx64, frame_num, adjusted_rel_pc);
+    }
+    if (!map_info->name.empty()) {
+      printf("  %s", map_info->name.c_str());
+      if (map_info->elf_offset != 0) {
+        printf(" (offset 0x%" PRIx64 ")", map_info->elf_offset);
+      }
+    } else {
+      printf("  <anonymous:%" PRIx64 ">", map_info->offset);
+    }
+    uint64_t func_offset;
+    if (elf->GetFunctionName(adjusted_rel_pc, &name, &func_offset)) {
+      printf(" (%s", name.c_str());
+      if (func_offset != 0) {
+        printf("+%" PRId64, func_offset);
+      }
+      printf(")");
+    }
+    printf("\n");
+
+    if (!elf->Step(rel_pc + map_info->elf_offset, regs, &remote_memory)) {
+      break;
+    }
+  }
+}
+
+int main(int argc, char** argv) {
+  if (argc != 2) {
+    printf("Usage: unwind <PID>\n");
+    return 1;
+  }
+
+  pid_t pid = atoi(argv[1]);
+  if (!Attach(pid)) {
+    printf("Failed to attach to pid %d: %s\n", pid, strerror(errno));
+    return 1;
+  }
+
+  DoUnwind(pid);
+
+  Detach(pid);
+
+  return 0;
+}
diff --git a/libunwindstack/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
similarity index 92%
rename from libunwindstack/unwind_info.cpp
rename to libunwindstack/tools/unwind_info.cpp
index da1522b..66a9439 100644
--- a/libunwindstack/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -21,17 +21,20 @@
 #include <stdio.h>
 #include <string.h>
 #include <sys/mman.h>
-#include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
+#include <unwindstack/DwarfSection.h>
+#include <unwindstack/DwarfStructs.h>
+#include <unwindstack/Elf.h>
+#include <unwindstack/ElfInterface.h>
+#include <unwindstack/Log.h>
+
 #include "ArmExidx.h"
-#include "DwarfSection.h"
-#include "DwarfStructs.h"
-#include "Elf.h"
-#include "ElfInterface.h"
 #include "ElfInterfaceArm.h"
-#include "Log.h"
+
+namespace unwindstack {
 
 void DumpArm(ElfInterfaceArm* interface) {
   if (interface == nullptr) {
@@ -100,31 +103,12 @@
   }
 }
 
-int main(int argc, char** argv) {
-  if (argc != 2) {
-    printf("Need to pass the name of an elf file to the program.\n");
-    return 1;
-  }
-
-  struct stat st;
-  if (stat(argv[1], &st) == -1) {
-    printf("Cannot stat %s: %s\n", argv[1], strerror(errno));
-    return 1;
-  }
-  if (!S_ISREG(st.st_mode)) {
-    printf("%s is not a regular file.\n", argv[1]);
-    return 1;
-  }
-  if (S_ISDIR(st.st_mode)) {
-    printf("%s is a directory.\n", argv[1]);
-    return 1;
-  }
-
+int GetElfInfo(const char* file) {
   // Send all log messages to stdout.
   log_to_stdout(true);
 
   MemoryFileAtOffset* memory = new MemoryFileAtOffset;
-  if (!memory->Init(argv[1], 0)) {
+  if (!memory->Init(file, 0)) {
     // Initializatation failed.
     printf("Failed to init\n");
     return 1;
@@ -132,7 +116,7 @@
 
   Elf elf(memory);
   if (!elf.Init() || !elf.valid()) {
-    printf("%s is not a valid elf file.\n", argv[1]);
+    printf("%s is not a valid elf file.\n", file);
     return 1;
   }
 
@@ -177,3 +161,24 @@
 
   return 0;
 }
+
+}  // namespace unwindstack
+
+int main(int argc, char** argv) {
+  if (argc != 2) {
+    printf("Need to pass the name of an elf file to the program.\n");
+    return 1;
+  }
+
+  struct stat st;
+  if (stat(argv[1], &st) == -1) {
+    printf("Cannot stat %s: %s\n", argv[1], strerror(errno));
+    return 1;
+  }
+  if (!S_ISREG(st.st_mode)) {
+    printf("%s is not a regular file.\n", argv[1]);
+    return 1;
+  }
+
+  return unwindstack::GetElfInfo(argv[1]);
+}
diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp
new file mode 100644
index 0000000..b757c1e
--- /dev/null
+++ b/libunwindstack/tools/unwind_symbols.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 <elf.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Log.h>
+#include <unwindstack/Memory.h>
+
+int main(int argc, char** argv) {
+  if (argc != 2) {
+    printf("Need to pass the name of an elf file to the program.\n");
+    return 1;
+  }
+
+  struct stat st;
+  if (stat(argv[1], &st) == -1) {
+    printf("Cannot stat %s: %s\n", argv[1], strerror(errno));
+    return 1;
+  }
+  if (!S_ISREG(st.st_mode)) {
+    printf("%s is not a regular file.\n", argv[1]);
+    return 1;
+  }
+
+  // Send all log messages to stdout.
+  unwindstack::log_to_stdout(true);
+
+  unwindstack::MemoryFileAtOffset* memory = new unwindstack::MemoryFileAtOffset;
+  if (!memory->Init(argv[1], 0)) {
+    printf("Failed to init\n");
+    return 1;
+  }
+
+  unwindstack::Elf elf(memory);
+  if (!elf.Init() || !elf.valid()) {
+    printf("%s is not a valid elf file.\n", argv[1]);
+    return 1;
+  }
+
+  switch (elf.machine_type()) {
+    case EM_ARM:
+      printf("ABI: arm\n");
+      break;
+    case EM_AARCH64:
+      printf("ABI: arm64\n");
+      break;
+    case EM_386:
+      printf("ABI: x86\n");
+      break;
+    case EM_X86_64:
+      printf("ABI: x86_64\n");
+      break;
+    default:
+      printf("ABI: unknown\n");
+      return 1;
+  }
+
+  // This is a crude way to get the symbols in order.
+  std::string name;
+  uint64_t load_bias = elf.interface()->load_bias();
+  for (const auto& entry : elf.interface()->pt_loads()) {
+    uint64_t start = entry.second.offset + load_bias;
+    uint64_t end = entry.second.table_size + load_bias;
+    for (uint64_t addr = start; addr < end; addr += 4) {
+      std::string cur_name;
+      uint64_t func_offset;
+      if (elf.GetFunctionName(addr, &cur_name, &func_offset)) {
+        if (cur_name != name) {
+          printf("<0x%" PRIx64 "> Function: %s\n", addr - func_offset, cur_name.c_str());
+        }
+        name = cur_name;
+      }
+    }
+  }
+
+  return 0;
+}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index ef16d56..787c10a 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -18,10 +18,12 @@
     host_supported: true,
 
     header_libs: [
+        "liblog_headers",
         "libsystem_headers",
         "libcutils_headers"
     ],
     export_header_lib_headers: [
+        "liblog_headers",
         "libsystem_headers",
         "libcutils_headers"
     ],
@@ -50,7 +52,6 @@
         "CallStack.cpp",
         "FileMap.cpp",
         "JenkinsHash.cpp",
-        "Log.cpp",
         "NativeHandle.cpp",
         "Printer.cpp",
         "PropertyMap.cpp",
@@ -82,9 +83,6 @@
     shared_libs: [
         "liblog",
     ],
-    export_shared_lib_headers: [
-        "liblog",
-    ],
 
     arch: {
         mips: {
@@ -147,8 +145,6 @@
             enabled: true,
         },
     },
-
-    clang: true,
 }
 
 // Include subdirectory makefiles
diff --git a/libutils/Log.cpp b/libutils/Log.cpp
deleted file mode 100644
index 2c1fb86..0000000
--- a/libutils/Log.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#define LOG_TAG "Log"
-
-#include <utils/Log.h>
-#include <utils/Timers.h>
-
-namespace android {
-
-LogIfSlow::LogIfSlow(
-        const char* tag, android_LogPriority priority, int timeoutMillis, const char* message)
-        : mTag(tag), mPriority(priority), mTimeoutMillis(timeoutMillis), mMessage(message),
-          mStart(systemTime(SYSTEM_TIME_BOOTTIME)) {
-}
-
-LogIfSlow::~LogIfSlow() {
-    int durationMillis = (int)nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_BOOTTIME) - mStart);
-    if (durationMillis > mTimeoutMillis) {
-        LOG_PRI(mPriority, mTag, "%s: %dms", mMessage, durationMillis);
-    }
-}
-
-} // namespace android
diff --git a/libutils/include/utils/Log.h b/libutils/include/utils/Log.h
index 5276a49..42e03e7 100644
--- a/libutils/include/utils/Log.h
+++ b/libutils/include/utils/Log.h
@@ -1,72 +1,7 @@
-/*
- * Copyright (C) 2005 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.
- */
+// DO NOT INCLUDE ANYTHING NEW IN THIS FILE.
 
-//
-// C/C++ logging functions.  See the logging documentation for API details.
-//
-// We'd like these to be available from C code (in case we import some from
-// somewhere), so this has a C interface.
-//
-// The output will be correct when the log file is shared between multiple
-// threads and/or multiple processes so long as the operating system
-// supports O_APPEND.  These calls have mutex-protected data structures
-// and so are NOT reentrant.  Do not use LOG in a signal handler.
-//
-#ifndef _LIBS_UTILS_LOG_H
-#define _LIBS_UTILS_LOG_H
-
-#include <sys/types.h>
+// <log/log.h> has replaced this file and all changes should go there instead.
+// This path remains strictly to include that header as there are thousands of
+// references to <utils/Log.h> in the tree.
 
 #include <log/log.h>
-
-#ifdef __cplusplus
-
-namespace android {
-
-/*
- * A very simple utility that yells in the log when an operation takes too long.
- */
-class LogIfSlow {
-public:
-    LogIfSlow(const char* tag, android_LogPriority priority,
-            int timeoutMillis, const char* message);
-    ~LogIfSlow();
-
-private:
-    const char* const mTag;
-    const android_LogPriority mPriority;
-    const int mTimeoutMillis;
-    const char* const mMessage;
-    const int64_t mStart;
-};
-
-/*
- * Writes the specified debug log message if this block takes longer than the
- * specified number of milliseconds to run.  Includes the time actually taken.
- *
- * {
- *     ALOGD_IF_SLOW(50, "Excessive delay doing something.");
- *     doSomething();
- * }
- */
-#define ALOGD_IF_SLOW(timeoutMillis, message) \
-    android::LogIfSlow _logIfSlow(LOG_TAG, ANDROID_LOG_DEBUG, timeoutMillis, message);
-
-} // namespace android
-
-#endif // __cplusplus
-
-#endif // _LIBS_UTILS_LOG_H
diff --git a/libutils/include/utils/Mutex.h b/libutils/include/utils/Mutex.h
index d106185..af6076c 100644
--- a/libutils/include/utils/Mutex.h
+++ b/libutils/include/utils/Mutex.h
@@ -28,6 +28,53 @@
 #include <utils/Errors.h>
 #include <utils/Timers.h>
 
+// Enable thread safety attributes only with clang.
+// The attributes can be safely erased when compiling with other compilers.
+#if defined(__clang__) && (!defined(SWIG))
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
+#else
+#define THREAD_ANNOTATION_ATTRIBUTE__(x)  // no-op
+#endif
+
+#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
+
+#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+
+#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+
+#define ACQUIRED_BEFORE(...) THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
+
+#define ACQUIRED_AFTER(...) THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
+
+#define REQUIRES(...) THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
+
+#define REQUIRES_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
+
+#define ACQUIRE(...) THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
+
+#define ACQUIRE_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
+
+#define RELEASE(...) THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
+
+#define RELEASE_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
+
+#define TRY_ACQUIRE(...) THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
+
+#define TRY_ACQUIRE_SHARED(...) \
+    THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
+
+#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+
+#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
+
+#define ASSERT_SHARED_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
+
+#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
+#define NO_THREAD_SAFETY_ANALYSIS THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+
 // ---------------------------------------------------------------------------
 namespace android {
 // ---------------------------------------------------------------------------
@@ -44,24 +91,24 @@
  * The mutex must be unlocked by the thread that locked it.  They are not
  * recursive, i.e. the same thread can't lock it multiple times.
  */
-class Mutex {
-public:
+class CAPABILITY("mutex") Mutex {
+  public:
     enum {
         PRIVATE = 0,
         SHARED = 1
     };
 
-                Mutex();
-    explicit    Mutex(const char* name);
-    explicit    Mutex(int type, const char* name = NULL);
-                ~Mutex();
+    Mutex();
+    explicit Mutex(const char* name);
+    explicit Mutex(int type, const char* name = NULL);
+    ~Mutex();
 
     // lock or unlock the mutex
-    status_t    lock();
-    void        unlock();
+    status_t lock() ACQUIRE();
+    void unlock() RELEASE();
 
     // lock if possible; returns 0 on success, error otherwise
-    status_t    tryLock();
+    status_t tryLock() TRY_ACQUIRE(true);
 
 #if defined(__ANDROID__)
     // Lock the mutex, but don't wait longer than timeoutNs (relative time).
@@ -75,32 +122,36 @@
     // which is subject to NTP adjustments, and includes time during suspend,
     // so a timeout may occur even though no processes could run.
     // Not holding a partial wakelock may lead to a system suspend.
-    status_t    timedLock(nsecs_t timeoutNs);
+    status_t timedLock(nsecs_t timeoutNs) TRY_ACQUIRE(true);
 #endif
 
     // Manages the mutex automatically. It'll be locked when Autolock is
     // constructed and released when Autolock goes out of scope.
-    class Autolock {
-    public:
-        inline explicit Autolock(Mutex& mutex) : mLock(mutex)  { mLock.lock(); }
-        inline explicit Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
-        inline ~Autolock() { mLock.unlock(); }
-    private:
+    class SCOPED_CAPABILITY Autolock {
+      public:
+        inline explicit Autolock(Mutex& mutex) ACQUIRE(mutex) : mLock(mutex) { mLock.lock(); }
+        inline explicit Autolock(Mutex* mutex) ACQUIRE(mutex) : mLock(*mutex) { mLock.lock(); }
+        inline ~Autolock() RELEASE() { mLock.unlock(); }
+
+      private:
         Mutex& mLock;
+        // Cannot be copied or moved - declarations only
+        Autolock(const Autolock&);
+        Autolock& operator=(const Autolock&);
     };
 
-private:
+  private:
     friend class Condition;
 
     // A mutex cannot be copied
-                Mutex(const Mutex&);
-    Mutex&      operator = (const Mutex&);
+    Mutex(const Mutex&);
+    Mutex& operator=(const Mutex&);
 
 #if !defined(_WIN32)
     pthread_mutex_t mMutex;
 #else
-    void    _init();
-    void*   mState;
+    void _init();
+    void* mState;
 #endif
 };
 
diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp
index 7b62c24..0869175 100644
--- a/libutils/tests/Android.bp
+++ b/libutils/tests/Android.bp
@@ -23,6 +23,7 @@
     srcs: [
         "BitSet_test.cpp",
         "LruCache_test.cpp",
+        "Mutex_test.cpp",
         "Singleton_test.cpp",
         "String8_test.cpp",
         "StrongPointer_test.cpp",
@@ -71,6 +72,7 @@
         "-Wall",
         "-Wextra",
         "-Werror",
+        "-Wthread-safety",
     ],
 }
 
diff --git a/libunwindstack/Log.h b/libutils/tests/Mutex_test.cpp
similarity index 68%
copy from libunwindstack/Log.h
copy to libutils/tests/Mutex_test.cpp
index 2d01aa8..8a1805f 100644
--- a/libunwindstack/Log.h
+++ b/libutils/tests/Mutex_test.cpp
@@ -14,12 +14,19 @@
  * limitations under the License.
  */
 
-#ifndef _LIBUNWINDSTACK_LOG_H
-#define _LIBUNWINDSTACK_LOG_H
+#include <utils/Mutex.h>
 
-#include <stdint.h>
+#include <gtest/gtest.h>
 
-void log_to_stdout(bool enable);
-void log(uint8_t indent, const char* format, ...);
+static android::Mutex mLock;
+static int i GUARDED_BY(mLock);
 
-#endif  // _LIBUNWINDSTACK_LOG_H
+void modifyLockedVariable() REQUIRES(mLock) {
+    i = 1;
+}
+
+TEST(Mutex, compile) {
+    android::Mutex::Autolock _l(mLock);
+    i = 0;
+    modifyLockedVariable();
+}
\ No newline at end of file
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 84a9a2f..333835c 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -50,6 +50,8 @@
         "libbase",
         "liblog",
     ],
+
+    export_include_dirs: ["include"],
 }
 
 cc_library {
@@ -65,7 +67,6 @@
         "liblog",
         "libbase",
     ],
-    export_include_dirs: ["include"],
     target: {
         android: {
             shared_libs: [
diff --git a/libziparchive/include/ziparchive/zip_archive_stream_entry.h b/libziparchive/include/ziparchive/zip_archive_stream_entry.h
index a40b799..b4766f8 100644
--- a/libziparchive/include/ziparchive/zip_archive_stream_entry.h
+++ b/libziparchive/include/ziparchive/zip_archive_stream_entry.h
@@ -40,7 +40,8 @@
 
   ZipArchiveHandle handle_;
 
-  uint32_t crc32_;
+  off64_t offset_ = 0;
+  uint32_t crc32_ = 0u;
 };
 
 #endif  // LIBZIPARCHIVE_ZIPARCHIVESTREAMENTRY_H_
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 17c268b..ad40d42 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -435,13 +435,20 @@
 
 static int32_t ValidateDataDescriptor(MappedZipFile& mapped_zip, ZipEntry* entry) {
   uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
-  if (!mapped_zip.ReadData(ddBuf, sizeof(ddBuf))) {
+  off64_t offset = entry->offset;
+  if (entry->method != kCompressStored) {
+    offset += entry->compressed_length;
+  } else {
+    offset += entry->uncompressed_length;
+  }
+
+  if (!mapped_zip.ReadAtOffset(ddBuf, sizeof(ddBuf), offset)) {
     return kIoError;
   }
 
   const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf));
-  const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0;
-  const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset);
+  const uint16_t ddOffset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0;
+  const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + ddOffset);
 
   // Validate that the values in the data descriptor match those in the central
   // directory.
@@ -899,7 +906,9 @@
     /* read as much as we can */
     if (zstream.avail_in == 0) {
       const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
-      if (!mapped_zip.ReadData(read_buf.data(), getSize)) {
+      off64_t offset = entry->offset + (entry->compressed_length - compressed_length);
+      // Make sure to read at offset to ensure concurrent access to the fd.
+      if (!mapped_zip.ReadAtOffset(read_buf.data(), getSize, offset)) {
         ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno));
         return kIoError;
       }
@@ -962,12 +971,15 @@
   uint64_t crc = 0;
   while (count < length) {
     uint32_t remaining = length - count;
+    off64_t offset = entry->offset + count;
 
-    // Safe conversion because kBufSize is narrow enough for a 32 bit signed
-    // value.
+    // Safe conversion because kBufSize is narrow enough for a 32 bit signed value.
     const size_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
-    if (!mapped_zip.ReadData(buf.data(), block_size)) {
-      ALOGW("CopyFileToFile: copy read failed, block_size = %zu: %s", block_size, strerror(errno));
+
+    // Make sure to read at offset to ensure concurrent access to the fd.
+    if (!mapped_zip.ReadAtOffset(buf.data(), block_size, offset)) {
+      ALOGW("CopyFileToFile: copy read failed, block_size = %zu, offset = %" PRId64 ": %s",
+            block_size, static_cast<int64_t>(offset), strerror(errno));
       return kIoError;
     }
 
@@ -986,12 +998,6 @@
 int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, Writer* writer) {
   ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
   const uint16_t method = entry->method;
-  off64_t data_offset = entry->offset;
-
-  if (!archive->mapped_zip.SeekToOffset(data_offset)) {
-    ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset));
-    return kIoError;
-  }
 
   // this should default to kUnknownCompressionMethod.
   int32_t return_value = -1;
@@ -1111,52 +1117,21 @@
   }
 }
 
-bool MappedZipFile::SeekToOffset(off64_t offset) {
-  if (has_fd_) {
-    if (lseek64(fd_, offset, SEEK_SET) != offset) {
-      ALOGE("Zip: lseek to %" PRId64 " failed: %s\n", offset, strerror(errno));
-      return false;
-    }
-    return true;
-  } else {
-    if (offset < 0 || offset > static_cast<off64_t>(data_length_)) {
-      ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n", offset, data_length_);
-      return false;
-    }
-
-    read_pos_ = offset;
-    return true;
-  }
-}
-
-bool MappedZipFile::ReadData(uint8_t* buffer, size_t read_amount) {
-  if (has_fd_) {
-    if (!android::base::ReadFully(fd_, buffer, read_amount)) {
-      ALOGE("Zip: read from %d failed\n", fd_);
-      return false;
-    }
-  } else {
-    memcpy(buffer, static_cast<uint8_t*>(base_ptr_) + read_pos_, read_amount);
-    read_pos_ += read_amount;
-  }
-  return true;
-}
-
 // Attempts to read |len| bytes into |buf| at offset |off|.
 bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) {
-#if !defined(_WIN32)
   if (has_fd_) {
-    if (static_cast<size_t>(TEMP_FAILURE_RETRY(pread64(fd_, buf, len, off))) != len) {
+    if (!android::base::ReadFullyAtOffset(fd_, buf, len, off)) {
       ALOGE("Zip: failed to read at offset %" PRId64 "\n", off);
       return false;
     }
-    return true;
+  } else {
+    if (off < 0 || off > static_cast<off64_t>(data_length_)) {
+      ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n", off, data_length_);
+      return false;
+    }
+    memcpy(buf, static_cast<uint8_t*>(base_ptr_) + off, len);
   }
-#endif
-  if (!SeekToOffset(off)) {
-    return false;
-  }
-  return ReadData(buf, len);
+  return true;
 }
 
 void CentralDirectory::Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size) {
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 840f1af..174aa3f 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -93,14 +93,10 @@
 class MappedZipFile {
  public:
   explicit MappedZipFile(const int fd)
-      : has_fd_(true), fd_(fd), base_ptr_(nullptr), data_length_(0), read_pos_(0) {}
+      : has_fd_(true), fd_(fd), base_ptr_(nullptr), data_length_(0) {}
 
   explicit MappedZipFile(void* address, size_t length)
-      : has_fd_(false),
-        fd_(-1),
-        base_ptr_(address),
-        data_length_(static_cast<off64_t>(length)),
-        read_pos_(0) {}
+      : has_fd_(false), fd_(-1), base_ptr_(address), data_length_(static_cast<off64_t>(length)) {}
 
   bool HasFd() const { return has_fd_; }
 
@@ -110,10 +106,6 @@
 
   off64_t GetFileLength() const;
 
-  bool SeekToOffset(off64_t offset);
-
-  bool ReadData(uint8_t* buffer, size_t read_amount);
-
   bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off);
 
  private:
@@ -127,8 +119,6 @@
 
   void* const base_ptr_;
   const off64_t data_length_;
-  // read_pos_ is the offset to the base_ptr_ where we read data from.
-  size_t read_pos_;
 };
 
 class CentralDirectory {
diff --git a/libziparchive/zip_archive_stream_entry.cc b/libziparchive/zip_archive_stream_entry.cc
index 50352ef..9ec89b1 100644
--- a/libziparchive/zip_archive_stream_entry.cc
+++ b/libziparchive/zip_archive_stream_entry.cc
@@ -38,13 +38,8 @@
 static constexpr size_t kBufSize = 65535;
 
 bool ZipArchiveStreamEntry::Init(const ZipEntry& entry) {
-  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
-  off64_t data_offset = entry.offset;
-  if (!archive->mapped_zip.SeekToOffset(data_offset)) {
-    ALOGW("lseek to data at %" PRId64 " failed: %s", data_offset, strerror(errno));
-    return false;
-  }
   crc32_ = entry.crc32;
+  offset_ = entry.offset;
   return true;
 }
 
@@ -61,11 +56,11 @@
  protected:
   bool Init(const ZipEntry& entry) override;
 
-  uint32_t length_;
+  uint32_t length_ = 0u;
 
  private:
   std::vector<uint8_t> data_;
-  uint32_t computed_crc32_;
+  uint32_t computed_crc32_ = 0u;
 };
 
 bool ZipArchiveStreamEntryUncompressed::Init(const ZipEntry& entry) {
@@ -89,7 +84,7 @@
   size_t bytes = (length_ > data_.size()) ? data_.size() : length_;
   ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
   errno = 0;
-  if (!archive->mapped_zip.ReadData(data_.data(), bytes)) {
+  if (!archive->mapped_zip.ReadAtOffset(data_.data(), bytes, offset_)) {
     if (errno != 0) {
       ALOGE("Error reading from archive fd: %s", strerror(errno));
     } else {
@@ -104,6 +99,7 @@
   }
   computed_crc32_ = crc32(computed_crc32_, data_.data(), data_.size());
   length_ -= bytes;
+  offset_ += bytes;
   return &data_;
 }
 
@@ -129,9 +125,9 @@
   z_stream z_stream_;
   std::vector<uint8_t> in_;
   std::vector<uint8_t> out_;
-  uint32_t uncompressed_length_;
-  uint32_t compressed_length_;
-  uint32_t computed_crc32_;
+  uint32_t uncompressed_length_ = 0u;
+  uint32_t compressed_length_ = 0u;
+  uint32_t computed_crc32_ = 0u;
 };
 
 // This method is using libz macros with old-style-casts
@@ -210,7 +206,7 @@
       size_t bytes = (compressed_length_ > in_.size()) ? in_.size() : compressed_length_;
       ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
       errno = 0;
-      if (!archive->mapped_zip.ReadData(in_.data(), bytes)) {
+      if (!archive->mapped_zip.ReadAtOffset(in_.data(), bytes, offset_)) {
         if (errno != 0) {
           ALOGE("Error reading from archive fd: %s", strerror(errno));
         } else {
@@ -220,6 +216,7 @@
       }
 
       compressed_length_ -= bytes;
+      offset_ += bytes;
       z_stream_.next_in = in_.data();
       z_stream_.avail_in = bytes;
     }
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index e9ef9cc..f64196f 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1638,7 +1638,7 @@
                 logcat_panic(context, HELP_FALSE, "read: unexpected length.\n");
                 break;
             }
-            logcat_panic(context, HELP_FALSE, "logcat read failure");
+            logcat_panic(context, HELP_FALSE, "logcat read failure\n");
             break;
         }
 
diff --git a/logd/tests/Android.mk b/logd/tests/Android.mk
index 1915677..a0875ea 100644
--- a/logd/tests/Android.mk
+++ b/logd/tests/Android.mk
@@ -63,7 +63,7 @@
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 LOCAL_SHARED_LIBRARIES := libbase libcutils liblog libselinux
 LOCAL_STATIC_LIBRARIES := libgtest libgtest_main
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
 LOCAL_CTS_TEST_PACKAGE := android.core.logd
 include $(BUILD_CTS_EXECUTABLE)
 
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 2e5575f..046557e 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -194,7 +194,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := ld.config.txt
-ifeq ($(PRODUCT_FULL_TREBLE),true)
+ifeq ($(PRODUCT_FULL_TREBLE)|$(SANITIZE_TARGET),true|)
 LOCAL_SRC_FILES := etc/ld.config.txt
 else
 LOCAL_SRC_FILES := etc/ld.config.legacy.txt
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 908a115..3cb5c1d 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -7,6 +7,10 @@
 dir.system = /system/bin/
 dir.system = /system/xbin/
 dir.vendor = /vendor/bin/
+dir.test = /data/nativetest/
+dir.test = /data/nativetest64/
+dir.test = /data/benchmarktest/
+dir.test = /data/benchmarktest64/
 
 [system]
 additional.namespaces = sphal,vndk,rs
@@ -105,9 +109,23 @@
 namespace.vndk.links = default
 namespace.vndk.link.default.shared_libs = android.hidl.memory@1.0-impl.so:libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libvndksupport.so
 
-
+###############################################################################
+# Namespace config for vendor processes. In O, no restriction is enforced for
+# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
+# the default namespace. 'system' namespace will be added to give limited
+# (LL-NDK only) access.
+###############################################################################
 [vendor]
 namespace.default.isolated = false
 namespace.default.search.paths = /vendor/${LIB}:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/system/${LIB}
 
 namespace.default.asan.search.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/system/${LIB}:/system/${LIB}
+
+###############################################################################
+# Namespace config for tests. No VNDK restriction is enforced for these tests.
+###############################################################################
+[test]
+namespace.default.isolated = false
+namespace.default.search.paths = /vendor/${LIB}:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/system/${LIB}
+
+namespace.default.asan.search.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/system/${LIB}:/system/${LIB}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index f734f61..901d066 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -37,7 +37,7 @@
     # app mem cgroups, used by activity manager, lmkd and zygote
     mkdir /dev/memcg/apps/ 0755 system system
     # cgroup for system_server and surfaceflinger
-    mkdir /dev/memcg/system 0755 system system
+    mkdir /dev/memcg/system 0550 system system
 
     start ueventd
 
@@ -386,6 +386,20 @@
 
     # create basic filesystem structure
     mkdir /data/misc 01771 system misc
+    mkdir /data/misc/recovery 0770 system log
+    copy /data/misc/recovery/default.prop /data/misc/recovery/default.prop.1
+    chmod 0440 /data/misc/recovery/default.prop.1
+    chown system log /data/misc/recovery/default.prop.1
+    copy /default.prop /data/misc/recovery/default.prop
+    chmod 0440 /data/misc/recovery/default.prop
+    chown system log /data/misc/recovery/default.prop
+    mkdir /data/misc/recovery/proc 0770 system log
+    copy /data/misc/recovery/proc/version /data/misc/recovery/proc/version.1
+    chmod 0440 /data/misc/recovery/proc/version.1
+    chown system log /data/misc/recovery/proc/version.1
+    copy /proc/version /data/misc/recovery/proc/version
+    chmod 0440 /data/misc/recovery/proc/version
+    chown system log /data/misc/recovery/proc/version
     mkdir /data/misc/bluedroid 02770 bluetooth bluetooth
     # Fix the access permissions and group ownership for 'bt_config.conf'
     chmod 0660 /data/misc/bluedroid/bt_config.conf
@@ -685,12 +699,17 @@
 on property:security.perf_harden=1
     write /proc/sys/kernel/perf_event_paranoid 3
 
+# on shutdown
+# In device's init.rc, this trigger can be used to do device-specific actions
+# before shutdown. e.g disable watchdog and mask error handling
+
 ## Daemon processes to be run by init.
 ##
 service ueventd /sbin/ueventd
     class core
     critical
     seclabel u:r:ueventd:s0
+    shutdown critical
 
 service healthd /system/bin/healthd
     class core
diff --git a/sdcard/Android.mk b/sdcard/Android.mk
index 0c58574..5b4dc58 100644
--- a/sdcard/Android.mk
+++ b/sdcard/Android.mk
@@ -8,6 +8,5 @@
 LOCAL_SHARED_LIBRARIES := libbase libcutils libminijail libpackagelistparser
 
 LOCAL_SANITIZE := integer
-LOCAL_CLANG := true
 
 include $(BUILD_EXECUTABLE)
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index 6d35fed..9620d63 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -4,7 +4,6 @@
         "bzip2",
         "grep",
         "grep_vendor",
-        "gzip",
         "mkshrc",
         "mkshrc_vendor",
         "reboot",
diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h
index 49b0ca8..bd99361 100644
--- a/storaged/include/storaged.h
+++ b/storaged/include/storaged.h
@@ -240,6 +240,7 @@
     uid_monitor mUidm;
     time_t mStarttime;
     sp<IBatteryPropertiesRegistrar> battery_properties;
+    std::unique_ptr<storage_info_t> storage_info;
 public:
     storaged_t(void);
     ~storaged_t() {}
@@ -269,6 +270,8 @@
     void init_battery_service();
     virtual void batteryPropertiesChanged(struct BatteryProperties props);
     void binderDied(const wp<IBinder>& who);
+
+    void report_storage_info();
 };
 
 // Eventlog tag
diff --git a/storaged/include/storaged_info.h b/storaged/include/storaged_info.h
index 913c814..7d04c7a 100644
--- a/storaged/include/storaged_info.h
+++ b/storaged/include/storaged_info.h
@@ -27,39 +27,46 @@
 class storage_info_t {
 protected:
     FRIEND_TEST(storaged_test, storage_info_t);
+    // emmc lifetime
     uint16_t eol;                   // pre-eol (end of life) information
     uint16_t lifetime_a;            // device life time estimation (type A)
     uint16_t lifetime_b;            // device life time estimation (type B)
     string version;                 // version string
+    // free space
+    const string userdata_path = "/data";
+    uint64_t userdata_total_kb;
+    uint64_t userdata_free_kb;
+
+    storage_info_t() : eol(0), lifetime_a(0), lifetime_b(0),
+        userdata_total_kb(0), userdata_free_kb(0) {}
     void publish();
+    storage_info_t* s_info;
 public:
-    storage_info_t() : eol(0), lifetime_a(0), lifetime_b(0) {}
+    static storage_info_t* get_storage_info();
     virtual ~storage_info_t() {}
-    virtual bool report() = 0;
+    virtual void report() {};
+    void refresh();
 };
 
 class emmc_info_t : public storage_info_t {
 private:
-    const string emmc_sysfs = "/sys/bus/mmc/devices/mmc0:0001/";
-    const string emmc_debugfs = "/d/mmc0/mmc0:0001/ext_csd";
-    const char* emmc_ver_str[9] = {
-        "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0", "5.1"
-    };
-public:
-    virtual ~emmc_info_t() {}
-    bool report();
     bool report_sysfs();
     bool report_debugfs();
+public:
+    static const string emmc_sysfs;
+    static const string emmc_debugfs;
+    static const char* emmc_ver_str[];
+
+    virtual ~emmc_info_t() {}
+    virtual void report();
 };
 
 class ufs_info_t : public storage_info_t {
-private:
-    const string health_file = "/sys/devices/soc/624000.ufshc/health";
 public:
-    virtual ~ufs_info_t() {}
-    bool report();
-};
+    static const string health_file;
 
-void report_storage_health();
+    virtual ~ufs_info_t() {}
+    virtual void report();
+};
 
 #endif /* _STORAGED_INFO_H_ */
diff --git a/storaged/main.cpp b/storaged/main.cpp
index 094f074..49bd916 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -49,6 +49,7 @@
     storaged = new storaged_t();
 
     storaged->init_battery_service();
+    storaged->report_storage_info();
 
     LOG_TO(SYSTEM, INFO) << "storaged: Start";
 
@@ -119,7 +120,6 @@
     }
 
     if (flag_main_service) { // start main thread
-        report_storage_health();
         // Start the main thread of storaged
         pthread_t storaged_main_thread;
         errno = pthread_create(&storaged_main_thread, NULL, storaged_main, NULL);
diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp
index 54d429c..06afea6 100644
--- a/storaged/storaged.cpp
+++ b/storaged/storaged.cpp
@@ -200,6 +200,10 @@
     }
 }
 
+void storaged_t::report_storage_info() {
+    storage_info->report();
+}
+
 /* storaged_t */
 storaged_t::storaged_t(void) {
     if (access(MMC_DISK_STATS_PATH, R_OK) < 0 && access(SDA_DISK_STATS_PATH, R_OK) < 0) {
@@ -222,6 +226,8 @@
     mConfig.periodic_chores_interval_uid_io =
         property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO);
 
+    storage_info.reset(storage_info_t::get_storage_info());
+
     mStarttime = time(NULL);
 }
 
@@ -229,6 +235,7 @@
     if (mConfig.diskstats_available) {
         mDiskStats.update();
         mDsm.update();
+        storage_info->refresh();
         if (mTimer && (mTimer % mConfig.periodic_chores_interval_disk_stats_publish) == 0) {
             mDiskStats.publish();
         }
diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp
index 434bd74..b5fb13e 100644
--- a/storaged/storaged_info.cpp
+++ b/storaged/storaged_info.cpp
@@ -18,6 +18,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <sys/statvfs.h>
 
 #include <android-base/file.h>
 #include <android-base/parseint.h>
@@ -30,13 +31,42 @@
 using namespace std;
 using namespace android::base;
 
-void report_storage_health()
-{
-    emmc_info_t mmc;
-    ufs_info_t ufs;
+const string emmc_info_t::emmc_sysfs = "/sys/bus/mmc/devices/mmc0:0001/";
+const string emmc_info_t::emmc_debugfs = "/d/mmc0/mmc0:0001/ext_csd";
+const char* emmc_info_t::emmc_ver_str[9] = {
+    "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0", "5.1"
+};
 
-    mmc.report();
-    ufs.report();
+const string ufs_info_t::health_file = "/sys/devices/soc/624000.ufshc/health";
+
+static bool FileExists(const std::string& filename)
+{
+  struct stat buffer;
+  return stat(filename.c_str(), &buffer) == 0;
+}
+
+storage_info_t* storage_info_t::get_storage_info()
+{
+    if (FileExists(emmc_info_t::emmc_sysfs) ||
+        FileExists(emmc_info_t::emmc_debugfs)) {
+        return new emmc_info_t;
+    }
+    if (FileExists(ufs_info_t::health_file)) {
+        return new ufs_info_t;
+    }
+    return new storage_info_t;
+}
+
+void storage_info_t::refresh()
+{
+    struct statvfs buf;
+    if (statvfs(userdata_path.c_str(), &buf) != 0) {
+        PLOG_TO(SYSTEM, WARNING) << "Failed to get userdata info";
+        return;
+    }
+
+    userdata_total_kb = buf.f_bsize * buf.f_blocks >> 10;
+    userdata_free_kb = buf.f_bfree * buf.f_blocks >> 10;
 }
 
 void storage_info_t::publish()
@@ -46,13 +76,12 @@
         << LOG_ID_EVENTS;
 }
 
-bool emmc_info_t::report()
+void emmc_info_t::report()
 {
     if (!report_sysfs() && !report_debugfs())
-        return false;
+        return;
 
     publish();
-    return true;
 }
 
 bool emmc_info_t::report_sysfs()
@@ -136,21 +165,21 @@
     return true;
 }
 
-bool ufs_info_t::report()
+void ufs_info_t::report()
 {
     string buffer;
     if (!ReadFileToString(health_file, &buffer)) {
-        return false;
+        return;
     }
 
     vector<string> lines = Split(buffer, "\n");
     if (lines.empty()) {
-        return false;
+        return;
     }
 
     char rev[8];
     if (sscanf(lines[0].c_str(), "ufs version: 0x%7s\n", rev) < 1) {
-        return false;
+        return;
     }
 
     version = "ufs " + string(rev);
@@ -175,10 +204,9 @@
     }
 
     if (eol == 0 || (lifetime_a == 0 && lifetime_b == 0)) {
-        return false;
+        return;
     }
 
     publish();
-    return true;
 }
 
diff --git a/trusty/keymaster/trusty_keymaster_device_test.cpp b/trusty/keymaster/trusty_keymaster_device_test.cpp
index 3bb5430..e8f5c0b 100644
--- a/trusty/keymaster/trusty_keymaster_device_test.cpp
+++ b/trusty/keymaster/trusty_keymaster_device_test.cpp
@@ -16,8 +16,8 @@
 #include <algorithm>
 #include <fstream>
 
-#include <UniquePtr.h>
 #include <gtest/gtest.h>
+#include <nativehelper/UniquePtr.h>
 #include <openssl/engine.h>
 
 #include <hardware/keymaster0.h>