Merge "Do not calculate CRC for sparse images during fastboot flash"
diff --git a/adb/Android.bp b/adb/Android.bp
index bccc71a..7f82ca6 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -24,6 +24,7 @@
         "-Wno-missing-field-initializers",
         "-Wvla",
     ],
+    cpp_std: "gnu++17",
     rtti: true,
 
     use_version_lib: true,
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index 8c39a20..d55096a 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -32,6 +32,10 @@
 #include <unistd.h>
 #include <utime.h>
 
+#include <memory>
+#include <string>
+#include <vector>
+
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
@@ -47,6 +51,7 @@
 #include "security_log_tags.h"
 #include "sysdeps/errno.h"
 
+using android::base::Dirname;
 using android::base::StringPrintf;
 
 static bool should_use_fs_config(const std::string& path) {
@@ -219,7 +224,7 @@
     }
 
     if (fd < 0 && errno == ENOENT) {
-        if (!secure_mkdirs(android::base::Dirname(path))) {
+        if (!secure_mkdirs(Dirname(path))) {
             SendSyncFailErrno(s, "secure_mkdirs failed");
             goto fail;
         }
@@ -327,8 +332,6 @@
 #else
 static bool handle_send_link(int s, const std::string& path, std::vector<char>& buffer) {
     syncmsg msg;
-    unsigned int len;
-    int ret;
 
     if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false;
 
@@ -337,24 +340,28 @@
         return false;
     }
 
-    len = msg.data.size;
+    unsigned int len = msg.data.size;
     if (len > buffer.size()) { // TODO: resize buffer?
         SendSyncFail(s, "oversize data message");
         return false;
     }
     if (!ReadFdExactly(s, &buffer[0], len)) return false;
 
-    ret = symlink(&buffer[0], path.c_str());
-    if (ret && errno == ENOENT) {
-        if (!secure_mkdirs(android::base::Dirname(path))) {
-            SendSyncFailErrno(s, "secure_mkdirs failed");
+    std::string buf_link;
+    if (!android::base::Readlink(path, &buf_link) || (buf_link != &buffer[0])) {
+        adb_unlink(path.c_str());
+        auto ret = symlink(&buffer[0], path.c_str());
+        if (ret && errno == ENOENT) {
+            if (!secure_mkdirs(Dirname(path))) {
+                SendSyncFailErrno(s, "secure_mkdirs failed");
+                return false;
+            }
+            ret = symlink(&buffer[0], path.c_str());
+        }
+        if (ret) {
+            SendSyncFailErrno(s, "symlink failed");
             return false;
         }
-        ret = symlink(&buffer[0], path.c_str());
-    }
-    if (ret) {
-        SendSyncFailErrno(s, "symlink failed");
-        return false;
     }
 
     if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false;
@@ -391,7 +398,8 @@
 
     // Don't delete files before copying if they are not "regular" or symlinks.
     struct stat st;
-    bool do_unlink = (lstat(path.c_str(), &st) == -1) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode);
+    bool do_unlink = (lstat(path.c_str(), &st) == -1) || S_ISREG(st.st_mode) ||
+                     (S_ISLNK(st.st_mode) && !S_ISLNK(mode));
     if (do_unlink) {
         adb_unlink(path.c_str());
     }
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 1534792..dfd9a0a 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -26,10 +26,14 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <map>
 #include <mutex>
 #include <string>
+#include <thread>
 #include <vector>
 
+#include <android-base/thread_annotations.h>
+
 #if !ADB_HOST
 #include <android-base/properties.h>
 #include <log/log_properties.h>
@@ -37,9 +41,150 @@
 
 #include "adb.h"
 #include "adb_io.h"
+#include "adb_utils.h"
+#include "sysdeps/chrono.h"
 #include "transport.h"
 #include "types.h"
 
+// The standard (RFC 1122 - 4.2.2.13) says that if we call close on a
+// socket while we have pending data, a TCP RST should be sent to the
+// other end to notify it that we didn't read all of its data. However,
+// this can result in data that we've successfully written out to be dropped
+// on the other end. To avoid this, instead of immediately closing a
+// socket, call shutdown on it instead, and then read from the file
+// descriptor until we hit EOF or an error before closing.
+struct LingeringSocketCloser {
+    LingeringSocketCloser() = default;
+    ~LingeringSocketCloser() = delete;
+
+    // Defer thread creation until it's needed, because we need for there to
+    // only be one thread when dropping privileges in adbd.
+    void Start() {
+        CHECK(!thread_.joinable());
+
+        int fds[2];
+        if (adb_socketpair(fds) != 0) {
+            PLOG(FATAL) << "adb_socketpair failed";
+        }
+
+        set_file_block_mode(fds[0], false);
+        set_file_block_mode(fds[1], false);
+
+        notify_fd_read_.reset(fds[0]);
+        notify_fd_write_.reset(fds[1]);
+
+        thread_ = std::thread([this]() { Run(); });
+    }
+
+    void EnqueueSocket(unique_fd socket) {
+        // Shutdown the socket in the outgoing direction only, so that
+        // we don't have the same problem on the opposite end.
+        adb_shutdown(socket.get(), SHUT_WR);
+        set_file_block_mode(socket.get(), false);
+
+        std::lock_guard<std::mutex> lock(mutex_);
+        int fd = socket.get();
+        SocketInfo info = {
+                .fd = std::move(socket),
+                .deadline = std::chrono::steady_clock::now() + 1s,
+        };
+
+        D("LingeringSocketCloser received fd %d", fd);
+
+        fds_.emplace(fd, std::move(info));
+        if (adb_write(notify_fd_write_, "", 1) == -1 && errno != EAGAIN) {
+            PLOG(FATAL) << "failed to write to LingeringSocketCloser notify fd";
+        }
+    }
+
+  private:
+    std::vector<adb_pollfd> GeneratePollFds() {
+        std::lock_guard<std::mutex> lock(mutex_);
+        std::vector<adb_pollfd> result;
+        result.push_back(adb_pollfd{.fd = notify_fd_read_, .events = POLLIN});
+        for (auto& [fd, _] : fds_) {
+            result.push_back(adb_pollfd{.fd = fd, .events = POLLIN});
+        }
+        return result;
+    }
+
+    void Run() {
+        while (true) {
+            std::vector<adb_pollfd> pfds = GeneratePollFds();
+            int rc = adb_poll(pfds.data(), pfds.size(), 1000);
+            if (rc == -1) {
+                PLOG(FATAL) << "poll failed in LingeringSocketCloser";
+            }
+
+            std::lock_guard<std::mutex> lock(mutex_);
+            if (rc == 0) {
+                // Check deadlines.
+                auto now = std::chrono::steady_clock::now();
+                for (auto it = fds_.begin(); it != fds_.end();) {
+                    if (now > it->second.deadline) {
+                        D("LingeringSocketCloser closing fd %d due to deadline", it->first);
+                        it = fds_.erase(it);
+                    } else {
+                        D("deadline still not expired for fd %d", it->first);
+                        ++it;
+                    }
+                }
+                continue;
+            }
+
+            for (auto& pfd : pfds) {
+                if ((pfd.revents & POLLIN) == 0) {
+                    continue;
+                }
+
+                // Empty the fd.
+                ssize_t rc;
+                char buf[32768];
+                while ((rc = adb_read(pfd.fd, buf, sizeof(buf))) > 0) {
+                    continue;
+                }
+
+                if (pfd.fd == notify_fd_read_) {
+                    continue;
+                }
+
+                auto it = fds_.find(pfd.fd);
+                if (it == fds_.end()) {
+                    LOG(FATAL) << "fd is missing";
+                }
+
+                if (rc == -1 && errno == EAGAIN) {
+                    if (std::chrono::steady_clock::now() > it->second.deadline) {
+                        D("LingeringSocketCloser closing fd %d due to deadline", pfd.fd);
+                    } else {
+                        continue;
+                    }
+                } else if (rc == -1) {
+                    D("LingeringSocketCloser closing fd %d due to error %d", pfd.fd, errno);
+                } else {
+                    D("LingeringSocketCloser closing fd %d due to EOF", pfd.fd);
+                }
+
+                fds_.erase(it);
+            }
+        }
+    }
+
+    std::thread thread_;
+    unique_fd notify_fd_read_;
+    unique_fd notify_fd_write_;
+
+    struct SocketInfo {
+        unique_fd fd;
+        std::chrono::steady_clock::time_point deadline;
+    };
+
+    std::mutex mutex_;
+    std::map<int, SocketInfo> fds_ GUARDED_BY(mutex_);
+};
+
+static auto& socket_closer = *new LingeringSocketCloser();
+
 static std::recursive_mutex& local_socket_list_lock = *new std::recursive_mutex();
 static unsigned local_socket_next_id = 1;
 
@@ -243,10 +388,12 @@
 
     D("LS(%d): destroying fde.fd=%d", s->id, s->fd);
 
-    /* IMPORTANT: the remove closes the fd
-    ** that belongs to this socket
-    */
-    fdevent_destroy(s->fde);
+    // Defer thread creation until it's needed, because we need for there to
+    // only be one thread when dropping privileges in adbd.
+    static std::once_flag once;
+    std::call_once(once, []() { socket_closer.Start(); });
+
+    socket_closer.EnqueueSocket(fdevent_release(s->fde));
 
     remove_socket(s);
     delete s;
diff --git a/adb/test_device.py b/adb/test_device.py
index c3166ff..4c45a73 100755
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -35,6 +35,8 @@
 import time
 import unittest
 
+from datetime import datetime
+
 import adb
 
 def requires_root(func):
@@ -1335,6 +1337,63 @@
             self.device.forward_remove("tcp:{}".format(local_port))
 
 
+class SocketTest(DeviceTest):
+    def test_socket_flush(self):
+        """Test that we handle socket closure properly.
+
+        If we're done writing to a socket, closing before the other end has
+        closed will send a TCP_RST if we have incoming data queued up, which
+        may result in data that we've written being discarded.
+
+        Bug: http://b/74616284
+        """
+        s = socket.create_connection(("localhost", 5037))
+
+        def adb_length_prefixed(string):
+            encoded = string.encode("utf8")
+            result = b"%04x%s" % (len(encoded), encoded)
+            return result
+
+        if "ANDROID_SERIAL" in os.environ:
+            transport_string = "host:transport:" + os.environ["ANDROID_SERIAL"]
+        else:
+            transport_string = "host:transport-any"
+
+        s.sendall(adb_length_prefixed(transport_string))
+        response = s.recv(4)
+        self.assertEquals(b"OKAY", response)
+
+        shell_string = "shell:sleep 0.5; dd if=/dev/zero bs=1m count=1 status=none; echo foo"
+        s.sendall(adb_length_prefixed(shell_string))
+
+        response = s.recv(4)
+        self.assertEquals(b"OKAY", response)
+
+        # Spawn a thread that dumps garbage into the socket until failure.
+        def spam():
+            buf = b"\0" * 16384
+            try:
+                while True:
+                    s.sendall(buf)
+            except Exception as ex:
+                print(ex)
+
+        thread = threading.Thread(target=spam)
+        thread.start()
+
+        time.sleep(1)
+
+        received = b""
+        while True:
+            read = s.recv(512)
+            if len(read) == 0:
+                break
+            received += read
+
+        self.assertEquals(1024 * 1024 + len("foo\n"), len(received))
+        thread.join()
+
+
 if sys.platform == "win32":
     # From https://stackoverflow.com/a/38749458
     import os
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
index 9444fdd..be8b97b 100644
--- a/base/include/android-base/parseint.h
+++ b/base/include/android-base/parseint.h
@@ -22,6 +22,7 @@
 
 #include <limits>
 #include <string>
+#include <type_traits>
 
 namespace android {
 namespace base {
@@ -33,6 +34,7 @@
 template <typename T>
 bool ParseUint(const char* s, T* out, T max = std::numeric_limits<T>::max(),
                bool allow_suffixes = false) {
+  static_assert(std::is_unsigned<T>::value, "ParseUint can only be used with unsigned types");
   while (isspace(*s)) {
     s++;
   }
@@ -96,6 +98,7 @@
 bool ParseInt(const char* s, T* out,
               T min = std::numeric_limits<T>::min(),
               T max = std::numeric_limits<T>::max()) {
+  static_assert(std::is_signed<T>::value, "ParseInt can only be used with signed types");
   while (isspace(*s)) {
     s++;
   }
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 3f663ef..6e45133 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -131,6 +131,11 @@
     if (args.size() < 2) {
         return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
     }
+
+    if (GetDeviceLockStatus()) {
+        return device->WriteStatus(FastbootResult::FAIL, "Erase is not allowed on locked devices");
+    }
+
     PartitionHandle handle;
     if (!OpenPartition(device, args[1], &handle)) {
         return device->WriteStatus(FastbootResult::FAIL, "Partition doesn't exist");
@@ -163,9 +168,15 @@
     if (args.size() < 2) {
         return device->WriteStatus(FastbootResult::FAIL, "size argument unspecified");
     }
+
+    if (GetDeviceLockStatus()) {
+        return device->WriteStatus(FastbootResult::FAIL,
+                                   "Download is not allowed on locked devices");
+    }
+
     // arg[0] is the command name, arg[1] contains size of data to be downloaded
     unsigned int size;
-    if (!android::base::ParseUint("0x" + args[1], &size, UINT_MAX)) {
+    if (!android::base::ParseUint("0x" + args[1], &size, kMaxDownloadSizeDefault)) {
         return device->WriteStatus(FastbootResult::FAIL, "Invalid size");
     }
     device->download_data().resize(size);
@@ -203,6 +214,11 @@
         return device->WriteStatus(FastbootResult::FAIL, "Missing slot argument");
     }
 
+    if (GetDeviceLockStatus()) {
+        return device->WriteStatus(FastbootResult::FAIL,
+                                   "set_active command is not allowed on locked devices");
+    }
+
     // Slot suffix needs to be between 'a' and 'z'.
     Slot slot;
     if (!GetSlotNumber(args[1], &slot)) {
@@ -221,7 +237,13 @@
     CommandResult ret;
     auto cb = [&ret](CommandResult result) { ret = result; };
     auto result = boot_control_hal->setActiveBootSlot(slot, cb);
-    if (result.isOk() && ret.success) return device->WriteStatus(FastbootResult::OKAY, "");
+    if (result.isOk() && ret.success) {
+        // Save as slot suffix to match the suffix format as returned from
+        // the boot control HAL.
+        auto current_slot = "_" + args[1];
+        device->set_active_slot(current_slot);
+        return device->WriteStatus(FastbootResult::OKAY, "");
+    }
     return device->WriteStatus(FastbootResult::FAIL, "Unable to set slot");
 }
 
diff --git a/fastboot/device/commands.h b/fastboot/device/commands.h
index 9df43a9..bb1f988 100644
--- a/fastboot/device/commands.h
+++ b/fastboot/device/commands.h
@@ -19,6 +19,8 @@
 #include <string>
 #include <vector>
 
+constexpr unsigned int kMaxDownloadSizeDefault = 0x20000000;
+
 class FastbootDevice;
 
 enum class FastbootResult {
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index b843c05..6cb4892 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -57,7 +57,8 @@
       transport_(std::make_unique<ClientUsbTransport>()),
       boot_control_hal_(IBootControl::getService()),
       health_hal_(get_health_service()),
-      fastboot_hal_(IFastboot::getService()) {}
+      fastboot_hal_(IFastboot::getService()),
+      active_slot_("") {}
 
 FastbootDevice::~FastbootDevice() {
     CloseDevice();
@@ -68,6 +69,11 @@
 }
 
 std::string FastbootDevice::GetCurrentSlot() {
+    // Check if a set_active ccommand was issued earlier since the boot control HAL
+    // returns the slot that is currently booted into.
+    if (!active_slot_.empty()) {
+        return active_slot_;
+    }
     // Non-A/B devices must not have boot control HALs.
     if (!boot_control_hal_) {
         return "";
diff --git a/fastboot/device/fastboot_device.h b/fastboot/device/fastboot_device.h
index 2eb7177..091aadf 100644
--- a/fastboot/device/fastboot_device.h
+++ b/fastboot/device/fastboot_device.h
@@ -56,6 +56,8 @@
     }
     android::sp<android::hardware::health::V2_0::IHealth> health_hal() { return health_hal_; }
 
+    void set_active_slot(const std::string& active_slot) { active_slot_ = active_slot; }
+
   private:
     const std::unordered_map<std::string, CommandHandler> kCommandMap;
 
@@ -64,4 +66,5 @@
     android::sp<android::hardware::health::V2_0::IHealth> health_hal_;
     android::sp<android::hardware::fastboot::V1_0::IFastboot> fastboot_hal_;
     std::vector<char> download_data_;
+    std::string active_slot_;
 };
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index 528abec..b844b9f 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -23,6 +23,7 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/strings.h>
 #include <fs_mgr.h>
 #include <fs_mgr_dm_linear.h>
 #include <liblp/liblp.h>
@@ -82,6 +83,10 @@
 }
 
 std::optional<std::string> FindPhysicalPartition(const std::string& name) {
+    // Check for an invalid file name
+    if (android::base::StartsWith(name, "../") || name.find("/../") != std::string::npos) {
+        return {};
+    }
     std::string path = "/dev/block/by-name/" + name;
     if (access(path.c_str(), W_OK) < 0) {
         return {};
@@ -164,6 +169,9 @@
 
 bool GetDeviceLockStatus() {
     std::string cmdline;
-    android::base::ReadFileToString("/proc/cmdline", &cmdline);
+    // Return lock status true if unable to read kernel command line.
+    if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
+        return true;
+    }
     return cmdline.find("androidboot.verifiedbootstate=orange") == std::string::npos;
 }
diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp
index 2de79b1..cbd2856 100644
--- a/fastboot/device/variables.cpp
+++ b/fastboot/device/variables.cpp
@@ -36,7 +36,6 @@
 using ::android::hardware::fastboot::V1_0::Result;
 using ::android::hardware::fastboot::V1_0::Status;
 
-constexpr int kMaxDownloadSizeDefault = 0x20000000;
 constexpr char kFastbootProtocolVersion[] = "0.4";
 
 bool GetVersion(FastbootDevice* /* device */, const std::vector<std::string>& /* args */,
@@ -289,7 +288,7 @@
     bool is_zero_length;
     if (LogicalPartitionExists(args[0], device->GetCurrentSlot(), &is_zero_length) &&
         is_zero_length) {
-        *message = "0";
+        *message = "0x0";
         return true;
     }
     // Otherwise, open the partition as normal.
@@ -309,7 +308,14 @@
         *message = "Missing argument";
         return false;
     }
+
     std::string partition_name = args[0];
+    if (!FindPhysicalPartition(partition_name) &&
+        !LogicalPartitionExists(partition_name, device->GetCurrentSlot())) {
+        *message = "Invalid partition";
+        return false;
+    }
+
     auto fastboot_hal = device->fastboot_hal();
     if (!fastboot_hal) {
         *message = "Fastboot HAL not found";
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index e2076f5..c02ab1c 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -43,6 +43,7 @@
 #include <thread>
 #include <vector>
 
+#include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 #include <gtest/gtest.h>
 #include <sparse/sparse.h>
@@ -331,8 +332,9 @@
                 << cmd + " responded with a string with leading whitespace";
         EXPECT_FALSE(resp.compare(0, 2, "0x"))
                 << cmd + "responded with a string that does not start with 0x...";
-        int64_t size = strtoll(resp.c_str(), nullptr, 16);
-        EXPECT_GT(size, 0) << "'" + resp + "' is not a valid response from " + cmd;
+        uint64_t size;
+        ASSERT_TRUE(android::base::ParseUint(resp, &size))
+                << "'" + resp + "' is not a valid response from " + cmd;
     }
 }
 
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 3ab9732..3226010 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -37,6 +37,7 @@
 #include <memory>
 #include <string>
 #include <thread>
+#include <utility>
 #include <vector>
 
 #include <android-base/file.h>
@@ -850,56 +851,115 @@
     return true;
 }
 
-bool fs_mgr_update_checkpoint_partition(struct fstab_rec* rec) {
-    if (fs_mgr_is_checkpoint_fs(rec)) {
-        if (!strcmp(rec->fs_type, "f2fs")) {
-            std::string opts(rec->fs_options);
+class CheckpointManager {
+  public:
+    CheckpointManager(int needs_checkpoint = -1) : needs_checkpoint_(needs_checkpoint) {}
 
-            opts += ",checkpoint=disable";
-            free(rec->fs_options);
-            rec->fs_options = strdup(opts.c_str());
-        } else {
-            LERROR << rec->fs_type << " does not implement checkpoints.";
+    bool Update(struct fstab_rec* rec) {
+        if (!fs_mgr_is_checkpoint(rec)) {
+            return true;
         }
-    } else if (fs_mgr_is_checkpoint_blk(rec)) {
-        call_vdc({"checkpoint", "restoreCheckpoint", rec->blk_device});
 
-        android::base::unique_fd fd(
-                TEMP_FAILURE_RETRY(open(rec->blk_device, O_RDONLY | O_CLOEXEC)));
-        if (!fd) {
-            PERROR << "Cannot open device " << rec->blk_device;
+        if (fs_mgr_is_checkpoint_blk(rec)) {
+            call_vdc({"checkpoint", "restoreCheckpoint", rec->blk_device});
+        }
+
+        if (needs_checkpoint_ == UNKNOWN &&
+            !call_vdc_ret({"checkpoint", "needsCheckpoint"}, &needs_checkpoint_)) {
+            LERROR << "Failed to find if checkpointing is needed. Assuming no.";
+            needs_checkpoint_ = NO;
+        }
+
+        if (needs_checkpoint_ != YES) {
+            return true;
+        }
+
+        if (!UpdateCheckpointPartition(rec)) {
+            LERROR << "Could not set up checkpoint partition, skipping!";
             return false;
         }
 
-        uint64_t size = get_block_device_size(fd) / 512;
-        if (!size) {
-            PERROR << "Cannot get device size";
-            return false;
+        return true;
+    }
+
+    bool Revert(struct fstab_rec* rec) {
+        if (!fs_mgr_is_checkpoint(rec)) {
+            return true;
         }
 
-        android::dm::DmTable table;
-        if (!table.AddTarget(
-                    std::make_unique<android::dm::DmTargetBow>(0, size, rec->blk_device))) {
-            LERROR << "Failed to add Bow target";
-            return false;
+        if (device_map_.find(rec->blk_device) == device_map_.end()) {
+            return true;
         }
 
+        std::string bow_device = rec->blk_device;
+        free(rec->blk_device);
+        rec->blk_device = strdup(device_map_[bow_device].c_str());
+        device_map_.erase(bow_device);
+
         DeviceMapper& dm = DeviceMapper::Instance();
-        if (!dm.CreateDevice("bow", table)) {
-            PERROR << "Failed to create bow device";
-            return false;
+        if (!dm.DeleteDevice("bow")) {
+            PERROR << "Failed to remove bow device";
         }
 
-        std::string name;
-        if (!dm.GetDmDevicePathByName("bow", &name)) {
-            PERROR << "Failed to get bow device name";
-            return false;
-        }
-
-        rec->blk_device = strdup(name.c_str());
+        return true;
     }
-    return true;
-}
+
+  private:
+    bool UpdateCheckpointPartition(struct fstab_rec* rec) {
+        if (fs_mgr_is_checkpoint_fs(rec)) {
+            if (!strcmp(rec->fs_type, "f2fs")) {
+                std::string opts(rec->fs_options);
+
+                opts += ",checkpoint=disable";
+                free(rec->fs_options);
+                rec->fs_options = strdup(opts.c_str());
+            } else {
+                LERROR << rec->fs_type << " does not implement checkpoints.";
+            }
+        } else if (fs_mgr_is_checkpoint_blk(rec)) {
+            android::base::unique_fd fd(
+                    TEMP_FAILURE_RETRY(open(rec->blk_device, O_RDONLY | O_CLOEXEC)));
+            if (!fd) {
+                PERROR << "Cannot open device " << rec->blk_device;
+                return false;
+            }
+
+            uint64_t size = get_block_device_size(fd) / 512;
+            if (!size) {
+                PERROR << "Cannot get device size";
+                return false;
+            }
+
+            android::dm::DmTable table;
+            if (!table.AddTarget(
+                        std::make_unique<android::dm::DmTargetBow>(0, size, rec->blk_device))) {
+                LERROR << "Failed to add bow target";
+                return false;
+            }
+
+            DeviceMapper& dm = DeviceMapper::Instance();
+            if (!dm.CreateDevice("bow", table)) {
+                PERROR << "Failed to create bow device";
+                return false;
+            }
+
+            std::string name;
+            if (!dm.GetDmDevicePathByName("bow", &name)) {
+                PERROR << "Failed to get bow device name";
+                return false;
+            }
+
+            device_map_[name] = rec->blk_device;
+            free(rec->blk_device);
+            rec->blk_device = strdup(name.c_str());
+        }
+        return true;
+    }
+
+    enum { UNKNOWN = -1, NO = 0, YES = 1 };
+    int needs_checkpoint_;
+    std::map<std::string, std::string> device_map_;
+};
 
 /* When multiple fstab records share the same mount_point, it will
  * try to mount each one in turn, and ignore any duplicates after a
@@ -913,7 +973,7 @@
     int mret = -1;
     int mount_errno = 0;
     int attempted_idx = -1;
-    int need_checkpoint = -1;
+    CheckpointManager checkpoint_manager;
     FsManagerAvbUniquePtr avb_handle(nullptr);
 
     if (!fstab) {
@@ -960,16 +1020,8 @@
             }
         }
 
-        if (fs_mgr_is_checkpoint(&fstab->recs[i])) {
-            if (need_checkpoint == -1 &&
-                !call_vdc_ret({"checkpoint", "needsCheckpoint"}, &need_checkpoint)) {
-                LERROR << "Failed to find if checkpointing is needed. Assuming no.";
-                need_checkpoint = 0;
-            }
-            if (need_checkpoint == 1 && !fs_mgr_update_checkpoint_partition(&fstab->recs[i])) {
-                LERROR << "Could not set up checkpoint partition, skipping!";
-                continue;
-            }
+        if (!checkpoint_manager.Update(&fstab->recs[i])) {
+            continue;
         }
 
         if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
@@ -1052,6 +1104,9 @@
                    << " is wiped and " << fstab->recs[top_idx].mount_point
                    << " " << fstab->recs[top_idx].fs_type
                    << " is formattable. Format it.";
+
+            checkpoint_manager.Revert(&fstab->recs[top_idx]);
+
             if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) &&
                 strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) {
                 int fd = open(fstab->recs[top_idx].key_loc, O_WRONLY);
@@ -1172,11 +1227,12 @@
  * in turn, and stop on 1st success, or no more match.
  */
 static int fs_mgr_do_mount_helper(fstab* fstab, const char* n_name, char* n_blk_device,
-                                  char* tmp_mount_point, int need_checkpoint) {
+                                  char* tmp_mount_point, int needs_checkpoint) {
     int i = 0;
     int mount_errors = 0;
     int first_mount_errno = 0;
     char* mount_point;
+    CheckpointManager checkpoint_manager(needs_checkpoint);
     FsManagerAvbUniquePtr avb_handle(nullptr);
 
     if (!fstab) {
@@ -1205,16 +1261,9 @@
             }
         }
 
-        if (fs_mgr_is_checkpoint(&fstab->recs[i])) {
-            if (need_checkpoint == -1 &&
-                !call_vdc_ret({"checkpoint", "needsCheckpoint"}, &need_checkpoint)) {
-                LERROR << "Failed to find if checkpointing is needed. Assuming no.";
-                need_checkpoint = 0;
-            }
-            if (need_checkpoint == 1 && !fs_mgr_update_checkpoint_partition(&fstab->recs[i])) {
-                LERROR << "Could not set up checkpoint partition, skipping!";
-                continue;
-            }
+        if (!checkpoint_manager.Update(&fstab->recs[i])) {
+            LERROR << "Could not set up checkpoint partition, skipping!";
+            continue;
         }
 
         /* First check the filesystem if requested */
@@ -1291,8 +1340,8 @@
 }
 
 int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
-                    bool needs_cp) {
-    return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, needs_cp);
+                    bool needs_checkpoint) {
+    return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, needs_checkpoint);
 }
 
 /*
@@ -1500,16 +1549,17 @@
     bool system_root = android::base::GetProperty("ro.build.system_root_image", "") == "true";
 
     for (int i = 0; i < fstab->num_entries; i++) {
-        if (!fs_mgr_is_verified(&fstab->recs[i]) && !fs_mgr_is_avb(&fstab->recs[i])) {
+        auto fsrec = &fstab->recs[i];
+        if (!fs_mgr_is_verified(fsrec) && !fs_mgr_is_avb(fsrec)) {
             continue;
         }
 
         std::string mount_point;
-        if (system_root && !strcmp(fstab->recs[i].mount_point, "/")) {
+        if (system_root && !strcmp(fsrec->mount_point, "/")) {
             // In AVB, the dm device name is vroot instead of system.
-            mount_point = fs_mgr_is_avb(&fstab->recs[i]) ? "vroot" : "system";
+            mount_point = fs_mgr_is_avb(fsrec) ? "vroot" : "system";
         } else {
-            mount_point = basename(fstab->recs[i].mount_point);
+            mount_point = basename(fsrec->mount_point);
         }
 
         if (dm.GetState(mount_point) == DmDeviceState::INVALID) {
@@ -1517,15 +1567,14 @@
             continue;
         }
 
-        const char* status = nullptr;
+        const char* status;
         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) {
-                status = "V";
-            } else {
-                PERROR << "Failed to query DM_TABLE_STATUS for " << mount_point.c_str();
+            if (!fs_mgr_is_verifyatboot(fsrec)) {
+                PERROR << "Failed to query DM_TABLE_STATUS for " << mount_point;
                 continue;
             }
+            status = "V";
         } else {
             status = table[0].data.c_str();
         }
@@ -1535,7 +1584,7 @@
         // instead of [partition.vroot.verified].
         if (mount_point == "vroot") mount_point = "system";
         if (*status == 'C' || *status == 'V') {
-            callback(&fstab->recs[i], mount_point.c_str(), mode, *status);
+            callback(fsrec, mount_point.c_str(), mode, *status);
         }
     }
 
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 95326d1..35f8be8 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -29,6 +29,7 @@
 #include <sys/vfs.h>
 #include <unistd.h>
 
+#include <algorithm>
 #include <map>
 #include <memory>
 #include <string>
@@ -40,12 +41,18 @@
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <ext4_utils/ext4_utils.h>
+#include <fs_mgr_dm_linear.h>
 #include <fs_mgr_overlayfs.h>
 #include <fstab/fstab.h>
+#include <libdm/dm.h>
+#include <liblp/builder.h>
+#include <liblp/liblp.h>
 
 #include "fs_mgr_priv.h"
 
 using namespace std::literals;
+using namespace android::dm;
+using namespace android::fs_mgr;
 
 #if ALLOW_ADBD_DISABLE_VERITY == 0  // If we are a user build, provide stubs
 
@@ -71,8 +78,10 @@
 
 namespace {
 
-// acceptable overlayfs backing storage
-const auto kOverlayMountPoint = "/cache"s;
+// list of acceptable overlayfs backing storage
+const auto kScratchMountPoint = "/mnt/scratch"s;
+const auto kCacheMountPoint = "/cache"s;
+const std::vector<const std::string> kOverlayMountPoints = {kScratchMountPoint, kCacheMountPoint};
 
 // Return true if everything is mounted, but before adb is started.  Right
 // after 'trigger load_persist_props_action' is done.
@@ -133,14 +142,17 @@
 
 std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point) {
     if (!fs_mgr_is_dir(mount_point)) return "";
-    auto dir =
-            kOverlayMountPoint + kOverlayTopDir + "/" + android::base::Basename(mount_point) + "/";
-    auto upper = dir + kUpperName;
-    if (!fs_mgr_is_dir(upper)) return "";
-    auto work = dir + kWorkName;
-    if (!fs_mgr_is_dir(work)) return "";
-    if (!fs_mgr_dir_is_writable(work)) return "";
-    return dir;
+    const auto base = android::base::Basename(mount_point) + "/";
+    for (const auto& overlay_mount_point : kOverlayMountPoints) {
+        auto dir = overlay_mount_point + kOverlayTopDir + "/" + base;
+        auto upper = dir + kUpperName;
+        if (!fs_mgr_is_dir(upper)) continue;
+        auto work = dir + kWorkName;
+        if (!fs_mgr_is_dir(work)) continue;
+        if (!fs_mgr_dir_is_writable(work)) continue;
+        return dir;
+    }
+    return "";
 }
 
 const auto kLowerdirOption = "lowerdir="s;
@@ -184,6 +196,14 @@
     return ret;
 }
 
+bool fs_mgr_rw_access(const std::string& path) {
+    if (path.empty()) return false;
+    auto save_errno = errno;
+    auto ret = access(path.c_str(), R_OK | W_OK) == 0;
+    errno = save_errno;
+    return ret;
+}
+
 // return true if system supports overlayfs
 bool fs_mgr_wants_overlayfs() {
     // Properties will return empty on init first_stage_mount, so speculative
@@ -197,7 +217,7 @@
     return fs_mgr_access("/sys/module/overlay/parameters/override_creds");
 }
 
-bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point) {
+bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true) {
     std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab("/proc/mounts"),
                                                                fs_mgr_free_fstab);
     if (!fstab) return false;
@@ -206,10 +226,11 @@
         const auto fsrec = &fstab->recs[i];
         const auto fs_type = fsrec->fs_type;
         if (!fs_type) continue;
-        if (("overlay"s != fs_type) && ("overlayfs"s != fs_type)) continue;
+        if (overlay_only && ("overlay"s != fs_type) && ("overlayfs"s != fs_type)) continue;
         auto fsrec_mount_point = fsrec->mount_point;
         if (!fsrec_mount_point) continue;
         if (mount_point != fsrec_mount_point) continue;
+        if (!overlay_only) return true;
         const auto fs_options = fsrec->fs_options;
         if (!fs_options) continue;
         const auto options = android::base::Split(fs_options, ",");
@@ -222,13 +243,12 @@
     return false;
 }
 
-bool fs_mgr_overlayfs_verity_enabled(const std::string& basename_mount_point) {
-    auto found = false;
-    fs_mgr_update_verity_state(
-            [&basename_mount_point, &found](fstab_rec*, const char* mount_point, int, int) {
-                if (mount_point && (basename_mount_point == mount_point)) found = true;
-            });
-    return found;
+std::vector<std::string> fs_mgr_overlayfs_verity_enabled_list() {
+    std::vector<std::string> ret;
+    fs_mgr_update_verity_state([&ret](fstab_rec*, const char* mount_point, int, int) {
+        ret.emplace_back(mount_point);
+    });
+    return ret;
 }
 
 bool fs_mgr_wants_overlayfs(const fstab_rec* fsrec) {
@@ -254,7 +274,7 @@
 
     if (!fs_mgr_overlayfs_enabled(fsrec)) return false;
 
-    return !fs_mgr_overlayfs_verity_enabled(android::base::Basename(fsrec_mount_point));
+    return true;
 }
 
 bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr) {
@@ -371,6 +391,67 @@
     return ret;
 }
 
+uint32_t fs_mgr_overlayfs_slot_number() {
+    return SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix());
+}
+
+std::string fs_mgr_overlayfs_super_device(uint32_t slot_number) {
+    return "/dev/block/by-name/" + fs_mgr_get_super_partition_name(slot_number);
+}
+
+bool fs_mgr_overlayfs_has_logical(const fstab* fstab) {
+    if (!fstab) return false;
+    for (auto i = 0; i < fstab->num_entries; i++) {
+        const auto fsrec = &fstab->recs[i];
+        if (fs_mgr_is_logical(fsrec)) return true;
+    }
+    return false;
+}
+
+// reduce 'DM_DEV_STATUS failed for scratch: No such device or address' noise
+std::string scratch_device_cache;
+
+bool fs_mgr_overlayfs_teardown_scratch(const std::string& overlay, bool* change) {
+    // umount and delete kScratchMountPoint storage if we have logical partitions
+    if (overlay != kScratchMountPoint) return true;
+    scratch_device_cache.erase();
+    auto slot_number = fs_mgr_overlayfs_slot_number();
+    auto super_device = fs_mgr_overlayfs_super_device(slot_number);
+    if (!fs_mgr_rw_access(super_device)) return true;
+
+    auto save_errno = errno;
+    if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) {
+        // Lazy umount will allow us to move on and possibly later
+        // establish a new fresh mount without requiring a reboot should
+        // the developer wish to restart.  Old references should melt
+        // away or have no data.  Main goal is to shut the door on the
+        // current overrides with an expectation of a subsequent reboot,
+        // thus any errors here are ignored.
+        umount2(kScratchMountPoint.c_str(), MNT_DETACH);
+    }
+    auto builder = MetadataBuilder::New(super_device, slot_number);
+    if (!builder) {
+        errno = save_errno;
+        return true;
+    }
+    const auto partition_name = android::base::Basename(kScratchMountPoint);
+    if (builder->FindPartition(partition_name) == nullptr) {
+        errno = save_errno;
+        return true;
+    }
+    builder->RemovePartition(partition_name);
+    auto metadata = builder->Export();
+    if (metadata && UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
+        if (change) *change = true;
+        if (!DestroyLogicalPartition(partition_name, 0s)) return false;
+    } else {
+        PERROR << "delete partition " << overlay;
+        return false;
+    }
+    errno = save_errno;
+    return true;
+}
+
 bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string& mount_point,
                                    bool* change) {
     const auto top = overlay + kOverlayTopDir;
@@ -404,13 +485,16 @@
         save_errno = errno;
         if (!rmdir(top.c_str())) {
             if (change) *change = true;
+            cleanup_all = true;
         } else if ((errno != ENOENT) && (errno != ENOTEMPTY)) {
             ret = false;
             PERROR << "rmdir " << top;
         } else {
             errno = save_errno;
+            cleanup_all = true;
         }
     }
+    if (cleanup_all) ret &= fs_mgr_overlayfs_teardown_scratch(overlay, change);
     return ret;
 }
 
@@ -445,11 +529,16 @@
     std::vector<std::string> mounts;
     if (!fstab) return mounts;
 
+    auto verity = fs_mgr_overlayfs_verity_enabled_list();
     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;
+        if (std::find(verity.begin(), verity.end(), android::base::Basename(new_mount_point)) !=
+            verity.end()) {
+            continue;
+        }
         auto duplicate_or_more_specific = false;
         for (auto it = mounts.begin(); it != mounts.end();) {
             if ((*it == new_mount_point) ||
@@ -465,19 +554,170 @@
         }
         if (!duplicate_or_more_specific) mounts.emplace_back(new_mount_point);
     }
-    // if not itemized /system or /, system as root, fake up
-    // fs_mgr_wants_overlayfs evaluation of /system as candidate.
 
-    if ((std::find(mounts.begin(), mounts.end(), "/system") == mounts.end()) &&
-        !fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), "/") &&
-        !fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), "/system") &&
-        (!mount_point || ("/system"s == mount_point)) &&
-        !fs_mgr_overlayfs_verity_enabled("system")) {
-        mounts.emplace_back("/system");
+    // if not itemized /system or /, system as root, fake one up?
+
+    // do we want or need to?
+    if (mount_point && ("/system"s != mount_point)) return mounts;
+    if (std::find(mounts.begin(), mounts.end(), "/system") != mounts.end()) return mounts;
+
+    // fs_mgr_overlayfs_verity_enabled_list says not to?
+    if (std::find(verity.begin(), verity.end(), "system") != verity.end()) return mounts;
+
+    // confirm that fstab is missing system
+    if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), "/")) {
+        return mounts;
     }
+    if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), "/system")) {
+        return mounts;
+    }
+
+    // Manually check dm state because stunted fstab (w/o system as root) borken
+    auto& dm = DeviceMapper::Instance();
+    auto found = false;
+    for (auto& system : {"system", "vroot"}) {
+        if (dm.GetState(system) == DmDeviceState::INVALID) continue;
+        std::vector<DeviceMapper::TargetInfo> table;
+        found = !dm.GetTableStatus(system, &table) || table.empty() || table[0].data.empty() ||
+                (table[0].data[0] == 'C') || (table[0].data[0] == 'V');
+        if (found) break;
+    }
+    if (!found) mounts.emplace_back("/system");
     return mounts;
 }
 
+// Mount kScratchMountPoint
+bool fs_mgr_overlayfs_mount_scratch(const std::string& device_path, const std::string mnt_type) {
+    if (setfscreatecon(kOverlayfsFileContext)) {
+        PERROR << "setfscreatecon " << kOverlayfsFileContext;
+    }
+    if (mkdir(kScratchMountPoint.c_str(), 0755) && (errno != EEXIST)) {
+        PERROR << "create " << kScratchMountPoint;
+    }
+
+    std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> local_fstab(
+            static_cast<fstab*>(calloc(1, sizeof(fstab))), fs_mgr_free_fstab);
+    auto fsrec = static_cast<fstab_rec*>(calloc(1, sizeof(fstab_rec)));
+    local_fstab->num_entries = 1;
+    local_fstab->recs = fsrec;
+    fsrec->blk_device = strdup(device_path.c_str());
+    fsrec->mount_point = strdup(kScratchMountPoint.c_str());
+    fsrec->fs_type = strdup(mnt_type.c_str());
+    fsrec->flags = MS_RELATIME;
+    fsrec->fs_options = strdup("");
+    auto mounted = fs_mgr_do_mount_one(fsrec) == 0;
+    auto save_errno = errno;
+    setfscreatecon(nullptr);
+    if (!mounted) rmdir(kScratchMountPoint.c_str());
+    errno = save_errno;
+    return mounted;
+}
+
+const std::string kMkF2fs("/system/bin/make_f2fs");
+const std::string kMkExt4("/system/bin/mke2fs");
+
+std::string fs_mgr_overlayfs_scratch_mount_type() {
+    if (!access(kMkF2fs.c_str(), X_OK)) return "f2fs";
+    if (!access(kMkExt4.c_str(), X_OK)) return "ext4";
+    return "auto";
+}
+
+std::string fs_mgr_overlayfs_scratch_device() {
+    if (!scratch_device_cache.empty()) return scratch_device_cache;
+
+    auto& dm = DeviceMapper::Instance();
+    const auto partition_name = android::base::Basename(kScratchMountPoint);
+    std::string path;
+    if (!dm.GetDmDevicePathByName(partition_name, &path)) return "";
+    return scratch_device_cache = path;
+}
+
+// Create and mount kScratchMountPoint storage if we have logical partitions
+bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) {
+    if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
+    auto mnt_type = fs_mgr_overlayfs_scratch_mount_type();
+    auto scratch_device = fs_mgr_overlayfs_scratch_device();
+    auto partition_exists = fs_mgr_rw_access(scratch_device);
+    if (!partition_exists) {
+        auto slot_number = fs_mgr_overlayfs_slot_number();
+        auto super_device = fs_mgr_overlayfs_super_device(slot_number);
+        if (!fs_mgr_rw_access(super_device)) return false;
+        if (!fs_mgr_overlayfs_has_logical(fstab)) return false;
+        auto builder = MetadataBuilder::New(super_device, slot_number);
+        if (!builder) {
+            PERROR << "open " << super_device << " metadata";
+            return false;
+        }
+        const auto partition_name = android::base::Basename(kScratchMountPoint);
+        partition_exists = builder->FindPartition(partition_name) != nullptr;
+        if (!partition_exists) {
+            auto partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE);
+            if (!partition) {
+                PERROR << "create " << partition_name;
+                return false;
+            }
+            auto partition_size = builder->AllocatableSpace() - builder->UsedSpace();
+            // 512MB or half the remaining available space, whichever is greater.
+            partition_size = std::max(uint64_t(512 * 1024 * 1024), partition_size / 2);
+            if (!builder->ResizePartition(partition, partition_size)) {
+                PERROR << "resize " << partition_name;
+                return false;
+            }
+
+            auto metadata = builder->Export();
+            if (!metadata) {
+                LERROR << "generate new metadata " << partition_name;
+                return false;
+            }
+            if (!UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
+                LERROR << "update " << partition_name;
+                return false;
+            }
+
+            if (change) *change = true;
+        }
+
+        if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
+                                    &scratch_device))
+            return false;
+    }
+
+    if (partition_exists) {
+        if (fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type)) {
+            if (change) *change = true;
+            return true;
+        }
+        // partition existed, but was not initialized;
+        errno = 0;
+    }
+
+    auto ret = system((mnt_type == "f2fs")
+                              ? ((kMkF2fs + " -d1 " + scratch_device).c_str())
+                              : ((kMkExt4 + " -b 4096 -t ext4 -m 0 -M "s + kScratchMountPoint +
+                                  " -O has_journal " + scratch_device)
+                                         .c_str()));
+    if (ret) {
+        LERROR << "make " << mnt_type << " filesystem on " << scratch_device << " error=" << ret;
+        return false;
+    }
+
+    if (change) *change = true;
+
+    return fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type);
+}
+
+bool fs_mgr_overlayfs_scratch_can_be_mounted(const std::string& scratch_device) {
+    if (scratch_device.empty()) return false;
+    if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return false;
+    if (fs_mgr_rw_access(scratch_device)) return true;
+    auto slot_number = fs_mgr_overlayfs_slot_number();
+    auto super_device = fs_mgr_overlayfs_super_device(slot_number);
+    if (!fs_mgr_rw_access(super_device)) return false;
+    auto builder = MetadataBuilder::New(super_device, slot_number);
+    if (!builder) return false;
+    return builder->FindPartition(android::base::Basename(kScratchMountPoint)) != nullptr;
+}
+
 }  // namespace
 
 bool fs_mgr_overlayfs_mount_all(const fstab* fstab) {
@@ -487,14 +727,37 @@
 
     if (!fstab) return ret;
 
+    auto scratch_can_be_mounted = true;
     for (const auto& mount_point : fs_mgr_candidate_list(fstab)) {
         if (fs_mgr_overlayfs_already_mounted(mount_point)) continue;
+        if (scratch_can_be_mounted) {
+            scratch_can_be_mounted = false;
+            auto scratch_device = fs_mgr_overlayfs_scratch_device();
+            if (fs_mgr_overlayfs_scratch_can_be_mounted(scratch_device) &&
+                fs_mgr_wait_for_file(scratch_device, 10s) &&
+                fs_mgr_overlayfs_mount_scratch(scratch_device,
+                                               fs_mgr_overlayfs_scratch_mount_type()) &&
+                !fs_mgr_access(kScratchMountPoint + kOverlayTopDir)) {
+                umount2(kScratchMountPoint.c_str(), MNT_DETACH);
+                rmdir(kScratchMountPoint.c_str());
+            }
+        }
         if (fs_mgr_overlayfs_mount(mount_point)) ret = true;
     }
     return ret;
 }
 
-std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab*) {
+std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab* fstab) {
+    if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), kScratchMountPoint)) {
+        return {};
+    }
+
+    for (const auto& mount_point : fs_mgr_candidate_list(fstab)) {
+        if (fs_mgr_overlayfs_already_mounted(mount_point)) continue;
+        auto device = fs_mgr_overlayfs_scratch_device();
+        if (!fs_mgr_overlayfs_scratch_can_be_mounted(device)) break;
+        return {device};
+    }
     return {};
 }
 
@@ -503,10 +766,6 @@
 bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* change) {
     if (change) *change = false;
     auto ret = false;
-    if (backing && (kOverlayMountPoint != backing)) {
-        errno = EINVAL;
-        return ret;
-    }
     if (!fs_mgr_wants_overlayfs()) return ret;
     if (!fs_mgr_boot_completed()) {
         errno = EBUSY;
@@ -516,16 +775,32 @@
 
     std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
                                                                fs_mgr_free_fstab);
-    if (fstab && !fs_mgr_get_entry_for_mount_point(fstab.get(), kOverlayMountPoint)) return ret;
+    if (!fstab) 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 (mounts.empty()) return ret;
+
+    std::string dir;
+    for (const auto& overlay_mount_point : kOverlayMountPoints) {
+        if (backing && backing[0] && (overlay_mount_point != backing)) continue;
+        if (overlay_mount_point == kScratchMountPoint) {
+            if (!fs_mgr_rw_access(fs_mgr_overlayfs_super_device(fs_mgr_overlayfs_slot_number())) ||
+                !fs_mgr_overlayfs_has_logical(fstab.get())) {
+                continue;
+            }
+            if (!fs_mgr_overlayfs_setup_scratch(fstab.get(), change)) continue;
+        } else {
+            if (!fs_mgr_get_entry_for_mount_point(fstab.get(), overlay_mount_point)) continue;
+        }
+        dir = overlay_mount_point;
+        break;
+    }
+    if (dir.empty()) {
+        errno = ESRCH;
+        return ret;
+    }
 
     std::string overlay;
-    ret |= fs_mgr_overlayfs_setup_dir(kOverlayMountPoint, &overlay, change);
-
-    if (!fstab && mount_point && fs_mgr_overlayfs_setup_one(overlay, mount_point, change)) {
-        ret = true;
-    }
+    ret |= fs_mgr_overlayfs_setup_dir(dir, &overlay, change);
     for (const auto& fsrec_mount_point : mounts) {
         ret |= fs_mgr_overlayfs_setup_one(overlay, fsrec_mount_point, change);
     }
@@ -540,7 +815,10 @@
                                              fs_mgr_read_fstab_default(), fs_mgr_free_fstab)
                                              .get(),
                                      mount_point);
-    auto ret = fs_mgr_overlayfs_teardown_one(kOverlayMountPoint, mount_point ?: "", change);
+    auto ret = true;
+    for (const auto& overlay_mount_point : kOverlayMountPoints) {
+        ret &= fs_mgr_overlayfs_teardown_one(overlay_mount_point, mount_point ?: "", change);
+    }
     if (!fs_mgr_wants_overlayfs()) {
         // After obligatory teardown to make sure everything is clean, but if
         // we didn't want overlayfs in the the first place, we do not want to
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 506e81d..5e83cfb 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -128,10 +128,10 @@
                           FileWaitMode wait_mode = FileWaitMode::Exists);
 
 int fs_mgr_set_blk_ro(const char* blockdev);
-bool fs_mgr_update_for_slotselect(struct fstab *fstab);
+bool fs_mgr_update_for_slotselect(fstab* fstab);
 bool fs_mgr_is_device_unlocked();
 const std::string& get_android_dt_dir();
 bool is_dt_compatible();
-int load_verity_state(struct fstab_rec* fstab, int* mode);
+int load_verity_state(fstab_rec* fstab, int* mode);
 
 #endif /* __CORE_FS_MGR_PRIV_H */
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index a4544b2..5dabe76 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -51,8 +51,8 @@
 };
 
 // Callback function for verity status
-typedef void fs_mgr_verity_state_callback(struct fstab_rec* fstab, const char* mount_point,
-                                          int mode, int status);
+typedef void fs_mgr_verity_state_callback(fstab_rec* fstab, const char* mount_point, int mode,
+                                          int status);
 
 #define FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED 7
 #define FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION 6
@@ -63,32 +63,31 @@
 #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1
 #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
 #define FS_MGR_MNTALL_FAIL (-1)
-int fs_mgr_mount_all(struct fstab *fstab, int mount_mode);
+int fs_mgr_mount_all(fstab* fstab, int mount_mode);
 
 #define FS_MGR_DOMNT_FAILED (-1)
 #define FS_MGR_DOMNT_BUSY (-2)
 #define FS_MGR_DOMNT_SUCCESS 0
 
-int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
-                    char *tmp_mount_point);
-int fs_mgr_do_mount(struct fstab* fstab, const char* n_name, char* n_blk_device,
-                    char* tmp_mount_point, bool need_cp);
-int fs_mgr_do_mount_one(struct fstab_rec *rec);
+int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point);
+int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
+                    bool need_cp);
+int fs_mgr_do_mount_one(fstab_rec* rec);
 int fs_mgr_do_tmpfs_mount(const char *n_name);
-struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab);
-void fs_mgr_get_crypt_info(struct fstab* fstab, char* key_loc, char* real_blk_device, size_t size);
+fstab_rec const* fs_mgr_get_crypt_entry(fstab const* fstab);
+void fs_mgr_get_crypt_info(fstab* fstab, char* key_loc, char* real_blk_device, size_t size);
 bool fs_mgr_load_verity_state(int* mode);
 bool fs_mgr_update_verity_state(std::function<fs_mgr_verity_state_callback> callback);
 int fs_mgr_swapon_all(struct fstab *fstab);
 bool fs_mgr_update_logical_partition(struct fstab_rec* rec);
 
-int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
+int fs_mgr_do_format(fstab_rec* fstab, bool reserve_footer);
 
 #define FS_MGR_SETUP_VERITY_SKIPPED  (-3)
 #define FS_MGR_SETUP_VERITY_DISABLED (-2)
 #define FS_MGR_SETUP_VERITY_FAIL (-1)
 #define FS_MGR_SETUP_VERITY_SUCCESS 0
-int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev);
+int fs_mgr_setup_verity(fstab_rec* fstab, bool wait_for_verity_dev);
 
 // Return the name of the super partition if it exists. If a slot number is
 // specified, the super partition for the corresponding metadata slot will be
diff --git a/gatekeeperd/IGateKeeperService.cpp b/gatekeeperd/IGateKeeperService.cpp
index 1c339f4..43d5708 100644
--- a/gatekeeperd/IGateKeeperService.cpp
+++ b/gatekeeperd/IGateKeeperService.cpp
@@ -70,7 +70,7 @@
             } else {
                 reply->writeInt32(GATEKEEPER_RESPONSE_ERROR);
             }
-            return NO_ERROR;
+            return OK;
         }
         case VERIFY: {
             CHECK_INTERFACE(IGateKeeperService, data, reply);
@@ -102,7 +102,7 @@
             } else {
                 reply->writeInt32(GATEKEEPER_RESPONSE_ERROR);
             }
-            return NO_ERROR;
+            return OK;
         }
         case VERIFY_CHALLENGE: {
             CHECK_INTERFACE(IGateKeeperService, data, reply);
@@ -141,7 +141,7 @@
             } else {
                 reply->writeInt32(GATEKEEPER_RESPONSE_ERROR);
             }
-            return NO_ERROR;
+            return OK;
         }
         case GET_SECURE_USER_ID: {
             CHECK_INTERFACE(IGateKeeperService, data, reply);
@@ -149,20 +149,20 @@
             uint64_t sid = getSecureUserId(uid);
             reply->writeNoException();
             reply->writeInt64(sid);
-            return NO_ERROR;
+            return OK;
         }
         case CLEAR_SECURE_USER_ID: {
             CHECK_INTERFACE(IGateKeeperService, data, reply);
             uint32_t uid = data.readInt32();
             clearSecureUserId(uid);
             reply->writeNoException();
-            return NO_ERROR;
+            return OK;
         }
         case REPORT_DEVICE_SETUP_COMPLETE: {
             CHECK_INTERFACE(IGateKeeperService, data, reply);
             reportDeviceSetupComplete();
             reply->writeNoException();
-            return NO_ERROR;
+            return OK;
         }
         default:
             return BBinder::onTransact(code, data, reply, flags);
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index 5f3ce36..f2818f3 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -386,7 +386,7 @@
             write(fd, result, strlen(result) + 1);
         }
 
