Merge "Make runtime namespace visible."
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 06e4c50..a5b2f7b 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1134,7 +1134,9 @@
         std::string host;
         int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
         std::string error;
-        if (!android::base::ParseNetAddress(address, &host, &port, &serial, &error)) {
+        if (address.starts_with("vsock:")) {
+            serial = address;
+        } else if (!android::base::ParseNetAddress(address, &host, &port, &serial, &error)) {
             SendFail(reply_fd, android::base::StringPrintf("couldn't parse '%s': %s",
                                                            address.c_str(), error.c_str()));
             return true;
diff --git a/adb/daemon/transport_qemu.cpp b/adb/daemon/transport_qemu.cpp
index 8ad2572..e996c17 100644
--- a/adb/daemon/transport_qemu.cpp
+++ b/adb/daemon/transport_qemu.cpp
@@ -78,7 +78,7 @@
         /* This could be an older version of the emulator, that doesn't
          * implement adb QEMUD service. Fall back to the old TCP way. */
         D("adb service is not available. Falling back to TCP socket.");
-        std::thread(server_socket_thread, port).detach();
+        std::thread(server_socket_thread, android::base::StringPrintf("tcp:%d", port)).detach();
         return;
     }
 
diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp
index cc67b6b..de4fff9 100644
--- a/adb/socket_spec.cpp
+++ b/adb/socket_spec.cpp
@@ -46,6 +46,11 @@
 #define ADB_WINDOWS 0
 #endif
 
+#if ADB_LINUX
+#include <sys/socket.h>
+#include "sysdeps/vm_sockets.h"
+#endif
+
 // Not static because it is used in commandline.c.
 int gListenAll = 0;
 
@@ -174,6 +179,62 @@
             return true;
         }
         return false;
+    } else if (address.starts_with("vsock:")) {
+#if ADB_LINUX
+        std::string spec_str(address);
+        std::vector<std::string> fragments = android::base::Split(spec_str, ":");
+        unsigned int port_value = port ? *port : 0;
+        if (fragments.size() != 2 && fragments.size() != 3) {
+            *error = android::base::StringPrintf("expected vsock:cid or vsock:port:cid in '%s'",
+                                                 spec_str.c_str());
+            errno = EINVAL;
+            return false;
+        }
+        unsigned int cid = 0;
+        if (!android::base::ParseUint(fragments[1], &cid)) {
+            *error = android::base::StringPrintf("could not parse vsock cid in '%s'",
+                                                 spec_str.c_str());
+            errno = EINVAL;
+            return false;
+        }
+        if (fragments.size() == 3 && !android::base::ParseUint(fragments[2], &port_value)) {
+            *error = android::base::StringPrintf("could not parse vsock port in '%s'",
+                                                 spec_str.c_str());
+            errno = EINVAL;
+            return false;
+        }
+        if (port_value == 0) {
+            *error = android::base::StringPrintf("vsock port was not provided.");
+            errno = EINVAL;
+            return false;
+        }
+        fd->reset(socket(AF_VSOCK, SOCK_STREAM, 0));
+        if (fd->get() == -1) {
+            *error = "could not open vsock socket";
+            return false;
+        }
+        sockaddr_vm addr{};
+        addr.svm_family = AF_VSOCK;
+        addr.svm_port = port_value;
+        addr.svm_cid = cid;
+        if (serial) {
+            *serial = android::base::StringPrintf("vsock:%u:%d", cid, port_value);
+        }
+        if (connect(fd->get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) {
+            int error_num = errno;
+            *error = android::base::StringPrintf("could not connect to vsock address '%s'",
+                                                 spec_str.c_str());
+            errno = error_num;
+            return false;
+        }
+        if (port) {
+            *port = port_value;
+        }
+        return true;
+#else   // ADB_LINUX
+        *error = "vsock is only supported on linux";
+        return false;
+#endif  // ADB_LINUX
     }
 
     for (const auto& it : kLocalSocketTypes) {
@@ -187,6 +248,9 @@
 
             fd->reset(network_local_client(&address[prefix.length()], it.second.socket_namespace,
                                            SOCK_STREAM, error));
+            if (serial) {
+                *serial = address;
+            }
             return true;
         }
     }
@@ -196,7 +260,7 @@
     return false;
 }
 
