Merge changes I172acf0f,I97b6e17a

* changes:
  init: change kill order and fix error reporting in KillProcessGroup()
  Better logging in libprocessgroup and make resources clean up themselves
diff --git a/adb/Android.mk b/adb/Android.mk
index 819bad1..efdff5d 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -8,14 +8,12 @@
 adb_host_sanitize :=
 adb_target_sanitize :=
 
-adb_version := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/null)-android
-
 ADB_COMMON_CFLAGS := \
     -Wall -Wextra -Werror \
     -Wno-unused-parameter \
     -Wno-missing-field-initializers \
     -Wvla \
-    -DADB_REVISION='"$(adb_version)"' \
+    -DADB_REVISION=\"$(BUILD_NUMBER_FROM_FILE)\" \
 
 ADB_COMMON_posix_CFLAGS := \
     -Wexit-time-destructors \
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 39e71e5..0181daa 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -31,6 +31,8 @@
 #include <time.h>
 
 #include <chrono>
+#include <condition_variable>
+#include <mutex>
 #include <string>
 #include <thread>
 #include <vector>
@@ -48,6 +50,7 @@
 #include "adb_io.h"
 #include "adb_listeners.h"
 #include "adb_utils.h"
+#include "sysdeps/chrono.h"
 #include "transport.h"
 
 #if !ADB_HOST
@@ -313,19 +316,15 @@
     if (type == "bootloader") {
         D("setting connection_state to kCsBootloader");
         t->SetConnectionState(kCsBootloader);
-        update_transports();
     } else if (type == "device") {
         D("setting connection_state to kCsDevice");
         t->SetConnectionState(kCsDevice);
-        update_transports();
     } else if (type == "recovery") {
         D("setting connection_state to kCsRecovery");
         t->SetConnectionState(kCsRecovery);
-        update_transports();
     } else if (type == "sideload") {
         D("setting connection_state to kCsSideload");
         t->SetConnectionState(kCsSideload);
-        update_transports();
     } else {
         D("setting connection_state to kCsHost");
         t->SetConnectionState(kCsHost);
@@ -353,6 +352,8 @@
         send_auth_request(t);
     }
 #endif
+
+    update_transports();
 }
 
 void handle_packet(apacket *p, atransport *t)
@@ -1229,4 +1230,50 @@
       return ret - 1;
     return -1;
 }
+
+static auto& init_mutex = *new std::mutex();
+static auto& init_cv = *new std::condition_variable();
+static bool device_scan_complete = false;
+static bool transports_ready = false;
+
+void update_transport_status() {
+    bool result = iterate_transports([](const atransport* t) {
+        if (t->type == kTransportUsb && t->online != 1) {
+            return false;
+        }
+        return true;
+    });
+
+    D("update_transport_status: transports_ready = %s", result ? "true" : "false");
+
+    bool ready;
+
+    {
+        std::lock_guard<std::mutex> lock(init_mutex);
+        transports_ready = result;
+        ready = transports_ready && device_scan_complete;
+    }
+
+    if (ready) {
+        D("update_transport_status: notifying");
+        init_cv.notify_all();
+    }
+}
+
+void adb_notify_device_scan_complete() {
+    D("device scan complete");
+
+    {
+        std::lock_guard<std::mutex> lock(init_mutex);
+        device_scan_complete = true;
+    }
+
+    update_transport_status();
+}
+
+void adb_wait_for_device_initialization() {
+    std::unique_lock<std::mutex> lock(init_mutex);
+    init_cv.wait_for(lock, 3s, []() { return device_scan_complete && transports_ready; });
+}
+
 #endif  // ADB_HOST
diff --git a/adb/adb.h b/adb/adb.h
index e3675d8..d6b2b81 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -228,4 +228,18 @@
 
 void parse_banner(const std::string&, atransport* t);
 
+// On startup, the adb server needs to wait until all of the connected devices are ready.
+// To do this, we need to know when the scan has identified all of the potential new transports, and
+// when each transport becomes ready.
+// TODO: Do this for mDNS as well, instead of just USB?
+
+// We've found all of the transports we potentially care about.
+void adb_notify_device_scan_complete();
+
+// One or more transports have changed status, check to see if we're ready.
+void update_transport_status();
+
+// Wait until device scan has completed and every transport is ready, or a timeout elapses.
+void adb_wait_for_device_initialization();
+
 #endif
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index b656887..4f3ff25 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -28,12 +28,15 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <condition_variable>
+#include <mutex>
 #include <string>
 #include <thread>
 #include <vector>
 
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android-base/thread_annotations.h>
 #include <cutils/sockets.h>
 
 #include "adb_io.h"
@@ -177,9 +180,8 @@
         } else {
             fprintf(stderr, "* daemon started successfully\n");
         }
-        // Give the server some time to start properly and detect devices.
-        std::this_thread::sleep_for(3s);
-        // fall through to _adb_connect
+        // The server will wait until it detects all of its connected devices before acking.
+        // Fall through to _adb_connect.
     } else {
         // If a server is already running, check its version matches.
         int version = ADB_SERVER_VERSION - 1;
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 606203c..fe5099c 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -156,33 +156,38 @@
         }
 #endif
 
-        // Inform our parent that we are up and running.
+        // Wait for the USB scan to complete before notifying the parent that we're up.
+        // We need to perform this in a thread, because we would otherwise block the event loop.
+        std::thread notify_thread([ack_reply_fd]() {
+            adb_wait_for_device_initialization();
 
-        // Any error output written to stderr now goes to adb.log. We could
-        // keep around a copy of the stderr fd and use that to write any errors
-        // encountered by the following code, but that is probably overkill.
+            // Any error output written to stderr now goes to adb.log. We could
+            // keep around a copy of the stderr fd and use that to write any errors
+            // encountered by the following code, but that is probably overkill.
 #if defined(_WIN32)
-        const HANDLE ack_reply_handle = cast_int_to_handle(ack_reply_fd);
-        const CHAR ack[] = "OK\n";
-        const DWORD bytes_to_write = arraysize(ack) - 1;
-        DWORD written = 0;
-        if (!WriteFile(ack_reply_handle, ack, bytes_to_write, &written, NULL)) {
-            fatal("adb: cannot write ACK to handle 0x%p: %s", ack_reply_handle,
-                  android::base::SystemErrorCodeToString(GetLastError()).c_str());
-        }
-        if (written != bytes_to_write) {
-            fatal("adb: cannot write %lu bytes of ACK: only wrote %lu bytes",
-                  bytes_to_write, written);
-        }
-        CloseHandle(ack_reply_handle);
+            const HANDLE ack_reply_handle = cast_int_to_handle(ack_reply_fd);
+            const CHAR ack[] = "OK\n";
+            const DWORD bytes_to_write = arraysize(ack) - 1;
+            DWORD written = 0;
+            if (!WriteFile(ack_reply_handle, ack, bytes_to_write, &written, NULL)) {
+                fatal("adb: cannot write ACK to handle 0x%p: %s", ack_reply_handle,
+                      android::base::SystemErrorCodeToString(GetLastError()).c_str());
+            }
+            if (written != bytes_to_write) {
+                fatal("adb: cannot write %lu bytes of ACK: only wrote %lu bytes", bytes_to_write,
+                      written);
+            }
+            CloseHandle(ack_reply_handle);
 #else
-        // TODO(danalbert): Can't use SendOkay because we're sending "OK\n", not
-        // "OKAY".
-        if (!android::base::WriteStringToFd("OK\n", ack_reply_fd)) {
-            fatal_errno("error writing ACK to fd %d", ack_reply_fd);
-        }
-        unix_close(ack_reply_fd);
+            // TODO(danalbert): Can't use SendOkay because we're sending "OK\n", not
+            // "OKAY".
+            if (!android::base::WriteStringToFd("OK\n", ack_reply_fd)) {
+                fatal_errno("error writing ACK to fd %d", ack_reply_fd);
+            }
+            unix_close(ack_reply_fd);
 #endif
+        });
+        notify_thread.detach();
     }
 
     D("Event loop starting");
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index d39884a..15d4b7a 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -159,6 +159,22 @@
                         libusb_get_device_address(device));
 }
 
+#if defined(__linux__)
+static std::string get_device_serial_path(libusb_device* device) {
+    uint8_t ports[7];
+    int port_count = libusb_get_port_numbers(device, ports, 7);
+    if (port_count < 0) return "";
+
+    std::string path =
+        StringPrintf("/sys/bus/usb/devices/%d-%d", libusb_get_bus_number(device), ports[0]);
+    for (int port = 1; port < port_count; ++port) {
+        path += StringPrintf(".%d", ports[port]);
+    }
+    path += "/serial";
+    return path;
+}
+#endif
+
 static bool endpoint_is_output(uint8_t endpoint) {
     return (endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT;
 }
@@ -168,6 +184,195 @@
            (write_length & zero_mask) == 0;
 }
 
+static void process_device(libusb_device* device) {
+    std::string device_address = get_device_address(device);
+    std::string device_serial;
+
+    // Figure out if we want to open the device.
+    libusb_device_descriptor device_desc;
+    int rc = libusb_get_device_descriptor(device, &device_desc);
+    if (rc != 0) {
+        LOG(WARNING) << "failed to get device descriptor for device at " << device_address << ": "
+                     << libusb_error_name(rc);
+        return;
+    }
+
+    if (device_desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE) {
+        // Assume that all Android devices have the device class set to per interface.
+        // TODO: Is this assumption valid?
+        LOG(VERBOSE) << "skipping device with incorrect class at " << device_address;
+        return;
+    }
+
+    libusb_config_descriptor* config_raw;
+    rc = libusb_get_active_config_descriptor(device, &config_raw);
+    if (rc != 0) {
+        LOG(WARNING) << "failed to get active config descriptor for device at " << device_address
+                     << ": " << libusb_error_name(rc);
+        return;
+    }
+    const unique_config_descriptor config(config_raw);
+
+    // Use size_t for interface_num so <iostream>s don't mangle it.
+    size_t interface_num;
+    uint16_t zero_mask;
+    uint8_t bulk_in = 0, bulk_out = 0;
+    size_t packet_size = 0;
+    bool found_adb = false;
+
+    for (interface_num = 0; interface_num < config->bNumInterfaces; ++interface_num) {
+        const libusb_interface& interface = config->interface[interface_num];
+        if (interface.num_altsetting != 1) {
+            // Assume that interfaces with alternate settings aren't adb interfaces.
+            // TODO: Is this assumption valid?
+            LOG(VERBOSE) << "skipping interface with incorrect num_altsetting at " << device_address
+                         << " (interface " << interface_num << ")";
+            return;
+        }
+
+        const libusb_interface_descriptor& interface_desc = interface.altsetting[0];
+        if (!is_adb_interface(interface_desc.bInterfaceClass, interface_desc.bInterfaceSubClass,
+                              interface_desc.bInterfaceProtocol)) {
+            LOG(VERBOSE) << "skipping non-adb interface at " << device_address << " (interface "
+                         << interface_num << ")";
+            return;
+        }
+
+        LOG(VERBOSE) << "found potential adb interface at " << device_address << " (interface "
+                     << interface_num << ")";
+
+        bool found_in = false;
+        bool found_out = false;
+        for (size_t endpoint_num = 0; endpoint_num < interface_desc.bNumEndpoints; ++endpoint_num) {
+            const auto& endpoint_desc = interface_desc.endpoint[endpoint_num];
+            const uint8_t endpoint_addr = endpoint_desc.bEndpointAddress;
+            const uint8_t endpoint_attr = endpoint_desc.bmAttributes;
+
+            const uint8_t transfer_type = endpoint_attr & LIBUSB_TRANSFER_TYPE_MASK;
+
+            if (transfer_type != LIBUSB_TRANSFER_TYPE_BULK) {
+                return;
+            }
+
+            if (endpoint_is_output(endpoint_addr) && !found_out) {
+                found_out = true;
+                bulk_out = endpoint_addr;
+                zero_mask = endpoint_desc.wMaxPacketSize - 1;
+            } else if (!endpoint_is_output(endpoint_addr) && !found_in) {
+                found_in = true;
+                bulk_in = endpoint_addr;
+            }
+
+            size_t endpoint_packet_size = endpoint_desc.wMaxPacketSize;
+            CHECK(endpoint_packet_size != 0);
+            if (packet_size == 0) {
+                packet_size = endpoint_packet_size;
+            } else {
+                CHECK(packet_size == endpoint_packet_size);
+            }
+        }
+
+        if (found_in && found_out) {
+            found_adb = true;
+            break;
+        } else {
+            LOG(VERBOSE) << "rejecting potential adb interface at " << device_address
+                         << "(interface " << interface_num << "): missing bulk endpoints "
+                         << "(found_in = " << found_in << ", found_out = " << found_out << ")";
+        }
+    }
+
+    if (!found_adb) {
+        LOG(VERBOSE) << "skipping device with no adb interfaces at " << device_address;
+        return;
+    }
+
+    {
+        std::unique_lock<std::mutex> lock(usb_handles_mutex);
+        if (usb_handles.find(device_address) != usb_handles.end()) {
+            LOG(VERBOSE) << "device at " << device_address
+                         << " has already been registered, skipping";
+            return;
+        }
+    }
+
+    bool writable = true;
+    libusb_device_handle* handle_raw = nullptr;
+    rc = libusb_open(device, &handle_raw);
+    unique_device_handle handle(handle_raw);
+    if (rc == 0) {
+        LOG(DEBUG) << "successfully opened adb device at " << device_address << ", "
+                   << StringPrintf("bulk_in = %#x, bulk_out = %#x", bulk_in, bulk_out);
+
+        device_serial.resize(255);
+        rc = libusb_get_string_descriptor_ascii(handle_raw, device_desc.iSerialNumber,
+                                                reinterpret_cast<unsigned char*>(&device_serial[0]),
+                                                device_serial.length());
+        if (rc == 0) {
+            LOG(WARNING) << "received empty serial from device at " << device_address;
+            return;
+        } else if (rc < 0) {
+            LOG(WARNING) << "failed to get serial from device at " << device_address
+                         << libusb_error_name(rc);
+            return;
+        }
+        device_serial.resize(rc);
+
+        // WARNING: this isn't released via RAII.
+        rc = libusb_claim_interface(handle.get(), interface_num);
+        if (rc != 0) {
+            LOG(WARNING) << "failed to claim adb interface for device '" << device_serial << "'"
+                         << libusb_error_name(rc);
+            return;
+        }
+
+        for (uint8_t endpoint : {bulk_in, bulk_out}) {
+            rc = libusb_clear_halt(handle.get(), endpoint);
+            if (rc != 0) {
+                LOG(WARNING) << "failed to clear halt on device '" << device_serial
+                             << "' endpoint 0x" << std::hex << endpoint << ": "
+                             << libusb_error_name(rc);
+                libusb_release_interface(handle.get(), interface_num);
+                return;
+            }
+        }
+    } else {
+        LOG(WARNING) << "failed to open usb device at " << device_address << ": "
+                     << libusb_error_name(rc);
+        writable = false;
+
+#if defined(__linux__)
+        // libusb doesn't think we should be messing around with devices we don't have
+        // write access to, but Linux at least lets us get the serial number anyway.
+        if (!android::base::ReadFileToString(get_device_serial_path(device), &device_serial)) {
+            // We don't actually want to treat an unknown serial as an error because
+            // devices aren't able to communicate a serial number in early bringup.
+            // http://b/20883914
+            device_serial = "unknown";
+        }
+        device_serial = android::base::Trim(device_serial);
+#else
+        // On Mac OS and Windows, we're screwed. But I don't think this situation actually
+        // happens on those OSes.
+        return;
+#endif
+    }
+
+    auto result =
+        std::make_unique<usb_handle>(device_address, device_serial, std::move(handle),
+                                     interface_num, bulk_in, bulk_out, zero_mask, packet_size);
+    usb_handle* usb_handle_raw = result.get();
+
+    {
+        std::unique_lock<std::mutex> lock(usb_handles_mutex);
+        usb_handles[device_address] = std::move(result);
+    }
+
+    register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), writable);
+
+    LOG(INFO) << "registered new usb device '" << device_serial << "'";
+}
+
 static void poll_for_devices() {
     libusb_device** list;
     adb_thread_setname("device poll");
@@ -177,181 +382,13 @@
         LOG(VERBOSE) << "found " << device_count << " attached devices";
 
         for (ssize_t i = 0; i < device_count; ++i) {
-            libusb_device* device = list[i];
-            std::string device_address = get_device_address(device);
-            std::string device_serial;
-
-            // Figure out if we want to open the device.
-            libusb_device_descriptor device_desc;
-            int rc = libusb_get_device_descriptor(device, &device_desc);
-            if (rc != 0) {
-                LOG(WARNING) << "failed to get device descriptor for device at " << device_address
-                             << ": " << libusb_error_name(rc);
-            }
-
-            if (device_desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE) {
-                // Assume that all Android devices have the device class set to per interface.
-                // TODO: Is this assumption valid?
-                LOG(VERBOSE) << "skipping device with incorrect class at " << device_address;
-                continue;
-            }
-
-            libusb_config_descriptor* config_raw;
-            rc = libusb_get_active_config_descriptor(device, &config_raw);
-            if (rc != 0) {
-                LOG(WARNING) << "failed to get active config descriptor for device at "
-                             << device_address << ": " << libusb_error_name(rc);
-                continue;
-            }
-            const unique_config_descriptor config(config_raw);
-
-            // Use size_t for interface_num so <iostream>s don't mangle it.
-            size_t interface_num;
-            uint16_t zero_mask;
-            uint8_t bulk_in = 0, bulk_out = 0;
-            size_t packet_size = 0;
-            bool found_adb = false;
-
-            for (interface_num = 0; interface_num < config->bNumInterfaces; ++interface_num) {
-                const libusb_interface& interface = config->interface[interface_num];
-                if (interface.num_altsetting != 1) {
-                    // Assume that interfaces with alternate settings aren't adb interfaces.
-                    // TODO: Is this assumption valid?
-                    LOG(VERBOSE) << "skipping interface with incorrect num_altsetting at "
-                                 << device_address << " (interface " << interface_num << ")";
-                    continue;
-                }
-
-                const libusb_interface_descriptor& interface_desc = interface.altsetting[0];
-                if (!is_adb_interface(interface_desc.bInterfaceClass,
-                                      interface_desc.bInterfaceSubClass,
-                                      interface_desc.bInterfaceProtocol)) {
-                    LOG(VERBOSE) << "skipping non-adb interface at " << device_address
-                                 << " (interface " << interface_num << ")";
-                    continue;
-                }
-
-                LOG(VERBOSE) << "found potential adb interface at " << device_address
-                             << " (interface " << interface_num << ")";
-
-                bool found_in = false;
-                bool found_out = false;
-                for (size_t endpoint_num = 0; endpoint_num < interface_desc.bNumEndpoints;
-                     ++endpoint_num) {
-                    const auto& endpoint_desc = interface_desc.endpoint[endpoint_num];
-                    const uint8_t endpoint_addr = endpoint_desc.bEndpointAddress;
-                    const uint8_t endpoint_attr = endpoint_desc.bmAttributes;
-
-                    const uint8_t transfer_type = endpoint_attr & LIBUSB_TRANSFER_TYPE_MASK;
-
-                    if (transfer_type != LIBUSB_TRANSFER_TYPE_BULK) {
-                        continue;
-                    }
-
-                    if (endpoint_is_output(endpoint_addr) && !found_out) {
-                        found_out = true;
-                        bulk_out = endpoint_addr;
-                        zero_mask = endpoint_desc.wMaxPacketSize - 1;
-                    } else if (!endpoint_is_output(endpoint_addr) && !found_in) {
-                        found_in = true;
-                        bulk_in = endpoint_addr;
-                    }
-
-                    size_t endpoint_packet_size = endpoint_desc.wMaxPacketSize;
-                    CHECK(endpoint_packet_size != 0);
-                    if (packet_size == 0) {
-                        packet_size = endpoint_packet_size;
-                    } else {
-                        CHECK(packet_size == endpoint_packet_size);
-                    }
-                }
-
-                if (found_in && found_out) {
-                    found_adb = true;
-                    break;
-                } else {
-                    LOG(VERBOSE) << "rejecting potential adb interface at " << device_address
-                                 << "(interface " << interface_num << "): missing bulk endpoints "
-                                 << "(found_in = " << found_in << ", found_out = " << found_out
-                                 << ")";
-                }
-            }
-
-            if (!found_adb) {
-                LOG(VERBOSE) << "skipping device with no adb interfaces at " << device_address;
-                continue;
-            }
-
-            {
-                std::unique_lock<std::mutex> lock(usb_handles_mutex);
-                if (usb_handles.find(device_address) != usb_handles.end()) {
-                    LOG(VERBOSE) << "device at " << device_address
-                                 << " has already been registered, skipping";
-                    continue;
-                }
-            }
-
-            libusb_device_handle* handle_raw;
-            rc = libusb_open(device, &handle_raw);
-            if (rc != 0) {
-                LOG(WARNING) << "failed to open usb device at " << device_address << ": "
-                             << libusb_error_name(rc);
-                continue;
-            }
-
-            unique_device_handle handle(handle_raw);
-            LOG(DEBUG) << "successfully opened adb device at " << device_address << ", "
-                       << StringPrintf("bulk_in = %#x, bulk_out = %#x", bulk_in, bulk_out);
-
-            device_serial.resize(255);
-            rc = libusb_get_string_descriptor_ascii(
-                handle_raw, device_desc.iSerialNumber,
-                reinterpret_cast<unsigned char*>(&device_serial[0]), device_serial.length());
-            if (rc == 0) {
-                LOG(WARNING) << "received empty serial from device at " << device_address;
-                continue;
-            } else if (rc < 0) {
-                LOG(WARNING) << "failed to get serial from device at " << device_address
-                             << libusb_error_name(rc);
-                continue;
-            }
-            device_serial.resize(rc);
-
-            // WARNING: this isn't released via RAII.
-            rc = libusb_claim_interface(handle.get(), interface_num);
-            if (rc != 0) {
-                LOG(WARNING) << "failed to claim adb interface for device '" << device_serial << "'"
-                             << libusb_error_name(rc);
-                continue;
-            }
-
-            for (uint8_t endpoint : {bulk_in, bulk_out}) {
-                rc = libusb_clear_halt(handle.get(), endpoint);
-                if (rc != 0) {
-                    LOG(WARNING) << "failed to clear halt on device '" << device_serial
-                                 << "' endpoint 0x" << std::hex << endpoint << ": "
-                                 << libusb_error_name(rc);
-                    libusb_release_interface(handle.get(), interface_num);
-                    continue;
-                }
-            }
-
-            auto result = std::make_unique<usb_handle>(device_address, device_serial,
-                                                       std::move(handle), interface_num, bulk_in,
-                                                       bulk_out, zero_mask, packet_size);
-            usb_handle* usb_handle_raw = result.get();
-
-            {
-                std::unique_lock<std::mutex> lock(usb_handles_mutex);
-                usb_handles[device_address] = std::move(result);
-            }
-
-            register_usb_transport(usb_handle_raw, device_serial.c_str(), device_address.c_str(), 1);
-
-            LOG(INFO) << "registered new usb device '" << device_serial << "'";
+            process_device(list[i]);
         }
+
         libusb_free_device_list(list, 1);
 
+        adb_notify_device_scan_complete();
+
         std::this_thread::sleep_for(500ms);
     }
 }
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index e4a543b..e366754 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -38,6 +38,7 @@
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
 
 #include "adb.h"
 #include "transport.h"
