Merge "Make init.userspace_reboot.is_supported a rw property"
diff --git a/adb/Android.bp b/adb/Android.bp
index 81d20c1..a557090 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -114,6 +114,46 @@
     },
 }
 
+cc_defaults {
+    name: "libadbd_binary_dependencies",
+    static_libs: [
+        "libadb_crypto",
+        "libadb_pairing_connection",
+        "libadb_tls_connection",
+        "libadbd",
+        "libadbd_core",
+        "libadbconnection_server",
+        "libasyncio",
+        "libbrotli",
+        "libcutils_sockets",
+        "libdiagnose_usb",
+        "libmdnssd",
+        "libbase",
+
+        "libadb_protos",
+        "libapp_processes_protos_lite",
+        "libprotobuf-cpp-lite",
+    ],
+
+    shared_libs: [
+        "libadbd_auth",
+        "libadbd_fs",
+        "libcrypto",
+        "libcrypto_utils",
+        "liblog",
+        "libselinux",
+    ],
+
+    target: {
+        recovery: {
+            exclude_static_libs: [
+                "libadb_pairing_auth",
+                "libadb_pairing_connection",
+            ],
+        },
+    },
+}
+
 // libadb
 // =========================================================
 // These files are compiled for both the host and the device.
@@ -133,7 +173,6 @@
     "transport.cpp",
     "transport_fd.cpp",
     "transport_local.cpp",
-    "transport_usb.cpp",
     "types.cpp",
 ]
 
@@ -169,6 +208,7 @@
         "client/usb_libusb.cpp",
         "client/usb_dispatch.cpp",
         "client/transport_mdns.cpp",
+        "client/transport_usb.cpp",
         "client/pairing/pairing_client.cpp",
     ],
 
@@ -246,39 +286,6 @@
     },
 }
 
-cc_benchmark {
-    name: "adb_benchmark",
-    defaults: ["adb_defaults"],
-
-    srcs: ["transport_benchmark.cpp"],
-    target: {
-        android: {
-            static_libs: [
-                "libadbd",
-            ],
-        },
-        host: {
-            static_libs: [
-                "libadb_host",
-            ],
-        },
-    },
-
-    static_libs: [
-        "libadb_crypto_static",
-        "libadb_tls_connection_static",
-        "libadbd_auth",
-        "libbase",
-        "libcutils",
-        "libcrypto_utils",
-        "libcrypto_static",
-        "libdiagnose_usb",
-        "liblog",
-        "libssl",
-        "libusb",
-    ],
-}
-
 cc_binary_host {
     name: "adb",
 
@@ -382,10 +389,6 @@
         "daemon/adb_wifi.cpp",
     ],
 
-    local_include_dirs: [
-        "daemon/include",
-    ],
-
     generated_headers: ["platform_tools_version"],
 
     static_libs: [
@@ -404,6 +407,7 @@
         "libbase",
         "libcrypto",
         "libcrypto_utils",
+        "libcutils_sockets",
         "liblog",
     ],
 
@@ -422,12 +426,6 @@
                 "daemon/transport_qemu.cpp",
                 "daemon/usb.cpp",
                 "daemon/usb_ffs.cpp",