-int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_tcp_port) {
+int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_port) {
     if (spec.starts_with("tcp:")) {
         std::string hostname;
         int port;
@@ -215,10 +279,59 @@
             return -1;
         }
 
-        if (result >= 0 && port == 0 && resolved_tcp_port) {
-            *resolved_tcp_port = adb_socket_get_local_port(result);
+        if (result >= 0 && resolved_port) {
+            *resolved_port = adb_socket_get_local_port(result);
         }
         return result;
+    } else if (spec.starts_with("vsock:")) {
+#if ADB_LINUX
+        std::string spec_str(spec);
+        std::vector<std::string> fragments = android::base::Split(spec_str, ":");
+        if (fragments.size() != 2) {
+            *error = "given vsock server socket string was invalid";
+            return -1;
+        }
+        int port;
+        if (!android::base::ParseInt(fragments[1], &port)) {
+            *error = "could not parse vsock port";
+            errno = EINVAL;
+            return -1;
+        } else if (port < 0) {
+            *error = "vsock port was negative.";
+            errno = EINVAL;
+            return -1;
+        }
+        unique_fd serverfd(socket(AF_VSOCK, SOCK_STREAM, 0));
+        if (serverfd == -1) {
+            int error_num = errno;
+            *error = android::base::StringPrintf("could not create vsock server: '%s'",
+                                                 strerror(error_num));
+            errno = error_num;
+            return -1;
+        }
+        sockaddr_vm addr{};
+        addr.svm_family = AF_VSOCK;
+        addr.svm_port = port == 0 ? VMADDR_PORT_ANY : port;
+        addr.svm_cid = VMADDR_CID_ANY;
+        socklen_t addr_len = sizeof(addr);
+        if (bind(serverfd, reinterpret_cast<struct sockaddr*>(&addr), addr_len)) {
+            return -1;
+        }
+        if (listen(serverfd, 4)) {
+            return -1;
+        }
+        if (serverfd >= 0 && resolved_port) {
+            if (getsockname(serverfd, reinterpret_cast<sockaddr*>(&addr), &addr_len) == 0) {
+                *resolved_port = addr.svm_port;
+            } else {
+                return -1;
+            }
+        }
+        return serverfd.release();
+#else   // ADB_LINUX
+        *error = "vsock is only supported on linux";
+        return -1;
+#endif  // ADB_LINUX
     }
 
     for (const auto& it : kLocalSocketTypes) {
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 28da975..5b4c51e 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -609,6 +609,14 @@
             return false;
         }
     }
