Merge "Add definition for zip64 struct"
diff --git a/adb/Android.bp b/adb/Android.bp
index d8fa713..b879753 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -436,6 +436,15 @@
             ],
         }
     },
+
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.adbd",
+    ],
+    visibility: [
+        "//bootable/recovery/minadbd",
+        "//system/core/adb",
+    ],
 }
 
 cc_library {
@@ -502,6 +511,15 @@
             ],
         },
     },
+
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.adbd",
+    ],
+    visibility: [
+        "//system/core/adb",
+    ],
+
 }
 
 cc_library {
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index 04ad536..d201239 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -204,7 +204,8 @@
 
 class SyncConnection {
   public:
-    SyncConnection() {
+    SyncConnection() : acknowledgement_buffer_(sizeof(sync_status) + SYNC_DATA_MAX) {
+        acknowledgement_buffer_.resize(0);
         max = SYNC_DATA_MAX; // TODO: decide at runtime.
 
         std::string error;
@@ -502,34 +503,6 @@
         return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
     }
 
-    bool ReadAcknowledgments() {
-        bool result = true;
-        while (!deferred_acknowledgements_.empty()) {
-            auto [from, to] = std::move(deferred_acknowledgements_.front());
-            deferred_acknowledgements_.pop_front();
-            result &= CopyDone(from, to);
-        }
-        return result;
-    }
-
-    bool CopyDone(const std::string& from, const std::string& to) {
-        syncmsg msg;
-        if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
-            Error("failed to copy '%s' to '%s': couldn't read from device", from.c_str(),
-                  to.c_str());
-            return false;
-        }
-        if (msg.status.id == ID_OKAY) {
-            return true;
-        }
-        if (msg.status.id != ID_FAIL) {
-            Error("failed to copy '%s' to '%s': unknown reason %d", from.c_str(), to.c_str(),
-                  msg.status.id);
-            return false;
-        }
-        return ReportCopyFailure(from, to, msg);
-    }
-
     bool ReportCopyFailure(const std::string& from, const std::string& to, const syncmsg& msg) {
         std::vector<char> buf(msg.status.msglen + 1);
         if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
@@ -542,6 +515,97 @@
         return false;
     }
 
+    void CopyDone() { deferred_acknowledgements_.pop_front(); }
+
+    void ReportDeferredCopyFailure(const std::string& msg) {
+        auto& [from, to] = deferred_acknowledgements_.front();
+        Error("failed to copy '%s' to '%s': remote %s", from.c_str(), to.c_str(), msg.c_str());
+        deferred_acknowledgements_.pop_front();
+    }
+
+    bool ReadAcknowledgements(bool read_all = false) {
+        // We need to read enough such that adbd's intermediate socket's write buffer can't be
+        // full. The default buffer on Linux is 212992 bytes, but there's 576 bytes of bookkeeping
+        // overhead per write. The worst case scenario is a continuous string of failures, since
+        // each logical packet is divided into two writes. If our packet size if conservatively 512
+        // bytes long, this leaves us with space for 128 responses.
+        constexpr size_t max_deferred_acks = 128;
+        auto& buf = acknowledgement_buffer_;
+        adb_pollfd pfd = {.fd = fd.get(), .events = POLLIN};
+        while (!deferred_acknowledgements_.empty()) {
+            bool should_block = read_all || deferred_acknowledgements_.size() >= max_deferred_acks;
+
+            ssize_t rc = adb_poll(&pfd, 1, should_block ? -1 : 0);
+            if (rc == 0) {
+                CHECK(!should_block);
+                return true;
+            }
+
+            if (acknowledgement_buffer_.size() < sizeof(sync_status)) {
+                const ssize_t header_bytes_left = sizeof(sync_status) - buf.size();
+                ssize_t rc = adb_read(fd, buf.end(), header_bytes_left);
+                if (rc <= 0) {
+                    Error("failed to read copy response");
+                    return false;
+                }
+
+                buf.resize(buf.size() + rc);
+                if (rc != header_bytes_left) {
+                    // Early exit if we run out of data in the socket.
+                    return true;
+                }
+
+                if (!should_block) {
+                    // We don't want to read again yet, because the socket might be empty.
+                    continue;
+                }
+            }
+
+            auto* hdr = reinterpret_cast<sync_status*>(buf.data());
+            if (hdr->id == ID_OKAY) {
+                buf.resize(0);
+                if (hdr->msglen != 0) {
+                    Error("received ID_OKAY with msg_len (%" PRIu32 " != 0", hdr->msglen);
+                    return false;
+                }
+                CopyDone();
+                continue;
+            } else if (hdr->id != ID_FAIL) {
+                Error("unexpected response from daemon: id = %#" PRIx32, hdr->id);
+                return false;
+            } else if (hdr->msglen > SYNC_DATA_MAX) {
+                Error("too-long message length from daemon: msglen = %" PRIu32, hdr->msglen);
+                return false;
+            }
+
+            const ssize_t msg_bytes_left = hdr->msglen + sizeof(sync_status) - buf.size();
+            CHECK_GE(msg_bytes_left, 0);
+            if (msg_bytes_left > 0) {
+                ssize_t rc = adb_read(fd, buf.end(), msg_bytes_left);
+                if (rc <= 0) {
+                    Error("failed to read copy failure message");
+                    return false;
+                }
+
+                buf.resize(buf.size() + rc);
+                if (rc != msg_bytes_left) {
+                    if (should_block) {
+                        continue;
+                    } else {
+                        return true;
+                    }
+                }
+
+                std::string msg(buf.begin() + sizeof(sync_status), buf.end());
+                ReportDeferredCopyFailure(msg);
+                buf.resize(0);
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     void Printf(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
         std::string s;
 
@@ -608,6 +672,7 @@
 
   private:
     std::deque<std::pair<std::string, std::string>> deferred_acknowledgements_;
+    Block acknowledgement_buffer_;
     FeatureSet features_;
     bool have_stat_v2_;
     bool have_ls_v2_;
@@ -716,7 +781,7 @@
         if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, buf, data_length)) {
             return false;
         }
-        return true;
+        return sc.ReadAcknowledgements();
 #endif
     }
 
@@ -739,7 +804,7 @@
             return false;
         }
     }
-    return true;
+    return sc.ReadAcknowledgements();
 }
 
 static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath,
@@ -966,8 +1031,9 @@
     }
 
     sc.RecordFilesSkipped(skipped);
+    bool success = sc.ReadAcknowledgements(true);
     sc.ReportTransferRate(lpath, TransferDirection::push);
-    return true;
+    return success;
 }
 
 bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync) {
@@ -1060,7 +1126,7 @@
         sc.ReportTransferRate(src_path, TransferDirection::push);
     }
 
-    success &= sc.ReadAcknowledgments();
+    success &= sc.ReadAcknowledgements(true);
     sc.ReportOverallTransferRate(TransferDirection::push);
     return success;
 }
diff --git a/adb/file_sync_protocol.h b/adb/file_sync_protocol.h
index 508c138..87ede0c 100644
--- a/adb/file_sync_protocol.h
+++ b/adb/file_sync_protocol.h
@@ -41,57 +41,69 @@
     // Followed by 'path_length' bytes of path (not NUL-terminated).
 } __attribute__((packed));
 
+struct __attribute__((packed)) sync_stat_v1 {
+    uint32_t id;
+    uint32_t mode;
+    uint32_t size;
+    uint32_t mtime;
+};
+
+struct __attribute__((packed)) sync_stat_v2 {
+    uint32_t id;
+    uint32_t error;
+    uint64_t dev;
+    uint64_t ino;
+    uint32_t mode;
+    uint32_t nlink;
+    uint32_t uid;
+    uint32_t gid;
+    uint64_t size;
+    int64_t atime;
+    int64_t mtime;
+    int64_t ctime;
+};
+
+struct __attribute__((packed)) sync_dent_v1 {
+    uint32_t id;
+    uint32_t mode;
+    uint32_t size;
+    uint32_t mtime;
+    uint32_t namelen;
+};  // followed by `namelen` bytes of the name.
+
+struct __attribute__((packed)) sync_dent_v2 {
+    uint32_t id;
+    uint32_t error;
+    uint64_t dev;
+    uint64_t ino;
+    uint32_t mode;
+    uint32_t nlink;
+    uint32_t uid;
+    uint32_t gid;
+    uint64_t size;
+    int64_t atime;
+    int64_t mtime;
+    int64_t ctime;
+    uint32_t namelen;
+};  // followed by `namelen` bytes of the name.
+
+struct __attribute__((packed)) sync_data {
+    uint32_t id;
+    uint32_t size;
+};  // followed by `size` bytes of data.
+
+struct __attribute__((packed)) sync_status {
+    uint32_t id;
+    uint32_t msglen;
+};  // followed by `msglen` bytes of error message, if id == ID_FAIL.
+
 union syncmsg {
-    struct __attribute__((packed)) {
-        uint32_t id;
-        uint32_t mode;
-        uint32_t size;
-        uint32_t mtime;
-    } stat_v1;
-    struct __attribute__((packed)) {
-        uint32_t id;
-        uint32_t error;
-        uint64_t dev;
-        uint64_t ino;
-        uint32_t mode;
-        uint32_t nlink;
-        uint32_t uid;
-        uint32_t gid;
-        uint64_t size;
-        int64_t atime;
-        int64_t mtime;
-        int64_t ctime;
-    } stat_v2;
-    struct __attribute__((packed)) {
-        uint32_t id;
-        uint32_t mode;
-        uint32_t size;
-        uint32_t mtime;
-        uint32_t namelen;
-    } dent_v1; // followed by `namelen` bytes of the name.
-    struct __attribute__((packed)) {
-        uint32_t id;
-        uint32_t error;
-        uint64_t dev;
-        uint64_t ino;
-        uint32_t mode;
-        uint32_t nlink;
-        uint32_t uid;
-        uint32_t gid;
-        uint64_t size;
-        int64_t atime;
-        int64_t mtime;
-        int64_t ctime;
-        uint32_t namelen;
-    } dent_v2; // followed by `namelen` bytes of the name.
-    struct __attribute__((packed)) {
-        uint32_t id;
-        uint32_t size;
-    } data; // followed by `size` bytes of data.
-    struct __attribute__((packed)) {
-        uint32_t id;
-        uint32_t msglen;
-    } status; // followed by `msglen` bytes of error message, if id == ID_FAIL.
+    sync_stat_v1 stat_v1;
+    sync_stat_v2 stat_v2;
+    sync_dent_v1 dent_v1;
+    sync_dent_v2 dent_v2;
+    sync_data data;
+    sync_status status;
 };
 
 #define SYNC_DATA_MAX (64 * 1024)
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index f28c778..c7bd1a8 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -103,9 +103,14 @@
     export_include_dirs: ["include"],
 }
 
