Merge "Remove ashmem from system/core"
diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp
index 869e858..f1bf559 100644
--- a/adb/client/usb_linux.cpp
+++ b/adb/client/usb_linux.cpp
@@ -30,6 +30,7 @@
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/time.h>
+#include <sys/sysmacros.h>
 #include <sys/types.h>
 #include <unistd.h>
 
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
index f7017dd..ed5f944 100644
--- a/adb/daemon/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -38,7 +38,6 @@
 #include <android-base/properties.h>
 #include <bootloader_message/bootloader_message.h>
 #include <cutils/android_reboot.h>
-#include <ext4_utils/ext4_utils.h>
 #include <fs_mgr.h>
 #include <fs_mgr_overlayfs.h>
 
@@ -96,27 +95,6 @@
     return result;
 }
 
-static bool fs_has_shared_blocks(const std::string& mount_point, const std::string& device) {
-    std::string path = mount_point + "/lost+found";
-    struct statfs fs;
-    if (statfs(path.c_str(), &fs) == -1 || fs.f_type != EXT4_SUPER_MAGIC) {
-        return false;
-    }
-    unique_fd fd(unix_open(device.c_str(), O_RDONLY));
-    if (fd < 0) {
-        return false;
-    }
-    struct ext4_super_block sb;
-    if (lseek64(fd, 1024, SEEK_SET) < 0 || unix_read(fd, &sb, sizeof(sb)) < 0) {
-        return false;
-    }
-    struct fs_info info;
-    if (ext4_parse_sb(&sb, &info) < 0) {
-        return false;
-    }
-    return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0;
-}
-
 static bool can_unshare_blocks(int fd, const char* dev) {
     const char* E2FSCK_BIN = "/system/bin/e2fsck";
     if (access(E2FSCK_BIN, X_OK)) {
@@ -250,7 +228,7 @@
     std::set<std::string> dedup;
     for (const auto& partition : partitions) {
         std::string dev = find_mount(partition.c_str(), partition == "/");
-        if (dev.empty() || !fs_has_shared_blocks(partition, dev)) {
+        if (dev.empty() || !fs_mgr_has_shared_blocks(partition, dev)) {
             continue;
         }
         if (can_unshare_blocks(fd.get(), dev.c_str())) {
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
index 5bfa47e..9444fdd 100644
--- a/base/include/android-base/parseint.h
+++ b/base/include/android-base/parseint.h
@@ -38,6 +38,7 @@
   }
 
   if (s[0] == '-') {
+    errno = EINVAL;
     return false;
   }
 
@@ -45,14 +46,22 @@
   errno = 0;
   char* end;
   unsigned long long int result = strtoull(s, &end, base);
-  if (errno != 0 || end == s) return false;
+  if (errno != 0) return false;
+  if (end == s) {
+    errno = EINVAL;
+    return false;
+  }
   if (*end != '\0') {
     const char* suffixes = "bkmgtpe";
     const char* suffix;
-    if (!allow_suffixes || (suffix = strchr(suffixes, tolower(*end))) == nullptr) return false;
-    if (__builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) return false;
+    if ((!allow_suffixes || (suffix = strchr(suffixes, tolower(*end))) == nullptr) ||
+        __builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) {
+      errno = EINVAL;
+      return false;
+    }
   }
   if (max < result) {
+    errno = ERANGE;
     return false;
   }
   if (out != nullptr) {
@@ -95,10 +104,15 @@
   errno = 0;
   char* end;
   long long int result = strtoll(s, &end, base);
-  if (errno != 0 || s == end || *end != '\0') {
+  if (errno != 0) {
+    return false;
+  }
+  if (s == end || *end != '\0') {
+    errno = EINVAL;
     return false;
   }
   if (result < min || max < result) {
+    errno = ERANGE;
     return false;
   }
   if (out != nullptr) {
diff --git a/base/parseint_test.cpp b/base/parseint_test.cpp
index b8cf654..e449c33 100644
--- a/base/parseint_test.cpp
+++ b/base/parseint_test.cpp
@@ -16,15 +16,22 @@
 
 #include "android-base/parseint.h"
 
+#include <errno.h>
+
 #include <gtest/gtest.h>
 
 TEST(parseint, signed_smoke) {
+  errno = 0;
   int i = 0;
   ASSERT_FALSE(android::base::ParseInt("x", &i));
+  ASSERT_EQ(EINVAL, errno);
+  errno = 0;
   ASSERT_FALSE(android::base::ParseInt("123x", &i));
+  ASSERT_EQ(EINVAL, errno);
 
   ASSERT_TRUE(android::base::ParseInt("123", &i));
   ASSERT_EQ(123, i);
+  ASSERT_EQ(0, errno);
   i = 0;
   EXPECT_TRUE(android::base::ParseInt("  123", &i));
   EXPECT_EQ(123, i);
@@ -40,26 +47,43 @@
 
   ASSERT_TRUE(android::base::ParseInt("12", &i, 0, 15));
   ASSERT_EQ(12, i);
+  errno = 0;
   ASSERT_FALSE(android::base::ParseInt("-12", &i, 0, 15));
+  ASSERT_EQ(ERANGE, errno);
+  errno = 0;
   ASSERT_FALSE(android::base::ParseInt("16", &i, 0, 15));
+  ASSERT_EQ(ERANGE, errno);
 
+  errno = 0;
   ASSERT_FALSE(android::base::ParseInt<int>("x", nullptr));
+  ASSERT_EQ(EINVAL, errno);
+  errno = 0;
   ASSERT_FALSE(android::base::ParseInt<int>("123x", nullptr));
+  ASSERT_EQ(EINVAL, errno);
   ASSERT_TRUE(android::base::ParseInt<int>("1234", nullptr));
 }
 
 TEST(parseint, unsigned_smoke) {
+  errno = 0;
   unsigned int i = 0u;
   ASSERT_FALSE(android::base::ParseUint("x", &i));
+  ASSERT_EQ(EINVAL, errno);
+  errno = 0;
   ASSERT_FALSE(android::base::ParseUint("123x", &i));
+  ASSERT_EQ(EINVAL, errno);
 
   ASSERT_TRUE(android::base::ParseUint("123", &i));
   ASSERT_EQ(123u, i);
+  ASSERT_EQ(0, errno);
   i = 0u;
   EXPECT_TRUE(android::base::ParseUint("  123", &i));
   EXPECT_EQ(123u, i);
+  errno = 0;
   ASSERT_FALSE(android::base::ParseUint("-123", &i));
+  EXPECT_EQ(EINVAL, errno);
+  errno = 0;
   EXPECT_FALSE(android::base::ParseUint("  -123", &i));
+  EXPECT_EQ(EINVAL, errno);
 
   unsigned short s = 0u;
   ASSERT_TRUE(android::base::ParseUint("1234", &s));
@@ -67,16 +91,28 @@
 
   ASSERT_TRUE(android::base::ParseUint("12", &i, 15u));
   ASSERT_EQ(12u, i);
+  errno = 0;
   ASSERT_FALSE(android::base::ParseUint("-12", &i, 15u));
+  ASSERT_EQ(EINVAL, errno);
+  errno = 0;
   ASSERT_FALSE(android::base::ParseUint("16", &i, 15u));
+  ASSERT_EQ(ERANGE, errno);
 
+  errno = 0;
   ASSERT_FALSE(android::base::ParseUint<unsigned short>("x", nullptr));
+  ASSERT_EQ(EINVAL, errno);
+  errno = 0;
   ASSERT_FALSE(android::base::ParseUint<unsigned short>("123x", nullptr));
+  ASSERT_EQ(EINVAL, errno);
   ASSERT_TRUE(android::base::ParseUint<unsigned short>("1234", nullptr));
 
+  errno = 0;
   unsigned long long int lli;
   EXPECT_FALSE(android::base::ParseUint("-123", &lli));
+  EXPECT_EQ(EINVAL, errno);
+  errno = 0;
   EXPECT_FALSE(android::base::ParseUint("  -123", &lli));
+  EXPECT_EQ(EINVAL, errno);
 }
 
 TEST(parseint, no_implicit_octal) {
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index dfb7a6a..e2ea480 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -29,6 +29,7 @@
 #include <regex>
 #include <thread>
 
+#include <android/fdsan.h>
 #include <android/set_abort_message.h>
 
 #include <android-base/file.h>
@@ -801,6 +802,31 @@
   AssertDeath(SIGABRT);
 }
 
+TEST_F(CrasherTest, fdsan_warning_abort_message) {
+  int intercept_result;
+  unique_fd output_fd;
+
+  StartProcess([]() {
+    android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
+    unique_fd fd(open("/dev/null", O_RDONLY | O_CLOEXEC));
+    if (fd == -1) {
+      abort();
+    }
+    close(fd.get());
+    _exit(0);
+  });
+
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  AssertDeath(0);
+  FinishIntercept(&intercept_result);
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+  ASSERT_MATCH(result, "Abort message: 'attempted to close");
+}
+
 TEST(crash_dump, zombie) {
   pid_t forkpid = fork();
 
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 91e6f71..15557b6 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -457,14 +457,14 @@
     info = nullptr;
   }
 
-  struct siginfo si = {};
+  struct siginfo dummy_info = {};
   if (!info) {
-    memset(&si, 0, sizeof(si));
-    si.si_signo = signal_number;
-    si.si_code = SI_USER;
-    si.si_pid = __getpid();
-    si.si_uid = getuid();
-    info = &si;
+    memset(&dummy_info, 0, sizeof(dummy_info));
+    dummy_info.si_signo = signal_number;
+    dummy_info.si_code = SI_USER;
+    dummy_info.si_pid = __getpid();
+    dummy_info.si_uid = getuid();
+    info = &dummy_info;
   } else if (info->si_code >= 0 || info->si_code == SI_TKILL) {
     // rt_tgsigqueueinfo(2)'s documentation appears to be incorrect on kernels
     // that contain commit 66dd34a (3.9+). The manpage claims to only allow
@@ -473,8 +473,18 @@
   }
 
   void* abort_message = nullptr;
-  if (signal_number != DEBUGGER_SIGNAL && g_callbacks.get_abort_message) {
-    abort_message = g_callbacks.get_abort_message();
+  if (signal_number == DEBUGGER_SIGNAL) {
+    if (info->si_code == SI_QUEUE && info->si_pid == __getpid()) {
+      // Allow for the abort message to be explicitly specified via the sigqueue value.
+      // Keep the bottom bit intact for representing whether we want a backtrace or a tombstone.
+      uintptr_t value = reinterpret_cast<uintptr_t>(info->si_ptr);
+      abort_message = reinterpret_cast<void*>(value & ~1);
+      info->si_ptr = reinterpret_cast<void*>(value & 1);
+    }
+  } else {
+    if (g_callbacks.get_abort_message) {
+      abort_message = g_callbacks.get_abort_message();
+    }
   }
 
   // If sival_int is ~0, it means that the fallback handler has been called
diff --git a/debuggerd/libdebuggerd/open_files_list.cpp b/debuggerd/libdebuggerd/open_files_list.cpp
index 03e4e8e..743a2e7 100644
--- a/debuggerd/libdebuggerd/open_files_list.cpp
+++ b/debuggerd/libdebuggerd/open_files_list.cpp
@@ -18,6 +18,7 @@
 
 #include "libdebuggerd/open_files_list.h"
 
+#include <android/fdsan.h>
 #include <dirent.h>
 #include <errno.h>
 #include <stdio.h>
@@ -122,8 +123,10 @@
     const std::optional<std::string>& path = entry.path;
     const std::optional<uint64_t>& fdsan_owner = entry.fdsan_owner;
     if (path && fdsan_owner) {
-      _LOG(log, logtype::OPEN_FILES, "%sfd %i: %s (owned by %#" PRIx64 ")\n", prefix, fd,
-           path->c_str(), *fdsan_owner);
+      const char* type = android_fdsan_get_tag_type(*fdsan_owner);
+      uint64_t value = android_fdsan_get_tag_value(*fdsan_owner);
+      _LOG(log, logtype::OPEN_FILES, "%sfd %i: %s (owned by %s %#" PRIx64 ")\n", prefix, fd,
+           path->c_str(), type, value);
     } else if (path && !fdsan_owner) {
       _LOG(log, logtype::OPEN_FILES, "%sfd %i: %s (unowned)\n", prefix, fd, path->c_str());
     } else if (!path && fdsan_owner) {
diff --git a/fastboot/README.md b/fastboot/README.md
index 15b5965..c224448 100644
--- a/fastboot/README.md
+++ b/fastboot/README.md
@@ -136,10 +136,6 @@
                        should not support "upload" unless it supports an
                        oem command that requires "upload" capabilities.
 
-    verify:%08x        Send a digital signature to verify the downloaded
-                       data.  Required if the bootloader is "secure"
-                       otherwise "flash" and "boot" will be ignored.
-
     flash:%s           Write the previously downloaded image to the
                        named partition (if possible).
 
@@ -159,8 +155,6 @@
                        the bootloader and then upgrading other partitions
                        using the new bootloader.
 
-    powerdown          Power off the device.
-
 
 
 ## Client Variables
diff --git a/fastboot/constants.h b/fastboot/constants.h
index 6542b83..063cd40 100644
--- a/fastboot/constants.h
+++ b/fastboot/constants.h
@@ -18,7 +18,6 @@
 #define FB_CMD_GETVAR "getvar"
 #define FB_CMD_DOWNLOAD "download"
 #define FB_CMD_UPLOAD "upload"
-#define FB_CMD_VERIFY "verify"
 #define FB_CMD_FLASH "flash"
 #define FB_CMD_ERASE "erase"
 #define FB_CMD_BOOT "boot"
@@ -29,7 +28,6 @@
 #define FB_CMD_REBOOT_BOOTLOADER "reboot-bootloader"
 #define FB_CMD_REBOOT_RECOVERY "reboot-recovery"
 #define FB_CMD_REBOOT_FASTBOOT "reboot-fastboot"
-#define FB_CMD_POWERDOWN "powerdown"
 #define FB_CMD_CREATE_PARTITION "create-logical-partition"
 #define FB_CMD_DELETE_PARTITION "delete-logical-partition"
 #define FB_CMD_RESIZE_PARTITION "resize-logical-partition"
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 6890643..6a52b12 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -79,12 +79,18 @@
 static std::vector<std::unique_ptr<Action>> action_list;
 static fastboot::FastBootDriver* fb = nullptr;
 
+static constexpr char kStatusFormat[] = "%-50s ";
+
 void fb_init(fastboot::FastBootDriver& fbi) {
     fb = &fbi;
     auto cb = [](std::string& info) { fprintf(stderr, "(bootloader) %s\n", info.c_str()); };
     fb->SetInfoCallback(cb);
 }
 
+void fb_reinit(Transport* transport) {
+    fb->set_transport(transport);
+}
+
 const std::string fb_get_error() {
     return fb->Error();
 }
@@ -332,7 +338,7 @@
     for (auto& a : action_list) {
         a->start = now();
         if (!a->msg.empty()) {
-            fprintf(stderr, "%-50s ", a->msg.c_str());
+            fprintf(stderr, kStatusFormat, a->msg.c_str());
             verbose("\n");
         }
         if (a->op == OP_DOWNLOAD) {
@@ -372,3 +378,20 @@
     action_list.clear();
     return status;
 }
+
+bool fb_reboot_to_userspace() {
+    // First ensure that the queue is flushed.
+    fb_execute_queue();
+
+    fprintf(stderr, kStatusFormat, "Rebooting to userspace fastboot");
+    verbose("\n");
+
+    if (fb->RebootTo("fastboot") != fastboot::RetCode::SUCCESS) {
+        fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
+        return false;
+    }
+    fprintf(stderr, "OKAY\n");
+
+    fb->set_transport(nullptr);
+    return true;
+}
diff --git a/fastboot/engine.h b/fastboot/engine.h
index 8aebdd7..f098ca7 100644
--- a/fastboot/engine.h
+++ b/fastboot/engine.h
@@ -50,6 +50,7 @@
 /* engine.c - high level command queue engine */
 
 void fb_init(fastboot::FastBootDriver& fbi);
+void fb_reinit(Transport* transport);
 
 bool fb_getvar(const std::string& key, std::string* value);
 void fb_queue_flash(const std::string& partition, void* data, uint32_t sz);
@@ -74,6 +75,7 @@
 void fb_queue_resize_partition(const std::string& partition, const std::string& size);
 int64_t fb_execute_queue();
 void fb_set_active(const std::string& slot);
+bool fb_reboot_to_userspace();
 
 /* Current product */
 extern char cur_product[FB_RESPONSE_SZ + 1];
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 20c3359..331b0c8 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -107,44 +107,56 @@
     int64_t image_size;
 };
 
+enum class ImageType {
+    // Must be flashed for device to boot into the kernel.
+    BootCritical,
+    // Normal partition to be flashed during "flashall".
+    Normal,
+    // Partition that is never flashed during "flashall".
+    Extra
+};
+
 struct Image {
     const char* nickname;
     const char* img_name;
     const char* sig_name;
     const char* part_name;
     bool optional_if_no_image;
-    bool optional_if_no_partition;
+    ImageType type;
     bool IsSecondary() const { return nickname == nullptr; }
 };
 
 static Image images[] = {
         // clang-format off
-    { "boot",     "boot.img",         "boot.sig",     "boot",     false, false },
-    { nullptr,    "boot_other.img",   "boot.sig",     "boot",     true,  false },
-    { "dtbo",     "dtbo.img",         "dtbo.sig",     "dtbo",     true,  false },
-    { "dts",      "dt.img",           "dt.sig",       "dts",      true,  false },
-    { "odm",      "odm.img",          "odm.sig",      "odm",      true,  false },
-    { "product",  "product.img",      "product.sig",  "product",  true,  false },
+    { "boot",     "boot.img",         "boot.sig",     "boot",     false, ImageType::BootCritical },
+    { nullptr,    "boot_other.img",   "boot.sig",     "boot",     true,  ImageType::Normal },
+    { "cache",    "cache.img",        "cache.sig",    "cache",    true,  ImageType::Extra },
+    { "dtbo",     "dtbo.img",         "dtbo.sig",     "dtbo",     true,  ImageType::BootCritical },
+    { "dts",      "dt.img",           "dt.sig",       "dts",      true,  ImageType::BootCritical },
+    { "odm",      "odm.img",          "odm.sig",      "odm",      true,  ImageType::Normal },
+    { "product",  "product.img",      "product.sig",  "product",  true,  ImageType::Normal },
     { "product_services",
                   "product_services.img",
                                       "product_services.sig",
                                                       "product_services",
-                                                                  true,  true  },
-    { "recovery", "recovery.img",     "recovery.sig", "recovery", true,  false },
-    { "system",   "system.img",       "system.sig",   "system",   false, true  },
-    { nullptr,    "system_other.img", "system.sig",   "system",   true,  false },
-    { "vbmeta",   "vbmeta.img",       "vbmeta.sig",   "vbmeta",   true,  false },
-    { "vendor",   "vendor.img",       "vendor.sig",   "vendor",   true,  true  },
-    { nullptr,    "vendor_other.img", "vendor.sig",   "vendor",   true,  false },
+                                                                  true,  ImageType::Normal },
+    { "recovery", "recovery.img",     "recovery.sig", "recovery", true,  ImageType::BootCritical },
+    { "super",    "super.img",        "super.sig",    "super",    true,  ImageType::Extra },
+    { "system",   "system.img",       "system.sig",   "system",   false, ImageType::Normal },
+    { nullptr,    "system_other.img", "system.sig",   "system",   true,  ImageType::Normal },
+    { "userdata", "userdata.img",     "userdata.sig", "userdata", true,  ImageType::Extra },
+    { "vbmeta",   "vbmeta.img",       "vbmeta.sig",   "vbmeta",   true,  ImageType::BootCritical },
+    { "vendor",   "vendor.img",       "vendor.sig",   "vendor",   true,  ImageType::Normal },
+    { nullptr,    "vendor_other.img", "vendor.sig",   "vendor",   true,  ImageType::Normal },
         // clang-format on
 };
 
-static std::string find_item_given_name(const char* img_name) {
+static std::string find_item_given_name(const std::string& img_name) {
     char* dir = getenv("ANDROID_PRODUCT_OUT");
     if (dir == nullptr || dir[0] == '\0') {
         die("ANDROID_PRODUCT_OUT not set");
     }
-    return android::base::StringPrintf("%s/%s", dir, img_name);
+    return std::string(dir) + "/" + img_name;
 }
 
 static std::string find_item(const std::string& item) {
@@ -154,9 +166,6 @@
         }
     }
 
-    if (item == "userdata") return find_item_given_name("userdata.img");
-    if (item == "cache") return find_item_given_name("cache.img");
-
     fprintf(stderr, "unknown partition '%s'\n", item.c_str());
     return "";
 }
@@ -244,13 +253,8 @@
 // The returned Transport is a singleton, so multiple calls to this function will return the same
 // object, and the caller should not attempt to delete the returned Transport.
 static Transport* open_device() {
-    static Transport* transport = nullptr;
     bool announce = true;
 
-    if (transport != nullptr) {
-        return transport;
-    }
-
     Socket::Protocol protocol = Socket::Protocol::kTcp;
     std::string host;
     int port = 0;
@@ -275,6 +279,7 @@
         }
     }
 
+    Transport* transport = nullptr;
     while (true) {
         if (!host.empty()) {
             std::string error;
@@ -640,8 +645,7 @@
     // "require partition-exists=x" is a special case, added because of the trouble we had when
     // Pixel 2 shipped with new partitions and users used old versions of fastboot to flash them,
     // missing out new partitions. A device with new partitions can use "partition-exists" to
-    // override the fields `optional_if_no_image` and 'optional_if_no_partition' in the `images`
-    // array.
+    // override the fields `optional_if_no_image` in the `images` array.
     if (!strcmp(name, "partition-exists")) {
         const char* partition_name = val[0];
         std::string has_slot;
@@ -653,7 +657,6 @@
         for (size_t i = 0; i < arraysize(images); ++i) {
             if (images[i].nickname && !strcmp(images[i].nickname, partition_name)) {
                 images[i].optional_if_no_image = false;
-                images[i].optional_if_no_partition = false;
                 known_partition = true;
             }
         }
@@ -1128,11 +1131,6 @@
             die("non-optional file %s missing", images[i].img_name);
         }
 
-        if (images[i].optional_if_no_partition &&
-            !if_partition_exists(images[i].part_name, slot)) {
-            continue;
-        }
-
         fastboot_buffer buf;
         if (!load_buf_fd(fd, &buf)) {
             die("cannot load %s from flash: %s", images[i].img_name, strerror(errno));
@@ -1177,6 +1175,17 @@
     return fb_getvar("is-logical:" + partition, &value) && value == "yes";
 }
 
+static void reboot_to_userspace_fastboot() {
+    if (!fb_reboot_to_userspace()) {
+        die("Must reboot to userspace fastboot to flash logical partitions");
+    }
+
+    // Give the current connection time to close.
+    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+
+    fb_reinit(open_device());
+}
+
 static void update_super_partition(bool force_wipe) {
     if (!if_partition_exists("super", "")) {
         return;
@@ -1187,7 +1196,7 @@
     }
 
     if (!is_userspace_fastboot()) {
-        die("Must have userspace fastboot to flash logical partitions");
+        reboot_to_userspace_fastboot();
     }
 
     int fd = open(image.c_str(), O_RDONLY);
@@ -1207,6 +1216,26 @@
     fb_execute_queue();
 }
 
+static void flash_images(const std::vector<std::pair<const Image*, std::string>>& images) {
+    // Flash each partition in the list if it has a corresponding image.
+    for (const auto& [image, slot] : images) {
+        auto fname = find_item_given_name(image->img_name);
+        fastboot_buffer buf;
+        if (!load_buf(fname.c_str(), &buf)) {
+            if (image->optional_if_no_image) continue;
+            die("could not load '%s': %s", image->img_name, strerror(errno));
+        }
+        auto flashall = [&](const std::string &partition) {
+            do_send_signature(fname.c_str());
+            if (is_logical(partition)) {
+                fb_queue_resize_partition(partition, std::to_string(buf.image_size));
+            }
+            flash_buf(partition.c_str(), &buf);
+        };
+        do_for_partitions(image->part_name, slot, flashall, false);
+    }
+}
+
 static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) {
     std::string fname;
     queue_info_dump();
@@ -1237,10 +1266,9 @@
         }
     }
 
-    update_super_partition(wipe);
-
     // List of partitions to flash and their slots.
-    std::vector<std::pair<const Image*, std::string>> entries;
+    std::vector<std::pair<const Image*, std::string>> boot_images;
+    std::vector<std::pair<const Image*, std::string>> os_images;
     for (size_t i = 0; i < arraysize(images); i++) {
         const char* slot = NULL;
         if (images[i].IsSecondary()) {
@@ -1249,39 +1277,33 @@
             slot = slot_override.c_str();
         }
         if (!slot) continue;
-        entries.emplace_back(&images[i], slot);
+        if (images[i].type == ImageType::BootCritical) {
+            boot_images.emplace_back(&images[i], slot);
+        } else if (images[i].type == ImageType::Normal) {
+            os_images.emplace_back(&images[i], slot);
+        }
+    }
 
-        // Resize any logical partition to 0, so each partition is reset to 0
-        // extents, and will achieve more optimal allocation.
+    // First flash boot partitions. We allow this to happen either in userspace
+    // or in bootloader fastboot.
+    flash_images(boot_images);
+
+    // Sync the super partition. This will reboot to userspace fastboot if needed.
+    update_super_partition(wipe);
+
+    // Resize any logical partition to 0, so each partition is reset to 0
+    // extents, and will achieve more optimal allocation.
+    for (const auto& [image, slot] : os_images) {
         auto resize_partition = [](const std::string& partition) -> void {
             if (is_logical(partition)) {
                 fb_queue_resize_partition(partition, "0");
             }
         };
-        do_for_partitions(images[i].part_name, slot, resize_partition, false);
+        do_for_partitions(image->part_name, slot, resize_partition, false);
     }
 
-    // Flash each partition in the list if it has a corresponding image.
-    for (const auto& [image, slot] : entries) {
-        fname = find_item_given_name(image->img_name);
-        fastboot_buffer buf;
-        if (!load_buf(fname.c_str(), &buf)) {
-            if (image->optional_if_no_image) continue;
-            die("could not load '%s': %s", image->img_name, strerror(errno));
-        }
-        if (image->optional_if_no_partition &&
-            !if_partition_exists(image->part_name, slot)) {
-            continue;
-        }
-        auto flashall = [&](const std::string &partition) {
-            do_send_signature(fname.c_str());
-            if (is_logical(partition)) {
-                fb_queue_resize_partition(partition, std::to_string(buf.image_size));
-            }
-            flash_buf(partition.c_str(), &buf);
-        };
-        do_for_partitions(image->part_name, slot, flashall, false);
-    }
+    // Flash OS images, resizing logical partitions as needed.
+    flash_images(os_images);
 
     if (slot_override == "all") {
         set_active("a");
diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp
index c508abe..ceee066 100644
--- a/fastboot/fastboot_driver.cpp
+++ b/fastboot/fastboot_driver.cpp
@@ -52,11 +52,15 @@
 /*************************** PUBLIC *******************************/
 FastBootDriver::FastBootDriver(Transport* transport, std::function<void(std::string&)> info,
                                bool no_checks)
-    : transport(transport) {
+    : transport_(transport) {
     info_cb_ = info;
     disable_checks_ = no_checks;
 }
 
+FastBootDriver::~FastBootDriver() {
+    set_transport(nullptr);
+}
+
 RetCode FastBootDriver::Boot(std::string* response, std::vector<std::string>* info) {
     return RawCommand(Commands::BOOT, response, info);
 }
@@ -85,24 +89,20 @@
     return GetVar("all", &tmp, response);
 }
 
-RetCode FastBootDriver::Powerdown(std::string* response, std::vector<std::string>* info) {
-    return RawCommand(Commands::POWERDOWN, response, info);
-}
-
 RetCode FastBootDriver::Reboot(std::string* response, std::vector<std::string>* info) {
     return RawCommand(Commands::REBOOT, response, info);
 }
 
+RetCode FastBootDriver::RebootTo(std::string target, std::string* response,
+                                 std::vector<std::string>* info) {
+    return RawCommand("reboot-" + target, response, info);
+}
+
 RetCode FastBootDriver::SetActive(const std::string& part, std::string* response,
                                   std::vector<std::string>* info) {
     return RawCommand(Commands::SET_ACTIVE + part, response, info);
 }
 
-RetCode FastBootDriver::Verify(uint32_t num, std::string* response, std::vector<std::string>* info) {
-    std::string cmd = android::base::StringPrintf("%s%08" PRIx32, Commands::VERIFY.c_str(), num);
-    return RawCommand(cmd, response, info);
-}
-
 RetCode FastBootDriver::FlashPartition(const std::string& part, const std::vector<char>& data) {
     RetCode ret;
     if ((ret = Download(data))) {
@@ -332,7 +332,7 @@
 }
 
 RetCode FastBootDriver::WaitForDisconnect() {
-    return transport->WaitForDisconnect() ? IO_ERROR : SUCCESS;
+    return transport_->WaitForDisconnect() ? IO_ERROR : SUCCESS;
 }
 
 /****************************** PROTECTED *************************************/
@@ -344,7 +344,7 @@
         return BAD_ARG;
     }
 
-    if (transport->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
+    if (transport_->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
         error_ = ErrnoStr("Write to device failed");
         return IO_ERROR;
     }
@@ -378,7 +378,7 @@
     // erase response
     set_response("");
     while ((std::chrono::system_clock::now() - start) < std::chrono::seconds(RESP_TIMEOUT)) {
-        int r = transport->Read(status, FB_RESPONSE_SZ);
+        int r = transport_->Read(status, FB_RESPONSE_SZ);
         if (r < 0) {
             error_ = ErrnoStr("Status read failed");
             return IO_ERROR;
@@ -427,11 +427,9 @@
 const std::string FastBootDriver::Commands::ERASE = "erase:";
 const std::string FastBootDriver::Commands::FLASH = "flash:";
 const std::string FastBootDriver::Commands::GET_VAR = "getvar:";
-const std::string FastBootDriver::Commands::POWERDOWN = "powerdown";
 const std::string FastBootDriver::Commands::REBOOT = "reboot";
 const std::string FastBootDriver::Commands::SET_ACTIVE = "set_active:";
 const std::string FastBootDriver::Commands::UPLOAD = "upload";
-const std::string FastBootDriver::Commands::VERIFY = "verify:";
 
 /******************************* PRIVATE **************************************/
 RetCode FastBootDriver::SendBuffer(int fd, size_t size) {
@@ -472,7 +470,7 @@
         return BAD_ARG;
     }
     // Write the buffer
-    ssize_t tmp = transport->Write(buf, size);
+    ssize_t tmp = transport_->Write(buf, size);
 
     if (tmp < 0) {
         error_ = ErrnoStr("Write to device failed in SendBuffer()");
@@ -493,7 +491,7 @@
 
 RetCode FastBootDriver::ReadBuffer(void* buf, size_t size) {
     // Read the buffer
-    ssize_t tmp = transport->Read(buf, size);
+    ssize_t tmp = transport_->Read(buf, size);
 
     if (tmp < 0) {
         error_ = ErrnoStr("Read from device failed in ReadBuffer()");
@@ -539,4 +537,12 @@
     return 0;
 }
 
+void FastBootDriver::set_transport(Transport* transport) {
+    if (transport_) {
+        transport_->Close();
+        delete transport_;
+    }
+    transport_ = transport;
+}
+
 }  // End namespace fastboot
diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h
index 51be3db..4647945 100644
--- a/fastboot/fastboot_driver.h
+++ b/fastboot/fastboot_driver.h
@@ -66,6 +66,7 @@
     FastBootDriver(Transport* transport,
                    std::function<void(std::string&)> info = [](std::string&) {},
                    bool no_checks = false);
+    ~FastBootDriver();
 
     RetCode Boot(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
     RetCode Continue(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
@@ -85,14 +86,13 @@
     RetCode GetVar(const std::string& key, std::string* val,
                    std::vector<std::string>* info = nullptr);
     RetCode GetVarAll(std::vector<std::string>* response);
-    RetCode Powerdown(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
     RetCode Reboot(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
+    RetCode RebootTo(std::string target, std::string* response = nullptr,
+                     std::vector<std::string>* info = nullptr);
     RetCode SetActive(const std::string& part, std::string* response = nullptr,
                       std::vector<std::string>* info = nullptr);
     RetCode Upload(const std::string& outfile, std::string* response = nullptr,
                    std::vector<std::string>* info = nullptr);
-    RetCode Verify(uint32_t num, std::string* response = nullptr,
-                   std::vector<std::string>* info = nullptr);
 
     /* HIGHER LEVEL COMMANDS -- Composed of the commands above */
     RetCode FlashPartition(const std::string& part, const std::vector<char>& data);
@@ -109,6 +109,10 @@
     std::string Error();
     RetCode WaitForDisconnect();
 
+    // Note: changing the transport will close and delete the existing one.
+    void set_transport(Transport* transport);
+    Transport* transport() const { return transport_; }
+
     // This is temporarily public for engine.cpp
     RetCode RawCommand(const std::string& cmd, std::string* response = nullptr,
                        std::vector<std::string>* info = nullptr, int* dsize = nullptr);
@@ -129,14 +133,12 @@
         static const std::string ERASE;
         static const std::string FLASH;
         static const std::string GET_VAR;
-        static const std::string POWERDOWN;
         static const std::string REBOOT;
         static const std::string SET_ACTIVE;
         static const std::string UPLOAD;
-        static const std::string VERIFY;
     };
 
-    Transport* const transport;
+    Transport* transport_;
 
   private:
     RetCode SendBuffer(int fd, size_t size);
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index 14bf5bf..1d30f8b 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -86,9 +86,8 @@
 
 const std::string DEFAULT_OUPUT_NAME = "out.img";
 // const char scratch_partition[] = "userdata";
-const std::vector<std::string> CMDS{"boot",        "continue", "download:", "erase:",
-                                    "flash:",      "getvar:",  "powerdown", "reboot",
-                                    "set_active:", "upload",   "verify"};
+const std::vector<std::string> CMDS{"boot",    "continue", "download:",   "erase:", "flash:",
+                                    "getvar:", "reboot",   "set_active:", "upload"};
 
 // For pretty printing we need all these overloads
 ::std::ostream& operator<<(::std::ostream& os, const RetCode& ret) {
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 99f2df8..e3c2c2b 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -79,7 +79,8 @@
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
-using DeviceMapper = android::dm::DeviceMapper;
+using android::dm::DeviceMapper;
+using android::dm::DmDeviceState;
 
 // record fs stat
 enum FsStatFlags {
@@ -790,7 +791,8 @@
         argv.emplace_back(arg.c_str());
     }
     LOG(INFO) << "Calling: " << android::base::Join(argv, ' ');
-    int ret = android_fork_execvp(4, const_cast<char**>(argv.data()), nullptr, false, true);
+    int ret =
+            android_fork_execvp(argv.size(), const_cast<char**>(argv.data()), nullptr, false, true);
     if (ret != 0) {
         LOG(ERROR) << "vdc returned error code: " << ret;
         return false;
@@ -852,7 +854,8 @@
         }
 
         /* Skip mounting the root partition, as it will already have been mounted */
-        if (!strcmp(fstab->recs[i].mount_point, "/")) {
+        if (!strcmp(fstab->recs[i].mount_point, "/") ||
+            !strcmp(fstab->recs[i].mount_point, "/system")) {
             if ((fstab->recs[i].fs_mgr_flags & MS_RDONLY) != 0) {
                 fs_mgr_set_blk_ro(fstab->recs[i].blk_device);
             }
@@ -1400,8 +1403,12 @@
             mount_point = basename(fstab->recs[i].mount_point);
         }
 
-        const char* status = nullptr;
+        if (dm.GetState(mount_point) == DmDeviceState::INVALID) {
+            PERROR << "Could not find verity device for mount point: " << mount_point;
+            continue;
+        }
 
+        const char* status = nullptr;
         std::vector<DeviceMapper::TargetInfo> table;
         if (!dm.GetTableStatus(mount_point, &table) || table.empty() || table[0].data.empty()) {
             if (fstab->recs[i].fs_mgr_flags & MF_VERIFYATBOOT) {
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 78151d5..720dcfd 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -16,6 +16,7 @@
 
 #include <dirent.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <linux/fs.h>
 #include <selinux/selinux.h>
 #include <stdio.h>
@@ -23,7 +24,9 @@
 #include <sys/mount.h>
 #include <sys/param.h>
 #include <sys/stat.h>
+#include <sys/statvfs.h>
 #include <sys/types.h>
+#include <sys/vfs.h>
 #include <unistd.h>
 
 #include <map>
@@ -35,6 +38,8 @@
 #include <android-base/macros.h>
 #include <android-base/properties.h>
 #include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <ext4_utils/ext4_utils.h>
 #include <fs_mgr_overlayfs.h>
 #include <fstab/fstab.h>
 
@@ -96,9 +101,26 @@
     return "";
 }
 
+// At less than 1% free space return value of false,
+// means we will try to wrap with overlayfs.
+bool fs_mgr_filesystem_has_space(const char* mount_point) {
+    // If we have access issues to find out space remaining, return true
+    // to prevent us trying to override with overlayfs.
+    struct statvfs vst;
+    if (statvfs(mount_point, &vst)) return true;
+
+    static constexpr int percent = 1;  // 1%
+
+    return (vst.f_bfree >= (vst.f_blocks * percent / 100));
+}
+
 bool fs_mgr_overlayfs_enabled(const struct fstab_rec* fsrec) {
     // readonly filesystem, can not be mount -o remount,rw
-    return "squashfs"s == fsrec->fs_type;
+    // if squashfs or if free space is (near) zero making such a remount
+    // virtually useless, or if there are shared blocks that prevent remount,rw
+    return ("squashfs"s == fsrec->fs_type) ||
+           fs_mgr_has_shared_blocks(fsrec->mount_point, fsrec->blk_device) ||
+           !fs_mgr_filesystem_has_space(fsrec->mount_point);
 }
 
 constexpr char upper_name[] = "upper";
@@ -119,14 +141,13 @@
 constexpr char upperdir_option[] = "upperdir=";
 
 // default options for mount_point, returns empty string for none available.
-std::string fs_mgr_get_overlayfs_options(const char* mount_point) {
-    auto fsrec_mount_point = std::string(mount_point);
-    auto candidate = fs_mgr_get_overlayfs_candidate(fsrec_mount_point);
+std::string fs_mgr_get_overlayfs_options(const std::string& mount_point) {
+    auto candidate = fs_mgr_get_overlayfs_candidate(mount_point);
     if (candidate.empty()) return "";
 
-    auto context = fs_mgr_get_context(fsrec_mount_point);
+    auto context = fs_mgr_get_context(mount_point);
     if (!context.empty()) context = ",rootcontext="s + context;
-    return "override_creds=off,"s + lowerdir_option + fsrec_mount_point + "," + upperdir_option +
+    return "override_creds=off,"s + lowerdir_option + mount_point + "," + upperdir_option +
            candidate + upper_name + ",workdir=" + candidate + work_name + context;
 }
 
@@ -145,10 +166,11 @@
     return true;
 }
 
-std::string fs_mgr_get_overlayfs_options(const fstab* fstab, const char* mount_point) {
-    if (fs_mgr_system_root_image(fstab) && ("/"s == mount_point)) mount_point = "/system";
-
-    return fs_mgr_get_overlayfs_options(mount_point);
+const char* fs_mgr_mount_point(const fstab* fstab, const char* mount_point) {
+    if (!mount_point) return mount_point;
+    if ("/"s != mount_point) return mount_point;
+    if (!fs_mgr_system_root_image(fstab)) return mount_point;
+    return "/system";
 }
 
 // return true if system supports overlayfs
@@ -174,7 +196,8 @@
     if (!fsrec) return false;
 
     auto fsrec_mount_point = fsrec->mount_point;
-    if (!fsrec_mount_point) return false;
+    if (!fsrec_mount_point || !fsrec_mount_point[0]) return false;
+    if (!fsrec->blk_device) return false;
 
     if (!fsrec->fs_type) return false;
 
@@ -242,10 +265,17 @@
     return ret;
 }
 
+constexpr char overlayfs_file_context[] = "u:object_r:overlayfs_file:s0";
+
 bool fs_mgr_overlayfs_setup_one(const std::string& overlay, const std::string& mount_point,
                                 bool* change) {
     auto ret = true;
     auto fsrec_mount_point = overlay + android::base::Basename(mount_point) + "/";
+
+    if (setfscreatecon(overlayfs_file_context)) {
+        ret = false;
+        PERROR << "overlayfs setfscreatecon " << overlayfs_file_context;
+    }
     auto save_errno = errno;
     if (!mkdir(fsrec_mount_point.c_str(), 0755)) {
         if (change) *change = true;
@@ -265,6 +295,7 @@
     } else {
         errno = save_errno;
     }
+    setfscreatecon(nullptr);
 
     auto new_context = fs_mgr_get_context(mount_point);
     if (!new_context.empty() && setfscreatecon(new_context.c_str())) {
@@ -286,15 +317,12 @@
     return ret;
 }
 
-bool fs_mgr_overlayfs_mount(const fstab* fstab, const fstab_rec* fsrec) {
-    if (!fs_mgr_wants_overlayfs(fsrec)) return false;
-    auto fsrec_mount_point = fsrec->mount_point;
-    if (!fsrec_mount_point || !fsrec_mount_point[0]) return false;
-    auto options = fs_mgr_get_overlayfs_options(fstab, fsrec_mount_point);
+bool fs_mgr_overlayfs_mount(const std::string& mount_point) {
+    auto options = fs_mgr_get_overlayfs_options(mount_point);
     if (options.empty()) return false;
 
     // hijack __mount() report format to help triage
-    auto report = "__mount(source=overlay,target="s + fsrec_mount_point + ",type=overlay";
+    auto report = "__mount(source=overlay,target="s + mount_point + ",type=overlay";
     const auto opt_list = android::base::Split(options, ",");
     for (const auto opt : opt_list) {
         if (android::base::StartsWith(opt, upperdir_option)) {
@@ -304,7 +332,7 @@
     }
     report = report + ")=";
 
-    auto ret = mount("overlay", fsrec_mount_point, "overlay", MS_RDONLY | MS_RELATIME,
+    auto ret = mount("overlay", mount_point.c_str(), "overlay", MS_RDONLY | MS_RELATIME,
                      options.c_str());
     if (ret) {
         PERROR << report << ret;
@@ -315,8 +343,7 @@
     }
 }
 
-bool fs_mgr_overlayfs_already_mounted(const char* mount_point) {
-    if (!mount_point) return false;
+bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point) {
     std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(
             fs_mgr_read_fstab("/proc/mounts"), fs_mgr_free_fstab);
     if (!fstab) return false;
@@ -328,7 +355,7 @@
         if (("overlay"s != fs_type) && ("overlayfs"s != fs_type)) continue;
         auto fsrec_mount_point = fsrec->mount_point;
         if (!fsrec_mount_point) continue;
-        if (strcmp(fsrec_mount_point, mount_point)) continue;
+        if (mount_point != fsrec_mount_point) continue;
         const auto fs_options = fsrec->fs_options;
         if (!fs_options) continue;
         const auto options = android::base::Split(fs_options, ",");
@@ -341,6 +368,34 @@
     return false;
 }
 
+std::vector<std::string> fs_mgr_candidate_list(const fstab* fstab,
+                                               const char* mount_point = nullptr) {
+    std::vector<std::string> mounts;
+    if (!fstab) return mounts;
+
+    for (auto i = 0; i < fstab->num_entries; i++) {
+        const auto fsrec = &fstab->recs[i];
+        if (!fs_mgr_wants_overlayfs(fsrec)) continue;
+        std::string new_mount_point(fs_mgr_mount_point(fstab, fsrec->mount_point));
+        if (mount_point && (new_mount_point != mount_point)) continue;
+        auto duplicate_or_more_specific = false;
+        for (auto it = mounts.begin(); it != mounts.end();) {
+            if ((*it == new_mount_point) ||
+                (android::base::StartsWith(new_mount_point, *it + "/"))) {
+                duplicate_or_more_specific = true;
+                break;
+            }
+            if (android::base::StartsWith(*it, new_mount_point + "/")) {
+                it = mounts.erase(it);
+            } else {
+                ++it;
+            }
+        }
+        if (!duplicate_or_more_specific) mounts.emplace_back(new_mount_point);
+    }
+    return mounts;
+}
+
 }  // namespace
 
 bool fs_mgr_overlayfs_mount_all() {
@@ -352,13 +407,9 @@
                                                                       fs_mgr_free_fstab);
     if (!fstab) return ret;
 
-    for (auto i = 0; i < fstab->num_entries; i++) {
-        const auto fsrec = &fstab->recs[i];
-        auto fsrec_mount_point = fsrec->mount_point;
-        if (!fsrec_mount_point) continue;
-        if (fs_mgr_overlayfs_already_mounted(fsrec_mount_point)) continue;
-
-        if (fs_mgr_overlayfs_mount(fstab.get(), fsrec)) ret = true;
+    for (const auto& mount_point : fs_mgr_candidate_list(fstab.get())) {
+        if (fs_mgr_overlayfs_already_mounted(mount_point)) continue;
+        if (fs_mgr_overlayfs_mount(mount_point)) ret = true;
     }
     return ret;
 }
@@ -381,22 +432,12 @@
 
     std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
                                                                       fs_mgr_free_fstab);
-    std::vector<std::string> mounts;
-    if (fstab) {
-        if (!fs_mgr_get_entry_for_mount_point(fstab.get(), kOverlayMountPoint)) return ret;
-        for (auto i = 0; i < fstab->num_entries; i++) {
-            const auto fsrec = &fstab->recs[i];
-            auto fsrec_mount_point = fsrec->mount_point;
-            if (!fsrec_mount_point) continue;
-            if (mount_point && strcmp(fsrec_mount_point, mount_point)) continue;
-            if (!fs_mgr_wants_overlayfs(fsrec)) continue;
-            mounts.emplace_back(fsrec_mount_point);
-        }
-        if (mounts.empty()) return ret;
-    }
+    if (fstab && !fs_mgr_get_entry_for_mount_point(fstab.get(), kOverlayMountPoint)) return ret;
+    auto mounts = fs_mgr_candidate_list(fstab.get(), fs_mgr_mount_point(fstab.get(), mount_point));
+    if (fstab && mounts.empty()) return ret;
 
-    if (mount_point && ("/"s == mount_point) && fs_mgr_system_root_image(fstab.get())) {
-        mount_point = "/system";
+    if (setfscreatecon(overlayfs_file_context)) {
+        PERROR << "overlayfs setfscreatecon " << overlayfs_file_context;
     }
     auto overlay = kOverlayMountPoint + "/overlay/";
     auto save_errno = errno;
@@ -407,6 +448,7 @@
     } else {
         errno = save_errno;
     }
+    setfscreatecon(nullptr);
     if (!fstab && mount_point && fs_mgr_overlayfs_setup_one(overlay, mount_point, change)) {
         ret = true;
     }
@@ -420,11 +462,10 @@
 // If something is altered, set *change.
 bool fs_mgr_overlayfs_teardown(const char* mount_point, bool* change) {
     if (change) *change = false;
-    if (mount_point && ("/"s == mount_point)) {
-        std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(
-                fs_mgr_read_fstab_default(), fs_mgr_free_fstab);
-        if (fs_mgr_system_root_image(fstab.get())) mount_point = "/system";
-    }
+    mount_point = fs_mgr_mount_point(std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)>(
+                                             fs_mgr_read_fstab_default(), fs_mgr_free_fstab)
+                                             .get(),
+                                     mount_point);
     auto ret = true;
     const auto overlay = kOverlayMountPoint + "/overlay";
     const auto oldpath = overlay + (mount_point ?: "");
@@ -477,3 +518,25 @@
 }
 
 #endif  // ALLOW_ADBD_DISABLE_VERITY != 0
+
+bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev) {
+    struct statfs fs;
+    if ((statfs((mount_point + "/lost+found").c_str(), &fs) == -1) ||
+        (fs.f_type != EXT4_SUPER_MAGIC)) {
+        return false;
+    }
+
+    android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC));
+    if (fd < 0) return false;
+
+    struct ext4_super_block sb;
+    if ((TEMP_FAILURE_RETRY(lseek64(fd, 1024, SEEK_SET)) < 0) ||
+        (TEMP_FAILURE_RETRY(read(fd, &sb, sizeof(sb))) < 0)) {
+        return false;
+    }
+
+    struct fs_info info;
+    if (ext4_parse_sb(&sb, &info) < 0) return false;
+
+    return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0;
+}
diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h
index 1d2ff03..ceb45de 100644
--- a/fs_mgr/include/fs_mgr_overlayfs.h
+++ b/fs_mgr/include/fs_mgr_overlayfs.h
@@ -18,7 +18,10 @@
 
 #include <fstab/fstab.h>
 
+#include <string>
+
 bool fs_mgr_overlayfs_mount_all();
 bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_point = nullptr,
                             bool* change = nullptr);
 bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr);
+bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev);
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index 8bcbec2..2b526f6 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -98,9 +98,16 @@
     return nullptr;
 }
 
-DmDeviceState DeviceMapper::state(const std::string& /* name */) const {
-    // TODO(b/110035986): Return the state, as read from the kernel instead
-    return DmDeviceState::INVALID;
+DmDeviceState DeviceMapper::GetState(const std::string& name) const {
+    struct dm_ioctl io;
+    InitIo(&io, name);
+    if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
+        return DmDeviceState::INVALID;
+    }
+    if ((io.flags & DM_ACTIVE_PRESENT_FLAG) && !(io.flags & DM_SUSPEND_FLAG)) {
+        return DmDeviceState::ACTIVE;
+    }
+    return DmDeviceState::SUSPENDED;
 }
 
 bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table) {
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index 9b61ddc..91f8bb4 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -79,7 +79,7 @@
     // Returns the current state of the underlying device mapper device
     // with given name.
     // One of INVALID, SUSPENDED or ACTIVE.
-    DmDeviceState state(const std::string& name) const;
+    DmDeviceState GetState(const std::string& name) const;
 
     // Creates a device, loads the given table, and activates it. If the device
     // is not able to be activated, it is destroyed, and false is returned.
diff --git a/init/Android.bp b/init/Android.bp
index 84a78e2..a2c49d0 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -59,33 +59,24 @@
         },
     },
     static_libs: [
-        "libbootloader_message",
-        "libfs_mgr",
-        "libfec",
-        "libfec_rs",
-        "libhidl-gen-utils",
-        "libsquashfs_utils",
-        "liblogwrap",
-        "libext4_utils",
         "libseccomp_policy",
-        "libcrypto_utils",
-        "libsparse",
         "libprocessgroup",
         "libavb",
-        "libkeyutils",
         "libprotobuf-cpp-lite",
         "libpropertyinfoserializer",
         "libpropertyinfoparser",
     ],
     shared_libs: [
-        "libcutils",
         "libbase",
-        "libc",
-        "liblog",
-        "libcrypto",
-        "libc++",
+        "libbootloader_message",
+        "libcutils",
         "libdl",
-        "libz",
+        "libext4_utils",
+        "libfs_mgr",
+        "libhidl-gen-utils",
+        "libkeyutils",
+        "liblog",
+        "liblogwrap",
         "libselinux",
     ],
 }
@@ -160,6 +151,7 @@
 cc_test {
     name: "init_tests",
     defaults: ["init_defaults"],
+    compile_multilib: "first",
     srcs: [
         "devices_test.cpp",
         "init_test.cpp",
diff --git a/init/Android.mk b/init/Android.mk
index ada87b8..dc400ad 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -47,6 +47,7 @@
     init_first_stage.cpp \
     reboot_utils.cpp \
     selinux.cpp \
+    switch_root.cpp \
     uevent_listener.cpp \
     util.cpp \
 
@@ -54,8 +55,15 @@
 
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 
-LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
-LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
+LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)
+LOCAL_UNSTRIPPED_PATH := $(TARGET_RAMDISK_OUT_UNSTRIPPED)
+
+# Set up the same mount points on the ramdisk that system-as-root contains.
+LOCAL_POST_INSTALL_CMD := \
+    mkdir -p $(TARGET_RAMDISK_OUT)/dev \
+    mkdir -p $(TARGET_RAMDISK_OUT)/mnt \
+    mkdir -p $(TARGET_RAMDISK_OUT)/proc \
+    mkdir -p $(TARGET_RAMDISK_OUT)/sys \
 
 LOCAL_STATIC_LIBRARIES := \
     libfs_mgr \
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 0c5cf76..1496935 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -29,19 +29,22 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/strings.h>
+#include <fs_mgr.h>
+#include <fs_mgr_avb.h>
+#include <fs_mgr_dm_linear.h>
+#include <fs_mgr_overlayfs.h>
 #include <liblp/metadata_format.h>
 
 #include "devices.h"
-#include "fs_mgr.h"
-#include "fs_mgr_avb.h"
-#include "fs_mgr_dm_linear.h"
-#include "fs_mgr_overlayfs.h"
+#include "switch_root.h"
 #include "uevent.h"
 #include "uevent_listener.h"
 #include "util.h"
 
 using android::base::Timer;
 
+using namespace std::literals;
+
 namespace android {
 namespace init {
 
@@ -63,6 +66,7 @@
     bool InitRequiredDevices();
     bool InitMappedDevice(const std::string& verity_device);
     bool CreateLogicalPartitions();
+    bool MountPartition(fstab_rec* fstab_rec);
     bool MountPartitions();
     bool GetBackingDmLinearDevices();
 
@@ -333,26 +337,51 @@
     return true;
 }
 
-bool FirstStageMount::MountPartitions() {
-    for (auto fstab_rec : mount_fstab_recs_) {
-        if (fs_mgr_is_logical(fstab_rec)) {
-            if (!fs_mgr_update_logical_partition(fstab_rec)) {
-                return false;
-            }
-            if (!InitMappedDevice(fstab_rec->blk_device)) {
-                return false;
-            }
-        }
-        if (!SetUpDmVerity(fstab_rec)) {
-            PLOG(ERROR) << "Failed to setup verity for '" << fstab_rec->mount_point << "'";
+bool FirstStageMount::MountPartition(fstab_rec* fstab_rec) {
+    if (fs_mgr_is_logical(fstab_rec)) {
+        if (!fs_mgr_update_logical_partition(fstab_rec)) {
             return false;
         }
-        if (fs_mgr_do_mount_one(fstab_rec)) {
-            PLOG(ERROR) << "Failed to mount '" << fstab_rec->mount_point << "'";
+        if (!InitMappedDevice(fstab_rec->blk_device)) {
             return false;
         }
     }
+    if (!SetUpDmVerity(fstab_rec)) {
+        PLOG(ERROR) << "Failed to setup verity for '" << fstab_rec->mount_point << "'";
+        return false;
+    }
+    if (fs_mgr_do_mount_one(fstab_rec)) {
+        PLOG(ERROR) << "Failed to mount '" << fstab_rec->mount_point << "'";
+        return false;
+    }
+    return true;
+}
+
+bool FirstStageMount::MountPartitions() {
+    // If system is in the fstab then we're not a system-as-root device, and in
+    // this case, we mount system first then pivot to it.  From that point on,
+    // we are effectively identical to a system-as-root device.
+    auto system_partition =
+            std::find_if(mount_fstab_recs_.begin(), mount_fstab_recs_.end(),
+                         [](const auto& rec) { return rec->mount_point == "/system"s; });
+    if (system_partition != mount_fstab_recs_.end()) {
+        if (!MountPartition(*system_partition)) {
+            return false;
+        }
+
+        SwitchRoot("/system");
+
+        mount_fstab_recs_.erase(system_partition);
+    }
+
+    for (auto fstab_rec : mount_fstab_recs_) {
+        if (!MountPartition(fstab_rec)) {
+            return false;
+        }
+    }
+
     fs_mgr_overlayfs_mount_all();
+
     return true;
 }
 
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 1af06dd..b8c1cfd 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -192,7 +192,7 @@
 
 void Keychords::GeteventOpenDevice(const std::string& device) {
     if (registration_.count(device)) return;
-    auto fd = TEMP_FAILURE_RETRY(::open(device.c_str(), O_RDWR | O_CLOEXEC));
+    auto fd = TEMP_FAILURE_RETRY(::open(device.c_str(), O_RDONLY | O_CLOEXEC));
     if (fd == -1) {
         PLOG(ERROR) << "Can not open " << device;
         return;
diff --git a/init/switch_root.cpp b/init/switch_root.cpp
new file mode 100644
index 0000000..0e59b57
--- /dev/null
+++ b/init/switch_root.cpp
@@ -0,0 +1,151 @@
+/*
+ * 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 "switch_root.h"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+using android::base::StartsWith;
+
+using namespace std::literals;
+
+namespace android {
+namespace init {
+
+namespace {
+
+void FreeRamdisk(DIR* dir, dev_t dev) {
+    int dfd = dirfd(dir);
+
+    dirent* de;
+    while ((de = readdir(dir)) != nullptr) {
+        if (de->d_name == "."s || de->d_name == ".."s) {
+            continue;
+        }
+
+        bool is_dir = false;
+
+        if (de->d_type == DT_DIR || de->d_type == DT_UNKNOWN) {
+            struct stat info;
+            if (fstatat(dfd, de->d_name, &info, AT_SYMLINK_NOFOLLOW) != 0) {
+                continue;
+            }
+
+            if (info.st_dev != dev) {
+                continue;
+            }
+
+            if (S_ISDIR(info.st_mode)) {
+                is_dir = true;
+                auto fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
+                if (fd >= 0) {
+                    auto subdir =
+                            std::unique_ptr<DIR, decltype(&closedir)>{fdopendir(fd), closedir};
+                    if (subdir) {
+                        FreeRamdisk(subdir.get(), dev);
+                    } else {
+                        close(fd);
+                    }
+                }
+            }
+        }
+        unlinkat(dfd, de->d_name, is_dir ? AT_REMOVEDIR : 0);
+    }
+}
+
+std::vector<std::string> GetMounts(const std::string& new_root) {
+    auto fp = std::unique_ptr<std::FILE, decltype(&endmntent)>{setmntent("/proc/mounts", "re"),
+                                                               endmntent};
+    if (fp == nullptr) {
+        PLOG(FATAL) << "Failed to open /proc/mounts";
+    }
+
+    std::vector<std::string> result;
+    mntent* mentry;
+    while ((mentry = getmntent(fp.get())) != nullptr) {
+        // We won't try to move rootfs.
+        if (mentry->mnt_dir == "/"s) {
+            continue;
+        }
+
+        // The new root mount is handled separately.
+        if (mentry->mnt_dir == new_root) {
+            continue;
+        }
+
+        // Move operates on subtrees, so do not try to move children of other mounts.
+        if (std::find_if(result.begin(), result.end(), [&mentry](const auto& older_mount) {
+                return StartsWith(mentry->mnt_dir, older_mount);
+            }) != result.end()) {
+            continue;
+        }
+
+        result.emplace_back(mentry->mnt_dir);
+    }
+
+    return result;
+}
+
+}  // namespace
+
+void SwitchRoot(const std::string& new_root) {
+    auto mounts = GetMounts(new_root);
+
+    for (const auto& mount_path : mounts) {
+        auto new_mount_path = new_root + mount_path;
+        if (mount(mount_path.c_str(), new_mount_path.c_str(), nullptr, MS_MOVE, nullptr) != 0) {
+            PLOG(FATAL) << "Unable to move mount at '" << mount_path << "'";
+        }
+    }
+
+    auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir};
+    if (!old_root_dir) {
+        PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk";
+    }
+
+    struct stat old_root_info;
+    if (stat("/", &old_root_info) != 0) {
+        PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
+        old_root_dir.reset();
+    }
+
+    if (chdir(new_root.c_str()) != 0) {
+        PLOG(FATAL) << "Could not chdir to new_root, '" << new_root << "'";
+    }
+
+    if (mount(new_root.c_str(), "/", nullptr, MS_MOVE, nullptr) != 0) {
+        PLOG(FATAL) << "Unable to move root mount to new_root, '" << new_root << "'";
+    }
+
+    if (chroot(".") != 0) {
+        PLOG(FATAL) << "Unable to chroot to new root";
+    }
+
+    if (old_root_dir) {
+        FreeRamdisk(old_root_dir.get(), old_root_info.st_dev);
+    }
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/switch_root.h b/init/switch_root.h
new file mode 100644
index 0000000..d515e5d
--- /dev/null
+++ b/init/switch_root.h
@@ -0,0 +1,27 @@
+/*
+ * 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 <string>
+
+namespace android {
+namespace init {
+
+void SwitchRoot(const std::string& new_root);
+
+}  // namespace init
+}  // namespace android
diff --git a/libcutils/tests/sched_policy_test.cpp b/libcutils/tests/sched_policy_test.cpp
index 5942ee5..1f657e2 100644
--- a/libcutils/tests/sched_policy_test.cpp
+++ b/libcutils/tests/sched_policy_test.cpp
@@ -67,6 +67,21 @@
 }
 
 TEST(SchedPolicy, set_sched_policy) {
+    if (!schedboost_enabled()) {
+        // schedboost_enabled() (i.e. CONFIG_CGROUP_SCHEDTUNE) is optional;
+        // it's only needed on devices using energy-aware scheduler.
+        GTEST_LOG_(INFO) << "skipping test that requires CONFIG_CGROUP_SCHEDTUNE";
+        return;
+    }
+
+    ASSERT_EQ(0, set_sched_policy(0, SP_BACKGROUND));
+    AssertPolicy(SP_BACKGROUND);
+
+    ASSERT_EQ(0, set_sched_policy(0, SP_FOREGROUND));
+    AssertPolicy(SP_FOREGROUND);
+}
+
+TEST(SchedPolicy, set_sched_policy_timerslack) {
     if (!hasCapSysNice()) {
         GTEST_LOG_(INFO) << "skipping test that requires CAP_SYS_NICE";
         return;
@@ -82,11 +97,9 @@
     const unsigned int BG_FG_SLACK_FACTOR = 100;
 
     ASSERT_EQ(0, set_sched_policy(0, SP_BACKGROUND));
-    AssertPolicy(SP_BACKGROUND);
     auto bgSleepTime = medianSleepTime();
 
     ASSERT_EQ(0, set_sched_policy(0, SP_FOREGROUND));
-    AssertPolicy(SP_FOREGROUND);
     auto fgSleepTime = medianSleepTime();
     ASSERT_GT(bgSleepTime, fgSleepTime * BG_FG_SLACK_FACTOR);
 }
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index c7306cd..14883f4 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -72,8 +72,7 @@
 LOCAL_SRC_FILES_mips64 := $(PIXELFLINGER_SRC_FILES_mips64)
 LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS) \
-		    external/safe-iop/include
+LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
 LOCAL_SHARED_LIBRARIES := libcutils liblog libutils
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libpixelflinger/arch-arm64/t32cb16blend.S b/libpixelflinger/arch-arm64/t32cb16blend.S
index b1a950d..a9733c0 100644
--- a/libpixelflinger/arch-arm64/t32cb16blend.S
+++ b/libpixelflinger/arch-arm64/t32cb16blend.S
@@ -49,7 +49,7 @@
  *      upper 16-bit pixels in DREG into FB
  *
  *
- * clobbered: w6, w7, w16, w17, w18
+ * clobbered: w6, w7, w15, w16, w17
  *
  */
 
@@ -73,8 +73,8 @@
     add     w16, w6, w16, lsr #8
     cmp     w16, #0x1F
     orr     w17, \FB, #(0x1F<<(16 + 11))
-    orr     w18, \FB, w16, lsl #(16 + 11)
-    csel    \FB, w17, w18, hi
+    orr     w15, \FB, w16, lsl #(16 + 11)
+    csel    \FB, w17, w15, hi
         // green
         and     w6, \DREG, #(0x3F<<(16 + 5))
         lsr     w17,w6,#(16+5)
@@ -84,8 +84,8 @@
         add     w6, w16, w6, lsr #8
         cmp     w6, #0x3F
         orr     w17, \FB, #(0x3F<<(16 + 5))
-        orr     w18, \FB, w6, lsl #(16 + 5)
-        csel    \FB, w17, w18, hi
+        orr     w15, \FB, w6, lsl #(16 + 5)
+        csel    \FB, w17, w15, hi
             // blue
             and     w16, \DREG, #(0x1F << 16)
             lsr     w17,w16,#16
@@ -95,8 +95,8 @@
             add     w16, w6, w16, lsr #8
             cmp     w16, #0x1F
             orr     w17, \FB, #(0x1F << 16)
-            orr     w18, \FB, w16, lsl #16
-            csel    \FB, w17, w18, hi
+            orr     w15, \FB, w16, lsl #16
+            csel    \FB, w17, w15, hi
 
 .else //Blending even pixel present in bottom 16 bits of DREG register
 
@@ -109,8 +109,8 @@
     add     w16, w6, w16, lsr #8
     cmp     w16, #0x1F
     mov     w17, #(0x1F<<11)
-    lsl     w18, w16, #11
-    csel    \FB, w17, w18, hi
+    lsl     w15, w16, #11
+    csel    \FB, w17, w15, hi
 
 
         // green
@@ -121,8 +121,8 @@
         add     w6, w16, w6, lsr #(5+8)
         cmp     w6, #0x3F
         orr     w17, \FB, #(0x3F<<5)
-        orr     w18, \FB, w6, lsl #5
-        csel    \FB, w17, w18, hi
+        orr     w15, \FB, w6, lsl #5
+        csel    \FB, w17, w15, hi
 
             // blue
             and     w16, \DREG, #0x1F
@@ -132,8 +132,8 @@
             add     w16, w6, w16, lsr #8
             cmp     w16, #0x1F
             orr     w17, \FB, #0x1F
-            orr     w18, \FB, w16
-            csel    \FB, w17, w18, hi
+            orr     w15, \FB, w16
+            csel    \FB, w17, w15, hi
 
 .endif // End of blending even pixel
 
diff --git a/libsysutils/Android.bp b/libsysutils/Android.bp
index 3a12292..29d23c8 100644
--- a/libsysutils/Android.bp
+++ b/libsysutils/Android.bp
@@ -27,3 +27,16 @@
 
     export_include_dirs: ["include"],
 }
+
+cc_test {
+    name: "libsysutils_tests",
+    test_suites: ["device-tests"],
+    srcs: [
+        "src/SocketListener_test.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libsysutils",
+    ],
+}
diff --git a/libsysutils/include/sysutils/FrameworkListener.h b/libsysutils/include/sysutils/FrameworkListener.h
index 2137069..d9a561a 100644
--- a/libsysutils/include/sysutils/FrameworkListener.h
+++ b/libsysutils/include/sysutils/FrameworkListener.h
@@ -38,13 +38,13 @@
     FrameworkListener(const char *socketName);
     FrameworkListener(const char *socketName, bool withSeq);
     FrameworkListener(int sock);
-    virtual ~FrameworkListener() {}
+    ~FrameworkListener() override {}
 
-protected:
+  protected:
     void registerCmd(FrameworkCommand *cmd);
-    virtual bool onDataAvailable(SocketClient *c);
+    bool onDataAvailable(SocketClient* c) override;
 
-private:
+  private:
     void dispatchCommand(SocketClient *c, char *data);
     void init(const char *socketName, bool withSeq);
 };
diff --git a/libsysutils/include/sysutils/OWNERS b/libsysutils/include/sysutils/OWNERS
index b78918e..645baf4 100644
--- a/libsysutils/include/sysutils/OWNERS
+++ b/libsysutils/include/sysutils/OWNERS
@@ -1,2 +1 @@
-per-file Netlink* = ek@google.com
-per-file Netlink* = lorenzo@google.com
+per-file OWNERS,Netlink* = ek@google.com,lorenzo@google.com
diff --git a/libsysutils/include/sysutils/SocketClient.h b/libsysutils/include/sysutils/SocketClient.h
index 1004f06..c657526 100644
--- a/libsysutils/include/sysutils/SocketClient.h
+++ b/libsysutils/include/sysutils/SocketClient.h
@@ -1,8 +1,6 @@
 #ifndef _SOCKET_CLIENT_H
 #define _SOCKET_CLIENT_H
 
-#include "List.h"
-
 #include <pthread.h>
 #include <cutils/atomic.h>
 #include <sys/types.h>
@@ -35,7 +33,7 @@
     SocketClient(int sock, bool owned, bool useCmdNum);
     virtual ~SocketClient();
 
-    int getSocket() { return mSocket; }
+    int getSocket() const { return mSocket; }
     pid_t getPid() const { return mPid; }
     uid_t getUid() const { return mUid; }
     gid_t getGid() const { return mGid; }
@@ -84,5 +82,4 @@
     int sendDataLockedv(struct iovec *iov, int iovcnt);
 };
 
-typedef android::sysutils::List<SocketClient *> SocketClientCollection;
 #endif
diff --git a/libsysutils/include/sysutils/SocketListener.h b/libsysutils/include/sysutils/SocketListener.h
index bc93b86..67a691a 100644
--- a/libsysutils/include/sysutils/SocketListener.h
+++ b/libsysutils/include/sysutils/SocketListener.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2014 The Android Open Source Project
+ * Copyright (C) 2008 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.
@@ -18,6 +18,8 @@
 
 #include <pthread.h>
 
+#include <unordered_map>
+
 #include <sysutils/SocketClient.h>
 #include "SocketClientCommand.h"
 
@@ -25,7 +27,7 @@
     bool                    mListen;
     const char              *mSocketName;
     int                     mSock;
-    SocketClientCollection  *mClients;
+    std::unordered_map<int, SocketClient*> mClients;
     pthread_mutex_t         mClientsLock;
     int                     mCtrlPipe[2];
     pthread_t               mThread;
@@ -51,8 +53,13 @@
     virtual bool onDataAvailable(SocketClient *c) = 0;
 
 private:
-    bool release(SocketClient *c, bool wakeup);
     static void *threadStart(void *obj);
+
+    // Add all clients to a separate list, so we don't have to hold the lock
+    // while processing it.
+    std::vector<SocketClient*> snapshotClients();
+
+    bool release(SocketClient *c, bool wakeup);
     void runListener();
     void init(const char *socketName, int socketFd, bool listen, bool useCmdNum);
 };
diff --git a/libsysutils/src/OWNERS b/libsysutils/src/OWNERS
index b78918e..645baf4 100644
--- a/libsysutils/src/OWNERS
+++ b/libsysutils/src/OWNERS
@@ -1,2 +1 @@
-per-file Netlink* = ek@google.com
-per-file Netlink* = lorenzo@google.com
+per-file OWNERS,Netlink* = ek@google.com,lorenzo@google.com
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 0c8a688..ded5adb 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2014 The Android Open Source Project
+ * Copyright (C) 2008 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.
@@ -19,13 +19,15 @@
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sys/select.h>
+#include <sys/poll.h>
 #include <sys/socket.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/un.h>
 #include <unistd.h>
 
+#include <vector>
+
 #include <cutils/sockets.h>
 #include <log/log.h>
 #include <sysutils/SocketListener.h>
@@ -52,7 +54,6 @@
     mSock = socketFd;
     mUseCmdNum = useCmdNum;
     pthread_mutex_init(&mClientsLock, nullptr);
-    mClients = new SocketClientCollection();
 }
 
 SocketListener::~SocketListener() {
@@ -63,12 +64,9 @@
         close(mCtrlPipe[0]);
         close(mCtrlPipe[1]);
     }
-    SocketClientCollection::iterator it;
-    for (it = mClients->begin(); it != mClients->end();) {
-        (*it)->decRef();
-        it = mClients->erase(it);
+    for (auto pair : mClients) {
+        pair.second->decRef();
     }
-    delete mClients;
 }
 
 int SocketListener::startListener() {
@@ -95,7 +93,7 @@
         SLOGE("Unable to listen on socket (%s)", strerror(errno));
         return -1;
     } else if (!mListen)
-        mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
+        mClients[mSock] = new SocketClient(mSock, false, mUseCmdNum);
 
     if (pipe(mCtrlPipe)) {
         SLOGE("pipe failed (%s)", strerror(errno));
@@ -135,11 +133,10 @@
         mSock = -1;
     }
 
-    SocketClientCollection::iterator it;
-    for (it = mClients->begin(); it != mClients->end();) {
-        delete (*it);
-        it = mClients->erase(it);
+    for (auto pair : mClients) {
+        delete pair.second;
     }
+    mClients.clear();
     return 0;
 }
 
@@ -152,47 +149,30 @@
 }
 
 void SocketListener::runListener() {
-
-    SocketClientCollection pendingList;
-
-    while(1) {
-        SocketClientCollection::iterator it;
-        fd_set read_fds;
-        int rc = 0;
-        int max = -1;
-
-        FD_ZERO(&read_fds);
-
-        if (mListen) {
-            max = mSock;
-            FD_SET(mSock, &read_fds);
-        }
-
-        FD_SET(mCtrlPipe[0], &read_fds);
-        if (mCtrlPipe[0] > max)
-            max = mCtrlPipe[0];
+    while (true) {
+        std::vector<pollfd> fds;
 
         pthread_mutex_lock(&mClientsLock);
-        for (it = mClients->begin(); it != mClients->end(); ++it) {
+        fds.reserve(2 + mClients.size());
+        fds.push_back({.fd = mCtrlPipe[0], .events = POLLIN});
+        if (mListen) fds.push_back({.fd = mSock, .events = POLLIN});
+        for (auto pair : mClients) {
             // NB: calling out to an other object with mClientsLock held (safe)
-            int fd = (*it)->getSocket();
-            FD_SET(fd, &read_fds);
-            if (fd > max) {
-                max = fd;
-            }
+            const int fd = pair.second->getSocket();
+            if (fd != pair.first) SLOGE("fd mismatch: %d != %d", fd, pair.first);
+            fds.push_back({.fd = fd, .events = POLLIN});
         }
         pthread_mutex_unlock(&mClientsLock);
-        SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
-        if ((rc = select(max + 1, &read_fds, nullptr, nullptr, nullptr)) < 0) {
-            if (errno == EINTR)
-                continue;
-            SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
+
+        SLOGV("mListen=%d, mSocketName=%s", mListen, mSocketName);
+        int rc = TEMP_FAILURE_RETRY(poll(fds.data(), fds.size(), -1));
+        if (rc < 0) {
+            SLOGE("poll failed (%s) mListen=%d", strerror(errno), mListen);
             sleep(1);
             continue;
-        } else if (!rc)
-            continue;
+        }
 
-        if (FD_ISSET(mCtrlPipe[0], &read_fds)) {
+        if (fds[0].revents & (POLLIN | POLLERR)) {
             char c = CtrlPipe_Shutdown;
             TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
             if (c == CtrlPipe_Shutdown) {
@@ -200,7 +180,7 @@
             }
             continue;
         }
-        if (mListen && FD_ISSET(mSock, &read_fds)) {
+        if (mListen && (fds[1].revents & (POLLIN | POLLERR))) {
             int c = TEMP_FAILURE_RETRY(accept4(mSock, nullptr, nullptr, SOCK_CLOEXEC));
             if (c < 0) {
                 SLOGE("accept failed (%s)", strerror(errno));
@@ -208,32 +188,33 @@
                 continue;
             }
             pthread_mutex_lock(&mClientsLock);
-            mClients->push_back(new SocketClient(c, true, mUseCmdNum));
+            mClients[c] = new SocketClient(c, true, mUseCmdNum);
             pthread_mutex_unlock(&mClientsLock);
         }
 
-        /* Add all active clients to the pending list first */
-        pendingList.clear();
+        // Add all active clients to the pending list first, so we can release
+        // the lock before invoking the callbacks.
+        std::vector<SocketClient*> pending;
         pthread_mutex_lock(&mClientsLock);
-        for (it = mClients->begin(); it != mClients->end(); ++it) {
-            SocketClient* c = *it;
-            // NB: calling out to an other object with mClientsLock held (safe)
-            int fd = c->getSocket();
-            if (FD_ISSET(fd, &read_fds)) {
-                pendingList.push_back(c);
+        const int size = fds.size();
+        for (int i = mListen ? 2 : 1; i < size; ++i) {
+            const struct pollfd& p = fds[i];
+            if (p.revents & (POLLIN | POLLERR)) {
+                auto it = mClients.find(p.fd);
+                if (it == mClients.end()) {
+                    SLOGE("fd vanished: %d", p.fd);
+                    continue;
+                }
+                SocketClient* c = it->second;
+                pending.push_back(c);
                 c->incRef();
             }
         }
         pthread_mutex_unlock(&mClientsLock);
 
-        /* Process the pending list, since it is owned by the thread,
-         * there is no need to lock it */
-        while (!pendingList.empty()) {
-            /* Pop the first item from the list */
-            it = pendingList.begin();
-            SocketClient* c = *it;
-            pendingList.erase(it);
-            /* Process it, if false is returned, remove from list */
+        for (SocketClient* c : pending) {
+            // Process it, if false is returned, remove from the map
+            SLOGV("processing fd %d", c->getSocket());
             if (!onDataAvailable(c)) {
                 release(c, false);
             }
@@ -246,17 +227,10 @@
     bool ret = false;
     /* if our sockets are connection-based, remove and destroy it */
     if (mListen && c) {
-        /* Remove the client from our array */
+        /* Remove the client from our map */
         SLOGV("going to zap %d for %s", c->getSocket(), mSocketName);
         pthread_mutex_lock(&mClientsLock);
-        SocketClientCollection::iterator it;
-        for (it = mClients->begin(); it != mClients->end(); ++it) {
-            if (*it == c) {
-                mClients->erase(it);
-                ret = true;
-                break;
-            }
-        }
+        ret = (mClients.erase(c->getSocket()) != 0);
         pthread_mutex_unlock(&mClientsLock);
         if (ret) {
             ret = c->decRef();
@@ -269,26 +243,22 @@
     return ret;
 }
 
-void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
-    SocketClientCollection safeList;
-
-    /* Add all active clients to the safe list first */
-    safeList.clear();
+std::vector<SocketClient*> SocketListener::snapshotClients() {
+    std::vector<SocketClient*> clients;
     pthread_mutex_lock(&mClientsLock);
-    SocketClientCollection::iterator i;
-
-    for (i = mClients->begin(); i != mClients->end(); ++i) {
-        SocketClient* c = *i;
+    clients.reserve(mClients.size());
+    for (auto pair : mClients) {
+        SocketClient* c = pair.second;
         c->incRef();
-        safeList.push_back(c);
+        clients.push_back(c);
     }
     pthread_mutex_unlock(&mClientsLock);
 
-    while (!safeList.empty()) {
-        /* Pop the first item from the list */
-        i = safeList.begin();
-        SocketClient* c = *i;
-        safeList.erase(i);
+    return clients;
+}
+
+void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
+    for (SocketClient* c : snapshotClients()) {
         // broadcasts are unsolicited and should not include a cmd number
         if (c->sendMsg(code, msg, addErrno, false)) {
             SLOGW("Error sending broadcast (%s)", strerror(errno));
@@ -298,25 +268,7 @@
 }
 
 void SocketListener::runOnEachSocket(SocketClientCommand *command) {
-    SocketClientCollection safeList;
-
-    /* Add all active clients to the safe list first */
-    safeList.clear();
-    pthread_mutex_lock(&mClientsLock);
-    SocketClientCollection::iterator i;
-
-    for (i = mClients->begin(); i != mClients->end(); ++i) {
-        SocketClient* c = *i;
-        c->incRef();
-        safeList.push_back(c);
-    }
-    pthread_mutex_unlock(&mClientsLock);
-
-    while (!safeList.empty()) {
-        /* Pop the first item from the list */
-        i = safeList.begin();
-        SocketClient* c = *i;
-        safeList.erase(i);
+    for (SocketClient* c : snapshotClients()) {
         command->runSocketCommand(c);
         c->decRef();
     }
diff --git a/libsysutils/src/SocketListener_test.cpp b/libsysutils/src/SocketListener_test.cpp
new file mode 100644
index 0000000..fed4546
--- /dev/null
+++ b/libsysutils/src/SocketListener_test.cpp
@@ -0,0 +1,182 @@
+/*
+ * 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 <sysutils/FrameworkListener.h>
+
+#include <poll.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <algorithm>
+#include <memory>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <cutils/sockets.h>
+#include <gtest/gtest.h>
+
+using android::base::unique_fd;
+
+namespace {
+
+std::string testSocketPath() {
+    const testing::TestInfo* const test_info =
+            testing::UnitTest::GetInstance()->current_test_info();
+    return std::string(ANDROID_SOCKET_DIR "/") + std::string(test_info->test_case_name()) +
+           std::string(".") + std::string(test_info->name());
+}
+
+unique_fd serverSocket(const std::string& path) {
+    unlink(path.c_str());
+
+    unique_fd fd(socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
+    EXPECT_GE(fd.get(), 0);
+
+    struct sockaddr_un addr = {.sun_family = AF_UNIX};
+    strlcpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path));
+
+    EXPECT_EQ(bind(fd.get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr)), 0)
+            << "bind() to " << path << " failed: " << strerror(errno);
+    EXPECT_EQ(android_get_control_socket(path.c_str()), -1);
+
+    return fd;
+}
+
+unique_fd clientSocket(const std::string& path) {
+    unique_fd fd(socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
+    EXPECT_GE(fd.get(), 0);
+
+    struct sockaddr_un addr = {.sun_family = AF_UNIX};
+    strlcpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path));
+
+    EXPECT_EQ(0, connect(fd.get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr)))
+            << "connect() to " << path << " failed: " << strerror(errno);
+
+    return fd;
+}
+
+void sendCmd(int fd, const char* cmd) {
+    EXPECT_TRUE(android::base::WriteFully(fd, cmd, strlen(cmd) + 1))
+            << "write() to socket failed: " << strerror(errno);
+}
+
+std::string recvReply(int fd) {
+    pollfd fds = {.fd = fd, .events = POLLIN};
+    int poll_events = poll(&fds, 1, -1);
+    EXPECT_EQ(1, poll_events);
+
+    // Technically, this one-shot read() is incorrect: we should keep on
+    // reading the socket until we get a \0. But this is also how
+    // FrameworkListener::onDataAvailable() reads, and it works because
+    // replies are always send with a single write() call, and clients
+    // always read replies before queueing the next command.
+    char buf[1024];
+    ssize_t len = read(fd, buf, sizeof(buf));
+    EXPECT_GE(len, 0) << "read() from socket failed: " << strerror(errno);
+    return len > 0 ? std::string(buf, buf + len) : "";
+}
+
+// Test command which echoes back all its arguments as a comma-separated list.
+// Always returns error code 42
+//
+// TODO: enable testing replies with addErrno=true and useCmdNum=true
+class TestCommand : public FrameworkCommand {
+  public:
+    TestCommand() : FrameworkCommand("test") {}
+    ~TestCommand() override {}
+
+    int runCommand(SocketClient* cli, int argc, char** argv) {
+        std::vector<std::string> args(argv, argv + argc);
+        std::string reply = android::base::Join(args, ',');
+        cli->sendMsg(42, reply.c_str(), /*addErrno=*/false, /*useCmdNum=*/false);
+        return 0;
+    }
+};
+
+// A test listener with a single command.
+class TestListener : public FrameworkListener {
+  public:
+    TestListener(int fd) : FrameworkListener(fd) {
+        registerCmd(new TestCommand);  // Leaked :-(
+    }
+};
+
+}  // unnamed namespace
+
+class FrameworkListenerTest : public testing::Test {
+  public:
+    FrameworkListenerTest() {
+        mSocketPath = testSocketPath();
+        mSserverFd = serverSocket(mSocketPath);
+        mListener = std::make_unique<TestListener>(mSserverFd.get());
+        EXPECT_EQ(0, mListener->startListener());
+    }
+
+    ~FrameworkListenerTest() override {
+        EXPECT_EQ(0, mListener->stopListener());
+
+        // Wouldn't it be cool if unique_fd had an option for taking care of this?
+        unlink(mSocketPath.c_str());
+    }
+
+    void testCommand(const char* command, const char* expected) {
+        unique_fd client_fd = clientSocket(mSocketPath);
+        sendCmd(client_fd.get(), command);
+
+        std::string reply = recvReply(client_fd.get());
+        EXPECT_EQ(std::string(expected) + '\0', reply);
+    }
+
+  protected:
+    std::string mSocketPath;
+    unique_fd mSserverFd;
+    std::unique_ptr<TestListener> mListener;
+};
+
+TEST_F(FrameworkListenerTest, DoesNothing) {
+    // Let the test harness start and stop a FrameworkListener
+    // without sending any commands through it.
+}
+
+TEST_F(FrameworkListenerTest, DispatchesValidCommands) {
+    testCommand("test", "42 test");
+    testCommand("test arg1 arg2", "42 test,arg1,arg2");
+    testCommand("test \"arg1 still_arg1\" arg2", "42 test,arg1 still_arg1,arg2");
+    testCommand("test \"escaped quote: '\\\"'\"", "42 test,escaped quote: '\"'");
+
+    // Perhaps this behavior was unintended, but would be good to detect any
+    // changes, in case anyone depends on it.
+    testCommand("test   ", "42 test,,,");
+}
+
+TEST_F(FrameworkListenerTest, RejectsInvalidCommands) {
+    testCommand("unknown arg1 arg2", "500 Command not recognized");
+    testCommand("test \"arg1 arg2", "500 Unclosed quotes error");
+    testCommand("test \\a", "500 Unsupported escape sequence");
+}
+
+TEST_F(FrameworkListenerTest, MultipleClients) {
+    unique_fd client1 = clientSocket(mSocketPath);
+    unique_fd client2 = clientSocket(mSocketPath);
+    sendCmd(client1.get(), "test 1");
+    sendCmd(client2.get(), "test 2");
+
+    EXPECT_EQ(std::string("42 test,2") + '\0', recvReply(client2.get()));
+    EXPECT_EQ(std::string("42 test,1") + '\0', recvReply(client1.get()));
+}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index d635e65..1c1bdf7 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -58,7 +58,6 @@
         "-Wall",
         "-Werror",
     ],
-    include_dirs: ["external/safe-iop/include"],
     header_libs: [
         "libutils_headers",
     ],
diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp
index 00a904d..e16f88d 100644
--- a/libutils/VectorImpl.cpp
+++ b/libutils/VectorImpl.cpp
@@ -24,8 +24,6 @@
 
 #include <log/log.h>
 
-#include <safe_iop.h>
-
 #include "SharedBuffer.h"
 
 /*****************************************************************************/
@@ -342,7 +340,7 @@
     }
 
     size_t new_allocation_size = 0;
-    LOG_ALWAYS_FATAL_IF(!safe_mul(&new_allocation_size, new_capacity, mItemSize));
+    LOG_ALWAYS_FATAL_IF(__builtin_mul_overflow(new_capacity, mItemSize, &new_allocation_size));
     SharedBuffer* sb = SharedBuffer::alloc(new_allocation_size);
     if (sb) {
         void* array = sb->data();
@@ -386,7 +384,7 @@
             this, (int)where, (int)amount, (int)mCount); // caller already checked
 
     size_t new_size;
-    LOG_ALWAYS_FATAL_IF(!safe_add(&new_size, mCount, amount), "new_size overflow");
+    LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(mCount, amount, &new_size), "new_size overflow");
 
     if (capacity() < new_size) {
         // NOTE: This implementation used to resize vectors as per ((3*x + 1) / 2)
@@ -397,17 +395,18 @@
         //
         // This approximates the old calculation, using (x + (x/2) + 1) instead.
         size_t new_capacity = 0;
-        LOG_ALWAYS_FATAL_IF(!safe_add(&new_capacity, new_size, (new_size / 2)),
+        LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(new_size, (new_size / 2), &new_capacity),
                             "new_capacity overflow");
-        LOG_ALWAYS_FATAL_IF(!safe_add(&new_capacity, new_capacity, static_cast<size_t>(1u)),
-                            "new_capacity overflow");
+        LOG_ALWAYS_FATAL_IF(
+                __builtin_add_overflow(new_capacity, static_cast<size_t>(1u), &new_capacity),
+                "new_capacity overflow");
         new_capacity = max(kMinVectorCapacity, new_capacity);
 
         size_t new_alloc_size = 0;
-        LOG_ALWAYS_FATAL_IF(!safe_mul(&new_alloc_size, new_capacity, mItemSize),
+        LOG_ALWAYS_FATAL_IF(__builtin_mul_overflow(new_capacity, mItemSize, &new_alloc_size),
                             "new_alloc_size overflow");
 
-//        ALOGV("grow vector %p, new_capacity=%d", this, (int)new_capacity);
+        // ALOGV("grow vector %p, new_capacity=%d", this, (int)new_capacity);
         if ((mStorage) &&
             (mCount==where) &&
             (mFlags & HAS_TRIVIAL_COPY) &&
@@ -464,7 +463,7 @@
             this, (int)where, (int)amount, (int)mCount); // caller already checked
 
     size_t new_size;
-    LOG_ALWAYS_FATAL_IF(!safe_sub(&new_size, mCount, amount));
+    LOG_ALWAYS_FATAL_IF(__builtin_sub_overflow(mCount, amount, &new_size));
 
     if (new_size < (capacity() / 2)) {
         // NOTE: (new_size * 2) is safe because capacity didn't overflow and
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 9536fc7..add6e14 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -41,6 +41,7 @@
 #include <android-base/logging.h>
 #include <android-base/macros.h>  // TEMP_FAILURE_RETRY may or may not be in unistd
 #include <android-base/memory.h>
+#include <android-base/utf8.h>
 #include <log/log.h>
 #include <utils/Compat.h>
 #include <utils/FileMap.h>
@@ -471,7 +472,7 @@
 }
 
 int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
-  const int fd = open(fileName, O_RDONLY | O_BINARY, 0);
+  const int fd = ::android::base::utf8::open(fileName, O_RDONLY | O_BINARY, 0);
   ZipArchive* archive = new ZipArchive(fd, true);
   *handle = archive;
 
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
index 48551f2..bb55d1f 100644
--- a/llkd/libllkd.cpp
+++ b/llkd/libllkd.cpp
@@ -738,6 +738,8 @@
 }
 
 void* llkThread(void* obj) {
+    prctl(PR_SET_DUMPABLE, 0);
+
     LOG(INFO) << "started";
 
     std::string name = std::to_string(::gettid());
diff --git a/llkd/llkd.cpp b/llkd/llkd.cpp
index f10253d..1920198 100644
--- a/llkd/llkd.cpp
+++ b/llkd/llkd.cpp
@@ -17,6 +17,7 @@
 #include "llkd.h"
 
 #include <sched.h>
+#include <sys/prctl.h>
 #include <unistd.h>
 
 #include <chrono>
@@ -26,6 +27,8 @@
 using namespace std::chrono;
 
 int main(int, char**) {
+    prctl(PR_SET_DUMPABLE, 0);
+
     LOG(INFO) << "started";
 
     bool enabled = llkInit();
diff --git a/rootdir/init.rc b/rootdir/init.rc
index db89ea8..1c2ef64 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -716,12 +716,12 @@
     class_start main
 
 on property:vold.decrypt=trigger_restart_framework
-    stop surfaceflinger
-    start surfaceflinger
     # A/B update verifier that marks a successful boot.
     exec_start update_verifier
     class_start main
     class_start late_start
+    setprop service.bootanim.exit 0
+    start bootanim
 
 on property:vold.decrypt=trigger_shutdown_framework
     class_reset late_start
diff --git a/toolbox/getevent.c b/toolbox/getevent.c
index e6def6b..39033ad 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -321,7 +321,7 @@
     char idstr[80];
     struct input_id id;
 
-    fd = open(device, O_RDWR);
+    fd = open(device, O_RDONLY | O_CLOEXEC);
     if(fd < 0) {
         if(print_flags & PRINT_DEVICE_ERRORS)
             fprintf(stderr, "could not open %s, %s\n", device, strerror(errno));