Merge "Assert that ParseInt/ParseUint are only used with signed/unsigned numbers respectively"
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/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
index b40faee..fe79acd 100644
--- a/adb/daemon/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -212,6 +212,7 @@
 
 static void jdwp_process_event(int socket, unsigned events, void* _proc) {
     JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc);
+    CHECK_EQ(socket, proc->socket);
 
     if (events & FDE_READ) {
         if (proc->pid < 0) {
@@ -225,82 +226,50 @@
             D("Adding pid %d to jdwp process list", proc->pid);
             jdwp_process_list_updated();
         } else {
-            /* the pid was read, if we get there it's probably because the connection
-             * was closed (e.g. the JDWP process exited or crashed) */
-            char buf[32];
-
-            while (true) {
-                int len = TEMP_FAILURE_RETRY(recv(socket, buf, sizeof(buf), 0));
-
-                if (len == 0) {
-                    D("terminating JDWP %d connection: EOF", proc->pid);
-                    break;
-                } else if (len < 0) {
-                    if (len < 0 && errno == EAGAIN) {
-                        return;
-                    }
-
-                    D("terminating JDWP %d connection: EOF", proc->pid);
-                    break;
-                } else {
-                    D("ignoring unexpected JDWP %d control socket activity (%d bytes)", proc->pid,
-                      len);
-                }
-            }
-
+            // We already have the PID, if we can read from the socket, we've probably hit EOF.
+            D("terminating JDWP connection %d", proc->pid);
             goto CloseProcess;
         }
     }
 
     if (events & FDE_WRITE) {
         D("trying to send fd to JDWP process (count = %zu)", proc->out_fds.size());
-        if (!proc->out_fds.empty()) {
-            int fd = proc->out_fds.back().get();
-            struct cmsghdr* cmsg;
-            struct msghdr msg;
-            struct iovec iov;
-            char dummy = '!';
-            char buffer[sizeof(struct cmsghdr) + sizeof(int)];
+        CHECK(!proc->out_fds.empty());
 
-            iov.iov_base = &dummy;
-            iov.iov_len = 1;
-            msg.msg_name = nullptr;
-            msg.msg_namelen = 0;
-            msg.msg_iov = &iov;
-            msg.msg_iovlen = 1;
-            msg.msg_flags = 0;
-            msg.msg_control = buffer;
-            msg.msg_controllen = sizeof(buffer);
+        int fd = proc->out_fds.back().get();
+        struct cmsghdr* cmsg;
+        struct msghdr msg;
+        struct iovec iov;
+        char dummy = '!';
+        char buffer[sizeof(struct cmsghdr) + sizeof(int)];
 
-            cmsg = CMSG_FIRSTHDR(&msg);
-            cmsg->cmsg_len = msg.msg_controllen;
-            cmsg->cmsg_level = SOL_SOCKET;
-            cmsg->cmsg_type = SCM_RIGHTS;
-            ((int*)CMSG_DATA(cmsg))[0] = fd;
+        iov.iov_base = &dummy;
+        iov.iov_len = 1;
+        msg.msg_name = nullptr;
+        msg.msg_namelen = 0;
+        msg.msg_iov = &iov;
+        msg.msg_iovlen = 1;
+        msg.msg_flags = 0;
+        msg.msg_control = buffer;
+        msg.msg_controllen = sizeof(buffer);
 
-            if (!set_file_block_mode(proc->socket, true)) {
-                VLOG(JDWP) << "failed to set blocking mode for fd " << proc->socket;
-                goto CloseProcess;
-            }
+        cmsg = CMSG_FIRSTHDR(&msg);
+        cmsg->cmsg_len = msg.msg_controllen;
+        cmsg->cmsg_level = SOL_SOCKET;
+        cmsg->cmsg_type = SCM_RIGHTS;
+        ((int*)CMSG_DATA(cmsg))[0] = fd;
 
-            int ret = TEMP_FAILURE_RETRY(sendmsg(proc->socket, &msg, 0));
-            if (ret < 0) {
-                D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno));
-                goto CloseProcess;
-            }
+        int ret = TEMP_FAILURE_RETRY(sendmsg(socket, &msg, 0));
+        if (ret < 0) {
+            D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno));
+            goto CloseProcess;
+        }
 
-            D("sent file descriptor %d to JDWP process %d", fd, proc->pid);
+        D("sent file descriptor %d to JDWP process %d", fd, proc->pid);
 
