Merge changes from topic "protobuf-3.9.1"

* changes:
  Use installed paths of vndk libraries for ld.config.txt
  Adapt to google::protobuf::int64 type change
diff --git a/adb/tools/Android.bp b/adb/tools/Android.bp
new file mode 100644
index 0000000..71e32b7
--- /dev/null
+++ b/adb/tools/Android.bp
@@ -0,0 +1,36 @@
+// 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_binary_host {
+    name: "check_ms_os_desc",
+
+    defaults: ["adb_defaults"],
+
+    srcs: [
+        "check_ms_os_desc.cpp",
+    ],
+
+    static_libs: [
+        "libbase",
+        "libusb",
+    ],
+
+    stl: "libc++_static",
+
+    dist: {
+        targets: [
+            "sdk",
+        ],
+    },
+}
diff --git a/adb/tools/check_ms_os_desc.cpp b/adb/tools/check_ms_os_desc.cpp
new file mode 100644
index 0000000..8743ff7
--- /dev/null
+++ b/adb/tools/check_ms_os_desc.cpp
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <optional>
+#include <string>
+#include <vector>
+
+#include <libusb/libusb.h>
+
+static bool is_adb_device(libusb_device* device) {
+    libusb_device_descriptor device_desc;
+    libusb_get_device_descriptor(device, &device_desc);
+    if (device_desc.bDeviceClass != 0) {
+        return false;
+    }
+
+    libusb_config_descriptor* config_desc;
+    int rc = libusb_get_active_config_descriptor(device, &config_desc);
+    if (rc != 0) {
+        fprintf(stderr, "failed to get config descriptor for device %u:%u: %s\n",
+                libusb_get_bus_number(device), libusb_get_port_number(device),
+                libusb_error_name(rc));
+        return false;
+    }
+
+    for (size_t i = 0; i < config_desc->bNumInterfaces; ++i) {
+        const libusb_interface* interface = &config_desc->interface[i];
+        for (int j = 0; j < interface->num_altsetting; ++j) {
+            const libusb_interface_descriptor* interface_descriptor = &interface->altsetting[j];
+            if (interface_descriptor->bInterfaceClass == 0xff &&
+                interface_descriptor->bInterfaceSubClass == 0x42 &&
+                interface_descriptor->bInterfaceProtocol == 1) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+static std::optional<std::vector<uint8_t>> get_descriptor(libusb_device_handle* handle,
+                                                          uint8_t type, uint8_t index,
+                                                          uint16_t length) {
+    std::vector<uint8_t> result;
+    result.resize(length);
+    int rc = libusb_get_descriptor(handle, type, index, result.data(), result.size());
+    if (rc < 0) {
+        fprintf(stderr, "libusb_get_descriptor failed: %s\n", libusb_error_name(rc));
+        return std::nullopt;
+    }
+    result.resize(rc);
+    return result;
+}
+
+static std::optional<std::string> get_string_descriptor(libusb_device_handle* handle,
+                                                        uint8_t index) {
+    std::string result;
+    result.resize(4096);
+    int rc = libusb_get_string_descriptor_ascii(
+            handle, index, reinterpret_cast<uint8_t*>(result.data()), result.size());
+    if (rc < 0) {
+        fprintf(stderr, "libusb_get_string_descriptor_ascii failed: %s\n", libusb_error_name(rc));
+        return std::nullopt;
+    }
+    result.resize(rc);
+    return result;
+}
+
+static void check_ms_os_desc_v1(libusb_device_handle* device_handle, const std::string& serial) {
+    auto os_desc = get_descriptor(device_handle, 0x03, 0xEE, 0x12);
+    if (!os_desc) {
+        errx(1, "failed to retrieve MS OS descriptor");
+    }
+
+    if (os_desc->size() != 0x12) {
+        errx(1, "os descriptor size mismatch");
+    }
+
+    if (memcmp(os_desc->data() + 2, u"MSFT100\0", 14) != 0) {
+        errx(1, "os descriptor signature mismatch");
+    }
+
+    uint8_t vendor_code = (*os_desc)[16];
+    uint8_t pad = (*os_desc)[17];
+
+    if (pad != 0) {
+        errx(1, "os descriptor padding non-zero");
+    }
+
+    std::vector<uint8_t> data;
+    data.resize(0x10);
+    int rc = libusb_control_transfer(device_handle, 0xC0, vendor_code, 0x00, 0x04, data.data(),
+                                     data.size(), 0);
+    if (rc != 0x10) {
+        errx(1, "failed to retrieve MS OS v1 compat descriptor header: %s", libusb_error_name(rc));
+    }
+
+    struct __attribute__((packed)) ms_os_desc_v1_header {
+        uint32_t dwLength;
+        uint16_t bcdVersion;
+        uint16_t wIndex;
+        uint8_t bCount;
+        uint8_t reserved[7];
+    };
+    static_assert(sizeof(ms_os_desc_v1_header) == 0x10);
+
+    ms_os_desc_v1_header hdr;
+    memcpy(&hdr, data.data(), data.size());
+
+    data.resize(hdr.dwLength);
+    rc = libusb_control_transfer(device_handle, 0xC0, vendor_code, 0x00, 0x04, data.data(),
+                                 data.size(), 0);
+    if (static_cast<size_t>(rc) != data.size()) {
+        errx(1, "failed to retrieve MS OS v1 compat descriptor: %s", libusb_error_name(rc));
+    }
+
+    memcpy(&hdr, data.data(), data.size());
+
+    struct __attribute__((packed)) ms_os_desc_v1_function {
+        uint8_t bFirstInterfaceNumber;
+        uint8_t reserved1;
+        uint8_t compatibleID[8];
+        uint8_t subCompatibleID[8];
+        uint8_t reserved2[6];
+    };
+
+    if (sizeof(ms_os_desc_v1_header) + hdr.bCount * sizeof(ms_os_desc_v1_function) != data.size()) {
+        errx(1, "MS OS v1 compat descriptor size mismatch");
+    }
+
+    for (int i = 0; i < hdr.bCount; ++i) {
+        ms_os_desc_v1_function function;
+        memcpy(&function,
+               data.data() + sizeof(ms_os_desc_v1_header) + i * sizeof(ms_os_desc_v1_function),
+               sizeof(function));
+        if (memcmp("WINUSB\0\0", function.compatibleID, 8) == 0) {
+            return;
+        }
+    }
+
+    errx(1, "failed to find v1 MS OS descriptor specifying WinUSB for device %s", serial.c_str());
+}
+
+static void check_ms_os_desc_v2(libusb_device_handle* device_handle, const std::string& serial) {
+    libusb_bos_descriptor* bos;
+    int rc = libusb_get_bos_descriptor(device_handle, &bos);
+
+    if (rc != 0) {
+        fprintf(stderr, "failed to get bos descriptor for device %s\n", serial.c_str());
+        return;
+    }
+
+    for (size_t i = 0; i < bos->bNumDeviceCaps; ++i) {
+        libusb_bos_dev_capability_descriptor* desc = bos->dev_capability[i];
+        if (desc->bDescriptorType != LIBUSB_DT_DEVICE_CAPABILITY) {
+            errx(1, "invalid BOS descriptor type: %d", desc->bDescriptorType);
+        }
+
+        if (desc->bDevCapabilityType != 0x05 /* PLATFORM */) {
+            fprintf(stderr, "skipping non-platform dev capability: %#02x\n",
+                    desc->bDevCapabilityType);
+            continue;
+        }
+
+        if (desc->bLength < sizeof(*desc) + 16) {
+            errx(1, "received device capability descriptor not long enough to contain a UUID?");
+        }
+
+        char uuid[16];
+        memcpy(uuid, desc->dev_capability_data, 16);
+
+        constexpr uint8_t ms_os_uuid[16] = {0xD8, 0xDD, 0x60, 0xDF, 0x45, 0x89, 0x4C, 0xC7,
+                                            0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F};
+        if (memcmp(uuid, ms_os_uuid, 16) != 0) {
+            fprintf(stderr, "skipping unknown UUID\n");
+            continue;
+        }
+
+        size_t data_length = desc->bLength - sizeof(*desc) - 16;
+        fprintf(stderr, "found MS OS 2.0 descriptor, length = %zu\n", data_length);
+
+        // Linux does not appear to support MS OS 2.0 Descriptors.
+        // TODO: If and when it does, verify that we're emitting them properly.
+    }
+}
+
+int main(int argc, char** argv) {
+    libusb_context* ctx;
+    if (libusb_init(&ctx) != 0) {
+        errx(1, "failed to initialize libusb context");
+    }
+
+    libusb_device** device_list = nullptr;
+    ssize_t device_count = libusb_get_device_list(ctx, &device_list);
+    if (device_count < 0) {
+        errx(1, "libusb_get_device_list failed");
+    }
+
+    const char* expected_serial = getenv("ANDROID_SERIAL");
+    bool found = false;
+
+    for (ssize_t i = 0; i < device_count; ++i) {
+        libusb_device* device = device_list[i];
+        if (!is_adb_device(device)) {
+            continue;
+        }
+
+        libusb_device_handle* device_handle = nullptr;
+        int rc = libusb_open(device, &device_handle);
+        if (rc != 0) {
+            fprintf(stderr, "failed to open device %u:%u: %s\n", libusb_get_bus_number(device),
+                    libusb_get_port_number(device), libusb_error_name(rc));
+            continue;
+        }
+
+        libusb_device_descriptor device_desc;
+        libusb_get_device_descriptor(device, &device_desc);
+
+        std::optional<std::string> serial =
+                get_string_descriptor(device_handle, device_desc.iSerialNumber);
+        if (!serial) {
+            errx(1, "failed to get serial for device %u:%u", libusb_get_bus_number(device),
+                 libusb_get_port_number(device));
+        }
+
+        if (expected_serial && *serial != expected_serial) {
+            fprintf(stderr, "skipping %s (wanted %s)\n", serial->c_str(), expected_serial);
+            continue;
+        }
+
+        // Check for MS OS Descriptor v1.
+        // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeusb/c2f351f9-84d2-4a1b-9fe3-a6ca195f84d0
+        fprintf(stderr, "fetching v1 OS descriptor from device %s\n", serial->c_str());
+        check_ms_os_desc_v1(device_handle, *serial);
+        fprintf(stderr, "found v1 OS descriptor for device %s\n", serial->c_str());
+
+        // Read BOS for MS OS Descriptor 2.0 descriptors:
+        // http://download.microsoft.com/download/3/5/6/3563ED4A-F318-4B66-A181-AB1D8F6FD42D/MS_OS_2_0_desc.docx
+        fprintf(stderr, "fetching v2 OS descriptor from device %s\n", serial->c_str());
+        check_ms_os_desc_v2(device_handle, *serial);
+
+        found = true;
+    }
+
+    if (expected_serial && !found) {
+        errx(1, "failed to find device with serial %s", expected_serial);
+    }
+    return 0;
+}
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 716fe95..978eed0 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -134,8 +134,6 @@
         "libfs_mgr",
         "libgsi",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "liblp",
         "libsparse",
diff --git a/fs_mgr/README.overlayfs.md b/fs_mgr/README.overlayfs.md
index fe2e052..bb63df8 100644
--- a/fs_mgr/README.overlayfs.md
+++ b/fs_mgr/README.overlayfs.md
@@ -1,33 +1,27 @@
-Android Overlayfs integration with adb remount
+Android OverlayFS Integration with adb Remount
 ==============================================
 
 Introduction
 ------------
 
-Users working with userdebug or eng builds expect to be able to
-remount the system partition as read-write and then add or modify
-any number of files without reflashing the system image, which is
-understandably efficient for a development cycle.
-Limited memory systems that chose to use readonly filesystems like
-*squashfs*, or *Logical Resizable Android Partitions* which land
-system partition images right-sized, and with filesystem that have
-been deduped on the block level to compress the content; means that
-either a remount is not possible directly, or when done offers
-little or no utility because of remaining space limitations or
-support logistics.
+Users working with userdebug or eng builds expect to be able to remount the
+system partition as read-write and then add or modify any number of files
+without reflashing the system image, which is efficient for a development cycle.
 
-*Overlayfs* comes to the rescue for these debug scenarios, and logic
-will _automatically_ setup backing storage for a writable filesystem
-as an upper reference, and mount overtop the lower.  These actions
-will be performed in the **adb disable-verity** and **adb remount**
-requests.
+Limited memory systems use read-only types of file systems or logical resizable
+Android partitions (LRAPs). These file systems land system partition images
+right-sized, and have been deduped at the block level to compress the content.
+This means that a remount either isn’t possible, or isn't useful because of
+space limitations or support logistics.
 
-Operations
-----------
+OverlayFS resolves these debug scenarios with the _adb disable-verity_ and
+_adb remount_ commands, which set up backing storage for a writable file
+system as an upper reference, and mount the lower reference on top.
 
-### Cookbook
+Performing a remount
+--------------------
 
-The typical action to utilize the remount facility is:
+Use the following sequence to perform the remount.
 
     $ adb root
     $ adb disable-verity
@@ -36,7 +30,7 @@
     $ adb root
     $ adb remount
 
-Followed by one of the following:
+Then enter one of the following sequences:
 
     $ adb stop
     $ adb sync
@@ -48,75 +42,67 @@
     $ adb push <source> <destination>
     $ adb reboot
 
-Note that the sequence above:
+Note that you can replace these two lines:
 
     $ adb disable-verity
     $ adb reboot
 
-*or*
-
-    $ adb remount
-
-can be replaced in both places with:
+with this line:
 
     $ adb remount -R
 
-which will not reboot if everything is already prepared and ready
-to go.
+**Note:** _adb reboot -R_ won’t reboot if the device is already in the adb remount state.
 
-None of this changes if *overlayfs* needs to be engaged.
-The decisions whether to use traditional direct filesystem remount,
-or one wrapped by *overlayfs* is automatically determined based on
-a probe of the filesystem types and space remaining.
+None of this changes if OverlayFS needs to be engaged.
+The decisions whether to use traditional direct file-system remount,
+or one wrapped by OverlayFS is automatically determined based on
+a probe of the file-system types and space remaining.
 
 ### Backing Storage
 
-When *overlayfs* logic is feasible, it will use either the
+When *OverlayFS* logic is feasible, it uses either the
 **/cache/overlay/** directory for non-A/B devices, or the
 **/mnt/scratch/overlay** directory for A/B devices that have
-access to *Logical Resizable Android Partitions*.
+access to *LRAP*.
+It is also possible for an A/B device to use the system_<other> partition
+for backing storage. eg: if booting off system_a+vendor_a, use system_b.
 The backing store is used as soon as possible in the boot
-process and can occur at first stage init, or at the
-mount_all init rc commands.
+process and can occur at first stage init, or when the
+*mount_all* commands are run in init RC scripts.
 
-This early as possible attachment of *overlayfs* means that
-*sepolicy* or *init* itself can also be pushed and used after
-the exec phases that accompany each stage.
+By attaching OverlayFS early, SEpolicy or init can be pushed and used after the exec phases of each stage.
 
 Caveats
 -------
 
-- Space used in the backing storage is on a file by file basis
-  and will require more space than if updated in place.  As such
-  it is important to be mindful of any wasted space, for instance
-  **BOARD_<partition>IMAGE_PARTITION_RESERVED_SIZE** being defined
-  will have a negative impact on the overall right-sizing of images
-  and thus free dynamic partition space.
-- Kernel must have CONFIG_OVERLAY_FS=y and will need to be patched
-  with "*overlayfs: override_creds=off option bypass creator_cred*"
-  if kernel is 4.4 or higher.
+- Backing storage requires more space than immutable storage, as backing is
+  done file by file. Be mindful of wasted space. For example, defining
+  **BOARD_IMAGE_PARTITION_RESERVED_SIZE** has a negative impact on the
+  right-sizing of images and requires more free dynamic partition space.
+- The kernel requires **CONFIG_OVERLAY_FS=y**. If the kernel version is higher
+  than 4.4, it requires source to be in line with android-common kernels. 
   The patch series is available on the upstream mailing list and the latest as
-  of Jul 24 2019 is https://lore.kernel.org/patchwork/patch/1104577/.
-  This patch adds an override_creds _mount_ option to overlayfs that
+  of Sep 5 2019 is https://www.spinics.net/lists/linux-mtd/msg08331.html
+  This patch adds an override_creds _mount_ option to OverlayFS that
   permits legacy behavior for systems that do not have overlapping
   sepolicy rules, principals of least privilege, which is how Android behaves.
-- *adb enable-verity* will free up overlayfs and as a bonus the
-  device will be reverted pristine to before any content was updated.
-  Update engine does not take advantage of this, will perform a full OTA.
-- Update engine may not run if *fs_mgr_overlayfs_is_setup*() reports
-  true as adb remount overrides are incompatible with an OTA resources.
+  For 4.19 and higher a rework of the xattr handling to deal with recursion
+  is required. https://patchwork.kernel.org/patch/11117145/ is a start of that
+  adjustment.
+- _adb enable-verity_ frees up OverlayFS and reverts the device to the state
+  prior to content updates. The update engine performs a full OTA.
+- _adb remount_ overrides are incompatible with OTA resources, so the update
+  engine may not run if fs_mgr_overlayfs_is_setup() returns true.
+- If a dynamic partition runs out of space, making a logical partition larger
+  may fail because of the scratch partition. If this happens, clear the scratch
+  storage by running either either _fastboot flashall_ or _adb enable-verity_.
+  Then reinstate the overrides and continue.
 - For implementation simplicity on retrofit dynamic partition devices,
   take the whole alternate super (eg: if "*a*" slot, then the whole of
   "*system_b*").
   Since landing a filesystem on the alternate super physical device
   without differentiating if it is setup to support logical or physical,
   the alternate slot metadata and previous content will be lost.
-- If dynamic partitions runs out of space, resizing a logical
-  partition larger may fail because of the scratch partition.
-  If this happens, either fastboot flashall or adb enable-verity can
-  be used to clear scratch storage to permit the flash.
-  Then reinstate the overrides and continue.
-- File bugs or submit fixes for review.
 - There are other subtle caveats requiring complex logic to solve.
   Have evaluated them as too complex or not worth the trouble, please
   File a bug if a use case needs to be covered.
@@ -125,7 +111,7 @@
     out and we reserve the right to not inform, if the layering
     does not prevent any messaging.
   - Space remaining threshold is hard coded.  If 1% or more space
-    still remains, overlayfs will not be used, yet that amount of
+    still remains, OverlayFS will not be used, yet that amount of
     space remaining is problematic.
   - Flashing a partition via bootloader fastboot, as opposed to user
     space fastbootd, is not detected, thus a partition may have
@@ -139,3 +125,4 @@
     to confusion.  When debugging using **adb remount** it is
     currently advised to confirm update is present after a reboot
     to develop confidence.
+- File bugs or submit fixes for review.
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index bc197cd..4dbacd7 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -706,10 +706,12 @@
 
 // For GSI to skip mounting /product and /system_ext, until there are well-defined interfaces
 // between them and /system. Otherwise, the GSI flashed on /system might not be able to work with
-// /product and /system_ext. When they're skipped here, /system/product and /system/system_ext in
-// GSI will be used.
+// device-specific /product and /system_ext. skip_mount.cfg belongs to system_ext partition because
+// only common files for all targets can be put into system partition. It is under
+// /system/system_ext because GSI is a single system.img that includes the contents of system_ext
+// partition and product partition under /system/system_ext and /system/product, respectively.
 bool SkipMountingPartitions(Fstab* fstab) {
-    constexpr const char kSkipMountConfig[] = "/system/etc/init/config/skip_mount.cfg";
+    constexpr const char kSkipMountConfig[] = "/system/system_ext/etc/init/config/skip_mount.cfg";
 
     std::string skip_config;
     auto save_errno = errno;
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index 58a88b5..6b842b3 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -17,6 +17,7 @@
 #include "images.h"
 
 #include <limits.h>
+#include <sys/stat.h>
 
 #include <android-base/file.h>
 
@@ -27,12 +28,45 @@
 namespace android {
 namespace fs_mgr {
 
+using android::base::borrowed_fd;
 using android::base::unique_fd;
 
 #if defined(_WIN32)
 static const int O_NOFOLLOW = 0;
 #endif
 
+static bool IsEmptySuperImage(borrowed_fd fd) {
+    struct stat s;
+    if (fstat(fd.get(), &s) < 0) {
+        PERROR << __PRETTY_FUNCTION__ << " fstat failed";
+        return false;
+    }
+    if (s.st_size < LP_METADATA_GEOMETRY_SIZE) {
+        return false;
+    }
+
+    // Rewind back to the start, read the geometry struct.
+    LpMetadataGeometry geometry = {};
+    if (SeekFile64(fd.get(), 0, SEEK_SET) < 0) {
+        PERROR << __PRETTY_FUNCTION__ << " lseek failed";
+        return false;
+    }
+    if (!android::base::ReadFully(fd, &geometry, sizeof(geometry))) {
+        PERROR << __PRETTY_FUNCTION__ << " read failed";
+        return false;
+    }
+    return geometry.magic == LP_METADATA_GEOMETRY_MAGIC;
+}
+
+bool IsEmptySuperImage(const std::string& file) {
+    unique_fd fd = GetControlFileOrOpen(file, O_RDONLY | O_CLOEXEC);
+    if (fd < 0) {
+        PERROR << __PRETTY_FUNCTION__ << " open failed";
+        return false;
+    }
+    return IsEmptySuperImage(fd);
+}
+
 std::unique_ptr<LpMetadata> ReadFromImageFile(int fd) {
     std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
     if (SeekFile64(fd, 0, SEEK_SET) < 0) {
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index 135a1b3..cd860cd 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -70,8 +70,15 @@
                           uint32_t slot_number);
 std::unique_ptr<LpMetadata> ReadMetadata(const std::string& super_partition, uint32_t slot_number);
 
+// Returns whether an image is an "empty" image or not. An empty image contains
+// only metadata. Unlike a flashed block device, there are no reserved bytes or
+// backup sections, and only one slot is stored (even if multiple slots are
+// supported). It is a format specifically for storing only metadata.
+bool IsEmptySuperImage(const std::string& file);
+
 // Read/Write logical partition metadata to an image file, for diagnostics or
-// flashing.
+// flashing. If no partition images are specified, the file will be in the
+// empty format.
 bool WriteToImageFile(const std::string& file, const LpMetadata& metadata, uint32_t block_size,
                       const std::map<std::string, std::string>& images, bool sparsify);
 bool WriteToImageFile(const std::string& file, const LpMetadata& metadata);
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index afcce8f..48c5c83 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -205,9 +205,9 @@
 #endif
 }
 
-base::unique_fd GetControlFileOrOpen(const char* path, int flags) {
+base::unique_fd GetControlFileOrOpen(std::string_view path, int flags) {
 #if defined(__ANDROID__)
-    int fd = android_get_control_file(path);
+    int fd = android_get_control_file(path.data());
     if (fd >= 0) {
         int newfd = TEMP_FAILURE_RETRY(dup(fd));
         if (newfd >= 0) {
@@ -216,7 +216,7 @@
         PERROR << "Cannot dup fd for already controlled file: " << path << ", reopening...";
     }
 #endif
-    return base::unique_fd(open(path, flags));
+    return base::unique_fd(open(path.data(), flags));
 }
 
 bool UpdateMetadataForInPlaceSnapshot(LpMetadata* metadata, uint32_t source_slot_number,
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index 25ab66b..0661769 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -21,6 +21,9 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <string>
+#include <string_view>
+
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 
@@ -94,7 +97,7 @@
 // Call BLKROSET ioctl on fd so that fd is readonly / read-writable.
 bool SetBlockReadonly(int fd, bool readonly);
 
-::android::base::unique_fd GetControlFileOrOpen(const char* path, int flags);
+::android::base::unique_fd GetControlFileOrOpen(std::string_view path, int flags);
 
 // For Virtual A/B updates, modify |metadata| so that it can be written to |target_slot_number|.
 bool UpdateMetadataForInPlaceSnapshot(LpMetadata* metadata, uint32_t source_slot_number,
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index a54db58..8df9c52 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -49,6 +49,7 @@
     name: "libsnapshot_sources",
     srcs: [
         "snapshot.cpp",
+        "utility.cpp",
     ],
 }
 
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 6f0e804..c41a951 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -211,25 +211,44 @@
     std::unique_ptr<LockedFile> OpenFile(const std::string& file, int open_flags, int lock_flags);
     bool Truncate(LockedFile* file);
 
+    enum class SnapshotState : int { None, Created, Merging, MergeCompleted };
+    static std::string to_string(SnapshotState state);
+
+    // This state is persisted per-snapshot in /metadata/ota/snapshots/.
+    struct SnapshotStatus {
+        SnapshotState state = SnapshotState::None;
+        uint64_t device_size = 0;
+        uint64_t snapshot_size = 0;
+        uint64_t cow_partition_size = 0;
+        uint64_t cow_file_size = 0;
+
+        // These are non-zero when merging.
+        uint64_t sectors_allocated = 0;
+        uint64_t metadata_sectors = 0;
+    };
+
     // Create a new snapshot record. This creates the backing COW store and
     // persists information needed to map the device. The device can be mapped
     // with MapSnapshot().
     //
-    // |device_size| should be the size of the base_device that will be passed
-    // via MapDevice(). |snapshot_size| should be the number of bytes in the
-    // base device, starting from 0, that will be snapshotted. The cow_size
+    // |status|.device_size should be the size of the base_device that will be passed
+    // via MapDevice(). |status|.snapshot_size should be the number of bytes in the
+    // base device, starting from 0, that will be snapshotted. |status|.cow_file_size
     // should be the amount of space that will be allocated to store snapshot
     // deltas.
     //
-    // If |snapshot_size| < device_size, then the device will always
+    // If |status|.snapshot_size < |status|.device_size, then the device will always
     // be mapped with two table entries: a dm-snapshot range covering
     // snapshot_size, and a dm-linear range covering the remainder.
     //
-    // All sizes are specified in bytes, and the device and snapshot sizes
-    // must be a multiple of the sector size (512 bytes). |cow_size| will
-    // be rounded up to the nearest sector.
-    bool CreateSnapshot(LockedFile* lock, const std::string& name, uint64_t device_size,
-                        uint64_t snapshot_size, uint64_t cow_size);
+    // All sizes are specified in bytes, and the device, snapshot and COW partition sizes
+    // must be a multiple of the sector size (512 bytes). COW file size will be rounded up
+    // to the nearest sector.
+    bool CreateSnapshot(LockedFile* lock, const std::string& name, SnapshotStatus status);
+
+    // |name| should be the base partition name (e.g. "system_a"). Create the
+    // backing COW image using the size previously passed to CreateSnapshot().
+    bool CreateCowImage(LockedFile* lock, const std::string& name);
 
     // Map a snapshot device that was previously created with CreateSnapshot.
     // If a merge was previously initiated, the device-mapper table will have a
@@ -239,15 +258,23 @@
     // timeout_ms is 0, then no wait will occur and |dev_path| may not yet
     // exist on return.
     bool MapSnapshot(LockedFile* lock, const std::string& name, const std::string& base_device,
-                     const std::chrono::milliseconds& timeout_ms, std::string* dev_path);
+                     const std::string& cow_device, const std::chrono::milliseconds& timeout_ms,
+                     std::string* dev_path);
 
-    // Remove the backing copy-on-write image for the named snapshot. The
+    // Map a COW image that was previous created with CreateCowImage.
+    bool MapCowImage(const std::string& name, const std::chrono::milliseconds& timeout_ms,
+                     std::string* cow_image_device);
+
+    // Remove the backing copy-on-write image and snapshot states for the named snapshot. The
     // caller is responsible for ensuring that the snapshot is unmapped.
     bool DeleteSnapshot(LockedFile* lock, const std::string& name);
 
     // Unmap a snapshot device previously mapped with MapSnapshotDevice().
     bool UnmapSnapshot(LockedFile* lock, const std::string& name);
 
+    // Unmap a COW image device previously mapped with MapCowImage().
+    bool UnmapCowImage(const std::string& name);
+
     // Unmap and remove all known snapshots.
     bool RemoveAllSnapshots(LockedFile* lock);
 
@@ -270,22 +297,6 @@
     bool WriteUpdateState(LockedFile* file, UpdateState state);
     std::string GetStateFilePath() const;
 
-    enum class SnapshotState : int { Created, Merging, MergeCompleted };
-    static std::string to_string(SnapshotState state);
-
-    // This state is persisted per-snapshot in /metadata/ota/snapshots/.
-    struct SnapshotStatus {
-        SnapshotState state;
-        uint64_t device_size;
-        uint64_t snapshot_size;
-        uint64_t cow_partition_size;
-        uint64_t cow_file_size;
-
-        // These are non-zero when merging.
-        uint64_t sectors_allocated = 0;
-        uint64_t metadata_sectors = 0;
-    };
-
     // Helpers for merging.
     bool SwitchSnapshotToMerge(LockedFile* lock, const std::string& name);
     bool RewriteSnapshotDeviceTable(const std::string& dm_name);
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 7e57421..5813a2d 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -36,6 +36,8 @@
 #include <libfiemap/image_manager.h>
 #include <liblp/liblp.h>
 
+#include "utility.h"
+
 namespace android {
 namespace snapshot {
 
@@ -54,6 +56,7 @@
 using android::fs_mgr::GetPartitionName;
 using android::fs_mgr::LpMetadata;
 using android::fs_mgr::SlotNumberForSlotSuffix;
+using std::chrono::duration_cast;
 using namespace std::chrono_literals;
 using namespace std::string_literals;
 
@@ -99,10 +102,14 @@
     metadata_dir_ = device_->GetMetadataDir();
 }
 
-static std::string GetCowName(const std::string& snapshot_name) {
+[[maybe_unused]] static std::string GetCowName(const std::string& snapshot_name) {
     return snapshot_name + "-cow";
 }
 
+static std::string GetCowImageDeviceName(const std::string& snapshot_name) {
+    return snapshot_name + "-cow-img";
+}
+
 static std::string GetBaseDeviceName(const std::string& partition_name) {
     return partition_name + "-base";
 }
@@ -129,11 +136,27 @@
 
     UpdateState state = ReadUpdateState(file.get());
     if (state == UpdateState::None) return true;
-    if (state != UpdateState::Initiated) {
-        LOG(ERROR) << "Cannot cancel update after it has completed or started merging";
-        return false;
+
+    if (state == UpdateState::Initiated) {
+        LOG(INFO) << "Update has been initiated, now canceling";
+        return RemoveAllUpdateState(file.get());
     }
-    return RemoveAllUpdateState(file.get());
+
+    if (state == UpdateState::Unverified) {
+        // We completed an update, but it can still be canceled if we haven't booted into it.
+        auto boot_file = GetSnapshotBootIndicatorPath();
+        std::string contents;
+        if (!android::base::ReadFileToString(boot_file, &contents)) {
+            PLOG(WARNING) << "Cannot read " << boot_file << ", proceed to canceling the update:";
+            return RemoveAllUpdateState(file.get());
+        }
+        if (device_->GetSlotSuffix() == contents) {
+            LOG(INFO) << "Canceling a previously completed update";
+            return RemoveAllUpdateState(file.get());
+        }
+    }
+    LOG(ERROR) << "Cannot cancel update after it has completed or started merging";
+    return false;
 }
 
 bool SnapshotManager::RemoveAllUpdateState(LockedFile* lock) {
@@ -177,49 +200,60 @@
 }
 
 bool SnapshotManager::CreateSnapshot(LockedFile* lock, const std::string& name,
-                                     uint64_t device_size, uint64_t snapshot_size,
-                                     uint64_t cow_size) {
+                                     SnapshotManager::SnapshotStatus status) {
     CHECK(lock);
-    if (!EnsureImageManager()) return false;
-
+    CHECK(lock->lock_mode() == LOCK_EX);
     // Sanity check these sizes. Like liblp, we guarantee the partition size
     // is respected, which means it has to be sector-aligned. (This guarantee
     // is useful for locating avb footers correctly). The COW size, however,
     // can be arbitrarily larger than specified, so we can safely round it up.
-    if (device_size % kSectorSize != 0) {
+    if (status.device_size % kSectorSize != 0) {
         LOG(ERROR) << "Snapshot " << name
-                   << " device size is not a multiple of the sector size: " << device_size;
+                   << " device size is not a multiple of the sector size: " << status.device_size;
         return false;
     }
-    if (snapshot_size % kSectorSize != 0) {
-        LOG(ERROR) << "Snapshot " << name
-                   << " snapshot size is not a multiple of the sector size: " << snapshot_size;
+    if (status.snapshot_size % kSectorSize != 0) {
+        LOG(ERROR) << "Snapshot " << name << " snapshot size is not a multiple of the sector size: "
+                   << status.snapshot_size;
         return false;
     }
 
     // Round the COW size up to the nearest sector.
-    cow_size += kSectorSize - 1;
-    cow_size &= ~(kSectorSize - 1);
+    status.cow_file_size += kSectorSize - 1;
+    status.cow_file_size &= ~(kSectorSize - 1);
 
-    LOG(INFO) << "Snapshot " << name << " will have COW size " << cow_size;
+    status.state = SnapshotState::Created;
+    status.sectors_allocated = 0;
+    status.metadata_sectors = 0;
 
-    // Note, we leave the status file hanging around if we fail to create the
-    // actual backing image. This is harmless, since it'll get removed when
-    // CancelUpdate is called.
-    SnapshotStatus status = {
-            .state = SnapshotState::Created,
-            .device_size = device_size,
-            .snapshot_size = snapshot_size,
-            .cow_file_size = cow_size,
-    };
     if (!WriteSnapshotStatus(lock, name, status)) {
         PLOG(ERROR) << "Could not write snapshot status: " << name;
         return false;
     }
+    return true;
+}
 
-    auto cow_name = GetCowName(name);
+bool SnapshotManager::CreateCowImage(LockedFile* lock, const std::string& name) {
+    CHECK(lock);
+    CHECK(lock->lock_mode() == LOCK_EX);
+    if (!EnsureImageManager()) return false;
+
+    SnapshotStatus status;
+    if (!ReadSnapshotStatus(lock, name, &status)) {
+        return false;
+    }
+
+    // The COW file size should have been rounded up to the nearest sector in CreateSnapshot.
+    // Sanity check this.
+    if (status.cow_file_size % kSectorSize != 0) {
+        LOG(ERROR) << "Snapshot " << name << " COW file size is not a multiple of the sector size: "
+                   << status.cow_file_size;
+        return false;
+    }
+
+    std::string cow_image_name = GetCowImageDeviceName(name);
     int cow_flags = IImageManager::CREATE_IMAGE_DEFAULT;
-    if (!images_->CreateBackingImage(cow_name, cow_size, cow_flags)) {
+    if (!images_->CreateBackingImage(cow_image_name, status.cow_file_size, cow_flags)) {
         return false;
     }
 
@@ -238,11 +272,11 @@
     // workaround that will be discussed again when the kernel API gets
     // consolidated.
     ssize_t dm_snap_magic_size = 4;  // 32 bit
-    return images_->ZeroFillNewImage(cow_name, dm_snap_magic_size);
+    return images_->ZeroFillNewImage(cow_image_name, dm_snap_magic_size);
 }
 
 bool SnapshotManager::MapSnapshot(LockedFile* lock, const std::string& name,
-                                  const std::string& base_device,
+                                  const std::string& base_device, const std::string& cow_device,
                                   const std::chrono::milliseconds& timeout_ms,
                                   std::string* dev_path) {
     CHECK(lock);
@@ -288,22 +322,7 @@
     uint64_t snapshot_sectors = status.snapshot_size / kSectorSize;
     uint64_t linear_sectors = (status.device_size - status.snapshot_size) / kSectorSize;
 
-    auto cow_name = GetCowName(name);
 
-    bool ok;
-    std::string cow_dev;
-    if (has_local_image_manager_) {
-        // If we forced a local image manager, it means we don't have binder,
-        // which means first-stage init. We must use device-mapper.
-        const auto& opener = device_->GetPartitionOpener();
-        ok = images_->MapImageWithDeviceMapper(opener, cow_name, &cow_dev);
-    } else {
-        ok = images_->MapImageDevice(cow_name, timeout_ms, &cow_dev);
-    }
-    if (!ok) {
-        LOG(ERROR) << "Could not map image device: " << cow_name;
-        return false;
-    }
 
     auto& dm = DeviceMapper::Instance();
 
@@ -335,27 +354,31 @@
     auto snap_name = (linear_sectors > 0) ? GetSnapshotExtraDeviceName(name) : name;
 
     DmTable table;
-    table.Emplace<DmTargetSnapshot>(0, snapshot_sectors, base_device, cow_dev, mode,
+    table.Emplace<DmTargetSnapshot>(0, snapshot_sectors, base_device, cow_device, mode,
                                     kSnapshotChunkSize);
     if (!dm.CreateDevice(snap_name, table, dev_path, timeout_ms)) {
         LOG(ERROR) << "Could not create snapshot device: " << snap_name;
-        images_->UnmapImageDevice(cow_name);
         return false;
     }
 
     if (linear_sectors) {
+        std::string snap_dev;
+        if (!dm.GetDeviceString(snap_name, &snap_dev)) {
+            LOG(ERROR) << "Cannot determine major/minor for: " << snap_name;
+            return false;
+        }
+
         // Our stacking will looks like this:
         //     [linear, linear] ; to snapshot, and non-snapshot region of base device
         //     [snapshot-inner]
         //     [base device]   [cow]
         DmTable table;
-        table.Emplace<DmTargetLinear>(0, snapshot_sectors, *dev_path, 0);
+        table.Emplace<DmTargetLinear>(0, snapshot_sectors, snap_dev, 0);
         table.Emplace<DmTargetLinear>(snapshot_sectors, linear_sectors, base_device,
                                       snapshot_sectors);
         if (!dm.CreateDevice(name, table, dev_path, timeout_ms)) {
             LOG(ERROR) << "Could not create outer snapshot device: " << name;
             dm.DeleteDevice(snap_name);
-            images_->UnmapImageDevice(cow_name);
             return false;
         }
     }
@@ -366,9 +389,29 @@
     return true;
 }
 
+bool SnapshotManager::MapCowImage(const std::string& name,
+                                  const std::chrono::milliseconds& timeout_ms,
+                                  std::string* cow_dev) {
+    if (!EnsureImageManager()) return false;
+    auto cow_image_name = GetCowImageDeviceName(name);
+
+    bool ok;
+    if (has_local_image_manager_) {
+        // If we forced a local image manager, it means we don't have binder,
+        // which means first-stage init. We must use device-mapper.
+        const auto& opener = device_->GetPartitionOpener();
+        ok = images_->MapImageWithDeviceMapper(opener, cow_image_name, cow_dev);
+    } else {
+        ok = images_->MapImageDevice(cow_image_name, timeout_ms, cow_dev);
+    }
+    if (!ok) {
+        LOG(ERROR) << "Could not map image device: " << cow_image_name;
+    }
+    return ok;
+}
+
 bool SnapshotManager::UnmapSnapshot(LockedFile* lock, const std::string& name) {
     CHECK(lock);
-    if (!EnsureImageManager()) return false;
 
     SnapshotStatus status;
     if (!ReadSnapshotStatus(lock, name, &status)) {
@@ -389,23 +432,25 @@
         return false;
     }
 
-    auto cow_name = GetCowName(name);
-    if (images_->IsImageMapped(cow_name) && !images_->UnmapImageDevice(cow_name)) {
-        return false;
-    }
     return true;
 }
 
+bool SnapshotManager::UnmapCowImage(const std::string& name) {
+    if (!EnsureImageManager()) return false;
+    return images_->UnmapImageIfExists(GetCowImageDeviceName(name));
+}
+
 bool SnapshotManager::DeleteSnapshot(LockedFile* lock, const std::string& name) {
     CHECK(lock);
+    CHECK(lock->lock_mode() == LOCK_EX);
     if (!EnsureImageManager()) return false;
 
-    auto cow_name = GetCowName(name);
-    if (images_->BackingImageExists(cow_name)) {
-        if (images_->IsImageMapped(cow_name) && !images_->UnmapImageDevice(cow_name)) {
+    auto cow_image_name = GetCowImageDeviceName(name);
+    if (images_->BackingImageExists(cow_image_name)) {
+        if (!images_->UnmapImageIfExists(cow_image_name)) {
             return false;
         }
-        if (!images_->DeleteBackingImage(cow_name)) {
+        if (!images_->DeleteBackingImage(cow_image_name)) {
             return false;
         }
     }
@@ -904,8 +949,8 @@
         return false;
     }
 
-    uint64_t num_sectors = status.snapshot_size / kSectorSize;
-    if (num_sectors * kSectorSize != status.snapshot_size) {
+    uint64_t snapshot_sectors = status.snapshot_size / kSectorSize;
+    if (snapshot_sectors * kSectorSize != status.snapshot_size) {
         LOG(ERROR) << "Snapshot " << name
                    << " size is not sector aligned: " << status.snapshot_size;
         return false;
@@ -933,10 +978,16 @@
                 return false;
             }
         }
-        uint64_t sectors = outer_table[0].spec.length + outer_table[1].spec.length;
-        if (sectors != num_sectors) {
-            LOG(ERROR) << "Outer snapshot " << name << " should have " << num_sectors
-                       << ", got: " << sectors;
+        if (outer_table[0].spec.length != snapshot_sectors) {
+            LOG(ERROR) << "dm-snapshot " << name << " should have " << snapshot_sectors
+                       << " sectors, got: " << outer_table[0].spec.length;
+            return false;
+        }
+        uint64_t expected_device_sectors = status.device_size / kSectorSize;
+        uint64_t actual_device_sectors = outer_table[0].spec.length + outer_table[1].spec.length;
+        if (expected_device_sectors != actual_device_sectors) {
+            LOG(ERROR) << "Outer device " << name << " should have " << expected_device_sectors
+                       << " sectors, got: " << actual_device_sectors;
             return false;
         }
     }
@@ -1153,9 +1204,28 @@
     return true;
 }
 
+static std::chrono::milliseconds GetRemainingTime(
+        const std::chrono::milliseconds& timeout,
+        const std::chrono::time_point<std::chrono::steady_clock>& begin) {
+    // If no timeout is specified, execute all commands without specifying any timeout.
+    if (timeout.count() == 0) return std::chrono::milliseconds(0);
+    auto passed_time = std::chrono::steady_clock::now() - begin;
+    auto remaining_time = timeout - duration_cast<std::chrono::milliseconds>(passed_time);
+    if (remaining_time.count() <= 0) {
+        LOG(ERROR) << "MapPartitionWithSnapshot has reached timeout " << timeout.count() << "ms ("
+                   << remaining_time.count() << "ms remaining)";
+        // Return min() instead of remaining_time here because 0 is treated as a special value for
+        // no timeout, where the rest of the commands will still be executed.
+        return std::chrono::milliseconds::min();
+    }
+    return remaining_time;
+}
+
 bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
                                                CreateLogicalPartitionParams params,
                                                std::string* path) {
+    auto begin = std::chrono::steady_clock::now();
+
     CHECK(lock);
     path->clear();
 
@@ -1207,6 +1277,11 @@
         params.device_name = GetBaseDeviceName(params.GetPartitionName());
     }
 
+    AutoDeviceList created_devices;
+
+    // Create the base device for the snapshot, or if there is no snapshot, the
+    // device itself. This device consists of the real blocks in the super
+    // partition that this logical partition occupies.
     auto& dm = DeviceMapper::Instance();
     std::string ignore_path;
     if (!CreateLogicalPartition(params, &ignore_path)) {
@@ -1214,7 +1289,10 @@
                    << " as device " << params.GetDeviceName();
         return false;
     }
+    created_devices.EmplaceBack<AutoUnmapDevice>(&dm, params.GetDeviceName());
+
     if (!live_snapshot_status.has_value()) {
+        created_devices.Release();
         return true;
     }
 
@@ -1225,10 +1303,35 @@
         LOG(ERROR) << "Could not determine major/minor for: " << params.GetDeviceName();
         return false;
     }
-    if (!MapSnapshot(lock, params.GetPartitionName(), base_device, {}, path)) {
+
+    // If there is a timeout specified, compute the remaining time to call Map* functions.
+    // init calls CreateLogicalAndSnapshotPartitions, which has no timeout specified. Still call
+    // Map* functions in this case.
+    auto remaining_time = GetRemainingTime(params.timeout_ms, begin);
+    if (remaining_time.count() < 0) return false;
+
+    std::string cow_image_device;
+    if (!MapCowImage(params.GetPartitionName(), remaining_time, &cow_image_device)) {
+        LOG(ERROR) << "Could not map cow image for partition: " << params.GetPartitionName();
+        return false;
+    }
+    created_devices.EmplaceBack<AutoUnmapImage>(images_.get(),
+                                                GetCowImageDeviceName(params.partition_name));
+
+    // TODO: map cow linear device here
+    std::string cow_device = cow_image_device;
+
+    remaining_time = GetRemainingTime(params.timeout_ms, begin);
+    if (remaining_time.count() < 0) return false;
+
+    if (!MapSnapshot(lock, params.GetPartitionName(), base_device, cow_device, remaining_time,
+                     path)) {
         LOG(ERROR) << "Could not map snapshot for partition: " << params.GetPartitionName();
         return false;
     }
+    // No need to add params.GetPartitionName() to created_devices since it is immediately released.
+
+    created_devices.Release();
 
     LOG(INFO) << "Mapped " << params.GetPartitionName() << " as snapshot device at " << *path;
 
@@ -1373,7 +1476,9 @@
         return false;
     }
 
-    if (pieces[0] == "created") {
+    if (pieces[0] == "none") {
+        status->state = SnapshotState::None;
+    } else if (pieces[0] == "created") {
         status->state = SnapshotState::Created;
     } else if (pieces[0] == "merging") {
         status->state = SnapshotState::Merging;
@@ -1381,6 +1486,7 @@
         status->state = SnapshotState::MergeCompleted;
     } else {
         LOG(ERROR) << "Unrecognized state " << pieces[0] << " for snapshot: " << name;
+        return false;
     }
 
     if (!android::base::ParseUint(pieces[1], &status->device_size)) {
@@ -1412,6 +1518,8 @@
 
 std::string SnapshotManager::to_string(SnapshotState state) {
     switch (state) {
+        case SnapshotState::None:
+            return "none";
         case SnapshotState::Created:
             return "created";
         case SnapshotState::Merging:
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 8487339..429fd8e 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -106,7 +106,7 @@
                                               "test_partition_b"};
         for (const auto& snapshot : snapshots) {
             DeleteSnapshotDevice(snapshot);
-            DeleteBackingImage(image_manager_, snapshot + "-cow");
+            DeleteBackingImage(image_manager_, snapshot + "-cow-img");
 
             auto status_file = sm->GetSnapshotStatusFilePath(snapshot);
             android::base::RemoveFileIfExists(status_file);
@@ -214,6 +214,7 @@
     void DeleteSnapshotDevice(const std::string& snapshot) {
         DeleteDevice(snapshot);
         DeleteDevice(snapshot + "-inner");
+        ASSERT_TRUE(image_manager_->UnmapImageIfExists(snapshot + "-cow-img"));
     }
     void DeleteDevice(const std::string& device) {
         if (dm_.GetState(device) != DmDeviceState::INVALID) {
@@ -231,8 +232,11 @@
     ASSERT_TRUE(AcquireLock());
 
     static const uint64_t kDeviceSize = 1024 * 1024;
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot", kDeviceSize, kDeviceSize,
-                                   kDeviceSize));
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot",
+                                   {.device_size = kDeviceSize,
+                                    .snapshot_size = kDeviceSize,
+                                    .cow_file_size = kDeviceSize}));
+    ASSERT_TRUE(sm->CreateCowImage(lock_.get(), "test-snapshot"));
 
     std::vector<std::string> snapshots;
     ASSERT_TRUE(sm->ListSnapshots(lock_.get(), &snapshots));
@@ -249,6 +253,7 @@
     }
 
     ASSERT_TRUE(sm->UnmapSnapshot(lock_.get(), "test-snapshot"));
+    ASSERT_TRUE(sm->UnmapCowImage("test-snapshot"));
     ASSERT_TRUE(sm->DeleteSnapshot(lock_.get(), "test-snapshot"));
 }
 
@@ -256,14 +261,21 @@
     ASSERT_TRUE(AcquireLock());
 
     static const uint64_t kDeviceSize = 1024 * 1024;
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot", kDeviceSize, kDeviceSize,
-                                   kDeviceSize));
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot",
+                                   {.device_size = kDeviceSize,
+                                    .snapshot_size = kDeviceSize,
+                                    .cow_file_size = kDeviceSize}));
+    ASSERT_TRUE(sm->CreateCowImage(lock_.get(), "test-snapshot"));
 
     std::string base_device;
     ASSERT_TRUE(CreatePartition("base-device", kDeviceSize, &base_device));
 
+    std::string cow_device;
+    ASSERT_TRUE(sm->MapCowImage("test-snapshot", 10s, &cow_device));
+
     std::string snap_device;
-    ASSERT_TRUE(sm->MapSnapshot(lock_.get(), "test-snapshot", base_device, 10s, &snap_device));
+    ASSERT_TRUE(sm->MapSnapshot(lock_.get(), "test-snapshot", base_device, cow_device, 10s,
+                                &snap_device));
     ASSERT_TRUE(android::base::StartsWith(snap_device, "/dev/block/dm-"));
 }
 
@@ -272,14 +284,21 @@
 
     static const uint64_t kSnapshotSize = 1024 * 1024;
     static const uint64_t kDeviceSize = 1024 * 1024 * 2;
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot", kDeviceSize, kSnapshotSize,
-                                   kSnapshotSize));
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot",
+                                   {.device_size = kDeviceSize,
+                                    .snapshot_size = kSnapshotSize,
+                                    .cow_file_size = kSnapshotSize}));
+    ASSERT_TRUE(sm->CreateCowImage(lock_.get(), "test-snapshot"));
 
     std::string base_device;
     ASSERT_TRUE(CreatePartition("base-device", kDeviceSize, &base_device));
 
+    std::string cow_device;
+    ASSERT_TRUE(sm->MapCowImage("test-snapshot", 10s, &cow_device));
+
     std::string snap_device;
-    ASSERT_TRUE(sm->MapSnapshot(lock_.get(), "test-snapshot", base_device, 10s, &snap_device));
+    ASSERT_TRUE(sm->MapSnapshot(lock_.get(), "test-snapshot", base_device, cow_device, 10s,
+                                &snap_device));
     ASSERT_TRUE(android::base::StartsWith(snap_device, "/dev/block/dm-"));
 }
 
@@ -317,13 +336,18 @@
 
     static const uint64_t kDeviceSize = 1024 * 1024;
 
-    std::string base_device, snap_device;
+    std::string base_device, cow_device, snap_device;
     ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
     ASSERT_TRUE(MapUpdatePartitions());
     ASSERT_TRUE(dm_.GetDmDevicePathByName("test_partition_b-base", &base_device));
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b", kDeviceSize, kDeviceSize,
-                                   kDeviceSize));
-    ASSERT_TRUE(sm->MapSnapshot(lock_.get(), "test_partition_b", base_device, 10s, &snap_device));
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b",
+                                   {.device_size = kDeviceSize,
+                                    .snapshot_size = kDeviceSize,
+                                    .cow_file_size = kDeviceSize}));
+    ASSERT_TRUE(sm->CreateCowImage(lock_.get(), "test_partition_b"));
+    ASSERT_TRUE(sm->MapCowImage("test_partition_b", 10s, &cow_device));
+    ASSERT_TRUE(sm->MapSnapshot(lock_.get(), "test_partition_b", base_device, cow_device, 10s,
+                                &snap_device));
 
     std::string test_string = "This is a test string.";
     {
@@ -375,16 +399,21 @@
     ASSERT_TRUE(AcquireLock());
 
     static const uint64_t kDeviceSize = 1024 * 1024;
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot", kDeviceSize, kDeviceSize,
-                                   kDeviceSize));
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot",
+                                   {.device_size = kDeviceSize,
+                                    .snapshot_size = kDeviceSize,
+                                    .cow_file_size = kDeviceSize}));
+    ASSERT_TRUE(sm->CreateCowImage(lock_.get(), "test-snapshot"));
 
