Merge "Add force_suspend function"
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 7fec47d..fb8a205 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -195,6 +195,7 @@
         "libcutils",
         "libdebuggerd_client",
         "liblog",
+        "libminijail",
         "libnativehelper"
     ],
 
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
new file mode 100644
index 0000000..3bc1742
--- /dev/null
+++ b/debuggerd/Android.mk
@@ -0,0 +1,23 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := crash_dump.policy
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MULTILIB := both
+
+ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64))
+LOCAL_MODULE_STEM_32 := crash_dump.arm.policy
+LOCAL_MODULE_STEM_64 := crash_dump.arm64.policy
+endif
+
+ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86 x86_64))
+LOCAL_MODULE_STEM_32 := crash_dump.x86.policy
+LOCAL_MODULE_STEM_64 := crash_dump.x86_64.policy
+endif
+
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
+LOCAL_SRC_FILES_arm := seccomp_policy/crash_dump.arm.policy
+LOCAL_SRC_FILES_arm64 := seccomp_policy/crash_dump.arm64.policy
+LOCAL_SRC_FILES_x86 := seccomp_policy/crash_dump.x86.policy
+LOCAL_SRC_FILES_x86_64 := seccomp_policy/crash_dump.x86_64.policy
+include $(BUILD_PREBUILT)
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 939f4d2..f8b4bad 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -41,6 +41,9 @@
 #include <cutils/sockets.h>
 #include <gtest/gtest.h>
 
+#include <libminijail.h>
+#include <scoped_minijail.h>
+
 #include "debuggerd/handler.h"
 #include "protocol.h"
 #include "tombstoned/tombstoned.h"
@@ -76,9 +79,8 @@
     return value;                                                  \
   }()
 
-#define ASSERT_BACKTRACE_FRAME(result, frame_name)                        \
-  ASSERT_MATCH(result, R"(#\d\d pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX \
-                       R"(/libc.so \()" frame_name R"(\+)")
+#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
+  ASSERT_MATCH(result, R"(#\d\d pc [0-9a-f]+\s+ \S+ \()" frame_name R"(\+)");
 
 static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
                                  InterceptStatus* status, DebuggerdDumpType intercept_type) {
@@ -565,6 +567,141 @@
   ASSERT_BACKTRACE_FRAME(result, "tgkill");
 }
 
+static const char* const kDebuggerdSeccompPolicy =
+    "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
+
+pid_t seccomp_fork() {
+  unique_fd policy_fd(open(kDebuggerdSeccompPolicy, O_RDONLY | O_CLOEXEC));
+  if (policy_fd == -1) {
+    LOG(FATAL) << "failed to open policy " << kDebuggerdSeccompPolicy;
+  }
+
+  ScopedMinijail jail{minijail_new()};
+  if (!jail) {
+    LOG(FATAL) << "failed to create minijail";
+  }
+
+  minijail_no_new_privs(jail.get());
+  minijail_log_seccomp_filter_failures(jail.get());
+  minijail_use_seccomp_filter(jail.get());
+  minijail_parse_seccomp_filters_from_fd(jail.get(), policy_fd.release());
+
+  pid_t result = fork();
+  if (result == -1) {
+    return result;
+  } else if (result != 0) {
+    return result;
+  }
+
+  // Spawn and detach a thread that spins forever.
+  std::atomic<bool> thread_ready(false);
+  std::thread thread([&jail, &thread_ready]() {
+    minijail_enter(jail.get());
+    thread_ready = true;
+    for (;;)
+      ;
+  });
+  thread.detach();
+
+  while (!thread_ready) {
+    continue;
+  }
+
+  minijail_enter(jail.get());
+  return result;
+}
+
+TEST_F(CrasherTest, seccomp_crash) {
+  int intercept_result;
+  unique_fd output_fd;
+
+  StartProcess([]() { abort(); }, &seccomp_fork);
+
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  AssertDeath(SIGABRT);
+  FinishIntercept(&intercept_result);
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+  ASSERT_BACKTRACE_FRAME(result, "abort");
+}
+
+__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
+  siginfo_t siginfo;
+  siginfo.si_code = SI_QUEUE;
+  siginfo.si_pid = getpid();
+  siginfo.si_uid = getuid();
+
+  if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
+    PLOG(FATAL) << "invalid dump type";
+  }
+
+  siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
+
+  if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), DEBUGGER_SIGNAL, &siginfo) != 0) {
+    PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
+    return false;
+  }
+
+  return true;
+}
+
+TEST_F(CrasherTest, seccomp_tombstone) {
+  int intercept_result;
+  unique_fd output_fd;
+
+  static const auto dump_type = kDebuggerdTombstone;
+  StartProcess(
+      []() {
+        raise_debugger_signal(dump_type);
+        _exit(0);
+      },
+      &seccomp_fork);
+
+  StartIntercept(&output_fd, dump_type);
+  FinishCrasher();
+  AssertDeath(0);
+  FinishIntercept(&intercept_result);
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+  ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
+}
+
+TEST_F(CrasherTest, seccomp_backtrace) {
+  int intercept_result;
+  unique_fd output_fd;
+
+  static const auto dump_type = kDebuggerdNativeBacktrace;
+  StartProcess(
+      []() {
+        raise_debugger_signal(dump_type);
+        _exit(0);
+      },
+      &seccomp_fork);
+
+  StartIntercept(&output_fd, dump_type);
+  FinishCrasher();
+  AssertDeath(0);
+  FinishIntercept(&intercept_result);
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+  ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
+}
+
+TEST_F(CrasherTest, seccomp_crash_logcat) {
+  StartProcess([]() { abort(); }, &seccomp_fork);
+  FinishCrasher();
+
+  // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
+  AssertDeath(SIGABRT);
+}
+
 TEST_F(CrasherTest, competing_tracer) {
   int intercept_result;
   unique_fd output_fd;
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
index 198c48b..be90d0f 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
@@ -40,16 +40,16 @@
 /* Creates a tombstone file and writes the crash dump to it. */
 void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files,
                        pid_t pid, pid_t tid, const std::string& process_name,
-                       const std::map<pid_t, std::string>& threads, uintptr_t abort_msg_address,
+                       const std::map<pid_t, std::string>& threads, uint64_t abort_msg_address,
                        std::string* amfd_data);
 
-void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
+void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, siginfo_t* siginfo,
                                 ucontext_t* ucontext);
 
 void engrave_tombstone(android::base::unique_fd output_fd, BacktraceMap* map,
                        unwindstack::Memory* process_memory,
                        const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread,
-                       uintptr_t abort_msg_address, OpenFilesList* open_files,
+                       uint64_t abort_msg_address, OpenFilesList* open_files,
                        std::string* amfd_data);
 
 #endif  // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index c5abfe2..0f049fd 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -68,7 +68,7 @@
 class Memory;
 }
 
-void dump_memory(log_t* log, unwindstack::Memory* backtrace, uintptr_t addr, const char* fmt, ...);
+void dump_memory(log_t* log, unwindstack::Memory* backtrace, uint64_t addr, const char* fmt, ...);
 
 void read_with_default(const char* path, char* buf, size_t len, const char* default_value);
 
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index 1e3a10f..421ce43 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -437,9 +437,9 @@
   map_mock_->AddMap(map);
 
 #if defined(__LP64__)
-  uintptr_t addr = 0x12345a534040UL;
+  uint64_t addr = 0x12345a534040UL;
 #else
-  uintptr_t addr = 0xf534040UL;
+  uint64_t addr = 0xf534040UL;
 #endif
   dump_all_maps(&log_, map_mock_.get(), nullptr, addr);
 
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 89a125b..7d85602 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -127,7 +127,7 @@
 }
 
 static void dump_stack_segment(log_t* log, BacktraceMap* backtrace_map, Memory* process_memory,
-                               uintptr_t* sp, size_t words, int label) {
+                               uint64_t* sp, size_t words, int label) {
   // Read the data all at once.
   word_t stack_data[words];
 
@@ -144,18 +144,18 @@
     } else {
       line += "     ";
     }
-    line += StringPrintf("%" PRIPTR "  %" PRIPTR, *sp, stack_data[i]);
+    line += StringPrintf("%" PRIPTR "  %" PRIPTR, *sp, static_cast<uint64_t>(stack_data[i]));
 
     backtrace_map_t map;
     backtrace_map->FillIn(stack_data[i], &map);
     if (BacktraceMap::IsValid(map) && !map.name.empty()) {
       line += "  " + map.name;
-      uintptr_t offset = 0;
+      uint64_t offset = 0;
       std::string func_name = backtrace_map->GetFunctionName(stack_data[i], &offset);
       if (!func_name.empty()) {
         line += " (" + func_name;
         if (offset) {
-          line += StringPrintf("+%" PRIuPTR, offset);
+          line += StringPrintf("+%" PRIu64, offset);
         }
         line += ')';
       }
@@ -185,7 +185,7 @@
   first--;
 
   // Dump a few words before the first frame.
-  word_t sp = frames[first].sp - STACK_WORDS * sizeof(word_t);
+  uint64_t sp = frames[first].sp - STACK_WORDS * sizeof(word_t);
   dump_stack_segment(log, backtrace_map, process_memory, &sp, STACK_WORDS, -1);
 
   // Dump a few words from all successive frames.
@@ -213,19 +213,19 @@
   }
 }
 