-        return NO_ERROR;
+        return OK;
     }
 
 private:
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 80c5afe..2a5667c 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -357,7 +357,7 @@
         if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
             val->valueInt64 =
                 getIntField(mHealthdConfig->batteryChargeCounterPath);
-            ret = NO_ERROR;
+            ret = OK;
         } else {
             ret = NAME_NOT_FOUND;
         }
@@ -367,7 +367,7 @@
         if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
             val->valueInt64 =
                 getIntField(mHealthdConfig->batteryCurrentNowPath);
-            ret = NO_ERROR;
+            ret = OK;
         } else {
             ret = NAME_NOT_FOUND;
         }
@@ -377,7 +377,7 @@
         if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
             val->valueInt64 =
                 getIntField(mHealthdConfig->batteryCurrentAvgPath);
-            ret = NO_ERROR;
+            ret = OK;
         } else {
             ret = NAME_NOT_FOUND;
         }
@@ -387,7 +387,7 @@
         if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
             val->valueInt64 =
                 getIntField(mHealthdConfig->batteryCapacityPath);
-            ret = NO_ERROR;
+            ret = OK;
         } else {
             ret = NAME_NOT_FOUND;
         }
@@ -403,7 +403,7 @@
 
     case BATTERY_PROP_BATTERY_STATUS:
         val->valueInt64 = getChargeStatus();