-    std::string base_device, snap_device;
+    std::string base_device, cow_device, snap_device;
     ASSERT_TRUE(CreatePartition("base-device", kDeviceSize, &base_device));
-    ASSERT_TRUE(sm->MapSnapshot(lock_.get(), "test-snapshot", base_device, 10s, &snap_device));
+    ASSERT_TRUE(sm->MapCowImage("test-snapshot", 10s, &cow_device));
+    ASSERT_TRUE(sm->MapSnapshot(lock_.get(), "test-snapshot", base_device, cow_device, 10s,
+                                &snap_device));
 
     // Keep an open handle to the cow device. This should cause the merge to
     // be incomplete.
-    auto cow_path = android::base::GetProperty("gsid.mapped_image.test-snapshot-cow", "");
+    auto cow_path = android::base::GetProperty("gsid.mapped_image.test-snapshot-cow-img", "");
     unique_fd fd(open(cow_path.c_str(), O_RDONLY | O_CLOEXEC));
     ASSERT_GE(fd, 0);
 
@@ -399,12 +428,18 @@
     // COW cannot be removed due to open fd, so expect a soft failure.
     ASSERT_EQ(sm->ProcessUpdateState(), UpdateState::MergeNeedsReboot);
 
+    // Release the handle to the COW device to fake a reboot.
+    fd.reset();
+    // Wait 1s, otherwise DeleteSnapshotDevice may fail with EBUSY.
+    sleep(1);
     // Forcefully delete the snapshot device, so it looks like we just rebooted.
     DeleteSnapshotDevice("test-snapshot");
 
     // Map snapshot should fail now, because we're in a merge-complete state.
     ASSERT_TRUE(AcquireLock());
