Merge "Allow fuzzy_fastboot number to run for a specific device serial number"
diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp
index e9d9c63..3c8f393 100644
--- a/adb/daemon/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -406,11 +406,16 @@
                                              strerror(errno));
         return false;
     }
-    // Raw subprocess + shell protocol allows for splitting stderr.
-    if (!CreateSocketpair(&stderr_sfd_, &child_stderr_sfd)) {
-        *error = android::base::StringPrintf("failed to create socketpair for stderr: %s",
-                                             strerror(errno));
-        return false;
+    if (protocol_ == SubprocessProtocol::kShell) {
+        // Shell protocol allows for splitting stderr.
+        if (!CreateSocketpair(&stderr_sfd_, &child_stderr_sfd)) {
+            *error = android::base::StringPrintf("failed to create socketpair for stderr: %s",
+                                                 strerror(errno));
+            return false;
+        }
+    } else {
+        // Raw protocol doesn't support multiple output streams, so combine stdout and stderr.
+        child_stderr_sfd.reset(dup(child_stdinout_sfd));
     }
 
     D("execinprocess: stdin/stdout FD = %d, stderr FD = %d", stdinout_sfd_.get(),
diff --git a/adb/daemon/shell_service_test.cpp b/adb/daemon/shell_service_test.cpp
index 323bcec..dc79d12 100644
--- a/adb/daemon/shell_service_test.cpp
+++ b/adb/daemon/shell_service_test.cpp
@@ -35,7 +35,6 @@
     static void SetUpTestCase() {
         // This is normally done in main.cpp.
         saved_sigpipe_handler_ = signal(SIGPIPE, SIG_IGN);
-
     }
 
     static void TearDownTestCase() {
@@ -49,26 +48,32 @@
                              SubprocessProtocol protocol);
     void CleanupTestSubprocess();
 
-    virtual void TearDown() override {
-        void CleanupTestSubprocess();
-    }
+    void StartTestCommandInProcess(std::string name, Command command, SubprocessProtocol protocol);
+
+    virtual void TearDown() override { CleanupTestSubprocess(); }
 
     static sighandler_t saved_sigpipe_handler_;
 
-    unique_fd subprocess_fd_;
+    unique_fd command_fd_;
 };
 
 sighandler_t ShellServiceTest::saved_sigpipe_handler_ = nullptr;
 
 void ShellServiceTest::StartTestSubprocess(
         const char* command, SubprocessType type, SubprocessProtocol protocol) {
-    subprocess_fd_ = StartSubprocess(command, nullptr, type, protocol);
-    ASSERT_TRUE(subprocess_fd_ >= 0);
+    command_fd_ = StartSubprocess(command, nullptr, type, protocol);
+    ASSERT_TRUE(command_fd_ >= 0);
 }
 
 void ShellServiceTest::CleanupTestSubprocess() {
 }
 
+void ShellServiceTest::StartTestCommandInProcess(std::string name, Command command,
+                                                 SubprocessProtocol protocol) {
+    command_fd_ = StartCommandInProcess(std::move(name), std::move(command), protocol);
+    ASSERT_TRUE(command_fd_ >= 0);
+}
+
 namespace {
 
 // Reads raw data from |fd| until it closes or errors.
@@ -93,7 +98,7 @@
     stdout->clear();
     stderr->clear();
 
-    ShellProtocol* protocol = new ShellProtocol(fd);
+    auto protocol = std::make_unique<ShellProtocol>(fd);
     while (protocol->Read()) {
         switch (protocol->id()) {
             case ShellProtocol::kIdStdout:
@@ -111,7 +116,6 @@
                 ADD_FAILURE() << "Unidentified packet ID: " << protocol->id();
         }
     }
-    delete protocol;
 
     return exit_code;
 }
@@ -154,7 +158,7 @@
 
     // [ -t 0 ] == 0 means we have a terminal (PTY). Even when requesting a raw subprocess, without
     // the shell protocol we should always force a PTY to ensure proper cleanup.
-    ExpectLinesEqual(ReadRaw(subprocess_fd_), {"foo", "bar", "0"});
+    ExpectLinesEqual(ReadRaw(command_fd_), {"foo", "bar", "0"});
 }
 
 // Tests a PTY subprocess with no protocol.
@@ -165,7 +169,7 @@
             SubprocessType::kPty, SubprocessProtocol::kNone));
 
     // [ -t 0 ] == 0 means we have a terminal (PTY).
-    ExpectLinesEqual(ReadRaw(subprocess_fd_), {"foo", "bar", "0"});
+    ExpectLinesEqual(ReadRaw(command_fd_), {"foo", "bar", "0"});
 }
 
 // Tests a raw subprocess with the shell protocol.
@@ -175,7 +179,7 @@
             SubprocessType::kRaw, SubprocessProtocol::kShell));
 
     std::string stdout, stderr;
-    EXPECT_EQ(24, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+    EXPECT_EQ(24, ReadShellProtocol(command_fd_, &stdout, &stderr));
     ExpectLinesEqual(stdout, {"foo", "baz"});
     ExpectLinesEqual(stderr, {"bar"});
 }
@@ -189,7 +193,7 @@
     // PTY always combines stdout and stderr but the shell protocol should
     // still give us an exit code.
     std::string stdout, stderr;
-    EXPECT_EQ(50, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+    EXPECT_EQ(50, ReadShellProtocol(command_fd_, &stdout, &stderr));
     ExpectLinesEqual(stdout, {"foo", "bar", "baz"});
     ExpectLinesEqual(stderr, {});
 }
@@ -204,7 +208,7 @@
                               "echo --${TEST_STR}--",
                               "exit"};
 
-    ShellProtocol* protocol = new ShellProtocol(subprocess_fd_);
+    ShellProtocol* protocol = new ShellProtocol(command_fd_);
     for (std::string command : commands) {
         // Interactive shell requires a newline to complete each command.
         command.push_back('\n');
@@ -214,7 +218,7 @@
     delete protocol;
 
     std::string stdout, stderr;
-    EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+    EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr));
     // An unpredictable command prompt makes parsing exact output difficult but
     // it should at least contain echoed input and the expected output.
     for (const char* command : commands) {
@@ -230,14 +234,14 @@
             SubprocessType::kRaw, SubprocessProtocol::kShell));
 
     std::string input = "foo\nbar";
-    ShellProtocol* protocol = new ShellProtocol(subprocess_fd_);
+    ShellProtocol* protocol = new ShellProtocol(command_fd_);
     memcpy(protocol->data(), input.data(), input.length());
     ASSERT_TRUE(protocol->Write(ShellProtocol::kIdStdin, input.length()));
     ASSERT_TRUE(protocol->Write(ShellProtocol::kIdCloseStdin, 0));
     delete protocol;
 
     std::string stdout, stderr;
-    EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+    EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr));
     ExpectLinesEqual(stdout, {"foo", "barTEST_DONE"});
     ExpectLinesEqual(stderr, {});
 }
@@ -249,7 +253,7 @@
             SubprocessType::kRaw, SubprocessProtocol::kShell));
 
     std::string stdout, stderr;
-    EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+    EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr));
     ExpectLinesEqual(stdout, {});
     ExpectLinesEqual(stderr, {"bar"});
 }
@@ -261,7 +265,56 @@
             SubprocessType::kRaw, SubprocessProtocol::kShell));
 
     std::string stdout, stderr;
-    EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+    EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr));
     ExpectLinesEqual(stdout, {"foo"});
     ExpectLinesEqual(stderr, {});
 }
+
+// Tests an inprocess command with no protocol.
+TEST_F(ShellServiceTest, RawNoProtocolInprocess) {
+    ASSERT_NO_FATAL_FAILURE(
+            StartTestCommandInProcess("123",
+                                      [](auto args, auto in, auto out, auto err) -> int {
+                                          EXPECT_EQ("123", args);
+                                          char input[10];
+                                          EXPECT_TRUE(ReadFdExactly(in, input, 2));
+                                          input[2] = 0;
+                                          EXPECT_STREQ("in", input);
+                                          WriteFdExactly(out, "out\n");
+                                          WriteFdExactly(err, "err\n");
+                                          return 0;
+                                      },
+                                      SubprocessProtocol::kNone));
+
+    WriteFdExactly(command_fd_, "in");
+    ExpectLinesEqual(ReadRaw(command_fd_), {"out", "err"});
+}
+
+// Tests an inprocess command with the shell protocol.
+TEST_F(ShellServiceTest, RawShellProtocolInprocess) {
+    ASSERT_NO_FATAL_FAILURE(
+            StartTestCommandInProcess("321",
+                                      [](auto args, auto in, auto out, auto err) -> int {
+                                          EXPECT_EQ("321", args);
+                                          char input[10];
+                                          EXPECT_TRUE(ReadFdExactly(in, input, 2));
+                                          input[2] = 0;
+                                          EXPECT_STREQ("in", input);
+                                          WriteFdExactly(out, "out\n");
+                                          WriteFdExactly(err, "err\n");
+                                          return 0;
+                                      },
+                                      SubprocessProtocol::kShell));
+
+    {
+        auto write_protocol = std::make_unique<ShellProtocol>(command_fd_);
+        memcpy(write_protocol->data(), "in", 2);
+        write_protocol->Write(ShellProtocol::kIdStdin, 2);
+    }
+
+    std::string stdout, stderr;
+    // For in-process commands the exit code is always the default (1).
+    EXPECT_EQ(1, ReadShellProtocol(command_fd_, &stdout, &stderr));
+    ExpectLinesEqual(stdout, {"out"});
+    ExpectLinesEqual(stderr, {"err"});
+}
diff --git a/adb/types.h b/adb/types.h
index 0090c98..cd1366d 100644
--- a/adb/types.h
+++ b/adb/types.h
@@ -216,7 +216,10 @@
     // Add a nonempty block to the chain.
     // The end of the chain must be a complete block (i.e. end_offset_ == 0).
     void append(std::unique_ptr<const block_type> block) {
-        CHECK_NE(0ULL, block->size());
+        if (block->size() == 0) {
+            return;
+        }
+
         CHECK_EQ(0ULL, end_offset_);
         chain_length_ += block->size();
         chain_.emplace_back(std::move(block));
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 437450c..82ba0a1 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -48,6 +48,7 @@
 #define ATRACE_TAG ATRACE_TAG_BIONIC
 #include <utils/Trace.h>
 
+#include <unwindstack/DexFiles.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
@@ -566,7 +567,7 @@
 
   // TODO: Use seccomp to lock ourselves down.
   unwindstack::UnwinderFromPid unwinder(256, vm_pid);
-  if (!unwinder.Init()) {
+  if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
     LOG(FATAL) << "Failed to init unwinder object.";
   }
 
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index 5f7ebc3..bbec612 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -42,6 +42,7 @@
 #include <android-base/file.h>
 #include <android-base/unique_fd.h>
 #include <async_safe/log.h>
+#include <unwindstack/DexFiles.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
@@ -80,12 +81,12 @@
     thread.pid = getpid();
     thread.tid = gettid();
     thread.thread_name = get_thread_name(gettid());
-    thread.registers.reset(
-        unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
+    unwindstack::ArchEnum arch = unwindstack::Regs::CurrentArch();
+    thread.registers.reset(unwindstack::Regs::CreateFromUcontext(arch, ucontext));
 
     // TODO: Create this once and store it in a global?
     unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid());
-    if (unwinder.Init()) {
+    if (unwinder.Init(arch)) {
       dump_backtrace_thread(output_fd, &unwinder, thread);
     } else {
       async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Unable to init unwinder.");
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 7c5304e..238c00c 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -18,6 +18,7 @@
 #ifndef _DEBUGGERD_UTILITY_H
 #define _DEBUGGERD_UTILITY_H
 
+#include <inttypes.h>
 #include <signal.h>
 #include <stdbool.h>
 #include <sys/types.h>
@@ -25,7 +26,6 @@
 #include <string>
 
 #include <android-base/macros.h>
-#include <backtrace/Backtrace.h>
 
 struct log_t {
   // Tombstone file descriptor.
@@ -61,6 +61,14 @@
   OPEN_FILES
 };
 
+#if defined(__LP64__)
+#define PRIPTR "016" PRIx64
+typedef uint64_t word_t;
+#else
+#define PRIPTR "08" PRIx64
+typedef uint32_t word_t;
+#endif
+
 // Log information onto the tombstone.
 void _LOG(log_t* log, logtype ltype, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
 
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index eed5bd3..3196ce8 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <stdlib.h>
+#include <sys/mman.h>
 #include <time.h>
 
 #include <memory>
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 4bdb9c8..cc337ed 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -27,6 +27,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/mman.h>
 #include <sys/ptrace.h>
 #include <sys/stat.h>
 #include <time.h>
@@ -44,6 +45,7 @@
 #include <log/log.h>
 #include <log/logprint.h>
 #include <private/android_filesystem_config.h>
+#include <unwindstack/DexFiles.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
@@ -649,7 +651,7 @@
   };
 
   unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid);
-  if (!unwinder.Init()) {
+  if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
     LOG(FATAL) << "Failed to init unwinder object.";
   }
 
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index d0c5234..7aebea8 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -35,7 +35,6 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
-#include <backtrace/Backtrace.h>
 #include <debuggerd/handler.h>
 #include <log/log.h>
 #include <unwindstack/Memory.h>
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index 82d5cc9..ff918a7 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -201,18 +201,28 @@
     ASSERT_TRUE(UserSpaceFastboot());
     std::string has_slot;
     EXPECT_EQ(fb->GetVar("has-slot:system", &has_slot), SUCCESS) << "getvar has-slot:system failed";
-    std::string is_logical_cmd;
+    std::string is_logical_cmd_system = "is-logical:system";
+    std::string is_logical_cmd_vendor = "is-logical:vendor";
+    std::string is_logical_cmd_boot = "is-logical:boot";
     if (has_slot == "yes") {
         std::string current_slot;
-        EXPECT_EQ(fb->GetVar("current-slot", &current_slot), SUCCESS)
+        ASSERT_EQ(fb->GetVar("current-slot", &current_slot), SUCCESS)
                 << "getvar current-slot failed";
-        is_logical_cmd = "is-logical:system_" + current_slot;
-    } else {
-        is_logical_cmd = "is-logical:system";
+        std::string slot_suffix = "_" + current_slot;
+        is_logical_cmd_system += slot_suffix;
+        is_logical_cmd_vendor += slot_suffix;
+        is_logical_cmd_boot += slot_suffix;
     }
     std::string is_logical;
-    EXPECT_EQ(fb->GetVar(is_logical_cmd, &is_logical), SUCCESS) << "getvar is-logical failed";
-    ASSERT_EQ(is_logical, "yes");
+    EXPECT_EQ(fb->GetVar(is_logical_cmd_system, &is_logical), SUCCESS)
+            << "system must be a logical partition";
+    EXPECT_EQ(is_logical, "yes");
+    EXPECT_EQ(fb->GetVar(is_logical_cmd_vendor, &is_logical), SUCCESS)
+            << "vendor must be a logical partition";
+    EXPECT_EQ(is_logical, "yes");
+    EXPECT_EQ(fb->GetVar(is_logical_cmd_boot, &is_logical), SUCCESS)
+            << "boot must not be logical partition";
+    EXPECT_EQ(is_logical, "no");
 }
 
 TEST_F(LogicalPartitionCompliance, FastbootRebootTest) {
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index f6f6f50..4043fc6 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -754,14 +754,15 @@
 
 FstabEntry BuildGsiSystemFstabEntry() {
     // .logical_partition_name is required to look up AVB Hashtree descriptors.
-    FstabEntry system = {.blk_device = "system_gsi",
-                         .mount_point = "/system",
-                         .fs_type = "ext4",
-                         .flags = MS_RDONLY,
-                         .fs_options = "barrier=1",
-                         // could add more keys separated by ':'.
-                         .avb_keys = "/avb/gsi.avbpubkey:",
-                         .logical_partition_name = "system"};
+    FstabEntry system = {
+            .blk_device = "system_gsi",
+            .mount_point = "/system",
+            .fs_type = "ext4",
+            .flags = MS_RDONLY,
+            .fs_options = "barrier=1",
+            // could add more keys separated by ':'.
+            .avb_keys = "/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey",
+            .logical_partition_name = "system"};
     system.fs_mgr_flags.wait = true;
     system.fs_mgr_flags.logical = true;
     system.fs_mgr_flags.first_stage_mount = true;
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index dea4844..4ac78e1 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -612,7 +612,9 @@
         if (!dm.GetDmDevicePathByName(partition_name, &path)) {
             // non-DAP A/B device?
             if (fs_mgr_access(super_device)) return "";
-            path = kPhysicalDevice + "system" + (slot_number ? "_a" : "_b");
+            auto other_slot = fs_mgr_get_other_slot_suffix();
+            if (other_slot.empty()) return "";
+            path = kPhysicalDevice + "system" + other_slot;
         }
     }
     return scratch_device_cache = path;
@@ -715,7 +717,7 @@
     }
 
     if (changed || partition_create) {
-        if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
+        if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 10s,
                                     scratch_device))
             return false;
 
@@ -940,7 +942,7 @@
             auto slot_number = fs_mgr_overlayfs_slot_number();
             auto super_device = fs_mgr_overlayfs_super_device(slot_number);
             const auto partition_name = android::base::Basename(kScratchMountPoint);
