Merge "Make memunreachable_binder_test suitable for VTS"
diff --git a/adb/adb.cpp b/adb/adb.cpp
index ee3503b..c4df5c4 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -42,7 +42,6 @@
 #include <android-base/logging.h>
 #include <android-base/macros.h>
 #include <android-base/parsenetaddress.h>
-#include <android-base/quick_exit.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 
@@ -105,31 +104,27 @@
 }
 
 uint32_t calculate_apacket_checksum(const apacket* p) {
-    const unsigned char* x = reinterpret_cast<const unsigned char*>(p->data);
     uint32_t sum = 0;
-    size_t count = p->msg.data_length;
-
-    while (count-- > 0) {
-        sum += *x++;
+    for (size_t i = 0; i < p->msg.data_length; ++i) {
+        sum += static_cast<uint8_t>(p->payload[i]);
     }
-
     return sum;
 }
 
 apacket* get_apacket(void)
 {
-    apacket* p = reinterpret_cast<apacket*>(malloc(sizeof(apacket)));
+    apacket* p = new apacket();
     if (p == nullptr) {
       fatal("failed to allocate an apacket");
     }
 
-    memset(p, 0, sizeof(apacket) - MAX_PAYLOAD);
+    memset(&p->msg, 0, sizeof(p->msg));
     return p;
 }
 
 void put_apacket(apacket *p)
 {
-    free(p);
+    delete p;
 }
 
 void handle_online(atransport *t)
@@ -155,8 +150,7 @@
 #define DUMPMAX 32
 void print_packet(const char *label, apacket *p)
 {
-    char *tag;
-    char *x;
+    const char* tag;
     unsigned count;
 
     switch(p->msg.command){
@@ -173,15 +167,15 @@
     fprintf(stderr, "%s: %s %08x %08x %04x \"",
             label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length);
     count = p->msg.data_length;
-    x = (char*) p->data;
-    if(count > DUMPMAX) {
+    const char* x = p->payload.data();
+    if (count > DUMPMAX) {
         count = DUMPMAX;
         tag = "\n";
     } else {
         tag = "\"\n";
     }
-    while(count-- > 0){
-        if((*x >= ' ') && (*x < 127)) {
+    while (count-- > 0) {
+        if ((*x >= ' ') && (*x < 127)) {
             fputc(*x, stderr);
         } else {
             fputc('.', stderr);
@@ -254,8 +248,8 @@
                    << connection_str.length() << ")";
     }
 
-    memcpy(cp->data, connection_str.c_str(), connection_str.length());
-    cp->msg.data_length = connection_str.length();
+    cp->payload = std::move(connection_str);
+    cp->msg.data_length = cp->payload.size();
 
     send_packet(cp, t);
 }
@@ -329,9 +323,7 @@
     }
 
     t->update_version(p->msg.arg0, p->msg.arg1);
-    std::string banner(reinterpret_cast<const char*>(p->data),
-                       p->msg.data_length);
-    parse_banner(banner, t);
+    parse_banner(p->payload, t);
 
 #if ADB_HOST
     handle_online(t);
@@ -354,6 +346,7 @@
             ((char*) (&(p->msg.command)))[2],
             ((char*) (&(p->msg.command)))[3]);
     print_packet("recv", p);
+    CHECK_EQ(p->payload.size(), p->msg.data_length);
 
     switch(p->msg.command){
     case A_SYNC:
@@ -380,11 +373,11 @@
                 if (t->GetConnectionState() == kCsOffline) {
                     t->SetConnectionState(kCsUnauthorized);
                 }
-                send_auth_response(p->data, p->msg.data_length, t);
+                send_auth_response(p->payload.data(), p->msg.data_length, t);
                 break;
 #else
             case ADB_AUTH_SIGNATURE:
-                if (adbd_auth_verify(t->token, sizeof(t->token), p->data, p->msg.data_length)) {
+                if (adbd_auth_verify(t->token, sizeof(t->token), p->payload)) {
                     adbd_auth_verified(t);
                     t->failed_auth_attempts = 0;
                 } else {
@@ -394,7 +387,7 @@
                 break;
 
             case ADB_AUTH_RSAPUBLICKEY:
-                adbd_auth_confirm_key(p->data, p->msg.data_length, t);
+                adbd_auth_confirm_key(p->payload.data(), p->msg.data_length, t);
                 break;
 #endif
             default:
@@ -406,9 +399,7 @@
 
     case A_OPEN: /* OPEN(local-id, 0, "destination") */
         if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
-            char *name = (char*) p->data;
-            name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
-            asocket* s = create_local_service_socket(name, t);
+            asocket* s = create_local_service_socket(p->payload.c_str(), t);
             if (s == nullptr) {
                 send_close(0, p->msg.arg0, t);
             } else {
@@ -474,11 +465,7 @@
             asocket* s = find_local_socket(p->msg.arg1, p->msg.arg0);
             if (s) {
                 unsigned rid = p->msg.arg0;
-
-                // TODO: Convert apacket::data to a type that we can move out of.
-                std::string copy(p->data, p->data + p->msg.data_length);
-
-                if (s->enqueue(s, std::move(copy)) == 0) {
+                if (s->enqueue(s, std::move(p->payload)) == 0) {
                     D("Enqueue the socket");
                     send_ready(s->id, rid, t);
                 }
@@ -1071,7 +1058,7 @@
         SendOkay(reply_fd);
 
         // Rely on process exit to close the socket for us.
-        android::base::quick_exit(0);
+        exit(0);
     }
 
     // "transport:" is used for switching transport with a specified serial number
diff --git a/adb/adb.h b/adb/adb.h
index c9c635a..a6d0463 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -74,7 +74,7 @@
 
 struct apacket {
     amessage msg;
-    char data[MAX_PAYLOAD];
+    std::string payload;
 };
 
 uint32_t calculate_apacket_checksum(const apacket* packet);
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index a6f224f..715e04f 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -49,7 +49,7 @@
 void adbd_auth_verified(atransport *t);
 
 void adbd_cloexec_auth_socket();
-bool adbd_auth_verify(const char* token, size_t token_size, const char* sig, int sig_len);
+bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig);
 void adbd_auth_confirm_key(const char* data, size_t len, atransport* t);
 
 void send_auth_request(atransport *t);
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 365bf77..c3aef16 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -299,20 +299,25 @@
     return result;
 }
 
-static int adb_auth_sign(RSA* key, const char* token, size_t token_size, char* sig) {
+static std::string adb_auth_sign(RSA* key, const char* token, size_t token_size) {
     if (token_size != TOKEN_SIZE) {
         D("Unexpected token size %zd", token_size);
         return 0;
     }
 
+    std::string result;
+    result.resize(MAX_PAYLOAD);
+
     unsigned int len;
     if (!RSA_sign(NID_sha1, reinterpret_cast<const uint8_t*>(token), token_size,
-                  reinterpret_cast<uint8_t*>(sig), &len, key)) {
-        return 0;
+                  reinterpret_cast<uint8_t*>(&result[0]), &len, key)) {
+        return std::string();
     }
 
+    result.resize(len);
+
     D("adb_auth_sign len=%d", len);
-    return (int)len;
+    return result;
 }
 
 std::string adb_auth_get_userkey() {
@@ -446,13 +451,14 @@
     }
 
     apacket* p = get_apacket();
-    memcpy(p->data, key.c_str(), key.size() + 1);
-
     p->msg.command = A_AUTH;
     p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
 
+    p->payload = std::move(key);
+
     // adbd expects a null-terminated string.
-    p->msg.data_length = key.size() + 1;
+    p->payload.push_back('\0');
+    p->msg.data_length = p->payload.size();
     send_packet(p, t);
 }
 
@@ -467,8 +473,8 @@
     LOG(INFO) << "Calling send_auth_response";
     apacket* p = get_apacket();
 
-    int ret = adb_auth_sign(key.get(), token, token_size, p->data);
-    if (!ret) {
+    std::string result = adb_auth_sign(key.get(), token, token_size);
+    if (result.empty()) {
         D("Error signing the token");
         put_apacket(p);
         return;
@@ -476,6 +482,7 @@
 
     p->msg.command = A_AUTH;
     p->msg.arg0 = ADB_AUTH_SIGNATURE;
-    p->msg.data_length = ret;
+    p->payload = std::move(result);
+    p->msg.data_length = p->payload.size();
     send_packet(p, t);
 }
diff --git a/adb/adbd_auth.cpp b/adb/adbd_auth.cpp
index 3488ad1..3fd2b31 100644
--- a/adb/adbd_auth.cpp
+++ b/adb/adbd_auth.cpp
@@ -46,7 +46,7 @@
 
 bool auth_required = true;
 
-bool adbd_auth_verify(const char* token, size_t token_size, const char* sig, int sig_len) {
+bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig) {
     static constexpr const char* key_paths[] = { "/adb_keys", "/data/misc/adb/adb_keys", nullptr };
 
     for (const auto& path : key_paths) {
@@ -80,7 +80,8 @@
 
                 bool verified =
                     (RSA_verify(NID_sha1, reinterpret_cast<const uint8_t*>(token), token_size,
-                                reinterpret_cast<const uint8_t*>(sig), sig_len, key) == 1);
+                                reinterpret_cast<const uint8_t*>(sig.c_str()), sig.size(),
+                                key) == 1);
                 RSA_free(key);
                 if (verified) return true;
             }
@@ -210,10 +211,10 @@
     }
 
     apacket* p = get_apacket();
-    memcpy(p->data, t->token, sizeof(t->token));
     p->msg.command = A_AUTH;
     p->msg.arg0 = ADB_AUTH_TOKEN;
     p->msg.data_length = sizeof(t->token);
+    p->payload.assign(t->token, t->token + sizeof(t->token));
     send_packet(p, t);
 }
 
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index f0d0ce7..f28302b 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -28,7 +28,6 @@
 #include <android-base/errors.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
-#include <android-base/quick_exit.h>
 #include <android-base/stringprintf.h>
 
 #include "adb.h"
@@ -61,7 +60,7 @@
 static BOOL WINAPI ctrlc_handler(DWORD type) {
     // TODO: Consider trying to kill a starting up adb server (if we're in
     // launch_server) by calling GenerateConsoleCtrlEvent().
-    android::base::quick_exit(STATUS_CONTROL_C_EXIT);
+    exit(STATUS_CONTROL_C_EXIT);
     return TRUE;
 }
 #endif
@@ -95,7 +94,7 @@
     SetConsoleCtrlHandler(ctrlc_handler, TRUE);
 #else
     signal(SIGINT, [](int) {
-        fdevent_run_on_main_thread([]() { android::base::quick_exit(0); });
+        fdevent_run_on_main_thread([]() { exit(0); });
     });
 #endif
 
@@ -104,7 +103,7 @@
         setup_daemon_logging();
     }
 
-    android::base::at_quick_exit(adb_server_cleanup);
+    atexit(adb_server_cleanup);
 
     init_transport_registration();
     init_mdns_transport_discovery();
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index 18f585d..46c3f58 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -19,6 +19,7 @@
 #include "sysdeps.h"
 
 #include <stdint.h>
+#include <stdlib.h>
 
 #include <atomic>
 #include <chrono>
@@ -33,7 +34,6 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
-#include <android-base/quick_exit.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index b28de4b..d285561 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -26,6 +26,7 @@
 #include <unistd.h>
 
 #include <atomic>
+#include <deque>
 #include <functional>
 #include <list>
 #include <mutex>
@@ -81,7 +82,7 @@
 
 static auto& run_queue_notify_fd = *new unique_fd();
 static auto& run_queue_mutex = *new std::mutex();
-static auto& run_queue GUARDED_BY(run_queue_mutex) = *new std::vector<std::function<void()>>();
+static auto& run_queue GUARDED_BY(run_queue_mutex) = *new std::deque<std::function<void()>>();
 
 void check_main_thread() {
     if (main_thread_valid) {
@@ -359,11 +360,21 @@
 }
 #endif // !ADB_HOST
 
-static void fdevent_run_flush() REQUIRES(run_queue_mutex) {
-    for (auto& f : run_queue) {
-        f();
+static void fdevent_run_flush() EXCLUDES(run_queue_mutex) {
+    // We need to be careful around reentrancy here, since a function we call can queue up another
+    // function.
+    while (true) {
+        std::function<void()> fn;
+        {
+            std::lock_guard<std::mutex> lock(run_queue_mutex);
+            if (run_queue.empty()) {
+                break;
+            }
+            fn = run_queue.front();
+            run_queue.pop_front();
+        }
+        fn();
     }
-    run_queue.clear();
 }
 
 static void fdevent_run_func(int fd, unsigned ev, void* /* userdata */) {
@@ -377,22 +388,23 @@
         PLOG(FATAL) << "failed to empty run queue notify fd";
     }
 
-    std::lock_guard<std::mutex> lock(run_queue_mutex);
     fdevent_run_flush();
 }
 
 static void fdevent_run_setup() {
-    std::lock_guard<std::mutex> lock(run_queue_mutex);
-    CHECK(run_queue_notify_fd.get() == -1);
-    int s[2];
-    if (adb_socketpair(s) != 0) {
-        PLOG(FATAL) << "failed to create run queue notify socketpair";
-    }
+    {
+        std::lock_guard<std::mutex> lock(run_queue_mutex);
+        CHECK(run_queue_notify_fd.get() == -1);
+        int s[2];
+        if (adb_socketpair(s) != 0) {
+            PLOG(FATAL) << "failed to create run queue notify socketpair";
+        }
 
-    run_queue_notify_fd.reset(s[0]);
-    fdevent* fde = fdevent_create(s[1], fdevent_run_func, nullptr);
-    CHECK(fde != nullptr);
-    fdevent_add(fde, FDE_READ);
+        run_queue_notify_fd.reset(s[0]);
+        fdevent* fde = fdevent_create(s[1], fdevent_run_func, nullptr);
+        CHECK(fde != nullptr);
+        fdevent_add(fde, FDE_READ);
+    }
 
     fdevent_run_flush();
 }
diff --git a/adb/fdevent_test.cpp b/adb/fdevent_test.cpp
index 86e0209..63cc4d1 100644
--- a/adb/fdevent_test.cpp
+++ b/adb/fdevent_test.cpp
@@ -194,3 +194,31 @@
         ASSERT_EQ(i, vec[i]);
     }
 }
+
+static std::function<void()> make_appender(std::vector<int>* vec, int value) {
+    return [vec, value]() {
+        check_main_thread();
+        if (value == 100) {
+            return;
+        }
+
+        vec->push_back(value);
+        fdevent_run_on_main_thread(make_appender(vec, value + 1));
+    };
+}
+
+TEST_F(FdeventTest, run_on_main_thread_reentrant) {
+    std::vector<int> vec;
+
+    PrepareThread();
+    std::thread thread(fdevent_loop);
+
+    fdevent_run_on_main_thread(make_appender(&vec, 0));
+
+    TerminateThread(thread);
+
+    ASSERT_EQ(100u, vec.size());
+    for (int i = 0; i < 100; ++i) {
+        ASSERT_EQ(i, vec[i]);
+    }
+}
diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp
index 32ed28f..a4c7a5a 100644
--- a/adb/remount_service.cpp
+++ b/adb/remount_service.cpp
@@ -62,9 +62,9 @@
 
 // The proc entry for / is full of lies, so check fstab instead.
 // /proc/mounts lists rootfs and /dev/root, neither of which is what we want.
-static std::string find_mount(const char* dir) {
-    if (strcmp(dir, "/") == 0) {
-       return find_fstab_mount(dir);
+static std::string find_mount(const char* dir, bool is_root) {
+    if (is_root) {
+        return find_fstab_mount(dir);
     } else {
        return find_proc_mount(dir);
     }
@@ -86,17 +86,29 @@
     if (!directory_exists(dir)) {
         return true;
     }
-    std::string dev = find_mount(dir);
-    if (dev.empty()) {
+    bool is_root = strcmp(dir, "/") == 0;
+    std::string dev = find_mount(dir, is_root);
+    // Even if the device for the root is not found, we still try to remount it
+    // as rw. This typically only happens when running Android in a container:
+    // the root will almost always be in a loop device, which is dynamic, so
+    // it's not convenient to put in the fstab.
+    if (dev.empty() && !is_root) {
         return true;
     }
-    if (!make_block_device_writable(dev)) {
+    if (!dev.empty() && !make_block_device_writable(dev)) {
         WriteFdFmt(fd, "remount of %s failed; couldn't make block device %s writable: %s\n",
                    dir, dev.c_str(), strerror(errno));
         return false;
     }
+    if (mount(dev.c_str(), dir, "none", MS_REMOUNT | MS_BIND, nullptr) == -1) {
+        // This is useful for cases where the superblock is already marked as
+        // read-write, but the mount itself is read-only, such as containers
+        // where the remount with just MS_REMOUNT is forbidden by the kernel.
+        WriteFdFmt(fd, "remount of the %s mount failed: %s.\n", dir, strerror(errno));
+        return false;
+    }
     if (mount(dev.c_str(), dir, "none", MS_REMOUNT, nullptr) == -1) {
-        WriteFdFmt(fd, "remount of %s failed: %s\n", dir, strerror(errno));
+        WriteFdFmt(fd, "remount of the %s superblock failed: %s\n", dir, strerror(errno));
         return false;
     }
     return true;
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 307cbfe..0007fed 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -413,15 +413,15 @@
     p->msg.command = A_WRTE;
     p->msg.arg0 = s->peer->id;
     p->msg.arg1 = s->id;
-    p->msg.data_length = data.size();
 
-    if (data.size() > sizeof(p->data)) {
+    if (data.size() > MAX_PAYLOAD) {
         put_apacket(p);
         return -1;
     }
 
-    // TODO: Convert apacket::data to a type that we can move into.
-    memcpy(p->data, data.data(), data.size());
+    p->payload = std::move(data);
+    p->msg.data_length = p->payload.size();
+
     send_packet(p, s->transport);
     return 1;
 }
@@ -482,17 +482,20 @@
 void connect_to_remote(asocket* s, const char* destination) {
     D("Connect_to_remote call RS(%d) fd=%d", s->id, s->fd);
     apacket* p = get_apacket();
-    size_t len = strlen(destination) + 1;
-
-    if (len > (s->get_max_payload() - 1)) {
-        fatal("destination oversized");
-    }
 
     D("LS(%d): connect('%s')", s->id, destination);
     p->msg.command = A_OPEN;
     p->msg.arg0 = s->id;
-    p->msg.data_length = len;
-    strcpy((char*)p->data, destination);
+
+    // adbd expects a null-terminated string.
+    p->payload = destination;
+    p->payload.push_back('\0');
+    p->msg.data_length = p->payload.size();
+
+    if (p->msg.data_length > s->get_max_payload()) {
+        fatal("destination oversized");
+    }
+
     send_packet(p, s->transport);
 }
 
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 9ae1297..6b1a00b 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -34,7 +34,6 @@
 
 #include <android-base/logging.h>
 #include <android-base/parsenetaddress.h>
-#include <android-base/quick_exit.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/thread_annotations.h>
@@ -72,12 +71,14 @@
         return false;
     }
 
-    if (packet->msg.data_length > sizeof(packet->data)) {
+    if (packet->msg.data_length > MAX_PAYLOAD) {
         D("remote local: read overflow (data length = %" PRIu32 ")", packet->msg.data_length);
         return false;
     }
 
-    if (!ReadFdExactly(fd_.get(), &packet->data, packet->msg.data_length)) {
+    packet->payload.resize(packet->msg.data_length);
+
+    if (!ReadFdExactly(fd_.get(), &packet->payload[0], packet->payload.size())) {
         D("remote local: terminated (data)");
         return false;
     }
@@ -86,13 +87,18 @@
 }
 
 bool FdConnection::Write(apacket* packet) {
-    uint32_t length = packet->msg.data_length;
-
-    if (!WriteFdExactly(fd_.get(), &packet->msg, sizeof(amessage) + length)) {
+    if (!WriteFdExactly(fd_.get(), &packet->msg, sizeof(packet->msg))) {
         D("remote local: write terminated");
         return false;
     }
 
+    if (packet->msg.data_length) {
+        if (!WriteFdExactly(fd_.get(), &packet->payload[0], packet->msg.data_length)) {
+            D("remote local: write terminated");
+            return false;
+        }
+    }
+
     return true;
 }
 
@@ -133,7 +139,7 @@
 
     std::string result = android::base::StringPrintf("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ", name,
                                                      func, cmd, arg0, arg1, len);
-    result += dump_hex(p->data, len);
+    result += dump_hex(p->payload.data(), p->payload.size());
     return result;
 }
 
@@ -191,9 +197,10 @@
         apacket* p = 0;
         if (read_packet(fd, t->serial, &p)) {
             D("%s: failed to read packet from transport socket on fd %d", t->serial, fd);
-        } else {
-            handle_packet(p, (atransport*)_t);
+            return;
         }
+
+        handle_packet(p, (atransport*)_t);
     }
 }
 
@@ -243,6 +250,7 @@
     p->msg.arg0 = 1;
     p->msg.arg1 = ++(t->sync_token);
     p->msg.magic = A_SYNC ^ 0xffffffff;
+    D("sending SYNC packet (len = %u, payload.size() = %zu)", p->msg.data_length, p->payload.size());
     if (write_packet(t->fd, t->serial, &p)) {
         put_apacket(p);
         D("%s: failed to write SYNC packet", t->serial);
@@ -336,6 +344,13 @@
             if (active) {
                 D("%s: transport got packet, sending to remote", t->serial);
                 ATRACE_NAME("write_transport write_remote");
+
+                // Allow sending the payload's implicit null terminator.
+                if (p->msg.data_length != p->payload.size()) {
+                    LOG(FATAL) << "packet data length doesn't match payload: msg.data_length = "
+                               << p->msg.data_length << ", payload.size() = " << p->payload.size();
+                }
+
                 if (t->Write(p) != 0) {
                     D("%s: remote write failed for transport", t->serial);
                     put_apacket(p);
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index a108699..d7565f6 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -61,13 +61,12 @@
 static int UsbReadPayload(usb_handle* h, apacket* p) {
     D("UsbReadPayload(%d)", p->msg.data_length);
 
-    if (p->msg.data_length > sizeof(p->data)) {
+    if (p->msg.data_length > MAX_PAYLOAD) {
         return -1;
     }
 
 #if CHECK_PACKET_OVERFLOW
     size_t usb_packet_size = usb_get_max_packet_size(h);
-    CHECK_EQ(0ULL, sizeof(p->data) % usb_packet_size);
 
     // Round the data length up to the nearest packet size boundary.
     // The device won't send a zero packet for packet size aligned payloads,
@@ -77,10 +76,18 @@
     if (rem_size) {
         len += usb_packet_size - rem_size;
     }
-    CHECK_LE(len, sizeof(p->data));
-    return usb_read(h, &p->data, len);
+
+    p->payload.resize(len);
+    int rc = usb_read(h, &p->payload[0], p->payload.size());
+    if (rc != static_cast<int>(p->msg.data_length)) {
+        return -1;
+    }
+
+    p->payload.resize(rc);
+    return rc;
 #else
-    return usb_read(h, &p->data, p->msg.data_length);
+    p->payload.resize(p->msg.data_length);
+    return usb_read(h, &p->payload[0], p->payload.size());
 #endif
 }
 
@@ -120,12 +127,13 @@
     }
 
     if (p->msg.data_length) {
-        if (p->msg.data_length > sizeof(p->data)) {
+        if (p->msg.data_length > MAX_PAYLOAD) {
             PLOG(ERROR) << "remote usb: read overflow (data length = " << p->msg.data_length << ")";
             return -1;
         }
 
-        if (usb_read(usb, p->data, p->msg.data_length)) {
+        p->payload.resize(p->msg.data_length);
+        if (usb_read(usb, &p->payload[0], p->payload.size())) {
             PLOG(ERROR) << "remote usb: terminated (data)";
             return -1;
         }
@@ -152,7 +160,7 @@
         return false;
     }
 
-    if (packet->msg.data_length != 0 && usb_write(handle_, &packet->data, size) != 0) {
+    if (packet->msg.data_length != 0 && usb_write(handle_, packet->payload.data(), size) != 0) {
         PLOG(ERROR) << "remote usb: 2 - write terminated";
         return false;
     }
diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h
index c11acb1..4d9fa34 100644
--- a/base/include/android-base/strings.h
+++ b/base/include/android-base/strings.h
@@ -67,8 +67,8 @@
 // TODO: string_view
 bool EndsWith(const std::string& s, const char* suffix);
 bool EndsWithIgnoreCase(const std::string& s, const char* suffix);
-bool EndsWith(const std::string& s, const std::string& prefix);
-bool EndsWithIgnoreCase(const std::string& s, const std::string& prefix);
+bool EndsWith(const std::string& s, const std::string& suffix);
+bool EndsWithIgnoreCase(const std::string& s, const std::string& suffix);
 
 // Tests whether 'lhs' equals 'rhs', ignoring case.
 bool EqualsIgnoreCase(const std::string& lhs, const std::string& rhs);
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 3bc1742..c03b41d 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -20,4 +20,5 @@
 LOCAL_SRC_FILES_arm64 := seccomp_policy/crash_dump.arm64.policy
 LOCAL_SRC_FILES_x86 := seccomp_policy/crash_dump.x86.policy
 LOCAL_SRC_FILES_x86_64 := seccomp_policy/crash_dump.x86_64.policy
+LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
 include $(BUILD_PREBUILT)
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index f8b4bad..397ff2f 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -20,6 +20,7 @@
 #include <sys/capability.h>
 #include <sys/prctl.h>
 #include <sys/ptrace.h>
+#include <sys/resource.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -570,7 +571,7 @@
 static const char* const kDebuggerdSeccompPolicy =
     "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
 
-pid_t seccomp_fork() {
+static pid_t seccomp_fork_impl(void (*prejail)()) {
   unique_fd policy_fd(open(kDebuggerdSeccompPolicy, O_RDONLY | O_CLOEXEC));
   if (policy_fd == -1) {
     LOG(FATAL) << "failed to open policy " << kDebuggerdSeccompPolicy;
@@ -607,10 +608,18 @@
     continue;
   }
 
+  if (prejail) {
+    prejail();
+  }
+
   minijail_enter(jail.get());
   return result;
 }
 
+static pid_t seccomp_fork() {
+  return seccomp_fork_impl(nullptr);
+}
+
 TEST_F(CrasherTest, seccomp_crash) {
   int intercept_result;
   unique_fd output_fd;
@@ -628,6 +637,46 @@
   ASSERT_BACKTRACE_FRAME(result, "abort");
 }
 
+static pid_t seccomp_fork_rlimit() {
+  return seccomp_fork_impl([]() {
+    struct rlimit rlim = {
+        .rlim_cur = 512 * 1024 * 1024,
+        .rlim_max = 512 * 1024 * 1024,
+    };
+
+    if (setrlimit(RLIMIT_AS, &rlim) != 0) {
+      raise(SIGINT);
+    }
+  });
+}
+
+TEST_F(CrasherTest, seccomp_crash_oom) {
+  int intercept_result;
+  unique_fd output_fd;
+
+  StartProcess(
+      []() {
+        std::vector<void*> vec;
+        for (int i = 0; i < 512; ++i) {
+          char* buf = static_cast<char*>(malloc(1024 * 1024));
+          if (!buf) {
+            abort();
+          }
+          memset(buf, 0xff, 1024 * 1024);
+          vec.push_back(buf);
+        }
+      },
+      &seccomp_fork_rlimit);
+
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  AssertDeath(SIGABRT);
+  FinishIntercept(&intercept_result);
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  // We can't actually generate a backtrace, just make sure that the process terminates.
+}
+
 __attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
   siginfo_t siginfo;
   siginfo.si_code = SI_QUEUE;
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index 364fca5..dea2e17 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -37,6 +37,7 @@
 
 #include <atomic>
 #include <memory>
+#include <mutex>
 
 #include <android-base/file.h>
 #include <android-base/unique_fd.h>
@@ -298,11 +299,13 @@
 static void crash_handler(siginfo_t* info, ucontext_t* ucontext, void* abort_message) {
   // Only allow one thread to handle a crash at a time (this can happen multiple times without
   // exit, since tombstones can be requested without a real crash happening.)
-  static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
-  int ret = pthread_mutex_lock(&crash_mutex);
-  if (ret != 0) {
-    async_safe_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_lock failed: %s", strerror(ret));
-    return;
+  static std::recursive_mutex crash_mutex;
+  static int lock_count;
+
+  crash_mutex.lock();
+  if (lock_count++ > 0) {
+    async_safe_format_log(ANDROID_LOG_ERROR, "libc", "recursed signal handler call, exiting");
+    _exit(1);
   }
 
   unique_fd tombstone_socket, output_fd;
@@ -313,7 +316,8 @@
     tombstoned_notify_completion(tombstone_socket.get());
   }
 
-  pthread_mutex_unlock(&crash_mutex);
+  --lock_count;
+  crash_mutex.unlock();
 }
 
 extern "C" void debuggerd_fallback_handler(siginfo_t* info, ucontext_t* ucontext,
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 1c01d8c..9b7405a 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -39,6 +39,7 @@
     char *key_loc;
     char* key_dir;
     char *verity_loc;
+    char *sysfs_path;
     long long part_length;
     char *label;
     int partnum;
@@ -104,6 +105,7 @@
     {"quota", MF_QUOTA},
     {"eraseblk=", MF_ERASEBLKSIZE},
     {"logicalblk=", MF_LOGICALBLKSIZE},
+    {"sysfs_path=", MF_SYSFS},
     {"defaults", 0},
     {0, 0},
 };
@@ -341,6 +343,9 @@
                     unsigned int val = strtoul(strchr(p, '=') + 1, NULL, 0);
                     if (val >= 4096 && (val & (val - 1)) == 0)
                         flag_vals->logical_blk_size = val;
+                } else if ((fl[i].flag == MF_SYSFS) && flag_vals) {
+                    /* The path to trigger device gc by idle-maint of vold. */
+                    flag_vals->sysfs_path = strdup(strchr(p, '=') + 1);
                 }
                 break;
             }
@@ -615,6 +620,7 @@
         fstab->recs[cnt].file_names_mode = flag_vals.file_names_mode;
         fstab->recs[cnt].erase_blk_size = flag_vals.erase_blk_size;
         fstab->recs[cnt].logical_blk_size = flag_vals.logical_blk_size;
+        fstab->recs[cnt].sysfs_path = flag_vals.sysfs_path;
         cnt++;
     }
     /* If an A/B partition, modify block device to be the real block device */
@@ -787,6 +793,7 @@
         free(fstab->recs[i].key_loc);
         free(fstab->recs[i].key_dir);
         free(fstab->recs[i].label);
+        free(fstab->recs[i].sysfs_path);
     }
 
     /* Free the fstab_recs array created by calloc(3) */
@@ -922,3 +929,8 @@
 int fs_mgr_is_quota(const struct fstab_rec* fstab) {
     return fstab->fs_mgr_flags & MF_QUOTA;
 }
+
+int fs_mgr_has_sysfs_path(const struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_SYSFS;
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 724156d..ade0cc4 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -109,7 +109,8 @@
 #define MF_ERASEBLKSIZE     0x800000
 #define MF_LOGICALBLKSIZE  0X1000000
 #define MF_AVB             0X2000000
-#define MF_KEYDIRECTORY 0X4000000
+#define MF_KEYDIRECTORY    0X4000000
+#define MF_SYSFS           0X8000000
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 94aacfd..8c585dd 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -56,6 +56,7 @@
     unsigned int file_names_mode;
     unsigned int erase_blk_size;
     unsigned int logical_blk_size;
+    char* sysfs_path;
 };
 
 struct fstab* fs_mgr_read_fstab_default();
@@ -83,6 +84,7 @@
 int fs_mgr_is_nofail(const struct fstab_rec* fstab);
 int fs_mgr_is_latemount(const struct fstab_rec* fstab);
 int fs_mgr_is_quota(const struct fstab_rec* fstab);
+int fs_mgr_has_sysfs_path(const struct fstab_rec* fstab);
 
 std::string fs_mgr_get_slot_suffix();
 
diff --git a/init/README.md b/init/README.md
index d7edf21..5c2352b 100644
--- a/init/README.md
+++ b/init/README.md
@@ -10,7 +10,11 @@
 whitespace from breaking text into multiple tokens.  The backslash,
 when it is the last character on a line, may be used for line-folding.
 
-Lines which start with a # (leading whitespace allowed) are comments.
+Lines which start with a `#` (leading whitespace allowed) are comments.
+
+System properties can be expanded using the syntax
+`${property.name}`. This also works in contexts where concatenation is
+required, such as `import /init.recovery.${ro.hardware}.rc`.
 
 Actions and Services implicitly declare a new section.  All commands
 or options belong to the section most recently declared.  Commands
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 242750a..03ed55a 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -20,6 +20,7 @@
 #include <fcntl.h>
 #include <linux/fs.h>
 #include <mntent.h>
+#include <semaphore.h>
 #include <sys/capability.h>
 #include <sys/cdefs.h>
 #include <sys/ioctl.h>
@@ -89,12 +90,13 @@
           mnt_opts_(entry.mnt_opts) {}
 
     bool Umount(bool force) {
+        LOG(INFO) << "Unmounting " << mnt_fsname_ << ":" << mnt_dir_ << " opts " << mnt_opts_;
         int r = umount2(mnt_dir_.c_str(), force ? MNT_FORCE : 0);
         if (r == 0) {
-            LOG(INFO) << "umounted " << mnt_fsname_ << ":" << mnt_dir_ << " opts " << mnt_opts_;
+            LOG(INFO) << "Umounted " << mnt_fsname_ << ":" << mnt_dir_ << " opts " << mnt_opts_;
             return true;
         } else {
-            PLOG(WARNING) << "cannot umount " << mnt_fsname_ << ":" << mnt_dir_ << " opts "
+            PLOG(WARNING) << "Cannot umount " << mnt_fsname_ << ":" << mnt_dir_ << " opts "
                           << mnt_opts_;
             return false;
         }
@@ -328,39 +330,9 @@
     return stat;
 }
 
-void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
-              bool runFsck) {
+void RebootThread(unsigned int cmd, std::chrono::milliseconds shutdown_timeout, bool runFsck,
+                  sem_t* reboot_semaphore) {
     Timer t;
-    LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
-
-    // 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,");
-    }
-    property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str() + skip);
-    sync();
-
-    bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF;
-
-    auto shutdown_timeout = 0ms;
-    if (!SHUTDOWN_ZERO_TIMEOUT) {
-        if (is_thermal_shutdown) {
-            constexpr unsigned int thermal_shutdown_timeout = 1;
-            shutdown_timeout = std::chrono::seconds(thermal_shutdown_timeout);
-        } else {
-            constexpr unsigned int shutdown_timeout_default = 6;
-            auto shutdown_timeout_property = android::base::GetUintProperty(
-                "ro.build.shutdown_timeout", shutdown_timeout_default);
-            shutdown_timeout = std::chrono::seconds(shutdown_timeout_property);
-        }
-    }
-    LOG(INFO) << "Shutdown timeout: " << shutdown_timeout.count() << " ms";
-
     // keep debugging tools until non critical ones are all gone.
     const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
     // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
@@ -384,7 +356,7 @@
     }
 
     // remaining operations (specifically fsck) may take a substantial duration
-    if (cmd == ANDROID_RB_POWEROFF || is_thermal_shutdown) {
+    if (cmd == ANDROID_RB_POWEROFF || cmd == ANDROID_RB_THERMOFF) {
         TurnOffBacklight();
     }
 
@@ -461,8 +433,77 @@
     UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
     // Follow what linux shutdown is doing: one more sync with little bit delay
     sync();
-    if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms);
+    if (cmd != ANDROID_RB_THERMOFF) std::this_thread::sleep_for(100ms);
     LogShutdownTime(stat, &t);
+
+    if (reboot_semaphore != nullptr) {
+        sem_post(reboot_semaphore);
+    }
+}
+
+void RunRebootThread(unsigned int cmd, std::chrono::milliseconds shutdown_timeout) {
+    sem_t reboot_semaphore;
+    timespec shutdown_timeout_timespec;
+
+    if (sem_init(&reboot_semaphore, false, 0) == -1 ||
+        clock_gettime(CLOCK_REALTIME, &shutdown_timeout_timespec) == -1) {
+        // These should never fail, but if they do, skip the graceful reboot and reboot immediately.
+        return;
+    }
+
+    std::thread reboot_thread(&RebootThread, cmd, shutdown_timeout, false, &reboot_semaphore);
+    reboot_thread.detach();
+
+    // One extra second than the timeout passed to the thread as there is a final Umount pass
+    // after the timeout is reached.
+    shutdown_timeout_timespec.tv_sec += 1 + shutdown_timeout.count() / 1000;
+
+    int sem_return = 0;
+    while ((sem_return = sem_timedwait(&reboot_semaphore, &shutdown_timeout_timespec)) == -1 &&
+           errno == EINTR) {
+    }
+
+    if (sem_return == -1) {
+        LOG(ERROR) << "Reboot thread timed out";
+    }
+}
+
+void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
+              bool runFsck) {
+    LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
+
+    // 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,");
+    }
+    property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str() + skip);
+    sync();
+
+    auto shutdown_timeout = 0ms;
+    if (!SHUTDOWN_ZERO_TIMEOUT) {
+        if (cmd == ANDROID_RB_THERMOFF) {
+            constexpr auto kThermalShutdownTimeout = 1s;
+            shutdown_timeout = kThermalShutdownTimeout;
+        } else {
+            constexpr unsigned int kShutdownTimeoutDefault = 6;
+            auto shutdown_timeout_property = android::base::GetUintProperty(
+                "ro.build.shutdown_timeout", kShutdownTimeoutDefault);
+            shutdown_timeout = std::chrono::seconds(shutdown_timeout_property);
+        }
+    }
+    LOG(INFO) << "Shutdown timeout: " << shutdown_timeout.count() << " ms";
+
+    if (runFsck) {
+        RebootThread(cmd, shutdown_timeout, true, nullptr);
+    } else {
+        RunRebootThread(cmd, shutdown_timeout);
+    }
+
     // Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
     RebootSystem(cmd, rebootTarget);
     abort();
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 0e32e47..711a12a 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -128,6 +128,22 @@
   return true;
 }
 
+bool Backtrace::UnwindOffline(unwindstack::Regs* regs, BacktraceMap* back_map,
+                              const backtrace_stackinfo_t& stack,
+                              std::vector<backtrace_frame_data_t>* frames,
+                              BacktraceUnwindError* error) {
+  UnwindStackOfflineMap* offline_map = reinterpret_cast<UnwindStackOfflineMap*>(back_map);
+  // Create the process memory from the stack data since this will almost
+  // always be different each unwind.
+  if (!offline_map->CreateProcessMemory(stack)) {
+    if (error != nullptr) {
+      error->error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
+    }
+    return false;
+  }
+  return Backtrace::Unwind(regs, back_map, frames, 0U, nullptr, error);
+}
+
 UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map)
     : BacktraceCurrent(pid, tid, map) {}
 
@@ -221,12 +237,12 @@
 Backtrace* Backtrace::CreateOffline(ArchEnum arch, pid_t pid, pid_t tid,
                                     const std::vector<backtrace_map_t>& maps,
                                     const backtrace_stackinfo_t& stack) {
-  BacktraceMap* map = BacktraceMap::CreateOffline(pid, maps, stack);
-  if (map == nullptr) {
+  std::unique_ptr<UnwindStackOfflineMap> map(
+      reinterpret_cast<UnwindStackOfflineMap*>(BacktraceMap::CreateOffline(pid, maps)));
+  if (map.get() == nullptr || !map->CreateProcessMemory(stack)) {
     return nullptr;
   }
-
-  return new UnwindStackOffline(arch, pid, tid, map, false);
+  return new UnwindStackOffline(arch, pid, tid, map.release(), false);
 }
 
 Backtrace* Backtrace::CreateOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map) {
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 6dcc621..9c6fed4 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -127,12 +127,7 @@
   return false;
 }
 
-bool UnwindStackOfflineMap::Build(const std::vector<backtrace_map_t>& backtrace_maps,
-                                  const backtrace_stackinfo_t& stack) {
-  if (stack.start >= stack.end) {
-    return false;
-  }
-
+bool UnwindStackOfflineMap::Build(const std::vector<backtrace_map_t>& backtrace_maps) {
   for (const backtrace_map_t& map : backtrace_maps) {
     maps_.push_back(map);
   }
@@ -145,6 +140,13 @@
   for (const backtrace_map_t& map : maps_) {
     maps->Add(map.start, map.end, map.offset, map.flags, map.name, map.load_bias);
   }
+  return true;
+}
+
+bool UnwindStackOfflineMap::CreateProcessMemory(const backtrace_stackinfo_t& stack) {
+  if (stack.start >= stack.end) {
+    return false;
+  }
 
   // Create the process memory from the stack data.
   uint64_t size = stack.end - stack.start;
@@ -154,7 +156,6 @@
   std::shared_ptr<unwindstack::Memory> shared_memory(memory);
 
   process_memory_.reset(new unwindstack::MemoryRange(shared_memory, 0, size, stack.start));
-
   return true;
 }
 
@@ -182,10 +183,9 @@
 //-------------------------------------------------------------------------
 // BacktraceMap create offline function.
 //-------------------------------------------------------------------------
-BacktraceMap* BacktraceMap::CreateOffline(pid_t pid, const std::vector<backtrace_map_t>& maps,
-                                          const backtrace_stackinfo_t& stack) {
+BacktraceMap* BacktraceMap::CreateOffline(pid_t pid, const std::vector<backtrace_map_t>& maps) {
   UnwindStackOfflineMap* map = new UnwindStackOfflineMap(pid);
-  if (!map->Build(maps, stack)) {
+  if (!map->Build(maps)) {
     delete map;
     return nullptr;
   }
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index 94cbfb2..ec0d9c1 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -76,7 +76,9 @@
 
   bool Build() override;
 
-  bool Build(const std::vector<backtrace_map_t>& maps, const backtrace_stackinfo_t& stack);
+  bool Build(const std::vector<backtrace_map_t>& maps);
+
+  bool CreateProcessMemory(const backtrace_stackinfo_t& stack);
 };
 
 #endif  // _LIBBACKTRACE_UNWINDSTACK_MAP_H
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 7a37015..a088207 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -151,6 +151,11 @@
                      std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
                      std::vector<std::string>* skip_names, BacktraceUnwindError* error = nullptr);
 
+  static bool UnwindOffline(unwindstack::Regs* regs, BacktraceMap* back_map,
+                            const backtrace_stackinfo_t& stack_info,
+                            std::vector<backtrace_frame_data_t>* frames,
+                            BacktraceUnwindError* error = nullptr);
+
   // Get the function name and offset into the function given the pc.
   // If the string is empty, then no valid function name was found,
   // or the pc is not in any valid map.
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index da54472..473d195 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -64,8 +64,7 @@
   // is unsupported.
   static BacktraceMap* Create(pid_t pid, bool uncached = false);
 
-  static BacktraceMap* CreateOffline(pid_t pid, const std::vector<backtrace_map_t>& maps,
-                                     const backtrace_stackinfo_t& stack);
+  static BacktraceMap* CreateOffline(pid_t pid, const std::vector<backtrace_map_t>& maps);
 
   virtual ~BacktraceMap();
 
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index a993d41..5ea981f 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -202,16 +202,6 @@
                                            CAP_MASK_LONG(CAP_NET_RAW),
                                               "vendor/bin/hw/android.hardware.wifi@1.0-service" },
 
-    // A non-privileged zygote that spawns isolated processes for web rendering.
-    { 0750,  AID_ROOT,      AID_ROOT,      CAP_MASK_LONG(CAP_SETUID) |
-                                           CAP_MASK_LONG(CAP_SETGID) |
-                                           CAP_MASK_LONG(CAP_SETPCAP),
-                                              "system/bin/webview_zygote32" },
-    { 0750,  AID_ROOT,      AID_ROOT,      CAP_MASK_LONG(CAP_SETUID) |
-                                           CAP_MASK_LONG(CAP_SETGID) |
-                                           CAP_MASK_LONG(CAP_SETPCAP),
-                                              "system/bin/webview_zygote64" },
-
     // generic defaults
     { 00755, AID_ROOT,      AID_ROOT,      0, "bin/*" },
     { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index 1974f2c..b0bc497 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -1,7 +1,7 @@
 cc_library {
     srcs: ["processgroup.cpp"],
     name: "libprocessgroup",
-    defaults: ["linux_bionic_supported"],
+    host_supported: true,
     shared_libs: ["libbase"],
     export_include_dirs: ["include"],
     cflags: [
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 8526b3a..6dfa697 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -22,6 +22,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -33,15 +34,19 @@
 #include <memory>
 #include <mutex>
 #include <set>
+#include <string>
 #include <thread>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
-#include <android-base/unique_fd.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <private/android_filesystem_config.h>
 
 #include <processgroup/processgroup.h>
 
+using android::base::StartsWith;
+using android::base::StringPrintf;
 using android::base::WriteStringToFile;
 
 using namespace std::chrono_literals;
@@ -50,171 +55,58 @@
 #define MEM_CGROUP_TASKS "/dev/memcg/apps/tasks"
 #define ACCT_CGROUP_PATH "/acct"
 
-#define PROCESSGROUP_UID_PREFIX "uid_"
-#define PROCESSGROUP_PID_PREFIX "pid_"
 #define PROCESSGROUP_CGROUP_PROCS_FILE "/cgroup.procs"
-#define PROCESSGROUP_MAX_UID_LEN 11
-#define PROCESSGROUP_MAX_PID_LEN 11
-#define PROCESSGROUP_MAX_PATH_LEN \
-        ((sizeof(MEM_CGROUP_PATH) > sizeof(ACCT_CGROUP_PATH) ? \
-          sizeof(MEM_CGROUP_PATH) : sizeof(ACCT_CGROUP_PATH)) + \
-         sizeof(PROCESSGROUP_UID_PREFIX) + 1 + \
-         PROCESSGROUP_MAX_UID_LEN + \
-         sizeof(PROCESSGROUP_PID_PREFIX) + 1 + \
-         PROCESSGROUP_MAX_PID_LEN + \
-         sizeof(PROCESSGROUP_CGROUP_PROCS_FILE) + \
-         1)
 
 std::once_flag init_path_flag;
 
-class ProcessGroup {
-  public:
-    ProcessGroup() : buf_ptr_(buf_), buf_len_(0) {}
-
-    bool Open(uid_t uid, int pid);
-
-    // Return positive number and sets *pid = next pid in process cgroup on success
-    // Returns 0 if there are no pids left in the process cgroup
-    // Returns -errno if an error was encountered
-    int GetOneAppProcess(pid_t* pid);
-
-  private:
-    // Returns positive number of bytes filled on success
-    // Returns 0 if there was nothing to read
-    // Returns -errno if an error was encountered
-    int RefillBuffer();
-
-    android::base::unique_fd fd_;
-    char buf_[128];
-    char* buf_ptr_;
-    size_t buf_len_;
-};
-
-static const char* getCgroupRootPath() {
-    static const char* cgroup_root_path = NULL;
+static const std::string& GetCgroupRootPath() {
+    static std::string cgroup_root_path;
     std::call_once(init_path_flag, [&]() {
             // Check if mem cgroup is mounted, only then check for write-access to avoid
             // SELinux denials
-            cgroup_root_path = access(MEM_CGROUP_TASKS, F_OK) || access(MEM_CGROUP_PATH, W_OK) ?
-                    ACCT_CGROUP_PATH : MEM_CGROUP_PATH;
+            cgroup_root_path =
+                (access(MEM_CGROUP_TASKS, F_OK) || access(MEM_CGROUP_PATH, W_OK) ? ACCT_CGROUP_PATH
+                                                                                 : MEM_CGROUP_PATH);
             });
     return cgroup_root_path;
 }
 
-static int convertUidToPath(char *path, size_t size, uid_t uid)
-{
-    return snprintf(path, size, "%s/%s%d",
-            getCgroupRootPath(),
-            PROCESSGROUP_UID_PREFIX,
-            uid);
+static std::string ConvertUidToPath(uid_t uid) {
+    return StringPrintf("%s/uid_%d", GetCgroupRootPath().c_str(), uid);
 }
 
-static int convertUidPidToPath(char *path, size_t size, uid_t uid, int pid)
-{
-    return snprintf(path, size, "%s/%s%d/%s%d",
-            getCgroupRootPath(),
-            PROCESSGROUP_UID_PREFIX,
-            uid,
-            PROCESSGROUP_PID_PREFIX,
-            pid);
+static std::string ConvertUidPidToPath(uid_t uid, int pid) {
+    return StringPrintf("%s/uid_%d/pid_%d", GetCgroupRootPath().c_str(), uid, pid);
 }
 
-bool ProcessGroup::Open(uid_t uid, int pid) {
-    char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
-    convertUidPidToPath(path, sizeof(path), uid, pid);
-    strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
-
-    int fd = open(path, O_RDONLY);
-    if (fd < 0) return false;
-
-    fd_.reset(fd);
-
-    LOG(VERBOSE) << "Initialized context for " << path;
-
-    return true;
-}
-
-int ProcessGroup::RefillBuffer() {
-    memmove(buf_, buf_ptr_, buf_len_);
-    buf_ptr_ = buf_;
-
-    ssize_t ret = read(fd_, buf_ptr_ + buf_len_, sizeof(buf_) - buf_len_ - 1);
-    if (ret < 0) {
-        return -errno;
-    } else if (ret == 0) {
-        return 0;
-    }
-
-    buf_len_ += ret;
-    buf_[buf_len_] = 0;
-    LOG(VERBOSE) << "Read " << ret << " to buffer: " << buf_;
-
-    assert(buf_len_ <= sizeof(buf_));
-
-    return ret;
-}
-
-int ProcessGroup::GetOneAppProcess(pid_t* out_pid) {
-    *out_pid = 0;
-
-    char* eptr;
-    while ((eptr = static_cast<char*>(memchr(buf_ptr_, '\n', buf_len_))) == nullptr) {
-        int ret = RefillBuffer();
-        if (ret <= 0) return ret;
-    }
-
-    *eptr = '\0';
-    char* pid_eptr = nullptr;
-    errno = 0;
-    long pid = strtol(buf_ptr_, &pid_eptr, 10);
-    if (errno != 0) {
-        return -errno;
-    }
-    if (pid_eptr != eptr) {
-        errno = EINVAL;
-        return -errno;
-    }
-
-    buf_len_ -= (eptr - buf_ptr_) + 1;
-    buf_ptr_ = eptr + 1;
-
-    *out_pid = static_cast<pid_t>(pid);
-    return 1;
-}
-
-static int removeProcessGroup(uid_t uid, int pid)
-{
+static int RemoveProcessGroup(uid_t uid, int pid) {
     int ret;
-    char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
 
-    convertUidPidToPath(path, sizeof(path), uid, pid);
-    ret = rmdir(path);
+    auto uid_pid_path = ConvertUidPidToPath(uid, pid);
+    ret = rmdir(uid_pid_path.c_str());
 
-    convertUidToPath(path, sizeof(path), uid);
-    rmdir(path);
+    auto uid_path = ConvertUidToPath(uid);
+    rmdir(uid_path.c_str());
 
     return ret;
 }
 
-static void removeUidProcessGroups(const char *uid_path)
-{
-    std::unique_ptr<DIR, decltype(&closedir)> uid(opendir(uid_path), closedir);
+static void RemoveUidProcessGroups(const std::string& uid_path) {
+    std::unique_ptr<DIR, decltype(&closedir)> uid(opendir(uid_path.c_str()), closedir);
     if (uid != NULL) {
         dirent* dir;
         while ((dir = readdir(uid.get())) != nullptr) {
-            char path[PROCESSGROUP_MAX_PATH_LEN];
-
             if (dir->d_type != DT_DIR) {
                 continue;
             }
 
-            if (strncmp(dir->d_name, PROCESSGROUP_PID_PREFIX, strlen(PROCESSGROUP_PID_PREFIX))) {
+            if (!StartsWith(dir->d_name, "pid_")) {
                 continue;
             }
 
-            snprintf(path, sizeof(path), "%s/%s", uid_path, dir->d_name);
+            auto path = StringPrintf("%s/%s", uid_path.c_str(), dir->d_name);
             LOG(VERBOSE) << "Removing " << path;
-            if (rmdir(path) == -1) PLOG(WARNING) << "Failed to remove " << path;
+            if (rmdir(path.c_str()) == -1) PLOG(WARNING) << "Failed to remove " << path;
         }
     }
 }
@@ -222,38 +114,38 @@
 void removeAllProcessGroups()
 {
     LOG(VERBOSE) << "removeAllProcessGroups()";
-    const char* cgroup_root_path = getCgroupRootPath();
-    std::unique_ptr<DIR, decltype(&closedir)> root(opendir(cgroup_root_path), closedir);
+    const auto& cgroup_root_path = GetCgroupRootPath();
+    std::unique_ptr<DIR, decltype(&closedir)> root(opendir(cgroup_root_path.c_str()), closedir);
     if (root == NULL) {
         PLOG(ERROR) << "Failed to open " << cgroup_root_path;
     } else {
         dirent* dir;
         while ((dir = readdir(root.get())) != nullptr) {
-            char path[PROCESSGROUP_MAX_PATH_LEN];
-
             if (dir->d_type != DT_DIR) {
                 continue;
             }
-            if (strncmp(dir->d_name, PROCESSGROUP_UID_PREFIX, strlen(PROCESSGROUP_UID_PREFIX))) {
+
+            if (!StartsWith(dir->d_name, "uid_")) {
                 continue;
             }
 
-            snprintf(path, sizeof(path), "%s/%s", cgroup_root_path, dir->d_name);
-            removeUidProcessGroups(path);
+            auto path = StringPrintf("%s/%s", cgroup_root_path.c_str(), dir->d_name);
+            RemoveUidProcessGroups(path);
             LOG(VERBOSE) << "Removing " << path;
-            if (rmdir(path) == -1) PLOG(WARNING) << "Failed to remove " << path;
+            if (rmdir(path.c_str()) == -1) PLOG(WARNING) << "Failed to remove " << path;
         }
     }
 }
 
 // Returns number of processes killed on success
 // Returns 0 if there are no processes in the process cgroup left to kill
-// Returns -errno on error
-static int doKillProcessGroupOnce(uid_t uid, int initialPid, int signal) {
-    ProcessGroup process_group;
-    if (!process_group.Open(uid, initialPid)) {
+// Returns -1 on error
+static int DoKillProcessGroupOnce(uid_t uid, int initialPid, int signal) {
+    auto path = ConvertUidPidToPath(uid, initialPid) + PROCESSGROUP_CGROUP_PROCS_FILE;
+    std::unique_ptr<FILE, decltype(&fclose)> fd(fopen(path.c_str(), "re"), fclose);
+    if (!fd) {
         PLOG(WARNING) << "Failed to open process cgroup uid " << uid << " pid " << initialPid;
-        return -errno;
+        return -1;
     }
 
     // We separate all of the pids in the cgroup into those pids that are also the leaders of
@@ -262,10 +154,9 @@
     pgids.emplace(initialPid);
     std::set<pid_t> pids;
 
-    int ret;
     pid_t pid;
     int processes = 0;
-    while ((ret = process_group.GetOneAppProcess(&pid)) > 0 && pid >= 0) {
+    while (fscanf(fd.get(), "%d\n", &pid) == 1 && pid >= 0) {
         processes++;
         if (pid == 0) {
             // Should never happen...  but if it does, trying to kill this
@@ -312,15 +203,15 @@
         }
     }
 
-    return ret >= 0 ? processes : ret;
+    return feof(fd.get()) ? processes : -1;
 }
 
-static int killProcessGroup(uid_t uid, int initialPid, int signal, int retries) {
+static int KillProcessGroup(uid_t uid, int initialPid, int signal, int retries) {
     std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
 
     int retry = retries;
     int processes;
-    while ((processes = doKillProcessGroupOnce(uid, initialPid, signal)) > 0) {
+    while ((processes = DoKillProcessGroupOnce(uid, initialPid, signal)) > 0) {
         LOG(VERBOSE) << "Killed " << processes << " processes for processgroup " << initialPid;
         if (retry > 0) {
             std::this_thread::sleep_for(5ms);
@@ -350,7 +241,7 @@
             LOG(INFO) << "Successfully killed process cgroup uid " << uid << " pid " << initialPid
                       << " in " << static_cast<int>(ms) << "ms";
         }
-        return removeProcessGroup(uid, initialPid);
+        return RemoveProcessGroup(uid, initialPid);
     } else {
         if (retries > 0) {
             LOG(ERROR) << "Failed to kill process cgroup uid " << uid << " pid " << initialPid
@@ -362,22 +253,21 @@
 }
 
 int killProcessGroup(uid_t uid, int initialPid, int signal) {
-    return killProcessGroup(uid, initialPid, signal, 40 /*retries*/);
+    return KillProcessGroup(uid, initialPid, signal, 40 /*retries*/);
 }
 
 int killProcessGroupOnce(uid_t uid, int initialPid, int signal) {
-    return killProcessGroup(uid, initialPid, signal, 0 /*retries*/);
+    return KillProcessGroup(uid, initialPid, signal, 0 /*retries*/);
 }
 
-static bool mkdirAndChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
-{
-    if (mkdir(path, mode) == -1 && errno != EEXIST) {
+static bool MkdirAndChown(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
+    if (mkdir(path.c_str(), mode) == -1 && errno != EEXIST) {
         return false;
     }
 
-    if (chown(path, uid, gid) == -1) {
+    if (chown(path.c_str(), uid, gid) == -1) {
         int saved_errno = errno;
-        rmdir(path);
+        rmdir(path.c_str());
         errno = saved_errno;
         return false;
     }
@@ -387,42 +277,38 @@
 
 int createProcessGroup(uid_t uid, int initialPid)
 {
-    char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
+    auto uid_path = ConvertUidToPath(uid);
 
-    convertUidToPath(path, sizeof(path), uid);
-
-    if (!mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM)) {
-        PLOG(ERROR) << "Failed to make and chown " << path;
+    if (!MkdirAndChown(uid_path, 0750, AID_SYSTEM, AID_SYSTEM)) {
+        PLOG(ERROR) << "Failed to make and chown " << uid_path;
         return -errno;
     }
 
-    convertUidPidToPath(path, sizeof(path), uid, initialPid);
+    auto uid_pid_path = ConvertUidPidToPath(uid, initialPid);
 
-    if (!mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM)) {
-        PLOG(ERROR) << "Failed to make and chown " << path;
+    if (!MkdirAndChown(uid_pid_path, 0750, AID_SYSTEM, AID_SYSTEM)) {
+        PLOG(ERROR) << "Failed to make and chown " << uid_pid_path;
         return -errno;
     }
 
-    strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
+    auto uid_pid_procs_file = uid_pid_path + PROCESSGROUP_CGROUP_PROCS_FILE;
 
     int ret = 0;
-    if (!WriteStringToFile(std::to_string(initialPid), path)) {
+    if (!WriteStringToFile(std::to_string(initialPid), uid_pid_procs_file)) {
         ret = -errno;
-        PLOG(ERROR) << "Failed to write '" << initialPid << "' to " << path;
+        PLOG(ERROR) << "Failed to write '" << initialPid << "' to " << uid_pid_procs_file;
     }
 
     return ret;
 }
 
-static bool setProcessGroupValue(uid_t uid, int pid, const char* fileName, int64_t value) {
-    char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
-    if (strcmp(getCgroupRootPath(), MEM_CGROUP_PATH)) {
-        PLOG(ERROR) << "Memcg is not mounted." << path;
+static bool SetProcessGroupValue(uid_t uid, int pid, const std::string& file_name, int64_t value) {
+    if (GetCgroupRootPath() != MEM_CGROUP_PATH) {
+        PLOG(ERROR) << "Memcg is not mounted.";
         return false;
     }
 
-    convertUidPidToPath(path, sizeof(path), uid, pid);
-    strlcat(path, fileName, sizeof(path));
+    auto path = ConvertUidPidToPath(uid, pid) + file_name;
 
     if (!WriteStringToFile(std::to_string(value), path)) {
         PLOG(ERROR) << "Failed to write '" << value << "' to " << path;
@@ -432,13 +318,13 @@
 }
 
 bool setProcessGroupSwappiness(uid_t uid, int pid, int swappiness) {
-    return setProcessGroupValue(uid, pid, "/memory.swappiness", swappiness);
+    return SetProcessGroupValue(uid, pid, "/memory.swappiness", swappiness);
 }
 
 bool setProcessGroupSoftLimit(uid_t uid, int pid, int64_t soft_limit_in_bytes) {
-    return setProcessGroupValue(uid, pid, "/memory.soft_limit_in_bytes", soft_limit_in_bytes);
+    return SetProcessGroupValue(uid, pid, "/memory.soft_limit_in_bytes", soft_limit_in_bytes);
 }
 
 bool setProcessGroupLimit(uid_t uid, int pid, int64_t limit_in_bytes) {
-    return setProcessGroupValue(uid, pid, "/memory.limit_in_bytes", limit_in_bytes);
+    return SetProcessGroupValue(uid, pid, "/memory.limit_in_bytes", limit_in_bytes);
 }
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
index c5f8138..430f6c5 100644
--- a/libunwindstack/DexFiles.cpp
+++ b/libunwindstack/DexFiles.cpp
@@ -77,7 +77,8 @@
 
 uint64_t DexFiles::ReadEntryPtr32(uint64_t addr) {
   uint32_t entry;
-  if (!memory_->ReadFully(addr, &entry, sizeof(entry))) {
+  const uint32_t field_offset = 12;  // offset of first_entry_ in the descriptor struct.
+  if (!memory_->ReadFully(addr + field_offset, &entry, sizeof(entry))) {
     return 0;
   }
   return entry;
@@ -85,7 +86,8 @@
 
 uint64_t DexFiles::ReadEntryPtr64(uint64_t addr) {
   uint64_t entry;
-  if (!memory_->ReadFully(addr, &entry, sizeof(entry))) {
+  const uint32_t field_offset = 16;  // offset of first_entry_ in the descriptor struct.
+  if (!memory_->ReadFully(addr + field_offset, &entry, sizeof(entry))) {
     return 0;
   }
   return entry;
@@ -122,7 +124,7 @@
   initialized_ = true;
   entry_addr_ = 0;
 
-  const std::string dex_debug_name("__art_debug_dexfiles");
+  const std::string dex_debug_name("__dex_debug_descriptor");
   for (MapInfo* info : *maps) {
     if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
       continue;
diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp
index dca5605..d029bb0 100644
--- a/libunwindstack/tests/DexFilesTest.cpp
+++ b/libunwindstack/tests/DexFilesTest.cpp
@@ -63,7 +63,7 @@
     elf->FakeSetValid(true);
     ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
     elf->FakeSetInterface(interface);
-    interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
+    interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x800);
     map_info->elf.reset(elf);
 
     // Global variable not set by default.
@@ -74,7 +74,7 @@
     elf->FakeSetValid(true);
     interface = new ElfInterfaceFake(memory);
     elf->FakeSetInterface(interface);
-    interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
+    interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x800);
     map_info->elf.reset(elf);
 
     // Global variable set in this map.
@@ -85,10 +85,12 @@
     elf->FakeSetValid(true);
     interface = new ElfInterfaceFake(memory);
     elf->FakeSetInterface(interface);
-    interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
+    interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x800);
     map_info->elf.reset(elf);
   }
 
+  void WriteDescriptor32(uint64_t addr, uint32_t head);
+  void WriteDescriptor64(uint64_t addr, uint64_t head);
   void WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, uint32_t dex_file);
   void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file);
   void WriteDex(uint64_t dex_file);
@@ -105,6 +107,16 @@
   std::unique_ptr<BufferMaps> maps_;
 };
 
+void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t head) {
+  //   void* first_entry_
+  memory_->SetData32(addr + 12, head);
+}
+
+void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t head) {
+  //   void* first_entry_
+  memory_->SetData64(addr + 16, head);
+}
+
 void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev,
                                 uint32_t dex_file) {
   // Format of the 32 bit DEXFileEntry structure:
@@ -146,7 +158,7 @@
   uint64_t method_offset = 0x124;
   MapInfo* info = maps_->Get(kMapDexFiles);
 
-  memory_->SetData32(0xf800, 0x200000);
+  WriteDescriptor32(0xf800, 0x200000);
   WriteEntry32(0x200000, 0, 0, 0x300000);
   WriteDex(0x300000);
 
@@ -161,7 +173,7 @@
   MapInfo* info = maps_->Get(kMapDexFiles);
 
   dex_files_->SetArch(ARCH_ARM64);
-  memory_->SetData64(0xf800, 0x200000);
+  WriteDescriptor64(0xf800, 0x200000);
   WriteEntry64(0x200000, 0, 0, 0x301000);
   WriteDex(0x301000);
 
@@ -175,7 +187,7 @@
   uint64_t method_offset = 0x124;
   MapInfo* info = maps_->Get(kMapDexFiles);
 
-  memory_->SetData32(0xf800, 0x200000);
+  WriteDescriptor32(0xf800, 0x200000);
   WriteEntry32(0x200000, 0x200100, 0, 0x100000);
   WriteEntry32(0x200100, 0, 0x200000, 0x300000);
   WriteDex(0x300000);
@@ -191,7 +203,7 @@
   MapInfo* info = maps_->Get(kMapDexFiles);
 
   dex_files_->SetArch(ARCH_ARM64);
-  memory_->SetData64(0xf800, 0x200000);
+  WriteDescriptor64(0xf800, 0x200000);
   WriteEntry64(0x200000, 0x200100, 0, 0x100000);
   WriteEntry64(0x200100, 0, 0x200000, 0x300000);
   WriteDex(0x300000);
@@ -206,7 +218,7 @@
   uint64_t method_offset = 0x124;
   MapInfo* info = maps_->Get(kMapDexFiles);
 
-  memory_->SetData32(0xf800, 0x200000);
+  WriteDescriptor32(0xf800, 0x200000);
   WriteEntry32(0x200000, 0, 0, 0x300000);
   WriteDex(0x300000);
 
@@ -226,7 +238,7 @@
   uint64_t method_offset = 0x124;
   MapInfo* info = maps_->Get(kMapDexFiles);
 
-  memory_->SetData32(0xf800, 0x200000);
+  WriteDescriptor32(0xf800, 0x200000);
   WriteEntry32(0x200000, 0x200100, 0, 0x100000);
   WriteEntry32(0x200100, 0, 0x200000, 0x300000);
   WriteDex(0x300000);
@@ -259,9 +271,9 @@
   MapInfo* info = maps_->Get(kMapDexFiles);
 
   // First global variable found, but value is zero.
-  memory_->SetData32(0xc800, 0);
+  WriteDescriptor32(0xc800, 0);
 
-  memory_->SetData32(0xf800, 0x200000);
+  WriteDescriptor32(0xf800, 0x200000);
   WriteEntry32(0x200000, 0, 0, 0x300000);
   WriteDex(0x300000);
 
@@ -274,7 +286,7 @@
   dex_files_->SetArch(ARCH_ARM);
   method_name = "fail";
   method_offset = 0x123;
-  memory_->SetData32(0xc800, 0x100000);
+  WriteDescriptor32(0xc800, 0x100000);
   dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("fail", method_name);
   EXPECT_EQ(0x123U, method_offset);
@@ -286,9 +298,9 @@
   MapInfo* info = maps_->Get(kMapDexFiles);
 
   // First global variable found, but value is zero.
-  memory_->SetData64(0xc800, 0);
+  WriteDescriptor64(0xc800, 0);
 
-  memory_->SetData64(0xf800, 0x200000);
+  WriteDescriptor64(0xf800, 0x200000);
   WriteEntry64(0x200000, 0, 0, 0x300000);
   WriteDex(0x300000);
 
@@ -302,7 +314,7 @@
   dex_files_->SetArch(ARCH_ARM64);
   method_name = "fail";
   method_offset = 0x123;
-  memory_->SetData32(0xc800, 0x100000);
+  WriteDescriptor64(0xc800, 0x100000);
   dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("fail", method_name);
   EXPECT_EQ(0x123U, method_offset);
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 209bf9a..80dcdcb 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -201,5 +201,3 @@
         "-Werror",
     ],
 }
-
-subdirs = ["tests"]