-    ASSERT_FALSE(sm->MapSnapshot(lock_.get(), "test-snapshot", base_device, 10s, &snap_device));
+    ASSERT_TRUE(sm->MapCowImage("test-snapshot", 10s, &cow_device));
+    ASSERT_FALSE(sm->MapSnapshot(lock_.get(), "test-snapshot", base_device, cow_device, 10s,
+                                 &snap_device));
 
     // Release everything and now the merge should complete.
     fd = {};
@@ -423,8 +458,11 @@
 
     ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
     ASSERT_TRUE(MapUpdatePartitions());
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b", kDeviceSize, kDeviceSize,
-                                   kDeviceSize));
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b",
+                                   {.device_size = kDeviceSize,
+                                    .snapshot_size = kDeviceSize,
+                                    .cow_file_size = kDeviceSize}));
+    ASSERT_TRUE(sm->CreateCowImage(lock_.get(), "test_partition_b"));
 
     // Simulate a reboot into the new slot.
     lock_ = nullptr;
@@ -462,8 +500,11 @@
 
     ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
     ASSERT_TRUE(MapUpdatePartitions());
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b", kDeviceSize, kDeviceSize,
-                                   kDeviceSize));
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b",
+                                   {.device_size = kDeviceSize,
+                                    .snapshot_size = kDeviceSize,
+                                    .cow_file_size = kDeviceSize}));
+    ASSERT_TRUE(sm->CreateCowImage(lock_.get(), "test_partition_b"));
 
     // Simulate a reboot into the new slot.
     lock_ = nullptr;