-        ret = NO_ERROR;
+        ret = OK;
         break;
 
     default:
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 866f40e..d476336 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -307,15 +307,14 @@
 
     auto shutdown_timeout = 0ms;
     if (!SHUTDOWN_ZERO_TIMEOUT) {
-        if (is_thermal_shutdown) {
-            constexpr unsigned int thermal_shutdown_timeout = 1;
-            shutdown_timeout = std::chrono::seconds(thermal_shutdown_timeout);
-        } else {
-            constexpr unsigned int shutdown_timeout_default = 6;
-            auto shutdown_timeout_property = android::base::GetUintProperty(
-                "ro.build.shutdown_timeout", shutdown_timeout_default);
-            shutdown_timeout = std::chrono::seconds(shutdown_timeout_property);
+        constexpr unsigned int shutdown_timeout_default = 6;
+        constexpr unsigned int max_thermal_shutdown_timeout = 3;
+        auto shutdown_timeout_final = android::base::GetUintProperty("ro.build.shutdown_timeout",
+                                                                     shutdown_timeout_default);
+        if (is_thermal_shutdown && shutdown_timeout_final > max_thermal_shutdown_timeout) {
+            shutdown_timeout_final = max_thermal_shutdown_timeout;
         }
+        shutdown_timeout = std::chrono::seconds(shutdown_timeout_final);
     }
     LOG(INFO) << "Shutdown timeout: " << shutdown_timeout.count() << " ms";
 
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 3be8ad0..845c586 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -131,6 +131,7 @@
 #define AID_SECURE_ELEMENT 1068  /* secure element subsystem */
 #define AID_LMKD 1069            /* low memory killer daemon */
 #define AID_LLKD 1070            /* live lock daemon */
+#define AID_IORAPD 1071          /* input/output readahead and pin daemon */
 /* Changes to this file must be made in AOSP, *not* in internal branches. */
 
 #define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/libcutils/partition_utils.cpp b/libcutils/partition_utils.cpp
index 6735d6c..2211ff6 100644
--- a/libcutils/partition_utils.cpp
+++ b/libcutils/partition_utils.cpp
@@ -25,7 +25,7 @@
 
 #include <cutils/properties.h>
 
-static int only_one_char(char *buf, int len, char c)
+static int only_one_char(uint8_t *buf, int len, uint8_t c)
 {
     int i, ret;
 
@@ -41,7 +41,7 @@
 
 int partition_wiped(char *source)
 {
-    char buf[4096];
+    uint8_t buf[4096];
     int fd, ret;
 
     if ((fd = open(source, O_RDONLY)) < 0) {
diff --git a/libpixelflinger/codeflinger/ARMAssembler.cpp b/libpixelflinger/codeflinger/ARMAssembler.cpp
index ac009a9..f47b6e4 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.cpp
+++ b/libpixelflinger/codeflinger/ARMAssembler.cpp
@@ -171,7 +171,7 @@
     }
 
     mAssembly->resize( int(pc()-base())*4 );
-    
+
     // the instruction cache is flushed by CodeCache
     const int64_t duration = ggl_system_time() - mDuration;
     const char * const format = "generated %s (%d ins) at [%p:%p] in %lld ns\n";
@@ -183,8 +183,8 @@
         printf(format, name, int(pc()-base()), base(), pc(), duration);
         disassemble(name);
     }
-    
-    return NO_ERROR;
+
+    return OK;
 }
 
 uint32_t* ARMAssembler::pcForLabel(const char* label)
@@ -213,14 +213,14 @@
 // multiply...
 void ARMAssembler::MLA(int cc, int s,
         int Rd, int Rm, int Rs, int Rn) {
-    if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; } 
+    if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
     LOG_FATAL_IF(Rd==Rm, "MLA(r%u,r%u,r%u,r%u)", Rd,Rm,Rs,Rn);
     *mPC++ =    (cc<<28) | (1<<21) | (s<<20) |
                 (Rd<<16) | (Rn<<12) | (Rs<<8) | 0x90 | Rm;
 }
 void ARMAssembler::MUL(int cc, int s,
         int Rd, int Rm, int Rs) {
-    if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; } 
+    if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
     LOG_FATAL_IF(Rd==Rm, "MUL(r%u,r%u,r%u)", Rd,Rm,Rs);
     *mPC++ = (cc<<28) | (s<<20) | (Rd<<16) | (Rs<<8) | 0x90 | Rm;
 }