-                "daemon/usb_legacy.cpp",
-            ]
-        },
-        linux_glibc: {
-            srcs: [
-                "daemon/usb_dummy.cpp",
             ]
         },
         recovery: {
@@ -479,16 +477,18 @@
         "libadb_pairing_connection",
         "libadb_protos",
         "libadb_tls_connection",
-        "libadbd_auth",
-        "libadbd_fs",
         "libapp_processes_protos_lite",
         "libasyncio",
         "libbase",
-        "libcrypto",
         "libcrypto_utils",
         "libcutils_sockets",
-        "liblog",
         "libprotobuf-cpp-lite",
+
+        // APEX dependencies.
+        "libadbd_auth",
+        "libadbd_fs",
+        "libcrypto",
+        "liblog",
     ],
 
     target: {
@@ -537,10 +537,6 @@
     // libminadbd wants both, as it's used to build native tests.
     compile_multilib: "both",
 
-    whole_static_libs: [
-        "libadbd_core",
-    ],
-
     shared_libs: [
         "libadbconnection_server",
         "libapp_processes_protos_lite",
@@ -548,15 +544,17 @@
         "libadb_crypto",
         "libadb_pairing_connection",
         "libadb_tls_connection",
-        "libadbd_auth",
-        "libadbd_fs",
-        "libadbd_services",
         "libasyncio",
         "libbase",
         "libcrypto",
         "libcrypto_utils",
         "liblog",
         "libselinux",
+
+        // APEX dependencies on the system image.
+        "libadbd_auth",
+        "libadbd_fs",
+        "libadbd_services",
     ],
 
     target: {
@@ -569,20 +567,22 @@
     },
 
     static_libs: [
+        "libadbd_core",
         "libbrotli",
         "libcutils_sockets",
         "libdiagnose_usb",
         "libmdnssd",
     ],
 
-    export_include_dirs: [
-        "daemon/include",
+    visibility: [
+        "//bootable/recovery/minadbd",
+        "//system/core/adb",
     ],
 }
 
 cc_binary {
     name: "adbd",
-    defaults: ["adbd_defaults", "host_adbd_supported"],
+    defaults: ["adbd_defaults", "host_adbd_supported", "libadbd_binary_dependencies"],
     stl: "libc++_static",
     recovery_available: true,
     apex_available: ["com.android.adbd"],
@@ -601,33 +601,17 @@
     },
 
     static_libs: [
-        "libadb_crypto",
-        "libadb_tls_connection",
-        "libadbconnection_server",
         "libadbd",
         "libadbd_services",
-        "libapp_processes_protos_lite",
         "libasyncio",
-        "libbase",
-        "libbrotli",
         "libcap",
-        "libcrypto_utils",
-        "libcutils_sockets",
-        "libdiagnose_usb",
-        "libmdnssd",
         "libminijail",
-        "libprotobuf-cpp-lite",
         "libssl",
     ],
 
     shared_libs: [
-        "libadb_pairing_connection",
         "libadb_protos",
         "libadbd_auth",
-        "libadbd_fs",
-        "libcrypto",
-        "liblog",
-        "libselinux",
     ],
 
     target: {
@@ -699,8 +683,7 @@
 cc_test {
     name: "adbd_test",
 
-    defaults: ["adbd_defaults"],
-    stl: "libc++_static",
+    defaults: ["adbd_defaults", "libadbd_binary_dependencies"],
 
     recovery_available: false,
     srcs: libadb_test_srcs + [
@@ -711,21 +694,16 @@
         "shell_service_protocol_test.cpp",
     ],
 
+    shared_libs: [
+        "liblog",
+    ],
+
     static_libs: [
         "libadbd",
         "libadbd_auth",
-        "libadb_crypto_static",
-        "libadb_pairing_connection_static",
-        "libadb_tls_connection_static",
         "libbase",
         "libcrypto_utils",
-        "libcrypto_static",
-        "libcutils_sockets",
-        "libdiagnose_usb",
-        "liblog",
         "libusb",
-        "libmdnssd",
-        "libselinux",
     ],
     test_suites: ["device-tests", "mts"],
     require_root: true,
diff --git a/adb/adb.cpp b/adb/adb.cpp
index b514368..6c03f74 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -66,6 +66,10 @@
 #include "daemon/logging.h"
 #endif
 
+#if ADB_HOST
+#include "client/usb.h"
+#endif
+
 std::string adb_version() {
     // Don't change the format of this --- it's parsed by ddmlib.
     return android::base::StringPrintf(
diff --git a/adb/adb.h b/adb/adb.h
index 9f8d299..7bc60fc 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -29,7 +29,6 @@
 #include "fdevent/fdevent.h"
 #include "socket.h"
 #include "types.h"
-#include "usb.h"
 
 constexpr size_t MAX_PAYLOAD_V1 = 4 * 1024;
 constexpr size_t MAX_PAYLOAD = 1024 * 1024;
@@ -139,7 +138,6 @@
 
 /* initialize a transport object's func pointers and state */
 int init_socket_transport(atransport* t, unique_fd s, int port, int local);
-void init_usb_transport(atransport* t, usb_handle* usb);
 
 std::string getEmulatorSerialString(int console_port);
 #if ADB_HOST
@@ -253,4 +251,5 @@
 // Wait until device scan has completed and every transport is ready, or a timeout elapses.
 void adb_wait_for_device_initialization();
 
+void usb_init();
 #endif
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index e4d010c..092a866 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -325,7 +325,12 @@
         }
     }
 
-    if (first_apk == -1) error_exit("Need at least one APK file on command line");
+    if (first_apk == -1) {
+        if (!silent) {
+            fprintf(stderr, "error: need at least one APK file on command line\n");
+        }
+        return -1;
+    }
 
     auto files = incremental::Files{argv + first_apk, argv + last_apk + 1};
     if (silent) {
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 33e0716..4a9eadc 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -36,6 +36,7 @@
 #include "adb_listeners.h"
 #include "adb_utils.h"
 #include "adb_wifi.h"
+#include "client/usb.h"
 #include "commandline.h"
 #include "sysdeps/chrono.h"
 #include "transport.h"
diff --git a/adb/transport_usb.cpp b/adb/client/transport_usb.cpp
similarity index 96%
rename from adb/transport_usb.cpp
rename to adb/client/transport_usb.cpp
index fb81b37..777edde 100644
--- a/adb/transport_usb.cpp
+++ b/adb/client/transport_usb.cpp
@@ -16,6 +16,10 @@
 
 #define TRACE_TAG TRANSPORT
 
+#include "sysdeps.h"
+
+#include "client/usb.h"
+
 #include <memory>
 
 #include "sysdeps.h"
@@ -135,8 +139,8 @@
         }
 
         p->payload.resize(p->msg.data_length);
-        if (usb_read(usb, &p->payload[0], p->payload.size())
-                != static_cast<int>(p->payload.size())) {
+        if (usb_read(usb, &p->payload[0], p->payload.size()) !=
+            static_cast<int>(p->payload.size())) {
             PLOG(ERROR) << "remote usb: terminated (data)";
             return -1;
         }
diff --git a/adb/usb.h b/adb/client/usb.h
similarity index 72%
rename from adb/usb.h
rename to adb/client/usb.h
index eb8ca6c..b371788 100644
--- a/adb/usb.h
+++ b/adb/client/usb.h
@@ -18,6 +18,9 @@
 
 #include <sys/types.h>
 
+#include "adb.h"
+#include "transport.h"
+
 // USB host/client interface.
 
 #define ADB_USB_INTERFACE(handle_ref_type)                       \
@@ -30,35 +33,38 @@
     void usb_kick(handle_ref_type h);                            \
     size_t usb_get_max_packet_size(handle_ref_type)
 
-#if !ADB_HOST
-// The daemon has a single implementation.
-
-struct usb_handle;
-ADB_USB_INTERFACE(usb_handle*);
-
-#else // linux host || darwin
 // Linux and Darwin clients have native and libusb implementations.
 
 namespace libusb {
-    struct usb_handle;
-    ADB_USB_INTERFACE(libusb::usb_handle*);
-}
+struct usb_handle;
+ADB_USB_INTERFACE(libusb::usb_handle*);
+}  // namespace libusb
 
 namespace native {
-    struct usb_handle;
-    ADB_USB_INTERFACE(native::usb_handle*);
-}
+struct usb_handle;
+ADB_USB_INTERFACE(native::usb_handle*);
+}  // namespace native
 
 // Empty base that both implementations' opaque handles inherit from.
-struct usb_handle {
-};
+struct usb_handle {};
 
 ADB_USB_INTERFACE(::usb_handle*);
 
-#endif // linux host || darwin
-
-
 // USB device detection.
 int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol);
 
 bool should_use_libusb();
+
+struct UsbConnection : public BlockingConnection {
+    explicit UsbConnection(usb_handle* handle) : handle_(handle) {}
+    ~UsbConnection();
+
+    bool Read(apacket* packet) override final;
+    bool Write(apacket* packet) override final;
+    bool DoTlsHandshake(RSA* key, std::string* auth_key) override final;
+
+    void Close() override final;
+    virtual void Reset() override final;
+
+    usb_handle* handle_;
+};
diff --git a/adb/client/usb_dispatch.cpp b/adb/client/usb_dispatch.cpp
index f55ae90..7b97117 100644
--- a/adb/client/usb_dispatch.cpp
+++ b/adb/client/usb_dispatch.cpp
@@ -15,7 +15,8 @@
  */
 
 #include <android-base/logging.h>
-#include "usb.h"
+
+#include "client/usb.h"
 
 void usb_init() {
     if (should_use_libusb()) {
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index 53f01a0..07cbc94 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-#include "usb.h"
-
 #include "sysdeps.h"
 
+#include "client/usb.h"
+
 #include <stdint.h>
 #include <stdlib.h>
 
@@ -40,7 +40,6 @@
 #include "adb.h"
 #include "adb_utils.h"
 #include "transport.h"
-#include "usb.h"
 
 using android::base::StringPrintf;
 
diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp
index 343e7b5..95b1817 100644
--- a/adb/client/usb_linux.cpp
+++ b/adb/client/usb_linux.cpp
@@ -18,6 +18,8 @@
 
 #include "sysdeps.h"
 
+#include "client/usb.h"
+
 #include <ctype.h>
 #include <dirent.h>
 #include <errno.h>
@@ -48,7 +50,6 @@
 
 #include "adb.h"
 #include "transport.h"
-#include "usb.h"
 
 using namespace std::chrono_literals;
 using namespace std::literals;
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index 7207ca7..a93fa3a 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -18,6 +18,8 @@
 
 #include "sysdeps.h"
 
+#include "client/usb.h"
+
 #include <CoreFoundation/CoreFoundation.h>
 
 #include <IOKit/IOKitLib.h>
diff --git a/adb/client/usb_windows.cpp b/adb/client/usb_windows.cpp
index 197c6fa..e209230 100644
--- a/adb/client/usb_windows.cpp
+++ b/adb/client/usb_windows.cpp
@@ -18,6 +18,8 @@
 
 #include "sysdeps.h"
 
+#include "client/usb.h"
+
 // clang-format off
 #include <winsock2.h>  // winsock.h *must* be included before windows.h.
 #include <windows.h>
diff --git a/adb/crypto/Android.bp b/adb/crypto/Android.bp
index ce1de4a..9d14b03 100644
--- a/adb/crypto/Android.bp
+++ b/adb/crypto/Android.bp
@@ -40,6 +40,7 @@
 
     visibility: [
         "//system/core/adb:__subpackages__",
+        "//bootable/recovery/minadbd:__subpackages__",
     ],
 
     host_supported: true,
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 87937fb..7fff05a 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -45,19 +45,15 @@
 #include <android-base/properties.h>
 #include <android-base/thread_annotations.h>
 
-#include <adbd/usb.h>
-
 #include "adb_unique_fd.h"
 #include "adb_utils.h"
+#include "daemon/usb_ffs.h"
 #include "sysdeps/chrono.h"
 #include "transport.h"
 #include "types.h"
 
 using android::base::StringPrintf;
 
-// We can't find out whether we have support for AIO on ffs endpoints until we submit a read.
-static std::optional<bool> gFfsAioSupported;
-
 // Not all USB controllers support operations larger than 16k, so don't go above that.
 // Also, each submitted operation does an allocation in the kernel of that size, so we want to
 // minimize our queue depth while still maintaining a deep enough queue to keep the USB stack fed.
@@ -612,17 +608,10 @@
         block->pending = true;
         struct iocb* iocb = &block->control;
         if (io_submit(aio_context_.get(), 1, &iocb) != 1) {
-            if (errno == EINVAL && !gFfsAioSupported.has_value()) {
-                HandleError("failed to submit first read, AIO on FFS not supported");
-                gFfsAioSupported = false;
-                return false;
-            }
-
             HandleError(StringPrintf("failed to submit read: %s", strerror(errno)));
             return false;
         }
 
-        gFfsAioSupported = true;
         return true;
     }
 
@@ -741,17 +730,10 @@
     static constexpr int kInterruptionSignal = SIGUSR1;
 };
 
-void usb_init_legacy();
-
 static void usb_ffs_open_thread() {
     adb_thread_setname("usb ffs open");
 
     while (true) {
-        if (gFfsAioSupported.has_value() && !gFfsAioSupported.value()) {
-            LOG(INFO) << "failed to use nonblocking ffs, falling back to legacy";
-            return usb_init_legacy();
-        }
-
         unique_fd control;
         unique_fd bulk_out;
         unique_fd bulk_in;
@@ -773,13 +755,5 @@
 }
 
 void usb_init() {
-    bool use_nonblocking = android::base::GetBoolProperty(
-            "persist.adb.nonblocking_ffs",
-            android::base::GetBoolProperty("ro.adb.nonblocking_ffs", true));
-
-    if (use_nonblocking) {
-        std::thread(usb_ffs_open_thread).detach();
-    } else {
-        usb_init_legacy();
-    }
+    std::thread(usb_ffs_open_thread).detach();
 }
diff --git a/adb/daemon/usb_dummy.cpp b/adb/daemon/usb_dummy.cpp
deleted file mode 100644
index c9bf797..0000000
--- a/adb/daemon/usb_dummy.cpp
+++ /dev/null
@@ -1,42 +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.
- */
-
-#include <adbd/usb.h>
-
-#include <android-base/logging.h>
-
-int usb_write(usb_handle*, const void*, int) {
-    LOG(FATAL) << "unimplemented";
-    return -1;
-}
-
-int usb_read(usb_handle*, void*, int) {
-    LOG(FATAL) << "unimplemented";
-    return -1;
-}
-
-int usb_close(usb_handle*) {
-    LOG(FATAL) << "unimplemented";
-    return -1;
-}
-
-void usb_reset(usb_handle*) {
-    LOG(FATAL) << "unimplemented";
-}
-
-void usb_kick(usb_handle*) {
-    LOG(FATAL) << "unimplemented";
-}
diff --git a/adb/daemon/usb_ffs.cpp b/adb/daemon/usb_ffs.cpp
index cb7e2fb..7bd611b 100644
--- a/adb/daemon/usb_ffs.cpp
+++ b/adb/daemon/usb_ffs.cpp
@@ -18,6 +18,8 @@
 
 #include "sysdeps.h"
 
+#include "daemon/usb_ffs.h"
+
 #include <linux/usb/ch9.h>
 #include <linux/usb/functionfs.h>
 
@@ -26,7 +28,6 @@
 #include <android-base/unique_fd.h>
 
 #include "adb.h"
-#include "adbd/usb.h"
 
 #define MAX_PACKET_SIZE_FS 64
 #define MAX_PACKET_SIZE_HS 512
diff --git a/adb/daemon/usb_ffs.h b/adb/daemon/usb_ffs.h
new file mode 100644
index 0000000..a19d7cc
--- /dev/null
+++ b/adb/daemon/usb_ffs.h
@@ -0,0 +1,22 @@
+/*
+ * 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 <android-base/unique_fd.h>
+
+bool open_functionfs(android::base::unique_fd* control, android::base::unique_fd* bulk_out,
+                     android::base::unique_fd* bulk_in);
diff --git a/adb/pairing_connection/Android.bp b/adb/pairing_connection/Android.bp
index bcde7b1..707161b 100644
--- a/adb/pairing_connection/Android.bp
+++ b/adb/pairing_connection/Android.bp
@@ -41,6 +41,9 @@
         "//art:__subpackages__",
         "//system/core/adb:__subpackages__",
         "//frameworks/base/services:__subpackages__",
+
+        // This needs to be visible to minadbd, even though it's removed via exclude_shared_libs.
+        "//bootable/recovery/minadbd:__subpackages__",
     ],
     apex_available: [
         "com.android.adbd",
diff --git a/adb/proto/Android.bp b/adb/proto/Android.bp
index fe828a0..086d10e 100644
--- a/adb/proto/Android.bp
+++ b/adb/proto/Android.bp
@@ -41,6 +41,9 @@
 
     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",
@@ -92,6 +95,9 @@
 
     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",
diff --git a/adb/tls/Android.bp b/adb/tls/Android.bp
index f2837e1..e5204f3 100644
--- a/adb/tls/Android.bp
+++ b/adb/tls/Android.bp
@@ -39,6 +39,7 @@
     recovery_available: true,
 
     visibility: [
+        "//bootable/recovery/minadbd:__subpackages__",
         "//system/core/adb:__subpackages__",
     ],
 
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 6dccb7f..e06dbe3 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -1452,6 +1452,7 @@
 
 #endif
 
+#if ADB_HOST
 void register_usb_transport(usb_handle* usb, const char* serial, const char* devpath,
                             unsigned writeable) {
     atransport* t = new atransport(writeable ? kCsOffline : kCsNoPerm);
@@ -1473,6 +1474,7 @@
 
     register_transport(t);
 }
+#endif
 
 #if ADB_HOST
 // This should only be used for transports with connection_state == kCsNoPerm.
diff --git a/adb/transport.h b/adb/transport.h
index 3a77cf6..b1984db 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -39,7 +39,6 @@
 #include "adb.h"
 #include "adb_unique_fd.h"
 #include "types.h"
-#include "usb.h"
 
 typedef std::unordered_set<std::string> FeatureSet;
 
@@ -204,20 +203,6 @@
     std::unique_ptr<adb::tls::TlsConnection> tls_;
 };
 
-struct UsbConnection : public BlockingConnection {
-    explicit UsbConnection(usb_handle* handle) : handle_(handle) {}
-    ~UsbConnection();
-
-    bool Read(apacket* packet) override final;
-    bool Write(apacket* packet) override final;
-    bool DoTlsHandshake(RSA* key, std::string* auth_key) override final;
-
-    void Close() override final;
-    virtual void Reset() override final;
-
-    usb_handle* handle_;
-};
-
 // Waits for a transport's connection to be not pending. This is a separate
 // object so that the transport can be destroyed and another thread can be
 // notified of it in a race-free way.
@@ -253,6 +238,10 @@
     Abort,
 };
 
+#if ADB_HOST
+struct usb_handle;
+#endif
+
 class atransport : public enable_weak_from_this<atransport> {
   public:
     // TODO(danalbert): We expose waaaaaaay too much stuff because this was
@@ -293,8 +282,10 @@
         return connection_;
     }
 
+#if ADB_HOST
     void SetUsbHandle(usb_handle* h) { usb_handle_ = h; }
     usb_handle* GetUsbHandle() { return usb_handle_; }
+#endif
 
     const TransportId id;
 
@@ -401,8 +392,10 @@
     // The underlying connection object.
     std::shared_ptr<Connection> connection_ GUARDED_BY(mutex_);
 
+#if ADB_HOST
     // USB handle for the connection, if available.
     usb_handle* usb_handle_ = nullptr;
+#endif
 
     // A callback that will be invoked when the atransport needs to reconnect.
     ReconnectCallback reconnect_;
@@ -443,8 +436,15 @@
 #endif
 
 void register_transport(atransport* transport);
-void register_usb_transport(usb_handle* h, const char* serial,
-                            const char* devpath, unsigned writeable);
+
+#if ADB_HOST
+void init_usb_transport(atransport* t, usb_handle* usb);
+void register_usb_transport(usb_handle* h, const char* serial, const char* devpath,
+                            unsigned writeable);
+
+// This should only be used for transports with connection_state == kCsNoPerm.
+void unregister_usb_transport(usb_handle* usb);
+#endif
 
 /* Connect to a network address and register it as a device */
 void connect_device(const std::string& address, std::string* response);
@@ -454,9 +454,6 @@
                                atransport::ReconnectCallback reconnect, bool use_tls,
                                int* error = nullptr);
 
-// This should only be used for transports with connection_state == kCsNoPerm.
-void unregister_usb_transport(usb_handle* usb);
-
 bool check_header(apacket* p, atransport* t);
 
 void close_usb_devices(bool reset = false);
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 6a38145..0cd2350 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -264,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:
@@ -280,25 +278,32 @@
         break;
     };
 