-static std::string get_addr_string(uintptr_t addr) {
+static std::string get_addr_string(uint64_t addr) {
   std::string addr_str;
 #if defined(__LP64__)
   addr_str = StringPrintf("%08x'%08x",
                           static_cast<uint32_t>(addr >> 32),
                           static_cast<uint32_t>(addr & 0xffffffff));
 #else
-  addr_str = StringPrintf("%08x", addr);
+  addr_str = StringPrintf("%08x", static_cast<uint32_t>(addr));
 #endif
   return addr_str;
 }
 
-static void dump_abort_message(log_t* log, Memory* process_memory, uintptr_t address) {
+static void dump_abort_message(log_t* log, Memory* process_memory, uint64_t address) {
   if (address == 0) {
     return;
   }
@@ -251,7 +251,7 @@
   _LOG(log, logtype::HEADER, "Abort message: '%s'\n", msg);
 }
 
-static void dump_all_maps(log_t* log, BacktraceMap* map, Memory* process_memory, uintptr_t addr) {
+static void dump_all_maps(log_t* log, BacktraceMap* map, Memory* process_memory, uint64_t addr) {
   bool print_fault_address_marker = addr;
 
   ScopedBacktraceMapIteratorLock lock(map);
@@ -301,7 +301,7 @@
     } else {
       line += '-';
     }
-    line += StringPrintf("  %8" PRIxPTR "  %8" PRIxPTR, entry->offset, entry->end - entry->start);
+    line += StringPrintf("  %8" PRIx64 "  %8" PRIx64, entry->offset, entry->end - entry->start);
     bool space_needed = true;
     if (entry->name.length() > 0) {
       space_needed = false;
@@ -315,7 +315,7 @@
       if (space_needed) {
         line += ' ';
       }
-      line += StringPrintf(" (load bias 0x%" PRIxPTR ")", entry->load_bias);
+      line += StringPrintf(" (load bias 0x%" PRIx64 ")", entry->load_bias);
     }
     _LOG(log, logtype::MAPS, "%s\n", line.c_str());
   }
@@ -335,9 +335,9 @@
                                const std::vector<std::pair<std::string, uint64_t>>& registers) {
   std::string output;
   for (auto& [name, value] : registers) {
-    output += android::base::StringPrintf("  %-3s %0*" PRIxPTR, name.c_str(),
+    output += android::base::StringPrintf("  %-3s %0*" PRIx64, name.c_str(),
                                           static_cast<int>(2 * sizeof(void*)),
-                                          static_cast<uintptr_t>(value));
+                                          static_cast<uint64_t>(value));
   }
 
   _LOG(log, logtype::REGISTERS, "  %s\n", output.c_str());
@@ -389,7 +389,7 @@
 }
 
 static bool dump_thread(log_t* log, BacktraceMap* map, Memory* process_memory,
-                        const ThreadInfo& thread_info, uintptr_t abort_msg_address,
+                        const ThreadInfo& thread_info, uint64_t abort_msg_address,
                         bool primary_thread) {
   UNUSED(process_memory);
   log->current_tid = thread_info.tid;
@@ -425,10 +425,10 @@
   if (primary_thread) {
     dump_memory_and_code(log, process_memory, thread_info.registers.get());
     if (map) {
-      uintptr_t addr = 0;
+      uint64_t addr = 0;
       siginfo_t* si = thread_info.siginfo;
       if (signal_has_si_addr(si->si_signo, si->si_code)) {
-        addr = reinterpret_cast<uintptr_t>(si->si_addr);
+        addr = reinterpret_cast<uint64_t>(si->si_addr);
       }
       dump_all_maps(log, map, process_memory, addr);
     }
@@ -572,7 +572,7 @@
   dump_log_file(log, pid, "main", tail);
 }
 
-void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
+void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, siginfo_t* siginfo,
                                 ucontext_t* ucontext) {
   pid_t pid = getpid();
   pid_t tid = gettid();
@@ -614,7 +614,7 @@
 
 void engrave_tombstone(unique_fd output_fd, BacktraceMap* map, Memory* process_memory,
                        const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
-                       uintptr_t abort_msg_address, OpenFilesList* open_files,
+                       uint64_t abort_msg_address, OpenFilesList* open_files,
                        std::string* amfd_data) {
   // don't copy log messages to tombstone unless this is a dev device
   bool want_logs = android::base::GetBoolProperty("ro.debuggable", false);
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 247d806..3ac98f5 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -124,7 +124,7 @@
 #define MEMORY_BYTES_TO_DUMP 256
 #define MEMORY_BYTES_PER_LINE 16
 
-void dump_memory(log_t* log, unwindstack::Memory* memory, uintptr_t addr, const char* fmt, ...) {
+void dump_memory(log_t* log, unwindstack::Memory* memory, uint64_t addr, const char* fmt, ...) {
   std::string log_msg;
   va_list ap;
   va_start(ap, fmt);
@@ -159,7 +159,7 @@
     bytes &= ~(sizeof(uintptr_t) - 1);
   }
 
-  uintptr_t start = 0;
+  uint64_t start = 0;
   bool skip_2nd_read = false;
   if (bytes == 0) {
     // In this case, we might want to try another read at the beginning of
@@ -206,7 +206,7 @@
     std::string ascii;
     for (size_t i = 0; i < MEMORY_BYTES_PER_LINE / sizeof(uintptr_t); i++) {
       if (current >= start && current + sizeof(uintptr_t) <= total_bytes) {
-        android::base::StringAppendF(&logline, " %" PRIPTR, *data_ptr);
+        android::base::StringAppendF(&logline, " %" PRIPTR, static_cast<uint64_t>(*data_ptr));
 
         // Fill out the ascii string from the data.
         uint8_t* ptr = reinterpret_cast<uint8_t*>(data_ptr);
diff --git a/debuggerd/seccomp_policy/crash_dump.arm.policy b/debuggerd/seccomp_policy/crash_dump.arm.policy
new file mode 100644
index 0000000..c64e288
--- /dev/null
+++ b/debuggerd/seccomp_policy/crash_dump.arm.policy
@@ -0,0 +1,37 @@
+read: 1
+write: 1
+exit: 1
+rt_sigreturn: 1
+sigreturn: 1
+exit_group: 1
+clock_gettime: 1
+gettimeofday: 1
+futex: 1
+getrandom: 1
+getpid: 1
+gettid: 1
+ppoll: 1
+pipe2: 1
+openat: 1
+dup: 1
+close: 1
+lseek: 1
+getdents64: 1
+faccessat: 1
+recvmsg: 1
+process_vm_readv: 1
+tgkill: 1
+rt_sigprocmask: 1
+rt_tgsigqueueinfo: 1
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
+madvise: 1
+mprotect: arg2 in PROT_READ|PROT_WRITE
+munmap: 1
+getuid32: 1
+fstat64: 1
+mmap2: arg2 in PROT_READ|PROT_WRITE
+sigaction: 1
+geteuid32: 1
+getgid32: 1
+getegid32: 1
+getgroups32: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.arm64.policy b/debuggerd/seccomp_policy/crash_dump.arm64.policy
new file mode 100644
index 0000000..0c689bb
--- /dev/null
+++ b/debuggerd/seccomp_policy/crash_dump.arm64.policy
@@ -0,0 +1,36 @@
+read: 1
+write: 1
+exit: 1
+rt_sigreturn: 1
+exit_group: 1
+clock_gettime: 1
+gettimeofday: 1
+futex: 1
+getrandom: 1
+getpid: 1
+gettid: 1
+ppoll: 1
+pipe2: 1
+openat: 1
+dup: 1
+close: 1
+lseek: 1
+getdents64: 1
+faccessat: 1
+recvmsg: 1
+process_vm_readv: 1
+tgkill: 1
+rt_sigprocmask: 1
+rt_tgsigqueueinfo: 1
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
+madvise: 1
+mprotect: arg2 in PROT_READ|PROT_WRITE
+munmap: 1
+getuid: 1
+fstat: 1
+mmap: arg2 in PROT_READ|PROT_WRITE
+rt_sigaction: 1
+geteuid: 1
+getgid: 1
+getegid: 1
+getgroups: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.policy.def b/debuggerd/seccomp_policy/crash_dump.policy.def
new file mode 100644
index 0000000..dadffac
--- /dev/null
+++ b/debuggerd/seccomp_policy/crash_dump.policy.def
@@ -0,0 +1,64 @@
+// SECCOMP_MODE_STRICT
+read: 1
+write: 1
+exit: 1
+rt_sigreturn: 1
+#if !defined(__LP64__)
+sigreturn: 1
+#endif
+
+exit_group: 1
+clock_gettime: 1
+gettimeofday: 1
+futex: 1
+getrandom: 1
+getpid: 1
+gettid: 1
+
+ppoll: 1
+pipe2: 1
+openat: 1
+dup: 1
+close: 1
+lseek: 1
+getdents64: 1
+faccessat: 1
+recvmsg: 1
+
+process_vm_readv: 1
+
+tgkill: 1
+rt_sigprocmask: 1
+rt_tgsigqueueinfo: 1
+
+#define PR_SET_VMA 0x53564d41
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == PR_SET_VMA
+
+madvise: 1
+mprotect: arg2 in PROT_READ|PROT_WRITE
+munmap: 1
+
+#if defined(__LP64__)
+getuid: 1
+fstat: 1
+mmap: arg2 in PROT_READ|PROT_WRITE
+rt_sigaction: 1
+#else
+getuid32: 1
+fstat64: 1
+mmap2: arg2 in PROT_READ|PROT_WRITE
+sigaction: 1
+#endif
+
+// Needed for logging.
+#if defined(__LP64__)
+geteuid: 1
+getgid: 1
+getegid: 1
+getgroups: 1
+#else
+geteuid32: 1
+getgid32: 1
+getegid32: 1
+getgroups32: 1
+#endif
diff --git a/debuggerd/seccomp_policy/crash_dump.x86.policy b/debuggerd/seccomp_policy/crash_dump.x86.policy
new file mode 100644
index 0000000..c64e288
--- /dev/null
+++ b/debuggerd/seccomp_policy/crash_dump.x86.policy
@@ -0,0 +1,37 @@
+read: 1
+write: 1
+exit: 1
+rt_sigreturn: 1
+sigreturn: 1
+exit_group: 1
+clock_gettime: 1
+gettimeofday: 1
+futex: 1
+getrandom: 1
+getpid: 1
+gettid: 1
+ppoll: 1
+pipe2: 1
+openat: 1
+dup: 1
+close: 1
+lseek: 1
+getdents64: 1
+faccessat: 1
+recvmsg: 1
+process_vm_readv: 1
+tgkill: 1
+rt_sigprocmask: 1
+rt_tgsigqueueinfo: 1
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
+madvise: 1
+mprotect: arg2 in PROT_READ|PROT_WRITE
+munmap: 1
+getuid32: 1
+fstat64: 1
+mmap2: arg2 in PROT_READ|PROT_WRITE
+sigaction: 1
+geteuid32: 1
+getgid32: 1
+getegid32: 1
+getgroups32: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.x86_64.policy b/debuggerd/seccomp_policy/crash_dump.x86_64.policy
new file mode 100644
index 0000000..0c689bb
--- /dev/null
+++ b/debuggerd/seccomp_policy/crash_dump.x86_64.policy
@@ -0,0 +1,36 @@
+read: 1
+write: 1
+exit: 1
+rt_sigreturn: 1
+exit_group: 1
+clock_gettime: 1
+gettimeofday: 1
+futex: 1
+getrandom: 1
+getpid: 1
+gettid: 1
+ppoll: 1
+pipe2: 1
+openat: 1
+dup: 1
+close: 1
+lseek: 1
+getdents64: 1
+faccessat: 1
+recvmsg: 1
+process_vm_readv: 1
+tgkill: 1
+rt_sigprocmask: 1
+rt_tgsigqueueinfo: 1
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
+madvise: 1
+mprotect: arg2 in PROT_READ|PROT_WRITE
+munmap: 1
+getuid: 1
+fstat: 1
+mmap: arg2 in PROT_READ|PROT_WRITE
+rt_sigaction: 1
+geteuid: 1
+getgid: 1
+getegid: 1
+getgroups: 1
diff --git a/debuggerd/seccomp_policy/generate.sh b/debuggerd/seccomp_policy/generate.sh
new file mode 100755
index 0000000..8c58b05
--- /dev/null
+++ b/debuggerd/seccomp_policy/generate.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+set -ex
+
+cd "$(dirname "$0")"
+CPP='cpp -undef -E -P crash_dump.policy.def'
+$CPP -D__arm__ -o crash_dump.arm.policy
+$CPP -D__aarch64__ -D__LP64__ -o crash_dump.arm64.policy
+$CPP -D__i386__ -o crash_dump.x86.policy
+$CPP -D__x86_64__ -D__LP64__ -o crash_dump.x86_64.policy
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index c1028ef..62a26b3 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -28,13 +28,15 @@
 
 #include "bootimg_utils.h"
 
+#include "fastboot.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-void bootimg_set_cmdline(boot_img_hdr* h, const char* cmdline)
-{
-    strcpy((char*) h->cmdline, cmdline);
+void bootimg_set_cmdline(boot_img_hdr* h, const char* cmdline) {
+    if (strlen(cmdline) >= sizeof(h->cmdline)) die("command line too large: %zu", strlen(cmdline));
+    strcpy(reinterpret_cast<char*>(h->cmdline), cmdline);
 }
 
 boot_img_hdr* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offset,
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 6175f59..536d64e 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -447,8 +447,11 @@
     if (kdata == nullptr) die("cannot load '%s': %s", kernel.c_str(), strerror(errno));
 
     // Is this actually a boot image?
+    if (ksize < static_cast<int64_t>(sizeof(boot_img_hdr))) {
+        die("cannot load '%s': too short", kernel.c_str());
+    }
     if (!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
-        if (cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
+        if (cmdline) bootimg_set_cmdline(reinterpret_cast<boot_img_hdr*>(kdata), cmdline);
 
         if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk");
 
diff --git a/init/Android.bp b/init/Android.bp
index 2fea359..6c80ee6 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -58,6 +58,34 @@
             cppflags: ["-DUSER_MODE_LINUX"],
         }
     },
+    static_libs: [
+        "libbootloader_message",
+        "libfs_mgr",
+        "libfec",
+        "libfec_rs",
+        "libhidl-gen-utils",
+        "libsquashfs_utils",
+        "liblogwrap",
+        "libext4_utils",
+        "libcutils",
+        "libbase",
+        "libc",
+        "libseccomp_policy",
+        "libselinux",
+        "liblog",
+        "libcrypto_utils",
+        "libcrypto",
+        "libc++_static",
+        "libdl",
+        "libsparse",
+        "libz",
+        "libprocessgroup",
+        "libavb",
+        "libkeyutils",
+        "libprotobuf-cpp-lite",
+        "libpropertyinfoserializer",
+        "libpropertyinfoparser",
+    ],
 }
 
 cc_library_static {
@@ -65,39 +93,38 @@
     defaults: ["init_defaults"],
     srcs: [
         "action.cpp",
+        "bootchart.cpp",
+        "builtins.cpp",
         "capabilities.cpp",
         "descriptors.cpp",
         "devices.cpp",
         "firmware_handler.cpp",
         "import_parser.cpp",
+        "init.cpp",
+        "init_first_stage.cpp",
+        "keychords.cpp",
         "log.cpp",
         "parser.cpp",
         "persistent_properties.cpp",
         "persistent_properties.proto",
         "property_service.cpp",
+        "property_type.cpp",
+        "reboot.cpp",
         "security.cpp",
         "selinux.cpp",
         "service.cpp",
+        "sigchld_handler.cpp",
         "subcontext.cpp",
         "subcontext.proto",
         "rlimit_parser.cpp",
         "tokenizer.cpp",
         "uevent_listener.cpp",
+        "ueventd.cpp",
         "ueventd_parser.cpp",
         "util.cpp",
+        "watchdogd.cpp",
     ],
     whole_static_libs: ["libcap"],
-    static_libs: [
-        "libbase",
-        "libhidl-gen-utils",
-        "libselinux",
-        "liblog",
-        "libprocessgroup",
-        "libfs_mgr",
-        "libprotobuf-cpp-lite",
-        "libpropertyinfoserializer",
-        "libpropertyinfoparser",
-    ],
     include_dirs: [
         "system/core/mkbootimg",
     ],
@@ -124,42 +151,7 @@
         "make_f2fs",
     ],
     static_executable: true,
-    srcs: [
-        "bootchart.cpp",
-        "builtins.cpp",
-        "init.cpp",
-        "init_first_stage.cpp",
-        "keychords.cpp",
-        "reboot.cpp",
-        "sigchld_handler.cpp",
-        "ueventd.cpp",
-        "watchdogd.cpp",
-    ],
-    static_libs: [
-        "libinit",
-        "libbootloader_message",
-        "libfs_mgr",
-        "libfec",
-        "libfec_rs",
-        "libhidl-gen-utils",
-        "libsquashfs_utils",
-        "liblogwrap",
-        "libext4_utils",
-        "libcutils",
-        "libbase",
-        "libc",
-        "libselinux",
-        "liblog",
-        "libcrypto_utils",
-        "libcrypto",
-        "libc++_static",
-        "libdl",
-        "libsparse",
-        "libz",
-        "libprocessgroup",
-        "libavb",
-        "libkeyutils",
-    ],
+    srcs: ["main.cpp"],
     symlinks: [
         "sbin/ueventd",
         "sbin/watchdogd",
@@ -173,11 +165,13 @@
 cc_test {
     name: "init_tests",
     defaults: ["init_defaults"],
+    static_executable: true,
     srcs: [
         "devices_test.cpp",
         "init_test.cpp",
         "persistent_properties_test.cpp",
         "property_service_test.cpp",
+        "property_type_test.cpp",
         "result_test.cpp",
         "rlimit_parser_test.cpp",
         "service_test.cpp",
@@ -185,36 +179,17 @@
         "ueventd_test.cpp",
         "util_test.cpp",
     ],
-    shared_libs: [
-        "libbase",
-        "libcutils",
-    ],
-    static_libs: [
-        "libinit",
-        "libhidl-gen-utils",
-        "libselinux",
-        "libcrypto",
-        "libprotobuf-cpp-lite",
-        "libpropertyinfoparser",
-    ],
+    static_libs: ["libinit"],
 }
 
 cc_benchmark {
     name: "init_benchmarks",
+    static_executable: true,
     defaults: ["init_defaults"],
     srcs: [
         "subcontext_benchmark.cpp",
     ],
-    shared_libs: [
-        "libbase",
-        "libcutils",
-    ],
-    static_libs: [
-        "libinit",
-        "libselinux",
-        "libcrypto",
-        "libprotobuf-cpp-lite",
-    ],
+    static_libs: ["libinit"],
 }
 
 subdirs = ["*"]
diff --git a/init/Android.mk b/init/Android.mk
index 5239366..c4a6a50 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -41,16 +41,7 @@
 
 include $(CLEAR_VARS)
 LOCAL_CPPFLAGS := $(init_cflags)
-LOCAL_SRC_FILES:= \
-    bootchart.cpp \
-    builtins.cpp \
-    init.cpp \
-    init_first_stage.cpp \
-    keychords.cpp \
-    reboot.cpp \
-    sigchld_handler.cpp \
-    ueventd.cpp \
-    watchdogd.cpp \
+LOCAL_SRC_FILES := main.cpp
 
 LOCAL_MODULE:= init
 
diff --git a/init/action.cpp b/init/action.cpp
index 16ecdcd..ba03e66 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -21,6 +21,7 @@
 #include <android-base/properties.h>
 #include <android-base/strings.h>
 
+#include "stable_properties.h"
 #include "util.h"
 
 using android::base::Join;
@@ -134,6 +135,25 @@
     }
 }
 
+static bool IsActionableProperty(Subcontext* subcontext, const std::string& prop_name) {
+    static bool enabled =
+        android::base::GetBoolProperty("ro.actionable_compatible_property.enabled", false);
+
+    if (subcontext == nullptr || !enabled) {
+        return true;
+    }
+
+    if (kExportedActionableProperties.count(prop_name) == 1) {
+        return true;
+    }
+    for (const auto& prefix : kPartnerPrefixes) {
+        if (android::base::StartsWith(prop_name, prefix)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 Result<Success> Action::ParsePropertyTrigger(const std::string& trigger) {
     const static std::string prop_str("property:");
     std::string prop_name(trigger.substr(prop_str.length()));
@@ -145,6 +165,10 @@
     std::string prop_value(prop_name.substr(equal_pos + 1));
     prop_name.erase(equal_pos);
 
+    if (!IsActionableProperty(subcontext_, prop_name)) {
+        return Error() << "unexported property tigger found: " << prop_name;
+    }
+
     if (auto [it, inserted] = property_triggers_.emplace(prop_name, prop_value); !inserted) {
         return Error() << "multiple property triggers found for same property";
     }
diff --git a/init/init.cpp b/init/init.cpp
index 571da7c..95f272b 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -746,7 +746,3 @@
 
 }  // namespace init
 }  // namespace android
-
-int main(int argc, char** argv) {
-    android::init::main(argc, argv);
-}
diff --git a/init/init.h b/init/init.h
index b757c1d..ff7bdeb 100644
--- a/init/init.h
+++ b/init/init.h
@@ -47,6 +47,8 @@
 
 void ResetWaitForProp();
 
+int main(int argc, char** argv);
+
 }  // namespace init
 }  // namespace android
 
diff --git a/init/main.cpp b/init/main.cpp
new file mode 100644
index 0000000..9ed451b
--- /dev/null
+++ b/init/main.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 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 "init.h"
+
+int main(int argc, char** argv) {
+    android::init::main(argc, argv);
+}
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 7aa94b0..79f7f25 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -58,6 +58,7 @@
 
 #include "init.h"
 #include "persistent_properties.h"
+#include "property_type.h"
 #include "util.h"
 
 using android::base::ReadFileToString;
@@ -95,14 +96,9 @@
         LOG(FATAL) << "Failed to load serialized property info file";
     }
 }
-static bool check_mac_perms(const std::string& name, char* sctx, struct ucred* cr) {
-    if (!sctx) {
-      return false;
-    }
-
-    const char* target_context = nullptr;
-    property_info_area->GetPropertyInfo(name.c_str(), &target_context, nullptr);
-    if (target_context == nullptr) {
+static bool CheckMacPerms(const std::string& name, const char* target_context,
+                          const char* source_context, struct ucred* cr) {
+    if (!target_context || !source_context) {
         return false;
     }
 
@@ -111,29 +107,12 @@
     audit_data.name = name.c_str();
     audit_data.cr = cr;
 
-    bool has_access =
-        (selinux_check_access(sctx, target_context, "property_service", "set", &audit_data) == 0);
+    bool has_access = (selinux_check_access(source_context, target_context, "property_service",
+                                            "set", &audit_data) == 0);
 
     return has_access;
 }
 
-static int check_control_mac_perms(const char *name, char *sctx, struct ucred *cr)
-{
-    /*
-     *  Create a name prefix out of ctl.<service name>
-     *  The new prefix allows the use of the existing
-     *  property service backend labeling while avoiding
-     *  mislabels based on true property prefixes.
-     */
-    char ctl_name[PROP_VALUE_MAX+4];
-    int ret = snprintf(ctl_name, sizeof(ctl_name), "ctl.%s", name);
-
-    if (ret < 0 || (size_t) ret >= sizeof(ctl_name))
-        return 0;
-
-    return check_mac_perms(ctl_name, sctx, cr);
-}
-
 bool is_legal_property_name(const std::string& name) {
     size_t namelen = name.size();
 
@@ -422,52 +401,70 @@
   struct ucred cr = socket.cred();
   char* source_ctx = nullptr;
   getpeercon(socket.socket(), &source_ctx);
+  std::string source_context = source_ctx;
+  freecon(source_ctx);
 
   if (StartsWith(name, "ctl.")) {
-    if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) {
+      // ctl. properties have their name ctl.<action> and their value is the name of the service to
+      // apply that action to.  Permissions for these actions are based on the service, so we must
+      // create a fake name of ctl.<service> to check permissions.
+      auto control_string = "ctl." + value;
+      const char* target_context = nullptr;
+      const char* type = nullptr;
+      property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type);
+      if (!CheckMacPerms(control_string, target_context, source_context.c_str(), &cr)) {
+          LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
+                     << " service ctl [" << value << "]"
+                     << " uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid;
+          if (!legacy_protocol) {
+              socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
+          }
+          return;
+      }
+
       handle_control_message(name.c_str() + 4, value.c_str());
       if (!legacy_protocol) {
-        socket.SendUint32(PROP_SUCCESS);
+          socket.SendUint32(PROP_SUCCESS);
       }
-    } else {
-      LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
-                 << " service ctl [" << value << "]"
-                 << " uid:" << cr.uid
-                 << " gid:" << cr.gid
-                 << " pid:" << cr.pid;
-      if (!legacy_protocol) {
-        socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
-      }
-    }
   } else {
-    if (check_mac_perms(name, source_ctx, &cr)) {
+      const char* target_context = nullptr;
+      const char* type = nullptr;
+      property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
+      if (!CheckMacPerms(name, target_context, source_context.c_str(), &cr)) {
+          LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid
+                     << " name:" << name;
+          if (!legacy_protocol) {
+              socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
+          }
+          return;
+      }
+      if (type == nullptr || !CheckType(type, value)) {
+          LOG(ERROR) << "sys_prop(" << cmd_name << "): type check failed, type: '"
+                     << (type ?: "(null)") << "' value: '" << value << "'";
+          if (!legacy_protocol) {
+              socket.SendUint32(PROP_ERROR_INVALID_VALUE);
+          }
+          return;
+      }
       // sys.powerctl is a special property that is used to make the device reboot.  We want to log
       // any process that sets this property to be able to accurately blame the cause of a shutdown.
       if (name == "sys.powerctl") {
-        std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
-        std::string process_cmdline;
-        std::string process_log_string;
-        if (ReadFileToString(cmdline_path, &process_cmdline)) {
-          // Since cmdline is null deliminated, .c_str() conveniently gives us just the process path.
-          process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
-        }
-        LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
-                  << process_log_string;
+          std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
+          std::string process_cmdline;
+          std::string process_log_string;
+          if (ReadFileToString(cmdline_path, &process_cmdline)) {
+              // Since cmdline is null deliminated, .c_str() conveniently gives us just the process path.
+              process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
+          }
+          LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
+                    << process_log_string;
       }
 
       uint32_t result = property_set(name, value);
       if (!legacy_protocol) {
-        socket.SendUint32(result);
+          socket.SendUint32(result);
       }
-    } else {
-      LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid << " name:" << name;
-      if (!legacy_protocol) {
-        socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
-      }
-    }
   }
-
-  freecon(source_ctx);
 }
 
 static void handle_property_set_fd() {
@@ -764,9 +761,10 @@
         }
         LoadPropertyInfoFromFile("/nonplat_property_contexts", &property_infos);
     }
+
     auto serialized_contexts = std::string();
     auto error = std::string();
-    if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "\\s*", &serialized_contexts,
+    if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "string", &serialized_contexts,
                    &error)) {
         LOG(ERROR) << "Unable to serialize property contexts: " << error;
         return;
diff --git a/init/property_type.cpp b/init/property_type.cpp
new file mode 100644
index 0000000..249b12b
--- /dev/null
+++ b/init/property_type.cpp
@@ -0,0 +1,81 @@
+//
+// 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 "property_type.h"
+
+#include <android-base/parsedouble.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
+using android::base::ParseDouble;
+using android::base::ParseInt;
+using android::base::ParseUint;
+using android::base::Split;
+
+namespace android {
+namespace init {
+
+bool CheckType(const std::string& type_string, const std::string& value) {
+    auto type_strings = Split(type_string, " ");
+    if (type_strings.empty()) {
+        return false;
+    }
+    auto type = type_strings[0];
+
+    if (type == "string") {
+        return true;
+    }
+    if (type == "bool") {
+        return value == "true" || value == "false" || value == "1" || value == "0";
+    }
+    if (type == "int") {
+        int64_t parsed;
+        return ParseInt(value, &parsed);
+    }
+    if (type == "uint") {
+        uint64_t parsed;
+        if (value.empty() || value.front() == '-') {
+            return false;
+        }
+        return ParseUint(value, &parsed);
+    }
+    if (type == "double") {
+        double parsed;
+        return ParseDouble(value.c_str(), &parsed);
+    }
+    if (type == "size") {
+        auto it = value.begin();
+        while (it != value.end() && isdigit(*it)) {
+            it++;
+        }
+        if (it == value.begin() || it == value.end() || (*it != 'g' && *it != 'k' && *it != 'm')) {
+            return false;
+        }
+        it++;
+        return it == value.end();
+    }
+    if (type == "enum") {
+        for (auto it = std::next(type_strings.begin()); it != type_strings.end(); ++it) {
+            if (*it == value) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/property_type.h b/init/property_type.h
new file mode 100644
index 0000000..c889e16
--- /dev/null
+++ b/init/property_type.h
@@ -0,0 +1,30 @@
+/*
+ * 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 _INIT_PROPERTY_TYPE_H
+#define _INIT_PROPERTY_TYPE_H
+
+#include <string>
+
+namespace android {
+namespace init {
+
+bool CheckType(const std::string& type_string, const std::string& value);
+
+}  // namespace init
+}  // namespace android
+
+#endif
diff --git a/init/property_type_test.cpp b/init/property_type_test.cpp
new file mode 100644
index 0000000..068bccc
--- /dev/null
+++ b/init/property_type_test.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 "property_type.h"
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace init {
+
+TEST(property_type, CheckType_string) {
+    EXPECT_TRUE(CheckType("string", ""));
+    EXPECT_TRUE(CheckType("string", "-234"));
+    EXPECT_TRUE(CheckType("string", "234"));
+    EXPECT_TRUE(CheckType("string", "true"));
+    EXPECT_TRUE(CheckType("string", "false"));
+    EXPECT_TRUE(CheckType("string", "45645634563456345634563456"));
+    EXPECT_TRUE(CheckType("string", "some other string"));
+}
+
+TEST(property_type, CheckType_int) {
+    EXPECT_FALSE(CheckType("int", ""));
+    EXPECT_FALSE(CheckType("int", "abc"));
+    EXPECT_FALSE(CheckType("int", "-abc"));
+    EXPECT_TRUE(CheckType("int", "0"));
+    EXPECT_TRUE(CheckType("int", std::to_string(std::numeric_limits<int64_t>::min())));
+    EXPECT_TRUE(CheckType("int", std::to_string(std::numeric_limits<int64_t>::max())));
+    EXPECT_TRUE(CheckType("int", "123"));
+    EXPECT_TRUE(CheckType("int", "-123"));
+}
+
+TEST(property_type, CheckType_uint) {
+    EXPECT_FALSE(CheckType("uint", ""));
+    EXPECT_FALSE(CheckType("uint", "abc"));
+    EXPECT_FALSE(CheckType("uint", "-abc"));
+    EXPECT_TRUE(CheckType("uint", "0"));
+    EXPECT_TRUE(CheckType("uint", std::to_string(std::numeric_limits<uint64_t>::max())));
+    EXPECT_TRUE(CheckType("uint", "123"));
+    EXPECT_FALSE(CheckType("uint", "-123"));
+}
+
+TEST(property_type, CheckType_double) {
+    EXPECT_FALSE(CheckType("double", ""));
+    EXPECT_FALSE(CheckType("double", "abc"));
+    EXPECT_FALSE(CheckType("double", "-abc"));
+    EXPECT_TRUE(CheckType("double", "0.0"));
+    EXPECT_TRUE(CheckType("double", std::to_string(std::numeric_limits<double>::min())));
+    EXPECT_TRUE(CheckType("double", std::to_string(std::numeric_limits<double>::max())));
+    EXPECT_TRUE(CheckType("double", "123.1"));
+    EXPECT_TRUE(CheckType("double", "-123.1"));
+}
+
+TEST(property_type, CheckType_size) {
+    EXPECT_FALSE(CheckType("size", ""));
+    EXPECT_FALSE(CheckType("size", "ab"));
+    EXPECT_FALSE(CheckType("size", "abcd"));
+    EXPECT_FALSE(CheckType("size", "0"));
+
+    EXPECT_TRUE(CheckType("size", "512g"));
+    EXPECT_TRUE(CheckType("size", "512k"));
+    EXPECT_TRUE(CheckType("size", "512m"));
+
+    EXPECT_FALSE(CheckType("size", "512gggg"));
+    EXPECT_FALSE(CheckType("size", "512mgk"));
+    EXPECT_FALSE(CheckType("size", "g"));
+    EXPECT_FALSE(CheckType("size", "m"));
+}
+
+TEST(property_type, CheckType_enum) {
+    EXPECT_FALSE(CheckType("enum abc", ""));
+    EXPECT_FALSE(CheckType("enum abc", "ab"));
+    EXPECT_FALSE(CheckType("enum abc", "abcd"));
+    EXPECT_FALSE(CheckType("enum 123 456 789", "0"));
+
+    EXPECT_TRUE(CheckType("enum abc", "abc"));
+    EXPECT_TRUE(CheckType("enum 123 456 789", "123"));
+    EXPECT_TRUE(CheckType("enum 123 456 789", "456"));
+    EXPECT_TRUE(CheckType("enum 123 456 789", "789"));
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 21086dc..a88a42d 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -137,25 +137,12 @@
 
 // Turn off backlight while we are performing power down cleanup activities.
 static void TurnOffBacklight() {
-    static constexpr char OFF[] = "0";
-
-    android::base::WriteStringToFile(OFF, "/sys/class/leds/lcd-backlight/brightness");
-
-    static const char backlightDir[] = "/sys/class/backlight";
-    std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(backlightDir), closedir);
-    if (!dir) {
+    Service* service = ServiceList::GetInstance().FindService("blank_screen");
+    if (service == nullptr) {
+        LOG(WARNING) << "cannot find blank_screen in TurnOffBacklight";
         return;
     }
-
-    struct dirent* dp;
-    while ((dp = readdir(dir.get())) != nullptr) {
-        if (((dp->d_type != DT_DIR) && (dp->d_type != DT_LNK)) || (dp->d_name[0] == '.')) {
-            continue;
-        }
-
-        std::string fileName = StringPrintf("%s/%s/brightness", backlightDir, dp->d_name);
-        android::base::WriteStringToFile(OFF, fileName);
-    }
+    service->Start();
 }
 
 static void ShutdownVold() {
@@ -316,8 +303,6 @@
     std::vector<MountEntry> block_devices;
     std::vector<MountEntry> emulated_devices;
 
-    TurnOffBacklight();  // this part can take time. save power.
-
     if (runFsck && !FindPartitionsToUmount(&block_devices, &emulated_devices, false)) {
         return UMOUNT_STAT_ERROR;
     }
@@ -397,6 +382,11 @@
         }
     }
 
+    // remaining operations (specifically fsck) may take a substantial duration
+    if (cmd == ANDROID_RB_POWEROFF || is_thermal_shutdown) {
+        TurnOffBacklight();
+    }
+
     Service* bootAnim = ServiceList::GetInstance().FindService("bootanim");
     Service* surfaceFlinger = ServiceList::GetInstance().FindService("surfaceflinger");
     if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
diff --git a/init/stable_properties.h b/init/stable_properties.h
new file mode 100644
index 0000000..8219838
--- /dev/null
+++ b/init/stable_properties.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 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 _INIT_STABLE_PROPERTIES_H
+#define _INIT_STABLE_PROPERTIES_H
+
+#include <set>
+#include <string>
+
+namespace android {
+namespace init {
+
+static constexpr const char* kPartnerPrefixes[] = {
+    "init.svc.vendor.", "ro.vendor.", "persist.vendor.", "vendor.",
+    "init.svc.odm.",    "ro.odm.",    "persist.odm.",    "odm.",
+};
+
+static const std::set<std::string> kExportedActionableProperties = {
+    "init.svc.zygote",         "persist.bluetooth.btsnoopenable",
+    "persist.sys.crash_rcu",   "persist.sys.zram_enabled",
+    "ro.boot.revision",        "ro.bootmode",
+    "ro.build.type",           "sys.boot_completed",
+    "sys.retaildemo.enabled",  "sys.shutdown.requested",
+    "sys.usb.config",          "sys.usb.configfs",
+    "sys.usb.ffs.mtp.ready",   "sys.usb.ffs.ready",
+    "sys.user.0.ce_available", "sys.vdso",
+    "vts.native_server.on",
+};
+
+}  // namespace init
+}  // namespace android
+
+#endif
diff --git a/init/subcontext.h b/init/subcontext.h
index 262440d..5601b80 100644
--- a/init/subcontext.h
+++ b/init/subcontext.h
@@ -25,6 +25,7 @@
 #include <android-base/unique_fd.h>
 
 #include "builtins.h"
+#include "result.h"
 #include "system/core/init/subcontext.pb.h"
 
 namespace android {
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 9eaeae8..d9eed76 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -50,9 +50,6 @@
     "BacktracePtrace.cpp",
     "thread_utils.c",
     "ThreadEntry.cpp",
-    "UnwindCurrent.cpp",
-    "UnwindMap.cpp",
-    "UnwindPtrace.cpp",
     "UnwindStack.cpp",
     "UnwindStackMap.cpp",
 ]
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 5bb6edc..1195e5f 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -30,8 +30,6 @@
 #include <demangle.h>
 
 #include "BacktraceLog.h"
-#include "UnwindCurrent.h"
-#include "UnwindPtrace.h"
 #include "UnwindStack.h"
 #include "thread_utils.h"
 
@@ -55,7 +53,7 @@
   }
 }
 
-std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset, const backtrace_map_t* map) {
+std::string Backtrace::GetFunctionName(uint64_t pc, uint64_t* offset, const backtrace_map_t* map) {
   backtrace_map_t map_value;
   if (map == nullptr) {
     FillInMap(pc, &map_value);
@@ -68,7 +66,7 @@
   return demangle(GetFunctionNameRaw(pc, offset).c_str());
 }
 
-bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) {
+bool Backtrace::VerifyReadWordArgs(uint64_t ptr, word_t* out_value) {
   if (ptr & (sizeof(word_t)-1)) {
     BACK_LOGW("invalid pointer %p", reinterpret_cast<void*>(ptr));
     *out_value = static_cast<word_t>(-1);
@@ -105,12 +103,12 @@
   // Special handling for non-zero offset maps, we need to print that
   // information.
   if (frame->map.offset != 0) {
-    line += " (offset " + StringPrintf("0x%" PRIxPTR, frame->map.offset) + ")";
+    line += " (offset " + StringPrintf("0x%" PRIx64, frame->map.offset) + ")";
   }
   if (!frame->func_name.empty()) {
     line += " (" + frame->func_name;
     if (frame->func_offset) {
-      line += StringPrintf("+%" PRIuPTR, frame->func_offset);
+      line += StringPrintf("+%" PRIu64, frame->func_offset);
     }
     line += ')';
   }
@@ -118,7 +116,7 @@
   return line;
 }
 
-void Backtrace::FillInMap(uintptr_t pc, backtrace_map_t* map) {
+void Backtrace::FillInMap(uint64_t pc, backtrace_map_t* map) {
   if (map_ != nullptr) {
     map_->FillIn(pc, map);
   }
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index 474d099..d61b281 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -36,7 +36,7 @@
 #include "ThreadEntry.h"
 #include "thread_utils.h"
 
-bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) {
+bool BacktraceCurrent::ReadWord(uint64_t ptr, word_t* out_value) {
   if (!VerifyReadWordArgs(ptr, out_value)) {
     return false;
   }
@@ -53,7 +53,7 @@
   }
 }
 
-size_t BacktraceCurrent::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+size_t BacktraceCurrent::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
   backtrace_map_t map;
   FillInMap(addr, &map);
   if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
diff --git a/libbacktrace/BacktraceCurrent.h b/libbacktrace/BacktraceCurrent.h
index 072ffd2..60a9117 100644
--- a/libbacktrace/BacktraceCurrent.h
+++ b/libbacktrace/BacktraceCurrent.h
@@ -40,9 +40,9 @@
   BacktraceCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
   virtual ~BacktraceCurrent() {}
 
-  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
+  size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
 
-  bool ReadWord(uintptr_t ptr, word_t* out_value) override;
+  bool ReadWord(uint64_t ptr, word_t* out_value) override;
 
   bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override;
 
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 0f1ae11..2a657b8 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -38,7 +38,7 @@
 BacktraceMap::~BacktraceMap() {
 }
 
-void BacktraceMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
+void BacktraceMap::FillIn(uint64_t addr, backtrace_map_t* map) {
   ScopedBacktraceMapIteratorLock lock(this);
   for (auto it = begin(); it != end(); ++it) {
     const backtrace_map_t* entry = *it;
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index 30845a2..a056716 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -57,7 +57,7 @@
   uint64_t hdr_vaddr;
   uint64_t vaddr;
   uint64_t fde_table_offset;
-  uintptr_t min_func_vaddr;
+  uint64_t min_func_vaddr;
   std::vector<uint8_t> hdr_data;
   std::vector<uint8_t> data;
 };
@@ -221,8 +221,8 @@
       frames_.resize(num_frames + 1);
       backtrace_frame_data_t* frame = &frames_[num_frames];
       frame->num = num_frames;
-      frame->pc = static_cast<uintptr_t>(pc);
-      frame->sp = static_cast<uintptr_t>(sp);
+      frame->pc = static_cast<uint64_t>(pc);
+      frame->sp = static_cast<uint64_t>(sp);
       frame->stack_size = 0;
 
       if (num_frames > 0) {
@@ -253,12 +253,12 @@
   return true;
 }
 
-bool BacktraceOffline::ReadWord(uintptr_t ptr, word_t* out_value) {
+bool BacktraceOffline::ReadWord(uint64_t ptr, word_t* out_value) {
   size_t bytes_read = Read(ptr, reinterpret_cast<uint8_t*>(out_value), sizeof(word_t));
   return bytes_read == sizeof(word_t);
 }
 
-size_t BacktraceOffline::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+size_t BacktraceOffline::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
   // Normally, libunwind needs stack information and call frame information to do remote unwinding.
   // If call frame information is stored in .debug_frame, libunwind can read it from file
   // by itself. If call frame information is stored in .eh_frame, we need to provide data in
@@ -386,9 +386,8 @@
         proc_info->start_ip = *it;
         proc_info->format = UNW_INFO_FORMAT_ARM_EXIDX;
         proc_info->unwind_info = reinterpret_cast<void*>(
-            static_cast<uintptr_t>(index * sizeof(ArmIdxEntry) +
-                                   debug_frame->arm_exidx.exidx_vaddr +
-                                   debug_frame->min_vaddr));
+            static_cast<uint64_t>(index * sizeof(ArmIdxEntry) + debug_frame->arm_exidx.exidx_vaddr +
+                                  debug_frame->min_vaddr));
         eh_frame_hdr_space_.Clear();
         eh_frame_space_.Clear();
         // Prepare arm_exidx space and arm_extab space.
@@ -595,7 +594,7 @@
   return result;
 }
 
-std::string BacktraceOffline::GetFunctionNameRaw(uintptr_t, uintptr_t* offset) {
+std::string BacktraceOffline::GetFunctionNameRaw(uint64_t, uint64_t* offset) {
   // We don't have enough information to support this. And it is expensive.
   *offset = 0;
   return "";
diff --git a/libbacktrace/BacktraceOffline.h b/libbacktrace/BacktraceOffline.h
index fcde379..e028cd8 100644
--- a/libbacktrace/BacktraceOffline.h
+++ b/libbacktrace/BacktraceOffline.h
@@ -57,9 +57,9 @@
 
   bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
 
-  bool ReadWord(uintptr_t ptr, word_t* out_value) override;
+  bool ReadWord(uint64_t ptr, word_t* out_value) override;
 
-  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
+  size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
 
   bool FindProcInfo(unw_addr_space_t addr_space, uint64_t ip, unw_proc_info_t* proc_info,
                     int need_unwind_info);
@@ -67,7 +67,7 @@
   bool ReadReg(size_t reg_index, uint64_t* value);
 
  protected:
-  std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
+  std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) override;
   DebugFrameInfo* GetDebugFrameInFile(const std::string& filename);
 
   bool cache_file_;
diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp
index fd8b713..bf6b16f 100644
--- a/libbacktrace/BacktracePtrace.cpp
+++ b/libbacktrace/BacktracePtrace.cpp
@@ -31,7 +31,7 @@
 #include "thread_utils.h"
 
 #if !defined(__APPLE__)
-static bool PtraceRead(pid_t tid, uintptr_t addr, word_t* out_value) {
+static bool PtraceRead(pid_t tid, uint64_t addr, word_t* out_value) {
   // ptrace() returns -1 and sets errno when the operation fails.
   // To disambiguate -1 from a valid result, we clear errno beforehand.
   errno = 0;
@@ -43,7 +43,7 @@
 }
 #endif
 
-bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
+bool BacktracePtrace::ReadWord(uint64_t ptr, word_t* out_value) {
 #if defined(__APPLE__)
   BACK_LOGW("MacOS does not support reading from another pid.");
   return false;
@@ -62,7 +62,7 @@
 #endif
 }
 
-size_t BacktracePtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+size_t BacktracePtrace::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
 #if defined(__APPLE__)
   BACK_LOGW("MacOS does not support reading from another pid.");
   return 0;
diff --git a/libbacktrace/BacktracePtrace.h b/libbacktrace/BacktracePtrace.h
index d110b48..1ae3adf 100644
--- a/libbacktrace/BacktracePtrace.h
+++ b/libbacktrace/BacktracePtrace.h
@@ -29,9 +29,9 @@
   BacktracePtrace(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
   virtual ~BacktracePtrace() {}
 
-  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
+  size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
 
-  bool ReadWord(uintptr_t ptr, word_t* out_value) override;
+  bool ReadWord(uint64_t ptr, word_t* out_value) override;
 };
 
 #endif // _LIBBACKTRACE_BACKTRACE_PTRACE_H
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
deleted file mode 100644
index 3ccf13c..0000000
--- a/libbacktrace/UnwindCurrent.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <ucontext.h>
-
-#include <memory>
-#include <string>
-
-#define UNW_LOCAL_ONLY
-#include <libunwind.h>
-
-#include <android-base/logging.h>
-#include <backtrace/Backtrace.h>
-
-#include "BacktraceLog.h"
-#include "UnwindCurrent.h"
-
-std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
-  if (!initialized_) {
-    // If init local is not called, then trying to get a function name will
-    // fail, so try to initialize first.
-    std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t);
-    if (unw_init_local(cursor.get(), &context_) < 0) {
-      return "";
-    }
-    initialized_ = true;
-  }
-
-  *offset = 0;
-  char buf[512];
-  unw_word_t value;
-  if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf),
-                              &value, &context_) >= 0 && buf[0] != '\0') {
-    *offset = static_cast<uintptr_t>(value);
-    return buf;
-  }
-  return "";
-}
-
-void UnwindCurrent::GetUnwContextFromUcontext(const ucontext_t* ucontext) {
-  unw_tdep_context_t* unw_context = reinterpret_cast<unw_tdep_context_t*>(&context_);
-
-#if defined(__arm__)
-  unw_context->regs[0] = ucontext->uc_mcontext.arm_r0;
-  unw_context->regs[1] = ucontext->uc_mcontext.arm_r1;
-  unw_context->regs[2] = ucontext->uc_mcontext.arm_r2;
-  unw_context->regs[3] = ucontext->uc_mcontext.arm_r3;
-  unw_context->regs[4] = ucontext->uc_mcontext.arm_r4;
-  unw_context->regs[5] = ucontext->uc_mcontext.arm_r5;
-  unw_context->regs[6] = ucontext->uc_mcontext.arm_r6;
-  unw_context->regs[7] = ucontext->uc_mcontext.arm_r7;
-  unw_context->regs[8] = ucontext->uc_mcontext.arm_r8;
-  unw_context->regs[9] = ucontext->uc_mcontext.arm_r9;
-  unw_context->regs[10] = ucontext->uc_mcontext.arm_r10;
-  unw_context->regs[11] = ucontext->uc_mcontext.arm_fp;
-  unw_context->regs[12] = ucontext->uc_mcontext.arm_ip;
-  unw_context->regs[13] = ucontext->uc_mcontext.arm_sp;
-  unw_context->regs[14] = ucontext->uc_mcontext.arm_lr;
-  unw_context->regs[15] = ucontext->uc_mcontext.arm_pc;
-#else
-  unw_context->uc_mcontext = ucontext->uc_mcontext;
-#endif
-}
-
-bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
-  if (ucontext == nullptr) {
-    int ret = unw_getcontext(&context_);
-    if (ret < 0) {
-      BACK_LOGW("unw_getcontext failed %d", ret);
-      error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
-      return false;
-    }
-  } else {
-    GetUnwContextFromUcontext(ucontext);
-  }
-
-  // The cursor structure is pretty large, do not put it on the stack.
-  std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t);
-  int ret = unw_init_local(cursor.get(), &context_);
-  if (ret < 0) {
-    BACK_LOGW("unw_init_local failed %d", ret);
-    error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
-    return false;
-  }
-  initialized_ = true;
-
-  size_t num_frames = 0;
-  do {
-    unw_word_t pc;
-    ret = unw_get_reg(cursor.get(), UNW_REG_IP, &pc);
-    if (ret < 0) {
-      BACK_LOGW("Failed to read IP %d", ret);
-      break;
-    }
-    unw_word_t sp;
-    ret = unw_get_reg(cursor.get(), UNW_REG_SP, &sp);
-    if (ret < 0) {
-      BACK_LOGW("Failed to read SP %d", ret);
-      break;
-    }
-
-    frames_.resize(num_frames+1);
-    backtrace_frame_data_t* frame = &frames_.at(num_frames);
-    frame->num = num_frames;
-    frame->pc = static_cast<uintptr_t>(pc);
-    frame->sp = static_cast<uintptr_t>(sp);
-    frame->stack_size = 0;
-
-    FillInMap(frame->pc, &frame->map);
-    // Check to see if we should skip this frame because it's coming
-    // from within the library, and we are doing a local unwind.
-    if (ucontext != nullptr || num_frames != 0 || !DiscardFrame(*frame)) {
-      if (num_ignore_frames == 0) {
-        // GetFunctionName is an expensive call, only do it if we are
-        // keeping the frame.
-        frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map);
-        if (num_frames > 0) {
-          // Set the stack size for the previous frame.
-          backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
-          prev->stack_size = frame->sp - prev->sp;
-        }
-        if (BacktraceMap::IsValid(frame->map)) {
-          frame->rel_pc = frame->pc - frame->map.start + frame->map.load_bias;
-        } else {
-          frame->rel_pc = frame->pc;
-        }
-        num_frames++;
-      } else {
-        num_ignore_frames--;
-        // Set the number of frames to zero to remove the frame added
-        // above. By definition, if we still have frames to ignore
-        // there should only be one frame in the vector.
-        CHECK(num_frames == 0);
-        frames_.resize(0);
-      }
-    }
-    // If the pc is in a device map, then don't try to step.
-    if (frame->map.flags & PROT_DEVICE_MAP) {
-      break;
-    }
-    // Verify the sp is not in a device map too.
-    backtrace_map_t map;
-    FillInMap(frame->sp, &map);
-    if (map.flags & PROT_DEVICE_MAP) {
-      break;
-    }
-    ret = unw_step (cursor.get());
-  } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
-
-  return true;
-}
diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h
deleted file mode 100644
index 3656104..0000000
--- a/libbacktrace/UnwindCurrent.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2013 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 _LIBBACKTRACE_UNWIND_CURRENT_H
-#define _LIBBACKTRACE_UNWIND_CURRENT_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <ucontext.h>
-
-#include <string>
-
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include "BacktraceCurrent.h"
-
-#define UNW_LOCAL_ONLY
-#include <libunwind.h>
-
-class UnwindCurrent : public BacktraceCurrent {
- public:
-  UnwindCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : BacktraceCurrent(pid, tid, map) {}
-  virtual ~UnwindCurrent() {}
-
-  std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
-
- private:
-  void GetUnwContextFromUcontext(const ucontext_t* ucontext);
-
-  bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;
-
-  unw_context_t context_;
-
-  bool initialized_ = false;
-};
-
-#endif // _LIBBACKTRACE_UNWIND_CURRENT_H
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index 3cab0d1..798c769 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -134,7 +134,7 @@
   return (map_created_ = (unw_map_local_create() == 0)) && GenerateMap();;
 }
 
-void UnwindMapLocal::FillIn(uintptr_t addr, backtrace_map_t* map) {
+void UnwindMapLocal::FillIn(uint64_t addr, backtrace_map_t* map) {
   BacktraceMap::FillIn(addr, map);
   if (!IsValid(*map)) {
     // Check to see if the underlying map changed and regenerate the map
diff --git a/libbacktrace/UnwindMap.h b/libbacktrace/UnwindMap.h
index 6ffdafd..15544e8 100644
--- a/libbacktrace/UnwindMap.h
+++ b/libbacktrace/UnwindMap.h
@@ -55,7 +55,7 @@
 
   bool Build() override;
 
-  void FillIn(uintptr_t addr, backtrace_map_t* map) override;
+  void FillIn(uint64_t addr, backtrace_map_t* map) override;
 
   void LockIterator() override { pthread_rwlock_rdlock(&map_lock_); }
   void UnlockIterator() override { pthread_rwlock_unlock(&map_lock_); }
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
deleted file mode 100644
index 2155b8a..0000000
--- a/libbacktrace/UnwindPtrace.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <ucontext.h>
-
-#include <libunwind.h>
-#include <libunwind-ptrace.h>
-
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include "BacktraceLog.h"
-#include "UnwindMap.h"
-#include "UnwindPtrace.h"
-
-UnwindPtrace::UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
-    : BacktracePtrace(pid, tid, map), addr_space_(nullptr), upt_info_(nullptr) {
-}
-
-UnwindPtrace::~UnwindPtrace() {
-  if (upt_info_) {
-    _UPT_destroy(upt_info_);
-    upt_info_ = nullptr;
-  }
-
-  if (addr_space_) {
-    // Remove the map from the address space before destroying it.
-    // It will be freed in the UnwindMap destructor.
-    unw_map_set(addr_space_, nullptr);
-
-    unw_destroy_addr_space(addr_space_);
-    addr_space_ = nullptr;
-  }
-}
-
-bool UnwindPtrace::Init() {
-  if (upt_info_) {
-    return true;
-  }
-
-  if (addr_space_) {
-    // If somehow the addr_space_ gets initialized but upt_info_ doesn't,
-    // then that indicates there is some kind of failure.
-    return false;
-  }
-
-  addr_space_ = unw_create_addr_space(&_UPT_accessors, 0);
-  if (!addr_space_) {
-    BACK_LOGW("unw_create_addr_space failed.");
-    error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
-    return false;
-  }
-
-  UnwindMap* map = static_cast<UnwindMap*>(GetMap());
-  unw_map_set(addr_space_, map->GetMapCursor());
-
-  upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(Tid()));
-  if (!upt_info_) {
-    BACK_LOGW("Failed to create upt info.");
-    error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
-    return false;
-  }
-
-  return true;
-}
-
-bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
-  if (GetMap() == nullptr) {
-    // Without a map object, we can't do anything.
-    error_.error_code = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
-    return false;
-  }
-
-  error_.error_code = BACKTRACE_UNWIND_NO_ERROR;
-
-  if (ucontext) {
-    BACK_LOGW("Unwinding from a specified context not supported yet.");
-    error_.error_code = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION;
-    return false;
-  }
-
-  if (!Init()) {
-    return false;
-  }
-
-  unw_cursor_t cursor;
-  int ret = unw_init_remote(&cursor, addr_space_, upt_info_);
-  if (ret < 0) {
-    BACK_LOGW("unw_init_remote failed %d", ret);
-    error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
-    return false;
-  }
-
-  size_t num_frames = 0;
-  do {
-    unw_word_t pc;
-    ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
-    if (ret < 0) {
-      BACK_LOGW("Failed to read IP %d", ret);
-      break;
-    }
-    unw_word_t sp;
-    ret = unw_get_reg(&cursor, UNW_REG_SP, &sp);
-    if (ret < 0) {
-      BACK_LOGW("Failed to read SP %d", ret);
-      break;
-    }
-
-    if (num_ignore_frames == 0) {
-      frames_.resize(num_frames+1);
-      backtrace_frame_data_t* frame = &frames_.at(num_frames);
-      frame->num = num_frames;
-      frame->pc = static_cast<uintptr_t>(pc);
-      frame->sp = static_cast<uintptr_t>(sp);
-      frame->stack_size = 0;
-
-      if (num_frames > 0) {
-        backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
-        prev->stack_size = frame->sp - prev->sp;
-      }
-
-      FillInMap(frame->pc, &frame->map);
-      if (BacktraceMap::IsValid(frame->map)) {
-        frame->rel_pc = frame->pc - frame->map.start + frame->map.load_bias;
-      } else {
-        frame->rel_pc = frame->pc;
-      }
-
-      frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map);
-
-      num_frames++;
-      // If the pc is in a device map, then don't try to step.
-      if (frame->map.flags & PROT_DEVICE_MAP) {
-        break;
-      }
-    } else {
-      // If the pc is in a device map, then don't try to step.
-      backtrace_map_t map;
-      FillInMap(pc, &map);
-      if (map.flags & PROT_DEVICE_MAP) {
-        break;
-      }
-      num_ignore_frames--;
-    }
-    // Verify the sp is not in a device map.
-    backtrace_map_t map;
-    FillInMap(sp, &map);
-    if (map.flags & PROT_DEVICE_MAP) {
-      break;
-    }
-    ret = unw_step (&cursor);
-  } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
-
-  return true;
-}
-
-std::string UnwindPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
-  if (!Init()) {
-    return "";
-  }
-
-  *offset = 0;
-  char buf[512];
-  unw_word_t value;
-  if (unw_get_proc_name_by_ip(addr_space_, pc, buf, sizeof(buf), &value,
-                              upt_info_) >= 0 && buf[0] != '\0') {
-    *offset = static_cast<uintptr_t>(value);
-    return buf;
-  }
-  return "";
-}
diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h
deleted file mode 100644
index 4688110..0000000
--- a/libbacktrace/UnwindPtrace.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2013 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 _LIBBACKTRACE_UNWIND_PTRACE_H
-#define _LIBBACKTRACE_UNWIND_PTRACE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <string>
-
-#ifdef UNW_LOCAL_ONLY
-#undef UNW_LOCAL_ONLY
-#endif
-#include <libunwind.h>
-
-#include "BacktracePtrace.h"
-
-class UnwindPtrace : public BacktracePtrace {
- public:
-  UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map);
-  virtual ~UnwindPtrace();
-
-  bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override;
-
-  std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
-
- private:
-  bool Init();
-
-  unw_addr_space_t addr_space_;
-  struct UPT_info* upt_info_;
-};
-
-#endif // _LIBBACKTRACE_UNWIND_PTRACE_H
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index b0345a1..bbfbdda 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -70,6 +70,7 @@
     back_frame->rel_pc = frame->rel_pc;
     back_frame->pc = frame->pc;
     back_frame->sp = frame->sp;
+    back_frame->dex_pc = frame->dex_pc;
 
     back_frame->func_name = demangle(frame->function_name.c_str());
     back_frame->func_offset = frame->function_offset;
@@ -88,7 +89,7 @@
 UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map)
     : BacktraceCurrent(pid, tid, map) {}
 
-std::string UnwindStackCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+std::string UnwindStackCurrent::GetFunctionNameRaw(uint64_t pc, uint64_t* offset) {
   return GetMap()->GetFunctionName(pc, offset);
 }
 
@@ -111,7 +112,7 @@
 UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
     : BacktracePtrace(pid, tid, map), memory_(pid) {}
 
-std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+std::string UnwindStackPtrace::GetFunctionNameRaw(uint64_t pc, uint64_t* offset) {
   return GetMap()->GetFunctionName(pc, offset);
 }
 
@@ -127,6 +128,6 @@
   return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr);
 }
 
-size_t UnwindStackPtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+size_t UnwindStackPtrace::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
   return memory_.Read(addr, buffer, bytes);
 }
diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h
index ee2a706..498ad4e 100644
--- a/libbacktrace/UnwindStack.h
+++ b/libbacktrace/UnwindStack.h
@@ -32,7 +32,7 @@
   UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map);
   virtual ~UnwindStackCurrent() = default;
 
-  std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
+  std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) override;
 
   bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;
 };
@@ -44,9 +44,9 @@
 
   bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
 
-  std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+  std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset);
 
-  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
+  size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
 
  private:
   unwindstack::MemoryRemote memory_;
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 93406dc..60c7952 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -57,7 +57,7 @@
     map.end = map_info->end;
     map.offset = map_info->offset;
     // Set to -1 so that it is demand loaded.
-    map.load_bias = static_cast<uintptr_t>(-1);
+    map.load_bias = static_cast<uint64_t>(-1);
     map.flags = map_info->flags;
     map.name = map_info->name;
 
@@ -67,9 +67,9 @@
   return true;
 }
 
-void UnwindStackMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
+void UnwindStackMap::FillIn(uint64_t addr, backtrace_map_t* map) {
   BacktraceMap::FillIn(addr, map);
-  if (map->load_bias != static_cast<uintptr_t>(-1)) {
+  if (map->load_bias != static_cast<uint64_t>(-1)) {
     return;
   }
 
@@ -93,7 +93,7 @@
   return map_info->GetLoadBias(process_memory_);
 }
 
-std::string UnwindStackMap::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
+std::string UnwindStackMap::GetFunctionName(uint64_t pc, uint64_t* offset) {
   *offset = 0;
   unwindstack::Maps* maps = stack_maps();
 
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index 12c5909..6b98809 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -33,9 +33,9 @@
 
   bool Build() override;
 
-  void FillIn(uintptr_t addr, backtrace_map_t* map) override;
+  void FillIn(uint64_t addr, backtrace_map_t* map) override;
 
-  virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset) override;
+  virtual std::string GetFunctionName(uint64_t pc, uint64_t* offset) override;
   virtual std::shared_ptr<unwindstack::Memory> GetProcessMemory() override final;
 
   unwindstack::Maps* stack_maps() { return stack_maps_.get(); }
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index e92bc61..e2a7441 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -75,20 +75,20 @@
 
 struct FunctionSymbol {
   std::string name;
-  uintptr_t start;
-  uintptr_t end;
+  uint64_t start;
+  uint64_t end;
 };
 
 static std::vector<FunctionSymbol> GetFunctionSymbols() {
   std::vector<FunctionSymbol> symbols = {
       {"unknown_start", 0, 0},
-      {"test_level_one", reinterpret_cast<uintptr_t>(&test_level_one), 0},
-      {"test_level_two", reinterpret_cast<uintptr_t>(&test_level_two), 0},
-      {"test_level_three", reinterpret_cast<uintptr_t>(&test_level_three), 0},
-      {"test_level_four", reinterpret_cast<uintptr_t>(&test_level_four), 0},
-      {"test_recursive_call", reinterpret_cast<uintptr_t>(&test_recursive_call), 0},
-      {"test_get_context_and_wait", reinterpret_cast<uintptr_t>(&test_get_context_and_wait), 0},
-      {"unknown_end", static_cast<uintptr_t>(-1), static_cast<uintptr_t>(-1)},
+      {"test_level_one", reinterpret_cast<uint64_t>(&test_level_one), 0},
+      {"test_level_two", reinterpret_cast<uint64_t>(&test_level_two), 0},
+      {"test_level_three", reinterpret_cast<uint64_t>(&test_level_three), 0},
+      {"test_level_four", reinterpret_cast<uint64_t>(&test_level_four), 0},
+      {"test_recursive_call", reinterpret_cast<uint64_t>(&test_recursive_call), 0},
+      {"test_get_context_and_wait", reinterpret_cast<uint64_t>(&test_get_context_and_wait), 0},
+      {"unknown_end", static_cast<uint64_t>(-1), static_cast<uint64_t>(-1)},
   };
   std::sort(
       symbols.begin(), symbols.end(),
@@ -141,7 +141,7 @@
   const size_t stack_size = 16 * 1024;
   void* stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   ASSERT_NE(MAP_FAILED, stack);
-  uintptr_t stack_addr = reinterpret_cast<uintptr_t>(stack);
+  uint64_t stack_addr = reinterpret_cast<uint64_t>(stack);
   pthread_attr_t attr;
   ASSERT_EQ(0, pthread_attr_init(&attr));
   ASSERT_EQ(0, pthread_attr_setstack(&attr, reinterpret_cast<void*>(stack), stack_size));
@@ -174,8 +174,8 @@
   for (auto it = map->begin(); it != map->end(); ++it) {
     const backtrace_map_t* entry = *it;
     testdata +=
-        android::base::StringPrintf("map: start: %" PRIxPTR " end: %" PRIxPTR " offset: %" PRIxPTR
-                                    " load_bias: %" PRIxPTR " flags: %d name: %s\n",
+        android::base::StringPrintf("map: start: %" PRIx64 " end: %" PRIx64 " offset: %" PRIx64
+                                    " load_bias: %" PRIx64 " flags: %d name: %s\n",
                                     entry->start, entry->end, entry->offset, entry->load_bias,
                                     entry->flags, entry->name.c_str());
   }
@@ -194,9 +194,9 @@
   // 5. Dump function symbols
   std::vector<FunctionSymbol> function_symbols = GetFunctionSymbols();
   for (const auto& symbol : function_symbols) {
-    testdata += android::base::StringPrintf(
-        "function: start: %" PRIxPTR " end: %" PRIxPTR" name: %s\n",
-        symbol.start, symbol.end, symbol.name.c_str());
+    testdata +=
+        android::base::StringPrintf("function: start: %" PRIx64 " end: %" PRIx64 " name: %s\n",
+                                    symbol.start, symbol.end, symbol.name.c_str());
   }
 
   ASSERT_TRUE(android::base::WriteStringToFile(testdata, "offline_testdata"));
@@ -204,7 +204,7 @@
 
 // Return the name of the function which matches the address. Although we don't know the
 // exact end of each function, it is accurate enough for the tests.
-static std::string FunctionNameForAddress(uintptr_t addr,
+static std::string FunctionNameForAddress(uint64_t addr,
                                           const std::vector<FunctionSymbol>& symbols) {
   for (auto& symbol : symbols) {
     if (addr >= symbol.start && addr < symbol.end) {
@@ -240,7 +240,7 @@
       backtrace_map_t& map = testdata->maps.back();
       int pos;
       sscanf(line.c_str(),
-             "map: start: %" SCNxPTR " end: %" SCNxPTR " offset: %" SCNxPTR " load_bias: %" SCNxPTR
+             "map: start: %" SCNx64 " end: %" SCNx64 " offset: %" SCNx64 " load_bias: %" SCNx64
              " flags: %d name: %n",
              &map.start, &map.end, &map.offset, &map.load_bias, &map.flags, &pos);
       map.name = android::base::Trim(line.substr(pos));
@@ -302,9 +302,8 @@
       testdata->symbols.resize(testdata->symbols.size() + 1);
       FunctionSymbol& symbol = testdata->symbols.back();
       int pos;
-      sscanf(line.c_str(),
-             "function: start: %" SCNxPTR " end: %" SCNxPTR " name: %n",
-             &symbol.start, &symbol.end, &pos);
+      sscanf(line.c_str(), "function: start: %" SCNx64 " end: %" SCNx64 " name: %n", &symbol.start,
+             &symbol.end, &pos);
       symbol.name = line.substr(pos);
     }
   }
@@ -342,7 +341,7 @@
   ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
 
   // Collect pc values of the call stack frames.
-  std::vector<uintptr_t> pc_values;
+  std::vector<uint64_t> pc_values;
   for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
     pc_values.push_back(backtrace->GetFrame(i)->pc);
   }
@@ -420,7 +419,7 @@
 
   ASSERT_EQ(testdata.symbols.size(), backtrace->NumFrames());
   for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
-    uintptr_t vaddr_in_file =
+    uint64_t vaddr_in_file =
         backtrace->GetFrame(i)->pc - testdata.maps[0].start + testdata.maps[0].load_bias;
     std::string name = FunctionNameForAddress(vaddr_in_file, testdata.symbols);
     ASSERT_EQ(name, testdata.symbols[i].name);
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 57b7553..10152f7 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -745,8 +745,8 @@
   delete back_map;
 
   ASSERT_FALSE(BacktraceMap::IsValid(map));
-  ASSERT_EQ(static_cast<uintptr_t>(0), map.start);
-  ASSERT_EQ(static_cast<uintptr_t>(0), map.end);
+  ASSERT_EQ(static_cast<uint64_t>(0), map.start);
+  ASSERT_EQ(static_cast<uint64_t>(0), map.end);
   ASSERT_EQ(0, map.flags);
   ASSERT_EQ("", map.name);
 }
@@ -851,8 +851,8 @@
 }
 
 struct map_test_t {
-  uintptr_t start;
-  uintptr_t end;
+  uint64_t start;
+  uint64_t end;
 };
 
 static bool map_sort(map_test_t i, map_test_t j) { return i.start < j.start; }
@@ -863,7 +863,7 @@
   }
   std::string map_txt;
   for (auto map : maps) {
-    map_txt += android::base::StringPrintf("%" PRIxPTR "-%" PRIxPTR "\n", map.start, map.end);
+    map_txt += android::base::StringPrintf("%" PRIx64 "-%" PRIx64 "\n", map.start, map.end);
   }
   return map_txt;
 }
@@ -875,7 +875,7 @@
   std::string map_txt;
   for (const backtrace_map_t* map : *maps) {
     map_txt += android::base::StringPrintf(
-        "%" PRIxPTR "-%" PRIxPTR " flags: 0x%x offset: 0x%" PRIxPTR " load_bias: 0x%" PRIxPTR,
+        "%" PRIx64 "-%" PRIx64 " flags: 0x%x offset: 0x%" PRIx64 " load_bias: 0x%" PRIx64,
         map->start, map->end, map->flags, map->offset, map->load_bias);
     if (!map->name.empty()) {
       map_txt += ' ' + map->name;
@@ -894,7 +894,7 @@
   std::vector<map_test_t> test_maps;
   while (fgets(buffer, sizeof(buffer), map_file)) {
     map_test_t map;
-    ASSERT_EQ(2, sscanf(buffer, "%" SCNxPTR "-%" SCNxPTR " ", &map.start, &map.end));
+    ASSERT_EQ(2, sscanf(buffer, "%" SCNx64 "-%" SCNx64 " ", &map.start, &map.end));
     test_maps.push_back(map);
   }
   fclose(map_file);
@@ -984,7 +984,7 @@
   return nullptr;
 }
 
-static void RunReadTest(Backtrace* backtrace, uintptr_t read_addr) {
+static void RunReadTest(Backtrace* backtrace, uint64_t read_addr) {
   size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
 
   // Create a page of data to use to do quick compares.
@@ -1035,15 +1035,15 @@
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
   ASSERT_TRUE(backtrace.get() != nullptr);
 
-  RunReadTest(backtrace.get(), reinterpret_cast<uintptr_t>(thread_data.data));
+  RunReadTest(backtrace.get(), reinterpret_cast<uint64_t>(thread_data.data));
 
   android_atomic_acquire_store(0, &thread_data.state);
 
   ASSERT_TRUE(WaitForNonZero(&thread_data.state, 10));
 }
 
-volatile uintptr_t g_ready = 0;
-volatile uintptr_t g_addr = 0;
+volatile uint64_t g_ready = 0;
+volatile uint64_t g_addr = 0;
 
 static void ForkedReadTest() {
   // Create two map pages.
@@ -1063,7 +1063,7 @@
   // Set up a simple pattern in memory.
   InitMemory(memory, pagesize);
 
-  g_addr = reinterpret_cast<uintptr_t>(memory);
+  g_addr = reinterpret_cast<uint64_t>(memory);
   g_ready = 1;
 
   while (1) {
@@ -1089,17 +1089,15 @@
       std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
       ASSERT_TRUE(backtrace.get() != nullptr);
 
-      uintptr_t read_addr;
-      size_t bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(&g_ready),
-                                          reinterpret_cast<uint8_t*>(&read_addr),
-                                          sizeof(uintptr_t));
-      ASSERT_EQ(sizeof(uintptr_t), bytes_read);
+      uint64_t read_addr;
+      size_t bytes_read = backtrace->Read(reinterpret_cast<uint64_t>(&g_ready),
+                                          reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t));
+      ASSERT_EQ(sizeof(uint64_t), bytes_read);
       if (read_addr) {
         // The forked process is ready to be read.
-        bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(&g_addr),
-                                     reinterpret_cast<uint8_t*>(&read_addr),
-                                     sizeof(uintptr_t));
-        ASSERT_EQ(sizeof(uintptr_t), bytes_read);
+        bytes_read = backtrace->Read(reinterpret_cast<uint64_t>(&g_addr),
+                                     reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t));
+        ASSERT_EQ(sizeof(uint64_t), bytes_read);
 
         RunReadTest(backtrace.get(), read_addr);
 
@@ -1173,7 +1171,7 @@
 
   struct stat buf;
   ASSERT_TRUE(stat(tmp_so_name, &buf) != -1);
-  uintptr_t map_size = buf.st_size;
+  uint64_t map_size = buf.st_size;
 
   int fd = open(tmp_so_name, O_RDONLY);
   ASSERT_TRUE(fd != -1);
@@ -1192,11 +1190,10 @@
   backtrace->Unwind(0);
 
   // Loop through the entire map, and get every function we can find.
-  map_size += reinterpret_cast<uintptr_t>(map);
+  map_size += reinterpret_cast<uint64_t>(map);
   std::string last_func;
-  for (uintptr_t read_addr = reinterpret_cast<uintptr_t>(map);
-       read_addr < map_size; read_addr += 4) {
-    uintptr_t offset;
+  for (uint64_t read_addr = reinterpret_cast<uint64_t>(map); read_addr < map_size; read_addr += 4) {
+    uint64_t offset;
     std::string func_name = backtrace->GetFunctionName(read_addr, &offset);
     if (!func_name.empty() && last_func != func_name) {
       found_functions.push_back(func_name);
@@ -1204,7 +1201,7 @@
     last_func = func_name;
   }
 
-  ASSERT_TRUE(munmap(map, map_size - reinterpret_cast<uintptr_t>(map)) == 0);
+  ASSERT_TRUE(munmap(map, map_size - reinterpret_cast<uint64_t>(map)) == 0);
 
   VerifyFunctionsFound(found_functions);
 }
@@ -1217,7 +1214,7 @@
 
   struct stat buf;
   ASSERT_TRUE(stat(tmp_so_name, &buf) != -1);
-  uintptr_t map_size = buf.st_size;
+  uint64_t map_size = buf.st_size;
 
   pid_t pid;
   if ((pid = fork()) == 0) {
@@ -1240,7 +1237,7 @@
       exit(0);
     }
 
-    g_addr = reinterpret_cast<uintptr_t>(map);
+    g_addr = reinterpret_cast<uint64_t>(map);
     g_ready = 1;
     while (true) {
       usleep(US_PER_MSEC);
@@ -1260,10 +1257,14 @@
     std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
     ASSERT_TRUE(backtrace.get() != nullptr);
 
-    uintptr_t read_addr;
-    ASSERT_EQ(sizeof(uintptr_t), backtrace->Read(reinterpret_cast<uintptr_t>(&g_ready), reinterpret_cast<uint8_t*>(&read_addr), sizeof(uintptr_t)));
+    uint64_t read_addr;
+    ASSERT_EQ(sizeof(uint64_t),
+              backtrace->Read(reinterpret_cast<uint64_t>(&g_ready),
+                              reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t)));
     if (read_addr) {
-      ASSERT_EQ(sizeof(uintptr_t), backtrace->Read(reinterpret_cast<uintptr_t>(&g_addr), reinterpret_cast<uint8_t*>(&read_addr), sizeof(uintptr_t)));
+      ASSERT_EQ(sizeof(uint64_t),
+                backtrace->Read(reinterpret_cast<uint64_t>(&g_addr),
+                                reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t)));
 
       // Needed before GetFunctionName will work.
       backtrace->Unwind(0);
@@ -1272,7 +1273,7 @@
       map_size += read_addr;
       std::string last_func;
       for (; read_addr < map_size; read_addr += 4) {
-        uintptr_t offset;
+        uint64_t offset;
         std::string func_name = backtrace->GetFunctionName(read_addr, &offset);
         if (!func_name.empty() && last_func != func_name) {
           found_functions.push_back(func_name);
@@ -1295,7 +1296,7 @@
   VerifyFunctionsFound(found_functions);
 }
 
-static bool FindFuncFrameInBacktrace(Backtrace* backtrace, uintptr_t test_func, size_t* frame_num) {
+static bool FindFuncFrameInBacktrace(Backtrace* backtrace, uint64_t test_func, size_t* frame_num) {
   backtrace_map_t map;
   backtrace->FillInMap(test_func, &map);
   if (!BacktraceMap::IsValid(map)) {
@@ -1314,7 +1315,7 @@
   return false;
 }
 
-static void VerifyUnreadableElfFrame(Backtrace* backtrace, uintptr_t test_func, size_t frame_num) {
+static void VerifyUnreadableElfFrame(Backtrace* backtrace, uint64_t test_func, size_t frame_num) {
   ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
     << DumpFrames(backtrace);
 
@@ -1322,11 +1323,12 @@
   // Make sure that there is at least one more frame above the test func call.
   ASSERT_LT(frame_num, backtrace->NumFrames()) << DumpFrames(backtrace);
 
-  uintptr_t diff = backtrace->GetFrame(frame_num)->pc - test_func;
+  uint64_t diff = backtrace->GetFrame(frame_num)->pc - test_func;
   ASSERT_LT(diff, 200U) << DumpFrames(backtrace);
 }
 
-static void VerifyUnreadableElfBacktrace(uintptr_t test_func) {
+static void VerifyUnreadableElfBacktrace(void* func) {
+  uint64_t test_func = reinterpret_cast<uint64_t>(func);
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
                                                          BACKTRACE_CURRENT_THREAD));
   ASSERT_TRUE(backtrace.get() != nullptr);
@@ -1339,7 +1341,7 @@
   VerifyUnreadableElfFrame(backtrace.get(), test_func, frame_num);
 }
 
-typedef int (*test_func_t)(int, int, int, int, void (*)(uintptr_t), uintptr_t);
+typedef int (*test_func_t)(int, int, int, int, void (*)(void*), void*);
 
 TEST(libbacktrace, unwind_through_unreadable_elf_local) {
   const char* tmp_so_name = CopySharedLibrary();
@@ -1352,8 +1354,8 @@
   test_func = reinterpret_cast<test_func_t>(dlsym(lib_handle, "test_level_one"));
   ASSERT_TRUE(test_func != nullptr);
 
-  ASSERT_NE(test_func(1, 2, 3, 4, VerifyUnreadableElfBacktrace,
-                      reinterpret_cast<uintptr_t>(test_func)), 0);
+  ASSERT_NE(test_func(1, 2, 3, 4, VerifyUnreadableElfBacktrace, reinterpret_cast<void*>(test_func)),
+            0);
 
   ASSERT_TRUE(dlclose(lib_handle) == 0);
 }
@@ -1391,10 +1393,9 @@
     ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
 
     size_t frame_num;
-    if (FindFuncFrameInBacktrace(backtrace.get(),
-                                 reinterpret_cast<uintptr_t>(test_func), &frame_num)) {
-
-      VerifyUnreadableElfFrame(backtrace.get(), reinterpret_cast<uintptr_t>(test_func), frame_num);
+    if (FindFuncFrameInBacktrace(backtrace.get(), reinterpret_cast<uint64_t>(test_func),
+                                 &frame_num)) {
+      VerifyUnreadableElfFrame(backtrace.get(), reinterpret_cast<uint64_t>(test_func), frame_num);
       done = true;
     }
 
@@ -1426,8 +1427,8 @@
   ASSERT_TRUE(backtrace.get() != nullptr);
 
   // Verify that trying to get a function name before doing an unwind works.
-  uintptr_t cur_func_offset = reinterpret_cast<uintptr_t>(&test_level_one) + 1;
-  size_t offset;
+  uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
+  uint64_t offset;
   ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
 }
 
@@ -1439,14 +1440,14 @@
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
 
   // Verify that trying to get a function name before doing an unwind works.
-  uintptr_t cur_func_offset = reinterpret_cast<uintptr_t>(&test_level_one) + 1;
-  size_t offset;
+  uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
+  uint64_t offset;
   ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
 
   FinishRemoteProcess(pid);
 }
 
-static void SetUcontextSp(uintptr_t sp, ucontext_t* ucontext) {
+static void SetUcontextSp(uint64_t sp, ucontext_t* ucontext) {
 #if defined(__arm__)
   ucontext->uc_mcontext.arm_sp = sp;
 #elif defined(__aarch64__)
@@ -1462,7 +1463,7 @@
 #endif
 }
 
-static void SetUcontextPc(uintptr_t pc, ucontext_t* ucontext) {
+static void SetUcontextPc(uint64_t pc, ucontext_t* ucontext) {
 #if defined(__arm__)
   ucontext->uc_mcontext.arm_pc = pc;
 #elif defined(__aarch64__)
@@ -1478,7 +1479,7 @@
 #endif
 }
 
-static void SetUcontextLr(uintptr_t lr, ucontext_t* ucontext) {
+static void SetUcontextLr(uint64_t lr, ucontext_t* ucontext) {
 #if defined(__arm__)
   ucontext->uc_mcontext.arm_lr = lr;
 #elif defined(__aarch64__)
@@ -1513,7 +1514,7 @@
 }
 
 static void UnwindFromDevice(Backtrace* backtrace, void* device_map) {
-  uintptr_t device_map_uint = reinterpret_cast<uintptr_t>(device_map);
+  uint64_t device_map_uint = reinterpret_cast<uint64_t>(device_map);
 
   backtrace_map_t map;
   backtrace->FillInMap(device_map_uint, &map);
@@ -1521,12 +1522,12 @@
   ASSERT_EQ(PROT_DEVICE_MAP, map.flags & PROT_DEVICE_MAP);
 
   // Quick sanity checks.
-  size_t offset;
+  uint64_t offset;
   ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset));
   ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset, &map));
   ASSERT_EQ(std::string(""), backtrace->GetFunctionName(0, &offset));
 
-  uintptr_t cur_func_offset = reinterpret_cast<uintptr_t>(&test_level_one) + 1;
+  uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
   // Now verify the device map flag actually causes the function name to be empty.
   backtrace->FillInMap(cur_func_offset, &map);
   ASSERT_TRUE((map.flags & PROT_DEVICE_MAP) == 0);
@@ -1539,7 +1540,7 @@
   // Create a context that has the pc in the device map, but the sp
   // in a non-device map.
   memset(&ucontext, 0, sizeof(ucontext));
-  SetUcontextSp(reinterpret_cast<uintptr_t>(&ucontext), &ucontext);
+  SetUcontextSp(reinterpret_cast<uint64_t>(&ucontext), &ucontext);
   SetUcontextPc(device_map_uint, &ucontext);
   SetUcontextLr(cur_func_offset, &ucontext);
 
@@ -1549,7 +1550,7 @@
   ASSERT_EQ(1U, backtrace->NumFrames());
   const backtrace_frame_data_t* frame = backtrace->GetFrame(0);
   ASSERT_EQ(device_map_uint, frame->pc);
-  ASSERT_EQ(reinterpret_cast<uintptr_t>(&ucontext), frame->sp);
+  ASSERT_EQ(reinterpret_cast<uint64_t>(&ucontext), frame->sp);
 
   // Check what happens when skipping the first frame.
   ASSERT_TRUE(backtrace->Unwind(1, &ucontext));
@@ -1669,7 +1670,7 @@
     std::unique_ptr<BacktraceMap> map(map_create_func(pid, false));
     std::unique_ptr<Backtrace> backtrace(create_func(pid, pid, map.get()));
 
-    size_t bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(const_cast<int*>(&value)),
+    size_t bytes_read = backtrace->Read(reinterpret_cast<uint64_t>(const_cast<int*>(&value)),
                                         reinterpret_cast<uint8_t*>(&read_value), sizeof(read_value));
     ASSERT_EQ(sizeof(read_value), bytes_read);
 
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 5922664..1b8ad19 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -26,11 +26,11 @@
 #include <backtrace/backtrace_constants.h>
 #include <backtrace/BacktraceMap.h>
 
-#if __LP64__
-#define PRIPTR "016" PRIxPTR
+#if defined(__LP64__)
+#define PRIPTR "016" PRIx64
 typedef uint64_t word_t;
 #else
-#define PRIPTR "08" PRIxPTR
+#define PRIPTR "08" PRIx64
 typedef uint32_t word_t;
 #endif
 
@@ -77,13 +77,15 @@
 
 struct backtrace_frame_data_t {
   size_t num;             // The current fame number.
-  uintptr_t pc;           // The absolute pc.
-  uintptr_t rel_pc;       // The relative pc.
-  uintptr_t sp;           // The top of the stack.
+  uint64_t pc;            // The absolute pc.
+  uint64_t rel_pc;        // The relative pc.
+  uint64_t sp;            // The top of the stack.
   size_t stack_size;      // The size of the stack, zero indicate an unknown stack size.
+  uint64_t dex_pc;        // If non-zero, the Dex PC for the ART interpreter.
   backtrace_map_t map;    // The map associated with the given pc.
   std::string func_name;  // The function name associated with this pc, NULL if not found.
-  uintptr_t func_offset;  // pc relative to the start of the function, only valid if func_name is not NULL.
+  uint64_t func_offset;  // pc relative to the start of the function, only valid if func_name is not
+                         // NULL.
 };
 
 #if defined(__APPLE__)
@@ -138,20 +140,20 @@
   // Get the function name and offset into the function given the pc.
   // If the string is empty, then no valid function name was found,
   // or the pc is not in any valid map.
-  virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset,
+  virtual std::string GetFunctionName(uint64_t pc, uint64_t* offset,
                                       const backtrace_map_t* map = NULL);
 
   // Fill in the map data associated with the given pc.
-  virtual void FillInMap(uintptr_t pc, backtrace_map_t* map);
+  virtual void FillInMap(uint64_t pc, backtrace_map_t* map);
 
   // Read the data at a specific address.
-  virtual bool ReadWord(uintptr_t ptr, word_t* out_value) = 0;
+  virtual bool ReadWord(uint64_t ptr, word_t* out_value) = 0;
 
   // Read arbitrary data from a specific address. If a read request would
   // span from one map to another, this call only reads up until the end
   // of the current map.
   // Returns the total number of bytes actually read.
-  virtual size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) = 0;
+  virtual size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) = 0;
 
   // Create a string representing the formatted line of backtrace information
   // for a single frame.
@@ -188,9 +190,9 @@
 
   // The name returned is not demangled, GetFunctionName() takes care of
   // demangling the name.
-  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) = 0;
+  virtual std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) = 0;
 
-  virtual bool VerifyReadWordArgs(uintptr_t ptr, word_t* out_value);
+  virtual bool VerifyReadWordArgs(uint64_t ptr, word_t* out_value);
 
   bool BuildMap();
 
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index 4ae68dd..4d020e6 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -39,10 +39,10 @@
 static constexpr int PROT_DEVICE_MAP = 0x8000;
 
 struct backtrace_map_t {
-  uintptr_t start = 0;
-  uintptr_t end = 0;
-  uintptr_t offset = 0;
-  uintptr_t load_bias = 0;
+  uint64_t start = 0;
+  uint64_t end = 0;
+  uint64_t offset = 0;
+  uint64_t load_bias = 0;
   int flags = 0;
   std::string name;
 };
@@ -91,7 +91,7 @@
         return nullptr;
       }
       backtrace_map_t* map = &map_->maps_[index_];
-      if (map->load_bias == static_cast<uintptr_t>(-1)) {
+      if (map->load_bias == static_cast<uint64_t>(-1)) {
         map->load_bias = map_->GetLoadBias(index_);
       }
       return map;
@@ -106,15 +106,15 @@
   iterator end() { return iterator(this, maps_.size()); }
 
   // Fill in the map data structure for the given address.
-  virtual void FillIn(uintptr_t addr, backtrace_map_t* map);
+  virtual void FillIn(uint64_t addr, backtrace_map_t* map);
 
   // Only supported with the new unwinder.
-  virtual std::string GetFunctionName(uintptr_t /*pc*/, uintptr_t* /*offset*/) { return ""; }
+  virtual std::string GetFunctionName(uint64_t /*pc*/, uint64_t* /*offset*/) { return ""; }
   virtual std::shared_ptr<unwindstack::Memory> GetProcessMemory() { return nullptr; }
 
   // The flags returned are the same flags as used by the mmap call.
   // The values are PROT_*.
-  int GetFlags(uintptr_t pc) {
+  int GetFlags(uint64_t pc) {
     backtrace_map_t map;
     FillIn(pc, &map);
     if (IsValid(map)) {
@@ -123,9 +123,9 @@
     return PROT_NONE;
   }
 
-  bool IsReadable(uintptr_t pc) { return GetFlags(pc) & PROT_READ; }
-  bool IsWritable(uintptr_t pc) { return GetFlags(pc) & PROT_WRITE; }
-  bool IsExecutable(uintptr_t pc) { return GetFlags(pc) & PROT_EXEC; }
+  bool IsReadable(uint64_t pc) { return GetFlags(pc) & PROT_READ; }
+  bool IsWritable(uint64_t pc) { return GetFlags(pc) & PROT_WRITE; }
+  bool IsExecutable(uint64_t pc) { return GetFlags(pc) & PROT_EXEC; }
 
   // In order to use the iterators on this object, a caller must
   // call the LockIterator and UnlockIterator function to guarantee
diff --git a/liblog/Android.bp b/liblog/Android.bp
index eae0b10..7d9e306 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -80,6 +80,10 @@
                 address: false,
             },
         },
+        android_arm: {
+            // TODO: This is to work around b/24465209. Remove after root cause is fixed
+            ldflags: ["-Wl,--hash-style=both"],
+        },
         windows: {
             srcs: ["uio.c"],
             enabled: true,
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 0954187..91d855b 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -34,6 +34,8 @@
 
 namespace unwindstack {
 
+constexpr uint64_t DEX_PC_REG = 0x20444558;
+
 DwarfSection::DwarfSection(Memory* memory) : memory_(memory), last_error_(DWARF_ERROR_NONE) {}
 
 const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
@@ -98,6 +100,84 @@
 }
 
 template <typename AddressType>
+struct EvalInfo {
+  const dwarf_loc_regs_t* loc_regs;
+  const DwarfCie* cie;
+  RegsImpl<AddressType>* cur_regs;
+  Memory* regular_memory;
+  AddressType cfa;
+  bool return_address_undefined = false;
+  uint64_t reg_map = 0;
+  AddressType reg_values[64];
+};
+
+template <typename AddressType>
+bool DwarfSectionImpl<AddressType>::EvalRegister(const DwarfLocation* loc, uint32_t reg,
+                                                 AddressType* reg_ptr, void* info) {
+  EvalInfo<AddressType>* eval_info = reinterpret_cast<EvalInfo<AddressType>*>(info);
+  Memory* regular_memory = eval_info->regular_memory;
+  switch (loc->type) {
+    case DWARF_LOCATION_OFFSET:
+      if (!regular_memory->ReadFully(eval_info->cfa + loc->values[0], reg_ptr, sizeof(AddressType))) {
+        last_error_ = DWARF_ERROR_MEMORY_INVALID;
+        return false;
+      }
+      break;
+    case DWARF_LOCATION_VAL_OFFSET:
+      *reg_ptr = eval_info->cfa + loc->values[0];
+      break;
+    case DWARF_LOCATION_REGISTER: {
+      uint32_t cur_reg = loc->values[0];
+      if (cur_reg >= eval_info->cur_regs->total_regs()) {
+        last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+        return false;
+      }
+      AddressType* cur_reg_ptr = &(*eval_info->cur_regs)[cur_reg];
+      const auto& entry = eval_info->loc_regs->find(cur_reg);
+      if (entry != eval_info->loc_regs->end()) {
+        if (!(eval_info->reg_map & (1 << cur_reg))) {
+          eval_info->reg_map |= 1 << cur_reg;
+          eval_info->reg_values[cur_reg] = *cur_reg_ptr;
+          if (!EvalRegister(&entry->second, cur_reg, cur_reg_ptr, eval_info)) {
+            return false;
+          }
+        }
+
+        // Use the register value from before any evaluations.
+        *reg_ptr = eval_info->reg_values[cur_reg] + loc->values[1];
+      } else {
+        *reg_ptr = *cur_reg_ptr + loc->values[1];
+      }
+      break;
+    }
+    case DWARF_LOCATION_EXPRESSION:
+    case DWARF_LOCATION_VAL_EXPRESSION: {
+      AddressType value;
+      if (!EvalExpression(*loc, eval_info->cie->version, regular_memory, &value)) {
+        return false;
+      }
+      if (loc->type == DWARF_LOCATION_EXPRESSION) {
+        if (!regular_memory->ReadFully(value, reg_ptr, sizeof(AddressType))) {
+          last_error_ = DWARF_ERROR_MEMORY_INVALID;
+          return false;
+        }
+      } else {
+        *reg_ptr = value;
+      }
+      break;
+    }
+    case DWARF_LOCATION_UNDEFINED:
+      if (reg == eval_info->cie->return_address_register) {
+        eval_info->return_address_undefined = true;
+      }
+    default:
+      break;
+  }
+
+  return true;
+}
+
+template <typename AddressType>
 bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_memory,
                                          const dwarf_loc_regs_t& loc_regs, Regs* regs,
                                          bool* finished) {
@@ -114,9 +194,13 @@
     return false;
   }
 
+  // Always set the dex pc to zero when evaluating.
+  cur_regs->set_dex_pc(0);
+
   AddressType prev_cfa = regs->sp();
 
-  AddressType cfa;
+  EvalInfo<AddressType> eval_info{
+      .loc_regs = &loc_regs, .cie = cie, .regular_memory = regular_memory, .cur_regs = cur_regs};
   const DwarfLocation* loc = &cfa_entry->second;
   // Only a few location types are valid for the cfa.
   switch (loc->type) {
@@ -129,11 +213,11 @@
       // pointer register does not have any associated location
       // information, use the current cfa value.
       if (regs->sp_reg() == loc->values[0] && loc_regs.count(regs->sp_reg()) == 0) {
-        cfa = prev_cfa;
+        eval_info.cfa = prev_cfa;
       } else {
-        cfa = (*cur_regs)[loc->values[0]];
+        eval_info.cfa = (*cur_regs)[loc->values[0]];
       }
-      cfa += loc->values[1];
+      eval_info.cfa += loc->values[1];
       break;
     case DWARF_LOCATION_EXPRESSION:
     case DWARF_LOCATION_VAL_EXPRESSION: {
@@ -142,12 +226,12 @@
         return false;
       }
       if (loc->type == DWARF_LOCATION_EXPRESSION) {
-        if (!regular_memory->ReadFully(value, &cfa, sizeof(AddressType))) {
+        if (!regular_memory->ReadFully(value, &eval_info.cfa, sizeof(AddressType))) {
           last_error_ = DWARF_ERROR_MEMORY_INVALID;
           return false;
         }
       } else {
-        cfa = value;
+        eval_info.cfa = value;
       }
       break;
     }
@@ -156,81 +240,38 @@
       return false;
   }
 
-  // This code is not guaranteed to work in cases where a register location
-  // is a double indirection to the actual value. For example, if r3 is set
-  // to r5 + 4, and r5 is set to CFA + 4, then this won't necessarily work
-  // because it does not guarantee that r5 is evaluated before r3.
-  // Check that this case does not exist, and error if it does.
-  bool return_address_undefined = false;
   for (const auto& entry : loc_regs) {
-    uint16_t reg = entry.first;
+    uint32_t reg = entry.first;
     // Already handled the CFA register.
     if (reg == CFA_REG) continue;
 
-    if (reg >= cur_regs->total_regs()) {
-      // Skip this unknown register.
+    AddressType* reg_ptr;
+    AddressType dex_pc = 0;
+    if (reg == DEX_PC_REG) {
+      // Special register that indicates this is a dex pc.
+      dex_pc = 0;
+      reg_ptr = &dex_pc;
+    } else if (reg >= cur_regs->total_regs() || eval_info.reg_map & (1 << reg)) {
+      // Skip this unknown register, or a register that has already been
+      // processed.
       continue;
+    } else {
+      reg_ptr = &(*cur_regs)[reg];
+      eval_info.reg_map |= 1 << reg;
+      eval_info.reg_values[reg] = *reg_ptr;
     }
 
-    const DwarfLocation* loc = &entry.second;
-    switch (loc->type) {
-      case DWARF_LOCATION_OFFSET:
-        if (!regular_memory->ReadFully(cfa + loc->values[0], &(*cur_regs)[reg],
-                                       sizeof(AddressType))) {
-          last_error_ = DWARF_ERROR_MEMORY_INVALID;
-          return false;
-        }
-        break;
-      case DWARF_LOCATION_VAL_OFFSET:
-        (*cur_regs)[reg] = cfa + loc->values[0];
-        break;
-      case DWARF_LOCATION_REGISTER: {
-        uint16_t cur_reg = loc->values[0];
-        if (cur_reg >= cur_regs->total_regs()) {
-          last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
-          return false;
-        }
-        if (loc_regs.find(cur_reg) != loc_regs.end()) {
-          // This is a double indirection, a register definition references
-          // another register which is also defined as something other
-          // than a register.
-          log(0,
-              "Invalid indirection: register %d references register %d which is "
-              "not a plain register.\n",
-              reg, cur_reg);
-          last_error_ = DWARF_ERROR_ILLEGAL_STATE;
-          return false;
-        }
-        (*cur_regs)[reg] = (*cur_regs)[cur_reg] + loc->values[1];
-        break;
-      }
-      case DWARF_LOCATION_EXPRESSION:
-      case DWARF_LOCATION_VAL_EXPRESSION: {
-        AddressType value;
-        if (!EvalExpression(*loc, cie->version, regular_memory, &value)) {
-          return false;
-        }
-        if (loc->type == DWARF_LOCATION_EXPRESSION) {
-          if (!regular_memory->ReadFully(value, &(*cur_regs)[reg], sizeof(AddressType))) {
-            last_error_ = DWARF_ERROR_MEMORY_INVALID;
-            return false;
-          }
-        } else {
-          (*cur_regs)[reg] = value;
-        }
-        break;
-      }
-      case DWARF_LOCATION_UNDEFINED:
-        if (reg == cie->return_address_register) {
-          return_address_undefined = true;
-        }
-      default:
-        break;
+    if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) {
+      return false;
+    }
+
+    if (reg == DEX_PC_REG) {
+      cur_regs->set_dex_pc(dex_pc);
     }
   }
 
   // Find the return address location.
-  if (return_address_undefined) {
+  if (eval_info.return_address_undefined) {
     cur_regs->set_pc(0);
   } else {
     cur_regs->set_pc((*cur_regs)[cie->return_address_register]);
@@ -239,7 +280,7 @@
   // If the pc was set to zero, consider this the final frame.
   *finished = (cur_regs->pc() == 0) ? true : false;
 
-  cur_regs->set_sp(cfa);
+  cur_regs->set_sp(eval_info.cfa);
 
   return true;
 }
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index b0a1c0c..d711772 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -40,6 +40,7 @@
   frame->num = frame_num;
   frame->sp = regs_->sp();
   frame->rel_pc = adjusted_rel_pc;
+  frame->dex_pc = regs_->dex_pc();
 
   if (map_info == nullptr) {
     frame->pc = regs_->pc();
diff --git a/libunwindstack/include/unwindstack/DwarfLocation.h b/libunwindstack/include/unwindstack/DwarfLocation.h
index 3467e6a..0881182 100644
--- a/libunwindstack/include/unwindstack/DwarfLocation.h
+++ b/libunwindstack/include/unwindstack/DwarfLocation.h
@@ -38,7 +38,7 @@
   uint64_t values[2];
 };
 
-typedef std::unordered_map<uint16_t, DwarfLocation> dwarf_loc_regs_t;
+typedef std::unordered_map<uint32_t, DwarfLocation> dwarf_loc_regs_t;
 
 }  // namespace unwindstack
 
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index 10be6b4..e0004aa 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -132,6 +132,8 @@
 
   const DwarfFde* GetFdeFromIndex(size_t index) override;
 
+  bool EvalRegister(const DwarfLocation* loc, uint32_t reg, AddressType* reg_ptr, void* info);
+
   bool Eval(const DwarfCie* cie, Memory* regular_memory, const dwarf_loc_regs_t& loc_regs,
             Regs* regs, bool* finished) override;
 
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 1904d4d..a5ba7a0 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -57,6 +57,9 @@
   virtual uint64_t pc() = 0;
   virtual uint64_t sp() = 0;
 
+  uint64_t dex_pc() { return dex_pc_; }
+  void set_dex_pc(uint64_t dex_pc) { dex_pc_ = dex_pc; }
+
   virtual uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) = 0;
 
   virtual bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) = 0;
@@ -79,6 +82,7 @@
   uint16_t total_regs_;
   uint16_t sp_reg_;
   Location return_loc_;
+  uint64_t dex_pc_ = 0;
 };
 
 template <typename AddressType>
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 5adec4f..32858ae 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -41,6 +41,7 @@
   uint64_t rel_pc;
   uint64_t pc;
   uint64_t sp;
+  uint64_t dex_pc;
 
   std::string function_name;
   uint64_t function_offset;
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index d54b0bf..dfd2ce0 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -266,13 +266,67 @@
 
   regs.set_pc(0x100);
   regs.set_sp(0x2000);
+  regs[1] = 0x100;
+  regs[3] = 0x300;
   regs[8] = 0x10;
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
-  loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 0}};
-  loc_regs[9] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 0}};
+  loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 1}};
+  loc_regs[9] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 2}};
   bool finished;