-// Fallback implementation.
+// Fallback implementation, for use in the Bionic linker only.
 cc_library_static {
     name: "libdebuggerd_handler_fallback",
+    visibility: ["//bionic/linker"],
+    apex_available: [
+        "com.android.runtime",
+        "//apex_available:platform",
+    ],
     defaults: ["debuggerd_defaults"],
     recovery_available: true,
     srcs: [
@@ -118,8 +123,7 @@
         "libasync_safe",
         "libbase",
         "libdebuggerd",
-        "libunwindstack",
-        "libdexfile_support_static",  // libunwindstack dependency
+        "libunwindstack_no_dex",
         "liblzma",
         "libcutils",
     ],
@@ -127,14 +131,6 @@
     header_libs: ["bionic_libc_platform_headers"],
     export_header_lib_headers: ["bionic_libc_platform_headers"],
 
-    target: {
-        recovery: {
-            exclude_static_libs: [
-                "libdexfile_support_static",
-            ],
-        },
-    },
-
     export_include_dirs: ["include"],
 }
 
@@ -188,7 +184,7 @@
     ],
 
     static_libs: [
-        "libdexfile_support_static",  // libunwindstack dependency
+        "libdexfile_support",  // libunwindstack dependency
         "libunwindstack",
         "liblzma",
         "libbase",
@@ -201,7 +197,7 @@
     target: {
         recovery: {
             exclude_static_libs: [
-                "libdexfile_support_static",
+                "libdexfile_support",
             ],
         },
     },
diff --git a/debuggerd/libdebuggerd/gwp_asan.cpp b/debuggerd/libdebuggerd/gwp_asan.cpp
index fe3a173..3130cd4 100644
--- a/debuggerd/libdebuggerd/gwp_asan.cpp
+++ b/debuggerd/libdebuggerd/gwp_asan.cpp
@@ -172,15 +172,12 @@
     return frame;
   }
 
-  unwindstack::Elf* elf =
-      map_info->GetElf(unwinder->GetProcessMemory(), unwindstack::Regs::CurrentArch());
+  unwindstack::ArchEnum arch = unwindstack::Regs::CurrentArch();
+  unwindstack::Elf* elf = map_info->GetElf(unwinder->GetProcessMemory(), arch);
 
   uint64_t relative_pc = elf->GetRelPc(pc, map_info);
 
-  // Create registers just to get PC adjustment. Doesn't matter what they point
-  // to.
-  unwindstack::Regs* regs = unwindstack::Regs::CreateFromLocal();
-  uint64_t pc_adjustment = regs->GetPcAdjustment(relative_pc, elf);
+  uint64_t pc_adjustment = unwindstack::GetPcAdjustment(relative_pc, elf, arch);
   relative_pc -= pc_adjustment;
   // The debug PC may be different if the PC comes from the JIT.
   uint64_t debug_pc = relative_pc;
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index 46d4bd3..2c0989e 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -34,14 +34,54 @@
 #include <stdlib.h>
 #include <string.h>
 