-    if (rc != expected_size) {
+    if (rc < expected_size) {
       LOG(FATAL) << "read " << rc << " bytes when reading target crash information, expected "
                  << expected_size;
     }
   }
 
   switch (crash_info->header.version) {
-    case 3:
-      process_info->gwp_asan_state = crash_info->data.v3.gwp_asan_state;
-      process_info->gwp_asan_metadata = crash_info->data.v3.gwp_asan_metadata;
-      FALLTHROUGH_INTENDED;
-    case 2:
-      process_info->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:
-      process_info->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:
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/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 9e3a649..ac28fe9 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -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/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
index 4f681c2..35c3fd6 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
@@ -41,4 +41,7 @@
   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/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 87bb8c5..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), "--------");
@@ -384,7 +384,7 @@
   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());
   }
 
   std::unique_ptr<GwpAsanCrashData> gwp_asan_crash_data;
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/fastboot/Android.bp b/fastboot/Android.bp
index a757d56..884856d 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -115,6 +115,7 @@
         "device/fastboot_device.cpp",
         "device/flashing.cpp",
         "device/main.cpp",
+        "device/usb.cpp",
         "device/usb_client.cpp",
         "device/utility.cpp",
         "device/variables.cpp",
@@ -125,7 +126,6 @@
         "android.hardware.boot@1.1",
         "android.hardware.fastboot@1.0",
         "android.hardware.health@2.0",
