Merge "init: add TODO for mount operations."
diff --git a/adb/Android.mk b/adb/Android.mk
index 0eeafb6..e52f0cb 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -11,6 +11,7 @@
 adb_target_sanitize :=
 
 ADB_COMMON_CFLAGS := \
+    -frtti \
     -Wall -Wextra -Werror \
     -Wno-unused-parameter \
     -Wno-missing-field-initializers \
diff --git a/adb/adb.h b/adb/adb.h
index 21e5d4b..b5d6bcb 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -136,9 +136,6 @@
 int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd);
 
 /* initialize a transport object's func pointers and state */
-#if ADB_HOST
-int get_available_local_transport_index();
-#endif
 int init_socket_transport(atransport* t, int s, int port, int local);
 void init_usb_transport(atransport* t, usb_handle* usb);
 
diff --git a/adb/services.cpp b/adb/services.cpp
index aff7012..6dc71cf 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -407,14 +407,6 @@
         return;
     }
 
-    // Check if more emulators can be registered. Similar unproblematic
-    // race condition as above.
-    int candidate_slot = get_available_local_transport_index();
-    if (candidate_slot < 0) {
-        *response = "Cannot accept more emulators";
-        return;
-    }
-
     // Preconditions met, try to connect to the emulator.
     std::string error;
     if (!local_connect_arbitrary_ports(console_port, adb_port, &error)) {
diff --git a/adb/transport.cpp b/adb/transport.cpp
index f221785..5acaaec 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -41,6 +41,7 @@
 
 #include "adb.h"
 #include "adb_auth.h"
+#include "adb_io.h"
 #include "adb_trace.h"
 #include "adb_utils.h"
 #include "diagnose_usb.h"
@@ -65,6 +66,36 @@
     return next++;
 }
 
