Merge "trusty*: Android.mk -> Android.bp"
diff --git a/adb/Android.mk b/adb/Android.mk
index 1b201c8..618fa4b 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/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index 20610ee..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,179 +382,9 @@
         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();
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/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/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/builtins.cpp b/init/builtins.cpp
index 9a2355b..bdd86ed 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) {
@@ -660,29 +678,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;
 }
 
@@ -741,7 +779,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 e7d01f4..eddfa50 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -871,7 +871,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();
         }
 
@@ -887,36 +889,36 @@
 // 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__");
+    selinux_android_restorecon("/dev/socket", 0);
+    selinux_android_restorecon("/dev/random", 0);
+    selinux_android_restorecon("/dev/urandom", 0);
+    selinux_android_restorecon("/dev/__properties__", 0);
 
-    restorecon("/file_contexts.bin");
-    restorecon("/plat_file_contexts");
-    restorecon("/nonplat_file_contexts");
-    restorecon("/plat_property_contexts");
-    restorecon("/nonplat_property_contexts");
-    restorecon("/plat_seapp_contexts");
-    restorecon("/nonplat_seapp_contexts");
-    restorecon("/plat_service_contexts");
-    restorecon("/nonplat_service_contexts");
-    restorecon("/plat_hwservice_contexts");
-    restorecon("/nonplat_hwservice_contexts");
-    restorecon("/sepolicy");
-    restorecon("/vndservice_contexts");
+    selinux_android_restorecon("/file_contexts.bin", 0);
+    selinux_android_restorecon("/plat_file_contexts", 0);
+    selinux_android_restorecon("/nonplat_file_contexts", 0);
+    selinux_android_restorecon("/plat_property_contexts", 0);
+    selinux_android_restorecon("/nonplat_property_contexts", 0);
+    selinux_android_restorecon("/plat_seapp_contexts", 0);
+    selinux_android_restorecon("/nonplat_seapp_contexts", 0);
+    selinux_android_restorecon("/plat_service_contexts", 0);
+    selinux_android_restorecon("/nonplat_service_contexts", 0);
+    selinux_android_restorecon("/plat_hwservice_contexts", 0);
+    selinux_android_restorecon("/nonplat_hwservice_contexts", 0);
+    selinux_android_restorecon("/sepolicy", 0);
+    selinux_android_restorecon("/vndservice_contexts", 0);
 
-    restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
-    restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
-    restorecon("/dev/device-mapper");
+    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.
@@ -1025,7 +1027,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 3a9f622..7c931da 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -209,21 +209,33 @@
 }
 
 void Service::KillProcessGroup(int signal) {
-    LOG(INFO) << "Sending signal " << signal
-              << " to service '" << name_
-              << "' (pid " << pid_ << ") process group...";
-    int r;
-    if (signal == SIGTERM) {
-        r = killProcessGroupOnce(uid_, pid_, signal);
-    } else {
-        r = killProcessGroup(uid_, pid_, signal);
-    }
-    if (r == -1) {
-        LOG(ERROR) << "killProcessGroup(" << uid_ << ", " << pid_ << ", " << signal << ") failed";
-    }
-    if (kill(-pid_, signal) == -1) {
+    // We ignore reporting errors of ESRCH as this commonly happens in the below case,
+    // 1) Terminate() is called, which sends SIGTERM to the process
+    // 2) The process successfully exits
+    // 3) ReapOneProcess() is called, which calls waitpid(-1, ...) which removes the pid entry.
+    // 4) Reap() is called, which sends SIGKILL, but the pid no longer exists.
+    // TODO: sigaction for SIGCHLD reports the pid of the exiting process,
+    // we should do this kill with that pid first before calling waitpid().
+    if (kill(-pid_, signal) == -1 && errno != ESRCH) {
         PLOG(ERROR) << "kill(" << pid_ << ", " << signal << ") failed";
     }
+
+    // If we've already seen a successful result from killProcessGroup*(), then we have removed
+    // the cgroup already and calling these functions a second time will simply result in an error.
+    // This is true regardless of which signal was sent.
+    // These functions handle their own logging, so no additional logging is needed.
+    if (!process_cgroup_empty_) {
+        LOG(INFO) << "Sending signal " << signal << " to service '" << name_ << "' (pid " << pid_
+                  << ") process group...";
+        int r;
+        if (signal == SIGTERM) {
+            r = killProcessGroupOnce(uid_, pid_, signal);
+        } else {
+            r = killProcessGroup(uid_, pid_, signal);
+        }
+
+        if (r == 0) process_cgroup_empty_ = true;
+    }
 }
 
 void Service::SetProcessAttributes() {
@@ -380,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;
 }
@@ -480,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 =
@@ -501,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;
     }