-        "libadbd",
         "libasyncio",
         "libbase",
         "libbootloader_message",
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/adb/daemon/usb_legacy.cpp b/fastboot/device/usb.cpp
similarity index 70%
rename from adb/daemon/usb_legacy.cpp
rename to fastboot/device/usb.cpp
index fe80e7d..4bee7b2 100644
--- a/adb/daemon/usb_legacy.cpp
+++ b/fastboot/device/usb.cpp
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-#define TRACE_TAG USB
-
-#include "sysdeps.h"
+#include "usb.h"
 
 #include <dirent.h>
 #include <errno.h>
@@ -41,12 +39,9 @@
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 
-#include "adb.h"
-#include "adbd/usb.h"
-#include "transport.h"
-
 using namespace std::chrono_literals;
 
+#define D(...)
 #define MAX_PACKET_SIZE_FS 64
 #define MAX_PACKET_SIZE_HS 512
 #define MAX_PACKET_SIZE_SS 1024
@@ -56,8 +51,6 @@
 // Number of buffers needed to fit MAX_PAYLOAD, with an extra for ZLPs.
 #define USB_FFS_NUM_BUFS ((4 * MAX_PAYLOAD / USB_FFS_BULK_SIZE) + 1)
 
-static unique_fd& dummy_fd = *new unique_fd();
-
 static void aio_block_init(aio_block* aiob, unsigned num_bufs) {
     aiob->iocb.resize(num_bufs);
     aiob->iocbs.resize(num_bufs);
@@ -82,46 +75,6 @@
     }
 }
 