+bool FdConnection::Read(apacket* packet) {
+    if (!ReadFdExactly(fd_.get(), &packet->msg, sizeof(amessage))) {
+        D("remote local: read terminated (message)");
+        return false;
+    }
+
+    if (!ReadFdExactly(fd_.get(), &packet->data, packet->msg.data_length)) {
+        D("remote local: terminated (data)");
+        return false;
+    }
+
+    return true;
+}
+
+bool FdConnection::Write(apacket* packet) {
+    uint32_t length = packet->msg.data_length;
+
+    if (!WriteFdExactly(fd_.get(), &packet->msg, sizeof(amessage) + length)) {
+        D("remote local: write terminated");
+        return false;
+    }
+
+    return true;
+}
+
+void FdConnection::Close() {
+    adb_shutdown(fd_.get());
+    fd_.reset();
+}
+
 static std::string dump_packet(const char* name, const char* func, apacket* p) {
     unsigned command = p->msg.command;
     int len = p->msg.data_length;
@@ -220,13 +251,21 @@
 
         {
             ATRACE_NAME("read_transport read_remote");
-            if (t->read_from_remote(p, t) != 0) {
+            if (!t->connection->Read(p)) {
                 D("%s: remote read failed for transport", t->serial);
                 put_apacket(p);
                 break;
             }
+
+            if (!check_header(p, t)) {
+                D("%s: remote read: bad header", t->serial);
+                put_apacket(p);
+                break;
+            }
+
 #if ADB_HOST
             if (p->msg.command == 0) {
+                put_apacket(p);
                 continue;
             }
 #endif
@@ -625,7 +664,7 @@
     t->ref_count--;
     if (t->ref_count == 0) {
         D("transport: %s unref (kicking and closing)", t->serial);
-        t->close(t);
+        t->connection->Close();
         remove_transport(t);
     } else {
         D("transport: %s unref (count=%zu)", t->serial, t->ref_count);
@@ -753,14 +792,14 @@
 }
 
 int atransport::Write(apacket* p) {
-    return write_func_(p, this);
+    return this->connection->Write(p) ? 0 : -1;
 }
 
 void atransport::Kick() {
     if (!kicked_) {
+        D("kicking transport %s", this->serial);
         kicked_ = true;
-        CHECK(kick_func_ != nullptr);
-        kick_func_(this);
+        this->connection->Close();
     }
 }
 
@@ -1082,8 +1121,12 @@
 // This should only be used for transports with connection_state == kCsNoPerm.
 void unregister_usb_transport(usb_handle* usb) {
     std::lock_guard<std::recursive_mutex> lock(transport_lock);
-    transport_list.remove_if(
-        [usb](atransport* t) { return t->usb == usb && t->GetConnectionState() == kCsNoPerm; });
+    transport_list.remove_if([usb](atransport* t) {
+        if (auto connection = dynamic_cast<UsbConnection*>(t->connection.get())) {
+            return connection->handle_ == usb && t->GetConnectionState() == kCsNoPerm;
+        }
+        return false;
+    });
 }
 
 bool check_header(apacket* p, atransport* t) {
diff --git a/adb/transport.h b/adb/transport.h
index 86cd992..9700f44 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -28,10 +28,11 @@
 #include <string>
 #include <unordered_set>
 
-#include "adb.h"
-
 #include <openssl/rsa.h>
 
+#include "adb.h"
+#include "adb_unique_fd.h"
+
 typedef std::unordered_set<std::string> FeatureSet;
 
 const FeatureSet& supported_features();
@@ -56,6 +57,50 @@
 
 TransportId NextTransportId();
 
+// Abstraction for a blocking packet transport.
+struct Connection {
+    Connection() = default;
+    Connection(const Connection& copy) = delete;
+    Connection(Connection&& move) = delete;
+
+    // Destroy a Connection. Formerly known as 'Close' in atransport.
+    virtual ~Connection() = default;
+
+    // Read/Write a packet. These functions are concurrently called from a transport's reader/writer
+    // threads.
+    virtual bool Read(apacket* packet) = 0;
+    virtual bool Write(apacket* packet) = 0;
+
+    // Terminate a connection.
+    // This method must be thread-safe, and must cause concurrent Reads/Writes to terminate.
+    // Formerly known as 'Kick' in atransport.
+    virtual void Close() = 0;
+};
+
+struct FdConnection : public Connection {
+    explicit FdConnection(unique_fd fd) : fd_(std::move(fd)) {}
+
+    bool Read(apacket* packet) override final;
+    bool Write(apacket* packet) override final;
+
+    void Close() override;
+
+  private:
+    unique_fd fd_;
+};
+
+struct UsbConnection : public Connection {
+    explicit UsbConnection(usb_handle* handle) : handle_(handle) {}
+    ~UsbConnection();
+
+    bool Read(apacket* packet) override final;
+    bool Write(apacket* packet) override final;
+
+    void Close() override final;
+
+    usb_handle* handle_;
+};
+
 class atransport {
   public:
     // TODO(danalbert): We expose waaaaaaay too much stuff because this was
@@ -73,12 +118,6 @@
     }
     virtual ~atransport() {}
 
-    int (*read_from_remote)(apacket* p, atransport* t) = nullptr;
-    void (*close)(atransport* t) = nullptr;
-
-    void SetWriteFunction(int (*write_func)(apacket*, atransport*)) { write_func_ = write_func; }
-    void SetKickFunction(void (*kick_func)(atransport*)) { kick_func_ = kick_func; }
-    bool IsKicked() { return kicked_; }
     int Write(apacket* p);
     void Kick();
 
@@ -95,9 +134,7 @@
     bool online = false;
     TransportType type = kTransportAny;
 
-    // USB handle or socket fd as needed.
-    usb_handle* usb = nullptr;
-    int sfd = -1;
+    std::unique_ptr<Connection> connection;
 
     // Used to identify transports for clients.
     char* serial = nullptr;
@@ -105,22 +142,8 @@
     char* model = nullptr;
     char* device = nullptr;
     char* devpath = nullptr;
-    void SetLocalPortForEmulator(int port) {
-        CHECK_EQ(local_port_for_emulator_, -1);
-        local_port_for_emulator_ = port;
-    }
 
-    bool GetLocalPortForEmulator(int* port) const {
-        if (type == kTransportLocal && local_port_for_emulator_ != -1) {
-            *port = local_port_for_emulator_;
-            return true;
-        }
-        return false;
-    }
-
-    bool IsTcpDevice() const {
-        return type == kTransportLocal && local_port_for_emulator_ == -1;
-    }
+    bool IsTcpDevice() const { return type == kTransportLocal; }
 
 #if ADB_HOST
     std::shared_ptr<RSA> NextKey();
@@ -165,10 +188,7 @@
     bool MatchesTarget(const std::string& target) const;
 
 private:
-    int local_port_for_emulator_ = -1;
     bool kicked_ = false;
-    void (*kick_func_)(atransport*) = nullptr;
-    int (*write_func_)(apacket*, atransport*) = nullptr;
 
     // A set of features transmitted in the banner with the initial connection.
     // This is stored in the banner as 'features=feature0,feature1,etc'.
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index d6c84da..560a031 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -28,10 +28,12 @@
 #include <condition_variable>
 #include <mutex>
 #include <thread>
+#include <unordered_map>
 #include <vector>
 
 #include <android-base/parsenetaddress.h>
 #include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
 #include <cutils/sockets.h>
 
 #if !ADB_HOST
@@ -40,6 +42,7 @@
 
 #include "adb.h"
 #include "adb_io.h"
+#include "adb_unique_fd.h"
 #include "adb_utils.h"
 #include "sysdeps/chrono.h"
 
@@ -53,48 +56,15 @@
 
 static std::mutex& local_transports_lock = *new std::mutex();
 
-/* we keep a list of opened transports. The atransport struct knows to which
- * local transport it is connected. The list is used to detect when we're
- * trying to connect twice to a given local transport.
- */
-static atransport*  local_transports[ ADB_LOCAL_TRANSPORT_MAX ];
+// We keep a map from emulator port to transport.
+// TODO: weak_ptr?
+static auto& local_transports GUARDED_BY(local_transports_lock) =
+    *new std::unordered_map<int, atransport*>();
 #endif /* ADB_HOST */
 
-static int remote_read(apacket *p, atransport *t)
-{
-    if (!ReadFdExactly(t->sfd, &p->msg, sizeof(amessage))) {
-        D("remote local: read terminated (message)");
-        return -1;
-    }
-
-    if (!check_header(p, t)) {
-        D("bad header: terminated (data)");
-        return -1;
-    }
-
-    if (!ReadFdExactly(t->sfd, p->data, p->msg.data_length)) {
-        D("remote local: terminated (data)");
-        return -1;
-    }
-
-    return 0;
-}
-
-static int remote_write(apacket *p, atransport *t)
-{
-    int   length = p->msg.data_length;
-
-    if(!WriteFdExactly(t->sfd, &p->msg, sizeof(amessage) + length)) {
-        D("remote local: write terminated");
-        return -1;
-    }
-
-    return 0;
-}
-
 bool local_connect(int port) {
     std::string dummy;
-    return local_connect_arbitrary_ports(port-1, port, &dummy) == 0;
+    return local_connect_arbitrary_ports(port - 1, port, &dummy) == 0;
 }
 
 void connect_device(const std::string& address, std::string* response) {
@@ -423,130 +393,83 @@
     std::thread(func, port).detach();
 }
 
-static void remote_kick(atransport *t)
-{
-    int fd = t->sfd;
-    t->sfd = -1;
-    adb_shutdown(fd);
-    adb_close(fd);
-
 #if ADB_HOST
-    int  nn;
-    std::lock_guard<std::mutex> lock(local_transports_lock);
-    for (nn = 0; nn < ADB_LOCAL_TRANSPORT_MAX; nn++) {
-        if (local_transports[nn] == t) {
-            local_transports[nn] = NULL;
-            break;
-        }
-    }
-#endif
-}
+struct EmulatorConnection : public FdConnection {
+    EmulatorConnection(unique_fd fd, int local_port)
+        : FdConnection(std::move(fd)), local_port_(local_port) {}
 
-static void remote_close(atransport *t)
-{
-    int fd = t->sfd;
-    if (fd != -1) {
-        t->sfd = -1;
-        adb_close(fd);
-    }
-#if ADB_HOST
-    int local_port;
-    if (t->GetLocalPortForEmulator(&local_port)) {
-        VLOG(TRANSPORT) << "remote_close, local_port = " << local_port;
+    ~EmulatorConnection() {
+        VLOG(TRANSPORT) << "remote_close, local_port = " << local_port_;
         std::unique_lock<std::mutex> lock(retry_ports_lock);
         RetryPort port;
-        port.port = local_port;
+        port.port = local_port_;
         port.retry_count = LOCAL_PORT_RETRY_COUNT;
         retry_ports.push_back(port);
         retry_ports_cond.notify_one();
     }
-#endif
-}
 
+    void Close() override {
+        std::lock_guard<std::mutex> lock(local_transports_lock);
+        local_transports.erase(local_port_);
+        FdConnection::Close();
+    }
 
-#if ADB_HOST
+    int local_port_;
+};
+
 /* Only call this function if you already hold local_transports_lock. */
 static atransport* find_emulator_transport_by_adb_port_locked(int adb_port)
-{
-    int i;
-    for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
-        int local_port;
-        if (local_transports[i] && local_transports[i]->GetLocalPortForEmulator(&local_port)) {
-            if (local_port == adb_port) {
-                return local_transports[i];
-            }
-        }
+    REQUIRES(local_transports_lock) {
+    auto it = local_transports.find(adb_port);
+    if (it == local_transports.end()) {
+        return nullptr;
     }
-    return NULL;
+    return it->second;
 }
 
-std::string getEmulatorSerialString(int console_port)
-{
+std::string getEmulatorSerialString(int console_port) {
     return android::base::StringPrintf("emulator-%d", console_port);
 }
 
-atransport* find_emulator_transport_by_adb_port(int adb_port)
-{
+atransport* find_emulator_transport_by_adb_port(int adb_port) {
     std::lock_guard<std::mutex> lock(local_transports_lock);
-    atransport* result = find_emulator_transport_by_adb_port_locked(adb_port);
-    return result;
+    return find_emulator_transport_by_adb_port_locked(adb_port);
 }
 
-atransport* find_emulator_transport_by_console_port(int console_port)
-{
+atransport* find_emulator_transport_by_console_port(int console_port) {
     return find_transport(getEmulatorSerialString(console_port).c_str());
 }
-
-
-/* Only call this function if you already hold local_transports_lock. */
-int get_available_local_transport_index_locked()
-{
-    int i;
-    for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
-        if (local_transports[i] == NULL) {
-            return i;
-        }
-    }
-    return -1;
-}
-
-int get_available_local_transport_index()
-{
-    std::lock_guard<std::mutex> lock(local_transports_lock);
-    int result = get_available_local_transport_index_locked();
-    return result;
-}
 #endif
 
-int init_socket_transport(atransport *t, int s, int adb_port, int local)
-{
-    int  fail = 0;
+int init_socket_transport(atransport* t, int s, int adb_port, int local) {
+    int fail = 0;
 
-    t->SetKickFunction(remote_kick);
-    t->SetWriteFunction(remote_write);
-    t->close = remote_close;
-    t->read_from_remote = remote_read;
-    t->sfd = s;
+    unique_fd fd(s);
     t->sync_token = 1;
     t->type = kTransportLocal;
 
 #if ADB_HOST
+    // Emulator connection.
     if (local) {
+        t->connection.reset(new EmulatorConnection(std::move(fd), adb_port));
         std::lock_guard<std::mutex> lock(local_transports_lock);
-        t->SetLocalPortForEmulator(adb_port);
         atransport* existing_transport = find_emulator_transport_by_adb_port_locked(adb_port);
-        int index = get_available_local_transport_index_locked();
         if (existing_transport != NULL) {
             D("local transport for port %d already registered (%p)?", adb_port, existing_transport);
             fail = -1;
-        } else if (index < 0) {
+        } else if (local_transports.size() >= ADB_LOCAL_TRANSPORT_MAX) {
             // Too many emulators.
             D("cannot register more emulators. Maximum is %d", ADB_LOCAL_TRANSPORT_MAX);
             fail = -1;
         } else {
-            local_transports[index] = t;
+            local_transports[adb_port] = t;
         }
+
+        return fail;
     }
 #endif
+
+    // Regular tcp connection.
+    t->connection.reset(new FdConnection(std::move(fd)));
     return fail;
 }
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 68689d4..d987d4f 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -20,22 +20,6 @@
 
 #include "adb.h"
 
-TEST(transport, kick_transport) {
-  atransport t;
-  static size_t kick_count;
-  kick_count = 0;
-  // Mutate some member so we can test that the function is run.
-  t.SetKickFunction([](atransport* trans) { kick_count++; });
-  ASSERT_FALSE(t.IsKicked());
-  t.Kick();
-  ASSERT_TRUE(t.IsKicked());
-  ASSERT_EQ(1u, kick_count);
-  // A transport can only be kicked once.
-  t.Kick();
-  ASSERT_TRUE(t.IsKicked());
-  ASSERT_EQ(1u, kick_count);
-}
-
 static void DisconnectFunc(void* arg, atransport*) {
     int* count = reinterpret_cast<int*>(arg);
     ++*count;
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 3474820..73e8e15 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -80,25 +80,18 @@
 #endif
 }
 
-static int remote_read(apacket* p, atransport* t) {
-    int n = UsbReadMessage(t->usb, &p->msg);
+static int remote_read(apacket* p, usb_handle* usb) {
+    int n = UsbReadMessage(usb, &p->msg);
     if (n < 0) {
         D("remote usb: read terminated (message)");
         return -1;
     }
-    if (static_cast<size_t>(n) != sizeof(p->msg) || !check_header(p, t)) {
-        D("remote usb: check_header failed, skip it");
-        goto err_msg;
-    }
-    if (t->GetConnectionState() == kCsOffline) {
-        // If we read a wrong msg header declaring a large message payload, don't read its payload.
-        // Otherwise we may miss true messages from the device.
-        if (p->msg.command != A_CNXN && p->msg.command != A_AUTH) {
-            goto err_msg;
-        }
+    if (static_cast<size_t>(n) != sizeof(p->msg)) {
+        D("remote usb: read received unexpected header length %d", n);
+        return -1;
     }
     if (p->msg.data_length) {
-        n = UsbReadPayload(t->usb, p);
+        n = UsbReadPayload(usb, p);
         if (n < 0) {
             D("remote usb: terminated (data)");
             return -1;
@@ -106,34 +99,24 @@
         if (static_cast<uint32_t>(n) != p->msg.data_length) {
             D("remote usb: read payload failed (need %u bytes, give %d bytes), skip it",
               p->msg.data_length, n);
-            goto err_msg;
+            return -1;
         }
     }
     return 0;
-
-err_msg:
-    p->msg.command = 0;
-    return 0;
 }
 
 #else
 
 // On Android devices, we rely on the kernel to provide buffered read.
 // So we can recover automatically from EOVERFLOW.
-static int remote_read(apacket *p, atransport *t)
-{
-    if (usb_read(t->usb, &p->msg, sizeof(amessage))) {
+static int remote_read(apacket* p, usb_handle* usb) {
+    if (usb_read(usb, &p->msg, sizeof(amessage))) {
         PLOG(ERROR) << "remote usb: read terminated (message)";
         return -1;
     }
 
-    if (!check_header(p, t)) {
-        LOG(ERROR) << "remote usb: check_header failed";
-        return -1;
-    }
-
     if (p->msg.data_length) {
-        if (usb_read(t->usb, p->data, p->msg.data_length)) {
+        if (usb_read(usb, p->data, p->msg.data_length)) {
             PLOG(ERROR) << "remote usb: terminated (data)";
             return -1;
         }
@@ -143,45 +126,43 @@
 }
 #endif
 
-static int remote_write(apacket *p, atransport *t)
-{
-    unsigned size = p->msg.data_length;
+UsbConnection::~UsbConnection() {
+    usb_close(handle_);
+}
 
-    if (usb_write(t->usb, &p->msg, sizeof(amessage))) {
+bool UsbConnection::Read(apacket* packet) {
+    int rc = remote_read(packet, handle_);
+    return rc == 0;
+}
+
+bool UsbConnection::Write(apacket* packet) {
+    unsigned size = packet->msg.data_length;
+
+    if (usb_write(handle_, &packet->msg, sizeof(packet->msg)) != 0) {
         PLOG(ERROR) << "remote usb: 1 - write terminated";
-        return -1;
+        return false;
     }
-    if (p->msg.data_length == 0) return 0;
-    if (usb_write(t->usb, &p->data, size)) {
+
+    if (packet->msg.data_length != 0 && usb_write(handle_, &packet->data, size) != 0) {
         PLOG(ERROR) << "remote usb: 2 - write terminated";
-        return -1;
+        return false;
     }
 
-    return 0;
+    return true;
 }
 
-static void remote_close(atransport* t) {
-    usb_close(t->usb);
-    t->usb = 0;
-}
-
-static void remote_kick(atransport* t) {
-    usb_kick(t->usb);
+void UsbConnection::Close() {
+    usb_kick(handle_);
 }
 
 void init_usb_transport(atransport* t, usb_handle* h) {
     D("transport: usb");
-    t->close = remote_close;
-    t->SetKickFunction(remote_kick);
-    t->SetWriteFunction(remote_write);
-    t->read_from_remote = remote_read;
+    t->connection.reset(new UsbConnection(h));
     t->sync_token = 1;
     t->type = kTransportUsb;
-    t->usb = h;
 }
 
-int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol)
-{
+int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol) {
     return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL);
 }
 
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index a2b80ad..9aab0ba 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -32,11 +32,14 @@
 #include <unistd.h>
 
 #include <memory>
+#include <string>
 #include <thread>
+#include <vector>
 
 #include <android-base/file.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <cutils/android_filesystem_config.h>
 #include <cutils/android_reboot.h>
@@ -775,6 +778,22 @@
     }
 }
 
+static bool call_vdc(const std::vector<std::string>& args) {
+    std::vector<char const*> argv;
+    argv.emplace_back("/system/bin/vdc");
+    for (auto& arg : args) {
+        argv.emplace_back(arg.c_str());
+    }
+    LOG(INFO) << "Calling: " << android::base::Join(argv, ' ');
+    int ret = android_fork_execvp(4, const_cast<char**>(argv.data()), nullptr, false, true);
+    if (ret != 0) {
+        LOG(ERROR) << "vdc returned error code: " << ret;
+        return false;
+    }
+    LOG(DEBUG) << "vdc finished successfully";
+    return true;
+}
+
 /* When multiple fstab records share the same mount_point, it will
  * try to mount each one in turn, and ignore any duplicates after a
  * first successful mount.
@@ -881,6 +900,13 @@
                     LERROR << "Only one encryptable/encrypted partition supported";
                 }
                 encryptable = status;
+                if (status == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
+                    if (!call_vdc(
+                            {"cryptfs", "encryptFstab", fstab->recs[attempted_idx].mount_point})) {
+                        LERROR << "Encryption failed";
+                        return FS_MGR_MNTALL_FAIL;
+                    }
+                }
             }
 
             /* Success!  Go get the next one */
@@ -955,7 +981,11 @@
             encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
         } else if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
                    should_use_metadata_encryption(&fstab->recs[attempted_idx])) {
+            if (!call_vdc({"cryptfs", "mountFstab", fstab->recs[attempted_idx].mount_point})) {
+                ++error_count;
+            }
             encryptable = FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED;
+            continue;
         } else {
             // fs_options might be null so we cannot use PERROR << directly.
             // Use StringPrintf to output "(null)" instead.
diff --git a/init/builtins.cpp b/init/builtins.cpp
index caf0c3f..be259c2 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -514,8 +514,9 @@
         property_set("ro.crypto.state", "encrypted");
         property_set("ro.crypto.type", "file");
 
-        // defaultcrypto detects file/block encryption. init flow is same for each.
-        ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
+        // Although encrypted, vold has already set the device up, so we do not need to
+        // do anything different from the nonencrypted case.
+        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
         return Success();
     } else if (code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
         if (e4crypt_install_keyring()) {
@@ -523,8 +524,9 @@
         }
         property_set("ro.crypto.type", "file");
 
-        // encrypt detects file/block encryption. init flow is same for each.
-        ActionManager::GetInstance().QueueEventTrigger("encrypt");
+        // Although encrypted, vold has already set the device up, so we do not need to
+        // do anything different from the nonencrypted case.
+        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
         return Success();
     } else if (code > 0) {
         Error() << "fs_mgr_mount_all() returned unexpected error " << code;
diff --git a/init/init.cpp b/init/init.cpp
index 79623c3..bd09e4b 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -19,6 +19,7 @@
 #include <dirent.h>
 #include <fcntl.h>
 #include <paths.h>
+#include <pthread.h>
 #include <seccomp_policy.h>
 #include <signal.h>
 #include <stdlib.h>
@@ -491,6 +492,16 @@
     HandlePowerctlMessage("shutdown,container");
 }
 
+static void UnblockSigterm() {
+    sigset_t mask;
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGTERM);
+
+    if (sigprocmask(SIG_UNBLOCK, &mask, nullptr) == -1) {
+        PLOG(FATAL) << "failed to unblock SIGTERM for PID " << getpid();
+    }
+}
+
 static void InstallSigtermHandler() {
     sigset_t mask;
     sigemptyset(&mask);
@@ -500,6 +511,12 @@
         PLOG(FATAL) << "failed to block SIGTERM";
     }
 
+    // Register a handler to unblock SIGTERM in the child processes.
+    const int result = pthread_atfork(nullptr, nullptr, &UnblockSigterm);
+    if (result != 0) {
+        LOG(FATAL) << "Failed to register a fork handler: " << strerror(result);
+    }
+
     sigterm_signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
     if (sigterm_signal_fd == -1) {
         PLOG(FATAL) << "failed to create signalfd for SIGTERM";
diff --git a/init/stable_properties.h b/init/stable_properties.h
index 8219838..be35457 100644
--- a/init/stable_properties.h
+++ b/init/stable_properties.h
@@ -24,19 +24,27 @@
 namespace init {
 
 static constexpr const char* kPartnerPrefixes[] = {
-    "init.svc.vendor.", "ro.vendor.", "persist.vendor.", "vendor.",
-    "init.svc.odm.",    "ro.odm.",    "persist.odm.",    "odm.",
+    "init.svc.vendor.", "ro.vendor.", "persist.vendor.", "vendor.", "init.svc.odm.", "ro.odm.",
+    "persist.odm.",     "odm.",       "ro.boot.",
 };
 
 static const std::set<std::string> kExportedActionableProperties = {
-    "init.svc.zygote",         "persist.bluetooth.btsnoopenable",
-    "persist.sys.crash_rcu",   "persist.sys.zram_enabled",
-    "ro.boot.revision",        "ro.bootmode",
-    "ro.build.type",           "sys.boot_completed",
-    "sys.retaildemo.enabled",  "sys.shutdown.requested",
-    "sys.usb.config",          "sys.usb.configfs",
-    "sys.usb.ffs.mtp.ready",   "sys.usb.ffs.ready",
-    "sys.user.0.ce_available", "sys.vdso",
+    "init.svc.mediadrm",
+    "init.svc.zygote",
+    "persist.bluetooth.btsnoopenable",
+    "persist.sys.crash_rcu",
+    "persist.sys.zram_enabled",
+    "ro.bootmode",
+    "ro.build.type",
+    "sys.boot_completed",
+    "sys.retaildemo.enabled",
+    "sys.shutdown.requested",
+    "sys.usb.config",
+    "sys.usb.configfs",
+    "sys.usb.ffs.mtp.ready",
+    "sys.usb.ffs.ready",
+    "sys.user.0.ce_available",
+    "sys.vdso",
     "vts.native_server.on",
 };
 
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 14ae445..10a4e46 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -50,7 +50,6 @@
     "BacktracePtrace.cpp",
     "thread_utils.c",
     "ThreadEntry.cpp",
-    "UnwindDexFile.cpp",
     "UnwindStack.cpp",
     "UnwindStackMap.cpp",
 ]
@@ -110,10 +109,9 @@
             static_libs: ["libasync_safe"],
         },
         vendor: {
-            cflags: ["-DNO_LIBDEXFILE"],
-            exclude_srcs: ["UnwindDexFile.cpp"],
+            cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
             exclude_shared_libs: ["libdexfile"],
-        },
+        }
     },
     whole_static_libs: ["libdemangle"],
 }
@@ -145,8 +143,6 @@
         "backtrace_test.cpp",
         "GetPss.cpp",
         "thread_utils.c",
-
-        "unwind_dex_test.cpp",
     ],
 
     cflags: [
diff --git a/libbacktrace/UnwindDexFile.h b/libbacktrace/UnwindDexFile.h
deleted file mode 100644
index dd70aba..0000000
--- a/libbacktrace/UnwindDexFile.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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 _LIBBACKTRACE_UNWIND_DEX_FILE_H
-#define _LIBBACKTRACE_UNWIND_DEX_FILE_H
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <dex/dex_file-inl.h>
-
-namespace unwindstack {
-class Memory;
-struct MapInfo;
-}  // namespace unwindstack
-
-class UnwindDexFile {
- public:
-  UnwindDexFile() = default;
-  virtual ~UnwindDexFile() = default;
-
-  void GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
-
-  static UnwindDexFile* Create(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory,
-                               unwindstack::MapInfo* info);
-
- protected:
-  std::unique_ptr<const art::DexFile> dex_file_;
-};
-
-class UnwindDexFileFromFile : public UnwindDexFile {
- public:
-  UnwindDexFileFromFile() = default;
-  virtual ~UnwindDexFileFromFile();
-
-  bool Open(uint64_t dex_file_offset_in_file, const std::string& name);
-
- private:
-  void* mapped_memory_ = nullptr;
-  size_t size_ = 0;
-};
-
-class UnwindDexFileFromMemory : public UnwindDexFile {
- public:
-  UnwindDexFileFromMemory() = default;
-  virtual ~UnwindDexFileFromMemory() = default;
-
-  bool Open(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory);
-
- private:
-  std::vector<uint8_t> memory_;
-};
-
-#endif  // _LIBBACKTRACE_UNWIND_DEX_FILE_H
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 158467e..7e2e6d0 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -36,70 +36,15 @@
 #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"
-#ifndef NO_LIBDEXFILE
-#include "UnwindDexFile.h"
-#endif
 #include "UnwindStack.h"
 #include "UnwindStackMap.h"
 
-static void FillInDexFrame(UnwindStackMap* stack_map, uint64_t dex_pc,
-                           backtrace_frame_data_t* frame) {
-  // The DEX PC points into the .dex section within an ELF file.
-  // However, this is a BBS section manually mmaped to a .vdex file,
-  // so we need to get the following map to find the ELF data.
-  unwindstack::Maps* maps = stack_map->stack_maps();
-  auto it = maps->begin();
-  uint64_t rel_dex_pc;
-  unwindstack::MapInfo* info;
-  for (; it != maps->end(); ++it) {
-    auto entry = *it;
-    if (dex_pc >= entry->start && dex_pc < entry->end) {
-      info = entry;
-      rel_dex_pc = dex_pc - entry->start;
-      frame->map.start = entry->start;
-      frame->map.end = entry->end;
-      frame->map.offset = entry->offset;
-      frame->map.load_bias = entry->load_bias;
-      frame->map.flags = entry->flags;
-      frame->map.name = entry->name;
-      frame->rel_pc = rel_dex_pc;
-      break;
-    }
-  }
-  if (it == maps->end() || ++it == maps->end()) {
-    return;
-  }
-
-  auto entry = *it;
-  auto process_memory = stack_map->process_memory();
-  unwindstack::Elf* elf = entry->GetElf(process_memory, true);
-  if (!elf->valid()) {
-    return;
-  }
-
-  // Adjust the relative dex by the offset.
-  rel_dex_pc += entry->elf_offset;
-
-  uint64_t dex_offset;
-  if (!elf->GetFunctionName(rel_dex_pc, &frame->func_name, &dex_offset)) {
-    return;
-  }
-  frame->func_offset = dex_offset;
-  if (frame->func_name != "$dexfile") {
-    return;
-  }
-
-#ifndef NO_LIBDEXFILE
-  UnwindDexFile* dex_file = stack_map->GetDexFile(dex_pc - dex_offset, info);
-  if (dex_file != nullptr) {
-    dex_file->GetMethodInformation(dex_offset, &frame->func_name, &frame->func_offset);
-  }
-#endif
-}
-
 bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
                        std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
                        std::vector<std::string>* skip_names, BacktraceUnwindError* error) {
@@ -110,6 +55,11 @@
   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()) {
@@ -150,36 +100,11 @@
   }
 
   auto unwinder_frames = unwinder.frames();
-  // Get the real number of frames we'll need.
-  size_t total_frames = 0;
-  for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++, total_frames++) {
-    if (unwinder_frames[i].dex_pc != 0) {
-      total_frames++;
-    }
-  }
-  frames->resize(total_frames);
+  frames->resize(unwinder.NumFrames() - num_ignore_frames);
   size_t cur_frame = 0;
   for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++) {
     auto frame = &unwinder_frames[i];
 
-    // Inject extra 'virtual' frame that represents the dex pc data.
-    // The dex pc is magic register defined in the Mterp interpreter,
-    // and thus it will be restored/observed in the frame after it.
-    // Adding the dex frame first here will create something like:
-    //   #7 pc 006b1ba1 libartd.so  ExecuteMterpImpl+14625
-    //   #8 pc 0015fa20 core.vdex   java.util.Arrays.binarySearch+8
-    //   #9 pc 0039a1ef libartd.so  art::interpreter::Execute+719
-    if (frame->dex_pc != 0) {
-      backtrace_frame_data_t* dex_frame = &frames->at(cur_frame);
-      dex_frame->num = cur_frame++;
-      dex_frame->pc = frame->dex_pc;
-      dex_frame->rel_pc = frame->dex_pc;
-      dex_frame->sp = frame->sp;
-      dex_frame->stack_size = 0;
-      dex_frame->func_offset = 0;
-      FillInDexFrame(stack_map, frame->dex_pc, dex_frame);
-    }
-
     backtrace_frame_data_t* back_frame = &frames->at(cur_frame);
 
     back_frame->num = cur_frame++;
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 97f8d78..6dcc621 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -26,20 +26,11 @@
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Maps.h>
 
-#include "UnwindDexFile.h"
 #include "UnwindStackMap.h"
 
 //-------------------------------------------------------------------------
 UnwindStackMap::UnwindStackMap(pid_t pid) : BacktraceMap(pid) {}
 
-UnwindStackMap::~UnwindStackMap() {
-#ifndef NO_LIBDEXFILE
-  for (auto& entry : dex_files_) {
-    delete entry.second;
-  }
-#endif
-}
-
 bool UnwindStackMap::Build() {
   if (pid_ == 0) {
     pid_ = getpid();
@@ -54,6 +45,9 @@
   // 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;
@@ -127,26 +121,6 @@
   return process_memory_;
 }
 
-#ifdef NO_LIBDEXFILE
-UnwindDexFile* UnwindStackMap::GetDexFile(uint64_t, unwindstack::MapInfo*) {
-  return nullptr;
-}
-#else
-UnwindDexFile* UnwindStackMap::GetDexFile(uint64_t dex_file_offset, unwindstack::MapInfo* info) {
-  // Lock while we get the data.
-  std::lock_guard<std::mutex> guard(dex_lock_);
-  UnwindDexFile* dex_file;
-  auto entry = dex_files_.find(dex_file_offset);
-  if (entry == dex_files_.end()) {
-    dex_file = UnwindDexFile::Create(dex_file_offset, process_memory_.get(), info);
-    dex_files_[dex_file_offset] = dex_file;
-  } else {
-    dex_file = entry->second;
-  }
-  return dex_file;
-}
-#endif
-
 UnwindStackOfflineMap::UnwindStackOfflineMap(pid_t pid) : UnwindStackMap(pid) {}
 
 bool UnwindStackOfflineMap::Build() {
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index be5c59e..94cbfb2 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/JitDebug.h>
 #include <unwindstack/Maps.h>
 
@@ -36,7 +39,7 @@
 class UnwindStackMap : public BacktraceMap {
  public:
   explicit UnwindStackMap(pid_t pid);
-  ~UnwindStackMap();
+  ~UnwindStackMap() = default;
 
   bool Build() override;
 
@@ -51,7 +54,9 @@
 
   unwindstack::JitDebug* GetJitDebug() { return jit_debug_.get(); }
 
-  UnwindDexFile* GetDexFile(uint64_t dex_file_offset, unwindstack::MapInfo* info);
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  unwindstack::DexFiles* GetDexFiles() { return dex_files_.get(); }
+#endif
 
  protected:
   uint64_t GetLoadBias(size_t index) override;
@@ -59,9 +64,8 @@
   std::unique_ptr<unwindstack::Maps> stack_maps_;
   std::shared_ptr<unwindstack::Memory> process_memory_;
   std::unique_ptr<unwindstack::JitDebug> jit_debug_;
-#ifndef NO_LIBDEXFILE
-  std::mutex dex_lock_;
-  std::unordered_map<uint64_t, UnwindDexFile*> dex_files_;
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  std::unique_ptr<unwindstack::DexFiles> dex_files_;
 #endif
 };
 
diff --git a/libbacktrace/unwind_dex_test.cpp b/libbacktrace/unwind_dex_test.cpp
deleted file mode 100644
index 449e662..0000000
--- a/libbacktrace/unwind_dex_test.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * 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/types.h>
-#include <unistd.h>
-
-#include <unordered_map>
-
-#include <android-base/test_utils.h>
-
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Memory.h>
-
-#include <dex/code_item_accessors-no_art-inl.h>
-#include <dex/standard_dex_file.h>
-
-#include <gtest/gtest.h>
-
-#include "UnwindDexFile.h"
-
-class MemoryFake : public unwindstack::Memory {
- public:
-  MemoryFake() = default;
-  virtual ~MemoryFake() = default;
-
-  size_t Read(uint64_t addr, void* buffer, size_t size) override;
-
-  void SetMemory(uint64_t addr, const void* memory, size_t length);
-
-  void Clear() { data_.clear(); }
-
- private:
-  std::unordered_map<uint64_t, uint8_t> data_;
-};
-
-void MemoryFake::SetMemory(uint64_t addr, const void* memory, size_t length) {
-  const uint8_t* src = reinterpret_cast<const uint8_t*>(memory);
-  for (size_t i = 0; i < length; i++, addr++) {
-    auto value = data_.find(addr);
-    if (value != data_.end()) {
-      value->second = src[i];
-    } else {
-      data_.insert({addr, src[i]});
-    }
-  }
-}
-
-size_t MemoryFake::Read(uint64_t addr, void* memory, size_t size) {
-  uint8_t* dst = reinterpret_cast<uint8_t*>(memory);
-  for (size_t i = 0; i < size; i++, addr++) {
-    auto value = data_.find(addr);
-    if (value == data_.end()) {
-      return i;
-    }
-    dst[i] = value->second;
-  }
-  return size;
-}
-
-// Borrowed from art/dex/dex_file_test.cc.
-static constexpr uint32_t kDexData[] = {
-    0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
-    0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
-    0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
-    0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
-    0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
-    0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
-    0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
-    0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
-    0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
-    0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
-    0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
-    0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
-    0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
-    0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
-    0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
-    0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
-    0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
-};
-
-TEST(UnwindDexTest, from_file_open_non_exist) {
-  UnwindDexFileFromFile dex_file;
-  ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist"));
-}
-
-TEST(UnwindDexTest, from_file_open_too_small) {
-  TemporaryFile tf;
-  ASSERT_TRUE(tf.fd != -1);
-
-  ASSERT_EQ(sizeof(art::DexFile::Header) - 2,
-            static_cast<size_t>(
-                TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)) - 2)));
-
-  // Header too small.
-  UnwindDexFileFromFile dex_file;
-  ASSERT_FALSE(dex_file.Open(0, tf.path));
-
-  // Header correct, file too small.
-  ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
-  ASSERT_EQ(sizeof(art::DexFile::Header), static_cast<size_t>(TEMP_FAILURE_RETRY(write(
-                                              tf.fd, kDexData, sizeof(art::DexFile::Header)))));
-  ASSERT_FALSE(dex_file.Open(0, tf.path));
-}
-
-TEST(UnwindDexTest, from_file_open) {
-  TemporaryFile tf;
-  ASSERT_TRUE(tf.fd != -1);
-
-  ASSERT_EQ(sizeof(kDexData),
-            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
-
-  UnwindDexFileFromFile dex_file;
-  ASSERT_TRUE(dex_file.Open(0, tf.path));
-}
-
-TEST(UnwindDexTest, from_file_open_non_zero_offset) {
-  TemporaryFile tf;
-  ASSERT_TRUE(tf.fd != -1);
-
-  ASSERT_EQ(0x100, lseek(tf.fd, 0x100, SEEK_SET));
-  ASSERT_EQ(sizeof(kDexData),
-            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
-
-  UnwindDexFileFromFile dex_file;
-  ASSERT_TRUE(dex_file.Open(0x100, tf.path));
-}
-
-TEST(UnwindDexTest, from_memory_fail_too_small_for_header) {
-  MemoryFake memory;
-
-  memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1);
-  UnwindDexFileFromMemory dex_file;
-
-  ASSERT_FALSE(dex_file.Open(0x1000, &memory));
-}
-
-TEST(UnwindDexTest, from_memory_fail_too_small_for_data) {
-  MemoryFake memory;
-
-  memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2);
-  UnwindDexFileFromMemory dex_file;
-
-  ASSERT_FALSE(dex_file.Open(0x1000, &memory));
-}
-
-TEST(UnwindDexTest, from_memory_open) {
-  MemoryFake memory;
-
-  memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
-  UnwindDexFileFromMemory dex_file;
-
-  ASSERT_TRUE(dex_file.Open(0x1000, &memory));
-}
-
-TEST(UnwindDexTest, create_using_file) {
-  TemporaryFile tf;
-  ASSERT_TRUE(tf.fd != -1);
-
-  ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
-  ASSERT_EQ(sizeof(kDexData),
-            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
-
-  MemoryFake memory;
-  unwindstack::MapInfo info(0, 0x10000, 0, 0x5, tf.path);
-  std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x500, &memory, &info));
-  ASSERT_TRUE(dex_file != nullptr);
-}
-
-TEST(UnwindDexTest, create_using_file_non_zero_start) {
-  TemporaryFile tf;
-  ASSERT_TRUE(tf.fd != -1);
-
-  ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
-  ASSERT_EQ(sizeof(kDexData),
-            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
-
-  MemoryFake memory;
-  unwindstack::MapInfo info(0x100, 0x10000, 0, 0x5, tf.path);
-  std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x600, &memory, &info));
-  ASSERT_TRUE(dex_file != nullptr);
-}
-
-TEST(UnwindDexTest, create_using_file_non_zero_offset) {
-  TemporaryFile tf;
-  ASSERT_TRUE(tf.fd != -1);
-
-  ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
-  ASSERT_EQ(sizeof(kDexData),
-            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
-
-  MemoryFake memory;
-  unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, tf.path);
-  std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x400, &memory, &info));
-  ASSERT_TRUE(dex_file != nullptr);
-}
-
-TEST(UnwindDexTest, create_using_memory_empty_file) {
-  MemoryFake memory;
-  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
-  unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
-  std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
-  ASSERT_TRUE(dex_file != nullptr);
-}
-
-TEST(UnwindDexTest, create_using_memory_file_does_not_exist) {
-  MemoryFake memory;
-  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
-  unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
-  std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
-  ASSERT_TRUE(dex_file != nullptr);
-}
-
-TEST(UnwindDexTest, create_using_memory_file_is_malformed) {
-  TemporaryFile tf;
-  ASSERT_TRUE(tf.fd != -1);
-
-  ASSERT_EQ(sizeof(kDexData) - 10,
-            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData) - 10))));
-
-  MemoryFake memory;
-  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
-  unwindstack::MapInfo info(0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
-  std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
-  ASSERT_TRUE(dex_file != nullptr);
-
-  // Check it came from memory by clearing memory and verifying it fails.
-  memory.Clear();
-  dex_file.reset(UnwindDexFile::Create(0x4000, &memory, &info));
-  ASSERT_TRUE(dex_file == nullptr);
-}
-
-TEST(UnwindDexTest, get_method_not_opened) {
-  std::string method("something");
-  uint64_t method_offset = 100;
-  UnwindDexFile dex_file;
-  dex_file.GetMethodInformation(0x100, &method, &method_offset);
-  EXPECT_EQ("something", method);
-  EXPECT_EQ(100U, method_offset);
-}
-
-TEST(UnwindDexTest, get_method) {
-  MemoryFake memory;
-  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
-  unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
-  std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
-  ASSERT_TRUE(dex_file != nullptr);
-
-  std::string method;
-  uint64_t method_offset;
-  dex_file->GetMethodInformation(0x102, &method, &method_offset);
-  EXPECT_EQ("Main.<init>", method);
-  EXPECT_EQ(2U, method_offset);
-
-  method = "not_in_a_method";
-  method_offset = 0x123;
-  dex_file->GetMethodInformation(0x100000, &method, &method_offset);
-  EXPECT_EQ("not_in_a_method", method);
-  EXPECT_EQ(0x123U, method_offset);
-}
diff --git a/libcutils/tests/AshmemTest.cpp b/libcutils/tests/AshmemTest.cpp
index a87e23e..b37d020 100644
--- a/libcutils/tests/AshmemTest.cpp
+++ b/libcutils/tests/AshmemTest.cpp
@@ -14,11 +14,18 @@
  * limitations under the License.
  */
 