-            proc->out_fds.pop_back();
-
-            if (!set_file_block_mode(proc->socket, false)) {
-                VLOG(JDWP) << "failed to set non-blocking mode for fd " << proc->socket;
-                goto CloseProcess;
-            }
-
-            if (proc->out_fds.empty()) {
-                fdevent_del(proc->fde, FDE_WRITE);
-            }
+        proc->out_fds.pop_back();
+        if (proc->out_fds.empty()) {
+            fdevent_del(proc->fde, FDE_WRITE);
         }
     }
 
@@ -406,9 +375,10 @@
     return 0;
 }
 
-static void jdwp_control_event(int s, unsigned events, void* _control) {
+static void jdwp_control_event(int fd, unsigned events, void* _control) {
     JdwpControl* control = (JdwpControl*)_control;
 
+    CHECK_EQ(fd, control->listen_socket);
     if (events & FDE_READ) {
         int s = adb_socket_accept(control->listen_socket, nullptr, nullptr);
         if (s < 0) {
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index 2bac486..720ec6a 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -202,6 +202,27 @@
     return StartSubprocess(command.c_str(), terminal_type.c_str(), type, protocol);
 }
 
+static void spin_service(unique_fd fd) {
+    if (!__android_log_is_debuggable()) {
+        WriteFdExactly(fd.get(), "refusing to spin on non-debuggable build\n");
+        return;
+    }
+
+    // A service that creates an fdevent that's always pending, and then ignores it.
+    unique_fd pipe_read, pipe_write;
+    if (!Pipe(&pipe_read, &pipe_write)) {
+        WriteFdExactly(fd.get(), "failed to create pipe\n");
+        return;
+    }
+
+    fdevent_run_on_main_thread([fd = pipe_read.release()]() {
+        fdevent* fde = fdevent_create(fd, [](int, unsigned, void*) {}, nullptr);
+        fdevent_add(fde, FDE_READ);
+    });
+
+    WriteFdExactly(fd.get(), "spinning\n");
+}
+
 unique_fd daemon_service_to_fd(const char* name, atransport* transport) {
     if (!strncmp("dev:", name, 4)) {
         return unique_fd{unix_open(name + 4, O_RDWR | O_CLOEXEC)};
@@ -254,6 +275,9 @@
     } else if (!strcmp(name, "reconnect")) {
         return create_service_thread(
                 "reconnect", std::bind(reconnect_service, std::placeholders::_1, transport));
+    } else if (!strcmp(name, "spin")) {
+        return create_service_thread("spin", spin_service);
     }
+
     return unique_fd{};
 }
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 98a73eb..e096560 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -35,6 +35,8 @@
 #include <unordered_map>
 #include <vector>
 
+#include <android-base/chrono_utils.h>
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/thread_annotations.h>
@@ -44,6 +46,7 @@
 #include "adb_trace.h"
 #include "adb_unique_fd.h"
 #include "adb_utils.h"
+#include "sysdeps/chrono.h"
 
 #define FDE_EVENTMASK  0x00ff
 #define FDE_STATEMASK  0xff00
@@ -247,6 +250,7 @@
     }
     CHECK_GT(pollfds.size(), 0u);
     D("poll(), pollfds = %s", dump_pollfds(pollfds).c_str());
+
     int ret = adb_poll(&pollfds[0], pollfds.size(), -1);
     if (ret == -1) {
         PLOG(ERROR) << "poll(), ret = " << ret;
@@ -367,10 +371,66 @@
     }
 }
 
+static void fdevent_check_spin(uint64_t cycle) {
+    // Check to see if we're spinning because we forgot about an fdevent
+    // by keeping track of how long fdevents have been continuously pending.
+    struct SpinCheck {
+        fdevent* fde;
+        android::base::boot_clock::time_point timestamp;
+        uint64_t cycle;
+    };
+    static auto& g_continuously_pending = *new std::unordered_map<uint64_t, SpinCheck>();
+    static auto last_cycle = android::base::boot_clock::now();
+
+    auto now = android::base::boot_clock::now();
+    if (now - last_cycle > 10ms) {
+        // We're not spinning.
+        g_continuously_pending.clear();
+        last_cycle = now;
+        return;
+    }
+    last_cycle = now;
+
+    for (auto* fde : g_pending_list) {
+        auto it = g_continuously_pending.find(fde->id);
+        if (it == g_continuously_pending.end()) {
+            g_continuously_pending[fde->id] =
+                    SpinCheck{.fde = fde, .timestamp = now, .cycle = cycle};
+        } else {
+            it->second.cycle = cycle;
+        }
+    }
+
+    for (auto it = g_continuously_pending.begin(); it != g_continuously_pending.end();) {
+        if (it->second.cycle != cycle) {
+            it = g_continuously_pending.erase(it);
+        } else {
+            // Use an absurdly long window, since all we really care about is
+            // getting a bugreport eventually.
+            if (now - it->second.timestamp > 300s) {
+                LOG(FATAL_WITHOUT_ABORT)
+                        << "detected spin in fdevent: " << dump_fde(it->second.fde);
+#if defined(__linux__)
+                int fd = it->second.fde->fd.get();
+                std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
+                std::string path;
+                if (!android::base::Readlink(fd_path, &path)) {
+                    PLOG(FATAL_WITHOUT_ABORT) << "readlink of fd " << fd << " failed";
+                }
+                LOG(FATAL_WITHOUT_ABORT) << "fd " << fd << " = " << path;
+#endif
+                abort();
+            }
+            ++it;
+        }
+    }
+}
+
 void fdevent_loop() {
     set_main_thread();
     fdevent_run_setup();
 
+    uint64_t cycle = 0;
     while (true) {
         if (terminate_loop) {
             return;
@@ -380,6 +440,8 @@
 
         fdevent_process();
 
+        fdevent_check_spin(cycle++);
+
         while (!g_pending_list.empty()) {
             fdevent* fde = g_pending_list.front();
             g_pending_list.pop_front();
diff --git a/fastboot/constants.h b/fastboot/constants.h
index 2eaf006..705da33 100644
--- a/fastboot/constants.h
+++ b/fastboot/constants.h
@@ -63,3 +63,4 @@
 #define FB_VAR_VARIANT "variant"
 #define FB_VAR_OFF_MODE_CHARGE_STATE "off-mode-charge"
 #define FB_VAR_BATTERY_VOLTAGE "battery-voltage"
+#define FB_VAR_BATTERY_SOC_OK "battery-soc-ok"
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 6c0aba1..b3fce54 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -98,6 +98,7 @@
             {FB_VAR_IS_USERSPACE, {GetIsUserspace, nullptr}},
             {FB_VAR_OFF_MODE_CHARGE_STATE, {GetOffModeChargeState, nullptr}},
             {FB_VAR_BATTERY_VOLTAGE, {GetBatteryVoltage, nullptr}},
+            {FB_VAR_BATTERY_SOC_OK, {GetBatterySoCOk, nullptr}},
             {FB_VAR_HW_REVISION, {GetHardwareRevision, nullptr}}};
 
     if (args.size() < 2) {
@@ -130,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");
@@ -162,6 +168,12 @@
     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)) {
@@ -202,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)) {
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 01415d7..2de79b1 100644
--- a/fastboot/device/variables.cpp
+++ b/fastboot/device/variables.cpp
@@ -96,6 +96,56 @@
     return true;
 }
 
+bool GetBatteryVoltageHelper(FastbootDevice* device, int32_t* battery_voltage) {
+    using android::hardware::health::V2_0::HealthInfo;
+    using android::hardware::health::V2_0::Result;
+
+    auto health_hal = device->health_hal();
+    if (!health_hal) {
+        return false;
+    }
+
+    Result ret;
+    auto ret_val = health_hal->getHealthInfo([&](Result result, HealthInfo info) {
+        *battery_voltage = info.legacy.batteryVoltage;
+        ret = result;
+    });
+    if (!ret_val.isOk() || (ret != Result::SUCCESS)) {
+        return false;
+    }
+
+    return true;
+}
+
+bool GetBatterySoCOk(FastbootDevice* device, const std::vector<std::string>& /* args */,
+                     std::string* message) {
+    int32_t battery_voltage = 0;
+    if (!GetBatteryVoltageHelper(device, &battery_voltage)) {
+        *message = "Unable to read battery voltage";
+        return false;
+    }
+
+    auto fastboot_hal = device->fastboot_hal();
+    if (!fastboot_hal) {
+        *message = "Fastboot HAL not found";
+        return false;
+    }
+
+    Result ret;
+    auto ret_val = fastboot_hal->getBatteryVoltageFlashingThreshold(
+            [&](int32_t voltage_threshold, Result result) {
+                *message = battery_voltage >= voltage_threshold ? "yes" : "no";
+                ret = result;
+            });
+
+    if (!ret_val.isOk() || ret.status != Status::SUCCESS) {
+        *message = "Unable to get battery voltage flashing threshold";
+        return false;
+    }
+
+    return true;
+}
+
 bool GetOffModeChargeState(FastbootDevice* device, const std::vector<std::string>& /* args */,
                            std::string* message) {
     auto fastboot_hal = device->fastboot_hal();
@@ -120,26 +170,13 @@
 
 bool GetBatteryVoltage(FastbootDevice* device, const std::vector<std::string>& /* args */,
                        std::string* message) {
-    using android::hardware::health::V2_0::HealthInfo;
-    using android::hardware::health::V2_0::Result;
-
-    auto health_hal = device->health_hal();
-    if (!health_hal) {
-        *message = "Health HAL not found";
-        return false;
+    int32_t battery_voltage = 0;
+    if (GetBatteryVoltageHelper(device, &battery_voltage)) {
+        *message = std::to_string(battery_voltage);
+        return true;
     }
-
-    Result ret;
-    auto ret_val = health_hal->getHealthInfo([&](Result result, HealthInfo info) {
-        *message = std::to_string(info.legacy.batteryVoltage);
-        ret = result;
-    });
-    if (!ret_val.isOk() || (ret != Result::SUCCESS)) {
-        *message = "Unable to get battery voltage";
-        return false;
-    }
-
-    return true;
+    *message = "Unable to get battery voltage";
+    return false;
 }
 
 bool GetCurrentSlot(FastbootDevice* device, const std::vector<std::string>& /* args */,
diff --git a/fastboot/device/variables.h b/fastboot/device/variables.h
index e7c3c7c..59b71e8 100644
--- a/fastboot/device/variables.h
+++ b/fastboot/device/variables.h
@@ -57,6 +57,9 @@
                            std::string* message);
 bool GetBatteryVoltage(FastbootDevice* device, const std::vector<std::string>& args,
                        std::string* message);
+bool GetBatterySoCOk(FastbootDevice* device, const std::vector<std::string>& args,
+                     std::string* message);
+
 // Helpers for getvar all.
 std::vector<std::vector<std::string>> GetAllPartitionArgsWithSlot(FastbootDevice* device);
 std::vector<std::vector<std::string>> GetAllPartitionArgsNoSlot(FastbootDevice* device);
diff --git a/fastboot/fuzzy_fastboot/fixtures.cpp b/fastboot/fuzzy_fastboot/fixtures.cpp
index c18af1d..280cfb6 100644
--- a/fastboot/fuzzy_fastboot/fixtures.cpp
+++ b/fastboot/fuzzy_fastboot/fixtures.cpp
@@ -86,6 +86,12 @@
     return true;
 }
 
+bool FastBootTest::UserSpaceFastboot() {
+    std::string value;
+    fb->GetVar("is-userspace", &value);
+    return value == "yes";
+}
+
 RetCode FastBootTest::DownloadCommand(uint32_t size, std::string* response,
                                       std::vector<std::string>* info) {
     return fb->DownloadCommand(size, response, info);
@@ -158,6 +164,12 @@
         return;
     }
 
+    // User space fastboot implementations are not allowed to communicate to
+    // secure hardware and hence cannot lock/unlock the device.
+    if (UserSpaceFastboot()) {
+        return;
+    }
+
     std::string resp;
     std::vector<std::string> info;
     // To avoid risk of bricking device, make sure unlock ability is set to 1
diff --git a/fastboot/fuzzy_fastboot/fixtures.h b/fastboot/fuzzy_fastboot/fixtures.h
index e47d0fd..e0f829e 100644
--- a/fastboot/fuzzy_fastboot/fixtures.h
+++ b/fastboot/fuzzy_fastboot/fixtures.h
@@ -47,6 +47,7 @@
 
     static int MatchFastboot(usb_ifc_info* info, const char* local_serial = nullptr);
     bool UsbStillAvailible();
+    bool UserSpaceFastboot();
 
   protected:
     RetCode DownloadCommand(uint32_t size, std::string* response = nullptr,
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index 90a2e74..e2076f5 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -289,6 +289,12 @@
 TEST_F(Conformance, UnlockAbility) {
     std::string resp;
     std::vector<std::string> info;
+    // Userspace fastboot implementations do not have a way to get this
+    // information.
+    if (UserSpaceFastboot()) {
+        GTEST_LOG_(INFO) << "This test is skipped for userspace fastboot.";
+        return;
+    }
     EXPECT_EQ(fb->RawCommand("flashing get_unlock_ability", &resp, &info), SUCCESS)
             << "'flashing get_unlock_ability' failed";
     // There are two ways this can be reported, through info or the actual response
@@ -412,6 +418,10 @@
     ASSERT_TRUE(resp == "yes" || resp == "no")
             << "Device did not respond with 'yes' or 'no' for getvar:unlocked";
     bool curr = resp == "yes";
+    if (UserSpaceFastboot()) {
+        GTEST_LOG_(INFO) << "This test is skipped for userspace fastboot.";
+        return;
+    }
 
     for (int i = 0; i < 2; i++) {
         std::string action = !curr ? "unlock" : "lock";
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 3ab9732..7f9d9a4 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>
@@ -1500,16 +1501,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 +1519,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 +1536,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 1edd573..95326d1 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -177,9 +177,16 @@
     return "/system";
 }
 
+bool fs_mgr_access(const std::string& path) {
+    auto save_errno = errno;
+    auto ret = access(path.c_str(), F_OK) == 0;
+    errno = save_errno;
+    return ret;
+}
+
 // return true if system supports overlayfs
 bool fs_mgr_wants_overlayfs() {
-    // This will return empty on init first_stage_mount, so speculative
+    // Properties will return empty on init first_stage_mount, so speculative
     // determination, empty (unset) _or_ "1" is true which differs from the
     // official ro.debuggable policy.  ALLOW_ADBD_DISABLE_VERITY == 0 should
     // protect us from false in any case, so this is insurance.
@@ -187,13 +194,7 @@
     if (debuggable != "1") return false;
 
     // Overlayfs available in the kernel, and patched for override_creds?
-    static signed char overlayfs_in_kernel = -1;  // cache for constant condition
-    if (overlayfs_in_kernel == -1) {
-        auto save_errno = errno;
-        overlayfs_in_kernel = !access("/sys/module/overlay/parameters/override_creds", F_OK);
-        errno = save_errno;
-    }
-    return overlayfs_in_kernel;
+    return fs_mgr_access("/sys/module/overlay/parameters/override_creds");
 }
 
 bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point) {
@@ -373,15 +374,14 @@
 bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string& mount_point,
                                    bool* change) {
     const auto top = overlay + kOverlayTopDir;
-    auto save_errno = errno;
-    auto missing = access(top.c_str(), F_OK);
-    errno = save_errno;
-    if (missing) return false;
 
-    const auto oldpath = top + (mount_point.empty() ? "" : ("/"s + mount_point));
+    if (!fs_mgr_access(top)) return false;
+
+    auto cleanup_all = mount_point.empty();
+    const auto oldpath = top + (cleanup_all ? "" : ("/"s + mount_point));
     const auto newpath = oldpath + ".teardown";
     auto ret = fs_mgr_rm_all(newpath);
-    save_errno = errno;
+    auto save_errno = errno;
     if (!rename(oldpath.c_str(), newpath.c_str())) {
         if (change) *change = true;
     } else if (errno != ENOENT) {
@@ -400,7 +400,7 @@
     } else {
         errno = save_errno;
     }
-    if (!mount_point.empty()) {
+    if (!cleanup_all) {
         save_errno = errno;
         if (!rmdir(top.c_str())) {
             if (change) *change = true;
@@ -471,6 +471,7 @@
     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");
     }
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/llkd/README.md b/llkd/README.md
index 1f69718..e5be850 100644
--- a/llkd/README.md
+++ b/llkd/README.md
@@ -127,7 +127,7 @@
 default 2 minutes samples of threads for D or Z.
 
 #### ro.llk.stack
-default *empty* or false, comma separated list of kernel symbols.
+default cma_alloc,__get_user_pages, comma separated list of kernel symbols.
 The string "*false*" is the equivalent to an *empty* list.
 Look for kernel stack symbols that if ever persistently present can
 indicate a subsystem is locked up.
diff --git a/llkd/include/llkd.h b/llkd/include/llkd.h
index d0188ec..1e2df2f 100644
--- a/llkd/include/llkd.h
+++ b/llkd/include/llkd.h
@@ -48,7 +48,7 @@
 /* LLK_CHECK_MS_DEFAULT = actual timeout_ms / LLK_CHECKS_PER_TIMEOUT_DEFAULT */
 #define LLK_CHECKS_PER_TIMEOUT_DEFAULT 5
 #define LLK_CHECK_STACK_PROPERTY       "ro.llk.stack"
-#define LLK_CHECK_STACK_DEFAULT        ""
+#define LLK_CHECK_STACK_DEFAULT        "cma_alloc,__get_user_pages"
 #define LLK_BLACKLIST_PROCESS_PROPERTY "ro.llk.blacklist.process"
 #define LLK_BLACKLIST_PROCESS_DEFAULT  \
     "0,1,2,init,[kthreadd],[khungtaskd],lmkd,lmkd.llkd,llkd,watchdogd,[watchdogd],[watchdogd/0]"
@@ -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