-void bootimg_set_cmdline(boot_img_hdr_v2* h, const std::string& cmdline) {
+static void bootimg_set_cmdline_v3(boot_img_hdr_v3* h, const std::string& cmdline) {
     if (cmdline.size() >= sizeof(h->cmdline)) die("command line too large: %zu", cmdline.size());
     strcpy(reinterpret_cast<char*>(h->cmdline), cmdline.c_str());
 }
 
+void bootimg_set_cmdline(boot_img_hdr_v2* h, const std::string& cmdline) {
+    if (h->header_version == 3) {
+        return bootimg_set_cmdline_v3(reinterpret_cast<boot_img_hdr_v3*>(h), cmdline);
+    }
+    if (cmdline.size() >= sizeof(h->cmdline)) die("command line too large: %zu", cmdline.size());
+    strcpy(reinterpret_cast<char*>(h->cmdline), cmdline.c_str());
+}
+
+static boot_img_hdr_v3* mkbootimg_v3(const std::vector<char>& kernel,
+                                     const std::vector<char>& ramdisk, const boot_img_hdr_v2& src,
+                                     std::vector<char>* out) {
+#define V3_PAGE_SIZE 4096
+    const size_t page_mask = V3_PAGE_SIZE - 1;
+    int64_t kernel_actual = (kernel.size() + page_mask) & (~page_mask);
+    int64_t ramdisk_actual = (ramdisk.size() + page_mask) & (~page_mask);
+
+    int64_t bootimg_size = V3_PAGE_SIZE + kernel_actual + ramdisk_actual;
+    out->resize(bootimg_size);
+
+    boot_img_hdr_v3* hdr = reinterpret_cast<boot_img_hdr_v3*>(out->data());
+
+    memcpy(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
+    hdr->kernel_size = kernel.size();
+    hdr->ramdisk_size = ramdisk.size();
+    hdr->os_version = src.os_version;
+    hdr->header_size = sizeof(boot_img_hdr_v3);
+    hdr->header_version = 3;
+
+    memcpy(hdr->magic + V3_PAGE_SIZE, kernel.data(), kernel.size());
+    memcpy(hdr->magic + V3_PAGE_SIZE + kernel_actual, ramdisk.data(), ramdisk.size());
+
+    return hdr;
+}
+
 boot_img_hdr_v2* mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
                            const std::vector<char>& second, const std::vector<char>& dtb,
                            size_t base, const boot_img_hdr_v2& src, std::vector<char>* out) {
+    if (src.header_version == 3) {
+        if (!second.empty() || !dtb.empty()) {
+            die("Second stage bootloader and dtb not supported in v3 boot image\n");
+        }
+        return reinterpret_cast<boot_img_hdr_v2*>(mkbootimg_v3(kernel, ramdisk, src, out));
+    }
     const size_t page_mask = src.page_size - 1;
 
     int64_t header_actual = (sizeof(boot_img_hdr_v1) + page_mask) & (~page_mask);
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 7fdc28b..7f6e723 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -464,7 +464,7 @@
     }
 
     // Is this actually a boot image?
-    if (kernel_data.size() < sizeof(boot_img_hdr_v2)) {
+    if (kernel_data.size() < sizeof(boot_img_hdr_v3)) {
         die("cannot load '%s': too short", kernel.c_str());
     }
     if (!memcmp(kernel_data.data(), BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
@@ -493,7 +493,7 @@
 
     std::vector<char> dtb_data;
     if (!g_dtb_path.empty()) {
-        if (g_boot_img_hdr.header_version < 2) {
+        if (g_boot_img_hdr.header_version != 2) {
                     die("Argument dtb not supported for boot image header version %d\n",
                         g_boot_img_hdr.header_version);
         }
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 957c26c..5c276b4 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -230,8 +230,14 @@
     // devices;
     // - CreateResult::ERROR if a fatal error occurred, mounting /system should
     // be aborted.
+    // This function mounts /metadata when called, and unmounts /metadata upon
+    // return.
     CreateResult RecoveryCreateSnapshotDevices();
 
+    // Same as RecoveryCreateSnapshotDevices(), but does not auto mount/umount
+    // /metadata.
+    CreateResult RecoveryCreateSnapshotDevices(const std::unique_ptr<AutoDevice>& metadata_device);
+
     // Dump debug information.
     bool Dump(std::ostream& os);
 
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index ed052b1..1eec6a4 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -2587,6 +2587,20 @@
         LOG(ERROR) << "Couldn't mount Metadata.";
         return CreateResult::NOT_CREATED;
     }
+    return RecoveryCreateSnapshotDevices(mount);
+}
+
+CreateResult SnapshotManager::RecoveryCreateSnapshotDevices(
+        const std::unique_ptr<AutoDevice>& metadata_device) {
+    if (!device_->IsRecovery()) {
+        LOG(ERROR) << __func__ << " is only allowed in recovery.";
+        return CreateResult::NOT_CREATED;
+    }
+
+    if (metadata_device == nullptr || !metadata_device->HasDevice()) {
+        LOG(ERROR) << "Metadata not mounted.";
+        return CreateResult::NOT_CREATED;
+    }
 
     auto state_file = GetStateFilePath();
     if (access(state_file.c_str(), F_OK) != 0 && errno == ENOENT) {
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 8e9e074..8b67e22 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -233,6 +233,15 @@
     return value;
 }
 
+bool BatteryMonitor::isScopedPowerSupply(const char* name) {
+    constexpr char kScopeDevice[] = "Device";
+
+    String8 path;
+    path.appendFormat("%s/%s/scope", POWER_SUPPLY_SYSFS_PATH, name);
+    std::string scope;
+    return (readFromFile(path, &scope) > 0 && scope == kScopeDevice);
+}
+
 void BatteryMonitor::updateValues(void) {
     initHealthInfo(mHealthInfo.get());
 
@@ -547,6 +556,11 @@
                 break;
 
             case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
+                // Some devices expose the battery status of sub-component like
+                // stylus. Such a device-scoped battery info needs to be skipped
+                // in BatteryMonitor, which is intended to report the status of
+                // the battery supplying the power to the whole system.
+                if (isScopedPowerSupply(name)) continue;
                 mBatteryDevicePresent = true;
 
                 if (mHealthdConfig->batteryStatusPath.isEmpty()) {
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index d41a374..fadb5a5 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -78,6 +78,7 @@
     PowerSupplyType readPowerSupplyType(const String8& path);
     bool getBooleanField(const String8& path);
     int getIntField(const String8& path);
+    bool isScopedPowerSupply(const char* name);
 };
 
 }; // namespace android
diff --git a/init/Android.bp b/init/Android.bp
index 72a7bfe..d2bdf98 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -240,6 +240,7 @@
         "firmware_handler_test.cpp",
         "init_test.cpp",
         "keychords_test.cpp",
+        "oneshot_on_test.cpp",
         "persistent_properties_test.cpp",
         "property_service_test.cpp",
         "property_type_test.cpp",
diff --git a/init/Android.mk b/init/Android.mk
index 07b0f95..207b5e7 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -105,9 +105,8 @@
     libgsi \
     libcom.android.sysprop.apex \
     liblzma \
-    libdexfile_support_static \
-    libunwindstack \
-    libbacktrace \
+    libunwindstack_no_dex \
+    libbacktrace_no_dex \
     libmodprobe \
     libext2_uuid \
     libprotobuf-cpp-lite \
diff --git a/init/README.md b/init/README.md
index 4f0a7ec..13f1bac 100644
--- a/init/README.md
+++ b/init/README.md
@@ -720,23 +720,35 @@
   characteristics in a device agnostic manner.
 
 Init responds to properties that begin with `ctl.`.  These properties take the format of
-`ctl.<command>` and the _value_ of the system property is used as a parameter, for example:
-`SetProperty("ctl.start", "logd")` will run the `start` command on `logd`.  Note that these
+`ctl.[<target>_]<command>` and the _value_ of the system property is used as a parameter.  The
+_target_ is optional and specifies the service option that _value_ is meant to match with.  There is
+only one option for _target_, `interface` which indicates that _value_ will refer to an interface
+that a service provides and not the service name itself.
+
+For example:
+
+`SetProperty("ctl.start", "logd")` will run the `start` command on `logd`.
+
+`SetProperty("ctl.interface_start", "aidl/aidl_lazy_test_1")` will run the `start` command on the
+service that exposes the `aidl aidl_lazy_test_1` interface.
+
+Note that these
 properties are only settable; they will have no value when read.
 
-`ctl.start` \
-`ctl.restart` \
-`ctl.stop`
-> These are equivalent to using the `start`, `restart`, and `stop` commands on the service specified
+The _commands_ are listed below.
+
+`start` \
+`restart` \
+`stop` \
+These are equivalent to using the `start`, `restart`, and `stop` commands on the service specified
 by the _value_ of the property.
 
-`ctl.interface_start` \
-`ctl.interface_restart` \
-`ctl.interface_stop`
-> These are equivalent to using the `interface_start`, `interface_restart`, and `interface_stop`
-commands on the interface specified by the _value_ of the property.
+`oneshot_one` and `oneshot_off` will turn on or off the _oneshot_
+flag for the service specified by the _value_ of the property.  This is
+particularly intended for services that are conditionally lazy HALs.  When
+they are lazy HALs, oneshot must be on, otherwise oneshot should be off.
 
-`ctl.sigstop_on` and `ctl.sigstop_off` will turn on or off the _sigstop_ feature for the service
+`sigstop_on` and `sigstop_off` will turn on or off the _sigstop_ feature for the service
 specified by the _value_ of the property.  See the _Debugging init_ section below for more details
 about this feature.
 
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 622e457..3451264 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -97,7 +97,7 @@
     bool TrySwitchSystemAsRoot();
     bool TrySkipMountingPartitions();
     bool IsDmLinearEnabled();
-    void GetDmLinearMetadataDevice(std::set<std::string>* devices);
+    void GetSuperDeviceName(std::set<std::string>* devices);
     bool InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata);
     void UseDsuIfPresent();
     // Reads all fstab.avb_keys from the ramdisk for first-stage mount.
@@ -116,7 +116,8 @@
     bool dsu_not_on_userdata_ = false;
 
     Fstab fstab_;
-    std::string lp_metadata_partition_;
+    // The super path is only set after InitDevices, and is invalid before.
+    std::string super_path_;
     std::string super_partition_name_;
     std::unique_ptr<DeviceHandler> device_handler_;
     UeventListener uevent_listener_;
@@ -268,12 +269,23 @@
 
 bool FirstStageMount::InitDevices() {
     std::set<std::string> devices;
-    GetDmLinearMetadataDevice(&devices);
+    GetSuperDeviceName(&devices);
 
     if (!GetDmVerityDevices(&devices)) {
         return false;
     }
-    return InitRequiredDevices(std::move(devices));
+    if (!InitRequiredDevices(std::move(devices))) {
+        return false;
+    }
+
+    if (IsDmLinearEnabled()) {
+        auto super_symlink = "/dev/block/by-name/"s + super_partition_name_;
+        if (!android::base::Realpath(super_symlink, &super_path_)) {
+            PLOG(ERROR) << "realpath failed: " << super_symlink;
+            return false;
+        }
+    }
+    return true;
 }
 
 bool FirstStageMount::IsDmLinearEnabled() {
@@ -283,7 +295,7 @@
     return false;
 }
 
-void FirstStageMount::GetDmLinearMetadataDevice(std::set<std::string>* devices) {
+void FirstStageMount::GetSuperDeviceName(std::set<std::string>* devices) {
     // Add any additional devices required for dm-linear mappings.
     if (!IsDmLinearEnabled()) {
         return;
@@ -375,7 +387,7 @@
     if (!IsDmLinearEnabled()) {
         return true;
     }
-    if (lp_metadata_partition_.empty()) {
+    if (super_path_.empty()) {
         LOG(ERROR) << "Could not locate logical partition tables in partition "
                    << super_partition_name_;
         return false;
@@ -392,19 +404,19 @@
             if (!InitRequiredDevices({"userdata"})) {
                 return false;
             }
-            return sm->CreateLogicalAndSnapshotPartitions(lp_metadata_partition_);
+            return sm->CreateLogicalAndSnapshotPartitions(super_path_);
         }
     }
 
-    auto metadata = android::fs_mgr::ReadCurrentMetadata(lp_metadata_partition_);
+    auto metadata = android::fs_mgr::ReadCurrentMetadata(super_path_);
     if (!metadata) {
-        LOG(ERROR) << "Could not read logical partition metadata from " << lp_metadata_partition_;
+        LOG(ERROR) << "Could not read logical partition metadata from " << super_path_;
         return false;
     }
     if (!InitDmLinearBackingDevices(*metadata.get())) {
         return false;
     }
-    return android::fs_mgr::CreateLogicalPartitions(*metadata.get(), lp_metadata_partition_);
+    return android::fs_mgr::CreateLogicalPartitions(*metadata.get(), super_path_);
 }
 
 ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const Uevent& uevent,
@@ -415,10 +427,6 @@
     auto iter = required_devices->find(name);
     if (iter != required_devices->end()) {
         LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
-        if (IsDmLinearEnabled() && name == super_partition_name_) {
-            std::vector<std::string> links = device_handler_->GetBlockDeviceSymlinks(uevent);
-            lp_metadata_partition_ = links[0];
-        }
         required_devices->erase(iter);
         device_handler_->HandleUevent(uevent);
         if (required_devices->empty()) {
diff --git a/init/init.cpp b/init/init.cpp
index 4289dcf..5444a32 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -81,6 +81,7 @@
 using namespace std::string_literals;
 
 using android::base::boot_clock;
+using android::base::ConsumePrefix;
 using android::base::GetProperty;
 using android::base::ReadFileToString;
 using android::base::SetProperty;
@@ -367,40 +368,27 @@
     INTERFACE,  // action gets called for every service that holds this interface
 };
 
-struct ControlMessageFunction {
-    ControlTarget target;
-    std::function<Result<void>(Service*)> action;
-};
+using ControlMessageFunction = std::function<Result<void>(Service*)>;
 
-static const std::map<std::string, ControlMessageFunction>& get_control_message_map() {
+static const std::map<std::string, ControlMessageFunction, std::less<>>& GetControlMessageMap() {
     // clang-format off
-    static const std::map<std::string, ControlMessageFunction> control_message_functions = {
-        {"sigstop_on",        {ControlTarget::SERVICE,
-                               [](auto* service) { service->set_sigstop(true); return Result<void>{}; }}},
-        {"sigstop_off",       {ControlTarget::SERVICE,
-                               [](auto* service) { service->set_sigstop(false); return Result<void>{}; }}},
-        {"start",             {ControlTarget::SERVICE,   DoControlStart}},
-        {"stop",              {ControlTarget::SERVICE,   DoControlStop}},
-        {"restart",           {ControlTarget::SERVICE,   DoControlRestart}},
-        {"interface_start",   {ControlTarget::INTERFACE, DoControlStart}},
-        {"interface_stop",    {ControlTarget::INTERFACE, DoControlStop}},
-        {"interface_restart", {ControlTarget::INTERFACE, DoControlRestart}},
+    static const std::map<std::string, ControlMessageFunction, std::less<>> control_message_functions = {
+        {"sigstop_on",        [](auto* service) { service->set_sigstop(true); return Result<void>{}; }},
+        {"sigstop_off",       [](auto* service) { service->set_sigstop(false); return Result<void>{}; }},
+        {"oneshot_on",        [](auto* service) { service->set_oneshot(true); return Result<void>{}; }},
+        {"oneshot_off",       [](auto* service) { service->set_oneshot(false); return Result<void>{}; }},
+        {"start",             DoControlStart},
+        {"stop",              DoControlStop},
+        {"restart",           DoControlRestart},
     };
     // clang-format on
 
     return control_message_functions;
 }
 
-bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t pid) {
-    const auto& map = get_control_message_map();
-    const auto it = map.find(msg);
-
-    if (it == map.end()) {
-        LOG(ERROR) << "Unknown control msg '" << msg << "'";
-        return false;
-    }
-
-    std::string cmdline_path = StringPrintf("proc/%d/cmdline", pid);
+static bool HandleControlMessage(std::string_view message, const std::string& name,
+                                 pid_t from_pid) {
+    std::string cmdline_path = StringPrintf("proc/%d/cmdline", from_pid);
     std::string process_cmdline;
     if (ReadFileToString(cmdline_path, &process_cmdline)) {
         std::replace(process_cmdline.begin(), process_cmdline.end(), '\0', ' ');
@@ -409,37 +397,37 @@
         process_cmdline = "unknown process";
     }
 
-    const ControlMessageFunction& function = it->second;
-
-    Service* svc = nullptr;
-
-    switch (function.target) {
-        case ControlTarget::SERVICE:
-            svc = ServiceList::GetInstance().FindService(name);
-            break;
-        case ControlTarget::INTERFACE:
-            svc = ServiceList::GetInstance().FindInterface(name);
-            break;
-        default:
-            LOG(ERROR) << "Invalid function target from static map key ctl." << msg << ": "
-                       << static_cast<std::underlying_type<ControlTarget>::type>(function.target);
-            return false;
+    Service* service = nullptr;
+    auto action = message;
+    if (ConsumePrefix(&action, "interface_")) {
+        service = ServiceList::GetInstance().FindInterface(name);
+    } else {
+        service = ServiceList::GetInstance().FindService(name);
     }
 
-    if (svc == nullptr) {
-        LOG(ERROR) << "Control message: Could not find '" << name << "' for ctl." << msg
-                   << " from pid: " << pid << " (" << process_cmdline << ")";
+    if (service == nullptr) {
+        LOG(ERROR) << "Control message: Could not find '" << name << "' for ctl." << message
+                   << " from pid: " << from_pid << " (" << process_cmdline << ")";
         return false;
     }
 
-    if (auto result = function.action(svc); !result.ok()) {
-        LOG(ERROR) << "Control message: Could not ctl." << msg << " for '" << name
-                   << "' from pid: " << pid << " (" << process_cmdline << "): " << result.error();
+    const auto& map = GetControlMessageMap();
+    const auto it = map.find(action);
+    if (it == map.end()) {
+        LOG(ERROR) << "Unknown control msg '" << message << "'";
+        return false;
+    }
+    const auto& function = it->second;
+
+    if (auto result = function(service); !result.ok()) {
+        LOG(ERROR) << "Control message: Could not ctl." << message << " for '" << name
+                   << "' from pid: " << from_pid << " (" << process_cmdline
+                   << "): " << result.error();
         return false;
     }
 
-    LOG(INFO) << "Control message: Processed ctl." << msg << " for '" << name
-              << "' from pid: " << pid << " (" << process_cmdline << ")";
+    LOG(INFO) << "Control message: Processed ctl." << message << " for '" << name
+              << "' from pid: " << from_pid << " (" << process_cmdline << ")";
     return true;
 }
 
diff --git a/init/oneshot_on_test.cpp b/init/oneshot_on_test.cpp
new file mode 100644
index 0000000..7e7cc36
--- /dev/null
+++ b/init/oneshot_on_test.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 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 <gtest/gtest.h>
+
+#include <chrono>
+
+#include <android-base/properties.h>
+
+using android::base::GetProperty;
+using android::base::SetProperty;
+using android::base::WaitForProperty;
+using namespace std::literals;
+
+TEST(init, oneshot_on) {
+    // Bootanim shouldn't be running once the device has booted.
+    ASSERT_EQ("stopped", GetProperty("init.svc.bootanim", ""));
+
+    SetProperty("ctl.oneshot_off", "bootanim");
+    SetProperty("ctl.start", "bootanim");
+
+    // Bootanim exits quickly when the device is fully booted, so check that it goes back to the
+    // 'restarting' state that non-oneshot services enter once they've restarted.
+    EXPECT_TRUE(WaitForProperty("init.svc.bootanim", "restarting", 10s));
+
+    SetProperty("ctl.oneshot_on", "bootanim");
+    SetProperty("ctl.start", "bootanim");
+
+    // Now that oneshot is enabled again, bootanim should transition into the 'stopped' state.
+    EXPECT_TRUE(WaitForProperty("init.svc.bootanim", "stopped", 10s));
+}
diff --git a/init/service.h b/init/service.h
index cf3f0c2..9f1d697 100644
--- a/init/service.h
+++ b/init/service.h
@@ -130,6 +130,13 @@
     bool is_updatable() const { return updatable_; }
     bool is_post_data() const { return post_data_; }
     bool is_from_apex() const { return from_apex_; }
+    void set_oneshot(bool value) {
+        if (value) {
+            flags_ |= SVC_ONESHOT;
+        } else {
+            flags_ &= ~SVC_ONESHOT;
+        }
+    }
 
   private:
     void NotifyStateChange(const std::string& new_state) const;
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 76caadc..dc989a0 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -50,20 +50,9 @@
     ],
 }
 
-cc_library {
-    name: "libbacktrace",
-    vendor_available: false,
-    recovery_available: true,
-    apex_available: [
-        "//apex_available:platform",
-        "//apex_available:anyapex",
-    ],
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
+cc_defaults {
+    name: "libbacktrace_defaults",
     defaults: ["libbacktrace_common"],
-    host_supported: true,
 
     cflags: [
         "-Wexit-time-destructors",
@@ -88,7 +77,6 @@
             shared_libs: [
                 "libbase",
                 "liblog",
-                "libunwindstack",
             ],
 
             static_libs: [
@@ -101,6 +89,30 @@
                 whole_static_libs: ["libasync_safe"],
             },
         },
+    },
+}
+
+cc_library {
+    name: "libbacktrace",
+    vendor_available: false,
+    recovery_available: true,
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    host_supported: true,
+    defaults: ["libbacktrace_defaults"],
+
+    target: {
+        linux: {
+            shared_libs: [
+                "libunwindstack",
+            ],
+        },
         vendor: {
             cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
         },
@@ -110,6 +122,21 @@
     },
 }
 
+// Static library without DEX support to avoid dependencies on the ART APEX.
+cc_library_static {
+    name: "libbacktrace_no_dex",
+    visibility: ["//system/core/debuggerd"],
+    defaults: ["libbacktrace_defaults"],
+    cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
+    target: {
+        linux: {
+            static_libs: [
+                "libunwindstack_no_dex",
+            ],
+        },
+    },
+}
+
 cc_test_library {
     name: "libbacktrace_test",
     defaults: ["libbacktrace_common"],
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 3534eb8..1f26263 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -22,6 +22,10 @@
 TEST(libc, __pstore_append) {
 #ifdef __ANDROID__
 #ifndef NO_PSTORE
+  if (access("/dev/pmsg0", W_OK) != 0) {
+    GTEST_SKIP() << "pmsg0 not found, skipping test";
+  }
+
   FILE* fp;
   ASSERT_TRUE(NULL != (fp = fopen("/dev/pmsg0", "ae")));
   static const char message[] = "libc.__pstore_append\n";
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index a60d2df..773bac2 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -160,7 +160,6 @@
   return ret;
 }
 
-#ifndef NO_PSTORE
 static bool isPmsgActive() {
   pid_t pid = getpid();
 
@@ -170,7 +169,6 @@
 
   return std::string::npos != myPidFds.find(" -> /dev/pmsg0");
 }
-#endif /* NO_PSTORE */
 
 static bool isLogdwActive() {
   std::string logdwSignature =
@@ -222,16 +220,18 @@
   log_time ts(CLOCK_MONOTONIC);
   log_time ts1(ts);
 
+  bool has_pstore = access("/dev/pmsg0", W_OK) == 0;
+
   auto write_function = [&] {
     EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
     // Check that we can close and reopen the logger
     bool logdwActiveAfter__android_log_btwrite;
     if (getuid() == AID_ROOT) {
       tested__android_log_close = true;
-#ifndef NO_PSTORE
-      bool pmsgActiveAfter__android_log_btwrite = isPmsgActive();
-      EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
-#endif /* NO_PSTORE */
+      if (has_pstore) {
+        bool pmsgActiveAfter__android_log_btwrite = isPmsgActive();
+        EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
+      }
       logdwActiveAfter__android_log_btwrite = isLogdwActive();
       EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
     } else if (!tested__android_log_close) {
@@ -239,10 +239,10 @@
     }
     __android_log_close();
     if (getuid() == AID_ROOT) {
-#ifndef NO_PSTORE
-      bool pmsgActiveAfter__android_log_close = isPmsgActive();
-      EXPECT_FALSE(pmsgActiveAfter__android_log_close);
-#endif /* NO_PSTORE */
+      if (has_pstore) {
+        bool pmsgActiveAfter__android_log_close = isPmsgActive();
+        EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+      }
       bool logdwActiveAfter__android_log_close = isLogdwActive();
       EXPECT_FALSE(logdwActiveAfter__android_log_close);
     }
@@ -250,10 +250,10 @@
     ts1 = log_time(CLOCK_MONOTONIC);
     EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
     if (getuid() == AID_ROOT) {
-#ifndef NO_PSTORE
-      bool pmsgActiveAfter__android_log_btwrite = isPmsgActive();
-      EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
-#endif /* NO_PSTORE */
+      if (has_pstore) {
+        bool pmsgActiveAfter__android_log_btwrite = isPmsgActive();
+        EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
+      }
       logdwActiveAfter__android_log_btwrite = isLogdwActive();
       EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
     }
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 36449eb..9afc9a3 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -35,20 +35,13 @@
     },
 }
 
-cc_library {
-    name: "libunwindstack",
-    vendor_available: true,
-    recovery_available: true,
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
+cc_defaults {
+    name: "libunwindstack_defaults",
     defaults: ["libunwindstack_flags"],
     export_include_dirs: ["include"],
 
     srcs: [
         "ArmExidx.cpp",
-        "DexFile.cpp",
         "DexFiles.cpp",
         "DwarfCfa.cpp",
         "DwarfEhFrameWithHdr.cpp",
@@ -77,7 +70,6 @@
     ],
 
     cflags: [
-        "-DDEXFILE_SUPPORT",
         "-Wexit-time-destructors",
     ],
 
@@ -89,24 +81,6 @@
                 "-g",
             ],
         },
-        vendor: {
-            cflags: ["-UDEXFILE_SUPPORT"],
-            exclude_srcs: [
-                "DexFile.cpp",
-            ],
-            exclude_shared_libs: [
-                "libdexfile_support",
-            ],
-        },
-        recovery: {
-            cflags: ["-UDEXFILE_SUPPORT"],
-            exclude_srcs: [
-                "DexFile.cpp",
-            ],
-            exclude_shared_libs: [
-                "libdexfile_support",
-            ],
-        },
     },
 
     arch: {
@@ -124,12 +98,56 @@
 
     shared_libs: [
         "libbase",
-        "libdexfile_support",
         "liblog",
         "liblzma",
     ],
 }
 
+cc_library {
+    name: "libunwindstack",
+    vendor_available: true,
+    recovery_available: true,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    defaults: ["libunwindstack_defaults"],
+
+    srcs: ["DexFile.cpp"],
+    cflags: ["-DDEXFILE_SUPPORT"],
+    shared_libs: ["libdexfile_support"],
+
+    target: {
+        vendor: {
+            cflags: ["-UDEXFILE_SUPPORT"],
+            exclude_srcs: ["DexFile.cpp"],
+            exclude_shared_libs: ["libdexfile_support"],
+        },
+        recovery: {
+            cflags: ["-UDEXFILE_SUPPORT"],
+            exclude_srcs: ["DexFile.cpp"],
+            exclude_shared_libs: ["libdexfile_support"],
+        },
+    },
+}
+
+// Static library without DEX support to avoid dependencies on the ART APEX.
+cc_library_static {
+    name: "libunwindstack_no_dex",
+    recovery_available: true,
+    defaults: ["libunwindstack_defaults"],
+
+    visibility: [
+        "//system/core/debuggerd",
+        "//system/core/init",
+        "//system/core/libbacktrace",
+    ],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.runtime",
+    ],
+}
+
 //-------------------------------------------------------------------------
 // Unit Tests
 //-------------------------------------------------------------------------
diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp
index dff7a8b..bf63abf 100644
--- a/libunwindstack/DexFile.cpp
+++ b/libunwindstack/DexFile.cpp
@@ -89,7 +89,7 @@
     return nullptr;
   }
 
-  return std::unique_ptr<DexFileFromFile>(new DexFileFromFile(std::move(*art_dex_file.release())));
+  return std::unique_ptr<DexFileFromFile>(new DexFileFromFile(art_dex_file));
 }
 
 std::unique_ptr<DexFileFromMemory> DexFileFromMemory::Create(uint64_t dex_file_offset_in_memory,
@@ -108,7 +108,7 @@
 
     if (art_dex_file != nullptr) {
       return std::unique_ptr<DexFileFromMemory>(
-          new DexFileFromMemory(std::move(*art_dex_file.release()), std::move(backing_memory)));
+          new DexFileFromMemory(art_dex_file, std::move(backing_memory)));
     }
 
     if (!error_msg.empty()) {
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
index ca658e6..4e8369f 100644
--- a/libunwindstack/DexFile.h
+++ b/libunwindstack/DexFile.h
@@ -39,7 +39,8 @@
                                          MapInfo* info);
 
  protected:
-  DexFile(art_api::dex::DexFile&& art_dex_file) : art_api::dex::DexFile(std::move(art_dex_file)) {}
+  DexFile(std::unique_ptr<art_api::dex::DexFile>& art_dex_file)
+      : art_api::dex::DexFile(art_dex_file) {}
 };
 
 class DexFileFromFile : public DexFile {
@@ -48,7 +49,7 @@
                                                  const std::string& file);
 
  private:
-  DexFileFromFile(art_api::dex::DexFile&& art_dex_file) : DexFile(std::move(art_dex_file)) {}
+  DexFileFromFile(std::unique_ptr<art_api::dex::DexFile>& art_dex_file) : DexFile(art_dex_file) {}
 };
 
 class DexFileFromMemory : public DexFile {
@@ -57,8 +58,9 @@
                                                    Memory* memory, const std::string& name);
 
  private:
-  DexFileFromMemory(art_api::dex::DexFile&& art_dex_file, std::vector<uint8_t>&& memory)
-      : DexFile(std::move(art_dex_file)), memory_(std::move(memory)) {}
+  DexFileFromMemory(std::unique_ptr<art_api::dex::DexFile>& art_dex_file,
+                    std::vector<uint8_t>&& memory)
+      : DexFile(art_dex_file), memory_(std::move(memory)) {}
 
   std::vector<uint8_t> memory_;
 };
diff --git a/libunwindstack/LocalUnwinder.cpp b/libunwindstack/LocalUnwinder.cpp
index 5d81200..05650fb 100644
--- a/libunwindstack/LocalUnwinder.cpp
+++ b/libunwindstack/LocalUnwinder.cpp
@@ -106,7 +106,7 @@
     uint64_t step_pc = rel_pc;
     uint64_t pc_adjustment;
     if (adjust_pc) {
-      pc_adjustment = regs->GetPcAdjustment(rel_pc, elf);
+      pc_adjustment = GetPcAdjustment(rel_pc, elf, arch);
     } else {
       pc_adjustment = 0;
     }
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index e0a785b..03aa6c2 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -121,4 +121,62 @@
   return regs;
 }
 
+uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf, ArchEnum arch) {
+  switch (arch) {
+    case ARCH_ARM: {
+      if (!elf->valid()) {
+        return 2;
+      }
+
+      uint64_t load_bias = elf->GetLoadBias();
+      if (rel_pc < load_bias) {
+        if (rel_pc < 2) {
+          return 0;
+        }
+        return 2;
+      }
+      uint64_t adjusted_rel_pc = rel_pc - load_bias;
+      if (adjusted_rel_pc < 5) {
+        if (adjusted_rel_pc < 2) {
+          return 0;
+        }
+        return 2;
+      }
+
+      if (adjusted_rel_pc & 1) {
+        // This is a thumb instruction, it could be 2 or 4 bytes.
+        uint32_t value;
+        if (!elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
+            (value & 0xe000f000) != 0xe000f000) {
+          return 2;
+        }
+      }
+      return 4;
+    }
+  case ARCH_ARM64: {
+    if (rel_pc < 4) {
+      return 0;
+    }
+    return 4;
+  }
+  case ARCH_MIPS:
+  case ARCH_MIPS64: {
+    if (rel_pc < 8) {
+      return 0;
+    }
+    // For now, just assume no compact branches
+    return 8;
+  }
+  case ARCH_X86:
+  case ARCH_X86_64: {
+    if (rel_pc == 0) {
+      return 0;
+    }
+    return 1;
+  }
+  case ARCH_UNKNOWN:
+    return 0;
+  }
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/RegsArm.cpp b/libunwindstack/RegsArm.cpp
index 1b1f7eb..1aaa08f 100644
--- a/libunwindstack/RegsArm.cpp
+++ b/libunwindstack/RegsArm.cpp
@@ -51,37 +51,6 @@
   regs_[ARM_REG_SP] = sp;
 }
 
-uint64_t RegsArm::GetPcAdjustment(uint64_t rel_pc, Elf* elf) {
-  if (!elf->valid()) {
-    return 2;
-  }
-
-  uint64_t load_bias = elf->GetLoadBias();
-  if (rel_pc < load_bias) {
-    if (rel_pc < 2) {
-      return 0;
-    }
-    return 2;
-  }
-  uint64_t adjusted_rel_pc = rel_pc - load_bias;
-  if (adjusted_rel_pc < 5) {
-    if (adjusted_rel_pc < 2) {
-      return 0;
-    }
-    return 2;
-  }
-
-  if (adjusted_rel_pc & 1) {
-    // This is a thumb instruction, it could be 2 or 4 bytes.
-    uint32_t value;
-    if (!elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
-        (value & 0xe000f000) != 0xe000f000) {
-      return 2;
-    }
-  }
-  return 4;
-}
-
 bool RegsArm::SetPcFromReturnAddress(Memory*) {
   uint32_t lr = regs_[ARM_REG_LR];
   if (regs_[ARM_REG_PC] == lr) {
diff --git a/libunwindstack/RegsArm64.cpp b/libunwindstack/RegsArm64.cpp
index 00b3367..5b7431a 100644
--- a/libunwindstack/RegsArm64.cpp
+++ b/libunwindstack/RegsArm64.cpp
@@ -52,13 +52,6 @@
   regs_[ARM64_REG_SP] = sp;
 }
 
-uint64_t RegsArm64::GetPcAdjustment(uint64_t rel_pc, Elf*) {
-  if (rel_pc < 4) {
-    return 0;
-  }
-  return 4;
-}
-
 bool RegsArm64::SetPcFromReturnAddress(Memory*) {
   uint64_t lr = regs_[ARM64_REG_LR];
   if (regs_[ARM64_REG_PC] == lr) {
diff --git a/libunwindstack/RegsMips.cpp b/libunwindstack/RegsMips.cpp
index ebefe42..ab84691 100644
--- a/libunwindstack/RegsMips.cpp
+++ b/libunwindstack/RegsMips.cpp
@@ -52,14 +52,6 @@
   regs_[MIPS_REG_SP] = static_cast<uint32_t>(sp);
 }
 
-uint64_t RegsMips::GetPcAdjustment(uint64_t rel_pc, Elf*) {
-  if (rel_pc < 8) {
-    return 0;
-  }
-  // For now, just assume no compact branches
-  return 8;
-}
-
 bool RegsMips::SetPcFromReturnAddress(Memory*) {
   uint32_t ra = regs_[MIPS_REG_RA];
   if (regs_[MIPS_REG_PC] == ra) {
diff --git a/libunwindstack/RegsMips64.cpp b/libunwindstack/RegsMips64.cpp
index be2fd22..7f600d3 100644
--- a/libunwindstack/RegsMips64.cpp
+++ b/libunwindstack/RegsMips64.cpp
@@ -52,14 +52,6 @@
   regs_[MIPS64_REG_SP] = sp;
 }
 
-uint64_t RegsMips64::GetPcAdjustment(uint64_t rel_pc, Elf*) {
-  if (rel_pc < 8) {
-    return 0;
-  }
-  // For now, just assume no compact branches
-  return 8;
-}
-
 bool RegsMips64::SetPcFromReturnAddress(Memory*) {
   uint64_t ra = regs_[MIPS64_REG_RA];
   if (regs_[MIPS64_REG_PC] == ra) {
diff --git a/libunwindstack/RegsX86.cpp b/libunwindstack/RegsX86.cpp
index 5538fc0..4d3c246 100644
--- a/libunwindstack/RegsX86.cpp
+++ b/libunwindstack/RegsX86.cpp
@@ -50,13 +50,6 @@
   regs_[X86_REG_SP] = static_cast<uint32_t>(sp);
 }
 
-uint64_t RegsX86::GetPcAdjustment(uint64_t rel_pc, Elf*) {
-  if (rel_pc == 0) {
-    return 0;
-  }
-  return 1;
-}
-
 bool RegsX86::SetPcFromReturnAddress(Memory* process_memory) {
   // Attempt to get the return address from the top of the stack.
   uint32_t new_pc;
diff --git a/libunwindstack/RegsX86_64.cpp b/libunwindstack/RegsX86_64.cpp
index 5b9aa58..c9e245d 100644
--- a/libunwindstack/RegsX86_64.cpp
+++ b/libunwindstack/RegsX86_64.cpp
@@ -51,13 +51,6 @@
   regs_[X86_64_REG_SP] = sp;
 }
 
-uint64_t RegsX86_64::GetPcAdjustment(uint64_t rel_pc, Elf*) {
-  if (rel_pc == 0) {
-    return 0;
-  }
-  return 1;
-}
-
 bool RegsX86_64::SetPcFromReturnAddress(Memory* process_memory) {
   // Attempt to get the return address from the top of the stack.
   uint64_t new_pc;
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 1bb0319..560030e 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -181,7 +181,7 @@
         step_pc = rel_pc;
       }
       if (adjust_pc) {
-        pc_adjustment = regs_->GetPcAdjustment(rel_pc, elf);
+        pc_adjustment = GetPcAdjustment(rel_pc, elf, arch);
       } else {
         pc_adjustment = 0;
       }
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 4f761b4..a367e6c 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -64,8 +64,6 @@
   uint64_t dex_pc() { return dex_pc_; }
   void set_dex_pc(uint64_t dex_pc) { dex_pc_ = dex_pc; }
 
-  virtual uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) = 0;
-
   virtual bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) = 0;
 
   virtual bool SetPcFromReturnAddress(Memory* process_memory) = 0;
@@ -110,6 +108,8 @@
   std::vector<AddressType> regs_;
 };
 
+uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf, ArchEnum arch);
+
 }  // namespace unwindstack
 
 #endif  // _LIBUNWINDSTACK_REGS_H
diff --git a/libunwindstack/include/unwindstack/RegsArm.h b/libunwindstack/include/unwindstack/RegsArm.h
index aa029be..fbb34e7 100644
--- a/libunwindstack/include/unwindstack/RegsArm.h
+++ b/libunwindstack/include/unwindstack/RegsArm.h
@@ -36,8 +36,6 @@
 
   ArchEnum Arch() override final;
 
-  uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
-
   bool SetPcFromReturnAddress(Memory* process_memory) override;
 
   bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
diff --git a/libunwindstack/include/unwindstack/RegsArm64.h b/libunwindstack/include/unwindstack/RegsArm64.h
index 5cd7e5b..2b3ddeb 100644
--- a/libunwindstack/include/unwindstack/RegsArm64.h
+++ b/libunwindstack/include/unwindstack/RegsArm64.h
@@ -36,8 +36,6 @@
 
   ArchEnum Arch() override final;
 
-  uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
-
   bool SetPcFromReturnAddress(Memory* process_memory) override;
 
   bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
diff --git a/libunwindstack/include/unwindstack/RegsMips.h b/libunwindstack/include/unwindstack/RegsMips.h
index 8164a15..dc09b83 100644
--- a/libunwindstack/include/unwindstack/RegsMips.h
+++ b/libunwindstack/include/unwindstack/RegsMips.h
@@ -36,8 +36,6 @@
 
   ArchEnum Arch() override final;
 
-  uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
-
   bool SetPcFromReturnAddress(Memory* process_memory) override;
 
   bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
diff --git a/libunwindstack/include/unwindstack/RegsMips64.h b/libunwindstack/include/unwindstack/RegsMips64.h
index c982542..64a80dc 100644
--- a/libunwindstack/include/unwindstack/RegsMips64.h
+++ b/libunwindstack/include/unwindstack/RegsMips64.h
@@ -36,8 +36,6 @@
 
   ArchEnum Arch() override final;
 
-  uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
-
   bool SetPcFromReturnAddress(Memory* process_memory) override;
 
   bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
diff --git a/libunwindstack/include/unwindstack/RegsX86.h b/libunwindstack/include/unwindstack/RegsX86.h
index 2323a4f..cfbdda6 100644
--- a/libunwindstack/include/unwindstack/RegsX86.h
+++ b/libunwindstack/include/unwindstack/RegsX86.h
@@ -37,8 +37,6 @@
 
   ArchEnum Arch() override final;
 
-  uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
-
   bool SetPcFromReturnAddress(Memory* process_memory) override;
 
   bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
diff --git a/libunwindstack/include/unwindstack/RegsX86_64.h b/libunwindstack/include/unwindstack/RegsX86_64.h
index 3e919a4..a11aef0 100644
--- a/libunwindstack/include/unwindstack/RegsX86_64.h
+++ b/libunwindstack/include/unwindstack/RegsX86_64.h
@@ -37,8 +37,6 @@
 
   ArchEnum Arch() override final;
 
-  uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf) override;
-
   bool SetPcFromReturnAddress(Memory* process_memory) override;
 
   bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