-static bool init_functionfs(struct usb_handle* h) {
-    LOG(INFO) << "initializing functionfs";
-    if (!open_functionfs(&h->control, &h->bulk_out, &h->bulk_in)) {
-        return false;
-    }
-
-    h->read_aiob.fd = h->bulk_out.get();
-    h->write_aiob.fd = h->bulk_in.get();
-    h->reads_zero_packets = true;
-    return true;
-}
-
-static void usb_legacy_ffs_open_thread(usb_handle* usb) {
-    adb_thread_setname("usb legacy ffs open");
-
-    while (true) {
-        // wait until the USB device needs opening
-        std::unique_lock<std::mutex> lock(usb->lock);
-        while (!usb->open_new_connection) {
-            usb->notify.wait(lock);
-        }
-        usb->open_new_connection = false;
-        lock.unlock();
-
-        while (true) {
-            if (init_functionfs(usb)) {
-                LOG(INFO) << "functionfs successfully initialized";
-                break;
-            }
-            std::this_thread::sleep_for(1s);
-        }
-
-        LOG(INFO) << "registering usb transport";
-        register_usb_transport(usb, nullptr, nullptr, 1);
-    }
-
-    // never gets here
-    abort();
-}
-
 static int usb_ffs_write(usb_handle* h, const void* data, int len) {
     D("about to write (fd=%d, len=%d)", h->bulk_in.get(), len);
 
@@ -129,7 +82,7 @@
     int orig_len = len;
     while (len > 0) {
         int write_len = std::min(USB_FFS_BULK_SIZE, len);
-        int n = adb_write(h->bulk_in, buf, write_len);
+        int n = write(h->bulk_in, buf, write_len);
         if (n < 0) {
             D("ERROR: fd = %d, n = %d: %s", h->bulk_in.get(), n, strerror(errno));
             return -1;
@@ -150,7 +103,7 @@
     unsigned count = 0;
     while (len > 0) {
         int read_len = std::min(USB_FFS_BULK_SIZE, len);
-        int n = adb_read(h->bulk_out, buf, read_len);
+        int n = read(h->bulk_out, buf, read_len);
         if (n < 0) {
             D("ERROR: fd = %d, n = %d: %s", h->bulk_out.get(), n, strerror(errno));
             return -1;
@@ -232,7 +185,7 @@
     }
 }
 
-static int usb_ffs_aio_read(usb_handle* h, void* data, int len, bool allow_partial) {
+static int usb_ffs_aio_read(usb_handle* h, void* data, int len, bool /* allow_partial */) {
     return usb_ffs_do_aio(h, data, len, true);
 }
 
@@ -240,32 +193,9 @@
     return usb_ffs_do_aio(h, data, len, false);
 }
 
-static void usb_ffs_kick(usb_handle* h) {
-    int err;
-
-    err = ioctl(h->bulk_in.get(), FUNCTIONFS_CLEAR_HALT);
-    if (err < 0) {
-        D("[ kick: source (fd=%d) clear halt failed (%d) ]", h->bulk_in.get(), errno);
-    }
-
-    err = ioctl(h->bulk_out.get(), FUNCTIONFS_CLEAR_HALT);
-    if (err < 0) {
-        D("[ kick: sink (fd=%d) clear halt failed (%d) ]", h->bulk_out.get(), errno);
-    }
-
-    // don't close ep0 here, since we may not need to reinitialize it with
-    // the same descriptors again. if however ep1/ep2 fail to re-open in
-    // init_functionfs, only then would we close and open ep0 again.
-    // Ditto the comment in usb_adb_kick.
-    h->kicked = true;
-    TEMP_FAILURE_RETRY(dup2(dummy_fd.get(), h->bulk_out.get()));
-    TEMP_FAILURE_RETRY(dup2(dummy_fd.get(), h->bulk_in.get()));
-}
-
 static void usb_ffs_close(usb_handle* h) {
     LOG(INFO) << "closing functionfs transport";
 
-    h->kicked = false;
     h->bulk_out.reset();
     h->bulk_in.reset();
 
@@ -291,37 +221,6 @@
         aio_block_init(&h->write_aiob, num_bufs);
     }
     h->io_size = io_size;
-    h->kick = usb_ffs_kick;
     h->close = usb_ffs_close;
     return h;
 }
-
-void usb_init_legacy() {
-    D("[ usb_init - using legacy FunctionFS ]");
-    dummy_fd.reset(adb_open("/dev/null", O_WRONLY | O_CLOEXEC));
-    CHECK_NE(-1, dummy_fd.get());
-
-    std::thread(usb_legacy_ffs_open_thread, create_usb_handle(USB_FFS_NUM_BUFS, USB_FFS_BULK_SIZE))
-            .detach();
-}
-
-int usb_write(usb_handle* h, const void* data, int len) {
-    return h->write(h, data, len);
-}
-
-int usb_read(usb_handle* h, void* data, int len) {
-    return h->read(h, data, len, false /* allow_partial */);
-}
-
-int usb_close(usb_handle* h) {
-    h->close(h);
-    return 0;
-}
-
-void usb_reset(usb_handle* h) {
-    usb_close(h);
-}
-
-void usb_kick(usb_handle* h) {
-    h->kick(h);
-}
diff --git a/adb/daemon/include/adbd/usb.h b/fastboot/device/usb.h
similarity index 84%
rename from adb/daemon/include/adbd/usb.h
rename to fastboot/device/usb.h
index 2204246..6c3f542 100644
--- a/adb/daemon/include/adbd/usb.h
+++ b/fastboot/device/usb.h
@@ -36,17 +36,14 @@
 };
 
 struct usb_handle {
-    usb_handle() : kicked(false) {
-    }
+    usb_handle() {}
 
     std::condition_variable notify;
     std::mutex lock;
-    std::atomic<bool> kicked;
     bool open_new_connection = true;
 
     int (*write)(usb_handle* h, const void* data, int len);
     int (*read)(usb_handle* h, void* data, int len, bool allow_partial);
-    void (*kick)(usb_handle* h);
     void (*close)(usb_handle* h);
 
     // FunctionFS
@@ -63,6 +60,4 @@
     size_t io_size;
 };
 
-usb_handle *create_usb_handle(unsigned num_bufs, unsigned io_size);
-bool open_functionfs(android::base::unique_fd* control, android::base::unique_fd* bulk_out,
-                     android::base::unique_fd* bulk_in);
+usb_handle* create_usb_handle(unsigned num_bufs, unsigned io_size);
diff --git a/fastboot/device/usb_client.h b/fastboot/device/usb_client.h
index e6a1a8b..e702a0d 100644
--- a/fastboot/device/usb_client.h
+++ b/fastboot/device/usb_client.h
@@ -17,7 +17,7 @@
 
 #include <memory>
 
-#include <adbd/usb.h>
+#include "usb.h"
 
 #include "transport.h"
 
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 1e4e127..655b8de 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -489,7 +489,9 @@
         }
         LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
                   << process_log_string;