@@ -522,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;
 }
 
@@ -736,6 +778,7 @@
     time_started_ = boot_clock::now();
     pid_ = pid;
     flags_ |= SVC_RUNNING;
+    process_cgroup_empty_ = false;
 
     errno = -createProcessGroup(uid_, pid_);
     if (errno != 0) {
@@ -936,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/service.h b/init/service.h
index 426577f..b9c270a 100644
--- a/init/service.h
+++ b/init/service.h
@@ -107,6 +107,7 @@
     int ioprio_pri() const { return ioprio_pri_; }
     int priority() const { return priority_; }
     int oom_score_adjust() const { return oom_score_adjust_; }
+    bool process_cgroup_empty() const { return process_cgroup_empty_; }
     const std::vector<std::string>& args() const { return args_; }
 
   private:
@@ -179,6 +180,8 @@
 
     int oom_score_adjust_;
 
+    bool process_cgroup_empty_ = false;
+
     std::vector<std::string> args_;
 };
 
diff --git a/init/service_test.cpp b/init/service_test.cpp
index 4493f25..b9c4627 100644
--- a/init/service_test.cpp
+++ b/init/service_test.cpp
@@ -45,6 +45,7 @@
     EXPECT_EQ(0, service_in_old_memory->ioprio_pri());
     EXPECT_EQ(0, service_in_old_memory->priority());
     EXPECT_EQ(-1000, service_in_old_memory->oom_score_adjust());
+    EXPECT_FALSE(service_in_old_memory->process_cgroup_empty());
 
     for (std::size_t i = 0; i < memory_size; ++i) {
         old_memory[i] = 0xFF;
@@ -64,4 +65,5 @@
     EXPECT_EQ(0, service_in_old_memory2->ioprio_pri());
     EXPECT_EQ(0, service_in_old_memory2->priority());
     EXPECT_EQ(-1000, service_in_old_memory2->oom_score_adjust());
+    EXPECT_FALSE(service_in_old_memory->process_cgroup_empty());
 }
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/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/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/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/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/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 47f6ff3..f0c3795 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -22,8 +22,13 @@
 
 __BEGIN_DECLS
 
+// Return 0 and removes the cgroup if there are no longer any processes in it.
+// Returns -1 in the case of an error occurring or if there are processes still running
+// even after retrying for up to 200ms.
 int killProcessGroup(uid_t uid, int initialPid, int signal);
 
+// Returns the same as killProcessGroup(), however it does not retry, which means
+// that it only returns 0 in the case that the cgroup exists and it contains no processes.
 int killProcessGroupOnce(uid_t uid, int initialPid, int signal);
 
 int createProcessGroup(uid_t uid, int initialPid);
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 1572cb3..27b4065 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -34,6 +34,7 @@
 #include <thread>
 
 #include <android-base/logging.h>
+#include <android-base/unique_fd.h>
 #include <private/android_filesystem_config.h>
 
 #include <processgroup/processgroup.h>
@@ -64,12 +65,27 @@
 
 std::once_flag init_path_flag;
 
-struct ctx {
-    bool initialized;
-    int fd;
-    char buf[128];
-    char *buf_ptr;
-    size_t buf_len;
+class ProcessGroup {
+  public:
+    ProcessGroup() : buf_ptr_(buf_), buf_len_(0) {}
+
+    bool Open(uid_t uid, int pid);
+
+    // Return positive number and sets *pid = next pid in process cgroup on success
+    // Returns 0 if there are no pids left in the process cgroup
+    // Returns -errno if an error was encountered
+    int GetOneAppProcess(pid_t* pid);
+
+  private:
+    // Returns positive number of bytes filled on success
+    // Returns 0 if there was nothing to read
+    // Returns -errno if an error was encountered
+    int RefillBuffer();
+
+    android::base::unique_fd fd_;
+    char buf_[128];
+    char* buf_ptr_;
+    size_t buf_len_;
 };
 
 static const char* getCgroupRootPath() {
@@ -105,87 +121,67 @@
             pid);
 }
 