index 1b54da6..dc935a3 100644
--- a/libunwindstack/tests/DexFileTest.cpp
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <malloc.h>
 #include <stdint.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -72,6 +73,37 @@
   EXPECT_TRUE(DexFileFromFile::Create(0x100, tf.path) != nullptr);
 }
 
+static constexpr size_t kNumLeakLoops = 5000;
+static constexpr size_t kMaxAllowedLeakBytes = 1024;
+
+static void CheckForLeak(size_t loop, size_t* first_allocated_bytes, size_t* last_allocated_bytes) {
+  size_t allocated_bytes = mallinfo().uordblks;
+  if (*first_allocated_bytes == 0) {
+    *first_allocated_bytes = allocated_bytes;
+  } else if (*last_allocated_bytes > *first_allocated_bytes) {
+    // Check that the total memory did not increase too much over the first loop.
+    ASSERT_LE(*last_allocated_bytes - *first_allocated_bytes, kMaxAllowedLeakBytes)
+        << "Failed in loop " << loop << " first_allocated_bytes " << *first_allocated_bytes
+        << " last_allocated_bytes " << *last_allocated_bytes;
+  }
+  *last_allocated_bytes = allocated_bytes;
+}
+
+TEST(DexFileTest, from_file_no_leak) {
+  TemporaryFile tf;
+  ASSERT_TRUE(tf.fd != -1);
+
+  ASSERT_EQ(sizeof(kDexData),
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+  size_t first_allocated_bytes = 0;
+  size_t last_allocated_bytes = 0;
+  for (size_t i = 0; i < kNumLeakLoops; i++) {
+    EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) != nullptr);
+    ASSERT_NO_FATAL_FAILURE(CheckForLeak(i, &first_allocated_bytes, &last_allocated_bytes));
+  }
+}
+
 TEST(DexFileTest, from_memory_fail_too_small_for_header) {
   MemoryFake memory;
 
@@ -96,6 +128,19 @@
   EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") != nullptr);
 }
 