@@ -577,4 +577,3 @@
 }
 
 }; // namespace android
-
diff --git a/libpixelflinger/codeflinger/Arm64Assembler.cpp b/libpixelflinger/codeflinger/Arm64Assembler.cpp
index aebc129..8926776 100644
--- a/libpixelflinger/codeflinger/Arm64Assembler.cpp
+++ b/libpixelflinger/codeflinger/Arm64Assembler.cpp
@@ -325,7 +325,7 @@
         printf(format, name, int(pc()-base()), base(), pc(), duration);
         disassemble(name);
     }
-    return NO_ERROR;
+    return OK;
 }
 
 uint32_t* ArmToArm64Assembler::pcForLabel(const char* label)
@@ -1238,4 +1238,3 @@
 }
 
 }; // namespace android
-
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.cpp b/libpixelflinger/codeflinger/MIPSAssembler.cpp
index 039a725..7de8cc1 100644
--- a/libpixelflinger/codeflinger/MIPSAssembler.cpp
+++ b/libpixelflinger/codeflinger/MIPSAssembler.cpp
@@ -1421,7 +1421,7 @@
         disassemble(name);
     }
 
-    return NO_ERROR;
+    return OK;
 }
 
 uint32_t* MIPSAssembler::pcForLabel(const char* label)