-static int initCtx(uid_t uid, int pid, struct ctx *ctx)
-{
-    int ret;
+bool ProcessGroup::Open(uid_t uid, int pid) {
     char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
     convertUidPidToPath(path, sizeof(path), uid, pid);
     strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
 
     int fd = open(path, O_RDONLY);
-    if (fd < 0) {
-        ret = -errno;
-        PLOG(WARNING) << "failed to open " << path;
-        return ret;
-    }
+    if (fd < 0) return false;
 
-    ctx->fd = fd;
-    ctx->buf_ptr = ctx->buf;
-    ctx->buf_len = 0;
-    ctx->initialized = true;
+    fd_.reset(fd);
 
     LOG(VERBOSE) << "Initialized context for " << path;
 
-    return 0;
+    return true;
 }
 
-static int refillBuffer(struct ctx *ctx)
-{
-    memmove(ctx->buf, ctx->buf_ptr, ctx->buf_len);
-    ctx->buf_ptr = ctx->buf;
+int ProcessGroup::RefillBuffer() {
+    memmove(buf_, buf_ptr_, buf_len_);
+    buf_ptr_ = buf_;
 
-    ssize_t ret = read(ctx->fd, ctx->buf_ptr + ctx->buf_len,
-                sizeof(ctx->buf) - ctx->buf_len - 1);
+    ssize_t ret = read(fd_, buf_ptr_ + buf_len_, sizeof(buf_) - buf_len_ - 1);
     if (ret < 0) {
         return -errno;
     } else if (ret == 0) {
         return 0;
     }
 
-    ctx->buf_len += ret;
-    ctx->buf[ctx->buf_len] = 0;
-    LOG(VERBOSE) << "Read " << ret << " to buffer: " << ctx->buf;
+    buf_len_ += ret;
+    buf_[buf_len_] = 0;
+    LOG(VERBOSE) << "Read " << ret << " to buffer: " << buf_;
 
-    assert(ctx->buf_len <= sizeof(ctx->buf));
+    assert(buf_len_ <= sizeof(buf_));
 
     return ret;
 }
 
-static pid_t getOneAppProcess(uid_t uid, int appProcessPid, struct ctx *ctx)
-{
-    if (!ctx->initialized) {
-        int ret = initCtx(uid, appProcessPid, ctx);
-        if (ret < 0) {
-            return ret;
-        }
-    }
+int ProcessGroup::GetOneAppProcess(pid_t* out_pid) {
+    *out_pid = 0;
 
-    char *eptr;
-    while ((eptr = (char *)memchr(ctx->buf_ptr, '\n', ctx->buf_len)) == NULL) {
-        int ret = refillBuffer(ctx);
-        if (ret == 0) {
-            return -ERANGE;
-        }
-        if (ret < 0) {
-            return ret;
-        }
+    char* eptr;
+    while ((eptr = static_cast<char*>(memchr(buf_ptr_, '\n', buf_len_))) == nullptr) {
+        int ret = RefillBuffer();
+        if (ret <= 0) return ret;
     }
 
     *eptr = '\0';
-    char *pid_eptr = NULL;
+    char* pid_eptr = nullptr;
     errno = 0;
-    long pid = strtol(ctx->buf_ptr, &pid_eptr, 10);
+    long pid = strtol(buf_ptr_, &pid_eptr, 10);
     if (errno != 0) {
         return -errno;
     }
     if (pid_eptr != eptr) {
-        return -EINVAL;
+        errno = EINVAL;
+        return -errno;
     }
 
-    ctx->buf_len -= (eptr - ctx->buf_ptr) + 1;
-    ctx->buf_ptr = eptr + 1;
+    buf_len_ -= (eptr - buf_ptr_) + 1;
+    buf_ptr_ = eptr + 1;
 
-    return (pid_t)pid;
+    *out_pid = static_cast<pid_t>(pid);
+    return 1;
 }
 
 static int removeProcessGroup(uid_t uid, int pid)
@@ -219,8 +215,8 @@
             }
 
             snprintf(path, sizeof(path), "%s/%s", uid_path, dir->d_name);
-            LOG(VERBOSE) << "removing " << path;
-            if (rmdir(path) == -1) PLOG(WARNING) << "failed to remove " << path;
+            LOG(VERBOSE) << "Removing " << path;
+            if (rmdir(path) == -1) PLOG(WARNING) << "Failed to remove " << path;
         }
     }
 }