@@ -507,8 +548,11 @@
 
     ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
     ASSERT_TRUE(MapUpdatePartitions());
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b", kDeviceSize, kDeviceSize,
-                                   kDeviceSize));
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b",
+                                   {.device_size = kDeviceSize,
+                                    .snapshot_size = kDeviceSize,
+                                    .cow_file_size = kDeviceSize}));
+    ASSERT_TRUE(sm->CreateCowImage(lock_.get(), "test_partition_b"));
 
     // Simulate a reboot into the new slot.
     lock_ = nullptr;
@@ -527,7 +571,7 @@
     // Now, reflash super. Note that we haven't called ProcessUpdateState, so the
     // status is still Merging.
     DeleteSnapshotDevice("test_partition_b");
-    ASSERT_TRUE(init->image_manager()->UnmapImageDevice("test_partition_b-cow"));
+    ASSERT_TRUE(init->image_manager()->UnmapImageIfExists("test_partition_b-cow-img"));
     FormatFakeSuper();
     ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize));
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
new file mode 100644
index 0000000..164b472
--- /dev/null
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -0,0 +1,56 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "utility.h"
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+namespace android {
+namespace snapshot {
+
+void AutoDevice::Release() {
+    name_.clear();
+}
+
+AutoDeviceList::~AutoDeviceList() {
+    // Destroy devices in the reverse order because newer devices may have dependencies
+    // on older devices.
+    for (auto it = devices_.rbegin(); it != devices_.rend(); ++it) {
+        it->reset();
+    }
+}
+
+void AutoDeviceList::Release() {
+    for (auto&& p : devices_) {
+        p->Release();
+    }
+}
+
+AutoUnmapDevice::~AutoUnmapDevice() {
+    if (name_.empty()) return;
+    if (!dm_->DeleteDeviceIfExists(name_)) {
+        LOG(ERROR) << "Failed to auto unmap device " << name_;
+    }
+}
+
+AutoUnmapImage::~AutoUnmapImage() {
+    if (name_.empty()) return;
+    if (!images_->UnmapImageIfExists(name_)) {
+        LOG(ERROR) << "Failed to auto unmap cow image " << name_;
+    }
+}
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
new file mode 100644
index 0000000..cbab472
--- /dev/null
+++ b/fs_mgr/libsnapshot/utility.h
@@ -0,0 +1,85 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <string>
+
+#include <android-base/macros.h>
+#include <libdm/dm.h>
+#include <libfiemap/image_manager.h>
+
+namespace android {
+namespace snapshot {
+
+struct AutoDevice {
+    virtual ~AutoDevice(){};
+    void Release();
+
+  protected:
+    AutoDevice(const std::string& name) : name_(name) {}
+    std::string name_;
+
+  private:
+    DISALLOW_COPY_AND_ASSIGN(AutoDevice);
+    AutoDevice(AutoDevice&& other) = delete;
+};
+
+// A list of devices we created along the way.
+// - Whenever a device is created that is subject to GC'ed at the end of
+//   this function, add it to this list.
+// - If any error has occurred, the list is destroyed, and all these devices
+//   are cleaned up.
+// - Upon success, Release() should be called so that the created devices
+//   are kept.
+struct AutoDeviceList {
+    ~AutoDeviceList();
+    template <typename T, typename... Args>
+    void EmplaceBack(Args&&... args) {
+        devices_.emplace_back(std::make_unique<T>(std::forward<Args>(args)...));
+    }
+    void Release();
+
+  private:
+    std::vector<std::unique_ptr<AutoDevice>> devices_;
+};
+
+// Automatically unmap a device upon deletion.
+struct AutoUnmapDevice : AutoDevice {
+    // On destruct, delete |name| from device mapper.
+    AutoUnmapDevice(android::dm::DeviceMapper* dm, const std::string& name)
+        : AutoDevice(name), dm_(dm) {}
+    AutoUnmapDevice(AutoUnmapDevice&& other) = default;
+    ~AutoUnmapDevice();
+
+  private:
+    DISALLOW_COPY_AND_ASSIGN(AutoUnmapDevice);
+    android::dm::DeviceMapper* dm_ = nullptr;
+};
+
+// Automatically unmap an image upon deletion.
+struct AutoUnmapImage : AutoDevice {
+    // On destruct, delete |name| from image manager.
+    AutoUnmapImage(android::fiemap::IImageManager* images, const std::string& name)
+        : AutoDevice(name), images_(images) {}
+    AutoUnmapImage(AutoUnmapImage&& other) = default;
+    ~AutoUnmapImage();
+
+  private:
+    DISALLOW_COPY_AND_ASSIGN(AutoUnmapImage);
+    android::fiemap::IImageManager* images_ = nullptr;
+};
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/gatekeeperd/Android.bp b/gatekeeperd/Android.bp
index 778e08c..27a6452 100644
--- a/gatekeeperd/Android.bp
+++ b/gatekeeperd/Android.bp
@@ -38,8 +38,6 @@
         "libkeystore_aidl",
         "libkeystore_binder",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "android.hardware.gatekeeper@1.0",
         "libgatekeeper_aidl",
     ],
diff --git a/healthd/Android.bp b/healthd/Android.bp
index 53be526..4f89bfb 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -42,8 +42,6 @@
         "libbase",
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
         "android.hardware.health@2.0",
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 4e34759..66ff399 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -21,7 +21,6 @@
     android.hardware.health@1.0-convert \
     libbinderthreadstate \
     libcharger_sysprop \
-    libhidltransport \
     libhidlbase \
     libhealthstoragedefault \
     libminui \
@@ -74,7 +73,6 @@
     android.hardware.health@1.0-convert \
     libbinderthreadstate \
     libcharger_sysprop \
-    libhidltransport \
     libhidlbase \
     libhealthstoragedefault \
     libvndksupport \
diff --git a/init/Android.bp b/init/Android.bp
index 57555f6..9c4b5b9 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -109,7 +109,6 @@
         "action.cpp",
         "action_manager.cpp",
         "action_parser.cpp",
-        "boringssl_self_test.cpp",
         "bootchart.cpp",
         "builtins.cpp",
         "capabilities.cpp",
@@ -130,6 +129,7 @@
         "persistent_properties.cpp",
         "persistent_properties.proto",
         "property_service.cpp",
+        "property_service.proto",
         "property_type.cpp",
         "reboot.cpp",
         "reboot_utils.cpp",
diff --git a/init/README.ueventd.md b/init/README.ueventd.md
index c592c37..7e90e0c 100644
--- a/init/README.ueventd.md
+++ b/init/README.ueventd.md
@@ -110,3 +110,9 @@
 
 For boot time purposes, this is done in parallel across a set of child processes. `ueventd.cpp` in
 this directory contains documentation on how the parallelization is done.
+
+There is an option to parallelize the restorecon function during cold boot as well. This should only
+be done for devices that do not use genfscon, which is the recommended method for labeling sysfs
+nodes. To enable this option, use the below line in a ueventd.rc script:
+
+    parallel_restorecon enabled
diff --git a/init/boringssl_self_test.cpp b/init/boringssl_self_test.cpp
deleted file mode 100644
index 759eb43..0000000
--- a/init/boringssl_self_test.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "boringssl_self_test.h"
-
-#include <android-base/logging.h>
-#include <cutils/android_reboot.h>
-#include <openssl/crypto.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-namespace android {
-namespace init {
-
-Result<void> StartBoringSslSelfTest(const BuiltinArguments&) {
-    pid_t id = fork();
-
-    if (id == 0) {
-        if (BORINGSSL_self_test() != 1) {
-            LOG(INFO) << "BoringSSL crypto self tests failed";
-
-            // This check has failed, so the device should refuse
-            // to boot. Rebooting to bootloader to wait for
-            // further action from the user.
-
-            int result = android_reboot(ANDROID_RB_RESTART2, 0,
-                                        "bootloader,boringssl-self-check-failed");
-            if (result != 0) {
-                LOG(ERROR) << "Failed to reboot into bootloader";
-            }
-        }
-
-        _exit(0);
-    } else if (id == -1) {
-        // Failed to fork, so cannot run the test. Refuse to continue.
-        PLOG(FATAL) << "Failed to fork for BoringSSL self test";
-    }
-
-    return {};
-}
-
-}  // namespace init
-}  // namespace android
diff --git a/init/boringssl_self_test.h b/init/boringssl_self_test.h
deleted file mode 100644
index 9e717d0..0000000
--- a/init/boringssl_self_test.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "builtin_arguments.h"
-#include "result.h"
-
-namespace android {
-namespace init {
-
-Result<void> StartBoringSslSelfTest(const BuiltinArguments&);
-
-}  // namespace init
-}  // namespace android
diff --git a/init/builtins.cpp b/init/builtins.cpp
index d2c73cb..21db8dc 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -80,6 +80,7 @@
 using namespace std::literals::string_literals;
 
 using android::base::Basename;
+using android::base::StartsWith;
 using android::base::StringPrintf;
 using android::base::unique_fd;
 using android::fs_mgr::Fstab;
@@ -701,6 +702,15 @@
 }
 
 static Result<void> do_setprop(const BuiltinArguments& args) {
+    if (StartsWith(args[1], "ctl.")) {
+        return Error()
+               << "Cannot set ctl. properties from init; call the Service functions directly";
+    }
+    if (args[1] == kRestoreconProperty) {
+        return Error() << "Cannot set '" << kRestoreconProperty
+                       << "' from init; use the restorecon builtin directly";
+    }
+
     property_set(args[1], args[2]);
     return {};
 }
@@ -1016,7 +1026,20 @@
 }
 
 static Result<void> do_load_persist_props(const BuiltinArguments& args) {
-    load_persist_props();
+    // Devices with FDE have load_persist_props called twice; the first time when the temporary
+    // /data partition is mounted and then again once /data is truly mounted.  We do not want to
+    // read persistent properties from the temporary /data partition or mark persistent properties
+    // as having been loaded during the first call, so we return in that case.
+    std::string crypto_state = android::base::GetProperty("ro.crypto.state", "");
+    std::string crypto_type = android::base::GetProperty("ro.crypto.type", "");
+    if (crypto_state == "encrypted" && crypto_type == "block") {
+        static size_t num_calls = 0;
+        if (++num_calls == 1) return {};
+    }
+
+    SendLoadPersistentPropertiesMessage();
+
+    start_waiting_for_property("ro.persistent_properties.ready", "true");
     return {};
 }
 
diff --git a/init/fscrypt_init_extensions.cpp b/init/fscrypt_init_extensions.cpp
index 0f5a864..9c2ca75 100644
--- a/init/fscrypt_init_extensions.cpp
+++ b/init/fscrypt_init_extensions.cpp
@@ -175,7 +175,6 @@
         return -1;
     }
 
-    LOG(INFO) << "Setting policy on " << dir;
     int result =
             fscrypt_policy_ensure(dir.c_str(), policy.c_str(), policy.length(), modes[0].c_str(),
                                   modes.size() >= 2 ? modes[1].c_str() : "aes-256-cts");
diff --git a/init/init.cpp b/init/init.cpp
index d4cbb5f..4e9a14f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -28,6 +28,9 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
 #include <functional>
 #include <map>
 #include <memory>
@@ -51,7 +54,6 @@
 #include <selinux/android.h>
 
 #include "action_parser.h"
-#include "boringssl_self_test.h"
 #include "builtins.h"
 #include "epoll.h"
 #include "first_stage_init.h"
@@ -61,6 +63,7 @@
 #include "mount_handler.h"
 #include "mount_namespace.h"
 #include "property_service.h"
+#include "proto_utils.h"
 #include "reboot.h"
 #include "reboot_utils.h"
 #include "security.h"
@@ -69,6 +72,7 @@
 #include "service.h"
 #include "service_parser.h"
 #include "sigchld_handler.h"
+#include "system/core/init/property_service.pb.h"
 #include "util.h"
 
 using namespace std::chrono_literals;
@@ -90,6 +94,7 @@
 static char qemu[32];
 
 static int signal_fd = -1;
+static int property_fd = -1;
 
 static std::unique_ptr<Timer> waiting_for_prop(nullptr);
 static std::string wait_prop_name;
@@ -615,6 +620,60 @@
                                 selinux_start_time_ns));
 }
 