-        DebugRebootLogging();
+        if (!value.empty()) {
+            DebugRebootLogging();
+        }
     }
 
     // If a process other than init is writing a non-empty value, it means that process is
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/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/libziparchive/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
index 435bfb6..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;
 
diff --git a/libziparchive/test_ziparchive_large.py b/libziparchive/test_ziparchive_large.py
index c29c37e..6b82f63 100644
--- a/libziparchive/test_ziparchive_large.py
+++ b/libziparchive/test_ziparchive_large.py
@@ -26,13 +26,17 @@
 
 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():
-      contents = name[0] * 1024
       file_path = tempfile.NamedTemporaryFile()
-      with open(file_path.name, 'w') as f:
-        for it in range(0, size):
-          f.write(contents)
+      Zip64Test._WriteFile(file_path.name, size)
       output_zip.write(file_path.name, arcname = name)
 
   def _getEntryNames(self, zip_name):
@@ -93,6 +97,22 @@
     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__)))
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 849b68c..031d43a 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -57,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;
@@ -221,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;
       }
@@ -360,8 +358,9 @@
   // Data Size - 2 bytes
   uint16_t offset = 0;
   while (offset < extraFieldLength - 4) {
-    auto headerId = get_unaligned<uint16_t>(extraFieldStart + offset);
-    auto dataSize = get_unaligned<uint16_t>(extraFieldStart + offset + 2);
+    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) {
@@ -376,54 +375,44 @@
       continue;
     }
 