@@ -231,7 +227,7 @@
     const char* cgroup_root_path = getCgroupRootPath();
     std::unique_ptr<DIR, decltype(&closedir)> root(opendir(cgroup_root_path), closedir);
     if (root == NULL) {
-        PLOG(ERROR) << "failed to open " << cgroup_root_path;
+        PLOG(ERROR) << "Failed to open " << cgroup_root_path;
     } else {
         dirent* dir;
         while ((dir = readdir(root.get())) != nullptr) {
@@ -246,20 +242,26 @@
 
             snprintf(path, sizeof(path), "%s/%s", cgroup_root_path, dir->d_name);
             removeUidProcessGroups(path);
-            LOG(VERBOSE) << "removing " << path;
-            if (rmdir(path) == -1) PLOG(WARNING) << "failed to remove " << path;
+            LOG(VERBOSE) << "Removing " << path;
+            if (rmdir(path) == -1) PLOG(WARNING) << "Failed to remove " << path;
         }
     }
 }
 
+// Returns number of processes killed on success
+// Returns 0 if there are no processes in the process cgroup left to kill
+// Returns -errno on error
 static int doKillProcessGroupOnce(uid_t uid, int initialPid, int signal) {
-    int processes = 0;
-    struct ctx ctx;
+    ProcessGroup process_group;
+    if (!process_group.Open(uid, initialPid)) {
+        PLOG(WARNING) << "Failed to open process cgroup uid " << uid << " pid " << initialPid;
+        return -errno;
+    }
+
+    int ret;
     pid_t pid;
-
-    ctx.initialized = false;
-
-    while ((pid = getOneAppProcess(uid, initialPid, &ctx)) >= 0) {
+    int processes = 0;
+    while ((ret = process_group.GetOneAppProcess(&pid)) > 0 && pid >= 0) {
         processes++;
         if (pid == 0) {
             // Should never happen...  but if it does, trying to kill this
@@ -267,55 +269,68 @@
             LOG(WARNING) << "Yikes, we've been told to kill pid 0!  How about we don't do that?";
             continue;
         }
-        LOG(VERBOSE) << "Killing pid " << pid << " in uid " << uid
-                     << " as part of process group " << initialPid;
+        LOG(VERBOSE) << "Killing pid " << pid << " in uid " << uid << " as part of process cgroup "
+                     << initialPid;
         if (kill(pid, signal) == -1) {
             PLOG(WARNING) << "kill(" << pid << ", " << signal << ") failed";
         }
     }
 
-    if (ctx.initialized) {
-        close(ctx.fd);
-    }
-
-    return processes;
+    return ret >= 0 ? processes : ret;
 }
 
-static int killProcessGroup(uid_t uid, int initialPid, int signal, int retry) {
+static int killProcessGroup(uid_t uid, int initialPid, int signal, int retries) {
     std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
 
+    int retry = retries;
     int processes;
     while ((processes = doKillProcessGroupOnce(uid, initialPid, signal)) > 0) {
-        LOG(VERBOSE) << "killed " << processes << " processes for processgroup " << initialPid;
+        LOG(VERBOSE) << "Killed " << processes << " processes for processgroup " << initialPid;
         if (retry > 0) {
             std::this_thread::sleep_for(5ms);
             --retry;
         } else {
-            LOG(ERROR) << "failed to kill " << processes << " processes for processgroup "
-                       << initialPid;
             break;
         }
     }
 
-    std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
+    if (processes < 0) {
+        PLOG(ERROR) << "Error encountered killing process cgroup uid " << uid << " pid "
+                    << initialPid;
+        return -1;
+    }
 
+    std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
     auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
-    LOG(VERBOSE) << "Killed process group uid " << uid << " pid " << initialPid << " in "
-                 << static_cast<int>(ms) << "ms, " << processes << " procs remain";
+
+    // We only calculate the number of 'processes' when killing the processes.
+    // In the retries == 0 case, we only kill the processes once and therefore
+    // will not have waited then recalculated how many processes are remaining
+    // after the first signals have been sent.
+    // Logging anything regarding the number of 'processes' here does not make sense.
 
     if (processes == 0) {
+        if (retries > 0) {
+            LOG(INFO) << "Successfully killed process cgroup uid " << uid << " pid " << initialPid
+                      << " in " << static_cast<int>(ms) << "ms";
+        }
         return removeProcessGroup(uid, initialPid);
     } else {
+        if (retries > 0) {
+            LOG(ERROR) << "Failed to kill process cgroup uid " << uid << " pid " << initialPid
+                       << " in " << static_cast<int>(ms) << "ms, " << processes
+                       << " processes remain";
+        }
         return -1;
     }
 }
 
 int killProcessGroup(uid_t uid, int initialPid, int signal) {
-    return killProcessGroup(uid, initialPid, signal, 40 /*maxRetry*/);
+    return killProcessGroup(uid, initialPid, signal, 40 /*retries*/);
 }
 
 int killProcessGroupOnce(uid_t uid, int initialPid, int signal) {
-    return killProcessGroup(uid, initialPid, signal, 0 /*maxRetry*/);
+    return killProcessGroup(uid, initialPid, signal, 0 /*retries*/);
 }
 
 static bool mkdirAndChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
@@ -341,14 +356,14 @@
     convertUidToPath(path, sizeof(path), uid);
 
     if (!mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM)) {
-        PLOG(ERROR) << "failed to make and chown " << path;
+        PLOG(ERROR) << "Failed to make and chown " << path;
         return -errno;
     }
 
     convertUidPidToPath(path, sizeof(path), uid, initialPid);
 
     if (!mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM)) {
-        PLOG(ERROR) << "failed to make and chown " << path;
+        PLOG(ERROR) << "Failed to make and chown " << path;
         return -errno;
     }
 