@@ -429,7 +430,7 @@
     VLOG(USB) << "RunLoopThread done";
 }
 
-static void usb_cleanup() {
+static void usb_cleanup() NO_THREAD_SAFETY_ANALYSIS {
     VLOG(USB) << "usb_cleanup";
     // Wait until usb operations in RunLoopThread finish, and prevent further operations.
     operate_device_lock.lock();
diff --git a/adb/diagnose_usb.cpp b/adb/diagnose_usb.cpp
index 0f067b0..9f721bf 100644
--- a/adb/diagnose_usb.cpp
+++ b/adb/diagnose_usb.cpp
@@ -25,13 +25,14 @@
 
 #if defined(__linux__)
 #include <grp.h>
+#include <pwd.h>
 #endif
 
 static const char kPermissionsHelpUrl[] = "http://developer.android.com/tools/device.html";
 
-// Returns a message describing any potential problems we find with udev, or nullptr if we can't
-// find plugdev information (i.e. udev is not installed).
-static const char* GetUdevProblem() {
+// Returns a message describing any potential problems we find with udev, or an empty string if we
+// can't find plugdev information (i.e. udev is not installed).
+static std::string GetUdevProblem() {
 #if defined(__linux__)
     errno = 0;
     group* plugdev_group = getgrnam("plugdev");
@@ -41,43 +42,45 @@
             perror("failed to read plugdev group info");
         }
         // We can't give any generally useful advice here, just let the caller print the help URL.
-        return nullptr;
+        return "";
     }
 
-    // getgroups(2) indicates that the group_member() may not check the egid so we check it
+    // getgroups(2) indicates that the GNU group_member(3) may not check the egid so we check it
     // additionally just to be sure.
     if (group_member(plugdev_group->gr_gid) || getegid() == plugdev_group->gr_gid) {
         // The user is in plugdev so the problem is likely with the udev rules.
-        return "verify udev rules";
+        return "user in plugdev group; are your udev rules wrong?";
     }
-    return "udev requires plugdev group membership";
+    passwd* pwd = getpwuid(getuid());
+    return android::base::StringPrintf("user %s is not in the plugdev group",
+                                       pwd ? pwd->pw_name : "?");
 #else
-    return nullptr;
+    return "";
 #endif
 }
 
 // Short help text must be a single line, and will look something like:
-//   no permissions (reason); see <URL>
+//
+//   no permissions (reason); see [URL]
 std::string UsbNoPermissionsShortHelpText() {
     std::string help_text = "no permissions";
 
-    const char* problem = GetUdevProblem();
-    if (problem != nullptr) {
-        help_text += android::base::StringPrintf(" (%s)", problem);
-    }
+    std::string problem(GetUdevProblem());
+    if (!problem.empty()) help_text += " (" + problem + ")";
 
     return android::base::StringPrintf("%s; see [%s]", help_text.c_str(), kPermissionsHelpUrl);
 }
 
-// Long help text can span multiple lines and should provide more detailed information.
+// Long help text can span multiple lines but doesn't currently provide more detailed information:
+//
+//   insufficient permissions for device: reason
+//   See [URL] for more information
 std::string UsbNoPermissionsLongHelpText() {
     std::string header = "insufficient permissions for device";
 
-    const char* problem = GetUdevProblem();
-    if (problem != nullptr) {
-        header += android::base::StringPrintf(": %s", problem);
-    }
+    std::string problem(GetUdevProblem());
+    if (!problem.empty()) header += ": " + problem;
 
-    return android::base::StringPrintf("%s.\nSee [%s] for more information.",
-                                       header.c_str(), kPermissionsHelpUrl);
+    return android::base::StringPrintf("%s\nSee [%s] for more information", header.c_str(),
+                                       kPermissionsHelpUrl);
 }
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 72c9eef..b28de4b 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -26,15 +26,19 @@
 #include <unistd.h>
 
 #include <atomic>
+#include <functional>
 #include <list>
+#include <mutex>
 #include <unordered_map>
 #include <vector>
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
 
 #include "adb_io.h"
 #include "adb_trace.h"
+#include "adb_unique_fd.h"
 #include "adb_utils.h"
 
 #if !ADB_HOST
@@ -75,6 +79,10 @@
 static bool main_thread_valid;
 static unsigned long main_thread_id;
 
+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()>>();
+
 void check_main_thread() {
     if (main_thread_valid) {
         CHECK_EQ(main_thread_id, adb_thread_id());
@@ -112,8 +120,7 @@
     return android::base::StringPrintf("(fdevent %d %s)", fde->fd, state.c_str());
 }
 
-fdevent *fdevent_create(int fd, fd_func func, void *arg)
-{
+fdevent* fdevent_create(int fd, fd_func func, void* arg) {
     check_main_thread();
     fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
     if(fde == 0) return 0;
@@ -122,8 +129,7 @@
     return fde;
 }
 
-void fdevent_destroy(fdevent *fde)
-{
+void fdevent_destroy(fdevent* fde) {
     check_main_thread();
     if(fde == 0) return;
     if(!(fde->state & FDE_CREATED)) {
@@ -278,8 +284,7 @@
     }
 }
 
-static void fdevent_call_fdfunc(fdevent* fde)
-{
+static void fdevent_call_fdfunc(fdevent* fde) {
     unsigned events = fde->events;
     fde->events = 0;
     CHECK(fde->state & FDE_PENDING);
@@ -292,10 +297,7 @@
 
 #include <sys/ioctl.h>
 
-static void fdevent_subproc_event_func(int fd, unsigned ev,
-                                       void* /* userdata */)
-{
-
+static void fdevent_subproc_event_func(int fd, unsigned ev, void* /* userdata */) {
     D("subproc handling on fd = %d, ev = %x", fd, ev);
 
     CHECK_GE(fd, 0);
@@ -342,8 +344,7 @@
     }
 }
 
-void fdevent_subproc_setup()
-{
+static void fdevent_subproc_setup() {
     int s[2];
 
     if(adb_socketpair(s)) {
@@ -358,12 +359,63 @@
 }
 #endif // !ADB_HOST
 
-void fdevent_loop()
-{
+static void fdevent_run_flush() REQUIRES(run_queue_mutex) {
+    for (auto& f : run_queue) {
+        f();
+    }
+    run_queue.clear();
+}
+
+static void fdevent_run_func(int fd, unsigned ev, void* /* userdata */) {
+    CHECK_GE(fd, 0);
+    CHECK(ev & FDE_READ);
+
+    char buf[1024];
+
+    // Empty the fd.
+    if (adb_read(fd, buf, sizeof(buf)) == -1) {
+        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";
+    }
+
+    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();
+}
+
+void fdevent_run_on_main_thread(std::function<void()> fn) {
+    std::lock_guard<std::mutex> lock(run_queue_mutex);
+    run_queue.push_back(std::move(fn));
+
+    // run_queue_notify_fd could still be -1 if we're called before fdevent has finished setting up.
+    // In that case, rely on the setup code to flush the queue without a notification being needed.
+    if (run_queue_notify_fd != -1) {
+        if (adb_write(run_queue_notify_fd.get(), "", 1) != 1) {
+            PLOG(FATAL) << "failed to write to run queue notify fd";
+        }
+    }
+}
+
+void fdevent_loop() {
     set_main_thread();
 #if !ADB_HOST
     fdevent_subproc_setup();
 #endif // !ADB_HOST
+    fdevent_run_setup();
 
     while (true) {
         if (terminate_loop) {
@@ -393,6 +445,11 @@
 void fdevent_reset() {
     g_poll_node_map.clear();
     g_pending_list.clear();
+
+    std::lock_guard<std::mutex> lock(run_queue_mutex);
+    run_queue_notify_fd.reset();
+    run_queue.clear();
+
     main_thread_valid = false;
     terminate_loop = false;
 }
diff --git a/adb/fdevent.h b/adb/fdevent.h
index e32845a..896400a 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -20,6 +20,8 @@
 #include <stddef.h>
 #include <stdint.h>  /* for int64_t */
 
+#include <functional>
+
 /* events that may be observed */
 #define FDE_READ              0x0001
 #define FDE_WRITE             0x0002
@@ -78,6 +80,9 @@
 
 void check_main_thread();
 
+// Queue an operation to run on the main thread.
+void fdevent_run_on_main_thread(std::function<void()> fn);
+
 // The following functions are used only for tests.
 void fdevent_terminate_loop();
 size_t fdevent_installed_count();
diff --git a/adb/fdevent_test.cpp b/adb/fdevent_test.cpp
index bdb973a..86e0209 100644
--- a/adb/fdevent_test.cpp
+++ b/adb/fdevent_test.cpp
@@ -173,3 +173,24 @@
     std::thread thread(InvalidFdThreadFunc);
     thread.join();
 }
+
+TEST_F(FdeventTest, run_on_main_thread) {
+    std::vector<int> vec;
+
+    PrepareThread();
+    std::thread thread(fdevent_loop);
+
+    for (int i = 0; i < 100; ++i) {
+        fdevent_run_on_main_thread([i, &vec]() {
+            check_main_thread();
+            vec.push_back(i);
+        });
+    }
+
+    TerminateThread(thread);
+
+    ASSERT_EQ(100u, vec.size());
+    for (int i = 0; i < 100; ++i) {
+        ASSERT_EQ(i, vec[i]);
+    }
+}
diff --git a/adb/fdevent_test.h b/adb/fdevent_test.h
index f4215ae..5ca49ac 100644
--- a/adb/fdevent_test.h
+++ b/adb/fdevent_test.h
@@ -53,11 +53,11 @@
 
     size_t GetAdditionalLocalSocketCount() {
 #if ADB_HOST
-        // dummy socket installed in PrepareThread()
-        return 1;
-#else
-        // dummy socket and one more socket installed in fdevent_subproc_setup()
+        // dummy socket installed in PrepareThread() + fdevent_run_on_main_thread socket
         return 2;
+#else
+        // dummy socket + fdevent_run_on_main_thread + fdevent_subproc_setup() sockets
+        return 3;
 #endif
     }
 
diff --git a/adb/transport.cpp b/adb/transport.cpp
index cc8c162..20de642 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -400,8 +400,27 @@
     return &tracker->socket;
 }
 
+// Check if all of the USB transports are connected.
+bool iterate_transports(std::function<bool(const atransport*)> fn) {
+    std::lock_guard<std::mutex> lock(transport_lock);
+    for (const auto& t : transport_list) {
+        if (!fn(t)) {
+            return false;
+        }
+    }
+    for (const auto& t : pending_list) {
+        if (!fn(t)) {
+            return false;
+        }
+    }
+    return true;
+}
+
 // Call this function each time the transport list has changed.
 void update_transports() {
+    update_transport_status();
+
+    // Notify `adb track-devices` clients.
     std::string transports = list_transports(false);
 
     device_tracker* tracker = device_tracker_list;
diff --git a/adb/transport.h b/adb/transport.h
index 8c15d66..e129355 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -198,6 +198,10 @@
 void kick_transport(atransport* t);
 void update_transports(void);
 
+// Iterates across all of the current and pending transports.
+// Stops iteration and returns false if fn returns false, otherwise returns true.
+bool iterate_transports(std::function<bool(const atransport*)> fn);
+
 void init_transport_registration(void);
 void init_mdns_transport_discovery(void);
 std::string list_transports(bool long_listing);
diff --git a/adb/transport_mdns.cpp b/adb/transport_mdns.cpp
index e49b1c6..3603f09 100644
--- a/adb/transport_mdns.cpp
+++ b/adb/transport_mdns.cpp
@@ -24,6 +24,8 @@
 #include <arpa/inet.h>
 #endif
 
+#include <thread>
+
 #include <android-base/stringprintf.h>
 #include <dns_sd.h>
 
@@ -262,19 +264,22 @@
     }
 }
 
-void init_mdns_transport_discovery(void) {
-    DNSServiceErrorType errorCode =
-        DNSServiceBrowse(&service_ref, 0, 0, kADBServiceType, nullptr,
-                         register_mdns_transport, nullptr);
+void init_mdns_transport_discovery_thread(void) {
+    DNSServiceErrorType errorCode = DNSServiceBrowse(&service_ref, 0, 0, kADBServiceType, nullptr,
+                                                     register_mdns_transport, nullptr);
 
     if (errorCode != kDNSServiceErr_NoError) {
         D("Got %d initiating mDNS browse.", errorCode);
         return;
     }
 
-    fdevent_install(&service_ref_fde,
-                    adb_DNSServiceRefSockFD(service_ref),
-                    pump_service_ref,
-                    &service_ref);
-    fdevent_set(&service_ref_fde, FDE_READ);
+    fdevent_run_on_main_thread([]() {
+        fdevent_install(&service_ref_fde, adb_DNSServiceRefSockFD(service_ref), pump_service_ref,
+                        &service_ref);
+        fdevent_set(&service_ref_fde, FDE_READ);
+    });
+}
+
+void init_mdns_transport_discovery(void) {
+    std::thread(init_mdns_transport_discovery_thread).detach();
 }
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 79d5c08..37d54d7 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -1,6 +1,5 @@
 cc_defaults {
     name: "debuggerd_defaults",
-    defaults: ["linux_bionic_supported"],
     cflags: [
         "-Wall",
         "-Wextra",
@@ -222,7 +221,6 @@
         "libbase",
         "liblog",
         "libprocinfo",
-        "libselinux",
     ],
 }
 
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 88f390b..d2a4239 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -42,7 +42,6 @@
 #include <cutils/sockets.h>
 #include <log/log.h>
 #include <procinfo/process.h>
-#include <selinux/selinux.h>
 
 #include "backtrace.h"
 #include "tombstone.h"
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 568879e..0b4bbfb 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -29,6 +29,7 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/macros.h>
 #include <android-base/parseint.h>
 #include <android-base/properties.h>
 #include <android-base/strings.h>
@@ -149,7 +150,7 @@
   // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
   void FinishIntercept(int* result);
 
-  void StartProcess(std::function<void()> function);
+  void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
   void StartCrasher(const std::string& crash_type);
   void FinishCrasher();
   void AssertDeath(int signo);
@@ -195,14 +196,14 @@
   }
 }
 
-void CrasherTest::StartProcess(std::function<void()> function) {
+void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
   unique_fd read_pipe;
   unique_fd crasher_read_pipe;
   if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
     FAIL() << "failed to create pipe: " << strerror(errno);
   }
 
-  crasher_pid = fork();
+  crasher_pid = forker();
   if (crasher_pid == -1) {
     FAIL() << "fork failed: " << strerror(errno);
   } else if (crasher_pid == 0) {
@@ -527,6 +528,37 @@
   ASSERT_MATCH(result, R"(#00 pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX R"(/libc.so \(tgkill)");
 }
 
+TEST_F(CrasherTest, fake_pid) {
+  int intercept_result;
+  unique_fd output_fd;
+
+  // Prime the getpid/gettid caches.
+  UNUSED(getpid());
+  UNUSED(gettid());
+
+  std::function<pid_t()> clone_fn = []() {
+    return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
+  };
+  StartProcess(
+      []() {
+        ASSERT_NE(getpid(), syscall(__NR_getpid));
+        ASSERT_NE(gettid(), syscall(__NR_gettid));
+        raise(SIGSEGV);
+      },
+      clone_fn);
+
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  AssertDeath(SIGSEGV);
+  FinishIntercept(&intercept_result);
+
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+  ASSERT_MATCH(result, R"(#00 pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX R"(/libc.so \(tgkill)");
+}
+
 TEST(crash_dump, zombie) {
   pid_t forkpid = fork();
 
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 6e3e6ac..8fd6e11 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -61,6 +61,16 @@
 
 #define CRASH_DUMP_PATH "/system/bin/" CRASH_DUMP_NAME
 
+// Wrappers that directly invoke the respective syscalls, in case the cached values are invalid.
+#pragma GCC poison getpid gettid
+static pid_t __getpid() {
+  return syscall(__NR_getpid);
+}
+
+static pid_t __gettid() {
+  return syscall(__NR_gettid);
+}
+
 static inline void futex_wait(volatile void* ftx, int value) {
   syscall(__NR_futex, ftx, FUTEX_WAIT, value, nullptr, nullptr, 0);
 }
@@ -124,7 +134,7 @@
   }
 
   if (signum == DEBUGGER_SIGNAL) {
-    async_safe_format_log(ANDROID_LOG_INFO, "libc", "Requested dump for tid %d (%s)", gettid(),
+    async_safe_format_log(ANDROID_LOG_INFO, "libc", "Requested dump for tid %d (%s)", __gettid(),
                           thread_name);
     return;
   }
@@ -177,7 +187,7 @@
   }
 
   async_safe_format_log(ANDROID_LOG_FATAL, "libc", "Fatal signal %d (%s)%s%s in tid %d (%s)",
-                        signum, signal_name, code_desc, addr_desc, gettid(), thread_name);
+                        signum, signal_name, code_desc, addr_desc, __gettid(), thread_name);
 }
 
 /*
@@ -337,7 +347,7 @@
   // rt_tgsigqueueinfo(2) to preserve SA_SIGINFO) will cause it to be delivered
   // when our signal handler returns.
   if (crash_dump_started || info->si_signo != DEBUGGER_SIGNAL) {
-    int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), gettid(), info->si_signo, info);
+    int rc = syscall(SYS_rt_tgsigqueueinfo, __getpid(), __gettid(), info->si_signo, info);
     if (rc != 0) {
       fatal_errno("failed to resend signal during crash");
     }
@@ -362,7 +372,7 @@
     memset(&si, 0, sizeof(si));
     si.si_signo = signal_number;
     si.si_code = SI_USER;
-    si.si_pid = getpid();
+    si.si_pid = __getpid();
     si.si_uid = getuid();
     info = &si;
   } else if (info->si_code >= 0 || info->si_code == SI_TKILL) {
@@ -404,7 +414,7 @@
   debugger_thread_info thread_info = {
     .crash_dump_started = false,
     .pseudothread_tid = -1,
-    .crashing_tid = gettid(),
+    .crashing_tid = __gettid(),
     .signal_number = signal_number,
     .info = info
   };
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 2c578a9..e675d7d 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -14,8 +14,6 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-fastboot_version := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/null)-android
-
 include $(CLEAR_VARS)
 
 LOCAL_C_INCLUDES := \
@@ -39,7 +37,7 @@
 LOCAL_MODULE_HOST_OS := darwin linux windows
 LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
 
-LOCAL_CFLAGS += -DFASTBOOT_REVISION='"$(fastboot_version)"'
+LOCAL_CFLAGS += -DFASTBOOT_REVISION=\"$(BUILD_NUMBER_FROM_FILE)\"
 
 LOCAL_SRC_FILES_linux := usb_linux.cpp
 LOCAL_STATIC_LIBRARIES_linux := libselinux
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e438801..5d5ac9b 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -75,7 +75,6 @@
 char cur_product[FB_RESPONSE_SZ + 1];
 
 static const char* serial = nullptr;
-static const char* product = nullptr;
 static const char* cmdline = nullptr;
 static unsigned short vendor_id = 0;
 static int long_listing = 0;
@@ -108,66 +107,46 @@
 };
 
 static struct {
-    char img_name[17];
-    char sig_name[17];
-    char part_name[9];
+    const char* nickname;
+    const char* img_name;
+    const char* sig_name;
+    const char* part_name;
     bool is_optional;
     bool is_secondary;
 } images[] = {
-    {"boot.img", "boot.sig", "boot", false, false},
-    {"boot_other.img", "boot.sig", "boot", true, true},
-    {"recovery.img", "recovery.sig", "recovery", true, false},
-    {"system.img", "system.sig", "system", false, false},
-    {"system_other.img", "system.sig", "system", true, true},
-    {"vendor.img", "vendor.sig", "vendor", true, false},
-    {"vendor_other.img", "vendor.sig", "vendor", true, true},
-    {"vbmeta.img", "vbmeta.sig", "vbmeta", true, false},
-    {"dtbo.img", "dtbo.sig", "dtbo", true, false},
+    // clang-format off
+    { "boot",     "boot.img",         "boot.sig",     "boot",     false, false },
+    { nullptr,    "boot_other.img",   "boot.sig",     "boot",     true,  true  },
+    { "dtbo",     "dtbo.img",         "dtbo.sig",     "dtbo",     true,  false },
+    { "recovery", "recovery.img",     "recovery.sig", "recovery", true,  false },
+    { "system",   "system.img",       "system.sig",   "system",   false, false },
+    { nullptr,    "system_other.img", "system.sig",   "system",   true,  true  },
+    { "vbmeta",   "vbmeta.img",       "vbmeta.sig",   "vbmeta",   true,  false },
+    { "vendor",   "vendor.img",       "vendor.sig",   "vendor",   true,  false },
+    { nullptr,    "vendor_other.img", "vendor.sig",   "vendor",   true,  true  },
+    // clang-format on
 };
 
-static std::string find_item_given_name(const char* img_name, const char* product) {
-    if(product) {
-        std::string path = android::base::GetExecutablePath();
-        path.erase(path.find_last_of('/'));
-        return android::base::StringPrintf("%s/../../../target/product/%s/%s",
-                                           path.c_str(), product, img_name);
-    }
-
-    char *dir = getenv("ANDROID_PRODUCT_OUT");
+static std::string find_item_given_name(const char* img_name) {
+    char* dir = getenv("ANDROID_PRODUCT_OUT");
     if (dir == nullptr || dir[0] == '\0') {
-        die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
+        die("ANDROID_PRODUCT_OUT not set");
     }
-
     return android::base::StringPrintf("%s/%s", dir, img_name);
 }
 
-std::string find_item(const char* item, const char* product) {
-    const char *fn;
-
-    if (!strcmp(item,"boot")) {
-        fn = "boot.img";
-    } else if(!strcmp(item,"recovery")) {
-        fn = "recovery.img";
-    } else if(!strcmp(item,"system")) {
-        fn = "system.img";
-    } else if(!strcmp(item,"vendor")) {
-        fn = "vendor.img";
-    } else if(!strcmp(item,"vbmeta")) {
-        fn = "vbmeta.img";
-    } else if(!strcmp(item,"dtbo")) {
-        fn = "dtbo.img";
-    } else if(!strcmp(item,"userdata")) {
-        fn = "userdata.img";
-    } else if(!strcmp(item,"cache")) {
-        fn = "cache.img";
-    } else if(!strcmp(item,"info")) {
-        fn = "android-info.txt";
-    } else {
-        fprintf(stderr,"unknown partition '%s'\n", item);
-        return "";
+std::string find_item(const char* item) {
+    for (size_t i = 0; i < arraysize(images); ++i) {
+        if (images[i].nickname && !strcmp(images[i].nickname, item)) {
+            return find_item_given_name(images[i].img_name);
+        }
     }
 
-    return find_item_given_name(fn, product);
+    if (!strcmp(item, "userdata")) return find_item_given_name("userdata.img");
+    if (!strcmp(item, "cache")) return find_item_given_name("cache.img");
+
+    fprintf(stderr, "unknown partition '%s'\n", item);
+    return "";
 }
 
 static int64_t get_file_size(int fd) {
@@ -391,7 +370,6 @@
             "                                           For ethernet, provide an address in the\n"
             "                                           form <protocol>:<hostname>[:port] where\n"
             "                                           <protocol> is either tcp or udp.\n"
-            "  -p <product>                             Specify product name.\n"
             "  -c <cmdline>                             Override kernel commandline.\n"
             "  -i <vendor id>                           Specify a custom USB vendor id.\n"
             "  -b, --base <base_addr>                   Specify a custom kernel base\n"
@@ -627,7 +605,7 @@
     }
 }
 
-static int unzip_to_file(ZipArchiveHandle zip, char* entry_name) {
+static int unzip_to_file(ZipArchiveHandle zip, const char* entry_name) {
     unique_fd fd(make_temporary_fd());
     if (fd == -1) {
         fprintf(stderr, "failed to create temporary file for '%s': %s\n",
@@ -1081,9 +1059,9 @@
     flash_buf(pname, &buf);
 }
 
-static void do_update_signature(ZipArchiveHandle zip, char* fn) {
+static void do_update_signature(ZipArchiveHandle zip, const char* filename) {
     int64_t sz;
-    void* data = unzip_file(zip, fn, &sz);
+    void* data = unzip_file(zip, filename, &sz);
     if (data == nullptr) return;
     fb_queue_download("signature", data, sz);
     fb_queue_command("signature", "installing signature");
@@ -1210,7 +1188,7 @@
 
     fb_queue_query_save("product", cur_product, sizeof(cur_product));
 
-    fname = find_item("info", product);
+    fname = find_item_given_name("android-info.txt");
     if (fname.empty()) die("cannot find android-info.txt");
 
     int64_t sz;
@@ -1242,7 +1220,7 @@
             slot = slot_override.c_str();
         }
         if (!slot) continue;
-        fname = find_item_given_name(images[i].img_name, product);
+        fname = find_item_given_name(images[i].img_name);
         fastboot_buffer buf;
         if (!load_buf(transport, fname.c_str(), &buf)) {
             if (images[i].is_optional) continue;
@@ -1509,7 +1487,7 @@
     serial = getenv("ANDROID_SERIAL");
 
     while (1) {
-        int c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lp:c:i:m:ha::", longopts, &longindex);
+        int c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lc:i:m:ha::", longopts, &longindex);
         if (c < 0) {
             break;
         }
@@ -1549,9 +1527,6 @@
             page_size = (unsigned)strtoul(optarg, nullptr, 0);
             if (!page_size) die("invalid page size");
             break;
-        case 'p':
-            product = optarg;
-            break;
         case 'r':
             ramdisk_offset = strtoul(optarg, 0, 16);
             break;
@@ -1764,7 +1739,7 @@
                 fname = argv[2];
                 skip(3);
             } else {
-                fname = find_item(pname, product);
+                fname = find_item(pname);
                 skip(2);
             }
             if (fname.empty()) die("cannot determine image filename for '%s'", pname);
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 6e9069e..60ce43e 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1046,8 +1046,7 @@
         }
 
         int fs_stat = 0;
-        int force_check = do_quota_with_shutdown_check(fstab->recs[i].blk_device,
-                                                       fstab->recs[i].fs_type,
+        int force_check = do_quota_with_shutdown_check(n_blk_device, fstab->recs[i].fs_type,
                                                        &fstab->recs[i], &fs_stat);
 
         if ((fstab->recs[i].fs_mgr_flags & MF_CHECK) || force_check) {
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 94cea57..31babfe 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -483,13 +483,34 @@
     // Only allow two verify results:
     //   - AVB_SLOT_VERIFY_RESULT_OK.
     //   - AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION (for UNLOCKED state).
-    if (verify_result == AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION) {
-        if (!avb_verifier->IsDeviceUnlocked()) {
-            LERROR << "ERROR_VERIFICATION isn't allowed";
+    //     If the device is UNLOCKED, i.e., |allow_verification_error| is true for
+    //     AvbSlotVerify(), then the following return values are all non-fatal:
+    //       * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION
+    //       * AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED
+    //       * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX
+    //     The latter two results were checked by bootloader prior to start fs_mgr so
+    //     we just need to handle the first result here. See *dummy* operations in
+    //     FsManagerAvbOps and the comments in external/avb/libavb/avb_slot_verify.h
+    //     for more details.
+    switch (verify_result) {
+        case AVB_SLOT_VERIFY_RESULT_OK:
+            avb_handle->status_ = kFsManagerAvbHandleSuccess;
+            break;
+        case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+            if (!avb_verifier->IsDeviceUnlocked()) {
+                LERROR << "ERROR_VERIFICATION isn't allowed when the device is LOCKED";
+                return nullptr;
+            }
+            avb_handle->status_ = kFsManagerAvbHandleErrorVerification;
+            break;
+        default:
+            LERROR << "avb_slot_verify failed, result: " << verify_result;
             return nullptr;
-        }
-    } else if (verify_result != AVB_SLOT_VERIFY_RESULT_OK) {
-        LERROR << "avb_slot_verify failed, result: " << verify_result;
+    }
+
+    // Verifies vbmeta images against the digest passed from bootloader.
+    if (!avb_verifier->VerifyVbmetaImages(*avb_handle->avb_slot_data_)) {
+        LERROR << "VerifyVbmetaImages failed";
         return nullptr;
     }
 
@@ -497,30 +518,20 @@
     avb_handle->avb_version_ =
         android::base::StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR);
 
-    // Verifies vbmeta images against the digest passed from bootloader.
-    if (!avb_verifier->VerifyVbmetaImages(*avb_handle->avb_slot_data_)) {
-        LERROR << "VerifyVbmetaImages failed";
-        return nullptr;
-    } else {
-        // Checks whether FLAGS_HASHTREE_DISABLED is set.
-        AvbVBMetaImageHeader vbmeta_header;
-        avb_vbmeta_image_header_to_host_byte_order(
-            (AvbVBMetaImageHeader*)avb_handle->avb_slot_data_->vbmeta_images[0].vbmeta_data,
-            &vbmeta_header);
+    // Checks whether FLAGS_HASHTREE_DISABLED is set.
+    AvbVBMetaImageHeader vbmeta_header;
+    avb_vbmeta_image_header_to_host_byte_order(
+        (AvbVBMetaImageHeader*)avb_handle->avb_slot_data_->vbmeta_images[0].vbmeta_data,
+        &vbmeta_header);
 
-        bool hashtree_disabled =
-            ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
-        if (hashtree_disabled) {
-            avb_handle->status_ = kFsManagerAvbHandleHashtreeDisabled;
-            return avb_handle;
-        }
+    bool hashtree_disabled =
+        ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
+    if (hashtree_disabled) {
+        avb_handle->status_ = kFsManagerAvbHandleHashtreeDisabled;
     }
 
-    if (verify_result == AVB_SLOT_VERIFY_RESULT_OK) {
-        avb_handle->status_ = kFsManagerAvbHandleSuccess;
-        return avb_handle;
-    }
-    return nullptr;
+    LINFO << "Returning avb_handle with status: " << avb_handle->status_;
+    return avb_handle;
 }
 
 bool FsManagerAvbHandle::SetUpAvb(struct fstab_rec* fstab_entry, bool wait_for_verity_dev) {
@@ -528,11 +539,12 @@
     if (!avb_slot_data_ || avb_slot_data_->num_vbmeta_images < 1) {
         return false;
     }
+
+    if (status_ == kFsManagerAvbHandleUninitialized) return false;
     if (status_ == kFsManagerAvbHandleHashtreeDisabled) {
         LINFO << "AVB HASHTREE disabled on:" << fstab_entry->mount_point;
         return true;
     }
-    if (status_ != kFsManagerAvbHandleSuccess) return false;
 
     std::string partition_name(basename(fstab_entry->mount_point));
     if (!avb_validate_utf8((const uint8_t*)partition_name.c_str(), partition_name.length())) {
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 0bf173b..5fa10bc 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -663,7 +663,7 @@
     /* use the kernel parameter if set */
     std::string veritymode;
     if (fs_mgr_get_boot_config("veritymode", &veritymode)) {
-        if (veritymode.compare("enforcing")) {
+        if (veritymode == "enforcing") {
             *mode = VERITY_MODE_DEFAULT;
         }
         return 0;
diff --git a/fs_mgr/include/fs_mgr_avb.h b/fs_mgr/include/fs_mgr_avb.h
index a66ff42..65ff9941 100644
--- a/fs_mgr/include/fs_mgr_avb.h
+++ b/fs_mgr/include/fs_mgr_avb.h
@@ -25,9 +25,10 @@
 #include "fs_mgr.h"
 
 enum FsManagerAvbHandleStatus {
+    kFsManagerAvbHandleUninitialized = -1,
     kFsManagerAvbHandleSuccess = 0,
     kFsManagerAvbHandleHashtreeDisabled = 1,
-    kFsManagerAvbHandleFail = 2,
+    kFsManagerAvbHandleErrorVerification = 2,
 };
 
 class FsManagerAvbHandle;
@@ -88,7 +89,7 @@
     };
 
   protected:
-    FsManagerAvbHandle() : avb_slot_data_(nullptr), status_(kFsManagerAvbHandleFail) {}
+    FsManagerAvbHandle() : avb_slot_data_(nullptr), status_(kFsManagerAvbHandleUninitialized) {}
 
   private:
     AvbSlotVerifyData* avb_slot_data_;
diff --git a/init/README.md b/init/README.md
index 9fc8d47..72b6c6b 100644
--- a/init/README.md
+++ b/init/README.md
@@ -356,9 +356,9 @@
   Init halts executing commands until the forked process exits.
 
 `exec_start <service>`
-> Start service a given service and halt processing of additional init commands
-  until it returns.  It functions similarly to the `exec` command, but uses an
-  existing service definition instead of providing them as arguments.
+> Start a given service and halt the processing of additional init commands
+  until it returns.  The command functions similarly to the `exec` command,
+  but uses an existing service definition in place of the exec argument vector.
 
 `export <name> <value>`
 > Set the environment variable _name_ equal to _value_ in the
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 3dadfd7..1eacb36 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -150,7 +150,12 @@
 }
 
 static int do_domainname(const std::vector<std::string>& args) {
-    return write_file("/proc/sys/kernel/domainname", args[1]) ? 0 : 1;
+    std::string err;
+    if (!WriteFile("/proc/sys/kernel/domainname", args[1], &err)) {
+        LOG(ERROR) << err;
+        return -1;
+    }
+    return 0;
 }
 
 static int do_enable(const std::vector<std::string>& args) {
@@ -174,7 +179,12 @@
 }
 
 static int do_hostname(const std::vector<std::string>& args) {
-    return write_file("/proc/sys/kernel/hostname", args[1]) ? 0 : 1;
+    std::string err;
+    if (!WriteFile("/proc/sys/kernel/hostname", args[1], &err)) {
+        LOG(ERROR) << err;
+        return -1;
+    }
+    return 0;
 }
 
 static int do_ifup(const std::vector<std::string>& args) {
@@ -215,11 +225,19 @@
     }
 
     if (args.size() >= 4) {
-        uid_t uid = decode_uid(args[3].c_str());
+        uid_t uid;
+        std::string decode_uid_err;
+        if (!DecodeUid(args[3], &uid, &decode_uid_err)) {
+            LOG(ERROR) << "Unable to find UID for '" << args[3] << "': " << decode_uid_err;
+            return -1;
+        }
         gid_t gid = -1;
 
         if (args.size() == 5) {
-            gid = decode_uid(args[4].c_str());
+            if (!DecodeUid(args[4], &gid, &decode_uid_err)) {
+                LOG(ERROR) << "Unable to find GID for '" << args[3] << "': " << decode_uid_err;
+                return -1;
+            }
         }
 
         if (lchown(args[1].c_str(), uid, gid) == -1) {
@@ -643,29 +661,49 @@
 }
 
 static int do_write(const std::vector<std::string>& args) {
-    return write_file(args[1], args[2]) ? 0 : 1;
+    std::string err;
+    if (!WriteFile(args[1], args[2], &err)) {
+        LOG(ERROR) << err;
+        return -1;
+    }
+    return 0;
 }
 
 static int do_copy(const std::vector<std::string>& args) {
     std::string data;
-    if (read_file(args[1], &data)) {
-        return write_file(args[2], data) ? 0 : 1;
+    std::string err;
+    if (!ReadFile(args[1], &data, &err)) {
+        LOG(ERROR) << err;
+        return -1;
     }
-    return 1;
+    if (!WriteFile(args[2], data, &err)) {
+        LOG(ERROR) << err;
+        return -1;
+    }
+    return 0;
 }
 
 static int do_chown(const std::vector<std::string>& args) {
-    /* GID is optional. */
-    if (args.size() == 3) {
-        if (lchown(args[2].c_str(), decode_uid(args[1].c_str()), -1) == -1)
-            return -errno;
-    } else if (args.size() == 4) {
-        if (lchown(args[3].c_str(), decode_uid(args[1].c_str()),
-                   decode_uid(args[2].c_str())) == -1)
-            return -errno;
-    } else {
+    uid_t uid;
+    std::string decode_uid_err;
+    if (!DecodeUid(args[1], &uid, &decode_uid_err)) {
+        LOG(ERROR) << "Unable to find UID for '" << args[1] << "': " << decode_uid_err;
         return -1;
     }
+
+    // GID is optional and pushes the index of path out by one if specified.
+    const std::string& path = (args.size() == 4) ? args[3] : args[2];
+    gid_t gid = -1;
+
+    if (args.size() == 4) {
+        if (!DecodeUid(args[2], &gid, &decode_uid_err)) {
+            LOG(ERROR) << "Unable to find GID for '" << args[2] << "': " << decode_uid_err;
+            return -1;
+        }
+    }
+
+    if (lchown(path.c_str(), uid, gid) == -1) return -errno;
+
     return 0;
 }
 
@@ -724,7 +762,7 @@
             }
         } else {
             in_flags = false;
-            if (restorecon(args[i].c_str(), flag) < 0) {
+            if (selinux_android_restorecon(args[i].c_str(), flag) < 0) {
                 ret = -errno;
             }
         }
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
index b2142ca..6f729a3 100644
--- a/init/descriptors.cpp
+++ b/init/descriptors.cpp
@@ -23,6 +23,7 @@
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <cutils/android_get_control_file.h>
 #include <cutils/sockets.h>
@@ -77,10 +78,12 @@
 }
 
 int SocketInfo::Create(const std::string& context) const {
-  int flags = ((type() == "stream" ? SOCK_STREAM :
-                (type() == "dgram" ? SOCK_DGRAM :
-                 SOCK_SEQPACKET)));
-  return create_socket(name().c_str(), flags, perm(), uid(), gid(), context.c_str(), sehandle);
+    auto types = android::base::Split(type(), "+");
+    int flags =
+        ((types[0] == "stream" ? SOCK_STREAM : (types[0] == "dgram" ? SOCK_DGRAM : SOCK_SEQPACKET)));
+    bool passcred = types.size() > 1 && types[1] == "passcred";
+    return CreateSocket(name().c_str(), flags, passcred, perm(), uid(), gid(), context.c_str(),
+                        sehandle);
 }
 
 const std::string SocketInfo::key() const {
diff --git a/init/devices.cpp b/init/devices.cpp
index 74f099a..d8258cf 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -251,7 +251,7 @@
 
     if (access(path.c_str(), F_OK) == 0) {
         LOG(VERBOSE) << "restorecon_recursive: " << path;
-        restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
+        selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
     }
 }
 
diff --git a/init/init.cpp b/init/init.cpp
index 52f6b0c..878f164 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -853,7 +853,9 @@
             }
         }
 
-        if (!write_file("/sys/fs/selinux/checkreqprot", "0")) {
+        std::string err;
+        if (!WriteFile("/sys/fs/selinux/checkreqprot", "0", &err)) {
+            LOG(ERROR) << err;
             security_failure();
         }
 
@@ -869,23 +871,23 @@
 // value. This must happen before /dev is populated by ueventd.
 static void selinux_restore_context() {
     LOG(INFO) << "Running restorecon...";
-    restorecon("/dev");
-    restorecon("/dev/kmsg");
+    selinux_android_restorecon("/dev", 0);
+    selinux_android_restorecon("/dev/kmsg", 0);
     if constexpr (WORLD_WRITABLE_KMSG) {
-      restorecon("/dev/kmsg_debug");
+      selinux_android_restorecon("/dev/kmsg_debug", 0);
     }
-    restorecon("/dev/socket");
-    restorecon("/dev/random");
-    restorecon("/dev/urandom");
-    restorecon("/dev/__properties__");
-    restorecon("/plat_property_contexts");
-    restorecon("/nonplat_property_contexts");
-    restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
-    restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
-    restorecon("/dev/device-mapper");
+    selinux_android_restorecon("/dev/socket", 0);
+    selinux_android_restorecon("/dev/random", 0);
+    selinux_android_restorecon("/dev/urandom", 0);
+    selinux_android_restorecon("/dev/__properties__", 0);
+    selinux_android_restorecon("/plat_property_contexts", 0);
+    selinux_android_restorecon("/nonplat_property_contexts", 0);
+    selinux_android_restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
+    selinux_android_restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
+    selinux_android_restorecon("/dev/device-mapper", 0);
 
-    restorecon("/sbin/mke2fs");
-    restorecon("/sbin/e2fsdroid");
+    selinux_android_restorecon("/sbin/mke2fs", 0);
+    selinux_android_restorecon("/sbin/e2fsdroid", 0);
 }
 
 // Set the UDC controller for the ConfigFS USB Gadgets.
@@ -994,7 +996,7 @@
 
         // We're in the kernel domain, so re-exec init to transition to the init domain now
         // that the SELinux policy has been loaded.
-        if (restorecon("/init") == -1) {
+        if (selinux_android_restorecon("/init", 0) == -1) {
             PLOG(ERROR) << "restorecon failed";
             security_failure();
         }
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 620367a..1b31cf2 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -110,7 +110,9 @@
     LOG(INFO) << "Parsing file " << path << "...";
     Timer t;
     std::string data;
-    if (!read_file(path, &data)) {
+    std::string err;
+    if (!ReadFile(path, &data, &err)) {
+        LOG(ERROR) << err;
         return false;
     }
 
diff --git a/init/init_parser_test.cpp b/init/init_parser_test.cpp
index d8fd2ba..86d60d0 100644
--- a/init/init_parser_test.cpp
+++ b/init/init_parser_test.cpp
@@ -86,19 +86,29 @@
         ASSERT_EQ("", svc->seclabel());
     }
     if (uid) {
-        ASSERT_EQ(decode_uid("log"), svc->uid());
+        uid_t decoded_uid;
+        std::string err;
+        ASSERT_TRUE(DecodeUid("log", &decoded_uid, &err));
+        ASSERT_EQ(decoded_uid, svc->uid());
     } else {
         ASSERT_EQ(0U, svc->uid());
     }
     if (gid) {
-        ASSERT_EQ(decode_uid("shell"), svc->gid());
+        uid_t decoded_uid;
+        std::string err;
+        ASSERT_TRUE(DecodeUid("shell", &decoded_uid, &err));
+        ASSERT_EQ(decoded_uid, svc->gid());
     } else {
         ASSERT_EQ(0U, svc->gid());
     }
     if (supplementary_gids) {
         ASSERT_EQ(2U, svc->supp_gids().size());
-        ASSERT_EQ(decode_uid("system"), svc->supp_gids()[0]);
-        ASSERT_EQ(decode_uid("adb"), svc->supp_gids()[1]);
+        uid_t decoded_uid;
+        std::string err;
+        ASSERT_TRUE(DecodeUid("system", &decoded_uid, &err));
+        ASSERT_EQ(decoded_uid, svc->supp_gids()[0]);
+        ASSERT_TRUE(DecodeUid("adb", &decoded_uid, &err));
+        ASSERT_EQ(decoded_uid, svc->supp_gids()[1]);
     } else {
         ASSERT_EQ(0U, svc->supp_gids().size());
     }
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 3da14b5..7093ba9 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -152,10 +152,11 @@
                                "on boot\n"
                                "execute 3";
     // clang-format on
-    // write_file() ensures the right mode is set
-    ASSERT_TRUE(write_file(std::string(dir.path) + "/a.rc", dir_a_script));
+    // WriteFile() ensures the right mode is set
+    std::string err;
+    ASSERT_TRUE(WriteFile(std::string(dir.path) + "/a.rc", dir_a_script, &err));
 
-    ASSERT_TRUE(write_file(std::string(dir.path) + "/b.rc", "on boot\nexecute 5"));
+    ASSERT_TRUE(WriteFile(std::string(dir.path) + "/b.rc", "on boot\nexecute 5", &err));
 
     // clang-format off
     std::string start_script = "import " + std::string(first_import.path) + "\n"
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 6f40d1c..18e47e3 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -177,7 +177,7 @@
     }
 
     if (name == "selinux.restorecon_recursive" && valuelen > 0) {
-        if (restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+        if (selinux_android_restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
             LOG(ERROR) << "Failed to restorecon_recursive " << value;
         }
     }
@@ -510,8 +510,9 @@
 static void load_properties_from_file(const char* filename, const char* filter) {
     Timer t;
     std::string data;
-    if (!read_file(filename, &data)) {
-        PLOG(WARNING) << "Couldn't load properties from " << filename;
+    std::string err;
+    if (!ReadFile(filename, &data, &err)) {
+        PLOG(WARNING) << "Couldn't load property file: " << err;
         return;
     }
     data.push_back('\n');
@@ -658,8 +659,8 @@
 void start_property_service() {
     property_set("ro.property_service.version", "2");
 
-    property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
-                                    0666, 0, 0, nullptr, sehandle);
+    property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+                                   false, 0666, 0, 0, nullptr, sehandle);
     if (property_set_fd == -1) {
         PLOG(ERROR) << "start_property_service socket creation failed";
         exit(1);
diff --git a/init/service.cpp b/init/service.cpp
index 881825f..7c931da 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -392,9 +392,18 @@
 }
 
 bool Service::ParseGroup(const std::vector<std::string>& args, std::string* err) {
-    gid_ = decode_uid(args[1].c_str());
+    std::string decode_uid_err;
+    if (!DecodeUid(args[1], &gid_, &decode_uid_err)) {
+        *err = "Unable to find GID for '" + args[1] + "': " + decode_uid_err;
+        return false;
+    }
     for (std::size_t n = 2; n < args.size(); n++) {
-        supp_gids_.emplace_back(decode_uid(args[n].c_str()));
+        gid_t gid;
+        if (!DecodeUid(args[n], &gid, &decode_uid_err)) {
+            *err = "Unable to find GID for '" + args[n] + "': " + decode_uid_err;
+            return false;
+        }
+        supp_gids_.emplace_back(gid);
     }
     return true;
 }
@@ -492,10 +501,25 @@
 template <typename T>
 bool Service::AddDescriptor(const std::vector<std::string>& args, std::string* err) {
     int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
-    uid_t uid = args.size() > 4 ? decode_uid(args[4].c_str()) : 0;
-    gid_t gid = args.size() > 5 ? decode_uid(args[5].c_str()) : 0;
+    uid_t uid = 0;
+    gid_t gid = 0;
     std::string context = args.size() > 6 ? args[6] : "";
 
+    std::string decode_uid_err;
+    if (args.size() > 4) {
+        if (!DecodeUid(args[4], &uid, &decode_uid_err)) {
+            *err = "Unable to find UID for '" + args[4] + "': " + decode_uid_err;
+            return false;
+        }
+    }
+
+    if (args.size() > 5) {
+        if (!DecodeUid(args[5], &gid, &decode_uid_err)) {
+            *err = "Unable to find GID for '" + args[5] + "': " + decode_uid_err;
+            return false;
+        }
+    }
+
     auto descriptor = std::make_unique<T>(args[1], args[2], uid, gid, perm, context);
 
     auto old =
@@ -513,7 +537,9 @@
 
 // name type perm [ uid gid context ]
 bool Service::ParseSocket(const std::vector<std::string>& args, std::string* err) {
-    if (args[2] != "dgram" && args[2] != "stream" && args[2] != "seqpacket") {
+    if (!android::base::StartsWith(args[2], "dgram") &&
+        !android::base::StartsWith(args[2], "stream") &&
+        !android::base::StartsWith(args[2], "seqpacket")) {
         *err = "socket type must be 'dgram', 'stream' or 'seqpacket'";
         return false;
     }
@@ -534,7 +560,11 @@
 }
 
 bool Service::ParseUser(const std::vector<std::string>& args, std::string* err) {
-    uid_ = decode_uid(args[1].c_str());
+    std::string decode_uid_err;
+    if (!DecodeUid(args[1], &uid_, &decode_uid_err)) {
+        *err = "Unable to find UID for '" + args[1] + "': " + decode_uid_err;
+        return false;
+    }
     return true;
 }
 
@@ -949,15 +979,28 @@
     }
     uid_t uid = 0;
     if (command_arg > 3) {
-        uid = decode_uid(args[2].c_str());
+        std::string decode_uid_err;
+        if (!DecodeUid(args[2], &uid, &decode_uid_err)) {
+            LOG(ERROR) << "Unable to find UID for '" << args[2] << "': " << decode_uid_err;
+            return nullptr;
+        }
     }
     gid_t gid = 0;
     std::vector<gid_t> supp_gids;
     if (command_arg > 4) {
-        gid = decode_uid(args[3].c_str());
+        std::string decode_uid_err;
+        if (!DecodeUid(args[3], &gid, &decode_uid_err)) {
+            LOG(ERROR) << "Unable to find GID for '" << args[3] << "': " << decode_uid_err;
+            return nullptr;
+        }
         std::size_t nr_supp_gids = command_arg - 1 /* -- */ - 4 /* exec SECLABEL UID GID */;
         for (size_t i = 0; i < nr_supp_gids; ++i) {
-            supp_gids.push_back(decode_uid(args[4 + i].c_str()));
+            gid_t supp_gid;
+            if (!DecodeUid(args[4 + i], &supp_gid, &decode_uid_err)) {
+                LOG(ERROR) << "Unable to find UID for '" << args[4 + i] << "': " << decode_uid_err;
+                return nullptr;
+            }
+            supp_gids.push_back(supp_gid);
         }
     }
 
diff --git a/init/util.cpp b/init/util.cpp
index 87b8d9d..75f81b9 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -48,49 +48,43 @@
 #endif
 
 using android::base::boot_clock;
+using namespace std::literals::string_literals;
 
-static unsigned int do_decode_uid(const char *s)
-{
-    unsigned int v;
+// DecodeUid() - decodes and returns the given string, which can be either the
+// numeric or name representation, into the integer uid or gid. Returns
+// UINT_MAX on error.
+bool DecodeUid(const std::string& name, uid_t* uid, std::string* err) {
+    *uid = UINT_MAX;
+    *err = "";
 
-    if (!s || *s == '\0')
-        return UINT_MAX;
-
-    if (isalpha(s[0])) {
-        struct passwd* pwd = getpwnam(s);
-        if (!pwd)
-            return UINT_MAX;
-        return pwd->pw_uid;
+    if (isalpha(name[0])) {
+        passwd* pwd = getpwnam(name.c_str());
+        if (!pwd) {
+            *err = "getpwnam failed: "s + strerror(errno);
+            return false;
+        }
+        *uid = pwd->pw_uid;
+        return true;
     }
 
     errno = 0;
-    v = (unsigned int) strtoul(s, 0, 0);
-    if (errno)
-        return UINT_MAX;
-    return v;
-}
-
-/*
- * decode_uid - decodes and returns the given string, which can be either the
- * numeric or name representation, into the integer uid or gid. Returns
- * UINT_MAX on error.
- */
-unsigned int decode_uid(const char *s) {
-    unsigned int v = do_decode_uid(s);
-    if (v == UINT_MAX) {
-        LOG(ERROR) << "decode_uid: Unable to find UID for '" << s << "'; returning UINT_MAX";
+    uid_t result = static_cast<uid_t>(strtoul(name.c_str(), 0, 0));
+    if (errno) {
+        *err = "strtoul failed: "s + strerror(errno);
+        return false;
     }
-    return v;
+    *uid = result;
+    return true;
 }
 
 /*
- * create_socket - creates a Unix domain socket in ANDROID_SOCKET_DIR
+ * CreateSocket - creates a Unix domain socket in ANDROID_SOCKET_DIR
  * ("/dev/socket") as dictated in init.rc. This socket is inherited by the
  * daemon. We communicate the file descriptor's value via the environment
  * variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
  */
-int create_socket(const char* name, int type, mode_t perm, uid_t uid, gid_t gid,
-                  const char* socketcon, selabel_handle* sehandle) {
+int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
+                 const char* socketcon, selabel_handle* sehandle) {
     if (socketcon) {
         if (setsockcreatecon(socketcon) == -1) {
             PLOG(ERROR) << "setsockcreatecon(\"" << socketcon << "\") failed";
@@ -124,6 +118,14 @@
         }
     }
 
+    if (passcred) {
+        int on = 1;
+        if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
+            PLOG(ERROR) << "Failed to set SO_PASSCRED '" << name << "'";
+            return -1;
+        }
+    }
+
     int ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
     int savederrno = errno;
 
@@ -157,12 +159,14 @@
     return -1;
 }
 
-bool read_file(const std::string& path, std::string* content) {
+bool ReadFile(const std::string& path, std::string* content, std::string* err) {
     content->clear();
+    *err = "";
 
     android::base::unique_fd fd(
         TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
     if (fd == -1) {
+        *err = "Unable to open '" + path + "': " + strerror(errno);
         return false;
     }
 
@@ -170,29 +174,35 @@
     // or group-writable files.
     struct stat sb;
     if (fstat(fd, &sb) == -1) {
-        PLOG(ERROR) << "fstat failed for '" << path << "'";
+        *err = "fstat failed for '" + path + "': " + strerror(errno);
         return false;
     }
     if ((sb.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
-        LOG(ERROR) << "skipping insecure file '" << path << "'";
+        *err = "Skipping insecure file '" + path + "'";
         return false;
     }
 
-    return android::base::ReadFdToString(fd, content);
+    if (!android::base::ReadFdToString(fd, content)) {
+        *err = "Unable to read '" + path + "': " + strerror(errno);
+        return false;
+    }
+    return true;
 }
 
-bool write_file(const std::string& path, const std::string& content) {
+bool WriteFile(const std::string& path, const std::string& content, std::string* err) {
+    *err = "";
+
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(
         open(path.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0600)));
     if (fd == -1) {
-        PLOG(ERROR) << "write_file: Unable to open '" << path << "'";
+        *err = "Unable to open '" + path + "': " + strerror(errno);
         return false;
     }
-    bool success = android::base::WriteStringToFd(content, fd);
-    if (!success) {
-        PLOG(ERROR) << "write_file: Unable to write to '" << path << "'";
+    if (!android::base::WriteStringToFd(content, fd)) {
+        *err = "Unable to write to '" + path + "': " + strerror(errno);
+        return false;
     }
-    return success;
+    return true;
 }
 
 int mkdir_recursive(const std::string& path, mode_t mode, selabel_handle* sehandle) {
@@ -256,11 +266,6 @@
     return rc;
 }
 
-int restorecon(const char* pathname, int flags)
-{
-    return selinux_android_restorecon(pathname, flags);
-}
-
 /*
  * Writes hex_len hex characters (1/2 byte) to hex from bytes.
  */
diff --git a/init/util.h b/init/util.h
index 55ebded..1ad6b77 100644
--- a/init/util.h
+++ b/init/util.h
@@ -35,11 +35,11 @@
 using android::base::boot_clock;
 using namespace std::chrono_literals;
 
-int create_socket(const char* name, int type, mode_t perm, uid_t uid, gid_t gid,
-                  const char* socketcon, selabel_handle* sehandle);
+int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
+                 const char* socketcon, selabel_handle* sehandle);
 
-bool read_file(const std::string& path, std::string* content);
-bool write_file(const std::string& path, const std::string& content);
+bool ReadFile(const std::string& path, std::string* content, std::string* err);
+bool WriteFile(const std::string& path, const std::string& content, std::string* err);
 
 class Timer {
   public:
@@ -61,14 +61,13 @@
 
 std::ostream& operator<<(std::ostream& os, const Timer& t);
 
-unsigned int decode_uid(const char *s);
+bool DecodeUid(const std::string& name, uid_t* uid, std::string* err);
 
 int mkdir_recursive(const std::string& pathname, mode_t mode, selabel_handle* sehandle);
 int wait_for_file(const char *filename, std::chrono::nanoseconds timeout);
 void import_kernel_cmdline(bool in_qemu,
                            const std::function<void(const std::string&, const std::string&, bool)>&);
 int make_dir(const char* path, mode_t mode, selabel_handle* sehandle);
-int restorecon(const char *pathname, int flags = 0);
 std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len);
 bool is_dir(const char* pathname);
 bool expand_props(const std::string& src, std::string* dst);
diff --git a/init/util_test.cpp b/init/util_test.cpp
index ac23a32..4bb8a83 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -24,53 +24,67 @@
 #include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
-TEST(util, read_file_ENOENT) {
-  std::string s("hello");
-  errno = 0;
-  EXPECT_FALSE(read_file("/proc/does-not-exist", &s));
-  EXPECT_EQ(ENOENT, errno);
-  EXPECT_EQ("", s); // s was cleared.
+using namespace std::literals::string_literals;
+
+TEST(util, ReadFile_ENOENT) {
+    std::string s("hello");
+    std::string err;
+    errno = 0;
+    EXPECT_FALSE(ReadFile("/proc/does-not-exist", &s, &err));
+    EXPECT_EQ("Unable to open '/proc/does-not-exist': No such file or directory", err);
+    EXPECT_EQ(ENOENT, errno);
+    EXPECT_EQ("", s);  // s was cleared.
 }
 
-TEST(util, read_file_group_writeable) {
+TEST(util, ReadFileGroupWriteable) {
     std::string s("hello");
     TemporaryFile tf;
+    std::string err;
     ASSERT_TRUE(tf.fd != -1);
-    EXPECT_TRUE(write_file(tf.path, s)) << strerror(errno);
+    EXPECT_TRUE(WriteFile(tf.path, s, &err)) << strerror(errno);
+    EXPECT_EQ("", err);
     EXPECT_NE(-1, fchmodat(AT_FDCWD, tf.path, 0620, AT_SYMLINK_NOFOLLOW)) << strerror(errno);
-    EXPECT_FALSE(read_file(tf.path, &s)) << strerror(errno);
+    EXPECT_FALSE(ReadFile(tf.path, &s, &err)) << strerror(errno);
+    EXPECT_EQ("Skipping insecure file '"s + tf.path + "'", err);
     EXPECT_EQ("", s);  // s was cleared.
 }
 
-TEST(util, read_file_world_writeable) {
+TEST(util, ReadFileWorldWiteable) {
     std::string s("hello");
     TemporaryFile tf;
+    std::string err;
     ASSERT_TRUE(tf.fd != -1);
-    EXPECT_TRUE(write_file(tf.path, s.c_str())) << strerror(errno);
+    EXPECT_TRUE(WriteFile(tf.path, s, &err)) << strerror(errno);
+    EXPECT_EQ("", err);
     EXPECT_NE(-1, fchmodat(AT_FDCWD, tf.path, 0602, AT_SYMLINK_NOFOLLOW)) << strerror(errno);
-    EXPECT_FALSE(read_file(tf.path, &s)) << strerror(errno);
+    EXPECT_FALSE(ReadFile(tf.path, &s, &err)) << strerror(errno);
+    EXPECT_EQ("Skipping insecure file '"s + tf.path + "'", err);
     EXPECT_EQ("", s);  // s was cleared.
 }
 
-TEST(util, read_file_symbolic_link) {
+TEST(util, ReadFileSymbolicLink) {
     std::string s("hello");
     errno = 0;
     // lrwxrwxrwx 1 root root 13 1970-01-01 00:00 charger -> /sbin/healthd
-    EXPECT_FALSE(read_file("/charger", &s));
+    std::string err;
+    EXPECT_FALSE(ReadFile("/charger", &s, &err));
+    EXPECT_EQ("Unable to open '/charger': Too many symbolic links encountered", err);
     EXPECT_EQ(ELOOP, errno);
     EXPECT_EQ("", s);  // s was cleared.
 }
 
-TEST(util, read_file_success) {
-  std::string s("hello");
-  EXPECT_TRUE(read_file("/proc/version", &s));
-  EXPECT_GT(s.length(), 6U);
-  EXPECT_EQ('\n', s[s.length() - 1]);
-  s[5] = 0;
-  EXPECT_STREQ("Linux", s.c_str());
+TEST(util, ReadFileSuccess) {
+    std::string s("hello");
+    std::string err;
+    EXPECT_TRUE(ReadFile("/proc/version", &s, &err));
+    EXPECT_EQ("", err);
+    EXPECT_GT(s.length(), 6U);
+    EXPECT_EQ('\n', s[s.length() - 1]);
+    s[5] = 0;
+    EXPECT_STREQ("Linux", s.c_str());
 }
 
-TEST(util, write_file_binary) {
+TEST(util, WriteFileBinary) {
     std::string contents("abcd");
     contents.push_back('\0');
     contents.push_back('\0');
@@ -78,22 +92,28 @@
     ASSERT_EQ(10u, contents.size());
 
     TemporaryFile tf;
+    std::string err;
     ASSERT_TRUE(tf.fd != -1);
-    EXPECT_TRUE(write_file(tf.path, contents)) << strerror(errno);
+    EXPECT_TRUE(WriteFile(tf.path, contents, &err)) << strerror(errno);
+    EXPECT_EQ("", err);
 
     std::string read_back_contents;
-    EXPECT_TRUE(read_file(tf.path, &read_back_contents)) << strerror(errno);
+    EXPECT_TRUE(ReadFile(tf.path, &read_back_contents, &err)) << strerror(errno);
+    EXPECT_EQ("", err);
     EXPECT_EQ(contents, read_back_contents);
     EXPECT_EQ(10u, read_back_contents.size());
 }
 
-TEST(util, write_file_not_exist) {
+TEST(util, WriteFileNotExist) {
     std::string s("hello");
     std::string s2("hello");
     TemporaryDir test_dir;
     std::string path = android::base::StringPrintf("%s/does-not-exist", test_dir.path);
-    EXPECT_TRUE(write_file(path, s));
-    EXPECT_TRUE(read_file(path, &s2));
+    std::string err;
+    EXPECT_TRUE(WriteFile(path, s, &err));
+    EXPECT_EQ("", err);
+    EXPECT_TRUE(ReadFile(path, &s2, &err));
+    EXPECT_EQ("", err);
     EXPECT_EQ(s, s2);
     struct stat sb;
     int fd = open(path.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
@@ -103,22 +123,38 @@
     EXPECT_EQ(0, unlink(path.c_str()));
 }
 
-TEST(util, write_file_exist) {
+TEST(util, WriteFileExist) {
     std::string s2("");
     TemporaryFile tf;
     ASSERT_TRUE(tf.fd != -1);
-    EXPECT_TRUE(write_file(tf.path, "1hello1")) << strerror(errno);
-    EXPECT_TRUE(read_file(tf.path, &s2));
+    std::string err;
+    EXPECT_TRUE(WriteFile(tf.path, "1hello1", &err)) << strerror(errno);
+    EXPECT_EQ("", err);
+    EXPECT_TRUE(ReadFile(tf.path, &s2, &err));
+    EXPECT_EQ("", err);
     EXPECT_STREQ("1hello1", s2.c_str());
-    EXPECT_TRUE(write_file(tf.path, "2ll2"));
-    EXPECT_TRUE(read_file(tf.path, &s2));
+    EXPECT_TRUE(WriteFile(tf.path, "2ll2", &err));
+    EXPECT_EQ("", err);
+    EXPECT_TRUE(ReadFile(tf.path, &s2, &err));
+    EXPECT_EQ("", err);
     EXPECT_STREQ("2ll2", s2.c_str());
 }
 
-TEST(util, decode_uid) {
-  EXPECT_EQ(0U, decode_uid("root"));
-  EXPECT_EQ(UINT_MAX, decode_uid("toot"));
-  EXPECT_EQ(123U, decode_uid("123"));
+TEST(util, DecodeUid) {
+    uid_t decoded_uid;
+    std::string err;
+
+    EXPECT_TRUE(DecodeUid("root", &decoded_uid, &err));
+    EXPECT_EQ("", err);
+    EXPECT_EQ(0U, decoded_uid);
+
+    EXPECT_FALSE(DecodeUid("toot", &decoded_uid, &err));
+    EXPECT_EQ("getpwnam failed: No such file or directory", err);
+    EXPECT_EQ(UINT_MAX, decoded_uid);
+
+    EXPECT_TRUE(DecodeUid("123", &decoded_uid, &err));
+    EXPECT_EQ("", err);
+    EXPECT_EQ(123U, decoded_uid);
 }
 
 TEST(util, is_dir) {
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 285aa6e..7dd9227 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -110,7 +110,7 @@
                 "libunwind",
             ],
 
-            static_libs: ["libcutils"],
+            static_libs: ["libasync_safe", "libcutils"],
         },
     },
 }
diff --git a/libbacktrace/BacktraceAsyncSafeLog.h b/libbacktrace/BacktraceAsyncSafeLog.h
new file mode 100644
index 0000000..14f51be
--- /dev/null
+++ b/libbacktrace/BacktraceAsyncSafeLog.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBBACKTRACE_BACKTRACE_ASYNC_SAFE_LOG_H
+#define _LIBBACKTRACE_BACKTRACE_ASYNC_SAFE_LOG_H
+
+#if defined(__ANDROID__)
+
+#include <async_safe/log.h>
+
+// Logging macros for use in signal handler, only available on target.
+#define BACK_ASYNC_SAFE_LOGW(format, ...)                                                     \
+  async_safe_format_log(ANDROID_LOG_WARN, "libbacktrace", "%s: " format, __PRETTY_FUNCTION__, \
+                        ##__VA_ARGS__)
+
+#define BACK_ASYNC_SAFE_LOGE(format, ...)                                                      \
+  async_safe_format_log(ANDROID_LOG_ERROR, "libbacktrace", "%s: " format, __PRETTY_FUNCTION__, \
+                        ##__VA_ARGS__)
+
+#else
+
+#define BACK_ASYNC_SAFE_LOGW(format, ...)
+
+#define BACK_ASYNC_SAFE_LOGE(format, ...)
+
+#endif
+
+#endif  // _LIBBACKTRACE_BACKTRACE_ASYNC_SAFE_LOG_H
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index d7a3b01..fb76b85 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -31,8 +31,8 @@
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
+#include "BacktraceAsyncSafeLog.h"
 #include "BacktraceCurrent.h"
-#include "BacktraceLog.h"
 #include "ThreadEntry.h"
 #include "thread_utils.h"
 
@@ -47,7 +47,7 @@
     *out_value = *reinterpret_cast<word_t*>(ptr);
     return true;
   } else {
-    BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
+    BACK_ASYNC_SAFE_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
     *out_value = static_cast<word_t>(-1);
     return false;
   }
@@ -114,7 +114,8 @@
 static void SignalLogOnly(int, siginfo_t*, void*) {
   ErrnoRestorer restore;
 
-  BACK_LOGE("pid %d, tid %d: Received a spurious signal %d\n", getpid(), gettid(), THREAD_SIGNAL);
+  BACK_ASYNC_SAFE_LOGE("pid %d, tid %d: Received a spurious signal %d\n", getpid(), gettid(),
+                       THREAD_SIGNAL);
 }
 
 static void SignalHandler(int, siginfo_t*, void* sigcontext) {
@@ -122,7 +123,7 @@
 
   ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false);
   if (!entry) {
-    BACK_LOGE("pid %d, tid %d entry not found", getpid(), gettid());
+    BACK_ASYNC_SAFE_LOGE("pid %d, tid %d entry not found", getpid(), gettid());
     return;
   }
 
@@ -141,7 +142,7 @@
     entry->Wake();
   } else {
     // At this point, it is possible that entry has been freed, so just exit.
-    BACK_LOGE("Timed out waiting for unwind thread to indicate it completed.");
+    BACK_ASYNC_SAFE_LOGE("Timed out waiting for unwind thread to indicate it completed.");
   }
 }
 
@@ -159,7 +160,7 @@
   act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
   sigemptyset(&act.sa_mask);
   if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) {
-    BACK_LOGE("sigaction failed: %s", strerror(errno));
+    BACK_ASYNC_SAFE_LOGE("sigaction failed: %s", strerror(errno));
     ThreadEntry::Remove(entry);
     pthread_mutex_unlock(&g_sigaction_mutex);
     error_ = BACKTRACE_UNWIND_ERROR_INTERNAL;
@@ -212,7 +213,7 @@
     // Wait for the thread to indicate it is done with the ThreadEntry.
     if (!entry->Wait(3)) {
       // Send a warning, but do not mark as a failure to unwind.
-      BACK_LOGW("Timed out waiting for signal handler to indicate it finished.");
+      BACK_ASYNC_SAFE_LOGW("Timed out waiting for signal handler to indicate it finished.");
     }
   } else {
     // Check to see if the thread has disappeared.
@@ -220,7 +221,7 @@
       error_ = BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST;
     } else {
       error_ = BACKTRACE_UNWIND_ERROR_THREAD_TIMEOUT;
-      BACK_LOGE("Timed out waiting for signal handler to get ucontext data.");
+      BACK_ASYNC_SAFE_LOGE("Timed out waiting for signal handler to get ucontext data.");
     }
   }
 
diff --git a/libbacktrace/ThreadEntry.cpp b/libbacktrace/ThreadEntry.cpp
index 084c1aa..9bd59e4 100644
--- a/libbacktrace/ThreadEntry.cpp
+++ b/libbacktrace/ThreadEntry.cpp
@@ -21,7 +21,7 @@
 #include <time.h>
 #include <ucontext.h>
 
-#include "BacktraceLog.h"
+#include "BacktraceAsyncSafeLog.h"
 #include "ThreadEntry.h"
 
 // Initialize static member variables.
@@ -106,7 +106,7 @@
   while (wait_value_ != value) {
     int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts);
     if (ret != 0) {
-      BACK_LOGW("pthread_cond_timedwait for value %d failed: %s", value, strerror(ret));
+      BACK_ASYNC_SAFE_LOGW("pthread_cond_timedwait for value %d failed: %s", value, strerror(ret));
       wait_completed = false;
       break;
     }
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index a2dd677..2b3443f 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -92,6 +92,9 @@
     { 00755, AID_ROOT,         AID_ROOT,         0, 0 },
     // clang-format on
 };
+#ifndef __ANDROID_VNDK__
+auto __for_testing_only__android_dirs = android_dirs;
+#endif
 
 // Rules for files.
 // These rules are applied based on "first match", so they
@@ -238,6 +241,9 @@
     { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
     // clang-format on
 };
+#ifndef __ANDROID_VNDK__
+auto __for_testing_only__android_files = android_files;
+#endif
 
 static size_t strip(const char* path, size_t len, const char suffix[]) {
     if (len < strlen(suffix)) return len;
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index bbba853..fdead23 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -53,7 +53,7 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
 
-#if defined(__ANDROID__)
+#if defined(__BIONIC__)
 #include <linux/capability.h>
 #else
 #include "android_filesystem_capability.h"
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index a0b1d7b..7884190 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -27,7 +27,8 @@
                 "test_str_parms.cpp",
                 "android_get_control_socket_test.cpp",
                 "android_get_control_file_test.cpp",
-                "multiuser_test.cpp"
+                "multiuser_test.cpp",
+                "fs_config.cpp",
             ],
         },
 
diff --git a/libcutils/tests/AshmemTest.cpp b/libcutils/tests/AshmemTest.cpp
index 51c679f..a87e23e 100644
--- a/libcutils/tests/AshmemTest.cpp
+++ b/libcutils/tests/AshmemTest.cpp
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-#include <sys/mman.h>
+#include <android-base/unique_fd.h>
 #include <cutils/ashmem.h>
 #include <gtest/gtest.h>
-#include <android-base/unique_fd.h>
+#include <linux/fs.h>
+#include <sys/mman.h>
 
 using android::base::unique_fd;
 
@@ -29,8 +30,8 @@
     ASSERT_EQ(0, ashmem_set_prot_region(fd, prot));
 }
 
-void TestMmap(const unique_fd &fd, size_t size, int prot, void **region) {
-    *region = mmap(nullptr, size, prot, MAP_SHARED, fd, 0);
+void TestMmap(const unique_fd& fd, size_t size, int prot, void** region, off_t off = 0) {
+    *region = mmap(nullptr, size, prot, MAP_SHARED, fd, off);
     ASSERT_NE(MAP_FAILED, *region);
 }
 
@@ -38,6 +39,10 @@
     EXPECT_EQ(MAP_FAILED, mmap(nullptr, size, prot, MAP_SHARED, fd, 0));
 }
 
+void TestProtIs(const unique_fd& fd, int prot) {
+    EXPECT_EQ(prot, ioctl(fd, ASHMEM_GET_PROT_MASK));
+}
+
 void FillData(uint8_t* data, size_t dataLen) {
     for (size_t i = 0; i < dataLen; i++) {
         data[i] = i & 0xFF;
@@ -101,6 +106,63 @@
     EXPECT_EQ(0, munmap(region2, size));
 }
 
+TEST(AshmemTest, FileOperationsTest) {
+    unique_fd fd;
+    void* region;
+
+    // Allocate a 4-page buffer, but leave page-sized holes on either side
+    constexpr size_t size = PAGE_SIZE * 4;
+    constexpr size_t dataSize = PAGE_SIZE * 2;
+    constexpr size_t holeSize = PAGE_SIZE;
+    ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
+    ASSERT_NO_FATAL_FAILURE(TestMmap(fd, dataSize, PROT_READ | PROT_WRITE, &region, holeSize));
+
+    uint8_t data[dataSize];
+    FillData(data, dataSize);
+    memcpy(region, data, dataSize);
+
+    constexpr off_t dataStart = holeSize;
+    constexpr off_t dataEnd = dataStart + dataSize;
+
+    // The sequence of seeks below looks something like this:
+    //
+    // [    ][data][data][    ]
+    // --^                          lseek(99, SEEK_SET)
+    //   ------^                    lseek(dataStart, SEEK_CUR)
+    // ------^                      lseek(0, SEEK_DATA)
+    //       ------------^          lseek(dataStart, SEEK_HOLE)
+    //                      ^--     lseek(-99, SEEK_END)
+    //                ^------       lseek(-dataStart, SEEK_CUR)
+    const struct {
+        // lseek() parameters
+        off_t offset;
+        int whence;
+        // Expected lseek() return value
+        off_t ret;
+    } seeks[] = {
+        {99, SEEK_SET, 99},         {dataStart, SEEK_CUR, dataStart + 99},
+        {0, SEEK_DATA, dataStart},  {dataStart, SEEK_HOLE, dataEnd},
+        {-99, SEEK_END, size - 99}, {-dataStart, SEEK_CUR, dataEnd - 99},
+    };
+    for (const auto& cfg : seeks) {
+        errno = 0;
+        auto off = lseek(fd, cfg.offset, cfg.whence);
+        ASSERT_EQ(cfg.ret, off) << "lseek(" << cfg.offset << ", " << cfg.whence << ") failed"
+                                << (errno ? ": " : "") << (errno ? strerror(errno) : "");
+
+        if (off >= dataStart && off < dataEnd) {
+            off_t dataOff = off - dataStart;
+            ssize_t readSize = dataSize - dataOff;
+            uint8_t buf[readSize];
+
+            ASSERT_EQ(readSize, TEMP_FAILURE_RETRY(read(fd, buf, readSize)));
+            EXPECT_EQ(0, memcmp(buf, data + dataOff, readSize));
+        }
+    }
+
+    EXPECT_EQ(0, munmap(region, dataSize));
+}
+
 TEST(AshmemTest, ProtTest) {
     unique_fd fd;
     constexpr size_t size = PAGE_SIZE;
@@ -108,13 +170,25 @@
 
     ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ));
     TestProtDenied(fd, size, PROT_WRITE);
+    TestProtIs(fd, PROT_READ);
     ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ, &region));
     EXPECT_EQ(0, munmap(region, size));
 
     ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_WRITE));
     TestProtDenied(fd, size, PROT_READ);
+    TestProtIs(fd, PROT_WRITE);
     ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_WRITE, &region));
     EXPECT_EQ(0, munmap(region, size));
+
+    ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
+    TestProtIs(fd, PROT_READ | PROT_WRITE);
+    ASSERT_EQ(0, ashmem_set_prot_region(fd, PROT_READ));
+    errno = 0;
+    ASSERT_EQ(-1, ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE))
+        << "kernel shouldn't allow adding protection bits";
+    EXPECT_EQ(EINVAL, errno);
+    TestProtIs(fd, PROT_READ);
+    TestProtDenied(fd, size, PROT_WRITE);
 }
 
 TEST(AshmemTest, ForkProtTest) {
diff --git a/libcutils/tests/fs_config.cpp b/libcutils/tests/fs_config.cpp
new file mode 100644
index 0000000..3917a0b
--- /dev/null
+++ b/libcutils/tests/fs_config.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 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 <string>
+
+#include <gtest/gtest.h>
+
+#include <android-base/strings.h>
+
+#include <private/android_filesystem_config.h>
+
+extern const struct fs_path_config* __for_testing_only__android_dirs;
+extern const struct fs_path_config* __for_testing_only__android_files;
+
+static void check_one(const struct fs_path_config* paths, const std::string& prefix,
+                      const std::string& alternate) {
+    for (size_t idx = 0; paths[idx].prefix; ++idx) {
+        std::string path(paths[idx].prefix);
+        if (android::base::StartsWith(path, prefix.c_str())) {
+            path = alternate + path.substr(prefix.length());
+            size_t second;
+            for (second = 0; paths[second].prefix; ++second) {
+                if (path == paths[second].prefix) break;
+            }
+            if (!paths[second].prefix) {
+                // guaranteed to fail expectations, trigger test failure with
+                // a message that reports the violation as an inequality.
+                EXPECT_STREQ((prefix + path.substr(alternate.length())).c_str(), path.c_str());
+            }
+        }
+    }
+}
+
+static void check_two(const struct fs_path_config* paths, const std::string& prefix) {
+    ASSERT_FALSE(paths == nullptr);
+    std::string alternate = "system/" + prefix;
+    check_one(paths, prefix, alternate);
+    check_one(paths, alternate, prefix);
+}
+
+TEST(fs_config, vendor_dirs_alias) {
+    check_two(__for_testing_only__android_dirs, "vendor/");
+}
+
+TEST(fs_config, vendor_files_alias) {
+    check_two(__for_testing_only__android_files, "vendor/");
+}
+
+TEST(fs_config, oem_dirs_alias) {
+    check_two(__for_testing_only__android_dirs, "oem/");
+}
+
+TEST(fs_config, oem_files_alias) {
+    check_two(__for_testing_only__android_files, "oem/");
+}
+
+TEST(fs_config, odm_dirs_alias) {
+    check_two(__for_testing_only__android_dirs, "odm/");
+}
+
+TEST(fs_config, odm_files_alias) {
+    check_two(__for_testing_only__android_files, "odm/");
+}
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index ae7a334..1483c24 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -15,9 +15,7 @@
  */
 /*
  * Intercepts log messages intended for the Android log device.
- * When running in the context of the simulator, the messages are
- * passed on to the underlying (fake) log device.  When not in the
- * simulator, messages are printed to stderr.
+ * Messages are printed to stderr.
  */
 #include <ctype.h>
 #include <errno.h>
@@ -561,7 +559,8 @@
  *  tag (N bytes -- null-terminated ASCII string)
  *  message (N bytes -- null-terminated ASCII string)
  */
-static ssize_t logWritev(int fd, const struct iovec* vector, int count) {
+LIBLOG_HIDDEN ssize_t fakeLogWritev(int fd, const struct iovec* vector,
+                                    int count) {
   LogState* state;
 
   /* Make sure that no-one frees the LogState while we're using it.
@@ -626,8 +625,18 @@
 
 /*
  * Free up our state and close the fake descriptor.
+ *
+ * The logger API has no means or need to 'stop' or 'close' using the logs,
+ * and as such, there is no way for that 'stop' or 'close' to translate into
+ * a close operation to the fake log handler. fakeLogClose is provided for
+ * completeness only.
+ *
+ * We have no intention of adding a log close operation as it would complicate
+ * every user of the logging API with no gain since the only valid place to
+ * call is in the exit handler. Logging can continue in the exit handler to
+ * help debug HOST tools ...
  */
-static int logClose(int fd) {
+LIBLOG_HIDDEN int fakeLogClose(int fd) {
   deleteFakeFd(fd);
   return 0;
 }
@@ -635,7 +644,7 @@
 /*
  * Open a log output device and return a fake fd.
  */
-static int logOpen(const char* pathName, int flags __unused) {
+LIBLOG_HIDDEN int fakeLogOpen(const char* pathName) {
   LogState* logState;
   int fd = -1;
 
@@ -654,66 +663,6 @@
   return fd;
 }
 
-/*
- * Runtime redirection.  If this binary is running in the simulator,
- * just pass log messages to the emulated device.  If it's running
- * outside of the simulator, write the log messages to stderr.
- */
-
-static int (*redirectOpen)(const char* pathName, int flags) = NULL;
-static int (*redirectClose)(int fd) = NULL;
-static ssize_t (*redirectWritev)(int fd, const struct iovec* vector,
-                                 int count) = NULL;
-
-static void setRedirects() {
-  const char* ws;
-
-  /* Wrapsim sets this environment variable on children that it's
-   * created using its LD_PRELOAD wrapper.
-   */
-  ws = getenv("ANDROID_WRAPSIM");
-  if (ws != NULL && strcmp(ws, "1") == 0) {
-    /* We're running inside wrapsim, so we can just write to the device. */
-    redirectOpen = (int (*)(const char* pathName, int flags))open;
-    redirectClose = close;
-    redirectWritev = writev;
-  } else {
-    /* There's no device to delegate to; handle the logging ourselves. */
-    redirectOpen = logOpen;
-    redirectClose = logClose;
-    redirectWritev = logWritev;
-  }
-}
-
-LIBLOG_HIDDEN int fakeLogOpen(const char* pathName, int flags) {
-  if (redirectOpen == NULL) {
-    setRedirects();
-  }
-  return redirectOpen(pathName, flags);
-}
-
-/*
- * The logger API has no means or need to 'stop' or 'close' using the logs,
- * and as such, there is no way for that 'stop' or 'close' to translate into
- * a close operation to the fake log handler. fakeLogClose is provided for
- * completeness only.
- *
- * We have no intention of adding a log close operation as it would complicate
- * every user of the logging API with no gain since the only valid place to
- * call is in the exit handler. Logging can continue in the exit handler to
- * help debug HOST tools ...
- */
-LIBLOG_HIDDEN int fakeLogClose(int fd) {
-  /* Assume that open() was called first. */
-  return redirectClose(fd);
-}
-
-LIBLOG_HIDDEN ssize_t fakeLogWritev(int fd, const struct iovec* vector,
-                                    int count) {
-  /* Assume that open() was called first. */
-  return redirectWritev(fd, vector, count);
-}
-
 LIBLOG_HIDDEN ssize_t __send_log_msg(char* buf __unused,
                                      size_t buf_size __unused) {
   return -ENODEV;
diff --git a/liblog/fake_log_device.h b/liblog/fake_log_device.h
index 462d026..7b0e745 100644
--- a/liblog/fake_log_device.h
+++ b/liblog/fake_log_device.h
@@ -23,7 +23,7 @@
 
 struct iovec;
 
-LIBLOG_HIDDEN int fakeLogOpen(const char* pathName, int flags);
+LIBLOG_HIDDEN int fakeLogOpen(const char* pathName);
 LIBLOG_HIDDEN int fakeLogClose(int fd);
 LIBLOG_HIDDEN ssize_t fakeLogWritev(int fd, const struct iovec* vector,
                                     int count);
diff --git a/liblog/fake_writer.c b/liblog/fake_writer.c
index 969661a..403dc72 100644
--- a/liblog/fake_writer.c
+++ b/liblog/fake_writer.c
@@ -55,9 +55,9 @@
       continue;
     }
     snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
-    logFds[i] = fakeLogOpen(buf, O_WRONLY);
+    logFds[i] = fakeLogOpen(buf);
     if (logFds[i] < 0) {
-      fprintf(stderr, "fakeLogOpen(%s, O_WRONLY) failed\n", buf);
+      fprintf(stderr, "fakeLogOpen(%s) failed\n", buf);
     }
   }
   return 0;
diff --git a/libmemunreachable/.clang-format b/libmemunreachable/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/libmemunreachable/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index 2867f64..cdac76b 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -9,8 +9,16 @@
     clang: true,
     shared_libs: [
         "libbase",
-        "liblog",
     ],
+
+    target: {
+        android: {
+            static_libs: ["libasync_safe"],
+        },
+        host: {
+            shared_libs: ["liblog"],
+        }
+    },
 }
 
 cc_library_shared {
diff --git a/libmemunreachable/HeapWalker.cpp b/libmemunreachable/HeapWalker.cpp
index 62366f2..c365ae5 100644
--- a/libmemunreachable/HeapWalker.cpp
+++ b/libmemunreachable/HeapWalker.cpp
@@ -42,11 +42,9 @@
   } else {
     Range overlap = inserted.first->first;
     if (overlap != range) {
-      ALOGE("range %p-%p overlaps with existing range %p-%p",
-          reinterpret_cast<void*>(begin),
-          reinterpret_cast<void*>(end),
-          reinterpret_cast<void*>(overlap.begin),
-          reinterpret_cast<void*>(overlap.end));
+      MEM_ALOGE("range %p-%p overlaps with existing range %p-%p", reinterpret_cast<void*>(begin),
+                reinterpret_cast<void*>(end), reinterpret_cast<void*>(overlap.begin),
+                reinterpret_cast<void*>(overlap.end));
     }
     return false;
   }
@@ -154,7 +152,7 @@
 
   void* ret = mmap(page, page_size, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0);
   if (ret == MAP_FAILED) {
-    ALOGE("failed to map page at %p: %s", page, strerror(errno));
+    MEM_ALOGE("failed to map page at %p: %s", page, strerror(errno));
     return false;
   }
 
@@ -167,7 +165,7 @@
     handler.reset();
     return;
   }
-  ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
+  MEM_ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
   if (!MapOverPage(si->si_addr)) {
     handler.reset();
   }
diff --git a/libmemunreachable/LeakPipe.cpp b/libmemunreachable/LeakPipe.cpp
index 080f8a7..78117e2 100644
--- a/libmemunreachable/LeakPipe.cpp
+++ b/libmemunreachable/LeakPipe.cpp
@@ -44,11 +44,11 @@
 
   int ret = sendmsg(sock, &hdr, 0);
   if (ret < 0) {
-    ALOGE("failed to send fd: %s", strerror(errno));
+    MEM_ALOGE("failed to send fd: %s", strerror(errno));
     return false;
   }
   if (ret == 0) {
-    ALOGE("eof when sending fd");
+    MEM_ALOGE("eof when sending fd");
     return false;
   }
 
@@ -71,17 +71,17 @@
 
   int ret = recvmsg(sock, &hdr, 0);
   if (ret < 0) {
-    ALOGE("failed to receive fd: %s", strerror(errno));
+    MEM_ALOGE("failed to receive fd: %s", strerror(errno));
     return -1;
   }
   if (ret == 0) {
-    ALOGE("eof when receiving fd");
+    MEM_ALOGE("eof when receiving fd");
     return -1;
   }
 
   struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
   if (cmsg == NULL || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
-    ALOGE("missing fd while receiving fd");
+    MEM_ALOGE("missing fd while receiving fd");
     return -1;
   }
 
diff --git a/libmemunreachable/LeakPipe.h b/libmemunreachable/LeakPipe.h
index 3f4e0b7..3ea2d8f 100644
--- a/libmemunreachable/LeakPipe.h
+++ b/libmemunreachable/LeakPipe.h
@@ -36,7 +36,7 @@
   LeakPipe() {
     int ret = socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sv_);
     if (ret < 0) {
-      LOG_ALWAYS_FATAL("failed to create socketpair: %s", strerror(errno));
+      MEM_LOG_ALWAYS_FATAL("failed to create socketpair: %s", strerror(errno));
     }
   }
 
@@ -105,10 +105,10 @@
     bool Send(const T& value) {
       ssize_t ret = TEMP_FAILURE_RETRY(write(fd_, &value, sizeof(T)));
       if (ret < 0) {
-        ALOGE("failed to send value: %s", strerror(errno));
+        MEM_ALOGE("failed to send value: %s", strerror(errno));
         return false;
       } else if (static_cast<size_t>(ret) != sizeof(T)) {
-        ALOGE("eof while writing value");
+        MEM_ALOGE("eof while writing value");
         return false;
       }
 
@@ -124,10 +124,10 @@
 
       ssize_t ret = TEMP_FAILURE_RETRY(write(fd_, vector.data(), size));
       if (ret < 0) {
-        ALOGE("failed to send vector: %s", strerror(errno));
+        MEM_ALOGE("failed to send vector: %s", strerror(errno));
         return false;
       } else if (static_cast<size_t>(ret) != size) {
-        ALOGE("eof while writing vector");
+        MEM_ALOGE("eof while writing vector");
         return false;
       }
 
@@ -143,10 +143,10 @@
     bool Receive(T* value) {
       ssize_t ret = TEMP_FAILURE_RETRY(read(fd_, reinterpret_cast<void*>(value), sizeof(T)));
       if (ret < 0) {
-        ALOGE("failed to receive value: %s", strerror(errno));
+        MEM_ALOGE("failed to receive value: %s", strerror(errno));
         return false;
       } else if (static_cast<size_t>(ret) != sizeof(T)) {
-        ALOGE("eof while receiving value");
+        MEM_ALOGE("eof while receiving value");
         return false;
       }
 
@@ -166,10 +166,10 @@
       while (size > 0) {
         ssize_t ret = TEMP_FAILURE_RETRY(read(fd_, ptr, size));
         if (ret < 0) {
-          ALOGE("failed to send vector: %s", strerror(errno));
+          MEM_ALOGE("failed to send vector: %s", strerror(errno));
           return false;
         } else if (ret == 0) {
-          ALOGE("eof while reading vector");
+          MEM_ALOGE("eof while reading vector");
           return false;
         }
         size -= ret;
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index ac19a66..e7c0beb 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -78,51 +78,49 @@
 
 bool MemUnreachable::CollectAllocations(const allocator::vector<ThreadInfo>& threads,
     const allocator::vector<Mapping>& mappings) {
-  ALOGI("searching process %d for allocations", pid_);
+  MEM_ALOGI("searching process %d for allocations", pid_);
   allocator::vector<Mapping> heap_mappings{mappings};
   allocator::vector<Mapping> anon_mappings{mappings};
   allocator::vector<Mapping> globals_mappings{mappings};
   allocator::vector<Mapping> stack_mappings{mappings};
-  if (!ClassifyMappings(mappings, heap_mappings, anon_mappings,
-      globals_mappings, stack_mappings)) {
+  if (!ClassifyMappings(mappings, heap_mappings, anon_mappings, globals_mappings, stack_mappings)) {
     return false;
   }
 
   for (auto it = heap_mappings.begin(); it != heap_mappings.end(); it++) {
-    ALOGV("Heap mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
-    HeapIterate(*it, [&](uintptr_t base, size_t size) {
-      heap_walker_.Allocation(base, base + size);
-    });
+    MEM_ALOGV("Heap mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
+    HeapIterate(*it,
+                [&](uintptr_t base, size_t size) { heap_walker_.Allocation(base, base + size); });
   }
 
   for (auto it = anon_mappings.begin(); it != anon_mappings.end(); it++) {
-    ALOGV("Anon mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
+    MEM_ALOGV("Anon mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
     heap_walker_.Allocation(it->begin, it->end);
   }
 
   for (auto it = globals_mappings.begin(); it != globals_mappings.end(); it++) {
-    ALOGV("Globals mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
+    MEM_ALOGV("Globals mapping %" PRIxPTR "-%" PRIxPTR " %s", it->begin, it->end, it->name);
     heap_walker_.Root(it->begin, it->end);
   }
 
   for (auto thread_it = threads.begin(); thread_it != threads.end(); thread_it++) {
     for (auto it = stack_mappings.begin(); it != stack_mappings.end(); it++) {
       if (thread_it->stack.first >= it->begin && thread_it->stack.first <= it->end) {
-        ALOGV("Stack %" PRIxPTR "-%" PRIxPTR " %s", thread_it->stack.first, it->end, it->name);
+        MEM_ALOGV("Stack %" PRIxPTR "-%" PRIxPTR " %s", thread_it->stack.first, it->end, it->name);
         heap_walker_.Root(thread_it->stack.first, it->end);
       }
     }
     heap_walker_.Root(thread_it->regs);
   }
 
-  ALOGI("searching done");
+  MEM_ALOGI("searching done");
 
   return true;
 }
 
 bool MemUnreachable::GetUnreachableMemory(allocator::vector<Leak>& leaks,
     size_t limit, size_t* num_leaks, size_t* leak_bytes) {
-  ALOGI("sweeping process %d for unreachable memory", pid_);
+  MEM_ALOGI("sweeping process %d for unreachable memory", pid_);
   leaks.clear();
 
   if (!heap_walker_.DetectLeaks()) {
@@ -133,9 +131,9 @@
   allocator::vector<Range> leaked1{allocator_};
   heap_walker_.Leaked(leaked1, 0, num_leaks, leak_bytes);
 
-  ALOGI("sweeping done");
+  MEM_ALOGI("sweeping done");
 
-  ALOGI("folding related leaks");
+  MEM_ALOGI("folding related leaks");
 
   LeakFolding folding(allocator_, heap_walker_);
   if (!folding.FoldLeaks()) {
@@ -188,7 +186,7 @@
         std::min(leak->size, Leak::contents_length));
   }
 
-  ALOGI("folding done");
+  MEM_ALOGI("folding done");
 
   std::sort(leaks.begin(), leaks.end(), [](const Leak& a, const Leak& b) {
     return a.total_size > b.total_size;
@@ -276,7 +274,7 @@
     /////////////////////////////////////////////
     // Collection thread
     /////////////////////////////////////////////
-    ALOGI("collecting thread info for process %d...", parent_pid);
+    MEM_ALOGI("collecting thread info for process %d...", parent_pid);
 
     ThreadCapture thread_capture(parent_pid, heap);
     allocator::vector<ThreadInfo> thread_info(heap);
@@ -351,7 +349,7 @@
     } else {
       // Nothing left to do in the collection thread, return immediately,
       // releasing all the captured threads.
-      ALOGI("collection thread done");
+      MEM_ALOGI("collection thread done");
       return 0;
     }
   }};
@@ -397,10 +395,10 @@
     return false;
   }
 
-  ALOGI("unreachable memory detection done");
-  ALOGE("%zu bytes in %zu allocation%s unreachable out of %zu bytes in %zu allocation%s",
-      info.leak_bytes, info.num_leaks, plural(info.num_leaks),
-      info.allocation_bytes, info.num_allocations, plural(info.num_allocations));
+  MEM_ALOGI("unreachable memory detection done");
+  MEM_ALOGE("%zu bytes in %zu allocation%s unreachable out of %zu bytes in %zu allocation%s",
+            info.leak_bytes, info.num_leaks, plural(info.num_leaks), info.allocation_bytes,
+            info.num_allocations, plural(info.num_allocations));
   return true;
 }
 
@@ -517,7 +515,7 @@
   }
 
   for (auto it = info.leaks.begin(); it != info.leaks.end(); it++) {
-    ALOGE("%s", it->ToString(log_contents).c_str());
+    MEM_ALOGE("%s", it->ToString(log_contents).c_str());
   }
   return true;
 }
diff --git a/libmemunreachable/PtracerThread.cpp b/libmemunreachable/PtracerThread.cpp
index 4e3c41e..73b0493 100644
--- a/libmemunreachable/PtracerThread.cpp
+++ b/libmemunreachable/PtracerThread.cpp
@@ -70,7 +70,7 @@
     child_pid_(0) {
   stack_ = std::make_unique<Stack>(PTHREAD_STACK_MIN);
   if (stack_->top() == nullptr) {
-    LOG_ALWAYS_FATAL("failed to mmap child stack: %s", strerror(errno));
+    MEM_LOG_ALWAYS_FATAL("failed to mmap child stack: %s", strerror(errno));
   }
 
   func_ = std::function<int()>{[&, func]() -> int {
@@ -102,7 +102,7 @@
        CLONE_VM|CLONE_FS|CLONE_FILES/*|CLONE_UNTRACED*/,
        reinterpret_cast<void*>(&func_));
   if (child_pid_ < 0) {
-    ALOGE("failed to clone child: %s", strerror(errno));
+    MEM_ALOGE("failed to clone child: %s", strerror(errno));
     return false;
   }
 
@@ -120,7 +120,7 @@
   int status;
   int ret = TEMP_FAILURE_RETRY(waitpid(child_pid_, &status, __WALL));
   if (ret < 0) {
-    ALOGE("waitpid %d failed: %s", child_pid_, strerror(errno));
+    MEM_ALOGE("waitpid %d failed: %s", child_pid_, strerror(errno));
     return -1;
   }
 
@@ -131,7 +131,7 @@
   } else if (WIFSIGNALED(status)) {
     return -WTERMSIG(status);
   } else {
-    ALOGE("unexpected status %x", status);
+    MEM_ALOGE("unexpected status %x", status);
     return -1;
   }
 }
diff --git a/libmemunreachable/ScopedPipe.h b/libmemunreachable/ScopedPipe.h
index 9beef9a..7f44953 100644
--- a/libmemunreachable/ScopedPipe.h
+++ b/libmemunreachable/ScopedPipe.h
@@ -26,7 +26,7 @@
   ScopedPipe() : pipefd_{-1, -1} {
     int ret = pipe2(pipefd_, O_CLOEXEC);
     if (ret < 0) {
-      LOG_ALWAYS_FATAL("failed to open pipe");
+      MEM_LOG_ALWAYS_FATAL("failed to open pipe");
     }
   }
   ~ScopedPipe() {
diff --git a/libmemunreachable/ScopedSignalHandler.h b/libmemunreachable/ScopedSignalHandler.h
index 1fd9d4d..ada2ae4 100644
--- a/libmemunreachable/ScopedSignalHandler.h
+++ b/libmemunreachable/ScopedSignalHandler.h
@@ -37,22 +37,18 @@
 
   template <class F>
   void install(int signal, F&& f) {
-    LOG_ALWAYS_FATAL_IF(signal_ != -1, "ScopedSignalHandler already installed");
+    MEM_LOG_ALWAYS_FATAL_IF(signal_ != -1, "ScopedSignalHandler already installed");
 
     handler_ = SignalFn(std::allocator_arg, allocator_,
-        [=](int signal, siginfo_t* si, void* uctx) {
-          f(*this, signal, si, uctx);
-        });
+                        [=](int signal, siginfo_t* si, void* uctx) { f(*this, signal, si, uctx); });
 
-    struct sigaction act{};
-    act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) {
-      handler_(signal, si, uctx);
-    };
+    struct sigaction act {};
+    act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) { handler_(signal, si, uctx); };
     act.sa_flags = SA_SIGINFO;
 
     int ret = sigaction(signal, &act, &old_act_);
     if (ret < 0) {
-      LOG_ALWAYS_FATAL("failed to install segfault handler: %s", strerror(errno));
+      MEM_LOG_ALWAYS_FATAL("failed to install segfault handler: %s", strerror(errno));
     }
 
     signal_ = signal;
@@ -62,7 +58,7 @@
     if (signal_ != -1) {
       int ret = sigaction(signal_, &old_act_, NULL);
       if (ret < 0) {
-        ALOGE("failed to uninstall segfault handler");
+        MEM_ALOGE("failed to uninstall segfault handler");
       }
       handler_ = SignalFn{};
       signal_ = -1;
diff --git a/libmemunreachable/ThreadCapture.cpp b/libmemunreachable/ThreadCapture.cpp
index 9155c29..3891f2d 100644
--- a/libmemunreachable/ThreadCapture.cpp
+++ b/libmemunreachable/ThreadCapture.cpp
@@ -110,7 +110,7 @@
 
   android::base::unique_fd fd(open(path, O_CLOEXEC | O_DIRECTORY | O_RDONLY));
   if (fd == -1) {
-    ALOGE("failed to open %s: %s", path, strerror(errno));
+    MEM_ALOGE("failed to open %s: %s", path, strerror(errno));
     return false;
   }
 
@@ -126,7 +126,7 @@
   do {
     nread = syscall(SYS_getdents64, fd.get(), dirent_buf, sizeof(dirent_buf));
     if (nread < 0) {
-      ALOGE("failed to get directory entries from %s: %s", path, strerror(errno));
+      MEM_ALOGE("failed to get directory entries from %s: %s", path, strerror(errno));
       return false;
     } else if (nread > 0) {
       ssize_t off = 0;
@@ -177,8 +177,7 @@
 void ThreadCaptureImpl::PtraceDetach(pid_t tid, unsigned int signal) {
   void* sig_ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(signal));
   if (ptrace(PTRACE_DETACH, tid, NULL, sig_ptr) < 0 && errno != ESRCH) {
-    ALOGE("failed to detach from thread %d of process %d: %s", tid, pid_,
-        strerror(errno));
+    MEM_ALOGE("failed to detach from thread %d of process %d: %s", tid, pid_, strerror(errno));
   }
 }
 
@@ -187,8 +186,7 @@
 int ThreadCaptureImpl::PtraceAttach(pid_t tid) {
   int ret = ptrace(PTRACE_SEIZE, tid, NULL, NULL);
   if (ret < 0) {
-    ALOGE("failed to attach to thread %d of process %d: %s", tid, pid_,
-        strerror(errno));
+    MEM_ALOGE("failed to attach to thread %d of process %d: %s", tid, pid_, strerror(errno));
     return -1;
   }
 
@@ -200,8 +198,7 @@
     if (errno == ESRCH) {
       return 0;
     } else {
-      ALOGE("failed to interrupt thread %d of process %d: %s", tid, pid_,
-          strerror(errno));
+      MEM_ALOGE("failed to interrupt thread %d of process %d: %s", tid, pid_, strerror(errno));
       PtraceDetach(tid, 0);
       return -1;
     }
@@ -219,8 +216,7 @@
   iovec.iov_len = sizeof(regs);
 
   if (ptrace(PTRACE_GETREGSET, tid, reinterpret_cast<void*>(NT_PRSTATUS), &iovec)) {
-    ALOGE("ptrace getregset for thread %d of process %d failed: %s",
-        tid, pid_, strerror(errno));
+    MEM_ALOGE("ptrace getregset for thread %d of process %d failed: %s", tid, pid_, strerror(errno));
     return false;
   }
 
@@ -258,15 +254,13 @@
 
   int status = 0;
   if (TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL)) < 0) {
-    ALOGE("failed to wait for pause of thread %d of process %d: %s", tid, pid_,
-        strerror(errno));
+    MEM_ALOGE("failed to wait for pause of thread %d of process %d: %s", tid, pid_, strerror(errno));
     PtraceDetach(tid, 0);
     return -1;
   }
 
   if (!WIFSTOPPED(status)) {
-    ALOGE("thread %d of process %d was not paused after waitpid, killed?",
-        tid, pid_);
+    MEM_ALOGE("thread %d of process %d was not paused after waitpid, killed?", tid, pid_);
     return 0;
   }
 
@@ -285,8 +279,8 @@
         // normal ptrace interrupt stop
         break;
       default:
-        ALOGE("unexpected signal %d with PTRACE_EVENT_STOP for thread %d of process %d",
-            signal, tid, pid_);
+        MEM_ALOGE("unexpected signal %d with PTRACE_EVENT_STOP for thread %d of process %d", signal,
+                  tid, pid_);
         return -1;
     }
   } else {
diff --git a/libmemunreachable/log.h b/libmemunreachable/log.h
index cdfbfd9..1725c53 100644
--- a/libmemunreachable/log.h
+++ b/libmemunreachable/log.h
@@ -19,6 +19,32 @@
 
 #define LOG_TAG "libmemunreachable"
 
+#if defined(__ANDROID__)
+
+#include <async_safe/log.h>
+
+#define MEM_ALOGE(...) async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, ##__VA_ARGS__)
+#define MEM_ALOGW(...) async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, ##__VA_ARGS__)
+#define MEM_ALOGI(...) async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG, ##__VA_ARGS__)
+#define MEM_ALOGV(...) async_safe_format_log(ANDROID_LOG_VERBOSE, LOG_TAG, ##__VA_ARGS__)
+
+#define MEM_LOG_ALWAYS_FATAL(...) async_safe_fatal(__VA_ARGS__)
+
+#define MEM_LOG_ALWAYS_FATAL_IF(cond, ...) \
+  ((__predict_false(cond)) ? async_safe_fatal(__VA_ARGS__) : (void)0)
+
+#else
+
 #include <log/log.h>
 
+#define MEM_ALOGW ALOGW
+#define MEM_ALOGE ALOGE
+#define MEM_ALOGV ALOGV
+#define MEM_ALOGI ALOGI
+
+#define MEM_LOG_ALWAYS_FATAL LOG_ALWAYS_FATAL
+#define MEM_LOG_ALWAYS_FATAL_IF LOG_ALWAYS_FATAL_IF
+
+#endif
+
 #endif // LIBMEMUNREACHABLE_LOG_H_
diff --git a/libmemunreachable/tests/DisableMalloc_test.cpp b/libmemunreachable/tests/DisableMalloc_test.cpp
index ea5c22c..4e6155b 100644
--- a/libmemunreachable/tests/DisableMalloc_test.cpp
+++ b/libmemunreachable/tests/DisableMalloc_test.cpp
@@ -74,7 +74,7 @@
     {
       alarm(100ms);
       ScopedDisableMalloc disable_malloc;
-      char* ptr = new(char);
+      char* ptr = new (std::nothrow)(char);
       ASSERT_NE(ptr, nullptr);
       delete(ptr);
     }
@@ -89,6 +89,8 @@
       alarm(250ms);
       ScopedDisableMalloc disable_malloc;
       delete(ptr);
+      // Force ptr usage or this code gets optimized away by the arm64 compiler.
+      ASSERT_NE(ptr, nullptr);
     }
   }, "");
 }
diff --git a/libmemunreachable/tests/MemUnreachable_test.cpp b/libmemunreachable/tests/MemUnreachable_test.cpp
index 2ae3db8..71da365 100644
--- a/libmemunreachable/tests/MemUnreachable_test.cpp
+++ b/libmemunreachable/tests/MemUnreachable_test.cpp
@@ -23,8 +23,6 @@
 
 #include <memunreachable/memunreachable.h>
 
-void* ptr;
-
 class HiddenPointer {
  public:
   explicit HiddenPointer(size_t size = 256) {
@@ -92,10 +90,12 @@
   }
 }
 
+void* g_ptr;
+
 TEST(MemunreachableTest, global) {
   HiddenPointer hidden_ptr;
 
-  ptr = hidden_ptr.Get();
+  g_ptr = hidden_ptr.Get();
 
   {
     UnreachableMemoryInfo info;
@@ -104,7 +104,7 @@
     ASSERT_EQ(0U, info.leaks.size());
   }
 
-  ptr = NULL;
+  g_ptr = nullptr;
 
   {
     UnreachableMemoryInfo info;
@@ -126,7 +126,7 @@
 TEST(MemunreachableTest, tls) {
   HiddenPointer hidden_ptr;
   pthread_key_t key;
-  pthread_key_create(&key, NULL);
+  pthread_key_create(&key, nullptr);
 
   pthread_setspecific(key, hidden_ptr.Get());
 
diff --git a/libmemunreachable/tests/ThreadCapture_test.cpp b/libmemunreachable/tests/ThreadCapture_test.cpp
index 41ed84e..44aabd7 100644
--- a/libmemunreachable/tests/ThreadCapture_test.cpp
+++ b/libmemunreachable/tests/ThreadCapture_test.cpp
@@ -55,7 +55,7 @@
     threads_.reserve(threads);
     tids_.reserve(threads);
     for (unsigned int i = 0; i < threads; i++) {
-      threads_.emplace_back([&, i, threads, this]() {
+      threads_.emplace_back([&, threads, this]() {
         {
           std::lock_guard<std::mutex> lk(m_);
           tids_.push_back(gettid());
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
index 5fb56f2..377b7dd 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -22,3 +22,5 @@
         },
     },
 }
+
+subdirs = ["tests"]
\ No newline at end of file
diff --git a/libnativebridge/tests/Android.bp b/libnativebridge/tests/Android.bp
new file mode 100644
index 0000000..efd3978
--- /dev/null
+++ b/libnativebridge/tests/Android.bp
@@ -0,0 +1,53 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_defaults {
+    name: "libnativebridge-dummy-defaults",
+
+    host_supported: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    cppflags: ["-fvisibility=protected"],
+    target: {
+        android: {
+            shared_libs: ["libdl"],
+        },
+        host: {
+            host_ldlibs: ["-ldl"],
+        },
+    },
+}
+
+cc_library_shared {
+    name: "libnativebridge-dummy",
+    srcs: ["DummyNativeBridge.cpp"],
+    defaults: ["libnativebridge-dummy-defaults"],
+}
+
+cc_library_shared {
+    name: "libnativebridge2-dummy",
+    srcs: ["DummyNativeBridge2.cpp"],
+    defaults: ["libnativebridge-dummy-defaults"],
+}
+
+cc_library_shared {
+    name: "libnativebridge3-dummy",
+    srcs: ["DummyNativeBridge3.cpp"],
+    defaults: ["libnativebridge-dummy-defaults"],
+}
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index c9468f0..70b3fcc 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -1,8 +1,6 @@
 # Build the unit tests.
 LOCAL_PATH := $(call my-dir)
 
-include $(LOCAL_PATH)/Android.nativebridge-dummy.mk
-
 include $(CLEAR_VARS)
 
 # Build the unit tests.
diff --git a/libnativebridge/tests/Android.nativebridge-dummy.mk b/libnativebridge/tests/Android.nativebridge-dummy.mk
deleted file mode 100644
index 2d78be0..0000000
--- a/libnativebridge/tests/Android.nativebridge-dummy.mk
+++ /dev/null
@@ -1,108 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-NATIVE_BRIDGE_COMMON_SRC_FILES := \
-  DummyNativeBridge.cpp
-
-# Shared library for target
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -fvisibility=protected
-LOCAL_SHARED_LIBRARIES := libdl
-LOCAL_MULTILIB := both
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Shared library for host
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
-# v2.
-
-NATIVE_BRIDGE2_COMMON_SRC_FILES := \
-  DummyNativeBridge2.cpp
-
-# Shared library for target
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge2-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE2_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -fvisibility=protected
-LOCAL_SHARED_LIBRARIES := libdl
-LOCAL_MULTILIB := both
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Shared library for host
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge2-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE2_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
-# v3.
-
-NATIVE_BRIDGE3_COMMON_SRC_FILES := \
-  DummyNativeBridge3.cpp
-
-# Shared library for target
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge3-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Shared library for host
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge3-dummy
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 709646e..3c0d08d 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -119,14 +119,14 @@
     static const char socketName[] = "logdw";
     int sock = android_get_control_socket(socketName);
 
-    if (sock < 0) {
+    if (sock < 0) {  // logd started up in init.sh
         sock = socket_local_server(
             socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM);
-    }
 
-    int on = 1;
-    if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
-        return -1;
+        int on = 1;
+        if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
+            return -1;
+        }
     }
     return sock;
 }
diff --git a/logd/logd.rc b/logd/logd.rc
index 7494d8f..8804246 100644
--- a/logd/logd.rc
+++ b/logd/logd.rc
@@ -1,7 +1,7 @@
 service logd /system/bin/logd
     socket logd stream 0666 logd logd
     socket logdr seqpacket 0666 logd logd
-    socket logdw dgram 0222 logd logd
+    socket logdw dgram+passcred 0222 logd logd
     file /proc/kmsg r
     file /dev/kmsg w
     user logd
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 8cdc13f..540e976 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -419,6 +419,7 @@
     # For security reasons, /data/local/tmp should always be empty.
     # Do not place files or directories in /data/local/tmp
     mkdir /data/local/tmp 0771 shell shell
+    mkdir /data/data 0771 system system
     mkdir /data/app-private 0771 system system
     mkdir /data/app-ephemeral 0771 system system
     mkdir /data/app-asec 0700 root root
@@ -471,8 +472,7 @@
 
     mkdir /data/user 0711 system system
     mkdir /data/user_de 0711 system system
-    mkdir /data/user/0 0711 system system
-    symlink /data/user/0 /data/data
+    symlink /data/data /data/user/0
 
     mkdir /data/media 0770 media_rw media_rw
     mkdir /data/media/obb 0770 media_rw media_rw
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index aa755ed..d6ead1a 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -95,13 +95,3 @@
 LOCAL_MODULE := grep
 LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,egrep fgrep,ln -sf grep $(TARGET_OUT)/bin/$(t);)
 include $(BUILD_EXECUTABLE)
-
-
-# We build gzip separately, so it can provide gunzip and zcat too.
-include $(CLEAR_VARS)
-LOCAL_MODULE := gzip
-LOCAL_SRC_FILES := gzip.c
-LOCAL_CFLAGS += -Wall -Werror
-LOCAL_SHARED_LIBRARIES += libz
-LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,gunzip zcat,ln -sf gzip $(TARGET_OUT)/bin/$(t);)
-include $(BUILD_EXECUTABLE)
diff --git a/toolbox/gzip.c b/toolbox/gzip.c
deleted file mode 100644
index 62c4518..0000000
--- a/toolbox/gzip.c
+++ /dev/null
@@ -1,261 +0,0 @@
-/* gzip.c - gzip/gunzip/zcat tools for gzip data
- *
- * Copyright 2017 The Android Open Source Project
- *
- * GZIP RFC: http://www.ietf.org/rfc/rfc1952.txt
-
-TODO: port to toybox.
-
-*/
-
-#define _GNU_SOURCE
-
-#include <errno.h>
-#include <error.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#include <zlib.h>
-
-// toybox-style flags/globals.
-#define FLAG_c 1
-#define FLAG_d 2
-#define FLAG_f 4
-#define FLAG_k 8
-static struct {
-  int optflags;
-} toys;
-static struct {
-  int level;
-} TT;
-
-static void xstat(const char *path, struct stat *sb)
-{
-  if (stat(path, sb)) error(1, errno, "stat %s", path);
-}
-
-static void fix_time(const char *path, struct stat *sb)
-{
-  struct timespec times[] = { sb->st_atim, sb->st_mtim };
-
-  if (utimensat(AT_FDCWD, path, times, 0)) error(1, errno, "utimes");
-}
-
-static FILE *xfdopen(const char *name, int flags, mode_t open_mode,
-    const char *mode)
-{
-  FILE *fp;
-  int fd;
-
-  if (!strcmp(name, "-")) fd = dup((*mode == 'r') ? 0 : 1);
-  else fd = open(name, flags, open_mode);
-
-  if (fd == -1) error(1, errno, "open %s (%s)", name, mode);
-  fp = fdopen(fd, mode);
-  if (fp == NULL) error(1, errno, "fopen %s (%s)", name, mode);
-  return fp;
-}
-
-static gzFile xgzopen(const char *name, int flags, mode_t open_mode,
-    const char *mode)
-{
-  gzFile f;
-  int fd;
-
-  if (!strcmp(name, "-")) fd = dup((*mode == 'r') ? 0 : 1);
-  else fd = open(name, flags, open_mode);
-
-  if (fd == -1) error(1, errno, "open %s (%s)", name, mode);
-  f = gzdopen(fd, mode);
-  if (f == NULL) error(1, errno, "gzdopen %s (%s)", name, mode);
-  return f;
-}
-
-static void gzfatal(gzFile f, char *what)
-{
-  int err;
-  const char *msg = gzerror(f, &err);
-
-  error(1, (err == Z_ERRNO) ? errno : 0, "%s: %s", what, msg);
-}
-
-static void gunzip(char *arg)
-{
-  struct stat sb;
-  char buf[BUFSIZ];
-  int len, both_files;
-  char *in_name, *out_name;
-  gzFile in;
-  FILE *out;
-
-  // "gunzip x.gz" will decompress "x.gz" to "x".
-  len = strlen(arg);
-  if (len > 3 && !strcmp(arg+len-3, ".gz")) {
-    in_name = strdup(arg);
-    out_name = strdup(arg);
-    out_name[len-3] = '\0';
-  } else if (!strcmp(arg, "-")) {
-    // "-" means stdin; assume output to stdout.
-    // TODO: require -f to read compressed data from tty?
-    in_name = strdup("-");
-    out_name = strdup("-");
-  } else error(1, 0, "unknown suffix");
-
-  if (toys.optflags&FLAG_c) {
-    free(out_name);
-    out_name = strdup("-");
-  }
-
-  both_files = strcmp(in_name, "-") && strcmp(out_name, "-");
-  if (both_files) xstat(in_name, &sb);
-
-  in = xgzopen(in_name, O_RDONLY, 0, "r");
-  out = xfdopen(out_name, O_CREAT|O_WRONLY|((toys.optflags&FLAG_f)?0:O_EXCL),
-      both_files?sb.st_mode:0666, "w");
-
-  while ((len = gzread(in, buf, sizeof(buf))) > 0) {
-    if (fwrite(buf, 1, len, out) != (size_t) len) error(1, errno, "fwrite");
-  }
-  if (len < 0) gzfatal(in, "gzread");
-  if (fclose(out)) error(1, errno, "fclose");
-  if (gzclose(in) != Z_OK) error(1, 0, "gzclose");
-
-  if (both_files) fix_time(out_name, &sb);
-  if (!(toys.optflags&(FLAG_c|FLAG_k))) unlink(in_name);
-  free(in_name);
-  free(out_name);
-}
-
-static void gzip(char *in_name)
-{
-  char buf[BUFSIZ];
-  size_t len;
-  char *out_name;
-  FILE *in;
-  gzFile out;
-  struct stat sb;
-  int both_files;
-
-  if (toys.optflags&FLAG_c) {
-    out_name = strdup("-");
-  } else {
-    if (asprintf(&out_name, "%s.gz", in_name) == -1) {
-      error(1, errno, "asprintf");
-    }
-  }
-
-  both_files = strcmp(in_name, "-") && strcmp(out_name, "-");
-  if (both_files) xstat(in_name, &sb);
-
-  snprintf(buf, sizeof(buf), "w%d", TT.level);
-  in = xfdopen(in_name, O_RDONLY, 0, "r");
-  out = xgzopen(out_name, O_CREAT|O_WRONLY|((toys.optflags&FLAG_f)?0:O_EXCL),
-      both_files?sb.st_mode:0, buf);
-
-  while ((len = fread(buf, 1, sizeof(buf), in)) > 0) {
-    if (gzwrite(out, buf, len) != (int) len) gzfatal(out, "gzwrite");
-  }
-  if (ferror(in)) error(1, errno, "fread");
-  if (fclose(in)) error(1, errno, "fclose");
-  if (gzclose(out) != Z_OK) error(1, 0, "gzclose");
-
-  if (both_files) fix_time(out_name, &sb);
-  if (!(toys.optflags&(FLAG_c|FLAG_k))) unlink(in_name);
-  free(out_name);
-}
-
-static void do_file(char *arg)
-{
-  if (toys.optflags&FLAG_d) gunzip(arg);
-  else gzip(arg);
-}
-
-static void usage()
-{
-  char *cmd = basename(getprogname());
-
-  printf("usage: %s [-c] [-d] [-f] [-#] [FILE...]\n", cmd);
-  printf("\n");
-  if (!strcmp(cmd, "zcat")) {
-    printf("Decompress files to stdout. Like `gzip -dc`.\n");
-    printf("\n");
-    printf("-c\tOutput to stdout\n");
-    printf("-f\tForce: allow read from tty\n");
-  } else if (!strcmp(cmd, "gunzip")) {
-    printf("Decompress files. With no files, decompresses stdin to stdout.\n");
-    printf("On success, the input files are removed and replaced by new\n");
-    printf("files without the .gz suffix.\n");
-    printf("\n");
-    printf("-c\tOutput to stdout\n");
-    printf("-f\tForce: allow read from tty\n");
-    printf("-k\tKeep input files (don't remove)\n");
-  } else { // gzip
-    printf("Compress files. With no files, compresses stdin to stdout.\n");
-    printf("On success, the input files are removed and replaced by new\n");
-    printf("files with the .gz suffix.\n");
-    printf("\n");
-    printf("-c\tOutput to stdout\n");
-    printf("-d\tDecompress (act as gunzip)\n");
-    printf("-f\tForce: allow overwrite of output file\n");
-    printf("-k\tKeep input files (don't remove)\n");
-    printf("-#\tCompression level 1-9 (1:fastest, 6:default, 9:best)\n");
-  }
-  printf("\n");
-}
-
-int main(int argc, char *argv[])
-{
-  char *cmd = basename(argv[0]);
-  int opt_ch;
-
-  toys.optflags = 0;
-  TT.level = 6;
-
-  if (!strcmp(cmd, "gunzip")) {
-    // gunzip == gzip -d
-    toys.optflags = FLAG_d;
-  } else if (!strcmp(cmd, "zcat")) {
-    // zcat == gzip -dc
-    toys.optflags = (FLAG_c|FLAG_d);
-  }
-
-  while ((opt_ch = getopt(argc, argv, "cdfhk123456789")) != -1) {
-    switch (opt_ch) {
-    case 'c': toys.optflags |= FLAG_c; break;
-    case 'd': toys.optflags |= FLAG_d; break;
-    case 'f': toys.optflags |= FLAG_f; break;
-    case 'k': toys.optflags |= FLAG_k; break;
-
-    case '1':
-    case '2':
-    case '3':
-    case '4':
-    case '5':
-    case '6':
-    case '7':
-    case '8':
-    case '9':
-      TT.level = opt_ch - '0';
-      break;
-
-    default:
-      usage();
-      return 1;
-    }
-  }
-
-  if (optind == argc) {
-    // With no arguments, we go from stdin to stdout.
-    toys.optflags |= FLAG_c;
-    do_file("-");
-    return 0;
-  }
-
-  // Otherwise process each file in turn.
-  while (optind < argc) do_file(argv[optind++]);
-  return 0;
-}
diff --git a/trusty/Android.bp b/trusty/Android.bp
index 1b2e2c7..9681488 100644
--- a/trusty/Android.bp
+++ b/trusty/Android.bp
@@ -1,3 +1,4 @@
 subdirs = [
     "libtrusty",
+    "storage/*",
 ]
diff --git a/trusty/storage/interface/Android.bp b/trusty/storage/interface/Android.bp
new file mode 100644
index 0000000..a551c37
--- /dev/null
+++ b/trusty/storage/interface/Android.bp
@@ -0,0 +1,20 @@
+//
+// Copyright (C) 2015 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.
+//
+
+cc_library_static {
+    name: "libtrustystorageinterface",
+    export_include_dirs: ["include"],
+}
diff --git a/trusty/storage/interface/Android.mk b/trusty/storage/interface/Android.mk
deleted file mode 100644
index 15cb6f3..0000000
--- a/trusty/storage/interface/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# Copyright (C) 2015 The Android Open-Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libtrustystorageinterface
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/trusty/storage/lib/Android.bp b/trusty/storage/lib/Android.bp
new file mode 100644
index 0000000..5eb3f07
--- /dev/null
+++ b/trusty/storage/lib/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2015 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.
+//
+
+cc_library_static {
+    name: "libtrustystorage",
+
+    srcs: ["storage.c"],
+
+    export_include_dirs: ["include"],
+
+    static_libs: [
+        "liblog",
+        "libtrusty",
+        "libtrustystorageinterface",
+    ],
+
+    cflags: [
+        "-fvisibility=hidden",
+        "-Wall",
+        "-Werror",
+    ]
+}
diff --git a/trusty/storage/lib/Android.mk b/trusty/storage/lib/Android.mk
deleted file mode 100644
index 7e0fc9d..0000000
--- a/trusty/storage/lib/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Copyright (C) 2015 The Android Open-Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libtrustystorage
-
-LOCAL_SRC_FILES := \
-	storage.c \
-
-LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-
-LOCAL_STATIC_LIBRARIES := \
-	liblog \
-	libtrusty \
-	libtrustystorageinterface
-
-include $(BUILD_STATIC_LIBRARY)
-
diff --git a/trusty/storage/proxy/Android.bp b/trusty/storage/proxy/Android.bp
new file mode 100644
index 0000000..eb34df0
--- /dev/null
+++ b/trusty/storage/proxy/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_binary {
+    name: "storageproxyd",
+
+    srcs: [
+        "ipc.c",
+        "rpmb.c",
+        "storage.c",
+        "proxy.c",
+    ],
+
+    shared_libs: ["liblog"],
+
+    static_libs: [
+        "libtrustystorageinterface",
+        "libtrusty",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ]
+}
diff --git a/trusty/storage/proxy/Android.mk b/trusty/storage/proxy/Android.mk
deleted file mode 100644
index 745e302..0000000
--- a/trusty/storage/proxy/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# Copyright (C) 2016 The Android Open-Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := storageproxyd
-
-LOCAL_C_INCLUDES += bionic/libc/kernel/uapi
-
-LOCAL_SRC_FILES := \
-	ipc.c \
-	rpmb.c \
-	storage.c \
-	proxy.c
-
-LOCAL_CLFAGS = -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog \
-
-LOCAL_STATIC_LIBRARIES := \
-	libtrustystorageinterface \
-	libtrusty
-
-include $(BUILD_EXECUTABLE)
-
diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c
index d645ac0..27e5891 100644
--- a/trusty/storage/proxy/proxy.c
+++ b/trusty/storage/proxy/proxy.c
@@ -229,7 +229,6 @@
 int main(int argc, char *argv[])
 {
     int rc;
-    uint retry_cnt;
 
     /* drop privileges */
     if (drop_privs() < 0)
diff --git a/trusty/storage/tests/Android.bp b/trusty/storage/tests/Android.bp
new file mode 100644
index 0000000..3eff3f2
--- /dev/null
+++ b/trusty/storage/tests/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_test {
+    name: "secure-storage-unit-test",
+
+    cflags: [
+        "-g",
+        "-Wall",
+        "-Werror",
+        "-std=gnu++11",
+        "-Wno-missing-field-initializers",
+    ],
+
+    static_libs: [
+        "libtrustystorageinterface",
+        "libtrustystorage",
+        "libtrusty",
+        "liblog",
+    ],
+
+    srcs: ["main.cpp"],
+}
diff --git a/trusty/storage/tests/Android.mk b/trusty/storage/tests/Android.mk
deleted file mode 100644
index 71c904d..0000000
--- a/trusty/storage/tests/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := secure-storage-unit-test
-LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
-LOCAL_STATIC_LIBRARIES := \
-	libtrustystorageinterface \
-	libtrustystorage \
-	libtrusty \
-	liblog
-LOCAL_SRC_FILES := main.cpp
-include $(BUILD_NATIVE_TEST)
-