+#include <errno.h>
+#include <linux/fs.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/macros.h>
 #include <android-base/unique_fd.h>
 #include <cutils/ashmem.h>
 #include <gtest/gtest.h>
-#include <linux/fs.h>
-#include <sys/mman.h>
 
 using android::base::unique_fd;
 
@@ -31,15 +38,21 @@
 }
 
 void TestMmap(const unique_fd& fd, size_t size, int prot, void** region, off_t off = 0) {
+    ASSERT_TRUE(fd >= 0);
+    ASSERT_TRUE(ashmem_valid(fd));
     *region = mmap(nullptr, size, prot, MAP_SHARED, fd, off);
     ASSERT_NE(MAP_FAILED, *region);
 }
 
 void TestProtDenied(const unique_fd &fd, size_t size, int prot) {
+    ASSERT_TRUE(fd >= 0);
+    ASSERT_TRUE(ashmem_valid(fd));
     EXPECT_EQ(MAP_FAILED, mmap(nullptr, size, prot, MAP_SHARED, fd, 0));
 }
 
 void TestProtIs(const unique_fd& fd, int prot) {
+    ASSERT_TRUE(fd >= 0);
+    ASSERT_TRUE(ashmem_valid(fd));
     EXPECT_EQ(prot, ioctl(fd, ASHMEM_GET_PROT_MASK));
 }
 