+void SendLoadPersistentPropertiesMessage() {
+    auto init_message = InitMessage{};
+    init_message.set_load_persistent_properties(true);
+    if (auto result = SendMessage(property_fd, init_message); !result) {
+        LOG(ERROR) << "Failed to send load persistent properties message: " << result.error();
+    }
+}
+
+void SendStopSendingMessagesMessage() {
+    auto init_message = InitMessage{};
+    init_message.set_stop_sending_messages(true);
+    if (auto result = SendMessage(property_fd, init_message); !result) {
+        LOG(ERROR) << "Failed to send load persistent properties message: " << result.error();
+    }
+}
+
+static void HandlePropertyFd() {
+    auto message = ReadMessage(property_fd);
+    if (!message) {
+        LOG(ERROR) << "Could not read message from property service: " << message.error();
+        return;
+    }
+
+    auto property_message = PropertyMessage{};
+    if (!property_message.ParseFromString(*message)) {
+        LOG(ERROR) << "Could not parse message from property service";
+        return;
+    }
+
+    switch (property_message.msg_case()) {
+        case PropertyMessage::kControlMessage: {
+            auto& control_message = property_message.control_message();
+            bool success = HandleControlMessage(control_message.msg(), control_message.name(),
+                                                control_message.pid());
+
+            uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+            if (control_message.has_fd()) {
+                int fd = control_message.fd();
+                TEMP_FAILURE_RETRY(send(fd, &response, sizeof(response), 0));
+                close(fd);
+            }
+            break;
+        }
+        case PropertyMessage::kChangedMessage: {
+            auto& changed_message = property_message.changed_message();
+            property_changed(changed_message.name(), changed_message.value());
+            break;
+        }
+        default:
+            LOG(ERROR) << "Unknown message type from property service: "
+                       << property_message.msg_case();
+    }
+}
+
 int SecondStageMain(int argc, char** argv) {
     if (REBOOT_BOOTLOADER_ON_PANIC) {
         InstallRebootSignalHandlers();
@@ -686,7 +745,12 @@
     UmountDebugRamdisk();
     fs_mgr_vendor_overlay_mount_all();
     export_oem_lock_status();
-    StartPropertyService(&epoll);
+
+    StartPropertyService(&property_fd);
+    if (auto result = epoll.RegisterHandler(property_fd, HandlePropertyFd); !result) {
+        LOG(FATAL) << "Could not register epoll handler for property fd: " << result.error();
+    }
+
     MountHandler mount_handler(&epoll);
     set_usb_controller();
 
@@ -739,9 +803,6 @@
     // Trigger all the boot actions to get us started.
     am.QueueEventTrigger("init");
 
-    // Starting the BoringSSL self test, for NIAP certification compliance.
-    am.QueueBuiltinAction(StartBoringSslSelfTest, "StartBoringSslSelfTest");
-
     // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
     // wasn't ready immediately after wait_for_coldboot_done
     am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
diff --git a/init/init.h b/init/init.h
index cfc28f1..8ac52e2 100644
--- a/init/init.h
+++ b/init/init.h
@@ -31,16 +31,15 @@
 Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
 Parser CreateServiceOnlyParser(ServiceList& service_list);
 
-bool HandleControlMessage(const std::string& msg, const std::string& arg, pid_t pid);
-
-void property_changed(const std::string& name, const std::string& value);
-
 bool start_waiting_for_property(const char *name, const char *value);
 
 void DumpState();
 
 void ResetWaitForProp();
 
+void SendLoadPersistentPropertiesMessage();
+void SendStopSendingMessagesMessage();
+
 int SecondStageMain(int argc, char** argv);
 
 }  // namespace init
diff --git a/init/interface_utils.cpp b/init/interface_utils.cpp
index a54860f..ddbacd7 100644
--- a/init/interface_utils.cpp
+++ b/init/interface_utils.cpp
@@ -77,6 +77,12 @@
                                                 const InterfaceInheritanceHierarchyMap& hierarchy) {
     std::set<FQName> interface_fqnames;
     for (const std::string& instance : instances) {
+        // There is insufficient build-time information on AIDL interfaces to check them here
+        // TODO(b/139307527): Rework how services store interfaces to avoid excess string parsing
+        if (base::Split(instance, "/")[0] == "aidl") {
+            continue;
+        }
+
         FqInstance fqinstance;
         if (!fqinstance.setTo(instance)) {
             return Error() << "Unable to parse interface instance '" << instance << "'";
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 3408ff3..c18decc 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -42,6 +42,7 @@
 #include <map>
 #include <memory>
 #include <mutex>
+#include <optional>
 #include <queue>
 #include <thread>
 #include <vector>
@@ -63,8 +64,10 @@
 #include "init.h"
 #include "persistent_properties.h"
 #include "property_type.h"
+#include "proto_utils.h"
 #include "selinux.h"
 #include "subcontext.h"
+#include "system/core/init/property_service.pb.h"
 #include "util.h"
 
 using namespace std::literals;
@@ -76,6 +79,7 @@
 using android::base::StringPrintf;
 using android::base::Timer;
 using android::base::Trim;
+using android::base::unique_fd;
 using android::base::WriteStringToFile;
 using android::properties::BuildTrie;
 using android::properties::ParsePropertyInfoFile;
@@ -85,18 +89,13 @@
 namespace android {
 namespace init {
 
-static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive";
-
 static bool persistent_properties_loaded = false;
 
 static int property_set_fd = -1;
+static int init_socket = -1;
 
 static PropertyInfoAreaFile property_info_area;
 
-uint32_t InitPropertySet(const std::string& name, const std::string& value);
-
-uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet;
-
 void CreateSerializedPropertyInfo();
 
 struct PropertyAuditData {
@@ -164,6 +163,17 @@
     return has_access;
 }
 
+static void SendPropertyChanged(const std::string& name, const std::string& value) {
+    auto property_msg = PropertyMessage{};
+    auto* changed_message = property_msg.mutable_changed_message();
+    changed_message->set_name(name);
+    changed_message->set_value(value);
+
+    if (auto result = SendMessage(init_socket, property_msg); !result) {
+        LOG(ERROR) << "Failed to send property changed message: " << result.error();
+    }
+}
+
 static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
     size_t valuelen = value.size();
 
@@ -199,7 +209,11 @@
     if (persistent_properties_loaded && StartsWith(name, "persist.")) {
         WritePersistentProperty(name, value);
     }
-    property_changed(name, value);
+    // If init hasn't started its main loop, then it won't be handling property changed messages
+    // anyway, so there's no need to try to send them.
+    if (init_socket != -1) {
+        SendPropertyChanged(name, value);
+    }
     return PROP_SUCCESS;
 }
 
@@ -239,35 +253,10 @@
     bool thread_started_ = false;
 };
 
-uint32_t InitPropertySet(const std::string& name, const std::string& value) {
-    if (StartsWith(name, "ctl.")) {
-        LOG(ERROR) << "InitPropertySet: Do not set ctl. properties from init; call the Service "
-                      "functions directly";
-        return PROP_ERROR_INVALID_NAME;
-    }
-    if (name == kRestoreconProperty) {
-        LOG(ERROR) << "InitPropertySet: Do not set '" << kRestoreconProperty
-                   << "' from init; use the restorecon builtin directly";
-        return PROP_ERROR_INVALID_NAME;
-    }
-
-    uint32_t result = 0;
-    ucred cr = {.pid = 1, .uid = 0, .gid = 0};
-    std::string error;
-    result = HandlePropertySet(name, value, kInitContext.c_str(), cr, &error);
-    if (result != PROP_SUCCESS) {
-        LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
-    }
-
-    return result;
-}
-
 class SocketConnection {
   public:
     SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
 
-    ~SocketConnection() { close(socket_); }
-
     bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
         return RecvFully(value, sizeof(*value), timeout_ms);
     }
@@ -304,6 +293,9 @@
     }
 
     bool SendUint32(uint32_t value) {
+        if (!socket_.ok()) {
+            return true;
+        }
         int result = TEMP_FAILURE_RETRY(send(socket_, &value, sizeof(value), 0));
         return result == sizeof(value);
     }
@@ -318,7 +310,7 @@
         return true;
     }
 
-    int socket() { return socket_; }
+    [[nodiscard]] int Release() { return socket_.release(); }
 
     const ucred& cred() { return cred_; }
 
@@ -389,12 +381,46 @@
         return bytes_left == 0;
     }
 
-    int socket_;
+    unique_fd socket_;
     ucred cred_;
 
     DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
 };
 
+static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid,
+                                   SocketConnection* socket, std::string* error) {
+    if (init_socket == -1) {
+        *error = "Received control message after shutdown, ignoring";
+        return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+    }
+
+    auto property_msg = PropertyMessage{};
+    auto* control_message = property_msg.mutable_control_message();
+    control_message->set_msg(msg);
+    control_message->set_name(name);
+    control_message->set_pid(pid);
+
+    // We must release the fd before sending it to init, otherwise there will be a race with init.
+    // If init calls close() before Release(), then fdsan will see the wrong tag and abort().
+    int fd = -1;
+    if (socket != nullptr) {
+        fd = socket->Release();
+        control_message->set_fd(fd);
+    }
+
+    if (auto result = SendMessage(init_socket, property_msg); !result) {
+        // We've already released the fd above, so if we fail to send the message to init, we need
+        // to manually free it here.
+        if (fd != -1) {
+            close(fd);
+        }
+        *error = "Failed to send control message: " + result.error().message();
+        return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+    }
+
+    return PROP_SUCCESS;
+}
+
 bool CheckControlPropertyPerms(const std::string& name, const std::string& value,
                                const std::string& source_context, const ucred& cr) {
     // We check the legacy method first but these properties are dontaudit, so we only log an audit
@@ -462,15 +488,14 @@
 
 // This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
 uint32_t HandlePropertySet(const std::string& name, const std::string& value,
-                           const std::string& source_context, const ucred& cr, std::string* error) {
+                           const std::string& source_context, const ucred& cr,
+                           SocketConnection* socket, std::string* error) {
     if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) {
         return ret;
     }
 
     if (StartsWith(name, "ctl.")) {
-        return HandleControlMessage(name.c_str() + 4, value, cr.pid)
-                       ? PROP_SUCCESS
-                       : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+        return SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error);
     }
 
     // sys.powerctl is a special property that is used to make the device reboot.  We want to log
@@ -501,6 +526,20 @@
     return PropertySet(name, value, error);
 }
 
+uint32_t InitPropertySet(const std::string& name, const std::string& value) {
+    uint32_t result = 0;
+    ucred cr = {.pid = 1, .uid = 0, .gid = 0};
+    std::string error;
+    result = HandlePropertySet(name, value, kInitContext.c_str(), cr, nullptr, &error);
+    if (result != PROP_SUCCESS) {
+        LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
+    }
+
+    return result;
+}
+
+uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet;
+
 static void handle_property_set_fd() {
     static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
 
@@ -549,7 +588,8 @@
 
         const auto& cr = socket.cred();
         std::string error;
-        uint32_t result = HandlePropertySet(prop_name, prop_value, source_context, cr, &error);
+        uint32_t result =
+                HandlePropertySet(prop_name, prop_value, source_context, cr, nullptr, &error);
         if (result != PROP_SUCCESS) {
             LOG(ERROR) << "Unable to set property '" << prop_name << "' from uid:" << cr.uid
                        << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
@@ -577,7 +617,7 @@
 
         const auto& cr = socket.cred();
         std::string error;
-        uint32_t result = HandlePropertySet(name, value, source_context, cr, &error);
+        uint32_t result = HandlePropertySet(name, value, source_context, cr, &socket, &error);
         if (result != PROP_SUCCESS) {
             LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid
                        << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
@@ -741,33 +781,6 @@
     }
 }
 
-/* When booting an encrypted system, /data is not mounted when the
- * property service is started, so any properties stored there are
- * not loaded.  Vold triggers init to load these properties once it
- * has mounted /data.
- */
-void load_persist_props(void) {
-    // Devices with FDE have load_persist_props called twice; the first time when the temporary
-    // /data partition is mounted and then again once /data is truly mounted.  We do not want to
-    // read persistent properties from the temporary /data partition or mark persistent properties
-    // as having been loaded during the first call, so we return in that case.
-    std::string crypto_state = android::base::GetProperty("ro.crypto.state", "");
-    std::string crypto_type = android::base::GetProperty("ro.crypto.type", "");
-    if (crypto_state == "encrypted" && crypto_type == "block") {
-        static size_t num_calls = 0;
-        if (++num_calls == 1) return;
-    }
-
-    load_override_properties();
-    /* Read persistent properties after all default values have been loaded. */
-    auto persistent_properties = LoadPersistentProperties();
-    for (const auto& persistent_property_record : persistent_properties.properties()) {
-        property_set(persistent_property_record.name(), persistent_property_record.value());
-    }
-    persistent_properties_loaded = true;
-    property_set("ro.persistent_properties.ready", "true");
-}
-
 // If the ro.product.[brand|device|manufacturer|model|name] properties have not been explicitly
 // set, derive them from ro.product.${partition}.* properties
 static void property_initialize_ro_product_props() {
@@ -985,21 +998,92 @@
     selinux_android_restorecon(kPropertyInfosPath, 0);
 }
 
-void StartPropertyService(Epoll* epoll) {
+static void HandleInitSocket() {
+    auto message = ReadMessage(init_socket);
+    if (!message) {
+        LOG(ERROR) << "Could not read message from init_dedicated_recv_socket: " << message.error();
+        return;
+    }
+
+    auto init_message = InitMessage{};
+    if (!init_message.ParseFromString(*message)) {
+        LOG(ERROR) << "Could not parse message from init";
+        return;
+    }
+
+    switch (init_message.msg_case()) {
+        case InitMessage::kLoadPersistentProperties: {
+            load_override_properties();
+            // Read persistent properties after all default values have been loaded.
+            auto persistent_properties = LoadPersistentProperties();
+            for (const auto& persistent_property_record : persistent_properties.properties()) {
+                InitPropertySet(persistent_property_record.name(),
+                                persistent_property_record.value());
+            }
+            InitPropertySet("ro.persistent_properties.ready", "true");
+            persistent_properties_loaded = true;
+            break;
+        }
+        case InitMessage::kStopSendingMessages: {
+            init_socket = -1;
+            break;
+        }
+        default:
+            LOG(ERROR) << "Unknown message type from init: " << init_message.msg_case();
+    }
+}
+
+static void PropertyServiceThread() {
+    Epoll epoll;
+    if (auto result = epoll.Open(); !result) {
+        LOG(FATAL) << result.error();
+    }
+
+    if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd); !result) {
+        LOG(FATAL) << result.error();
+    }
+
+    if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result) {
+        LOG(FATAL) << result.error();
+    }
+
+    while (true) {
+        auto pending_functions = epoll.Wait(std::nullopt);
+        if (!pending_functions) {
+            LOG(ERROR) << pending_functions.error();
+        } else {
+            for (const auto& function : *pending_functions) {
+                (*function)();
+            }
+        }
+    }
+}
+
+void StartPropertyService(int* epoll_socket) {
     property_set("ro.property_service.version", "2");
 
+    int sockets[2];
+    if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {
+        PLOG(FATAL) << "Failed to socketpair() between property_service and init";
+    }
+    *epoll_socket = sockets[0];
+    init_socket = sockets[1];
+
     if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                    false, 0666, 0, 0, {})) {
         property_set_fd = *result;
     } else {
-        PLOG(FATAL) << "start_property_service socket creation failed: " << result.error();
+        LOG(FATAL) << "start_property_service socket creation failed: " << result.error();
     }
 
     listen(property_set_fd, 8);
 
-    if (auto result = epoll->RegisterHandler(property_set_fd, handle_property_set_fd); !result) {
-        PLOG(FATAL) << result.error();
-    }
+    std::thread{PropertyServiceThread}.detach();
+
+    property_set = [](const std::string& key, const std::string& value) -> uint32_t {
+        android::base::SetProperty(key, value);
+        return 0;
+    };
 }
 
 }  // namespace init
diff --git a/init/property_service.h b/init/property_service.h
index 7f9f844..8f7d8d9 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -25,17 +25,15 @@
 namespace android {
 namespace init {
 
+static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive";
+
 bool CanReadProperty(const std::string& source_context, const std::string& name);
 
 extern uint32_t (*property_set)(const std::string& name, const std::string& value);
 
-uint32_t HandlePropertySet(const std::string& name, const std::string& value,
-                           const std::string& source_context, const ucred& cr, std::string* error);
-
 void property_init();
 void property_load_boot_defaults(bool load_debug_prop);
-void load_persist_props();
-void StartPropertyService(Epoll* epoll);
+void StartPropertyService(int* epoll_socket);
 
 }  // namespace init
 }  // namespace android
diff --git a/init/property_service.proto b/init/property_service.proto
new file mode 100644
index 0000000..ea454d4
--- /dev/null
+++ b/init/property_service.proto
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+message PropertyMessage {
+    message ControlMessage {
+        optional string msg = 1;
+        optional string name = 2;
+        optional int32 pid = 3;
+        optional int32 fd = 4;
+    }
+
+    message ChangedMessage {
+        optional string name = 1;
+        optional string value = 2;
+    }
+
+    oneof msg {
+        ControlMessage control_message = 1;
+        ChangedMessage changed_message = 2;
+    };
+}
+
+message InitMessage {
+    oneof msg {
+        bool load_persistent_properties = 1;
+        bool stop_sending_messages = 2;
+    };
+}
diff --git a/init/proto_utils.h b/init/proto_utils.h
new file mode 100644
index 0000000..93a7d57
--- /dev/null
+++ b/init/proto_utils.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "result.h"
+
+namespace android {
+namespace init {
+
+constexpr size_t kBufferSize = 4096;
+
+inline Result<std::string> ReadMessage(int socket) {
+    char buffer[kBufferSize] = {};
+    auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0));
+    if (result == 0) {
+        return Error();
+    } else if (result < 0) {
+        return ErrnoError();
+    }
+    return std::string(buffer, result);
+}
+
+template <typename T>
+Result<void> SendMessage(int socket, const T& message) {
+    std::string message_string;
+    if (!message.SerializeToString(&message_string)) {
+        return Error() << "Unable to serialize message";
+    }
+
+    if (message_string.size() > kBufferSize) {
+        return Error() << "Serialized message too long to send";
+    }
+
+    if (auto result =
+                TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0));
+        result != static_cast<long>(message_string.size())) {
+        return ErrnoError() << "send() failed to send message contents";
+    }
+    return {};
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/reboot.cpp b/init/reboot.cpp
index b0b5b54..786a084 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -730,6 +730,12 @@
         s->UnSetExec();
     }
 