+TEST(DexFileTest, from_memory_no_leak) {
+  MemoryFake memory;
+
+  memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
+
+  size_t first_allocated_bytes = 0;
+  size_t last_allocated_bytes = 0;
+  for (size_t i = 0; i < kNumLeakLoops; i++) {
+    EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") != nullptr);
+    ASSERT_NO_FATAL_FAILURE(CheckForLeak(i, &first_allocated_bytes, &last_allocated_bytes));
+  }
+}
+
 TEST(DexFileTest, create_using_file) {
   TemporaryFile tf;
   ASSERT_TRUE(tf.fd != -1);
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index 207d46e..75fc9d0 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -54,8 +54,6 @@
     return fake_arch_ == ARCH_ARM || fake_arch_ == ARCH_X86 || fake_arch_ == ARCH_MIPS;
   }
 
-  uint64_t GetPcAdjustment(uint64_t, Elf*) override { return 2; }
-
   bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
 
   void FakeSetArch(ArchEnum arch) { fake_arch_ = arch; }
@@ -86,7 +84,6 @@
   void set_pc(uint64_t pc) override { fake_pc_ = pc; }
   void set_sp(uint64_t sp) override { fake_sp_ = sp; }
 
-  uint64_t GetPcAdjustment(uint64_t, Elf*) override { return 0; }
   bool SetPcFromReturnAddress(Memory*) override { return false; }
   bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
 
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 0a33e2f..e4fc6f0 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -93,123 +93,104 @@
 }
 
 TEST_F(RegsTest, rel_pc) {
-  RegsArm64 arm64;
-  EXPECT_EQ(4U, arm64.GetPcAdjustment(0x10, elf_.get()));
-  EXPECT_EQ(4U, arm64.GetPcAdjustment(0x4, elf_.get()));
-  EXPECT_EQ(0U, arm64.GetPcAdjustment(0x3, elf_.get()));
-  EXPECT_EQ(0U, arm64.GetPcAdjustment(0x2, elf_.get()));
-  EXPECT_EQ(0U, arm64.GetPcAdjustment(0x1, elf_.get()));
-  EXPECT_EQ(0U, arm64.GetPcAdjustment(0x0, elf_.get()));
+  EXPECT_EQ(4U, GetPcAdjustment(0x10, elf_.get(), ARCH_ARM64));
+  EXPECT_EQ(4U, GetPcAdjustment(0x4, elf_.get(), ARCH_ARM64));
+  EXPECT_EQ(0U, GetPcAdjustment(0x3, elf_.get(), ARCH_ARM64));
+  EXPECT_EQ(0U, GetPcAdjustment(0x2, elf_.get(), ARCH_ARM64));
+  EXPECT_EQ(0U, GetPcAdjustment(0x1, elf_.get(), ARCH_ARM64));
+  EXPECT_EQ(0U, GetPcAdjustment(0x0, elf_.get(), ARCH_ARM64));
 
-  RegsX86 x86;
-  EXPECT_EQ(1U, x86.GetPcAdjustment(0x100, elf_.get()));
-  EXPECT_EQ(1U, x86.GetPcAdjustment(0x2, elf_.get()));
-  EXPECT_EQ(1U, x86.GetPcAdjustment(0x1, elf_.get()));
-  EXPECT_EQ(0U, x86.GetPcAdjustment(0x0, elf_.get()));
+  EXPECT_EQ(1U, GetPcAdjustment(0x100, elf_.get(), ARCH_X86));
+  EXPECT_EQ(1U, GetPcAdjustment(0x2, elf_.get(), ARCH_X86));
+  EXPECT_EQ(1U, GetPcAdjustment(0x1, elf_.get(), ARCH_X86));
+  EXPECT_EQ(0U, GetPcAdjustment(0x0, elf_.get(), ARCH_X86));
 
-  RegsX86_64 x86_64;
-  EXPECT_EQ(1U, x86_64.GetPcAdjustment(0x100, elf_.get()));
-  EXPECT_EQ(1U, x86_64.GetPcAdjustment(0x2, elf_.get()));
-  EXPECT_EQ(1U, x86_64.GetPcAdjustment(0x1, elf_.get()));
-  EXPECT_EQ(0U, x86_64.GetPcAdjustment(0x0, elf_.get()));
+  EXPECT_EQ(1U, GetPcAdjustment(0x100, elf_.get(), ARCH_X86_64));
+  EXPECT_EQ(1U, GetPcAdjustment(0x2, elf_.get(), ARCH_X86_64));
+  EXPECT_EQ(1U, GetPcAdjustment(0x1, elf_.get(), ARCH_X86_64));
+  EXPECT_EQ(0U, GetPcAdjustment(0x0, elf_.get(), ARCH_X86_64));
 
-  RegsMips mips;
-  EXPECT_EQ(8U, mips.GetPcAdjustment(0x10, elf_.get()));
-  EXPECT_EQ(8U, mips.GetPcAdjustment(0x8, elf_.get()));
-  EXPECT_EQ(0U, mips.GetPcAdjustment(0x7, elf_.get()));
-  EXPECT_EQ(0U, mips.GetPcAdjustment(0x6, elf_.get()));
-  EXPECT_EQ(0U, mips.GetPcAdjustment(0x5, elf_.get()));
-  EXPECT_EQ(0U, mips.GetPcAdjustment(0x4, elf_.get()));
-  EXPECT_EQ(0U, mips.GetPcAdjustment(0x3, elf_.get()));
-  EXPECT_EQ(0U, mips.GetPcAdjustment(0x2, elf_.get()));
-  EXPECT_EQ(0U, mips.GetPcAdjustment(0x1, elf_.get()));
-  EXPECT_EQ(0U, mips.GetPcAdjustment(0x0, elf_.get()));
+  EXPECT_EQ(8U, GetPcAdjustment(0x10, elf_.get(), ARCH_MIPS));
+  EXPECT_EQ(8U, GetPcAdjustment(0x8, elf_.get(), ARCH_MIPS));
+  EXPECT_EQ(0U, GetPcAdjustment(0x7, elf_.get(), ARCH_MIPS));
+  EXPECT_EQ(0U, GetPcAdjustment(0x6, elf_.get(), ARCH_MIPS));
+  EXPECT_EQ(0U, GetPcAdjustment(0x5, elf_.get(), ARCH_MIPS));
+  EXPECT_EQ(0U, GetPcAdjustment(0x4, elf_.get(), ARCH_MIPS));
+  EXPECT_EQ(0U, GetPcAdjustment(0x3, elf_.get(), ARCH_MIPS));
+  EXPECT_EQ(0U, GetPcAdjustment(0x2, elf_.get(), ARCH_MIPS));
+  EXPECT_EQ(0U, GetPcAdjustment(0x1, elf_.get(), ARCH_MIPS));
+  EXPECT_EQ(0U, GetPcAdjustment(0x0, elf_.get(), ARCH_MIPS));
 
-  RegsMips64 mips64;
-  EXPECT_EQ(8U, mips64.GetPcAdjustment(0x10, elf_.get()));
-  EXPECT_EQ(8U, mips64.GetPcAdjustment(0x8, elf_.get()));
-  EXPECT_EQ(0U, mips64.GetPcAdjustment(0x7, elf_.get()));
-  EXPECT_EQ(0U, mips64.GetPcAdjustment(0x6, elf_.get()));
-  EXPECT_EQ(0U, mips64.GetPcAdjustment(0x5, elf_.get()));
-  EXPECT_EQ(0U, mips64.GetPcAdjustment(0x4, elf_.get()));
-  EXPECT_EQ(0U, mips64.GetPcAdjustment(0x3, elf_.get()));
-  EXPECT_EQ(0U, mips64.GetPcAdjustment(0x2, elf_.get()));
-  EXPECT_EQ(0U, mips64.GetPcAdjustment(0x1, elf_.get()));
-  EXPECT_EQ(0U, mips64.GetPcAdjustment(0x0, elf_.get()));
+  EXPECT_EQ(8U, GetPcAdjustment(0x10, elf_.get(), ARCH_MIPS64));
+  EXPECT_EQ(8U, GetPcAdjustment(0x8, elf_.get(), ARCH_MIPS64));
+  EXPECT_EQ(0U, GetPcAdjustment(0x7, elf_.get(), ARCH_MIPS64));
+  EXPECT_EQ(0U, GetPcAdjustment(0x6, elf_.get(), ARCH_MIPS64));
+  EXPECT_EQ(0U, GetPcAdjustment(0x5, elf_.get(), ARCH_MIPS64));
+  EXPECT_EQ(0U, GetPcAdjustment(0x4, elf_.get(), ARCH_MIPS64));
+  EXPECT_EQ(0U, GetPcAdjustment(0x3, elf_.get(), ARCH_MIPS64));
+  EXPECT_EQ(0U, GetPcAdjustment(0x2, elf_.get(), ARCH_MIPS64));
+  EXPECT_EQ(0U, GetPcAdjustment(0x1, elf_.get(), ARCH_MIPS64));
+  EXPECT_EQ(0U, GetPcAdjustment(0x0, elf_.get(), ARCH_MIPS64));
 }
 
 TEST_F(RegsTest, rel_pc_arm) {
-  RegsArm arm;
-
   // Check fence posts.
   elf_->FakeSetLoadBias(0);
-  EXPECT_EQ(2U, arm.GetPcAdjustment(0x5, elf_.get()));
-  EXPECT_EQ(2U, arm.GetPcAdjustment(0x4, elf_.get()));
-  EXPECT_EQ(2U, arm.GetPcAdjustment(0x3, elf_.get()));
-  EXPECT_EQ(2U, arm.GetPcAdjustment(0x2, elf_.get()));
-  EXPECT_EQ(0U, arm.GetPcAdjustment(0x1, elf_.get()));
-  EXPECT_EQ(0U, arm.GetPcAdjustment(0x0, elf_.get()));
+  EXPECT_EQ(2U, GetPcAdjustment(0x5, elf_.get(), ARCH_ARM));
+  EXPECT_EQ(2U, GetPcAdjustment(0x4, elf_.get(), ARCH_ARM));
+  EXPECT_EQ(2U, GetPcAdjustment(0x3, elf_.get(), ARCH_ARM));
+  EXPECT_EQ(2U, GetPcAdjustment(0x2, elf_.get(), ARCH_ARM));
+  EXPECT_EQ(0U, GetPcAdjustment(0x1, elf_.get(), ARCH_ARM));
+  EXPECT_EQ(0U, GetPcAdjustment(0x0, elf_.get(), ARCH_ARM));
 
   elf_->FakeSetLoadBias(0x100);
-  EXPECT_EQ(0U, arm.GetPcAdjustment(0x1, elf_.get()));
-  EXPECT_EQ(2U, arm.GetPcAdjustment(0x2, elf_.get()));
-  EXPECT_EQ(2U, arm.GetPcAdjustment(0xff, elf_.get()));
-  EXPECT_EQ(2U, arm.GetPcAdjustment(0x105, elf_.get()));
-  EXPECT_EQ(2U, arm.GetPcAdjustment(0x104, elf_.get()));
-  EXPECT_EQ(2U, arm.GetPcAdjustment(0x103, elf_.get()));
-  EXPECT_EQ(2U, arm.GetPcAdjustment(0x102, elf_.get()));
-  EXPECT_EQ(0U, arm.GetPcAdjustment(0x101, elf_.get()));
-  EXPECT_EQ(0U, arm.GetPcAdjustment(0x100, elf_.get()));
+  EXPECT_EQ(0U, GetPcAdjustment(0x1, elf_.get(), ARCH_ARM));
+  EXPECT_EQ(2U, GetPcAdjustment(0x2, elf_.get(), ARCH_ARM));
+  EXPECT_EQ(2U, GetPcAdjustment(0xff, elf_.get(), ARCH_ARM));
+  EXPECT_EQ(2U, GetPcAdjustment(0x105, elf_.get(), ARCH_ARM));
+  EXPECT_EQ(2U, GetPcAdjustment(0x104, elf_.get(), ARCH_ARM));
+  EXPECT_EQ(2U, GetPcAdjustment(0x103, elf_.get(), ARCH_ARM));
+  EXPECT_EQ(2U, GetPcAdjustment(0x102, elf_.get(), ARCH_ARM));
+  EXPECT_EQ(0U, GetPcAdjustment(0x101, elf_.get(), ARCH_ARM));
+  EXPECT_EQ(0U, GetPcAdjustment(0x100, elf_.get(), ARCH_ARM));
 
   // Check thumb instructions handling.
   elf_->FakeSetLoadBias(0);
   memory_->SetData32(0x2000, 0);
-  EXPECT_EQ(2U, arm.GetPcAdjustment(0x2005, elf_.get()));
+  EXPECT_EQ(2U, GetPcAdjustment(0x2005, elf_.get(), ARCH_ARM));
   memory_->SetData32(0x2000, 0xe000f000);
-  EXPECT_EQ(4U, arm.GetPcAdjustment(0x2005, elf_.get()));
+  EXPECT_EQ(4U, GetPcAdjustment(0x2005, elf_.get(), ARCH_ARM));
 
   elf_->FakeSetLoadBias(0x400);
   memory_->SetData32(0x2100, 0);
-  EXPECT_EQ(2U, arm.GetPcAdjustment(0x2505, elf_.get()));
+  EXPECT_EQ(2U, GetPcAdjustment(0x2505, elf_.get(), ARCH_ARM));
   memory_->SetData32(0x2100, 0xf111f111);
-  EXPECT_EQ(4U, arm.GetPcAdjustment(0x2505, elf_.get()));
+  EXPECT_EQ(4U, GetPcAdjustment(0x2505, elf_.get(), ARCH_ARM));
 }
 
 TEST_F(RegsTest, elf_invalid) {
-  RegsArm regs_arm;
-  RegsArm64 regs_arm64;
-  RegsX86 regs_x86;
-  RegsX86_64 regs_x86_64;
-  RegsMips regs_mips;
-  RegsMips64 regs_mips64;
   MapInfo map_info(nullptr, nullptr, 0x1000, 0x2000, 0, 0, "");
   Elf* invalid_elf = new Elf(nullptr);
   map_info.elf.reset(invalid_elf);
 
-  regs_arm.set_pc(0x1500);
-  EXPECT_EQ(0x500U, invalid_elf->GetRelPc(regs_arm.pc(), &map_info));
-  EXPECT_EQ(2U, regs_arm.GetPcAdjustment(0x500U, invalid_elf));
-  EXPECT_EQ(2U, regs_arm.GetPcAdjustment(0x511U, invalid_elf));
+  EXPECT_EQ(0x500U, invalid_elf->GetRelPc(0x1500, &map_info));
+  EXPECT_EQ(2U, GetPcAdjustment(0x500U, invalid_elf, ARCH_ARM));
+  EXPECT_EQ(2U, GetPcAdjustment(0x511U, invalid_elf, ARCH_ARM));
 
-  regs_arm64.set_pc(0x1600);
-  EXPECT_EQ(0x600U, invalid_elf->GetRelPc(regs_arm64.pc(), &map_info));
-  EXPECT_EQ(4U, regs_arm64.GetPcAdjustment(0x600U, invalid_elf));
+  EXPECT_EQ(0x600U, invalid_elf->GetRelPc(0x1600, &map_info));
+  EXPECT_EQ(4U, GetPcAdjustment(0x600U, invalid_elf, ARCH_ARM64));
 
-  regs_x86.set_pc(0x1700);
-  EXPECT_EQ(0x700U, invalid_elf->GetRelPc(regs_x86.pc(), &map_info));
-  EXPECT_EQ(1U, regs_x86.GetPcAdjustment(0x700U, invalid_elf));
+  EXPECT_EQ(0x700U, invalid_elf->GetRelPc(0x1700, &map_info));
+  EXPECT_EQ(1U, GetPcAdjustment(0x700U, invalid_elf, ARCH_X86));
 
-  regs_x86_64.set_pc(0x1800);
-  EXPECT_EQ(0x800U, invalid_elf->GetRelPc(regs_x86_64.pc(), &map_info));
-  EXPECT_EQ(1U, regs_x86_64.GetPcAdjustment(0x800U, invalid_elf));
+  EXPECT_EQ(0x800U, invalid_elf->GetRelPc(0x1800, &map_info));
+  EXPECT_EQ(1U, GetPcAdjustment(0x800U, invalid_elf, ARCH_X86_64));
 
-  regs_mips.set_pc(0x1900);
-  EXPECT_EQ(0x900U, invalid_elf->GetRelPc(regs_mips.pc(), &map_info));
-  EXPECT_EQ(8U, regs_mips.GetPcAdjustment(0x900U, invalid_elf));
+  EXPECT_EQ(0x900U, invalid_elf->GetRelPc(0x1900, &map_info));
+  EXPECT_EQ(8U, GetPcAdjustment(0x900U, invalid_elf, ARCH_MIPS));
 
-  regs_mips64.set_pc(0x1a00);
-  EXPECT_EQ(0xa00U, invalid_elf->GetRelPc(regs_mips64.pc(), &map_info));
-  EXPECT_EQ(8U, regs_mips64.GetPcAdjustment(0xa00U, invalid_elf));
+  EXPECT_EQ(0xa00U, invalid_elf->GetRelPc(0x1a00, &map_info));
+  EXPECT_EQ(8U, GetPcAdjustment(0xa00U, invalid_elf, ARCH_MIPS64));
 }
 
 TEST_F(RegsTest, arm_verify_sp_pc) {
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index ef1950c..dd33aa9 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -161,8 +161,8 @@
 
   regs_.set_pc(0x1000);
   regs_.set_sp(0x10000);
-  ElfInterfaceFake::FakePushStepData(StepData(0x1102, 0x10010, false));
-  ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x1104, 0x10010, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x1204, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
@@ -225,8 +225,8 @@
 
   regs_.set_pc(0x1000);
   regs_.set_sp(0x10000);
-  ElfInterfaceFake::FakePushStepData(StepData(0x1102, 0x10010, false));
-  ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x1104, 0x10010, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x1204, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
@@ -445,7 +445,7 @@
 TEST_F(UnwinderTest, max_frames) {
   for (size_t i = 0; i < 30; i++) {
     ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame" + std::to_string(i), i));
-    ElfInterfaceFake::FakePushStepData(StepData(0x1102 + i * 0x100, 0x10010 + i * 0x10, false));
+    ElfInterfaceFake::FakePushStepData(StepData(0x1104 + i * 0x100, 0x10010 + i * 0x10, false));
   }
 
   regs_.set_pc(0x1000);
@@ -484,12 +484,12 @@
 
   regs_.set_pc(0x20000);
   regs_.set_sp(0x10000);
-  ElfInterfaceFake::FakePushStepData(StepData(0x23002, 0x10010, false));
-  ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false));
-  ElfInterfaceFake::FakePushStepData(StepData(0x20002, 0x10030, false));
-  ElfInterfaceFake::FakePushStepData(StepData(0x21002, 0x10040, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x23004, 0x10010, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x23104, 0x10020, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x20004, 0x10030, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x21004, 0x10040, false));
   ElfInterfaceFake::FakePushStepData(StepData(0x1002, 0x10050, false));