@@ -1953,5 +1953,3 @@
 
 
 }; // namespace android:
-
-
diff --git a/libsystem/include/system/camera.h b/libsystem/include/system/camera.h
index 7d79673..2ca90c3 100644
--- a/libsystem/include/system/camera.h
+++ b/libsystem/include/system/camera.h
@@ -158,8 +158,8 @@
      *
      * When any camera method returns error, the client can use ping command
      * to see if the camera has been taken away by other clients. If the result
-     * is NO_ERROR, it means the camera hardware is not released. If the result
-     * is not NO_ERROR, the camera has been released and the existing client
+     * is OK, it means the camera hardware is not released. If the result
+     * is not OK, the camera has been released and the existing client
      * can silently finish itself or show a dialog.
      */
     CAMERA_CMD_PING = 9,
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
index 430f6c5..17e2526 100644
--- a/libunwindstack/DexFiles.cpp
+++ b/libunwindstack/DexFiles.cpp
@@ -126,7 +126,7 @@
 
   const std::string dex_debug_name("__dex_debug_descriptor");
   for (MapInfo* info : *maps) {
-    if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
+    if (!(info->flags & PROT_READ) || info->offset != 0) {
       continue;
     }
 
diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp
index 0c319ec..821aacf 100644
--- a/libunwindstack/JitDebug.cpp
+++ b/libunwindstack/JitDebug.cpp
@@ -174,7 +174,7 @@
 
   const std::string descriptor_name("__jit_debug_descriptor");
   for (MapInfo* info : *maps) {
-    if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
+    if (!(info->flags & PROT_READ) || info->offset != 0) {
       continue;
     }
 
@@ -194,10 +194,9 @@
 
     Elf* elf = info->GetElf(memory_, true);
     uint64_t descriptor_addr;
-    if (elf->GetGlobalVariable(descriptor_name, &descriptor_addr)) {
-      // Search for the first non-zero entry.
-      descriptor_addr += info->start;
-      entry_addr_ = (this->*read_descriptor_func_)(descriptor_addr);
+    // Find first non-empty entry (libart might be loaded multiple times).
+    if (elf->GetGlobalVariable(descriptor_name, &descriptor_addr) && descriptor_addr != 0) {
+      entry_addr_ = (this->*read_descriptor_func_)(descriptor_addr + info->start);
       if (entry_addr_ != 0) {
         break;
       }
diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp
index d029bb0..c6d7f33 100644
--- a/libunwindstack/tests/DexFilesTest.cpp
+++ b/libunwindstack/tests/DexFilesTest.cpp
@@ -46,17 +46,17 @@
     maps_.reset(
         new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
                        "4000-6000 r--s 00000000 00:00 0\n"
-                       "6000-8000 -w-s 00000000 00:00 0\n"
-                       "a000-c000 r-xp 00000000 00:00 0\n"
-                       "c000-f000 rwxp 00000000 00:00 0\n"
-                       "f000-11000 r-xp 00000000 00:00 0\n"
+                       "6000-8000 -wxs 00000000 00:00 0\n"
+                       "a000-c000 r--p 00000000 00:00 0\n"
+                       "c000-f000 rw-p 00000000 00:00 0\n"
+                       "f000-11000 r--p 00000000 00:00 0\n"
                        "100000-110000 rw-p 0000000 00:00 0\n"
                        "200000-210000 rw-p 0000000 00:00 0\n"
                        "300000-400000 rw-p 0000000 00:00 0\n"));
     ASSERT_TRUE(maps_->Parse());
 
-    // Global variable in a section that is not readable/executable.
-    MapInfo* map_info = maps_->Get(kMapGlobalNonReadableExectable);
+    // Global variable in a section that is not readable.
+    MapInfo* map_info = maps_->Get(kMapGlobalNonReadable);
     ASSERT_TRUE(map_info != nullptr);
     MemoryFake* memory = new MemoryFake;
     ElfFake* elf = new ElfFake(memory);
@@ -95,7 +95,7 @@
   void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file);
   void WriteDex(uint64_t dex_file);
 
-  static constexpr size_t kMapGlobalNonReadableExectable = 3;
+  static constexpr size_t kMapGlobalNonReadable = 2;
   static constexpr size_t kMapGlobalSetToZero = 4;
   static constexpr size_t kMapGlobal = 5;
   static constexpr size_t kMapDexFileEntries = 7;
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index c1c45f8..66f0859 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -45,11 +45,11 @@
     maps_.reset(
         new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
                        "4000-6000 r--s 00000000 00:00 0\n"
-                       "6000-8000 -w-s 00000000 00:00 0\n"
+                       "6000-8000 -wxs 00000000 00:00 0\n"
                        "a000-c000 --xp 00000000 00:00 0\n"
-                       "c000-f000 rwxp 00000000 00:00 0\n"
-                       "f000-11000 r-xp 00000000 00:00 0\n"
-                       "12000-14000 r-xp 00000000 00:00 0\n"
+                       "c000-f000 rw-p 00000000 00:00 0\n"
+                       "f000-11000 r--p 00000000 00:00 0\n"
+                       "12000-14000 r--p 00000000 00:00 0\n"
                        "100000-110000 rw-p 0000000 00:00 0\n"
                        "200000-210000 rw-p 0000000 00:00 0\n"));
     ASSERT_TRUE(maps_->Parse());
diff --git a/libutils/PropertyMap.cpp b/libutils/PropertyMap.cpp
index b8c065d..f00272a 100644
--- a/libutils/PropertyMap.cpp
+++ b/libutils/PropertyMap.cpp
@@ -208,7 +208,7 @@
 
         mTokenizer->nextLine();
     }
