Merge "bootstat: power_on* handling"
diff --git a/adb/Android.bp b/adb/Android.bp
index b6aff3e..6558b1b 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -124,7 +124,8 @@
     "adb_trace.cpp",
     "adb_unique_fd.cpp",
     "adb_utils.cpp",
-    "fdevent.cpp",
+    "fdevent/fdevent.cpp",
+    "fdevent/fdevent_poll.cpp",
     "services.cpp",
     "sockets.cpp",
     "socket_spec.cpp",
@@ -144,7 +145,7 @@
     "adb_io_test.cpp",
     "adb_listeners_test.cpp",
     "adb_utils_test.cpp",
-    "fdevent_test.cpp",
+    "fdevent/fdevent_test.cpp",
     "socket_spec_test.cpp",
     "socket_test.cpp",
     "sysdeps_test.cpp",
@@ -435,7 +436,6 @@
             shared_libs: [
                 "libbootloader_message",
                 "libmdnssd",
-                "libext4_utils",
                 "libfec",
                 "libfs_mgr",
                 "libselinux",
diff --git a/adb/adb.h b/adb/adb.h
index 3a6f059..352b2fe 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -26,7 +26,7 @@
 #include <android-base/macros.h>
 
 #include "adb_trace.h"
-#include "fdevent.h"
+#include "fdevent/fdevent.h"
 #include "socket.h"
 #include "types.h"
 #include "usb.h"
diff --git a/adb/adb_listeners_test.cpp b/adb/adb_listeners_test.cpp
index b697769..a7e2dea 100644
--- a/adb/adb_listeners_test.cpp
+++ b/adb/adb_listeners_test.cpp
@@ -21,7 +21,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 
-#include "fdevent.h"
+#include "fdevent/fdevent.h"
 #include "sysdeps.h"
 #include "transport.h"
 
diff --git a/adb/client/transport_mdns.cpp b/adb/client/transport_mdns.cpp
index 283fac5..1a34384 100644
--- a/adb/client/transport_mdns.cpp
+++ b/adb/client/transport_mdns.cpp
@@ -31,7 +31,7 @@
 
 #include "adb_mdns.h"
 #include "adb_trace.h"
-#include "fdevent.h"
+#include "fdevent/fdevent.h"
 #include "sysdeps.h"
 
 static DNSServiceRef service_ref;
diff --git a/adb/daemon/auth.cpp b/adb/daemon/auth.cpp
index 1800f84..2b8f461 100644
--- a/adb/daemon/auth.cpp
+++ b/adb/daemon/auth.cpp
@@ -18,7 +18,8 @@
 
 #include "adb.h"
 #include "adb_auth.h"
-#include "fdevent.h"
+#include "adb_io.h"
+#include "fdevent/fdevent.h"
 #include "sysdeps.h"
 #include "transport.h"
 
diff --git a/adb/daemon/framebuffer_service.cpp b/adb/daemon/framebuffer_service.cpp
index 2a6418a..676f8e9 100644
--- a/adb/daemon/framebuffer_service.cpp
+++ b/adb/daemon/framebuffer_service.cpp
@@ -33,7 +33,6 @@
 #include "adb.h"
 #include "adb_io.h"
 #include "adb_utils.h"
-#include "fdevent.h"
 
 /* TODO:
 ** - sync with vsync to avoid tearing
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
deleted file mode 100644
index 32f9086..0000000
--- a/adb/fdevent.cpp
+++ /dev/null
@@ -1,553 +0,0 @@
-/* http://frotznet.googlecode.com/svn/trunk/utils/fdevent.c
-**
-** Copyright 2006, Brian Swetland <swetland@frotz.net>
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define TRACE_TAG FDEVENT
-
-#include "sysdeps.h"
-#include "fdevent.h"
-
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <atomic>
-#include <deque>
-#include <functional>
-#include <list>
-#include <mutex>
-#include <optional>
-#include <unordered_map>
-#include <utility>
-#include <variant>
-#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>
-#include <android-base/threads.h>
-
-#include "adb_io.h"
-#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
-
-#define FDE_ACTIVE     0x0100
-#define FDE_PENDING    0x0200
-#define FDE_CREATED    0x0400
-
-struct PollNode {
-  fdevent* fde;
-  adb_pollfd pollfd;
-
-  explicit PollNode(fdevent* fde) : fde(fde) {
-      memset(&pollfd, 0, sizeof(pollfd));
-      pollfd.fd = fde->fd.get();
-
-#if defined(__linux__)
-      // Always enable POLLRDHUP, so the host server can take action when some clients disconnect.
-      // Then we can avoid leaving many sockets in CLOSE_WAIT state. See http://b/23314034.
-      pollfd.events = POLLRDHUP;
-#endif
-  }
-};
-
-// All operations to fdevent should happen only in the main thread.
-// That's why we don't need a lock for fdevent.
-static auto& g_poll_node_map = *new std::unordered_map<int, PollNode>();
-static auto& g_pending_list = *new std::list<fdevent*>();
-static std::atomic<bool> terminate_loop(false);
-static bool main_thread_valid;
-static uint64_t main_thread_id;
-
-static uint64_t fdevent_id;
-
-static bool run_needs_flush = false;
-static auto& run_queue_notify_fd = *new unique_fd();
-static auto& run_queue_mutex = *new std::mutex();
-static auto& run_queue GUARDED_BY(run_queue_mutex) = *new std::deque<std::function<void()>>();
-
-void check_main_thread() {
-    if (main_thread_valid) {
-        CHECK_EQ(main_thread_id, android::base::GetThreadId());
-    }
-}
-
-void set_main_thread() {
-    main_thread_valid = true;
-    main_thread_id = android::base::GetThreadId();
-}
-
-static std::string dump_fde(const fdevent* fde) {
-    std::string state;
-    if (fde->state & FDE_ACTIVE) {
-        state += "A";
-    }
-    if (fde->state & FDE_PENDING) {
-        state += "P";
-    }
-    if (fde->state & FDE_CREATED) {
-        state += "C";
-    }
-    if (fde->state & FDE_READ) {
-        state += "R";
-    }
-    if (fde->state & FDE_WRITE) {
-        state += "W";
-    }
-    if (fde->state & FDE_ERROR) {
-        state += "E";
-    }
-    return android::base::StringPrintf("(fdevent %" PRIu64 ": fd %d %s)", fde->id, fde->fd.get(),
-                                       state.c_str());
-}
-
-template <typename F>
-static fdevent* fdevent_create_impl(int fd, F func, void* arg) {
-    check_main_thread();
-    CHECK_GE(fd, 0);
-
-    fdevent* fde = new fdevent();
-    fde->id = fdevent_id++;
-    fde->state = FDE_ACTIVE;
-    fde->fd.reset(fd);
-    fde->func = func;
-    fde->arg = arg;
-    if (!set_file_block_mode(fd, false)) {
-        // Here is not proper to handle the error. If it fails here, some error is
-        // likely to be detected by poll(), then we can let the callback function
-        // to handle it.
-        LOG(ERROR) << "failed to set non-blocking mode for fd " << fd;
-    }
-    auto pair = g_poll_node_map.emplace(fde->fd.get(), PollNode(fde));
-    CHECK(pair.second) << "install existing fd " << fd;
-
-    fde->state |= FDE_CREATED;
-    return fde;
-}
-
-fdevent* fdevent_create(int fd, fd_func func, void* arg) {
-    return fdevent_create_impl(fd, func, arg);
-}
-
-fdevent* fdevent_create(int fd, fd_func2 func, void* arg) {
-    return fdevent_create_impl(fd, func, arg);
-}
-
-unique_fd fdevent_release(fdevent* fde) {
-    check_main_thread();
-    if (!fde) {
-        return {};
-    }
-
-    if (!(fde->state & FDE_CREATED)) {
-        LOG(FATAL) << "destroying fde not created by fdevent_create(): " << dump_fde(fde);
-    }
-
-    unique_fd result = std::move(fde->fd);
-    if (fde->state & FDE_ACTIVE) {
-        g_poll_node_map.erase(result.get());
-
-        if (fde->state & FDE_PENDING) {
-            g_pending_list.remove(fde);
-        }
-        fde->state = 0;
-        fde->events = 0;
-    }
-
-    delete fde;
-    return result;
-}
-
-void fdevent_destroy(fdevent* fde) {
-    // Release, and then let unique_fd's destructor cleanup.
-    fdevent_release(fde);
-}
-
-static void fdevent_update(fdevent* fde, unsigned events) {
-    auto it = g_poll_node_map.find(fde->fd.get());
-    CHECK(it != g_poll_node_map.end());
-    PollNode& node = it->second;
-    if (events & FDE_READ) {
-        node.pollfd.events |= POLLIN;
-    } else {
-        node.pollfd.events &= ~POLLIN;
-    }
-
-    if (events & FDE_WRITE) {
-        node.pollfd.events |= POLLOUT;
-    } else {
-        node.pollfd.events &= ~POLLOUT;
-    }
-    fde->state = (fde->state & FDE_STATEMASK) | events;
-}
-
-void fdevent_set(fdevent* fde, unsigned events) {
-    check_main_thread();
-    events &= FDE_EVENTMASK;
-    if ((fde->state & FDE_EVENTMASK) == events) {
-        return;
-    }
-    CHECK(fde->state & FDE_ACTIVE);
-    fdevent_update(fde, events);
-    D("fdevent_set: %s, events = %u", dump_fde(fde).c_str(), events);
-
-    if (fde->state & FDE_PENDING) {
-        // If we are pending, make sure we don't signal an event that is no longer wanted.
-        fde->events &= events;
-        if (fde->events == 0) {
-            g_pending_list.remove(fde);
-            fde->state &= ~FDE_PENDING;
-        }
-    }
-}
-
-void fdevent_add(fdevent* fde, unsigned events) {
-    check_main_thread();
-    CHECK(!(events & FDE_TIMEOUT));
-    fdevent_set(fde, (fde->state & FDE_EVENTMASK) | events);
-}
-
-void fdevent_del(fdevent* fde, unsigned events) {
-    check_main_thread();
-    CHECK(!(events & FDE_TIMEOUT));
-    fdevent_set(fde, (fde->state & FDE_EVENTMASK) & ~events);
-}
-
-void fdevent_set_timeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout) {
-    check_main_thread();
-    fde->timeout = timeout;
-    fde->last_active = std::chrono::steady_clock::now();
-}
-
-static std::string dump_pollfds(const std::vector<adb_pollfd>& pollfds) {
-    std::string result;
-    for (const auto& pollfd : pollfds) {
-        std::string op;
-        if (pollfd.events & POLLIN) {
-            op += "R";
-        }
-        if (pollfd.events & POLLOUT) {
-            op += "W";
-        }
-        android::base::StringAppendF(&result, " %d(%s)", pollfd.fd, op.c_str());
-    }
-    return result;
-}
-
-static std::optional<std::chrono::milliseconds> calculate_timeout() {
-    std::optional<std::chrono::milliseconds> result = std::nullopt;
-    auto now = std::chrono::steady_clock::now();
-    check_main_thread();
-
-    for (const auto& [fd, pollnode] : g_poll_node_map) {
-        UNUSED(fd);
-        auto timeout_opt = pollnode.fde->timeout;
-        if (timeout_opt) {
-            auto deadline = pollnode.fde->last_active + *timeout_opt;
-            auto time_left = std::chrono::duration_cast<std::chrono::milliseconds>(deadline - now);
-            if (time_left < std::chrono::milliseconds::zero()) {
-                time_left = std::chrono::milliseconds::zero();
-            }
-
-            if (!result) {
-                result = time_left;
-            } else {
-                result = std::min(*result, time_left);
-            }
-        }
-    }
-
-    return result;
-}
-
-static void fdevent_process() {
-    std::vector<adb_pollfd> pollfds;
-    for (const auto& pair : g_poll_node_map) {
-        pollfds.push_back(pair.second.pollfd);
-    }
-    CHECK_GT(pollfds.size(), 0u);
-    D("poll(), pollfds = %s", dump_pollfds(pollfds).c_str());
-
-    auto timeout = calculate_timeout();
-    int timeout_ms;
-    if (!timeout) {
-        timeout_ms = -1;
-    } else {
-        timeout_ms = timeout->count();
-    }
-
-    int ret = adb_poll(&pollfds[0], pollfds.size(), timeout_ms);
-    if (ret == -1) {
-        PLOG(ERROR) << "poll(), ret = " << ret;
-        return;
-    }
-
-    auto post_poll = std::chrono::steady_clock::now();
-
-    for (const auto& pollfd : pollfds) {
-        if (pollfd.revents != 0) {
-            D("for fd %d, revents = %x", pollfd.fd, pollfd.revents);
-        }
-        unsigned events = 0;
-        if (pollfd.revents & POLLIN) {
-            events |= FDE_READ;
-        }
-        if (pollfd.revents & POLLOUT) {
-            events |= FDE_WRITE;
-        }
-        if (pollfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
-            // We fake a read, as the rest of the code assumes that errors will
-            // be detected at that point.
-            events |= FDE_READ | FDE_ERROR;
-        }
-#if defined(__linux__)
-        if (pollfd.revents & POLLRDHUP) {
-            events |= FDE_READ | FDE_ERROR;
-        }
-#endif
-        auto it = g_poll_node_map.find(pollfd.fd);
-        CHECK(it != g_poll_node_map.end());
-        fdevent* fde = it->second.fde;
-
-        if (events == 0) {
-            // Check for timeout.
-            if (fde->timeout) {
-                auto deadline = fde->last_active + *fde->timeout;
-                if (deadline < post_poll) {
-                    events |= FDE_TIMEOUT;
-                }
-            }
-        }
-
-        if (events != 0) {
-            CHECK_EQ(fde->fd.get(), pollfd.fd);
-            fde->events |= events;
-            fde->last_active = post_poll;
-            D("%s got events %x", dump_fde(fde).c_str(), events);
-            fde->state |= FDE_PENDING;
-            g_pending_list.push_back(fde);
-        }
-    }
-}
-
-template <class T>
-struct always_false : std::false_type {};
-
-static void fdevent_call_fdfunc(fdevent* fde) {
-    unsigned events = fde->events;
-    fde->events = 0;
-    CHECK(fde->state & FDE_PENDING);
-    fde->state &= (~FDE_PENDING);
-    D("fdevent_call_fdfunc %s", dump_fde(fde).c_str());
-    std::visit(
-            [&](auto&& f) {
-                using F = std::decay_t<decltype(f)>;
-                if constexpr (std::is_same_v<fd_func, F>) {
-                    f(fde->fd.get(), events, fde->arg);
-                } else if constexpr (std::is_same_v<fd_func2, F>) {
-                    f(fde, events, fde->arg);
-                } else {
-                    static_assert(always_false<F>::value, "non-exhaustive visitor");
-                }
-            },
-            fde->func);
-}
-
-static void fdevent_run_flush() EXCLUDES(run_queue_mutex) {
-    // We need to be careful around reentrancy here, since a function we call can queue up another
-    // function.
-    while (true) {
-        std::function<void()> fn;
-        {
-            std::lock_guard<std::mutex> lock(run_queue_mutex);
-            if (run_queue.empty()) {
-                break;
-            }
-            fn = run_queue.front();
-            run_queue.pop_front();
-        }
-        fn();
-    }
-}
-
-static void fdevent_run_func(int fd, unsigned ev, void* /* userdata */) {
-    CHECK_GE(fd, 0);
-    CHECK(ev & FDE_READ);
-
-    char buf[1024];
-
-    // Empty the fd.
-    if (adb_read(fd, buf, sizeof(buf)) == -1) {
-        PLOG(FATAL) << "failed to empty run queue notify fd";
-    }
-
-    // Mark that we need to flush, and then run it at the end of fdevent_loop.
-    run_needs_flush = true;
-}
-
-static void fdevent_run_setup() {
-    {
-        std::lock_guard<std::mutex> lock(run_queue_mutex);
-        CHECK(run_queue_notify_fd.get() == -1);
-        int s[2];
-        if (adb_socketpair(s) != 0) {
-            PLOG(FATAL) << "failed to create run queue notify socketpair";
-        }
-
-        if (!set_file_block_mode(s[0], false) || !set_file_block_mode(s[1], false)) {
-            PLOG(FATAL) << "failed to make run queue notify socket nonblocking";
-        }
-
-        run_queue_notify_fd.reset(s[0]);
-        fdevent* fde = fdevent_create(s[1], fdevent_run_func, nullptr);
-        CHECK(fde != nullptr);
-        fdevent_add(fde, FDE_READ);
-    }
-
-    fdevent_run_flush();
-}
-
-void fdevent_run_on_main_thread(std::function<void()> fn) {
-    std::lock_guard<std::mutex> lock(run_queue_mutex);
-    run_queue.push_back(std::move(fn));
-
-    // run_queue_notify_fd could still be -1 if we're called before fdevent has finished setting up.
-    // In that case, rely on the setup code to flush the queue without a notification being needed.
-    if (run_queue_notify_fd != -1) {
-        int rc = adb_write(run_queue_notify_fd.get(), "", 1);
-
-        // It's possible that we get EAGAIN here, if lots of notifications came in while handling.
-        if (rc == 0) {
-            PLOG(FATAL) << "run queue notify fd was closed?";
-        } else if (rc == -1 && errno != EAGAIN) {
-            PLOG(FATAL) << "failed to write to run queue notify fd";
-        }
-    }
-}
-
-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;
-        }
-
-        D("--- --- waiting for events");
-
-        fdevent_process();
-
-        fdevent_check_spin(cycle++);
-
-        while (!g_pending_list.empty()) {
-            fdevent* fde = g_pending_list.front();
-            g_pending_list.pop_front();
-            fdevent_call_fdfunc(fde);
-        }
-
-        if (run_needs_flush) {
-            fdevent_run_flush();
-            run_needs_flush = false;
-        }
-    }
-}
-
-void fdevent_terminate_loop() {
-    terminate_loop = true;
-}
-
-size_t fdevent_installed_count() {
-    return g_poll_node_map.size();
-}
-
-void fdevent_reset() {
-    g_poll_node_map.clear();
-    g_pending_list.clear();
-
-    std::lock_guard<std::mutex> lock(run_queue_mutex);
-    run_queue_notify_fd.reset();
-    run_queue.clear();
-
-    main_thread_valid = false;
-    terminate_loop = false;
-}
diff --git a/adb/fdevent.h b/adb/fdevent.h
deleted file mode 100644
index 42dbb9e..0000000
--- a/adb/fdevent.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __FDEVENT_H
-#define __FDEVENT_H
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <chrono>
-#include <functional>
-#include <optional>
-#include <variant>
-
-#include "adb_unique_fd.h"
-
-// Events that may be observed
-#define FDE_READ 0x0001
-#define FDE_WRITE 0x0002
-#define FDE_ERROR 0x0004
-#define FDE_TIMEOUT 0x0008
-
-typedef void (*fd_func)(int fd, unsigned events, void *userdata);
-typedef void (*fd_func2)(struct fdevent* fde, unsigned events, void* userdata);
-
-struct fdevent {
-    uint64_t id;
-
-    unique_fd fd;
-    int force_eof = 0;
-
-    uint16_t state = 0;
-    uint16_t events = 0;
-    std::optional<std::chrono::milliseconds> timeout;
-    std::chrono::steady_clock::time_point last_active;
-
-    std::variant<fd_func, fd_func2> func;
-    void* arg = nullptr;
-};
-
-// Allocate and initialize a new fdevent object
-// TODO: Switch these to unique_fd.
-fdevent *fdevent_create(int fd, fd_func func, void *arg);
-fdevent* fdevent_create(int fd, fd_func2 func, void* arg);
-
-// Deallocate an fdevent object that was created by fdevent_create.
-void fdevent_destroy(fdevent *fde);
-
-// fdevent_destroy, except releasing the file descriptor previously owned by the fdevent.
-unique_fd fdevent_release(fdevent* fde);
-
-// Change which events should cause notifications
-void fdevent_set(fdevent *fde, unsigned events);
-void fdevent_add(fdevent *fde, unsigned events);
-void fdevent_del(fdevent *fde, unsigned events);
-
-// Set a timeout on an fdevent.
-// If no events are triggered by the timeout, an FDE_TIMEOUT will be generated.
-// Note timeouts are not defused automatically; if a timeout is set on an fdevent, it will
-// trigger repeatedly every |timeout| ms.
-void fdevent_set_timeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout);
-
-// Loop forever, handling events.
-void fdevent_loop();
-
-void check_main_thread();
-
-// Queue an operation to run on the main thread.
-void fdevent_run_on_main_thread(std::function<void()> fn);
-
-// The following functions are used only for tests.
-void fdevent_terminate_loop();
-size_t fdevent_installed_count();
-void fdevent_reset();
-void set_main_thread();
-
-#endif
diff --git a/adb/fdevent/fdevent.cpp b/adb/fdevent/fdevent.cpp
new file mode 100644
index 0000000..28b8f37
--- /dev/null
+++ b/adb/fdevent/fdevent.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2006, Brian Swetland <swetland@frotz.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define TRACE_TAG FDEVENT
+
+#include "sysdeps.h"
+
+#include <inttypes.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/threads.h>
+
+#include "adb_utils.h"
+#include "fdevent.h"
+#include "fdevent_poll.h"
+
+std::string dump_fde(const fdevent* fde) {
+    std::string state;
+    if (fde->state & FDE_ACTIVE) {
+        state += "A";
+    }
+    if (fde->state & FDE_PENDING) {
+        state += "P";
+    }
+    if (fde->state & FDE_READ) {
+        state += "R";
+    }
+    if (fde->state & FDE_WRITE) {
+        state += "W";
+    }
+    if (fde->state & FDE_ERROR) {
+        state += "E";
+    }
+    return android::base::StringPrintf("(fdevent %" PRIu64 ": fd %d %s)", fde->id, fde->fd.get(),
+                                       state.c_str());
+}
+
+fdevent* fdevent_context::Create(unique_fd fd, std::variant<fd_func, fd_func2> func, void* arg) {
+    CheckMainThread();
+    CHECK_GE(fd.get(), 0);
+
+    fdevent* fde = new fdevent();
+    fde->id = fdevent_id_++;
+    fde->state = FDE_ACTIVE;
+    fde->fd = std::move(fd);
+    fde->func = func;
+    fde->arg = arg;
+    if (!set_file_block_mode(fde->fd, false)) {
+        // Here is not proper to handle the error. If it fails here, some error is
+        // likely to be detected by poll(), then we can let the callback function
+        // to handle it.
+        LOG(ERROR) << "failed to set non-blocking mode for fd " << fde->fd.get();
+    }
+
+    this->Register(fde);
+    return fde;
+}
+
+unique_fd fdevent_context::Destroy(fdevent* fde) {
+    CheckMainThread();
+    if (!fde) {
+        return {};
+    }
+
+    this->Unregister(fde);
+
+    unique_fd result = std::move(fde->fd);
+    delete fde;
+    return result;
+}
+
+void fdevent_context::Add(fdevent* fde, unsigned events) {
+    Set(fde, (fde->state & FDE_EVENTMASK) | events);
+}
+
+void fdevent_context::Del(fdevent* fde, unsigned events) {
+    CHECK(!(events & FDE_TIMEOUT));
+    Set(fde, (fde->state & FDE_EVENTMASK) & ~events);
+}
+
+void fdevent_context::SetTimeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout) {
+    CheckMainThread();
+    fde->timeout = timeout;
+    fde->last_active = std::chrono::steady_clock::now();
+}
+
+void fdevent_context::CheckMainThread() {
+    if (main_thread_id_) {
+        CHECK_EQ(*main_thread_id_, android::base::GetThreadId());
+    }
+}
+
+void fdevent_context::Run(std::function<void()> fn) {
+    {
+        std::lock_guard<std::mutex> lock(run_queue_mutex_);
+        run_queue_.push_back(std::move(fn));
+    }
+
+    Interrupt();
+}
+
+void fdevent_context::TerminateLoop() {
+    terminate_loop_ = true;
+    Interrupt();
+}
+
+void fdevent_context::FlushRunQueue() {
+    // We need to be careful around reentrancy here, since a function we call can queue up another
+    // function.
+    while (true) {
+        std::function<void()> fn;
+        {
+            std::lock_guard<std::mutex> lock(this->run_queue_mutex_);
+            if (this->run_queue_.empty()) {
+                break;
+            }
+            fn = this->run_queue_.front();
+            this->run_queue_.pop_front();
+        }
+        fn();
+    }
+}
+
+static auto& g_ambient_fdevent_context =
+        *new std::unique_ptr<fdevent_context>(new fdevent_context_poll());
+
+static fdevent_context* fdevent_get_ambient() {
+    return g_ambient_fdevent_context.get();
+}
+
+fdevent* fdevent_create(int fd, fd_func func, void* arg) {
+    unique_fd ufd(fd);
+    return fdevent_get_ambient()->Create(std::move(ufd), func, arg);
+}
+
+fdevent* fdevent_create(int fd, fd_func2 func, void* arg) {
+    unique_fd ufd(fd);
+    return fdevent_get_ambient()->Create(std::move(ufd), func, arg);
+}
+
+unique_fd fdevent_release(fdevent* fde) {
+    return fdevent_get_ambient()->Destroy(fde);
+}
+
+void fdevent_destroy(fdevent* fde) {
+    fdevent_get_ambient()->Destroy(fde);
+}
+
+void fdevent_set(fdevent* fde, unsigned events) {
+    fdevent_get_ambient()->Set(fde, events);
+}
+
+void fdevent_add(fdevent* fde, unsigned events) {
+    fdevent_get_ambient()->Add(fde, events);
+}
+
+void fdevent_del(fdevent* fde, unsigned events) {
+    fdevent_get_ambient()->Del(fde, events);
+}
+
+void fdevent_set_timeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout) {
+    fdevent_get_ambient()->SetTimeout(fde, timeout);
+}
+
+void fdevent_run_on_main_thread(std::function<void()> fn) {
+    fdevent_get_ambient()->Run(std::move(fn));
+}
+
+void fdevent_loop() {
+    fdevent_get_ambient()->Loop();
+}
+
+void check_main_thread() {
+    fdevent_get_ambient()->CheckMainThread();
+}
+
+void fdevent_terminate_loop() {
+    fdevent_get_ambient()->TerminateLoop();
+}
+
+size_t fdevent_installed_count() {
+    return fdevent_get_ambient()->InstalledCount();
+}
+
+void fdevent_reset() {
+    g_ambient_fdevent_context.reset(new fdevent_context_poll());
+}
diff --git a/adb/fdevent/fdevent.h b/adb/fdevent/fdevent.h
new file mode 100644
index 0000000..ccb0c92
--- /dev/null
+++ b/adb/fdevent/fdevent.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __FDEVENT_H
+#define __FDEVENT_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <chrono>
+#include <deque>
+#include <functional>
+#include <mutex>
+#include <optional>
+#include <variant>
+
+#include <android-base/thread_annotations.h>
+
+#include "adb_unique_fd.h"
+
+// Events that may be observed
+#define FDE_READ 0x0001
+#define FDE_WRITE 0x0002
+#define FDE_ERROR 0x0004
+#define FDE_TIMEOUT 0x0008
+
+// Internal states.
+#define FDE_EVENTMASK  0x00ff
+#define FDE_STATEMASK  0xff00
+
+#define FDE_ACTIVE     0x0100
+#define FDE_PENDING    0x0200
+
+typedef void (*fd_func)(int fd, unsigned events, void *userdata);
+typedef void (*fd_func2)(struct fdevent* fde, unsigned events, void* userdata);
+
+struct fdevent;
+std::string dump_fde(const fdevent* fde);
+
+struct fdevent_context {
+  public:
+    virtual ~fdevent_context() = default;
+
+    // Allocate and initialize a new fdevent object.
+    fdevent* Create(unique_fd fd, std::variant<fd_func, fd_func2> func, void* arg);
+
+    // Deallocate an fdevent object, returning the file descriptor that was owned by it.
+    unique_fd Destroy(fdevent* fde);
+
+  protected:
+    // Register an fdevent that is being created by Create with the fdevent_context.
+    virtual void Register(fdevent* fde) = 0;
+
+    // Unregister an fdevent that is being destroyed by Destroy with the fdevent_context.
+    virtual void Unregister(fdevent* fde) = 0;
+
+  public:
+    // Change which events should cause notifications.
+    virtual void Set(fdevent* fde, unsigned events) = 0;
+    void Add(fdevent* fde, unsigned events);
+    void Del(fdevent* fde, unsigned events);
+
+    // Set a timeout on an fdevent.
+    // If no events are triggered by the timeout, an FDE_TIMEOUT will be generated.
+    // Note timeouts are not defused automatically; if a timeout is set on an fdevent, it will
+    // trigger repeatedly every |timeout| ms.
+    void SetTimeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout);
+
+    // Loop until TerminateLoop is called, handling events.
+    // Implementations should call FlushRunQueue on every iteration, and check the value of
+    // terminate_loop_ to determine whether to stop.
+    virtual void Loop() = 0;
+
+    // Assert that the caller is either running on the context's main thread, or that there is no
+    // active main thread.
+    void CheckMainThread();
+
+    // Queue an operation to be run on the main thread.
+    void Run(std::function<void()> fn);
+
+    // Test-only functionality:
+    void TerminateLoop();
+    virtual size_t InstalledCount() = 0;
+
+  protected:
+    // Interrupt the run loop.
+    virtual void Interrupt() = 0;
+
+    // Run all pending functions enqueued via Run().
+    void FlushRunQueue() EXCLUDES(run_queue_mutex_);
+
+    std::optional<uint64_t> main_thread_id_ = std::nullopt;
+    std::atomic<bool> terminate_loop_ = false;
+
+  private:
+    uint64_t fdevent_id_ = 0;
+    std::mutex run_queue_mutex_;
+    std::deque<std::function<void()>> run_queue_ GUARDED_BY(run_queue_mutex_);
+};
+
+struct fdevent {
+    uint64_t id;
+
+    unique_fd fd;
+    int force_eof = 0;
+
+    uint16_t state = 0;
+    uint16_t events = 0;
+    std::optional<std::chrono::milliseconds> timeout;
+    std::chrono::steady_clock::time_point last_active;
+
+    std::variant<fd_func, fd_func2> func;
+    void* arg = nullptr;
+};
+
+// Backwards compatibility shims that forward to the global fdevent_context.
+fdevent* fdevent_create(int fd, fd_func func, void* arg);
+fdevent* fdevent_create(int fd, fd_func2 func, void* arg);
+
+unique_fd fdevent_release(fdevent* fde);
+void fdevent_destroy(fdevent* fde);
+
+void fdevent_set(fdevent *fde, unsigned events);
+void fdevent_add(fdevent *fde, unsigned events);
+void fdevent_del(fdevent *fde, unsigned events);
+void fdevent_set_timeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout);
+void fdevent_loop();
+void check_main_thread();
+
+// Queue an operation to run on the main thread.
+void fdevent_run_on_main_thread(std::function<void()> fn);
+
+// The following functions are used only for tests.
+void fdevent_terminate_loop();
+size_t fdevent_installed_count();
+void fdevent_reset();
+
+#endif
diff --git a/adb/fdevent/fdevent_poll.cpp b/adb/fdevent/fdevent_poll.cpp
new file mode 100644
index 0000000..75ea081
--- /dev/null
+++ b/adb/fdevent/fdevent_poll.cpp
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define TRACE_TAG FDEVENT
+
+#include "sysdeps.h"
+#include "fdevent_poll.h"
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <deque>
+#include <functional>
+#include <list>
+#include <mutex>
+#include <optional>
+#include <unordered_map>
+#include <utility>
+#include <variant>
+#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/threads.h>
+
+#include "adb_io.h"
+#include "adb_trace.h"
+#include "adb_unique_fd.h"
+#include "adb_utils.h"
+#include "fdevent.h"
+#include "sysdeps/chrono.h"
+
+static void fdevent_interrupt(int fd, unsigned, void*) {
+    char buf[BUFSIZ];
+    ssize_t rc = TEMP_FAILURE_RETRY(adb_read(fd, buf, sizeof(buf)));
+    if (rc == -1) {
+        PLOG(FATAL) << "failed to read from fdevent interrupt fd";
+    }
+}
+
+fdevent_context_poll::fdevent_context_poll() {
+    int s[2];
+    if (adb_socketpair(s) != 0) {
+        PLOG(FATAL) << "failed to create fdevent interrupt socketpair";
+    }
+
+    if (!set_file_block_mode(s[0], false) || !set_file_block_mode(s[1], false)) {
+        PLOG(FATAL) << "failed to make fdevent interrupt socket nonblocking";
+    }
+
+    this->interrupt_fd_.reset(s[0]);
+    fdevent* fde = this->Create(unique_fd(s[1]), fdevent_interrupt, nullptr);
+    CHECK(fde != nullptr);
+    this->Add(fde, FDE_READ);
+}
+
+fdevent_context_poll::~fdevent_context_poll() {
+    this->Destroy(this->interrupt_fde_);
+}
+
+void fdevent_context_poll::Register(fdevent* fde) {
+    auto pair = poll_node_map_.emplace(fde->fd.get(), PollNode(fde));
+    CHECK(pair.second) << "install existing fd " << fde->fd.get();
+}
+
+void fdevent_context_poll::Unregister(fdevent* fde) {
+    if (fde->state & FDE_ACTIVE) {
+        poll_node_map_.erase(fde->fd.get());
+
+        if (fde->state & FDE_PENDING) {
+            pending_list_.remove(fde);
+        }
+        fde->state = 0;
+        fde->events = 0;
+    }
+}
+
+void fdevent_context_poll::Set(fdevent* fde, unsigned events) {
+    CheckMainThread();
+    events &= FDE_EVENTMASK;
+    if ((fde->state & FDE_EVENTMASK) == events) {
+        return;
+    }
+    CHECK(fde->state & FDE_ACTIVE);
+
+    auto it = poll_node_map_.find(fde->fd.get());
+    CHECK(it != poll_node_map_.end());
+    PollNode& node = it->second;
+    if (events & FDE_READ) {
+        node.pollfd.events |= POLLIN;
+    } else {
+        node.pollfd.events &= ~POLLIN;
+    }
+
+    if (events & FDE_WRITE) {
+        node.pollfd.events |= POLLOUT;
+    } else {
+        node.pollfd.events &= ~POLLOUT;
+    }
+    fde->state = (fde->state & FDE_STATEMASK) | events;
+
+    D("fdevent_set: %s, events = %u", dump_fde(fde).c_str(), events);
+
+    if (fde->state & FDE_PENDING) {
+        // If we are pending, make sure we don't signal an event that is no longer wanted.
+        fde->events &= events;
+        if (fde->events == 0) {
+            pending_list_.remove(fde);
+            fde->state &= ~FDE_PENDING;
+        }
+    }
+}
+
+static std::string dump_pollfds(const std::vector<adb_pollfd>& pollfds) {
+    std::string result;
+    for (const auto& pollfd : pollfds) {
+        std::string op;
+        if (pollfd.events & POLLIN) {
+            op += "R";
+        }
+        if (pollfd.events & POLLOUT) {
+            op += "W";
+        }
+        android::base::StringAppendF(&result, " %d(%s)", pollfd.fd, op.c_str());
+    }
+    return result;
+}
+
+static std::optional<std::chrono::milliseconds> calculate_timeout(fdevent_context_poll* ctx) {
+    std::optional<std::chrono::milliseconds> result = std::nullopt;
+    auto now = std::chrono::steady_clock::now();
+    ctx->CheckMainThread();
+
+    for (const auto& [fd, pollnode] : ctx->poll_node_map_) {
+        UNUSED(fd);
+        auto timeout_opt = pollnode.fde->timeout;
+        if (timeout_opt) {
+            auto deadline = pollnode.fde->last_active + *timeout_opt;
+            auto time_left = std::chrono::duration_cast<std::chrono::milliseconds>(deadline - now);
+            if (time_left < std::chrono::milliseconds::zero()) {
+                time_left = std::chrono::milliseconds::zero();
+            }
+
+            if (!result) {
+                result = time_left;
+            } else {
+                result = std::min(*result, time_left);
+            }
+        }
+    }
+
+    return result;
+}
+
+static void fdevent_process(fdevent_context_poll* ctx) {
+    std::vector<adb_pollfd> pollfds;
+    for (const auto& pair : ctx->poll_node_map_) {
+        pollfds.push_back(pair.second.pollfd);
+    }
+    CHECK_GT(pollfds.size(), 0u);
+    D("poll(), pollfds = %s", dump_pollfds(pollfds).c_str());
+
+    auto timeout = calculate_timeout(ctx);
+    int timeout_ms;
+    if (!timeout) {
+        timeout_ms = -1;
+    } else {
+        timeout_ms = timeout->count();
+    }
+
+    int ret = adb_poll(&pollfds[0], pollfds.size(), timeout_ms);
+    if (ret == -1) {
+        PLOG(ERROR) << "poll(), ret = " << ret;
+        return;
+    }
+
+    auto post_poll = std::chrono::steady_clock::now();
+
+    for (const auto& pollfd : pollfds) {
+        if (pollfd.revents != 0) {
+            D("for fd %d, revents = %x", pollfd.fd, pollfd.revents);
+        }
+        unsigned events = 0;
+        if (pollfd.revents & POLLIN) {
+            events |= FDE_READ;
+        }
+        if (pollfd.revents & POLLOUT) {
+            events |= FDE_WRITE;
+        }
+        if (pollfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
+            // We fake a read, as the rest of the code assumes that errors will
+            // be detected at that point.
+            events |= FDE_READ | FDE_ERROR;
+        }
+#if defined(__linux__)
+        if (pollfd.revents & POLLRDHUP) {
+            events |= FDE_READ | FDE_ERROR;
+        }
+#endif
+        auto it = ctx->poll_node_map_.find(pollfd.fd);
+        CHECK(it != ctx->poll_node_map_.end());
+        fdevent* fde = it->second.fde;
+
+        if (events == 0) {
+            // Check for timeout.
+            if (fde->timeout) {
+                auto deadline = fde->last_active + *fde->timeout;
+                if (deadline < post_poll) {
+                    events |= FDE_TIMEOUT;
+                }
+            }
+        }
+
+        if (events != 0) {
+            CHECK_EQ(fde->fd.get(), pollfd.fd);
+            fde->events |= events;
+            fde->last_active = post_poll;
+            D("%s got events %x", dump_fde(fde).c_str(), events);
+            fde->state |= FDE_PENDING;
+            ctx->pending_list_.push_back(fde);
+        }
+    }
+}
+
+template <class T>
+struct always_false : std::false_type {};
+
+static void fdevent_call_fdfunc(fdevent* fde) {
+    unsigned events = fde->events;
+    fde->events = 0;
+    CHECK(fde->state & FDE_PENDING);
+    fde->state &= (~FDE_PENDING);
+    D("fdevent_call_fdfunc %s", dump_fde(fde).c_str());
+    std::visit(
+            [&](auto&& f) {
+                using F = std::decay_t<decltype(f)>;
+                if constexpr (std::is_same_v<fd_func, F>) {
+                    f(fde->fd.get(), events, fde->arg);
+                } else if constexpr (std::is_same_v<fd_func2, F>) {
+                    f(fde, events, fde->arg);
+                } else {
+                    static_assert(always_false<F>::value, "non-exhaustive visitor");
+                }
+            },
+            fde->func);
+}
+
+static void fdevent_check_spin(fdevent_context_poll* ctx, 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;
+    };
+
+    // TODO: Move this into the base fdevent_context.
+    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 : ctx->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_context_poll::Loop() {
+    main_thread_id_ = android::base::GetThreadId();
+
+    uint64_t cycle = 0;
+    while (true) {
+        if (terminate_loop_) {
+            break;
+        }
+
+        D("--- --- waiting for events");
+
+        fdevent_process(this);
+
+        fdevent_check_spin(this, cycle++);
+
+        while (!pending_list_.empty()) {
+            fdevent* fde = pending_list_.front();
+            pending_list_.pop_front();
+            fdevent_call_fdfunc(fde);
+        }
+
+        this->FlushRunQueue();
+    }
+
+    main_thread_id_.reset();
+}
+
+size_t fdevent_context_poll::InstalledCount() {
+    // We always have an installed fde for interrupt.
+    return poll_node_map_.size() - 1;
+}
+
+void fdevent_context_poll::Interrupt() {
+    int rc = adb_write(this->interrupt_fd_, "", 1);
+
+    // It's possible that we get EAGAIN here, if lots of notifications came in while handling.
+    if (rc == 0) {
+        PLOG(FATAL) << "fdevent interrupt fd was closed?";
+    } else if (rc == -1 && errno != EAGAIN) {
+        PLOG(FATAL) << "failed to write to fdevent interrupt fd";
+    }
+}
diff --git a/adb/fdevent/fdevent_poll.h b/adb/fdevent/fdevent_poll.h
new file mode 100644
index 0000000..db08301
--- /dev/null
+++ b/adb/fdevent/fdevent_poll.h
@@ -0,0 +1,71 @@
+#pragma once
+
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sysdeps.h"
+
+#include <deque>
+#include <list>
+#include <mutex>
+#include <unordered_map>
+
+#include <android-base/thread_annotations.h>
+
+#include "adb_unique_fd.h"
+#include "fdevent.h"
+
+struct PollNode {
+  fdevent* fde;
+  adb_pollfd pollfd;
+
+  explicit PollNode(fdevent* fde) : fde(fde) {
+      memset(&pollfd, 0, sizeof(pollfd));
+      pollfd.fd = fde->fd.get();
+
+#if defined(__linux__)
+      // Always enable POLLRDHUP, so the host server can take action when some clients disconnect.
+      // Then we can avoid leaving many sockets in CLOSE_WAIT state. See http://b/23314034.
+      pollfd.events = POLLRDHUP;
+#endif
+  }
+};
+
+struct fdevent_context_poll : public fdevent_context {
+    fdevent_context_poll();
+    virtual ~fdevent_context_poll();
+
+    virtual void Register(fdevent* fde) final;
+    virtual void Unregister(fdevent* fde) final;
+
+    virtual void Set(fdevent* fde, unsigned events) final;
+
+    virtual void Loop() final;
+
+    virtual size_t InstalledCount() final;
+
+  protected:
+    virtual void Interrupt() final;
+
+  public:
+    // All operations to fdevent should happen only in the main thread.
+    // That's why we don't need a lock for fdevent.
+    std::unordered_map<int, PollNode> poll_node_map_;
+    std::list<fdevent*> pending_list_;
+
+    unique_fd interrupt_fd_;
+    fdevent* interrupt_fde_ = nullptr;
+};
diff --git a/adb/fdevent_test.cpp b/adb/fdevent/fdevent_test.cpp
similarity index 100%
rename from adb/fdevent_test.cpp
rename to adb/fdevent/fdevent_test.cpp
diff --git a/adb/fdevent_test.h b/adb/fdevent/fdevent_test.h
similarity index 95%
rename from adb/fdevent_test.h
rename to adb/fdevent/fdevent_test.h
index 24bce59..2139d0f 100644
--- a/adb/fdevent_test.h
+++ b/adb/fdevent/fdevent_test.h
@@ -78,8 +78,8 @@
     }
 
     size_t GetAdditionalLocalSocketCount() {
-        // dummy socket installed in PrepareThread() + fdevent_run_on_main_thread socket
-        return 2;
+        // dummy socket installed in PrepareThread()
+        return 1;
     }
 
     void TerminateThread() {
diff --git a/adb/socket.h b/adb/socket.h
index b8c559a..4276851 100644
--- a/adb/socket.h
+++ b/adb/socket.h
@@ -24,7 +24,7 @@
 #include <string>
 
 #include "adb_unique_fd.h"
-#include "fdevent.h"
+#include "fdevent/fdevent.h"
 #include "types.h"
 
 class atransport;
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index 5e28f76..1601ff0 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "fdevent.h"
+#include "fdevent/fdevent.h"
 
 #include <gtest/gtest.h>
 
@@ -29,7 +29,7 @@
 
 #include "adb.h"
 #include "adb_io.h"
-#include "fdevent_test.h"
+#include "fdevent/fdevent_test.h"
 #include "socket.h"
 #include "sysdeps.h"
 #include "sysdeps/chrono.h"
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 78abba5..b0e7fa0 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -64,8 +64,6 @@
 #include <memory>   // unique_ptr
 #include <string>
 
-#include "fdevent.h"
-
 #define OS_PATH_SEPARATORS "\\/"
 #define OS_PATH_SEPARATOR '\\'
 #define OS_PATH_SEPARATOR_STR "\\"
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 841865a..8bc925f 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -49,7 +49,7 @@
 #include "adb_io.h"
 #include "adb_trace.h"
 #include "adb_utils.h"
-#include "fdevent.h"
+#include "fdevent/fdevent.h"
 #include "sysdeps/chrono.h"
 
 using android::base::ScopedLockAssertion;
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index b66f8fa..00beb3a 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -19,7 +19,7 @@
 #include <gtest/gtest.h>
 
 #include "adb.h"
-#include "fdevent_test.h"
+#include "fdevent/fdevent_test.h"
 
 struct TransportTest : public FdeventTest {};
 
diff --git a/base/include/android-base/expected.h b/base/include/android-base/expected.h
index 957a8a0..030ef35e 100644
--- a/base/include/android-base/expected.h
+++ b/base/include/android-base/expected.h
@@ -81,15 +81,6 @@
 #define _NODISCARD_
 #endif
 
-namespace {
-template< class T >
-struct remove_cvref {
-  typedef std::remove_cv_t<std::remove_reference_t<T>> type;
-};
-template< class T >
-using remove_cvref_t = typename remove_cvref<T>::type;
-} // namespace
-
 // Class expected
 template<class T, class E>
 class _NODISCARD_ expected {
@@ -182,25 +173,23 @@
     else var_ = unexpected(std::move(rhs.error()));
   }
 
-  template<class U = T _ENABLE_IF(
-    std::is_constructible_v<T, U&&> &&
-    !std::is_same_v<remove_cvref_t<U>, std::in_place_t> &&
-    !std::is_same_v<expected<T, E>, remove_cvref_t<U>> &&
-    !std::is_same_v<unexpected<E>, remove_cvref_t<U>> &&
-    std::is_convertible_v<U&&,T> /* non-explicit */
-  )>
-  constexpr expected(U&& v)
-  : var_(std::in_place_index<0>, std::forward<U>(v)) {}
+  template <class U = T _ENABLE_IF(
+                std::is_constructible_v<T, U&&> &&
+                !std::is_same_v<std::remove_cv_t<std::remove_reference_t<U>>, std::in_place_t> &&
+                !std::is_same_v<expected<T, E>, std::remove_cv_t<std::remove_reference_t<U>>> &&
+                !std::is_same_v<unexpected<E>, std::remove_cv_t<std::remove_reference_t<U>>> &&
+                std::is_convertible_v<U&&, T> /* non-explicit */
+                )>
+  constexpr expected(U&& v) : var_(std::in_place_index<0>, std::forward<U>(v)) {}
 
-  template<class U = T _ENABLE_IF(
-    std::is_constructible_v<T, U&&> &&
-    !std::is_same_v<remove_cvref_t<U>, std::in_place_t> &&
-    !std::is_same_v<expected<T, E>, remove_cvref_t<U>> &&
-    !std::is_same_v<unexpected<E>, remove_cvref_t<U>> &&
-    !std::is_convertible_v<U&&,T> /* explicit */
-  )>
-  constexpr explicit expected(U&& v)
-  : var_(std::in_place_index<0>, T(std::forward<U>(v))) {}
+  template <class U = T _ENABLE_IF(
+                std::is_constructible_v<T, U&&> &&
+                !std::is_same_v<std::remove_cv_t<std::remove_reference_t<U>>, std::in_place_t> &&
+                !std::is_same_v<expected<T, E>, std::remove_cv_t<std::remove_reference_t<U>>> &&
+                !std::is_same_v<unexpected<E>, std::remove_cv_t<std::remove_reference_t<U>>> &&
+                !std::is_convertible_v<U&&, T> /* explicit */
+                )>
+  constexpr explicit expected(U&& v) : var_(std::in_place_index<0>, T(std::forward<U>(v))) {}
 
   template<class G = E _ENABLE_IF(
     std::is_constructible_v<E, const G&> &&
@@ -267,16 +256,15 @@
   expected& operator=(const expected& rhs) = default;
 
   // Note for SFNAIE above applies to here as well
-  expected& operator=(expected&& rhs) = default;
+  expected& operator=(expected&& rhs) noexcept(
+      std::is_nothrow_move_assignable_v<T>&& std::is_nothrow_move_assignable_v<E>) = default;
 
-  template<class U = T _ENABLE_IF(
-    !std::is_void_v<T> &&
-    !std::is_same_v<expected<T,E>, remove_cvref_t<U>> &&
-    !std::conjunction_v<std::is_scalar<T>, std::is_same<T, std::decay_t<U>>> &&
-    std::is_constructible_v<T,U> &&
-    std::is_assignable_v<T&,U> &&
-    std::is_nothrow_move_constructible_v<E>
-  )>
+  template <class U = T _ENABLE_IF(
+                !std::is_void_v<T> &&
+                !std::is_same_v<expected<T, E>, std::remove_cv_t<std::remove_reference_t<U>>> &&
+                !std::conjunction_v<std::is_scalar<T>, std::is_same<T, std::decay_t<U>>> &&
+                std::is_constructible_v<T, U> && std::is_assignable_v<T&, U> &&
+                std::is_nothrow_move_constructible_v<E>)>
   expected& operator=(U&& rhs) {
     var_ = T(std::forward<U>(rhs));
     return *this;
@@ -555,7 +543,7 @@
   expected& operator=(const expected& rhs) = default;
 
   // Note for SFNAIE above applies to here as well
-  expected& operator=(expected&& rhs) = default;
+  expected& operator=(expected&& rhs) noexcept(std::is_nothrow_move_assignable_v<E>) = default;
 
   template<class G = E>
   expected& operator=(const unexpected<G>& rhs) {
@@ -646,15 +634,13 @@
  public:
   // constructors
   constexpr unexpected(const unexpected&) = default;
-  constexpr unexpected(unexpected&&) = default;
+  constexpr unexpected(unexpected&&) noexcept(std::is_nothrow_move_constructible_v<E>) = default;
 
-  template<class Err = E _ENABLE_IF(
-    std::is_constructible_v<E, Err> &&
-    !std::is_same_v<remove_cvref_t<E>, std::in_place_t> &&
-    !std::is_same_v<remove_cvref_t<E>, unexpected>
-  )>
-  constexpr unexpected(Err&& e)
-  : val_(std::forward<Err>(e)) {}
+  template <class Err = E _ENABLE_IF(
+                std::is_constructible_v<E, Err> &&
+                !std::is_same_v<std::remove_cv_t<std::remove_reference_t<E>>, std::in_place_t> &&
+                !std::is_same_v<std::remove_cv_t<std::remove_reference_t<E>>, unexpected>)>
+  constexpr unexpected(Err&& e) : val_(std::forward<Err>(e)) {}
 
   template<class U, class... Args _ENABLE_IF(
     std::is_constructible_v<E, std::initializer_list<U>&, Args...>
@@ -724,7 +710,8 @@
 
   // assignment
   constexpr unexpected& operator=(const unexpected&) = default;
-  constexpr unexpected& operator=(unexpected&&) = default;
+  constexpr unexpected& operator=(unexpected&&) noexcept(std::is_nothrow_move_assignable_v<E>) =
+      default;
   template<class Err = E>
   constexpr unexpected& operator=(const unexpected<Err>& rhs) {
     val_ = rhs.value();
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index 2ebd57d..e01e39b 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -61,7 +61,7 @@
         LOG(ERROR) << "Could not map partition: " << partition_name;
         return false;
     }
-    auto closer = [partition_name]() -> void { DestroyLogicalPartition(partition_name, 5s); };
+    auto closer = [partition_name]() -> void { DestroyLogicalPartition(partition_name); };
     *handle = PartitionHandle(dm_path, std::move(closer));
     return true;
 }
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 3d3503c..65f0eff 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -73,6 +73,7 @@
     whole_static_libs: [
         "liblogwrap",
         "libdm",
+        "libext2_uuid",
         "libfstab",
     ],
     cppflags: [
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 259f800..7a0d019 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1331,7 +1331,7 @@
                 continue;
             }
         } else if ((current_entry.fs_mgr_flags.verify)) {
-            if (!fs_mgr_teardown_verity(&current_entry, true /* wait */)) {
+            if (!fs_mgr_teardown_verity(&current_entry)) {
                 LERROR << "Failed to tear down verified partition on mount point: "
                        << current_entry.mount_point;
                 ret |= FsMgrUmountStatus::ERROR_VERITY;
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index 1f21a71..04ba0bf 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -122,19 +122,9 @@
         table.set_readonly(false);
     }
     std::string name = GetPartitionName(partition);
-    if (!dm.CreateDevice(name, table)) {
+    if (!dm.CreateDevice(name, table, path, timeout_ms)) {
         return false;
     }
-    if (!dm.GetDmDevicePathByName(name, path)) {
-        return false;
-    }
-    if (timeout_ms > std::chrono::milliseconds::zero()) {
-        if (!WaitForFile(*path, timeout_ms)) {
-            DestroyLogicalPartition(name, {});
-            LERROR << "Timed out waiting for device path: " << *path;
-            return false;
-        }
-    }
     LINFO << "Created logical partition " << name << " on device " << *path;
     return true;
 }
@@ -194,24 +184,16 @@
                                   timeout_ms, path);
 }
 
-bool UnmapDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
+bool UnmapDevice(const std::string& name) {
     DeviceMapper& dm = DeviceMapper::Instance();
-    std::string path;
-    if (timeout_ms > std::chrono::milliseconds::zero()) {
-        dm.GetDmDevicePathByName(name, &path);
-    }
     if (!dm.DeleteDevice(name)) {
         return false;
     }
-    if (!path.empty() && !WaitForFileDeleted(path, timeout_ms)) {
-        LERROR << "Timed out waiting for device path to unlink: " << path;
-        return false;
-    }
     return true;
 }
 
-bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
-    if (!UnmapDevice(name, timeout_ms)) {
+bool DestroyLogicalPartition(const std::string& name) {
+    if (!UnmapDevice(name)) {
         return false;
     }
     LINFO << "Unmapped logical partition " << name;
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 31790b1..9a0f4fe 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -704,10 +704,9 @@
     return true;
 }
 
-// For GSI to skip mounting /product and /product_services, until there are
-// well-defined interfaces between them and /system. Otherwise, the GSI flashed
-// on /system might not be able to work with /product and /product_services.
-// When they're skipped here, /system/product and /system/product_services in
+// For GSI to skip mounting /product and /system_ext, until there are well-defined interfaces
+// between them and /system. Otherwise, the GSI flashed on /system might not be able to work with
+// /product and /system_ext. When they're skipped here, /system/product and /system/system_ext in
 // GSI will be used.
 bool SkipMountingPartitions(Fstab* fstab) {
     constexpr const char kSkipMountConfig[] = "/system/etc/init/config/skip_mount.cfg";
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 05ca5fc..ac15ce4 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -32,7 +32,6 @@
 #include <unistd.h>
 
 #include <algorithm>
-#include <map>
 #include <memory>
 #include <string>
 #include <vector>
@@ -445,7 +444,7 @@
     auto metadata = builder->Export();
     if (metadata && UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
         if (change) *change = true;
-        if (!DestroyLogicalPartition(partition_name, 0s)) return false;
+        if (!DestroyLogicalPartition(partition_name)) return false;
     } else {
         LERROR << "delete partition " << overlay;
         return false;
@@ -518,10 +517,166 @@
     return ret;
 }
 
+bool fs_mgr_overlayfs_set_shared_mount(const std::string& mount_point, bool shared_flag) {
+    auto ret = mount(nullptr, mount_point.c_str(), nullptr, shared_flag ? MS_SHARED : MS_PRIVATE,
+                     nullptr);
+    if (ret) {
+        PERROR << "__mount(target=" << mount_point
+               << ",flag=" << (shared_flag ? "MS_SHARED" : "MS_PRIVATE") << ")=" << ret;
+        return false;
+    }
+    return true;
+}
+
+bool fs_mgr_overlayfs_move_mount(const std::string& source, const std::string& target) {
+    auto ret = mount(source.c_str(), target.c_str(), nullptr, MS_MOVE, nullptr);
+    if (ret) {
+        PERROR << "__mount(source=" << source << ",target=" << target << ",flag=MS_MOVE)=" << ret;
+        return false;
+    }
+    return true;
+}
+
+struct mount_info {
+    std::string mount_point;
+    bool shared_flag;
+};
+
+std::vector<mount_info> ReadMountinfoFromFile(const std::string& path) {
+    std::vector<mount_info> info;
+
+    auto file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
+    if (!file) {
+        PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'";
+        return info;
+    }
+
+    ssize_t len;
+    size_t alloc_len = 0;
+    char* line = nullptr;
+    while ((len = getline(&line, &alloc_len, file.get())) != -1) {
+        /* if the last character is a newline, shorten the string by 1 byte */
+        if (line[len - 1] == '\n') {
+            line[len - 1] = '\0';
+        }
+
+        static constexpr char delim[] = " \t";
+        char* save_ptr;
+        if (!strtok_r(line, delim, &save_ptr)) {
+            LERROR << "Error parsing mount ID";
+            break;
+        }
+        if (!strtok_r(nullptr, delim, &save_ptr)) {
+            LERROR << "Error parsing parent ID";
+            break;
+        }
+        if (!strtok_r(nullptr, delim, &save_ptr)) {
+            LERROR << "Error parsing mount source";
+            break;
+        }
+        if (!strtok_r(nullptr, delim, &save_ptr)) {
+            LERROR << "Error parsing root";
+            break;
+        }
+
+        char* p;
+        if (!(p = strtok_r(nullptr, delim, &save_ptr))) {
+            LERROR << "Error parsing mount_point";
+            break;
+        }
+        mount_info entry = {p, false};
+
+        if (!strtok_r(nullptr, delim, &save_ptr)) {
+            LERROR << "Error parsing mount_flags";
+            break;
+        }
+
+        while ((p = strtok_r(nullptr, delim, &save_ptr))) {
+            if ((p[0] == '-') && (p[1] == '\0')) break;
+            if (android::base::StartsWith(p, "shared:")) entry.shared_flag = true;
+        }
+        if (!p) {
+            LERROR << "Error parsing fields";
+            break;
+        }
+        info.emplace_back(std::move(entry));
+    }
+
+    free(line);
+    if (info.empty()) {
+        LERROR << __FUNCTION__ << "(): failed to load mountinfo from : '" << path << "'";
+    }
+    return info;
+}
+
 bool fs_mgr_overlayfs_mount(const std::string& mount_point) {
     auto options = fs_mgr_get_overlayfs_options(mount_point);
     if (options.empty()) return false;
 
+    auto retval = true;
+    auto save_errno = errno;
+
+    struct move_entry {
+        std::string mount_point;
+        std::string dir;
+        bool shared_flag;
+    };
+    std::vector<move_entry> move;
+    auto parent_private = false;
+    auto parent_made_private = false;
+    auto dev_private = false;
+    auto dev_made_private = false;
+    for (auto& entry : ReadMountinfoFromFile("/proc/self/mountinfo")) {
+        if ((entry.mount_point == mount_point) && !entry.shared_flag) {
+            parent_private = true;
+        }
+        if ((entry.mount_point == "/dev") && !entry.shared_flag) {
+            dev_private = true;
+        }
+
+        if (!android::base::StartsWith(entry.mount_point, mount_point + "/")) {
+            continue;
+        }
+        if (std::find_if(move.begin(), move.end(), [&entry](const auto& it) {
+                return android::base::StartsWith(entry.mount_point, it.mount_point + "/");
+            }) != move.end()) {
+            continue;
+        }
+
+        // use as the bound directory in /dev.
+        auto new_context = fs_mgr_get_context(entry.mount_point);
+        if (!new_context.empty() && setfscreatecon(new_context.c_str())) {
+            PERROR << "setfscreatecon " << new_context;
+        }
+        move_entry new_entry = {std::move(entry.mount_point), "/dev/TemporaryDir-XXXXXX",
+                                entry.shared_flag};
+        const auto target = mkdtemp(new_entry.dir.data());
+        if (!target) {
+            retval = false;
+            save_errno = errno;
+            PERROR << "temporary directory for MS_BIND";
+            setfscreatecon(nullptr);
+            continue;
+        }
+        setfscreatecon(nullptr);
+
+        if (!parent_private && !parent_made_private) {
+            parent_made_private = fs_mgr_overlayfs_set_shared_mount(mount_point, false);
+        }
+        if (new_entry.shared_flag) {
+            new_entry.shared_flag = fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, false);
+        }
+        if (!fs_mgr_overlayfs_move_mount(new_entry.mount_point, new_entry.dir)) {
+            retval = false;
+            save_errno = errno;
+            if (new_entry.shared_flag) {
+                fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, true);
+            }
+            continue;
+        }
+        move.emplace_back(std::move(new_entry));
+    }
+
     // hijack __mount() report format to help triage
     auto report = "__mount(source=overlay,target="s + mount_point + ",type=overlay";
     const auto opt_list = android::base::Split(options, ",");
@@ -536,12 +691,38 @@
     auto ret = mount("overlay", mount_point.c_str(), "overlay", MS_RDONLY | MS_RELATIME,
                      options.c_str());
     if (ret) {
+        retval = false;
+        save_errno = errno;
         PERROR << report << ret;
-        return false;
     } else {
         LINFO << report << ret;
-        return true;
     }
+
+    // Move submounts back.
+    for (const auto& entry : move) {
+        if (!dev_private && !dev_made_private) {
+            dev_made_private = fs_mgr_overlayfs_set_shared_mount("/dev", false);
+        }
+
+        if (!fs_mgr_overlayfs_move_mount(entry.dir, entry.mount_point)) {
+            retval = false;
+            save_errno = errno;
+        } else if (entry.shared_flag &&
+                   !fs_mgr_overlayfs_set_shared_mount(entry.mount_point, true)) {
+            retval = false;
+            save_errno = errno;
+        }
+        rmdir(entry.dir.c_str());
+    }
+    if (dev_made_private) {
+        fs_mgr_overlayfs_set_shared_mount("/dev", true);
+    }
+    if (parent_made_private) {
+        fs_mgr_overlayfs_set_shared_mount(mount_point, true);
+    }
+
+    errno = save_errno;
+    return retval;
 }
 
 // Mount kScratchMountPoint
@@ -663,7 +844,7 @@
             if (!android::base::EndsWith(name, suffix)) {
                 continue;
             }
-            if (dm.GetState(name) != DmDeviceState::INVALID && !DestroyLogicalPartition(name, 2s)) {
+            if (dm.GetState(name) != DmDeviceState::INVALID && !DestroyLogicalPartition(name)) {
                 continue;
             }
             builder->ResizePartition(builder->FindPartition(name), 0);
@@ -737,7 +918,7 @@
                         return false;
                     }
                 }
-                if (!partition_create) DestroyLogicalPartition(partition_name, 10s);
+                if (!partition_create) DestroyLogicalPartition(partition_name);
                 changed = true;
                 *partition_exists = false;
             }
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 3a33cf3..c5e477c 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -97,10 +97,10 @@
 bool fs_mgr_is_ext4(const std::string& blk_device);
 bool fs_mgr_is_f2fs(const std::string& blk_device);
 
-bool fs_mgr_teardown_verity(android::fs_mgr::FstabEntry* fstab, bool wait);
+bool fs_mgr_teardown_verity(android::fs_mgr::FstabEntry* fstab);
 
 namespace android {
 namespace fs_mgr {
-bool UnmapDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms);
+bool UnmapDevice(const std::string& name);
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index be8077b..efa2180 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -547,9 +547,9 @@
     return retval;
 }
 
-bool fs_mgr_teardown_verity(FstabEntry* entry, bool wait) {
+bool fs_mgr_teardown_verity(FstabEntry* entry) {
     const std::string mount_point(basename(entry->mount_point.c_str()));
-    if (!android::fs_mgr::UnmapDevice(mount_point, wait ? 1000ms : 0ms)) {
+    if (!android::fs_mgr::UnmapDevice(mount_point)) {
         return false;
     }
     LINFO << "Unmapped verity device " << mount_point;
diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h
index f33fc02..a1dc2dc 100644
--- a/fs_mgr/include/fs_mgr_dm_linear.h
+++ b/fs_mgr/include/fs_mgr_dm_linear.h
@@ -68,7 +68,7 @@
 
 // Destroy the block device for a logical partition, by name. If |timeout_ms|
 // is non-zero, then this will block until the device path has been unlinked.
-bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms);
+bool DestroyLogicalPartition(const std::string& name);
 
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 21255df..e429d9f 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -29,6 +29,9 @@
         "loop_control.cpp",
     ],
 
+    static_libs: [
+        "libext2_uuid",
+    ],
     header_libs: [
         "libbase_headers",
         "liblog_headers",
@@ -46,6 +49,7 @@
     static_libs: [
         "libdm",
         "libbase",
+        "libext2_uuid",
         "libfs_mgr",
         "liblog",
     ],
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index d54b6ef..d56a4b1 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -20,12 +20,20 @@
 #include <sys/sysmacros.h>
 #include <sys/types.h>
 
+#include <functional>
+#include <thread>
+
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/macros.h>
+#include <android-base/strings.h>
+#include <uuid/uuid.h>
 
 namespace android {
 namespace dm {
 
+using namespace std::literals;
+
 DeviceMapper::DeviceMapper() : fd_(-1) {
     fd_ = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
     if (fd_ < 0) {
@@ -37,13 +45,13 @@
     static DeviceMapper instance;
     return instance;
 }
+
 // Creates a new device mapper device
-bool DeviceMapper::CreateDevice(const std::string& name) {
+bool DeviceMapper::CreateDevice(const std::string& name, const std::string& uuid) {
     if (name.empty()) {
         LOG(ERROR) << "Unnamed device mapper device creation is not supported";
         return false;
     }
-
     if (name.size() >= DM_NAME_LEN) {
         LOG(ERROR) << "[" << name << "] is too long to be device mapper name";
         return false;
@@ -51,6 +59,9 @@
 
     struct dm_ioctl io;
     InitIo(&io, name);
+    if (!uuid.empty()) {
+        snprintf(io.uuid, sizeof(io.uuid), "%s", uuid.c_str());
+    }
 
     if (ioctl(fd_, DM_DEV_CREATE, &io)) {
         PLOG(ERROR) << "DM_DEV_CREATE failed for [" << name << "]";
@@ -67,16 +78,6 @@
 }
 
 bool DeviceMapper::DeleteDevice(const std::string& name) {
-    if (name.empty()) {
-        LOG(ERROR) << "Unnamed device mapper device creation is not supported";
-        return false;
-    }
-
-    if (name.size() >= DM_NAME_LEN) {
-        LOG(ERROR) << "[" << name << "] is too long to be device mapper name";
-        return false;
-    }
-
     struct dm_ioctl io;
     InitIo(&io, name);
 
@@ -93,9 +94,81 @@
     return true;
 }
 
-const std::unique_ptr<DmTable> DeviceMapper::table(const std::string& /* name */) const {
-    // TODO(b/110035986): Return the table, as read from the kernel instead
-    return nullptr;
+bool WaitForCondition(const std::function<bool()>& condition,
+                      const std::chrono::milliseconds& timeout_ms) {
+    auto start_time = std::chrono::steady_clock::now();
+    while (true) {
+        if (condition()) return true;
+
+        std::this_thread::sleep_for(20ms);
+
+        auto now = std::chrono::steady_clock::now();
+        auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
+        if (time_elapsed > timeout_ms) return false;
+    }
+}
+
+static std::string GenerateUuid() {
+    uuid_t uuid_bytes;
+    uuid_generate(uuid_bytes);
+
+    char uuid_chars[37] = {};
+    uuid_unparse_lower(uuid_bytes, uuid_chars);
+
+    return std::string{uuid_chars};
+}
+
+bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
+                                const std::chrono::milliseconds& timeout_ms) {
+    std::string uuid = GenerateUuid();
+    if (!CreateDevice(name, uuid)) {
+        return false;
+    }
+
+    // We use the unique path for testing whether the device is ready. After
+    // that, it's safe to use the dm-N path which is compatible with callers
+    // that expect it to be formatted as such.
+    std::string unique_path;
+    if (!LoadTableAndActivate(name, table) || !GetDeviceUniquePath(name, &unique_path) ||
+        !GetDmDevicePathByName(name, path)) {
+        DeleteDevice(name);
+        return false;
+    }
+
+    if (timeout_ms <= std::chrono::milliseconds::zero()) {
+        return true;
+    }
+
+    auto condition = [&]() -> bool {
+        // If the file exists but returns EPERM or something, we consider the
+        // condition met.
+        if (access(unique_path.c_str(), F_OK) != 0) {
+            if (errno == ENOENT) return false;
+        }
+        return true;
+    };
+    if (!WaitForCondition(condition, timeout_ms)) {
+        LOG(ERROR) << "Timed out waiting for device path: " << unique_path;
+        DeleteDevice(name);
+        return false;
+    }
+    return true;
+}
+
+bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* path) {
+    struct dm_ioctl io;
+    InitIo(&io, name);
+    if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
+        PLOG(ERROR) << "Failed to get device path: " << name;
+        return false;
+    }
+
+    if (io.uuid[0] == '\0') {
+        LOG(ERROR) << "Device does not have a unique path: " << name;
+        return false;
+    }
+    *path = "/dev/block/mapper/by-uuid/"s + io.uuid;
+    return true;
 }
 
 DmDeviceState DeviceMapper::GetState(const std::string& name) const {
@@ -111,11 +184,8 @@
 }
 
 bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table) {
-    if (!CreateDevice(name)) {
-        return false;
-    }
-    if (!LoadTableAndActivate(name, table)) {
-        DeleteDevice(name);
+    std::string ignore_path;
+    if (!CreateDevice(name, table, &ignore_path, 0ms)) {
         return false;
     }
     return true;
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index c5881dd..7a834e2 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -52,10 +52,10 @@
   public:
     TempDevice(const std::string& name, const DmTable& table)
         : dm_(DeviceMapper::Instance()), name_(name), valid_(false) {
-        valid_ = dm_.CreateDevice(name, table);
+        valid_ = dm_.CreateDevice(name, table, &path_, 5s);
     }
     TempDevice(TempDevice&& other) noexcept
-        : dm_(other.dm_), name_(other.name_), valid_(other.valid_) {
+        : dm_(other.dm_), name_(other.name_), path_(other.path_), valid_(other.valid_) {
         other.valid_ = false;
     }
     ~TempDevice() {
@@ -70,29 +70,7 @@
         valid_ = false;
         return dm_.DeleteDevice(name_);
     }
-    bool WaitForUdev() const {
-        auto start_time = std::chrono::steady_clock::now();
-        while (true) {
-            if (!access(path().c_str(), F_OK)) {
-                return true;
-            }
-            if (errno != ENOENT) {
-                return false;
-            }
-            std::this_thread::sleep_for(50ms);
-            std::chrono::duration elapsed = std::chrono::steady_clock::now() - start_time;
-            if (elapsed >= 5s) {
-                return false;
-            }
-        }
-    }
-    std::string path() const {
-        std::string device_path;
-        if (!dm_.GetDmDevicePathByName(name_, &device_path)) {
-            return "";
-        }
-        return device_path;
-    }
+    std::string path() const { return path_; }
     const std::string& name() const { return name_; }
     bool valid() const { return valid_; }
 
@@ -109,6 +87,7 @@
   private:
     DeviceMapper& dm_;
     std::string name_;
+    std::string path_;
     bool valid_;
 };
 
@@ -139,7 +118,6 @@
     TempDevice dev("libdm-test-dm-linear", table);
     ASSERT_TRUE(dev.valid());
     ASSERT_FALSE(dev.path().empty());
-    ASSERT_TRUE(dev.WaitForUdev());
 
     auto& dm = DeviceMapper::Instance();
 
@@ -290,7 +268,6 @@
     origin_dev_ = std::make_unique<TempDevice>("libdm-test-dm-snapshot-origin", origin_table);
     ASSERT_TRUE(origin_dev_->valid());
     ASSERT_FALSE(origin_dev_->path().empty());
-    ASSERT_TRUE(origin_dev_->WaitForUdev());
 
     // chunk size = 4K blocks.
     DmTable snap_table;
@@ -302,7 +279,6 @@
     snapshot_dev_ = std::make_unique<TempDevice>("libdm-test-dm-snapshot", snap_table);
     ASSERT_TRUE(snapshot_dev_->valid());
     ASSERT_FALSE(snapshot_dev_->path().empty());
-    ASSERT_TRUE(snapshot_dev_->WaitForUdev());
 
     setup_ok_ = true;
 }
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index 08376c0..9c0c2f30 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -25,6 +25,7 @@
 #include <sys/sysmacros.h>
 #include <unistd.h>
 
+#include <chrono>
 #include <memory>
 #include <string>
 #include <utility>
@@ -73,10 +74,6 @@
     // Returns 'true' on success, false otherwise.
     bool DeleteDevice(const std::string& name);
 
-    // Reads the device mapper table from the device with given anme and
-    // returns it in a DmTable object.
-    const std::unique_ptr<DmTable> table(const std::string& name) const;
-
     // Returns the current state of the underlying device mapper device
     // with given name.
     // One of INVALID, SUSPENDED or ACTIVE.
@@ -84,6 +81,33 @@
 
     // Creates a device, loads the given table, and activates it. If the device
     // is not able to be activated, it is destroyed, and false is returned.
+    // After creation, |path| contains the result of calling
+    // GetDmDevicePathByName, and the path is guaranteed to exist. If after
+    // |timeout_ms| the path is not available, the device will be deleted and
+    // this function will return false.
+    //
+    // This variant must be used when depending on the device path. The
+    // following manual sequence should not be used:
+    //
+    //   1. CreateDevice(name, table)
+    //   2. GetDmDevicePathByName(name, &path)
+    //   3. fs_mgr::WaitForFile(path, <timeout>)
+    //
+    // This sequence has a race condition where, if another process deletes a
+    // device, CreateDevice may acquire the same path. When this happens, the
+    // WaitForFile() may early-return since ueventd has not yet processed all
+    // of the outstanding udev events. The caller may unexpectedly get an
+    // ENOENT on a system call using the affected path.
+    //
+    // If |timeout_ms| is 0ms, then this function will return true whether or
+    // not |path| is available. It is the caller's responsibility to ensure
+    // there are no races.
+    bool CreateDevice(const std::string& name, const DmTable& table, std::string* path,
+                      const std::chrono::milliseconds& timeout_ms);
+
+    // Create a device and activate the given table, without waiting to acquire
+    // a valid path. If the caller will use GetDmDevicePathByName(), it should
+    // use the timeout variant above.
     bool CreateDevice(const std::string& name, const DmTable& table);
 
     // Loads the device mapper table from parameter into the underlying device
@@ -110,8 +134,21 @@
     // Returns the path to the device mapper device node in '/dev' corresponding to
     // 'name'. If the device does not exist, false is returned, and the path
     // parameter is not set.
+    //
+    // This returns a path in the format "/dev/block/dm-N" that can be easily
+    // re-used with sysfs.
+    //
+    // WaitForFile() should not be used in conjunction with this call, since it
+    // could race with ueventd.
     bool GetDmDevicePathByName(const std::string& name, std::string* path);
 
+    // Returns a device's unique path as generated by ueventd. This will return
+    // true as long as the device has been created, even if ueventd has not
+    // processed it yet.
+    //
+    // The formatting of this path is /dev/block/mapper/by-uuid/<uuid>.
+    bool GetDeviceUniquePath(const std::string& name, std::string* path);
+
     // Returns the dev_t for the named device-mapper node.
     bool GetDeviceNumber(const std::string& name, dev_t* dev);
 
@@ -158,18 +195,12 @@
     // limit we are imposing here of 256.
     static constexpr uint32_t kMaxPossibleDmDevices = 256;
 
+    bool CreateDevice(const std::string& name, const std::string& uuid = {});
     bool GetTable(const std::string& name, uint32_t flags, std::vector<TargetInfo>* table);
-
     void InitIo(struct dm_ioctl* io, const std::string& name = std::string()) const;
 
     DeviceMapper();
 
-    // Creates a device mapper device with given name.
-    // Return 'true' on success and 'false' on failure to
-    // create OR if a device mapper device with the same name already
-    // exists.
-    bool CreateDevice(const std::string& name);
-
     int fd_;
     // Non-copyable & Non-movable
     DeviceMapper(const DeviceMapper&) = delete;
diff --git a/fs_mgr/libfs_avb/Android.bp b/fs_mgr/libfs_avb/Android.bp
index a3c76ab..414a186 100644
--- a/fs_mgr/libfs_avb/Android.bp
+++ b/fs_mgr/libfs_avb/Android.bp
@@ -61,6 +61,7 @@
         "libavb",
         "libavb_host_sysdeps",
         "libdm",
+        "libext2_uuid",
         "libfs_avb",
         "libfstab",
         "libgtest_host",
diff --git a/fs_mgr/libfs_avb/avb_util.cpp b/fs_mgr/libfs_avb/avb_util.cpp
index d9650f3..4505382 100644
--- a/fs_mgr/libfs_avb/avb_util.cpp
+++ b/fs_mgr/libfs_avb/avb_util.cpp
@@ -104,31 +104,23 @@
     }
     table.set_readonly(true);
 
+    std::chrono::milliseconds timeout = {};
+    if (wait_for_verity_dev) timeout = 1s;
+
+    std::string dev_path;
     const std::string mount_point(Basename(fstab_entry->mount_point));
     const std::string device_name(GetVerityDeviceName(*fstab_entry));
     android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance();
-    if (!dm.CreateDevice(device_name, table)) {
+    if (!dm.CreateDevice(device_name, table, &dev_path, timeout)) {
         LERROR << "Couldn't create verity device!";
         return false;
     }
 
-    std::string dev_path;
-    if (!dm.GetDmDevicePathByName(device_name, &dev_path)) {
-        LERROR << "Couldn't get verity device path!";
-        return false;
-    }
-
     // Marks the underlying block device as read-only.
     SetBlockDeviceReadOnly(fstab_entry->blk_device);
 
     // Updates fstab_rec->blk_device to verity device name.
     fstab_entry->blk_device = dev_path;
-
-    // Makes sure we've set everything up properly.
-    if (wait_for_verity_dev && !WaitForFile(dev_path, 1s)) {
-        return false;
-    }
-
     return true;
 }
 
diff --git a/init/Android.bp b/init/Android.bp
index 86dcb4c..ee339dd 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -74,7 +74,6 @@
     shared_libs: [
         "libbacktrace",
         "libbase",
-        "libbinder",
         "libbootloader_message",
         "libcutils",
         "libcrypto",
@@ -243,11 +242,12 @@
     ],
     whole_static_libs: ["libcap"],
     shared_libs: [
-        "libprotobuf-cpp-lite",
-        "libhidl-gen-utils",
-        "libprocessgroup",
-        "liblog",
         "libcutils",
+        "libhidl-gen-utils",
+        "libjsoncpp",
+        "liblog",
+        "libprocessgroup",
+        "libprotobuf-cpp-lite",
     ],
     srcs: [
         "action.cpp",
diff --git a/init/Android.mk b/init/Android.mk
index 9017772..006e1bf 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -113,6 +113,7 @@
     libunwindstack \
     libbacktrace \
     libmodprobe \
+    libext2_uuid \
 
 LOCAL_SANITIZE := signed-integer-overflow
 # First stage init is weird: it may start without stdout/stderr, and no /proc.
diff --git a/init/action.cpp b/init/action.cpp
index a169591..8cf7645 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -95,7 +95,7 @@
 }
 
 void Action::AddCommand(BuiltinFunction f, std::vector<std::string>&& args, int line) {
-    commands_.emplace_back(f, false, std::move(args), line);
+    commands_.emplace_back(std::move(f), false, std::move(args), line);
 }
 
 std::size_t Action::NumCommands() const {
diff --git a/init/action_manager.cpp b/init/action_manager.cpp
index 985b8ad..541c8f2 100644
--- a/init/action_manager.cpp
+++ b/init/action_manager.cpp
@@ -47,7 +47,7 @@
 void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
     auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0, name,
                                            std::map<std::string, std::string>{});
-    action->AddCommand(func, {name}, 0);
+    action->AddCommand(std::move(func), {name}, 0);
 
     event_queue_.emplace(action.get());
     actions_.emplace_back(std::move(action));
diff --git a/init/devices.cpp b/init/devices.cpp
index e8e6cd7..f6e453a 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -22,7 +22,6 @@
 #include <unistd.h>
 
 #include <chrono>
-#include <map>
 #include <memory>
 #include <string>
 #include <thread>
@@ -111,24 +110,16 @@
 // the supplied buffer with the dm module's instantiated name.
 // If it doesn't start with a virtual block device, or there is some
 // error, return false.
-static bool FindDmDevicePartition(const std::string& path, std::string* result) {
-    result->clear();
+static bool FindDmDevice(const std::string& path, std::string* name, std::string* uuid) {
     if (!StartsWith(path, "/devices/virtual/block/dm-")) return false;
-    if (getpid() == 1) return false;  // first_stage_init has no sepolicy needs
 
-    static std::map<std::string, std::string> cache;
-    // wait_for_file will not work, the content is also delayed ...
-    for (android::base::Timer t; t.duration() < 200ms; std::this_thread::sleep_for(10ms)) {
-        if (ReadFileToString("/sys" + path + "/dm/name", result) && !result->empty()) {
-            // Got it, set cache with result, when node arrives
-            cache[path] = *result = Trim(*result);
-            return true;
-        }
+    if (!ReadFileToString("/sys" + path + "/dm/name", name)) {
+        return false;
     }
-    auto it = cache.find(path);
-    if ((it == cache.end()) || (it->second.empty())) return false;
-    // Return cached results, when node goes away
-    *result = it->second;
+    ReadFileToString("/sys" + path + "/dm/uuid", uuid);
+
+    *name = android::base::Trim(*name);
+    *uuid = android::base::Trim(*uuid);
     return true;
 }
 
@@ -325,6 +316,7 @@
     std::string device;
     std::string type;
     std::string partition;
+    std::string uuid;
 
     if (FindPlatformDevice(uevent.path, &device)) {
         // Skip /devices/platform or /devices/ if present
@@ -342,8 +334,12 @@
         type = "pci";
     } else if (FindVbdDevicePrefix(uevent.path, &device)) {
         type = "vbd";
-    } else if (FindDmDevicePartition(uevent.path, &partition)) {
-        return {"/dev/block/mapper/" + partition};
+    } else if (FindDmDevice(uevent.path, &partition, &uuid)) {
+        std::vector<std::string> symlinks = {"/dev/block/mapper/" + partition};
+        if (!uuid.empty()) {
+            symlinks.emplace_back("/dev/block/mapper/by-uuid/" + uuid);
+        }
+        return symlinks;
     } else {
         return {};
     }
@@ -379,10 +375,41 @@
     return links;
 }
 
+static void RemoveDeviceMapperLinks(const std::string& devpath) {
+    std::vector<std::string> dirs = {
+            "/dev/block/mapper",
+            "/dev/block/mapper/by-uuid",
+    };
+    for (const auto& dir : dirs) {
+        if (access(dir.c_str(), F_OK) != 0) continue;
+
+        std::unique_ptr<DIR, decltype(&closedir)> dh(opendir(dir.c_str()), closedir);
+        if (!dh) {
+            PLOG(ERROR) << "Failed to open directory " << dir;
+            continue;
+        }
+
+        struct dirent* dp;
+        std::string link_path;
+        while ((dp = readdir(dh.get())) != nullptr) {
+            if (dp->d_type != DT_LNK) continue;
+
+            auto path = dir + "/" + dp->d_name;
+            if (Readlink(path, &link_path) && link_path == devpath) {
+                unlink(path.c_str());
+            }
+        }
+    }
+}
+
 void DeviceHandler::HandleDevice(const std::string& action, const std::string& devpath, bool block,
                                  int major, int minor, const std::vector<std::string>& links) const {
     if (action == "add") {
         MakeDevice(devpath, block, major, minor, links);
+    }
+
+    // We don't have full device-mapper information until a change event is fired.
+    if (action == "add" || (action == "change" && StartsWith(devpath, "/dev/block/dm-"))) {
         for (const auto& link : links) {
             if (!mkdir_recursive(Dirname(link), 0755)) {
                 PLOG(ERROR) << "Failed to create directory " << Dirname(link);
@@ -401,6 +428,9 @@
     }
 
     if (action == "remove") {
+        if (StartsWith(devpath, "/dev/block/dm-")) {
+            RemoveDeviceMapperLinks(devpath);
+        }
         for (const auto& link : links) {
             std::string link_path;
             if (Readlink(link, &link_path) && link_path == devpath) {
diff --git a/init/devices.h b/init/devices.h
index 9d39eaa..442c53f 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -84,9 +84,9 @@
     };
 
     Subsystem() {}
-    Subsystem(const std::string& name) : name_(name) {}
-    Subsystem(const std::string& name, DevnameSource source, const std::string& dir_name)
-        : name_(name), devname_source_(source), dir_name_(dir_name) {}
+    Subsystem(std::string name) : name_(std::move(name)) {}
+    Subsystem(std::string name, DevnameSource source, std::string dir_name)
+        : name_(std::move(name)), devname_source_(source), dir_name_(std::move(dir_name)) {}
 
     // Returns the full path for a uevent of a device that is a member of this subsystem,
     // according to the rules parsed from ueventd.rc
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
index 3e7c1a8..c408bc1 100644
--- a/init/devices_test.cpp
+++ b/init/devices_test.cpp
@@ -30,7 +30,7 @@
 class DeviceHandlerTester {
   public:
     void TestGetSymlinks(const std::string& platform_device, const Uevent& uevent,
-                         const std::vector<std::string> expected_links) {
+                         const std::vector<std::string>& expected_links) {
         TemporaryDir fake_sys_root;
         device_handler_.sysfs_mount_point_ = fake_sys_root.path;
 
diff --git a/init/host_init_verifier.cpp b/init/host_init_verifier.cpp
index 8aa3509..92c2aa5 100644
--- a/init/host_init_verifier.cpp
+++ b/init/host_init_verifier.cpp
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <fstream>
 #include <iostream>
 #include <iterator>
 #include <string>
@@ -29,6 +30,7 @@
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
+#include <json/json.h>
 
 #include "action.h"
 #include "action_manager.h"
@@ -129,21 +131,33 @@
     return nullptr;
 }
 
-static std::optional<std::set<std::string>> ReadKnownInterfaces(
-        const std::string& known_interfaces_file) {
-    if (known_interfaces_file.empty()) {
-        LOG(WARNING) << "Missing a known interfaces file.";
+static std::optional<android::init::InterfaceInheritanceHierarchyMap>
+ReadInterfaceInheritanceHierarchy(const std::string& interface_inheritance_hierarchy_file) {
+    if (interface_inheritance_hierarchy_file.empty()) {
+        LOG(WARNING) << "Missing an interface inheritance hierarchy file.";
         return {};
     }
 
-    std::string known_interfaces;
-    if (!ReadFileToString(known_interfaces_file, &known_interfaces)) {
-        LOG(ERROR) << "Failed to read known interfaces file '" << known_interfaces_file << "'";
+    Json::Value root;
+    Json::Reader reader;
+    std::ifstream stream(interface_inheritance_hierarchy_file);
+    if (!reader.parse(stream, root)) {
+        LOG(ERROR) << "Failed to read interface inheritance hierarchy file: "
+                   << interface_inheritance_hierarchy_file << "\n"
+                   << reader.getFormattedErrorMessages();
         return {};
     }
 
-    auto interfaces = Split(known_interfaces, " ");
-    return std::set<std::string>(interfaces.begin(), interfaces.end());
+    android::init::InterfaceInheritanceHierarchyMap result;
+    for (const Json::Value& entry : root) {
+        std::set<std::string> inherited_interfaces;
+        for (const Json::Value& intf : entry["inheritedInterfaces"]) {
+            inherited_interfaces.insert(intf.asString());
+        }
+        result[entry["interface"].asString()] = inherited_interfaces;
+    }
+
+    return result;
 }
 
 namespace android {
@@ -169,7 +183,7 @@
     android::base::InitLogging(argv, &android::base::StdioLogger);
     android::base::SetMinimumLogSeverity(android::base::ERROR);
 
-    std::string known_interfaces_file;
+    std::string interface_inheritance_hierarchy_file;
 
     while (true) {
         static const struct option long_options[] = {
@@ -177,7 +191,7 @@
                 {nullptr, 0, nullptr, 0},
         };
 
-        int arg = getopt_long(argc, argv, "p:k:", long_options, nullptr);
+        int arg = getopt_long(argc, argv, "p:i:", long_options, nullptr);
 
         if (arg == -1) {
             break;
@@ -190,8 +204,8 @@
             case 'p':
                 passwd_files.emplace_back(optarg);
                 break;
-            case 'k':
-                known_interfaces_file = optarg;
+            case 'i':
+                interface_inheritance_hierarchy_file = optarg;
                 break;
             default:
                 std::cerr << "getprop: getopt returned invalid result: " << arg << std::endl;
@@ -213,8 +227,10 @@
     ServiceList& sl = ServiceList::GetInstance();
     Parser parser;
     parser.AddSectionParser(
-            "service", std::make_unique<ServiceParser>(&sl, nullptr,
-                                                       ReadKnownInterfaces(known_interfaces_file)));
+            "service",
+            std::make_unique<ServiceParser>(
+                    &sl, nullptr,
+                    ReadInterfaceInheritanceHierarchy(interface_inheritance_hierarchy_file)));
     parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, nullptr));
     parser.AddSectionParser("import", std::make_unique<HostImportParser>());
 
diff --git a/init/init.cpp b/init/init.cpp
index 675f3e5..5dba54d 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -50,10 +50,6 @@
 #include <processgroup/setup.h>
 #include <selinux/android.h>
 
-#ifndef RECOVERY
-#include <binder/ProcessState.h>
-#endif
-
 #include "action_parser.h"
 #include "boringssl_self_test.h"
 #include "builtins.h"
@@ -139,12 +135,12 @@
         if (!parser.ParseConfig("/system/etc/init")) {
             late_import_paths.emplace_back("/system/etc/init");
         }
+        // late_import is available only in Q and earlier release. As we don't
+        // have system_ext in those versions, skip late_import for system_ext.
+        parser.ParseConfig("/system_ext/etc/init");
         if (!parser.ParseConfig("/product/etc/init")) {
             late_import_paths.emplace_back("/product/etc/init");
         }
-        if (!parser.ParseConfig("/product_services/etc/init")) {
-            late_import_paths.emplace_back("/product_services/etc/init");
-        }
         if (!parser.ParseConfig("/odm/etc/init")) {
             late_import_paths.emplace_back("/odm/etc/init");
         }
@@ -453,24 +449,6 @@
     return {};
 }
 
-static Result<void> InitBinder(const BuiltinArguments& args) {
-    // init's use of binder is very limited. init cannot:
-    //   - have any binder threads
-    //   - receive incoming binder calls
-    //   - pass local binder services to remote processes
-    //   - use death recipients
-    // The main supported usecases are:
-    //   - notifying other daemons (oneway calls only)
-    //   - retrieving data that is necessary to boot
-    // Also, binder can't be used by recovery.
-#ifndef RECOVERY
-    android::ProcessState::self()->setThreadPoolMaxThreadCount(0);
-    android::ProcessState::self()->setCallRestriction(
-            ProcessState::CallRestriction::ERROR_IF_NOT_ONEWAY);
-#endif
-    return {};
-}
-
 // Set the UDC controller for the ConfigFS USB Gadgets.
 // Read the UDC controller in use from "/sys/class/udc".
 // In case of multiple UDC controllers select the first one.
@@ -766,9 +744,6 @@
     // wasn't ready immediately after wait_for_coldboot_done
     am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
 
-    // Initialize binder before bringing up other system services
-    am.QueueBuiltinAction(InitBinder, "InitBinder");
-
     // Don't mount filesystems or start core system services in charger mode.
     std::string bootmode = GetProperty("ro.bootmode", "");
     if (bootmode == "charger") {
diff --git a/init/keychords.cpp b/init/keychords.cpp
index d0ca3e7..5f2682b 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -285,7 +285,7 @@
 
 void Keychords::Start(Epoll* epoll, std::function<void(const std::vector<int>&)> handler) {
     epoll_ = epoll;
-    handler_ = handler;
+    handler_ = std::move(handler);
     if (entries_.size()) GeteventOpenDevice();
 }
 
diff --git a/init/mount_handler.cpp b/init/mount_handler.cpp
index b0b63c5..791a019 100644
--- a/init/mount_handler.cpp
+++ b/init/mount_handler.cpp
@@ -140,11 +140,11 @@
         }
     }
     free(buf);
-    for (auto entry : untouched) {
+    for (auto& entry : untouched) {
         SetMountProperty(entry, false);
         mounts_.erase(entry);
     }
-    for (auto entry : touched) {
+    for (auto& entry : touched) {
         SetMountProperty(entry, true);
         mounts_.emplace(std::move(entry));
     }
diff --git a/init/parser.cpp b/init/parser.cpp
index bbfbdc6..6ab61cb 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -37,7 +37,7 @@
 }
 
 void Parser::AddSingleLineParser(const std::string& prefix, LineCallback callback) {
-    line_callbacks_.emplace_back(prefix, callback);
+    line_callbacks_.emplace_back(prefix, std::move(callback));
 }
 
 void Parser::ParseData(const std::string& filename, std::string* data) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index b89914f..8623c30 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -782,10 +782,9 @@
             "brand", "device", "manufacturer", "model", "name",
     };
     const char* RO_PRODUCT_PROPS_ALLOWED_SOURCES[] = {
-            "odm", "product", "product_services", "system", "vendor",
+            "odm", "product", "system_ext", "system", "vendor",
     };
-    const char* RO_PRODUCT_PROPS_DEFAULT_SOURCE_ORDER =
-            "product,product_services,odm,vendor,system";
+    const char* RO_PRODUCT_PROPS_DEFAULT_SOURCE_ORDER = "product,odm,vendor,system_ext,system";
     const std::string EMPTY = "";
 
     std::string ro_product_props_source_order =
@@ -892,6 +891,7 @@
         }
     }
     load_properties_from_file("/system/build.prop", nullptr, &properties);
+    load_properties_from_file("/system_ext/build.prop", nullptr, &properties);
     load_properties_from_file("/vendor/default.prop", nullptr, &properties);
     load_properties_from_file("/vendor/build.prop", nullptr, &properties);
     if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) {
@@ -901,7 +901,6 @@
         load_properties_from_file("/odm/build.prop", nullptr, &properties);
     }
     load_properties_from_file("/product/build.prop", nullptr, &properties);
-    load_properties_from_file("/product_services/build.prop", nullptr, &properties);
     load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
 
     if (load_debug_prop) {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index d9d885c..cb54d34 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -636,11 +636,9 @@
     bool run_fsck = false;
     bool command_invalid = false;
 
-    if (cmd_params.size() > 3) {
-        command_invalid = true;
-    } else if (cmd_params[0] == "shutdown") {
+    if (cmd_params[0] == "shutdown") {
         cmd = ANDROID_RB_POWEROFF;
-        if (cmd_params.size() == 2) {
+        if (cmd_params.size() >= 2) {
             if (cmd_params[1] == "userrequested") {
                 // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
                 // Run fsck once the file system is remounted in read-only mode.
@@ -671,6 +669,13 @@
                                   "bootloader_message: "
                                << err;
                 }
+            } else if (reboot_target == "recovery") {
+                const std::vector<std::string> options = {};
+                std::string err;
+                if (!write_bootloader_message(options, &err)) {
+                    LOG(ERROR) << "Failed to set bootloader message: " << err;
+                    return false;
+                }
             } else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
                        reboot_target == "fastboot") {
                 std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot"
@@ -686,9 +691,9 @@
                 reboot_target = "recovery";
             }
 
-            // If there is an additional parameter, pass it along
-            if ((cmd_params.size() == 3) && cmd_params[2].size()) {
-                reboot_target += "," + cmd_params[2];
+            // If there are additional parameter, pass them along
+            for (size_t i = 2; (cmd_params.size() > i) && cmd_params[i].size(); ++i) {
+                reboot_target += "," + cmd_params[i];
             }
         }
     } else {
diff --git a/init/security.cpp b/init/security.cpp
index 5d87f3c..586d0c7 100644
--- a/init/security.cpp
+++ b/init/security.cpp
@@ -83,7 +83,7 @@
     return {};
 }
 
-static bool SetHighestAvailableOptionValue(std::string path, int min, int max) {
+static bool SetHighestAvailableOptionValue(const std::string& path, int min, int max) {
     std::ifstream inf(path, std::fstream::in);
     if (!inf) {
         LOG(ERROR) << "Cannot open for reading: " << path;
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index ba35104..88ce364 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -18,6 +18,9 @@
 
 #include <linux/input.h>
 
+#include <algorithm>
+#include <sstream>
+
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
@@ -152,12 +155,6 @@
         return Error() << "Interface name must not be a value name '" << interface_name << "'";
     }
 
-    if (known_interfaces_ && known_interfaces_->count(interface_name) == 0) {
-        return Error() << "Interface is not in the known set of hidl_interfaces: '"
-                       << interface_name << "'. Please ensure the interface is built "
-                       << "by a hidl_interface target.";
-    }
-
     const std::string fullname = interface_name + "/" + instance_name;
 
     for (const auto& svc : *service_list_) {
@@ -540,6 +537,37 @@
         return {};
     }
 
+    if (interface_inheritance_hierarchy_) {
+        std::set<std::string> interface_names;
+        for (const std::string& intf : service_->interfaces()) {
+            interface_names.insert(Split(intf, "/")[0]);
+        }
+        std::ostringstream error_stream;
+        for (const std::string& intf : interface_names) {
+            if (interface_inheritance_hierarchy_->count(intf) == 0) {
+                error_stream << "\nInterface is not in the known set of hidl_interfaces: '" << intf
+                             << "'. Please ensure the interface is spelled correctly and built "
+                             << "by a hidl_interface target.";
+                continue;
+            }
+            const std::set<std::string>& required_interfaces =
+                    (*interface_inheritance_hierarchy_)[intf];
+            std::set<std::string> diff;
+            std::set_difference(required_interfaces.begin(), required_interfaces.end(),
+                                interface_names.begin(), interface_names.end(),
+                                std::inserter(diff, diff.begin()));
+            if (!diff.empty()) {
+                error_stream << "\nInterface '" << intf << "' requires its full inheritance "
+                             << "hierarchy to be listed in this init_rc file. Missing "
+                             << "interfaces: [" << base::Join(diff, " ") << "]";
+            }
+        }
+        const std::string& errors = error_stream.str();
+        if (!errors.empty()) {
+            return Error() << errors;
+        }
+    }
+
     Service* old_service = service_list_->FindService(service_->name());
     if (old_service) {
         if (!service_->is_override()) {
diff --git a/init/service_parser.h b/init/service_parser.h
index 5a16768..5ad26ef 100644
--- a/init/service_parser.h
+++ b/init/service_parser.h
@@ -26,13 +26,16 @@
 namespace android {
 namespace init {
 
+using InterfaceInheritanceHierarchyMap = std::map<std::string, std::set<std::string>>;
+
 class ServiceParser : public SectionParser {
   public:
-    ServiceParser(ServiceList* service_list, std::vector<Subcontext>* subcontexts,
-                  const std::optional<std::set<std::string>>& known_interfaces)
+    ServiceParser(
+            ServiceList* service_list, std::vector<Subcontext>* subcontexts,
+            const std::optional<InterfaceInheritanceHierarchyMap>& interface_inheritance_hierarchy)
         : service_list_(service_list),
           subcontexts_(subcontexts),
-          known_interfaces_(known_interfaces),
+          interface_inheritance_hierarchy_(interface_inheritance_hierarchy),
           service_(nullptr) {}
     Result<void> ParseSection(std::vector<std::string>&& args, const std::string& filename,
                               int line) override;
@@ -85,7 +88,7 @@
 
     ServiceList* service_list_;
     std::vector<Subcontext>* subcontexts_;
-    std::optional<std::set<std::string>> known_interfaces_;
+    std::optional<InterfaceInheritanceHierarchyMap> interface_inheritance_hierarchy_;
     std::unique_ptr<Service> service_;
     std::string filename_;
 };
diff --git a/init/test_function_map.h b/init/test_function_map.h
index 293f1f9..466836c 100644
--- a/init/test_function_map.h
+++ b/init/test_function_map.h
@@ -30,17 +30,17 @@
   public:
     // Helper for argument-less functions
     using BuiltinFunctionNoArgs = std::function<void(void)>;
-    void Add(const std::string& name, const BuiltinFunctionNoArgs function) {
-        Add(name, 0, 0, false, [function](const BuiltinArguments&) {
-            function();
+    void Add(const std::string& name, BuiltinFunctionNoArgs function) {
+        Add(name, 0, 0, false, [f = std::move(function)](const BuiltinArguments&) {
+            f();
             return Result<void>{};
         });
     }
 
     void Add(const std::string& name, std::size_t min_parameters, std::size_t max_parameters,
-             bool run_in_subcontext, const BuiltinFunction function) {
-        builtin_functions_[name] =
-            make_tuple(min_parameters, max_parameters, make_pair(run_in_subcontext, function));
+             bool run_in_subcontext, BuiltinFunction function) {
+        builtin_functions_[name] = make_tuple(min_parameters, max_parameters,
+                                              make_pair(run_in_subcontext, std::move(function)));
     }
 
   private:
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 3b9de0f..8b2cf62 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -146,7 +146,7 @@
 
 void ColdBoot::RegenerateUevents() {
     uevent_listener_.RegenerateUevents([this](const Uevent& uevent) {
-        uevent_queue_.emplace_back(std::move(uevent));
+        uevent_queue_.emplace_back(uevent);
         return ListenerAction::kContinue;
     });
 }
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 897a169..b29638c 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -106,7 +106,7 @@
 // oem/ file-system since the intent is to provide support for customized
 // portions of a separate vendor.img or oem.img.  Has to remain open so that
 // customization can also land on /system/vendor, /system/oem, /system/odm,
-// /system/product or /system/product_services.
+// /system/product or /system/system_ext.
 //
 // We expect build-time checking or filtering when constructing the associated
 // fs_config_* files (see build/tools/fs_config/fs_config_generate.c)
@@ -118,15 +118,12 @@
 static const char odm_conf_file[] = "/odm/etc/fs_config_files";
 static const char product_conf_dir[] = "/product/etc/fs_config_dirs";
 static const char product_conf_file[] = "/product/etc/fs_config_files";
-static const char product_services_conf_dir[] = "/product_services/etc/fs_config_dirs";
-static const char product_services_conf_file[] = "/product_services/etc/fs_config_files";
+static const char system_ext_conf_dir[] = "/system_ext/etc/fs_config_dirs";
+static const char system_ext_conf_file[] = "/system_ext/etc/fs_config_files";
 static const char* conf[][2] = {
-        {sys_conf_file, sys_conf_dir},
-        {ven_conf_file, ven_conf_dir},
-        {oem_conf_file, oem_conf_dir},
-        {odm_conf_file, odm_conf_dir},
-        {product_conf_file, product_conf_dir},
-        {product_services_conf_file, product_services_conf_dir},
+        {sys_conf_file, sys_conf_dir},         {ven_conf_file, ven_conf_dir},
+        {oem_conf_file, oem_conf_dir},         {odm_conf_file, odm_conf_dir},
+        {product_conf_file, product_conf_dir}, {system_ext_conf_file, system_ext_conf_dir},
 };
 
 // Do not use android_files to grant Linux capabilities.  Use ambient capabilities in their
@@ -158,9 +155,9 @@
     { 00600, AID_ROOT,      AID_ROOT,      0, "product/build.prop" },
     { 00444, AID_ROOT,      AID_ROOT,      0, product_conf_dir + 1 },
     { 00444, AID_ROOT,      AID_ROOT,      0, product_conf_file + 1 },
-    { 00600, AID_ROOT,      AID_ROOT,      0, "product_services/build.prop" },
-    { 00444, AID_ROOT,      AID_ROOT,      0, product_services_conf_dir + 1 },
-    { 00444, AID_ROOT,      AID_ROOT,      0, product_services_conf_file + 1 },
+    { 00600, AID_ROOT,      AID_ROOT,      0, "system_ext/build.prop" },
+    { 00444, AID_ROOT,      AID_ROOT,      0, system_ext_conf_dir + 1 },
+    { 00444, AID_ROOT,      AID_ROOT,      0, system_ext_conf_file + 1 },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/crash_dump32" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/crash_dump64" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/debuggerd" },
@@ -248,9 +245,9 @@
 }
 
 // if path is "odm/<stuff>", "oem/<stuff>", "product/<stuff>",
-// "product_services/<stuff>" or "vendor/<stuff>"
+// "system_ext/<stuff>" or "vendor/<stuff>"
 static bool is_partition(const std::string& path) {
-    static const char* partitions[] = {"odm/", "oem/", "product/", "product_services/", "vendor/"};
+    static const char* partitions[] = {"odm/", "oem/", "product/", "system_ext/", "vendor/"};
     for (size_t i = 0; i < (sizeof(partitions) / sizeof(partitions[0])); ++i) {
         if (StartsWith(path, partitions[i])) return true;
     }
@@ -285,10 +282,8 @@
     if (fnmatch(pattern.c_str(), input.c_str(), fnm_flags) == 0) return true;
 
     // Check match between logical partition's files and patterns.
-    static constexpr const char* kLogicalPartitions[] = {"system/product/",
-                                                         "system/product_services/",
-                                                         "system/vendor/",
-                                                         "vendor/odm/"};
+    static constexpr const char* kLogicalPartitions[] = {"system/product/", "system/system_ext/",
+                                                         "system/vendor/", "vendor/odm/"};
     for (auto& logical_partition : kLogicalPartitions) {
         if (StartsWith(input, logical_partition)) {
             std::string input_in_partition = input.substr(input.find('/') + 1);
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index 7fa3f43..a4b3cd7 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -407,63 +407,15 @@
 }
 
 int __android_log_buf_write(int bufID, int prio, const char* tag, const char* msg) {
-  struct iovec vec[3];
-  char tmp_tag[32];
-
   if (!tag) tag = "";
 
-  /* XXX: This needs to go! */
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wstring-plus-int"
-  if (bufID != LOG_ID_RADIO) {
-    switch (tag[0]) {
-      case 'H':
-        if (strcmp(tag + 1, "HTC_RIL" + 1)) break;
-        goto inform;
-      case 'R':
-        /* Any log tag with "RIL" as the prefix */
-        if (strncmp(tag + 1, "RIL" + 1, strlen("RIL") - 1)) break;
-        goto inform;
-      case 'Q':
-        /* Any log tag with "QC_RIL" as the prefix */
-        if (strncmp(tag + 1, "QC_RIL" + 1, strlen("QC_RIL") - 1)) break;
-        goto inform;
-      case 'I':
-        /* Any log tag with "IMS" as the prefix */
-        if (strncmp(tag + 1, "IMS" + 1, strlen("IMS") - 1)) break;
-        goto inform;
-      case 'A':
-        if (strcmp(tag + 1, "AT" + 1)) break;
-        goto inform;
-      case 'G':
-        if (strcmp(tag + 1, "GSM" + 1)) break;
-        goto inform;
-      case 'S':
-        if (strcmp(tag + 1, "STK" + 1) && strcmp(tag + 1, "SMS" + 1)) break;
-        goto inform;
-      case 'C':
-        if (strcmp(tag + 1, "CDMA" + 1)) break;
-        goto inform;
-      case 'P':
-        if (strcmp(tag + 1, "PHONE" + 1)) break;
-      /* FALLTHRU */
-      inform:
-        bufID = LOG_ID_RADIO;
-        snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
-        tag = tmp_tag;
-        [[fallthrough]];
-      default:
-        break;
-    }
-  }
-#pragma clang diagnostic pop
-
 #if __BIONIC__
   if (prio == ANDROID_LOG_FATAL) {
     android_set_abort_message(msg);
   }
 #endif
 
+  struct iovec vec[3];
   vec[0].iov_base = (unsigned char*)&prio;
   vec[0].iov_len = 1;
   vec[1].iov_base = (void*)tag;
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 5423de5..a0a6b4f 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -246,6 +246,7 @@
         "tests/files/offline/jit_debug_x86/*",
         "tests/files/offline/jit_map_arm/*",
         "tests/files/offline/gnu_debugdata_arm/*",
+        "tests/files/offline/load_bias_ro_rx_x86_64/*",
         "tests/files/offline/offset_arm/*",
         "tests/files/offline/shared_lib_in_apk_arm64/*",
         "tests/files/offline/shared_lib_in_apk_memory_only_arm64/*",
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index f0e4138..bdfee01 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -197,6 +197,7 @@
 template <typename EhdrType, typename PhdrType>
 void ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
   uint64_t offset = ehdr.e_phoff;
+  bool first_exec_load_header = true;
   for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
     PhdrType phdr;
     if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) {
@@ -212,9 +213,11 @@
 
       pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
                                           static_cast<size_t>(phdr.p_memsz)};
-      if (phdr.p_offset == 0) {
-        *load_bias = phdr.p_vaddr;
+      // Only set the load bias from the first executable load header.
+      if (first_exec_load_header && phdr.p_vaddr > phdr.p_offset) {
+        *load_bias = phdr.p_vaddr - phdr.p_offset;
       }
+      first_exec_load_header = false;
       break;
     }
 
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index cdc927a..f9ee9eb 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -360,7 +360,7 @@
 
   uint64_t load_bias = 0;
   ASSERT_TRUE(elf->Init(&load_bias));
-  EXPECT_EQ(0U, load_bias);
+  EXPECT_EQ(0x1001U, load_bias);
 
   const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
   ASSERT_EQ(1U, pt_loads.size());
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index baada82..e6158a2 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -1457,4 +1457,77 @@
   EXPECT_EQ(0xc2044218, unwinder.frames()[0].sp);
 }
 
+TEST_F(UnwindOfflineTest, load_bias_ro_rx_x86_64) {
+  ASSERT_NO_FATAL_FAILURE(Init("load_bias_ro_rx_x86_64/", ARCH_X86_64));
+
+  Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.Unwind();
+
+  std::string frame_info(DumpFrames(unwinder));
+  ASSERT_EQ(17U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+  EXPECT_EQ(
+      "  #00 pc 00000000000e9dd4  libc.so (__write+20)\n"
+      "  #01 pc 000000000007ab9c  libc.so (_IO_file_write+44)\n"
+      "  #02 pc 0000000000079f3e  libc.so\n"
+      "  #03 pc 000000000007bce8  libc.so (_IO_do_write+24)\n"
+      "  #04 pc 000000000007b26e  libc.so (_IO_file_xsputn+270)\n"
+      "  #05 pc 000000000004f7f9  libc.so (_IO_vfprintf+1945)\n"
+      "  #06 pc 0000000000057cb5  libc.so (_IO_printf+165)\n"
+      "  #07 pc 0000000000ed1796  perfetto_unittests "
+      "(testing::internal::PrettyUnitTestResultPrinter::OnTestIterationStart(testing::UnitTest "
+      "const&, int)+374)\n"
+      "  #08 pc 0000000000ed30fd  perfetto_unittests "
+      "(testing::internal::TestEventRepeater::OnTestIterationStart(testing::UnitTest const&, "
+      "int)+125)\n"
+      "  #09 pc 0000000000ed5e25  perfetto_unittests "
+      "(testing::internal::UnitTestImpl::RunAllTests()+581)\n"
+      "  #10 pc 0000000000ef63f3  perfetto_unittests "
+      "(_ZN7testing8internal38HandleSehExceptionsInMethodIfSupportedINS0_12UnitTestImplEbEET0_PT_"
+      "MS4_FS3_vEPKc+131)\n"
+      "  #11 pc 0000000000ee2a21  perfetto_unittests "
+      "(_ZN7testing8internal35HandleExceptionsInMethodIfSupportedINS0_12UnitTestImplEbEET0_PT_MS4_"
+      "FS3_vEPKc+113)\n"
+      "  #12 pc 0000000000ed5bb9  perfetto_unittests (testing::UnitTest::Run()+185)\n"
+      "  #13 pc 0000000000e900f0  perfetto_unittests (RUN_ALL_TESTS()+16)\n"
+      "  #14 pc 0000000000e900d8  perfetto_unittests (main+56)\n"
+      "  #15 pc 000000000002352a  libc.so (__libc_start_main+234)\n"
+      "  #16 pc 0000000000919029  perfetto_unittests (_start+41)\n",
+      frame_info);
+
+  EXPECT_EQ(0x7f9326a57dd4ULL, unwinder.frames()[0].pc);
+  EXPECT_EQ(0x7ffd224153c8ULL, unwinder.frames()[0].sp);
+  EXPECT_EQ(0x7f93269e8b9cULL, unwinder.frames()[1].pc);
+  EXPECT_EQ(0x7ffd224153d0ULL, unwinder.frames()[1].sp);
+  EXPECT_EQ(0x7f93269e7f3eULL, unwinder.frames()[2].pc);
+  EXPECT_EQ(0x7ffd22415400ULL, unwinder.frames()[2].sp);
+  EXPECT_EQ(0x7f93269e9ce8ULL, unwinder.frames()[3].pc);
+  EXPECT_EQ(0x7ffd22415440ULL, unwinder.frames()[3].sp);
+  EXPECT_EQ(0x7f93269e926eULL, unwinder.frames()[4].pc);
+  EXPECT_EQ(0x7ffd22415450ULL, unwinder.frames()[4].sp);
+  EXPECT_EQ(0x7f93269bd7f9ULL, unwinder.frames()[5].pc);
+  EXPECT_EQ(0x7ffd22415490ULL, unwinder.frames()[5].sp);
+  EXPECT_EQ(0x7f93269c5cb5ULL, unwinder.frames()[6].pc);
+  EXPECT_EQ(0x7ffd22415a10ULL, unwinder.frames()[6].sp);
+  EXPECT_EQ(0xed1796ULL, unwinder.frames()[7].pc);
+  EXPECT_EQ(0x7ffd22415af0ULL, unwinder.frames()[7].sp);
+  EXPECT_EQ(0xed30fdULL, unwinder.frames()[8].pc);
+  EXPECT_EQ(0x7ffd22415b70ULL, unwinder.frames()[8].sp);
+  EXPECT_EQ(0xed5e25ULL, unwinder.frames()[9].pc);
+  EXPECT_EQ(0x7ffd22415bb0ULL, unwinder.frames()[9].sp);
+  EXPECT_EQ(0xef63f3ULL, unwinder.frames()[10].pc);
+  EXPECT_EQ(0x7ffd22415c60ULL, unwinder.frames()[10].sp);
+  EXPECT_EQ(0xee2a21ULL, unwinder.frames()[11].pc);
+  EXPECT_EQ(0x7ffd22415cc0ULL, unwinder.frames()[11].sp);
+  EXPECT_EQ(0xed5bb9ULL, unwinder.frames()[12].pc);
+  EXPECT_EQ(0x7ffd22415d40ULL, unwinder.frames()[12].sp);
+  EXPECT_EQ(0xe900f0ULL, unwinder.frames()[13].pc);
+  EXPECT_EQ(0x7ffd22415d90ULL, unwinder.frames()[13].sp);
+  EXPECT_EQ(0xe900d8ULL, unwinder.frames()[14].pc);
+  EXPECT_EQ(0x7ffd22415da0ULL, unwinder.frames()[14].sp);
+  EXPECT_EQ(0x7f932699152aULL, unwinder.frames()[15].pc);
+  EXPECT_EQ(0x7ffd22415dd0ULL, unwinder.frames()[15].sp);
+  EXPECT_EQ(0x919029ULL, unwinder.frames()[16].pc);
+  EXPECT_EQ(0x7ffd22415e90ULL, unwinder.frames()[16].sp);
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/libc.so b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/libc.so
new file mode 100644
index 0000000..63383d0
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/maps.txt b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/maps.txt
new file mode 100644
index 0000000..ba5a31b
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/maps.txt
@@ -0,0 +1,3 @@
+200000-919000 r--p 0 00:00 0   perfetto_unittests
+919000-1a0c000 r-xp 719000 00:00 0   perfetto_unittests
+7f932696e000-7f9326b23000 r-xp 0 00:00 0   libc.so
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/perfetto_unittests b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/perfetto_unittests
new file mode 100644
index 0000000..a30e599
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/perfetto_unittests
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/regs.txt b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/regs.txt
new file mode 100644
index 0000000..6cb4055
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/regs.txt
@@ -0,0 +1,17 @@
+rax: 3b
+rbx: 3b
+rcx: 7f9326a57dd4
+rdx: 3b
+r8: 7ffd22415b09
+r9: 7ffd224155e0
+r10: 0
+r11: 246
+r12: 7f9326d28760
+r13: 3b
+r14: 7f9326d23760
+r15: 3b
+rdi: 1
+rsi: 2678850
+rbp: 2678850
+rsp: 7ffd224153c8
+rip: 7f9326a57dd4
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/stack.data b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/stack.data
new file mode 100644
index 0000000..4edfe07
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/stack.data
Binary files differ
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index a105474..3a02a8a 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -188,9 +188,6 @@
 // ---------------------------------------------------------------------------
 namespace android {
 
-class TextOutput;
-TextOutput& printWeakPointer(TextOutput& to, const void* val);
-
 // ---------------------------------------------------------------------------
 
 #define COMPARE_WEAK(_op_)                                      \
@@ -459,9 +456,6 @@
     weakref_type*   m_refs;
 };
 
-template <typename T>
-TextOutput& operator<<(TextOutput& to, const wp<T>& val);
-
 #undef COMPARE_WEAK
 
 // ---------------------------------------------------------------------------
@@ -635,12 +629,6 @@
     }
 }
 
-template <typename T>
-inline TextOutput& operator<<(TextOutput& to, const wp<T>& val)
-{
-    return printWeakPointer(to, val.unsafe_get());
-}
-
 // ---------------------------------------------------------------------------
 
 // this class just serves as a namespace so TYPE::moveReferences can stay
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 48140b8..42af751 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -79,6 +79,7 @@
 #define MEMCG_MEMORYSW_USAGE "/dev/memcg/memory.memsw.usage_in_bytes"
 #define ZONEINFO_PATH "/proc/zoneinfo"
 #define MEMINFO_PATH "/proc/meminfo"
+#define PROC_STATUS_TGID_FIELD "Tgid:"
 #define LINE_MAX 128
 
 /* Android Logger event logtags (see event.logtags) */
@@ -551,6 +552,49 @@
            (to->tv_nsec - from->tv_nsec) / (long)NS_PER_MS;
 }
 
+static int proc_get_tgid(int pid) {
+    char path[PATH_MAX];
+    char buf[PAGE_SIZE];
+    int fd;
+    ssize_t size;
+    char *pos;
+    int64_t tgid = -1;
+
+    snprintf(path, PATH_MAX, "/proc/%d/status", pid);
+    fd = open(path, O_RDONLY | O_CLOEXEC);
+    if (fd < 0) {
+        return -1;
+    }
+
+    size = read_all(fd, buf, sizeof(buf) - 1);
+    if (size < 0) {
+        goto out;
+    }
+    buf[size] = 0;
+
+    pos = buf;
+    while (true) {
+        pos = strstr(pos, PROC_STATUS_TGID_FIELD);
+        /* Stop if TGID tag not found or found at the line beginning */
+        if (pos == NULL || pos == buf || pos[-1] == '\n') {
+            break;
+        }
+        pos++;
+    }
+
+    if (pos == NULL) {
+        goto out;
+    }
+
+    pos += strlen(PROC_STATUS_TGID_FIELD);
+    while (*pos == ' ') pos++;
+    parse_int64(pos, &tgid);
+
+out:
+    close(fd);
+    return (int)tgid;
+}
+
 static void cmd_procprio(LMKD_CTRL_PACKET packet) {
     struct proc *procp;
     char path[80];
@@ -559,6 +603,7 @@
     struct lmk_procprio params;
     bool is_system_server;
     struct passwd *pwdrec;
+    int tgid;
 
     lmkd_pack_get_procprio(packet, &params);
 
@@ -568,6 +613,14 @@
         return;
     }
 
+    /* Check if registered process is a thread group leader */
+    tgid = proc_get_tgid(params.pid);
+    if (tgid >= 0 && tgid != params.pid) {
+        ALOGE("Attempt to register a task that is not a thread group leader (tid %d, tgid %d)",
+            params.pid, tgid);
+        return;
+    }
+
     /* gid containing AID_READPROC required */
     /* CAP_SYS_RESOURCE required */
     /* CAP_DAC_OVERRIDE required */
@@ -1332,6 +1385,7 @@
 static int kill_one_process(struct proc* procp, int min_oom_score) {
     int pid = procp->pid;
     uid_t uid = procp->uid;
+    int tgid;
     char *taskname;
     int tasksize;
     int r;
@@ -1345,6 +1399,12 @@
     (void)(min_oom_score);
 #endif
 
+    tgid = proc_get_tgid(pid);
+    if (tgid >= 0 && tgid != pid) {
+        ALOGE("Possible pid reuse detected (pid %d, tgid %d)!", pid, tgid);
+        goto out;
+    }
+
     taskname = proc_get_name(pid);
     if (!taskname) {
         goto out;
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index b1616d3..a6ea2ab 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -7,6 +7,7 @@
 # absolute path of an executable is selected.
 dir.system = /system/bin/
 dir.system = /system/xbin/
+dir.system = /%SYSTEM_EXT%/bin/
 dir.system = /%PRODUCT%/bin/
 
 dir.vendor = /odm/bin/
@@ -48,8 +49,8 @@
 namespace.default.visible = true
 
 namespace.default.search.paths  = /system/${LIB}
+namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
 namespace.default.search.paths += /%PRODUCT%/${LIB}
-namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
 
 # We can't have entire /system/${LIB} as permitted paths because doing so
 # makes it possible to load libs in /system/${LIB}/vndk* directories by
@@ -61,12 +62,15 @@
 namespace.default.permitted.paths  = /system/${LIB}/drm
 namespace.default.permitted.paths += /system/${LIB}/extractors
 namespace.default.permitted.paths += /system/${LIB}/hw
+namespace.default.permitted.paths += /%SYSTEM_EXT%/${LIB}
 namespace.default.permitted.paths += /%PRODUCT%/${LIB}
-namespace.default.permitted.paths += /%PRODUCT_SERVICES%/${LIB}
 # These are where odex files are located. libart has to be able to dlopen the files
 namespace.default.permitted.paths += /system/framework
 namespace.default.permitted.paths += /system/app
 namespace.default.permitted.paths += /system/priv-app
+namespace.default.permitted.paths += /%SYSTEM_EXT%/framework
+namespace.default.permitted.paths += /%SYSTEM_EXT%/app
+namespace.default.permitted.paths += /%SYSTEM_EXT%/priv-app
 namespace.default.permitted.paths += /vendor/framework
 namespace.default.permitted.paths += /vendor/app
 namespace.default.permitted.paths += /vendor/priv-app
@@ -80,9 +84,6 @@
 namespace.default.permitted.paths += /%PRODUCT%/framework
 namespace.default.permitted.paths += /%PRODUCT%/app
 namespace.default.permitted.paths += /%PRODUCT%/priv-app
-namespace.default.permitted.paths += /%PRODUCT_SERVICES%/framework
-namespace.default.permitted.paths += /%PRODUCT_SERVICES%/app
-namespace.default.permitted.paths += /%PRODUCT_SERVICES%/priv-app
 namespace.default.permitted.paths += /data
 namespace.default.permitted.paths += /mnt/expand
 namespace.default.permitted.paths += /apex/com.android.runtime/${LIB}/bionic
@@ -90,10 +91,10 @@
 
 namespace.default.asan.search.paths  = /data/asan/system/${LIB}
 namespace.default.asan.search.paths +=           /system/${LIB}
+namespace.default.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
+namespace.default.asan.search.paths +=           /%SYSTEM_EXT%/${LIB}
 namespace.default.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
 namespace.default.asan.search.paths +=           /%PRODUCT%/${LIB}
-namespace.default.asan.search.paths += /data/asan/%PRODUCT_SERVICES%/${LIB}
-namespace.default.asan.search.paths +=           /%PRODUCT_SERVICES%/${LIB}
 
 namespace.default.asan.permitted.paths  = /data
 namespace.default.asan.permitted.paths += /system/${LIB}/drm
@@ -102,6 +103,10 @@
 namespace.default.asan.permitted.paths += /system/framework
 namespace.default.asan.permitted.paths += /system/app
 namespace.default.asan.permitted.paths += /system/priv-app
+namespace.default.asan.permitted.paths += /%SYSTEM_EXT%/${LIB}
+namespace.default.asan.permitted.paths += /%SYSTEM_EXT%/framework
+namespace.default.asan.permitted.paths += /%SYSTEM_EXT%/app
+namespace.default.asan.permitted.paths += /%SYSTEM_EXT%/priv-app
 namespace.default.asan.permitted.paths += /vendor/framework
 namespace.default.asan.permitted.paths += /vendor/app
 namespace.default.asan.permitted.paths += /vendor/priv-app
@@ -116,10 +121,6 @@
 namespace.default.asan.permitted.paths += /%PRODUCT%/framework
 namespace.default.asan.permitted.paths += /%PRODUCT%/app
 namespace.default.asan.permitted.paths += /%PRODUCT%/priv-app
-namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/${LIB}
-namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/framework
-namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/app
-namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/priv-app
 namespace.default.asan.permitted.paths += /mnt/expand
 namespace.default.asan.permitted.paths += /apex/com.android.runtime/${LIB}/bionic
 namespace.default.asan.permitted.paths += /system/${LIB}/bootstrap
@@ -510,15 +511,15 @@
 namespace.system.isolated = false
 
 namespace.system.search.paths  = /system/${LIB}
+namespace.system.search.paths += /%SYSTEM_EXT%/${LIB}
 namespace.system.search.paths += /%PRODUCT%/${LIB}
-namespace.system.search.paths += /%PRODUCT_SERVICES%/${LIB}
 
 namespace.system.asan.search.paths  = /data/asan/system/${LIB}
 namespace.system.asan.search.paths +=           /system/${LIB}
-namespace.system.asan.search.paths += /data/asan/product/${LIB}
+namespace.system.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
+namespace.system.asan.search.paths +=           /%SYSTEM_EXT%/${LIB}
+namespace.system.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
 namespace.system.asan.search.paths +=           /%PRODUCT%/${LIB}
-namespace.system.asan.search.paths += /data/asan/product_services/${LIB}
-namespace.system.asan.search.paths +=           /%PRODUCT_SERVICES%/${LIB}
 
 namespace.system.links = runtime
 namespace.system.link.runtime.shared_libs  = libdexfile_external.so
@@ -553,15 +554,15 @@
 # The search paths here should be kept the same as that of the 'system'
 # namespace.
 namespace.vndk_in_system.search.paths  = /system/${LIB}
+namespace.vndk_in_system.search.paths += /%SYSTEM_EXT%/${LIB}
 namespace.vndk_in_system.search.paths += /%PRODUCT%/${LIB}
-namespace.vndk_in_system.search.paths += /%PRODUCT_SERVICES%/${LIB}
 
 namespace.vndk_in_system.asan.search.paths  = /data/asan/system/${LIB}
 namespace.vndk_in_system.asan.search.paths +=           /system/${LIB}
-namespace.vndk_in_system.asan.search.paths += /data/asan/product/${LIB}
+namespace.vndk_in_system.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
+namespace.vndk_in_system.asan.search.paths +=           /%SYSTEM_EXT%/${LIB}
+namespace.vndk_in_system.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
 namespace.vndk_in_system.asan.search.paths +=           /%PRODUCT%/${LIB}
-namespace.vndk_in_system.asan.search.paths += /data/asan/product_services/${LIB}
-namespace.vndk_in_system.asan.search.paths +=           /%PRODUCT_SERVICES%/${LIB}
 
 namespace.vndk_in_system.whitelisted = %VNDK_USING_CORE_VARIANT_LIBRARIES%
 
@@ -705,7 +706,7 @@
 [postinstall]
 namespace.default.isolated = false
 namespace.default.search.paths  = /system/${LIB}
+namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
 namespace.default.search.paths += /%PRODUCT%/${LIB}
-namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
 
 namespace.default.link.runtime.shared_libs = %SANITIZER_RUNTIME_LIBRARIES%
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 9212408..69535a9 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -7,6 +7,7 @@
 # absolute path of an executable is selected.
 dir.system = /system/bin/
 dir.system = /system/xbin/
+dir.system = /%SYSTEM_EXT%/bin/
 dir.system = /%PRODUCT%/bin/
 
 dir.vendor = /odm/bin/
@@ -48,21 +49,21 @@
 namespace.default.visible = true
 
 namespace.default.search.paths  = /system/${LIB}
+namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
+namespace.default.search.paths += /%PRODUCT%/${LIB}
 namespace.default.search.paths += /odm/${LIB}
 namespace.default.search.paths += /vendor/${LIB}
-namespace.default.search.paths += /%PRODUCT%/${LIB}
-namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
 
 namespace.default.asan.search.paths  = /data/asan/system/${LIB}
 namespace.default.asan.search.paths +=           /system/${LIB}
+namespace.default.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
+namespace.default.asan.search.paths +=           /%SYSTEM_EXT%/${LIB}
+namespace.default.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
+namespace.default.asan.search.paths +=           /%PRODUCT%/${LIB}
 namespace.default.asan.search.paths += /data/asan/odm/${LIB}
 namespace.default.asan.search.paths +=           /odm/${LIB}
 namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
 namespace.default.asan.search.paths +=           /vendor/${LIB}
-namespace.default.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
-namespace.default.asan.search.paths +=           /%PRODUCT%/${LIB}
-namespace.default.asan.search.paths += /data/asan/%PRODUCT_SERVICES%/${LIB}
-namespace.default.asan.search.paths +=           /%PRODUCT_SERVICES%/${LIB}
 
 # Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
 # If a shared library or an executable requests a shared library that
@@ -336,8 +337,9 @@
 # Access to system libraries is allowed
 namespace.default.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
 namespace.default.search.paths += /system/${LIB}
+namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
 namespace.default.search.paths += /%PRODUCT%/${LIB}
-namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
+# Put /system/lib/vndk at the last search order in vndk_lite for GSI
 namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER%
 
 namespace.default.asan.search.paths  = /data/asan/odm/${LIB}
@@ -356,10 +358,10 @@
 namespace.default.asan.search.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%
 namespace.default.asan.search.paths += /data/asan/system/${LIB}
 namespace.default.asan.search.paths +=           /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/product/${LIB}
+namespace.default.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
+namespace.default.asan.search.paths +=           /%SYSTEM_EXT%/${LIB}
+namespace.default.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
 namespace.default.asan.search.paths +=           /%PRODUCT%/${LIB}
-namespace.default.asan.search.paths += /data/asan/product_services/${LIB}
-namespace.default.asan.search.paths +=           /%PRODUCT_SERVICES%/${LIB}
 namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
 namespace.default.asan.search.paths +=           /system/${LIB}/vndk%VNDK_VER%
 
@@ -514,5 +516,5 @@
 [postinstall]
 namespace.default.isolated = false
 namespace.default.search.paths  = /system/${LIB}
+namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
 namespace.default.search.paths += /%PRODUCT%/${LIB}
-namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 3acf301..96ffa69 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -413,6 +413,10 @@
     # HALs required before storage encryption can get unlocked (FBE/FDE)
     class_start early_hal
 
+    # Check and mark a successful boot, before mounting userdata with mount_all.
+    # No-op for non-A/B device.
+    exec_start update_verifier_nonencrypted
+
 on post-fs-data
     mark_post_data
 
@@ -628,22 +632,16 @@
 # It is recommended to put unnecessary data/ initialization from post-fs-data
 # to start-zygote in device's init.rc to unblock zygote start.
 on zygote-start && property:ro.crypto.state=unencrypted
-    # A/B update verifier that marks a successful boot.
-    exec_start update_verifier_nonencrypted
     start netd
     start zygote
     start zygote_secondary
 
 on zygote-start && property:ro.crypto.state=unsupported
-    # A/B update verifier that marks a successful boot.
-    exec_start update_verifier_nonencrypted
     start netd
     start zygote
     start zygote_secondary
 
 on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
-    # A/B update verifier that marks a successful boot.
-    exec_start update_verifier_nonencrypted
     start netd
     start zygote
     start zygote_secondary
@@ -770,8 +768,6 @@
     trigger zygote-start
 
 on property:vold.decrypt=trigger_restart_min_framework
-    # A/B update verifier that marks a successful boot.
-    exec_start update_verifier
     class_start main
 
 on property:vold.decrypt=trigger_restart_framework
diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk
index f62c3df..c949a4f 100644
--- a/rootdir/update_and_install_ld_config.mk
+++ b/rootdir/update_and_install_ld_config.mk
@@ -147,12 +147,7 @@
 	$(hide) sed -i.bak -e "s?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g" $@
 	$(hide) sed -i.bak -e "s?%VNDK_VER%?$(PRIVATE_VNDK_VERSION_SUFFIX)?g" $@
 	$(hide) sed -i.bak -e "s?%PRODUCT%?$(TARGET_COPY_OUT_PRODUCT)?g" $@
-ifeq ($(TARGET_COPY_OUT_PRODUCT),$(TARGET_COPY_OUT_PRODUCT_SERVICES))
-	# Remove lines containing %PRODUCT_SERVICES% (identical to the %PRODUCT% ones)
-	$(hide) sed -i.bak -e "\?%PRODUCT_SERVICES%?d" $@
-else
-	$(hide) sed -i.bak -e "s?%PRODUCT_SERVICES%?$(TARGET_COPY_OUT_PRODUCT_SERVICES)?g" $@
-endif
+	$(hide) sed -i.bak -e "s?%SYSTEM_EXT%?$(TARGET_COPY_OUT_SYSTEM_EXT)?g" $@
 	$(hide) sed -i.bak -e "s?^$(PRIVATE_VNDK_VERSION_TAG)??g" $@
 	$(hide) sed -i.bak "/^\#VNDK[0-9]\{2\}\#.*$$/d" $@
 	$(hide) rm -f $@.bak
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
index 1926a4f..d391cc1 100644
--- a/shell_and_utilities/README.md
+++ b/shell_and_utilities/README.md
@@ -214,7 +214,7 @@
 
 ## Android R
 
-BSD: grep fsck\_msdos newfs\_msdos
+BSD: fsck\_msdos newfs\_msdos
 
 bzip2: bzcat bzip2 bunzip2