-  ElfInterfaceFake::FakePushStepData(StepData(0x21002, 0x10060, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x21004, 0x10060, false));
   ElfInterfaceFake::FakePushStepData(StepData(0x23002, 0x10070, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
@@ -553,7 +553,7 @@
 
   regs_.set_pc(0x1000);
   regs_.set_sp(0x63000);
-  ElfInterfaceFake::FakePushStepData(StepData(0x21002, 0x50020, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x21004, 0x50020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
@@ -670,10 +670,10 @@
   // Fake as if code called a nullptr function.
   regs_.set_pc(0);
   regs_.set_sp(0x10000);
-  regs_.FakeSetReturnAddress(0x1202);
+  regs_.FakeSetReturnAddress(0x1204);
   regs_.FakeSetReturnAddressValid(true);
 
-  ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x23104, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
@@ -789,7 +789,7 @@
   // Fake as if code called a nullptr function.
   regs_.set_pc(0);
   regs_.set_sp(0x10000);
-  regs_.FakeSetReturnAddress(0x1202);
+  regs_.FakeSetReturnAddress(0x1204);
   regs_.FakeSetReturnAddressValid(true);
 
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
@@ -858,8 +858,8 @@
   // Fake as if code called a nullptr function.
   regs_.set_pc(0x1000);
   regs_.set_sp(0x10000);
-  ElfInterfaceFake::FakePushStepData(StepData(0x43402, 0x10010, false));
-  ElfInterfaceFake::FakePushStepData(StepData(0x53502, 0x10020, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x43404, 0x10010, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x53504, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
@@ -915,11 +915,11 @@
 
   regs_.set_pc(0x1000);
   regs_.set_sp(0x10000);
-  ElfInterfaceFake::FakePushStepData(StepData(0x33402, 0x10010, false));
-  ElfInterfaceFake::FakePushStepData(StepData(0x33502, 0x10020, false));
-  ElfInterfaceFake::FakePushStepData(StepData(0x33502, 0x10020, false));
-  ElfInterfaceFake::FakePushStepData(StepData(0x33502, 0x10020, false));
-  ElfInterfaceFake::FakePushStepData(StepData(0x33502, 0x10020, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x33404, 0x10010, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x33504, 0x10020, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x33504, 0x10020, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x33504, 0x10020, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x33504, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
@@ -1113,7 +1113,7 @@
   regs_.set_pc(0x1000);
   regs_.set_sp(0x10000);
   regs_.FakeSetDexPc(0xa3400);
-  ElfInterfaceFake::FakePushStepData(StepData(0x33402, 0x10010, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x33404, 0x10010, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);