+    if (command.starts_with("vsock:")) {
+        // vsock serials are vsock:cid:port, which have an extra colon compared to tcp.
+        size_t next_colon = command.find(':');
+        if (next_colon == std::string::npos) {
+            return false;
+        }
+        consume(next_colon + 1);
+    }
 
     bool found_address = false;
     if (command[0] == '[') {
diff --git a/adb/sysdeps/vm_sockets.h b/adb/sysdeps/vm_sockets.h
new file mode 100644
index 0000000..75c5f44
--- /dev/null
+++ b/adb/sysdeps/vm_sockets.h
@@ -0,0 +1,49 @@
+#if __BIONIC__
+#include <linux/vm_sockets.h>
+#else
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   Copied and modified from bionic/libc/kernel/uapi/linux/vm_sockets.h
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI_VM_SOCKETS_H
+#define _UAPI_VM_SOCKETS_H
+#include <linux/socket.h>
+#define SO_VM_SOCKETS_BUFFER_SIZE 0
+#define SO_VM_SOCKETS_BUFFER_MIN_SIZE 1
+#define SO_VM_SOCKETS_BUFFER_MAX_SIZE 2
+#define SO_VM_SOCKETS_PEER_HOST_VM_ID 3
+#define SO_VM_SOCKETS_TRUSTED 5
+#define SO_VM_SOCKETS_CONNECT_TIMEOUT 6
+#define SO_VM_SOCKETS_NONBLOCK_TXRX 7
+#define VMADDR_CID_ANY -1U
+#define VMADDR_PORT_ANY -1U
+#define VMADDR_CID_HYPERVISOR 0
+#define VMADDR_CID_RESERVED 1
+#define VMADDR_CID_HOST 2
+#define VM_SOCKETS_INVALID_VERSION -1U
+#define VM_SOCKETS_VERSION_EPOCH(_v) (((_v)&0xFF000000) >> 24)
+#define VM_SOCKETS_VERSION_MAJOR(_v) (((_v)&0x00FF0000) >> 16)
+#define VM_SOCKETS_VERSION_MINOR(_v) (((_v)&0x0000FFFF))
+struct sockaddr_vm {
+    __kernel_sa_family_t svm_family;
+    unsigned short svm_reserved1;
+    unsigned int svm_port;
+    unsigned int svm_cid;
+    unsigned char svm_zero[sizeof(struct sockaddr) - sizeof(sa_family_t) - sizeof(unsigned short) -
+                           sizeof(unsigned int) - sizeof(unsigned int)];
+};
+#define IOCTL_VM_SOCKETS_GET_LOCAL_CID _IO(7, 0xb9)
+#ifndef AF_VSOCK
+#define AF_VSOCK 40
+#endif
+#endif
+#endif
diff --git a/adb/transport.h b/adb/transport.h
index 3baeb1c..71e4857 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -28,6 +28,7 @@
 #include <memory>
 #include <mutex>
 #include <string>
+#include <string_view>
 #include <thread>
 #include <unordered_set>
 
@@ -400,7 +401,7 @@
 asocket* create_device_tracker(bool long_output);
 
 #if !ADB_HOST
-void server_socket_thread(int port);
+void server_socket_thread(std::string_view spec);
 
 #if defined(__ANDROID__)
 void qemu_socket_thread(int port);
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 8885db4..c254d1d 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 
 #include <condition_variable>
+#include <functional>
 #include <memory>
 #include <mutex>
 #include <thread>
@@ -74,14 +75,15 @@
     unique_fd fd;
     int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
     std::string serial;
-    if (socket_spec_connect(&fd, "tcp:" + address, &port, &serial, response)) {
+    std::string prefix_addr = address.starts_with("vsock:") ? address : "tcp:" + address;
+    if (socket_spec_connect(&fd, prefix_addr, &port, &serial, response)) {
         close_on_exec(fd);
         if (!set_tcp_keepalive(fd, 1)) {
             D("warning: failed to configure TCP keepalives (%s)", strerror(errno));
         }
         return std::make_tuple(std::move(fd), port, serial);
     }
-    return std::make_tuple(unique_fd(), 0, "");
+    return std::make_tuple(unique_fd(), 0, serial);
 }
 
 void connect_device(const std::string& address, std::string* response) {
@@ -95,6 +97,9 @@
     int port;
     std::string serial;
     std::tie(fd, port, serial) = tcp_connect(address, response);
+    if (fd.get() == -1) {
+        return;
+    }
     auto reconnect = [address](atransport* t) {
         std::string response;
         unique_fd fd;
@@ -231,16 +236,20 @@
 
 #else  // !ADB_HOST
 
-void server_socket_thread(int port) {
+void server_socket_thread(std::string_view spec) {
     unique_fd serverfd;
 
     adb_thread_setname("server socket");
     D("transport: server_socket_thread() starting");
+    int port;
     while (serverfd == -1) {
-        std::string spec = android::base::StringPrintf("tcp:%d", port);
         std::string error;
-        serverfd.reset(socket_spec_listen(spec, &error));
-        if (serverfd < 0) {
+        errno = 0;
+        serverfd.reset(socket_spec_listen(spec, &error, &port));
+        if (errno == EAFNOSUPPORT || errno == EINVAL || errno == EPROTONOSUPPORT) {
+            D("unrecoverable error: '%s'", error.c_str());
+            return;
+        } else if (serverfd < 0) {
             D("server: cannot bind socket yet: %s", error.c_str());
             std::this_thread::sleep_for(1s);
             continue;
@@ -249,7 +258,8 @@
     }
 
     while (true) {
-        D("server: trying to get new connection from %d", port);
+        std::string spec_str{spec};
+        D("server: trying to get new connection from %s", spec_str.c_str());
         unique_fd fd(adb_socket_accept(serverfd, nullptr, nullptr));
         if (fd >= 0) {
             D("server: new connection on fd %d", fd.get());
@@ -266,25 +276,25 @@
 #endif
 
 void local_init(int port) {
-    void (*func)(int);
-    const char* debug_name = "";
-
 #if ADB_HOST
-    func = client_socket_thread;
-    debug_name = "client";
+    D("transport: local client init");
+    std::thread(client_socket_thread, port).detach();
 #elif !defined(__ANDROID__)
     // Host adbd.
-    func = server_socket_thread;
-    debug_name = "server";
+    D("transport: local server init");
+    std::thread(server_socket_thread, android::base::StringPrintf("tcp:%d", port)).detach();
+    std::thread(server_socket_thread, android::base::StringPrintf("vsock:%d", port)).detach();
 #else
+    D("transport: local server init");
     // For the adbd daemon in the system image we need to distinguish
     // between the device, and the emulator.
-    func = use_qemu_goldfish() ? qemu_socket_thread : server_socket_thread;
-    debug_name = "server";
+    if (use_qemu_goldfish()) {
+        std::thread(qemu_socket_thread, port).detach();
+    } else {
+        std::thread(server_socket_thread, android::base::StringPrintf("tcp:%d", port)).detach();
+    }
+    std::thread(server_socket_thread, android::base::StringPrintf("vsock:%d", port)).detach();
 #endif // !ADB_HOST
-
-    D("transport: local %s init", debug_name);
-    std::thread(func, port).detach();
 }
 
 #if ADB_HOST
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index e433787..46d4bd3 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -34,25 +34,27 @@
 #include <stdlib.h>
 #include <string.h>
 
-void bootimg_set_cmdline(boot_img_hdr_v1* h, const std::string& cmdline) {
+void bootimg_set_cmdline(boot_img_hdr_v2* h, const std::string& cmdline) {
     if (cmdline.size() >= sizeof(h->cmdline)) die("command line too large: %zu", cmdline.size());
     strcpy(reinterpret_cast<char*>(h->cmdline), cmdline.c_str());
 }
 
-boot_img_hdr_v1* mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
-                           const std::vector<char>& second, size_t base, const boot_img_hdr_v1& src,
-                           std::vector<char>* out) {
+boot_img_hdr_v2* mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
+                           const std::vector<char>& second, const std::vector<char>& dtb,
+                           size_t base, const boot_img_hdr_v2& src, std::vector<char>* out) {
     const size_t page_mask = src.page_size - 1;
 
     int64_t header_actual = (sizeof(boot_img_hdr_v1) + page_mask) & (~page_mask);
     int64_t kernel_actual = (kernel.size() + page_mask) & (~page_mask);
     int64_t ramdisk_actual = (ramdisk.size() + page_mask) & (~page_mask);
     int64_t second_actual = (second.size() + page_mask) & (~page_mask);
+    int64_t dtb_actual = (dtb.size() + page_mask) & (~page_mask);
 
-    int64_t bootimg_size = header_actual + kernel_actual + ramdisk_actual + second_actual;
+    int64_t bootimg_size =
+            header_actual + kernel_actual + ramdisk_actual + second_actual + dtb_actual;
     out->resize(bootimg_size);
 
-    boot_img_hdr_v1* hdr = reinterpret_cast<boot_img_hdr_v1*>(out->data());
+    boot_img_hdr_v2* hdr = reinterpret_cast<boot_img_hdr_v2*>(out->data());
 
     *hdr = src;
     memcpy(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
@@ -66,13 +68,19 @@
     hdr->second_addr += base;
     hdr->tags_addr += base;
 
-    if (hdr->header_version != 0) {
+    if (hdr->header_version == 1) {
         hdr->header_size = sizeof(boot_img_hdr_v1);
+    } else if (hdr->header_version == 2) {
+        hdr->header_size = sizeof(boot_img_hdr_v2);
+        hdr->dtb_size = dtb.size();
+        hdr->dtb_addr += base;
     }
 
     memcpy(hdr->magic + hdr->page_size, kernel.data(), kernel.size());
     memcpy(hdr->magic + hdr->page_size + kernel_actual, ramdisk.data(), ramdisk.size());
     memcpy(hdr->magic + hdr->page_size + kernel_actual + ramdisk_actual, second.data(),
            second.size());
+    memcpy(hdr->magic + hdr->page_size + kernel_actual + ramdisk_actual + second_actual, dtb.data(),
+           dtb.size());
     return hdr;
 }
diff --git a/fastboot/bootimg_utils.h b/fastboot/bootimg_utils.h
index a4e8870..b7cf9bd 100644
--- a/fastboot/bootimg_utils.h
+++ b/fastboot/bootimg_utils.h
@@ -35,7 +35,7 @@
 #include <string>
 #include <vector>
 
-boot_img_hdr_v1* mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
-                           const std::vector<char>& second, size_t base, const boot_img_hdr_v1& src,
-                           std::vector<char>* out);
-void bootimg_set_cmdline(boot_img_hdr_v1* h, const std::string& cmdline);
+boot_img_hdr_v2* mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
+                           const std::vector<char>& second, const std::vector<char>& dtb,
+                           size_t base, const boot_img_hdr_v2& src, std::vector<char>* out);
+void bootimg_set_cmdline(boot_img_hdr_v2* h, const std::string& cmdline);
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index d753f0f..17cab3a 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -92,8 +92,9 @@
 static int64_t target_sparse_limit = -1;
 
 static unsigned g_base_addr = 0x10000000;
-static boot_img_hdr_v1 g_boot_img_hdr = {};
+static boot_img_hdr_v2 g_boot_img_hdr = {};
 static std::string g_cmdline;
+static std::string g_dtb_path;
 
 static bool g_disable_verity = false;
 static bool g_disable_verification = false;
@@ -394,11 +395,13 @@
             "                            Download and boot kernel from RAM.\n"
             " flash:raw PARTITION KERNEL [RAMDISK [SECOND]]\n"
             "                            Create boot image and flash it.\n"
+            " --dtb DTB                  Specify path to DTB for boot image header version 2.\n"
             " --cmdline CMDLINE          Override kernel command line.\n"
             " --base ADDRESS             Set kernel base address (default: 0x10000000).\n"
             " --kernel-offset            Set kernel offset (default: 0x00008000).\n"
             " --ramdisk-offset           Set ramdisk offset (default: 0x01000000).\n"
             " --tags-offset              Set tags offset (default: 0x00000100).\n"
+            " --dtb-offset               Set dtb offset (default: 0x01100000).\n"
             " --page-size BYTES          Set flash page size (default: 2048).\n"
             " --header-version VERSION   Set boot image header version.\n"
             " --os-version MAJOR[.MINOR[.PATCH]]\n"
@@ -448,12 +451,12 @@
     }
 
     // Is this actually a boot image?
-    if (kernel_data.size() < sizeof(boot_img_hdr_v1)) {
+    if (kernel_data.size() < sizeof(boot_img_hdr_v2)) {
         die("cannot load '%s': too short", kernel.c_str());
     }
     if (!memcmp(kernel_data.data(), BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
         if (!g_cmdline.empty()) {
-            bootimg_set_cmdline(reinterpret_cast<boot_img_hdr_v1*>(kernel_data.data()), g_cmdline);
+            bootimg_set_cmdline(reinterpret_cast<boot_img_hdr_v2*>(kernel_data.data()), g_cmdline);
         }
 
         if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk");
@@ -474,15 +477,26 @@
             die("cannot load '%s': %s", second_stage.c_str(), strerror(errno));
         }
     }
+
+    std::vector<char> dtb_data;
+    if (!g_dtb_path.empty()) {
+        if (g_boot_img_hdr.header_version < 2) {
+                    die("Argument dtb not supported for boot image header version %d\n",
+                        g_boot_img_hdr.header_version);
+        }
+        if (!ReadFileToVector(g_dtb_path, &dtb_data)) {
+            die("cannot load '%s': %s", g_dtb_path.c_str(), strerror(errno));
+        }
+    }
+
     fprintf(stderr,"creating boot image...\n");
 
     std::vector<char> out;
-    boot_img_hdr_v1* boot_image_data = mkbootimg(kernel_data, ramdisk_data, second_stage_data,
-                                                 g_base_addr, g_boot_img_hdr, &out);
+    boot_img_hdr_v2* boot_image_data = mkbootimg(kernel_data, ramdisk_data, second_stage_data,
+                                                 dtb_data, g_base_addr, g_boot_img_hdr, &out);
 
     if (!g_cmdline.empty()) bootimg_set_cmdline(boot_image_data, g_cmdline);
     fprintf(stderr, "creating boot image - %zu bytes\n", out.size());
-
     return out;
 }
 
@@ -1586,6 +1600,7 @@
     g_boot_img_hdr.second_addr = 0x00f00000;
     g_boot_img_hdr.tags_addr = 0x00000100;
     g_boot_img_hdr.page_size = 2048;
+    g_boot_img_hdr.dtb_addr = 0x01100000;
 
     const struct option longopts[] = {
         {"base", required_argument, 0, 0},
@@ -1605,6 +1620,8 @@
         {"skip-secondary", no_argument, 0, 0},
         {"slot", required_argument, 0, 0},
         {"tags-offset", required_argument, 0, 0},
+        {"dtb", required_argument, 0, 0},
+        {"dtb-offset", required_argument, 0, 0},
         {"unbuffered", no_argument, 0, 0},
         {"verbose", no_argument, 0, 'v'},
         {"version", no_argument, 0, 0},
@@ -1632,6 +1649,8 @@
                 force_flash = true;
             } else if (name == "header-version") {
                 g_boot_img_hdr.header_version = strtoul(optarg, nullptr, 0);
+            } else if (name == "dtb") {
+                g_dtb_path = optarg;
             } else if (name == "kernel-offset") {
                 g_boot_img_hdr.kernel_addr = strtoul(optarg, 0, 16);
             } else if (name == "os-patch-level") {
@@ -1649,6 +1668,8 @@
                 skip_secondary = true;
             } else if (name == "slot") {
                 slot_override = optarg;
+            } else if (name == "dtb-offset") {
+                g_boot_img_hdr.dtb_addr = strtoul(optarg, 0, 16);
             } else if (name == "tags-offset") {
                 g_boot_img_hdr.tags_addr = strtoul(optarg, 0, 16);
             } else if (name == "unbuffered") {
@@ -1828,7 +1849,6 @@
             if (!args.empty()) ramdisk = next_arg(&args);
             std::string second_stage;
             if (!args.empty()) second_stage = next_arg(&args);
-
             auto data = LoadBootableImage(kernel, ramdisk, second_stage);
             fb->Download("boot.img", data);
             fb->Boot();
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 8076909..aeab893 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -720,10 +720,10 @@
 }
 
 // Returns fstab entries parsed from the device tree if they exist
-bool ReadFstabFromDt(Fstab* fstab) {
+bool ReadFstabFromDt(Fstab* fstab, bool log) {
     std::string fstab_buf = read_fstab_from_dt();
     if (fstab_buf.empty()) {
-        LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
+        if (log) LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
         return false;
     }
 
@@ -731,13 +731,15 @@
         fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
                  fstab_buf.length(), "r"), fclose);
     if (!fstab_file) {
-        PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
+        if (log) PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
         return false;
     }
 
     if (!fs_mgr_read_fstab_file(fstab_file.get(), false, fstab)) {
-        LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:"
-               << std::endl << fstab_buf;
+        if (log) {
+            LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl
+                   << fstab_buf;
+        }
         return false;
     }
 
@@ -779,7 +781,7 @@
 // Loads the fstab file and combines with fstab entries passed in from device tree.
 bool ReadDefaultFstab(Fstab* fstab) {
     Fstab dt_fstab;
-    ReadFstabFromDt(&dt_fstab);
+    ReadFstabFromDt(&dt_fstab, false);
 
     *fstab = std::move(dt_fstab);
 
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 38f96c0..9c4d2da 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -192,7 +192,7 @@
 using Fstab = std::vector<FstabEntry>;
 
 bool ReadFstabFromFile(const std::string& path, Fstab* fstab);
-bool ReadFstabFromDt(Fstab* fstab);
+bool ReadFstabFromDt(Fstab* fstab, bool log = true);
 bool ReadDefaultFstab(Fstab* fstab);
 
 // Temporary conversion functions.
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index d1b8271..c90f5b2 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -212,6 +212,7 @@
         "tests/RegsStepIfSignalHandlerTest.cpp",
         "tests/RegsTest.cpp",
         "tests/SymbolsTest.cpp",
+        "tests/TestUtils.cpp",
         "tests/UnwindOfflineTest.cpp",
         "tests/UnwindTest.cpp",
         "tests/UnwinderTest.cpp",
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index f319971..9e6bcd4 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -22,6 +22,8 @@
 #include <mutex>
 #include <string>
 
+#include <android-base/stringprintf.h>
+
 #include <unwindstack/Elf.h>
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Maps.h>
@@ -311,4 +313,16 @@
   return *reinterpret_cast<std::string*>(id);
 }
 
+std::string MapInfo::GetPrintableBuildID() {
+  std::string raw_build_id = GetBuildID();
+  if (raw_build_id.empty()) {
+    return "";
+  }
+  std::string printable_build_id;
+  for (const char& c : raw_build_id) {
+    printable_build_id += android::base::StringPrintf("%02x", c);
+  }
+  return printable_build_id;
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index 5143ff1..e938986 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -84,8 +84,12 @@
 
   bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset);
 
+  // Returns the raw build id read from the elf data.
   std::string GetBuildID();
 
+  // Returns the printable version of the build id (hex dump of raw data).
+  std::string GetPrintableBuildID();
+
  private:
   MapInfo(const MapInfo&) = delete;
   void operator=(const MapInfo&) = delete;
diff --git a/libunwindstack/tests/MapInfoGetBuildIDTest.cpp b/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
index 3b89c59..ea9befc 100644
--- a/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
+++ b/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
@@ -67,6 +67,7 @@
   MapInfo info(nullptr, 0x1000, 0x2000, 0, PROT_READ, "");
 
   EXPECT_EQ("", info.GetBuildID());
+  EXPECT_EQ("", info.GetPrintableBuildID());
 }
 
 TEST_F(MapInfoGetBuildIDTest, from_elf) {
@@ -74,6 +75,7 @@
   elf_interface_->FakeSetBuildID("FAKE_BUILD_ID");
 
   EXPECT_EQ("FAKE_BUILD_ID", map_info_->GetBuildID());
+  EXPECT_EQ("46414b455f4255494c445f4944", map_info_->GetPrintableBuildID());
 }
 
 void MapInfoGetBuildIDTest::MultipleThreadTest(std::string expected_build_id) {
@@ -172,6 +174,7 @@
   InitElfData(tf_->fd);
 
   EXPECT_EQ("ELF_BUILDID", map_info_->GetBuildID());
+  EXPECT_EQ("454c465f4255494c444944", map_info_->GetPrintableBuildID());
 }
 
 TEST_F(MapInfoGetBuildIDTest, multiple_thread_elf_exists_in_memory) {
diff --git a/libunwindstack/tests/TestUtils.cpp b/libunwindstack/tests/TestUtils.cpp
new file mode 100644
index 0000000..e76f5f8
--- /dev/null
+++ b/libunwindstack/tests/TestUtils.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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 <malloc.h>
+#include <stdint.h>
+
+#include <gtest/gtest.h>
+
+namespace unwindstack {
+
+void TestCheckForLeaks(void (*unwind_func)(void*), void* data) {
+  static constexpr size_t kNumLeakLoops = 200;
+  static constexpr size_t kMaxAllowedLeakBytes = 32 * 1024;
+
+  size_t first_allocated_bytes = 0;
+  size_t last_allocated_bytes = 0;
+  for (size_t i = 0; i < kNumLeakLoops; i++) {
+    unwind_func(data);
+
+    size_t allocated_bytes = mallinfo().uordblks;
+    if (first_allocated_bytes == 0) {
+      first_allocated_bytes = allocated_bytes;
+    } else if (last_allocated_bytes > first_allocated_bytes) {
+      // Check that the memory did not increase too much over the first loop.
+      ASSERT_LE(last_allocated_bytes - first_allocated_bytes, kMaxAllowedLeakBytes);
+    }
+    last_allocated_bytes = allocated_bytes;
+  }
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/TestUtils.h b/libunwindstack/tests/TestUtils.h
index 8c31aa6..a4d7b9b 100644
--- a/libunwindstack/tests/TestUtils.h
+++ b/libunwindstack/tests/TestUtils.h
@@ -50,6 +50,8 @@
   return ready;
 }
 
+void TestCheckForLeaks(void (*unwind_func)(void*), void* data);
+
 }  // namespace unwindstack
 
 #endif  // _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 0588a84..b5feb38 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -43,6 +43,7 @@
 #include <unwindstack/Unwinder.h>
 
 #include "ElfTestUtils.h"
+#include "TestUtils.h"
 
 namespace unwindstack {
 
@@ -901,6 +902,43 @@
   EXPECT_EQ(0xff85f0c0U, unwinder.frames()[75].sp);
 }
 
+struct LeakType {
+  LeakType(Maps* maps, Regs* regs, std::shared_ptr<Memory>& process_memory)
+      : maps(maps), regs(regs), process_memory(process_memory) {}
+
+  Maps* maps;
+  Regs* regs;
+  std::shared_ptr<Memory>& process_memory;
+};
+
+static void OfflineUnwind(void* data) {
+  LeakType* leak_data = reinterpret_cast<LeakType*>(data);
+
+  std::unique_ptr<Regs> regs_copy(leak_data->regs->Clone());
+  JitDebug jit_debug(leak_data->process_memory);
+  Unwinder unwinder(128, leak_data->maps, regs_copy.get(), leak_data->process_memory);
+  unwinder.SetJitDebug(&jit_debug, regs_copy->Arch());
+  unwinder.Unwind();
+  ASSERT_EQ(76U, unwinder.NumFrames());
+}
+
+TEST_F(UnwindOfflineTest, unwind_offline_check_for_leaks) {
+  ASSERT_NO_FATAL_FAILURE(Init("jit_debug_arm/", ARCH_ARM));
+
+  MemoryOfflineParts* memory = new MemoryOfflineParts;
+  AddMemory(dir_ + "descriptor.data", memory);
+  AddMemory(dir_ + "descriptor1.data", memory);
+  AddMemory(dir_ + "stack.data", memory);
+  for (size_t i = 0; i < 7; i++) {
+    AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory);
+    AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory);
+  }
+  process_memory_.reset(memory);
+
+  LeakType data(maps_.get(), regs_.get(), process_memory_);
+  TestCheckForLeaks(OfflineUnwind, &data);
+}
+
 // The eh_frame_hdr data is present but set to zero fdes. This should
 // fallback to iterating over the cies/fdes and ignore the eh_frame_hdr.
 // No .gnu_debugdata section in the elf file, so no symbols.
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index c747eab..4e38015 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -198,6 +198,21 @@
   OuterFunction(TEST_TYPE_LOCAL_UNWINDER_FROM_PID);
 }
 
+static void LocalUnwind(void* data) {
+  TestTypeEnum* test_type = reinterpret_cast<TestTypeEnum*>(data);
+  OuterFunction(*test_type);
+}
+
+TEST_F(UnwindTest, local_check_for_leak) {
+  TestTypeEnum test_type = TEST_TYPE_LOCAL_UNWINDER;
+  TestCheckForLeaks(LocalUnwind, &test_type);
+}
+
+TEST_F(UnwindTest, local_use_from_pid_check_for_leak) {
+  TestTypeEnum test_type = TEST_TYPE_LOCAL_UNWINDER_FROM_PID;
+  TestCheckForLeaks(LocalUnwind, &test_type);
+}
+
 void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) {
   *completed = false;
   // Need to sleep before attempting first ptrace. Without this, on the
@@ -279,6 +294,57 @@
       << "ptrace detach failed with unexpected error: " << strerror(errno);
 }
 
+static void RemoteCheckForLeaks(void (*unwind_func)(void*)) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    OuterFunction(TEST_TYPE_REMOTE);
+    exit(0);
+  }
+  ASSERT_NE(-1, pid);
+  TestScopedPidReaper reap(pid);
+
+  bool completed;
+  WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed);
+  ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
+
+  TestCheckForLeaks(unwind_func, &pid);
+
+  ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
+      << "ptrace detach failed with unexpected error: " << strerror(errno);
+}
+
+static void RemoteUnwind(void* data) {
+  pid_t* pid = reinterpret_cast<pid_t*>(data);
+
+  RemoteMaps maps(*pid);
+  ASSERT_TRUE(maps.Parse());
+  std::unique_ptr<Regs> regs(Regs::RemoteGet(*pid));
+  ASSERT_TRUE(regs.get() != nullptr);
+
+  VerifyUnwind(*pid, &maps, regs.get(), kFunctionOrder);
+}
+
+TEST_F(UnwindTest, remote_check_for_leaks) {
+  RemoteCheckForLeaks(RemoteUnwind);
+}
+
+static void RemoteUnwindFromPid(void* data) {
+  pid_t* pid = reinterpret_cast<pid_t*>(data);
+
+  std::unique_ptr<Regs> regs(Regs::RemoteGet(*pid));
+  ASSERT_TRUE(regs.get() != nullptr);
+
+  UnwinderFromPid unwinder(512, *pid);
+  ASSERT_TRUE(unwinder.Init(regs->Arch()));
+  unwinder.SetRegs(regs.get());
+
+  VerifyUnwind(&unwinder, kFunctionOrder);
+}
+
+TEST_F(UnwindTest, remote_unwind_for_pid_check_for_leaks) {
+  RemoteCheckForLeaks(RemoteUnwindFromPid);
+}
+
 TEST_F(UnwindTest, from_context) {
   std::atomic_int tid(0);
   std::thread thread([&]() {
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index 5e3b3f8..10b7550 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -36,7 +36,6 @@
 ###############################################################################
 
 additional.namespaces = runtime,conscrypt,media
-namespace.default.asan.permitted.paths += /apex/com.android.resolv/${LIB}
 
 # Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.default.links = runtime
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 537bf86..d081666 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -47,7 +47,7 @@
 
     # Mix device-specific information into the entropy pool
     copy /proc/cmdline /dev/urandom
-    copy /default.prop /dev/urandom
+    copy /system/etc/prop.default /dev/urandom
 
     symlink /proc/self/fd/0 /dev/stdin
     symlink /proc/self/fd/1 /dev/stdout