-  ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->last_error());
+  ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
+  EXPECT_EQ(0x301U, regs[1]);
+  EXPECT_EQ(0x300U, regs[3]);
+  EXPECT_EQ(0x10U, regs[8]);
+  EXPECT_EQ(0x102U, regs[9]);
+}
+
+TYPED_TEST_P(DwarfSectionImplTest, Eval_register_reference_chain) {
+  DwarfCie cie{.return_address_register = 5};
+  RegsImplFake<TypeParam> regs(10, 9);
+  dwarf_loc_regs_t loc_regs;
+
+  regs.set_pc(0x100);
+  regs.set_sp(0x2000);
+  regs[0] = 0x10;
+  regs[1] = 0x20;
+  regs[2] = 0x30;
+  regs[3] = 0x40;
+  regs[4] = 0x50;
+  regs[5] = 0x60;
+  regs[8] = 0x20;
+  loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+  loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 1}};
+  loc_regs[2] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 2}};
+  loc_regs[3] = DwarfLocation{DWARF_LOCATION_REGISTER, {2, 3}};
+  loc_regs[4] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 4}};
+  loc_regs[5] = DwarfLocation{DWARF_LOCATION_REGISTER, {4, 5}};
+  bool finished;
+  ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
+  EXPECT_EQ(0x10U, regs[0]);
+  EXPECT_EQ(0x11U, regs[1]);
+  EXPECT_EQ(0x22U, regs[2]);
+  EXPECT_EQ(0x33U, regs[3]);
+  EXPECT_EQ(0x44U, regs[4]);
+  EXPECT_EQ(0x55U, regs[5]);
+  EXPECT_EQ(0x20U, regs[8]);
+}
+
+TYPED_TEST_P(DwarfSectionImplTest, Eval_dex_pc) {
+  DwarfCie cie{.return_address_register = 5};
+  RegsImplFake<TypeParam> regs(10, 9);
+  dwarf_loc_regs_t loc_regs;
+
+  regs.set_pc(0x100);
+  regs.set_sp(0x2000);
+  regs[0] = 0x10;
+  regs[8] = 0x20;
+  loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+  loc_regs[0x20444558] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 1}};
+  bool finished;
+  ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
+  EXPECT_EQ(0x10U, regs[0]);
+  EXPECT_EQ(0x20U, regs[8]);
+  EXPECT_EQ(0x11U, regs.dex_pc());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_invalid_register) {
@@ -840,11 +894,11 @@
     DwarfSectionImplTest, Eval_cfa_expr_eval_fail, Eval_cfa_expr_no_stack,
     Eval_cfa_expr_is_register, Eval_cfa_expr, Eval_cfa_val_expr, Eval_bad_regs, Eval_no_cfa,
     Eval_cfa_bad, Eval_cfa_register_prev, Eval_cfa_register_from_value, Eval_double_indirection,
-    Eval_invalid_register, Eval_different_reg_locations, Eval_return_address_undefined,
-    Eval_pc_zero, Eval_return_address, Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
-    GetCie_fail_should_not_cache, GetCie_32_version_check, GetCie_negative_data_alignment_factor,
-    GetCie_64_no_augment, GetCie_augment, GetCie_version_3, GetCie_version_4,
-    GetFdeFromOffset_fail_should_not_cache, GetFdeFromOffset_32_no_augment,
+    Eval_register_reference_chain, Eval_dex_pc, Eval_invalid_register, Eval_different_reg_locations,
+    Eval_return_address_undefined, Eval_pc_zero, Eval_return_address, Eval_ignore_large_reg_loc,
+    Eval_reg_expr, Eval_reg_val_expr, GetCie_fail_should_not_cache, GetCie_32_version_check,
+    GetCie_negative_data_alignment_factor, GetCie_64_no_augment, GetCie_augment, GetCie_version_3,
+    GetCie_version_4, GetFdeFromOffset_fail_should_not_cache, GetFdeFromOffset_32_no_augment,
     GetFdeFromOffset_32_no_augment_non_zero_segment_size, GetFdeFromOffset_32_augment,
     GetFdeFromOffset_64_no_augment, GetFdeFromOffset_cached, GetCfaLocationInfo_cie_not_cached,
     GetCfaLocationInfo_cie_cached, Log);
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index 07e48af..33e5527 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -96,8 +96,13 @@
   unwinder.Unwind();
 
   // Print the frames.