-            CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
+            CreateLogicalPartition(super_device, slot_number, partition_name, true, 10s,
                                    &scratch_device);
         }
         mount_scratch = fs_mgr_overlayfs_mount_scratch(scratch_device,
diff --git a/fs_mgr/libfiemap_writer/Android.mk b/fs_mgr/libfiemap_writer/Android.mk
new file mode 100644
index 0000000..3c07b8e
--- /dev/null
+++ b/fs_mgr/libfiemap_writer/Android.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2019 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsFiemapWriterTest
+-include test/vts/tools/build/Android.host_config.mk
diff --git a/fs_mgr/libfiemap_writer/AndroidTest.xml b/fs_mgr/libfiemap_writer/AndroidTest.xml
new file mode 100644
index 0000000..08cff0e
--- /dev/null
+++ b/fs_mgr/libfiemap_writer/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for VTS VtsFiemapWriterTest">
+    <option name="config-descriptor:metadata" key="plan" value="vts-kernel" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+        <option name="abort-on-push-failure" value="false"/>
+        <option name="push-group" value="HostDrivenTest.push"/>
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+      <option name="test-module-name" value="VtsFiemapWriterTest"/>
+        <option name="binary-test-source" value="_32bit::DATA/nativetest/fiemap_writer_test/fiemap_writer_test" />
+        <option name="binary-test-source" value="_64bit::DATA/nativetest64/fiemap_writer_test/fiemap_writer_test" />
+        <option name="binary-test-type" value="gtest"/>
+        <option name="test-timeout" value="1m"/>
+    </test>
+</configuration>
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
index ca51689..dda7dfd 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
@@ -498,17 +498,22 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
-    if (argc <= 1) {
-        cerr << "Usage: <test_dir> [file_size]\n";
+    if (argc > 1 && argv[1] == "-h"s) {
+        cerr << "Usage: [test_dir] [file_size]\n";
         cerr << "\n";
         cerr << "Note: test_dir must be a writable, unencrypted directory.\n";
         exit(EXIT_FAILURE);
     }
     ::android::base::InitLogging(argv, ::android::base::StderrLogger);
 
-    std::string tempdir = argv[1] + "/XXXXXX"s;
+    std::string root_dir = "/data/local/unencrypted";
+    if (access(root_dir.c_str(), F_OK)) {
+        root_dir = "/data";
+    }
+
+    std::string tempdir = root_dir + "/XXXXXX"s;
     if (!mkdtemp(tempdir.data())) {
-        cerr << "unable to create tempdir on " << argv[1] << "\n";
+        cerr << "unable to create tempdir on " << root_dir << "\n";
         exit(EXIT_FAILURE);
     }
     if (!android::base::Realpath(tempdir, &gTestDir)) {
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index 56b5353..db27022 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -98,11 +98,12 @@
     return WriteToImageFile(fd, input);
 }
 
-SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
-                             const std::map<std::string, std::string>& images)
+ImageBuilder::ImageBuilder(const LpMetadata& metadata, uint32_t block_size,
+                           const std::map<std::string, std::string>& images, bool sparsify)
     : metadata_(metadata),
       geometry_(metadata.geometry),
       block_size_(block_size),
+      sparsify_(sparsify),
       images_(images) {
     uint64_t total_size = GetTotalSuperPartitionSize(metadata);
     if (block_size % LP_SECTOR_SIZE != 0) {
@@ -144,11 +145,11 @@
     }
 }
 
-bool SparseBuilder::IsValid() const {
+bool ImageBuilder::IsValid() const {
     return device_images_.size() == metadata_.block_devices.size();
 }
 
-bool SparseBuilder::Export(const char* file) {
+bool ImageBuilder::Export(const char* file) {
     unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644));
     if (fd < 0) {
         PERROR << "open failed: " << file;
@@ -158,8 +159,8 @@
         LERROR << "Cannot export to a single image on retrofit builds.";
         return false;
     }
-    // No gzip compression; sparseify; no checksum.
-    int ret = sparse_file_write(device_images_[0].get(), fd, false, true, false);
+    // No gzip compression; no checksum.
+    int ret = sparse_file_write(device_images_[0].get(), fd, false, sparsify_, false);
     if (ret != 0) {
         LERROR << "sparse_file_write failed (error code " << ret << ")";
         return false;
@@ -167,7 +168,7 @@
     return true;
 }
 
-bool SparseBuilder::ExportFiles(const std::string& output_dir) {
+bool ImageBuilder::ExportFiles(const std::string& output_dir) {
     for (size_t i = 0; i < device_images_.size(); i++) {
         std::string name = GetBlockDevicePartitionName(metadata_.block_devices[i]);
         std::string file_name = "super_" + name + ".img";
@@ -179,8 +180,8 @@
             PERROR << "open failed: " << file_path;
             return false;
         }
-        // No gzip compression; sparseify; no checksum.
-        int ret = sparse_file_write(device_images_[i].get(), fd, false, true, false);
+        // No gzip compression; no checksum.
+        int ret = sparse_file_write(device_images_[i].get(), fd, false, sparsify_, false);
         if (ret != 0) {
             LERROR << "sparse_file_write failed (error code " << ret << ")";
             return false;
@@ -189,7 +190,7 @@
     return true;
 }
 
-bool SparseBuilder::AddData(sparse_file* file, const std::string& blob, uint64_t sector) {
+bool ImageBuilder::AddData(sparse_file* file, const std::string& blob, uint64_t sector) {
     uint32_t block;
     if (!SectorToBlock(sector, &block)) {
         return false;
@@ -203,7 +204,7 @@
     return true;
 }
 
-bool SparseBuilder::SectorToBlock(uint64_t sector, uint32_t* block) {
+bool ImageBuilder::SectorToBlock(uint64_t sector, uint32_t* block) {
     // The caller must ensure that the metadata has an alignment that is a
     // multiple of the block size. liblp will take care of the rest, ensuring
     // that all partitions are on an aligned boundary. Therefore all writes
@@ -218,11 +219,11 @@
     return true;
 }
 
-uint64_t SparseBuilder::BlockToSector(uint64_t block) const {
+uint64_t ImageBuilder::BlockToSector(uint64_t block) const {
     return (block * block_size_) / LP_SECTOR_SIZE;
 }
 
-bool SparseBuilder::Build() {
+bool ImageBuilder::Build() {
     if (sparse_file_add_fill(device_images_[0].get(), 0, LP_PARTITION_RESERVED_BYTES, 0) < 0) {
         LERROR << "Could not add initial sparse block for reserved zeroes";
         return false;
@@ -275,8 +276,8 @@
     return true;
 }
 
-bool SparseBuilder::AddPartitionImage(const LpMetadataPartition& partition,
-                                      const std::string& file) {
+bool ImageBuilder::AddPartitionImage(const LpMetadataPartition& partition,
+                                     const std::string& file) {
     // Track which extent we're processing.
     uint32_t extent_index = partition.first_extent_index;
 
@@ -371,7 +372,7 @@
     return true;
 }
 
-uint64_t SparseBuilder::ComputePartitionSize(const LpMetadataPartition& partition) const {
+uint64_t ImageBuilder::ComputePartitionSize(const LpMetadataPartition& partition) const {
     uint64_t sectors = 0;
     for (size_t i = 0; i < partition.num_extents; i++) {
         sectors += metadata_.extents[partition.first_extent_index + i].num_sectors;
@@ -386,7 +387,7 @@
 //
 // Without this, it would be more difficult to find the appropriate extent for
 // an output block. With this guarantee it is a linear walk.
-bool SparseBuilder::CheckExtentOrdering() {
+bool ImageBuilder::CheckExtentOrdering() {
     std::vector<uint64_t> last_sectors(metadata_.block_devices.size());
 
     for (const auto& extent : metadata_.extents) {
@@ -407,7 +408,7 @@
     return true;
 }
 
-int SparseBuilder::OpenImageFile(const std::string& file) {
+int ImageBuilder::OpenImageFile(const std::string& file) {
     android::base::unique_fd source_fd = GetControlFileOrOpen(file.c_str(), O_RDONLY | O_CLOEXEC);
     if (source_fd < 0) {
         PERROR << "open image file failed: " << file;
@@ -437,15 +438,16 @@
     return temp_fds_.back().get();
 }
 
-bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
-                       const std::map<std::string, std::string>& images) {
-    SparseBuilder builder(metadata, block_size, images);
+bool WriteToImageFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
+                      const std::map<std::string, std::string>& images, bool sparsify) {
+    ImageBuilder builder(metadata, block_size, images, sparsify);
     return builder.IsValid() && builder.Build() && builder.Export(file);
 }
 
-bool WriteSplitSparseFiles(const std::string& output_dir, const LpMetadata& metadata,
-                           uint32_t block_size, const std::map<std::string, std::string>& images) {
-    SparseBuilder builder(metadata, block_size, images);
+bool WriteSplitImageFiles(const std::string& output_dir, const LpMetadata& metadata,
+                          uint32_t block_size, const std::map<std::string, std::string>& images,
+                          bool sparsify) {
+    ImageBuilder builder(metadata, block_size, images, sparsify);
     return builder.IsValid() && builder.Build() && builder.ExportFiles(output_dir);
 }
 
diff --git a/fs_mgr/liblp/images.h b/fs_mgr/liblp/images.h
index 44217a0..75060f9 100644
--- a/fs_mgr/liblp/images.h
+++ b/fs_mgr/liblp/images.h
@@ -32,13 +32,13 @@
 bool WriteToImageFile(const char* file, const LpMetadata& metadata);
 bool WriteToImageFile(int fd, const LpMetadata& metadata);
 
-// We use an object to build the sparse file since it requires that data
+// We use an object to build the image file since it requires that data
 // pointers be held alive until the sparse file is destroyed. It's easier
 // to do this when the data pointers are all in one place.
-class SparseBuilder {
+class ImageBuilder {
   public:
-    SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
-                  const std::map<std::string, std::string>& images);
+    ImageBuilder(const LpMetadata& metadata, uint32_t block_size,
+                 const std::map<std::string, std::string>& images, bool sparsify);
 
     bool Build();
     bool Export(const char* file);
@@ -60,6 +60,7 @@
     const LpMetadata& metadata_;
     const LpMetadataGeometry& geometry_;
     uint32_t block_size_;
+    bool sparsify_;
 
     std::vector<SparsePtr> device_images_;
     std::string all_metadata_;
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index 6348f55..5f782b0 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -72,8 +72,8 @@
 
 // Read/Write logical partition metadata to an image file, for diagnostics or
 // flashing.
-bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
-                       const std::map<std::string, std::string>& images);
+bool WriteToImageFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
+                      const std::map<std::string, std::string>& images, bool sparsify);
 bool WriteToImageFile(const char* file, const LpMetadata& metadata);
 std::unique_ptr<LpMetadata> ReadFromImageFile(const std::string& image_file);
 std::unique_ptr<LpMetadata> ReadFromImageBlob(const void* data, size_t bytes);
@@ -83,8 +83,9 @@
 // is intended for retrofit devices, and will generate one sparse file per
 // block device (each named super_<name>.img) and placed in the specified
 // output folder.
-bool WriteSplitSparseFiles(const std::string& output_dir, const LpMetadata& metadata,
-                           uint32_t block_size, const std::map<std::string, std::string>& images);
+bool WriteSplitImageFiles(const std::string& output_dir, const LpMetadata& metadata,
+                          uint32_t block_size, const std::map<std::string, std::string>& images,
+                          bool sparsify);
 
 // Helper to extract safe C++ strings from partition info.
 std::string GetPartitionName(const LpMetadataPartition& partition);
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 9f3314d..8fc02cb 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -598,7 +598,7 @@
     ASSERT_NE(exported, nullptr);
 
     // Build the sparse file.
-    SparseBuilder sparse(*exported.get(), 512, {});
+    ImageBuilder sparse(*exported.get(), 512, {}, true /* sparsify */);
     ASSERT_TRUE(sparse.IsValid());
     ASSERT_TRUE(sparse.Build());
 
diff --git a/fs_mgr/tests/adb-remount-sh.xml b/fs_mgr/tests/adb-remount-sh.xml
index 716e324..fa0d63f 100644
--- a/fs_mgr/tests/adb-remount-sh.xml
+++ b/fs_mgr/tests/adb-remount-sh.xml
@@ -18,6 +18,8 @@
     <!-- This test requires a device, so it's not annotated with a null-device -->
     <test class="com.android.tradefed.testtype.binary.ExecutableHostTest" >
         <option name="binary" value="adb-remount-test.sh" />
+        <!-- Increase default timeout as script is quite long -->
+        <option name="per-binary-timeout" value="1h" />
     </test>
 </configuration>
 
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 0e5aa4f..edf34f7 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -78,6 +78,7 @@
 #define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
 #define UNPLUGGED_DISPLAY_TIME (3 * MSEC_PER_SEC)
 #define MAX_BATT_LEVEL_WAIT_TIME (3 * MSEC_PER_SEC)
+#define UNPLUGGED_SHUTDOWN_TIME_PROP "ro.product.charger.unplugged_shutdown_time"
 
 #define LAST_KMSG_MAX_SZ (32 * 1024)
 
@@ -513,6 +514,7 @@
 }
 
 static void handle_power_supply_state(charger* charger, int64_t now) {
+    int timer_shutdown = UNPLUGGED_SHUTDOWN_TIME;
     if (!charger->have_battery_state) return;
 
     if (!charger->charger_connected) {
@@ -525,12 +527,14 @@
              * Reset & kick animation to show complete animation cycles
              * when charger disconnected.
              */
+            timer_shutdown =
+                    property_get_int32(UNPLUGGED_SHUTDOWN_TIME_PROP, UNPLUGGED_SHUTDOWN_TIME);
             charger->next_screen_transition = now - 1;
             reset_animation(charger->batt_anim);
             kick_animation(charger->batt_anim);
-            charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
+            charger->next_pwr_check = now + timer_shutdown;
             LOGW("[%" PRId64 "] device unplugged: shutting down in %" PRId64 " (@ %" PRId64 ")\n",
-                 now, (int64_t)UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
+                 now, (int64_t)timer_shutdown, charger->next_pwr_check);
         } else if (now >= charger->next_pwr_check) {
             LOGW("[%" PRId64 "] shutting down\n", now);
             reboot(RB_POWER_OFF);
diff --git a/init/README.md b/init/README.md
index d86f077..aadf11d 100644
--- a/init/README.md
+++ b/init/README.md
@@ -57,7 +57,7 @@
 The intention of these directories is:
 
    1. /system/etc/init/ is for core system items such as
-      SurfaceFlinger, MediaService, and logcatd.
+      SurfaceFlinger, MediaService, and logd.
    2. /vendor/etc/init/ is for SoC vendor items such as actions or
       daemons needed for core SoC functionality.
    3. /odm/etc/init/ is for device manufacturer items such as
@@ -72,7 +72,7 @@
 init .rc file should additionally contain any actions associated with
 its service.
 
-An example is the logcatd.rc and Android.mk files located in the
+An example is the userdebug logcatd.rc and Android.mk files located in the
 system/core/logcat directory.  The LOCAL\_INIT\_RC macro in the
 Android.mk file places logcatd.rc in /system/etc/init/ during the
 build process.  Init loads logcatd.rc during the mount\_all command and
@@ -317,7 +317,7 @@
   See the below section on debugging for how this can be used.
 
 `socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]`
-> Create a unix domain socket named /dev/socket/_name_ and pass its fd to the
+> Create a UNIX domain socket named /dev/socket/_name_ and pass its fd to the
   launched process.  _type_ must be "dgram", "stream" or "seqpacket".  User and
   group default to 0.  'seclabel' is the SELinux security context for the
   socket.  It defaults to the service security context, as specified by
@@ -506,10 +506,10 @@
 > Attempt to mount the named device at the directory _dir_
   _flag_s include "ro", "rw", "remount", "noatime", ...
   _options_ include "barrier=1", "noauto\_da\_alloc", "discard", ... as
-  a comma separated string, eg: barrier=1,noauto\_da\_alloc
+  a comma separated string, e.g. barrier=1,noauto\_da\_alloc
 
 `parse_apex_configs`
-> Parses config file(s) from the mounted APEXes. Intented to be used only once
+> Parses config file(s) from the mounted APEXes. Intended to be used only once
   when apexd notifies the mount event by setting apexd.status to ready.
 
 `restart <service>`
@@ -572,7 +572,7 @@
 `symlink <target> <path>`
 > Create a symbolic link at _path_ with the value _target_
 
-`sysclktz <mins_west_of_gmt>`
+`sysclktz <minutes_west_of_gmt>`
 > Set the system clock base (0 if system clock ticks in GMT)
 
 `trigger <event>`
@@ -635,7 +635,7 @@
 earlier executed trigger, or 2) place it in an Action with the same
 trigger within the same file at an earlier line.
 
-Nonetheless, the defacto order for first stage mount devices is:
+Nonetheless, the de facto order for first stage mount devices is:
 1. /init.rc is parsed then recursively each of its imports are
    parsed.
 2. The contents of /system/etc/init/ are alphabetized and parsed
@@ -725,7 +725,7 @@
 A handy script named compare-bootcharts.py can be used to compare the
 start/end time of selected processes. The aforementioned grab-bootchart.sh
 will leave a bootchart tarball named bootchart.tgz at /tmp/android-bootchart.
-If two such barballs are preserved on the host machine under different
+If two such tarballs are preserved on the host machine under different
 directories, the script can list the timestamps differences. For example:
 
 Usage: system/core/init/compare-bootcharts.py _base-bootchart-dir_ _exp-bootchart-dir_
@@ -773,7 +773,7 @@
 This option will send SIGSTOP to a service immediately before calling exec. This gives a window
 where developers can attach a debugger, strace, etc before continuing the service with SIGCONT.
 
-This flag can also be dynamically controled via the ctl.sigstop_on and ctl.sigstop_off properties.
+This flag can also be dynamically controlled via the ctl.sigstop_on and ctl.sigstop_off properties.
 
 Below is an example of dynamically debugging logd via the above:
 
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index d458924..3900f72 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -80,7 +80,7 @@
     bool InitMappedDevice(const std::string& verity_device);
     bool InitDeviceMapper();
     bool CreateLogicalPartitions();
-    bool MountPartition(const Fstab::iterator& begin, bool erase_used_fstab_entry,
+    bool MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
                         Fstab::iterator* end = nullptr);
 
     bool MountPartitions();
@@ -437,21 +437,26 @@
 
     uevent_listener_.RegenerateUeventsForPath(syspath, verity_callback);
     if (!found) {
-        LOG(INFO) << "dm-verity device not found in /sys, waiting for its uevent";
+        LOG(INFO) << "dm device '" << dm_device << "' not found in /sys, waiting for its uevent";
         Timer t;
         uevent_listener_.Poll(verity_callback, 10s);
-        LOG(INFO) << "wait for dm-verity device returned after " << t;
+        LOG(INFO) << "wait for dm device '" << dm_device << "' returned after " << t;
     }
     if (!found) {
-        LOG(ERROR) << "dm-verity device not found after polling timeout";
+        LOG(ERROR) << "dm device '" << dm_device << "' not found after polling timeout";
         return false;
     }
 
     return true;
 }
 
-bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_used_fstab_entry,
+bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
                                      Fstab::iterator* end) {
+    // Sets end to begin + 1, so we can just return on failure below.
+    if (end) {
+        *end = begin + 1;
+    }
+
     if (begin->fs_mgr_flags.logical) {
         if (!fs_mgr_update_logical_partition(&(*begin))) {
             return false;
@@ -477,7 +482,7 @@
             mounted = (fs_mgr_do_mount_one(*current) == 0);
         }
     }
-    if (erase_used_fstab_entry) {
+    if (erase_same_mounts) {
         current = fstab_.erase(begin, current);
     }
     if (end) {
@@ -494,7 +499,7 @@
         return entry.mount_point == "/metadata";
     });
     if (metadata_partition != fstab_.end()) {
-        if (MountPartition(metadata_partition, true /* erase_used_fstab_entry */)) {
+        if (MountPartition(metadata_partition, true /* erase_same_mounts */)) {
             UseGsiIfPresent();
         }
     }
@@ -505,7 +510,7 @@
 
     if (system_partition == fstab_.end()) return true;
 
-    if (MountPartition(system_partition, false)) {
+    if (MountPartition(system_partition, false /* erase_same_mounts */)) {
         if (gsi_not_on_userdata_ && fs_mgr_verity_is_check_at_most_once(*system_partition)) {
             LOG(ERROR) << "check_most_at_once forbidden on external media";
             return false;
@@ -560,7 +565,7 @@
         }
 
         Fstab::iterator end;
-        if (!MountPartition(current, false, &end)) {
+        if (!MountPartition(current, false /* erase_same_mounts */, &end)) {
             if (current->fs_mgr_flags.no_fail) {
                 LOG(INFO) << "Failed to mount " << current->mount_point
                           << ", ignoring mount for no_fail partition";
@@ -797,11 +802,9 @@
 bool FirstStageMountVBootV2::SetUpDmVerity(FstabEntry* fstab_entry) {
     AvbHashtreeResult hashtree_result;
 
-    if (fstab_entry->fs_mgr_flags.avb) {
-        if (!InitAvbHandle()) return false;
-        hashtree_result =
-                avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
-    } else if (!fstab_entry->avb_keys.empty()) {
+    // It's possible for a fstab_entry to have both avb_keys and avb flag.
+    // In this case, try avb_keys first, then fallback to avb flag.
+    if (!fstab_entry->avb_keys.empty()) {
         if (!InitAvbHandle()) return false;
         // Checks if hashtree should be disabled from the top-level /vbmeta.
         if (avb_handle_->status() == AvbHandleStatus::kHashtreeDisabled ||
@@ -813,14 +816,24 @@
             auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(*fstab_entry);
             if (!avb_standalone_handle) {
                 LOG(ERROR) << "Failed to load offline vbmeta for " << fstab_entry->mount_point;
-                return false;
+                // Fallbacks to built-in hashtree if fs_mgr_flags.avb is set.
+                if (!fstab_entry->fs_mgr_flags.avb) return false;
+                LOG(INFO) << "Fallback to built-in hashtree for " << fstab_entry->mount_point;
+                hashtree_result =
+                        avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
+            } else {
+                // Sets up hashtree via the standalone handle.
+                if (IsStandaloneImageRollback(*avb_handle_, *avb_standalone_handle, *fstab_entry)) {
+                    return false;
+                }
+                hashtree_result = avb_standalone_handle->SetUpAvbHashtree(
+                        fstab_entry, false /* wait_for_verity_dev */);
             }
-            if (IsStandaloneImageRollback(*avb_handle_, *avb_standalone_handle, *fstab_entry)) {
-                return false;
-            }
-            hashtree_result = avb_standalone_handle->SetUpAvbHashtree(
-                    fstab_entry, false /* wait_for_verity_dev */);
         }
+    } else if (fstab_entry->fs_mgr_flags.avb) {
+        if (!InitAvbHandle()) return false;
+        hashtree_result =
+                avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
     } else {
         return true;  // No need AVB, returns true to mount the partition directly.
     }
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index ff19833..f5f9b2a 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -32,6 +32,9 @@
 #include <unwindstack/Regs.h>
 #include <unwindstack/RegsGetLocal.h>
 
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <unwindstack/DexFiles.h>
+#endif
 #include <unwindstack/Unwinder.h>
 
 #include "BacktraceLog.h"
@@ -47,6 +50,14 @@
                                  regs, stack_map->process_memory());
   unwinder.SetResolveNames(stack_map->ResolveNames());
   stack_map->SetArch(regs->Arch());
+  if (stack_map->GetJitDebug() != nullptr) {
+    unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
+  }
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  if (stack_map->GetDexFiles() != nullptr) {
+    unwinder.SetDexFiles(stack_map->GetDexFiles(), regs->Arch());
+  }
+#endif
   unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore());
   if (error != nullptr) {
     switch (unwinder.LastErrorCode()) {
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 726fdfa..4518891 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -43,6 +43,13 @@
   // Create the process memory object.
   process_memory_ = unwindstack::Memory::CreateProcessMemory(pid_);
 
+  // Create a JitDebug object for getting jit unwind information.
+  std::vector<std::string> search_libs_{"libart.so", "libartd.so"};
+  jit_debug_.reset(new unwindstack::JitDebug(process_memory_, search_libs_));
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  dex_files_.reset(new unwindstack::DexFiles(process_memory_, search_libs_));
+#endif
+
   if (!stack_maps_->Parse()) {
     return false;
   }
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index 9bb9709..e19b605 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -27,6 +27,9 @@
 
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <unwindstack/DexFiles.h>
+#endif
 #include <unwindstack/Elf.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
@@ -50,6 +53,12 @@
 
   const std::shared_ptr<unwindstack::Memory>& process_memory() { return process_memory_; }
 
+  unwindstack::JitDebug* GetJitDebug() { return jit_debug_.get(); }
+
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  unwindstack::DexFiles* GetDexFiles() { return dex_files_.get(); }
+#endif
+
   void SetArch(unwindstack::ArchEnum arch) { arch_ = arch; }
 
  protected:
@@ -57,6 +66,11 @@
 
   std::unique_ptr<unwindstack::Maps> stack_maps_;
   std::shared_ptr<unwindstack::Memory> process_memory_;
+  std::unique_ptr<unwindstack::JitDebug> jit_debug_;
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  std::unique_ptr<unwindstack::DexFiles> dex_files_;
+#endif
+
   unwindstack::ArchEnum arch_ = unwindstack::ARCH_UNKNOWN;
 };
 
diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp
index e35b91a..e67b458 100644
--- a/libcutils/ashmem-dev.cpp
+++ b/libcutils/ashmem-dev.cpp
@@ -73,6 +73,8 @@
 #ifndef __ANDROID_VNDK__
 using openFdType = int (*)();
 
+static openFdType openFd;
+
 openFdType initOpenAshmemFd() {
     openFdType openFd = nullptr;
     void* handle = dlopen("libashmemd_client.so", RTLD_NOW);
@@ -221,7 +223,10 @@
 
     int fd = -1;
 #ifndef __ANDROID_VNDK__
-    static auto openFd = initOpenAshmemFd();
+    if (!openFd) {
+        openFd = initOpenAshmemFd();
+    }
+
     if (openFd) {
         fd = openFd();
     }
@@ -480,3 +485,11 @@
 
     return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL)));
 }
+
+void ashmem_init() {
+#ifndef __ANDROID_VNDK__
+    pthread_mutex_lock(&__ashmem_lock);
+    openFd = initOpenAshmemFd();
+    pthread_mutex_unlock(&__ashmem_lock);
+#endif  //__ANDROID_VNDK__
+}
diff --git a/libcutils/ashmem-host.cpp b/libcutils/ashmem-host.cpp
index bb990d5..32446d4 100644
--- a/libcutils/ashmem-host.cpp
+++ b/libcutils/ashmem-host.cpp
@@ -82,3 +82,5 @@
 
     return buf.st_size;
 }
+
+void ashmem_init() {}
diff --git a/libcutils/include/cutils/ashmem.h b/libcutils/include/cutils/ashmem.h
index d80caa6..abc5068 100644
--- a/libcutils/include/cutils/ashmem.h
+++ b/libcutils/include/cutils/ashmem.h
@@ -26,6 +26,7 @@
 int ashmem_pin_region(int fd, size_t offset, size_t len);
 int ashmem_unpin_region(int fd, size_t offset, size_t len);
 int ashmem_get_size_region(int fd);
+void ashmem_init();
 
 #ifdef __cplusplus
 }
diff --git a/libkeyutils/mini_keyctl_utils.cpp b/libkeyutils/mini_keyctl_utils.cpp
index 56afea4..b012a33 100644
--- a/libkeyutils/mini_keyctl_utils.cpp
+++ b/libkeyutils/mini_keyctl_utils.cpp
@@ -18,6 +18,7 @@
 
 #include <dirent.h>
 #include <errno.h>
+#include <error.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -29,7 +30,6 @@
 #include <vector>
 
 #include <android-base/file.h>
-#include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/properties.h>
 #include <android-base/strings.h>
@@ -47,22 +47,18 @@
 // kernel keyring, the id is looked up from /proc/keys. The keyring description may contain other
 // information in the descritption section depending on the key type, only the first word in the
 // keyring description is used for searching.
-static bool GetKeyringId(const std::string& keyring_desc, key_serial_t* keyring_id) {
-  if (!keyring_id) {
-    LOG(ERROR) << "keyring_id is null";
-    return false;
-  }
-
+static key_serial_t GetKeyringIdOrDie(const std::string& keyring_desc) {
   // If the keyring id is already a hex number, directly convert it to keyring id
-  if (android::base::ParseInt(keyring_desc.c_str(), keyring_id)) {
-    return true;
+  key_serial_t keyring_id;
+  if (android::base::ParseInt(keyring_desc.c_str(), &keyring_id)) {
+    return keyring_id;
   }
 
   // Only keys allowed by SELinux rules will be shown here.
   std::ifstream proc_keys_file("/proc/keys");
   if (!proc_keys_file.is_open()) {
-    PLOG(ERROR) << "Failed to open /proc/keys";
-    return false;
+    error(1, errno, "Failed to open /proc/keys");
+    return -1;
   }
 
   std::string line;
@@ -80,21 +76,19 @@
     if (key_type != "keyring" || key_desc_prefix != key_desc_pattern) {
       continue;
     }
-    *keyring_id = std::stoi(key_id, nullptr, 16);
-    return true;
+    if (!android::base::ParseInt(key_id.c_str(), &keyring_id)) {
+      error(1, 0, "Unexpected key format in /proc/keys");
+      return -1;
+    }
+    return keyring_id;
   }
-  return false;
+  return -1;
 }
 
 int Unlink(key_serial_t key, const std::string& keyring) {
-  key_serial_t keyring_id;
-  if (!GetKeyringId(keyring, &keyring_id)) {
-    LOG(ERROR) << "Can't find keyring " << keyring;
-    return 1;
-  }
-
+  key_serial_t keyring_id = GetKeyringIdOrDie(keyring);
   if (keyctl_unlink(key, keyring_id) < 0) {
-    PLOG(ERROR) << "Failed to unlink key 0x" << std::hex << key << " from keyring " << keyring_id;
+    error(1, errno, "Failed to unlink key %x from keyring %s", key, keyring.c_str());
     return 1;
   }
   return 0;
@@ -103,63 +97,49 @@
 int Add(const std::string& type, const std::string& desc, const std::string& data,
         const std::string& keyring) {
   if (data.size() > kMaxCertSize) {
-    LOG(ERROR) << "Certificate too large";
+    error(1, 0, "Certificate too large");
     return 1;
   }
 
-  key_serial_t keyring_id;
-  if (!GetKeyringId(keyring, &keyring_id)) {
-    LOG(ERROR) << "Can not find keyring id";
-    return 1;
-  }
-
+  key_serial_t keyring_id = GetKeyringIdOrDie(keyring);
   key_serial_t key = add_key(type.c_str(), desc.c_str(), data.c_str(), data.size(), keyring_id);
 
   if (key < 0) {
-    PLOG(ERROR) << "Failed to add key";
+    error(1, errno, "Failed to add key");
     return 1;
   }
 
-  LOG(INFO) << "Key " << desc << " added to " << keyring << " with key id: 0x" << std::hex << key;
+  std::cout << key << std::endl;
   return 0;
 }
 
 int Padd(const std::string& type, const std::string& desc, const std::string& keyring) {
-  key_serial_t keyring_id;
-  if (!GetKeyringId(keyring, &keyring_id)) {
-    LOG(ERROR) << "Can not find keyring id";
-    return 1;
-  }
+  key_serial_t keyring_id = GetKeyringIdOrDie(keyring);
 
   // read from stdin to get the certificates
   std::istreambuf_iterator<char> begin(std::cin), end;
   std::string data(begin, end);
 
   if (data.size() > kMaxCertSize) {
-    LOG(ERROR) << "Certificate too large";
+    error(1, 0, "Certificate too large");
     return 1;
   }
 
   key_serial_t key = add_key(type.c_str(), desc.c_str(), data.c_str(), data.size(), keyring_id);
 
   if (key < 0) {
-    PLOG(ERROR) << "Failed to add key";
+    error(1, errno, "Failed to add key");
     return 1;
   }
 
-  LOG(INFO) << "Key " << desc << " added to " << keyring << " with key id: 0x" << std::hex << key;
+  std::cout << key << std::endl;
   return 0;
 }
 
 int RestrictKeyring(const std::string& keyring) {
-  key_serial_t keyring_id;
-  if (!GetKeyringId(keyring, &keyring_id)) {
-    LOG(ERROR) << "Cannot find keyring id";
-    return 1;
-  }
-
+  key_serial_t keyring_id = GetKeyringIdOrDie(keyring);
   if (keyctl_restrict_keyring(keyring_id, nullptr, nullptr) < 0) {
-    PLOG(ERROR) << "Cannot restrict keyring " << keyring;
+    error(1, errno, "Cannot restrict keyring '%s'", keyring.c_str());
     return 1;
   }
   return 0;
@@ -172,11 +152,11 @@
   context.resize(kMaxSupportedSize);
   long retval = keyctl_get_security(key, context.data(), kMaxSupportedSize);
   if (retval < 0) {
-    PLOG(ERROR) << "Cannot get security context of key 0x" << std::hex << key;
+    error(1, errno, "Cannot get security context of key %x", key);
     return std::string();
   }
   if (retval > kMaxSupportedSize) {
-    LOG(ERROR) << "The key has unexpectedly long security context than " << kMaxSupportedSize;
+    error(1, 0, "The key has unexpectedly long security context than %d", kMaxSupportedSize);
     return std::string();
   }
   context.resize(retval);
diff --git a/libmeminfo/tools/procrank.cpp b/libmeminfo/tools/procrank.cpp
index 21a684c..5e89254 100644
--- a/libmeminfo/tools/procrank.cpp
+++ b/libmeminfo/tools/procrank.cpp
@@ -14,11 +14,17 @@
  * limitations under the License.
  */
 
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <dirent.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <linux/kernel-page-flags.h>
 #include <linux/oom.h>
+#include <meminfo/procmeminfo.h>
+#include <meminfo/sysmeminfo.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
@@ -29,14 +35,6 @@
 #include <sstream>
 #include <vector>
 
-#include <android-base/file.h>
-#include <android-base/parseint.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#include <meminfo/procmeminfo.h>
-#include <meminfo/sysmeminfo.h>
-
 using ::android::meminfo::MemUsage;
 using ::android::meminfo::ProcMemInfo;
 
@@ -460,8 +458,16 @@
     auto mark_swap_usage = [&](pid_t pid) -> bool {
         ProcessRecord proc(pid, show_wss, pgflags, pgflags_mask);
         if (!proc.valid()) {
-            std::cerr << "Failed to create process record for: " << pid << std::endl;
-            return false;
+            // Check to see if the process is still around, skip the process if the proc
+            // directory is inaccessible. It was most likely killed while creating the process
+            // record
+            std::string procdir = ::android::base::StringPrintf("/proc/%d", pid);
+            if (access(procdir.c_str(), F_OK | R_OK)) return true;
+
+            // Warn if we failed to gather process stats even while it is still alive.
+            // Return success here, so we continue to print stats for other processes.
+            std::cerr << "warning: failed to create process record for: " << pid << std::endl;
+            return true;
         }
 
         // Skip processes with no memory mappings
@@ -479,9 +485,9 @@
         return true;
     };
 
-    // Get a list of all pids currently running in the system in
-    // 1st pass through all processes. Mark each swap offset used by the process as we find them
-    // for calculating proportional swap usage later.
+    // Get a list of all pids currently running in the system in 1st pass through all processes.
+    // Mark each swap offset used by the process as we find them for calculating proportional
+    // swap usage later.
     if (!read_all_pids(&pids, mark_swap_usage)) {
         std::cerr << "Failed to read all pids from the system" << std::endl;
         exit(EXIT_FAILURE);
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index b9f0dbf..66cb49f 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -24,6 +24,13 @@
         "libnativebridge",
         "libbase",
     ],
+    target: {
+        android: {
+            shared_libs: [
+                "libdl_android",
+            ],
+        },
+    },
     required: [
         "llndk.libraries.txt",
         "vndksp.libraries.txt",
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index ded5adb..9780606 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -95,7 +95,7 @@
     } else if (!mListen)
         mClients[mSock] = new SocketClient(mSock, false, mUseCmdNum);
 
-    if (pipe(mCtrlPipe)) {
+    if (pipe2(mCtrlPipe, O_CLOEXEC)) {
         SLOGE("pipe failed (%s)", strerror(errno));
         return -1;
     }
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index ce25108..b7650a1 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -49,6 +49,7 @@
     srcs: [
         "ArmExidx.cpp",
         "DexFile.cpp",
+        "DexFiles.cpp",
         "DwarfCfa.cpp",
         "DwarfEhFrameWithHdr.cpp",
         "DwarfMemory.cpp",
@@ -91,6 +92,7 @@
             cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
             exclude_srcs: [
                 "DexFile.cpp",
+                "DexFiles.cpp",
             ],
             exclude_shared_libs: [
                 "libdexfile_support",
@@ -100,6 +102,7 @@
             cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
             exclude_srcs: [
                 "DexFile.cpp",
+                "DexFiles.cpp",
             ],
             exclude_shared_libs: [
                 "libdexfile_support",
diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp
index d8d5a24..eaf867f 100644
--- a/libunwindstack/DexFile.cpp
+++ b/libunwindstack/DexFile.cpp
@@ -35,31 +35,22 @@
 std::unique_ptr<DexFile> DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory,
                                          MapInfo* info) {
   if (!info->name.empty()) {
-    std::unique_ptr<DexFile> dex_file_from_file =
+    std::unique_ptr<DexFile> dex_file =
         DexFileFromFile::Create(dex_file_offset_in_memory - info->start + info->offset, info->name);
-    if (dex_file_from_file) {
-      dex_file_from_file->addr_ = dex_file_offset_in_memory;
-      return dex_file_from_file;
+    if (dex_file) {
+      return dex_file;
     }
   }
-  std::unique_ptr<DexFile> dex_file_from_memory =
-      DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name);
-  if (dex_file_from_memory) {
-    dex_file_from_memory->addr_ = dex_file_offset_in_memory;
-    return dex_file_from_memory;
-  }
-  return nullptr;
+  return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name);
 }
 
-bool DexFile::GetFunctionName(uint64_t dex_pc, std::string* method_name, uint64_t* method_offset) {
-  uint64_t dex_offset = dex_pc - addr_;
+bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
+                                   uint64_t* method_offset) {
   art_api::dex::MethodInfo method_info = GetMethodInfoForOffset(dex_offset, false);
   if (method_info.offset == 0) {
     return false;
   }
-  if (method_name != nullptr) {
-    *method_name = method_info.name;
-  }
+  *method_name = method_info.name;
   *method_offset = dex_offset - method_info.offset;
   return true;
 }
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
index 1448a4b..ca658e6 100644
--- a/libunwindstack/DexFile.h
+++ b/libunwindstack/DexFile.h
@@ -29,22 +29,17 @@
 
 namespace unwindstack {
 
-class Memory;
-struct MapInfo;
-
 class DexFile : protected art_api::dex::DexFile {
  public:
   virtual ~DexFile() = default;
 
-  bool GetFunctionName(uint64_t dex_pc, std::string* method_name, uint64_t* method_offset);
+  bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
 
   static std::unique_ptr<DexFile> Create(uint64_t dex_file_offset_in_memory, Memory* memory,
                                          MapInfo* info);
 
  protected:
   DexFile(art_api::dex::DexFile&& art_dex_file) : art_api::dex::DexFile(std::move(art_dex_file)) {}
-
-  uint64_t addr_ = 0;
 };
 
 class DexFileFromFile : public DexFile {
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
new file mode 100644
index 0000000..63a77e5
--- /dev/null
+++ b/libunwindstack/DexFiles.cpp
@@ -0,0 +1,179 @@
+/*
+ * 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 <stdint.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+#include "DexFile.h"
+
+namespace unwindstack {
+
+struct DEXFileEntry32 {
+  uint32_t next;
+  uint32_t prev;
+  uint32_t dex_file;
+};
+
+struct DEXFileEntry64 {
+  uint64_t next;
+  uint64_t prev;
+  uint64_t dex_file;
+};
+
+DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : Global(memory) {}
+
+DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
+    : Global(memory, search_libs) {}
+
+DexFiles::~DexFiles() {}
+
+void DexFiles::ProcessArch() {
+  switch (arch()) {
+    case ARCH_ARM:
+    case ARCH_MIPS:
+    case ARCH_X86:
+      read_entry_ptr_func_ = &DexFiles::ReadEntryPtr32;
+      read_entry_func_ = &DexFiles::ReadEntry32;
+      break;
+
+    case ARCH_ARM64:
+    case ARCH_MIPS64:
+    case ARCH_X86_64:
+      read_entry_ptr_func_ = &DexFiles::ReadEntryPtr64;
+      read_entry_func_ = &DexFiles::ReadEntry64;
+      break;
+
+    case ARCH_UNKNOWN:
+      abort();
+  }
+}
+
+uint64_t DexFiles::ReadEntryPtr32(uint64_t addr) {
+  uint32_t entry;
+  const uint32_t field_offset = 12;  // offset of first_entry_ in the descriptor struct.
+  if (!memory_->ReadFully(addr + field_offset, &entry, sizeof(entry))) {
+    return 0;
+  }
+  return entry;
+}
+
+uint64_t DexFiles::ReadEntryPtr64(uint64_t addr) {
+  uint64_t entry;
+  const uint32_t field_offset = 16;  // offset of first_entry_ in the descriptor struct.
+  if (!memory_->ReadFully(addr + field_offset, &entry, sizeof(entry))) {
+    return 0;
+  }
+  return entry;
+}
+
+bool DexFiles::ReadEntry32() {
+  DEXFileEntry32 entry;
+  if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) {
+    entry_addr_ = 0;
+    return false;
+  }
+
+  addrs_.push_back(entry.dex_file);
+  entry_addr_ = entry.next;
+  return true;
+}
+
+bool DexFiles::ReadEntry64() {
+  DEXFileEntry64 entry;
+  if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) {
+    entry_addr_ = 0;
+    return false;
+  }
+
+  addrs_.push_back(entry.dex_file);
+  entry_addr_ = entry.next;
+  return true;
+}
+
+bool DexFiles::ReadVariableData(uint64_t ptr_offset) {
+  entry_addr_ = (this->*read_entry_ptr_func_)(ptr_offset);
+  return entry_addr_ != 0;
+}
+
+void DexFiles::Init(Maps* maps) {
+  if (initialized_) {
+    return;
+  }
+  initialized_ = true;
+  entry_addr_ = 0;
+
+  FindAndReadVariable(maps, "__dex_debug_descriptor");
+}
+
+DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) {
+  // Lock while processing the data.
+  DexFile* dex_file;
+  auto entry = files_.find(dex_file_offset);
+  if (entry == files_.end()) {
+    std::unique_ptr<DexFile> new_dex_file = DexFile::Create(dex_file_offset, memory_.get(), info);
+    dex_file = new_dex_file.get();
+    files_[dex_file_offset] = std::move(new_dex_file);
+  } else {
+    dex_file = entry->second.get();
+  }
+  return dex_file;
+}
+
+bool DexFiles::GetAddr(size_t index, uint64_t* addr) {
+  if (index < addrs_.size()) {
+    *addr = addrs_[index];
+    return true;
+  }
+  if (entry_addr_ != 0 && (this->*read_entry_func_)()) {
+    *addr = addrs_.back();
+    return true;
+  }
+  return false;
+}
+
+void DexFiles::GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc,
+                                    std::string* method_name, uint64_t* method_offset) {
+  std::lock_guard<std::mutex> guard(lock_);
+  if (!initialized_) {
+    Init(maps);
+  }
+
+  size_t index = 0;
+  uint64_t addr;
+  while (GetAddr(index++, &addr)) {
+    if (addr < info->start || addr >= info->end) {
+      continue;
+    }
+
+    DexFile* dex_file = GetDexFile(addr, info);
+    if (dex_file != nullptr &&
+        dex_file->GetMethodInformation(dex_pc - addr, method_name, method_offset)) {
+      break;
+    }
+  }
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 5b402ed..4b93abb 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -243,24 +243,6 @@
   return false;
 }
 
-bool Elf::GetTextRange(uint64_t* addr, uint64_t* size) {
-  if (!valid_) {
-    return false;
-  }
-
-  if (interface_->GetTextRange(addr, size)) {
-    *addr += load_bias_;
-    return true;
-  }
-
-  if (gnu_debugdata_interface_ != nullptr && gnu_debugdata_interface_->GetTextRange(addr, size)) {
-    *addr += load_bias_;
-    return true;
-  }
-
-  return false;
-}
-
 ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) {
   if (!IsValidElf(memory)) {
     return nullptr;
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 32c637f..dee8eb3 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -69,15 +69,6 @@
   return false;
 }
 
-bool ElfInterface::GetTextRange(uint64_t* addr, uint64_t* size) {
-  if (text_size_ != 0) {
-    *addr = text_addr_;
-    *size = text_size_;
-    return true;
-  }
-  return false;
-}
-
 Memory* ElfInterface::CreateGnuDebugdataMemory() {
   if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) {
     return nullptr;
@@ -339,26 +330,29 @@
       }
       symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
                                      str_shdr.sh_offset, str_shdr.sh_size));
-    } else if (shdr.sh_type == SHT_PROGBITS || shdr.sh_type == SHT_NOBITS) {
+    } else if (shdr.sh_type == SHT_PROGBITS && sec_size != 0) {
       // Look for the .debug_frame and .gnu_debugdata.
       if (shdr.sh_name < sec_size) {
         std::string name;
         if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) {
+          uint64_t* offset_ptr = nullptr;
+          uint64_t* size_ptr = nullptr;
           if (name == ".debug_frame") {
-            debug_frame_offset_ = shdr.sh_offset;
-            debug_frame_size_ = shdr.sh_size;
+            offset_ptr = &debug_frame_offset_;
+            size_ptr = &debug_frame_size_;
           } else if (name == ".gnu_debugdata") {
-            gnu_debugdata_offset_ = shdr.sh_offset;
-            gnu_debugdata_size_ = shdr.sh_size;
+            offset_ptr = &gnu_debugdata_offset_;
+            size_ptr = &gnu_debugdata_size_;
           } else if (name == ".eh_frame") {
-            eh_frame_offset_ = shdr.sh_offset;
-            eh_frame_size_ = shdr.sh_size;
+            offset_ptr = &eh_frame_offset_;
+            size_ptr = &eh_frame_size_;
           } else if (eh_frame_hdr_offset_ == 0 && name == ".eh_frame_hdr") {
-            eh_frame_hdr_offset_ = shdr.sh_offset;
-            eh_frame_hdr_size_ = shdr.sh_size;
-          } else if (name == ".text") {
-            text_addr_ = shdr.sh_addr;
-            text_size_ = shdr.sh_size;
+            offset_ptr = &eh_frame_hdr_offset_;
+            size_ptr = &eh_frame_hdr_size_;
+          }
+          if (offset_ptr != nullptr) {
+            *offset_ptr = shdr.sh_offset;
+            *size_ptr = shdr.sh_size;
           }
         }
       }
diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp
index 71665a1..20bc4b9 100644
--- a/libunwindstack/JitDebug.cpp
+++ b/libunwindstack/JitDebug.cpp
@@ -16,13 +16,8 @@
 
 #include <stdint.h>
 #include <sys/mman.h>
-#include <cstddef>
 
-#include <atomic>
-#include <deque>
-#include <map>
 #include <memory>
-#include <unordered_set>
 #include <vector>
 
 #include <unwindstack/Elf.h>
@@ -30,334 +25,197 @@
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
 
-#if !defined(NO_LIBDEXFILE_SUPPORT)
-#include <DexFile.h>
-#endif
-
 // This implements the JIT Compilation Interface.
 // See https://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html
 
 namespace unwindstack {
 
-// 32-bit platforms may differ in alignment of uint64_t.
-struct Uint64_P {
-  uint64_t value;
+struct JITCodeEntry32Pack {
+  uint32_t next;
+  uint32_t prev;
+  uint32_t symfile_addr;
+  uint64_t symfile_size;
 } __attribute__((packed));
-struct Uint64_A {
-  uint64_t value;
-} __attribute__((aligned(8)));
 
-// Wrapper around other memory object which protects us against data races.
-// It will check seqlock after every read, and fail if the seqlock changed.
-// This ensues that the read memory has not been partially modified.
-struct JitMemory : public Memory {
-  size_t Read(uint64_t addr, void* dst, size_t size) override;
-
-  Memory* parent_ = nullptr;
-  uint64_t seqlock_addr_ = 0;
-  uint32_t expected_seqlock_ = 0;
-  bool failed_due_to_race_ = false;
+struct JITCodeEntry32Pad {
+  uint32_t next;
+  uint32_t prev;
+  uint32_t symfile_addr;
+  uint32_t pad;
+  uint64_t symfile_size;
 };
 
-template <typename Symfile>
-struct JitCacheEntry {
-  // PC memory range described by this entry.
-  uint64_t addr_ = 0;
-  uint64_t size_ = 0;
-  std::unique_ptr<Symfile> symfile_;
-
-  bool Init(Maps* maps, JitMemory* memory, uint64_t addr, uint64_t size);
+struct JITCodeEntry64 {
+  uint64_t next;
+  uint64_t prev;
+  uint64_t symfile_addr;
+  uint64_t symfile_size;
 };
 
-template <typename Symfile, typename PointerT, typename Uint64_T>
-class JitDebugImpl : public JitDebug<Symfile>, public Global {
- public:
-  static constexpr const char* kDescriptorExtMagic = "Android1";
-  static constexpr int kMaxRaceRetries = 16;
+struct JITDescriptorHeader {
+  uint32_t version;
+  uint32_t action_flag;
+};
 
-  struct JITCodeEntry {
-    PointerT next;
-    PointerT prev;
-    PointerT symfile_addr;
-    Uint64_T symfile_size;
-  };
+struct JITDescriptor32 {
+  JITDescriptorHeader header;
+  uint32_t relevant_entry;
+  uint32_t first_entry;
+};
 
-  struct JITDescriptor {
-    uint32_t version;
-    uint32_t action_flag;
-    PointerT relevant_entry;
-    PointerT first_entry;
-  };
+struct JITDescriptor64 {
+  JITDescriptorHeader header;
+  uint64_t relevant_entry;
+  uint64_t first_entry;
+};
 
-  // Android-specific extensions.
-  struct JITDescriptorExt {
-    JITDescriptor desc;
-    uint8_t magic[8];
-    uint32_t flags;
-    uint32_t sizeof_descriptor;
-    uint32_t sizeof_entry;
-    uint32_t action_seqlock;
-    uint64_t action_timestamp;
-  };
+JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : Global(memory) {}
 
-  JitDebugImpl(ArchEnum arch, std::shared_ptr<Memory>& memory,
-               std::vector<std::string>& search_libs)
-      : Global(memory, search_libs) {
-    SetArch(arch);
+JitDebug::JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
+    : Global(memory, search_libs) {}
+
+JitDebug::~JitDebug() {
+  for (auto* elf : elf_list_) {
+    delete elf;
+  }
+}
+
+uint64_t JitDebug::ReadDescriptor32(uint64_t addr) {
+  JITDescriptor32 desc;
+  if (!memory_->ReadFully(addr, &desc, sizeof(desc))) {
+    return 0;
   }
 
-  Symfile* Get(Maps* maps, uint64_t pc) override;
-  virtual bool ReadVariableData(uint64_t offset);
-  virtual void ProcessArch() {}
-  bool Update(Maps* maps);
-  bool Read(Maps* maps, JitMemory* memory);
+  if (desc.header.version != 1 || desc.first_entry == 0) {
+    // Either unknown version, or no jit entries.
+    return 0;
+  }
 
-  bool initialized_ = false;
-  uint64_t descriptor_addr_ = 0;  // Non-zero if we have found (non-empty) descriptor.
-  uint64_t seqlock_addr_ = 0;     // Re-read entries if the value at this address changes.
-  uint32_t last_seqlock_ = ~0u;   // The value of seqlock when we last read the entries.
+  return desc.first_entry;
+}
 
-  std::deque<JitCacheEntry<Symfile>> entries_;
+uint64_t JitDebug::ReadDescriptor64(uint64_t addr) {
+  JITDescriptor64 desc;
+  if (!memory_->ReadFully(addr, &desc, sizeof(desc))) {
+    return 0;
+  }
 
-  std::mutex lock_;
-};
+  if (desc.header.version != 1 || desc.first_entry == 0) {
+    // Either unknown version, or no jit entries.
+    return 0;
+  }
 
-template <typename Symfile>
-std::unique_ptr<JitDebug<Symfile>> JitDebug<Symfile>::Create(ArchEnum arch,
-                                                             std::shared_ptr<Memory>& memory,
-                                                             std::vector<std::string> search_libs) {
-  typedef JitDebugImpl<Symfile, uint32_t, Uint64_P> JitDebugImpl32P;
-  typedef JitDebugImpl<Symfile, uint32_t, Uint64_A> JitDebugImpl32A;
-  typedef JitDebugImpl<Symfile, uint64_t, Uint64_A> JitDebugImpl64A;
-  switch (arch) {
+  return desc.first_entry;
+}
+
+uint64_t JitDebug::ReadEntry32Pack(uint64_t* start, uint64_t* size) {
+  JITCodeEntry32Pack code;
+  if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) {
+    return 0;
+  }
+
+  *start = code.symfile_addr;
+  *size = code.symfile_size;
+  return code.next;
+}
+
+uint64_t JitDebug::ReadEntry32Pad(uint64_t* start, uint64_t* size) {
+  JITCodeEntry32Pad code;
+  if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) {
+    return 0;
+  }
+
+  *start = code.symfile_addr;
+  *size = code.symfile_size;
+  return code.next;
+}
+
+uint64_t JitDebug::ReadEntry64(uint64_t* start, uint64_t* size) {
+  JITCodeEntry64 code;
+  if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) {
+    return 0;
+  }
+
+  *start = code.symfile_addr;
+  *size = code.symfile_size;
+  return code.next;
+}
+
+void JitDebug::ProcessArch() {
+  switch (arch()) {
     case ARCH_X86:
-      static_assert(sizeof(typename JitDebugImpl32P::JITCodeEntry) == 20, "layout");
-      static_assert(sizeof(typename JitDebugImpl32P::JITDescriptor) == 16, "layout");
-      static_assert(sizeof(typename JitDebugImpl32P::JITDescriptorExt) == 48, "layout");
-      return std::unique_ptr<JitDebug>(new JitDebugImpl32P(arch, memory, search_libs));
+      read_descriptor_func_ = &JitDebug::ReadDescriptor32;
+      read_entry_func_ = &JitDebug::ReadEntry32Pack;
       break;
+
     case ARCH_ARM:
     case ARCH_MIPS:
-      static_assert(sizeof(typename JitDebugImpl32A::JITCodeEntry) == 24, "layout");
-      static_assert(sizeof(typename JitDebugImpl32A::JITDescriptor) == 16, "layout");
-      static_assert(sizeof(typename JitDebugImpl32A::JITDescriptorExt) == 48, "layout");
-      return std::unique_ptr<JitDebug>(new JitDebugImpl32A(arch, memory, search_libs));
+      read_descriptor_func_ = &JitDebug::ReadDescriptor32;
+      read_entry_func_ = &JitDebug::ReadEntry32Pad;
       break;
+
     case ARCH_ARM64:
     case ARCH_X86_64:
     case ARCH_MIPS64:
-      static_assert(sizeof(typename JitDebugImpl64A::JITCodeEntry) == 32, "layout");
-      static_assert(sizeof(typename JitDebugImpl64A::JITDescriptor) == 24, "layout");
-      static_assert(sizeof(typename JitDebugImpl64A::JITDescriptorExt) == 56, "layout");
-      return std::unique_ptr<JitDebug>(new JitDebugImpl64A(arch, memory, search_libs));
+      read_descriptor_func_ = &JitDebug::ReadDescriptor64;
+      read_entry_func_ = &JitDebug::ReadEntry64;
       break;
-    default:
+    case ARCH_UNKNOWN:
       abort();
   }
 }
 
-size_t JitMemory::Read(uint64_t addr, void* dst, size_t size) {
-  if (!parent_->ReadFully(addr, dst, size)) {
-    return 0;
-  }
-  // This is required for memory synchronization if the we are working with local memory.
-  // For other types of memory (e.g. remote) this is no-op and has no significant effect.
-  std::atomic_thread_fence(std::memory_order_acquire);
-  uint32_t seen_seqlock;
-  if (!parent_->Read32(seqlock_addr_, &seen_seqlock)) {
-    return 0;
-  }
-  if (seen_seqlock != expected_seqlock_) {
-    failed_due_to_race_ = true;
-    return 0;
-  }
-  return size;
+bool JitDebug::ReadVariableData(uint64_t ptr) {
+  entry_addr_ = (this->*read_descriptor_func_)(ptr);
+  return entry_addr_ != 0;
 }
 
-template <typename Symfile, typename PointerT, typename Uint64_T>
-bool JitDebugImpl<Symfile, PointerT, Uint64_T>::ReadVariableData(uint64_t addr) {
-  JITDescriptor desc;
-  if (!this->memory_->ReadFully(addr, &desc, sizeof(desc))) {
-    return false;
+void JitDebug::Init(Maps* maps) {
+  if (initialized_) {
+    return;
   }
-  if (desc.version != 1) {
-    return false;
-  }
-  if (desc.first_entry == 0) {
-    return false;  // There could be multiple descriptors. Ignore empty ones.
-  }
-  descriptor_addr_ = addr;
-  JITDescriptorExt desc_ext;
-  if (this->memory_->ReadFully(addr, &desc_ext, sizeof(desc_ext)) &&
-      memcmp(desc_ext.magic, kDescriptorExtMagic, 8) == 0) {
-    seqlock_addr_ = descriptor_addr_ + offsetof(JITDescriptorExt, action_seqlock);
-  } else {
-    // In the absence of Android-specific fields, use the head pointer instead.
-    seqlock_addr_ = descriptor_addr_ + offsetof(JITDescriptor, first_entry);
-  }
-  return true;
+  // Regardless of what happens below, consider the init finished.
+  initialized_ = true;
+
+  FindAndReadVariable(maps, "__jit_debug_descriptor");
 }
 
-template <typename Symfile>
-static const char* GetDescriptorName();
-
-template <>
-const char* GetDescriptorName<Elf>() {
-  return "__jit_debug_descriptor";
-}
-
-template <typename Symfile, typename PointerT, typename Uint64_T>
-Symfile* JitDebugImpl<Symfile, PointerT, Uint64_T>::Get(Maps* maps, uint64_t pc) {
+Elf* JitDebug::GetElf(Maps* maps, uint64_t pc) {
+  // Use a single lock, this object should be used so infrequently that
+  // a fine grain lock is unnecessary.
   std::lock_guard<std::mutex> guard(lock_);
   if (!initialized_) {
-    FindAndReadVariable(maps, GetDescriptorName<Symfile>());
-    initialized_ = true;
+    Init(maps);
   }
 
-  if (descriptor_addr_ == 0) {
-    return nullptr;
-  }
-
-  if (!Update(maps)) {
-    return nullptr;
-  }
-
-  Symfile* fallback = nullptr;
-  for (auto& entry : entries_) {
-    // Skip entries which are obviously not relevant (if we know the PC range).
-    if (entry.size_ == 0 || (entry.addr_ <= pc && (pc - entry.addr_) < entry.size_)) {
-      // Double check the entry contains the PC in case there are overlapping entries.
-      // This is might happen for native-code due to GC and for DEX due to data sharing.
-      std::string method_name;
-      uint64_t method_offset;
-      if (entry.symfile_->GetFunctionName(pc, &method_name, &method_offset)) {
-        return entry.symfile_.get();
-      }
-      fallback = entry.symfile_.get();  // Tests don't have any symbols.
-    }
-  }
-  return fallback;  // Not found.
-}
-
-// Update JIT entries if needed.  It will retry if there are data races.
-template <typename Symfile, typename PointerT, typename Uint64_T>
-bool JitDebugImpl<Symfile, PointerT, Uint64_T>::Update(Maps* maps) {
-  // We might need to retry the whole read in the presence of data races.
-  for (int i = 0; i < kMaxRaceRetries; i++) {
-    // Read the seqlock (counter which is incremented before and after any modification).
-    uint32_t seqlock = 0;
-    if (!this->memory_->Read32(seqlock_addr_, &seqlock)) {
-      return false;  // Failed to read seqlock.
-    }
-
-    // Check if anything changed since the last time we checked.
-    if (last_seqlock_ != seqlock) {
-      // Create memory wrapper to allow us to read the entries safely even in a live process.
-      JitMemory safe_memory;
-      safe_memory.parent_ = this->memory_.get();
-      safe_memory.seqlock_addr_ = seqlock_addr_;
-      safe_memory.expected_seqlock_ = seqlock;
-      std::atomic_thread_fence(std::memory_order_acquire);
-
-      // Add all entries to our cache.
-      if (!Read(maps, &safe_memory)) {
-        if (safe_memory.failed_due_to_race_) {
-          sleep(0);
-          continue;  // Try again (there was a data race).
-        } else {
-          return false;  // Proper failure (we could not read the data).
-        }
-      }
-      last_seqlock_ = seqlock;
-    }
-    return true;
-  }
-  return false;  // Too many retries.
-}
-
-// Read all JIT entries.  It might randomly fail due to data races.
-template <typename Symfile, typename PointerT, typename Uint64_T>
-bool JitDebugImpl<Symfile, PointerT, Uint64_T>::Read(Maps* maps, JitMemory* memory) {
-  std::unordered_set<uint64_t> seen_entry_addr;
-
-  // Read and verify the descriptor (must be after we have read the initial seqlock).
-  JITDescriptor desc;
-  if (!(memory->ReadFully(descriptor_addr_, &desc, sizeof(desc)))) {
-    return false;
-  }
-
-  entries_.clear();
-  JITCodeEntry entry;
-  for (uint64_t entry_addr = desc.first_entry; entry_addr != 0; entry_addr = entry.next) {
-    // Check for infinite loops in the lined list.
-    if (!seen_entry_addr.emplace(entry_addr).second) {
-      return true;  // TODO: Fail when seening infinite loop.
-    }
-
-    // Read the entry (while checking for data races).
-    if (!memory->ReadFully(entry_addr, &entry, sizeof(entry))) {
-      return false;
-    }
-
-    // Copy and load the symfile.
-    entries_.emplace_back(JitCacheEntry<Symfile>());
-    if (!entries_.back().Init(maps, memory, entry.symfile_addr, entry.symfile_size.value)) {
-      return false;
+  // Search the existing elf object first.
+  for (Elf* elf : elf_list_) {
+    if (elf->IsValidPc(pc)) {
+      return elf;
     }
   }
 
-  return true;
-}
+  while (entry_addr_ != 0) {
+    uint64_t start;
+    uint64_t size;
+    entry_addr_ = (this->*read_entry_func_)(&start, &size);
 
-// Copy and load ELF file.
-template <>
-bool JitCacheEntry<Elf>::Init(Maps*, JitMemory* memory, uint64_t addr, uint64_t size) {
-  // Make a copy of the in-memory symbol file (while checking for data races).
-  std::unique_ptr<MemoryBuffer> buffer(new MemoryBuffer());
-  buffer->Resize(size);
-  if (!memory->ReadFully(addr, buffer->GetPtr(0), buffer->Size())) {
-    return false;
+    Elf* elf = new Elf(new MemoryRange(memory_, start, size, 0));
+    elf->Init();
+    if (!elf->valid()) {
+      // The data is not formatted in a way we understand, do not attempt
+      // to process any other entries.
+      entry_addr_ = 0;
+      delete elf;
+      return nullptr;
+    }
+    elf_list_.push_back(elf);
+
+    if (elf->IsValidPc(pc)) {
+      return elf;
+    }
   }
-
-  // Load and validate the ELF file.
-  symfile_.reset(new Elf(buffer.release()));
-  symfile_->Init();
-  if (!symfile_->valid()) {
-    return false;
-  }
-
-  symfile_->GetTextRange(&addr_, &size_);
-  return true;
+  return nullptr;
 }
 
-template std::unique_ptr<JitDebug<Elf>> JitDebug<Elf>::Create(ArchEnum, std::shared_ptr<Memory>&,
-                                                              std::vector<std::string>);
-
-#if !defined(NO_LIBDEXFILE_SUPPORT)
-
-template <>
-const char* GetDescriptorName<DexFile>() {
-  return "__dex_debug_descriptor";
-}
-
-// Copy and load DEX file.
-template <>
-bool JitCacheEntry<DexFile>::Init(Maps* maps, JitMemory* memory, uint64_t addr, uint64_t) {
-  MapInfo* info = maps->Find(addr);
-  if (info == nullptr) {
-    return false;
-  }
-  symfile_ = DexFile::Create(addr, memory, info);
-  if (symfile_ == nullptr) {
-    return false;
-  }
-  return true;
-}
-
-template std::unique_ptr<JitDebug<DexFile>> JitDebug<DexFile>::Create(ArchEnum,
-                                                                      std::shared_ptr<Memory>&,
-                                                                      std::vector<std::string>);
-
-#endif
-
 }  // namespace unwindstack
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 73c5a04..3f2e1c1 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -36,38 +36,11 @@
 #include <unwindstack/Unwinder.h>
 
 #if !defined(NO_LIBDEXFILE_SUPPORT)
-#include <DexFile.h>
+#include <unwindstack/DexFiles.h>
 #endif
 
 namespace unwindstack {
 
-Unwinder::Unwinder(size_t max_frames, Maps* maps, Regs* regs,
-                   std::shared_ptr<Memory> process_memory)
-    : max_frames_(max_frames), maps_(maps), regs_(regs), process_memory_(process_memory) {
-  frames_.reserve(max_frames);
-  if (regs != nullptr) {
-    ArchEnum arch = regs_->Arch();
-
-    jit_debug_ = JitDebug<Elf>::Create(arch, process_memory_);
-#if !defined(NO_LIBDEXFILE_SUPPORT)
-    dex_files_ = JitDebug<DexFile>::Create(arch, process_memory_);
-#endif
-  }
-}
-
-void Unwinder::SetRegs(Regs* regs) {
-  regs_ = regs;
-
-  if (jit_debug_ == nullptr) {
-    ArchEnum arch = regs_->Arch();
-
-    jit_debug_ = JitDebug<Elf>::Create(arch, process_memory_);
-#if !defined(NO_LIBDEXFILE_SUPPORT)
-    dex_files_ = JitDebug<DexFile>::Create(arch, process_memory_);
-#endif
-  }
-}
-
 // Inject extra 'virtual' frame that represents the dex pc data.
 // The dex pc is a magic register defined in the Mterp interpreter,
 // and thus it will be restored/observed in the frame after it.
@@ -111,7 +84,8 @@
     return;
   }
 
-  dex_files_->GetFunctionName(maps_, dex_pc, &frame->function_name, &frame->function_offset);
+  dex_files_->GetMethodInformation(maps_, info, dex_pc, &frame->function_name,
+                                   &frame->function_offset);
 #endif
 }
 
@@ -211,7 +185,7 @@
       // using the jit debug information.
       if (!elf->valid() && jit_debug_ != nullptr) {
         uint64_t adjusted_jit_pc = regs_->pc() - pc_adjustment;
-        Elf* jit_elf = jit_debug_->Get(maps_, adjusted_jit_pc);
+        Elf* jit_elf = jit_debug_->GetElf(maps_, adjusted_jit_pc);
         if (jit_elf != nullptr) {
           // The jit debug information requires a non relative adjusted pc.
           step_pc = adjusted_jit_pc;
@@ -356,7 +330,19 @@
   return FormatFrame(frames_[frame_num]);
 }
 
-bool UnwinderFromPid::Init() {
+void Unwinder::SetJitDebug(JitDebug* jit_debug, ArchEnum arch) {
+  jit_debug->SetArch(arch);
+  jit_debug_ = jit_debug;
+}
+
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+void Unwinder::SetDexFiles(DexFiles* dex_files, ArchEnum arch) {
+  dex_files->SetArch(arch);
+  dex_files_ = dex_files;
+}
+#endif
+
+bool UnwinderFromPid::Init(ArchEnum arch) {
   if (pid_ == getpid()) {
     maps_ptr_.reset(new LocalMaps());
   } else {
@@ -369,6 +355,15 @@
 
   process_memory_ = Memory::CreateProcessMemoryCached(pid_);
 
+  jit_debug_ptr_.reset(new JitDebug(process_memory_));
+  jit_debug_ = jit_debug_ptr_.get();
+  SetJitDebug(jit_debug_, arch);
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  dex_files_ptr_.reset(new DexFiles(process_memory_));
+  dex_files_ = dex_files_ptr_.get();
+  SetDexFiles(dex_files_, arch);
+#endif
+
   return true;
 }
 
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
new file mode 100644
index 0000000..67a9640
--- /dev/null
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -0,0 +1,79 @@
+/*
+ * 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 _LIBUNWINDSTACK_DEX_FILES_H
+#define _LIBUNWINDSTACK_DEX_FILES_H
+
+#include <stdint.h>
+
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <unwindstack/Global.h>
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class DexFile;
+class Maps;
+struct MapInfo;
+enum ArchEnum : uint8_t;
+
+class DexFiles : public Global {
+ public:
+  explicit DexFiles(std::shared_ptr<Memory>& memory);
+  DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
+  virtual ~DexFiles();
+
+  DexFile* GetDexFile(uint64_t dex_file_offset, MapInfo* info);
+
+  void GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc, std::string* method_name,
+                            uint64_t* method_offset);
+
+ private:
+  void Init(Maps* maps);
+
+  bool GetAddr(size_t index, uint64_t* addr);
+
+  uint64_t ReadEntryPtr32(uint64_t addr);
+
+  uint64_t ReadEntryPtr64(uint64_t addr);
+
+  bool ReadEntry32();
+
+  bool ReadEntry64();
+
+  bool ReadVariableData(uint64_t ptr_offset) override;
+
+  void ProcessArch() override;
+
+  std::mutex lock_;
+  bool initialized_ = false;
+  std::unordered_map<uint64_t, std::unique_ptr<DexFile>> files_;
+
+  uint64_t entry_addr_ = 0;
+  uint64_t (DexFiles::*read_entry_ptr_func_)(uint64_t) = nullptr;
+  bool (DexFiles::*read_entry_func_)() = nullptr;
+  std::vector<uint64_t> addrs_;
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_DEX_FILES_H
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index 25a665d..ac94f10 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -78,8 +78,6 @@
 
   bool IsValidPc(uint64_t pc);
 
-  bool GetTextRange(uint64_t* addr, uint64_t* size);
-
   void GetLastError(ErrorData* data);
   ErrorCode GetLastErrorCode();
   uint64_t GetLastErrorAddress();
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index 945c277..dbd917d 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -68,8 +68,6 @@
 
   virtual bool IsValidPc(uint64_t pc);
 
-  bool GetTextRange(uint64_t* addr, uint64_t* size);
-
   Memory* CreateGnuDebugdataMemory();
 
   Memory* memory() { return memory_; }
@@ -158,9 +156,6 @@
   uint64_t gnu_build_id_offset_ = 0;
   uint64_t gnu_build_id_size_ = 0;
 
-  uint64_t text_addr_ = 0;
-  uint64_t text_size_ = 0;
-
   uint8_t soname_type_ = SONAME_UNKNOWN;
   std::string soname_;
 
diff --git a/libunwindstack/include/unwindstack/JitDebug.h b/libunwindstack/include/unwindstack/JitDebug.h
index 0c3ded9..8b7b4b5 100644
--- a/libunwindstack/include/unwindstack/JitDebug.h
+++ b/libunwindstack/include/unwindstack/JitDebug.h
@@ -19,7 +19,6 @@
 
 #include <stdint.h>
 
-#include <map>
 #include <memory>
 #include <mutex>
 #include <string>
@@ -31,24 +30,40 @@
 namespace unwindstack {
 
 // Forward declarations.
+class Elf;
 class Maps;
 enum ArchEnum : uint8_t;
 
-template <typename Symfile>
-class JitDebug {
+class JitDebug : public Global {
  public:
-  static std::unique_ptr<JitDebug> Create(ArchEnum arch, std::shared_ptr<Memory>& memory,
-                                          std::vector<std::string> search_libs = {});
-  virtual ~JitDebug() {}
+  explicit JitDebug(std::shared_ptr<Memory>& memory);
+  JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
+  virtual ~JitDebug();
 
-  // Find symbol file for given pc.
-  virtual Symfile* Get(Maps* maps, uint64_t pc) = 0;
+  Elf* GetElf(Maps* maps, uint64_t pc);
 
-  // Find symbol for given pc.
-  bool GetFunctionName(Maps* maps, uint64_t pc, std::string* name, uint64_t* offset) {
-    Symfile* file = Get(maps, pc);
-    return file != nullptr && file->GetFunctionName(pc, name, offset);
-  }
+ private:
+  void Init(Maps* maps);
+
+  uint64_t (JitDebug::*read_descriptor_func_)(uint64_t) = nullptr;
+  uint64_t (JitDebug::*read_entry_func_)(uint64_t*, uint64_t*) = nullptr;
+
+  uint64_t ReadDescriptor32(uint64_t);
+  uint64_t ReadDescriptor64(uint64_t);
+
+  uint64_t ReadEntry32Pack(uint64_t* start, uint64_t* size);
+  uint64_t ReadEntry32Pad(uint64_t* start, uint64_t* size);
+  uint64_t ReadEntry64(uint64_t* start, uint64_t* size);
+
+  bool ReadVariableData(uint64_t ptr_offset) override;
+
+  void ProcessArch() override;
+
+  uint64_t entry_addr_ = 0;
+  bool initialized_ = false;
+  std::vector<Elf*> elf_list_;
+
+  std::mutex lock_;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index a04d7c3..8b01654 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -24,6 +24,7 @@
 #include <string>
 #include <vector>
 
+#include <unwindstack/DexFiles.h>
 #include <unwindstack/Error.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
@@ -33,7 +34,6 @@
 namespace unwindstack {
 
 // Forward declarations.
-class DexFile;
 class Elf;
 enum ArchEnum : uint8_t;
 
@@ -63,14 +63,14 @@
 
 class Unwinder {
  public:
-  Unwinder(size_t max_frames, Maps* maps, Regs* regs, std::shared_ptr<Memory> process_memory);
+  Unwinder(size_t max_frames, Maps* maps, Regs* regs, std::shared_ptr<Memory> process_memory)
+      : max_frames_(max_frames), maps_(maps), regs_(regs), process_memory_(process_memory) {
+    frames_.reserve(max_frames);
+  }
   Unwinder(size_t max_frames, Maps* maps, std::shared_ptr<Memory> process_memory)
-      : Unwinder(max_frames, maps, nullptr, process_memory) {}
-
-  Unwinder(const Unwinder&) = delete;
-  Unwinder& operator=(const Unwinder&) = delete;
-  Unwinder(Unwinder&&) = default;
-  Unwinder& operator=(Unwinder&&) = default;
+      : max_frames_(max_frames), maps_(maps), process_memory_(process_memory) {
+    frames_.reserve(max_frames);
+  }
 
   virtual ~Unwinder() = default;
 
@@ -90,7 +90,9 @@
   std::string FormatFrame(size_t frame_num);
   std::string FormatFrame(const FrameData& frame);
 
-  void SetRegs(Regs* regs);
+  void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
+
+  void SetRegs(Regs* regs) { regs_ = regs; }
   Maps* GetMaps() { return maps_; }
   std::shared_ptr<Memory>& GetProcessMemory() { return process_memory_; }
 
@@ -105,6 +107,10 @@
 
   void SetDisplayBuildID(bool display_build_id) { display_build_id_ = display_build_id; }
 
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
+#endif
+
   ErrorCode LastErrorCode() { return last_error_.code; }
   uint64_t LastErrorAddress() { return last_error_.address; }
 
@@ -120,9 +126,9 @@
   Regs* regs_;
   std::vector<FrameData> frames_;
   std::shared_ptr<Memory> process_memory_;
-  std::unique_ptr<JitDebug<Elf>> jit_debug_;
+  JitDebug* jit_debug_ = nullptr;
 #if !defined(NO_LIBDEXFILE_SUPPORT)
-  std::unique_ptr<JitDebug<DexFile>> dex_files_;
+  DexFiles* dex_files_ = nullptr;
 #endif
   bool resolve_names_ = true;
   bool embedded_soname_ = true;
@@ -135,11 +141,15 @@
   UnwinderFromPid(size_t max_frames, pid_t pid) : Unwinder(max_frames), pid_(pid) {}
   virtual ~UnwinderFromPid() = default;
 
-  bool Init();
+  bool Init(ArchEnum arch);
 
  private:
   pid_t pid_;
   std::unique_ptr<Maps> maps_ptr_;
+  std::unique_ptr<JitDebug> jit_debug_ptr_;
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  std::unique_ptr<DexFiles> dex_files_ptr_;
+#endif
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
index df7b31d..0149a42 100644
--- a/libunwindstack/tests/DexFileTest.cpp
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -177,11 +177,11 @@
 
   std::string method;
   uint64_t method_offset;
-  ASSERT_TRUE(dex_file->GetFunctionName(0x4102, &method, &method_offset));
+  ASSERT_TRUE(dex_file->GetMethodInformation(0x102, &method, &method_offset));
   EXPECT_EQ("Main.<init>", method);
   EXPECT_EQ(2U, method_offset);
 
-  ASSERT_TRUE(dex_file->GetFunctionName(0x4118, &method, &method_offset));
+  ASSERT_TRUE(dex_file->GetMethodInformation(0x118, &method, &method_offset));
   EXPECT_EQ("Main.main", method);
   EXPECT_EQ(0U, method_offset);
 }
@@ -195,9 +195,9 @@
 
   std::string method;
   uint64_t method_offset;
-  EXPECT_FALSE(dex_file->GetFunctionName(0x100000, &method, &method_offset));
+  EXPECT_FALSE(dex_file->GetMethodInformation(0x100000, &method, &method_offset));
 
-  EXPECT_FALSE(dex_file->GetFunctionName(0x98, &method, &method_offset));
+  EXPECT_FALSE(dex_file->GetMethodInformation(0x98, &method, &method_offset));
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp
index 655dcc8..1ea9e5c 100644
--- a/libunwindstack/tests/DexFilesTest.cpp
+++ b/libunwindstack/tests/DexFilesTest.cpp
@@ -22,8 +22,8 @@
 
 #include <gtest/gtest.h>
 
+#include <unwindstack/DexFiles.h>
 #include <unwindstack/Elf.h>
-#include <unwindstack/JitDebug.h>
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
@@ -32,10 +32,6 @@
 #include "ElfFake.h"
 #include "MemoryFake.h"
 
-#if !defined(NO_LIBDEXFILE_SUPPORT)
-#include <DexFile.h>
-#endif
-
 namespace unwindstack {
 
 class DexFilesTest : public ::testing::Test {
@@ -52,7 +48,8 @@
   }
 
   void Init(ArchEnum arch) {
-    dex_files_ = JitDebug<DexFile>::Create(arch, process_memory_);
+    dex_files_.reset(new DexFiles(process_memory_));
+    dex_files_->SetArch(arch);
 
     maps_.reset(
         new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n"
@@ -89,11 +86,10 @@
     Init(ARCH_ARM);
   }
 
-  void WriteDescriptor32(uint64_t addr, uint32_t entry);
-  void WriteDescriptor64(uint64_t addr, uint64_t entry);
-  void WriteEntry32Pack(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex);
-  void WriteEntry32Pad(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex);
-  void WriteEntry64(uint64_t addr, uint64_t next, uint64_t prev, uint64_t dex);
+  void WriteDescriptor32(uint64_t addr, uint32_t head);
+  void WriteDescriptor64(uint64_t addr, uint64_t head);
+  void WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, uint32_t dex_file);
+  void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file);
   void WriteDex(uint64_t dex_file);
 
   static constexpr size_t kMapGlobalNonReadable = 2;
@@ -105,70 +101,40 @@
 
   std::shared_ptr<Memory> process_memory_;
   MemoryFake* memory_;
-  std::unique_ptr<JitDebug<DexFile>> dex_files_;
+  std::unique_ptr<DexFiles> dex_files_;
   std::unique_ptr<BufferMaps> maps_;
 };
 
-void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t entry) {
-  // Format of the 32 bit JITDescriptor structure:
-  //   uint32_t version
-  memory_->SetData32(addr, 1);
-  //   uint32_t action_flag
-  memory_->SetData32(addr + 4, 0);
-  //   uint32_t relevant_entry
-  memory_->SetData32(addr + 8, 0);
-  //   uint32_t first_entry
-  memory_->SetData32(addr + 12, entry);
+void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t head) {
+  //   void* first_entry_
+  memory_->SetData32(addr + 12, head);
 }
 
-void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t entry) {
-  // Format of the 64 bit JITDescriptor structure:
-  //   uint32_t version
-  memory_->SetData32(addr, 1);
-  //   uint32_t action_flag
-  memory_->SetData32(addr + 4, 0);
-  //   uint64_t relevant_entry
-  memory_->SetData64(addr + 8, 0);
-  //   uint64_t first_entry
-  memory_->SetData64(addr + 16, entry);
+void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t head) {
+  //   void* first_entry_
+  memory_->SetData64(addr + 16, head);
 }
 
-void DexFilesTest::WriteEntry32Pack(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex) {
-  // Format of the 32 bit JITCodeEntry structure:
+void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev,
+                                uint32_t dex_file) {
+  // Format of the 32 bit DEXFileEntry structure:
   //   uint32_t next
-  memory_->SetData32(addr, next);
+  memory_->SetData32(entry_addr, next);
   //   uint32_t prev
-  memory_->SetData32(addr + 4, prev);
-  //   uint32_t dex
-  memory_->SetData32(addr + 8, dex);
-  //   uint64_t symfile_size
-  memory_->SetData64(addr + 12, sizeof(kDexData) * sizeof(uint32_t));
+  memory_->SetData32(entry_addr + 4, prev);
+  //   uint32_t dex_file
+  memory_->SetData32(entry_addr + 8, dex_file);
 }
 
-void DexFilesTest::WriteEntry32Pad(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex) {
-  // Format of the 32 bit JITCodeEntry structure:
-  //   uint32_t next
-  memory_->SetData32(addr, next);
-  //   uint32_t prev
-  memory_->SetData32(addr + 4, prev);
-  //   uint32_t dex
-  memory_->SetData32(addr + 8, dex);
-  //   uint32_t pad
-  memory_->SetData32(addr + 12, 0);
-  //   uint64_t symfile_size
-  memory_->SetData64(addr + 16, sizeof(kDexData) * sizeof(uint32_t));
-}
-
-void DexFilesTest::WriteEntry64(uint64_t addr, uint64_t next, uint64_t prev, uint64_t dex) {
-  // Format of the 64 bit JITCodeEntry structure:
+void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev,
+                                uint64_t dex_file) {
+  // Format of the 64 bit DEXFileEntry structure:
   //   uint64_t next
-  memory_->SetData64(addr, next);
+  memory_->SetData64(entry_addr, next);
   //   uint64_t prev
-  memory_->SetData64(addr + 8, prev);
-  //   uint64_t dex
-  memory_->SetData64(addr + 16, dex);
-  //   uint64_t symfile_size
-  memory_->SetData64(addr + 24, sizeof(kDexData) * sizeof(uint32_t));
+  memory_->SetData64(entry_addr + 8, prev);
+  //   uint64_t dex_file
+  memory_->SetData64(entry_addr + 16, dex_file);
 }
 
 void DexFilesTest::WriteDex(uint64_t dex_file) {
@@ -178,8 +144,9 @@
 TEST_F(DexFilesTest, get_method_information_invalid) {
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFileEntries);
 
-  dex_files_->GetFunctionName(maps_.get(), 0, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset);
   EXPECT_EQ("nothing", method_name);
   EXPECT_EQ(0x124U, method_offset);
 }
@@ -187,12 +154,13 @@
 TEST_F(DexFilesTest, get_method_information_32) {
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
 
   WriteDescriptor32(0xf800, 0x200000);
-  WriteEntry32Pad(0x200000, 0, 0, 0x300000);
+  WriteEntry32(0x200000, 0, 0, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(0U, method_offset);
 }
@@ -202,12 +170,13 @@
 
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
 
   WriteDescriptor64(0xf800, 0x200000);
   WriteEntry64(0x200000, 0, 0, 0x301000);
   WriteDex(0x301000);
 
-  dex_files_->GetFunctionName(maps_.get(), 0x301102, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(2U, method_offset);
 }
@@ -215,14 +184,14 @@
 TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
 
   WriteDescriptor32(0xf800, 0x200000);
-  WriteEntry32Pad(0x200000, 0x200100, 0, 0x100000);
-  WriteDex(0x100000);
-  WriteEntry32Pad(0x200100, 0, 0x200000, 0x300000);
+  WriteEntry32(0x200000, 0x200100, 0, 0x100000);
+  WriteEntry32(0x200100, 0, 0x200000, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(4U, method_offset);
 }
@@ -232,14 +201,14 @@
 
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
 
   WriteDescriptor64(0xf800, 0x200000);
   WriteEntry64(0x200000, 0x200100, 0, 0x100000);
-  WriteDex(0x100000);
   WriteEntry64(0x200100, 0, 0x200000, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetFunctionName(maps_.get(), 0x300106, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(6U, method_offset);
 }
@@ -247,18 +216,19 @@
 TEST_F(DexFilesTest, get_method_information_cached) {
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
 
   WriteDescriptor32(0xf800, 0x200000);
-  WriteEntry32Pad(0x200000, 0, 0, 0x300000);
+  WriteEntry32(0x200000, 0, 0, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(0U, method_offset);
 
   // Clear all memory and make sure that data is acquired from the cache.
   memory_->Clear();
-  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(0U, method_offset);
 }
@@ -266,24 +236,26 @@
 TEST_F(DexFilesTest, get_method_information_search_libs) {
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
 
   WriteDescriptor32(0xf800, 0x200000);
-  WriteEntry32Pad(0x200000, 0x200100, 0, 0x100000);
-  WriteDex(0x100000);
-  WriteEntry32Pad(0x200100, 0, 0x200000, 0x300000);
+  WriteEntry32(0x200000, 0x200100, 0, 0x100000);
+  WriteEntry32(0x200100, 0, 0x200000, 0x300000);
   WriteDex(0x300000);
 
   // Only search a given named list of libs.
   std::vector<std::string> libs{"libart.so"};
-  dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_, libs);
+  dex_files_.reset(new DexFiles(process_memory_, libs));
+  dex_files_->SetArch(ARCH_ARM);
 
-  dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
   EXPECT_EQ("nothing", method_name);
   EXPECT_EQ(0x124U, method_offset);
 
   MapInfo* map_info = maps_->Get(kMapGlobal);
   map_info->name = "/system/lib/libart.so";
-  dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_, libs);
+  dex_files_.reset(new DexFiles(process_memory_, libs));
+  dex_files_->SetArch(ARCH_ARM);
   // Set the rw map to the same name or this will not scan this entry.
   map_info = maps_->Get(kMapGlobalRw);
   map_info->name = "/system/lib/libart.so";
@@ -291,7 +263,7 @@
   // DexFiles object.
   libs.clear();
 
-  dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(4U, method_offset);
 }
@@ -299,24 +271,26 @@
 TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
 
   // First global variable found, but value is zero.
   WriteDescriptor32(0xa800, 0);
 
   WriteDescriptor32(0xf800, 0x200000);
-  WriteEntry32Pad(0x200000, 0, 0, 0x300000);
+  WriteEntry32(0x200000, 0, 0, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(0U, method_offset);
 
   // Verify that second is ignored when first is set to non-zero
-  dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_);
+  dex_files_.reset(new DexFiles(process_memory_));
+  dex_files_->SetArch(ARCH_ARM);
   method_name = "fail";
   method_offset = 0x123;
   WriteDescriptor32(0xa800, 0x100000);
-  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("fail", method_name);
   EXPECT_EQ(0x123U, method_offset);
 }
@@ -326,6 +300,7 @@
 
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
 
   // First global variable found, but value is zero.
   WriteDescriptor64(0xa800, 0);
@@ -334,16 +309,17 @@
   WriteEntry64(0x200000, 0, 0, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(0U, method_offset);
 
   // Verify that second is ignored when first is set to non-zero
-  dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM64, process_memory_);
+  dex_files_.reset(new DexFiles(process_memory_));
+  dex_files_->SetArch(ARCH_ARM64);
   method_name = "fail";
   method_offset = 0x123;
   WriteDescriptor64(0xa800, 0x100000);
-  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("fail", method_name);
   EXPECT_EQ(0x123U, method_offset);
 }
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index 438194a..b1ca111 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -46,7 +46,8 @@
   }
 
   void Init(ArchEnum arch) {
-    jit_debug_ = JitDebug<Elf>::Create(arch, process_memory_);
+    jit_debug_.reset(new JitDebug(process_memory_));
+    jit_debug_->SetArch(arch);
 
     maps_.reset(
         new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf1\n"
@@ -61,12 +62,6 @@
                        "200000-210000 rw-p 0002000 00:00 0 /fake/elf4\n"));
     ASSERT_TRUE(maps_->Parse());
 
-    // Ensure all memory of the ELF file is initialized,
-    // otherwise reads within it may fail.
-    for (uint64_t addr = 0x4000; addr < 0x6000; addr += 8) {
-      memory_->SetData64(addr, 0);
-    }
-
     MapInfo* map_info = maps_->Get(3);
     ASSERT_TRUE(map_info != nullptr);
     CreateFakeElf(map_info);
@@ -99,7 +94,7 @@
     ehdr.e_shstrndx = 1;
     ehdr.e_shoff = sh_offset;
     ehdr.e_shentsize = sizeof(ShdrType);
-    ehdr.e_shnum = 4;
+    ehdr.e_shnum = 3;
     memory_->SetMemory(offset, &ehdr, sizeof(ehdr));
 
     ShdrType shdr;
@@ -115,7 +110,6 @@
     shdr.sh_size = 0x100;
     memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
     memory_->SetMemory(offset + 0x500, ".debug_frame");
-    memory_->SetMemory(offset + 0x550, ".text");
 
     sh_offset += sizeof(shdr);
     memset(&shdr, 0, sizeof(shdr));
@@ -126,15 +120,6 @@
     shdr.sh_size = 0x200;
     memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
 
-    sh_offset += sizeof(shdr);
-    memset(&shdr, 0, sizeof(shdr));
-    shdr.sh_type = SHT_NOBITS;
-    shdr.sh_name = 0x50;
-    shdr.sh_addr = pc;
-    shdr.sh_offset = 0;
-    shdr.sh_size = size;
-    memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
-
     // Now add a single cie/fde.
     uint64_t dwarf_offset = offset + 0x600;
     if (class_type == ELFCLASS32) {
@@ -183,7 +168,7 @@
 
   std::shared_ptr<Memory> process_memory_;
   MemoryFake* memory_;
-  std::unique_ptr<JitDebug<Elf>> jit_debug_;
+  std::unique_ptr<JitDebug> jit_debug_;
   std::unique_ptr<BufferMaps> maps_;
 };
 
@@ -253,20 +238,20 @@
 }
 
 TEST_F(JitDebugTest, get_elf_invalid) {
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
 TEST_F(JitDebugTest, get_elf_no_global_variable) {
   maps_.reset(new BufferMaps(""));
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
 TEST_F(JitDebugTest, get_elf_no_valid_descriptor_in_memory) {
   CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);
 
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
@@ -275,7 +260,7 @@
 
   WriteDescriptor32(0xf800, 0x200000);
 
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
@@ -284,7 +269,7 @@
 
   WriteDescriptor32(0xf800, 0);
 
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
@@ -295,7 +280,7 @@
   // Set the version to an invalid value.
   memory_->SetData32(0xf800, 2);
 
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
@@ -305,18 +290,12 @@
   WriteDescriptor32(0xf800, 0x200000);
   WriteEntry32Pad(0x200000, 0, 0, 0x4000, 0x1000);
 
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf != nullptr);
-  uint64_t text_addr;
-  uint64_t text_size;
-  ASSERT_TRUE(elf->GetTextRange(&text_addr, &text_size));
-  ASSERT_EQ(text_addr, 0x1500u);
-  ASSERT_EQ(text_size, 0x200u);
 
   // Clear the memory and verify all of the data is cached.
   memory_->Clear();
-  WriteDescriptor32(0xf800, 0x200000);
-  Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf2 != nullptr);
   EXPECT_EQ(elf, elf2);
 }
@@ -330,15 +309,16 @@
   WriteDescriptor32(0x12800, 0x201000);
   WriteEntry32Pad(0x201000, 0, 0, 0x5000, 0x1000);
 
-  ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) != nullptr);
-  ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x2000) == nullptr);
+  ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr);
+  ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) == nullptr);
 
   // Now clear the descriptor entry for the first one.
   WriteDescriptor32(0xf800, 0);
-  jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_);
+  jit_debug_.reset(new JitDebug(process_memory_));
+  jit_debug_->SetArch(ARCH_ARM);
 
-  ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) == nullptr);
-  ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x2000) != nullptr);
+  ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) == nullptr);
+  ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) != nullptr);
 }
 
 TEST_F(JitDebugTest, get_elf_x86) {
@@ -349,14 +329,13 @@
   WriteDescriptor32(0xf800, 0x200000);
   WriteEntry32Pack(0x200000, 0, 0, 0x4000, 0x1000);
 
-  jit_debug_ = JitDebug<Elf>::Create(ARCH_X86, process_memory_);
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  jit_debug_->SetArch(ARCH_X86);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf != nullptr);
 
   // Clear the memory and verify all of the data is cached.
   memory_->Clear();
-  WriteDescriptor32(0xf800, 0x200000);
-  Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf2 != nullptr);
   EXPECT_EQ(elf, elf2);
 }
@@ -369,13 +348,12 @@
   WriteDescriptor64(0xf800, 0x200000);
   WriteEntry64(0x200000, 0, 0, 0x4000, 0x1000);
 
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf != nullptr);
 
   // Clear the memory and verify all of the data is cached.
   memory_->Clear();
-  WriteDescriptor64(0xf800, 0x200000);
-  Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf2 != nullptr);
   EXPECT_EQ(elf, elf2);
 }
@@ -388,21 +366,20 @@
   WriteEntry32Pad(0x200000, 0, 0x200100, 0x4000, 0x1000);
   WriteEntry32Pad(0x200100, 0x200100, 0, 0x5000, 0x1000);
 
-  Elf* elf_2 = jit_debug_->Get(maps_.get(), 0x2400);
+  Elf* elf_2 = jit_debug_->GetElf(maps_.get(), 0x2400);
   ASSERT_TRUE(elf_2 != nullptr);
 
-  Elf* elf_1 = jit_debug_->Get(maps_.get(), 0x1600);
+  Elf* elf_1 = jit_debug_->GetElf(maps_.get(), 0x1600);
   ASSERT_TRUE(elf_1 != nullptr);
 
   // Clear the memory and verify all of the data is cached.
   memory_->Clear();
-  WriteDescriptor32(0xf800, 0x200000);
-  EXPECT_EQ(elf_1, jit_debug_->Get(maps_.get(), 0x1500));
-  EXPECT_EQ(elf_1, jit_debug_->Get(maps_.get(), 0x16ff));
-  EXPECT_EQ(elf_2, jit_debug_->Get(maps_.get(), 0x2300));
-  EXPECT_EQ(elf_2, jit_debug_->Get(maps_.get(), 0x26ff));
-  EXPECT_EQ(nullptr, jit_debug_->Get(maps_.get(), 0x1700));
-  EXPECT_EQ(nullptr, jit_debug_->Get(maps_.get(), 0x2700));
+  EXPECT_EQ(elf_1, jit_debug_->GetElf(maps_.get(), 0x1500));
+  EXPECT_EQ(elf_1, jit_debug_->GetElf(maps_.get(), 0x16ff));
+  EXPECT_EQ(elf_2, jit_debug_->GetElf(maps_.get(), 0x2300));
+  EXPECT_EQ(elf_2, jit_debug_->GetElf(maps_.get(), 0x26ff));
+  EXPECT_EQ(nullptr, jit_debug_->GetElf(maps_.get(), 0x1700));
+  EXPECT_EQ(nullptr, jit_debug_->GetElf(maps_.get(), 0x2700));
 }
 
 TEST_F(JitDebugTest, get_elf_search_libs) {
@@ -413,19 +390,21 @@
 
   // Only search a given named list of libs.
   std::vector<std::string> libs{"libart.so"};
-  jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_, libs);
-  EXPECT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) == nullptr);
+  jit_debug_.reset(new JitDebug(process_memory_, libs));
+  jit_debug_->SetArch(ARCH_ARM);
+  EXPECT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) == nullptr);
 
   // Change the name of the map that includes the value and verify this works.
   MapInfo* map_info = maps_->Get(5);
   map_info->name = "/system/lib/libart.so";
   map_info = maps_->Get(6);
   map_info->name = "/system/lib/libart.so";
-  jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_);
+  jit_debug_.reset(new JitDebug(process_memory_, libs));
   // Make sure that clearing our copy of the libs doesn't affect the
   // JitDebug object.
   libs.clear();
-  EXPECT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) != nullptr);
+  jit_debug_->SetArch(ARCH_ARM);
+  EXPECT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr);
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index e3c646a..02ba9c8 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -307,7 +307,9 @@
   }
   process_memory_.reset(memory);
 
+  JitDebug jit_debug(process_memory_);
   Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.SetJitDebug(&jit_debug, regs_->Arch());
   unwinder.Unwind();
 
   std::string frame_info(DumpFrames(unwinder));
@@ -607,7 +609,9 @@
   }
   process_memory_.reset(memory);
 
+  JitDebug jit_debug(process_memory_);
   Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.SetJitDebug(&jit_debug, regs_->Arch());
   unwinder.Unwind();
 
   std::string frame_info(DumpFrames(unwinder));
@@ -928,7 +932,9 @@
   LeakType* leak_data = reinterpret_cast<LeakType*>(data);
 
   std::unique_ptr<Regs> regs_copy(leak_data->regs->Clone());
+  JitDebug jit_debug(leak_data->process_memory);
   Unwinder unwinder(128, leak_data->maps, regs_copy.get(), leak_data->process_memory);
+  unwinder.SetJitDebug(&jit_debug, regs_copy->Arch());
   unwinder.Unwind();
   ASSERT_EQ(76U, unwinder.NumFrames());
 }
@@ -1049,7 +1055,9 @@
   }
   process_memory_.reset(memory);
 
+  JitDebug jit_debug(process_memory_);
   Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.SetJitDebug(&jit_debug, regs_->Arch());
   unwinder.Unwind();
 
   std::string frame_info(DumpFrames(unwinder));
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 5e7e6bf..4e38015 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -170,7 +170,7 @@
     unwinder.reset(new Unwinder(512, maps.get(), regs.get(), process_memory));
   } else {
     UnwinderFromPid* unwinder_from_pid = new UnwinderFromPid(512, getpid());
-    ASSERT_TRUE(unwinder_from_pid->Init());
+    ASSERT_TRUE(unwinder_from_pid->Init(regs->Arch()));
     unwinder_from_pid->SetRegs(regs.get());
     unwinder.reset(unwinder_from_pid);
   }
@@ -283,7 +283,7 @@
   ASSERT_TRUE(regs.get() != nullptr);
 
   UnwinderFromPid unwinder(512, pid);
-  ASSERT_TRUE(unwinder.Init());
+  ASSERT_TRUE(unwinder.Init(regs->Arch()));
   unwinder.SetRegs(regs.get());
 
   VerifyUnwind(&unwinder, kFunctionOrder);
@@ -335,7 +335,7 @@
   ASSERT_TRUE(regs.get() != nullptr);
 
   UnwinderFromPid unwinder(512, *pid);
-  ASSERT_TRUE(unwinder.Init());
+  ASSERT_TRUE(unwinder.Init(regs->Arch()));
   unwinder.SetRegs(regs.get());
 
   VerifyUnwind(&unwinder, kFunctionOrder);
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index cad95f8..1812e50 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <unwindstack/DexFiles.h>
 #include <unwindstack/Elf.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
@@ -89,7 +90,7 @@
   printf("\n");
 
   unwindstack::UnwinderFromPid unwinder(1024, pid);
-  if (!unwinder.Init()) {
+  if (!unwinder.Init(regs->Arch())) {
     printf("Failed to init unwinder object.\n");
     return;
   }
diff --git a/libunwindstack/tools/unwind_for_offline.cpp b/libunwindstack/tools/unwind_for_offline.cpp
index 86f3163..4f67d67 100644
--- a/libunwindstack/tools/unwind_for_offline.cpp
+++ b/libunwindstack/tools/unwind_for_offline.cpp
@@ -248,7 +248,7 @@
   // Do an unwind so we know how much of the stack to save, and what
   // elf files are involved.
   unwindstack::UnwinderFromPid unwinder(1024, pid);
-  if (!unwinder.Init()) {
+  if (!unwinder.Init(regs->Arch())) {
     printf("Unable to init unwinder object.\n");
     return 1;
   }
diff --git a/libvndksupport/Android.bp b/libvndksupport/Android.bp
index bfa2508..546c15c 100644
--- a/libvndksupport/Android.bp
+++ b/libvndksupport/Android.bp
@@ -9,7 +9,10 @@
     ],
     local_include_dirs: ["include/vndksupport"],
     export_include_dirs: ["include"],
-    shared_libs: ["liblog"],
+    shared_libs: [
+        "libdl_android",
+        "liblog",
+    ],
     version_script: "libvndksupport.map.txt",
     stubs: {
         symbol_file: "libvndksupport.map.txt",
diff --git a/libziparchive/unzip.cpp b/libziparchive/unzip.cpp
index 6756007..cc059d8 100644
--- a/libziparchive/unzip.cpp
+++ b/libziparchive/unzip.cpp
@@ -17,6 +17,7 @@
 #include <errno.h>
 #include <error.h>
 #include <fcntl.h>
+#include <fnmatch.h>
 #include <getopt.h>
 #include <inttypes.h>
 #include <stdio.h>
@@ -52,9 +53,21 @@
 static uint64_t total_compressed_length = 0;
 static size_t file_count = 0;
 
-static bool Filter(const std::string& name) {
-  if (!excludes.empty() && excludes.find(name) != excludes.end()) return true;
-  if (!includes.empty() && includes.find(name) == includes.end()) return true;
+static bool ShouldInclude(const std::string& name) {
+  // Explicitly excluded?
+  if (!excludes.empty()) {
+    for (const auto& exclude : excludes) {
+      if (!fnmatch(exclude.c_str(), name.c_str(), 0)) return false;
+    }
+  }
+
+  // Implicitly included?
+  if (includes.empty()) return true;
+
+  // Explicitly included?
+  for (const auto& include : includes) {
+    if (!fnmatch(include.c_str(), name.c_str(), 0)) return true;
+  }
   return false;
 }
 
@@ -245,7 +258,7 @@
   ZipString string;
   while ((err = Next(cookie, &entry, &string)) >= 0) {
     std::string name(string.name, string.name + string.name_length);
-    if (!Filter(name)) ProcessOne(zah, entry, name);
+    if (ShouldInclude(name)) ProcessOne(zah, entry, name);
   }
 
   if (err < -1) error(1, 0, "failed iterating %s: %s", archive_name, ErrorCodeString(err));
@@ -260,7 +273,8 @@
 
   printf(
       "\n"
-      "Extract FILEs from ZIP archive. Default is all files.\n"
+      "Extract FILEs from ZIP archive. Default is all files. Both the include and\n"
+      "exclude (-x) lists use shell glob patterns.\n"
       "\n"
       "-d DIR	Extract into DIR\n"
       "-l	List contents (-lq excludes archive name, -lv is verbose)\n"
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 0710d0a..e1ec47a 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -102,21 +102,8 @@
 }
 
 static uint32_t ComputeHash(const ZipString& name) {
-#if !defined(_WIN32)
-  return std::hash<std::string_view>{}(
-      std::string_view(reinterpret_cast<const char*>(name.name), name.name_length));
-#else
-  // Remove this code path once the windows compiler knows how to compile the above statement.
-  uint32_t hash = 0;
-  uint16_t len = name.name_length;
-  const uint8_t* str = name.name;
-
-  while (len--) {
-    hash = hash * 31 + *str++;
-  }
-
-  return hash;
-#endif
+  return static_cast<uint32_t>(std::hash<std::string_view>{}(
+      std::string_view(reinterpret_cast<const char*>(name.name), name.name_length)));
 }
 
 static bool isZipStringEqual(const uint8_t* start, const ZipString& zip_string,
diff --git a/libziparchive/zip_writer_test.cc b/libziparchive/zip_writer_test.cc
index c284273..7322afb 100644
--- a/libziparchive/zip_writer_test.cc
+++ b/libziparchive/zip_writer_test.cc
@@ -257,7 +257,7 @@
   std::vector<uint8_t> buffer(kBufSize);
   size_t prev = 1;
   for (size_t i = 0; i < kBufSize; i++) {
-    buffer[i] = i + prev;
+    buffer[i] = static_cast<uint8_t>(i + prev);
     prev = i;
   }
 
diff --git a/logd/Android.bp b/logd/Android.bp
index 360f2fe..9b86258 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -80,6 +80,24 @@
     cflags: ["-Werror"],
 }
 
+cc_binary {
+    name: "auditctl",
+
+    srcs: ["auditctl.cpp"],
+
+    static_libs: [
+        "liblogd",
+    ],
+
+    shared_libs: ["libbase"],
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wconversion"
+    ],
+}
 
 prebuilt_etc {
     name: "logtagd.rc",
diff --git a/logd/auditctl.cpp b/logd/auditctl.cpp
new file mode 100644
index 0000000..98bb02d
--- /dev/null
+++ b/logd/auditctl.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/parseint.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "libaudit.h"
+
+static void usage(const char* cmdline) {
+    fprintf(stderr, "Usage: %s [-r rate]\n", cmdline);
+}
+
+static void do_update_rate(uint32_t rate) {
+    int fd = audit_open();
+    if (fd == -1) {
+        error(EXIT_FAILURE, errno, "Unable to open audit socket");
+    }
+    int result = audit_rate_limit(fd, rate);
+    close(fd);
+    if (result < 0) {
+        fprintf(stderr, "Can't update audit rate limit: %d\n", result);
+        exit(EXIT_FAILURE);
+    }
+}
+
+int main(int argc, char* argv[]) {
+    uint32_t rate = 0;
+    bool update_rate = false;
+    int opt;
+
+    while ((opt = getopt(argc, argv, "r:")) != -1) {
+        switch (opt) {
+            case 'r':
+                if (!android::base::ParseUint<uint32_t>(optarg, &rate)) {
+                    error(EXIT_FAILURE, errno, "Invalid Rate");
+                }
+                update_rate = true;
+                break;
+            default: /* '?' */
+                usage(argv[0]);
+                exit(EXIT_FAILURE);
+        }
+    }
+
+    // In the future, we may add other options to auditctl
+    // so this if statement will expand.
+    // if (!update_rate && !update_backlog && !update_whatever) ...
+    if (!update_rate) {
+        fprintf(stderr, "Nothing to do\n");
+        usage(argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    if (update_rate) {
+        do_update_rate(rate);
+    }
+
+    return 0;
+}
diff --git a/logd/libaudit.c b/logd/libaudit.c
index 9d9a857..f452c71 100644
--- a/logd/libaudit.c
+++ b/logd/libaudit.c
@@ -160,8 +160,7 @@
      * and the the mask set to AUDIT_STATUS_PID
      */
     status.pid = pid;
-    status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT;
-    status.rate_limit = AUDIT_RATE_LIMIT; /* audit entries per second */
+    status.mask = AUDIT_STATUS_PID;
 
     /* Let the kernel know this pid will be registering for audit events */
     rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
@@ -188,6 +187,14 @@
     return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT);
 }
 
+int audit_rate_limit(int fd, uint32_t limit) {
+    struct audit_status status;
+    memset(&status, 0, sizeof(status));
+    status.mask = AUDIT_STATUS_RATE_LIMIT;
+    status.rate_limit = limit; /* audit entries per second */
+    return audit_send(fd, AUDIT_SET, &status, sizeof(status));
+}
+
 int audit_get_reply(int fd, struct audit_message* rep, reply_t block, int peek) {
     ssize_t len;
     int flags;
diff --git a/logd/libaudit.h b/logd/libaudit.h
index 2a93ea3..b4a92a8 100644
--- a/logd/libaudit.h
+++ b/logd/libaudit.h
@@ -89,8 +89,17 @@
  */
 extern int audit_setup(int fd, pid_t pid);
 
-/* Max audit messages per second  */
-#define AUDIT_RATE_LIMIT 5
+/**
+ * Throttle kernel messages at the provided rate
+ * @param fd
+ *  The fd returned by a call to audit_open()
+ * @param rate
+ *  The rate, in messages per second, above which the kernel
+ *  should drop audit messages.
+ * @return
+ *  This function returns 0 on success, -errno on error.
+ */
+extern int audit_rate_limit(int fd, uint32_t limit);
 
 __END_DECLS
 
diff --git a/logd/logd.rc b/logd/logd.rc
index c740ecf..438419a 100644
--- a/logd/logd.rc
+++ b/logd/logd.rc
@@ -16,8 +16,19 @@
     group logd
     writepid /dev/cpuset/system-background/tasks
 
+# Limit SELinux denial generation to 5/second
+service logd-auditctl /system/bin/auditctl -r 5
+    oneshot
+    disabled
+    user logd
+    group logd
+    capabilities AUDIT_CONTROL
+
 on fs
     write /dev/event-log-tags "# content owned by logd
 "
     chown logd logd /dev/event-log-tags
     chmod 0644 /dev/event-log-tags
+
+on property:sys.boot_completed=1
+    start logd-auditctl
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 7d7a22f..447b067 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -39,7 +39,6 @@
 #endif
 
 #include "../LogReader.h"  // pickup LOGD_SNDTIMEO
-#include "../libaudit.h"   // pickup AUDIT_RATE_LIMIT_*
 
 #ifdef __ANDROID__
 static void send_to_control(char* buf, size_t len) {
@@ -1065,145 +1064,3 @@
 TEST(logd, multiple_test_10) {
     __android_log_btwrite_multiple__helper(10);
 }
-
-#ifdef __ANDROID__
-// returns violating pid
-static pid_t sepolicy_rate(unsigned rate, unsigned num) {
-    pid_t pid = fork();
-
-    if (pid) {
-        siginfo_t info = {};
-        if (TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED))) return -1;
-        if (info.si_status) return -1;
-        return pid;
-    }
-
-    // We may have DAC, but let's not have MAC
-    if ((setcon("u:object_r:shell:s0") < 0) && (setcon("u:r:shell:s0") < 0)) {
-        int save_errno = errno;
-        security_context_t context;
-        getcon(&context);
-        if (strcmp(context, "u:r:shell:s0")) {
-            fprintf(stderr, "setcon(\"u:r:shell:s0\") failed @\"%s\" %s\n",
-                    context, strerror(save_errno));
-            freecon(context);
-            _exit(-1);
-            // NOTREACHED
-            return -1;
-        }
-    }
-
-    // The key here is we are root, but we are in u:r:shell:s0,
-    // and the directory does not provide us DAC access
-    // (eg: 0700 system system) so we trigger the pair dac_override
-    // and dac_read_search on every try to get past the message
-    // de-duper.  We will also rotate the file name in the directory
-    // as another measure.
-    static const char file[] = "/data/drm/cannot_access_directory_%u";
-    static const unsigned avc_requests_per_access = 2;
-
-    rate /= avc_requests_per_access;
-    useconds_t usec;
-    if (rate == 0) {
-        rate = 1;
-        usec = 2000000;
-    } else {
-        usec = (1000000 + (rate / 2)) / rate;
-    }
-    num = (num + (avc_requests_per_access / 2)) / avc_requests_per_access;
-
-    if (usec < 2) usec = 2;
-
-    while (num > 0) {
-        if (access(android::base::StringPrintf(file, num).c_str(), F_OK) == 0) {
-            _exit(-1);
-            // NOTREACHED
-            return -1;
-        }
-        usleep(usec);
-        --num;
-    }
-    _exit(0);
-    // NOTREACHED
-    return -1;
-}
-
-static constexpr int background_period = 10;
-
-static int count_avc(pid_t pid) {
-    int count = 0;
-
-    // pid=-1 skip as pid is in error
-    if (pid == (pid_t)-1) return count;
-
-    // pid=0 means we want to report the background count of avc: activities
-    struct logger_list* logger_list =
-        pid ? android_logger_list_alloc(
-                  ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, pid)
-            : android_logger_list_alloc_time(
-                  ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
-                  log_time(android_log_clockid()) -
-                      log_time(background_period, 0),
-                  0);
-    if (!logger_list) return count;
-    struct logger* logger = android_logger_open(logger_list, LOG_ID_EVENTS);
-    if (!logger) {
-        android_logger_list_close(logger_list);
-        return count;
-    }
-    for (;;) {
-        log_msg log_msg;
-
-        if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
-
-        if ((log_msg.entry.pid != pid) || (log_msg.entry.len < (4 + 1 + 8)) ||
-            (log_msg.id() != LOG_ID_EVENTS))
-            continue;
-
-        char* eventData = log_msg.msg();
-        if (!eventData) continue;
-
-        uint32_t tag = get4LE(eventData);
-        if (tag != AUDITD_LOG_TAG) continue;
-
-        if (eventData[4] != EVENT_TYPE_STRING) continue;
-
-        // int len = get4LE(eventData + 4 + 1);
-        log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0';
-        const char* cp = strstr(eventData + 4 + 1 + 4, "): avc: denied");
-        if (!cp) continue;
-
-        ++count;
-    }
-
-    android_logger_list_close(logger_list);
-
-    return count;
-}
-#endif
-
-TEST(logd, sepolicy_rate_limiter) {
-#ifdef __ANDROID__
-    int background_selinux_activity_too_high = count_avc(0);
-    if (background_selinux_activity_too_high > 2) {
-        GTEST_LOG_(ERROR) << "Too much background selinux activity "
-                          << background_selinux_activity_too_high * 60 /
-                                 background_period
-                          << "/minute on the device, this test\n"
-                          << "can not measure the functionality of the "
-                          << "sepolicy rate limiter.  Expect test to\n"
-                          << "fail as this device is in a bad state, "
-                          << "but is not strictly a unit test failure.";
-    }
-
-    static const int rate = AUDIT_RATE_LIMIT;
-    static const int duration = 2;
-    // Two seconds of sustained denials. Depending on the overlap in the time
-    // window that the kernel is considering vs what this test is considering,
-    // allow some additional denials to prevent a flaky test.
-    EXPECT_LE(count_avc(sepolicy_rate(rate, rate * duration)),
-              rate * duration + rate);
-#else
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 5d307b8..462ae8b 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -89,7 +89,7 @@
 
 EXPORT_GLOBAL_GCOV_OPTIONS :=
 ifeq ($(NATIVE_COVERAGE),true)
-  EXPORT_GLOBAL_GCOV_OPTIONS := export GCOV_PREFIX /data/misc/gcov
+  EXPORT_GLOBAL_GCOV_OPTIONS := export GCOV_PREFIX /data/misc/trace
 endif
 
 # Put it here instead of in init.rc module definition,
diff --git a/rootdir/fsverity_init.sh b/rootdir/fsverity_init.sh
index 29e4519..4fee15f 100644
--- a/rootdir/fsverity_init.sh
+++ b/rootdir/fsverity_init.sh
@@ -24,6 +24,9 @@
     log -p e -t fsverity_init "Failed to load $cert"
 done
 
-# Prevent future key links to .fs-verity keyring
-/system/bin/mini-keyctl restrict_keyring .fs-verity ||
-  log -p e -t fsverity_init "Failed to restrict .fs-verity keyring"
+DEBUGGABLE=$(getprop ro.debuggable)
+if [ $DEBUGGABLE != "1" ]; then
+  # Prevent future key links to .fs-verity keyring
+  /system/bin/mini-keyctl restrict_keyring .fs-verity ||
+    log -p e -t fsverity_init "Failed to restrict .fs-verity keyring"
+fi
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 473cd8d..e94b8e2 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -280,6 +280,11 @@
     write /dev/cpu_variant:${ro.bionic.2nd_arch} ${ro.bionic.2nd_cpu_variant}
     chmod 0444 /dev/cpu_variant:${ro.bionic.2nd_arch}
 
+    # Allow system processes to read / write power state.
+    chown system system /sys/power/state
+    chown system system /sys/power/wakeup_count
+    chmod 0660 /sys/power/state
+
     # Start logd before any other services run to ensure we capture all of their logs.
     start logd
 
@@ -665,11 +670,8 @@
     chown radio system /sys/android_power/acquire_partial_wake_lock
     chown radio system /sys/android_power/release_wake_lock
     chown system system /sys/power/autosleep
-    chown system system /sys/power/state
-    chown system system /sys/power/wakeup_count
     chown radio wakelock /sys/power/wake_lock
     chown radio wakelock /sys/power/wake_unlock
-    chmod 0660 /sys/power/state
     chmod 0660 /sys/power/wake_lock
     chmod 0660 /sys/power/wake_unlock
 
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index f01a8c7..3bc3883 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -10,6 +10,7 @@
 phony {
     name: "shell_and_utilities_system",
     required: [
+        "auditctl",
         "awk",
         "bzip2",
         "grep",
diff --git a/toolbox/Android.bp b/toolbox/Android.bp
index 1f852ff..5289976 100644
--- a/toolbox/Android.bp
+++ b/toolbox/Android.bp
@@ -56,14 +56,6 @@
     defaults: ["toolbox_binary_defaults"],
 }
 
-// We only want 'r' on userdebug and eng builds.
-cc_binary {
-    name: "r",
-    defaults: ["toolbox_defaults"],
-    srcs: ["r.c"],
-    vendor_available: true,
-}
-
 // We build BSD grep separately (but see http://b/111849261).
 cc_defaults {
     name: "grep_common",
diff --git a/toolbox/r.c b/toolbox/r.c
deleted file mode 100644
index b96cdb2..0000000
--- a/toolbox/r.c
+++ /dev/null
@@ -1,102 +0,0 @@
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#if __LP64__
-#define strtoptr strtoull
-#else
-#define strtoptr strtoul
-#endif
-
-static int usage()
-{
-    fprintf(stderr,"r [-b|-s] <address> [<value>]\n");
-    return -1;
-}
-
-int main(int argc, char *argv[])
-{
-    if(argc < 2) return usage();
-
-    int width = 4;
-    if(!strcmp(argv[1], "-b")) {
-        width = 1;
-        argc--;
-        argv++;
-    } else if(!strcmp(argv[1], "-s")) {
-        width = 2;
-        argc--;
-        argv++;
-    }
-
-    if(argc < 2) return usage();
-    uintptr_t addr = strtoptr(argv[1], 0, 16);
-
-    uintptr_t endaddr = 0;
-    char* end = strchr(argv[1], '-');
-    if (end)
-        endaddr = strtoptr(end + 1, 0, 16);
-
-    if (!endaddr)
-        endaddr = addr + width - 1;
-
-    if (endaddr <= addr) {
-        fprintf(stderr, "end address <= start address\n");
-        return -1;
-    }
-
-    bool set = false;
-    uint32_t value = 0;
-    if(argc > 2) {
-        set = true;
-        value = strtoul(argv[2], 0, 16);
-    }
-
-    int fd = open("/dev/mem", O_RDWR | O_SYNC);
-    if(fd < 0) {
-        fprintf(stderr,"cannot open /dev/mem\n");
-        return -1;
-    }
-
-    off64_t mmap_start = addr & ~(PAGE_SIZE - 1);
-    size_t mmap_size = endaddr - mmap_start + 1;
-    mmap_size = (mmap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-
-    void* page = mmap64(0, mmap_size, PROT_READ | PROT_WRITE,
-                        MAP_SHARED, fd, mmap_start);
-
-    if(page == MAP_FAILED){
-        fprintf(stderr,"cannot mmap region\n");
-        return -1;
-    }
-
-    while (addr <= endaddr) {
-        switch(width){
-        case 4: {
-            uint32_t* x = (uint32_t*) (((uintptr_t) page) + (addr & 4095));
-            if(set) *x = value;
-            fprintf(stderr,"%08"PRIxPTR": %08x\n", addr, *x);
-            break;
-        }
-        case 2: {
-            uint16_t* x = (uint16_t*) (((uintptr_t) page) + (addr & 4095));
-            if(set) *x = value;
-            fprintf(stderr,"%08"PRIxPTR": %04x\n", addr, *x);
-            break;
-        }
-        case 1: {
-            uint8_t* x = (uint8_t*) (((uintptr_t) page) + (addr & 4095));
-            if(set) *x = value;
-            fprintf(stderr,"%08"PRIxPTR": %02x\n", addr, *x);
-            break;
-        }
-        }
-        addr += width;
-    }
-    return 0;
-}
diff --git a/trusty/trusty-base.mk b/trusty/trusty-base.mk
index 0a0ecec..00e3dbc 100644
--- a/trusty/trusty-base.mk
+++ b/trusty/trusty-base.mk
@@ -19,8 +19,13 @@
 # to pull in the baseline set of Trusty specific modules.
 #
 
+# For gatekeeper, we include the generic -service and -impl to use legacy
+# HAL loading of gatekeeper.trusty.
+
 PRODUCT_PACKAGES += \
 	android.hardware.keymaster@3.0-service.trusty \
+	android.hardware.gatekeeper@1.0-service \
+	android.hardware.gatekeeper@1.0-impl \
 	gatekeeper.trusty
 
 PRODUCT_PROPERTY_OVERRIDES += \