Merge changes from topic 'ext4_encryption_flag'

* changes:
  fs_mgr: set ext4 encryption flag with tune2fs when needed
  fs_mgr: refactor pre-mount logic into prepare_fs_for_mount()
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/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/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/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index dbd4ec8..ff9b84f 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>
@@ -89,34 +90,22 @@
     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)
@@ -487,6 +476,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.
@@ -506,10 +505,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);
     }
@@ -762,19 +762,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];
@@ -843,8 +830,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,8 +1036,9 @@
         }
 
         /* 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 = prepare_fs_for_mount(n_blk_device, &fstab->recs[i]);
@@ -1210,8 +1200,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_priv.h b/fs_mgr/fs_mgr_priv.h
index c985462..5ea6e98 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
@@ -110,9 +112,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..5de0903 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;
@@ -929,7 +929,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/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/README.md b/init/README.md
index 72b6c6b..422fdad 100644
--- a/init/README.md
+++ b/init/README.md
@@ -260,6 +260,14 @@
 > Sets the child's /proc/self/oom\_score\_adj to the specified value,
   which must range from -1000 to 1000.
 
+`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 00ffbc3..dfd7b73 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;
 }
 
@@ -538,9 +539,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 0562dad..bf251ff 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -73,6 +73,7 @@
 
 using android::base::boot_clock;
 using android::base::GetProperty;
+using android::base::Timer;
 
 namespace android {
 namespace init {
@@ -94,6 +95,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 +160,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 +233,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;
 }
 
@@ -859,7 +871,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();
     }
@@ -1135,7 +1147,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 0af6c21..925cc9b 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..969caec 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,
@@ -253,7 +257,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 +275,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 +304,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,13 +315,13 @@
         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);
         KillAllProcesses();
         // even if it succeeds, still it is timeout and do not run fsck with all processes killed
-        UmountPartitions(0);
+        UmountPartitions(0ms);
         if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(true);
     }
 
@@ -351,26 +355,27 @@
         abort();
     }
 
-    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 = 0s;
+    if (!SHUTDOWN_ZERO_TIMEOUT) {
+        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() << " seconds";
 
     // 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 +389,7 @@
 
     // optional shutdown step
     // 1. terminate all services except shutdown critical ones. wait for delay to finish
-    if (shutdownTimeout > 0) {
+    if (shutdown_timeout > 0s) {
         LOG(INFO) << "terminating init services";
 
         // Ask all services to terminate except shutdown critical ones.
@@ -393,9 +398,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) {
+        // Up to half as long as shutdown_timeout or 3 seconds, whichever is lower.
+        auto termination_wait_timeout = std::min((shutdown_timeout + 1s) / 2, 3s);
+        while (t.duration() < termination_wait_timeout) {
             ServiceManager::GetInstance().ReapAnyOutstandingChildren();
 
             service_count = 0;
@@ -443,7 +448,7 @@
     });
     // 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);
@@ -490,6 +495,9 @@
         }
     } else if (command == "thermal-shutdown") {  // no additional parameter allowed
         cmd = ANDROID_RB_THERMOFF;
+        // Do not queue "shutdown" trigger since we want to shutdown immediately
+        DoReboot(cmd, command, reboot_target, run_fsck);
+        return true;
     } else {
         command_invalid = true;
     }
@@ -498,7 +506,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..7a657c8 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;
@@ -499,6 +501,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;
@@ -602,6 +612,7 @@
         {"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 +633,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();
@@ -1088,14 +1099,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 +1127,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 +1162,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..f682abd 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_; }
@@ -137,6 +137,7 @@
     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);
@@ -186,7 +187,7 @@
 };
 
 class ServiceManager {
-public:
+  public:
     static ServiceManager& GetInstance();
 
     // Exposed for testing
@@ -208,14 +209,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/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/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/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/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index cdac76b..826a576 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -26,6 +26,7 @@
     defaults: ["libmemunreachable_defaults"],
     srcs: [
         "Allocator.cpp",
+        "Binder.cpp",
         "HeapWalker.cpp",
         "LeakFolding.cpp",
         "LeakPipe.cpp",
@@ -84,3 +85,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/libmemunreachable/Binder.h b/libmemunreachable/Binder.h
new file mode 100644
index 0000000..bf4fd3e
--- /dev/null
+++ b/libmemunreachable/Binder.h
@@ -0,0 +1,28 @@
+/*
+ * 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 LIBMEMUNREACHABLE_BINDER_H_
+#define LIBMEMUNREACHABLE_BINDER_H_
+
+#include "Allocator.h"
+
+namespace android {
+
+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/libnativebridge/Android.bp b/libnativebridge/Android.bp
index 377b7dd..1cea4cd 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -1,4 +1,11 @@
 
+cc_library_headers {
+    name: "libnativebridge-dummy-headers",
+
+    host_supported: true,
+    export_include_dirs=["include"],
+}
+
 cc_library {
     name: "libnativebridge",
 
@@ -7,6 +14,8 @@
     shared_libs: ["liblog"],
     clang: true,
 
+    export_include_dirs=["include"],
+
     cflags: [
         "-Werror",
         "-Wall",
@@ -23,4 +32,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/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..e6d3bff 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -31,18 +31,18 @@
         },
     },
 
-    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"],
 
     srcs: [
@@ -64,6 +64,15 @@
         "Symbols.cpp",
     ],
 
+    arch: {
+        x86: {
+            srcs: ["AsmGetRegsX86.S"],
+        },
+        x86_64: {
+            srcs: ["AsmGetRegsX86_64.S"],
+        },
+    },
+
     shared_libs: [
         "libbase",
         "liblog",
@@ -71,16 +80,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 +102,21 @@
         "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/RegsTest.cpp",
         "tests/SymbolsTest.cpp",
+        "tests/UnwindTest.cpp",
     ],
 
     cflags: [
@@ -119,6 +128,7 @@
         "libbase",
         "liblog",
         "liblzma",
+        "libunwindstack",
     ],
 
     static_libs: [
@@ -132,28 +142,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 +161,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 +202,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/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/Machine.h b/libunwindstack/Machine.h
index 323ce80..bcc3788 100644
--- a/libunwindstack/Machine.h
+++ b/libunwindstack/Machine.h
@@ -83,47 +83,51 @@
   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,
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 051f700..d7b483d 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -73,13 +73,15 @@
   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;
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index da22b07..92b6e22 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -27,6 +27,7 @@
 #include "Machine.h"
 #include "MapInfo.h"
 #include "Regs.h"
+#include "Ucontext.h"
 #include "User.h"
 
 template <typename AddressType>
@@ -88,6 +89,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 +108,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 +127,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 +147,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 +166,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 +187,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 +213,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 +246,111 @@
   }
   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;
+}
+
+static Regs* CreateFromX86Ucontext(void* ucontext) {
+  x86_ucontext_t* x86_ucontext = reinterpret_cast<x86_ucontext_t*>(ucontext);
+
+  RegsX86* regs = new RegsX86();
+  // Put the registers in the expected order.
+  (*regs)[X86_REG_GS] = x86_ucontext->uc_mcontext.gs;
+  (*regs)[X86_REG_FS] = x86_ucontext->uc_mcontext.fs;
+  (*regs)[X86_REG_ES] = x86_ucontext->uc_mcontext.es;
+  (*regs)[X86_REG_DS] = x86_ucontext->uc_mcontext.ds;
+  (*regs)[X86_REG_EDI] = x86_ucontext->uc_mcontext.edi;
+  (*regs)[X86_REG_ESI] = x86_ucontext->uc_mcontext.esi;
+  (*regs)[X86_REG_EBP] = x86_ucontext->uc_mcontext.ebp;
+  (*regs)[X86_REG_ESP] = x86_ucontext->uc_mcontext.esp;
+  (*regs)[X86_REG_EBX] = x86_ucontext->uc_mcontext.ebx;
+  (*regs)[X86_REG_EDX] = x86_ucontext->uc_mcontext.edx;
+  (*regs)[X86_REG_ECX] = x86_ucontext->uc_mcontext.ecx;
+  (*regs)[X86_REG_EAX] = x86_ucontext->uc_mcontext.eax;
+  (*regs)[X86_REG_EIP] = x86_ucontext->uc_mcontext.eip;
+  regs->SetFromRaw();
+  return regs;
+}
+
+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();
+  // Put the registers in the expected order.
+
+  // R8-R15
+  memcpy(&(*regs)[X86_64_REG_R8], &x86_64_ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));
+
+  // Rest of the registers.
+  (*regs)[X86_64_REG_RDI] = x86_64_ucontext->uc_mcontext.rdi;
+  (*regs)[X86_64_REG_RSI] = x86_64_ucontext->uc_mcontext.rsi;
+  (*regs)[X86_64_REG_RBP] = x86_64_ucontext->uc_mcontext.rbp;
+  (*regs)[X86_64_REG_RBX] = x86_64_ucontext->uc_mcontext.rbx;
+  (*regs)[X86_64_REG_RDX] = x86_64_ucontext->uc_mcontext.rdx;
+  (*regs)[X86_64_REG_RAX] = x86_64_ucontext->uc_mcontext.rax;
+  (*regs)[X86_64_REG_RCX] = x86_64_ucontext->uc_mcontext.rcx;
+  (*regs)[X86_64_REG_RSP] = x86_64_ucontext->uc_mcontext.rsp;
+  (*regs)[X86_64_REG_RIP] = x86_64_ucontext->uc_mcontext.rip;
+
+  regs->SetFromRaw();
+  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;
+}
diff --git a/libunwindstack/Regs.h b/libunwindstack/Regs.h
index 8f5a721..a7567d8 100644
--- a/libunwindstack/Regs.h
+++ b/libunwindstack/Regs.h
@@ -54,10 +54,15 @@
 
   virtual uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) = 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_;
@@ -98,6 +103,8 @@
   virtual ~RegsArm() = default;
 
   uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
 };
 
 class RegsArm64 : public RegsImpl<uint64_t> {
@@ -106,6 +113,8 @@
   virtual ~RegsArm64() = default;
 
   uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
 };
 
 class RegsX86 : public RegsImpl<uint32_t> {
@@ -114,6 +123,8 @@
   virtual ~RegsX86() = default;
 
   uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
 };
 
 class RegsX86_64 : public RegsImpl<uint64_t> {
@@ -122,6 +133,8 @@
   virtual ~RegsX86_64() = default;
 
   uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
+
+  void SetFromRaw() override;
 };
 
 #endif  // _LIBUNWINDSTACK_REGS_H
diff --git a/libunwindstack/RegsGetLocal.h b/libunwindstack/RegsGetLocal.h
new file mode 100644
index 0000000..8e6d04c
--- /dev/null
+++ b/libunwindstack/RegsGetLocal.h
@@ -0,0 +1,100 @@
+/*
+ * 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
+
+#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
+
+#endif  // _LIBUNWINDSTACK_REGS_GET_LOCAL_H
diff --git a/libunwindstack/Ucontext.h b/libunwindstack/Ucontext.h
new file mode 100644
index 0000000..95ba682
--- /dev/null
+++ b/libunwindstack/Ucontext.h
@@ -0,0 +1,180 @@
+/*
+ * 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>
+
+//-------------------------------------------------------------------
+// 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.
+};
+
+typedef struct x86_64_ucontext {
+  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.
+} x86_64_ucontext_t;
+//-------------------------------------------------------------------
+
+#endif  // _LIBUNWINDSTACK_UCONTEXT_H
diff --git a/libunwindstack/tests/DwarfMemoryTest.cpp b/libunwindstack/tests/DwarfMemoryTest.cpp
index 4877f36..b7df8f7 100644
--- a/libunwindstack/tests/DwarfMemoryTest.cpp
+++ b/libunwindstack/tests/DwarfMemoryTest.cpp
@@ -237,9 +237,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 +306,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 +327,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 +348,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 +369,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 +390,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() {
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 22cade2..bf0823b 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -24,6 +24,7 @@
 
 #include "Elf.h"
 
+#include "ElfTestUtils.h"
 #include "MemoryFake.h"
 
 #if !defined(PT_ARM_EXIDX)
@@ -36,36 +37,16 @@
     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 +55,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 +75,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 +97,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_;
 };
 
@@ -214,153 +176,64 @@
   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);
 }
diff --git a/libunwindstack/tests/ElfTestUtils.cpp b/libunwindstack/tests/ElfTestUtils.cpp
new file mode 100644
index 0000000..81064dd
--- /dev/null
+++ b/libunwindstack/tests/ElfTestUtils.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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"
+
+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);
diff --git a/libunwindstack/tests/ElfTestUtils.h b/libunwindstack/tests/ElfTestUtils.h
new file mode 100644
index 0000000..4fd3bbc
--- /dev/null
+++ b/libunwindstack/tests/ElfTestUtils.h
@@ -0,0 +1,31 @@
+/*
+ * 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>
+
+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);
+
+#endif  // _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
diff --git a/libunwindstack/tests/MapInfoTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
similarity index 85%
rename from libunwindstack/tests/MapInfoTest.cpp
rename to libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 6e47dc0..b82c841 100644
--- a/libunwindstack/tests/MapInfoTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -34,7 +34,7 @@
 #include "MapInfo.h"
 #include "Memory.h"
 
-class MapInfoTest : public ::testing::Test {
+class MapInfoCreateMemoryTest : public ::testing::Test {
  protected:
   static void SetUpTestCase() {
     std::vector<uint8_t> buffer(1024);
@@ -58,10 +58,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 +80,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 +100,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 +119,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 +135,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 +160,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 +201,5 @@
   ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
 
   kill(pid, SIGKILL);
-}
-
-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));
+  ASSERT_EQ(pid, wait(nullptr));
 }
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
new file mode 100644
index 0000000..fc36cc6
--- /dev/null
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -0,0 +1,140 @@
+/*
+ * 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 "Elf.h"
+#include "ElfTestUtils.h"
+#include "MapInfo.h"
+
+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);
+}
diff --git a/libunwindstack/tests/MemoryBuffer.cpp b/libunwindstack/tests/MemoryBufferTest.cpp
similarity index 100%
rename from libunwindstack/tests/MemoryBuffer.cpp
rename to libunwindstack/tests/MemoryBufferTest.cpp
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index e48edf7..7210786 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -91,6 +91,7 @@
   ASSERT_TRUE(Detach(pid));
 
   kill(pid, SIGKILL);
+  ASSERT_EQ(pid, wait(nullptr));
 }
 
 TEST_F(MemoryRemoteTest, read_fail) {
@@ -131,6 +132,7 @@
   ASSERT_TRUE(Detach(pid));
 
   kill(pid, SIGKILL);
+  ASSERT_EQ(pid, wait(nullptr));
 }
 
 TEST_F(MemoryRemoteTest, read_overflow) {
@@ -160,4 +162,5 @@
   ASSERT_TRUE(Detach(pid));
 
   kill(pid, SIGKILL);
+  ASSERT_EQ(pid, wait(nullptr));
 }
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index ff030c8..c57954c 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -30,6 +30,7 @@
 
   uint64_t GetRelPc(Elf*, const MapInfo*) override { return 0; }
   uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; }
+  void SetFromRaw() override {}
   bool GetReturnAddressFromDefault(Memory*, uint64_t*) { return false; }
 };
 
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 3056373..dde42de 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -56,7 +56,8 @@
       : 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 {}
 };
 
 class RegsTest : public ::testing::Test {
@@ -264,3 +265,43 @@
   ASSERT_EQ(0x800U, regs_x86_64.GetRelPc(&invalid_elf, &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());
+}
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
new file mode 100644
index 0000000..7497b65
--- /dev/null
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -0,0 +1,233 @@
+/*
+ * 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 "Elf.h"
+#include "MapInfo.h"
+#include "Maps.h"
+#include "Memory.h"
+#include "Regs.h"
+#include "RegsGetLocal.h"
+
+static std::atomic_bool g_ready(false);
+static volatile bool g_ready_for_remote = false;
+static std::atomic_bool g_finish(false);
+static std::atomic_uintptr_t g_ucontext;
+
+static void Signal(int, siginfo_t*, void* sigcontext) {
+  g_ucontext = reinterpret_cast<uintptr_t>(sigcontext);
+  while (!g_finish.load()) {
+  }
+}
+
+static std::string ErrorMsg(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) {
+  const char* function_names[] = {
+      "InnerFunction", "MiddleFunction", "OuterFunction",
+  };
+  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 = regs->GetRelPc(elf, 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]) {
+        function_name_index++;
+        if (function_name_index == sizeof(function_names) / sizeof(const char*)) {
+          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());
+  } 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);
+}
+
+TEST(UnwindTest, remote) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    OuterFunction(false);
+    exit(0);
+  }
+  ASSERT_NE(-1, pid);
+
+  bool ready = false;
+  uint64_t addr = reinterpret_cast<uint64_t>(&g_ready_for_remote);
+  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) {
+        // Check to see if process is ready to be unwound.
+        MemoryRemote memory(pid);
+        // Read the remote value to see if we are ready.
+        bool value;
+        if (memory.Read(addr, &value, sizeof(value)) && value) {
+          ready = true;
+          break;
+        }
+      }
+      usleep(1000);
+    }
+    if (ready) {
+      break;
+    }
+    ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
+    usleep(1000);
+  }
+  ASSERT_TRUE(read) << "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());
+
+  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 = Signal;
+  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)) << "Failed because "
+                                                                    << strerror(errno);
+
+  // Wait for context data.
+  void* ucontext;
+  for (size_t i = 0; i < 200; 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());
+
+  ASSERT_EQ(0, sigaction(SIGUSR1, &oldact, nullptr));
+
+  g_finish = true;
+  thread.join();
+}
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..34cd1ce
--- /dev/null
+++ b/libunwindstack/tools/unwind.cpp
@@ -0,0 +1,160 @@
+/*
+ * 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 <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 "Elf.h"
+#include "Maps.h"
+#include "Memory.h"
+#include "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) {
+  RemoteMaps remote_maps(pid);
+  if (!remote_maps.Parse()) {
+    printf("Failed to parse map data.\n");
+    return;
+  }
+
+  uint32_t machine_type;
+  Regs* regs = 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");
+
+  MemoryRemote remote_memory(pid);
+  for (size_t frame_num = 0; frame_num < 64; frame_num++) {
+    if (regs->pc() == 0) {
+      break;
+    }
+    MapInfo* map_info = remote_maps.Find(regs->pc());
+    if (map_info == nullptr) {
+      printf("Failed to find map data for the pc\n");
+      break;
+    }
+
+    Elf* elf = map_info->GetElf(pid, true);
+
+    uint64_t rel_pc = regs->GetRelPc(elf, 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 98%
rename from libunwindstack/unwind_info.cpp
rename to libunwindstack/tools/unwind_info.cpp
index da1522b..e889f8c 100644
--- a/libunwindstack/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -21,8 +21,8 @@
 #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 "ArmExidx.h"
@@ -115,10 +115,6 @@
     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;
-  }
 
   // Send all log messages to stdout.
   log_to_stdout(true);
diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp
new file mode 100644
index 0000000..c010dfc
--- /dev/null
+++ b/libunwindstack/tools/unwind_symbols.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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 <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "Elf.h"
+#include "ElfInterface.h"
+#include "Log.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.
+  log_to_stdout(true);
+
+  MemoryFileAtOffset* memory = new MemoryFileAtOffset;
+  if (!memory->Init(argv[1], 0)) {
+    printf("Failed to init\n");
+    return 1;
+  }
+
+  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 33770ba..0125eac 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"
     ],
@@ -76,6 +78,10 @@
     header_libs: ["libutils_headers"],
     export_header_lib_headers: ["libutils_headers"],
 
+    shared_libs: [
+        "liblog",
+    ],
+
     arch: {
         mips: {
             cflags: ["-DALIGN_DOUBLE"],
@@ -97,7 +103,6 @@
                 "libbacktrace",
                 "libcutils",
                 "libdl",
-                "liblog",
             ],
 
             sanitize: {
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/rootdir/init.rc b/rootdir/init.rc
index ebbec35..9301743 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
 
@@ -376,6 +376,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
@@ -681,12 +695,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 /sbin/healthd
     class core
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",