[automerger skipped] Make init.userspace_reboot.is_supported a rw property am: 9fd393f430 -s ours

am skip reason: Change-Id I7552d5ccc6e9b750a6081947eef8fcb027be13e1 with SHA-1 663cd35030 is in history

Change-Id: Iea491137db1f9dd047c3d82ecc6f97d83e860712
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 0ec505d..9b6213a 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -7,6 +7,12 @@
       "name": "adb_crypto_test"
     },
     {
+      "name": "adb_pairing_auth_test"
+    },
+    {
+      "name": "adb_pairing_connection_test"
+    },
+    {
       "name": "adb_tls_connection_test"
     },
     {
@@ -22,6 +28,9 @@
       "name": "fs_mgr_vendor_overlay_test"
     },
     {
+      "name": "init_kill_services_test"
+    },
+    {
       "name": "libbase_test"
     },
     {
@@ -58,5 +67,11 @@
     {
       "name": "ziparchive-tests"
     }
+  ],
+
+  "postsubmit": [
+    {
+      "name": "ziparchive_tests_large"
+    }
   ]
 }
diff --git a/adb/Android.bp b/adb/Android.bp
index 0af82e1..12d9a14 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -131,6 +131,8 @@
         "libbase",
 
         "libadb_protos",
+        "libapp_processes_protos_lite",
+        "libprotobuf-cpp-lite",
     ],
 
     shared_libs: [
@@ -315,11 +317,12 @@
     static_libs: [
         "libadb_crypto",
         "libadb_host",
-	"libadb_pairing_auth",
-	"libadb_pairing_connection",
+        "libadb_pairing_auth",
+        "libadb_pairing_connection",
         "libadb_protos",
         "libadb_tls_connection",
         "libandroidfw",
+        "libapp_processes_protos_full",
         "libbase",
         "libbrotli",
         "libcutils",
@@ -330,7 +333,7 @@
         "liblog",
         "liblz4",
         "libmdnssd",
-        "libprotobuf-cpp-lite",
+        "libprotobuf-cpp-full",
         "libssl",
         "libusb",
         "libutils",
@@ -389,16 +392,17 @@
     generated_headers: ["platform_tools_version"],
 
     static_libs: [
-        "libadbconnection_server",
         "libdiagnose_usb",
     ],
 
     shared_libs: [
+        "libadbconnection_server",
         "libadb_crypto",
         "libadb_pairing_connection",
         "libadb_protos",
         "libadb_tls_connection",
         "libadbd_auth",
+        "libapp_processes_protos_lite",
         "libasyncio",
         "libbase",
         "libcrypto",
@@ -407,6 +411,12 @@
         "liblog",
     ],
 
+    proto: {
+        type: "lite",
+        static: true,
+        export_proto_headers: true,
+    },
+
     target: {
         android: {
             whole_static_libs: [
@@ -422,9 +432,19 @@
             exclude_shared_libs: [
                 "libadb_pairing_auth",
                 "libadb_pairing_connection",
+                "libapp_processes_protos_lite",
             ],
         }
     },
+
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.adbd",
+    ],
+    visibility: [
+        "//bootable/recovery/minadbd",
+        "//system/core/adb",
+    ],
 }
 
 cc_library {
@@ -457,10 +477,12 @@
         "libadb_pairing_connection",
         "libadb_protos",
         "libadb_tls_connection",
+        "libapp_processes_protos_lite",
         "libasyncio",
         "libbase",
         "libcrypto_utils",
         "libcutils_sockets",
+        "libprotobuf-cpp-lite",
 
         // APEX dependencies.
         "libadbd_auth",
@@ -492,12 +514,22 @@
             ],
         },
     },
+
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.adbd",
+    ],
+    visibility: [
+        "//system/core/adb",
+    ],
+
 }
 
 cc_library {
     name: "libadbd",
     defaults: ["adbd_defaults", "host_adbd_supported"],
     recovery_available: true,
+    apex_available: ["com.android.adbd"],
 
     // avoid getting duplicate symbol of android::build::getbuildnumber().
     use_version_lib: false,
@@ -506,6 +538,9 @@
     compile_multilib: "both",
 
     shared_libs: [
+        "libadbconnection_server",
+        "libapp_processes_protos_lite",
+        "libprotobuf-cpp-lite",
         "libadb_crypto",
         "libadb_pairing_connection",
         "libadb_tls_connection",
@@ -550,6 +585,7 @@
     defaults: ["adbd_defaults", "host_adbd_supported", "libadbd_binary_dependencies"],
     stl: "libc++_static",
     recovery_available: true,
+    apex_available: ["com.android.adbd"],
 
     srcs: [
         "daemon/main.cpp",
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 44e5dac..6c03f74 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1020,8 +1020,12 @@
         if (kill_forward) {
             r = remove_listener(pieces[0].c_str(), transport);
         } else {
-            r = install_listener(pieces[0], pieces[1].c_str(), transport, no_rebind,
-                                 &resolved_tcp_port, &error);
+            int flags = 0;
+            if (no_rebind) {
+                flags |= INSTALL_LISTENER_NO_REBIND;
+            }
+            r = install_listener(pieces[0], pieces[1].c_str(), transport, flags, &resolved_tcp_port,
+                                 &error);
         }
         if (r == INSTALL_STATUS_OK) {
 #if ADB_HOST
diff --git a/adb/adb.h b/adb/adb.h
index ce12a55..7bc60fc 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -167,6 +167,7 @@
 int init_jdwp(void);
 asocket* create_jdwp_service_socket();
 asocket* create_jdwp_tracker_service_socket();
+asocket* create_app_tracker_service_socket();
 unique_fd create_jdwp_connection_fd(int jdwp_pid);
 #endif
 
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index 29909a5..43a9252 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -164,6 +164,15 @@
     }
 }
 
+void enable_daemon_sockets() EXCLUDES(listener_list_mutex) {
+    std::lock_guard<std::mutex> lock(listener_list_mutex);
+    for (auto& l : listener_list) {
+        if (l->connect_to == "*smartsocket*") {
+            fdevent_set(l->fde, FDE_READ);
+        }
+    }
+}
+
 void close_smartsockets() EXCLUDES(listener_list_mutex) {
     std::lock_guard<std::mutex> lock(listener_list_mutex);
     auto pred = [](const std::unique_ptr<alistener>& listener) {
@@ -173,7 +182,7 @@
 }
 
 InstallStatus install_listener(const std::string& local_name, const char* connect_to,
-                               atransport* transport, int no_rebind, int* resolved_tcp_port,
+                               atransport* transport, int flags, int* resolved_tcp_port,
                                std::string* error) EXCLUDES(listener_list_mutex) {
     std::lock_guard<std::mutex> lock(listener_list_mutex);
     for (auto& l : listener_list) {
@@ -184,8 +193,8 @@
                 return INSTALL_STATUS_INTERNAL_ERROR;
             }
 
-            // Can't repurpose a listener if 'no_rebind' is true.
-            if (no_rebind) {
+            // Can't repurpose a listener if INSTALL_LISTENER_NO_REBIND is set
+            if (flags & INSTALL_LISTENER_NO_REBIND) {
                 *error = "cannot rebind";
                 return INSTALL_STATUS_CANNOT_REBIND;
             }
@@ -222,7 +231,9 @@
     } else {
         listener->fde = fdevent_create(listener->fd, listener_event_func, listener.get());
     }
-    fdevent_set(listener->fde, FDE_READ);
+    if ((flags & INSTALL_LISTENER_DISABLED) == 0) {
+        fdevent_set(listener->fde, FDE_READ);
+    }
 
     listener->transport = transport;
 
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index 70a2ee1..354dcc5 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -32,8 +32,11 @@
   INSTALL_STATUS_LISTENER_NOT_FOUND = -4,
 };
 
+inline constexpr int INSTALL_LISTENER_NO_REBIND = 1 << 0;
+inline constexpr int INSTALL_LISTENER_DISABLED = 1 << 1;
+
 InstallStatus install_listener(const std::string& local_name, const char* connect_to,
-                               atransport* transport, int no_rebind, int* resolved_tcp_port,
+                               atransport* transport, int flags, int* resolved_tcp_port,
                                std::string* error);
 
 std::string format_listeners();
@@ -41,6 +44,7 @@
 InstallStatus remove_listener(const char* local_name, atransport* transport);
 void remove_all_listeners(void);
 
+void enable_daemon_sockets();
 void close_smartsockets();
 
 #endif /* __ADB_LISTENERS_H */
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index 8738ce7..4b2fa04 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -145,12 +145,12 @@
 
     std::lock_guard<std::mutex> lock(g_keys_mutex);
     std::string fingerprint = hash_key(key.get());
-    if (g_keys.find(fingerprint) != g_keys.end()) {
-        LOG(INFO) << "ignoring already-loaded key: " << file;
-    } else {
-        LOG(INFO) << "Loaded fingerprint=[" << SHA256BitsToHexString(fingerprint) << "]";
+    bool already_loaded = (g_keys.find(fingerprint) != g_keys.end());
+    if (!already_loaded) {
         g_keys[fingerprint] = std::move(key);
     }
+    LOG(INFO) << (already_loaded ? "ignored already-loaded" : "loaded new") << " key from '" << file
+              << "' with fingerprint " << SHA256BitsToHexString(fingerprint);
     return true;
 }
 
@@ -159,23 +159,25 @@
 
     struct stat st;
     if (stat(path.c_str(), &st) != 0) {
-        PLOG(ERROR) << "failed to stat '" << path << "'";
+        PLOG(ERROR) << "load_keys: failed to stat '" << path << "'";
         return false;
     }
 
     if (S_ISREG(st.st_mode)) {
         return load_key(path);
-    } else if (S_ISDIR(st.st_mode)) {
+    }
+
+    if (S_ISDIR(st.st_mode)) {
         if (!allow_dir) {
             // inotify isn't recursive. It would break expectations to load keys in nested
             // directories but not monitor them for new keys.
-            LOG(WARNING) << "refusing to recurse into directory '" << path << "'";
+            LOG(WARNING) << "load_keys: refusing to recurse into directory '" << path << "'";
             return false;
         }
 
         std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
         if (!dir) {
-            PLOG(ERROR) << "failed to open directory '" << path << "'";
+            PLOG(ERROR) << "load_keys: failed to open directory '" << path << "'";
             return false;
         }
 
@@ -189,7 +191,7 @@
             }
 
             if (!android::base::EndsWith(name, ".adb_key")) {
-                LOG(INFO) << "skipping non-adb_key '" << path << "/" << name << "'";
+                LOG(INFO) << "skipped non-adb_key '" << path << "/" << name << "'";
                 continue;
             }
 
@@ -198,7 +200,7 @@
         return result;
     }
 
-    LOG(ERROR) << "unexpected type for '" << path << "': 0x" << std::hex << st.st_mode;
+    LOG(ERROR) << "load_keys: unexpected type for '" << path << "': 0x" << std::hex << st.st_mode;
     return false;
 }
 
diff --git a/adb/client/bugreport.cpp b/adb/client/bugreport.cpp
index 8ca44e8..ab93f7d 100644
--- a/adb/client/bugreport.cpp
+++ b/adb/client/bugreport.cpp
@@ -282,5 +282,5 @@
 
 bool Bugreport::DoSyncPull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs,
                            const char* name) {
-    return do_sync_pull(srcs, dst, copy_attrs, name);
+    return do_sync_pull(srcs, dst, copy_attrs, false, name);
 }
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index ad4e21c..04b250d 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -50,6 +50,8 @@
 #include <unistd.h>
 #endif
 
+#include <google/protobuf/text_format.h>
+
 #include "adb.h"
 #include "adb_auth.h"
 #include "adb_client.h"
@@ -57,6 +59,7 @@
 #include "adb_io.h"
 #include "adb_unique_fd.h"
 #include "adb_utils.h"
+#include "app_processes.pb.h"
 #include "bugreport.h"
 #include "client/file_sync_client.h"
 #include "commandline.h"
@@ -197,8 +200,8 @@
         "     generate adb public/private key; private key stored in FILE,\n"
         "\n"
         "scripting:\n"
-        " wait-for[-TRANSPORT]-STATE\n"
-        "     wait for device to be in the given state\n"
+        " wait-for[-TRANSPORT]-STATE...\n"
+        "     wait for device to be in a given state\n"
         "     STATE: device, recovery, rescue, sideload, bootloader, or disconnect\n"
         "     TRANSPORT: usb, local, or any [default=any]\n"
         " get-state                print offline | bootloader | device\n"
@@ -1060,17 +1063,16 @@
 static bool wait_for_device(const char* service,
                             std::optional<std::chrono::milliseconds> timeout = std::nullopt) {
     std::vector<std::string> components = android::base::Split(service, "-");
-    if (components.size() < 3 || components.size() > 4) {
+    if (components.size() < 3) {
         fprintf(stderr, "adb: couldn't parse 'wait-for' command: %s\n", service);
         return false;
     }
 
-    TransportType t;
-    adb_get_transport(&t, nullptr, nullptr);
-
-    // Was the caller vague about what they'd like us to wait for?
-    // If so, check they weren't more specific in their choice of transport type.
-    if (components.size() == 3) {
+    // If the first thing after "wait-for-" wasn't a TRANSPORT, insert whatever
+    // the current transport implies.
+    if (components[2] != "usb" && components[2] != "local" && components[2] != "any") {
+        TransportType t;
+        adb_get_transport(&t, nullptr, nullptr);
         auto it = components.begin() + 2;
         if (t == kTransportUsb) {
             components.insert(it, "usb");
@@ -1079,23 +1081,9 @@
         } else {
             components.insert(it, "any");
         }
-    } else if (components[2] != "any" && components[2] != "local" && components[2] != "usb") {
-        fprintf(stderr, "adb: unknown type %s; expected 'any', 'local', or 'usb'\n",
-                components[2].c_str());
-        return false;
     }
 
-    if (components[3] != "any" && components[3] != "bootloader" && components[3] != "device" &&
-        components[3] != "recovery" && components[3] != "rescue" && components[3] != "sideload" &&
-        components[3] != "disconnect") {
-        fprintf(stderr,
-                "adb: unknown state %s; "
-                "expected 'any', 'bootloader', 'device', 'recovery', 'rescue', 'sideload', or "
-                "'disconnect'\n",
-                components[3].c_str());
-        return false;
-    }
-
+    // Stitch it back together and send it over...
     std::string cmd = format_host_command(android::base::Join(components, "-").c_str());
     if (timeout) {
         std::thread([timeout]() {
@@ -1372,17 +1360,49 @@
     }
 }
 
-static int adb_connect_command(const std::string& command, TransportId* transport = nullptr) {
+static int adb_connect_command(const std::string& command, TransportId* transport,
+                               StandardStreamsCallbackInterface* callback) {
     std::string error;
     unique_fd fd(adb_connect(transport, command, &error));
     if (fd < 0) {
         fprintf(stderr, "error: %s\n", error.c_str());
         return 1;
     }
-    read_and_dump(fd);
+    read_and_dump(fd, false, callback);
     return 0;
 }
 
+static int adb_connect_command(const std::string& command, TransportId* transport = nullptr) {
+    return adb_connect_command(command, transport, &DEFAULT_STANDARD_STREAMS_CALLBACK);
+}
+
+// A class that prints out human readable form of the protobuf message for "track-app" service
+// (received in binary format).
+class TrackAppStreamsCallback : public DefaultStandardStreamsCallback {
+  public:
+    TrackAppStreamsCallback() : DefaultStandardStreamsCallback(nullptr, nullptr) {}
+
+    // Assume the buffer contains at least 4 bytes of valid data.
+    void OnStdout(const char* buffer, int length) override {
+        if (length < 4) return;  // Unexpected length received. Do nothing.
+
+        adb::proto::AppProcesses binary_proto;
+        // The first 4 bytes are the length of remaining content in hexadecimal format.
+        binary_proto.ParseFromString(std::string(buffer + 4, length - 4));
+        char summary[24];  // The following string includes digits and 16 fixed characters.
+        int written = snprintf(summary, sizeof(summary), "Process count: %d\n",
+                               binary_proto.process_size());
+        OnStream(nullptr, stdout, summary, written);
+
+        std::string string_proto;
+        google::protobuf::TextFormat::PrintToString(binary_proto, &string_proto);
+        OnStream(nullptr, stdout, string_proto.data(), string_proto.length());
+    }
+
+  private:
+    DISALLOW_COPY_AND_ASSIGN(TrackAppStreamsCallback);
+};
+
 static int adb_connect_command_bidirectional(const std::string& command) {
     std::string error;
     unique_fd fd(adb_connect(command, &error));
@@ -1985,6 +2005,18 @@
         return adb_connect_command("jdwp");
     } else if (!strcmp(argv[0], "track-jdwp")) {
         return adb_connect_command("track-jdwp");
+    } else if (!strcmp(argv[0], "track-app")) {
+        FeatureSet features;
+        std::string error;
+        if (!adb_get_feature_set(&features, &error)) {
+            fprintf(stderr, "error: %s\n", error.c_str());
+            return 1;
+        }
+        if (!CanUseFeature(features, kFeatureTrackApp)) {
+            error_exit("track-app is not supported by the device");
+        }
+        TrackAppStreamsCallback callback;
+        return adb_connect_command("track-app", nullptr, &callback);
     } else if (!strcmp(argv[0], "track-devices")) {
         if (argc > 2 || (argc == 2 && strcmp(argv[1], "-l"))) {
             error_exit("usage: adb track-devices [-l]");
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index 190c235..2ed58b2 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -42,7 +42,7 @@
 #include "adb_client.h"
 #include "adb_io.h"
 #include "adb_utils.h"
-#include "brotli_utils.h"
+#include "compression_utils.h"
 #include "file_sync_protocol.h"
 #include "line_printer.h"
 #include "sysdeps/errno.h"
@@ -580,8 +580,8 @@
 
             while (true) {
                 Block output;
-                BrotliEncodeResult result = encoder.Encode(&output);
-                if (result == BrotliEncodeResult::Error) {
+                EncodeResult result = encoder.Encode(&output);
+                if (result == EncodeResult::Error) {
                     Error("compressing '%s' locally failed", lpath.c_str());
                     return false;
                 }
@@ -592,12 +592,12 @@
                     WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + output.size());
                 }
 
-                if (result == BrotliEncodeResult::Done) {
+                if (result == EncodeResult::Done) {
                     sending = false;
                     break;
-                } else if (result == BrotliEncodeResult::NeedInput) {
+                } else if (result == EncodeResult::NeedInput) {
                     break;
-                } else if (result == BrotliEncodeResult::MoreOutput) {
+                } else if (result == EncodeResult::MoreOutput) {
                     continue;
                 }
             }
@@ -617,7 +617,7 @@
         }
 
         std::string path_and_mode = android::base::StringPrintf("%s,%d", path.c_str(), mode);
-        if (!SendRequest(ID_SEND_V1, path_and_mode.c_str())) {
+        if (!SendRequest(ID_SEND_V1, path_and_mode)) {
             Error("failed to send ID_SEND_V1 message '%s': %s", path_and_mode.c_str(),
                   strerror(errno));
             return false;
@@ -1076,9 +1076,9 @@
 
         while (true) {
             std::span<char> output;
-            BrotliDecodeResult result = decoder.Decode(&output);
+            DecodeResult result = decoder.Decode(&output);
 
-            if (result == BrotliDecodeResult::Error) {
+            if (result == DecodeResult::Error) {
                 sc.Error("decompress failed");
                 adb_unlink(lpath);
                 return false;
@@ -1097,15 +1097,15 @@
             sc.RecordBytesTransferred(msg.data.size);
             sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, expected_size);
 
-            if (result == BrotliDecodeResult::NeedInput) {
+            if (result == DecodeResult::NeedInput) {
                 break;
-            } else if (result == BrotliDecodeResult::MoreOutput) {
+            } else if (result == DecodeResult::MoreOutput) {
                 continue;
-            } else if (result == BrotliDecodeResult::Done) {
+            } else if (result == DecodeResult::Done) {
                 reading = false;
                 break;
             } else {
-                LOG(FATAL) << "invalid BrotliDecodeResult: " << static_cast<int>(result);
+                LOG(FATAL) << "invalid DecodeResult: " << static_cast<int>(result);
             }
         }
     }
@@ -1435,14 +1435,14 @@
         }
     };
 
-    if (!sync_ls(sc, rpath.c_str(), callback)) {
+    if (!sync_ls(sc, rpath, callback)) {
         return false;
     }
 
     // Check each symlink we found to see whether it's a file or directory.
     for (copyinfo& link_ci : linklist) {
         struct stat st;
-        if (!sync_stat_fallback(sc, link_ci.rpath.c_str(), &st)) {
+        if (!sync_stat_fallback(sc, link_ci.rpath, &st)) {
             sc.Warning("stat failed for path %s: %s", link_ci.rpath.c_str(), strerror(errno));
             continue;
         }
diff --git a/adb/client/incremental.cpp b/adb/client/incremental.cpp
index b56df44..9765292 100644
--- a/adb/client/incremental.cpp
+++ b/adb/client/incremental.cpp
@@ -231,12 +231,8 @@
 
     std::string adb_path = android::base::GetExecutablePath();
 
-    auto osh = adb_get_os_handle(connection_fd.get());
-#ifdef _WIN32
-    auto fd_param = std::to_string(reinterpret_cast<intptr_t>(osh));
-#else /* !_WIN32 a.k.a. Unix */
+    auto osh = cast_handle_to_int(adb_get_os_handle(connection_fd.get()));
     auto fd_param = std::to_string(osh);
-#endif
 
     // pipe for child process to write output
     int print_fds[2];
@@ -247,7 +243,7 @@
         return {};
     }
     auto [pipe_read_fd, pipe_write_fd] = print_fds;
-    auto pipe_write_fd_param = std::to_string(intptr_t(adb_get_os_handle(pipe_write_fd)));
+    auto pipe_write_fd_param = std::to_string(cast_handle_to_int(adb_get_os_handle(pipe_write_fd)));
     close_on_exec(pipe_read_fd);
 
     std::vector<std::string> args(std::move(files));
diff --git a/adb/client/incremental_utils.cpp b/adb/client/incremental_utils.cpp
index caadb26..fa501e4 100644
--- a/adb/client/incremental_utils.cpp
+++ b/adb/client/incremental_utils.cpp
@@ -23,6 +23,7 @@
 #include <ziparchive/zip_archive.h>
 #include <ziparchive/zip_writer.h>
 
+#include <array>
 #include <cinttypes>
 #include <numeric>
 #include <unordered_set>
@@ -30,6 +31,8 @@
 #include "adb_trace.h"
 #include "sysdeps.h"
 
+using namespace std::literals;
+
 static constexpr int kBlockSize = 4096;
 
 static constexpr inline int32_t offsetToBlockIndex(int64_t offset) {
@@ -217,16 +220,24 @@
     return {zip, std::move(mapping)};
 }
 
-// TODO(b/151676293): avoid using libziparchive as it reads local file headers
-// which causes additional performance cost. Instead, only read from central directory.
 static std::vector<int32_t> InstallationPriorityBlocks(int fd, int64_t fileSize) {
+    static constexpr std::array<std::string_view, 3> additional_matches = {
+            "resources.arsc"sv, "AndroidManifest.xml"sv, "classes.dex"sv};
     auto [zip, _] = openZipArchive(fd, fileSize);
     if (!zip) {
         return {};
     }
 
+    auto matcher = [](std::string_view entry_name) {
+        if (entry_name.starts_with("lib/"sv) && entry_name.ends_with(".so"sv)) {
+            return true;
+        }
+        return std::any_of(additional_matches.begin(), additional_matches.end(),
+                           [entry_name](std::string_view i) { return i == entry_name; });
+    };
+
     void* cookie = nullptr;
-    if (StartIteration(zip, &cookie) != 0) {
+    if (StartIteration(zip, &cookie, std::move(matcher)) != 0) {
         D("%s failed at StartIteration: %d", __func__, errno);
         return {};
     }
@@ -235,8 +246,12 @@
     ZipEntry entry;
     std::string_view entryName;
     while (Next(cookie, &entry, &entryName) == 0) {
-        if (entryName == "resources.arsc" || entryName == "AndroidManifest.xml" ||
-            entryName.starts_with("lib/")) {
+        if (entryName == "classes.dex"sv) {
+            // Only the head is needed for installation
+            int32_t startBlockIndex = offsetToBlockIndex(entry.offset);
+            appendBlocks(startBlockIndex, 1, &installationPriorityBlocks);
+            D("\tadding to priority blocks: '%.*s' 1", (int)entryName.size(), entryName.data());
+        } else {
             // Full entries are needed for installation
             off64_t entryStartOffset = entry.offset;
             off64_t entryEndOffset =
@@ -248,11 +263,8 @@
             int32_t endBlockIndex = offsetToBlockIndex(entryEndOffset);
             int32_t numNewBlocks = endBlockIndex - startBlockIndex + 1;
             appendBlocks(startBlockIndex, numNewBlocks, &installationPriorityBlocks);
-            D("\tadding to priority blocks: '%.*s'", (int)entryName.size(), entryName.data());
-        } else if (entryName == "classes.dex") {
-            // Only the head is needed for installation
-            int32_t startBlockIndex = offsetToBlockIndex(entry.offset);
-            appendBlocks(startBlockIndex, 1, &installationPriorityBlocks);
+            D("\tadding to priority blocks: '%.*s' (%d)", (int)entryName.size(), entryName.data(),
+              numNewBlocks);
         }
     }
 
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 78f7b8f..4a9eadc 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -140,9 +140,10 @@
     auto start = std::chrono::steady_clock::now();
 
     // If we told a previous adb server to quit because of version mismatch, we can get to this
-    // point before it's finished exiting. Retry for a while to give it some time.
-    while (install_listener(socket_spec, "*smartsocket*", nullptr, 0, nullptr, &error) !=
-           INSTALL_STATUS_OK) {
+    // point before it's finished exiting. Retry for a while to give it some time. Don't actually
+    // accept any connections until adb_wait_for_device_initialization finishes below.
+    while (install_listener(socket_spec, "*smartsocket*", nullptr, INSTALL_LISTENER_DISABLED,
+                            nullptr, &error) != INSTALL_STATUS_OK) {
         if (std::chrono::steady_clock::now() - start > 0.5s) {
             LOG(FATAL) << "could not install *smartsocket* listener: " << error;
         }
@@ -163,12 +164,14 @@
             PLOG(FATAL) << "setsid() failed";
         }
 #endif
+    }
 
-        // Wait for the USB scan to complete before notifying the parent that we're up.
-        // We need to perform this in a thread, because we would otherwise block the event loop.
-        std::thread notify_thread([ack_reply_fd]() {
-            adb_wait_for_device_initialization();
+    // Wait for the USB scan to complete before notifying the parent that we're up.
+    // We need to perform this in a thread, because we would otherwise block the event loop.
+    std::thread notify_thread([ack_reply_fd]() {
+        adb_wait_for_device_initialization();
 
+        if (ack_reply_fd >= 0) {
             // Any error output written to stderr now goes to adb.log. We could
             // keep around a copy of the stderr fd and use that to write any errors
             // encountered by the following code, but that is probably overkill.
@@ -194,9 +197,13 @@
             }
             unix_close(ack_reply_fd);
 #endif
-        });
-        notify_thread.detach();
-    }
+        }
+        // We don't accept() client connections until this point: this way, clients
+        // can't see wonky state early in startup even if they're connecting directly
+        // to the server instead of going through the adb program.
+        fdevent_run_on_main_thread([] { enable_daemon_sockets(); });
+    });
+    notify_thread.detach();
 
 #if defined(__linux__)
     // Write our location to .android/adb.$PORT, so that older clients can exec us.
diff --git a/adb/client/pairing/pairing_client.cpp b/adb/client/pairing/pairing_client.cpp
index 04bbceb..937a5bd 100644
--- a/adb/client/pairing/pairing_client.cpp
+++ b/adb/client/pairing/pairing_client.cpp
@@ -141,11 +141,7 @@
                                           cert_.size(), priv_key_.data(), priv_key_.size()));
     CHECK(connection_);
 
-#ifdef _WIN32
     int osh = cast_handle_to_int(adb_get_os_handle(fd.release()));
-#else
-    int osh = adb_get_os_handle(fd.release());
-#endif
     if (!pairing_connection_start(connection_.get(), osh, OnPairingResult, this)) {
         LOG(ERROR) << "PairingClient failed to start the PairingConnection";
         state_ = State::Stopped;
diff --git a/adb/brotli_utils.h b/adb/compression_utils.h
similarity index 88%
rename from adb/brotli_utils.h
rename to adb/compression_utils.h
index c5be73d..c445095 100644
--- a/adb/brotli_utils.h
+++ b/adb/compression_utils.h
@@ -23,7 +23,14 @@
 
 #include "types.h"
 
-enum class BrotliDecodeResult {
+enum class DecodeResult {
+    Error,
+    Done,
+    NeedInput,
+    MoreOutput,
+};
+
+enum class EncodeResult {
     Error,
     Done,
     NeedInput,
@@ -38,7 +45,7 @@
 
     void Append(Block&& block) { input_buffer_.append(std::move(block)); }
 
-    BrotliDecodeResult Decode(std::span<char>* output) {
+    DecodeResult Decode(std::span<char>* output) {
         size_t available_in = input_buffer_.front_size();
         const uint8_t* next_in = reinterpret_cast<const uint8_t*>(input_buffer_.front_data());
 
@@ -56,16 +63,16 @@
 
         switch (r) {
             case BROTLI_DECODER_RESULT_SUCCESS:
-                return BrotliDecodeResult::Done;
+                return DecodeResult::Done;
             case BROTLI_DECODER_RESULT_ERROR:
-                return BrotliDecodeResult::Error;
+                return DecodeResult::Error;
             case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
                 // Brotli guarantees as one of its invariants that if it returns NEEDS_MORE_INPUT,
                 // it will consume the entire input buffer passed in, so we don't have to worry
                 // about bytes left over in the front block with more input remaining.
-                return BrotliDecodeResult::NeedInput;
+                return DecodeResult::NeedInput;
             case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
-                return BrotliDecodeResult::MoreOutput;
+                return DecodeResult::MoreOutput;
         }
     }
 
@@ -75,13 +82,6 @@
     std::unique_ptr<BrotliDecoderState, void (*)(BrotliDecoderState*)> decoder_;
 };
 
-enum class BrotliEncodeResult {
-    Error,
-    Done,
-    NeedInput,
-    MoreOutput,
-};
-
 template <size_t OutputBlockSize>
 struct BrotliEncoder {
     explicit BrotliEncoder()
@@ -95,7 +95,7 @@
     void Append(Block input) { input_buffer_.append(std::move(input)); }
     void Finish() { finished_ = true; }
 
-    BrotliEncodeResult Encode(Block* output) {
+    EncodeResult Encode(Block* output) {
         output->clear();
         while (true) {
             size_t available_in = input_buffer_.front_size();
@@ -112,7 +112,7 @@
 
             if (!BrotliEncoderCompressStream(encoder_.get(), op, &available_in, &next_in,
                                              &available_out, &next_out, nullptr)) {
-                return BrotliEncodeResult::Error;
+                return EncodeResult::Error;
             }
 
             size_t bytes_consumed = input_buffer_.front_size() - available_in;
@@ -123,14 +123,14 @@
             if (BrotliEncoderIsFinished(encoder_.get())) {
                 output_block_.resize(OutputBlockSize - output_bytes_left_);
                 *output = std::move(output_block_);
-                return BrotliEncodeResult::Done;
+                return EncodeResult::Done;
             } else if (output_bytes_left_ == 0) {
                 *output = std::move(output_block_);
                 output_block_.resize(OutputBlockSize);
                 output_bytes_left_ = OutputBlockSize;
-                return BrotliEncodeResult::MoreOutput;
+                return EncodeResult::MoreOutput;
             } else if (input_buffer_.empty()) {
-                return BrotliEncodeResult::NeedInput;
+                return EncodeResult::NeedInput;
             }
         }
     }
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index 07f6e65..5ccddea 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -57,7 +57,7 @@
 #include "adb_io.h"
 #include "adb_trace.h"
 #include "adb_utils.h"
-#include "brotli_utils.h"
+#include "compression_utils.h"
 #include "file_sync_protocol.h"
 #include "security_log_tags.h"
 #include "sysdeps/errno.h"
@@ -288,8 +288,8 @@
 
         while (true) {
             std::span<char> output;
-            BrotliDecodeResult result = decoder.Decode(&output);
-            if (result == BrotliDecodeResult::Error) {
+            DecodeResult result = decoder.Decode(&output);
+            if (result == DecodeResult::Error) {
                 SendSyncFailErrno(s, "decompress failed");
                 return false;
             }
@@ -299,14 +299,14 @@
                 return false;
             }
 
-            if (result == BrotliDecodeResult::NeedInput) {
+            if (result == DecodeResult::NeedInput) {
                 break;
-            } else if (result == BrotliDecodeResult::MoreOutput) {
+            } else if (result == DecodeResult::MoreOutput) {
                 continue;
-            } else if (result == BrotliDecodeResult::Done) {
+            } else if (result == DecodeResult::Done) {
                 break;
             } else {
-                LOG(FATAL) << "invalid BrotliDecodeResult: " << static_cast<int>(result);
+                LOG(FATAL) << "invalid DecodeResult: " << static_cast<int>(result);
             }
         }
     }
@@ -591,7 +591,6 @@
 static bool recv_uncompressed(borrowed_fd s, unique_fd fd, std::vector<char>& buffer) {
     syncmsg msg;
     msg.data.id = ID_DATA;
-    std::optional<BrotliEncoder<SYNC_DATA_MAX>> encoder;
     while (true) {
         int r = adb_read(fd.get(), &buffer[0], buffer.size() - sizeof(msg.data));
         if (r <= 0) {
@@ -633,8 +632,8 @@
 
         while (true) {
             Block output;
-            BrotliEncodeResult result = encoder.Encode(&output);
-            if (result == BrotliEncodeResult::Error) {
+            EncodeResult result = encoder.Encode(&output);
+            if (result == EncodeResult::Error) {
                 SendSyncFailErrno(s, "compress failed");
                 return false;
             }
@@ -647,12 +646,12 @@
                 }
             }
 
-            if (result == BrotliEncodeResult::Done) {
+            if (result == EncodeResult::Done) {
                 sending = false;
                 break;
-            } else if (result == BrotliEncodeResult::NeedInput) {
+            } else if (result == EncodeResult::NeedInput) {
                 break;
-            } else if (result == BrotliEncodeResult::MoreOutput) {
+            } else if (result == EncodeResult::MoreOutput) {
                 continue;
             }
         }
diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
index b92a7de..adae9f7 100644
--- a/adb/daemon/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -16,11 +16,13 @@
 
 #if !ADB_HOST
 
+#if !defined(__ANDROID_RECOVERY__)
 #define TRACE_TAG JDWP
 
 #include "sysdeps.h"
 
 #include <errno.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -33,6 +35,7 @@
 #include <thread>
 #include <vector>
 
+#include <adbconnection/process_info.h>
 #include <adbconnection/server.h>
 #include <android-base/cmsg.h>
 #include <android-base/unique_fd.h>
@@ -41,6 +44,7 @@
 #include "adb_io.h"
 #include "adb_unique_fd.h"
 #include "adb_utils.h"
+#include "app_processes.pb.h"
 
 using android::base::borrowed_fd;
 using android::base::unique_fd;
@@ -132,18 +136,24 @@
  ** for each JDWP process, we record its pid and its connected socket
  **/
 
+enum class TrackerKind {
+    kJdwp,
+    kApp,
+};
+
 static void jdwp_process_event(int socket, unsigned events, void* _proc);
 static void jdwp_process_list_updated(void);
+static void app_process_list_updated(void);
 
 struct JdwpProcess;
 static auto& _jdwp_list = *new std::list<std::unique_ptr<JdwpProcess>>();
 
 struct JdwpProcess {
-    JdwpProcess(unique_fd socket, pid_t pid) {
-        CHECK(pid != 0);
+    JdwpProcess(unique_fd socket, ProcessInfo process) {
+        CHECK(process.pid != 0);
 
         this->socket = socket;
-        this->pid = pid;
+        this->process = process;
         this->fde = fdevent_create(socket.release(), jdwp_process_event, this);
 
         if (!this->fde) {
@@ -171,17 +181,19 @@
     }
 
     borrowed_fd socket = -1;
-    int32_t pid = -1;
+    ProcessInfo process;
     fdevent* fde = nullptr;
 
     std::vector<unique_fd> out_fds;
 };
 
+// Populate the list of processes for "track-jdwp" service.
 static size_t jdwp_process_list(char* buffer, size_t bufferlen) {
     std::string temp;
 
     for (auto& proc : _jdwp_list) {
-        std::string next = std::to_string(proc->pid) + "\n";
+        if (!proc->process.debuggable) continue;
+        std::string next = std::to_string(proc->process.pid) + "\n";
         if (temp.length() + next.length() > bufferlen) {
             D("truncating JDWP process list (max len = %zu)", bufferlen);
             break;
@@ -193,7 +205,44 @@
     return temp.length();
 }
 
-static size_t jdwp_process_list_msg(char* buffer, size_t bufferlen) {
+// Populate the list of processes for "track-app" service.
+// The list is a protobuf message in the binary format for efficiency.
+static size_t app_process_list(char* buffer, size_t bufferlen) {
+    adb::proto::AppProcesses output;  // result that's guaranteed to fit in the given buffer
+    adb::proto::AppProcesses temp;    // temporary result that may be longer than the given buffer
+    std::string serialized_message;
+
+    for (auto& proc : _jdwp_list) {
+        if (!proc->process.debuggable && !proc->process.profileable) continue;
+        auto* entry = temp.add_process();
+        entry->set_pid(proc->process.pid);
+        entry->set_debuggable(proc->process.debuggable);
+        entry->set_profileable(proc->process.profileable);
+        entry->set_architecture(proc->process.arch_name, proc->process.arch_name_length);
+        temp.SerializeToString(&serialized_message);
+        if (serialized_message.size() > bufferlen) {
+            D("truncating app process list (max len = %zu)", bufferlen);
+            break;
+        }
+        output = temp;
+    }
+    output.SerializeToString(&serialized_message);
+    memcpy(buffer, serialized_message.data(), serialized_message.length());
+    return serialized_message.length();
+}
+
+// Populate the list of processes for either "track-jdwp" or "track-app" services,
+// depending on the given kind.
+static size_t process_list(TrackerKind kind, char* buffer, size_t bufferlen) {
+    switch (kind) {
+        case TrackerKind::kJdwp:
+            return jdwp_process_list(buffer, bufferlen);
+        case TrackerKind::kApp:
+            return app_process_list(buffer, bufferlen);
+    }
+}
+
+static size_t process_list_msg(TrackerKind kind, char* buffer, size_t bufferlen) {
     // Message is length-prefixed with 4 hex digits in ASCII.
     static constexpr size_t header_len = 4;
     if (bufferlen < header_len) {
@@ -201,7 +250,7 @@
     }
 
     char head[header_len + 1];
-    size_t len = jdwp_process_list(buffer + header_len, bufferlen - header_len);
+    size_t len = process_list(kind, buffer + header_len, bufferlen - header_len);
     snprintf(head, sizeof head, "%04zx", len);
     memcpy(buffer, head, header_len);
     return len + header_len;
@@ -213,7 +262,7 @@
 
     if (events & FDE_READ) {
         // We already have the PID, if we can read from the socket, we've probably hit EOF.
-        D("terminating JDWP connection %d", proc->pid);
+        D("terminating JDWP connection %" PRId64, proc->process.pid);
         goto CloseProcess;
     }
 
@@ -223,11 +272,12 @@
 
         int fd = proc->out_fds.back().get();
         if (android::base::SendFileDescriptors(socket, "", 1, fd) != 1) {
-            D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno));
+            D("sending new file descriptor to JDWP %" PRId64 " failed: %s", proc->process.pid,
+              strerror(errno));
             goto CloseProcess;
         }
 
-        D("sent file descriptor %d to JDWP process %d", fd, proc->pid);
+        D("sent file descriptor %d to JDWP process %" PRId64, fd, proc->process.pid);
 
         proc->out_fds.pop_back();
         if (proc->out_fds.empty()) {
@@ -238,15 +288,20 @@
     return;
 
 CloseProcess:
+    bool debuggable = proc->process.debuggable;
+    bool profileable = proc->process.profileable;
     proc->RemoveFromList();
-    jdwp_process_list_updated();
+    if (debuggable) jdwp_process_list_updated();
+    if (debuggable || profileable) app_process_list_updated();
 }
 
 unique_fd create_jdwp_connection_fd(int pid) {
     D("looking for pid %d in JDWP process list", pid);
 
     for (auto& proc : _jdwp_list) {
-        if (proc->pid == pid) {
+        // Don't allow JDWP connection to a non-debuggable process.
+        if (!proc->process.debuggable) continue;
+        if (proc->process.pid == static_cast<uint64_t>(pid)) {
             int fds[2];
 
             if (adb_socketpair(fds) < 0) {
@@ -338,18 +393,22 @@
  **/
 
 struct JdwpTracker : public asocket {
+    TrackerKind kind;
     bool need_initial;
+
+    explicit JdwpTracker(TrackerKind k, bool initial) : kind(k), need_initial(initial) {}
 };
 
 static auto& _jdwp_trackers = *new std::vector<std::unique_ptr<JdwpTracker>>();
 
-static void jdwp_process_list_updated(void) {
+static void process_list_updated(TrackerKind kind) {
     std::string data;
-    data.resize(1024);
-    data.resize(jdwp_process_list_msg(&data[0], data.size()));
+    const int kMaxLength = kind == TrackerKind::kJdwp ? 1024 : 2048;
+    data.resize(kMaxLength);
+    data.resize(process_list_msg(kind, &data[0], data.size()));
 
     for (auto& t : _jdwp_trackers) {
-        if (t->peer) {
+        if (t->kind == kind && t->peer) {
             // The tracker might not have been connected yet.
             apacket::payload_type payload(data.begin(), data.end());
             t->peer->enqueue(t->peer, std::move(payload));
@@ -357,6 +416,14 @@
     }
 }
 
+static void jdwp_process_list_updated(void) {
+    process_list_updated(TrackerKind::kJdwp);
+}
+
+static void app_process_list_updated(void) {
+    process_list_updated(TrackerKind::kApp);
+}
+
 static void jdwp_tracker_close(asocket* s) {
     D("LS(%d): destroying jdwp tracker service", s->id);
 
@@ -380,7 +447,7 @@
     if (t->need_initial) {
         apacket::payload_type data;
         data.resize(s->get_max_payload());
-        data.resize(jdwp_process_list_msg(&data[0], data.size()));
+        data.resize(process_list_msg(t->kind, &data[0], data.size()));
         t->need_initial = false;
         s->peer->enqueue(s->peer, std::move(data));
     }
@@ -393,8 +460,8 @@
     return -1;
 }
 
-asocket* create_jdwp_tracker_service_socket(void) {
-    auto t = std::make_unique<JdwpTracker>();
+static asocket* create_process_tracker_service_socket(TrackerKind kind) {
+    auto t = std::make_unique<JdwpTracker>(kind, true);
     if (!t) {
         LOG(FATAL) << "failed to allocate JdwpTracker";
     }
@@ -407,7 +474,6 @@
     t->ready = jdwp_tracker_ready;
     t->enqueue = jdwp_tracker_enqueue;
     t->close = jdwp_tracker_close;
-    t->need_initial = true;
 
     asocket* result = t.get();
 
@@ -416,23 +482,56 @@
     return result;
 }
 
+asocket* create_jdwp_tracker_service_socket() {
+    return create_process_tracker_service_socket(TrackerKind::kJdwp);
+}
+
+asocket* create_app_tracker_service_socket() {
+    return create_process_tracker_service_socket(TrackerKind::kApp);
+}
+
 int init_jdwp(void) {
     std::thread([]() {
         adb_thread_setname("jdwp control");
-        adbconnection_listen([](int fd, pid_t pid) {
-            LOG(INFO) << "jdwp connection from " << pid;
-            fdevent_run_on_main_thread([fd, pid] {
+        adbconnection_listen([](int fd, ProcessInfo process) {
+            LOG(INFO) << "jdwp connection from " << process.pid;
+            fdevent_run_on_main_thread([fd, process] {
                 unique_fd ufd(fd);
-                auto proc = std::make_unique<JdwpProcess>(std::move(ufd), pid);
+                auto proc = std::make_unique<JdwpProcess>(std::move(ufd), process);
                 if (!proc) {
                     LOG(FATAL) << "failed to allocate JdwpProcess";
                 }
                 _jdwp_list.emplace_back(std::move(proc));
-                jdwp_process_list_updated();
+                if (process.debuggable) jdwp_process_list_updated();
+                if (process.debuggable || process.profileable) app_process_list_updated();
             });
         });
     }).detach();
     return 0;
 }
 
+#else  // !defined(__ANDROID_RECOVERY)
+#include "adb.h"
+
+asocket* create_jdwp_service_socket(void) {
+    return nullptr;
+}
+
+unique_fd create_jdwp_connection_fd(int pid) {
+    return {};
+}
+
+asocket* create_app_tracker_service_socket() {
+    return nullptr;
+}
+
+asocket* create_jdwp_tracker_service_socket() {
+    return nullptr;
+}
+
+int init_jdwp() {
+    return 0;
+}
+
+#endif /* defined(__ANDROID_RECOVERY__) */
 #endif /* !ADB_HOST */
diff --git a/adb/daemon/mdns.cpp b/adb/daemon/mdns.cpp
index fa692c0..c1e766e 100644
--- a/adb/daemon/mdns.cpp
+++ b/adb/daemon/mdns.cpp
@@ -150,11 +150,11 @@
     for (size_t i = 0; i < len; ++i) {
         uint8_t val = dist(mt);
         if (val < 10) {
-            ret += '0' + val;
+            ret += static_cast<char>('0' + val);
         } else if (val < 36) {
-            ret += 'A' + (val - 10);
+            ret += static_cast<char>('A' + (val - 10));
         } else {
-            ret += 'a' + (val - 36);
+            ret += static_cast<char>('a' + (val - 36));
         }
     }
     return ret;
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index 6bbf66e..a9d1fe8 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -241,6 +241,8 @@
         return create_jdwp_service_socket();
     } else if (name == "track-jdwp") {
         return create_jdwp_tracker_service_socket();
+    } else if (name == "track-app") {
+        return create_app_tracker_service_socket();
     } else if (android::base::ConsumePrefix(&name, "sink:")) {
         uint64_t byte_count = 0;
         if (!ParseUint(&byte_count, name)) {
diff --git a/adb/libs/adbconnection/Android.bp b/adb/libs/adbconnection/Android.bp
index f6b0a42..ce2ab51 100644
--- a/adb/libs/adbconnection/Android.bp
+++ b/adb/libs/adbconnection/Android.bp
@@ -18,6 +18,11 @@
     use_version_lib: false,
 
     recovery_available: true,
+    apex_available: [
+        "com.android.adbd",
+        // TODO(b/151398197) remove the below
+        "//apex_available:platform",
+    ],
     compile_multilib: "both",
 }
 
diff --git a/adb/libs/adbconnection/adbconnection_client.cpp b/adb/libs/adbconnection/adbconnection_client.cpp
index ee48abb..c132342 100644
--- a/adb/libs/adbconnection/adbconnection_client.cpp
+++ b/adb/libs/adbconnection/adbconnection_client.cpp
@@ -29,6 +29,8 @@
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 
+#include "adbconnection/process_info.h"
+
 using android::base::unique_fd;
 
 static constexpr char kJdwpControlName[] = "\0jdwp-control";
@@ -60,6 +62,8 @@
 
   std::optional<uint64_t> pid;
   std::optional<bool> debuggable;
+  std::optional<bool> profileable;
+  std::optional<std::string> architecture;
 
   for (size_t i = 0; i < info_count; ++i) {
     auto info = info_elems[i];
@@ -77,7 +81,23 @@
           LOG(ERROR) << "multiple debuggable entries in AdbConnectionClientInfo, ignoring";
           continue;
         }
-        debuggable = info->data.pid;
+        debuggable = info->data.debuggable;
+        break;
+
+      case AdbConnectionClientInfoType::profileable:
+        if (profileable) {
+          LOG(ERROR) << "multiple profileable entries in AdbConnectionClientInfo, ignoring";
+          continue;
+        }
+        profileable = info->data.profileable;
+        break;
+
+      case AdbConnectionClientInfoType::architecture:
+        if (architecture) {
+          LOG(ERROR) << "multiple architecture entries in AdbConnectionClientInfo, ignoring";
+          continue;
+        }
+        architecture = std::string(info->data.architecture.name, info->data.architecture.size);
         break;
     }
   }
@@ -92,6 +112,16 @@
     return nullptr;
   }
 
+  if (!profileable) {
+    LOG(ERROR) << "AdbConnectionClientInfo missing required field profileable";
+    return nullptr;
+  }
+
+  if (!architecture) {
+    LOG(ERROR) << "AdbConnectionClientInfo missing required field architecture";
+    return nullptr;
+  }
+
   ctx->control_socket_.reset(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0));
   if (ctx->control_socket_ < 0) {
     PLOG(ERROR) << "failed to create Unix domain socket";
@@ -120,10 +150,10 @@
     return nullptr;
   }
 
-  uint32_t pid_u32 = static_cast<uint32_t>(*pid);
-  rc = TEMP_FAILURE_RETRY(write(ctx->control_socket_.get(), &pid_u32, sizeof(pid_u32)));
-  if (rc != sizeof(pid_u32)) {
-    PLOG(ERROR) << "failed to send JDWP process pid to adbd";
+  ProcessInfo process(*pid, *debuggable, *profileable, *architecture);
+  rc = TEMP_FAILURE_RETRY(write(ctx->control_socket_.get(), &process, sizeof(process)));
+  if (rc != sizeof(process)) {
+    PLOG(ERROR) << "failed to send JDWP process info to adbd";
   }
 
   return ctx.release();
diff --git a/adb/libs/adbconnection/adbconnection_server.cpp b/adb/libs/adbconnection/adbconnection_server.cpp
index 939da2f..aac9615 100644
--- a/adb/libs/adbconnection/adbconnection_server.cpp
+++ b/adb/libs/adbconnection/adbconnection_server.cpp
@@ -28,6 +28,8 @@
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 
+#include "adbconnection/process_info.h"
+
 using android::base::unique_fd;
 
 #define JDWP_CONTROL_NAME "\0jdwp-control"
@@ -36,7 +38,7 @@
 static_assert(JDWP_CONTROL_NAME_LEN <= sizeof(reinterpret_cast<sockaddr_un*>(0)->sun_path));
 
 // Listen for incoming jdwp clients forever.
-void adbconnection_listen(void (*callback)(int fd, pid_t pid)) {
+void adbconnection_listen(void (*callback)(int fd, ProcessInfo process)) {
   sockaddr_un addr = {};
   socklen_t addrlen = JDWP_CONTROL_NAME_LEN + sizeof(addr.sun_family);
 
@@ -106,16 +108,13 @@
                      << ") in pending connections";
         }
 
-        // Massively oversized buffer: we're expecting an int32_t from the other end.
-        char buf[32];
-        int rc = TEMP_FAILURE_RETRY(recv(it->get(), buf, sizeof(buf), MSG_DONTWAIT));
-        if (rc != 4) {
+        ProcessInfo process;
+        int rc = TEMP_FAILURE_RETRY(recv(it->get(), &process, sizeof(process), MSG_DONTWAIT));
+        if (rc != sizeof(process)) {
           LOG(ERROR) << "received data of incorrect size from JDWP client: read " << rc
-                     << ", expected 4";
+                     << ", expected " << sizeof(process);
         } else {
-          int32_t pid;
-          memcpy(&pid, buf, sizeof(pid));
-          callback(it->release(), static_cast<pid_t>(pid));
+          callback(it->release(), process);
         }
 
         if (epoll_ctl(epfd.get(), EPOLL_CTL_DEL, event.data.fd, nullptr) != 0) {
diff --git a/adb/libs/adbconnection/include/adbconnection/client.h b/adb/libs/adbconnection/include/adbconnection/client.h
index 692fea0..a74cd36 100644
--- a/adb/libs/adbconnection/include/adbconnection/client.h
+++ b/adb/libs/adbconnection/include/adbconnection/client.h
@@ -28,6 +28,8 @@
 enum AdbConnectionClientInfoType {
   pid,
   debuggable,
+  profileable,
+  architecture,
 };
 
 struct AdbConnectionClientInfo {
@@ -35,11 +37,17 @@
   union {
     uint64_t pid;
     bool debuggable;
+    bool profileable;
+    struct {
+      const char* name;
+      size_t size;
+    } architecture;
   } data;
 };
 
 // Construct a context and connect to adbd.
 // Returns null if we fail to connect to adbd.
+// Note this is an apex interface as it's loaded by ART.
 AdbConnectionClientContext* adbconnection_client_new(
     const AdbConnectionClientInfo* const* info_elems, size_t info_count);
 
diff --git a/adb/libs/adbconnection/include/adbconnection/process_info.h b/adb/libs/adbconnection/include/adbconnection/process_info.h
new file mode 100644
index 0000000..86d3259
--- /dev/null
+++ b/adb/libs/adbconnection/include/adbconnection/process_info.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <string.h>
+#include <string>
+
+struct ProcessInfo {
+  const static size_t kMaxArchNameLength = 16;
+
+  uint64_t pid;
+  bool debuggable;
+  bool profileable;
+  int32_t arch_name_length;            // length of architecture name in bytes
+  char arch_name[kMaxArchNameLength];  // ISA name, e.g., "arm64"
+
+  ProcessInfo() : pid(0), debuggable(false), profileable(false), arch_name_length(0) {}
+
+  ProcessInfo(uint64_t pid, bool dbg, bool prof, const std::string& arch)
+      : pid(pid), debuggable(dbg), profileable(prof) {
+    arch_name_length = std::min(arch.size(), kMaxArchNameLength);
+    memcpy(arch_name, arch.data(), arch_name_length);
+  }
+};
diff --git a/adb/libs/adbconnection/include/adbconnection/server.h b/adb/libs/adbconnection/include/adbconnection/server.h
index 57ca6cd..b1059ba 100644
--- a/adb/libs/adbconnection/include/adbconnection/server.h
+++ b/adb/libs/adbconnection/include/adbconnection/server.h
@@ -20,7 +20,7 @@
 
 #include <android-base/unique_fd.h>
 
-extern "C" {
+#include "adbconnection/process_info.h"
 
-void adbconnection_listen(void (*callback)(int fd, pid_t pid));
-}
+// Note this is NOT an apex interface as it's linked only into adbd.
+void adbconnection_listen(void (*callback)(int fd, ProcessInfo process));
diff --git a/adb/pairing_connection/tests/pairing_connection_test.cpp b/adb/pairing_connection/tests/pairing_connection_test.cpp
index b6e09f1..86b66aa 100644
--- a/adb/pairing_connection/tests/pairing_connection_test.cpp
+++ b/adb/pairing_connection/tests/pairing_connection_test.cpp
@@ -440,7 +440,7 @@
     EXPECT_FALSE(*(server_waiter.is_valid_));
 }
 
-TEST_F(AdbPairingConnectionTest, MultipleClientsOnePass) {
+TEST_F(AdbPairingConnectionTest, DISABLED_MultipleClientsOnePass) {
     // Send multiple clients with bad passwords, but send the last one with the
     // correct password.
     std::vector<uint8_t> pswd{0x01, 0x03, 0x05, 0x07};
diff --git a/adb/proto/Android.bp b/adb/proto/Android.bp
index f7cba95..086d10e 100644
--- a/adb/proto/Android.bp
+++ b/adb/proto/Android.bp
@@ -71,3 +71,64 @@
         "//apex_available:platform",
     ],
 }
+
+cc_defaults {
+    name: "libapp_processes_protos_defaults",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Wthread-safety",
+        "-Werror",
+    ],
+
+    compile_multilib: "both",
+
+    srcs: [
+        "app_processes.proto",
+    ],
+    target: {
+        windows: {
+            compile_multilib: "first",
+            enabled: true,
+        },
+    },
+
+    visibility: [
+        "//system/core/adb:__subpackages__",
+
+        // This needs to be visible to minadbd, even though it's removed via exclude_shared_libs.
+        "//bootable/recovery/minadbd:__subpackages__",
+    ],
+
+    stl: "libc++_static",
+
+    apex_available: [
+        "com.android.adbd",
+        "test_com.android.adbd",
+    ],
+}
+
+cc_library {
+    name: "libapp_processes_protos_lite",
+    defaults: ["libapp_processes_protos_defaults"],
+
+    apex_available: ["//apex_available:platform"],
+
+    proto: {
+        export_proto_headers: true,
+        type: "lite",
+    },
+
+    host_supported: true,
+    recovery_available: true,
+}
+
+cc_library_host_static {
+    name: "libapp_processes_protos_full",
+    defaults: ["libapp_processes_protos_defaults"],
+
+    proto: {
+        export_proto_headers: true,
+        type: "full",
+    },
+}
diff --git a/adb/proto/app_processes.proto b/adb/proto/app_processes.proto
new file mode 100644
index 0000000..1183645
--- /dev/null
+++ b/adb/proto/app_processes.proto
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+option java_package = "com.android.server.adb.protos";
+option java_outer_classname = "AppProcessesProto";
+
+package adb.proto;
+
+message ProcessEntry {
+    int64 pid = 1;
+    bool debuggable = 2;
+    bool profileable = 3;
+    string architecture = 4;
+}
+
+message AppProcesses {
+  repeated ProcessEntry process = 1;
+}
diff --git a/adb/services.cpp b/adb/services.cpp
index 853d658..d87948c 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -95,56 +95,6 @@
 }
 
 #if ADB_HOST
-struct state_info {
-    TransportType transport_type;
-    std::string serial;
-    TransportId transport_id;
-    ConnectionState state;
-};
-
-static void wait_for_state(unique_fd fd, state_info* sinfo) {
-    D("wait_for_state %d", sinfo->state);
-
-    while (true) {
-        bool is_ambiguous = false;
-        std::string error = "unknown error";
-        const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : nullptr;
-        atransport* t = acquire_one_transport(sinfo->transport_type, serial, sinfo->transport_id,
-                                              &is_ambiguous, &error);
-        if (sinfo->state == kCsOffline) {
-            // wait-for-disconnect uses kCsOffline, we don't actually want to wait for 'offline'.
-            if (t == nullptr) {
-                SendOkay(fd);
-                break;
-            }
-        } else if (t != nullptr &&
-                   (sinfo->state == kCsAny || sinfo->state == t->GetConnectionState())) {
-            SendOkay(fd);
-            break;
-        }
-
-        if (!is_ambiguous) {
-            adb_pollfd pfd = {.fd = fd.get(), .events = POLLIN};
-            int rc = adb_poll(&pfd, 1, 100);
-            if (rc < 0) {
-                SendFail(fd, error);
-                break;
-            } else if (rc > 0 && (pfd.revents & POLLHUP) != 0) {
-                // The other end of the socket is closed, probably because the other side was
-                // terminated, bail out.
-                break;
-            }
-
-            // Try again...
-        } else {
-            SendFail(fd, error);
-            break;
-        }
-    }
-
-    D("wait_for_state is done");
-}
-
 void connect_emulator(const std::string& port_spec, std::string* response) {
     std::vector<std::string> pieces = android::base::Split(port_spec, ",");
     if (pieces.size() != 2) {
@@ -201,6 +151,80 @@
     adb_wifi_pair_device(host, password, response);
     SendProtocolString(fd.get(), response);
 }
+
+static void wait_service(unique_fd fd, std::string serial, TransportId transport_id,
+                         std::string spec) {
+    std::vector<std::string> components = android::base::Split(spec, "-");
+    if (components.size() < 2) {
+        SendFail(fd, "short wait-for-: " + spec);
+        return;
+    }
+
+    TransportType transport_type;
+    if (components[0] == "local") {
+        transport_type = kTransportLocal;
+    } else if (components[0] == "usb") {
+        transport_type = kTransportUsb;
+    } else if (components[0] == "any") {
+        transport_type = kTransportAny;
+    } else {
+        SendFail(fd, "bad wait-for- transport: " + spec);
+        return;
+    }
+
+    std::vector<ConnectionState> states;
+    for (size_t i = 1; i < components.size(); ++i) {
+        if (components[i] == "device") {
+            states.push_back(kCsDevice);
+        } else if (components[i] == "recovery") {
+            states.push_back(kCsRecovery);
+        } else if (components[i] == "rescue") {
+            states.push_back(kCsRescue);
+        } else if (components[i] == "sideload") {
+            states.push_back(kCsSideload);
+        } else if (components[i] == "bootloader") {
+            states.push_back(kCsBootloader);
+        } else if (components[i] == "any") {
+            states.push_back(kCsAny);
+        } else if (components[i] == "disconnect") {
+            states.push_back(kCsOffline);
+        } else {
+            SendFail(fd, "bad wait-for- state: " + spec);
+            return;
+        }
+    }
+
+    while (true) {
+        bool is_ambiguous = false;
+        std::string error = "unknown error";
+        atransport* t =
+                acquire_one_transport(transport_type, !serial.empty() ? serial.c_str() : nullptr,
+                                      transport_id, &is_ambiguous, &error);
+
+        for (const auto& state : states) {
+            // wait-for-disconnect uses kCsOffline, we don't actually want to wait for 'offline'.
+            if ((t == nullptr && state == kCsOffline) || (t != nullptr && state == kCsAny) ||
+                (t != nullptr && state == t->GetConnectionState())) {
+                SendOkay(fd);
+                return;
+            }
+        }
+
+        if (is_ambiguous) {
+            SendFail(fd, error);
+            return;
+        }
+
+        // Sleep before retrying.
+        adb_pollfd pfd = {.fd = fd.get(), .events = POLLIN};
+        if (adb_poll(&pfd, 1, 100) != 0) {
+            // The other end of the socket is closed, probably because the
+            // client terminated. Bail out.
+            SendFail(fd, error);
+            return;
+        }
+    }
+}
 #endif
 
 #if ADB_HOST
@@ -211,45 +235,10 @@
     } else if (name == "track-devices-l") {
         return create_device_tracker(true);
     } else if (android::base::ConsumePrefix(&name, "wait-for-")) {
-        std::shared_ptr<state_info> sinfo = std::make_shared<state_info>();
-        if (sinfo == nullptr) {
-            fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno));
-            return nullptr;
-        }
-
-        sinfo->serial = serial;
-        sinfo->transport_id = transport_id;
-
-        if (android::base::ConsumePrefix(&name, "local")) {
-            sinfo->transport_type = kTransportLocal;
-        } else if (android::base::ConsumePrefix(&name, "usb")) {
-            sinfo->transport_type = kTransportUsb;
-        } else if (android::base::ConsumePrefix(&name, "any")) {
-            sinfo->transport_type = kTransportAny;
-        } else {
-            return nullptr;
-        }
-
-        if (name == "-device") {
-            sinfo->state = kCsDevice;
-        } else if (name == "-recovery") {
-            sinfo->state = kCsRecovery;
-        } else if (name == "-rescue") {
-            sinfo->state = kCsRescue;
-        } else if (name == "-sideload") {
-            sinfo->state = kCsSideload;
-        } else if (name == "-bootloader") {
-            sinfo->state = kCsBootloader;
-        } else if (name == "-any") {
-            sinfo->state = kCsAny;
-        } else if (name == "-disconnect") {
-            sinfo->state = kCsOffline;
-        } else {
-            return nullptr;
-        }
-
-        unique_fd fd = create_service_thread(
-                "wait", [sinfo](unique_fd fd) { wait_for_state(std::move(fd), sinfo.get()); });
+        std::string spec(name);
+        unique_fd fd =
+                create_service_thread("wait", std::bind(wait_service, std::placeholders::_1,
+                                                        std::string(serial), transport_id, spec));
         return create_local_socket(std::move(fd));
     } else if (android::base::ConsumePrefix(&name, "connect:")) {
         std::string host(name);
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 3e781b8..9a879b5 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -665,6 +665,10 @@
     return fd.get();
 }
 
+static __inline__ int cast_handle_to_int(int fd) {
+    return fd;
+}
+
 // A very simple wrapper over a launched child process
 class Process {
   public:
diff --git a/adb/sysdeps/errno.cpp b/adb/sysdeps/errno.cpp
index 9a37ea2..e6af68b 100644
--- a/adb/sysdeps/errno.cpp
+++ b/adb/sysdeps/errno.cpp
@@ -24,7 +24,7 @@
 
 #include "adb.h"
 
-// Use the linux asm-generic values for errno (which are used on all android archs but mips).
+// Use the linux asm-generic values for errno (which are used on all android architectures).
 #define ERRNO_VALUES()             \
     ERRNO_VALUE(EACCES, 13);       \
     ERRNO_VALUE(EEXIST, 17);       \
@@ -48,7 +48,7 @@
     ERRNO_VALUE(ETXTBSY, 26)
 
 // Make sure these values are actually correct.
-#if defined(__linux__) && !defined(__mips__)
+#if defined(__linux__)
 #define ERRNO_VALUE(error_name, wire_value) static_assert((error_name) == (wire_value), "")
 ERRNO_VALUES();
 #undef ERRNO_VALUE
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 61467cb..e06dbe3 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -81,6 +81,7 @@
 const char* const kFeatureFixedPushSymlinkTimestamp = "fixed_push_symlink_timestamp";
 const char* const kFeatureAbbExec = "abb_exec";
 const char* const kFeatureRemountShell = "remount_shell";
+const char* const kFeatureTrackApp = "track_app";
 const char* const kFeatureSendRecv2 = "sendrecv_v2";
 const char* const kFeatureSendRecv2Brotli = "sendrecv_v2_brotli";
 
@@ -499,12 +500,8 @@
     auto x509 = GenerateX509Certificate(evp_pkey.get());
     auto x509_str = X509ToPEMString(x509.get());
     auto evp_str = Key::ToPEMString(evp_pkey.get());
-#ifdef _WIN32
-    int osh = cast_handle_to_int(adb_get_os_handle(fd_));
-#else
-    int osh = adb_get_os_handle(fd_);
-#endif
 
+    int osh = cast_handle_to_int(adb_get_os_handle(fd_));
 #if ADB_HOST
     tls_ = TlsConnection::Create(TlsConnection::Role::Client,
 #else
@@ -1183,6 +1180,7 @@
             kFeatureFixedPushSymlinkTimestamp,
             kFeatureAbbExec,
             kFeatureRemountShell,
+            kFeatureTrackApp,
             kFeatureSendRecv2,
             kFeatureSendRecv2Brotli,
             // Increment ADB_SERVER_VERSION when adding a feature that adbd needs
diff --git a/adb/transport.h b/adb/transport.h
index 5bc1b5c..b1984db 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -82,6 +82,8 @@
 extern const char* const kFeatureFixedPushSymlinkTimestamp;
 // Implement `adb remount` via shelling out to /system/bin/remount.
 extern const char* const kFeatureRemountShell;
+// adbd supports `track-app` service reporting debuggable/profileable apps.
+extern const char* const kFeatureTrackApp;
 // adbd supports version 2 of send/recv.
 extern const char* const kFeatureSendRecv2;
 // adbd supports brotli for send/recv v2.
diff --git a/base/Android.bp b/base/Android.bp
index 3702b43..894ad6c 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -47,6 +47,10 @@
             enabled: true,
         },
     },
+    apex_available: [
+        "//apex_available:anyapex",
+        "//apex_available:platform",
+    ],
 }
 
 cc_defaults {
@@ -199,6 +203,23 @@
     test_suites: ["device-tests"],
 }
 
+cc_test {
+    name: "libbase_tidy_test",
+    defaults: ["libbase_cflags_defaults"],
+    host_supported: true,
+
+    tidy: true,
+    tidy_checks_as_errors: ["bugprone-use-after-move"],
+
+    srcs: [
+        "tidy/unique_fd_test.cpp",
+        "tidy/unique_fd_test2.cpp",
+    ],
+
+    shared_libs: ["libbase"],
+    test_suites: ["device_tests"],
+}
+
 cc_benchmark {
     name: "libbase_benchmark",
     defaults: ["libbase_cflags_defaults"],
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
index 5abf514..546b2ec 100644
--- a/base/include/android-base/macros.h
+++ b/base/include/android-base/macros.h
@@ -143,8 +143,4 @@
 #define ABI_STRING "x86"
 #elif defined(__x86_64__)
 #define ABI_STRING "x86_64"
-#elif defined(__mips__) && !defined(__LP64__)
-#define ABI_STRING "mips"
-#elif defined(__mips__) && defined(__LP64__)
-#define ABI_STRING "mips64"
 #endif
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index c4a0aad..9ceb5db 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -102,7 +102,7 @@
     return *this;
   }
 
-  void reset(int new_value = -1) { reset(new_value, nullptr); }
+  [[clang::reinitializes]] void reset(int new_value = -1) { reset(new_value, nullptr); }
 
   int get() const { return fd_; }
 
diff --git a/base/tidy/unique_fd_test.cpp b/base/tidy/unique_fd_test.cpp
new file mode 100644
index 0000000..b3a99fc
--- /dev/null
+++ b/base/tidy/unique_fd_test.cpp
@@ -0,0 +1,32 @@
+/*
+ * 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 "android-base/unique_fd.h"
+
+#include <utility>
+
+#include <gtest/gtest.h>
+
+extern void consume_unique_fd(android::base::unique_fd fd);
+
+TEST(unique_fd, bugprone_use_after_move) {
+  // Compile time test for clang-tidy's bugprone-use-after-move check.
+  android::base::unique_fd ufd(open("/dev/null", O_RDONLY | O_CLOEXEC));
+  consume_unique_fd(std::move(ufd));
+  ufd.reset(open("/dev/null", O_RDONLY | O_CLOEXEC));
+  ufd.get();
+  consume_unique_fd(std::move(ufd));
+}
diff --git a/base/tidy/unique_fd_test2.cpp b/base/tidy/unique_fd_test2.cpp
new file mode 100644
index 0000000..b0c71e2
--- /dev/null
+++ b/base/tidy/unique_fd_test2.cpp
@@ -0,0 +1,19 @@
+/*
+ * 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 "android-base/unique_fd.h"
+
+void consume_unique_fd(android::base::unique_fd) {}
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index c7bd1a8..d67b522 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -317,6 +317,10 @@
         "libprocinfo",
         "libunwindstack",
     ],
+
+    apex_available: [
+        "com.android.runtime",
+    ],
 }
 
 cc_binary {
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 3e99880..0cd2350 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -254,9 +254,7 @@
 }
 
 static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo,
-                          std::unique_ptr<unwindstack::Regs>* regs, uintptr_t* abort_msg_address,
-                          uintptr_t* fdsan_table_address, uintptr_t* gwp_asan_state,
-                          uintptr_t* gwp_asan_metadata) {
+                          std::unique_ptr<unwindstack::Regs>* regs, ProcessInfo* process_info) {
   std::aligned_storage<sizeof(CrashInfo) + 1, alignof(CrashInfo)>::type buf;
   CrashInfo* crash_info = reinterpret_cast<CrashInfo*>(&buf);
   ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &buf, sizeof(buf)));
@@ -266,15 +264,13 @@
     ssize_t expected_size = 0;
     switch (crash_info->header.version) {
       case 1:
-        expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV1);
-        break;
-
       case 2:
-        expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV2);
+      case 3:
+        expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataStatic);
         break;
 
-      case 3:
-        expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV3);
+      case 4:
+        expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataDynamic);
         break;
 
       default:
@@ -282,28 +278,32 @@
         break;
     };
 
-    if (rc != expected_size) {
+    if (rc < expected_size) {
       LOG(FATAL) << "read " << rc << " bytes when reading target crash information, expected "
                  << expected_size;
     }
   }
 
-  *fdsan_table_address = 0;
-  *gwp_asan_state = 0;
-  *gwp_asan_metadata = 0;
   switch (crash_info->header.version) {
-    case 3:
-      *gwp_asan_state = crash_info->data.v3.gwp_asan_state;
-      *gwp_asan_metadata = crash_info->data.v3.gwp_asan_metadata;
-      FALLTHROUGH_INTENDED;
-    case 2:
-      *fdsan_table_address = crash_info->data.v2.fdsan_table_address;
+    case 4:
+      process_info->fdsan_table_address = crash_info->data.d.fdsan_table_address;
+      process_info->gwp_asan_state = crash_info->data.d.gwp_asan_state;
+      process_info->gwp_asan_metadata = crash_info->data.d.gwp_asan_metadata;
       FALLTHROUGH_INTENDED;
     case 1:
-      *abort_msg_address = crash_info->data.v1.abort_msg_address;
-      *siginfo = crash_info->data.v1.siginfo;
+    case 2:
+    case 3:
+      process_info->abort_msg_address = crash_info->data.s.abort_msg_address;
+      *siginfo = crash_info->data.s.siginfo;
+      if (signal_has_si_addr(siginfo)) {
+        // Make a copy of the ucontext field because otherwise it is not aligned enough (due to
+        // being in a packed struct) and clang complains about that.
+        ucontext_t ucontext = crash_info->data.s.ucontext;
+        process_info->has_fault_address = true;
+        process_info->fault_address = get_fault_address(siginfo, &ucontext);
+      }
       regs->reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(),
-                                                        &crash_info->data.v1.ucontext));
+                                                        &crash_info->data.s.ucontext));
       break;
 
     default:
@@ -425,10 +425,7 @@
   ATRACE_NAME("after reparent");
   pid_t pseudothread_tid;
   DebuggerdDumpType dump_type;
-  uintptr_t abort_msg_address = 0;
-  uintptr_t fdsan_table_address = 0;
-  uintptr_t gwp_asan_state = 0;
-  uintptr_t gwp_asan_metadata = 0;
+  ProcessInfo process_info;
 
   Initialize(argv);
   ParseArgs(argc, argv, &pseudothread_tid, &dump_type);
@@ -489,8 +486,7 @@
 
       if (thread == g_target_thread) {
         // Read the thread's registers along with the rest of the crash info out of the pipe.
-        ReadCrashInfo(input_pipe, &siginfo, &info.registers, &abort_msg_address,
-                      &fdsan_table_address, &gwp_asan_state, &gwp_asan_metadata);
+        ReadCrashInfo(input_pipe, &siginfo, &info.registers, &process_info);
         info.siginfo = &siginfo;
         info.signo = info.siginfo->si_signo;
       } else {
@@ -599,14 +595,14 @@
   } else {
     {
       ATRACE_NAME("fdsan table dump");
-      populate_fdsan_table(&open_files, unwinder.GetProcessMemory(), fdsan_table_address);
+      populate_fdsan_table(&open_files, unwinder.GetProcessMemory(),
+                           process_info.fdsan_table_address);
     }
 
     {
       ATRACE_NAME("engrave_tombstone");
-      engrave_tombstone(std::move(g_output_fd), &unwinder, thread_info, g_target_thread,
-                        abort_msg_address, &open_files, &amfd_data, gwp_asan_state,
-                        gwp_asan_metadata);
+      engrave_tombstone(std::move(g_output_fd), &unwinder, thread_info, g_target_thread, process_info,
+                        &open_files, &amfd_data);
     }
   }
 
diff --git a/debuggerd/crasher/Android.bp b/debuggerd/crasher/Android.bp
index e86f499..61c5395 100644
--- a/debuggerd/crasher/Android.bp
+++ b/debuggerd/crasher/Android.bp
@@ -24,12 +24,6 @@
         arm64: {
             srcs: ["arm64/crashglue.S"],
         },
-        mips: {
-            srcs: ["mips/crashglue.S"],
-        },
-        mips64: {
-            srcs: ["mips64/crashglue.S"],
-        },
         x86: {
             srcs: ["x86/crashglue.S"],
         },
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index 3041664..a2b13a3 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -349,7 +349,7 @@
 int main(int argc, char** argv) {
 #if defined(STATIC_CRASHER)
     debuggerd_callbacks_t callbacks = {
-      .get_abort_message = []() {
+      .get_process_info = []() {
         static struct {
           size_t size;
           char msg[32];
@@ -357,7 +357,9 @@
 
         msg.size = strlen("dummy abort message");
         memcpy(msg.msg, "dummy abort message", strlen("dummy abort message"));
-        return reinterpret_cast<abort_msg_t*>(&msg);
+        return debugger_process_info{
+            .abort_msg = reinterpret_cast<void*>(&msg),
+        };
       },
       .post_dump = nullptr
     };
diff --git a/debuggerd/crasher/mips/crashglue.S b/debuggerd/crasher/mips/crashglue.S
deleted file mode 100644
index 70a6641..0000000
--- a/debuggerd/crasher/mips/crashglue.S
+++ /dev/null
@@ -1,48 +0,0 @@
-	.set	noat
-
-	.globl crash1
-	.globl crashnostack
-
-crash1:
-	li	$0,0xdead0000+0
-	li	$1,0xdead0000+1
-	li	$2,0xdead0000+2
-	li	$3,0xdead0000+3
-	li	$4,0xdead0000+4
-	li	$5,0xdead0000+5
-	li	$6,0xdead0000+6
-	li	$7,0xdead0000+7
-	li	$8,0xdead0000+8
-	li	$9,0xdead0000+9
-	li	$10,0xdead0000+10
-	li	$11,0xdead0000+11
-	li	$12,0xdead0000+12
-	li	$13,0xdead0000+13
-	li	$14,0xdead0000+14
-	li	$15,0xdead0000+15
-	li	$16,0xdead0000+16
-	li	$17,0xdead0000+17
-	li	$18,0xdead0000+18
-	li	$19,0xdead0000+19
-	li	$20,0xdead0000+20
-	li	$21,0xdead0000+21
-	li	$22,0xdead0000+22
-	li	$23,0xdead0000+23
-	li	$24,0xdead0000+24
-	li	$25,0xdead0000+25
-	li	$26,0xdead0000+26
-	li	$27,0xdead0000+27
-	li	$28,0xdead0000+28
-	# don't trash the stack otherwise the signal handler won't run
-	#li	$29,0xdead0000+29
-	li	$30,0xdead0000+30
-	li	$31,0xdead0000+31
-
-	lw	$zero,($0)
-	b .
-
-
-crashnostack:
-	li	$sp, 0
-	lw	$zero,($0)
-	b .
diff --git a/debuggerd/crasher/mips64/crashglue.S b/debuggerd/crasher/mips64/crashglue.S
deleted file mode 100644
index 70a6641..0000000
--- a/debuggerd/crasher/mips64/crashglue.S
+++ /dev/null
@@ -1,48 +0,0 @@
-	.set	noat
-
-	.globl crash1
-	.globl crashnostack
-
-crash1:
-	li	$0,0xdead0000+0
-	li	$1,0xdead0000+1
-	li	$2,0xdead0000+2
-	li	$3,0xdead0000+3
-	li	$4,0xdead0000+4
-	li	$5,0xdead0000+5
-	li	$6,0xdead0000+6
-	li	$7,0xdead0000+7
-	li	$8,0xdead0000+8
-	li	$9,0xdead0000+9
-	li	$10,0xdead0000+10
-	li	$11,0xdead0000+11
-	li	$12,0xdead0000+12
-	li	$13,0xdead0000+13
-	li	$14,0xdead0000+14
-	li	$15,0xdead0000+15
-	li	$16,0xdead0000+16
-	li	$17,0xdead0000+17
-	li	$18,0xdead0000+18
-	li	$19,0xdead0000+19
-	li	$20,0xdead0000+20
-	li	$21,0xdead0000+21
-	li	$22,0xdead0000+22
-	li	$23,0xdead0000+23
-	li	$24,0xdead0000+24
-	li	$25,0xdead0000+25
-	li	$26,0xdead0000+26
-	li	$27,0xdead0000+27
-	li	$28,0xdead0000+28
-	# don't trash the stack otherwise the signal handler won't run
-	#li	$29,0xdead0000+29
-	li	$30,0xdead0000+30
-	li	$31,0xdead0000+31
-
-	lw	$zero,($0)
-	b .
-
-
-crashnostack:
-	li	$sp, 0
-	lw	$zero,($0)
-	b .
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 6a8cc56..054f836 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -305,6 +305,32 @@
   ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
 }
 
+TEST_F(CrasherTest, tagged_fault_addr) {
+#if !defined(__aarch64__)
+  GTEST_SKIP() << "Requires aarch64";
+#endif
+  int intercept_result;
+  unique_fd output_fd;
+  StartProcess([]() {
+    *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
+  });
+
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  AssertDeath(SIGSEGV);
+  FinishIntercept(&intercept_result);
+
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+
+  // The address can either be tagged (new kernels) or untagged (old kernels).
+  ASSERT_MATCH(
+      result,
+      R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr (0x100000000000dead|0xdead))");
+}
+
 TEST_F(CrasherTest, LD_PRELOAD) {
   int intercept_result;
   unique_fd output_fd;
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 8b4b630..ac28fe9 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -83,7 +83,7 @@
 #define CRASH_DUMP_NAME "crash_dump32"
 #endif
 
-#define CRASH_DUMP_PATH "/system/bin/" CRASH_DUMP_NAME
+#define CRASH_DUMP_PATH "/apex/com.android.runtime/bin/" CRASH_DUMP_NAME
 
 // Wrappers that directly invoke the respective syscalls, in case the cached values are invalid.
 #pragma GCC poison getpid gettid
@@ -167,7 +167,7 @@
  * mutex is being held, so we don't want to use any libc functions that
  * could allocate memory or hold a lock.
  */
-static void log_signal_summary(const siginfo_t* info) {
+static void log_signal_summary(const siginfo_t* info, const ucontext_t* ucontext) {
   char thread_name[MAX_TASK_NAME_LEN + 1];  // one more for termination
   if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) {
     strcpy(thread_name, "<name unknown>");
@@ -186,7 +186,8 @@
   // Many signals don't have an address or sender.
   char addr_desc[32] = "";  // ", fault addr 0x1234"
   if (signal_has_si_addr(info)) {
-    async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
+    async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p",
+                             reinterpret_cast<void*>(get_fault_address(info, ucontext)));
   }
   pid_t self_pid = __getpid();
   char sender_desc[32] = {};  // " from pid 1234, uid 666"
@@ -297,10 +298,7 @@
   pid_t pseudothread_tid;
   siginfo_t* siginfo;
   void* ucontext;
-  uintptr_t abort_msg;
-  uintptr_t fdsan_table;
-  uintptr_t gwp_asan_state;
-  uintptr_t gwp_asan_metadata;
+  debugger_process_info process_info;
 };
 
 // Logging and contacting debuggerd requires free file descriptors, which we might not have.
@@ -344,25 +342,36 @@
     fatal_errno("failed to create pipe");
   }
 
-  // ucontext_t is absurdly large on AArch64, so piece it together manually with writev.
-  uint32_t version = 3;
-  constexpr size_t expected = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV3);
+  uint32_t version;
+  ssize_t expected;
 
+  // ucontext_t is absurdly large on AArch64, so piece it together manually with writev.
+  struct iovec iovs[4] = {
+      {.iov_base = &version, .iov_len = sizeof(version)},
+      {.iov_base = thread_info->siginfo, .iov_len = sizeof(siginfo_t)},
+      {.iov_base = thread_info->ucontext, .iov_len = sizeof(ucontext_t)},
+  };
+
+  if (thread_info->process_info.fdsan_table) {
+    // Dynamic executables always use version 4. There is no need to increment the version number if
+    // the format changes, because the sender (linker) and receiver (crash_dump) are version locked.
+    version = 4;
+    expected = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataDynamic);
+
+    iovs[3] = {.iov_base = &thread_info->process_info,
+               .iov_len = sizeof(thread_info->process_info)};
+  } else {
+    // Static executables always use version 1.
+    version = 1;
+    expected = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataStatic);
+
+    iovs[3] = {.iov_base = &thread_info->process_info.abort_msg, .iov_len = sizeof(uintptr_t)};
+  }
   errno = 0;
   if (fcntl(output_write.get(), F_SETPIPE_SZ, expected) < static_cast<int>(expected)) {
     fatal_errno("failed to set pipe buffer size");
   }
 
-  struct iovec iovs[] = {
-      {.iov_base = &version, .iov_len = sizeof(version)},
-      {.iov_base = thread_info->siginfo, .iov_len = sizeof(siginfo_t)},
-      {.iov_base = thread_info->ucontext, .iov_len = sizeof(ucontext_t)},
-      {.iov_base = &thread_info->abort_msg, .iov_len = sizeof(uintptr_t)},
-      {.iov_base = &thread_info->fdsan_table, .iov_len = sizeof(uintptr_t)},
-      {.iov_base = &thread_info->gwp_asan_state, .iov_len = sizeof(uintptr_t)},
-      {.iov_base = &thread_info->gwp_asan_metadata, .iov_len = sizeof(uintptr_t)},
-  };
-
   ssize_t rc = TEMP_FAILURE_RETRY(writev(output_write.get(), iovs, arraysize(iovs)));
   if (rc == -1) {
     fatal_errno("failed to write crash info");
@@ -468,6 +477,8 @@
   // making a syscall and checking errno.
   ErrnoRestorer restorer;
 
+  auto *ucontext = static_cast<ucontext_t*>(context);
+
   // It's possible somebody cleared the SA_SIGINFO flag, which would mean
   // our "info" arg holds an undefined value.
   if (!have_siginfo(signal_number)) {
@@ -489,29 +500,19 @@
     // check to allow all si_code values in calls coming from inside the house.
   }
 
-  void* abort_message = nullptr;
-  const gwp_asan::AllocatorState* gwp_asan_state = nullptr;
-  const gwp_asan::AllocationMetadata* gwp_asan_metadata = nullptr;
+  debugger_process_info process_info = {};
   uintptr_t si_val = reinterpret_cast<uintptr_t>(info->si_ptr);
   if (signal_number == BIONIC_SIGNAL_DEBUGGER) {
     if (info->si_code == SI_QUEUE && info->si_pid == __getpid()) {
       // Allow for the abort message to be explicitly specified via the sigqueue value.
       // Keep the bottom bit intact for representing whether we want a backtrace or a tombstone.
       if (si_val != kDebuggerdFallbackSivalUintptrRequestDump) {
-        abort_message = reinterpret_cast<void*>(si_val & ~1);
+        process_info.abort_msg = reinterpret_cast<void*>(si_val & ~1);
         info->si_ptr = reinterpret_cast<void*>(si_val & 1);
       }
     }
-  } else {
-    if (g_callbacks.get_abort_message) {
-      abort_message = g_callbacks.get_abort_message();
-    }
-    if (g_callbacks.get_gwp_asan_state) {
-      gwp_asan_state = g_callbacks.get_gwp_asan_state();
-    }
-    if (g_callbacks.get_gwp_asan_metadata) {
-      gwp_asan_metadata = g_callbacks.get_gwp_asan_metadata();
-    }
+  } else if (g_callbacks.get_process_info) {
+    process_info = g_callbacks.get_process_info();
   }
 
   // If sival_int is ~0, it means that the fallback handler has been called
@@ -524,7 +525,7 @@
     // This check might be racy if another thread sets NO_NEW_PRIVS, but this should be unlikely,
     // you can only set NO_NEW_PRIVS to 1, and the effect should be at worst a single missing
     // ANR trace.
-    debuggerd_fallback_handler(info, static_cast<ucontext_t*>(context), abort_message);
+    debuggerd_fallback_handler(info, ucontext, process_info.abort_msg);
     resend_signal(info);
     return;
   }
@@ -536,17 +537,14 @@
     return;
   }
 
-  log_signal_summary(info);
+  log_signal_summary(info, ucontext);
 
   debugger_thread_info thread_info = {
       .crashing_tid = __gettid(),
       .pseudothread_tid = -1,
       .siginfo = info,
       .ucontext = context,
-      .abort_msg = reinterpret_cast<uintptr_t>(abort_message),
-      .fdsan_table = reinterpret_cast<uintptr_t>(android_fdsan_get_fd_table()),
-      .gwp_asan_state = reinterpret_cast<uintptr_t>(gwp_asan_state),
-      .gwp_asan_metadata = reinterpret_cast<uintptr_t>(gwp_asan_metadata),
+      .process_info = process_info,
   };
 
   // Set PR_SET_DUMPABLE to 1, so that crash_dump can ptrace us.
diff --git a/debuggerd/include/debuggerd/handler.h b/debuggerd/include/debuggerd/handler.h
index 665d24a..6650294 100644
--- a/debuggerd/include/debuggerd/handler.h
+++ b/debuggerd/include/debuggerd/handler.h
@@ -33,13 +33,20 @@
 struct AllocationMetadata;
 };  // namespace gwp_asan
 
+// When updating this data structure, CrashInfoDataDynamic and the code in
+// ReadCrashInfo() must also be updated.
+struct debugger_process_info {
+  void* abort_msg;
+  void* fdsan_table;
+  const gwp_asan::AllocatorState* gwp_asan_state;
+  const gwp_asan::AllocationMetadata* gwp_asan_metadata;
+};
+
 // These callbacks are called in a signal handler, and thus must be async signal safe.
 // If null, the callbacks will not be called.
 typedef struct {
-  struct abort_msg_t* (*get_abort_message)();
+  debugger_process_info (*get_process_info)();
   void (*post_dump)();
-  const struct gwp_asan::AllocatorState* (*get_gwp_asan_state)();
-  const struct gwp_asan::AllocationMetadata* (*get_gwp_asan_metadata)();
 } debuggerd_callbacks_t;
 
 void debuggerd_init(debuggerd_callbacks_t* callbacks);
diff --git a/debuggerd/libdebuggerd/gwp_asan.cpp b/debuggerd/libdebuggerd/gwp_asan.cpp
index 53df783..f271365 100644
--- a/debuggerd/libdebuggerd/gwp_asan.cpp
+++ b/debuggerd/libdebuggerd/gwp_asan.cpp
@@ -63,12 +63,11 @@
 }
 
 GwpAsanCrashData::GwpAsanCrashData(unwindstack::Memory* process_memory,
-                                   uintptr_t gwp_asan_state_ptr, uintptr_t gwp_asan_metadata_ptr,
-                                   const ThreadInfo& thread_info) {
-  if (!process_memory || !gwp_asan_metadata_ptr || !gwp_asan_state_ptr) return;
+                                   const ProcessInfo& process_info, const ThreadInfo& thread_info) {
+  if (!process_memory || !process_info.gwp_asan_metadata || !process_info.gwp_asan_state) return;
   // Extract the GWP-ASan regions from the dead process.
-  if (!retrieve_gwp_asan_state(process_memory, gwp_asan_state_ptr, &state_)) return;
-  metadata_.reset(retrieve_gwp_asan_metadata(process_memory, state_, gwp_asan_metadata_ptr));
+  if (!retrieve_gwp_asan_state(process_memory, process_info.gwp_asan_state, &state_)) return;
+  metadata_.reset(retrieve_gwp_asan_metadata(process_memory, state_, process_info.gwp_asan_metadata));
   if (!metadata_.get()) return;
 
   // Get the external crash address from the thread info.
@@ -158,63 +157,6 @@
        error_string_, diff, byte_suffix, location_str, alloc_size, alloc_address);
 }
 
-// Build a frame for symbolization using the maps from the provided unwinder.
-// The constructed frame contains just enough information to be used to
-// symbolize a GWP-ASan stack trace.
-static unwindstack::FrameData BuildFrame(unwindstack::Unwinder* unwinder, uintptr_t pc,
-                                         size_t frame_num) {
-  unwindstack::FrameData frame;
-  frame.num = frame_num;
-
-  unwindstack::Maps* maps = unwinder->GetMaps();
-  unwindstack::MapInfo* map_info = maps->Find(pc);
-  if (!map_info) {
-    frame.rel_pc = pc;
-    return frame;
-  }
-
-  unwindstack::Elf* elf =
-      map_info->GetElf(unwinder->GetProcessMemory(), unwindstack::Regs::CurrentArch());
-
-  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);
-  relative_pc -= pc_adjustment;
-  // The debug PC may be different if the PC comes from the JIT.
-  uint64_t debug_pc = relative_pc;
-
-  // If we don't have a valid ELF file, check the JIT.
-  if (!elf->valid()) {
-    unwindstack::JitDebug jit_debug(unwinder->GetProcessMemory());
-    uint64_t jit_pc = pc - pc_adjustment;
-    unwindstack::Elf* jit_elf = jit_debug.GetElf(maps, jit_pc);
-    if (jit_elf != nullptr) {
-      debug_pc = jit_pc;
-      elf = jit_elf;
-    }
-  }
-
-  // Copy all the things we need into the frame for symbolization.
-  frame.rel_pc = relative_pc;
-  frame.pc = pc - pc_adjustment;
-  frame.map_name = map_info->name;
-  frame.map_elf_start_offset = map_info->elf_start_offset;
-  frame.map_exact_offset = map_info->offset;
-  frame.map_start = map_info->start;
-  frame.map_end = map_info->end;
-  frame.map_flags = map_info->flags;
-  frame.map_load_bias = elf->GetLoadBias();
-
-  if (!elf->GetFunctionName(relative_pc, &frame.function_name, &frame.function_offset)) {
-    frame.function_name = "";
-    frame.function_offset = 0;
-  }
-  return frame;
-}
-
 constexpr size_t kMaxTraceLength = gwp_asan::AllocationMetadata::kMaxTraceLengthToCollect;
 
 bool GwpAsanCrashData::HasDeallocationTrace() const {
@@ -241,7 +183,8 @@
 
   unwinder->SetDisplayBuildID(true);
   for (size_t i = 0; i < num_frames; ++i) {
-    unwindstack::FrameData frame_data = BuildFrame(unwinder, frames.get()[i], i);
+    unwindstack::FrameData frame_data = unwinder->BuildFrameFromPcOnly(frames.get()[i]);
+    frame_data.num = i;
     _LOG(log, logtype::BACKTRACE, "    %s\n", unwinder->FormatFrame(frame_data).c_str());
   }
 }
@@ -267,7 +210,8 @@
 
   unwinder->SetDisplayBuildID(true);
   for (size_t i = 0; i < num_frames; ++i) {
-    unwindstack::FrameData frame_data = BuildFrame(unwinder, frames.get()[i], i);
+    unwindstack::FrameData frame_data = unwinder->BuildFrameFromPcOnly(frames.get()[i]);
+    frame_data.num = i;
     _LOG(log, logtype::BACKTRACE, "    %s\n", unwinder->FormatFrame(frame_data).c_str());
   }
 }
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h b/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h
index aef4c62..6c88733 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h
@@ -38,8 +38,8 @@
   // still be responsible, as it terminates when it detects an internal error
   // (double free, invalid free). In these cases, we will retrieve the fault
   // address from the GWP-ASan allocator's state.
-  GwpAsanCrashData(unwindstack::Memory* process_memory, uintptr_t gwp_asan_state_ptr,
-                   uintptr_t gwp_asan_metadata_ptr, const ThreadInfo& thread_info);
+  GwpAsanCrashData(unwindstack::Memory* process_memory, const ProcessInfo& process_info,
+                   const ThreadInfo& thread_info);
 
   // Is GWP-ASan responsible for this crash.
   bool CrashIsMine() const;
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
index 291d994..3ff7d62 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
@@ -44,18 +44,13 @@
 int open_tombstone(std::string* path);
 
 /* Creates a tombstone file and writes the crash dump to it. */
-void engrave_tombstone(int tombstone_fd, unwindstack::Unwinder* unwinder,
-                       const OpenFilesList* open_files, pid_t pid, pid_t tid,
-                       const std::string& process_name, const std::map<pid_t, std::string>& threads,
-                       uint64_t abort_msg_address, std::string* amfd_data);
+void engrave_tombstone(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
+                       const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread,
+                       const ProcessInfo& process_info, OpenFilesList* open_files,
+                       std::string* amfd_data);
 
 void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, siginfo_t* siginfo,
                                 ucontext_t* ucontext);
 
-void engrave_tombstone(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
-                       const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread,
-                       uint64_t abort_msg_address, OpenFilesList* open_files,
-                       std::string* amfd_data, uintptr_t gwp_asan_state,
-                       uintptr_t gwp_asan_metadata);
 
 #endif  // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
index eb4b1b8..35c3fd6 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
@@ -35,3 +35,13 @@
   int signo = 0;
   siginfo_t* siginfo = nullptr;
 };
+
+struct ProcessInfo {
+  uintptr_t abort_msg_address = 0;
+  uintptr_t fdsan_table_address = 0;
+  uintptr_t gwp_asan_state = 0;
+  uintptr_t gwp_asan_metadata = 0;
+
+  bool has_fault_address = false;
+  uintptr_t fault_address = 0;
+};
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 75bac87..7bfcf5d 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -93,4 +93,6 @@
 const char* get_signame(const siginfo_t*);
 const char* get_sigcode(const siginfo_t*);
 
+uintptr_t get_fault_address(const siginfo_t* siginfo, const ucontext_t* ucontext);
+
 #endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index eed95bc..aec8c60 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -371,7 +371,7 @@
   GwpAsanCrashDataTest(
       gwp_asan::Error error,
       const gwp_asan::AllocationMetadata *responsible_allocation) :
-      GwpAsanCrashData(nullptr, 0u, 0u, ThreadInfo{}) {
+      GwpAsanCrashData(nullptr, ProcessInfo{}, ThreadInfo{}) {
     is_gwp_asan_responsible_ = true;
     error_ = error;
     responsible_allocation_ = responsible_allocation;
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index fd52e81..e0168d5 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -154,16 +154,16 @@
 }
 
 static void dump_signal_info(log_t* log, const ThreadInfo& thread_info,
-                             unwindstack::Memory* process_memory) {
+                             const ProcessInfo& process_info, unwindstack::Memory* process_memory) {
   char addr_desc[64];  // ", fault addr 0x1234"
-  if (signal_has_si_addr(thread_info.siginfo)) {
-    void* addr = thread_info.siginfo->si_addr;
+  if (process_info.has_fault_address) {
+    size_t addr = process_info.fault_address;
     if (thread_info.siginfo->si_signo == SIGILL) {
       uint32_t instruction = {};
-      process_memory->Read(reinterpret_cast<uint64_t>(addr), &instruction, sizeof(instruction));
-      snprintf(addr_desc, sizeof(addr_desc), "%p (*pc=%#08x)", addr, instruction);
+      process_memory->Read(addr, &instruction, sizeof(instruction));
+      snprintf(addr_desc, sizeof(addr_desc), "0x%zx (*pc=%#08x)", addr, instruction);
     } else {
-      snprintf(addr_desc, sizeof(addr_desc), "%p", addr);
+      snprintf(addr_desc, sizeof(addr_desc), "0x%zx", addr);
     }
   } else {
     snprintf(addr_desc, sizeof(addr_desc), "--------");
@@ -376,8 +376,7 @@
 }
 
 static bool dump_thread(log_t* log, unwindstack::Unwinder* unwinder, const ThreadInfo& thread_info,
-                        uint64_t abort_msg_address, bool primary_thread,
-                        const GwpAsanCrashData& gwp_asan_crash_data) {
+                        const ProcessInfo& process_info, bool primary_thread) {
   log->current_tid = thread_info.tid;
   if (!primary_thread) {
     _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
@@ -385,18 +384,24 @@
   dump_thread_info(log, thread_info);
 
   if (thread_info.siginfo) {
-    dump_signal_info(log, thread_info, unwinder->GetProcessMemory().get());
+    dump_signal_info(log, thread_info, process_info, unwinder->GetProcessMemory().get());
   }
 
-  if (primary_thread && gwp_asan_crash_data.CrashIsMine()) {
-    gwp_asan_crash_data.DumpCause(log);
+  std::unique_ptr<GwpAsanCrashData> gwp_asan_crash_data;
+  if (primary_thread) {
+    gwp_asan_crash_data = std::make_unique<GwpAsanCrashData>(unwinder->GetProcessMemory().get(),
+                                                             process_info, thread_info);
+  }
+
+  if (primary_thread && gwp_asan_crash_data->CrashIsMine()) {
+    gwp_asan_crash_data->DumpCause(log);
   } else if (thread_info.siginfo) {
     dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps(),
                         thread_info.registers.get());
   }
 
   if (primary_thread) {
-    dump_abort_message(log, unwinder->GetProcessMemory().get(), abort_msg_address);
+    dump_abort_message(log, unwinder->GetProcessMemory().get(), process_info.abort_msg_address);
   }
 
   dump_registers(log, thread_info.registers.get());
@@ -413,12 +418,12 @@
   }
 
   if (primary_thread) {
-    if (gwp_asan_crash_data.HasDeallocationTrace()) {
-      gwp_asan_crash_data.DumpDeallocationTrace(log, unwinder);
+    if (gwp_asan_crash_data->HasDeallocationTrace()) {
+      gwp_asan_crash_data->DumpDeallocationTrace(log, unwinder);
     }
 
-    if (gwp_asan_crash_data.HasAllocationTrace()) {
-      gwp_asan_crash_data.DumpAllocationTrace(log, unwinder);
+    if (gwp_asan_crash_data->HasAllocationTrace()) {
+      gwp_asan_crash_data->DumpAllocationTrace(log, unwinder);
     }
 
     unwindstack::Maps* maps = unwinder->GetMaps();
@@ -442,8 +447,6 @@
 // that don't match the specified pid, and writes them to the tombstone file.
 //
 // If "tail" is non-zero, log the last "tail" number of lines.
-static EventTagMap* g_eventTagMap = NULL;
-
 static void dump_log_file(log_t* log, pid_t pid, const char* filename, unsigned int tail) {
   bool first = true;
   logger_list* logger_list;
@@ -452,8 +455,8 @@
     return;
   }
 
-  logger_list = android_logger_list_open(
-      android_name_to_log_id(filename), ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, tail, pid);
+  logger_list =
+      android_logger_list_open(android_name_to_log_id(filename), ANDROID_LOG_NONBLOCK, tail, pid);
 
   if (!logger_list) {
     ALOGE("Unable to open %s: %s\n", filename, strerror(errno));
@@ -502,21 +505,6 @@
     ptm = localtime_r(&sec, &tmBuf);
     strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
 
-    if (log_entry.id() == LOG_ID_EVENTS) {
-      if (!g_eventTagMap) {
-        g_eventTagMap = android_openEventTagMap(nullptr);
-      }
-      AndroidLogEntry e;
-      char buf[512];
-      if (android_log_processBinaryLogBuffer(&log_entry.entry, &e, g_eventTagMap, buf,
-                                             sizeof(buf)) == 0) {
-        _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8.*s: %s\n", timeBuf,
-             log_entry.entry.nsec / 1000000, log_entry.entry.pid, log_entry.entry.tid, 'I',
-             (int)e.tagLen, e.tag, e.message);
-      }
-      continue;
-    }
-
     char* msg = log_entry.msg();
     if (msg == nullptr) {
       continue;
@@ -601,15 +589,16 @@
     LOG(FATAL) << "Failed to init unwinder object.";
   }
 
-  engrave_tombstone(unique_fd(dup(tombstone_fd)), &unwinder, threads, tid, abort_msg_address,
-                    nullptr, nullptr, 0u, 0u);
+  ProcessInfo process_info;
+  process_info.abort_msg_address = abort_msg_address;
+  engrave_tombstone(unique_fd(dup(tombstone_fd)), &unwinder, threads, tid, process_info, nullptr,
+                    nullptr);
 }
 
 void engrave_tombstone(unique_fd output_fd, unwindstack::Unwinder* unwinder,
                        const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
-                       uint64_t abort_msg_address, OpenFilesList* open_files,
-                       std::string* amfd_data, uintptr_t gwp_asan_state_ptr,
-                       uintptr_t gwp_asan_metadata_ptr) {
+                       const ProcessInfo& process_info, OpenFilesList* open_files,
+                       std::string* amfd_data) {
   // don't copy log messages to tombstone unless this is a dev device
   bool want_logs = android::base::GetBoolProperty("ro.debuggable", false);
 
@@ -628,12 +617,7 @@
     LOG(FATAL) << "failed to find target thread";
   }
 
-  GwpAsanCrashData gwp_asan_crash_data(unwinder->GetProcessMemory().get(),
-                                       gwp_asan_state_ptr,
-                                       gwp_asan_metadata_ptr, it->second);
-
-  dump_thread(&log, unwinder, it->second, abort_msg_address, true,
-              gwp_asan_crash_data);
+  dump_thread(&log, unwinder, it->second, process_info, true);
 
   if (want_logs) {
     dump_logs(&log, it->second.pid, 50);
@@ -644,7 +628,7 @@
       continue;
     }
 
-    dump_thread(&log, unwinder, thread_info, 0, false, gwp_asan_crash_data);
+    dump_thread(&log, unwinder, thread_info, process_info, false);
   }
 
   if (open_files) {
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 0a1d2a4..3bf28b6 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -449,3 +449,40 @@
     _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
   }
 }
+
+#if defined(__aarch64__)
+#define FAR_MAGIC 0x46415201
+
+struct far_context {
+  struct _aarch64_ctx head;
+  __u64 far;
+};
+#endif
+
+uintptr_t get_fault_address(const siginfo_t* siginfo, const ucontext_t* ucontext) {
+  (void)ucontext;
+#if defined(__aarch64__)
+  // This relies on a kernel patch:
+  //   https://patchwork.kernel.org/patch/11435077/
+  // that hasn't been accepted into the kernel yet. TODO(pcc): Update this to
+  // use the official interface once it lands.
+  auto* begin = reinterpret_cast<const char*>(ucontext->uc_mcontext.__reserved);
+  auto* end = begin + sizeof(ucontext->uc_mcontext.__reserved);
+  auto* ptr = begin;
+  while (1) {
+    auto* ctx = reinterpret_cast<const _aarch64_ctx*>(ptr);
+    if (ctx->magic == 0) {
+      break;
+    }
+    if (ctx->magic == FAR_MAGIC) {
+      auto* far_ctx = reinterpret_cast<const far_context*>(ctx);
+      return far_ctx->far;
+    }
+    ptr += ctx->size;
+    if (ctx->size % sizeof(void*) != 0 || ptr < begin || ptr >= end) {
+      break;
+    }
+  }
+#endif
+  return reinterpret_cast<uintptr_t>(siginfo->si_addr);
+}
diff --git a/debuggerd/protocol.h b/debuggerd/protocol.h
index bf53864..e85660c 100644
--- a/debuggerd/protocol.h
+++ b/debuggerd/protocol.h
@@ -85,17 +85,14 @@
   uint32_t version;
 };
 
-struct __attribute__((__packed__)) CrashInfoDataV1 {
+struct __attribute__((__packed__)) CrashInfoDataStatic {
   siginfo_t siginfo;
   ucontext_t ucontext;
   uintptr_t abort_msg_address;
 };
 
-struct __attribute__((__packed__)) CrashInfoDataV2 : public CrashInfoDataV1 {
+struct __attribute__((__packed__)) CrashInfoDataDynamic : public CrashInfoDataStatic {
   uintptr_t fdsan_table_address;
-};
-
-struct __attribute__((__packed__)) CrashInfoDataV3 : public CrashInfoDataV2 {
   uintptr_t gwp_asan_state;
   uintptr_t gwp_asan_metadata;
 };
@@ -103,8 +100,7 @@
 struct __attribute__((__packed__)) CrashInfo {
   CrashInfoHeader header;
   union {
-    CrashInfoDataV1 v1;
-    CrashInfoDataV2 v2;
-    CrashInfoDataV3 v3;
+    CrashInfoDataStatic s;
+    CrashInfoDataDynamic d;
   } data;
 };
diff --git a/diagnose_usb/Android.bp b/diagnose_usb/Android.bp
index 6bee28c..93d13bd 100644
--- a/diagnose_usb/Android.bp
+++ b/diagnose_usb/Android.bp
@@ -3,6 +3,11 @@
     cflags: ["-Wall", "-Wextra", "-Werror"],
     host_supported: true,
     recovery_available: true,
+    apex_available: [
+        "com.android.adbd",
+        // TODO(b/151398197) remove the below
+        "//apex_available:platform",
+    ],
     target: {
         windows: {
             enabled: true,
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index 7e7e507..fd6ff8e 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -135,7 +135,9 @@
         return -EOVERFLOW;
     }
     WipeOverlayfsForPartition(device, partition_name);
-    return FlashBlockDevice(handle.fd(), data);
+    int result = FlashBlockDevice(handle.fd(), data);
+    sync();
+    return result;
 }
 
 bool UpdateSuper(FastbootDevice* device, const std::string& super_name, bool wipe) {
@@ -165,6 +167,7 @@
             return device->WriteFail("Unable to flash new partition table");
         }
         fs_mgr_overlayfs_teardown();
+        sync();
         return device->WriteOkay("Successfully flashed partition table");
     }
 
@@ -204,5 +207,6 @@
         return device->WriteFail("Unable to write new partition table");
     }
     fs_mgr_overlayfs_teardown();
+    sync();
     return device->WriteOkay("Successfully updated partition table");
 }
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index d9167e7..e7f785b 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -261,6 +261,10 @@
     GTEST_LOG_(INFO) << "Flashing a logical partition..";
     EXPECT_EQ(fb->FlashPartition(test_partition_name, buf), SUCCESS)
             << "flash logical -partition failed";
+
+    GTEST_LOG_(INFO) << "Testing 'fastboot delete-logical-partition' command";
+    EXPECT_EQ(fb->DeletePartition(test_partition_name), SUCCESS)
+            << "delete logical-partition failed";
 }
 
 // Conformance tests
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 12aa1f0..7b7a93f 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -581,9 +581,8 @@
 
     // requires to give last_fsck_time to current to avoid insane time.
     // otherwise, tune2fs won't enable metadata_csum.
-    std::string now = std::to_string(time(0));
     const char* tune2fs_args[] = {TUNE2FS_BIN, "-O",        "metadata_csum,64bit,extent",
-                                  "-T",        now.c_str(), blk_device.c_str()};
+                                  "-T",        "now", blk_device.c_str()};
     const char* resize2fs_args[] = {RESIZE2FS_BIN, "-b", blk_device.c_str()};
 
     if (!run_command(tune2fs_args, ARRAY_SIZE(tune2fs_args))) {
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 910c4fc..0499e8d 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -84,17 +84,21 @@
 }
 
 cc_fuzz {
-  name: "dm_linear_table_fuzzer",
-  defaults: ["fs_mgr_defaults"],
-  srcs: [
-    "dm_linear_fuzzer.cpp",
-    "test_util.cpp",
-  ],
-  static_libs: [
+    name: "dm_linear_table_fuzzer",
+    defaults: ["fs_mgr_defaults"],
+    srcs: [
+        "dm_linear_fuzzer.cpp",
+        "test_util.cpp",
+    ],
+    static_libs: [
         "libdm",
         "libbase",
         "libext2_uuid",
         "libfs_mgr",
         "liblog",
-  ],
+    ],
+}
+
+vts_config {
+    name: "VtsKernelLibdmTest",
 }
diff --git a/fs_mgr/libdm/Android.mk b/fs_mgr/libdm/Android.mk
deleted file mode 100644
index 6aedc25..0000000
--- a/fs_mgr/libdm/Android.mk
+++ /dev/null
@@ -1,22 +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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := VtsKernelLibdmTest
--include test/vts/tools/build/Android.host_config.mk
diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp
index 2fd463c..ac589c7 100644
--- a/fs_mgr/libfiemap/Android.bp
+++ b/fs_mgr/libfiemap/Android.bp
@@ -45,6 +45,7 @@
     whole_static_libs: [
         "gsi_aidl_interface-cpp",
         "libgsi",
+        "libgsid",
     ],
     shared_libs: [
         "libbinder",
diff --git a/fs_mgr/libfiemap/binder.cpp b/fs_mgr/libfiemap/binder.cpp
index 5e29d4e..c8516ab 100644
--- a/fs_mgr/libfiemap/binder.cpp
+++ b/fs_mgr/libfiemap/binder.cpp
@@ -19,9 +19,9 @@
 #include <android-base/properties.h>
 #include <android/gsi/BnProgressCallback.h>
 #include <android/gsi/IGsiService.h>
-#include <binder/IServiceManager.h>
 #include <libfiemap/image_manager.h>
 #include <libgsi/libgsi.h>
+#include <libgsi/libgsid.h>
 
 namespace android {
 namespace fiemap {
@@ -224,19 +224,9 @@
     return false;
 }
 
-static sp<IGsiService> GetGsiService() {
-    auto sm = android::defaultServiceManager();
-    auto name = android::String16(kGsiServiceName);
-    android::sp<android::IBinder> res = sm->waitForService(name);
-    if (res) {
-        return android::interface_cast<IGsiService>(res);
-    }
-    return nullptr;
-}
-
 std::unique_ptr<IImageManager> IImageManager::Open(
         const std::string& dir, const std::chrono::milliseconds& /*timeout_ms*/) {
-    android::sp<IGsiService> service = GetGsiService();
+    android::sp<IGsiService> service = android::gsi::GetGsiService();
     android::sp<IImageService> manager;
 
     auto status = service->openImageService(dir, &manager);
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index ea0fca8..ad19f38 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -108,3 +108,6 @@
     defaults: ["liblp_test_defaults"],
 }
 
+vts_config {
+    name: "VtsKernelLiblpTest",
+}
diff --git a/fs_mgr/liblp/Android.mk b/fs_mgr/liblp/Android.mk
deleted file mode 100644
index 7f7f891..0000000
--- a/fs_mgr/liblp/Android.mk
+++ /dev/null
@@ -1,22 +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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := VtsKernelLiblpTest
--include test/vts/tools/build/Android.host_config.mk
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index e4d92ca..0b1e522 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -124,7 +124,7 @@
 }
 
 bool WriteToImageFile(const std::string& file, const LpMetadata& input) {
-    unique_fd fd(open(file.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644));
+    unique_fd fd(open(file.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_BINARY, 0644));
     if (fd < 0) {
         PERROR << __PRETTY_FUNCTION__ << " open failed: " << file;
         return false;
@@ -184,7 +184,7 @@
 }
 
 bool ImageBuilder::Export(const std::string& file) {
-    unique_fd fd(open(file.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644));
+    unique_fd fd(open(file.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_BINARY, 0644));
     if (fd < 0) {
         PERROR << "open failed: " << file;
         return false;
@@ -208,7 +208,7 @@
         std::string file_name = "super_" + name + ".img";
         std::string file_path = output_dir + "/" + file_name;
 
-        static const int kOpenFlags = O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_NOFOLLOW;
+        static const int kOpenFlags = O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
         unique_fd fd(open(file_path.c_str(), kOpenFlags, 0644));
         if (fd < 0) {
             PERROR << "open failed: " << file_path;
@@ -443,7 +443,7 @@
 }
 
 int ImageBuilder::OpenImageFile(const std::string& file) {
-    android::base::unique_fd source_fd = GetControlFileOrOpen(file.c_str(), O_RDONLY | O_CLOEXEC);
+    unique_fd source_fd = GetControlFileOrOpen(file.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY);
     if (source_fd < 0) {
         PERROR << "open image file failed: " << file;
         return -1;
diff --git a/fs_mgr/tests/Android.bp b/fs_mgr/tests/Android.bp
index 4f6ec5a..28dee88 100644
--- a/fs_mgr/tests/Android.bp
+++ b/fs_mgr/tests/Android.bp
@@ -18,6 +18,7 @@
         "cts",
         "device-tests",
         "vts",
+        "vts10",
     ],
     compile_multilib: "both",
     multilib: {
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index 1d65b1c..c81a80e 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -159,8 +159,8 @@
 
 #define GK_ERROR *gkResponse = GKResponse::error(), Status::ok()
 
-    Status enroll(int32_t uid, const std::unique_ptr<std::vector<uint8_t>>& currentPasswordHandle,
-                  const std::unique_ptr<std::vector<uint8_t>>& currentPassword,
+    Status enroll(int32_t uid, const std::optional<std::vector<uint8_t>>& currentPasswordHandle,
+                  const std::optional<std::vector<uint8_t>>& currentPassword,
                   const std::vector<uint8_t>& desiredPassword, GKResponse* gkResponse) override {
         IPCThreadState* ipc = IPCThreadState::self();
         const int calling_pid = ipc->getCallingPid();
diff --git a/init/Android.bp b/init/Android.bp
index 9053c39..d512a4e 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -259,6 +259,7 @@
         "cts",
         "device-tests",
         "vts",
+        "vts10",
     ],
 }
 
diff --git a/init/init.cpp b/init/init.cpp
index cadd5c5..a9d6301 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -46,6 +46,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <backtrace/Backtrace.h>
 #include <fs_avb/fs_avb.h>
 #include <fs_mgr_vendor_overlay.h>
 #include <keyutils.h>
@@ -215,6 +216,16 @@
     prop_waiter_state.ResetWaitForProp();
 }
 
+static void UnwindMainThreadStack() {
+    std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, 1));
+    if (!backtrace->Unwind(0)) {
+        LOG(ERROR) << __FUNCTION__ << ": Failed to unwind callstack.";
+    }
+    for (size_t i = 0; i < backtrace->NumFrames(); i++) {
+        LOG(ERROR) << backtrace->FormatFrameData(i);
+    }
+}
+
 static class ShutdownState {
   public:
     void TriggerShutdown(const std::string& command) {
@@ -238,12 +249,27 @@
         return {};
     }
 
+    bool do_shutdown() const { return do_shutdown_; }
+
   private:
     std::mutex shutdown_command_lock_;
     std::string shutdown_command_;
     bool do_shutdown_ = false;
 } shutdown_state;
 
+void DebugRebootLogging() {
+    LOG(INFO) << "do_shutdown: " << shutdown_state.do_shutdown()
+              << " IsShuttingDown: " << IsShuttingDown();
+    if (shutdown_state.do_shutdown()) {
+        LOG(ERROR) << "sys.powerctl set while a previous shutdown command has not been handled";
+        UnwindMainThreadStack();
+    }
+    if (IsShuttingDown()) {
+        LOG(ERROR) << "sys.powerctl set while init is already shutting down";
+        UnwindMainThreadStack();
+    }
+}
+
 void DumpState() {
     ServiceList::GetInstance().DumpState();
     ActionManager::GetInstance().DumpState();
@@ -845,6 +871,8 @@
 
         auto shutdown_command = shutdown_state.CheckShutdown();
         if (shutdown_command) {
+            LOG(INFO) << "Got shutdown_command '" << *shutdown_command
+                      << "' Calling HandlePowerctlMessage()";
             HandlePowerctlMessage(*shutdown_command);
         }
 
diff --git a/init/init.h b/init/init.h
index 27f64e2..4f686cb 100644
--- a/init/init.h
+++ b/init/init.h
@@ -42,6 +42,8 @@
 void PropertyChanged(const std::string& name, const std::string& value);
 bool QueueControlMessage(const std::string& message, const std::string& name, pid_t pid, int fd);
 
+void DebugRebootLogging();
+
 int SecondStageMain(int argc, char** argv);
 
 }  // namespace init
diff --git a/init/property_service.cpp b/init/property_service.cpp
index a5fea7c..842b2e5 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -47,6 +47,7 @@
 #include <thread>
 #include <vector>
 
+#include <InitProperties.sysprop.h>
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -85,6 +86,7 @@
 using android::properties::ParsePropertyInfoFile;
 using android::properties::PropertyInfoAreaFile;
 using android::properties::PropertyInfoEntry;
+using android::sysprop::InitProperties::is_userspace_reboot_supported;
 
 namespace android {
 namespace init {
@@ -489,6 +491,13 @@
         }
         LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
                   << process_log_string;
+        if (!value.empty()) {
+            DebugRebootLogging();
+        }
+        if (value == "reboot,userspace" && !is_userspace_reboot_supported().value_or(false)) {
+            *error = "Userspace reboot is not supported by this device";
+            return PROP_ERROR_INVALID_VALUE;
+        }
     }
 
     // If a process other than init is writing a non-empty value, it means that process is
diff --git a/init/property_service_test.cpp b/init/property_service_test.cpp
index 0f4cd0d..c6dcfa2 100644
--- a/init/property_service_test.cpp
+++ b/init/property_service_test.cpp
@@ -22,8 +22,10 @@
 #include <sys/_system_properties.h>
 
 #include <android-base/properties.h>
+#include <android-base/scopeguard.h>
 #include <gtest/gtest.h>
 
+using android::base::GetProperty;
 using android::base::SetProperty;
 
 namespace android {
@@ -74,5 +76,19 @@
     EXPECT_TRUE(SetProperty("property_service_utf8_test", "\xF0\x90\x80\x80"));
 }
 
+TEST(property_service, userspace_reboot_not_supported) {
+    if (getuid() != 0) {
+        GTEST_SKIP() << "Skipping test, must be run as root.";
+        return;
+    }
+    const std::string original_value = GetProperty("init.userspace_reboot.is_supported", "");
+    auto guard = android::base::make_scope_guard([&original_value]() {
+        SetProperty("init.userspace_reboot.is_supported", original_value);
+    });
+
+    ASSERT_TRUE(SetProperty("init.userspace_reboot.is_supported", "false"));
+    EXPECT_FALSE(SetProperty("sys.powerctl", "reboot,userspace"));
+}
+
 }  // namespace init
 }  // namespace android
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 081f695..d2dc6d3 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -102,7 +102,15 @@
     if (write_to_property) {
         SetProperty(LAST_REBOOT_REASON_PROPERTY, reason);
     }
-    WriteStringToFile(reason, LAST_REBOOT_REASON_FILE);
+    auto fd = unique_fd(TEMP_FAILURE_RETRY(open(
+            LAST_REBOOT_REASON_FILE, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY, 0666)));
+    if (!fd.ok()) {
+        PLOG(ERROR) << "Could not open '" << LAST_REBOOT_REASON_FILE
+                    << "' to persist reboot reason";
+        return;
+    }
+    WriteStringToFd(reason, fd);
+    fsync(fd.get());
 }
 
 // represents umount status during reboot / shutdown.
@@ -317,9 +325,9 @@
                          bool* reboot_monitor_run) {
     unsigned int remaining_shutdown_time = 0;
 
-    // 30 seconds more than the timeout passed to the thread as there is a final Umount pass
+    // 300 seconds more than the timeout passed to the thread as there is a final Umount pass
     // after the timeout is reached.
-    constexpr unsigned int shutdown_watchdog_timeout_default = 30;
+    constexpr unsigned int shutdown_watchdog_timeout_default = 300;
     auto shutdown_watchdog_timeout = android::base::GetUintProperty(
             "ro.build.shutdown.watchdog.timeout", shutdown_watchdog_timeout_default);
     remaining_shutdown_time = shutdown_watchdog_timeout + shutdown_timeout.count() / 1000;
@@ -539,26 +547,6 @@
     Timer t;
     LOG(INFO) << "Reboot start, reason: " << reason << ", reboot_target: " << reboot_target;
 
-    // Ensure last reboot reason is reduced to canonical
-    // alias reported in bootloader or system boot reason.
-    size_t skip = 0;
-    std::vector<std::string> reasons = Split(reason, ",");
-    if (reasons.size() >= 2 && reasons[0] == "reboot" &&
-        (reasons[1] == "recovery" || reasons[1] == "bootloader" || reasons[1] == "cold" ||
-         reasons[1] == "hard" || reasons[1] == "warm")) {
-        skip = strlen("reboot,");
-    }
-    PersistRebootReason(reason.c_str() + skip, true);
-    sync();
-
-    // If /data isn't mounted then we can skip the extra reboot steps below, since we don't need to
-    // worry about unmounting it.
-    if (!IsDataMounted()) {
-        sync();
-        RebootSystem(cmd, reboot_target);
-        abort();
-    }
-
     bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF;
 
     auto shutdown_timeout = 0ms;
@@ -591,6 +579,25 @@
     // Start reboot monitor thread
     sem_post(&reboot_semaphore);
 
+    // Ensure last reboot reason is reduced to canonical
+    // alias reported in bootloader or system boot reason.
+    size_t skip = 0;
+    std::vector<std::string> reasons = Split(reason, ",");
+    if (reasons.size() >= 2 && reasons[0] == "reboot" &&
+        (reasons[1] == "recovery" || reasons[1] == "bootloader" || reasons[1] == "cold" ||
+         reasons[1] == "hard" || reasons[1] == "warm")) {
+        skip = strlen("reboot,");
+    }
+    PersistRebootReason(reason.c_str() + skip, true);
+
+    // If /data isn't mounted then we can skip the extra reboot steps below, since we don't need to
+    // worry about unmounting it.
+    if (!IsDataMounted()) {
+        sync();
+        RebootSystem(cmd, reboot_target);
+        abort();
+    }
+
     // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
     const std::set<std::string> to_starts{"watchdogd"};
     std::vector<Service*> stop_first;
diff --git a/init/security.cpp b/init/security.cpp
index 6cbe642..2450d65 100644
--- a/init/security.cpp
+++ b/init/security.cpp
@@ -128,8 +128,7 @@
 #define MMAP_RND_PATH "/proc/sys/vm/mmap_rnd_bits"
 #define MMAP_RND_COMPAT_PATH "/proc/sys/vm/mmap_rnd_compat_bits"
 
-// __attribute__((unused)) due to lack of mips support: see mips block in SetMmapRndBitsAction
-static bool __attribute__((unused)) SetMmapRndBitsMin(int start, int min, bool compat) {
+static bool SetMmapRndBitsMin(int start, int min, bool compat) {
     std::string path;
     if (compat) {
         path = MMAP_RND_COMPAT_PATH;
@@ -174,9 +173,6 @@
     if (SetMmapRndBitsMin(16, 16, h64)) {
         return {};
     }
-#elif defined(__mips__) || defined(__mips64__)
-    // TODO: add mips support b/27788820
-    return {};
 #else
     LOG(ERROR) << "Unknown architecture";
 #endif
diff --git a/init/test_kill_services/Android.bp b/init/test_kill_services/Android.bp
new file mode 100644
index 0000000..f6e85e2
--- /dev/null
+++ b/init/test_kill_services/Android.bp
@@ -0,0 +1,7 @@
+cc_test {
+    name: "init_kill_services_test",
+    srcs: ["init_kill_services_test.cpp"],
+    shared_libs: ["libbase"],
+    test_suites: ["general-tests"],
+    require_root: true,
+}
diff --git a/init/test_kill_services/init_kill_services_test.cpp b/init/test_kill_services/init_kill_services_test.cpp
new file mode 100644
index 0000000..7e543f2
--- /dev/null
+++ b/init/test_kill_services/init_kill_services_test.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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 <android-base/properties.h>
+
+#include <iostream>
+
+using ::android::base::GetProperty;
+using ::android::base::SetProperty;
+
+void ExpectKillingServiceRecovers(const std::string& service_name) {
+    const std::string status_prop = "init.svc." + service_name;
+    const std::string pid_prop = "init.svc_debug_pid." + service_name;
+
+    const std::string initial_pid = GetProperty(pid_prop, "");
+
+    EXPECT_EQ("running", GetProperty(status_prop, "")) << status_prop;
+    EXPECT_NE("", initial_pid) << pid_prop;
+
+    EXPECT_EQ(0, system(("kill -9 " + initial_pid).c_str()));
+
+    constexpr size_t kMaxWaitMilliseconds = 10000;
+    constexpr size_t kRetryWaitMilliseconds = 100;
+
+    constexpr size_t kRetryTimes = kMaxWaitMilliseconds / kRetryWaitMilliseconds;
+
+    for (size_t retry = 0; retry < kRetryTimes; retry++) {
+        const std::string& pid = GetProperty(pid_prop, "");
+        if (pid != initial_pid && pid != "") break;
+        usleep(kRetryWaitMilliseconds * 1000);
+    }
+
+    // svc_debug_pid is set after svc property
+    EXPECT_EQ("running", GetProperty(status_prop, ""));
+}
+
+class InitKillServicesTest : public ::testing::TestWithParam<std::string> {};
+
+TEST_P(InitKillServicesTest, KillCriticalProcesses) {
+    ExpectKillingServiceRecovers(GetParam());
+
+    // sanity check init is still responding
+    EXPECT_TRUE(SetProperty("test.death.test", "asdf"));
+    EXPECT_EQ(GetProperty("test.death.test", ""), "asdf");
+    EXPECT_TRUE(SetProperty("test.death.test", ""));
+}
+
+static inline std::string PrintName(const testing::TestParamInfo<std::string>& info) {
+    return info.param;
+}
+
+INSTANTIATE_TEST_CASE_P(DeathTest, InitKillServicesTest,
+                        ::testing::Values("lmkd", "ueventd", "hwservicemanager", "servicemanager"),
+                        PrintName);
diff --git a/libasyncio/Android.bp b/libasyncio/Android.bp
index 4ab439d..44e7933 100644
--- a/libasyncio/Android.bp
+++ b/libasyncio/Android.bp
@@ -28,6 +28,10 @@
     defaults: ["libasyncio_defaults"],
     vendor_available: true,
     recovery_available: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.adbd",
+    ],
     host_supported: true,
     srcs: [
         "AsyncIO.cpp",
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index aa18c42..dc989a0 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -44,6 +44,10 @@
     recovery_available: true,
     native_bridge_supported: true,
     export_include_dirs: ["include"],
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
 }
 
 cc_defaults {
@@ -92,6 +96,10 @@
     name: "libbacktrace",
     vendor_available: false,
     recovery_available: true,
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
     vndk: {
         enabled: true,
         support_system_process: true,
diff --git a/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp
index e47560f..d7175e0 100644
--- a/libcrypto_utils/Android.bp
+++ b/libcrypto_utils/Android.bp
@@ -38,4 +38,8 @@
             enabled: true,
         },
     },
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.adbd",
+    ],
 }
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index fc06c1d..ffe236c 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -29,6 +29,10 @@
     vendor_available: true,
     recovery_available: true,
     host_supported: true,
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
     native_bridge_supported: true,
     export_include_dirs: ["include"],
     target: {
@@ -134,6 +138,10 @@
     },
     recovery_available: true,
     host_supported: true,
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
     native_bridge_supported: true,
     srcs: [
         "config_utils.cpp",
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 8410370..0b98e1a 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -38,6 +38,10 @@
     vendor_available: true,
     ramdisk_available: true,
     recovery_available: true,
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
     native_bridge_supported: true,
     export_include_dirs: ["include"],
     system_shared_libs: [],
diff --git a/liblog/README.md b/liblog/README.md
index 871399a..f64f376 100644
--- a/liblog/README.md
+++ b/liblog/README.md
@@ -118,10 +118,9 @@
 finally a call closing the logs.  A single log can be opened with `android_logger_list_open()`; or
 multiple logs can be opened with `android_logger_list_alloc()`, calling in turn the
 `android_logger_open()` for each log id.  Each entry can be retrieved with
-`android_logger_list_read()`.  The log(s) can be closed with `android_logger_list_free()`.  The logs
-should be opened with an `ANDROID_LOG_RDONLY` mode.  `ANDROID_LOG_NONBLOCK` mode will report when
-the log reading is done with an `EAGAIN` error return code, otherwise the
-`android_logger_list_read()` call will block for new entries.
+`android_logger_list_read()`.  The log(s) can be closed with `android_logger_list_free()`.
+`ANDROID_LOG_NONBLOCK` mode will report when the log reading is done with an `EAGAIN` error return 
+code, otherwise the `android_logger_list_read()` call will block for new entries.
 
 The `ANDROID_LOG_WRAP` mode flag to the `android_logger_list_alloc_time()` signals logd to quiesce
 the reader until the buffer is about to prune at the start time then proceed to dumping content.
@@ -130,14 +129,12 @@
 logs to the persistent logs from before the last reboot.
 
 The value returned by `android_logger_open()` can be used as a parameter to the
-`android_logger_clear()` function to empty the sub-log.  It is recommended to only open log
-`ANDROID_LOG_WRONLY` in that case.
+`android_logger_clear()` function to empty the sub-log.
 
 The value returned by `android_logger_open()` can be used as a parameter to the
 `android_logger_get_log_(size|readable_size|version)` to retrieve the sub-log maximum size, readable
 size and log buffer format protocol version respectively.  `android_logger_get_id()` returns the id
-that was used when opening the sub-log.  It is recommended to open the log `ANDROID_LOG_RDONLY` in
-these cases.
+that was used when opening the sub-log.
 
 Errors
 ------
diff --git a/liblog/include/log/log_read.h b/liblog/include/log/log_read.h
index 18c1c33..05ad25f 100644
--- a/liblog/include/log/log_read.h
+++ b/liblog/include/log/log_read.h
@@ -141,10 +141,6 @@
                                       char* buf, size_t len);
 int android_logger_set_prune_list(struct logger_list* logger_list, const char* buf, size_t len);
 
-#define ANDROID_LOG_RDONLY O_RDONLY
-#define ANDROID_LOG_WRONLY O_WRONLY
-#define ANDROID_LOG_RDWR O_RDWR
-#define ANDROID_LOG_ACCMODE O_ACCMODE
 #ifndef O_NONBLOCK
 #define ANDROID_LOG_NONBLOCK 0x00000800
 #else
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
index 6ca1a16..161fcf1 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -1,6 +1,6 @@
 LIBLOG {
   global:
-    android_name_to_log_id; # llndk
+    android_name_to_log_id; # apex llndk
     android_log_id_to_name; # llndk
     __android_log_assert;
     __android_log_buf_print;
@@ -22,7 +22,7 @@
     android_logger_list_alloc; # apex llndk
     android_logger_list_alloc_time; # apex llndk
     android_logger_list_free; # apex llndk
-    android_logger_list_open; # llndk
+    android_logger_list_open; # apex llndk
     android_logger_list_read; # apex llndk
     android_logger_open; # apex llndk
     android_logger_set_log_size; # llndk
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index 7c78ea1..c174b85 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -346,7 +346,7 @@
     return 0;
   }
 
-  char buf[LOG_BUF_SIZE];
+  __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
 
   vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
 
@@ -364,7 +364,7 @@
   }
 
   va_list ap;
-  char buf[LOG_BUF_SIZE];
+  __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
 
   va_start(ap, fmt);
   vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
@@ -384,7 +384,7 @@
   }
 
   va_list ap;
-  char buf[LOG_BUF_SIZE];
+  __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
 
   va_start(ap, fmt);
   vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
@@ -397,7 +397,7 @@
 }
 
 void __android_log_assert(const char* cond, const char* tag, const char* fmt, ...) {
-  char buf[LOG_BUF_SIZE];
+  __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
 
   if (fmt) {
     va_list ap;
diff --git a/liblog/pmsg_reader.cpp b/liblog/pmsg_reader.cpp
index 64a92b7..129d767 100644
--- a/liblog/pmsg_reader.cpp
+++ b/liblog/pmsg_reader.cpp
@@ -185,7 +185,7 @@
   /* Add just enough clues in logger_list and transp to make API function */
   memset(&logger_list, 0, sizeof(logger_list));
 
-  logger_list.mode = ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK | ANDROID_LOG_RDONLY;
+  logger_list.mode = ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK;
   logger_list.log_mask = (unsigned)-1;
   if (logId != LOG_ID_ANY) {
     logger_list.log_mask = (1 << logId);
diff --git a/liblog/tests/Android.bp b/liblog/tests/Android.bp
index b4bb77f..fffb809 100644
--- a/liblog/tests/Android.bp
+++ b/liblog/tests/Android.bp
@@ -97,6 +97,7 @@
     test_suites: [
         "cts",
         "vts",
+        "vts10",
     ],
 }
 
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_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 39ac7a5..3a6ed90 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -27,6 +27,7 @@
 #include <unordered_set>
 
 #include <android-base/file.h>
+#include <android-base/properties.h>
 #include <benchmark/benchmark.h>
 #include <cutils/sockets.h>
 #include <log/event_tag_map.h>
@@ -647,8 +648,7 @@
 static void BM_log_latency(benchmark::State& state) {
   pid_t pid = getpid();
 
-  struct logger_list* logger_list =
-      android_logger_list_open(LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 0, pid);
+  struct logger_list* logger_list = android_logger_list_open(LOG_ID_EVENTS, 0, 0, pid);
 
   if (!logger_list) {
     fprintf(stderr, "Unable to open events log: %s\n", strerror(errno));
@@ -722,8 +722,7 @@
 static void BM_log_delay(benchmark::State& state) {
   pid_t pid = getpid();
 
-  struct logger_list* logger_list =
-      android_logger_list_open(LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 0, pid);
+  struct logger_list* logger_list = android_logger_list_open(LOG_ID_EVENTS, 0, 0, pid);
 
   if (!logger_list) {
     fprintf(stderr, "Unable to open events log: %s\n", strerror(errno));
@@ -1025,3 +1024,14 @@
   }
 }
 BENCHMARK(BM_lookupEventTagNum_logd_existing);
+
+static void BM_log_verbose_overhead(benchmark::State& state) {
+  std::string test_log_tag = "liblog_verbose_tag";
+  android::base::SetProperty("log.tag." + test_log_tag, "I");
+  for (auto _ : state) {
+    __android_log_print(ANDROID_LOG_VERBOSE, test_log_tag.c_str(), "%s test log message %d %d",
+                        "test test", 123, 456);
+  }
+  android::base::SetProperty("log.tag." + test_log_tag, "");
+}
+BENCHMARK(BM_log_verbose_overhead);
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index a60d2df..a031531 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -82,7 +82,7 @@
   pid_t pid = getpid();
 
   auto logger_list = std::unique_ptr<struct logger_list, ListCloser>{
-      android_logger_list_open(log_buffer, ANDROID_LOG_RDONLY, 1000, pid)};
+      android_logger_list_open(log_buffer, 0, 1000, pid)};
   ASSERT_TRUE(logger_list);
 
   write_messages();
@@ -106,7 +106,7 @@
   }
 
   auto logger_list_non_block = std::unique_ptr<struct logger_list, ListCloser>{
-      android_logger_list_open(log_buffer, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)};
+      android_logger_list_open(log_buffer, ANDROID_LOG_NONBLOCK, 1000, pid)};
   ASSERT_TRUE(logger_list_non_block);
 
   size_t count = 0;
@@ -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);
     }
@@ -572,8 +572,7 @@
 
   v += pid & 0xFFFF;
 
-  ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-                           LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 1000, pid)));
+  ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(LOG_ID_EVENTS, 0, 1000, pid)));
 
   int count = 0;
 
@@ -728,8 +727,7 @@
 
   v += pid & 0xFFFF;
 
-  ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-                           LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 1000, pid)));
+  ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(LOG_ID_EVENTS, 0, 1000, pid)));
 
   int count = 0;
 
@@ -1093,11 +1091,11 @@
   pid_t pid = getpid();
 
   auto logger_list1 = std::unique_ptr<struct logger_list, ListCloser>{
-      android_logger_list_open(LOG_ID_MAIN, ANDROID_LOG_RDONLY, expected_count1, pid)};
+      android_logger_list_open(LOG_ID_MAIN, 0, expected_count1, pid)};
   ASSERT_TRUE(logger_list1);
 
   auto logger_list2 = std::unique_ptr<struct logger_list, ListCloser>{
-      android_logger_list_open(LOG_ID_MAIN, ANDROID_LOG_RDONLY, expected_count2, pid)};
+      android_logger_list_open(LOG_ID_MAIN, 0, expected_count2, pid)};
   ASSERT_TRUE(logger_list2);
 
   for (int i = 25; i > 0; --i) {
@@ -1128,14 +1126,12 @@
   }
 
   // Test again with the nonblocking reader.
-  auto logger_list_non_block1 =
-      std::unique_ptr<struct logger_list, ListCloser>{android_logger_list_open(
-          LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, expected_count1, pid)};
+  auto logger_list_non_block1 = std::unique_ptr<struct logger_list, ListCloser>{
+      android_logger_list_open(LOG_ID_MAIN, ANDROID_LOG_NONBLOCK, expected_count1, pid)};
   ASSERT_TRUE(logger_list_non_block1);
 
-  auto logger_list_non_block2 =
-      std::unique_ptr<struct logger_list, ListCloser>{android_logger_list_open(
-          LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, expected_count2, pid)};
+  auto logger_list_non_block2 = std::unique_ptr<struct logger_list, ListCloser>{
+      android_logger_list_open(LOG_ID_MAIN, ANDROID_LOG_NONBLOCK, expected_count2, pid)};
   ASSERT_TRUE(logger_list_non_block2);
   count1 = 0;
   count2 = 0;
@@ -1542,8 +1538,8 @@
 
   pid_t pid = getpid();
 
-  struct logger_list* logger_list = android_logger_list_open(
-      LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid);
+  struct logger_list* logger_list =
+      android_logger_list_open(LOG_ID_EVENTS, ANDROID_LOG_NONBLOCK, 1000, pid);
 
   int count = 0;
   if (logger_list == NULL) return count;
@@ -1832,10 +1828,8 @@
   gid = getgid();
   pid_t pid = getpid();
 
-  ASSERT_TRUE(NULL !=
-              (logger_list = android_logger_list_open(
-                   LOG_ID_SECURITY, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
-                   1000, pid)));
+  ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(LOG_ID_SECURITY, ANDROID_LOG_NONBLOCK,
+                                                              1000, pid)));
 
   log_time ts(CLOCK_MONOTONIC);
 
diff --git a/liblog/tests/log_read_test.cpp b/liblog/tests/log_read_test.cpp
index 1be99aa..3e09617 100644
--- a/liblog/tests/log_read_test.cpp
+++ b/liblog/tests/log_read_test.cpp
@@ -34,8 +34,7 @@
   // This test assumes the log buffers are filled with noise from
   // normal operations. It will fail if done immediately after a
   // logcat -c.
-  struct logger_list* logger_list =
-      android_logger_list_alloc(ANDROID_LOG_WRONLY, 0, 0);
+  struct logger_list* logger_list = android_logger_list_alloc(0, 0, 0);
 
   for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
     log_id_t id = static_cast<log_id_t>(i);
diff --git a/liblog/tests/log_wrap_test.cpp b/liblog/tests/log_wrap_test.cpp
index e06964f..755898a 100644
--- a/liblog/tests/log_wrap_test.cpp
+++ b/liblog/tests/log_wrap_test.cpp
@@ -32,7 +32,7 @@
 static void read_with_wrap() {
   // Read the last line in the log to get a starting timestamp. We're assuming
   // the log is not empty.
-  const int mode = ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
+  const int mode = ANDROID_LOG_NONBLOCK;
   struct logger_list* logger_list =
       android_logger_list_open(LOG_ID_MAIN, mode, 1000, 0);
 
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index 618a5c5..69533d7 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -23,6 +23,10 @@
         "task_profiles.cpp",
     ],
     name: "libprocessgroup",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.os.statsd",
+    ],
     host_supported: true,
     native_bridge_supported: true,
     recovery_available: true,
diff --git a/libprocessgroup/profiles/Android.bp b/libprocessgroup/profiles/Android.bp
index e05a690..12474f1 100644
--- a/libprocessgroup/profiles/Android.bp
+++ b/libprocessgroup/profiles/Android.bp
@@ -106,3 +106,7 @@
         },
     },
 }
+
+vts_config {
+    name: "VtsProcessgroupValidateTest",
+}
diff --git a/libprocessgroup/profiles/Android.mk b/libprocessgroup/profiles/Android.mk
deleted file mode 100644
index eab96d4..0000000
--- a/libprocessgroup/profiles/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# Copyright (C) 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := VtsProcessgroupValidateTest
--include test/vts/tools/build/Android.host_config.mk
diff --git a/libsync/OWNERS b/libsync/OWNERS
index dc61733..e75b15b 100644
--- a/libsync/OWNERS
+++ b/libsync/OWNERS
@@ -1,3 +1,3 @@
-ghackmann@google.com
+chrisforbes@google.com
+hridya@google.com
 jessehall@google.com
-marissaw@google.com
diff --git a/libsystem/Android.bp b/libsystem/Android.bp
index b265b61..ff886fd 100644
--- a/libsystem/Android.bp
+++ b/libsystem/Android.bp
@@ -4,6 +4,10 @@
     recovery_available: true,
     host_supported: true,
     native_bridge_supported: true,
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
     export_include_dirs: ["include"],
 
     target: {
diff --git a/libsystem/OWNERS b/libsystem/OWNERS
index fdea804..4f800d4 100644
--- a/libsystem/OWNERS
+++ b/libsystem/OWNERS
@@ -1,7 +1,6 @@
 # graphics/composer
 adyabr@google.com
 lpy@google.com
-marissaw@google.com
 stoza@google.com
 vhau@google.com
 
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 2351afa..5efe03f 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -529,6 +529,10 @@
         free(buf);
     } else if (opthdr->nd_opt_type == ND_OPT_DNSSL) {
         // TODO: support DNSSL.
+    } else if (opthdr->nd_opt_type == ND_OPT_CAPTIVE_PORTAL) {
+        // TODO: support CAPTIVE PORTAL.
+    } else if (opthdr->nd_opt_type == ND_OPT_PREF64) {
+        // TODO: support PREF64.
     } else {
         SLOGD("Unknown ND option type %d\n", opthdr->nd_opt_type);
         return false;
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 1f3ba59..9afc9a3 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -90,12 +90,6 @@
         x86_64: {
             srcs: ["AsmGetRegsX86_64.S"],
         },
-        mips: {
-            srcs: ["AsmGetRegsMips.S"],
-        },
-        mips64: {
-            srcs: ["AsmGetRegsMips64.S"],
-        },
     },
 
     static_libs: [
diff --git a/libunwindstack/AsmGetRegsMips.S b/libunwindstack/AsmGetRegsMips.S
deleted file mode 100644
index 183d0a9..0000000
--- a/libunwindstack/AsmGetRegsMips.S
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-  .text
-  .type     AsmGetRegs, %function
-  .globl    AsmGetRegs
-  .ent      AsmGetRegs
-  .balign   16
-AsmGetRegs:
-  .cfi_startproc
-  .cfi_def_cfa $sp, 0
-  .set push
-  .set noreorder
-  .cpload $t9
-  sw   $zero, 0($a0)
-  .set noat
-  sw   $at, 4($a0)
-  .set at
-  sw   $v0, 8($a0)
-  sw   $v1, 12($a0)
-  sw   $a0, 16($a0)
-  sw   $a1, 20($a0)
-  sw   $a2, 24($a0)
-  sw   $a3, 28($a0)
-  sw   $t0, 32($a0)
-  sw   $t1, 36($a0)
-  sw   $t2, 40($a0)
-  sw   $t3, 44($a0)
-  sw   $t4, 48($a0)
-  sw   $t5, 52($a0)
-  sw   $t6, 56($a0)
-  sw   $t7, 60($a0)
-  sw   $s0, 64($a0)
-  sw   $s1, 68($a0)
-  sw   $s2, 72($a0)
-  sw   $s3, 76($a0)
-  sw   $s4, 80($a0)
-  sw   $s5, 84($a0)
-  sw   $s6, 88($a0)
-  sw   $s7, 92($a0)
-  sw   $t8, 96($a0)
-  sw   $t9, 100($a0)
-  sw   $k0, 104($a0)
-  sw   $k1, 108($a0)
-  sw   $gp, 112($a0)
-  sw   $sp, 116($a0)
-  sw   $s8, 120($a0)
-  sw   $ra, 124($a0)
-  jalr $zero, $ra
-  sw   $ra, 128($a0)   // set PC to the calling function
-
-  .set pop
-  .cfi_endproc
-  .size     AsmGetRegs, .-AsmGetRegs
-  .end      AsmGetRegs
diff --git a/libunwindstack/AsmGetRegsMips64.S b/libunwindstack/AsmGetRegsMips64.S
deleted file mode 100644
index 7a244f6..0000000
--- a/libunwindstack/AsmGetRegsMips64.S
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-  .text
-  .type     AsmGetRegs, %function
-  .globl    AsmGetRegs
-  .ent      AsmGetRegs
-  .balign    16
-AsmGetRegs:
-  .cfi_startproc
-  .cfi_def_cfa $sp, 0
-  .set push
-  .set noreorder
-  .cpload $t9
-  sd   $zero, 0($a0)
-  .set noat
-  sd   $at, 8($a0)
-  .set at
-  sd   $v0, 16($a0)
-  sd   $v1, 24($a0)
-  sd   $a0, 32($a0)
-  sd   $a1, 40($a0)
-  sd   $a2, 48($a0)
-  sd   $a3, 56($a0)
-  sd   $a4, 64($a0)
-  sd   $a5, 72($a0)
-  sd   $a6, 80($a0)
-  sd   $a7, 88($a0)
-  sd   $t0, 96($a0)
-  sd   $t1, 104($a0)
-  sd   $t2, 112($a0)
-  sd   $t3, 120($a0)
-  sd   $s0, 128($a0)
-  sd   $s1, 136($a0)
-  sd   $s2, 144($a0)
-  sd   $s3, 152($a0)
-  sd   $s4, 160($a0)
-  sd   $s5, 168($a0)
-  sd   $s6, 176($a0)
-  sd   $s7, 184($a0)
-  sd   $t8, 192($a0)
-  sd   $t9, 200($a0)
-  sd   $k0, 208($a0)
-  sd   $k1, 216($a0)
-  sd   $gp, 224($a0)
-  sd   $sp, 232($a0)
-  sd   $s8, 240($a0)
-  sd   $ra, 248($a0)
-  jalr $zero, $ra
-  sd   $ra, 256($a0)   // set PC to the calling function
-
-  .set pop
-  .cfi_endproc
-  .size AsmGetRegs, .-AsmGetRegs
-  .end      AsmGetRegs
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 341275d..821e042 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -662,7 +662,7 @@
         if (note_size - offset < hdr.n_descsz || hdr.n_descsz == 0) {
           return "";
         }
-        std::string build_id(hdr.n_descsz - 1, '\0');
+        std::string build_id(hdr.n_descsz, '\0');
         if (memory->ReadFully(note_offset + offset, &build_id[0], hdr.n_descsz)) {
           return build_id;
         }
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 c7dec52..03aa6c2 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -100,10 +100,6 @@
   return ARCH_X86;
 #elif defined(__x86_64__)
   return ARCH_X86_64;
-#elif defined(__mips__) && !defined(__LP64__)
-  return ARCH_MIPS;
-#elif defined(__mips__) && defined(__LP64__)
-  return ARCH_MIPS64;
 #else
   abort();
 #endif
@@ -119,14 +115,68 @@
   regs = new RegsX86();
 #elif defined(__x86_64__)
   regs = new RegsX86_64();
-#elif defined(__mips__) && !defined(__LP64__)
-  regs = new RegsMips();
-#elif defined(__mips__) && defined(__LP64__)
-  regs = new RegsMips64();
 #else
   abort();
 #endif
   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..2d867cd 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;
       }
@@ -395,4 +395,54 @@
   return true;
 }
 
+FrameData Unwinder::BuildFrameFromPcOnly(uint64_t pc) {
+  FrameData frame;
+
+  Maps* maps = GetMaps();
+  MapInfo* map_info = maps->Find(pc);
+  if (!map_info) {
+    frame.rel_pc = pc;
+    return frame;
+  }
+
+  ArchEnum arch = Regs::CurrentArch();
+  Elf* elf = map_info->GetElf(GetProcessMemory(), arch);
+
+  uint64_t relative_pc = elf->GetRelPc(pc, map_info);
+
+  uint64_t pc_adjustment = 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;
+
+  // If we don't have a valid ELF file, check the JIT.
+  if (!elf->valid()) {
+    JitDebug jit_debug(GetProcessMemory());
+    uint64_t jit_pc = pc - pc_adjustment;
+    Elf* jit_elf = jit_debug.GetElf(maps, jit_pc);
+    if (jit_elf != nullptr) {
+      debug_pc = jit_pc;
+      elf = jit_elf;
+    }
+  }
+
+  // Copy all the things we need into the frame for symbolization.
+  frame.rel_pc = relative_pc;
+  frame.pc = pc - pc_adjustment;
+  frame.map_name = map_info->name;
+  frame.map_elf_start_offset = map_info->elf_start_offset;
+  frame.map_exact_offset = map_info->offset;
+  frame.map_start = map_info->start;
+  frame.map_end = map_info->end;
+  frame.map_flags = map_info->flags;
+  frame.map_load_bias = elf->GetLoadBias();
+
+  if (!resolve_names_ ||
+      !elf->GetFunctionName(relative_pc, &frame.function_name, &frame.function_offset)) {
+    frame.function_name = "";
+    frame.function_offset = 0;
+  }
+  return frame;
+}
+
 }  // namespace unwindstack
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/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
index f0b5e3a..300a3ec 100644
--- a/libunwindstack/include/unwindstack/RegsGetLocal.h
+++ b/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -81,7 +81,7 @@
       : "x12", "x13", "memory");
 }
 
-#elif defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+#elif defined(__i386__) || defined(__x86_64__)
 
 extern "C" void AsmGetRegs(void* regs);
 
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/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 67762c0..4d49f23 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -114,6 +114,13 @@
   ErrorCode LastErrorCode() { return last_error_.code; }
   uint64_t LastErrorAddress() { return last_error_.address; }
 
+  // Builds a frame for symbolization using the maps from this unwinder. The
+  // constructed frame contains just enough information to be used to symbolize
+  // frames collected by frame-pointer unwinding that's done outside of
+  // libunwindstack. This is used by tombstoned to symbolize frame pointer-based
+  // stack traces that are collected by tools such as GWP-ASan and MTE.
+  FrameData BuildFrameFromPcOnly(uint64_t pc);
+
  protected:
   Unwinder(size_t max_frames) : max_frames_(max_frames) { frames_.reserve(max_frames); }
 
diff --git a/libunwindstack/tests/MapInfoGetBuildIDTest.cpp b/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
index 6953e26..70e136b 100644
--- a/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
+++ b/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
@@ -142,15 +142,14 @@
 
   char note_section[128];
   Elf32_Nhdr note_header = {};
-  note_header.n_namesz = 4;   // "GNU"
-  note_header.n_descsz = 12;  // "ELF_BUILDID"
+  note_header.n_namesz = sizeof("GNU");
+  note_header.n_descsz = sizeof("ELF_BUILDID") - 1;
   note_header.n_type = NT_GNU_BUILD_ID;
   memcpy(&note_section, &note_header, sizeof(note_header));
   size_t note_offset = sizeof(note_header);
-  memcpy(&note_section[note_offset], "GNU", sizeof("GNU"));
-  note_offset += sizeof("GNU");
-  memcpy(&note_section[note_offset], "ELF_BUILDID", sizeof("ELF_BUILDID"));
-  note_offset += sizeof("ELF_BUILDID");
+  memcpy(&note_section[note_offset], "GNU", note_header.n_namesz);
+  note_offset += note_header.n_namesz;
+  memcpy(&note_section[note_offset], "ELF_BUILDID", note_header.n_descsz);
 
   Elf32_Shdr shdr = {};
   shdr.sh_type = SHT_NOTE;
@@ -195,4 +194,10 @@
   MultipleThreadTest("ELF_BUILDID");
 }
 
+TEST_F(MapInfoGetBuildIDTest, real_elf) {
+  MapInfo map_info(nullptr, nullptr, 0x1000, 0x20000, 0, PROT_READ | PROT_WRITE,
+                   TestGetFileDirectory() + "offline/empty_arm64/libc.so");
+  EXPECT_EQ("6df0590c4920f4c7b9f34fe833f37d54", map_info.GetPrintableBuildID());
+}
+
 }  // namespace unwindstack
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_);
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 415488f..3bed0e3 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -597,6 +597,11 @@
     if (iter->curr_desc >= iter->config_end)
         return NULL;
     next = (struct usb_descriptor_header*)iter->curr_desc;
+    // Corrupt descriptor with zero length, cannot continue iterating
+    if (next->bLength == 0) {
+       D("usb_descriptor_iter_next got zero length USB descriptor, ending iteration\n");
+       return NULL;
+    }
     iter->curr_desc += next->bLength;
     return next;
 }
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 3311793..3ab619b 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -18,6 +18,10 @@
     recovery_available: true,
     host_supported: true,
     native_bridge_supported: true,
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
 
     header_libs: [
         "liblog_headers",
@@ -74,12 +78,6 @@
         "liblog",
     ],
 
-    arch: {
-        mips: {
-            cflags: ["-DALIGN_DOUBLE"],
-        },
-    },
-
     target: {
         android: {
             cflags: ["-fvisibility=protected"],
@@ -174,12 +172,6 @@
         "CallStack.cpp",
     ],
 
-    arch: {
-        mips: {
-            cflags: ["-DALIGN_DOUBLE"],
-        },
-    },
-
     shared_libs: [
          "libutils",
          "libbacktrace",
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index e2a8c59..d514f29 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -90,19 +90,6 @@
 {
 }
 
-String16::String16(StaticLinkage)
-    : mString(nullptr)
-{
-    // this constructor is used when we can't rely on the static-initializers
-    // having run. In this case we always allocate an empty string. It's less
-    // efficient than using getEmptyString(), but we assume it's uncommon.
-
-    SharedBuffer* buf = static_cast<SharedBuffer*>(alloc(sizeof(char16_t)));
-    char16_t* data = static_cast<char16_t*>(buf->data());
-    data[0] = 0;
-    mString = data;
-}
-
 String16::String16(const String16& o)
     : mString(o.mString)
 {
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index d13548e..d00e39c 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -125,19 +125,6 @@
 {
 }
 
-String8::String8(StaticLinkage)
-    : mString(nullptr)
-{
-    // this constructor is used when we can't rely on the static-initializers
-    // having run. In this case we always allocate an empty string. It's less
-    // efficient than using getEmptyString(), but we assume it's uncommon.
-
-    char* data = static_cast<char*>(
-            SharedBuffer::alloc(sizeof(char))->data());
-    data[0] = 0;
-    mString = data;
-}
-
 String8::String8(const String8& o)
     : mString(o.mString)
 {
diff --git a/libutils/StrongPointer_test.cpp b/libutils/StrongPointer_test.cpp
index 7b2e37f..d37c1de 100644
--- a/libutils/StrongPointer_test.cpp
+++ b/libutils/StrongPointer_test.cpp
@@ -36,10 +36,8 @@
 
 TEST(StrongPointer, move) {
     bool isDeleted;
-    SPFoo* foo = new SPFoo(&isDeleted);
-    ASSERT_EQ(0, foo->getStrongCount());
-    ASSERT_FALSE(isDeleted) << "Already deleted...?";
-    sp<SPFoo> sp1(foo);
+    sp<SPFoo> sp1 = sp<SPFoo>::make(&isDeleted);
+    SPFoo* foo = sp1.get();
     ASSERT_EQ(1, foo->getStrongCount());
     {
         sp<SPFoo> sp2 = std::move(sp1);
@@ -65,7 +63,7 @@
 
 TEST(StrongPointer, PointerComparison) {
     bool isDeleted;
-    sp<SPFoo> foo = new SPFoo(&isDeleted);
+    sp<SPFoo> foo = sp<SPFoo>::make(&isDeleted);
     ASSERT_EQ(foo.get(), foo);
     ASSERT_EQ(foo, foo.get());
     ASSERT_NE(nullptr, foo);
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index 89f048d..e7acd17 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -297,6 +297,11 @@
     }
 
 protected:
+    // When constructing these objects, prefer using sp::make<>. Using a RefBase
+    // object on the stack or with other refcount mechanisms (e.g.
+    // std::shared_ptr) is inherently wrong. RefBase types have an implicit
+    // ownership model and cannot be safely used with other ownership models.
+
                             RefBase();
     virtual                 ~RefBase();
     
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index c0e3f1e..1a4b47e 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -39,17 +39,7 @@
 class String16
 {
 public:
-    /*
-     * Use String16(StaticLinkage) if you're statically linking against
-     * libutils and declaring an empty static String16, e.g.:
-     *
-     *   static String16 sAStaticEmptyString(String16::kEmptyString);
-     *   static String16 sAnotherStaticEmptyString(sAStaticEmptyString);
-     */
-    enum StaticLinkage { kEmptyString };
-
                                 String16();
-    explicit                    String16(StaticLinkage);
                                 String16(const String16& o);
                                 String16(const String16& o,
                                          size_t len,
@@ -197,7 +187,7 @@
 ANDROID_TRIVIAL_MOVE_TRAIT(String16)
 
 static inline std::ostream& operator<<(std::ostream& os, const String16& str) {
-    os << String8(str).c_str();
+    os << String8(str);
     return os;
 }
 
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index 0ddcbb2..0bcb716 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -17,7 +17,8 @@
 #ifndef ANDROID_STRING8_H
 #define ANDROID_STRING8_H
 
-#include <string> // for std::string
+#include <iostream>
+#include <string>
 
 #include <utils/Errors.h>
 #include <utils/Unicode.h>
@@ -39,16 +40,7 @@
 class String8
 {
 public:
-    /* use String8(StaticLinkage) if you're statically linking against
-     * libutils and declaring an empty static String8, e.g.:
-     *
-     *   static String8 sAStaticEmptyString(String8::kEmptyString);
-     *   static String8 sAnotherStaticEmptyString(sAStaticEmptyString);
-     */
-    enum StaticLinkage { kEmptyString };
-
                                 String8();
-    explicit                    String8(StaticLinkage);
                                 String8(const String8& o);
     explicit                    String8(const char* o);
     explicit                    String8(const char* o, size_t numChars);
@@ -241,6 +233,11 @@
 // require any change to the underlying SharedBuffer contents or reference count.
 ANDROID_TRIVIAL_MOVE_TRAIT(String8)
 
+static inline std::ostream& operator<<(std::ostream& os, const String8& str) {
+    os << str.c_str();
+    return os;
+}
+
 // ---------------------------------------------------------------------------
 // No user servicable parts below.
 
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index 6f4fb47..11128f2 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -32,6 +32,12 @@
 public:
     inline sp() : m_ptr(nullptr) { }
 
+    // TODO: switch everyone to using this over new, and make RefBase operator
+    // new private to that class so that we can avoid RefBase being used with
+    // other memory management mechanisms.
+    template <typename... Args>
+    static inline sp<T> make(Args&&... args);
+
     sp(T* other);  // NOLINT(implicit)
     sp(const sp<T>& other);
     sp(sp<T>&& other) noexcept;
@@ -160,9 +166,6 @@
 // It does not appear safe to broaden this check to include adjacent pages; apparently this code
 // is used in environments where there may not be a guard page below (at higher addresses than)
 // the bottom of the stack.
-//
-// TODO: Consider adding make_sp<T>() to allocate an object and wrap the resulting pointer safely
-// without checking overhead.
 template <typename T>
 void sp<T>::check_not_on_stack(const void* ptr) {
     static constexpr int MIN_PAGE_SIZE = 0x1000;  // 4K. Safer than including sys/user.h.
@@ -174,6 +177,18 @@
     }
 }
 
+// TODO: Ideally we should find a way to increment the reference count before running the
+// constructor, so that generating an sp<> to this in the constructor is no longer dangerous.
+template <typename T>
+template <typename... Args>
+sp<T> sp<T>::make(Args&&... args) {
+    T* t = new T(std::forward<Args>(args)...);
+    sp<T> result;
+    result.m_ptr = t;
+    t->incStrong(t);  // bypass check_not_on_stack for heap allocation
+    return result;
+}
+
 template<typename T>
 sp<T>::sp(T* other)
         : m_ptr(other) {
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 1bbffaf..786e7b3 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -60,6 +60,8 @@
     srcs: [
         "zip_archive.cc",
         "zip_archive_stream_entry.cc",
+        "zip_cd_entry_map.cc",
+        "zip_error.cpp",
         "zip_writer.cc",
     ],
 
@@ -210,3 +212,20 @@
     data: ["cli-tests/**/*"],
     target_required: ["cli-test", "ziptool"],
 }
+
+python_test_host {
+    name: "ziparchive_tests_large",
+    srcs: ["test_ziparchive_large.py"],
+    main: "test_ziparchive_large.py",
+    version: {
+        py2: {
+            enabled: true,
+            embedded_launcher: false,
+        },
+        py3: {
+            enabled: false,
+            embedded_launcher: false,
+        },
+    },
+    test_suites: ["general-tests"],
+}
diff --git a/libziparchive/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
index 098a9cb..4697bb7 100644
--- a/libziparchive/include/ziparchive/zip_archive.h
+++ b/libziparchive/include/ziparchive/zip_archive.h
@@ -77,6 +77,10 @@
   // footer.
   uint32_t uncompressed_length;
 
+  // If the value of uncompressed length and compressed length are stored in
+  // the zip64 extended info of the extra field.
+  bool zip64_format_size{false};
+
   // The offset to the start of data for this ZipEntry.
   off64_t offset;
 
@@ -145,7 +149,7 @@
   /** The size in bytes of the archive itself. Used by zipinfo. */
   off64_t archive_size;
   /** The number of entries in the archive. */
-  size_t entry_count;
+  uint64_t entry_count;
 };
 
 /**
@@ -188,6 +192,15 @@
                        const std::string_view optional_suffix = "");
 
 /*
+ * Start iterating over all entries of a zip file. Use the matcher functor to
+ * restrict iteration to entry names that make the functor return true.
+ *
+ * Returns 0 on success and negative values on failure.
+ */
+int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
+                       std::function<bool(std::string_view entry_name)> matcher);
+
+/*
  * Advance to the next element in the zipfile in iteration order.
  *
  * Returns 0 on success, -1 if there are no more elements in this
diff --git a/libziparchive/test_ziparchive_large.py b/libziparchive/test_ziparchive_large.py
new file mode 100644
index 0000000..6b82f63
--- /dev/null
+++ b/libziparchive/test_ziparchive_large.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+"""Unittests for parsing files in zip64 format"""
+
+import os
+import subprocess
+import tempfile
+import unittest
+import zipfile
+import time
+
+class Zip64Test(unittest.TestCase):
+  @staticmethod
+  def _WriteFile(path, size_in_kib):
+    contents = os.path.basename(path)[0] * 1024
+    with open(path, 'w') as f:
+      for it in range(0, size_in_kib):
+        f.write(contents)
+
+  @staticmethod
+  def _AddEntriesToZip(output_zip, entries_dict=None):
+    for name, size in entries_dict.items():
+      file_path = tempfile.NamedTemporaryFile()
+      Zip64Test._WriteFile(file_path.name, size)
+      output_zip.write(file_path.name, arcname = name)
+
+  def _getEntryNames(self, zip_name):
+    cmd = ['ziptool', 'zipinfo', '-1', zip_name]
+    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    output, _ = proc.communicate()
+    self.assertEquals(0, proc.returncode)
+    self.assertNotEqual(None, output)
+    return output.split()
+
+  def _ExtractEntries(self, zip_name):
+    temp_dir = tempfile.mkdtemp()
+    cmd = ['ziptool', 'unzip', '-d', temp_dir, zip_name]
+    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    proc.communicate()
+    self.assertEquals(0, proc.returncode)
+
+  def test_entriesSmallerThan2G(self):
+    zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
+    # Add a few entries with each of them smaller than 2GiB. But the entire zip file is larger
+    # than 4GiB in size.
+    with zipfile.ZipFile(zip_path, 'w', allowZip64=True) as output_zip:
+      entry_dict = {'a.txt': 1025 * 1024, 'b.txt': 1025 * 1024, 'c.txt': 1025 * 1024,
+                    'd.txt': 1025 * 1024, 'e.txt': 1024}
+      self._AddEntriesToZip(output_zip, entry_dict)
+
+    read_names = self._getEntryNames(zip_path.name)
+    self.assertEquals(sorted(entry_dict.keys()), sorted(read_names))
+    self._ExtractEntries(zip_path.name)
+
+
+  def test_largeNumberOfEntries(self):
+    zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
+    entry_dict = {}
+    # Add 100k entries (more than 65535|UINT16_MAX).
+    for num in range(0, 100 * 1024):
+      entry_dict[str(num)] = 50
+
+    with zipfile.ZipFile(zip_path, 'w', allowZip64=True) as output_zip:
+      self._AddEntriesToZip(output_zip, entry_dict)
+
+    read_names = self._getEntryNames(zip_path.name)
+    self.assertEquals(sorted(entry_dict.keys()), sorted(read_names))
+    self._ExtractEntries(zip_path.name)
+
+
+  def test_largeCompressedEntries(self):
+    zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
+    with zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_DEFLATED,
+                         allowZip64=True) as output_zip:
+      # Add entries close to 4GiB in size. Somehow the python library will put the (un)compressed
+      # sizes in the extra field. Test if our ziptool should be able to parse it.
+      entry_dict = {'e.txt': 4095 * 1024, 'f.txt': 4095 * 1024}
+      self._AddEntriesToZip(output_zip, entry_dict)
+
+    read_names = self._getEntryNames(zip_path.name)
+    self.assertEquals(sorted(entry_dict.keys()), sorted(read_names))
+    self._ExtractEntries(zip_path.name)
+
+
+  def test_forceDataDescriptor(self):
+    file_path = tempfile.NamedTemporaryFile(suffix='.txt')
+    # TODO create the entry > 4GiB.
+    self._WriteFile(file_path.name, 1024)
+
+    zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
+    with zipfile.ZipFile(zip_path, 'w', allowZip64=True) as output_zip:
+      pass
+    # The fd option force writes a data descriptor
+    cmd = ['zip', '-fd', zip_path.name, file_path.name]
+    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    proc.communicate()
+    read_names = self._getEntryNames(zip_path.name)
+    self.assertEquals([file_path.name[1:]], read_names)
+    self._ExtractEntries(zip_path.name)
+
+if __name__ == '__main__':
+  testsuite = unittest.TestLoader().discover(
+      os.path.dirname(os.path.realpath(__file__)))
+  unittest.TextTestRunner(verbosity=2).run(testsuite)
diff --git a/libziparchive/testdata/zip64.zip b/libziparchive/testdata/zip64.zip
new file mode 100644
index 0000000..3f25a4c
--- /dev/null
+++ b/libziparchive/testdata/zip64.zip
Binary files differ
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 958c34b..031d43a 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -32,6 +32,7 @@
 #include <unistd.h>
 
 #include <memory>
+#include <optional>
 #include <vector>
 
 #if defined(__APPLE__)
@@ -56,8 +57,6 @@
 #include "zip_archive_common.h"
 #include "zip_archive_private.h"
 
-using android::base::get_unaligned;
-
 // Used to turn on crc checks - verify that the content CRC matches the values
 // specified in the local file header and the central directory.
 static const bool kCrcChecksEnabled = false;
@@ -65,6 +64,10 @@
 // The maximum number of bytes to scan backwards for the EOCD start.
 static const uint32_t kMaxEOCDSearch = kMaxCommentLen + sizeof(EocdRecord);
 
+// Set a reasonable cap (256 GiB) for the zip file size. So the data is always valid when
+// we parse the fields in cd or local headers as 64 bits signed integers.
+static constexpr uint64_t kMaxFileLength = 256 * static_cast<uint64_t>(1u << 30u);
+
 /*
  * A Read-only Zip archive.
  *
@@ -85,76 +88,6 @@
  * of the string length into the hash table entry.
  */
 
-/*
- * Round up to the next highest power of 2.
- *
- * Found on http://graphics.stanford.edu/~seander/bithacks.html.
- */
-static uint32_t RoundUpPower2(uint32_t val) {
-  val--;
-  val |= val >> 1;
-  val |= val >> 2;
-  val |= val >> 4;
-  val |= val >> 8;
-  val |= val >> 16;
-  val++;
-
-  return val;
-}
-
-static uint32_t ComputeHash(std::string_view name) {
-  return static_cast<uint32_t>(std::hash<std::string_view>{}(name));
-}
-
-/*
- * Convert a ZipEntry to a hash table index, verifying that it's in a
- * valid range.
- */
-static int64_t EntryToIndex(const ZipStringOffset* hash_table, const uint32_t hash_table_size,
-                            std::string_view name, const uint8_t* start) {
-  const uint32_t hash = ComputeHash(name);
-
-  // NOTE: (hash_table_size - 1) is guaranteed to be non-negative.
-  uint32_t ent = hash & (hash_table_size - 1);
-  while (hash_table[ent].name_offset != 0) {
-    if (hash_table[ent].ToStringView(start) == name) {
-      return ent;
-    }
-    ent = (ent + 1) & (hash_table_size - 1);
-  }
-
-  ALOGV("Zip: Unable to find entry %.*s", static_cast<int>(name.size()), name.data());
-  return kEntryNotFound;
-}
-
-/*
- * Add a new entry to the hash table.
- */
-static int32_t AddToHash(ZipStringOffset* hash_table, const uint32_t hash_table_size,
-                         std::string_view name, const uint8_t* start) {
-  const uint64_t hash = ComputeHash(name);
-  uint32_t ent = hash & (hash_table_size - 1);
-
-  /*
-   * We over-allocated the table, so we're guaranteed to find an empty slot.
-   * Further, we guarantee that the hashtable size is not 0.
-   */
-  while (hash_table[ent].name_offset != 0) {
-    if (hash_table[ent].ToStringView(start) == name) {
-      // We've found a duplicate entry. We don't accept duplicates.
-      ALOGW("Zip: Found duplicate entry %.*s", static_cast<int>(name.size()), name.data());
-      return kDuplicateEntry;
-    }
-    ent = (ent + 1) & (hash_table_size - 1);
-  }
-
-  // `name` has already been validated before entry.
-  const char* start_char = reinterpret_cast<const char*>(start);
-  hash_table[ent].name_offset = static_cast<uint32_t>(name.data() - start_char);
-  hash_table[ent].name_length = static_cast<uint16_t>(name.size());
-  return 0;
-}
-
 #if defined(__BIONIC__)
 uint64_t GetOwnerTag(const ZipArchive* archive) {
   return android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_ZIPARCHIVE,
@@ -168,9 +101,7 @@
       directory_offset(0),
       central_directory(),
       directory_map(),
-      num_entries(0),
-      hash_table_size(0),
-      hash_table(nullptr) {
+      num_entries(0) {
 #if defined(__BIONIC__)
   if (assume_ownership) {
     CHECK(mapped_zip.HasFd());
@@ -185,9 +116,7 @@
       directory_offset(0),
       central_directory(),
       directory_map(),
-      num_entries(0),
-      hash_table_size(0),
-      hash_table(nullptr) {}
+      num_entries(0) {}
 
 ZipArchive::~ZipArchive() {
   if (close_file && mapped_zip.GetFileDescriptor() >= 0) {
@@ -197,16 +126,83 @@
     close(mapped_zip.GetFileDescriptor());
 #endif
   }
-
-  free(hash_table);
 }
 
-static int32_t MapCentralDirectory0(const char* debug_file_name, ZipArchive* archive,
-                                    off64_t file_length, uint32_t read_amount,
-                                    uint8_t* scan_buffer) {
+struct CentralDirectoryInfo {
+  uint64_t num_records;
+  // The size of the central directory (in bytes).
+  uint64_t cd_size;
+  // The offset of the start of the central directory, relative
+  // to the start of the file.
+  uint64_t cd_start_offset;
+};
+
+static ZipError FindCentralDirectoryInfoForZip64(const char* debugFileName, ZipArchive* archive,
+                                                 off64_t eocdOffset, CentralDirectoryInfo* cdInfo) {
+  if (eocdOffset <= sizeof(Zip64EocdLocator)) {
+    ALOGW("Zip: %s: Not enough space for zip64 eocd locator", debugFileName);
+    return kInvalidFile;
+  }
+  // We expect to find the zip64 eocd locator immediately before the zip eocd.
+  const int64_t locatorOffset = eocdOffset - sizeof(Zip64EocdLocator);
+  Zip64EocdLocator zip64EocdLocator{};
+  if (!archive->mapped_zip.ReadAtOffset(reinterpret_cast<uint8_t*>((&zip64EocdLocator)),
+                                        sizeof(Zip64EocdLocator), locatorOffset)) {
+    ALOGW("Zip: %s: Read %zu from offset %" PRId64 " failed %s", debugFileName,
+          sizeof(Zip64EocdLocator), locatorOffset, debugFileName);
+    return kIoError;
+  }
+
+  if (zip64EocdLocator.locator_signature != Zip64EocdLocator::kSignature) {
+    ALOGW("Zip: %s: Zip64 eocd locator signature not found at offset %" PRId64, debugFileName,
+          locatorOffset);
+    return kInvalidFile;
+  }
+
+  const int64_t zip64EocdOffset = zip64EocdLocator.zip64_eocd_offset;
+  if (locatorOffset <= sizeof(Zip64EocdRecord) ||
+      zip64EocdOffset > locatorOffset - sizeof(Zip64EocdRecord)) {
+    ALOGW("Zip: %s: Bad zip64 eocd offset %" PRId64 ", eocd locator offset %" PRId64, debugFileName,
+          zip64EocdOffset, locatorOffset);
+    return kInvalidOffset;
+  }
+
+  Zip64EocdRecord zip64EocdRecord{};
+  if (!archive->mapped_zip.ReadAtOffset(reinterpret_cast<uint8_t*>(&zip64EocdRecord),
+                                        sizeof(Zip64EocdRecord), zip64EocdOffset)) {
+    ALOGW("Zip: %s: read %zu from offset %" PRId64 " failed %s", debugFileName,
+          sizeof(Zip64EocdLocator), zip64EocdOffset, debugFileName);
+    return kIoError;
+  }
+
+  if (zip64EocdRecord.record_signature != Zip64EocdRecord::kSignature) {
+    ALOGW("Zip: %s: Zip64 eocd record signature not found at offset %" PRId64, debugFileName,
+          zip64EocdOffset);
+    return kInvalidFile;
+  }
+
+  if (zip64EocdOffset <= zip64EocdRecord.cd_size ||
+      zip64EocdRecord.cd_start_offset > zip64EocdOffset - zip64EocdRecord.cd_size) {
+    ALOGW("Zip: %s: Bad offset for zip64 central directory. cd offset %" PRIu64 ", cd size %" PRIu64
+          ", zip64 eocd offset %" PRIu64,
+          debugFileName, zip64EocdRecord.cd_start_offset, zip64EocdRecord.cd_size, zip64EocdOffset);
+    return kInvalidOffset;
+  }
+
+  *cdInfo = {.num_records = zip64EocdRecord.num_records,
+             .cd_size = zip64EocdRecord.cd_size,
+             .cd_start_offset = zip64EocdRecord.cd_start_offset};
+
+  return kSuccess;
+}
+
+static ZipError FindCentralDirectoryInfo(const char* debug_file_name, ZipArchive* archive,
+                                         off64_t file_length, uint32_t read_amount,
+                                         CentralDirectoryInfo* cdInfo) {
+  std::vector<uint8_t> scan_buffer(read_amount);
   const off64_t search_start = file_length - read_amount;
 
-  if (!archive->mapped_zip.ReadAtOffset(scan_buffer, read_amount, search_start)) {
+  if (!archive->mapped_zip.ReadAtOffset(scan_buffer.data(), read_amount, search_start)) {
     ALOGE("Zip: read %" PRId64 " from offset %" PRId64 " failed", static_cast<int64_t>(read_amount),
           static_cast<int64_t>(search_start));
     return kIoError;
@@ -223,7 +219,7 @@
   for (; i >= 0; i--) {
     if (scan_buffer[i] == 0x50) {
       uint32_t* sig_addr = reinterpret_cast<uint32_t*>(&scan_buffer[i]);
-      if (get_unaligned<uint32_t>(sig_addr) == EocdRecord::kSignature) {
+      if (android::base::get_unaligned<uint32_t>(sig_addr) == EocdRecord::kSignature) {
         ALOGV("+++ Found EOCD at buf+%d", i);
         break;
       }
@@ -235,7 +231,7 @@
   }
 
   const off64_t eocd_offset = search_start + i;
-  const EocdRecord* eocd = reinterpret_cast<const EocdRecord*>(scan_buffer + i);
+  auto eocd = reinterpret_cast<const EocdRecord*>(scan_buffer.data() + i);
   /*
    * Verify that there's no trailing space at the end of the central directory
    * and its comment.
@@ -247,6 +243,13 @@
     return kInvalidFile;
   }
 
+  // One of the field is 0xFFFFFFFF, look for the zip64 EOCD instead.
+  if (eocd->cd_size == UINT32_MAX || eocd->cd_start_offset == UINT32_MAX) {
+    ALOGV("Looking for the zip64 EOCD, cd_size: %" PRIu32 "cd_start_offset: %" PRId32,
+          eocd->cd_size, eocd->cd_start_offset);
+    return FindCentralDirectoryInfoForZip64(debug_file_name, archive, eocd_offset, cdInfo);
+  }
+
   /*
    * Grab the CD offset and size, and the number of entries in the
    * archive and verify that they look reasonable.
@@ -256,47 +259,29 @@
           eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
     return kInvalidOffset;
   }
-  if (eocd->num_records == 0) {
-#if defined(__ANDROID__)
-    ALOGW("Zip: empty archive?");
-#endif
-    return kEmptyArchive;
-  }
 
-  ALOGV("+++ num_entries=%" PRIu32 " dir_size=%" PRIu32 " dir_offset=%" PRIu32, eocd->num_records,
-        eocd->cd_size, eocd->cd_start_offset);
-
-  // It all looks good.  Create a mapping for the CD, and set the fields
-  // in archive.
-  if (!archive->InitializeCentralDirectory(static_cast<off64_t>(eocd->cd_start_offset),
-                                           static_cast<size_t>(eocd->cd_size))) {
-    return kMmapFailed;
-  }
-
-  archive->num_entries = eocd->num_records;
-  archive->directory_offset = eocd->cd_start_offset;
-
-  return 0;
+  *cdInfo = {.num_records = eocd->num_records,
+             .cd_size = eocd->cd_size,
+             .cd_start_offset = eocd->cd_start_offset};
+  return kSuccess;
 }
 
 /*
  * Find the zip Central Directory and memory-map it.
  *
- * On success, returns 0 after populating fields from the EOCD area:
+ * On success, returns kSuccess after populating fields from the EOCD area:
  *   directory_offset
  *   directory_ptr
  *   num_entries
  */
-static int32_t MapCentralDirectory(const char* debug_file_name, ZipArchive* archive) {
-  // Test file length. We use lseek64 to make sure the file
-  // is small enough to be a zip file (Its size must be less than
-  // 0xffffffff bytes).
+static ZipError MapCentralDirectory(const char* debug_file_name, ZipArchive* archive) {
+  // Test file length. We use lseek64 to make sure the file is small enough to be a zip file.
   off64_t file_length = archive->mapped_zip.GetFileLength();
   if (file_length == -1) {
     return kInvalidFile;
   }
 
-  if (file_length > static_cast<off64_t>(0xffffffff)) {
+  if (file_length > kMaxFileLength) {
     ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length));
     return kInvalidFile;
   }
@@ -323,10 +308,121 @@
     read_amount = static_cast<uint32_t>(file_length);
   }
 
-  std::vector<uint8_t> scan_buffer(read_amount);
-  int32_t result =
-      MapCentralDirectory0(debug_file_name, archive, file_length, read_amount, scan_buffer.data());
-  return result;
+  CentralDirectoryInfo cdInfo = {};
+  if (auto result =
+          FindCentralDirectoryInfo(debug_file_name, archive, file_length, read_amount, &cdInfo);
+      result != kSuccess) {
+    return result;
+  }
+
+  if (cdInfo.num_records == 0) {
+#if defined(__ANDROID__)
+    ALOGW("Zip: empty archive?");
+#endif
+    return kEmptyArchive;
+  }
+
+  if (cdInfo.cd_size >= SIZE_MAX) {
+    ALOGW("Zip: The size of central directory doesn't fit in range of size_t: %" PRIu64,
+          cdInfo.cd_size);
+    return kInvalidFile;
+  }
+
+  ALOGV("+++ num_entries=%" PRIu64 " dir_size=%" PRIu64 " dir_offset=%" PRIu64, cdInfo.num_records,
+        cdInfo.cd_size, cdInfo.cd_start_offset);
+
+  // It all looks good.  Create a mapping for the CD, and set the fields in archive.
+  if (!archive->InitializeCentralDirectory(static_cast<off64_t>(cdInfo.cd_start_offset),
+                                           static_cast<size_t>(cdInfo.cd_size))) {
+    return kMmapFailed;
+  }
+
+  archive->num_entries = cdInfo.num_records;
+  archive->directory_offset = cdInfo.cd_start_offset;
+
+  return kSuccess;
+}
+
+static ZipError ParseZip64ExtendedInfoInExtraField(
+    const uint8_t* extraFieldStart, uint16_t extraFieldLength, uint32_t zip32UncompressedSize,
+    uint32_t zip32CompressedSize, std::optional<uint32_t> zip32LocalFileHeaderOffset,
+    Zip64ExtendedInfo* zip64Info) {
+  if (extraFieldLength <= 4) {
+    ALOGW("Zip: Extra field isn't large enough to hold zip64 info, size %" PRIu16,
+          extraFieldLength);
+    return kInvalidFile;
+  }
+
+  // Each header MUST consist of:
+  // Header ID - 2 bytes
+  // Data Size - 2 bytes
+  uint16_t offset = 0;
+  while (offset < extraFieldLength - 4) {
+    auto readPtr = const_cast<uint8_t*>(extraFieldStart + offset);
+    auto headerId = ConsumeUnaligned<uint16_t>(&readPtr);
+    auto dataSize = ConsumeUnaligned<uint16_t>(&readPtr);
+
+    offset += 4;
+    if (dataSize > extraFieldLength - offset) {
+      ALOGW("Zip: Data size exceeds the boundary of extra field, data size %" PRIu16, dataSize);
+      return kInvalidOffset;
+    }
+
+    // Skip the other types of extensible data fields. Details in
+    // https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT section 4.5
+    if (headerId != Zip64ExtendedInfo::kHeaderId) {
+      offset += dataSize;
+      continue;
+    }
+
+    std::optional<uint64_t> uncompressedFileSize;
+    std::optional<uint64_t> compressedFileSize;
+    std::optional<uint64_t> localHeaderOffset;
+    if (zip32UncompressedSize == UINT32_MAX) {
+      uncompressedFileSize = ConsumeUnaligned<uint64_t>(&readPtr);
+    }
+    if (zip32CompressedSize == UINT32_MAX) {
+      compressedFileSize = ConsumeUnaligned<uint64_t>(&readPtr);
+    }
+    if (zip32LocalFileHeaderOffset == UINT32_MAX) {
+      localHeaderOffset = ConsumeUnaligned<uint64_t>(&readPtr);
+    }
+
+    // calculate how many bytes we read after the data size field.
+    size_t bytesRead = readPtr - (extraFieldStart + offset);
+    if (bytesRead == 0) {
+      ALOGW("Zip: Data size should not be 0 in zip64 extended field");
+      return kInvalidFile;
+    }
+
+    if (dataSize != bytesRead) {
+      auto localOffsetString = zip32LocalFileHeaderOffset.has_value()
+                                   ? std::to_string(zip32LocalFileHeaderOffset.value())
+                                   : "missing";
+      ALOGW("Zip: Invalid data size in zip64 extended field, expect %zu , get %" PRIu16
+            ", uncompressed size %" PRIu32 ", compressed size %" PRIu32 ", local header offset %s",
+            bytesRead, dataSize, zip32UncompressedSize, zip32CompressedSize,
+            localOffsetString.c_str());
+      return kInvalidFile;
+    }
+
+    // TODO(xunchang) Support handling file large than UINT32_MAX. It's theoretically possible
+    // for libz to (de)compressing file larger than UINT32_MAX. But we should use our own
+    // bytes counter to replace stream.total_out.
+    if ((uncompressedFileSize.has_value() && uncompressedFileSize.value() > UINT32_MAX) ||
+        (compressedFileSize.has_value() && compressedFileSize.value() > UINT32_MAX)) {
+      ALOGW("Zip: File size larger than UINT32_MAX isn't supported yet");
+      return kInvalidFile;
+    }
+
+    zip64Info->uncompressed_file_size = uncompressedFileSize;
+    zip64Info->compressed_file_size = compressedFileSize;
+    zip64Info->local_header_offset = localHeaderOffset;
+    return kSuccess;
+  }
+
+  ALOGW("Zip: zip64 extended info isn't found in the extra field.");
+  return kInvalidFile;
 }
 
 /*
@@ -335,22 +431,17 @@
  *
  * Returns 0 on success.
  */
-static int32_t ParseZipArchive(ZipArchive* archive) {
+static ZipError ParseZipArchive(ZipArchive* archive) {
   const uint8_t* const cd_ptr = archive->central_directory.GetBasePtr();
   const size_t cd_length = archive->central_directory.GetMapLength();
-  const uint16_t num_entries = archive->num_entries;
+  const uint64_t num_entries = archive->num_entries;
 
-  /*
-   * Create hash table.  We have a minimum 75% load factor, possibly as
-   * low as 50% after we round off to a power of 2.  There must be at
-   * least one unused entry to avoid an infinite loop during creation.
-   */
-  archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
-  archive->hash_table =
-      reinterpret_cast<ZipStringOffset*>(calloc(archive->hash_table_size, sizeof(ZipStringOffset)));
-  if (archive->hash_table == nullptr) {
-    ALOGW("Zip: unable to allocate the %u-entry hash_table, entry size: %zu",
-          archive->hash_table_size, sizeof(ZipStringOffset));
+  if (num_entries <= UINT16_MAX) {
+    archive->cd_entry_map = CdEntryMapZip32::Create(static_cast<uint16_t>(num_entries));
+  } else {
+    archive->cd_entry_map = CdEntryMapZip64::Create();
+  }
+  if (archive->cd_entry_map == nullptr) {
     return kAllocationFailed;
   }
 
@@ -360,9 +451,9 @@
    */
   const uint8_t* const cd_end = cd_ptr + cd_length;
   const uint8_t* ptr = cd_ptr;
-  for (uint16_t i = 0; i < num_entries; i++) {
+  for (uint64_t i = 0; i < num_entries; i++) {
     if (ptr > cd_end - sizeof(CentralDirectoryRecord)) {
-      ALOGW("Zip: ran off the end (item #%" PRIu16 ", %zu bytes of central directory)", i,
+      ALOGW("Zip: ran off the end (item #%" PRIu64 ", %zu bytes of central directory)", i,
             cd_length);
 #if defined(__ANDROID__)
       android_errorWriteLog(0x534e4554, "36392138");
@@ -370,16 +461,9 @@
       return kInvalidFile;
     }
 
-    const CentralDirectoryRecord* cdr = reinterpret_cast<const CentralDirectoryRecord*>(ptr);
+    auto cdr = reinterpret_cast<const CentralDirectoryRecord*>(ptr);
     if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
-      ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
-      return kInvalidFile;
-    }
-
-    const off64_t local_header_offset = cdr->local_file_header_offset;
-    if (local_header_offset >= archive->directory_offset) {
-      ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16,
-            static_cast<int64_t>(local_header_offset), i);
+      ALOGW("Zip: missed a central dir sig (at %" PRIu64 ")", i);
       return kInvalidFile;
     }
 
@@ -388,30 +472,58 @@
     const uint16_t comment_length = cdr->comment_length;
     const uint8_t* file_name = ptr + sizeof(CentralDirectoryRecord);
 
-    if (file_name + file_name_length > cd_end) {
-      ALOGW("Zip: file name for entry %" PRIu16
+    if (file_name_length >= cd_length || file_name > cd_end - file_name_length) {
+      ALOGW("Zip: file name for entry %" PRIu64
             " exceeds the central directory range, file_name_length: %" PRIu16 ", cd_length: %zu",
             i, file_name_length, cd_length);
       return kInvalidEntryName;
     }
+
+    const uint8_t* extra_field = file_name + file_name_length;
+    if (extra_length >= cd_length || extra_field > cd_end - extra_length) {
+      ALOGW("Zip: extra field for entry %" PRIu64
+            " exceeds the central directory range, file_name_length: %" PRIu16 ", cd_length: %zu",
+            i, extra_length, cd_length);
+      return kInvalidFile;
+    }
+
+    off64_t local_header_offset = cdr->local_file_header_offset;
+    if (local_header_offset == UINT32_MAX) {
+      Zip64ExtendedInfo zip64_info{};
+      if (auto status = ParseZip64ExtendedInfoInExtraField(
+              extra_field, extra_length, cdr->uncompressed_size, cdr->compressed_size,
+              cdr->local_file_header_offset, &zip64_info);
+          status != kSuccess) {
+        return status;
+      }
+      CHECK(zip64_info.local_header_offset.has_value());
+      local_header_offset = zip64_info.local_header_offset.value();
+    }
+
+    if (local_header_offset >= archive->directory_offset) {
+      ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu64,
+            static_cast<int64_t>(local_header_offset), i);
+      return kInvalidFile;
+    }
+
     // Check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters.
     if (!IsValidEntryName(file_name, file_name_length)) {
-      ALOGW("Zip: invalid file name at entry %" PRIu16, i);
+      ALOGW("Zip: invalid file name at entry %" PRIu64, i);
       return kInvalidEntryName;
     }
 
     // Add the CDE filename to the hash table.
     std::string_view entry_name{reinterpret_cast<const char*>(file_name), file_name_length};
-    const int add_result = AddToHash(archive->hash_table, archive->hash_table_size, entry_name,
-                                     archive->central_directory.GetBasePtr());
-    if (add_result != 0) {
+    if (auto add_result =
+            archive->cd_entry_map->AddToMap(entry_name, archive->central_directory.GetBasePtr());
+        add_result != 0) {
       ALOGW("Zip: Error adding entry to hash table %d", add_result);
       return add_result;
     }
 
     ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length;
     if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) {
-      ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16, ptr - cd_ptr, cd_length, i);
+      ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu64, ptr - cd_ptr, cd_length, i);
       return kInvalidFile;
     }
   }
@@ -431,14 +543,14 @@
     return kInvalidFile;
   }
 
-  ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries);
+  ALOGV("+++ zip good scan %" PRIu64 " entries", num_entries);
 
-  return 0;
+  return kSuccess;
 }
 
 static int32_t OpenArchiveInternal(ZipArchive* archive, const char* debug_file_name) {
   int32_t result = MapCentralDirectory(debug_file_name, archive);
-  return result != 0 ? result : ParseZipArchive(archive);
+  return result != kSuccess ? result : ParseZipArchive(archive);
 }
 
 int32_t OpenArchiveFd(int fd, const char* debug_file_name, ZipArchiveHandle* handle,
@@ -502,7 +614,8 @@
 }
 
 static int32_t ValidateDataDescriptor(MappedZipFile& mapped_zip, ZipEntry* entry) {
-  uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
+  // Maximum possible size for data descriptor: 2 * 4 + 2 * 8 = 24 bytes
+  uint8_t ddBuf[24];
   off64_t offset = entry->offset;
   if (entry->method != kCompressStored) {
     offset += entry->compressed_length;
@@ -515,32 +628,39 @@
   }
 
   const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf));
-  const uint16_t ddOffset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0;
-  const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + ddOffset);
+  uint8_t* ddReadPtr = (ddSignature == DataDescriptor::kOptSignature) ? ddBuf + 4 : ddBuf;
+  DataDescriptor descriptor{};
+  descriptor.crc32 = ConsumeUnaligned<uint32_t>(&ddReadPtr);
+  if (entry->zip64_format_size) {
+    descriptor.compressed_size = ConsumeUnaligned<uint64_t>(&ddReadPtr);
+    descriptor.uncompressed_size = ConsumeUnaligned<uint64_t>(&ddReadPtr);
+  } else {
+    descriptor.compressed_size = ConsumeUnaligned<uint32_t>(&ddReadPtr);
+    descriptor.uncompressed_size = ConsumeUnaligned<uint32_t>(&ddReadPtr);
+  }
 
   // Validate that the values in the data descriptor match those in the central
   // directory.
-  if (entry->compressed_length != descriptor->compressed_size ||
-      entry->uncompressed_length != descriptor->uncompressed_size ||
-      entry->crc32 != descriptor->crc32) {
+  if (entry->compressed_length != descriptor.compressed_size ||
+      entry->uncompressed_length != descriptor.uncompressed_size ||
+      entry->crc32 != descriptor.crc32) {
     ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32 ", %" PRIx32
-          "}, was {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}",
+          "}, was {%" PRIu64 ", %" PRIu64 ", %" PRIx32 "}",
           entry->compressed_length, entry->uncompressed_length, entry->crc32,
-          descriptor->compressed_size, descriptor->uncompressed_size, descriptor->crc32);
+          descriptor.compressed_size, descriptor.uncompressed_size, descriptor.crc32);
     return kInconsistentInformation;
   }
 
   return 0;
 }
 
-static int32_t FindEntry(const ZipArchive* archive, const int32_t ent, ZipEntry* data) {
-  const uint16_t nameLen = archive->hash_table[ent].name_length;
-
+static int32_t FindEntry(const ZipArchive* archive, std::string_view entryName,
+                         const uint64_t nameOffset, ZipEntry* data) {
   // Recover the start of the central directory entry from the filename
   // pointer.  The filename is the first entry past the fixed-size data,
   // so we can just subtract back from that.
   const uint8_t* base_ptr = archive->central_directory.GetBasePtr();
-  const uint8_t* ptr = base_ptr + archive->hash_table[ent].name_offset;
+  const uint8_t* ptr = base_ptr + nameOffset;
   ptr -= sizeof(CentralDirectoryRecord);
 
   // This is the base of our mmapped region, we have to sanity check that
@@ -551,7 +671,7 @@
     return kInvalidOffset;
   }
 
-  const CentralDirectoryRecord* cdr = reinterpret_cast<const CentralDirectoryRecord*>(ptr);
+  auto cdr = reinterpret_cast<const CentralDirectoryRecord*>(ptr);
 
   // The offset of the start of the central directory in the zipfile.
   // We keep this lying around so that we can sanity check all our lengths
@@ -570,7 +690,30 @@
   // Figure out the local header offset from the central directory. The
   // actual file data will begin after the local header and the name /
   // extra comments.
-  const off64_t local_header_offset = cdr->local_file_header_offset;
+  off64_t local_header_offset = cdr->local_file_header_offset;
+  // One of the info field is UINT32_MAX, try to parse the real value in the zip64 extended info in
+  // the extra field.
+  if (cdr->uncompressed_size == UINT32_MAX || cdr->compressed_size == UINT32_MAX ||
+      cdr->local_file_header_offset == UINT32_MAX) {
+    const uint8_t* extra_field = ptr + sizeof(CentralDirectoryRecord) + cdr->file_name_length;
+    Zip64ExtendedInfo zip64_info{};
+    if (auto status = ParseZip64ExtendedInfoInExtraField(
+            extra_field, cdr->extra_field_length, cdr->uncompressed_size, cdr->compressed_size,
+            cdr->local_file_header_offset, &zip64_info);
+        status != kSuccess) {
+      return status;
+    }
+
+    // TODO(xunchang) remove the size limit and support entry length > UINT32_MAX.
+    data->uncompressed_length =
+        static_cast<uint32_t>(zip64_info.uncompressed_file_size.value_or(cdr->uncompressed_size));
+    data->compressed_length =
+        static_cast<uint32_t>(zip64_info.compressed_file_size.value_or(cdr->compressed_size));
+    local_header_offset = zip64_info.local_header_offset.value_or(local_header_offset);
+    data->zip64_format_size =
+        cdr->uncompressed_size == UINT32_MAX || cdr->compressed_size == UINT32_MAX;
+  }
+
   if (local_header_offset + static_cast<off64_t>(sizeof(LocalFileHeader)) >= cd_offset) {
     ALOGW("Zip: bad local hdr offset in zip");
     return kInvalidOffset;
@@ -583,14 +726,75 @@
     return kIoError;
   }
 
-  const LocalFileHeader* lfh = reinterpret_cast<const LocalFileHeader*>(lfh_buf);
-
+  auto lfh = reinterpret_cast<const LocalFileHeader*>(lfh_buf);
   if (lfh->lfh_signature != LocalFileHeader::kSignature) {
     ALOGW("Zip: didn't find signature at start of lfh, offset=%" PRId64,
           static_cast<int64_t>(local_header_offset));
     return kInvalidOffset;
   }
 
+  // Check that the local file header name matches the declared name in the central directory.
+  CHECK_LE(entryName.size(), UINT16_MAX);
+  auto nameLen = static_cast<uint16_t>(entryName.size());
+  if (lfh->file_name_length != nameLen) {
+    ALOGW("Zip: lfh name length did not match central directory for %s: %" PRIu16 " %" PRIu16,
+          std::string(entryName).c_str(), lfh->file_name_length, nameLen);
+    return kInconsistentInformation;
+  }
+  const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader);
+  if (name_offset > cd_offset - lfh->file_name_length) {
+    ALOGW("Zip: lfh name has invalid declared length");
+    return kInvalidOffset;
+  }
+
+  std::vector<uint8_t> name_buf(nameLen);
+  if (!archive->mapped_zip.ReadAtOffset(name_buf.data(), nameLen, name_offset)) {
+    ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
+    return kIoError;
+  }
+  if (memcmp(entryName.data(), name_buf.data(), nameLen) != 0) {
+    ALOGW("Zip: lfh name did not match central directory");
+    return kInconsistentInformation;
+  }
+
+  uint64_t lfh_uncompressed_size = lfh->uncompressed_size;
+  uint64_t lfh_compressed_size = lfh->compressed_size;
+  if (lfh_uncompressed_size == UINT32_MAX || lfh_compressed_size == UINT32_MAX) {
+    if (lfh_uncompressed_size != UINT32_MAX || lfh_compressed_size != UINT32_MAX) {
+      ALOGW(
+          "Zip: The zip64 extended field in the local header MUST include BOTH original and "
+          "compressed file size fields.");
+      return kInvalidFile;
+    }
+
+    const off64_t lfh_extra_field_offset = name_offset + lfh->file_name_length;
+    const uint16_t lfh_extra_field_size = lfh->extra_field_length;
+    if (lfh_extra_field_offset > cd_offset - lfh_extra_field_size) {
+      ALOGW("Zip: extra field has a bad size for entry %s", std::string(entryName).c_str());
+      return kInvalidOffset;
+    }
+
+    std::vector<uint8_t> local_extra_field(lfh_extra_field_size);
+    if (!archive->mapped_zip.ReadAtOffset(local_extra_field.data(), lfh_extra_field_size,
+                                          lfh_extra_field_offset)) {
+      ALOGW("Zip: failed reading lfh extra field from offset %" PRId64, lfh_extra_field_offset);
+      return kIoError;
+    }
+
+    Zip64ExtendedInfo zip64_info{};
+    if (auto status = ParseZip64ExtendedInfoInExtraField(
+            local_extra_field.data(), lfh_extra_field_size, lfh->uncompressed_size,
+            lfh->compressed_size, std::nullopt, &zip64_info);
+        status != kSuccess) {
+      return status;
+    }
+
+    CHECK(zip64_info.uncompressed_file_size.has_value());
+    CHECK(zip64_info.compressed_file_size.has_value());
+    lfh_uncompressed_size = zip64_info.uncompressed_file_size.value();
+    lfh_compressed_size = zip64_info.compressed_file_size.value();
+  }
+
   // Paranoia: Match the values specified in the local file header
   // to those specified in the central directory.
 
@@ -616,12 +820,12 @@
   // header agree on the crc, compressed, and uncompressed sizes of the entry.
   if ((lfh->gpb_flags & kGPBDDFlagMask) == 0) {
     data->has_data_descriptor = 0;
-    if (data->compressed_length != lfh->compressed_size ||
-        data->uncompressed_length != lfh->uncompressed_size || data->crc32 != lfh->crc32) {
+    if (data->compressed_length != lfh_compressed_size ||
+        data->uncompressed_length != lfh_uncompressed_size || data->crc32 != lfh->crc32) {
       ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32 ", %" PRIx32
-            "}, was {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}",
-            data->compressed_length, data->uncompressed_length, data->crc32, lfh->compressed_size,
-            lfh->uncompressed_size, lfh->crc32);
+            "}, was {%" PRIu64 ", %" PRIu64 ", %" PRIx32 "}",
+            data->compressed_length, data->uncompressed_length, data->crc32, lfh_compressed_size,
+            lfh_uncompressed_size, lfh->crc32);
       return kInconsistentInformation;
     }
   } else {
@@ -644,29 +848,6 @@
   // Currently only needed to implement zipinfo.
   data->is_text = (cdr->internal_file_attributes & 1);
 
-  // Check that the local file header name matches the declared
-  // name in the central directory.
-  if (lfh->file_name_length != nameLen) {
-    ALOGW("Zip: lfh name length did not match central directory");
-    return kInconsistentInformation;
-  }
-  const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader);
-  if (name_offset + lfh->file_name_length > cd_offset) {
-    ALOGW("Zip: lfh name has invalid declared length");
-    return kInvalidOffset;
-  }
-  std::vector<uint8_t> name_buf(nameLen);
-  if (!archive->mapped_zip.ReadAtOffset(name_buf.data(), nameLen, name_offset)) {
-    ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
-    return kIoError;
-  }
-  const std::string_view entry_name =
-      archive->hash_table[ent].ToStringView(archive->central_directory.GetBasePtr());
-  if (memcmp(entry_name.data(), name_buf.data(), nameLen) != 0) {
-    ALOGW("Zip: lfh name did not match central directory");
-    return kInconsistentInformation;
-  }
-
   const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader) +
                               lfh->file_name_length + lfh->extra_field_length;
   if (data_offset > cd_offset) {
@@ -696,30 +877,40 @@
 struct IterationHandle {
   ZipArchive* archive;
 
-  std::string prefix;
-  std::string suffix;
+  std::function<bool(std::string_view)> matcher;
 
   uint32_t position = 0;
 
-  IterationHandle(ZipArchive* archive, std::string_view in_prefix, std::string_view in_suffix)
-      : archive(archive), prefix(in_prefix), suffix(in_suffix) {}
+  IterationHandle(ZipArchive* archive, std::function<bool(std::string_view)> in_matcher)
+      : archive(archive), matcher(std::move(in_matcher)) {}
+
+  bool Match(std::string_view entry_name) const { return matcher(entry_name); }
 };
 
 int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
                        const std::string_view optional_prefix,
                        const std::string_view optional_suffix) {
-  if (archive == NULL || archive->hash_table == NULL) {
-    ALOGW("Zip: Invalid ZipArchiveHandle");
-    return kInvalidHandle;
-  }
-
   if (optional_prefix.size() > static_cast<size_t>(UINT16_MAX) ||
       optional_suffix.size() > static_cast<size_t>(UINT16_MAX)) {
     ALOGW("Zip: prefix/suffix too long");
     return kInvalidEntryName;
   }
+  auto matcher = [prefix = std::string(optional_prefix),
+                  suffix = std::string(optional_suffix)](std::string_view name) mutable {
+    return android::base::StartsWith(name, prefix) && android::base::EndsWith(name, suffix);
+  };
+  return StartIteration(archive, cookie_ptr, std::move(matcher));
+}
 
-  *cookie_ptr = new IterationHandle(archive, optional_prefix, optional_suffix);
+int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
+                       std::function<bool(std::string_view)> matcher) {
+  if (archive == nullptr || archive->cd_entry_map == nullptr) {
+    ALOGW("Zip: Invalid ZipArchiveHandle");
+    return kInvalidHandle;
+  }
+
+  archive->cd_entry_map->ResetIteration();
+  *cookie_ptr = new IterationHandle(archive, matcher);
   return 0;
 }
 
@@ -734,14 +925,14 @@
     return kInvalidEntryName;
   }
 
-  const int64_t ent = EntryToIndex(archive->hash_table, archive->hash_table_size, entryName,
-                                   archive->central_directory.GetBasePtr());
-  if (ent < 0) {
+  const auto [result, offset] =
+      archive->cd_entry_map->GetCdEntryOffset(entryName, archive->central_directory.GetBasePtr());
+  if (result != 0) {
     ALOGV("Zip: Could not find entry %.*s", static_cast<int>(entryName.size()), entryName.data());
-    return static_cast<int32_t>(ent);  // kEntryNotFound is safe to truncate.
+    return static_cast<int32_t>(result);  // kEntryNotFound is safe to truncate.
   }
   // We know there are at most hash_table_size entries, safe to truncate.
-  return FindEntry(archive, static_cast<uint32_t>(ent), data);
+  return FindEntry(archive, entryName, offset, data);
 }
 
 int32_t Next(void* cookie, ZipEntry* data, std::string* name) {
@@ -755,35 +946,31 @@
 
 int32_t Next(void* cookie, ZipEntry* data, std::string_view* name) {
   IterationHandle* handle = reinterpret_cast<IterationHandle*>(cookie);
-  if (handle == NULL) {
+  if (handle == nullptr) {
     ALOGW("Zip: Null ZipArchiveHandle");
     return kInvalidHandle;
   }
 
   ZipArchive* archive = handle->archive;
-  if (archive == NULL || archive->hash_table == NULL) {
+  if (archive == nullptr || archive->cd_entry_map == nullptr) {
     ALOGW("Zip: Invalid ZipArchiveHandle");
     return kInvalidHandle;
   }
 
-  const uint32_t currentOffset = handle->position;
-  const uint32_t hash_table_length = archive->hash_table_size;
-  const ZipStringOffset* hash_table = archive->hash_table;
-  for (uint32_t i = currentOffset; i < hash_table_length; ++i) {
-    const std::string_view entry_name =
-        hash_table[i].ToStringView(archive->central_directory.GetBasePtr());
-    if (hash_table[i].name_offset != 0 && (android::base::StartsWith(entry_name, handle->prefix) &&
-                                           android::base::EndsWith(entry_name, handle->suffix))) {
-      handle->position = (i + 1);
-      const int error = FindEntry(archive, i, data);
+  auto entry = archive->cd_entry_map->Next(archive->central_directory.GetBasePtr());
+  while (entry != std::pair<std::string_view, uint64_t>()) {
+    const auto [entry_name, offset] = entry;
+    if (handle->Match(entry_name)) {
+      const int error = FindEntry(archive, entry_name, offset, data);
       if (!error && name) {
         *name = entry_name;
       }
       return error;
     }
+    entry = archive->cd_entry_map->Next(archive->central_directory.GetBasePtr());
   }
 
-  handle->position = 0;
+  archive->cd_entry_map->ResetIteration();
   return kIterationEnd;
 }
 
@@ -1127,20 +1314,6 @@
   return ExtractToWriter(archive, entry, &writer);
 }
 
-const char* ErrorCodeString(int32_t error_code) {
-  // Make sure that the number of entries in kErrorMessages and ErrorCodes
-  // match.
-  static_assert((-kLastErrorCode + 1) == arraysize(kErrorMessages),
-                "(-kLastErrorCode + 1) != arraysize(kErrorMessages)");
-
-  const uint32_t idx = -error_code;
-  if (idx < arraysize(kErrorMessages)) {
-    return kErrorMessages[idx];
-  }
-
-  return "Unknown return code";
-}
-
 int GetFileDescriptor(const ZipArchiveHandle archive) {
   return archive->mapped_zip.GetFileDescriptor();
 }
diff --git a/libziparchive/zip_archive_common.h b/libziparchive/zip_archive_common.h
index 8b99bde..d461856 100644
--- a/libziparchive/zip_archive_common.h
+++ b/libziparchive/zip_archive_common.h
@@ -21,6 +21,8 @@
 
 #include <inttypes.h>
 
+#include <optional>
+
 // The "end of central directory" (EOCD) record. Each archive
 // contains exactly once such record which appears at the end of
 // the archive. It contains archive wide information like the
@@ -163,16 +165,108 @@
 
   // CRC-32 checksum of the entry.
   uint32_t crc32;
-  // Compressed size of the entry.
-  uint32_t compressed_size;
-  // Uncompressed size of the entry.
-  uint32_t uncompressed_size;
+
+  // For ZIP64 format archives, the compressed and uncompressed sizes are 8
+  // bytes each. Also, the ZIP64 format MAY be used regardless of the size
+  // of a file.  When extracting, if the zip64 extended information extra field
+  // is present for the file the compressed and uncompressed sizes will be 8
+  // byte values.
+
+  // Compressed size of the entry, the field can be either 4 bytes or 8 bytes
+  // in the zip file.
+  uint64_t compressed_size;
+  // Uncompressed size of the entry, the field can be either 4 bytes or 8 bytes
+  // in the zip file.
+  uint64_t uncompressed_size;
 
  private:
   DataDescriptor() = default;
   DISALLOW_COPY_AND_ASSIGN(DataDescriptor);
+};
+
+// The zip64 end of central directory locator helps to find the zip64 EOCD.
+struct Zip64EocdLocator {
+  static constexpr uint32_t kSignature = 0x07064b50;
+
+  // The signature of zip64 eocd locator, must be |kSignature|
+  uint32_t locator_signature;
+  // The start disk of the zip64 eocd. This implementation assumes that each
+  // archive spans a single disk only.
+  uint32_t eocd_start_disk;
+  // The offset offset of the zip64 end of central directory record.
+  uint64_t zip64_eocd_offset;
+  // The total number of disks. This implementation assumes that each archive
+  // spans a single disk only.
+  uint32_t num_of_disks;
+
+ private:
+  Zip64EocdLocator() = default;
+  DISALLOW_COPY_AND_ASSIGN(Zip64EocdLocator);
 } __attribute__((packed));
 
+// The optional zip64 EOCD. If one of the fields in the end of central directory
+// record is too small to hold required data, the field SHOULD be  set to -1
+// (0xFFFF or 0xFFFFFFFF) and the ZIP64 format record SHOULD be created.
+struct Zip64EocdRecord {
+  static constexpr uint32_t kSignature = 0x06064b50;
+
+  // The signature of zip64 eocd record, must be |kSignature|
+  uint32_t record_signature;
+  // Size of zip64 end of central directory record. It SHOULD be the size of the
+  // remaining record and SHOULD NOT include the leading 12 bytes.
+  uint64_t record_size;
+  // The version of the tool that make this archive.
+  uint16_t version_made_by;
+  // Tool version needed to extract this archive.
+  uint16_t version_needed;
+  // Number of this disk.
+  uint32_t disk_num;
+  // Number of the disk with the start of the central directory.
+  uint32_t cd_start_disk;
+  // Total number of entries in the central directory on this disk.
+  // This implementation assumes that each archive spans a single
+  // disk only. i.e, that num_records_on_disk == num_records.
+  uint64_t num_records_on_disk;
+  // The total number of central directory records.
+  uint64_t num_records;
+  // The size of the central directory in bytes.
+  uint64_t cd_size;
+  // The offset of the start of the central directory, relative to the start of
+  // the file.
+  uint64_t cd_start_offset;
+
+ private:
+  Zip64EocdRecord() = default;
+  DISALLOW_COPY_AND_ASSIGN(Zip64EocdRecord);
+} __attribute__((packed));
+
+// The possible contents of the Zip64 Extended Information Extra Field. It may appear in
+// the 'extra' field of a central directory record or local file header. The order of
+// the fields in the zip64 extended information record is fixed, but the fields MUST
+// only appear if the corresponding local or central directory record field is set to
+// 0xFFFF or 0xFFFFFFFF. And this entry in the Local header MUST include BOTH original
+// and compressed file size fields.
+struct Zip64ExtendedInfo {
+  static constexpr uint16_t kHeaderId = 0x0001;
+  // The header tag for this 'extra' block, should be |kHeaderId|.
+  uint16_t header_id;
+  // The size in bytes of the remaining data (excluding the top 4 bytes).
+  uint16_t data_size;
+  // Size in bytes of the uncompressed file.
+  std::optional<uint64_t> uncompressed_file_size;
+  // Size in bytes of the compressed file.
+  std::optional<uint64_t> compressed_file_size;
+  // Local file header offset relative to the start of the zip file.
+  std::optional<uint64_t> local_header_offset;
+
+  // This implementation assumes that each archive spans a single disk only. So
+  // the disk_number is not used.
+  // uint32_t disk_num;
+ private:
+  Zip64ExtendedInfo() = default;
+  DISALLOW_COPY_AND_ASSIGN(Zip64ExtendedInfo);
+};
+
 // mask value that signifies that the entry has a DD
 static const uint32_t kGPBDDFlagMask = 0x0008;
 
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 3625038..4ed07aa 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -23,76 +23,14 @@
 #include <unistd.h>
 
 #include <memory>
+#include <utility>
 #include <vector>
 
 #include "android-base/macros.h"
 #include "android-base/mapped_file.h"
-
-static const char* kErrorMessages[] = {
-    "Success",
-    "Iteration ended",
-    "Zlib error",
-    "Invalid file",
-    "Invalid handle",
-    "Duplicate entries in archive",
-    "Empty archive",
-    "Entry not found",
-    "Invalid offset",
-    "Inconsistent information",
-    "Invalid entry name",
-    "I/O error",
-    "File mapping failed",
-    "Allocation failed",
-};
-
-enum ErrorCodes : int32_t {
-  kIterationEnd = -1,
-
-  // We encountered a Zlib error when inflating a stream from this file.
-  // Usually indicates file corruption.
-  kZlibError = -2,
-
-  // The input file cannot be processed as a zip archive. Usually because
-  // it's too small, too large or does not have a valid signature.
-  kInvalidFile = -3,
-
-  // An invalid iteration / ziparchive handle was passed in as an input
-  // argument.
-  kInvalidHandle = -4,
-
-  // The zip archive contained two (or possibly more) entries with the same
-  // name.
-  kDuplicateEntry = -5,
-
-  // The zip archive contains no entries.
-  kEmptyArchive = -6,
-
-  // The specified entry was not found in the archive.
-  kEntryNotFound = -7,
-
-  // The zip archive contained an invalid local file header pointer.
-  kInvalidOffset = -8,
-
-  // The zip archive contained inconsistent entry information. This could
-  // be because the central directory & local file header did not agree, or
-  // if the actual uncompressed length or crc32 do not match their declared
-  // values.
-  kInconsistentInformation = -9,
-
-  // An invalid entry name was encountered.
-  kInvalidEntryName = -10,
-
-  // An I/O related system call (read, lseek, ftruncate, map) failed.
-  kIoError = -11,
-
-  // We were not able to mmap the central directory or entry contents.
-  kMmapFailed = -12,
-
-  // An allocation failed.
-  kAllocationFailed = -13,
-
-  kLastErrorCode = kAllocationFailed,
-};
+#include "android-base/memory.h"
+#include "zip_cd_entry_map.h"
+#include "zip_error.h"
 
 class MappedZipFile {
  public:
@@ -147,26 +85,6 @@
   size_t length_;
 };
 
-/**
- * More space efficient string representation of strings in an mmaped zipped
- * file than std::string_view. Using std::string_view as an entry in the
- * ZipArchive hash table wastes space. std::string_view stores a pointer to a
- * string (on 64 bit, 8 bytes) and the length to read from that pointer,
- * 2 bytes. Because of alignment, the structure consumes 16 bytes, wasting
- * 6 bytes.
- *
- * ZipStringOffset stores a 4 byte offset from a fixed location in the memory
- * mapped file instead of the entire address, consuming 8 bytes with alignment.
- */
-struct ZipStringOffset {
-  uint32_t name_offset;
-  uint16_t name_length;
-
-  const std::string_view ToStringView(const uint8_t* start) const {
-    return std::string_view{reinterpret_cast<const char*>(start + name_offset), name_length};
-  }
-};
-
 struct ZipArchive {
   // open Zip archive
   mutable MappedZipFile mapped_zip;
@@ -178,14 +96,8 @@
   std::unique_ptr<android::base::MappedFile> directory_map;
 
   // number of entries in the Zip archive
-  uint16_t num_entries;
-
-  // We know how many entries are in the Zip archive, so we can have a
-  // fixed-size hash table. We define a load factor of 0.75 and over
-  // allocate so the maximum number entries can never be higher than
-  // ((4 * UINT16_MAX) / 3 + 1) which can safely fit into a uint32_t.
-  uint32_t hash_table_size;
-  ZipStringOffset* hash_table;
+  uint64_t num_entries;
+  std::unique_ptr<CdEntryMapInterface> cd_entry_map;
 
   ZipArchive(MappedZipFile&& map, bool assume_ownership);
   ZipArchive(const void* address, size_t length);
@@ -193,3 +105,20 @@
 
   bool InitializeCentralDirectory(off64_t cd_start_offset, size_t cd_size);
 };
+
+int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, zip_archive::Writer* writer);
+
+// Reads the unaligned data of type |T| and auto increment the offset.
+template <typename T>
+static T ConsumeUnaligned(uint8_t** address) {
+  auto ret = android::base::get_unaligned<T>(*address);
+  *address += sizeof(T);
+  return ret;
+}
+
+// Writes the unaligned data of type |T| and auto increment the offset.
+template <typename T>
+void EmitUnaligned(uint8_t** address, T data) {
+  android::base::put_unaligned<T>(*address, data);
+  *address += sizeof(T);
+}
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 35fb3fe..3563340 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include "zip_archive_private.h"
-
 #include <errno.h>
 #include <fcntl.h>
 #include <getopt.h>
@@ -23,17 +21,25 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <map>
 #include <memory>
+#include <set>
+#include <string_view>
 #include <vector>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/mapped_file.h>
+#include <android-base/memory.h>
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <gtest/gtest.h>
 #include <ziparchive/zip_archive.h>
 #include <ziparchive/zip_archive_stream_entry.h>
 
+#include "zip_archive_common.h"
+#include "zip_archive_private.h"
+
 static std::string test_data_dir = android::base::GetExecutableDirectory() + "/testdata";
 
 static const std::string kValidZip = "valid.zip";
@@ -53,6 +59,76 @@
   return OpenArchive(abs_path.c_str(), handle);
 }
 
+class CdEntryMapTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    names_ = {
+        "a.txt", "b.txt", "b/", "b/c.txt", "b/d.txt",
+    };
+    separator_ = "separator";
+    header_ = "metadata";
+    joined_names_ = header_ + android::base::Join(names_, separator_);
+    base_ptr_ = reinterpret_cast<uint8_t*>(&joined_names_[0]);
+
+    entry_maps_.emplace_back(CdEntryMapZip32::Create(static_cast<uint16_t>(names_.size())));
+    entry_maps_.emplace_back(CdEntryMapZip64::Create());
+    for (auto& cd_map : entry_maps_) {
+      ASSERT_NE(nullptr, cd_map);
+      size_t offset = header_.size();
+      for (const auto& name : names_) {
+        auto status = cd_map->AddToMap(
+            std::string_view{joined_names_.c_str() + offset, name.size()}, base_ptr_);
+        ASSERT_EQ(0, status);
+        offset += name.size() + separator_.size();
+      }
+    }
+  }
+
+  std::vector<std::string> names_;
+  // A continuous region of memory serves as a mock of the central directory.
+  std::string joined_names_;
+  // We expect some metadata at the beginning of the central directory and between filenames.
+  std::string header_;
+  std::string separator_;
+
+  std::vector<std::unique_ptr<CdEntryMapInterface>> entry_maps_;
+  uint8_t* base_ptr_{nullptr};  // Points to the start of the central directory.
+};
+
+TEST_F(CdEntryMapTest, AddDuplicatedEntry) {
+  for (auto& cd_map : entry_maps_) {
+    std::string_view name = "b.txt";
+    ASSERT_NE(0, cd_map->AddToMap(name, base_ptr_));
+  }
+}
+
+TEST_F(CdEntryMapTest, FindEntry) {
+  for (auto& cd_map : entry_maps_) {
+    uint64_t expected_offset = header_.size();
+    for (const auto& name : names_) {
+      auto [status, offset] = cd_map->GetCdEntryOffset(name, base_ptr_);
+      ASSERT_EQ(status, kSuccess);
+      ASSERT_EQ(offset, expected_offset);
+      expected_offset += name.size() + separator_.size();
+    }
+  }
+}
+
+TEST_F(CdEntryMapTest, Iteration) {
+  std::set<std::string_view> expected(names_.begin(), names_.end());
+  for (auto& cd_map : entry_maps_) {
+    cd_map->ResetIteration();
+    std::set<std::string_view> entry_set;
+    auto ret = cd_map->Next(base_ptr_);
+    while (ret != std::pair<std::string_view, uint64_t>{}) {
+      auto [it, insert_status] = entry_set.insert(ret.first);
+      ASSERT_TRUE(insert_status);
+      ret = cd_map->Next(base_ptr_);
+    }
+    ASSERT_EQ(expected, entry_set);
+  }
+}
+
 TEST(ziparchive, Open) {
   ZipArchiveHandle handle;
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
@@ -154,6 +230,22 @@
   CloseArchive(handle);
 }
 
+static void AssertIterationNames(void* iteration_cookie,
+                                 const std::vector<std::string>& expected_names_sorted) {
+  ZipEntry data;
+  std::vector<std::string> names;
+  std::string name;
+  for (size_t i = 0; i < expected_names_sorted.size(); ++i) {
+    ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+    names.push_back(name);
+  }
+  // End of iteration.
+  ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
+  // Assert that the names are as expected.
+  std::sort(names.begin(), names.end());
+  ASSERT_EQ(expected_names_sorted, names);
+}
+
 static void AssertIterationOrder(const std::string_view prefix, const std::string_view suffix,
                                  const std::vector<std::string>& expected_names_sorted) {
   ZipArchiveHandle handle;
@@ -161,23 +253,19 @@
 
   void* iteration_cookie;
   ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, prefix, suffix));
-
-  ZipEntry data;
-  std::vector<std::string> names;
-
-  std::string name;
-  for (size_t i = 0; i < expected_names_sorted.size(); ++i) {
-    ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
-    names.push_back(name);
-  }
-
-  // End of iteration.
-  ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
+  AssertIterationNames(iteration_cookie, expected_names_sorted);
   CloseArchive(handle);
+}
 
-  // Assert that the names are as expected.
-  std::sort(names.begin(), names.end());
-  ASSERT_EQ(expected_names_sorted, names);
+static void AssertIterationOrderWithMatcher(std::function<bool(std::string_view)> matcher,
+                                            const std::vector<std::string>& expected_names_sorted) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+  void* iteration_cookie;
+  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, matcher));
+  AssertIterationNames(iteration_cookie, expected_names_sorted);
+  CloseArchive(handle);
 }
 
 TEST(ziparchive, Iteration) {
@@ -206,6 +294,30 @@
   AssertIterationOrder("b", ".txt", kExpectedMatchesSorted);
 }
 
+TEST(ziparchive, IterationWithAdditionalMatchesExactly) {
+  static const std::vector<std::string> kExpectedMatchesSorted = {"a.txt"};
+  auto matcher = [](std::string_view name) { return name == "a.txt"; };
+  AssertIterationOrderWithMatcher(matcher, kExpectedMatchesSorted);
+}
+
+TEST(ziparchive, IterationWithAdditionalMatchesWithSuffix) {
+  static const std::vector<std::string> kExpectedMatchesSorted = {"a.txt", "b.txt", "b/c.txt",
+                                                                  "b/d.txt"};
+  auto matcher = [](std::string_view name) {
+    return name == "a.txt" || android::base::EndsWith(name, ".txt");
+  };
+  AssertIterationOrderWithMatcher(matcher, kExpectedMatchesSorted);
+}
+
+TEST(ziparchive, IterationWithAdditionalMatchesWithPrefixAndSuffix) {
+  static const std::vector<std::string> kExpectedMatchesSorted = {"a.txt", "b/c.txt", "b/d.txt"};
+  auto matcher = [](std::string_view name) {
+    return name == "a.txt" ||
+           (android::base::EndsWith(name, ".txt") && android::base::StartsWith(name, "b/"));
+  };
+  AssertIterationOrderWithMatcher(matcher, kExpectedMatchesSorted);
+}
+
 TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
   ZipArchiveHandle handle;
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
@@ -857,3 +969,356 @@
     ASSERT_EQ(0u, writer.GetOutput().size());
   }
 }
+
+// The class constructs a zipfile with zip64 format, and test the parsing logic.
+class Zip64ParseTest : public ::testing::Test {
+ protected:
+  struct LocalFileEntry {
+    std::vector<uint8_t> local_file_header;
+    std::string file_name;
+    std::vector<uint8_t> extended_field;
+    // Fake data to mimic the compressed bytes in the zipfile.
+    std::vector<uint8_t> compressed_bytes;
+    std::vector<uint8_t> data_descriptor;
+
+    size_t GetSize() const {
+      return local_file_header.size() + file_name.size() + extended_field.size() +
+             compressed_bytes.size() + data_descriptor.size();
+    }
+
+    void CopyToOutput(std::vector<uint8_t>* output) const {
+      std::copy(local_file_header.begin(), local_file_header.end(), std::back_inserter(*output));
+      std::copy(file_name.begin(), file_name.end(), std::back_inserter(*output));
+      std::copy(extended_field.begin(), extended_field.end(), std::back_inserter(*output));
+      std::copy(compressed_bytes.begin(), compressed_bytes.end(), std::back_inserter(*output));
+      std::copy(data_descriptor.begin(), data_descriptor.end(), std::back_inserter(*output));
+    }
+  };
+
+  struct CdRecordEntry {
+    std::vector<uint8_t> central_directory_record;
+    std::string file_name;
+    std::vector<uint8_t> extended_field;
+
+    size_t GetSize() const {
+      return central_directory_record.size() + file_name.size() + extended_field.size();
+    }
+
+    void CopyToOutput(std::vector<uint8_t>* output) const {
+      std::copy(central_directory_record.begin(), central_directory_record.end(),
+                std::back_inserter(*output));
+      std::copy(file_name.begin(), file_name.end(), std::back_inserter(*output));
+      std::copy(extended_field.begin(), extended_field.end(), std::back_inserter(*output));
+    }
+  };
+
+  static void ConstructLocalFileHeader(const std::string& name, std::vector<uint8_t>* output,
+                                       uint32_t uncompressed_size, uint32_t compressed_size) {
+    LocalFileHeader lfh = {};
+    lfh.lfh_signature = LocalFileHeader::kSignature;
+    lfh.compressed_size = compressed_size;
+    lfh.uncompressed_size = uncompressed_size;
+    lfh.file_name_length = static_cast<uint16_t>(name.size());
+    lfh.extra_field_length = 20;
+    *output = std::vector<uint8_t>(reinterpret_cast<uint8_t*>(&lfh),
+                                   reinterpret_cast<uint8_t*>(&lfh) + sizeof(LocalFileHeader));
+  }
+
+  // Put one zip64 extended info in the extended field.
+  static void ConstructExtendedField(const std::vector<uint64_t>& zip64_fields,
+                                     std::vector<uint8_t>* output) {
+    ASSERT_FALSE(zip64_fields.empty());
+    uint16_t data_size = 8 * static_cast<uint16_t>(zip64_fields.size());
+    std::vector<uint8_t> extended_field(data_size + 4);
+    android::base::put_unaligned(extended_field.data(), Zip64ExtendedInfo::kHeaderId);
+    android::base::put_unaligned(extended_field.data() + 2, data_size);
+    size_t offset = 4;
+    for (const auto& field : zip64_fields) {
+      android::base::put_unaligned(extended_field.data() + offset, field);
+      offset += 8;
+    }
+
+    *output = std::move(extended_field);
+  }
+
+  static void ConstructCentralDirectoryRecord(const std::string& name, uint32_t uncompressed_size,
+                                              uint32_t compressed_size, uint32_t local_offset,
+                                              std::vector<uint8_t>* output) {
+    CentralDirectoryRecord cdr = {};
+    cdr.record_signature = CentralDirectoryRecord::kSignature;
+    cdr.compressed_size = uncompressed_size;
+    cdr.uncompressed_size = compressed_size;
+    cdr.file_name_length = static_cast<uint16_t>(name.size());
+    cdr.extra_field_length = local_offset == UINT32_MAX ? 28 : 20;
+    cdr.local_file_header_offset = local_offset;
+    *output =
+        std::vector<uint8_t>(reinterpret_cast<uint8_t*>(&cdr),
+                             reinterpret_cast<uint8_t*>(&cdr) + sizeof(CentralDirectoryRecord));
+  }
+
+  // Add an entry to the zipfile, construct the corresponding local header and cd entry.
+  void AddEntry(const std::string& name, const std::vector<uint8_t>& content,
+                bool uncompressed_size_in_extended, bool compressed_size_in_extended,
+                bool local_offset_in_extended, bool include_data_descriptor = false) {
+    auto uncompressed_size = static_cast<uint32_t>(content.size());
+    auto compressed_size = static_cast<uint32_t>(content.size());
+    uint32_t local_file_header_offset = 0;
+    std::for_each(file_entries_.begin(), file_entries_.end(),
+                  [&local_file_header_offset](const LocalFileEntry& file_entry) {
+                    local_file_header_offset += file_entry.GetSize();
+                  });
+
+    std::vector<uint64_t> zip64_fields;
+    if (uncompressed_size_in_extended) {
+      zip64_fields.push_back(uncompressed_size);
+      uncompressed_size = UINT32_MAX;
+    }
+    if (compressed_size_in_extended) {
+      zip64_fields.push_back(compressed_size);
+      compressed_size = UINT32_MAX;
+    }
+    LocalFileEntry local_entry = {
+        .local_file_header = {},
+        .file_name = name,
+        .extended_field = {},
+        .compressed_bytes = content,
+    };
+    ConstructLocalFileHeader(name, &local_entry.local_file_header, uncompressed_size,
+                             compressed_size);
+    ConstructExtendedField(zip64_fields, &local_entry.extended_field);
+    if (include_data_descriptor) {
+      size_t descriptor_size = compressed_size_in_extended ? 24 : 16;
+      local_entry.data_descriptor.resize(descriptor_size);
+      uint8_t* write_ptr = local_entry.data_descriptor.data();
+      EmitUnaligned<uint32_t>(&write_ptr, DataDescriptor::kOptSignature);
+      EmitUnaligned<uint32_t>(&write_ptr, 0 /* crc */);
+      if (compressed_size_in_extended) {
+        EmitUnaligned<uint64_t>(&write_ptr, compressed_size_in_extended);
+        EmitUnaligned<uint64_t>(&write_ptr, uncompressed_size_in_extended);
+      } else {
+        EmitUnaligned<uint32_t>(&write_ptr, compressed_size_in_extended);
+        EmitUnaligned<uint32_t>(&write_ptr, uncompressed_size_in_extended);
+      }
+    }
+
+    file_entries_.push_back(std::move(local_entry));
+
+    if (local_offset_in_extended) {
+      zip64_fields.push_back(local_file_header_offset);
+      local_file_header_offset = UINT32_MAX;
+    }
+    CdRecordEntry cd_entry = {
+        .central_directory_record = {},
+        .file_name = name,
+        .extended_field = {},
+    };
+    ConstructCentralDirectoryRecord(name, uncompressed_size, compressed_size,
+                                    local_file_header_offset, &cd_entry.central_directory_record);
+    ConstructExtendedField(zip64_fields, &cd_entry.extended_field);
+    cd_entries_.push_back(std::move(cd_entry));
+  }
+
+  void ConstructEocd() {
+    ASSERT_EQ(file_entries_.size(), cd_entries_.size());
+    Zip64EocdRecord zip64_eocd = {};
+    zip64_eocd.record_signature = Zip64EocdRecord::kSignature;
+    zip64_eocd.num_records = file_entries_.size();
+    zip64_eocd.cd_size = 0;
+    std::for_each(
+        cd_entries_.begin(), cd_entries_.end(),
+        [&zip64_eocd](const CdRecordEntry& cd_entry) { zip64_eocd.cd_size += cd_entry.GetSize(); });
+    zip64_eocd.cd_start_offset = 0;
+    std::for_each(file_entries_.begin(), file_entries_.end(),
+                  [&zip64_eocd](const LocalFileEntry& file_entry) {
+                    zip64_eocd.cd_start_offset += file_entry.GetSize();
+                  });
+    zip64_eocd_record_ =
+        std::vector<uint8_t>(reinterpret_cast<uint8_t*>(&zip64_eocd),
+                             reinterpret_cast<uint8_t*>(&zip64_eocd) + sizeof(Zip64EocdRecord));
+
+    Zip64EocdLocator zip64_locator = {};
+    zip64_locator.locator_signature = Zip64EocdLocator::kSignature;
+    zip64_locator.zip64_eocd_offset = zip64_eocd.cd_start_offset + zip64_eocd.cd_size;
+    zip64_eocd_locator_ =
+        std::vector<uint8_t>(reinterpret_cast<uint8_t*>(&zip64_locator),
+                             reinterpret_cast<uint8_t*>(&zip64_locator) + sizeof(Zip64EocdLocator));
+
+    EocdRecord eocd = {};
+    eocd.eocd_signature = EocdRecord::kSignature,
+    eocd.num_records = file_entries_.size() > UINT16_MAX
+                           ? UINT16_MAX
+                           : static_cast<uint16_t>(file_entries_.size());
+    eocd.cd_size = UINT32_MAX;
+    eocd.cd_start_offset = UINT32_MAX;
+    eocd_record_ = std::vector<uint8_t>(reinterpret_cast<uint8_t*>(&eocd),
+                                        reinterpret_cast<uint8_t*>(&eocd) + sizeof(EocdRecord));
+  }
+
+  // Concatenate all the local file entries, cd entries, and eocd metadata.
+  void ConstructZipFile() {
+    for (const auto& file_entry : file_entries_) {
+      file_entry.CopyToOutput(&zip_content_);
+    }
+    for (const auto& cd_entry : cd_entries_) {
+      cd_entry.CopyToOutput(&zip_content_);
+    }
+    std::copy(zip64_eocd_record_.begin(), zip64_eocd_record_.end(),
+              std::back_inserter(zip_content_));
+    std::copy(zip64_eocd_locator_.begin(), zip64_eocd_locator_.end(),
+              std::back_inserter(zip_content_));
+    std::copy(eocd_record_.begin(), eocd_record_.end(), std::back_inserter(zip_content_));
+  }
+
+  std::vector<uint8_t> zip_content_;
+
+  std::vector<LocalFileEntry> file_entries_;
+  std::vector<CdRecordEntry> cd_entries_;
+  std::vector<uint8_t> zip64_eocd_record_;
+  std::vector<uint8_t> zip64_eocd_locator_;
+  std::vector<uint8_t> eocd_record_;
+};
+
+TEST_F(Zip64ParseTest, openFile) {
+  AddEntry("a.txt", std::vector<uint8_t>(100, 'a'), true, true, false);
+  ConstructEocd();
+  ConstructZipFile();
+
+  ZipArchiveHandle handle;
+  ASSERT_EQ(
+      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
+  CloseArchive(handle);
+}
+
+TEST_F(Zip64ParseTest, openFilelocalOffsetInExtendedField) {
+  AddEntry("a.txt", std::vector<uint8_t>(100, 'a'), true, true, true);
+  AddEntry("b.txt", std::vector<uint8_t>(200, 'b'), true, true, true);
+  ConstructEocd();
+  ConstructZipFile();
+
+  ZipArchiveHandle handle;
+  ASSERT_EQ(
+      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
+  CloseArchive(handle);
+}
+
+TEST_F(Zip64ParseTest, openFileCompressedNotInExtendedField) {
+  AddEntry("a.txt", std::vector<uint8_t>(100, 'a'), true, false, false);
+  ConstructEocd();
+  ConstructZipFile();
+
+  ZipArchiveHandle handle;
+  // Zip64 extended fields must include both uncompressed and compressed size.
+  ASSERT_NE(
+      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
+  CloseArchive(handle);
+}
+
+TEST_F(Zip64ParseTest, findEntry) {
+  AddEntry("a.txt", std::vector<uint8_t>(200, 'a'), true, true, true);
+  AddEntry("b.txt", std::vector<uint8_t>(300, 'b'), true, true, false);
+  ConstructEocd();
+  ConstructZipFile();
+
+  ZipArchiveHandle handle;
+  ASSERT_EQ(
+      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
+  ZipEntry entry;
+  ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry));
+  ASSERT_EQ(200, entry.uncompressed_length);
+  ASSERT_EQ(200, entry.compressed_length);
+
+  ASSERT_EQ(0, FindEntry(handle, "b.txt", &entry));
+  ASSERT_EQ(300, entry.uncompressed_length);
+  ASSERT_EQ(300, entry.compressed_length);
+  CloseArchive(handle);
+}
+
+TEST_F(Zip64ParseTest, openFileIncorrectDataSizeInLocalExtendedField) {
+  AddEntry("a.txt", std::vector<uint8_t>(100, 'a'), true, true, false);
+  ASSERT_EQ(1, file_entries_.size());
+  auto& extended_field = file_entries_[0].extended_field;
+  // data size exceeds the extended field size in local header.
+  android::base::put_unaligned<uint16_t>(extended_field.data() + 2, 30);
+  ConstructEocd();
+  ConstructZipFile();
+
+  ZipArchiveHandle handle;
+  ASSERT_EQ(
+      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
+  ZipEntry entry;
+  ASSERT_NE(0, FindEntry(handle, "a.txt", &entry));
+
+  CloseArchive(handle);
+}
+
+TEST_F(Zip64ParseTest, iterates) {
+  std::set<std::string_view> names{"a.txt", "b.txt", "c.txt", "d.txt", "e.txt"};
+  for (const auto& name : names) {
+    AddEntry(std::string(name), std::vector<uint8_t>(100, name[0]), true, true, true);
+  }
+  ConstructEocd();
+  ConstructZipFile();
+
+  ZipArchiveHandle handle;
+  ASSERT_EQ(
+      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
+
+  void* iteration_cookie;
+  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie));
+  std::set<std::string_view> result;
+  std::string_view name;
+  ZipEntry entry;
+  while (Next(iteration_cookie, &entry, &name) == 0) result.emplace(name);
+  ASSERT_EQ(names, result);
+
+  CloseArchive(handle);
+}
+
+TEST_F(Zip64ParseTest, zip64EocdWrongLocatorOffset) {
+  AddEntry("a.txt", std::vector<uint8_t>(1, 'a'), true, true, true);
+  ConstructEocd();
+  zip_content_.resize(20, 'a');
+  std::copy(zip64_eocd_locator_.begin(), zip64_eocd_locator_.end(),
+            std::back_inserter(zip_content_));
+  std::copy(eocd_record_.begin(), eocd_record_.end(), std::back_inserter(zip_content_));
+
+  ZipArchiveHandle handle;
+  ASSERT_NE(
+      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
+  CloseArchive(handle);
+}
+
+TEST_F(Zip64ParseTest, extract) {
+  std::vector<uint8_t> content(200, 'a');
+  AddEntry("a.txt", content, true, true, true);
+  ConstructEocd();
+  ConstructZipFile();
+
+  ZipArchiveHandle handle;
+  ASSERT_EQ(
+      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
+  ZipEntry entry;
+  ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry));
+
+  VectorWriter writer;
+  ASSERT_EQ(0, ExtractToWriter(handle, &entry, &writer));
+  ASSERT_EQ(content, writer.GetOutput());
+}
+
+TEST_F(Zip64ParseTest, extractWithDataDescriptor) {
+  std::vector<uint8_t> content(300, 'b');
+  AddEntry("a.txt", std::vector<uint8_t>(200, 'a'), true, true, true);
+  AddEntry("b.txt", content, true, true, true, true /* data descriptor */);
+  ConstructEocd();
+  ConstructZipFile();
+
+  ZipArchiveHandle handle;
+  ASSERT_EQ(
+      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
+  ZipEntry entry;
+  ASSERT_EQ(0, FindEntry(handle, "b.txt", &entry));
+
+  VectorWriter writer;
+  ASSERT_EQ(0, ExtractToWriter(handle, &entry, &writer));
+  ASSERT_EQ(content, writer.GetOutput());
+}
diff --git a/libziparchive/zip_cd_entry_map.cc b/libziparchive/zip_cd_entry_map.cc
new file mode 100644
index 0000000..f187c06
--- /dev/null
+++ b/libziparchive/zip_cd_entry_map.cc
@@ -0,0 +1,156 @@
+/*
+ * 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 "zip_cd_entry_map.h"
+
+#include <android-base/logging.h>
+#include <log/log.h>
+
+/*
+ * Round up to the next highest power of 2.
+ *
+ * Found on http://graphics.stanford.edu/~seander/bithacks.html.
+ */
+static uint32_t RoundUpPower2(uint32_t val) {
+  val--;
+  val |= val >> 1;
+  val |= val >> 2;
+  val |= val >> 4;
+  val |= val >> 8;
+  val |= val >> 16;
+  val++;
+
+  return val;
+}
+
+static uint32_t ComputeHash(std::string_view name) {
+  return static_cast<uint32_t>(std::hash<std::string_view>{}(name));
+}
+
+// Convert a ZipEntry to a hash table index, verifying that it's in a valid range.
+std::pair<ZipError, uint64_t> CdEntryMapZip32::GetCdEntryOffset(std::string_view name,
+                                                                const uint8_t* start) const {
+  const uint32_t hash = ComputeHash(name);
+
+  // NOTE: (hash_table_size - 1) is guaranteed to be non-negative.
+  uint32_t ent = hash & (hash_table_size_ - 1);
+  while (hash_table_[ent].name_offset != 0) {
+    if (hash_table_[ent].ToStringView(start) == name) {
+      return {kSuccess, hash_table_[ent].name_offset};
+    }
+    ent = (ent + 1) & (hash_table_size_ - 1);
+  }
+
+  ALOGV("Zip: Unable to find entry %.*s", static_cast<int>(name.size()), name.data());
+  return {kEntryNotFound, 0};
+}
+
+ZipError CdEntryMapZip32::AddToMap(std::string_view name, const uint8_t* start) {
+  const uint64_t hash = ComputeHash(name);
+  uint32_t ent = hash & (hash_table_size_ - 1);
+
+  /*
+   * We over-allocated the table, so we're guaranteed to find an empty slot.
+   * Further, we guarantee that the hashtable size is not 0.
+   */
+  while (hash_table_[ent].name_offset != 0) {
+    if (hash_table_[ent].ToStringView(start) == name) {
+      // We've found a duplicate entry. We don't accept duplicates.
+      ALOGW("Zip: Found duplicate entry %.*s", static_cast<int>(name.size()), name.data());
+      return kDuplicateEntry;
+    }
+    ent = (ent + 1) & (hash_table_size_ - 1);
+  }
+
+  // `name` has already been validated before entry.
+  const char* start_char = reinterpret_cast<const char*>(start);
+  hash_table_[ent].name_offset = static_cast<uint32_t>(name.data() - start_char);
+  hash_table_[ent].name_length = static_cast<uint16_t>(name.size());
+  return kSuccess;
+}
+
+void CdEntryMapZip32::ResetIteration() {
+  current_position_ = 0;
+}
+
+std::pair<std::string_view, uint64_t> CdEntryMapZip32::Next(const uint8_t* cd_start) {
+  while (current_position_ < hash_table_size_) {
+    const auto& entry = hash_table_[current_position_];
+    current_position_ += 1;
+
+    if (entry.name_offset != 0) {
+      return {entry.ToStringView(cd_start), entry.name_offset};
+    }
+  }
+  // We have reached the end of the hash table.
+  return {};
+}
+
+CdEntryMapZip32::CdEntryMapZip32(uint16_t num_entries) {
+  /*
+   * Create hash table.  We have a minimum 75% load factor, possibly as
+   * low as 50% after we round off to a power of 2.  There must be at
+   * least one unused entry to avoid an infinite loop during creation.
+   */
+  hash_table_size_ = RoundUpPower2(1 + (num_entries * 4) / 3);
+  hash_table_ = {
+      reinterpret_cast<ZipStringOffset*>(calloc(hash_table_size_, sizeof(ZipStringOffset))), free};
+}
+
+std::unique_ptr<CdEntryMapInterface> CdEntryMapZip32::Create(uint16_t num_entries) {
+  auto entry_map = new CdEntryMapZip32(num_entries);
+  CHECK(entry_map->hash_table_ != nullptr)
+      << "Zip: unable to allocate the " << entry_map->hash_table_size_
+      << " entry hash_table, entry size: " << sizeof(ZipStringOffset);
+  return std::unique_ptr<CdEntryMapInterface>(entry_map);
+}
+
+std::unique_ptr<CdEntryMapInterface> CdEntryMapZip64::Create() {
+  return std::unique_ptr<CdEntryMapInterface>(new CdEntryMapZip64());
+}
+
+ZipError CdEntryMapZip64::AddToMap(std::string_view name, const uint8_t* start) {
+  const auto [it, added] =
+      entry_table_.insert({name, name.data() - reinterpret_cast<const char*>(start)});
+  if (!added) {
+    ALOGW("Zip: Found duplicate entry %.*s", static_cast<int>(name.size()), name.data());
+    return kDuplicateEntry;
+  }
+  return kSuccess;
+}
+
+std::pair<ZipError, uint64_t> CdEntryMapZip64::GetCdEntryOffset(std::string_view name,
+                                                                const uint8_t* /*cd_start*/) const {
+  const auto it = entry_table_.find(name);
+  if (it == entry_table_.end()) {
+    ALOGV("Zip: Could not find entry %.*s", static_cast<int>(name.size()), name.data());
+    return {kEntryNotFound, 0};
+  }
+
+  return {kSuccess, it->second};
+}
+
+void CdEntryMapZip64::ResetIteration() {
+  iterator_ = entry_table_.begin();
+}
+
+std::pair<std::string_view, uint64_t> CdEntryMapZip64::Next(const uint8_t* /*cd_start*/) {
+  if (iterator_ == entry_table_.end()) {
+    return {};
+  }
+
+  return *iterator_++;
+}
diff --git a/libziparchive/zip_cd_entry_map.h b/libziparchive/zip_cd_entry_map.h
new file mode 100644
index 0000000..4957f75
--- /dev/null
+++ b/libziparchive/zip_cd_entry_map.h
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string_view>
+#include <utility>
+
+#include "zip_error.h"
+
+// This class is the interface of the central directory entries map. The map
+// helps to locate a particular cd entry based on the filename.
+class CdEntryMapInterface {
+ public:
+  virtual ~CdEntryMapInterface() = default;
+  // Adds an entry to the map. The |name| should internally points to the
+  // filename field of a cd entry. And |start| points to the beginning of the
+  // central directory. Returns 0 on success.
+  virtual ZipError AddToMap(std::string_view name, const uint8_t* start) = 0;
+  // For the zip entry |entryName|, finds the offset of its filename field in
+  // the central directory. Returns a pair of [status, offset]. The value of
+  // the status is 0 on success.
+  virtual std::pair<ZipError, uint64_t> GetCdEntryOffset(std::string_view name,
+                                                         const uint8_t* cd_start) const = 0;
+  // Resets the iterator to the beginning of the map.
+  virtual void ResetIteration() = 0;
+  // Returns the [name, cd offset] of the current element. Also increments the
+  // iterator to points to the next element. Returns an empty pair we have read
+  // past boundary.
+  virtual std::pair<std::string_view, uint64_t> Next(const uint8_t* cd_start) = 0;
+};
+
+/**
+ * More space efficient string representation of strings in an mmaped zipped
+ * file than std::string_view. Using std::string_view as an entry in the
+ * ZipArchive hash table wastes space. std::string_view stores a pointer to a
+ * string (on 64 bit, 8 bytes) and the length to read from that pointer,
+ * 2 bytes. Because of alignment, the structure consumes 16 bytes, wasting
+ * 6 bytes.
+ *
+ * ZipStringOffset stores a 4 byte offset from a fixed location in the memory
+ * mapped file instead of the entire address, consuming 8 bytes with alignment.
+ */
+struct ZipStringOffset {
+  uint32_t name_offset;
+  uint16_t name_length;
+
+  const std::string_view ToStringView(const uint8_t* start) const {
+    return std::string_view{reinterpret_cast<const char*>(start + name_offset), name_length};
+  }
+};
+
+// This implementation of CdEntryMap uses an array hash table. It uses less
+// memory than std::map; and it's used as the default implementation for zip
+// archives without zip64 extension.
+class CdEntryMapZip32 : public CdEntryMapInterface {
+ public:
+  static std::unique_ptr<CdEntryMapInterface> Create(uint16_t num_entries);
+
+  ZipError AddToMap(std::string_view name, const uint8_t* start) override;
+  std::pair<ZipError, uint64_t> GetCdEntryOffset(std::string_view name,
+                                                 const uint8_t* cd_start) const override;
+  void ResetIteration() override;
+  std::pair<std::string_view, uint64_t> Next(const uint8_t* cd_start) override;
+
+ private:
+  explicit CdEntryMapZip32(uint16_t num_entries);
+
+  // We know how many entries are in the Zip archive, so we can have a
+  // fixed-size hash table. We define a load factor of 0.75 and over
+  // allocate so the maximum number entries can never be higher than
+  // ((4 * UINT16_MAX) / 3 + 1) which can safely fit into a uint32_t.
+  uint32_t hash_table_size_{0};
+  std::unique_ptr<ZipStringOffset[], decltype(&free)> hash_table_{nullptr, free};
+
+  // The position of element for the current iteration.
+  uint32_t current_position_{0};
+};
+
+// This implementation of CdEntryMap uses a std::map
+class CdEntryMapZip64 : public CdEntryMapInterface {
+ public:
+  static std::unique_ptr<CdEntryMapInterface> Create();
+
+  ZipError AddToMap(std::string_view name, const uint8_t* start) override;
+  std::pair<ZipError, uint64_t> GetCdEntryOffset(std::string_view name,
+                                                 const uint8_t* cd_start) const override;
+  void ResetIteration() override;
+  std::pair<std::string_view, uint64_t> Next(const uint8_t* cd_start) override;
+
+ private:
+  CdEntryMapZip64() = default;
+
+  std::map<std::string_view, uint64_t> entry_table_;
+
+  std::map<std::string_view, uint64_t>::iterator iterator_;
+};
diff --git a/libziparchive/zip_error.cpp b/libziparchive/zip_error.cpp
new file mode 100644
index 0000000..107ec47
--- /dev/null
+++ b/libziparchive/zip_error.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 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 "zip_error.h"
+
+#include <android-base/macros.h>
+
+static const char* kErrorMessages[] = {
+    "Success",
+    "Iteration ended",
+    "Zlib error",
+    "Invalid file",
+    "Invalid handle",
+    "Duplicate entries in archive",
+    "Empty archive",
+    "Entry not found",
+    "Invalid offset",
+    "Inconsistent information",
+    "Invalid entry name",
+    "I/O error",
+    "File mapping failed",
+    "Allocation failed",
+};
+
+const char* ErrorCodeString(int32_t error_code) {
+  // Make sure that the number of entries in kErrorMessages and the ZipError
+  // enum match.
+  static_assert((-kLastErrorCode + 1) == arraysize(kErrorMessages),
+                "(-kLastErrorCode + 1) != arraysize(kErrorMessages)");
+
+  const uint32_t idx = -error_code;
+  if (idx < arraysize(kErrorMessages)) {
+    return kErrorMessages[idx];
+  }
+
+  return "Unknown return code";
+}
diff --git a/libziparchive/zip_error.h b/libziparchive/zip_error.h
new file mode 100644
index 0000000..37fd55f
--- /dev/null
+++ b/libziparchive/zip_error.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+enum ZipError : int32_t {
+  kSuccess = 0,
+
+  kIterationEnd = -1,
+
+  // We encountered a Zlib error when inflating a stream from this file.
+  // Usually indicates file corruption.
+  kZlibError = -2,
+
+  // The input file cannot be processed as a zip archive. Usually because
+  // it's too small, too large or does not have a valid signature.
+  kInvalidFile = -3,
+
+  // An invalid iteration / ziparchive handle was passed in as an input
+  // argument.
+  kInvalidHandle = -4,
+
+  // The zip archive contained two (or possibly more) entries with the same
+  // name.
+  kDuplicateEntry = -5,
+
+  // The zip archive contains no entries.
+  kEmptyArchive = -6,
+
+  // The specified entry was not found in the archive.
+  kEntryNotFound = -7,
+
+  // The zip archive contained an invalid local file header pointer.
+  kInvalidOffset = -8,
+
+  // The zip archive contained inconsistent entry information. This could
+  // be because the central directory & local file header did not agree, or
+  // if the actual uncompressed length or crc32 do not match their declared
+  // values.
+  kInconsistentInformation = -9,
+
+  // An invalid entry name was encountered.
+  kInvalidEntryName = -10,
+
+  // An I/O related system call (read, lseek, ftruncate, map) failed.
+  kIoError = -11,
+
+  // We were not able to mmap the central directory or entry contents.
+  kMmapFailed = -12,
+
+  // An allocation failed.
+  kAllocationFailed = -13,
+
+  kLastErrorCode = kAllocationFailed,
+};
diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc
index 67279a6..25b1da4 100644
--- a/libziparchive/zip_writer.cc
+++ b/libziparchive/zip_writer.cc
@@ -475,19 +475,16 @@
   if (ShouldUseDataDescriptor()) {
     // Some versions of ZIP don't allow STORED data to have a trailing DataDescriptor.
     // If this file is not seekable, or if the data is compressed, write a DataDescriptor.
-    const uint32_t sig = DataDescriptor::kOptSignature;
-    if (fwrite(&sig, sizeof(sig), 1, file_) != 1) {
+    // We haven't supported zip64 format yet. Write both uncompressed size and compressed
+    // size as uint32_t.
+    std::vector<uint32_t> dataDescriptor = {
+        DataDescriptor::kOptSignature, current_file_entry_.crc32,
+        current_file_entry_.compressed_size, current_file_entry_.uncompressed_size};
+    if (fwrite(dataDescriptor.data(), dataDescriptor.size() * sizeof(uint32_t), 1, file_) != 1) {
       return HandleError(kIoError);
     }
 
-    DataDescriptor dd = {};
-    dd.crc32 = current_file_entry_.crc32;
-    dd.compressed_size = current_file_entry_.compressed_size;
-    dd.uncompressed_size = current_file_entry_.uncompressed_size;
-    if (fwrite(&dd, sizeof(dd), 1, file_) != 1) {
-      return HandleError(kIoError);
-    }
-    current_offset_ += sizeof(DataDescriptor::kOptSignature) + sizeof(dd);
+    current_offset_ += sizeof(uint32_t) * dataDescriptor.size();
   } else {
     // Seek back to the header and rewrite to include the size.
     if (fseeko(file_, current_file_entry_.local_file_header_offset, SEEK_SET) != 0) {
diff --git a/libziparchive/ziptool.cpp b/libziparchive/ziptool.cpp
index dd42e90..f345ffc 100644
--- a/libziparchive/ziptool.cpp
+++ b/libziparchive/ziptool.cpp
@@ -133,8 +133,8 @@
     if (!flag_1 && includes.empty() && excludes.empty()) {
       ZipArchiveInfo info{GetArchiveInfo(zah)};
       printf("Archive:  %s\n", archive_name);
-      printf("Zip file size: %" PRId64 " bytes, number of entries: %zu\n", info.archive_size,
-             info.entry_count);
+      printf("Zip file size: %" PRId64 " bytes, number of entries: %" PRIu64 "\n",
+             info.archive_size, info.entry_count);
     }
   }
 }
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 76a970f..b065855 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -513,7 +513,7 @@
     unsigned long setLogSize = 0;
     const char* setPruneList = nullptr;
     const char* setId = nullptr;
-    int mode = ANDROID_LOG_RDONLY;
+    int mode = 0;
     std::string forceFilters;
     size_t tail_lines = 0;
     log_time tail_time(log_time::EPOCH);
@@ -591,8 +591,7 @@
                     break;
                 }
                 if (long_options[option_index].name == wrap_str) {
-                    mode |= ANDROID_LOG_WRAP | ANDROID_LOG_RDONLY |
-                            ANDROID_LOG_NONBLOCK;
+                    mode |= ANDROID_LOG_WRAP | ANDROID_LOG_NONBLOCK;
                     // ToDo: implement API that supports setting a wrap timeout
                     size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
                     if (optarg && (!ParseUint(optarg, &dummy) || dummy < 1)) {
@@ -626,21 +625,19 @@
 
             case 'c':
                 clearLog = true;
-                mode |= ANDROID_LOG_WRONLY;
                 break;
 
             case 'L':
-                mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_PSTORE |
-                        ANDROID_LOG_NONBLOCK;
+                mode |= ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK;
                 break;
 
             case 'd':
-                mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
+                mode |= ANDROID_LOG_NONBLOCK;
                 break;
 
             case 't':
                 got_t = true;
-                mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
+                mode |= ANDROID_LOG_NONBLOCK;
                 FALLTHROUGH_INTENDED;
             case 'T':
                 if (strspn(optarg, "0123456789") != strlen(optarg)) {
diff --git a/logd/LogTags.cpp b/logd/LogTags.cpp
index 0cc7886..8299e66 100644
--- a/logd/LogTags.cpp
+++ b/logd/LogTags.cpp
@@ -289,9 +289,8 @@
 // special pmsg event for log tags, and build up our internal
 // database with any found.
 void LogTags::ReadPersistEventLogTags() {
-    struct logger_list* logger_list = android_logger_list_alloc(
-        ANDROID_LOG_RDONLY | ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK, 0,
-        (pid_t)0);
+    struct logger_list* logger_list =
+            android_logger_list_alloc(ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK, 0, (pid_t)0);
     if (!logger_list) return;
 
     struct logger* e = android_logger_open(logger_list, LOG_ID_EVENTS);
diff --git a/logd/tests/Android.bp b/logd/tests/Android.bp
index d39da8a..2519a84 100644
--- a/logd/tests/Android.bp
+++ b/logd/tests/Android.bp
@@ -64,5 +64,6 @@
     test_suites: [
         "cts",
         "vts",
+        "vts10",
     ],
 }
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index f47bee1..c7f3480 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -870,10 +870,8 @@
     ASSERT_EQ(0, info.si_status);
 
     struct logger_list* logger_list;
-    ASSERT_TRUE(nullptr !=
-                (logger_list = android_logger_list_open(
-                     LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
-                     0, pid)));
+    ASSERT_TRUE(nullptr != (logger_list = android_logger_list_open(LOG_ID_EVENTS,
+                                                                   ANDROID_LOG_NONBLOCK, 0, pid)));
 
     int expected_count = (count < 2) ? count : 2;
     int expected_chatty_count = (count <= 2) ? 0 : 1;
diff --git a/qemu_pipe/Android.bp b/qemu_pipe/Android.bp
index c6bda4a..ad86a4e 100644
--- a/qemu_pipe/Android.bp
+++ b/qemu_pipe/Android.bp
@@ -4,6 +4,11 @@
     name: "libqemu_pipe",
     vendor_available: true,
     recovery_available: true,
+    apex_available: [
+        "com.android.adbd",
+        // TODO(b/151398197) remove the below
+        "//apex_available:platform",
+    ],
     sanitize: {
         misc_undefined: ["integer"],
     },
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 53d9f8f..645c87b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -743,7 +743,7 @@
     mkdir /data/misc/train-info/ 0770 statsd system
 
     # Wait for apexd to finish activating APEXes before starting more processes.
-    wait_for_prop apexd.status ready
+    wait_for_prop apexd.status activated
     perform_apex_config
 
     # Special-case /data/media/obb per b/64566063
@@ -758,7 +758,7 @@
     # Allow apexd to snapshot and restore device encrypted apex data in the case
     # of a rollback. This should be done immediately after DE_user data keys
     # are loaded. APEXes should not access this data until this has been
-    # completed.
+    # completed and apexd.status becomes "ready".
     exec_start apexd-snapshotde
 
     # Set SELinux security contexts on upgrade or policy update.
@@ -825,6 +825,11 @@
     start zygote
     start zygote_secondary
 
+on boot && property:ro.config.low_ram=true
+    # Tweak background writeout
+    write /proc/sys/vm/dirty_expire_centisecs 200
+    write /proc/sys/vm/dirty_background_ratio  5
+
 on boot
     # basic network init
     ifup lo
@@ -846,11 +851,7 @@
     chown root system /sys/block/zram0/writeback
     chmod 0664 /sys/block/zram0/writeback
 
-    # Tweak background writeout
-    write /proc/sys/vm/dirty_expire_centisecs 200
-    write /proc/sys/vm/dirty_background_ratio  5
-
-    # F2FS tuning. Set cp_interval larger than dirty_expire_centisecs
+    # F2FS tuning. Set cp_interval larger than dirty_expire_centisecs, 30 secs,
     # to avoid power consumption when system becomes mostly idle. Be careful
     # to make it too large, since it may bring userdata loss, if they
     # are not aware of using fsync()/sync() to prepare sudden power-cut.
diff --git a/run-as/run-as.cpp b/run-as/run-as.cpp
index 432c434..cc92c68 100644
--- a/run-as/run-as.cpp
+++ b/run-as/run-as.cpp
@@ -247,12 +247,12 @@
 
   std::string seinfo = std::string(info.seinfo) + ":fromRunAs";
   if (selinux_android_setcontext(uid, 0, seinfo.c_str(), pkgname) < 0) {
-    error(1, errno, "couldn't set SELinux security context");
+    error(1, errno, "couldn't set SELinux security context '%s'", seinfo.c_str());
   }
 
   // cd into the data directory, and set $HOME correspondingly.
   if (TEMP_FAILURE_RETRY(chdir(info.data_dir)) == -1) {
-    error(1, errno, "couldn't chdir to package's data directory");
+    error(1, errno, "couldn't chdir to package's data directory '%s'", info.data_dir);
   }
   setenv("HOME", info.data_dir, 1);
 
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index f32a69e..6840baa 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -14,70 +14,6 @@
 // limitations under the License.
 //
 
-// WARNING: Everything listed here will be built on ALL platforms,
-// including x86, the emulator, and the SDK.  Modules must be uniquely
-// named (liblights.panda), and must build everywhere, or limit themselves
-// to only building on ARM if they include assembly. Individual makefiles
-// are responsible for having their own logic, for fine-grained control.
-
-// trusty_keymaster is a binary used only for on-device testing.  It
-// runs Trusty Keymaster through a basic set of operations with RSA
-// and ECDSA keys.
-cc_binary {
-    name: "trusty_keymaster_tipc",
-    vendor: true,
-    srcs: [
-        "ipc/trusty_keymaster_ipc.cpp",
-        "legacy/trusty_keymaster_device.cpp",
-        "legacy/trusty_keymaster_main.cpp",
-    ],
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-
-    local_include_dirs: ["include"],
-
-    shared_libs: [
-        "libcrypto",
-        "libcutils",
-        "libkeymaster_portable",
-        "libtrusty",
-        "libkeymaster_messages",
-        "libsoftkeymasterdevice",
-        "liblog",
-    ],
-}
-
-// keystore.trusty is the HAL used by keystore on Trusty devices.
-cc_library_shared {
-    name: "keystore.trusty",
-    vendor: true,
-    relative_install_path: "hw",
-    srcs: [
-        "ipc/trusty_keymaster_ipc.cpp",
-        "legacy/module.cpp",
-        "legacy/trusty_keymaster_device.cpp",
-    ],
-
-    cflags: [
-        "-fvisibility=hidden",
-        "-Wall",
-        "-Werror",
-    ],
-
-    local_include_dirs: ["include"],
-
-    shared_libs: [
-        "libcrypto",
-        "libkeymaster_messages",
-        "libtrusty",
-        "liblog",
-        "libcutils",
-    ],
-    header_libs: ["libhardware_headers"],
-}
-
 cc_binary {
     name: "android.hardware.keymaster@3.0-service.trusty",
     defaults: ["hidl_defaults"],
diff --git a/trusty/keymaster/legacy/Makefile b/trusty/keymaster/legacy/Makefile
deleted file mode 100644
index f575381..0000000
--- a/trusty/keymaster/legacy/Makefile
+++ /dev/null
@@ -1,199 +0,0 @@
-#####
-# Local unit test Makefile
-#
-# This makefile builds and runs the trusty_keymaster unit tests locally on the development
-# machine, not on an Android device.
-#
-# To build and run these tests, one pre-requisite must be manually installed: BoringSSL.
-# This Makefile expects to find BoringSSL in a directory adjacent to $ANDROID_BUILD_TOP.
-# To get and build it, first install the Ninja build tool (e.g. apt-get install
-# ninja-build), then do:
-#
-# cd $ANDROID_BUILD_TOP/..
-# git clone https://boringssl.googlesource.com/boringssl
-# cd boringssl
-# mdkir build
-# cd build
-# cmake -GNinja ..
-# ninja
-#
-# Then return to $ANDROID_BUILD_TOP/system/keymaster and run "make".
-#####
-
-BASE=../../../..
-SUBS=system/core \
-	system/keymaster \
-	hardware/libhardware \
-	external/gtest
-GTEST=$(BASE)/external/gtest
-KM=$(BASE)/system/keymaster
-
-INCLUDES=$(foreach dir,$(SUBS),-I $(BASE)/$(dir)/include) \
-	-I $(BASE)/libnativehelper/include/nativehelper \
-	-I ../tipc/include \
-	-I $(BASE)/system/keymaster \
-	-I $(GTEST) \
-	-I$(BASE)/../boringssl/include
-
-ifdef USE_CLANG
-CC=/usr/bin/clang
-CXX=/usr/bin/clang
-CLANG_TEST_DEFINE=-DKEYMASTER_CLANG_TEST_BUILD
-COMPILER_SPECIFIC_ARGS=-std=c++11 $(CLANG_TEST_DEFINE)
-else
-COMPILER_SPECIFIC_ARGS=-std=c++0x -fprofile-arcs
-endif
-
-CPPFLAGS=$(INCLUDES) -g -O0 -MD
-CXXFLAGS=-Wall -Werror -Wno-unused -Winit-self -Wpointer-arith	-Wunused-parameter \
-	-Wmissing-declarations -ftest-coverage \
-	-Wno-deprecated-declarations -fno-exceptions -DKEYMASTER_NAME_TAGS \
-	$(COMPILER_SPECIFIC_ARGS)
-LDLIBS=-L$(BASE)/../boringssl/build/crypto -lcrypto -lpthread -lstdc++
-
-CPPSRCS=\
-	$(KM)/aead_mode_operation.cpp \
-	$(KM)/aes_key.cpp \
-	$(KM)/aes_operation.cpp \
-	$(KM)/android_keymaster.cpp \
-	$(KM)/android_keymaster_messages.cpp \
-	$(KM)/android_keymaster_messages_test.cpp \
-	$(KM)/android_keymaster_test.cpp \
-	$(KM)/android_keymaster_test_utils.cpp \
-	$(KM)/android_keymaster_utils.cpp \
-	$(KM)/asymmetric_key.cpp \
-	$(KM)/auth_encrypted_key_blob.cpp \
-	$(KM)/auth_encrypted_key_blob.cpp \
-	$(KM)/authorization_set.cpp \
-	$(KM)/authorization_set_test.cpp \
-	$(KM)/ec_key.cpp \
-	$(KM)/ec_keymaster0_key.cpp \
-	$(KM)/ecdsa_operation.cpp \
-	$(KM)/hmac_key.cpp \
-	$(KM)/hmac_operation.cpp \
-	$(KM)/integrity_assured_key_blob.cpp \
-	$(KM)/key.cpp \
-	$(KM)/key_blob_test.cpp \
-	$(KM)/keymaster0_engine.cpp \
-	$(KM)/logger.cpp \
-	$(KM)/ocb_utils.cpp \
-	$(KM)/openssl_err.cpp \
-	$(KM)/openssl_utils.cpp \
-	$(KM)/operation.cpp \
-	$(KM)/operation_table.cpp \
-	$(KM)/rsa_key.cpp \
-	$(KM)/rsa_keymaster0_key.cpp \
-	$(KM)/rsa_operation.cpp \
-	$(KM)/serializable.cpp \
-	$(KM)/soft_keymaster_context.cpp \
-	$(KM)/symmetric_key.cpp \
-	$(KM)/unencrypted_key_blob.cpp \
-	trusty_keymaster_device.cpp \
-	trusty_keymaster_device_test.cpp
-CCSRCS=$(GTEST)/src/gtest-all.cc
-CSRCS=ocb.c
-
-OBJS=$(CPPSRCS:.cpp=.o) $(CCSRCS:.cc=.o) $(CSRCS:.c=.o)
-DEPS=$(CPPSRCS:.cpp=.d) $(CCSRCS:.cc=.d) $(CSRCS:.c=.d)
-GCDA=$(CPPSRCS:.cpp=.gcda) $(CCSRCS:.cc=.gcda) $(CSRCS:.c=.gcda)
-GCNO=$(CPPSRCS:.cpp=.gcno) $(CCSRCS:.cc=.gcno) $(CSRCS:.c=.gcno)
-
-LINK.o=$(LINK.cc)
-
-BINARIES=trusty_keymaster_device_test
-
-ifdef TRUSTY
-BINARIES += trusty_keymaster_device_test
-endif # TRUSTY
-
-.PHONY: coverage memcheck massif clean run
-
-%.run: %
-	./$<
-	touch $@
-
-run: $(BINARIES:=.run)
-
-coverage: coverage.info
-	genhtml coverage.info --output-directory coverage
-
-coverage.info: run
-	lcov --capture --directory=. --output-file coverage.info
-
-%.coverage : %
-	$(MAKE) clean && $(MAKE) $<
-	./$<
-	lcov --capture --directory=. --output-file coverage.info
-	genhtml coverage.info --output-directory coverage
-
-#UNINIT_OPTS=--track-origins=yes
-UNINIT_OPTS=--undef-value-errors=no
-
-MEMCHECK_OPTS=--leak-check=full \
-	--show-reachable=yes \
-	--vgdb=full \
-	$(UNINIT_OPTS) \
-	--error-exitcode=1
-
-MASSIF_OPTS=--tool=massif \
-	--stacks=yes
-
-%.memcheck : %
-	valgrind $(MEMCHECK_OPTS) ./$< && \
-	touch $@
-
-%.massif : %
-	valgrind $(MASSIF_OPTS) --massif-out-file=$@ ./$<
-
-memcheck: $(BINARIES:=.memcheck)
-
-massif: $(BINARIES:=.massif)
-
-trusty_keymaster_device_test: trusty_keymaster_device_test.o \
-	trusty_keymaster_device.o \
-	$(KM)/aead_mode_operation.o \
-	$(KM)/aes_key.o \
-	$(KM)/aes_operation.o \
-	$(KM)/android_keymaster.o \
-	$(KM)/android_keymaster_messages.o \
-	$(KM)/android_keymaster_test_utils.o \
-	$(KM)/android_keymaster_utils.o \
-	$(KM)/asymmetric_key.o \
-	$(KM)/auth_encrypted_key_blob.o \
-	$(KM)/auth_encrypted_key_blob.o \
-	$(KM)/authorization_set.o \
-	$(KM)/ec_key.o \
-	$(KM)/ec_keymaster0_key.cpp \
-	$(KM)/ecdsa_operation.o \
-	$(KM)/hmac_key.o \
-	$(KM)/hmac_operation.o \
-	$(KM)/integrity_assured_key_blob.o \
-	$(KM)/key.o \
-	$(KM)/keymaster0_engine.o \
-	$(KM)/logger.o \
-	$(KM)/ocb.o \
-	$(KM)/ocb_utils.o \
-	$(KM)/openssl_err.o \
-	$(KM)/openssl_utils.o \
-	$(KM)/operation.o \
-	$(KM)/operation_table.o \
-	$(KM)/rsa_key.o \
-	$(KM)/rsa_keymaster0_key.o \
-	$(KM)/rsa_operation.o \
-	$(KM)/serializable.o \
-	$(KM)/soft_keymaster_context.o \
-	$(KM)/symmetric_key.o \
-	$(GTEST)/src/gtest-all.o
-
-$(GTEST)/src/gtest-all.o: CXXFLAGS:=$(subst -Wmissing-declarations,,$(CXXFLAGS))
-ocb.o: CFLAGS=$(CLANG_TEST_DEFINE)
-
-clean:
-	rm -f $(OBJS) $(DEPS) $(GCDA) $(GCNO) $(BINARIES) \
-		$(BINARIES:=.run) $(BINARIES:=.memcheck) $(BINARIES:=.massif) \
-		coverage.info
-	rm -rf coverage
-
--include $(CPPSRCS:.cpp=.d)
--include $(CCSRCS:.cc=.d)
-
diff --git a/trusty/keymaster/legacy/module.cpp b/trusty/keymaster/legacy/module.cpp
deleted file mode 100644
index 7aa1a4e..0000000
--- a/trusty/keymaster/legacy/module.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <errno.h>
-#include <string.h>
-
-#include <hardware/hardware.h>
-#include <hardware/keymaster0.h>
-
-#include <trusty_keymaster/legacy/trusty_keymaster_device.h>
-
-using keymaster::TrustyKeymasterDevice;
-
-/*
- * Generic device handling
- */
-static int trusty_keymaster_open(const hw_module_t* module, const char* name,
-                                 hw_device_t** device) {
-    if (strcmp(name, KEYSTORE_KEYMASTER) != 0) {
-        return -EINVAL;
-    }
-
-    TrustyKeymasterDevice* dev = new TrustyKeymasterDevice(module);
-    if (dev == NULL) {
-        return -ENOMEM;
-    }
-    *device = dev->hw_device();
-    // Do not delete dev; it will get cleaned up when the caller calls device->close(), and must
-    // exist until then.
-    return 0;
-}
-
-static struct hw_module_methods_t keystore_module_methods = {
-        .open = trusty_keymaster_open,
-};
-
-struct keystore_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
-        .common =
-                {
-                        .tag = HARDWARE_MODULE_TAG,
-                        .module_api_version = KEYMASTER_MODULE_API_VERSION_2_0,
-                        .hal_api_version = HARDWARE_HAL_API_VERSION,
-                        .id = KEYSTORE_HARDWARE_MODULE_ID,
-                        .name = "Trusty Keymaster HAL",
-                        .author = "The Android Open Source Project",
-                        .methods = &keystore_module_methods,
-                        .dso = 0,
-                        .reserved = {},
-                },
-};
diff --git a/trusty/keymaster/legacy/trusty_keymaster_device.cpp b/trusty/keymaster/legacy/trusty_keymaster_device.cpp
deleted file mode 100644
index 88c3e7b..0000000
--- a/trusty/keymaster/legacy/trusty_keymaster_device.cpp
+++ /dev/null
@@ -1,761 +0,0 @@
-/*
- * Copyright 2014 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.
- */
-
-#define LOG_TAG "TrustyKeymaster"
-
-#include <assert.h>
-#include <errno.h>
-#include <openssl/evp.h>
-#include <openssl/x509.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include <algorithm>
-#include <type_traits>
-
-#include <hardware/keymaster2.h>
-#include <keymaster/authorization_set.h>
-#include <log/log.h>
-
-#include <trusty_keymaster/ipc/keymaster_ipc.h>
-#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
-#include <trusty_keymaster/legacy/trusty_keymaster_device.h>
-
-const size_t kMaximumAttestationChallengeLength = 128;
-const size_t kMaximumFinishInputLength = 2048;
-
-namespace keymaster {
-
-TrustyKeymasterDevice::TrustyKeymasterDevice(const hw_module_t* module) {
-    static_assert(std::is_standard_layout<TrustyKeymasterDevice>::value,
-                  "TrustyKeymasterDevice must be standard layout");
-    static_assert(offsetof(TrustyKeymasterDevice, device_) == 0,
-                  "device_ must be the first member of TrustyKeymasterDevice");
-    static_assert(offsetof(TrustyKeymasterDevice, device_.common) == 0,
-                  "common must be the first member of keymaster2_device");
-
-    ALOGI("Creating device");
-    ALOGD("Device address: %p", this);
-
-    device_ = {};
-
-    device_.common.tag = HARDWARE_DEVICE_TAG;
-    device_.common.version = 1;
-    device_.common.module = const_cast<hw_module_t*>(module);
-    device_.common.close = close_device;
-
-    device_.flags = KEYMASTER_SUPPORTS_EC;
-
-    device_.configure = configure;
-    device_.add_rng_entropy = add_rng_entropy;
-    device_.generate_key = generate_key;
-    device_.get_key_characteristics = get_key_characteristics;
-    device_.import_key = import_key;
-    device_.export_key = export_key;
-    device_.attest_key = attest_key;
-    device_.upgrade_key = upgrade_key;
-    device_.delete_key = delete_key;
-    device_.delete_all_keys = delete_all_keys;
-    device_.begin = begin;
-    device_.update = update;
-    device_.finish = finish;
-    device_.abort = abort;
-
-    int rc = trusty_keymaster_connect();
-    error_ = translate_error(rc);
-    if (rc < 0) {
-        ALOGE("failed to connect to keymaster (%d)", rc);
-        return;
-    }
-
-    GetVersionRequest version_request;
-    GetVersionResponse version_response;
-    error_ = trusty_keymaster_send(KM_GET_VERSION, version_request, &version_response);
-    if (error_ == KM_ERROR_INVALID_ARGUMENT || error_ == KM_ERROR_UNIMPLEMENTED) {
-        ALOGE("\"Bad parameters\" error on GetVersion call.  Version 0 is not supported.");
-        error_ = KM_ERROR_VERSION_MISMATCH;
-        return;
-    }
-    message_version_ = MessageVersion(version_response.major_ver, version_response.minor_ver,
-                                      version_response.subminor_ver);
-    if (message_version_ < 0) {
-        // Can't translate version?  Keymaster implementation must be newer.
-        ALOGE("Keymaster version %d.%d.%d not supported.", version_response.major_ver,
-              version_response.minor_ver, version_response.subminor_ver);
-        error_ = KM_ERROR_VERSION_MISMATCH;
-    }
-}
-
-TrustyKeymasterDevice::~TrustyKeymasterDevice() {
-    trusty_keymaster_disconnect();
-}
-
-namespace {
-
-// Allocates a new buffer with malloc and copies the contents of |buffer| to it. Caller takes
-// ownership of the returned buffer.
-uint8_t* DuplicateBuffer(const uint8_t* buffer, size_t size) {
-    uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(size));
-    if (tmp) {
-        memcpy(tmp, buffer, size);
-    }
-    return tmp;
-}
-
-template <typename RequestType>
-void AddClientAndAppData(const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
-                         RequestType* request) {
-    request->additional_params.Clear();
-    if (client_id && client_id->data_length > 0) {
-        request->additional_params.push_back(TAG_APPLICATION_ID, *client_id);
-    }
-    if (app_data && app_data->data_length > 0) {
-        request->additional_params.push_back(TAG_APPLICATION_DATA, *app_data);
-    }
-}
-
-}  //  unnamed namespace
-
-keymaster_error_t TrustyKeymasterDevice::configure(const keymaster_key_param_set_t* params) {
-    ALOGD("Device received configure\n");
-
-    if (error_ != KM_ERROR_OK) {
-        return error_;
-    }
-    if (!params) {
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
-    }
-
-    AuthorizationSet params_copy(*params);
-    ConfigureRequest request(message_version_);
-    if (!params_copy.GetTagValue(TAG_OS_VERSION, &request.os_version) ||
-        !params_copy.GetTagValue(TAG_OS_PATCHLEVEL, &request.os_patchlevel)) {
-        ALOGD("Configuration parameters must contain OS version and patch level");
-        return KM_ERROR_INVALID_ARGUMENT;
-    }
-
-    ConfigureResponse response(message_version_);
-    keymaster_error_t err = trusty_keymaster_send(KM_CONFIGURE, request, &response);
-    if (err != KM_ERROR_OK) {
-        return err;
-    }
-
-    return KM_ERROR_OK;
-}
-
-keymaster_error_t TrustyKeymasterDevice::add_rng_entropy(const uint8_t* data, size_t data_length) {
-    ALOGD("Device received add_rng_entropy");
-
-    if (error_ != KM_ERROR_OK) {
-        return error_;
-    }
-
-    AddEntropyRequest request(message_version_);
-    request.random_data.Reinitialize(data, data_length);
-    AddEntropyResponse response(message_version_);
-    return trusty_keymaster_send(KM_ADD_RNG_ENTROPY, request, &response);
-}
-
-keymaster_error_t TrustyKeymasterDevice::generate_key(
-        const keymaster_key_param_set_t* params, keymaster_key_blob_t* key_blob,
-        keymaster_key_characteristics_t* characteristics) {
-    ALOGD("Device received generate_key");
-
-    if (error_ != KM_ERROR_OK) {
-        return error_;
-    }
-    if (!params) {
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
-    }
-    if (!key_blob) {
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-    }
-
-    GenerateKeyRequest request(message_version_);
-    request.key_description.Reinitialize(*params);
-    request.key_description.push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
-
-    GenerateKeyResponse response(message_version_);
-    keymaster_error_t err = trusty_keymaster_send(KM_GENERATE_KEY, request, &response);
-    if (err != KM_ERROR_OK) {
-        return err;
-    }
-
-    key_blob->key_material_size = response.key_blob.key_material_size;
-    key_blob->key_material =
-            DuplicateBuffer(response.key_blob.key_material, response.key_blob.key_material_size);
-    if (!key_blob->key_material) {
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-    }
-
-    if (characteristics) {
-        response.enforced.CopyToParamSet(&characteristics->hw_enforced);
-        response.unenforced.CopyToParamSet(&characteristics->sw_enforced);
-    }
-
-    return KM_ERROR_OK;
-}
-
-keymaster_error_t TrustyKeymasterDevice::get_key_characteristics(
-        const keymaster_key_blob_t* key_blob, const keymaster_blob_t* client_id,
-        const keymaster_blob_t* app_data, keymaster_key_characteristics_t* characteristics) {
-    ALOGD("Device received get_key_characteristics");
-
-    if (error_ != KM_ERROR_OK) {
-        return error_;
-    }
-    if (!key_blob || !key_blob->key_material) {
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
-    }
-    if (!characteristics) {
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-    }
-
-    GetKeyCharacteristicsRequest request(message_version_);
-    request.SetKeyMaterial(*key_blob);
-    AddClientAndAppData(client_id, app_data, &request);
-
-    GetKeyCharacteristicsResponse response(message_version_);
-    keymaster_error_t err = trusty_keymaster_send(KM_GET_KEY_CHARACTERISTICS, request, &response);
-    if (err != KM_ERROR_OK) {
-        return err;
-    }
-
-    response.enforced.CopyToParamSet(&characteristics->hw_enforced);
-    response.unenforced.CopyToParamSet(&characteristics->sw_enforced);
-
-    return KM_ERROR_OK;
-}
-
-keymaster_error_t TrustyKeymasterDevice::import_key(
-        const keymaster_key_param_set_t* params, keymaster_key_format_t key_format,
-        const keymaster_blob_t* key_data, keymaster_key_blob_t* key_blob,
-        keymaster_key_characteristics_t* characteristics) {
-    ALOGD("Device received import_key");
-
-    if (error_ != KM_ERROR_OK) {
-        return error_;
-    }
-    if (!params || !key_data) {
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
-    }
-    if (!key_blob) {
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-    }
-
-    ImportKeyRequest request(message_version_);
-    request.key_description.Reinitialize(*params);
-    request.key_description.push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
-
-    request.key_format = key_format;
-    request.SetKeyMaterial(key_data->data, key_data->data_length);
-
-    ImportKeyResponse response(message_version_);
-    keymaster_error_t err = trusty_keymaster_send(KM_IMPORT_KEY, request, &response);
-    if (err != KM_ERROR_OK) {
-        return err;
-    }
-
-    key_blob->key_material_size = response.key_blob.key_material_size;
-    key_blob->key_material =
-            DuplicateBuffer(response.key_blob.key_material, response.key_blob.key_material_size);
-    if (!key_blob->key_material) {
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-    }
-
-    if (characteristics) {
-        response.enforced.CopyToParamSet(&characteristics->hw_enforced);
-        response.unenforced.CopyToParamSet(&characteristics->sw_enforced);
-    }
-
-    return KM_ERROR_OK;
-}
-
-keymaster_error_t TrustyKeymasterDevice::export_key(keymaster_key_format_t export_format,
-                                                    const keymaster_key_blob_t* key_to_export,
-                                                    const keymaster_blob_t* client_id,
-                                                    const keymaster_blob_t* app_data,
-                                                    keymaster_blob_t* export_data) {
-    ALOGD("Device received export_key");
-
-    if (error_ != KM_ERROR_OK) {
-        return error_;
-    }
-    if (!key_to_export || !key_to_export->key_material) {
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
-    }
-    if (!export_data) {
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-    }
-
-    export_data->data = nullptr;
-    export_data->data_length = 0;
-
-    ExportKeyRequest request(message_version_);
-    request.key_format = export_format;
-    request.SetKeyMaterial(*key_to_export);
-    AddClientAndAppData(client_id, app_data, &request);
-
-    ExportKeyResponse response(message_version_);
-    keymaster_error_t err = trusty_keymaster_send(KM_EXPORT_KEY, request, &response);
-    if (err != KM_ERROR_OK) {
-        return err;
-    }
-
-    export_data->data_length = response.key_data_length;
-    export_data->data = DuplicateBuffer(response.key_data, response.key_data_length);
-    if (!export_data->data) {
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-    }
-
-    return KM_ERROR_OK;
-}
-
-keymaster_error_t TrustyKeymasterDevice::attest_key(const keymaster_key_blob_t* key_to_attest,
-                                                    const keymaster_key_param_set_t* attest_params,
-                                                    keymaster_cert_chain_t* cert_chain) {
-    ALOGD("Device received attest_key");
-
-    if (error_ != KM_ERROR_OK) {
-        return error_;
-    }
-    if (!key_to_attest || !attest_params) {
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
-    }
-    if (!cert_chain) {
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-    }
-
-    cert_chain->entry_count = 0;
-    cert_chain->entries = nullptr;
-
-    AttestKeyRequest request(message_version_);
-    request.SetKeyMaterial(*key_to_attest);
-    request.attest_params.Reinitialize(*attest_params);
-
-    keymaster_blob_t attestation_challenge = {};
-    request.attest_params.GetTagValue(TAG_ATTESTATION_CHALLENGE, &attestation_challenge);
-    if (attestation_challenge.data_length > kMaximumAttestationChallengeLength) {
-        ALOGE("%zu-byte attestation challenge; only %zu bytes allowed",
-              attestation_challenge.data_length, kMaximumAttestationChallengeLength);
-        return KM_ERROR_INVALID_INPUT_LENGTH;
-    }
-
-    AttestKeyResponse response(message_version_);
-    keymaster_error_t err = trusty_keymaster_send(KM_ATTEST_KEY, request, &response);
-    if (err != KM_ERROR_OK) {
-        return err;
-    }
-
-    // Allocate and clear storage for cert_chain.
-    keymaster_cert_chain_t& rsp_chain = response.certificate_chain;
-    cert_chain->entries = reinterpret_cast<keymaster_blob_t*>(
-            malloc(rsp_chain.entry_count * sizeof(*cert_chain->entries)));
-    if (!cert_chain->entries) {
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-    }
-    cert_chain->entry_count = rsp_chain.entry_count;
-    for (keymaster_blob_t& entry : array_range(cert_chain->entries, cert_chain->entry_count)) {
-        entry = {};
-    }
-
-    // Copy cert_chain contents
-    size_t i = 0;
-    for (keymaster_blob_t& entry : array_range(rsp_chain.entries, rsp_chain.entry_count)) {
-        cert_chain->entries[i].data = DuplicateBuffer(entry.data, entry.data_length);
-        if (!cert_chain->entries[i].data) {
-            keymaster_free_cert_chain(cert_chain);
-            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-        }
-        cert_chain->entries[i].data_length = entry.data_length;
-        ++i;
-    }
-
-    return KM_ERROR_OK;
-}
-
-keymaster_error_t TrustyKeymasterDevice::upgrade_key(
-        const keymaster_key_blob_t* key_to_upgrade, const keymaster_key_param_set_t* upgrade_params,
-        keymaster_key_blob_t* upgraded_key) {
-    ALOGD("Device received upgrade_key");
-
-    if (error_ != KM_ERROR_OK) {
-        return error_;
-    }
-    if (!key_to_upgrade || !upgrade_params) {
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
-    }
-    if (!upgraded_key) {
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-    }
-
-    UpgradeKeyRequest request(message_version_);
-    request.SetKeyMaterial(*key_to_upgrade);
-    request.upgrade_params.Reinitialize(*upgrade_params);
-
-    UpgradeKeyResponse response(message_version_);
-    keymaster_error_t err = trusty_keymaster_send(KM_UPGRADE_KEY, request, &response);
-    if (err != KM_ERROR_OK) {
-        return err;
-    }
-
-    upgraded_key->key_material_size = response.upgraded_key.key_material_size;
-    upgraded_key->key_material = DuplicateBuffer(response.upgraded_key.key_material,
-                                                 response.upgraded_key.key_material_size);
-    if (!upgraded_key->key_material) {
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-    }
-
-    return KM_ERROR_OK;
-}
-
-keymaster_error_t TrustyKeymasterDevice::begin(keymaster_purpose_t purpose,
-                                               const keymaster_key_blob_t* key,
-                                               const keymaster_key_param_set_t* in_params,
-                                               keymaster_key_param_set_t* out_params,
-                                               keymaster_operation_handle_t* operation_handle) {
-    ALOGD("Device received begin");
-
-    if (error_ != KM_ERROR_OK) {
-        return error_;
-    }
-    if (!key || !key->key_material) {
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
-    }
-    if (!operation_handle) {
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-    }
-
-    if (out_params) {
-        *out_params = {};
-    }
-
-    BeginOperationRequest request(message_version_);
-    request.purpose = purpose;
-    request.SetKeyMaterial(*key);
-    request.additional_params.Reinitialize(*in_params);
-
-    BeginOperationResponse response(message_version_);
-    keymaster_error_t err = trusty_keymaster_send(KM_BEGIN_OPERATION, request, &response);
-    if (err != KM_ERROR_OK) {
-        return err;
-    }
-
-    if (response.output_params.size() > 0) {
-        if (out_params) {
-            response.output_params.CopyToParamSet(out_params);
-        } else {
-            return KM_ERROR_OUTPUT_PARAMETER_NULL;
-        }
-    }
-    *operation_handle = response.op_handle;
-
-    return KM_ERROR_OK;
-}
-
-keymaster_error_t TrustyKeymasterDevice::update(keymaster_operation_handle_t operation_handle,
-                                                const keymaster_key_param_set_t* in_params,
-                                                const keymaster_blob_t* input,
-                                                size_t* input_consumed,
-                                                keymaster_key_param_set_t* out_params,
-                                                keymaster_blob_t* output) {
-    ALOGD("Device received update");
-
-    if (error_ != KM_ERROR_OK) {
-        return error_;
-    }
-    if (!input) {
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
-    }
-    if (!input_consumed) {
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-    }
-
-    if (out_params) {
-        *out_params = {};
-    }
-    if (output) {
-        *output = {};
-    }
-
-    UpdateOperationRequest request(message_version_);
-    request.op_handle = operation_handle;
-    if (in_params) {
-        request.additional_params.Reinitialize(*in_params);
-    }
-    if (input && input->data_length > 0) {
-        size_t max_input_size = TRUSTY_KEYMASTER_SEND_BUF_SIZE - request.SerializedSize();
-        request.input.Reinitialize(input->data, std::min(input->data_length, max_input_size));
-    }
-
-    UpdateOperationResponse response(message_version_);
-    keymaster_error_t err = trusty_keymaster_send(KM_UPDATE_OPERATION, request, &response);
-    if (err != KM_ERROR_OK) {
-        return err;
-    }
-
-    if (response.output_params.size() > 0) {
-        if (out_params) {
-            response.output_params.CopyToParamSet(out_params);
-        } else {
-            return KM_ERROR_OUTPUT_PARAMETER_NULL;
-        }
-    }
-    *input_consumed = response.input_consumed;
-    if (output) {
-        output->data_length = response.output.available_read();
-        output->data = DuplicateBuffer(response.output.peek_read(), output->data_length);
-        if (!output->data) {
-            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-        }
-    } else if (response.output.available_read() > 0) {
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-    }
-
-    return KM_ERROR_OK;
-}
-
-keymaster_error_t TrustyKeymasterDevice::finish(keymaster_operation_handle_t operation_handle,
-                                                const keymaster_key_param_set_t* in_params,
-                                                const keymaster_blob_t* input,
-                                                const keymaster_blob_t* signature,
-                                                keymaster_key_param_set_t* out_params,
-                                                keymaster_blob_t* output) {
-    ALOGD("Device received finish");
-
-    if (error_ != KM_ERROR_OK) {
-        return error_;
-    }
-    if (input && input->data_length > kMaximumFinishInputLength) {
-        ALOGE("%zu-byte input to finish; only %zu bytes allowed", input->data_length,
-              kMaximumFinishInputLength);
-        return KM_ERROR_INVALID_INPUT_LENGTH;
-    }
-
-    if (out_params) {
-        *out_params = {};
-    }
-    if (output) {
-        *output = {};
-    }
-
-    FinishOperationRequest request(message_version_);
-    request.op_handle = operation_handle;
-    if (signature && signature->data && signature->data_length > 0) {
-        request.signature.Reinitialize(signature->data, signature->data_length);
-    }
-    if (input && input->data && input->data_length) {
-        request.input.Reinitialize(input->data, input->data_length);
-    }
-    if (in_params) {
-        request.additional_params.Reinitialize(*in_params);
-    }
-
-    FinishOperationResponse response(message_version_);
-    keymaster_error_t err = trusty_keymaster_send(KM_FINISH_OPERATION, request, &response);
-    if (err != KM_ERROR_OK) {
-        return err;
-    }
-
-    if (response.output_params.size() > 0) {
-        if (out_params) {
-            response.output_params.CopyToParamSet(out_params);
-        } else {
-            return KM_ERROR_OUTPUT_PARAMETER_NULL;
-        }
-    }
-    if (output) {
-        output->data_length = response.output.available_read();
-        output->data = DuplicateBuffer(response.output.peek_read(), output->data_length);
-        if (!output->data) {
-            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-        }
-    } else if (response.output.available_read() > 0) {
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-    }
-
-    return KM_ERROR_OK;
-}
-
-keymaster_error_t TrustyKeymasterDevice::abort(keymaster_operation_handle_t operation_handle) {
-    ALOGD("Device received abort");
-
-    if (error_ != KM_ERROR_OK) {
-        return error_;
-    }
-
-    AbortOperationRequest request(message_version_);
-    request.op_handle = operation_handle;
-    AbortOperationResponse response(message_version_);
-    return trusty_keymaster_send(KM_ABORT_OPERATION, request, &response);
-}
-
-keymaster_error_t TrustyKeymasterDevice::delete_key(const keymaster_key_blob_t* key) {
-    ALOGD("Device received delete_key");
-
-    if (error_ != KM_ERROR_OK) {
-        return error_;
-    }
-
-    if (!key || !key->key_material)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
-
-    DeleteKeyRequest request(message_version_);
-    request.SetKeyMaterial(*key);
-    DeleteKeyResponse response(message_version_);
-    return trusty_keymaster_send(KM_DELETE_KEY, request, &response);
-}
-
-keymaster_error_t TrustyKeymasterDevice::delete_all_keys() {
-    ALOGD("Device received delete_all_key");
-
-    if (error_ != KM_ERROR_OK) {
-        return error_;
-    }
-
-    DeleteAllKeysRequest request(message_version_);
-    DeleteAllKeysResponse response(message_version_);
-    return trusty_keymaster_send(KM_DELETE_ALL_KEYS, request, &response);
-}
-
-hw_device_t* TrustyKeymasterDevice::hw_device() {
-    return &device_.common;
-}
-
-static inline TrustyKeymasterDevice* convert_device(const keymaster2_device_t* dev) {
-    return reinterpret_cast<TrustyKeymasterDevice*>(const_cast<keymaster2_device_t*>(dev));
-}
-
-/* static */
-int TrustyKeymasterDevice::close_device(hw_device_t* dev) {
-    delete reinterpret_cast<TrustyKeymasterDevice*>(dev);
-    return 0;
-}
-
-/* static */
-keymaster_error_t TrustyKeymasterDevice::configure(const keymaster2_device_t* dev,
-                                                   const keymaster_key_param_set_t* params) {
-    return convert_device(dev)->configure(params);
-}
-
-/* static */
-keymaster_error_t TrustyKeymasterDevice::add_rng_entropy(const keymaster2_device_t* dev,
-                                                         const uint8_t* data, size_t data_length) {
-    return convert_device(dev)->add_rng_entropy(data, data_length);
-}
-
-/* static */
-keymaster_error_t TrustyKeymasterDevice::generate_key(
-        const keymaster2_device_t* dev, const keymaster_key_param_set_t* params,
-        keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics) {
-    return convert_device(dev)->generate_key(params, key_blob, characteristics);
-}
-
-/* static */
-keymaster_error_t TrustyKeymasterDevice::get_key_characteristics(
-        const keymaster2_device_t* dev, const keymaster_key_blob_t* key_blob,
-        const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
-        keymaster_key_characteristics_t* characteristics) {
-    return convert_device(dev)->get_key_characteristics(key_blob, client_id, app_data,
-                                                        characteristics);
-}
-
-/* static */
-keymaster_error_t TrustyKeymasterDevice::import_key(
-        const keymaster2_device_t* dev, const keymaster_key_param_set_t* params,
-        keymaster_key_format_t key_format, const keymaster_blob_t* key_data,
-        keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics) {
-    return convert_device(dev)->import_key(params, key_format, key_data, key_blob, characteristics);
-}
-
-/* static */
-keymaster_error_t TrustyKeymasterDevice::export_key(const keymaster2_device_t* dev,
-                                                    keymaster_key_format_t export_format,
-                                                    const keymaster_key_blob_t* key_to_export,
-                                                    const keymaster_blob_t* client_id,
-                                                    const keymaster_blob_t* app_data,
-                                                    keymaster_blob_t* export_data) {
-    return convert_device(dev)->export_key(export_format, key_to_export, client_id, app_data,
-                                           export_data);
-}
-
-/* static */
-keymaster_error_t TrustyKeymasterDevice::attest_key(const keymaster2_device_t* dev,
-                                                    const keymaster_key_blob_t* key_to_attest,
-                                                    const keymaster_key_param_set_t* attest_params,
-                                                    keymaster_cert_chain_t* cert_chain) {
-    return convert_device(dev)->attest_key(key_to_attest, attest_params, cert_chain);
-}
-
-/* static */
-keymaster_error_t TrustyKeymasterDevice::upgrade_key(
-        const keymaster2_device_t* dev, const keymaster_key_blob_t* key_to_upgrade,
-        const keymaster_key_param_set_t* upgrade_params, keymaster_key_blob_t* upgraded_key) {
-    return convert_device(dev)->upgrade_key(key_to_upgrade, upgrade_params, upgraded_key);
-}
-
-/* static */
-keymaster_error_t TrustyKeymasterDevice::begin(const keymaster2_device_t* dev,
-                                               keymaster_purpose_t purpose,
-                                               const keymaster_key_blob_t* key,
-                                               const keymaster_key_param_set_t* in_params,
-                                               keymaster_key_param_set_t* out_params,
-                                               keymaster_operation_handle_t* operation_handle) {
-    return convert_device(dev)->begin(purpose, key, in_params, out_params, operation_handle);
-}
-
-/* static */
-keymaster_error_t TrustyKeymasterDevice::update(
-        const keymaster2_device_t* dev, keymaster_operation_handle_t operation_handle,
-        const keymaster_key_param_set_t* in_params, const keymaster_blob_t* input,
-        size_t* input_consumed, keymaster_key_param_set_t* out_params, keymaster_blob_t* output) {
-    return convert_device(dev)->update(operation_handle, in_params, input, input_consumed,
-                                       out_params, output);
-}
-
-/* static */
-keymaster_error_t TrustyKeymasterDevice::finish(const keymaster2_device_t* dev,
-                                                keymaster_operation_handle_t operation_handle,
-                                                const keymaster_key_param_set_t* in_params,
-                                                const keymaster_blob_t* input,
-                                                const keymaster_blob_t* signature,
-                                                keymaster_key_param_set_t* out_params,
-                                                keymaster_blob_t* output) {
-    return convert_device(dev)->finish(operation_handle, in_params, input, signature, out_params,
-                                       output);
-}
-
-/* static */
-keymaster_error_t TrustyKeymasterDevice::abort(const keymaster2_device_t* dev,
-                                               keymaster_operation_handle_t operation_handle) {
-    return convert_device(dev)->abort(operation_handle);
-}
-
-/* static */
-keymaster_error_t TrustyKeymasterDevice::delete_key(const keymaster2_device_t* dev,
-                                               const keymaster_key_blob_t* key) {
-   return convert_device(dev)->delete_key(key);
-}
-
-/* static */
-keymaster_error_t TrustyKeymasterDevice::delete_all_keys(const keymaster2_device_t* dev) {
-   return convert_device(dev)->delete_all_keys();
-}
-
-}  // namespace keymaster
diff --git a/trusty/keymaster/legacy/trusty_keymaster_device_test.cpp b/trusty/keymaster/legacy/trusty_keymaster_device_test.cpp
deleted file mode 100644
index 68def58..0000000
--- a/trusty/keymaster/legacy/trusty_keymaster_device_test.cpp
+++ /dev/null
@@ -1,561 +0,0 @@
-/*
- * Copyright (C) 2014 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 <algorithm>
-#include <fstream>
-#include <memory>
-
-#include <gtest/gtest.h>
-#include <openssl/engine.h>
-
-#include <hardware/keymaster0.h>
-
-#include <keymaster/android_keymaster.h>
-#include <keymaster/android_keymaster_messages.h>
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/keymaster_tags.h>
-#include <keymaster/soft_keymaster_context.h>
-
-#include <trusty_keymaster/legacy/trusty_keymaster_device.h>
-#include "android_keymaster_test_utils.h"
-#include "openssl_utils.h"
-
-using std::ifstream;
-using std::istreambuf_iterator;
-using std::string;
-
-static keymaster::AndroidKeymaster* impl_ = nullptr;
-
-extern "C" {
-int __android_log_print();
-}
-
-int __android_log_print() {
-    return 0;
-}
-
-int main(int argc, char** argv) {
-    ::testing::InitGoogleTest(&argc, argv);
-    int result = RUN_ALL_TESTS();
-    // Clean up stuff OpenSSL leaves around, so Valgrind doesn't complain.
-    CRYPTO_cleanup_all_ex_data();
-    ERR_free_strings();
-    return result;
-}
-
-int trusty_keymaster_connect() {
-    impl_ = new keymaster::AndroidKeymaster(new keymaster::SoftKeymasterContext(nullptr), 16);
-}
-
-void trusty_keymaster_disconnect() {
-    delete static_cast<keymaster::AndroidKeymaster*>(priv_);
-}
-
-template <typename Req, typename Rsp>
-static int fake_call(keymaster::AndroidKeymaster* device,
-                     void (keymaster::AndroidKeymaster::*method)(const Req&, Rsp*), void* in_buf,
-                     uint32_t in_size, void* out_buf, uint32_t* out_size) {
-    Req req;
-    const uint8_t* in = static_cast<uint8_t*>(in_buf);
-    req.Deserialize(&in, in + in_size);
-    Rsp rsp;
-    (device->*method)(req, &rsp);
-
-    *out_size = rsp.SerializedSize();
-    uint8_t* out = static_cast<uint8_t*>(out_buf);
-    rsp.Serialize(out, out + *out_size);
-    return 0;
-}
-
-int trusty_keymaster_call(uint32_t cmd, void* in_buf, uint32_t in_size, void* out_buf,
-                          uint32_t* out_size) {
-    switch (cmd) {
-        case KM_GENERATE_KEY:
-            return fake_call(impl_, &keymaster::AndroidKeymaster::GenerateKey, in_buf, in_size,
-                             out_buf, out_size);
-        case KM_BEGIN_OPERATION:
-            return fake_call(impl_, &keymaster::AndroidKeymaster::BeginOperation, in_buf, in_size,
-                             out_buf, out_size);
-        case KM_UPDATE_OPERATION:
-            return fake_call(impl_, &keymaster::AndroidKeymaster::UpdateOperation, in_buf, in_size,
-                             out_buf, out_size);
-        case KM_FINISH_OPERATION:
-            return fake_call(impl_, &keymaster::AndroidKeymaster::FinishOperation, in_buf, in_size,
-                             out_buf, out_size);
-        case KM_IMPORT_KEY:
-            return fake_call(impl_, &keymaster::AndroidKeymaster::ImportKey, in_buf, in_size,
-                             out_buf, out_size);
-        case KM_EXPORT_KEY:
-            return fake_call(impl_, &keymaster::AndroidKeymaster::ExportKey, in_buf, in_size,
-                             out_buf, out_size);
-    }
-    return -EINVAL;
-}
-
-namespace keymaster {
-namespace test {
-
-class TrustyKeymasterTest : public testing::Test {
-  protected:
-    TrustyKeymasterTest() : device(NULL) {}
-
-    keymaster_rsa_keygen_params_t build_rsa_params() {
-        keymaster_rsa_keygen_params_t rsa_params;
-        rsa_params.public_exponent = 65537;
-        rsa_params.modulus_size = 2048;
-        return rsa_params;
-    }
-
-    uint8_t* build_message(size_t length) {
-        uint8_t* msg = new uint8_t[length];
-        memset(msg, 'a', length);
-        return msg;
-    }
-
-    size_t dsa_message_len(const keymaster_dsa_keygen_params_t& params) {
-        switch (params.key_size) {
-            case 256:
-            case 1024:
-                return 48;
-            case 2048:
-            case 4096:
-                return 72;
-            default:
-                // Oops.
-                return 0;
-        }
-    }
-
-    TrustyKeymasterDevice device;
-};
-
-class Malloc_Delete {
-  public:
-    Malloc_Delete(void* p) : p_(p) {}
-    ~Malloc_Delete() { free(p_); }
-
-  private:
-    void* p_;
-};
-
-typedef TrustyKeymasterTest KeyGenTest;
-TEST_F(KeyGenTest, RsaSuccess) {
-    keymaster_rsa_keygen_params_t params = build_rsa_params();
-    uint8_t* ptr = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(ptr);
-}
-
-TEST_F(KeyGenTest, EcdsaSuccess) {
-    keymaster_ec_keygen_params_t ec_params = {256};
-    uint8_t* ptr = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &ec_params, &ptr, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(ptr);
-}
-
-typedef TrustyKeymasterTest SigningTest;
-TEST_F(SigningTest, RsaSuccess) {
-    keymaster_rsa_keygen_params_t params = build_rsa_params();
-    uint8_t* ptr = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(ptr);
-
-    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
-    size_t message_len = params.modulus_size / 8;
-    std::unique_ptr<uint8_t[]> message(build_message(message_len));
-    uint8_t* signature;
-    size_t siglen;
-    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
-                                            &signature, &siglen));
-    Malloc_Delete sig_deleter(signature);
-    EXPECT_EQ(message_len, siglen);
-}
-
-TEST_F(SigningTest, RsaShortMessage) {
-    keymaster_rsa_keygen_params_t params = build_rsa_params();
-    uint8_t* ptr = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(ptr);
-
-    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
-    size_t message_len = params.modulus_size / 8 - 1;
-    std::unique_ptr<uint8_t[]> message(build_message(message_len));
-    uint8_t* signature;
-    size_t siglen;
-    EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, device.sign_data(&sig_params, ptr, size, message.get(),
-                                                       message_len, &signature, &siglen));
-}
-
-TEST_F(SigningTest, RsaLongMessage) {
-    keymaster_rsa_keygen_params_t params = build_rsa_params();
-    uint8_t* ptr = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(ptr);
-
-    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
-    size_t message_len = params.modulus_size / 8 + 1;
-    std::unique_ptr<uint8_t[]> message(build_message(message_len));
-    uint8_t* signature;
-    size_t siglen;
-    EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, device.sign_data(&sig_params, ptr, size, message.get(),
-                                                       message_len, &signature, &siglen));
-}
-
-TEST_F(SigningTest, EcdsaSuccess) {
-    keymaster_ec_keygen_params_t params = {256};
-    uint8_t* ptr = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &ptr, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(ptr);
-
-    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
-    uint8_t message[] = "12345678901234567890123456789012";
-    uint8_t* signature;
-    size_t siglen;
-    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message,
-                                            array_size(message) - 1, &signature, &siglen));
-    Malloc_Delete sig_deleter(signature);
-    EXPECT_GT(siglen, 69U);
-    EXPECT_LT(siglen, 73U);
-}
-
-TEST_F(SigningTest, EcdsaEmptyMessageSuccess) {
-    keymaster_ec_keygen_params_t params = {256};
-    uint8_t* ptr = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &ptr, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(ptr);
-
-    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
-    uint8_t message[] = "";
-    uint8_t* signature;
-    size_t siglen;
-    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message,
-                                            array_size(message) - 1, &signature, &siglen));
-    Malloc_Delete sig_deleter(signature);
-    EXPECT_GT(siglen, 69U);
-    EXPECT_LT(siglen, 73U);
-}
-
-TEST_F(SigningTest, EcdsaLargeMessageSuccess) {
-    keymaster_ec_keygen_params_t params = {256};
-    uint8_t* ptr = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &ptr, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(ptr);
-
-    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
-    size_t message_len = 1024 * 7;
-    std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
-    // contents of message don't matter.
-    uint8_t* signature;
-    size_t siglen;
-    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
-                                            &signature, &siglen));
-    Malloc_Delete sig_deleter(signature);
-    EXPECT_GT(siglen, 69U);
-    EXPECT_LT(siglen, 73U);
-}
-
-typedef TrustyKeymasterTest VerificationTest;
-TEST_F(VerificationTest, RsaSuccess) {
-    keymaster_rsa_keygen_params_t params = build_rsa_params();
-    uint8_t* ptr = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(ptr);
-
-    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
-    size_t message_len = params.modulus_size / 8;
-    std::unique_ptr<uint8_t[]> message(build_message(message_len));
-    uint8_t* signature;
-    size_t siglen;
-    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
-                                            &signature, &siglen));
-    Malloc_Delete sig_deleter(signature);
-
-    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, ptr, size, message.get(), message_len,
-                                              signature, siglen));
-}
-
-TEST_F(VerificationTest, RsaBadSignature) {
-    keymaster_rsa_keygen_params_t params = build_rsa_params();
-    uint8_t* ptr = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(ptr);
-
-    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
-    size_t message_len = params.modulus_size / 8;
-    std::unique_ptr<uint8_t[]> message(build_message(message_len));
-    uint8_t* signature;
-    size_t siglen;
-    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
-                                            &signature, &siglen));
-
-    Malloc_Delete sig_deleter(signature);
-    signature[siglen / 2]++;
-    EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED,
-              device.verify_data(&sig_params, ptr, size, message.get(), message_len, signature,
-                                 siglen));
-}
-
-TEST_F(VerificationTest, RsaBadMessage) {
-    keymaster_rsa_keygen_params_t params = build_rsa_params();
-    uint8_t* ptr = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(ptr);
-
-    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
-    size_t message_len = params.modulus_size / 8;
-    std::unique_ptr<uint8_t[]> message(build_message(message_len));
-    uint8_t* signature;
-    size_t siglen;
-    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
-                                            &signature, &siglen));
-    Malloc_Delete sig_deleter(signature);
-    message[0]++;
-    EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED,
-              device.verify_data(&sig_params, ptr, size, message.get(), message_len, signature,
-                                 siglen));
-}
-
-TEST_F(VerificationTest, RsaShortMessage) {
-    keymaster_rsa_keygen_params_t params = build_rsa_params();
-    uint8_t* ptr = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(ptr);
-
-    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
-    size_t message_len = params.modulus_size / 8;
-    std::unique_ptr<uint8_t[]> message(build_message(message_len));
-    uint8_t* signature;
-    size_t siglen;
-    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
-                                            &signature, &siglen));
-
-    Malloc_Delete sig_deleter(signature);
-    EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH,
-              device.verify_data(&sig_params, ptr, size, message.get(), message_len - 1, signature,
-                                 siglen));
-}
-
-TEST_F(VerificationTest, RsaLongMessage) {
-    keymaster_rsa_keygen_params_t params = build_rsa_params();
-    uint8_t* ptr = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(ptr);
-
-    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
-    size_t message_len = params.modulus_size / 8;
-    std::unique_ptr<uint8_t[]> message(build_message(message_len + 1));
-    uint8_t* signature;
-    size_t siglen;
-    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
-                                            &signature, &siglen));
-    Malloc_Delete sig_deleter(signature);
-    EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH,
-              device.verify_data(&sig_params, ptr, size, message.get(), message_len + 1, signature,
-                                 siglen));
-}
-
-TEST_F(VerificationTest, EcdsaSuccess) {
-    keymaster_ec_keygen_params_t params = {256};
-    uint8_t* ptr = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &ptr, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(ptr);
-
-    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
-    uint8_t message[] = "12345678901234567890123456789012";
-    uint8_t* signature;
-    size_t siglen;
-    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message,
-                                            array_size(message) - 1, &signature, &siglen));
-    Malloc_Delete sig_deleter(signature);
-    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, ptr, size, message,
-                                              array_size(message) - 1, signature, siglen));
-}
-
-TEST_F(VerificationTest, EcdsaLargeMessageSuccess) {
-    keymaster_ec_keygen_params_t params = {256};
-    uint8_t* ptr = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &ptr, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(ptr);
-
-    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
-    size_t message_len = 1024 * 7;
-    std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
-    // contents of message don't matter.
-    uint8_t* signature;
-    size_t siglen;
-    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
-                                            &signature, &siglen));
-    Malloc_Delete sig_deleter(signature);
-    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, ptr, size, message.get(), message_len,
-                                              signature, siglen));
-}
-
-static string read_file(const string& file_name) {
-    ifstream file_stream(file_name, std::ios::binary);
-    istreambuf_iterator<char> file_begin(file_stream);
-    istreambuf_iterator<char> file_end;
-    return string(file_begin, file_end);
-}
-
-typedef TrustyKeymasterTest ImportKeyTest;
-TEST_F(ImportKeyTest, RsaSuccess) {
-    string pk8_key = read_file("../../../../system/keymaster/rsa_privkey_pk8.der");
-    ASSERT_EQ(633U, pk8_key.size());
-
-    uint8_t* key = NULL;
-    size_t size;
-    ASSERT_EQ(KM_ERROR_OK, device.import_keypair(reinterpret_cast<const uint8_t*>(pk8_key.data()),
-                                                 pk8_key.size(), &key, &size));
-    Malloc_Delete key_deleter(key);
-
-    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
-    size_t message_size = 1024 /* key size */ / 8;
-    std::unique_ptr<uint8_t[]> message(new uint8_t[message_size]);
-    memset(message.get(), 'a', message_size);
-    uint8_t* signature;
-    size_t siglen;
-    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, key, size, message.get(), message_size,
-                                            &signature, &siglen));
-    Malloc_Delete sig_deleter(signature);
-    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, key, size, message.get(), message_size,
-                                              signature, siglen));
-}
-
-TEST_F(ImportKeyTest, EcdsaSuccess) {
-    string pk8_key = read_file("../../../../system/keymaster/ec_privkey_pk8.der");
-    ASSERT_EQ(138U, pk8_key.size());
-
-    uint8_t* key = NULL;
-    size_t size;
-    ASSERT_EQ(KM_ERROR_OK, device.import_keypair(reinterpret_cast<const uint8_t*>(pk8_key.data()),
-                                                 pk8_key.size(), &key, &size));
-    Malloc_Delete key_deleter(key);
-
-    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
-    uint8_t message[] = "12345678901234567890123456789012";
-    uint8_t* signature;
-    size_t siglen;
-    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, key, size, message,
-                                            array_size(message) - 1, &signature, &siglen));
-    Malloc_Delete sig_deleter(signature);
-    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, key, size, message,
-                                              array_size(message) - 1, signature, siglen));
-}
-
-struct EVP_PKEY_CTX_Delete {
-    void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
-};
-
-static void VerifySignature(const uint8_t* key, size_t key_len, const uint8_t* signature,
-                            size_t signature_len, const uint8_t* message, size_t message_len) {
-    std::unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &key, key_len));
-    ASSERT_TRUE(pkey.get() != NULL);
-    std::unique_ptr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
-    ASSERT_TRUE(ctx.get() != NULL);
-    ASSERT_EQ(1, EVP_PKEY_verify_init(ctx.get()));
-    if (EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA)
-        ASSERT_EQ(1, EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING));
-    EXPECT_EQ(1, EVP_PKEY_verify(ctx.get(), signature, signature_len, message, message_len));
-}
-
-typedef TrustyKeymasterTest ExportKeyTest;
-TEST_F(ExportKeyTest, RsaSuccess) {
-    keymaster_rsa_keygen_params_t params = build_rsa_params();
-    uint8_t* ptr = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, &params, &ptr, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(ptr);
-
-    uint8_t* exported;
-    size_t exported_size;
-    EXPECT_EQ(KM_ERROR_OK, device.get_keypair_public(ptr, size, &exported, &exported_size));
-    Malloc_Delete exported_deleter(exported);
-
-    // Sign a message so we can verify it with the exported pubkey.
-    keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
-    size_t message_len = params.modulus_size / 8;
-    std::unique_ptr<uint8_t[]> message(build_message(message_len));
-    uint8_t* signature;
-    size_t siglen;
-    EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
-                                            &signature, &siglen));
-    Malloc_Delete sig_deleter(signature);
-    EXPECT_EQ(message_len, siglen);
-    const uint8_t* tmp = exported;
-
-    VerifySignature(exported, exported_size, signature, siglen, message.get(), message_len);
-}
-
-typedef TrustyKeymasterTest ExportKeyTest;
-TEST_F(ExportKeyTest, EcdsaSuccess) {
-    keymaster_ec_keygen_params_t params = {256};
-    uint8_t* key = NULL;
-    size_t size;
-    ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &params, &key, &size));
-    EXPECT_GT(size, 0U);
-    Malloc_Delete key_deleter(key);
-
-    uint8_t* exported;
-    size_t exported_size;
-    EXPECT_EQ(KM_ERROR_OK, device.get_keypair_public(key, size, &exported, &exported_size));
-    Malloc_Delete exported_deleter(exported);
-
-    // Sign a message so we can verify it with the exported pubkey.
-    keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
-    uint8_t message[] = "12345678901234567890123456789012";
-    uint8_t* signature;
-    size_t siglen;
-    ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, key, size, message,
-                                            array_size(message) - 1, &signature, &siglen));
-    Malloc_Delete sig_deleter(signature);
-    EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, key, size, message,
-                                              array_size(message) - 1, signature, siglen));
-
-    VerifySignature(exported, exported_size, signature, siglen, message, array_size(message) - 1);
-}
-
-}  // namespace test
-}  // namespace keymaster
diff --git a/trusty/keymaster/legacy/trusty_keymaster_main.cpp b/trusty/keymaster/legacy/trusty_keymaster_main.cpp
deleted file mode 100644
index e3e70e6..0000000
--- a/trusty/keymaster/legacy/trusty_keymaster_main.cpp
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- * Copyright 2014 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 <keymaster/keymaster_configuration.h>
-
-#include <stdio.h>
-#include <memory>
-
-#include <openssl/evp.h>
-#include <openssl/x509.h>
-
-#include <trusty_keymaster/legacy/trusty_keymaster_device.h>
-
-using keymaster::TrustyKeymasterDevice;
-
-unsigned char rsa_privkey_pk8_der[] = {
-        0x30, 0x82, 0x02, 0x75, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
-        0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x5f, 0x30, 0x82, 0x02, 0x5b,
-        0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xc6, 0x09, 0x54, 0x09, 0x04, 0x7d, 0x86, 0x34,
-        0x81, 0x2d, 0x5a, 0x21, 0x81, 0x76, 0xe4, 0x5c, 0x41, 0xd6, 0x0a, 0x75, 0xb1, 0x39, 0x01,
-        0xf2, 0x34, 0x22, 0x6c, 0xff, 0xe7, 0x76, 0x52, 0x1c, 0x5a, 0x77, 0xb9, 0xe3, 0x89, 0x41,
-        0x7b, 0x71, 0xc0, 0xb6, 0xa4, 0x4d, 0x13, 0xaf, 0xe4, 0xe4, 0xa2, 0x80, 0x5d, 0x46, 0xc9,
-        0xda, 0x29, 0x35, 0xad, 0xb1, 0xff, 0x0c, 0x1f, 0x24, 0xea, 0x06, 0xe6, 0x2b, 0x20, 0xd7,
-        0x76, 0x43, 0x0a, 0x4d, 0x43, 0x51, 0x57, 0x23, 0x3c, 0x6f, 0x91, 0x67, 0x83, 0xc3, 0x0e,
-        0x31, 0x0f, 0xcb, 0xd8, 0x9b, 0x85, 0xc2, 0xd5, 0x67, 0x71, 0x16, 0x97, 0x85, 0xac, 0x12,
-        0xbc, 0xa2, 0x44, 0xab, 0xda, 0x72, 0xbf, 0xb1, 0x9f, 0xc4, 0x4d, 0x27, 0xc8, 0x1e, 0x1d,
-        0x92, 0xde, 0x28, 0x4f, 0x40, 0x61, 0xed, 0xfd, 0x99, 0x28, 0x07, 0x45, 0xea, 0x6d, 0x25,
-        0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x81, 0x80, 0x1b, 0xe0, 0xf0, 0x4d, 0x9c, 0xae, 0x37,
-        0x18, 0x69, 0x1f, 0x03, 0x53, 0x38, 0x30, 0x8e, 0x91, 0x56, 0x4b, 0x55, 0x89, 0x9f, 0xfb,
-        0x50, 0x84, 0xd2, 0x46, 0x0e, 0x66, 0x30, 0x25, 0x7e, 0x05, 0xb3, 0xce, 0xab, 0x02, 0x97,
-        0x2d, 0xfa, 0xbc, 0xd6, 0xce, 0x5f, 0x6e, 0xe2, 0x58, 0x9e, 0xb6, 0x79, 0x11, 0xed, 0x0f,
-        0xac, 0x16, 0xe4, 0x3a, 0x44, 0x4b, 0x8c, 0x86, 0x1e, 0x54, 0x4a, 0x05, 0x93, 0x36, 0x57,
-        0x72, 0xf8, 0xba, 0xf6, 0xb2, 0x2f, 0xc9, 0xe3, 0xc5, 0xf1, 0x02, 0x4b, 0x06, 0x3a, 0xc0,
-        0x80, 0xa7, 0xb2, 0x23, 0x4c, 0xf8, 0xae, 0xe8, 0xf6, 0xc4, 0x7b, 0xbf, 0x4f, 0xd3, 0xac,
-        0xe7, 0x24, 0x02, 0x90, 0xbe, 0xf1, 0x6c, 0x0b, 0x3f, 0x7f, 0x3c, 0xdd, 0x64, 0xce, 0x3a,
-        0xb5, 0x91, 0x2c, 0xf6, 0xe3, 0x2f, 0x39, 0xab, 0x18, 0x83, 0x58, 0xaf, 0xcc, 0xcd, 0x80,
-        0x81, 0x02, 0x41, 0x00, 0xe4, 0xb4, 0x9e, 0xf5, 0x0f, 0x76, 0x5d, 0x3b, 0x24, 0xdd, 0xe0,
-        0x1a, 0xce, 0xaa, 0xf1, 0x30, 0xf2, 0xc7, 0x66, 0x70, 0xa9, 0x1a, 0x61, 0xae, 0x08, 0xaf,
-        0x49, 0x7b, 0x4a, 0x82, 0xbe, 0x6d, 0xee, 0x8f, 0xcd, 0xd5, 0xe3, 0xf7, 0xba, 0x1c, 0xfb,
-        0x1f, 0x0c, 0x92, 0x6b, 0x88, 0xf8, 0x8c, 0x92, 0xbf, 0xab, 0x13, 0x7f, 0xba, 0x22, 0x85,
-        0x22, 0x7b, 0x83, 0xc3, 0x42, 0xff, 0x7c, 0x55, 0x02, 0x41, 0x00, 0xdd, 0xab, 0xb5, 0x83,
-        0x9c, 0x4c, 0x7f, 0x6b, 0xf3, 0xd4, 0x18, 0x32, 0x31, 0xf0, 0x05, 0xb3, 0x1a, 0xa5, 0x8a,
-        0xff, 0xdd, 0xa5, 0xc7, 0x9e, 0x4c, 0xce, 0x21, 0x7f, 0x6b, 0xc9, 0x30, 0xdb, 0xe5, 0x63,
-        0xd4, 0x80, 0x70, 0x6c, 0x24, 0xe9, 0xeb, 0xfc, 0xab, 0x28, 0xa6, 0xcd, 0xef, 0xd3, 0x24,
-        0xb7, 0x7e, 0x1b, 0xf7, 0x25, 0x1b, 0x70, 0x90, 0x92, 0xc2, 0x4f, 0xf5, 0x01, 0xfd, 0x91,
-        0x02, 0x40, 0x23, 0xd4, 0x34, 0x0e, 0xda, 0x34, 0x45, 0xd8, 0xcd, 0x26, 0xc1, 0x44, 0x11,
-        0xda, 0x6f, 0xdc, 0xa6, 0x3c, 0x1c, 0xcd, 0x4b, 0x80, 0xa9, 0x8a, 0xd5, 0x2b, 0x78, 0xcc,
-        0x8a, 0xd8, 0xbe, 0xb2, 0x84, 0x2c, 0x1d, 0x28, 0x04, 0x05, 0xbc, 0x2f, 0x6c, 0x1b, 0xea,
-        0x21, 0x4a, 0x1d, 0x74, 0x2a, 0xb9, 0x96, 0xb3, 0x5b, 0x63, 0xa8, 0x2a, 0x5e, 0x47, 0x0f,
-        0xa8, 0x8d, 0xbf, 0x82, 0x3c, 0xdd, 0x02, 0x40, 0x1b, 0x7b, 0x57, 0x44, 0x9a, 0xd3, 0x0d,
-        0x15, 0x18, 0x24, 0x9a, 0x5f, 0x56, 0xbb, 0x98, 0x29, 0x4d, 0x4b, 0x6a, 0xc1, 0x2f, 0xfc,
-        0x86, 0x94, 0x04, 0x97, 0xa5, 0xa5, 0x83, 0x7a, 0x6c, 0xf9, 0x46, 0x26, 0x2b, 0x49, 0x45,
-        0x26, 0xd3, 0x28, 0xc1, 0x1e, 0x11, 0x26, 0x38, 0x0f, 0xde, 0x04, 0xc2, 0x4f, 0x91, 0x6d,
-        0xec, 0x25, 0x08, 0x92, 0xdb, 0x09, 0xa6, 0xd7, 0x7c, 0xdb, 0xa3, 0x51, 0x02, 0x40, 0x77,
-        0x62, 0xcd, 0x8f, 0x4d, 0x05, 0x0d, 0xa5, 0x6b, 0xd5, 0x91, 0xad, 0xb5, 0x15, 0xd2, 0x4d,
-        0x7c, 0xcd, 0x32, 0xcc, 0xa0, 0xd0, 0x5f, 0x86, 0x6d, 0x58, 0x35, 0x14, 0xbd, 0x73, 0x24,
-        0xd5, 0xf3, 0x36, 0x45, 0xe8, 0xed, 0x8b, 0x4a, 0x1c, 0xb3, 0xcc, 0x4a, 0x1d, 0x67, 0x98,
-        0x73, 0x99, 0xf2, 0xa0, 0x9f, 0x5b, 0x3f, 0xb6, 0x8c, 0x88, 0xd5, 0xe5, 0xd9, 0x0a, 0xc3,
-        0x34, 0x92, 0xd6};
-unsigned int rsa_privkey_pk8_der_len = 633;
-
-unsigned char dsa_privkey_pk8_der[] = {
-        0x30, 0x82, 0x01, 0x4b, 0x02, 0x01, 0x00, 0x30, 0x82, 0x01, 0x2b, 0x06, 0x07, 0x2a, 0x86,
-        0x48, 0xce, 0x38, 0x04, 0x01, 0x30, 0x82, 0x01, 0x1e, 0x02, 0x81, 0x81, 0x00, 0xa3, 0xf3,
-        0xe9, 0xb6, 0x7e, 0x7d, 0x88, 0xf6, 0xb7, 0xe5, 0xf5, 0x1f, 0x3b, 0xee, 0xac, 0xd7, 0xad,
-        0xbc, 0xc9, 0xd1, 0x5a, 0xf8, 0x88, 0xc4, 0xef, 0x6e, 0x3d, 0x74, 0x19, 0x74, 0xe7, 0xd8,
-        0xe0, 0x26, 0x44, 0x19, 0x86, 0xaf, 0x19, 0xdb, 0x05, 0xe9, 0x3b, 0x8b, 0x58, 0x58, 0xde,
-        0xe5, 0x4f, 0x48, 0x15, 0x01, 0xea, 0xe6, 0x83, 0x52, 0xd7, 0xc1, 0x21, 0xdf, 0xb9, 0xb8,
-        0x07, 0x66, 0x50, 0xfb, 0x3a, 0x0c, 0xb3, 0x85, 0xee, 0xbb, 0x04, 0x5f, 0xc2, 0x6d, 0x6d,
-        0x95, 0xfa, 0x11, 0x93, 0x1e, 0x59, 0x5b, 0xb1, 0x45, 0x8d, 0xe0, 0x3d, 0x73, 0xaa, 0xf2,
-        0x41, 0x14, 0x51, 0x07, 0x72, 0x3d, 0xa2, 0xf7, 0x58, 0xcd, 0x11, 0xa1, 0x32, 0xcf, 0xda,
-        0x42, 0xb7, 0xcc, 0x32, 0x80, 0xdb, 0x87, 0x82, 0xec, 0x42, 0xdb, 0x5a, 0x55, 0x24, 0x24,
-        0xa2, 0xd1, 0x55, 0x29, 0xad, 0xeb, 0x02, 0x15, 0x00, 0xeb, 0xea, 0x17, 0xd2, 0x09, 0xb3,
-        0xd7, 0x21, 0x9a, 0x21, 0x07, 0x82, 0x8f, 0xab, 0xfe, 0x88, 0x71, 0x68, 0xf7, 0xe3, 0x02,
-        0x81, 0x80, 0x19, 0x1c, 0x71, 0xfd, 0xe0, 0x03, 0x0c, 0x43, 0xd9, 0x0b, 0xf6, 0xcd, 0xd6,
-        0xa9, 0x70, 0xe7, 0x37, 0x86, 0x3a, 0x78, 0xe9, 0xa7, 0x47, 0xa7, 0x47, 0x06, 0x88, 0xb1,
-        0xaf, 0xd7, 0xf3, 0xf1, 0xa1, 0xd7, 0x00, 0x61, 0x28, 0x88, 0x31, 0x48, 0x60, 0xd8, 0x11,
-        0xef, 0xa5, 0x24, 0x1a, 0x81, 0xc4, 0x2a, 0xe2, 0xea, 0x0e, 0x36, 0xd2, 0xd2, 0x05, 0x84,
-        0x37, 0xcf, 0x32, 0x7d, 0x09, 0xe6, 0x0f, 0x8b, 0x0c, 0xc8, 0xc2, 0xa4, 0xb1, 0xdc, 0x80,
-        0xca, 0x68, 0xdf, 0xaf, 0xd2, 0x90, 0xc0, 0x37, 0x58, 0x54, 0x36, 0x8f, 0x49, 0xb8, 0x62,
-        0x75, 0x8b, 0x48, 0x47, 0xc0, 0xbe, 0xf7, 0x9a, 0x92, 0xa6, 0x68, 0x05, 0xda, 0x9d, 0xaf,
-        0x72, 0x9a, 0x67, 0xb3, 0xb4, 0x14, 0x03, 0xae, 0x4f, 0x4c, 0x76, 0xb9, 0xd8, 0x64, 0x0a,
-        0xba, 0x3b, 0xa8, 0x00, 0x60, 0x4d, 0xae, 0x81, 0xc3, 0xc5, 0x04, 0x17, 0x02, 0x15, 0x00,
-        0x81, 0x9d, 0xfd, 0x53, 0x0c, 0xc1, 0x8f, 0xbe, 0x8b, 0xea, 0x00, 0x26, 0x19, 0x29, 0x33,
-        0x91, 0x84, 0xbe, 0xad, 0x81};
-unsigned int dsa_privkey_pk8_der_len = 335;
-
-unsigned char ec_privkey_pk8_der[] = {
-        0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce,
-        0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04,
-        0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, 0x73, 0x7c, 0x2e, 0xcd, 0x7b, 0x8d,
-        0x19, 0x40, 0xbf, 0x29, 0x30, 0xaa, 0x9b, 0x4e, 0xd3, 0xff, 0x94, 0x1e, 0xed, 0x09,
-        0x36, 0x6b, 0xc0, 0x32, 0x99, 0x98, 0x64, 0x81, 0xf3, 0xa4, 0xd8, 0x59, 0xa1, 0x44,
-        0x03, 0x42, 0x00, 0x04, 0xbf, 0x85, 0xd7, 0x72, 0x0d, 0x07, 0xc2, 0x54, 0x61, 0x68,
-        0x3b, 0xc6, 0x48, 0xb4, 0x77, 0x8a, 0x9a, 0x14, 0xdd, 0x8a, 0x02, 0x4e, 0x3b, 0xdd,
-        0x8c, 0x7d, 0xdd, 0x9a, 0xb2, 0xb5, 0x28, 0xbb, 0xc7, 0xaa, 0x1b, 0x51, 0xf1, 0x4e,
-        0xbb, 0xbb, 0x0b, 0xd0, 0xce, 0x21, 0xbc, 0xc4, 0x1c, 0x6e, 0xb0, 0x00, 0x83, 0xcf,
-        0x33, 0x76, 0xd1, 0x1f, 0xd4, 0x49, 0x49, 0xe0, 0xb2, 0x18, 0x3b, 0xfe};
-unsigned int ec_privkey_pk8_der_len = 138;
-
-keymaster_key_param_t ec_params[] = {
-        keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_EC),
-        keymaster_param_long(KM_TAG_EC_CURVE, KM_EC_CURVE_P_521),
-        keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_SIGN),
-        keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_VERIFY),
-        keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
-        keymaster_param_bool(KM_TAG_NO_AUTH_REQUIRED),
-};
-keymaster_key_param_set_t ec_param_set = {ec_params, sizeof(ec_params) / sizeof(*ec_params)};
-
-keymaster_key_param_t rsa_params[] = {
-        keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_RSA),
-        keymaster_param_int(KM_TAG_KEY_SIZE, 1024),
-        keymaster_param_long(KM_TAG_RSA_PUBLIC_EXPONENT, 65537),
-        keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_SIGN),
-        keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_VERIFY),
-        keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE),
-        keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
-        keymaster_param_bool(KM_TAG_NO_AUTH_REQUIRED),
-};
-keymaster_key_param_set_t rsa_param_set = {rsa_params, sizeof(rsa_params) / sizeof(*rsa_params)};
-
-struct EVP_PKEY_Delete {
-    void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
-};
-
-struct EVP_PKEY_CTX_Delete {
-    void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
-};
-
-static bool do_operation(TrustyKeymasterDevice* device, keymaster_purpose_t purpose,
-                         keymaster_key_blob_t* key, keymaster_blob_t* input,
-                         keymaster_blob_t* signature, keymaster_blob_t* output) {
-    keymaster_key_param_t params[] = {
-            keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE),
-            keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
-    };
-    keymaster_key_param_set_t param_set = {params, sizeof(params) / sizeof(*params)};
-    keymaster_operation_handle_t op_handle;
-    keymaster_error_t error = device->begin(purpose, key, &param_set, nullptr, &op_handle);
-    if (error != KM_ERROR_OK) {
-        printf("Keymaster begin() failed: %d\n", error);
-        return false;
-    }
-    size_t input_consumed;
-    error = device->update(op_handle, nullptr, input, &input_consumed, nullptr, nullptr);
-    if (error != KM_ERROR_OK) {
-        printf("Keymaster update() failed: %d\n", error);
-        return false;
-    }
-    if (input_consumed != input->data_length) {
-        // This should never happen. If it does, it's a bug in the keymaster implementation.
-        printf("Keymaster update() did not consume all data.\n");
-        device->abort(op_handle);
-        return false;
-    }
-    error = device->finish(op_handle, nullptr, nullptr, signature, nullptr, output);
-    if (error != KM_ERROR_OK) {
-        printf("Keymaster finish() failed: %d\n", error);
-        return false;
-    }
-    return true;
-}
-
-static bool test_import_rsa(TrustyKeymasterDevice* device) {
-    printf("===================\n");
-    printf("= RSA Import Test =\n");
-    printf("===================\n\n");
-
-    printf("=== Importing RSA keypair === \n");
-    keymaster_key_blob_t key;
-    keymaster_blob_t private_key = {rsa_privkey_pk8_der, rsa_privkey_pk8_der_len};
-    int error =
-            device->import_key(&rsa_param_set, KM_KEY_FORMAT_PKCS8, &private_key, &key, nullptr);
-    if (error != KM_ERROR_OK) {
-        printf("Error importing RSA key: %d\n\n", error);
-        return false;
-    }
-    std::unique_ptr<const uint8_t[]> key_deleter(key.key_material);
-
-    printf("=== Signing with imported RSA key ===\n");
-    size_t message_len = 1024 / 8;
-    std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
-    memset(message.get(), 'a', message_len);
-    keymaster_blob_t input = {message.get(), message_len}, signature;
-
-    if (!do_operation(device, KM_PURPOSE_SIGN, &key, &input, nullptr, &signature)) {
-        printf("Error signing data with imported RSA key\n\n");
-        return false;
-    }
-    std::unique_ptr<const uint8_t[]> signature_deleter(signature.data);
-
-    printf("=== Verifying with imported RSA key === \n");
-    if (!do_operation(device, KM_PURPOSE_VERIFY, &key, &input, &signature, nullptr)) {
-        printf("Error verifying data with imported RSA key\n\n");
-        return false;
-    }
-
-    printf("\n");
-    return true;
-}
-
-static bool test_rsa(TrustyKeymasterDevice* device) {
-    printf("============\n");
-    printf("= RSA Test =\n");
-    printf("============\n\n");
-
-    printf("=== Generating RSA key pair ===\n");
-    keymaster_key_blob_t key;
-    int error = device->generate_key(&rsa_param_set, &key, nullptr);
-    if (error != KM_ERROR_OK) {
-        printf("Error generating RSA key pair: %d\n\n", error);
-        return false;
-    }
-    std::unique_ptr<const uint8_t[]> key_deleter(key.key_material);
-
-    printf("=== Signing with RSA key === \n");
-    size_t message_len = 1024 / 8;
-    std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
-    memset(message.get(), 'a', message_len);
-    keymaster_blob_t input = {message.get(), message_len}, signature;
-
-    if (!do_operation(device, KM_PURPOSE_SIGN, &key, &input, nullptr, &signature)) {
-        printf("Error signing data with RSA key\n\n");
-        return false;
-    }
-    std::unique_ptr<const uint8_t[]> signature_deleter(signature.data);
-
-    printf("=== Verifying with RSA key === \n");
-    if (!do_operation(device, KM_PURPOSE_VERIFY, &key, &input, &signature, nullptr)) {
-        printf("Error verifying data with RSA key\n\n");
-        return false;
-    }
-
-    printf("=== Exporting RSA public key ===\n");
-    keymaster_blob_t exported_key;
-    error = device->export_key(KM_KEY_FORMAT_X509, &key, nullptr, nullptr, &exported_key);
-    if (error != KM_ERROR_OK) {
-        printf("Error exporting RSA public key: %d\n\n", error);
-        return false;
-    }
-
-    printf("=== Verifying with exported key ===\n");
-    const uint8_t* tmp = exported_key.data;
-    std::unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
-            d2i_PUBKEY(NULL, &tmp, exported_key.data_length));
-    std::unique_ptr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
-    if (EVP_PKEY_verify_init(ctx.get()) != 1) {
-        printf("Error initializing openss EVP context\n\n");
-        return false;
-    }
-    if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) {
-        printf("Exported key was the wrong type?!?\n\n");
-        return false;
-    }
-
-    EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING);
-    if (EVP_PKEY_verify(ctx.get(), signature.data, signature.data_length, message.get(),
-                        message_len) != 1) {
-        printf("Verification with exported pubkey failed.\n\n");
-        return false;
-    } else {
-        printf("Verification succeeded\n");
-    }
-
-    printf("\n");
-    return true;
-}
-
-static bool test_import_ecdsa(TrustyKeymasterDevice* device) {
-    printf("=====================\n");
-    printf("= ECDSA Import Test =\n");
-    printf("=====================\n\n");
-
-    printf("=== Importing ECDSA keypair === \n");
-    keymaster_key_blob_t key;
-    keymaster_blob_t private_key = {ec_privkey_pk8_der, ec_privkey_pk8_der_len};
-    int error = device->import_key(&ec_param_set, KM_KEY_FORMAT_PKCS8, &private_key, &key, nullptr);
-    if (error != KM_ERROR_OK) {
-        printf("Error importing ECDSA key: %d\n\n", error);
-        return false;
-    }
-    std::unique_ptr<const uint8_t[]> deleter(key.key_material);
-
-    printf("=== Signing with imported ECDSA key ===\n");
-    size_t message_len = 30 /* arbitrary */;
-    std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
-    memset(message.get(), 'a', message_len);
-    keymaster_blob_t input = {message.get(), message_len}, signature;
-
-    if (!do_operation(device, KM_PURPOSE_SIGN, &key, &input, nullptr, &signature)) {
-        printf("Error signing data with imported ECDSA key\n\n");
-        return false;
-    }
-    std::unique_ptr<const uint8_t[]> signature_deleter(signature.data);
-
-    printf("=== Verifying with imported ECDSA key === \n");
-    if (!do_operation(device, KM_PURPOSE_VERIFY, &key, &input, &signature, nullptr)) {
-        printf("Error verifying data with imported ECDSA key\n\n");
-        return false;
-    }
-
-    printf("\n");
-    return true;
-}
-
-static bool test_ecdsa(TrustyKeymasterDevice* device) {
-    printf("==============\n");
-    printf("= ECDSA Test =\n");
-    printf("==============\n\n");
-
-    printf("=== Generating ECDSA key pair ===\n");
-    keymaster_key_blob_t key;
-    int error = device->generate_key(&ec_param_set, &key, nullptr);
-    if (error != KM_ERROR_OK) {
-        printf("Error generating ECDSA key pair: %d\n\n", error);
-        return false;
-    }
-    std::unique_ptr<const uint8_t[]> key_deleter(key.key_material);
-
-    printf("=== Signing with ECDSA key === \n");
-    size_t message_len = 30 /* arbitrary */;
-    std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
-    memset(message.get(), 'a', message_len);
-    keymaster_blob_t input = {message.get(), message_len}, signature;
-
-    if (!do_operation(device, KM_PURPOSE_SIGN, &key, &input, nullptr, &signature)) {
-        printf("Error signing data with ECDSA key\n\n");
-        return false;
-    }
-    std::unique_ptr<const uint8_t[]> signature_deleter(signature.data);
-
-    printf("=== Verifying with ECDSA key === \n");
-    if (!do_operation(device, KM_PURPOSE_VERIFY, &key, &input, &signature, nullptr)) {
-        printf("Error verifying data with ECDSA key\n\n");
-        return false;
-    }
-
-    printf("=== Exporting ECDSA public key ===\n");
-    keymaster_blob_t exported_key;
-    error = device->export_key(KM_KEY_FORMAT_X509, &key, nullptr, nullptr, &exported_key);
-    if (error != KM_ERROR_OK) {
-        printf("Error exporting ECDSA public key: %d\n\n", error);
-        return false;
-    }
-
-    printf("=== Verifying with exported key ===\n");
-    const uint8_t* tmp = exported_key.data;
-    std::unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
-            d2i_PUBKEY(NULL, &tmp, exported_key.data_length));
-    std::unique_ptr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
-    if (EVP_PKEY_verify_init(ctx.get()) != 1) {
-        printf("Error initializing openssl EVP context\n\n");
-        return false;
-    }
-    if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) {
-        printf("Exported key was the wrong type?!?\n\n");
-        return false;
-    }
-
-    if (EVP_PKEY_verify(ctx.get(), signature.data, signature.data_length, message.get(),
-                        message_len) != 1) {
-        printf("Verification with exported pubkey failed.\n\n");
-        return false;
-    } else {
-        printf("Verification succeeded\n");
-    }
-
-    printf("\n");
-    return true;
-}
-
-int main(void) {
-    TrustyKeymasterDevice device(NULL);
-    keymaster::ConfigureDevice(reinterpret_cast<keymaster2_device_t*>(&device));
-    if (device.session_error() != KM_ERROR_OK) {
-        printf("Failed to initialize Trusty session: %d\n", device.session_error());
-        return 1;
-    }
-    printf("Trusty session initialized\n");
-
-    bool success = true;
-    success &= test_rsa(&device);
-    success &= test_import_rsa(&device);
-    success &= test_ecdsa(&device);
-    success &= test_import_ecdsa(&device);
-
-    if (success) {
-        printf("\nTESTS PASSED!\n");
-    } else {
-        printf("\n!!!!TESTS FAILED!!!\n");
-    }
-
-    return success ? 0 : 1;
-}