@@ -86,18 +99,23 @@
     ASSERT_EQ(0, memcmp(region1, &data, size));
     EXPECT_EQ(0, munmap(region1, size));
 
-    ASSERT_EXIT({
-        void *region2 = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-        if (region2 == MAP_FAILED) {
-            _exit(1);
-        }
-        if (memcmp(region2, &data, size) != 0) {
-            _exit(2);
-        }
-        memset(region2, 0, size);
-        munmap(region2, size);
-        _exit(0);
-    }, ::testing::ExitedWithCode(0),"");
+    ASSERT_EXIT(
+        {
+            if (!ashmem_valid(fd)) {
+                _exit(3);
+            }
+            void* region2 = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+            if (region2 == MAP_FAILED) {
+                _exit(1);
+            }
+            if (memcmp(region2, &data, size) != 0) {
+                _exit(2);
+            }
+            memset(region2, 0, size);
+            munmap(region2, size);
+            _exit(0);
+        },
+        ::testing::ExitedWithCode(0), "");
 
     memset(&data, 0, size);
     void *region2;
@@ -146,6 +164,7 @@
     };
     for (const auto& cfg : seeks) {
         errno = 0;
+        ASSERT_TRUE(ashmem_valid(fd));
         auto off = lseek(fd, cfg.offset, cfg.whence);
         ASSERT_EQ(cfg.ret, off) << "lseek(" << cfg.offset << ", " << cfg.whence << ") failed"
                                 << (errno ? ": " : "") << (errno ? strerror(errno) : "");
@@ -196,15 +215,19 @@
     constexpr size_t size = PAGE_SIZE;
 
     int protFlags[] = { PROT_READ, PROT_WRITE };
-    for (int i = 0; i < 2; i++) {
+    for (size_t i = 0; i < arraysize(protFlags); i++) {
         ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
-        ASSERT_EXIT({
-            if (ashmem_set_prot_region(fd, protFlags[i]) >= 0) {
-                _exit(0);
-            } else {
-                _exit(1);
-            }
-        }, ::testing::ExitedWithCode(0), "");
+        ASSERT_EXIT(
+            {
+                if (!ashmem_valid(fd)) {
+                    _exit(3);
+                } else if (ashmem_set_prot_region(fd, protFlags[i]) >= 0) {
+                    _exit(0);
+                } else {
+                    _exit(1);
+                }
+            },
+            ::testing::ExitedWithCode(0), "");
         ASSERT_NO_FATAL_FAILURE(TestProtDenied(fd, size, protFlags[1-i]));
     }
 }
@@ -227,6 +250,9 @@
 
     ASSERT_EXIT({
         for (int i = 0; i < nRegions; i++) {
+            if (!ashmem_valid(fd[i])) {
+                _exit(3);
+            }
             void *region = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd[i], 0);
             if (region == MAP_FAILED) {
                 _exit(1);
diff --git a/libcutils/trace-dev.cpp b/libcutils/trace-dev.cpp
index 4da8215..27255c2 100644
--- a/libcutils/trace-dev.cpp
+++ b/libcutils/trace-dev.cpp
@@ -25,6 +25,7 @@
 void atrace_set_tracing_enabled(bool enabled)
 {
     atomic_store_explicit(&atrace_is_enabled, enabled, memory_order_release);
+    atomic_store_explicit(&atrace_is_ready, false, memory_order_release);
     atrace_update_tags();
 }
 
@@ -34,18 +35,17 @@
     if (atrace_marker_fd == -1) {
         ALOGE("Error opening trace file: %s (%d)", strerror(errno), errno);
         atrace_enabled_tags = 0;
-        goto done;
+        return;
     }
-
     atrace_enabled_tags = atrace_get_property();
-
-done:
-    atomic_store_explicit(&atrace_is_ready, true, memory_order_release);
 }
 
 void atrace_setup()
 {
-    pthread_once(&atrace_once_control, atrace_init_once);
+    if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
+        pthread_once(&atrace_once_control, atrace_init_once);
+    }
+    atomic_store_explicit(&atrace_is_ready, true, memory_order_release);
 }
 
 void atrace_begin_body(const char* name)
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 28d7e64..3354c90 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -80,7 +80,13 @@
         host: {
             cflags: ["-O0", "-g"],
         },
+        vendor: {
+            cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
+            exclude_static_libs: ["libunwindstack_dex"],
+            exclude_shared_libs: ["libdexfile"],
+        },
     },
+    whole_static_libs: ["libunwindstack_dex"],
 
     arch: {
         x86: {
@@ -99,14 +105,81 @@
 
     shared_libs: [
         "libbase",
+        "libdexfile",
         "liblog",
         "liblzma",
     ],
 }
 
+// Isolate the dex file processing into a separate library. Currently,
+// it is necessary to add art include directories directly, which also
+// adds the art elf.h file in the include path, overriding the system one.
+// Work to isolate libdexfile is b/72216369.
+cc_library_static {
+    name: "libunwindstack_dex",
+    vendor_available: false,
+    defaults: ["libunwindstack_flags"],
+
+    cflags: [
+        "-Wexit-time-destructors",
+    ],
+
+    srcs: [
+        "DexFile.cpp",
+        "DexFiles.cpp",
+    ],
+    target: {
+        // Always disable optimizations for host to make it easier to debug.
+        host: {
+            cflags: ["-O0", "-g"],
+        },
+    },
+
+    shared_libs: [
+        "libbase",
+        "libdexfile",
+    ],
+    local_include_dirs: ["include"],
+    allow_undefined_symbols: true,
+
+    // libdexfile will eventually properly export headers, for now include
+    // these directly.
+    include_dirs: [
+        "art/runtime",
+    ],
+}
+
 //-------------------------------------------------------------------------
 // Unit Tests
 //-------------------------------------------------------------------------
+cc_test_library {
+    name: "libunwindstack_dex_test",
+    vendor_available: false,
+    defaults: ["libunwindstack_flags"],
+
+    shared: {
+        enabled: false,
+    },
+
+    srcs: [
+        "tests/DexFileTest.cpp",
+        "tests/DexFilesTest.cpp",
+    ],
+    local_include_dirs: ["include"],
+    allow_undefined_symbols: true,
+
+    shared_libs: [
+        "libbase",
+        "libunwindstack",
+    ],
+
+    // libdexfile will eventually properly export headers, for now include
+    // these directly.
+    include_dirs: [
+        "art/runtime",
+    ],
+}
+
 cc_test {
     name: "libunwindstack_test",
     defaults: ["libunwindstack_flags"],
@@ -168,6 +241,8 @@
         "libgmock",
     ],
 
+    whole_static_libs: ["libunwindstack_dex_test"],
+
     data: [
         "tests/files/elf32.xz",
         "tests/files/elf64.xz",
diff --git a/libbacktrace/UnwindDexFile.cpp b/libunwindstack/DexFile.cpp
similarity index 68%
rename from libbacktrace/UnwindDexFile.cpp
rename to libunwindstack/DexFile.cpp
index 5780fbb..b4a992a 100644
--- a/libbacktrace/UnwindDexFile.cpp
+++ b/libunwindstack/DexFile.cpp
@@ -33,28 +33,39 @@
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Memory.h>
 
-#include "UnwindDexFile.h"
+#include "DexFile.h"
 
-UnwindDexFile* UnwindDexFile::Create(uint64_t dex_file_offset_in_memory,
-                                     unwindstack::Memory* memory, unwindstack::MapInfo* info) {
+namespace unwindstack {
+
+DexFile* DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info) {
   if (!info->name.empty()) {
-    std::unique_ptr<UnwindDexFileFromFile> dex_file(new UnwindDexFileFromFile);
+    std::unique_ptr<DexFileFromFile> dex_file(new DexFileFromFile);
     if (dex_file->Open(dex_file_offset_in_memory - info->start + info->offset, info->name)) {
       return dex_file.release();
     }
   }
 
-  std::unique_ptr<UnwindDexFileFromMemory> dex_file(new UnwindDexFileFromMemory);
+  std::unique_ptr<DexFileFromMemory> dex_file(new DexFileFromMemory);
   if (dex_file->Open(dex_file_offset_in_memory, memory)) {
     return dex_file.release();
   }
   return nullptr;
 }
 
-void UnwindDexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
-                                         uint64_t* method_offset) {
+DexFileFromFile::~DexFileFromFile() {
+  if (size_ != 0) {
+    munmap(mapped_memory_, size_);
+  }
+}
+
+bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
+                                   uint64_t* method_offset) {
   if (dex_file_ == nullptr) {
-    return;
+    return false;
+  }
+
+  if (!dex_file_->IsInDataSection(dex_file_->Begin() + dex_offset)) {
+    return false;  // The DEX offset is not within the bytecode of this dex file.
   }
 
   for (uint32_t i = 0; i < dex_file_->NumClassDefs(); ++i) {
@@ -81,19 +92,14 @@
       if (offset <= dex_offset && dex_offset < offset + size) {
         *method_name = dex_file_->PrettyMethod(it.GetMemberIndex(), false);
         *method_offset = dex_offset - offset;
-        return;
+        return true;
       }
     }
   }
+  return false;
 }
 
-UnwindDexFileFromFile::~UnwindDexFileFromFile() {
-  if (size_ != 0) {
-    munmap(mapped_memory_, size_);
-  }
-}
-
-bool UnwindDexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) {
+bool DexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) {
   android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
   if (fd == -1) {
     return false;
@@ -137,26 +143,44 @@
   return dex_file_ != nullptr;
 }
 
-bool UnwindDexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory) {
-  art::DexFile::Header header;
-  if (!memory->ReadFully(dex_file_offset_in_memory, &header, sizeof(header))) {
+bool DexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, Memory* memory) {
+  memory_.resize(sizeof(art::DexFile::Header));
+  if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) {
     return false;
   }
 
-  if (!art::StandardDexFile::IsMagicValid(header.magic_) &&
-      !art::CompactDexFile::IsMagicValid(header.magic_)) {
+  art::DexFile::Header* header = reinterpret_cast<art::DexFile::Header*>(memory_.data());
+  bool modify_data_off = false;
+  uint32_t file_size = header->file_size_;
+  if (art::CompactDexFile::IsMagicValid(header->magic_)) {
+    uint32_t computed_file_size;
+    if (__builtin_add_overflow(header->data_off_, header->data_size_, &computed_file_size)) {
+      return false;
+    }
+    if (computed_file_size > file_size) {
+      file_size = computed_file_size;
+      modify_data_off = true;
+    }
+  } else if (!art::StandardDexFile::IsMagicValid(header->magic_)) {
     return false;
   }
 
-  memory_.resize(header.file_size_);
-  if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), header.file_size_)) {
+  memory_.resize(file_size);
+  if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) {
     return false;
   }
 