-    return NO_ERROR;
+    return OK;
 }
 
 } // namespace android
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 5c0b406..818b171 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -157,12 +157,12 @@
     if (begin >= N) {
         SharedBuffer::bufferFromData(mString)->release();
         mString = getEmptyString();
-        return NO_ERROR;
+        return OK;
     }
     if ((begin+len) > N) len = N-begin;
     if (begin == 0 && len == N) {
         setTo(other);
-        return NO_ERROR;
+        return OK;
     }
 
     if (&other == this) {
@@ -191,7 +191,7 @@
         memmove(str, other, len*sizeof(char16_t));
         str[len] = 0;
         mString = str;
-        return NO_ERROR;
+        return OK;
     }
     return NO_MEMORY;
 }
@@ -202,9 +202,9 @@
     const size_t otherLen = other.size();
     if (myLen == 0) {
         setTo(other);
-        return NO_ERROR;
+        return OK;
     } else if (otherLen == 0) {
-        return NO_ERROR;
+        return OK;
     }
 
     if (myLen >= SIZE_MAX / sizeof(char16_t) - otherLen) {
@@ -218,7 +218,7 @@
         char16_t* str = (char16_t*)buf->data();
         memcpy(str+myLen, other, (otherLen+1)*sizeof(char16_t));
         mString = str;
-        return NO_ERROR;
+        return OK;
     }
     return NO_MEMORY;
 }