+  const std::vector<unwindstack::FrameData>& frames = unwinder.frames();
   for (size_t i = 0; i < unwinder.NumFrames(); i++) {
     printf("%s\n", unwinder.FormatFrame(i).c_str());
+    const unwindstack::FrameData* frame = &frames[i];
+    if (frame->dex_pc != 0) {
+      printf("      dex pc %" PRIx64 "\n", frame->dex_pc);
+    }
   }
 }
 
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 6b50f0c..3bca6c8 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -43,8 +43,8 @@
     },
 }
 
-cc_library {
-    name: "libutils",
+cc_defaults {
+    name: "libutils_defaults",
     vendor_available: true,
     vndk: {
         enabled: true,
@@ -52,29 +52,6 @@
     },
     host_supported: true,
 
-    srcs: [
-        "CallStack.cpp",
-        "FileMap.cpp",
-        "JenkinsHash.cpp",
-        "NativeHandle.cpp",
-        "Printer.cpp",
-        "PropertyMap.cpp",
-        "RefBase.cpp",
-        "SharedBuffer.cpp",
-        "Static.cpp",
-        "StopWatch.cpp",
-        "String8.cpp",
-        "String16.cpp",
-        "StrongPointer.cpp",
-        "SystemClock.cpp",
-        "Threads.cpp",
-        "Timers.cpp",
-        "Tokenizer.cpp",
-        "Unicode.cpp",
-        "VectorImpl.cpp",
-        "misc.cpp",
-    ],
-
     cflags: ["-Wall", "-Werror"],
     include_dirs: ["external/safe-iop/include"],
     header_libs: [
@@ -96,14 +73,9 @@
 
     target: {
         android: {
-            srcs: [
-                "Trace.cpp",
-            ],
-
             cflags: ["-fvisibility=protected"],
 
             shared_libs: [
-                "libbacktrace",
                 "libcutils",
                 "libdl",
                 "libvndksupport",
@@ -113,12 +85,6 @@
                 misc_undefined: ["integer"],
             },
         },
-        linux: {
-            srcs: [
-                "Looper.cpp",
-                "ProcessCallStack.cpp",
-            ],
-        },
 
         host: {
             cflags: ["-DLIBUTILS_NATIVE=1"],
@@ -148,6 +114,75 @@
     },
 }
 
+cc_library {
+    name: "libutils",
+    defaults: ["libutils_defaults"],
+
+    srcs: [
+        "FileMap.cpp",
+        "JenkinsHash.cpp",
+        "NativeHandle.cpp",
+        "Printer.cpp",
+        "PropertyMap.cpp",
+        "RefBase.cpp",
+        "SharedBuffer.cpp",
+        "Static.cpp",
+        "StopWatch.cpp",
+        "String8.cpp",
+        "String16.cpp",
+        "StrongPointer.cpp",
+        "SystemClock.cpp",
+        "Threads.cpp",
+        "Timers.cpp",
+        "Tokenizer.cpp",
+        "Unicode.cpp",
+        "VectorImpl.cpp",
+        "misc.cpp",
+    ],
+
+    target: {
+        android: {
+            srcs: [
+                "Trace.cpp",
+            ],
+        },
+        linux: {
+            srcs: [
+                "Looper.cpp",
+            ],
+        },
+    },
+}
+
+cc_library {
+    name: "libutilscallstack",
+    defaults: ["libutils_defaults"],
+
+    srcs: [
+        "CallStack.cpp",
+    ],
+
+    arch: {
+        mips: {
+            cflags: ["-DALIGN_DOUBLE"],
+        },
+    },
+
+    target: {
+        android: {
+            shared_libs: [
+                "libutils",
+                "libbacktrace",
+            ],
+        },
+        linux: {
+            srcs: [
+                "ProcessCallStack.cpp",
+            ],
+        },
+    },
+}
+
 // Include subdirectory makefiles
 // ============================================================
 
diff --git a/property_service/libpropertyinfoserializer/property_info_file.cpp b/property_service/libpropertyinfoserializer/property_info_file.cpp
index bf96d88..2cdc62d 100644
--- a/property_service/libpropertyinfoserializer/property_info_file.cpp
+++ b/property_service/libpropertyinfoserializer/property_info_file.cpp
@@ -1,9 +1,26 @@
+//
+// 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 <property_info_serializer/property_info_serializer.h>
 
 #include <android-base/strings.h>
 
 #include "space_tokenizer.h"
 
+using android::base::Join;
 using android::base::Split;
 using android::base::StartsWith;
 using android::base::Trim;
@@ -11,6 +28,34 @@
 namespace android {
 namespace properties {
 
+namespace {
+
+bool IsTypeValid(const std::vector<std::string>& type_strings) {
+  if (type_strings.empty()) {
+    return false;
+  }
+
+  // There must be at least one string following 'enum'
+  if (type_strings[0] == "enum") {
+    return type_strings.size() > 1;
+  }
+
+  // There should not be any string following any other types.
+  if (type_strings.size() != 1) {
+    return false;
+  }
+
+  // Check that the type matches one of remaining valid types.
+  static const char* const no_parameter_types[] = {"string", "bool",   "int",
+                                                   "uint",   "double", "size"};
+  for (const auto& type : no_parameter_types) {
+    if (type_strings[0] == type) {
+      return true;
+    }
+  }
+  return false;
+}
+
 bool ParsePropertyInfoLine(const std::string& line, PropertyInfoEntry* out, std::string* error) {
   auto tokenizer = SpaceTokenizer(line);
 
@@ -26,14 +71,28 @@
     return false;
   }
 
-  // It is not an error to not find these, as older files will not contain them.
+  // It is not an error to not find exact_match or a type, as older files will not contain them.
   auto exact_match = tokenizer.GetNext();
-  auto type = tokenizer.GetRemaining();
+  // We reformat type to be space deliminated regardless of the input whitespace for easier storage
+  // and subsequent parsing.
+  auto type_strings = std::vector<std::string>{};
+  auto type = tokenizer.GetNext();
+  while (!type.empty()) {
+    type_strings.emplace_back(type);
+    type = tokenizer.GetNext();
+  }
 
-  *out = {property, context, type, exact_match == "exact"};
+  if (!type_strings.empty() && !IsTypeValid(type_strings)) {
+    *error = "Type '" + Join(type_strings, " ") + "' is not valid";
+    return false;
+  }
+
+  *out = {property, context, Join(type_strings, " "), exact_match == "exact"};
   return true;
 }
 
+}  // namespace
+
 void ParsePropertyInfoFile(const std::string& file_contents,
                            std::vector<PropertyInfoEntry>* property_infos,
                            std::vector<std::string>* errors) {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 6ea598d..6a1872f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -459,6 +459,7 @@
     # For security reasons, /data/local/tmp should always be empty.
     # Do not place files or directories in /data/local/tmp
     mkdir /data/local/tmp 0771 shell shell
+    mkdir /data/local/traces 0777 shell shell
     mkdir /data/data 0771 system system
     mkdir /data/app-private 0771 system system
     mkdir /data/app-ephemeral 0771 system system