+  header = reinterpret_cast<art::DexFile::Header*>(memory_.data());
+  if (modify_data_off) {
+    header->data_off_ = header->file_size_;
+  }
+
   art::DexFileLoader loader;
   std::string error_msg;
   auto dex =
-      loader.Open(memory_.data(), header.file_size_, "", 0, nullptr, false, false, &error_msg);
+      loader.Open(memory_.data(), header->file_size_, "", 0, nullptr, false, false, &error_msg);
   dex_file_.reset(dex.release());
   return dex_file_ != nullptr;
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
new file mode 100644
index 0000000..3ce2f1e
--- /dev/null
+++ b/libunwindstack/DexFile.h
@@ -0,0 +1,68 @@
+/*
+ * 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_FILE_H
+#define _LIBUNWINDSTACK_DEX_FILE_H
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <dex/dex_file-inl.h>
+
+namespace unwindstack {
+
+class DexFile {
+ public:
+  DexFile() = default;
+  virtual ~DexFile() = default;
+
+  bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
+
+  static DexFile* Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info);
+
+ protected:
+  std::unique_ptr<const art::DexFile> dex_file_;
+};
+
+class DexFileFromFile : public DexFile {
+ public:
+  DexFileFromFile() = default;
+  virtual ~DexFileFromFile();
+
+  bool Open(uint64_t dex_file_offset_in_file, const std::string& name);
+
+ private:
+  void* mapped_memory_ = nullptr;
+  size_t size_ = 0;
+};
+
+class DexFileFromMemory : public DexFile {
+ public:
+  DexFileFromMemory() = default;
+  virtual ~DexFileFromMemory() = default;
+
+  bool Open(uint64_t dex_file_offset_in_memory, Memory* memory);
+
+ private:
+  std::vector<uint8_t> memory_;
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_DEX_FILE_H
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
new file mode 100644
index 0000000..c5f8138
--- /dev/null
+++ b/libunwindstack/DexFiles.cpp
@@ -0,0 +1,204 @@
+/*
+ * 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) : memory_(memory) {}
+
+DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
+    : memory_(memory), search_libs_(search_libs) {}
+
+DexFiles::~DexFiles() {
+  for (auto& entry : files_) {
+    delete entry.second;
+  }
+}
+
+void DexFiles::SetArch(ArchEnum arch) {
+  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;
+  if (!memory_->ReadFully(addr, &entry, sizeof(entry))) {
+    return 0;
+  }
+  return entry;
+}
+
+uint64_t DexFiles::ReadEntryPtr64(uint64_t addr) {
+  uint64_t entry;
+  if (!memory_->ReadFully(addr, &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;
+}
+
+void DexFiles::Init(Maps* maps) {
+  if (initialized_) {
+    return;
+  }
+  initialized_ = true;
+  entry_addr_ = 0;
+
+  const std::string dex_debug_name("__art_debug_dexfiles");
+  for (MapInfo* info : *maps) {
+    if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
+      continue;
+    }
+
+    if (!search_libs_.empty()) {
+      bool found = false;
+      const char* lib = basename(info->name.c_str());
+      for (const std::string& name : search_libs_) {
+        if (name == lib) {
+          found = true;
+          break;
+        }
+      }
+      if (!found) {
+        continue;
+      }
+    }
+
+    Elf* elf = info->GetElf(memory_, true);
+    uint64_t ptr;
+    // Find first non-empty list (libart might be loaded multiple times).
+    if (elf->GetGlobalVariable(dex_debug_name, &ptr) && ptr != 0) {
+      entry_addr_ = (this->*read_entry_ptr_func_)(ptr + info->start);
+      if (entry_addr_ != 0) {
+        break;
+      }
+    }
+  }
+}
+
+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()) {
+    dex_file = DexFile::Create(dex_file_offset, memory_.get(), info);
+    files_[dex_file_offset] = dex_file;
+  } else {
+    dex_file = entry->second;
+  }
+  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/JitDebug.cpp b/libunwindstack/JitDebug.cpp
index d1dc0e6..0c319ec 100644
--- a/libunwindstack/JitDebug.cpp
+++ b/libunwindstack/JitDebug.cpp
@@ -172,7 +172,7 @@
   // Regardless of what happens below, consider the init finished.
   initialized_ = true;
 
-  std::string descriptor_name("__jit_debug_descriptor");
+  const std::string descriptor_name("__jit_debug_descriptor");
   for (MapInfo* info : *maps) {
     if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
       continue;
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index f70ed7b..6119ee0 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -31,8 +31,48 @@
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Unwinder.h>
 
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <unwindstack/DexFiles.h>
+#endif
+
 namespace unwindstack {
 
+// 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.
+// Adding the dex frame first here will create something like:
+//   #7 pc 0015fa20 core.vdex   java.util.Arrays.binarySearch+8
+//   #8 pc 006b1ba1 libartd.so  ExecuteMterpImpl+14625
+//   #9 pc 0039a1ef libartd.so  art::interpreter::Execute+719
+void Unwinder::FillInDexFrame() {
+  size_t frame_num = frames_.size();
+  frames_.resize(frame_num + 1);
+  FrameData* frame = &frames_.at(frame_num);
+
+  uint64_t dex_pc = regs_->dex_pc();
+  frame->pc = dex_pc;
+  frame->sp = regs_->sp();
+
+  MapInfo* info = maps_->Find(dex_pc);
+  frame->map_start = info->start;
+  frame->map_end = info->end;
+  frame->map_offset = info->offset;
+  frame->map_load_bias = info->load_bias;
+  frame->map_flags = info->flags;
+  frame->map_name = info->name;
+  frame->rel_pc = dex_pc - info->start;
+
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  if (dex_files_ == nullptr) {
+    return;
+  }
+
+  // dex_files_->GetMethodInformation(dex_pc - dex_offset, dex_offset, info, &frame->function_name,
+  dex_files_->GetMethodInformation(maps_, info, dex_pc, &frame->function_name,
+                                   &frame->function_offset);
+#endif
+}
+
 void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc, uint64_t func_pc) {
   size_t frame_num = frames_.size();
   frames_.resize(frame_num + 1);
@@ -40,7 +80,6 @@
   frame->num = frame_num;
   frame->sp = regs_->sp();
   frame->rel_pc = adjusted_rel_pc;
-  frame->dex_pc = regs_->dex_pc();
 
   if (map_info == nullptr) {
     frame->pc = regs_->pc();
@@ -128,6 +167,11 @@
     if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
         std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
                   basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) {
+      if (regs_->dex_pc() != 0) {
+        // Add a frame to represent the dex file.
+        FillInDexFrame();
+      }
+
       FillInFrame(map_info, elf, adjusted_rel_pc, adjusted_pc);
 
       // Once a frame is added, stop skipping frames.
@@ -240,4 +284,11 @@
   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
+
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
new file mode 100644
index 0000000..26f5d35
--- /dev/null
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -0,0 +1,78 @@
+/*
+ * 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>
+
+namespace unwindstack {
+
+// Forward declarations.
+class DexFile;
+class Maps;
+struct MapInfo;
+class Memory;
+enum ArchEnum : uint8_t;
+
+class DexFiles {
+ public:
+  explicit DexFiles(std::shared_ptr<Memory>& memory);
+  DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
+  ~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);
+
+  void SetArch(ArchEnum arch);
+
+ 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();
+
+  std::shared_ptr<Memory> memory_;
+  std::vector<std::string> search_libs_;
+
+  std::mutex lock_;
+  bool initialized_ = false;
+  std::unordered_map<uint64_t, 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/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index a7b57e6..e8af8b4 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -32,6 +32,7 @@
 namespace unwindstack {
 
 // Forward declarations.
+class DexFiles;
 class Elf;
 class JitDebug;
 enum ArchEnum : uint8_t;
@@ -42,7 +43,6 @@
   uint64_t rel_pc;
   uint64_t pc;
   uint64_t sp;
-  uint64_t dex_pc;
 
   std::string function_name;
   uint64_t function_offset;
@@ -75,10 +75,15 @@
 
   void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
 
+#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; }
 
  private:
+  void FillInDexFrame();
   void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc, uint64_t adjusted_pc);
 
   size_t max_frames_;
@@ -87,6 +92,9 @@
   std::vector<FrameData> frames_;
   std::shared_ptr<Memory> process_memory_;
   JitDebug* jit_debug_ = nullptr;
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  DexFiles* dex_files_ = nullptr;
+#endif
   ErrorData last_error_;
 };
 
diff --git a/libunwindstack/tests/DexFileData.h b/libunwindstack/tests/DexFileData.h
new file mode 100644
index 0000000..6975c68
--- /dev/null
+++ b/libunwindstack/tests/DexFileData.h
@@ -0,0 +1,45 @@
+/*
+ * 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_DEXFILESDATA_H
+#define _LIBUNWINDSTACK_DEXFILESDATA_H
+
+namespace unwindstack {
+
+// Borrowed from art/dex/dex_file_test.cc.
+static constexpr uint32_t kDexData[] = {
+    0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
+    0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
+    0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
+    0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
+    0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
+    0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
+    0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
+    0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
+    0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
+    0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
+    0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
+    0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
+    0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
+    0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
+    0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
+    0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
+    0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_DEXFILESDATA_H
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
new file mode 100644
index 0000000..6e05c5e
--- /dev/null
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -0,0 +1,220 @@
+/*
+ * 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/types.h>
+#include <unistd.h>
+
+#include <unordered_map>
+
+#include <android-base/test_utils.h>
+
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+
+#include <dex/code_item_accessors-no_art-inl.h>
+#include <dex/standard_dex_file.h>
+
+#include <gtest/gtest.h>
+
+#include "DexFile.h"
+
+#include "DexFileData.h"
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+TEST(DexFileTest, from_file_open_non_exist) {
+  DexFileFromFile dex_file;
+  ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist"));
+}
+
+TEST(DexFileTest, from_file_open_too_small) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_EQ(sizeof(art::DexFile::Header) - 2,
+            static_cast<size_t>(
+                TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)) - 2)));
+
+  // Header too small.
+  DexFileFromFile dex_file;
+  ASSERT_FALSE(dex_file.Open(0, tf.path));
+
+  // Header correct, file too small.
+  ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
+  ASSERT_EQ(sizeof(art::DexFile::Header), static_cast<size_t>(TEMP_FAILURE_RETRY(write(
+                                              tf.fd, kDexData, sizeof(art::DexFile::Header)))));
+  ASSERT_FALSE(dex_file.Open(0, tf.path));
+}
+
+TEST(DexFileTest, from_file_open) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_EQ(sizeof(kDexData),
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+  DexFileFromFile dex_file;
+  ASSERT_TRUE(dex_file.Open(0, tf.path));
+}
+
+TEST(DexFileTest, from_file_open_non_zero_offset) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_EQ(0x100, lseek(tf.fd, 0x100, SEEK_SET));
+  ASSERT_EQ(sizeof(kDexData),
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+  DexFileFromFile dex_file;
+  ASSERT_TRUE(dex_file.Open(0x100, tf.path));
+}
+
+TEST(DexFileTest, from_memory_fail_too_small_for_header) {
+  MemoryFake memory;
+
+  memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1);
+  DexFileFromMemory dex_file;
+
+  ASSERT_FALSE(dex_file.Open(0x1000, &memory));
+}
+
+TEST(DexFileTest, from_memory_fail_too_small_for_data) {
+  MemoryFake memory;
+
+  memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2);
+  DexFileFromMemory dex_file;
+
+  ASSERT_FALSE(dex_file.Open(0x1000, &memory));
+}
+
+TEST(DexFileTest, from_memory_open) {
+  MemoryFake memory;
+
+  memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
+  DexFileFromMemory dex_file;
+
+  ASSERT_TRUE(dex_file.Open(0x1000, &memory));
+}
+
+TEST(DexFileTest, create_using_file) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
+  ASSERT_EQ(sizeof(kDexData),
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+  MemoryFake memory;
+  MapInfo info(0, 0x10000, 0, 0x5, tf.path);
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x500, &memory, &info));
+  ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_file_non_zero_start) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
+  ASSERT_EQ(sizeof(kDexData),
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+  MemoryFake memory;
+  MapInfo info(0x100, 0x10000, 0, 0x5, tf.path);
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x600, &memory, &info));
+  ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_file_non_zero_offset) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
+  ASSERT_EQ(sizeof(kDexData),
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+  MemoryFake memory;
+  MapInfo info(0x100, 0x10000, 0x200, 0x5, tf.path);
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x400, &memory, &info));
+  ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_memory_empty_file) {
+  MemoryFake memory;
+  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+  MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+  ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_memory_file_does_not_exist) {
+  MemoryFake memory;
+  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+  MapInfo info(0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+  ASSERT_TRUE(dex_file != nullptr);
+}
+
+TEST(DexFileTest, create_using_memory_file_is_malformed) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_EQ(sizeof(kDexData) - 10,
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData) - 10))));
+
+  MemoryFake memory;
+  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+  MapInfo info(0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+  ASSERT_TRUE(dex_file != nullptr);
+
+  // Check it came from memory by clearing memory and verifying it fails.
+  memory.Clear();
+  dex_file.reset(DexFile::Create(0x4000, &memory, &info));
+  ASSERT_TRUE(dex_file == nullptr);
+}
+
+TEST(DexFileTest, get_method_not_opened) {
+  std::string method("something");
+  uint64_t method_offset = 100;
+  DexFile dex_file;
+  dex_file.GetMethodInformation(0x100, &method, &method_offset);
+  EXPECT_EQ("something", method);
+  EXPECT_EQ(100U, method_offset);
+}
+
+TEST(DexFileTest, get_method) {
+  MemoryFake memory;
+  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+  MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+  ASSERT_TRUE(dex_file != nullptr);
+
+  std::string method;
+  uint64_t method_offset;
+  dex_file->GetMethodInformation(0x102, &method, &method_offset);
+  EXPECT_EQ("Main.<init>", method);
+  EXPECT_EQ(2U, method_offset);
+
+  method = "not_in_a_method";
+  method_offset = 0x123;
+  dex_file->GetMethodInformation(0x100000, &method, &method_offset);
+  EXPECT_EQ("not_in_a_method", method);
+  EXPECT_EQ(0x123U, method_offset);
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp
new file mode 100644
index 0000000..dca5605
--- /dev/null
+++ b/libunwindstack/tests/DexFilesTest.cpp
@@ -0,0 +1,311 @@
+/*
+ * 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 <elf.h>
+#include <string.h>
+
+#include <memory>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+#include "DexFileData.h"
+#include "ElfFake.h"
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+class DexFilesTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    memory_ = new MemoryFake;
+    process_memory_.reset(memory_);
+
+    dex_files_.reset(new DexFiles(process_memory_));
+    dex_files_->SetArch(ARCH_ARM);
+
+    maps_.reset(
+        new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
+                       "4000-6000 r--s 00000000 00:00 0\n"
+                       "6000-8000 -w-s 00000000 00:00 0\n"
+                       "a000-c000 r-xp 00000000 00:00 0\n"
+                       "c000-f000 rwxp 00000000 00:00 0\n"
+                       "f000-11000 r-xp 00000000 00:00 0\n"
+                       "100000-110000 rw-p 0000000 00:00 0\n"
+                       "200000-210000 rw-p 0000000 00:00 0\n"
+                       "300000-400000 rw-p 0000000 00:00 0\n"));
+    ASSERT_TRUE(maps_->Parse());
+
+    // Global variable in a section that is not readable/executable.
+    MapInfo* map_info = maps_->Get(kMapGlobalNonReadableExectable);
+    ASSERT_TRUE(map_info != nullptr);
+    MemoryFake* memory = new MemoryFake;
+    ElfFake* elf = new ElfFake(memory);
+    elf->FakeSetValid(true);
+    ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
+    elf->FakeSetInterface(interface);
+    interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
+    map_info->elf.reset(elf);
+
+    // Global variable not set by default.
+    map_info = maps_->Get(kMapGlobalSetToZero);
+    ASSERT_TRUE(map_info != nullptr);
+    memory = new MemoryFake;
+    elf = new ElfFake(memory);
+    elf->FakeSetValid(true);
+    interface = new ElfInterfaceFake(memory);
+    elf->FakeSetInterface(interface);
+    interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
+    map_info->elf.reset(elf);
+
+    // Global variable set in this map.
+    map_info = maps_->Get(kMapGlobal);
+    ASSERT_TRUE(map_info != nullptr);
+    memory = new MemoryFake;
+    elf = new ElfFake(memory);
+    elf->FakeSetValid(true);
+    interface = new ElfInterfaceFake(memory);
+    elf->FakeSetInterface(interface);
+    interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
+    map_info->elf.reset(elf);
+  }
+
+  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 kMapGlobalNonReadableExectable = 3;
+  static constexpr size_t kMapGlobalSetToZero = 4;
+  static constexpr size_t kMapGlobal = 5;
+  static constexpr size_t kMapDexFileEntries = 7;
+  static constexpr size_t kMapDexFiles = 8;
+
+  std::shared_ptr<Memory> process_memory_;
+  MemoryFake* memory_;
+  std::unique_ptr<DexFiles> dex_files_;
+  std::unique_ptr<BufferMaps> maps_;
+};
+
+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(entry_addr, next);
+  //   uint32_t prev
+  memory_->SetData32(entry_addr + 4, prev);
+  //   uint32_t dex_file
+  memory_->SetData32(entry_addr + 8, dex_file);
+}
+
+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(entry_addr, next);
+  //   uint64_t prev
+  memory_->SetData64(entry_addr + 8, prev);
+  //   uint64_t dex_file
+  memory_->SetData64(entry_addr + 16, dex_file);
+}
+
+void DexFilesTest::WriteDex(uint64_t dex_file) {
+  memory_->SetMemory(dex_file, kDexData, sizeof(kDexData) * sizeof(uint32_t));
+}
+
+TEST_F(DexFilesTest, get_method_information_invalid) {
+  std::string method_name = "nothing";
+  uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFileEntries);
+
+  dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset);
+  EXPECT_EQ("nothing", method_name);
+  EXPECT_EQ(0x124U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_32) {
+  std::string method_name = "nothing";
+  uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
+
+  memory_->SetData32(0xf800, 0x200000);
+  WriteEntry32(0x200000, 0, 0, 0x300000);
+  WriteDex(0x300000);
+
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  EXPECT_EQ("Main.<init>", method_name);
+  EXPECT_EQ(0U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_64) {
+  std::string method_name = "nothing";
+  uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
+
+  dex_files_->SetArch(ARCH_ARM64);
+  memory_->SetData64(0xf800, 0x200000);
+  WriteEntry64(0x200000, 0, 0, 0x301000);
+  WriteDex(0x301000);
+
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset);
+  EXPECT_EQ("Main.<init>", method_name);
+  EXPECT_EQ(2U, method_offset);
+}
+
+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);
+
+  memory_->SetData32(0xf800, 0x200000);
+  WriteEntry32(0x200000, 0x200100, 0, 0x100000);
+  WriteEntry32(0x200100, 0, 0x200000, 0x300000);
+  WriteDex(0x300000);
+
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
+  EXPECT_EQ("Main.<init>", method_name);
+  EXPECT_EQ(4U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_not_first_entry_64) {
+  std::string method_name = "nothing";
+  uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
+
+  dex_files_->SetArch(ARCH_ARM64);
+  memory_->SetData64(0xf800, 0x200000);
+  WriteEntry64(0x200000, 0x200100, 0, 0x100000);
+  WriteEntry64(0x200100, 0, 0x200000, 0x300000);
+  WriteDex(0x300000);
+
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset);
+  EXPECT_EQ("Main.<init>", method_name);
+  EXPECT_EQ(6U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_cached) {
+  std::string method_name = "nothing";
+  uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
+
+  memory_->SetData32(0xf800, 0x200000);
+  WriteEntry32(0x200000, 0, 0, 0x300000);
+  WriteDex(0x300000);
+
+  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_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  EXPECT_EQ("Main.<init>", method_name);
+  EXPECT_EQ(0U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_search_libs) {
+  std::string method_name = "nothing";
+  uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
+
+  memory_->SetData32(0xf800, 0x200000);
+  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_.reset(new DexFiles(process_memory_, libs));
+  dex_files_->SetArch(ARCH_ARM);
+
+  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_.reset(new DexFiles(process_memory_, libs));
+  dex_files_->SetArch(ARCH_ARM);
+  // Make sure that clearing out copy of the libs doesn't affect the
+  // DexFiles object.
+  libs.clear();
+
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
+  EXPECT_EQ("Main.<init>", method_name);
+  EXPECT_EQ(4U, method_offset);
+}
+
+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.
+  memory_->SetData32(0xc800, 0);
+
+  memory_->SetData32(0xf800, 0x200000);
+  WriteEntry32(0x200000, 0, 0, 0x300000);
+  WriteDex(0x300000);
+
+  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_.reset(new DexFiles(process_memory_));
+  dex_files_->SetArch(ARCH_ARM);
+  method_name = "fail";
+  method_offset = 0x123;
+  memory_->SetData32(0xc800, 0x100000);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  EXPECT_EQ("fail", method_name);
+  EXPECT_EQ(0x123U, method_offset);
+}
+
+TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
+  std::string method_name = "nothing";
+  uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
+
+  // First global variable found, but value is zero.
+  memory_->SetData64(0xc800, 0);
+
+  memory_->SetData64(0xf800, 0x200000);
+  WriteEntry64(0x200000, 0, 0, 0x300000);
+  WriteDex(0x300000);
+
+  dex_files_->SetArch(ARCH_ARM64);
+  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_.reset(new DexFiles(process_memory_));
+  dex_files_->SetArch(ARCH_ARM64);
+  method_name = "fail";
+  method_offset = 0x123;
+  memory_->SetData32(0xc800, 0x100000);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  EXPECT_EQ("fail", method_name);
+  EXPECT_EQ(0x123U, method_offset);
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index 37628f8..c1c45f8 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -56,30 +56,30 @@
 
     MapInfo* map_info = maps_->Get(3);
     ASSERT_TRUE(map_info != nullptr);
-    elf_memories_.push_back(new MemoryFake);
-    ElfFake* elf = new ElfFake(elf_memories_.back());
+    MemoryFake* memory = new MemoryFake;
+    ElfFake* elf = new ElfFake(memory);
     elf->FakeSetValid(true);
-    ElfInterfaceFake* interface = new ElfInterfaceFake(elf_memories_.back());
+    ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
     elf->FakeSetInterface(interface);
     interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
     map_info->elf.reset(elf);
 
     map_info = maps_->Get(5);
     ASSERT_TRUE(map_info != nullptr);
-    elf_memories_.push_back(new MemoryFake);
-    elf = new ElfFake(elf_memories_.back());
+    memory = new MemoryFake;
+    elf = new ElfFake(memory);
     elf->FakeSetValid(true);
-    interface = new ElfInterfaceFake(elf_memories_.back());
+    interface = new ElfInterfaceFake(memory);
     elf->FakeSetInterface(interface);
     interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
     map_info->elf.reset(elf);
 
     map_info = maps_->Get(6);
     ASSERT_TRUE(map_info != nullptr);
-    elf_memories_.push_back(new MemoryFake);
-    elf = new ElfFake(elf_memories_.back());
+    memory = new MemoryFake;
+    elf = new ElfFake(memory);
     elf->FakeSetValid(true);
-    interface = new ElfInterfaceFake(elf_memories_.back());
+    interface = new ElfInterfaceFake(memory);
     elf->FakeSetInterface(interface);
     interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
     map_info->elf.reset(elf);
@@ -171,7 +171,6 @@
 
   std::shared_ptr<Memory> process_memory_;
   MemoryFake* memory_;
-  std::vector<MemoryFake*> elf_memories_;
   std::unique_ptr<JitDebug> jit_debug_;
   std::unique_ptr<BufferMaps> maps_;
 };
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index 33e5527..22ca7bf 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>
@@ -91,18 +92,18 @@
 
   auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
   unwindstack::Unwinder unwinder(128, &remote_maps, regs, process_memory);
+
   unwindstack::JitDebug jit_debug(process_memory);
   unwinder.SetJitDebug(&jit_debug, regs->Arch());
+
+  unwindstack::DexFiles dex_files(process_memory);
+  unwinder.SetDexFiles(&dex_files, regs->Arch());
+
   unwinder.Unwind();
 
   // Print the frames.
-  const std::vector<unwindstack::FrameData>& frames = unwinder.frames();
   for (size_t i = 0; i < unwinder.NumFrames(); i++) {
     printf("%s\n", unwinder.FormatFrame(i).c_str());
-    const unwindstack::FrameData* frame = &frames[i];
-    if (frame->dex_pc != 0) {
-      printf("      dex pc %" PRIx64 "\n", frame->dex_pc);
-    }
   }
 }
 
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index 3168f40..f0681d2 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -18,10 +18,6 @@
     disabled
     seclabel u:r:adbd:s0
 
-# adbd on at boot in emulator
-on property:ro.kernel.qemu=1
-    start adbd
-
 on boot
     setprop sys.usb.configfs 0