+    // We no longer process messages about properties changing coming from property service, so we
+    // need to tell property service to stop sending us these messages, otherwise it'll fill the
+    // buffers and block indefinitely, causing future property sets, including those that init makes
+    // during shutdown in Service::NotifyStateChange() to also block indefinitely.
+    SendStopSendingMessagesMessage();
+
     return true;
 }
 
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
index d1a712f..de085cc 100644
--- a/init/reboot_utils.cpp
+++ b/init/reboot_utils.cpp
@@ -21,11 +21,12 @@
 
 #include <string>
 
-#include "android-base/file.h"
-#include "android-base/logging.h"
-#include "android-base/strings.h"
-#include "backtrace/Backtrace.h"
-#include "cutils/android_reboot.h"
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <backtrace/Backtrace.h>
+#include <cutils/android_reboot.h>
 
 #include "capabilities.h"
 
@@ -93,7 +94,14 @@
             break;
 
         case ANDROID_RB_THERMOFF:
-            reboot(RB_POWER_OFF);
+            if (android::base::GetBoolProperty("ro.thermal_warmreset", false)) {
+                LOG(INFO) << "Try to trigger a warm reset for thermal shutdown";
+                static constexpr const char kThermalShutdownTarget[] = "shutdown,thermal";
+                syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+                        LINUX_REBOOT_CMD_RESTART2, kThermalShutdownTarget);
+            } else {
+                reboot(RB_POWER_OFF);
+            }
             break;
     }
     // In normal case, reboot should not return.
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index dd552fb..543be23 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -145,17 +145,21 @@
     const std::string& interface_name = args[1];
     const std::string& instance_name = args[2];
 
-    FQName fq_name;
-    if (!FQName::parse(interface_name, &fq_name)) {
-        return Error() << "Invalid fully-qualified name for interface '" << interface_name << "'";
-    }
+    // AIDL services don't use fully qualified names and instead just use "interface aidl <name>"
+    if (interface_name != "aidl") {
+        FQName fq_name;
+        if (!FQName::parse(interface_name, &fq_name)) {
+            return Error() << "Invalid fully-qualified name for interface '" << interface_name
+                           << "'";
+        }
 
-    if (!fq_name.isFullyQualified()) {
-        return Error() << "Interface name not fully-qualified '" << interface_name << "'";
-    }
+        if (!fq_name.isFullyQualified()) {
+            return Error() << "Interface name not fully-qualified '" << interface_name << "'";
+        }
 
-    if (fq_name.isValidValueName()) {
-        return Error() << "Interface name must not be a value name '" << interface_name << "'";
+        if (fq_name.isValidValueName()) {
+            return Error() << "Interface name must not be a value name '" << interface_name << "'";
+        }
     }
 
     const std::string fullname = interface_name + "/" + instance_name;
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 00f91d8..ec93b58 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -18,16 +18,17 @@
 
 #include <fcntl.h>
 #include <poll.h>
-#include <sys/socket.h>
 #include <unistd.h>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <selinux/android.h>
 
 #include "action.h"
 #include "builtins.h"
+#include "proto_utils.h"
 #include "util.h"
 
 #if defined(__ANDROID__)
@@ -59,45 +60,6 @@
 
 namespace {
 
-constexpr size_t kBufferSize = 4096;
-
-Result<std::string> ReadMessage(int socket) {
-    char buffer[kBufferSize] = {};
-    auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0));
-    if (result == 0) {
-        return Error();
-    } else if (result < 0) {
-        return ErrnoError();
-    }
-    return std::string(buffer, result);
-}
-
-template <typename T>
-Result<void> SendMessage(int socket, const T& message) {
-    std::string message_string;
-    if (!message.SerializeToString(&message_string)) {
-        return Error() << "Unable to serialize message";
-    }
-
-    if (message_string.size() > kBufferSize) {
-        return Error() << "Serialized message too long to send";
-    }
-
-    if (auto result =
-            TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0));
-        result != static_cast<long>(message_string.size())) {
-        return ErrnoError() << "send() failed to send message contents";
-    }
-    return {};
-}
-
-std::vector<std::pair<std::string, std::string>> properties_to_set;
-
-uint32_t SubcontextPropertySet(const std::string& name, const std::string& value) {
-    properties_to_set.emplace_back(name, value);
-    return 0;
-}
-
 class SubcontextProcess {
   public:
     SubcontextProcess(const BuiltinFunctionMap* function_map, std::string context, int init_fd)
@@ -131,14 +93,6 @@
         result = RunBuiltinFunction(map_result->function, args, context_);
     }
 
-    for (const auto& [name, value] : properties_to_set) {
-        auto property = reply->add_properties_to_set();
-        property->set_name(name);
-        property->set_value(value);
-    }
-
-    properties_to_set.clear();
-
     if (result) {
         reply->set_success(true);
     } else {
@@ -224,7 +178,10 @@
 
     SelabelInitialize();
 
-    property_set = SubcontextPropertySet;
+    property_set = [](const std::string& key, const std::string& value) -> uint32_t {
+        android::base::SetProperty(key, value);
+        return 0;
+    };
 
     auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
     subcontext_process.MainLoop();
@@ -311,15 +268,6 @@
         return subcontext_reply.error();
     }
 
-    for (const auto& property : subcontext_reply->properties_to_set()) {
-        ucred cr = {.pid = pid_, .uid = 0, .gid = 0};
-        std::string error;
-        if (HandlePropertySet(property.name(), property.value(), context_, cr, &error) != 0) {
-            LOG(ERROR) << "Subcontext init could not set '" << property.name() << "' to '"
-                       << property.value() << "': " << error;
-        }
-    }
-
     if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
         auto& failure = subcontext_reply->failure();
         return ResultError(failure.error_string(), failure.error_errno());
diff --git a/init/subcontext.proto b/init/subcontext.proto
index c31f4fb..e68115e 100644
--- a/init/subcontext.proto
+++ b/init/subcontext.proto
@@ -38,10 +38,4 @@
         Failure failure = 2;
         ExpandArgsReply expand_args_reply = 3;
     }
-
-    message PropertyToSet {
-        optional string name = 1;
-        optional string value = 2;
-    }
-    repeated PropertyToSet properties_to_set = 4;
 }
\ No newline at end of file
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index cffc1b9..6741e2a 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -113,10 +113,12 @@
 class ColdBoot {
   public:
     ColdBoot(UeventListener& uevent_listener,
-             std::vector<std::unique_ptr<UeventHandler>>& uevent_handlers)
+             std::vector<std::unique_ptr<UeventHandler>>& uevent_handlers,
+             bool enable_parallel_restorecon)
         : uevent_listener_(uevent_listener),
           uevent_handlers_(uevent_handlers),
-          num_handler_subprocesses_(std::thread::hardware_concurrency() ?: 4) {}
+          num_handler_subprocesses_(std::thread::hardware_concurrency() ?: 4),
+          enable_parallel_restorecon_(enable_parallel_restorecon) {}
 
     void Run();
 
@@ -132,6 +134,8 @@
     std::vector<std::unique_ptr<UeventHandler>>& uevent_handlers_;
 
     unsigned int num_handler_subprocesses_;
+    bool enable_parallel_restorecon_;
+
     std::vector<Uevent> uevent_queue_;
 
     std::set<pid_t> subprocess_pids_;
@@ -155,7 +159,6 @@
 
         selinux_android_restorecon(dir.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
     }
-    _exit(EXIT_SUCCESS);
 }
 
 void ColdBoot::GenerateRestoreCon(const std::string& directory) {
@@ -195,7 +198,10 @@
 
         if (pid == 0) {
             UeventHandlerMain(i, num_handler_subprocesses_);
-            RestoreConHandler(i, num_handler_subprocesses_);
+            if (enable_parallel_restorecon_) {
+                RestoreConHandler(i, num_handler_subprocesses_);
+            }
+            _exit(EXIT_SUCCESS);
         }
 
         subprocess_pids_.emplace(pid);
@@ -240,14 +246,20 @@
 
     RegenerateUevents();
 
-    selinux_android_restorecon("/sys", 0);
-    selinux_android_restorecon("/sys/devices", 0);
-    GenerateRestoreCon("/sys");
-    // takes long time for /sys/devices, parallelize it
-    GenerateRestoreCon("/sys/devices");
+    if (enable_parallel_restorecon_) {
+        selinux_android_restorecon("/sys", 0);
+        selinux_android_restorecon("/sys/devices", 0);
+        GenerateRestoreCon("/sys");
+        // takes long time for /sys/devices, parallelize it
+        GenerateRestoreCon("/sys/devices");
+    }
 
     ForkSubProcesses();
 
+    if (!enable_parallel_restorecon_) {
+        selinux_android_restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
+    }
+
     WaitForSubProcesses();
 
     android::base::SetProperty(kColdBootDoneProp, "true");
@@ -293,7 +305,8 @@
     UeventListener uevent_listener(ueventd_configuration.uevent_socket_rcvbuf_size);
 
     if (!android::base::GetBoolProperty(kColdBootDoneProp, false)) {
-        ColdBoot cold_boot(uevent_listener, uevent_handlers);
+        ColdBoot cold_boot(uevent_listener, uevent_handlers,
+                           ueventd_configuration.enable_parallel_restorecon);
         cold_boot.Run();
     }
 
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 8ee0cce..1ca1715 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -88,18 +88,17 @@
     return {};
 }
 
-Result<void> ParseModaliasHandlingLine(std::vector<std::string>&& args,
-                                       bool* enable_modalias_handling) {
+Result<void> ParseEnabledDisabledLine(std::vector<std::string>&& args, bool* feature) {
     if (args.size() != 2) {
-        return Error() << "modalias_handling lines take exactly one parameter";
+        return Error() << args[0] << " lines take exactly one parameter";
     }
 
     if (args[1] == "enabled") {
-        *enable_modalias_handling = true;
+        *feature = true;
     } else if (args[1] == "disabled") {
-        *enable_modalias_handling = false;
+        *feature = false;
     } else {
-        return Error() << "modalias_handling takes either 'enabled' or 'disabled' as a parameter";
+        return Error() << args[0] << " takes either 'enabled' or 'disabled' as a parameter";
     }
 
     return {};
@@ -213,11 +212,14 @@
                                std::bind(ParseFirmwareDirectoriesLine, _1,
                                          &ueventd_configuration.firmware_directories));
     parser.AddSingleLineParser("modalias_handling",
-                               std::bind(ParseModaliasHandlingLine, _1,
+                               std::bind(ParseEnabledDisabledLine, _1,
                                          &ueventd_configuration.enable_modalias_handling));
     parser.AddSingleLineParser("uevent_socket_rcvbuf_size",
                                std::bind(ParseUeventSocketRcvbufSizeLine, _1,
                                          &ueventd_configuration.uevent_socket_rcvbuf_size));
+    parser.AddSingleLineParser("parallel_restorecon",
+                               std::bind(ParseEnabledDisabledLine, _1,
+                                         &ueventd_configuration.enable_parallel_restorecon));
 
     for (const auto& config : configs) {
         parser.ParseConfig(config);
diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h
index d476dec..b54dba8 100644
--- a/init/ueventd_parser.h
+++ b/init/ueventd_parser.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef _INIT_UEVENTD_PARSER_H
-#define _INIT_UEVENTD_PARSER_H
+#pragma once
 
 #include <string>
 #include <vector>
@@ -32,11 +31,10 @@
     std::vector<std::string> firmware_directories;
     bool enable_modalias_handling = false;
     size_t uevent_socket_rcvbuf_size = 0;
+    bool enable_parallel_restorecon = false;
 };
 
 UeventdConfiguration ParseConfig(const std::vector<std::string>& configs);
 
 }  // namespace init
 }  // namespace android
-
-#endif
diff --git a/init/ueventd_parser_test.cpp b/init/ueventd_parser_test.cpp
index 9c1cedf..885e79d 100644
--- a/init/ueventd_parser_test.cpp
+++ b/init/ueventd_parser_test.cpp
@@ -147,6 +147,24 @@
     TestUeventdFile(ueventd_file, {{}, {}, {}, {}, false, 8 * 1024 * 1024});
 }
 
+TEST(ueventd_parser, EnabledDisabledLines) {
+    auto ueventd_file = R"(
+modalias_handling enabled
+parallel_restorecon enabled
+modalias_handling disabled
+)";
+
+    TestUeventdFile(ueventd_file, {{}, {}, {}, {}, false, 0, true});
+
+    auto ueventd_file2 = R"(
+parallel_restorecon enabled
+modalias_handling enabled
+parallel_restorecon disabled
+)";
+
+    TestUeventdFile(ueventd_file2, {{}, {}, {}, {}, true, 0, false});
+}
+
 TEST(ueventd_parser, AllTogether) {
     auto ueventd_file = R"(
 
@@ -179,6 +197,8 @@
 firmware_directories /more
 
 uevent_socket_rcvbuf_size 6M
+modalias_handling enabled
+parallel_restorecon enabled
 
 #ending comment
 )";
@@ -211,7 +231,7 @@
     size_t uevent_socket_rcvbuf_size = 6 * 1024 * 1024;
 
     TestUeventdFile(ueventd_file, {subsystems, sysfs_permissions, permissions, firmware_directories,
-                                   false, uevent_socket_rcvbuf_size});
+                                   true, uevent_socket_rcvbuf_size, true});
 }
 
 // All of these lines are ill-formed, so test that there is 0 output.
@@ -230,6 +250,13 @@
 
 subsystem #no name
 
+modalias_handling
+modalias_handling enabled enabled
+modalias_handling blah
+
+parallel_restorecon
+parallel_restorecon enabled enabled
+parallel_restorecon blah
 )";
 
     TestUeventdFile(ueventd_file, {});
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index f8d5058..e000a00 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -79,7 +79,7 @@
       index_++;
       return *this;
     }
-    iterator& operator++(int increment) {
+    const iterator operator++(int increment) {
       index_ += increment;
       return *this;
     }
@@ -87,7 +87,7 @@
       index_--;
       return *this;
     }
-    iterator& operator--(int decrement) {
+    const iterator operator--(int decrement) {
       index_ -= decrement;
       return *this;
     }
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index b29638c..d0d83de 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -84,7 +84,7 @@
     { 00755, AID_ROOT,         AID_ROOT,         0, "system/etc/ppp" },
     { 00755, AID_ROOT,         AID_SHELL,        0, "system/vendor" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "system/xbin" },
-    { 00755, AID_ROOT,         AID_SHELL,        0, "system/apex/*/bin" },
+    { 00751, AID_ROOT,         AID_SHELL,        0, "system/apex/*/bin" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "vendor/bin" },
     { 00755, AID_ROOT,         AID_SHELL,        0, "vendor" },
     { 00755, AID_ROOT,         AID_ROOT,         0, 0 },
diff --git a/libion/tests/Android.bp b/libion/tests/Android.bp
index d3b4688..5600702 100644
--- a/libion/tests/Android.bp
+++ b/libion/tests/Android.bp
@@ -24,7 +24,8 @@
     srcs: [
         "allocate_test.cpp",
         "exit_test.cpp",
-    	"heap_query.cpp",
+        "heap_query.cpp",
+        "system_heap.cpp",
         "invalid_values_test.cpp",
         "ion_test_fixture.cpp",
         "map_test.cpp",
diff --git a/libion/tests/system_heap.cpp b/libion/tests/system_heap.cpp
new file mode 100644
index 0000000..fb63888
--- /dev/null
+++ b/libion/tests/system_heap.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+#include <iostream>
+
+#include <ion/ion.h>
+#include "ion_test_fixture.h"
+
+class SystemHeap : public IonTest {};
+
+TEST_F(SystemHeap, Presence) {
+    bool system_heap_found = false;
+    for (const auto& heap : ion_heaps) {
+        if (heap.type == ION_HEAP_TYPE_SYSTEM) {
+            system_heap_found = true;
+            EXPECT_TRUE((1 << heap.heap_id) & ION_HEAP_SYSTEM_MASK);
+        }
+    }
+    // We now expect the system heap to exist from Android
+    ASSERT_TRUE(system_heap_found);
+}
+
+TEST_F(SystemHeap, Allocate) {
+    int fd;
+    ASSERT_EQ(0, ion_alloc_fd(ionfd, getpagesize(), 0, ION_HEAP_SYSTEM_MASK, 0, &fd));
+    ASSERT_TRUE(fd != 0);
+    ASSERT_EQ(close(fd), 0);  // free the buffer
+}
diff --git a/libmemtrack/Android.bp b/libmemtrack/Android.bp
index 4e4554a..c7dff5a 100644
--- a/libmemtrack/Android.bp
+++ b/libmemtrack/Android.bp
@@ -15,8 +15,6 @@
         "liblog",
         "libbase",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "libutils",
         "android.hardware.memtrack@1.0",
     ],
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 8be4dd0..98921be 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -205,6 +205,7 @@
         "Mutex_test.cpp",
         "SharedBuffer_test.cpp",
         "String8_test.cpp",
+        "String16_test.cpp",
         "StrongPointer_test.cpp",
         "Unicode_test.cpp",
         "Vector_test.cpp",
@@ -289,3 +290,9 @@
     ],
     shared_libs: ["libutils_test_singleton1"],
 }