@@ -228,9 +228,9 @@
     const size_t myLen = size();
     if (myLen == 0) {
         setTo(chrs, otherLen);
-        return NO_ERROR;
+        return OK;
     } else if (otherLen == 0) {
-        return NO_ERROR;
+        return OK;
     }
 
     if (myLen >= SIZE_MAX / sizeof(char16_t) - otherLen) {
@@ -245,7 +245,7 @@
         memcpy(str+myLen, chrs, otherLen*sizeof(char16_t));
         str[myLen+otherLen] = 0;
         mString = str;
-        return NO_ERROR;
+        return OK;
     }
     return NO_MEMORY;
 }
@@ -260,9 +260,9 @@
     const size_t myLen = size();
     if (myLen == 0) {
         return setTo(chrs, len);
-        return NO_ERROR;
+        return OK;
     } else if (len == 0) {
-        return NO_ERROR;
+        return OK;
     }
 
     if (pos > myLen) pos = myLen;
@@ -286,7 +286,7 @@
         #if 0
         printf("Result (%d chrs): %s\n", size(), String8(*this).string());
         #endif
-        return NO_ERROR;
+        return OK;
     }
     return NO_MEMORY;
 }
@@ -357,7 +357,7 @@
             edit[i] = tolower((char)v);
         }
     }
-    return NO_ERROR;
+    return OK;
 }
 
 status_t String16::replaceAll(char16_t replaceThis, char16_t withThis)
@@ -378,7 +378,7 @@
             edit[i] = withThis;
         }
     }
-    return NO_ERROR;
+    return OK;
 }
 
 status_t String16::remove(size_t len, size_t begin)
@@ -387,11 +387,11 @@
     if (begin >= N) {
         SharedBuffer::bufferFromData(mString)->release();
         mString = getEmptyString();
-        return NO_ERROR;
+        return OK;
     }
     if ((begin+len) > N) len = N-begin;
     if (begin == 0 && len == N) {
-        return NO_ERROR;
+        return OK;
     }
 
     if (begin > 0) {
@@ -410,7 +410,7 @@
         char16_t* str = (char16_t*)buf->data();
         str[len] = 0;
         mString = str;
-        return NO_ERROR;
+        return OK;
     }
     return NO_MEMORY;
 }
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 8d318f7..0025c56 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -230,7 +230,7 @@
     const char *newString = allocFromUTF8(other, strlen(other));
     SharedBuffer::bufferFromData(mString)->release();
     mString = newString;
-    if (mString) return NO_ERROR;
+    if (mString) return OK;
 
     mString = getEmptyString();
     return NO_MEMORY;
@@ -241,7 +241,7 @@
     const char *newString = allocFromUTF8(other, len);
     SharedBuffer::bufferFromData(mString)->release();
     mString = newString;
-    if (mString) return NO_ERROR;
+    if (mString) return OK;
 
     mString = getEmptyString();
     return NO_MEMORY;
@@ -252,7 +252,7 @@
     const char *newString = allocFromUTF16(other, len);
     SharedBuffer::bufferFromData(mString)->release();
     mString = newString;
-    if (mString) return NO_ERROR;
+    if (mString) return OK;
 
     mString = getEmptyString();
     return NO_MEMORY;
@@ -263,7 +263,7 @@
     const char *newString = allocFromUTF32(other, len);
     SharedBuffer::bufferFromData(mString)->release();
     mString = newString;
-    if (mString) return NO_ERROR;
+    if (mString) return OK;
 
     mString = getEmptyString();
     return NO_MEMORY;
@@ -274,9 +274,9 @@
     const size_t otherLen = other.bytes();
     if (bytes() == 0) {
         setTo(other);
-        return NO_ERROR;
+        return OK;
     } else if (otherLen == 0) {
-        return NO_ERROR;
+        return OK;
     }
 
     return real_append(other.string(), otherLen);
@@ -292,7 +292,7 @@
     if (bytes() == 0) {
         return setTo(other, otherLen);
     } else if (otherLen == 0) {
-        return NO_ERROR;
+        return OK;
     }
 
     return real_append(other, otherLen);