-    uint16_t expectedDataSize = 0;
-    // We expect the extended field to include both uncompressed and compressed size.
-    if (zip32UncompressedSize == UINT32_MAX || zip32CompressedSize == UINT32_MAX) {
-      expectedDataSize += 16;
+    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) {
-      expectedDataSize += 8;
+      localHeaderOffset = ConsumeUnaligned<uint64_t>(&readPtr);
     }
 
-    if (expectedDataSize == 0) {
+    // 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 != expectedDataSize) {
+    if (dataSize != bytesRead) {
       auto localOffsetString = zip32LocalFileHeaderOffset.has_value()
                                    ? std::to_string(zip32LocalFileHeaderOffset.value())
                                    : "missing";
-      ALOGW("Zip: Invalid data size in zip64 extended field, expect %" PRIu16 ", get %" PRIu16
+      ALOGW("Zip: Invalid data size in zip64 extended field, expect %zu , get %" PRIu16
             ", uncompressed size %" PRIu32 ", compressed size %" PRIu32 ", local header offset %s",
-            expectedDataSize, dataSize, zip32UncompressedSize, zip32CompressedSize,
+            bytesRead, dataSize, zip32UncompressedSize, zip32CompressedSize,
             localOffsetString.c_str());
       return kInvalidFile;
     }
 
-    std::optional<uint64_t> uncompressedFileSize;
-    std::optional<uint64_t> compressedFileSize;
-    std::optional<uint64_t> localHeaderOffset;
-    if (zip32UncompressedSize == UINT32_MAX || zip32CompressedSize == UINT32_MAX) {
-      uncompressedFileSize = get_unaligned<uint64_t>(extraFieldStart + offset);
-      compressedFileSize = get_unaligned<uint64_t>(extraFieldStart + offset + 8);
-      offset += 16;
-
-      // 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.value() >= UINT32_MAX || compressedFileSize.value() >= UINT32_MAX) {
-        ALOGW(
-            "Zip: File size larger than UINT32_MAX isn't supported yet. uncompressed size %" PRIu64
-            ", compressed size %" PRIu64,
-            uncompressedFileSize.value(), compressedFileSize.value());
-        return kInvalidFile;
-      }
-    }
-
-    if (zip32LocalFileHeaderOffset == UINT32_MAX) {
-      localHeaderOffset = get_unaligned<uint64_t>(extraFieldStart + offset);
-      offset += 8;
+    // 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;
@@ -625,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;
@@ -638,18 +628,26 @@
   }
 
   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;
   }
 