+
+cc_benchmark {
+    name: "libutils_benchmark",
+    srcs: ["Vector_benchmark.cpp"],
+    shared_libs: ["libutils"],
+}
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index 7910c6e..3e703db 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -41,6 +41,7 @@
         // The following is OK on Android-supported platforms.
         sb->mRefs.store(1, std::memory_order_relaxed);
         sb->mSize = size;
+        sb->mClientMetadata = 0;
     }
     return sb;
 }
diff --git a/libutils/SharedBuffer.h b/libutils/SharedBuffer.h
index fdf13a9..476c842 100644
--- a/libutils/SharedBuffer.h
+++ b/libutils/SharedBuffer.h
@@ -102,7 +102,12 @@
         // Must be sized to preserve correct alignment.
         mutable std::atomic<int32_t>        mRefs;
                 size_t                      mSize;
-                uint32_t                    mReserved[2];
+                uint32_t                    mReserved;
+public:
+        // mClientMetadata is reserved for client use.  It is initialized to 0
+        // and the clients can do whatever they want with it.  Note that this is
+        // placed last so that it is adjcent to the buffer allocated.
+                uint32_t                    mClientMetadata;
 };
 
 static_assert(sizeof(SharedBuffer) % 8 == 0
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 818b171..5c3cf32 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -24,21 +24,21 @@
 
 namespace android {
 
+static const StaticString16 emptyString(u"");
 static inline char16_t* getEmptyString() {
-    static SharedBuffer* gEmptyStringBuf = [] {
-        SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t));
-        char16_t* str = static_cast<char16_t*>(buf->data());
-        *str = 0;
-        return buf;
-    }();
-
-    gEmptyStringBuf->acquire();
-    return static_cast<char16_t*>(gEmptyStringBuf->data());
+    return const_cast<char16_t*>(emptyString.string());
 }
 
 // ---------------------------------------------------------------------------
 
-static char16_t* allocFromUTF8(const char* u8str, size_t u8len)
+void* String16::alloc(size_t size)
+{
+    SharedBuffer* buf = SharedBuffer::alloc(size);
+    buf->mClientMetadata = kIsSharedBufferAllocated;
+    return buf;
+}
+
+char16_t* String16::allocFromUTF8(const char* u8str, size_t u8len)
 {
     if (u8len == 0) return getEmptyString();
 
@@ -49,7 +49,7 @@
         return getEmptyString();
     }
 
-    SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t)*(u16len+1));
+    SharedBuffer* buf = static_cast<SharedBuffer*>(alloc(sizeof(char16_t) * (u16len + 1)));
     if (buf) {
         u8cur = (const uint8_t*) u8str;
         char16_t* u16str = (char16_t*)buf->data();
@@ -66,13 +66,13 @@
     return getEmptyString();
 }
 