@@ -311,7 +311,7 @@
 
 status_t String8::appendFormatV(const char* fmt, va_list args)
 {
-    int n, result = NO_ERROR;
+    int n, result = OK;
     va_list tmp_args;
 
     /* args is undefined after vsnprintf.
@@ -346,7 +346,7 @@
         str += myLen;
         memcpy(str, other, otherLen);
         str[otherLen] = '\0';
-        return NO_ERROR;
+        return OK;
     }
     return NO_MEMORY;
 }
@@ -382,7 +382,7 @@
         mString = str;
     }
 
-    return NO_ERROR;
+    return OK;
 }
 
 ssize_t String8::find(const char* other, size_t start) const
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 43ec6c1..64bc402 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -379,7 +379,7 @@
 {
     DWORD dwWaitResult;
     dwWaitResult = WaitForSingleObject((HANDLE) mState, INFINITE);
-    return dwWaitResult != WAIT_OBJECT_0 ? -1 : NO_ERROR;
+    return dwWaitResult != WAIT_OBJECT_0 ? -1 : OK;
 }
 
 void Mutex::unlock()
@@ -506,7 +506,7 @@
         ReleaseMutex(condState->internalMutex);
         WaitForSingleObject(hMutex, INFINITE);
 
-        return res == WAIT_OBJECT_0 ? NO_ERROR : -1;
+        return res == WAIT_OBJECT_0 ? OK : -1;
     }
 } WinCondition;
 
@@ -639,13 +639,15 @@
  */
 
 Thread::Thread(bool canCallJava)
-    :   mCanCallJava(canCallJava),
-        mThread(thread_id_t(-1)),
-        mLock("Thread::mLock"),
-        mStatus(NO_ERROR),
-        mExitPending(false), mRunning(false)
+    : mCanCallJava(canCallJava),
+      mThread(thread_id_t(-1)),
+      mLock("Thread::mLock"),
+      mStatus(OK),
+      mExitPending(false),
+      mRunning(false)
 #if defined(__ANDROID__)
-        , mTid(-1)
+      ,
+      mTid(-1)
 #endif
 {
 }
@@ -656,7 +658,7 @@
 
 status_t Thread::readyToRun()
 {
-    return NO_ERROR;
+    return OK;
 }
 
 status_t Thread::run(const char* name, int32_t priority, size_t stack)
@@ -672,7 +674,7 @@
 
     // reset status and exitPending to their default value, so we can
     // try again after an error happened (either below, or in readyToRun())
-    mStatus = NO_ERROR;
+    mStatus = OK;
     mExitPending = false;
     mThread = thread_id_t(-1);
 
@@ -700,10 +702,10 @@
     }
 
     // Do not refer to mStatus here: The thread is already running (may, in fact
-    // already have exited with a valid mStatus result). The NO_ERROR indication
+    // already have exited with a valid mStatus result). The OK indication
     // here merely indicates successfully starting the thread and does not
     // imply successful termination/execution.
-    return NO_ERROR;
+    return OK;
 
     // Exiting scope of mLock is a memory barrier and allows new thread to run
 }
@@ -728,7 +730,7 @@
         if (first) {
             first = false;
             self->mStatus = self->readyToRun();
-            result = (self->mStatus == NO_ERROR);
+            result = (self->mStatus == OK);
 
             if (result && !self->exitPending()) {
                 // Binder threads (and maybe others) rely on threadLoop
diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp
index f73d699..98dd2fd 100644
--- a/libutils/Tokenizer.cpp
+++ b/libutils/Tokenizer.cpp
@@ -48,7 +48,7 @@
 status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) {
     *outTokenizer = nullptr;
 
-    int result = NO_ERROR;
+    int result = OK;
     int fd = ::open(filename.string(), O_RDONLY);
     if (fd < 0) {
         result = -errno;
diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp
index e16f88d..c97a19b 100644
--- a/libutils/VectorImpl.cpp
+++ b/libutils/VectorImpl.cpp
@@ -61,7 +61,7 @@
         "[%p] subclasses of VectorImpl must call finish_vector()"
         " in their destructor. Leaking %d bytes.",
         this, (int)(mCount*mItemSize));
-    // We can't call _do_destroy() here because the vtable is already gone. 
+    // We can't call _do_destroy() here because the vtable is already gone.
 }
 
 VectorImpl& VectorImpl::operator = (const VectorImpl& rhs)
@@ -197,7 +197,7 @@
                 _do_copy(temp, item, 1);
 
                 ssize_t j = i-1;
-                void* next = reinterpret_cast<char*>(array) + mItemSize*(i);                    
+                void* next = reinterpret_cast<char*>(array) + mItemSize*(i);
                 do {
                     _do_destroy(next, 1);
                     _do_copy(next, curr, 1);
@@ -214,13 +214,13 @@
             }
             i++;
         }
-        
+
         if (temp) {
             _do_destroy(temp, 1);
             free(temp);
         }
     }
-    return NO_ERROR;
+    return OK;
 }
 
 void VectorImpl::pop()
@@ -354,7 +354,7 @@
 }
 
 ssize_t VectorImpl::resize(size_t size) {
-    ssize_t result = NO_ERROR;
+    ssize_t result = OK;
     if (size > mCount) {
         result = insertAt(mCount, size - mCount);
     } else if (size < mCount) {
@@ -370,7 +370,7 @@
         if (sb->release(SharedBuffer::eKeepStorage) == 1) {
             _do_destroy(mStorage, mCount);
             SharedBuffer::dealloc(sb);
-        } 
+        }
     }
 }
 
@@ -644,13 +644,13 @@
             }
         }
     }
-    return NO_ERROR;
+    return OK;
 }
 
 ssize_t SortedVectorImpl::merge(const SortedVectorImpl& vector)
 {
     // we've merging a sorted vector... nice!
-    ssize_t err = NO_ERROR;
+    ssize_t err = OK;
     if (!vector.isEmpty()) {
         // first take care of the case where the vectors are sorted together
         if (do_compare(vector.itemLocation(vector.size()-1), arrayImpl()) <= 0) {
@@ -677,4 +677,3 @@
 /*****************************************************************************/
 
 }; // namespace android
-
diff --git a/libutils/include/utils/Errors.h b/libutils/include/utils/Errors.h
index 7093a20..7aafe42 100644
--- a/libutils/include/utils/Errors.h
+++ b/libutils/include/utils/Errors.h
@@ -43,8 +43,8 @@
 #endif
 
 enum {
-    OK                = 0,    // Everything's swell.
-    NO_ERROR          = 0,    // No errors.
+    OK                = 0,    // Preferred constant for checking success.
+    NO_ERROR          = OK,   // Deprecated synonym for `OK`. Prefer `OK` because it doesn't conflict with Windows.
 
     UNKNOWN_ERROR       = (-2147483647-1), // INT32_MIN value
 
diff --git a/libutils/include/utils/Flattenable.h b/libutils/include/utils/Flattenable.h
index 0a19019..9d00602 100644
--- a/libutils/include/utils/Flattenable.h
+++ b/libutils/include/utils/Flattenable.h
@@ -190,11 +190,11 @@
     inline status_t flatten(void* buffer, size_t size) const {
         if (size < sizeof(T)) return NO_MEMORY;
         memcpy(buffer, static_cast<T const*>(this), sizeof(T));
-        return NO_ERROR;
+        return OK;
     }
     inline status_t unflatten(void const* buffer, size_t) {
         memcpy(static_cast<T*>(this), buffer, sizeof(T));
-        return NO_ERROR;
+        return OK;
     }
 };
 
diff --git a/libutils/include/utils/Functor.h b/libutils/include/utils/Functor.h
index c0c8d57..c458699 100644
--- a/libutils/include/utils/Functor.h
+++ b/libutils/include/utils/Functor.h
@@ -29,7 +29,7 @@
 public:
     Functor() {}
     virtual ~Functor() {}
-    virtual status_t operator ()(int /*what*/, void* /*data*/) { return NO_ERROR; }
+    virtual status_t operator()(int /*what*/, void* /*data*/) { return OK; }
 };
 
 }  // namespace android
diff --git a/libutils/include/utils/Tokenizer.h b/libutils/include/utils/Tokenizer.h
index bb25f37..61c5ff7 100644
--- a/libutils/include/utils/Tokenizer.h
+++ b/libutils/include/utils/Tokenizer.h
@@ -37,7 +37,7 @@
     /**
      * Opens a file and maps it into memory.
      *
-     * Returns NO_ERROR and a tokenizer for the file, if successful.
+     * Returns OK and a tokenizer for the file, if successful.
      * Otherwise returns an error and sets outTokenizer to NULL.
      */
     static status_t open(const String8& filename, Tokenizer** outTokenizer);
@@ -45,7 +45,7 @@
     /**
      * Prepares to tokenize the contents of a string.
      *
-     * Returns NO_ERROR and a tokenizer for the string, if successful.
+     * Returns OK and a tokenizer for the string, if successful.
      * Otherwise returns an error and sets outTokenizer to NULL.
      */
     static status_t fromContents(const String8& filename,
diff --git a/llkd/include/llkd.h b/llkd/include/llkd.h
index c724fce..1e2df2f 100644
--- a/llkd/include/llkd.h
+++ b/llkd/include/llkd.h
@@ -57,7 +57,7 @@
 #define LLK_BLACKLIST_UID_PROPERTY     "ro.llk.blacklist.uid"
 #define LLK_BLACKLIST_UID_DEFAULT      ""
 #define LLK_BLACKLIST_STACK_PROPERTY   "ro.llk.blacklist.process.stack"
-#define LLK_BLACKLIST_STACK_DEFAULT    "init,lmkd.llkd,llkd,keystore,/system/bin/keystore"
+#define LLK_BLACKLIST_STACK_DEFAULT    "init,lmkd.llkd,llkd,keystore,/system/bin/keystore,ueventd"
 /* clang-format on */
 
 __END_DECLS
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 6a6a8f9..9aaad8f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -398,6 +398,10 @@
     class_start early_hal
 
 on post-fs-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
     chown system system /data
     chmod 0771 /data
@@ -405,8 +409,6 @@
     restorecon /data
 
     # Make sure we have the device encryption key.
-    start vold
-    exec - system system -- /system/bin/vdc checkpoint prepareDriveForCheckpoint /data
     installkey /data
 
     # Start bootcharting as soon as possible after the data partition is
diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp
index 17ea25b..45f1d4d 100644
--- a/storaged/storaged_service.cpp
+++ b/storaged/storaged_service.cpp
@@ -161,7 +161,7 @@
         storaged_sp->update_uid_io_interval(time_window);
     }
 
-    return NO_ERROR;
+    return OK;
 }
 
 binder::Status StoragedService::onUserStarted(int32_t userId) {
diff --git a/storaged/uid_info.cpp b/storaged/uid_info.cpp
index 58e3fd2..0f718de 100644
--- a/storaged/uid_info.cpp
+++ b/storaged/uid_info.cpp
@@ -32,7 +32,7 @@
         parcel->writeCString(task_it.second.comm.c_str());
         parcel->write(&task_it.second.io, sizeof(task_it.second.io));
     }
-    return NO_ERROR;
+    return OK;
 }
 
 status_t UidInfo::readFromParcel(const Parcel* parcel) {
@@ -48,5 +48,5 @@
         parcel->read(&task.io, sizeof(task.io));
         tasks[task.pid] = task;
     }
-    return NO_ERROR;
+    return OK;
 }