@@ -706,18 +704,14 @@
       return status;
     }
 
-    if (cdr->uncompressed_size == UINT32_MAX || cdr->compressed_size == UINT32_MAX) {
-      CHECK(zip64_info.uncompressed_file_size.has_value());
-      CHECK(zip64_info.compressed_file_size.has_value());
-      // 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());
-      data->compressed_length = static_cast<uint32_t>(zip64_info.compressed_file_size.value());
-    }
-
-    if (local_header_offset == UINT32_MAX) {
-      CHECK(zip64_info.local_header_offset.has_value());
-      local_header_offset = zip64_info.local_header_offset.value();
-    }
+    // 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) {
@@ -766,6 +760,13 @@
   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) {
diff --git a/libziparchive/zip_archive_common.h b/libziparchive/zip_archive_common.h
index a92d4d2..d461856 100644
--- a/libziparchive/zip_archive_common.h
+++ b/libziparchive/zip_archive_common.h
@@ -165,15 +165,24 @@
 
   // 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);
-} __attribute__((packed));
+};
 
 // The zip64 end of central directory locator helps to find the zip64 EOCD.
 struct Zip64EocdLocator {
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 5f5232f..4ed07aa 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -28,6 +28,7 @@
 
 #include "android-base/macros.h"
 #include "android-base/mapped_file.h"
+#include "android-base/memory.h"
 #include "zip_cd_entry_map.h"
 #include "zip_error.h"
 
@@ -104,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 69be3df..3563340 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -979,10 +979,11 @@
     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();
+             compressed_bytes.size() + data_descriptor.size();
     }
 
     void CopyToOutput(std::vector<uint8_t>* output) const {
@@ -990,6 +991,7 @@
       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));
     }
   };
 
@@ -1057,7 +1059,7 @@
   // 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 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;
@@ -1084,6 +1086,21 @@
     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) {
@@ -1270,3 +1287,38 @@
       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_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/rootdir/init.rc b/rootdir/init.rc
index 5ebffab..adfdb7b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -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.