@@ -357,7 +372,7 @@
     int fd = open(path, O_WRONLY);
     if (fd == -1) {
         int ret = -errno;
-        PLOG(ERROR) << "failed to open " << path;
+        PLOG(ERROR) << "Failed to open " << path;
         return ret;
     }
 
@@ -367,7 +382,7 @@
     int ret = 0;
     if (write(fd, pid, len) < 0) {
         ret = -errno;
-        PLOG(ERROR) << "failed to write '" << pid << "' to " << path;
+        PLOG(ERROR) << "Failed to write '" << pid << "' to " << path;
     }
 
     close(fd);
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/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 3e23d98..5f9f799 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -60,11 +60,7 @@
 namespace.sphal.links = default,vndk,rs
 
 # WARNING: only NDK libs can be listed here.
-# However, this is commented out because some SP-HALs (gralloc.msm8996.so, etc)
-# are currently using some non-stable libs such as libbacktrace.so. We will get back
-# to this list once the dependencies are fixed.
-#namespace.sphal.link.default.shared_libs = libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libsync.so
-namespace.sphal.link.default.shared_libs = libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libbacktrace.so:libGLESv1_CM.so:libGLESv2.so
+namespace.sphal.link.default.shared_libs = libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libGLESv1_CM.so:libGLESv2.so
 
 # WARNING: only VNDK-SP libs can be listed here. DO NOT EDIT this line.
 namespace.sphal.link.vndk.shared_libs = android.hardware.renderscript@1.0.so:android.hardware.graphics.allocator@2.0.so:android.hardware.graphics.mapper@2.0.so:android.hardware.graphics.common@1.0.so:libhwbinder.so:libbase.so:libcutils.so:libhardware.so:libhidlbase.so:libhidltransport.so:libutils.so:libc++.so
@@ -85,7 +81,7 @@
 namespace.rs.permitted.paths = /vendor/${LIB}:/data
 
 namespace.rs.links = default,vndk
-namespace.rs.link.default.shared_libs = libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libbacktrace.so:libGLESv1_CM.so:libGLESv2.so:libmediandk.so:libui.so
+namespace.rs.link.default.shared_libs = libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libGLESv1_CM.so:libGLESv2.so:libmediandk.so:libui.so
 namespace.rs.link.vndk.shared_libs = android.hardware.renderscript@1.0.so:android.hardware.graphics.allocator@2.0.so:android.hardware.graphics.mapper@2.0.so:android.hardware.graphics.common@1.0.so:libhwbinder.so:libbase.so:libcutils.so:libhardware.so:libhidlbase.so:libhidltransport.so:libutils.so:libc++.so
 
 ###############################################################################
@@ -104,13 +100,7 @@
 # to the default namespace. This is possible since their ABI is stable across
 # Android releases.
 namespace.vndk.links = default
-
-# WARNING: only NDK libs can be listed here.
-# However, this is commented out because some SP-HALs (gralloc.msm8996.so, etc)
-# are currently using some non-stable libs such as libbacktrace.so. We will get back
-# to this list once the dependencies are fixed.
-#namespace.vndk.link.default.shared_libs = libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libsync.so
-namespace.vndk.link.default.shared_libs = libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libbacktrace.so
+namespace.vndk.link.default.shared_libs = libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so
 
 
 [vendor]
diff --git a/rootdir/init.rc b/rootdir/init.rc
index acb0557..def686b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -422,6 +422,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
@@ -474,8 +475,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