-static char16_t* allocFromUTF16(const char16_t* u16str, size_t u16len) {
+char16_t* String16::allocFromUTF16(const char16_t* u16str, size_t u16len) {
     if (u16len >= SIZE_MAX / sizeof(char16_t)) {
         android_errorWriteLog(0x534e4554, "73826242");
         abort();
     }
 
-    SharedBuffer* buf = SharedBuffer::alloc((u16len + 1) * sizeof(char16_t));
+    SharedBuffer* buf = static_cast<SharedBuffer*>(alloc((u16len + 1) * sizeof(char16_t)));
     ALOG_ASSERT(buf, "Unable to allocate shared buffer");
     if (buf) {
         char16_t* str = (char16_t*)buf->data();
@@ -97,8 +97,8 @@
     // having run. In this case we always allocate an empty string. It's less
     // efficient than using getEmptyString(), but we assume it's uncommon.
 
-    char16_t* data = static_cast<char16_t*>(
-            SharedBuffer::alloc(sizeof(char16_t))->data());
+    SharedBuffer* buf = static_cast<SharedBuffer*>(alloc(sizeof(char16_t)));
+    char16_t* data = static_cast<char16_t*>(buf->data());
     data[0] = 0;
     mString = data;
 }
@@ -106,7 +106,7 @@
 String16::String16(const String16& o)
     : mString(o.mString)
 {
-    SharedBuffer::bufferFromData(mString)->acquire();
+    acquire();
 }
 
 String16::String16(const String16& o, size_t len, size_t begin)
@@ -136,26 +136,30 @@
 
 String16::~String16()
 {
-    SharedBuffer::bufferFromData(mString)->release();
+    release();
 }
 
 size_t String16::size() const
 {
-    return SharedBuffer::sizeFromData(mString)/sizeof(char16_t)-1;
+    if (isStaticString()) {
+        return staticStringSize();
+    } else {
+        return SharedBuffer::sizeFromData(mString) / sizeof(char16_t) - 1;
+    }
 }
 
 void String16::setTo(const String16& other)
 {
-    SharedBuffer::bufferFromData(other.mString)->acquire();
-    SharedBuffer::bufferFromData(mString)->release();
+    release();
     mString = other.mString;
+    acquire();
 }
 
 status_t String16::setTo(const String16& other, size_t len, size_t begin)
 {
     const size_t N = other.size();
     if (begin >= N) {
-        SharedBuffer::bufferFromData(mString)->release();
+        release();
         mString = getEmptyString();
         return OK;
     }
@@ -184,8 +188,7 @@
         abort();
     }
 
-    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
-        ->editResize((len+1)*sizeof(char16_t));
+    SharedBuffer* buf = static_cast<SharedBuffer*>(editResize((len + 1) * sizeof(char16_t)));
     if (buf) {
         char16_t* str = (char16_t*)buf->data();
         memmove(str, other, len*sizeof(char16_t));
@@ -212,8 +215,8 @@
         abort();
     }
 
-    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
-        ->editResize((myLen+otherLen+1)*sizeof(char16_t));
+    SharedBuffer* buf =
+            static_cast<SharedBuffer*>(editResize((myLen + otherLen + 1) * sizeof(char16_t)));
     if (buf) {
         char16_t* str = (char16_t*)buf->data();
         memcpy(str+myLen, other, (otherLen+1)*sizeof(char16_t));
@@ -238,8 +241,8 @@
         abort();
     }
 
-    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
-        ->editResize((myLen+otherLen+1)*sizeof(char16_t));
+    SharedBuffer* buf =
+            static_cast<SharedBuffer*>(editResize((myLen + otherLen + 1) * sizeof(char16_t)));
     if (buf) {
         char16_t* str = (char16_t*)buf->data();
         memcpy(str+myLen, chrs, otherLen*sizeof(char16_t));
@@ -273,8 +276,8 @@
            len, myLen, String8(chrs, len).string());
     #endif
 
-    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
-        ->editResize((myLen+len+1)*sizeof(char16_t));
+    SharedBuffer* buf =
+            static_cast<SharedBuffer*>(editResize((myLen + len + 1) * sizeof(char16_t)));
     if (buf) {
         char16_t* str = (char16_t*)buf->data();
         if (pos < myLen) {
@@ -338,23 +341,87 @@
     return strstr16(mString, chrs) != nullptr;
 }
 
+void* String16::edit() {
+    SharedBuffer* buf;
+    if (isStaticString()) {
+        buf = static_cast<SharedBuffer*>(alloc((size() + 1) * sizeof(char16_t)));
+        if (buf) {
+            buf->acquire();
+            memcpy(buf->data(), mString, (size() + 1) * sizeof(char16_t));
+        }
+    } else {
+        buf = SharedBuffer::bufferFromData(mString)->edit();
+        buf->mClientMetadata = kIsSharedBufferAllocated;
+    }
+    return buf;
+}
+
+void* String16::editResize(size_t newSize) {
+    SharedBuffer* buf;
+    if (isStaticString()) {
+        size_t copySize = (size() + 1) * sizeof(char16_t);
+        if (newSize < copySize) {
+            copySize = newSize;
+        }
+        buf = static_cast<SharedBuffer*>(alloc(newSize));
+        if (buf) {
+            buf->acquire();
+            memcpy(buf->data(), mString, copySize);
+        }
+    } else {
+        buf = SharedBuffer::bufferFromData(mString)->editResize(newSize);
+        buf->mClientMetadata = kIsSharedBufferAllocated;
+    }
+    return buf;
+}
+
+void String16::acquire()
+{
+    if (!isStaticString()) {
+        SharedBuffer::bufferFromData(mString)->acquire();
+    }
+}
+
+void String16::release()
+{
+    if (!isStaticString()) {
+        SharedBuffer::bufferFromData(mString)->release();
+    }
+}
+
+bool String16::isStaticString() const {
+    // See String16.h for notes on the memory layout of String16::StaticData and
+    // SharedBuffer.
+    static_assert(sizeof(SharedBuffer) - offsetof(SharedBuffer, mClientMetadata) == 4);
+    const uint32_t* p = reinterpret_cast<const uint32_t*>(mString);
+    return (*(p - 1) & kIsSharedBufferAllocated) == 0;
+}
+
+size_t String16::staticStringSize() const {
+    // See String16.h for notes on the memory layout of String16::StaticData and
+    // SharedBuffer.
+    static_assert(sizeof(SharedBuffer) - offsetof(SharedBuffer, mClientMetadata) == 4);
+    const uint32_t* p = reinterpret_cast<const uint32_t*>(mString);
+    return static_cast<size_t>(*(p - 1));
+}
+
 status_t String16::makeLower()
 {
     const size_t N = size();
     const char16_t* str = string();
-    char16_t* edit = nullptr;
+    char16_t* edited = nullptr;
     for (size_t i=0; i<N; i++) {
         const char16_t v = str[i];
         if (v >= 'A' && v <= 'Z') {
-            if (!edit) {
-                SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
+            if (!edited) {
+                SharedBuffer* buf = static_cast<SharedBuffer*>(edit());
                 if (!buf) {
                     return NO_MEMORY;
                 }
-                edit = (char16_t*)buf->data();
-                mString = str = edit;
+                edited = (char16_t*)buf->data();
+                mString = str = edited;
             }
-            edit[i] = tolower((char)v);
+            edited[i] = tolower((char)v);
         }
     }
     return OK;
@@ -364,18 +431,18 @@
 {
     const size_t N = size();
     const char16_t* str = string();
-    char16_t* edit = nullptr;
+    char16_t* edited = nullptr;
     for (size_t i=0; i<N; i++) {
         if (str[i] == replaceThis) {
-            if (!edit) {
-                SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
+            if (!edited) {
+                SharedBuffer* buf = static_cast<SharedBuffer*>(edit());
                 if (!buf) {
                     return NO_MEMORY;
                 }
-                edit = (char16_t*)buf->data();
-                mString = str = edit;
+                edited = (char16_t*)buf->data();
+                mString = str = edited;
             }
-            edit[i] = withThis;
+            edited[i] = withThis;
         }
     }
     return OK;
@@ -385,7 +452,7 @@
 {
     const size_t N = size();
     if (begin >= N) {
-        SharedBuffer::bufferFromData(mString)->release();
+        release();
         mString = getEmptyString();
         return OK;
     }
@@ -395,8 +462,7 @@
     }
 
     if (begin > 0) {
-        SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
-            ->editResize((N+1)*sizeof(char16_t));
+        SharedBuffer* buf = static_cast<SharedBuffer*>(editResize((N + 1) * sizeof(char16_t)));
         if (!buf) {
             return NO_MEMORY;
         }
@@ -404,8 +470,7 @@
         memmove(str, str+begin, (N-begin+1)*sizeof(char16_t));
         mString = str;
     }
-    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
-        ->editResize((len+1)*sizeof(char16_t));
+    SharedBuffer* buf = static_cast<SharedBuffer*>(editResize((len + 1) * sizeof(char16_t)));
     if (buf) {
         char16_t* str = (char16_t*)buf->data();
         str[len] = 0;
diff --git a/libutils/String16_test.cpp b/libutils/String16_test.cpp
new file mode 100644
index 0000000..f1f24c3
--- /dev/null
+++ b/libutils/String16_test.cpp
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+::testing::AssertionResult Char16_tStringEquals(const char16_t* a, const char16_t* b) {
+    if (strcmp16(a, b) != 0) {
+        return ::testing::AssertionFailure()
+               << "\"" << String8(a).c_str() << "\" not equal to \"" << String8(b).c_str() << "\"";
+    }
+    return ::testing::AssertionSuccess();
+}
+
+#define EXPECT_STR16EQ(a, b) EXPECT_TRUE(Char16_tStringEquals(a, b))
+
+TEST(String16Test, FromChar16_t) {
+    String16 tmp(u"Verify me");
+    EXPECT_STR16EQ(u"Verify me", tmp);
+}
+
+TEST(String16Test, FromChar16_tSized) {
+    String16 tmp(u"Verify me", 7);
+    EXPECT_STR16EQ(u"Verify ", tmp);
+}
+
+TEST(String16Test, FromChar) {
+    String16 tmp("Verify me");
+    EXPECT_STR16EQ(u"Verify me", tmp);
+}
+
+TEST(String16Test, FromCharSized) {
+    String16 tmp("Verify me", 7);
+    EXPECT_STR16EQ(u"Verify ", tmp);
+}
+
+TEST(String16Test, Copy) {
+    String16 tmp("Verify me");
+    String16 another = tmp;
+    EXPECT_STR16EQ(u"Verify me", tmp);
+    EXPECT_STR16EQ(u"Verify me", another);
+}
+
+TEST(String16Test, Move) {
+    String16 tmp("Verify me");
+    String16 another(std::move(tmp));
+    EXPECT_STR16EQ(u"Verify me", another);
+}
+
+TEST(String16Test, Size) {
+    String16 tmp("Verify me");
+    EXPECT_EQ(9U, tmp.size());
+}
+
+TEST(String16Test, setTo) {
+    String16 tmp("Verify me");
+    tmp.setTo(u"New content");
+    EXPECT_EQ(11U, tmp.size());
+    EXPECT_STR16EQ(u"New content", tmp);
+}
+
+TEST(String16Test, Append) {
+    String16 tmp("Verify me");
+    tmp.append(String16("Hello"));
+    EXPECT_EQ(14U, tmp.size());
+    EXPECT_STR16EQ(u"Verify meHello", tmp);
+}
+
+TEST(String16Test, Insert) {
+    String16 tmp("Verify me");
+    tmp.insert(6, u"Insert");
+    EXPECT_EQ(15U, tmp.size());
+    EXPECT_STR16EQ(u"VerifyInsert me", tmp);
+}
+
+TEST(String16Test, Remove) {
+    String16 tmp("Verify me");
+    tmp.remove(2, 6);
+    EXPECT_EQ(2U, tmp.size());
+    EXPECT_STR16EQ(u" m", tmp);
+}
+
+TEST(String16Test, MakeLower) {
+    String16 tmp("Verify Me!");
+    tmp.makeLower();
+    EXPECT_EQ(10U, tmp.size());
+    EXPECT_STR16EQ(u"verify me!", tmp);
+}
+
+TEST(String16Test, ReplaceAll) {
+    String16 tmp("Verify verify Verify");
+    tmp.replaceAll(u'r', u'!');
+    EXPECT_STR16EQ(u"Ve!ify ve!ify Ve!ify", tmp);
+}
+
+TEST(String16Test, Compare) {
+    String16 tmp("Verify me");
+    EXPECT_EQ(String16(u"Verify me"), tmp);
+}
+
+TEST(String16Test, StaticString) {
+    String16 nonStaticString("NonStatic");
+    StaticString16 staticString(u"Static");
+
+    EXPECT_TRUE(staticString.isStaticString());
+    EXPECT_FALSE(nonStaticString.isStaticString());
+}
+
+TEST(String16Test, StaticStringCopy) {
+    StaticString16 tmp(u"Verify me");
+    String16 another = tmp;
+    EXPECT_STR16EQ(u"Verify me", tmp);
+    EXPECT_STR16EQ(u"Verify me", another);
+    EXPECT_TRUE(tmp.isStaticString());
+    EXPECT_TRUE(another.isStaticString());
+}
+
+TEST(String16Test, StaticStringMove) {
+    StaticString16 tmp(u"Verify me");
+    String16 another(std::move(tmp));
+    EXPECT_STR16EQ(u"Verify me", another);
+    EXPECT_TRUE(another.isStaticString());
+}
+
+TEST(String16Test, StaticStringSize) {
+    StaticString16 tmp(u"Verify me");
+    EXPECT_EQ(9U, tmp.size());
+}
+
+TEST(String16Test, StaticStringSetTo) {
+    StaticString16 tmp(u"Verify me");
+    tmp.setTo(u"New content");
+    EXPECT_EQ(11U, tmp.size());
+    EXPECT_STR16EQ(u"New content", tmp);
+    EXPECT_FALSE(tmp.isStaticString());
+}
+
+TEST(String16Test, StaticStringAppend) {
+    StaticString16 tmp(u"Verify me");
+    tmp.append(String16("Hello"));
+    EXPECT_EQ(14U, tmp.size());
+    EXPECT_STR16EQ(u"Verify meHello", tmp);
+    EXPECT_FALSE(tmp.isStaticString());
+}
+
+TEST(String16Test, StaticStringInsert) {
+    StaticString16 tmp(u"Verify me");
+    tmp.insert(6, u"Insert");
+    EXPECT_EQ(15U, tmp.size());
+    EXPECT_STR16EQ(u"VerifyInsert me", tmp);
+    EXPECT_FALSE(tmp.isStaticString());
+}
+
+TEST(String16Test, StaticStringRemove) {
+    StaticString16 tmp(u"Verify me");
+    tmp.remove(2, 6);
+    EXPECT_EQ(2U, tmp.size());
+    EXPECT_STR16EQ(u" m", tmp);
+    EXPECT_FALSE(tmp.isStaticString());
+}
+
+TEST(String16Test, StaticStringMakeLower) {
+    StaticString16 tmp(u"Verify me!");
+    tmp.makeLower();
+    EXPECT_EQ(10U, tmp.size());
+    EXPECT_STR16EQ(u"verify me!", tmp);
+    EXPECT_FALSE(tmp.isStaticString());
+}
+
+TEST(String16Test, StaticStringReplaceAll) {
+    StaticString16 tmp(u"Verify verify Verify");
+    tmp.replaceAll(u'r', u'!');
+    EXPECT_STR16EQ(u"Ve!ify ve!ify Ve!ify", tmp);
+    EXPECT_FALSE(tmp.isStaticString());
+}
+
+TEST(String16Test, StaticStringCompare) {
+    StaticString16 tmp(u"Verify me");
+    EXPECT_EQ(String16(u"Verify me"), tmp);
+}
+
+TEST(String16Test, StringSetToStaticString) {
+    StaticString16 tmp(u"Verify me");
+    String16 another(u"nonstatic");
+    another = tmp;
+    EXPECT_STR16EQ(u"Verify me", tmp);
+    EXPECT_STR16EQ(u"Verify me", another);
+}
+
+TEST(String16Test, StringMoveFromStaticString) {
+    StaticString16 tmp(u"Verify me");
+    String16 another(std::move(tmp));
+    EXPECT_STR16EQ(u"Verify me", another);
+}
+
+TEST(String16Test, EmptyStringIsStatic) {
+    String16 tmp("");
+    EXPECT_TRUE(tmp.isStaticString());
+}
+
+}  // namespace android
diff --git a/libutils/Vector_benchmark.cpp b/libutils/Vector_benchmark.cpp
new file mode 100644
index 0000000..c23d499
--- /dev/null
+++ b/libutils/Vector_benchmark.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <benchmark/benchmark.h>
+#include <utils/Vector.h>
+#include <vector>
+
+void BM_fill_android_vector(benchmark::State& state) {
+    android::Vector<char> v;
+    while (state.KeepRunning()) {
+        v.push('A');
+    }
+}
+BENCHMARK(BM_fill_android_vector);
+
+void BM_fill_std_vector(benchmark::State& state) {
+    std::vector<char> v;
+    while (state.KeepRunning()) {
+        v.push_back('A');
+    }
+}
+BENCHMARK(BM_fill_std_vector);
+
+void BM_prepend_android_vector(benchmark::State& state) {
+    android::Vector<char> v;
+    while (state.KeepRunning()) {
+        v.insertAt('A', 0);
+    }
+}
+BENCHMARK(BM_prepend_android_vector);
+
+void BM_prepend_std_vector(benchmark::State& state) {
+    std::vector<char> v;
+    while (state.KeepRunning()) {
+        v.insert(v.begin(), 'A');
+    }
+}
+BENCHMARK(BM_prepend_std_vector);
+
+BENCHMARK_MAIN();
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index afbc2ed..adc3e7d 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -37,13 +37,17 @@
 
 class String8;
 
+template <size_t N>
+class StaticString16;
+
 // DO NOT USE: please use std::u16string
 
 //! This is a string holding UTF-16 characters.
 class String16
 {
 public:
-    /* use String16(StaticLinkage) if you're statically linking against
+    /*
+     * Use String16(StaticLinkage) if you're statically linking against
      * libutils and declaring an empty static String16, e.g.:
      *
      *   static String16 sAStaticEmptyString(String16::kEmptyString);
@@ -123,8 +127,76 @@
 
     inline                      operator const char16_t*() const;
 
-private:
-            const char16_t*     mString;
+    // Static and non-static String16 behave the same for the users, so
+    // this method isn't of much use for the users. It is public for testing.
+            bool                isStaticString() const;
+
+  private:
+    /*
+     * A flag indicating the type of underlying buffer.
+     */
+    static constexpr uint32_t kIsSharedBufferAllocated = 0x80000000;
+
+    /*
+     * alloc() returns void* so that SharedBuffer class is not exposed.
+     */
+    static void* alloc(size_t size);
+    static char16_t* allocFromUTF8(const char* u8str, size_t u8len);
+    static char16_t* allocFromUTF16(const char16_t* u16str, size_t u16len);
+
+    /*
+     * edit() and editResize() return void* so that SharedBuffer class
+     * is not exposed.
+     */
+    void* edit();
+    void* editResize(size_t new_size);
+
+    void acquire();
+    void release();
+
+    size_t staticStringSize() const;
+
+    const char16_t* mString;
+
+protected:
+    /*
+     * Data structure used to allocate static storage for static String16.
+     *
+     * Note that this data structure and SharedBuffer are used interchangably
+     * as the underlying data structure for a String16.  Therefore, the layout
+     * of this data structure must match the part in SharedBuffer that is
+     * visible to String16.
+     */
+    template <size_t N>
+    struct StaticData {
+        // The high bit of 'size' is used as a flag.
+        static_assert(N - 1 < kIsSharedBufferAllocated, "StaticString16 too long!");
+        constexpr StaticData() : size(N - 1), data{0} {}
+        const uint32_t size;
+        char16_t data[N];
+
+        constexpr StaticData(const StaticData<N>&) = default;
+    };
+
+    /*
+     * Helper function for constructing a StaticData object.
+     */
+    template <size_t N>
+    static constexpr const StaticData<N> makeStaticData(const char16_t (&s)[N]) {
+        StaticData<N> r;
+        // The 'size' field is at the same location where mClientMetadata would
+        // be for a SharedBuffer.  We do NOT set kIsSharedBufferAllocated flag
+        // here.
+        for (size_t i = 0; i < N - 1; ++i) r.data[i] = s[i];
+        return r;
+    }
+
+    template <size_t N>
+    explicit constexpr String16(const StaticData<N>& s) : mString(s.data) {}
+
+public:
+    template <size_t N>
+    explicit constexpr String16(const StaticString16<N>& s) : mString(s.mString) {}
 };
 
 // String16 can be trivially moved using memcpy() because moving does not
@@ -132,6 +204,42 @@
 ANDROID_TRIVIAL_MOVE_TRAIT(String16)
 
 // ---------------------------------------------------------------------------
+
+/*
+ * A StaticString16 object is a specialized String16 object.  Instead of holding
+ * the string data in a ref counted SharedBuffer object, it holds data in a
+ * buffer within StaticString16 itself.  Note that this buffer is NOT ref
+ * counted and is assumed to be available for as long as there is at least a
+ * String16 object using it.  Therefore, one must be extra careful to NEVER
+ * assign a StaticString16 to a String16 that outlives the StaticString16
+ * object.
+ *
+ * THE SAFEST APPROACH IS TO USE StaticString16 ONLY AS GLOBAL VARIABLES.
+ *
+ * A StaticString16 SHOULD NEVER APPEAR IN APIs.  USE String16 INSTEAD.
+ */
+template <size_t N>
+class StaticString16 : public String16 {
+public:
+    constexpr StaticString16(const char16_t (&s)[N]) : String16(mData), mData(makeStaticData(s)) {}
+
+    constexpr StaticString16(const StaticString16<N>& other)
+        : String16(mData), mData(other.mData) {}
+
+    constexpr StaticString16(const StaticString16<N>&&) = delete;
+
+    // There is no reason why one would want to 'new' a StaticString16.  Delete
+    // it to discourage misuse.
+    static void* operator new(std::size_t) = delete;
+
+private:
+    const StaticData<N> mData;
+};
+
+template <typename F>
+StaticString16(const F&)->StaticString16<sizeof(F) / sizeof(char16_t)>;
+
+// ---------------------------------------------------------------------------
 // No user servicable parts below.
 
 inline int compare_type(const String16& lhs, const String16& rhs)
diff --git a/rootdir/init.rc b/rootdir/init.rc
index afa1a86..d12096d 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -127,7 +127,7 @@
     mkdir /mnt/expand 0771 system system
     mkdir /mnt/appfuse 0711 root root
 
-    # tmpfs place for BORINGSSL_self_test() to remember whether it has run
+    # These must already exist by the time boringssl_self_test32 / boringssl_self_test64 run.
     mkdir /dev/boringssl 0755 root root
     mkdir /dev/boringssl/selftest 0755 root root
 
@@ -315,6 +315,16 @@
     start hwservicemanager
     start vndservicemanager
 
+# Run boringssl self test for each ABI so that later processes can skip it. http://b/139348610
+on init && property:ro.product.cpu.abilist32=*
+    exec_reboot_on_failure boringssl-self-check-failed /system/bin/boringssl_self_test32
+on init && property:ro.product.cpu.abilist64=*
+    exec_reboot_on_failure boringssl-self-check-failed /system/bin/boringssl_self_test64
+on property:apexd.status=ready && property:ro.product.cpu.abilist64=*
+    exec_reboot_on_failure boringssl-self-check-failed /apex/com.android.conscrypt/bin/boringssl_self_test64
+on property:apexd.status=ready && property:ro.product.cpu.abilist32=*
+    exec_reboot_on_failure boringssl-self-check-failed /apex/com.android.conscrypt/bin/boringssl_self_test32
+
 # Healthd can trigger a full boot from charger mode by signaling this
 # property when the power button is held.
 on property:sys.boot_from_charger_mode=1
@@ -435,7 +445,6 @@
     mark_post_data
 
     # Start checkpoint before we touch data
-    start vold
     exec - system system -- /system/bin/vdc checkpoint prepareCheckpoint
 
     # We chown/chmod /data again so because mount is run as root + defaults
diff --git a/storaged/Android.bp b/storaged/Android.bp
index 733b60f..cc19481 100644
--- a/storaged/Android.bp
+++ b/storaged/Android.bp
@@ -24,8 +24,6 @@
         "libbinder",
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libprotobuf-cpp-lite",
         "libsysutils",
diff --git a/trusty/gatekeeper/Android.bp b/trusty/gatekeeper/Android.bp
index 1666cfb..e553af1 100644
--- a/trusty/gatekeeper/Android.bp
+++ b/trusty/gatekeeper/Android.bp
@@ -42,7 +42,6 @@
         "android.hardware.gatekeeper@1.0",
         "libbase",
         "libhidlbase",
-        "libhidltransport",
         "libgatekeeper",
         "libutils",
         "liblog",
diff --git a/trusty/keymaster/4.0/TrustyKeymaster4Device.cpp b/trusty/keymaster/4.0/TrustyKeymaster4Device.cpp
index b5fc6bf..ec2ba12 100644
--- a/trusty/keymaster/4.0/TrustyKeymaster4Device.cpp
+++ b/trusty/keymaster/4.0/TrustyKeymaster4Device.cpp
@@ -17,6 +17,7 @@
 
 #define LOG_TAG "android.hardware.keymaster@4.0-impl.trusty"
 
+#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
 #include <authorization_set.h>
 #include <cutils/log.h>
 #include <keymaster/android_keymaster_messages.h>
@@ -46,6 +47,9 @@
 using ::keymaster::UpdateOperationResponse;
 using ::keymaster::ng::Tag;
 
+typedef ::android::hardware::keymaster::V3_0::Tag Tag3;
+using ::android::hardware::keymaster::V4_0::Constants;
+
 namespace keymaster {
 namespace V4_0 {
 namespace {
@@ -79,6 +83,45 @@
     return keymaster_tag_get_type(tag);
 }
 
+/*
+ * injectAuthToken translates a KM4 authToken into a legacy AUTH_TOKEN tag
+ *
+ * Currently, system/keymaster's reference implementation only accepts this
+ * method for passing an auth token, so until that changes we need to
+ * translate to the old format.
+ */
+inline hidl_vec<KeyParameter> injectAuthToken(const hidl_vec<KeyParameter>& keyParamsBase,
+                                              const HardwareAuthToken& authToken) {
+    std::vector<KeyParameter> keyParams(keyParamsBase);
+    const size_t mac_len = static_cast<size_t>(Constants::AUTH_TOKEN_MAC_LENGTH);
+    /*
+     * mac.size() == 0 indicates no token provided, so we should not copy.
+     * mac.size() != mac_len means it is incompatible with the old
+     *   hw_auth_token_t structure. This is forbidden by spec, but to be safe
+     *   we only copy if mac.size() == mac_len, e.g. there is an authToken
+     *   with a hw_auth_token_t compatible MAC.
+     */
+    if (authToken.mac.size() == mac_len) {
+        KeyParameter p;
+        p.tag = static_cast<Tag>(Tag3::AUTH_TOKEN);
+        p.blob.resize(sizeof(hw_auth_token_t));
+
+        hw_auth_token_t* auth_token = reinterpret_cast<hw_auth_token_t*>(p.blob.data());
+        auth_token->version = 0;
+        auth_token->challenge = authToken.challenge;
+        auth_token->user_id = authToken.userId;
+        auth_token->authenticator_id = authToken.authenticatorId;
+        auth_token->authenticator_type =
+                htobe32(static_cast<uint32_t>(authToken.authenticatorType));
+        auth_token->timestamp = htobe64(authToken.timestamp);
+        static_assert(mac_len == sizeof(auth_token->hmac));
+        memcpy(auth_token->hmac, authToken.mac.data(), mac_len);
+        keyParams.push_back(p);
+    }
+
+    return hidl_vec<KeyParameter>(std::move(keyParams));
+}
+
 class KmParamSet : public keymaster_key_param_set_t {
   public:
     KmParamSet(const hidl_vec<KeyParameter>& keyParams) {
@@ -472,11 +515,11 @@
 Return<void> TrustyKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
                                            const hidl_vec<KeyParameter>& inParams,
                                            const HardwareAuthToken& authToken, begin_cb _hidl_cb) {
-    (void)authToken;
+    hidl_vec<KeyParameter> extendedParams = injectAuthToken(inParams, authToken);
     BeginOperationRequest request;
     request.purpose = legacy_enum_conversion(purpose);
     request.SetKeyMaterial(key.data(), key.size());
-    request.additional_params.Reinitialize(KmParamSet(inParams));
+    request.additional_params.Reinitialize(KmParamSet(extendedParams));
 
     BeginOperationResponse response;
     impl_->BeginOperation(request, &response);
@@ -496,16 +539,16 @@
                                             const HardwareAuthToken& authToken,
                                             const VerificationToken& verificationToken,
                                             update_cb _hidl_cb) {
-    (void)authToken;
     (void)verificationToken;
     UpdateOperationRequest request;
     UpdateOperationResponse response;
     hidl_vec<KeyParameter> resultParams;
     hidl_vec<uint8_t> resultBlob;
+    hidl_vec<KeyParameter> extendedParams = injectAuthToken(inParams, authToken);
     uint32_t resultConsumed = 0;
 
     request.op_handle = operationHandle;
-    request.additional_params.Reinitialize(KmParamSet(inParams));
+    request.additional_params.Reinitialize(KmParamSet(extendedParams));
 
     size_t inp_size = input.size();
     size_t ser_size = request.SerializedSize();
@@ -537,13 +580,13 @@
                                             const HardwareAuthToken& authToken,
                                             const VerificationToken& verificationToken,
                                             finish_cb _hidl_cb) {
-    (void)authToken;
     (void)verificationToken;
     FinishOperationRequest request;
+    hidl_vec<KeyParameter> extendedParams = injectAuthToken(inParams, authToken);
     request.op_handle = operationHandle;
     request.input.Reinitialize(input.data(), input.size());
     request.signature.Reinitialize(signature.data(), signature.size());
-    request.additional_params.Reinitialize(KmParamSet(inParams));
+    request.additional_params.Reinitialize(KmParamSet(extendedParams));
 
     FinishOperationResponse response;
     impl_->FinishOperation(request, &response);
diff --git a/trusty/keymaster/4.0/android.hardware.keymaster@4.0-service.trusty.xml b/trusty/keymaster/4.0/android.hardware.keymaster@4.0-service.trusty.xml
new file mode 100644
index 0000000..aa30707
--- /dev/null
+++ b/trusty/keymaster/4.0/android.hardware.keymaster@4.0-service.trusty.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.keymaster</name>
+        <transport>hwbinder</transport>
+        <version>4.0</version>
+        <interface>
+        <name>IKeymasterDevice</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index d107b78..f32a69e 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -101,7 +101,6 @@
         "libutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "libtrusty",
         "libkeymaster_messages",
         "libkeymaster3device",
@@ -132,10 +131,11 @@
         "libutils",
         "libhardware",
         "libhidlbase",
-        "libhidltransport",
         "libtrusty",
         "libkeymaster_messages",
         "libkeymaster4",
         "android.hardware.keymaster@4.0"
     ],
+
+    vintf_fragments: ["4.0/android.hardware.keymaster@4.0-service.trusty.xml"],
 }
diff --git a/usbd/Android.bp b/usbd/Android.bp
index 3afa7a9..6a339a1 100644
--- a/usbd/Android.bp
+++ b/usbd/Android.bp
@@ -5,7 +5,6 @@
     shared_libs: [
         "libbase",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
         "libhardware",