Merge "Implement unique_fd.ok()"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 6f6481f..f6ef906 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -82,3 +82,9 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/sbin/charger)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/sbin)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/sbin)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product_services)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product_services.img)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product_services)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/product_services)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/product_services)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/debug_ramdisk/product_services)
diff --git a/adb/Android.bp b/adb/Android.bp
index b6aff3e..47dafff 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",
@@ -220,6 +221,7 @@
     target: {
         windows: {
             enabled: true,
+            ldflags: ["-municode"],
             shared_libs: ["AdbWinApi"],
         },
     },
@@ -435,7 +437,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/commandline.cpp b/adb/client/commandline.cpp
index 7211f72..11a3dfd 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -128,7 +128,7 @@
         " pull [-a] REMOTE... LOCAL\n"
         "     copy files/dirs from device\n"
         "     -a: preserve file timestamp and mode\n"
-        " sync [all|data|odm|oem|product_services|product|system|vendor]\n"
+        " sync [all|data|odm|oem|product|system|system_ext|vendor]\n"
         "     sync a local build from $ANDROID_PRODUCT_OUT to the device (default all)\n"
         "     -l: list but don't copy\n"
         "\n"
@@ -775,17 +775,16 @@
         error_exit("abb is not supported by the device");
     }
 
+    optind = 1;  // argv[0] is always "abb", so set `optind` appropriately.
+
     // Defaults.
     constexpr char escape_char = '~';  // -e
     constexpr bool use_shell_protocol = true;
     constexpr auto shell_type_arg = kShellServiceArgRaw;
     constexpr bool empty_command = false;
 
-    std::string service_string("abb:");
-    for (auto i = optind; i < argc; ++i) {
-        service_string.append(argv[i]);
-        service_string.push_back(ABB_ARG_DELIMETER);
-    }
+    std::vector<const char*> args(argv + optind, argv + argc);
+    std::string service_string = "abb:" + android::base::Join(args, ABB_ARG_DELIMETER);
 
     D("abb -e 0x%x [%*.s]\n", escape_char, static_cast<int>(service_string.size()),
       service_string.data());
@@ -1843,8 +1842,8 @@
         }
 
         if (src.empty()) src = "all";
-        std::vector<std::string> partitions{"data",   "odm",   "oem", "product", "product_services",
-                                            "system", "vendor"};
+        std::vector<std::string> partitions{"data",   "odm",        "oem",   "product",
+                                            "system", "system_ext", "vendor"};
         bool found = false;
         for (const auto& partition : partitions) {
             if (src == "all" || src == partition) {
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/client/usb_linux.cpp b/adb/client/usb_linux.cpp
index 81b8306..17b4db1 100644
--- a/adb/client/usb_linux.cpp
+++ b/adb/client/usb_linux.cpp
@@ -324,7 +324,7 @@
 
     h->urb_out_busy = true;
     while (true) {
-        auto now = std::chrono::system_clock::now();
+        auto now = std::chrono::steady_clock::now();
         if (h->cv.wait_until(lock, now + 5s) == std::cv_status::timeout || h->dead) {
             // TODO: call USBDEVFS_DISCARDURB?
             errno = ETIMEDOUT;
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/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index 79cebe6..0f4b39c 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -25,6 +25,21 @@
 #include "sysdeps.h"
 #include "sysdeps/chrono.h"
 
+#if defined(_WIN32)
+#include <windows.h>
+static bool IsWine() {
+    HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
+    if (!ntdll) {
+        return false;
+    }
+    return GetProcAddress(ntdll, "wine_get_version") != nullptr;
+}
+#else
+static bool IsWine() {
+    return false;
+}
+#endif
+
 TEST(sysdeps_socketpair, smoke) {
     int fds[2];
     ASSERT_EQ(0, adb_socketpair(fds)) << strerror(errno);
@@ -182,8 +197,10 @@
 
     EXPECT_EQ(1, adb_poll(&pfd, 1, 100));
 
-    // Linux returns POLLIN | POLLHUP, Windows returns just POLLHUP.
-    EXPECT_EQ(POLLHUP, pfd.revents & POLLHUP);
+    if (!IsWine()) {
+        // Linux returns POLLIN | POLLHUP, Windows returns just POLLHUP.
+        EXPECT_EQ(POLLHUP, pfd.revents & POLLHUP);
+    }
 }
 
 TEST_F(sysdeps_poll, fd_count) {
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index f86cd03..6372b3d 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -610,15 +610,6 @@
 
 static int _fh_socket_close(FH f) {
     if (f->fh_socket != INVALID_SOCKET) {
-        /* gently tell any peer that we're closing the socket */
-        if (shutdown(f->fh_socket, SD_BOTH) == SOCKET_ERROR) {
-            // If the socket is not connected, this returns an error. We want to
-            // minimize logging spam, so don't log these errors for now.
-#if 0
-            D("socket shutdown failed: %s",
-              android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
-#endif
-        }
         if (closesocket(f->fh_socket) == SOCKET_ERROR) {
             // Don't set errno here, since adb_close will ignore it.
             const DWORD err = WSAGetLastError();
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/Android.bp b/base/Android.bp
index 58b6fb5..357ce01 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -53,6 +53,7 @@
         "logging.cpp",
         "mapped_file.cpp",
         "parsenetaddress.cpp",
+        "process.cpp",
         "properties.cpp",
         "quick_exit.cpp",
         "stringprintf.cpp",
@@ -145,6 +146,7 @@
         "parsedouble_test.cpp",
         "parseint_test.cpp",
         "parsenetaddress_test.cpp",
+        "process_test.cpp",
         "properties_test.cpp",
         "quick_exit_test.cpp",
         "result_test.cpp",
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/base/include/android-base/logging.h b/base/include/android-base/logging.h
index f94cc25..ab6476c 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -469,7 +469,7 @@
 }  // namespace base
 }  // namespace android
 
-namespace std {
+namespace std {  // NOLINT(cert-dcl58-cpp)
 
 // Emit a warning of ostream<< with std::string*. The intention was most likely to print *string.
 //
diff --git a/base/include/android-base/process.h b/base/include/android-base/process.h
new file mode 100644
index 0000000..69ed3fb
--- /dev/null
+++ b/base/include/android-base/process.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <dirent.h>
+#include <sys/types.h>
+
+#include <iterator>
+#include <memory>
+#include <vector>
+
+namespace android {
+namespace base {
+
+class AllPids {
+  class PidIterator {
+   public:
+    PidIterator(DIR* dir) : dir_(dir, closedir) { Increment(); }
+    PidIterator& operator++() {
+      Increment();
+      return *this;
+    }
+    bool operator==(const PidIterator& other) const { return pid_ == other.pid_; }
+    bool operator!=(const PidIterator& other) const { return !(*this == other); }
+    long operator*() const { return pid_; }
+    // iterator traits
+    using difference_type = pid_t;
+    using value_type = pid_t;
+    using pointer = const pid_t*;
+    using reference = const pid_t&;
+    using iterator_category = std::input_iterator_tag;
+
+   private:
+    void Increment();
+
+    pid_t pid_ = -1;
+    std::unique_ptr<DIR, decltype(&closedir)> dir_;
+  };
+
+ public:
+  PidIterator begin() { return opendir("/proc"); }
+  PidIterator end() { return nullptr; }
+};
+
+}  // namespace base
+}  // namespace android
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 2b05956..6e11b4e 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -259,9 +259,9 @@
 
 // A wrapper type that can be implicitly constructed from either int or unique_fd.
 struct borrowed_fd {
-  /* implicit */ borrowed_fd(int fd) : fd_(fd) {}
+  /* implicit */ borrowed_fd(int fd) : fd_(fd) {}  // NOLINT
   template <typename T>
-  /* implicit */ borrowed_fd(const unique_fd_impl<T>& ufd) : fd_(ufd.get()) {}
+  /* implicit */ borrowed_fd(const unique_fd_impl<T>& ufd) : fd_(ufd.get()) {}  // NOLINT
 
   int get() const { return fd_; }
 
diff --git a/fs_mgr/libfiemap_writer/utility.h b/base/process.cpp
similarity index 66%
rename from fs_mgr/libfiemap_writer/utility.h
rename to base/process.cpp
index 2d418da..b8cabf6 100644
--- a/fs_mgr/libfiemap_writer/utility.h
+++ b/base/process.cpp
@@ -14,17 +14,26 @@
  * limitations under the License.
  */
 
-#pragma once
-
-#include <string>
+#include "android-base/process.h"
 
 namespace android {
-namespace fiemap_writer {
+namespace base {
 
-// Given a file that will be created, determine the maximum size its containing
-// filesystem allows. Note this is a theoretical maximum size; free space is
-// ignored entirely.
-uint64_t DetermineMaximumFileSize(const std::string& file_path);
+void AllPids::PidIterator::Increment() {
+  if (!dir_) {
+    return;
+  }
 
-}  // namespace fiemap_writer
+  dirent* de;
+  while ((de = readdir(dir_.get())) != nullptr) {
+    pid_t pid = atoi(de->d_name);
+    if (pid != 0) {
+      pid_ = pid;
+      return;
+    }
+  }
+  pid_ = -1;
+}
+
+}  // namespace base
 }  // namespace android
diff --git a/fs_mgr/libfiemap_writer/utility.h b/base/process_test.cpp
similarity index 62%
copy from fs_mgr/libfiemap_writer/utility.h
copy to base/process_test.cpp
index 2d418da..056f667 100644
--- a/fs_mgr/libfiemap_writer/utility.h
+++ b/base/process_test.cpp
@@ -14,17 +14,22 @@
  * limitations under the License.
  */
 
-#pragma once
+#include "android-base/process.h"
 
-#include <string>
+#include <unistd.h>
 
-namespace android {
-namespace fiemap_writer {
+#include <gtest/gtest.h>
 
-// Given a file that will be created, determine the maximum size its containing
-// filesystem allows. Note this is a theoretical maximum size; free space is
-// ignored entirely.
-uint64_t DetermineMaximumFileSize(const std::string& file_path);
+TEST(process, find_ourselves) {
+#if defined(__linux__)
+  bool found_our_pid = false;
+  for (const auto& pid : android::base::AllPids{}) {
+    if (pid == getpid()) {
+      found_our_pid = true;
+    }
+  }
 
-}  // namespace fiemap_writer
-}  // namespace android
+  EXPECT_TRUE(found_our_pid);
+
+#endif
+}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 6936cc2..cd9fda3 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -140,13 +140,13 @@
     {"mba_err", 13},
     {"Watchdog", 14},
     {"Panic", 15},
-    {"power_key", 16},  // Mediatek
-    {"power_on", 17},
+    {"power_key", 16},  // aliasReasons to cold,powerkey (Mediatek)
+    {"power_on", 17},   // aliasReasons to cold,powerkey
     {"Reboot", 18},
     {"rtc", 19},
     {"edl", 20},
     {"oem_pon1", 21},
-    {"oem_powerkey", 22},
+    {"oem_powerkey", 22},  // aliasReasons to cold,powerkey
     {"oem_unknown_reset", 23},
     {"srto: HWWDT reset SC", 24},
     {"srto: HWWDT reset platform", 25},
@@ -201,15 +201,15 @@
     {"hard,hw_reset", 72},
     {"shutdown,suspend", 73},    // Suspend to RAM
     {"shutdown,hibernate", 74},  // Suspend to DISK
-    {"power_on_key", 75},
-    {"reboot_by_key", 76},
-    {"wdt_by_pass_pwk", 77},  // Mediatek
-    {"reboot_longkey", 78},
-    {"powerkey", 79},
-    {"usb", 80},               // Mediatek
-    {"wdt", 81},               // Mediatek
-    {"tool_by_pass_pwk", 82},  // Mediatek
-    {"2sec_reboot", 83},       // Mediatek
+    {"power_on_key", 75},        // aliasReasons to cold,powerkey
+    {"reboot_by_key", 76},       // translated to reboot,by_key
+    {"wdt_by_pass_pwk", 77},     // Mediatek
+    {"reboot_longkey", 78},      // translated to reboot,longkey
+    {"powerkey", 79},            // aliasReasons to cold,powerkey
+    {"usb", 80},                 // aliasReasons to cold,charger (Mediatek)
+    {"wdt", 81},                 // Mediatek
+    {"tool_by_pass_pwk", 82},    // aliasReasons to reboot,tool (Mediatek)
+    {"2sec_reboot", 83},         // aliasReasons to cold,rtc,2sec (Mediatek)
     {"reboot,by_key", 84},
     {"reboot,longkey", 85},
     {"reboot,2sec", 86},  // Deprecate in two years, replaced with cold,rtc,2sec
@@ -219,28 +219,28 @@
     {"reboot,rescueparty", 90},
     {"charge", 91},
     {"oem_tz_crash", 92},
-    {"uvlo", 93},  // aliasReasons converts to reboot,undervoltage
+    {"uvlo", 93},  // aliasReasons to reboot,undervoltage
     {"oem_ps_hold", 94},
     {"abnormal_reset", 95},
     {"oemerr_unknown", 96},
     {"reboot_fastboot_mode", 97},
     {"watchdog_apps_bite", 98},
     {"xpu_err", 99},
-    {"power_on_usb", 100},
+    {"power_on_usb", 100},  // aliasReasons to cold,charger
     {"watchdog_rpm", 101},
     {"watchdog_nonsec", 102},
     {"watchdog_apps_bark", 103},
     {"reboot_dmverity_corrupted", 104},
-    {"reboot_smpl", 105},  // aliasReasons converts to reboot,powerloss
+    {"reboot_smpl", 105},  // aliasReasons to reboot,powerloss
     {"watchdog_sdi_apps_reset", 106},
-    {"smpl", 107},  // aliasReasons converts to reboot,powerloss
+    {"smpl", 107},  // aliasReasons to reboot,powerloss
     {"oem_modem_failed_to_powerup", 108},
     {"reboot_normal", 109},
     {"oem_lpass_cfg", 110},
     {"oem_xpu_ns_error", 111},
-    {"power_key_press", 112},
+    {"power_key_press", 112},  // aliasReasons to cold,powerkey
     {"hardware_reset", 113},
-    {"reboot_by_powerkey", 114},
+    {"reboot_by_powerkey", 114},  // aliasReasons to cold,powerkey (is this correct?)
     {"reboot_verity", 115},
     {"oem_rpm_undef_error", 116},
     {"oem_crash_on_the_lk", 117},
@@ -250,7 +250,7 @@
     {"factory_cable", 121},
     {"oem_ar6320_failed_to_powerup", 122},
     {"watchdog_rpm_bite", 123},
-    {"power_on_cable", 124},
+    {"power_on_cable", 124},  // aliasReasons to cold,charger
     {"reboot_unknown", 125},
     {"wireless_charger", 126},
     {"0x776655ff", 127},
@@ -839,12 +839,12 @@
     // following table smaller.
     static const std::vector<std::pair<const std::string, const std::string>> aliasReasons = {
         {"watchdog", "wdog"},
-        {"cold,powerkey", "powerkey|power_key|PowerKey"},
         {"kernel_panic", "panic"},
         {"shutdown,thermal", "thermal"},
         {"warm,s3_wakeup", "s3_wakeup"},
         {"hard,hw_reset", "hw_reset"},
-        {"cold,charger", "usb"},
+        {"cold,charger", "usb|power_on_cable"},
+        {"cold,powerkey", "powerkey|power_key|PowerKey|power_on"},
         {"cold,rtc", "rtc"},
         {"cold,rtc,2sec", "2sec_reboot"},
         {"!warm", "wdt_by_pass_pwk"},  // change flavour of blunt
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index 60eb241..1a5b435 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -22,9 +22,11 @@
 #include <sys/poll.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <time.h>
 #include <unistd.h>
 
 #include <chrono>
+#include <iomanip>
 
 #include <android-base/cmsg.h>
 #include <android-base/file.h>
@@ -42,8 +44,10 @@
 
 using namespace std::chrono_literals;
 
+using android::base::ReadFileToString;
 using android::base::SendFileDescriptors;
 using android::base::unique_fd;
+using android::base::WriteStringToFd;
 
 static bool send_signal(pid_t pid, const DebuggerdDumpType dump_type) {
   const int signal = (dump_type == kDebuggerdJavaBacktrace) ? SIGQUIT : DEBUGGER_SIGNAL;
@@ -65,6 +69,76 @@
   tv->tv_usec = static_cast<long>(microseconds.count());
 }
 
+static void get_wchan_header(pid_t pid, std::stringstream& buffer) {
+  struct tm now;
+  time_t t = time(nullptr);
+  localtime_r(&t, &now);
+  char timestamp[32];
+  strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", &now);
+  std::string time_now(timestamp);
+
+  std::string path = "/proc/" + std::to_string(pid) + "/cmdline";
+
+  char proc_name_buf[1024];
+  const char* proc_name = nullptr;
+  std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(path.c_str(), "r"), &fclose);
+
+  if (fp) {
+    proc_name = fgets(proc_name_buf, sizeof(proc_name_buf), fp.get());
+  }
+
+  if (!proc_name) {
+    proc_name = "<unknown>";
+  }
+
+  buffer << "\n----- Waiting Channels: pid " << pid << " at " << time_now << " -----\n"
+         << "Cmd line: " << proc_name << "\n";
+}
+
+static void get_wchan_footer(pid_t pid, std::stringstream& buffer) {
+  buffer << "----- end " << std::to_string(pid) << " -----\n";
+}
+
+/**
+ * Returns the wchan data for each thread in the process,
+ * or empty string if unable to obtain any data.
+ */
+static std::string get_wchan_data(pid_t pid) {
+  std::stringstream buffer;
+  std::vector<pid_t> tids;
+
+  if (!android::procinfo::GetProcessTids(pid, &tids)) {
+    LOG(WARNING) << "libdebuggerd_client: Failed to get process tids";
+    return buffer.str();
+  }
+
+  std::stringstream data;
+  for (int tid : tids) {
+    std::string path = "/proc/" + std::to_string(pid) + "/task/" + std::to_string(tid) + "/wchan";
+    std::string wchan_str;
+    if (!ReadFileToString(path, &wchan_str, true)) {
+      PLOG(WARNING) << "libdebuggerd_client: Failed to read \"" << path << "\"";
+      continue;
+    }
+    data << "sysTid=" << std::left << std::setw(10) << tid << wchan_str << "\n";
+  }
+
+  if (std::string str = data.str(); !str.empty()) {
+    get_wchan_header(pid, buffer);
+    buffer << "\n" << str << "\n";
+    get_wchan_footer(pid, buffer);
+    buffer << "\n";
+  }
+
+  return buffer.str();
+}
+
+static void dump_wchan_data(const std::string& data, int fd, pid_t pid) {
+  if (!WriteStringToFd(data, fd)) {
+    LOG(WARNING) << "libdebuggerd_client: Failed to dump wchan data for pid: " << pid;
+  }
+}
+
 bool debuggerd_trigger_dump(pid_t tid, DebuggerdDumpType dump_type, unsigned int timeout_ms,
                             unique_fd output_fd) {
   pid_t pid = tid;
@@ -261,6 +335,17 @@
   if (copy == -1) {
     return -1;
   }
+
+  // debuggerd_trigger_dump results in every thread in the process being interrupted
+  // by a signal, so we need to fetch the wchan data before calling that.
+  std::string wchan_data = get_wchan_data(tid);
+
   int timeout_ms = timeout_secs > 0 ? timeout_secs * 1000 : 0;
-  return debuggerd_trigger_dump(tid, dump_type, timeout_ms, std::move(copy)) ? 0 : -1;
+  int ret = debuggerd_trigger_dump(tid, dump_type, timeout_ms, std::move(copy)) ? 0 : -1;
+
+  // Dump wchan data, since only privileged processes (CAP_SYS_ADMIN) can read
+  // kernel stack traces (/proc/*/stack).
+  dump_wchan_data(wchan_data, fd, tid);
+
+  return ret;
 }
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 1f0e420..fbc8b97 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -1099,3 +1099,30 @@
   // This should be good enough, though...
   ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
 }
+
+static __attribute__((__noinline__)) void overflow_stack(void* p) {
+  void* buf[1];
+  buf[0] = p;
+  static volatile void* global = buf;
+  if (global) {
+    global = buf;
+    overflow_stack(&buf);
+  }
+}
+
+TEST_F(CrasherTest, stack_overflow) {
+  int intercept_result;
+  unique_fd output_fd;
+  StartProcess([]() { overflow_stack(nullptr); });
+
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  AssertDeath(SIGSEGV);
+  FinishIntercept(&intercept_result);
+
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+  ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
+}
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index d246722..da2ba58 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -86,7 +86,39 @@
   _LOG(log, logtype::HEADER, "Timestamp: %s\n", buf);
 }
 
-static void dump_probable_cause(log_t* log, const siginfo_t* si, unwindstack::Maps* maps) {
+static std::string get_stack_overflow_cause(uint64_t fault_addr, uint64_t sp,
+                                            unwindstack::Maps* maps) {
+  static constexpr uint64_t kMaxDifferenceBytes = 256;
+  uint64_t difference;
+  if (sp >= fault_addr) {
+    difference = sp - fault_addr;
+  } else {
+    difference = fault_addr - sp;
+  }
+  if (difference <= kMaxDifferenceBytes) {
+    // The faulting address is close to the current sp, check if the sp
+    // indicates a stack overflow.
+    // On arm, the sp does not get updated when the instruction faults.
+    // In this case, the sp will still be in a valid map, which is the
+    // last case below.
+    // On aarch64, the sp does get updated when the instruction faults.
+    // In this case, the sp will be in either an invalid map if triggered
+    // on the main thread, or in a guard map if in another thread, which
+    // will be the first case or second case from below.
+    unwindstack::MapInfo* map_info = maps->Find(sp);
+    if (map_info == nullptr) {
+      return "stack pointer is in a non-existent map; likely due to stack overflow.";
+    } else if ((map_info->flags & (PROT_READ | PROT_WRITE)) != (PROT_READ | PROT_WRITE)) {
+      return "stack pointer is not in a rw map; likely due to stack overflow.";
+    } else if ((sp - map_info->start) <= kMaxDifferenceBytes) {
+      return "stack pointer is close to top of stack; likely stack overflow.";
+    }
+  }
+  return "";
+}
+
+static void dump_probable_cause(log_t* log, const siginfo_t* si, unwindstack::Maps* maps,
+                                unwindstack::Regs* regs) {
   std::string cause;
   if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) {
     if (si->si_addr < reinterpret_cast<void*>(4096)) {
@@ -101,11 +133,16 @@
       cause = "call to kuser_memory_barrier";
     } else if (si->si_addr == reinterpret_cast<void*>(0xffff0f60)) {
       cause = "call to kuser_cmpxchg64";
+    } else {
+      cause = get_stack_overflow_cause(reinterpret_cast<uint64_t>(si->si_addr), regs->sp(), maps);
     }
   } else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) {
-    unwindstack::MapInfo* map_info = maps->Find(reinterpret_cast<uint64_t>(si->si_addr));
+    uint64_t fault_addr = reinterpret_cast<uint64_t>(si->si_addr);
+    unwindstack::MapInfo* map_info = maps->Find(fault_addr);
     if (map_info != nullptr && map_info->flags == PROT_EXEC) {
       cause = "execute-only (no-read) memory access error; likely due to data in .text.";
+    } else {
+      cause = get_stack_overflow_cause(fault_addr, regs->sp(), maps);
     }
   } else if (si->si_signo == SIGSYS && si->si_code == SYS_SECCOMP) {
     cause = StringPrintf("seccomp prevented call to disallowed %s system call %d", ABI_STRING,
@@ -447,7 +484,7 @@
 
   if (thread_info.siginfo) {
     dump_signal_info(log, thread_info, unwinder->GetProcessMemory().get());
-    dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps());
+    dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps(), thread_info.registers.get());
   }
 
   if (primary_thread) {
diff --git a/demangle/.clang-format b/demangle/.clang-format
deleted file mode 120000
index fd0645f..0000000
--- a/demangle/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-../.clang-format-2
\ No newline at end of file
diff --git a/demangle/Android.bp b/demangle/Android.bp
deleted file mode 100644
index fd79cf8..0000000
--- a/demangle/Android.bp
+++ /dev/null
@@ -1,87 +0,0 @@
-//
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-cc_defaults {
-    name: "libdemangle_defaults",
-
-    host_supported: true,
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wextra",
-    ],
-
-    target: {
-        linux_bionic: {
-            enabled: true,
-        },
-    },
-}
-
-cc_library {
-    name: "libdemangle",
-    defaults: ["libdemangle_defaults"],
-    vendor_available: true,
-    recovery_available: true,
-
-    srcs: [
-        "Demangler.cpp",
-    ],
-
-    local_include_dirs: [
-        "include",
-    ],
-
-    export_include_dirs: [
-        "include",
-    ],
-}
-
-cc_binary {
-    name: "demangle",
-    defaults: ["libdemangle_defaults"],
-    srcs: ["demangle.cpp"],
-    host_supported: true,
-
-    shared_libs: ["libdemangle"],
-}
-
-//-------------------------------------------------------------------------
-// Unit Tests
-//-------------------------------------------------------------------------
-cc_test {
-    name: "libdemangle_test",
-    defaults: ["libdemangle_defaults"],
-
-    srcs: [
-        "DemangleTest.cpp",
-    ],
-
-    cflags: [
-        "-O0",
-        "-g",
-    ],
-
-    shared_libs: [
-        "libdemangle",
-    ],
-
-    test_suites: ["device-tests"],
-    required: [
-        "libdemangle",
-    ],
-}
diff --git a/demangle/Android.mk b/demangle/Android.mk
deleted file mode 100644
index d8082a9..0000000
--- a/demangle/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-#
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := demangle_fuzzer
-LOCAL_SRC_FILES := \
-    Demangler.cpp \
-    demangle_fuzzer.cpp \
-
-LOCAL_CFLAGS := \
-    -Wall \
-    -Werror \
-    -Wextra \
-
-include $(BUILD_FUZZ_TEST)
diff --git a/demangle/DemangleTest.cpp b/demangle/DemangleTest.cpp
deleted file mode 100644
index 1787031..0000000
--- a/demangle/DemangleTest.cpp
+++ /dev/null
@@ -1,555 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdlib.h>
-
-#include <gtest/gtest.h>
-
-#include <demangle.h>
-
-#include "Demangler.h"
-
-TEST(DemangleTest, IllegalArgumentModifiers) {
-  Demangler demangler;
-
-  ASSERT_EQ("_Zpp4FUNKK", demangler.Parse("_Zpp4FUNKK"));
-  ASSERT_EQ("_Zpp4FUNVV", demangler.Parse("_Zpp4FUNVV"));
-}
-
-TEST(DemangleTest, VoidArgument) {
-  Demangler demangler;
-
-  ASSERT_EQ("func()", demangler.Parse("_ZN4funcEv"));
-  ASSERT_EQ("func(void&)", demangler.Parse("_ZN4funcERv"));
-  ASSERT_EQ("func(void, void)", demangler.Parse("_ZN4funcEvv"));
-  ASSERT_EQ("func(void*)", demangler.Parse("_ZN4funcEPv"));
-  ASSERT_EQ("func(void const)", demangler.Parse("_ZN4funcEKv"));
-  ASSERT_EQ("func(void volatile)", demangler.Parse("_ZN4funcEVv"));
-}
-
-TEST(DemangleTest, ArgumentModifiers) {
-  Demangler demangler;
-
-  ASSERT_EQ("func(char)", demangler.Parse("_ZN4funcEc"));
-  ASSERT_EQ("func(char*)", demangler.Parse("_ZN4funcEPc"));
-  ASSERT_EQ("func(char**)", demangler.Parse("_ZN4funcEPPc"));
-  ASSERT_EQ("func(char***)", demangler.Parse("_ZN4funcEPPPc"));
-  ASSERT_EQ("func(char&)", demangler.Parse("_ZN4funcERc"));
-  ASSERT_EQ("func(char*&)", demangler.Parse("_ZN4funcERPc"));
-  ASSERT_EQ("func(char&)", demangler.Parse("_ZN4funcERRc"));
-  ASSERT_EQ("func(char*&*)", demangler.Parse("_ZN4funcEPRPc"));
-  ASSERT_EQ("func(char**&)", demangler.Parse("_ZN4funcERRPPc"));
-  ASSERT_EQ("func(char const)", demangler.Parse("_ZN4funcEKc"));
-  ASSERT_EQ("func(char volatile)", demangler.Parse("_ZN4funcEVc"));
-  ASSERT_EQ("func(char volatile const)", demangler.Parse("_ZN4funcEKVc"));
-  ASSERT_EQ("func(char const volatile)", demangler.Parse("_ZN4funcEVKc"));
-  ASSERT_EQ("func(char const* volatile&)", demangler.Parse("_ZN4funcERVPKc"));
-  ASSERT_EQ("func(void, char, short)", demangler.Parse("_ZN4funcEvcs"));
-  ASSERT_EQ("func(void*, char&, short&*)", demangler.Parse("_ZN4funcEPvRcPRs"));
-}
-
-TEST(DemangleTest, FunctionModifiers) {
-  Demangler demangler;
-
-  ASSERT_EQ("func() const", demangler.Parse("_ZNK4funcEv"));
-  ASSERT_EQ("func() volatile", demangler.Parse("_ZNV4funcEv"));
-  ASSERT_EQ("func() volatile const", demangler.Parse("_ZNKV4funcEv"));
-  ASSERT_EQ("func() const volatile", demangler.Parse("_ZNVK4funcEv"));
-}
-
-TEST(DemangleTest, MultiplePartsInName) {
-  Demangler demangler;
-
-  ASSERT_EQ("one::two()", demangler.Parse("_ZN3one3twoEv"));
-  ASSERT_EQ("one::two::three()", demangler.Parse("_ZN3one3two5threeEv"));
-  ASSERT_EQ("one::two::three::four()", demangler.Parse("_ZN3one3two5three4fourEv"));
-  ASSERT_EQ("one::two::three::four::five()", demangler.Parse("_ZN3one3two5three4four4fiveEv"));
-  ASSERT_EQ("one(two::three::four::five)", demangler.Parse("_ZN3oneEN3two5three4four4fiveE"));
-}
-
-TEST(DemangleTest, AnonymousNamespace) {
-  Demangler demangler;
-
-  ASSERT_EQ("(anonymous namespace)::two()", demangler.Parse("_ZN12_GLOBAL__N_13twoEv"));
-  ASSERT_EQ("one::two((anonymous namespace))", demangler.Parse("_ZN3one3twoE12_GLOBAL__N_1"));
-}
-
-TEST(DemangleTest, DestructorValues) {
-  Demangler demangler;
-
-  ASSERT_EQ("one::two::~two()", demangler.Parse("_ZN3one3twoD0Ev"));
-  ASSERT_EQ("one::two::~two()", demangler.Parse("_ZN3one3twoD1Ev"));
-  ASSERT_EQ("one::two::~two()", demangler.Parse("_ZN3one3twoD2Ev"));
-  ASSERT_EQ("one::two::~two()", demangler.Parse("_ZN3one3twoD5Ev"));
-  ASSERT_EQ("one::two::three::~three()", demangler.Parse("_ZN3one3two5threeD0Ev"));
-
-  ASSERT_EQ("_ZN3one3twoD3Ev", demangler.Parse("_ZN3one3twoD3Ev"));
-  ASSERT_EQ("_ZN3one3twoD4Ev", demangler.Parse("_ZN3one3twoD4Ev"));
-  ASSERT_EQ("_ZN3one3twoD6Ev", demangler.Parse("_ZN3one3twoD6Ev"));
-  ASSERT_EQ("_ZN3one3twoD7Ev", demangler.Parse("_ZN3one3twoD7Ev"));
-  ASSERT_EQ("_ZN3one3twoD8Ev", demangler.Parse("_ZN3one3twoD8Ev"));
-  ASSERT_EQ("_ZN3one3twoD9Ev", demangler.Parse("_ZN3one3twoD9Ev"));
-
-  ASSERT_EQ("one::two<three::four>::~two()", demangler.Parse("_ZN3one3twoIN5three4fourEED2Ev"));
-}
-
-TEST(DemangleTest, ConstructorValues) {
-  Demangler demangler;
-
-  ASSERT_EQ("one::two::two()", demangler.Parse("_ZN3one3twoC1Ev"));
-  ASSERT_EQ("one::two::two()", demangler.Parse("_ZN3one3twoC2Ev"));
-  ASSERT_EQ("one::two::two()", demangler.Parse("_ZN3one3twoC3Ev"));
-  ASSERT_EQ("one::two::two()", demangler.Parse("_ZN3one3twoC5Ev"));
-  ASSERT_EQ("one::two::three::three()", demangler.Parse("_ZN3one3two5threeC1Ev"));
-
-  ASSERT_EQ("_ZN3one3twoC0Ev", demangler.Parse("_ZN3one3twoC0Ev"));
-  ASSERT_EQ("_ZN3one3twoC4Ev", demangler.Parse("_ZN3one3twoC4Ev"));
-  ASSERT_EQ("_ZN3one3twoC6Ev", demangler.Parse("_ZN3one3twoC6Ev"));
-  ASSERT_EQ("_ZN3one3twoC7Ev", demangler.Parse("_ZN3one3twoC7Ev"));
-  ASSERT_EQ("_ZN3one3twoC8Ev", demangler.Parse("_ZN3one3twoC8Ev"));
-  ASSERT_EQ("_ZN3one3twoC9Ev", demangler.Parse("_ZN3one3twoC9Ev"));
-
-  ASSERT_EQ("one::two<three::four>::two()", demangler.Parse("_ZN3one3twoIN5three4fourEEC1Ev"));
-}
-
-TEST(DemangleTest, OperatorValues) {
-  Demangler demangler;
-
-  ASSERT_EQ("operator&&()", demangler.Parse("_Zaav"));
-  ASSERT_EQ("operator&()", demangler.Parse("_Zadv"));
-  ASSERT_EQ("operator&()", demangler.Parse("_Zanv"));
-  ASSERT_EQ("operator&=()", demangler.Parse("_ZaNv"));
-  ASSERT_EQ("operator=()", demangler.Parse("_ZaSv"));
-  ASSERT_EQ("operator()()", demangler.Parse("_Zclv"));
-  ASSERT_EQ("operator,()", demangler.Parse("_Zcmv"));
-  ASSERT_EQ("operator~()", demangler.Parse("_Zcov"));
-  ASSERT_EQ("operator delete[]()", demangler.Parse("_Zdav"));
-  ASSERT_EQ("operator*()", demangler.Parse("_Zdev"));
-  ASSERT_EQ("operator delete()", demangler.Parse("_Zdlv"));
-  ASSERT_EQ("operator/()", demangler.Parse("_Zdvv"));
-  ASSERT_EQ("operator/=()", demangler.Parse("_ZdVv"));
-  ASSERT_EQ("operator^()", demangler.Parse("_Zeov"));
-  ASSERT_EQ("operator^=()", demangler.Parse("_ZeOv"));
-  ASSERT_EQ("operator==()", demangler.Parse("_Zeqv"));
-  ASSERT_EQ("operator>=()", demangler.Parse("_Zgev"));
-  ASSERT_EQ("operator>()", demangler.Parse("_Zgtv"));
-  ASSERT_EQ("operator[]()", demangler.Parse("_Zixv"));
-  ASSERT_EQ("operator<=()", demangler.Parse("_Zlev"));
-  ASSERT_EQ("operator<<()", demangler.Parse("_Zlsv"));
-  ASSERT_EQ("operator<<=()", demangler.Parse("_ZlSv"));
-  ASSERT_EQ("operator<()", demangler.Parse("_Zltv"));
-  ASSERT_EQ("operator-()", demangler.Parse("_Zmiv"));
-  ASSERT_EQ("operator-=()", demangler.Parse("_ZmIv"));
-  ASSERT_EQ("operator*()", demangler.Parse("_Zmlv"));
-  ASSERT_EQ("operator*=()", demangler.Parse("_ZmLv"));
-  ASSERT_EQ("operator--()", demangler.Parse("_Zmmv"));
-  ASSERT_EQ("operator new[]()", demangler.Parse("_Znav"));
-  ASSERT_EQ("operator!=()", demangler.Parse("_Znev"));
-  ASSERT_EQ("operator-()", demangler.Parse("_Zngv"));
-  ASSERT_EQ("operator!()", demangler.Parse("_Zntv"));
-  ASSERT_EQ("operator new()", demangler.Parse("_Znwv"));
-  ASSERT_EQ("operator||()", demangler.Parse("_Zoov"));
-  ASSERT_EQ("operator|()", demangler.Parse("_Zorv"));
-  ASSERT_EQ("operator|=()", demangler.Parse("_ZoRv"));
-  ASSERT_EQ("operator->*()", demangler.Parse("_Zpmv"));
-  ASSERT_EQ("operator+()", demangler.Parse("_Zplv"));
-  ASSERT_EQ("operator+=()", demangler.Parse("_ZpLv"));
-  ASSERT_EQ("operator++()", demangler.Parse("_Zppv"));
-  ASSERT_EQ("operator+()", demangler.Parse("_Zpsv"));
-  ASSERT_EQ("operator->()", demangler.Parse("_Zptv"));
-  ASSERT_EQ("operator?()", demangler.Parse("_Zquv"));
-  ASSERT_EQ("operator%()", demangler.Parse("_Zrmv"));
-  ASSERT_EQ("operator%=()", demangler.Parse("_ZrMv"));
-  ASSERT_EQ("operator>>()", demangler.Parse("_Zrsv"));
-  ASSERT_EQ("operator>>=()", demangler.Parse("_ZrSv"));
-
-  // Spot check using an operator as part of function name.
-  ASSERT_EQ("operator&&()", demangler.Parse("_ZNaaEv"));
-  ASSERT_EQ("operator++()", demangler.Parse("_ZNppEv"));
-  ASSERT_EQ("one::operator++()", demangler.Parse("_ZN3oneppEv"));
-
-  // Spot check using an operator in an argument name.
-  ASSERT_EQ("operator+(operator|=)", demangler.Parse("_ZNpsENoRE"));
-  ASSERT_EQ("operator==()", demangler.Parse("_Zeqv"));
-  ASSERT_EQ("one(arg1::operator|=, arg2::operator==)",
-            demangler.Parse("_ZN3oneEN4arg1oREN4arg2eqE"));
-}
-
-TEST(DemangleTest, FunctionStartsWithNumber) {
-  Demangler demangler;
-
-  ASSERT_EQ("value(char, int)", demangler.Parse("_Z5valueci"));
-  ASSERT_EQ("abcdefjklmn(signed char)", demangler.Parse("_Z11abcdefjklmna"));
-  ASSERT_EQ("value(one, signed char)", demangler.Parse("_Z5value3onea"));
-}
-
-TEST(DemangleTest, FunctionStartsWithLPlusNumber) {
-  Demangler demangler;
-
-  ASSERT_EQ("value(char, int)", demangler.Parse("_ZL5valueci"));
-  ASSERT_EQ("abcdefjklmn(signed char)", demangler.Parse("_ZL11abcdefjklmna"));
-  ASSERT_EQ("value(one, signed char)", demangler.Parse("_ZL5value3onea"));
-}
-
-TEST(DemangleTest, StdTypes) {
-  Demangler demangler;
-
-  ASSERT_EQ("std::one", demangler.Parse("_ZNSt3oneE"));
-  ASSERT_EQ("std::one(std::two)", demangler.Parse("_ZNSt3oneESt3two"));
-  ASSERT_EQ("std::std::one(std::two)", demangler.Parse("_ZNStSt3oneESt3two"));
-  ASSERT_EQ("std()", demangler.Parse("_ZNStEv"));
-  ASSERT_EQ("one::std::std::two::~two(one::std::std::two)",
-            demangler.Parse("_ZN3oneStSt3twoD0ES0_"));
-
-  ASSERT_EQ("std::allocator", demangler.Parse("_ZNSaE"));
-  ASSERT_EQ("std::basic_string", demangler.Parse("_ZNSbE"));
-  ASSERT_EQ("_ZNScE", demangler.Parse("_ZNScE"));
-  ASSERT_EQ("std::iostream", demangler.Parse("_ZNSdE"));
-  ASSERT_EQ("_ZNSeE", demangler.Parse("_ZNSeE"));
-  ASSERT_EQ("_ZNSfE", demangler.Parse("_ZNSfE"));
-  ASSERT_EQ("_ZNSgE", demangler.Parse("_ZNSgE"));
-  ASSERT_EQ("_ZNShE", demangler.Parse("_ZNShE"));
-  ASSERT_EQ("std::istream", demangler.Parse("_ZNSiE"));
-  ASSERT_EQ("_ZNSjE", demangler.Parse("_ZNSjE"));
-  ASSERT_EQ("_ZNSkE", demangler.Parse("_ZNSkE"));
-  ASSERT_EQ("_ZNSlE", demangler.Parse("_ZNSlE"));
-  ASSERT_EQ("_ZNSmE", demangler.Parse("_ZNSmE"));
-  ASSERT_EQ("_ZNSnE", demangler.Parse("_ZNSnE"));
-  ASSERT_EQ("std::ostream", demangler.Parse("_ZNSoE"));
-  ASSERT_EQ("_ZNSpE", demangler.Parse("_ZNSpE"));
-  ASSERT_EQ("_ZNSqE", demangler.Parse("_ZNSqE"));
-  ASSERT_EQ("_ZNSrE", demangler.Parse("_ZNSrE"));
-  ASSERT_EQ("std::string", demangler.Parse("_ZNSsE"));
-  ASSERT_EQ("_ZNSuE", demangler.Parse("_ZNSuE"));
-  ASSERT_EQ("_ZNSvE", demangler.Parse("_ZNSvE"));
-  ASSERT_EQ("_ZNSwE", demangler.Parse("_ZNSwE"));
-  ASSERT_EQ("_ZNSxE", demangler.Parse("_ZNSxE"));
-  ASSERT_EQ("_ZNSyE", demangler.Parse("_ZNSyE"));
-  ASSERT_EQ("_ZNSzE", demangler.Parse("_ZNSzE"));
-}
-
-TEST(DemangleTest, SingleLetterArguments) {
-  Demangler demangler;
-
-  ASSERT_EQ("func(signed char)", demangler.Parse("_ZN4funcEa"));
-  ASSERT_EQ("func(bool)", demangler.Parse("_ZN4funcEb"));
-  ASSERT_EQ("func(char)", demangler.Parse("_ZN4funcEc"));
-  ASSERT_EQ("func(double)", demangler.Parse("_ZN4funcEd"));
-  ASSERT_EQ("func(long double)", demangler.Parse("_ZN4funcEe"));
-  ASSERT_EQ("func(float)", demangler.Parse("_ZN4funcEf"));
-  ASSERT_EQ("func(__float128)", demangler.Parse("_ZN4funcEg"));
-  ASSERT_EQ("func(unsigned char)", demangler.Parse("_ZN4funcEh"));
-  ASSERT_EQ("func(int)", demangler.Parse("_ZN4funcEi"));
-  ASSERT_EQ("func(unsigned int)", demangler.Parse("_ZN4funcEj"));
-  ASSERT_EQ("_ZN4funcEk", demangler.Parse("_ZN4funcEk"));
-  ASSERT_EQ("func(long)", demangler.Parse("_ZN4funcEl"));
-  ASSERT_EQ("func(unsigned long)", demangler.Parse("_ZN4funcEm"));
-  ASSERT_EQ("func(__int128)", demangler.Parse("_ZN4funcEn"));
-  ASSERT_EQ("func(unsigned __int128)", demangler.Parse("_ZN4funcEo"));
-  ASSERT_EQ("_ZN4funcEp", demangler.Parse("_ZN4funcEp"));
-  ASSERT_EQ("_ZN4funcEq", demangler.Parse("_ZN4funcEq"));
-  ASSERT_EQ("_ZN4funcEr", demangler.Parse("_ZN4funcEr"));
-  ASSERT_EQ("func(short)", demangler.Parse("_ZN4funcEs"));
-  ASSERT_EQ("func(unsigned short)", demangler.Parse("_ZN4funcEt"));
-  ASSERT_EQ("_ZN4funcEu", demangler.Parse("_ZN4funcEu"));
-  ASSERT_EQ("func()", demangler.Parse("_ZN4funcEv"));
-  ASSERT_EQ("func(wchar_t)", demangler.Parse("_ZN4funcEw"));
-  ASSERT_EQ("func(long long)", demangler.Parse("_ZN4funcEx"));
-  ASSERT_EQ("func(unsigned long long)", demangler.Parse("_ZN4funcEy"));
-  ASSERT_EQ("func(...)", demangler.Parse("_ZN4funcEz"));
-}
-
-TEST(DemangleTest, DArguments) {
-  Demangler demangler;
-
-  ASSERT_EQ("func(auto)", demangler.Parse("_ZN4funcEDa"));
-  ASSERT_EQ("_ZN4funcEDb", demangler.Parse("_ZN4funcEDb"));
-  ASSERT_EQ("_ZN4funcEDc", demangler.Parse("_ZN4funcEDc"));
-  ASSERT_EQ("func(decimal64)", demangler.Parse("_ZN4funcEDd"));
-  ASSERT_EQ("func(decimal128)", demangler.Parse("_ZN4funcEDe"));
-  ASSERT_EQ("func(decimal32)", demangler.Parse("_ZN4funcEDf"));
-  ASSERT_EQ("_ZN4funcEDg", demangler.Parse("_ZN4funcEDg"));
-  ASSERT_EQ("func(half)", demangler.Parse("_ZN4funcEDh"));
-  ASSERT_EQ("func(char32_t)", demangler.Parse("_ZN4funcEDi"));
-  ASSERT_EQ("_ZN4funcEDj", demangler.Parse("_ZN4funcEDj"));
-  ASSERT_EQ("_ZN4funcEDk", demangler.Parse("_ZN4funcEDk"));
-  ASSERT_EQ("_ZN4funcEDl", demangler.Parse("_ZN4funcEDl"));
-  ASSERT_EQ("_ZN4funcEDm", demangler.Parse("_ZN4funcEDm"));
-  ASSERT_EQ("func(decltype(nullptr))", demangler.Parse("_ZN4funcEDn"));
-  ASSERT_EQ("_ZN4funcEDo", demangler.Parse("_ZN4funcEDo"));
-  ASSERT_EQ("_ZN4funcEDp", demangler.Parse("_ZN4funcEDp"));
-  ASSERT_EQ("_ZN4funcEDq", demangler.Parse("_ZN4funcEDq"));
-  ASSERT_EQ("_ZN4funcEDr", demangler.Parse("_ZN4funcEDr"));
-  ASSERT_EQ("func(char16_t)", demangler.Parse("_ZN4funcEDs"));
-  ASSERT_EQ("_ZN4funcEDt", demangler.Parse("_ZN4funcEDt"));
-  ASSERT_EQ("_ZN4funcEDu", demangler.Parse("_ZN4funcEDu"));
-  ASSERT_EQ("_ZN4funcEDv", demangler.Parse("_ZN4funcEDv"));
-  ASSERT_EQ("_ZN4funcEDw", demangler.Parse("_ZN4funcEDw"));
-  ASSERT_EQ("_ZN4funcEDx", demangler.Parse("_ZN4funcEDx"));
-  ASSERT_EQ("_ZN4funcEDy", demangler.Parse("_ZN4funcEDy"));
-  ASSERT_EQ("_ZN4funcEDz", demangler.Parse("_ZN4funcEDz"));
-}
-
-TEST(DemangleTest, FunctionArguments) {
-  Demangler demangler;
-
-  ASSERT_EQ("func(char ())", demangler.Parse("_ZN4funcEFcvE"));
-  ASSERT_EQ("func(char (*)())", demangler.Parse("_ZN4funcEPFcvE"));
-  ASSERT_EQ("func(char (&)())", demangler.Parse("_ZN4funcERFcvE"));
-  ASSERT_EQ("func(char (&)())", demangler.Parse("_ZN4funcERFcvE"));
-  ASSERT_EQ("func(char (*&)())", demangler.Parse("_ZN4funcERPFcvE"));
-  ASSERT_EQ("func(char (*)(int) const)", demangler.Parse("_ZN4funcEPKFciE"));
-  ASSERT_EQ("func(char (&)() const)", demangler.Parse("_ZN4funcERKFcvE"));
-  ASSERT_EQ("func(char (&)() volatile)", demangler.Parse("_ZN4funcERVFcvE"));
-  ASSERT_EQ("func(char (&)() volatile const)", demangler.Parse("_ZN4funcERKVFcvE"));
-  ASSERT_EQ("func(char (&)() const volatile)", demangler.Parse("_ZN4funcERVKFcvE"));
-  ASSERT_EQ("func(char (&)(int, signed char) const)", demangler.Parse("_ZN4funcERKFciaE"));
-  ASSERT_EQ("fake(char (&* volatile const)(void, void, signed char), signed char)",
-            demangler.Parse("_ZN4fakeEKVPRFcvvaEa"));
-}
-
-TEST(DemangleTest, TemplateFunction) {
-  Demangler demangler;
-
-  ASSERT_EQ("one<char>", demangler.Parse("_ZN3oneIcEE"));
-  ASSERT_EQ("one<void>", demangler.Parse("_ZN3oneIvEE"));
-  ASSERT_EQ("one<void*>", demangler.Parse("_ZN3oneIPvEE"));
-  ASSERT_EQ("one<void const>", demangler.Parse("_ZN3oneIKvEE"));
-  ASSERT_EQ("one<char, int, bool>", demangler.Parse("_ZN3oneIcibEE"));
-  ASSERT_EQ("one::two<three>", demangler.Parse("_ZN3one3twoIN5threeEEE"));
-  ASSERT_EQ("one<char, int, two::three>", demangler.Parse("_ZN3oneIciN3two5threeEEE"));
-  // Template within templates.
-  ASSERT_EQ("one::two<three<char, int>>", demangler.Parse("_ZN3one3twoIN5threeIciEEEE"));
-  ASSERT_EQ("one::two<three<char, four<int>>>", demangler.Parse("_ZN3one3twoIN5threeIcN4fourIiEEEEEE"));
-
-  ASSERT_EQ("one<char>", demangler.Parse("_Z3oneIcE"));
-  ASSERT_EQ("one<void>", demangler.Parse("_Z3oneIvE"));
-  ASSERT_EQ("one<void*>", demangler.Parse("_Z3oneIPvE"));
-  ASSERT_EQ("one<void const>", demangler.Parse("_Z3oneIKvE"));
-  ASSERT_EQ("one<char, int, bool>", demangler.Parse("_Z3oneIcibE"));
-  ASSERT_EQ("one(two<three>)", demangler.Parse("_Z3one3twoIN5threeEE"));
-  ASSERT_EQ("one<char, int, two::three>", demangler.Parse("_Z3oneIciN3two5threeEE"));
-  // Template within templates.
-  ASSERT_EQ("one(two<three<char, int>>)", demangler.Parse("_Z3one3twoIN5threeIciEEE"));
-  ASSERT_EQ("one(two<three<char, four<int>>>)",
-            demangler.Parse("_Z3one3twoIN5threeIcN4fourIiEEEEE"));
-}
-
-TEST(DemangleTest, TemplateFunctionWithReturnType) {
-  Demangler demangler;
-
-  ASSERT_EQ("char one<int>(char)", demangler.Parse("_Z3oneIiEcc"));
-  ASSERT_EQ("void one<int>()", demangler.Parse("_Z3oneIiEvv"));
-  ASSERT_EQ("char one<int>()", demangler.Parse("_Z3oneIiEcv"));
-  ASSERT_EQ("char one<int>(void, void)", demangler.Parse("_Z3oneIiEcvv"));
-  ASSERT_EQ("char one<int>()", demangler.Parse("_ZN3oneIiEEcv"));
-  ASSERT_EQ("char one<int>(void, void)", demangler.Parse("_ZN3oneIiEEcvv"));
-}
-
-TEST(DemangleTest, TemplateArguments) {
-  Demangler demangler;
-
-  ASSERT_EQ("one(two<char>)", demangler.Parse("_ZN3oneE3twoIcE"));
-  ASSERT_EQ("one(two<char, void>)", demangler.Parse("_ZN3oneE3twoIcvE"));
-  ASSERT_EQ("one(two<char, void, three<four, int>>)",
-            demangler.Parse("_ZN3oneE3twoIcv5threeI4fouriEE"));
-}
-
-TEST(DemangleTest, SubstitutionUnderscore) {
-  Demangler demangler;
-
-  ASSERT_EQ("a::a", demangler.Parse("_ZN1aS_E"));
-  ASSERT_EQ("one::one", demangler.Parse("_ZN3oneS_E"));
-  ASSERT_EQ("one::two::one", demangler.Parse("_ZN3one3twoS_E"));
-  ASSERT_EQ("one::two::three::one", demangler.Parse("_ZN3one3two5threeS_E"));
-  ASSERT_EQ("one::two(one)", demangler.Parse("_ZN3one3twoES_"));
-  ASSERT_EQ("one::two(three::one)", demangler.Parse("_ZN3one3twoEN5threeS_E"));
-
-  // Special case that St is part of the saved value used in the substitution.
-  ASSERT_EQ("std::one::std::one", demangler.Parse("_ZNSt3oneS_E"));
-
-  // Multiple substitutions in the string.
-  ASSERT_EQ("one::one(one, one)", demangler.Parse("_ZN3oneS_ES_S_"));
-  ASSERT_EQ("std::one::two::std::one(std::one)", demangler.Parse("_ZNSt3one3twoS_ES_"));
-}
-
-TEST(DemangleTest, SubstitutionByNumber) {
-  Demangler demangler;
-
-  // Basic substitution.
-  ASSERT_EQ("a::b::c(a::b)", demangler.Parse("_ZN1a1b1cES0_"));
-  ASSERT_EQ("_ZN1a1b1cES1_", demangler.Parse("_ZN1a1b1cES1_"));
-  ASSERT_EQ("a::b::c::d(a::b::c)", demangler.Parse("_ZN1a1b1c1dES1_"));
-  ASSERT_EQ("a::b::c::d::e::f::g::h::i::j::k::l::m::n::o::p::q(a::b::c::d::e::f::g::h::i::j::k::l)",
-            demangler.Parse("_ZN1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1qESA_"));
-  ASSERT_EQ("a::b::c::d::e::f::g::h::i::j::k::l::m::n::o::p::q(a::b::c::d::e::f::g::h::i::j::k::l::m)",
-            demangler.Parse("_ZN1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1qESB_"));
-
-  // Verify argument modifiers are included in substitution list.
-  ASSERT_EQ("one::two(char&* volatile const, char&)", demangler.Parse("_ZN3one3twoEKVPRcS0_"));
-  ASSERT_EQ("one::two(char&* volatile const, char&*)", demangler.Parse("_ZN3one3twoEKVPRcS1_"));
-  ASSERT_EQ("one::two(char&* volatile const, char&* volatile const)",
-            demangler.Parse("_ZN3one3twoEKVPRcS2_"));
-  ASSERT_EQ("one::two(int&* volatile* const, int&)", demangler.Parse("_ZN3one3twoEKPVPRiS0_"));
-  ASSERT_EQ("one::two(int&* volatile const, int&*)", demangler.Parse("_ZN3one3twoEKVPRiS1_"));
-  ASSERT_EQ("one::two(int&* volatile const, int&* volatile const)",
-            demangler.Parse("_ZN3one3twoEKVPRiS2_"));
-
-  // Verify Constructor/Destructor does properly save from function name.
-  ASSERT_EQ("_ZN1a1bES0_", demangler.Parse("_ZN1a1bES0_"));
-  ASSERT_EQ("a::b::b(a::b)", demangler.Parse("_ZN1a1bC1ES0_"));
-  ASSERT_EQ("a::b::~b(a::b)", demangler.Parse("_ZN1a1bD0ES0_"));
-
-  // Make sure substitution values are not saved.
-  ASSERT_EQ("a::b::b(a::b, char*, char*)", demangler.Parse("_ZN1a1bC1ES0_PcS1_"));
-}
-
-TEST(DemangleTest, ComplexSubstitution) {
-  Demangler demangler;
-
-  ASSERT_EQ("one::two<one::three>::two()", demangler.Parse("_ZN3one3twoINS_5threeEEC1Ev"));
-  ASSERT_EQ("one::two::two(one::two const&, bool, one::three*)",
-            demangler.Parse("_ZN3one3twoC2ERKS0_bPNS_5threeE"));
-  ASSERT_EQ("one::two::three::four<one::five>::~four(one::two*)",
-            demangler.Parse("_ZN3one3two5three4fourINS_4fiveEED2EPS0_"));
-  ASSERT_EQ("one::two::three::four<one::five>::~four(one::two::three*)",
-            demangler.Parse("_ZN3one3two5three4fourINS_4fiveEED2EPS1_"));
-  ASSERT_EQ("one::two::three::four<one::five>::~four(one::two::three::four*)",
-            demangler.Parse("_ZN3one3two5three4fourINS_4fiveEED2EPS2_"));
-  ASSERT_EQ("one::two::three::four<one::five>::~four(one::five*)",
-            demangler.Parse("_ZN3one3two5three4fourINS_4fiveEED2EPS3_"));
-}
-
-TEST(DemangleTest, TemplateSubstitution) {
-  Demangler demangler;
-
-  ASSERT_EQ("void one<int, double>(int)", demangler.Parse("_ZN3oneIidEEvT_"));
-  ASSERT_EQ("void one<int, double>(double)", demangler.Parse("_ZN3oneIidEEvT0_"));
-  ASSERT_EQ("void one<int, double, char, void>(char)", demangler.Parse("_ZN3oneIidcvEEvT1_"));
-
-  ASSERT_EQ("void one<int, double>(int)", demangler.Parse("_Z3oneIidEvT_"));
-  ASSERT_EQ("void one<int, double>(double)", demangler.Parse("_Z3oneIidEvT0_"));
-  ASSERT_EQ("void one<int, double, char, void>(char)", demangler.Parse("_Z3oneIidcvEvT1_"));
-
-  ASSERT_EQ("void one<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r>(l)",
-            demangler.Parse("_ZN3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEEvT10_"));
-  ASSERT_EQ("void one<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r>(m)",
-            demangler.Parse("_ZN3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEEvT11_"));
-
-  ASSERT_EQ("void one<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r>(l)",
-            demangler.Parse("_Z3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEvT10_"));
-  ASSERT_EQ("void one<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r>(m)",
-            demangler.Parse("_Z3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEvT11_"));
-}
-
-TEST(DemangleTest, StringTooLong) {
-  Demangler demangler;
-
-  ASSERT_EQ("_ZN3one3twoC2ERKS0_bPNS_5threeE",
-            demangler.Parse("_ZN3one3twoC2ERKS0_bPNS_5threeE", 10));
-  ASSERT_EQ("_ZN3one3twoC2ERKS0_bPNS_5threeE",
-            demangler.Parse("_ZN3one3twoC2ERKS0_bPNS_5threeE", 30));
-  ASSERT_EQ("one::two::two(one::two const&, bool, one::three*)",
-            demangler.Parse("_ZN3one3twoC2ERKS0_bPNS_5threeE", 31));
-
-  // Check the length check only occurs after the two letter value
-  // has been processed.
-  ASSERT_EQ("one::two(auto)", demangler.Parse("_ZN3one3twoEDa", 15));
-  ASSERT_EQ("one::two(auto)", demangler.Parse("_ZN3one3twoEDa", 14));
-  ASSERT_EQ("one::two(auto)", demangler.Parse("_ZN3one3twoEDa", 13));
-  ASSERT_EQ("_ZN3one3twoEDa", demangler.Parse("_ZN3one3twoEDa", 12));
-}
-
-TEST(DemangleTest, BooleanLiterals) {
-  Demangler demangler;
-
-  ASSERT_EQ("one<true>", demangler.Parse("_ZN3oneILb1EEE"));
-  ASSERT_EQ("one<false>", demangler.Parse("_ZN3oneILb0EEE"));
-  ASSERT_EQ("one<false, true>", demangler.Parse("_ZN3oneILb0ELb1EEE"));
-
-  ASSERT_EQ("one<true>", demangler.Parse("_Z3oneILb1EE"));
-  ASSERT_EQ("one<false>", demangler.Parse("_Z3oneILb0EE"));
-  ASSERT_EQ("one<false, true>", demangler.Parse("_Z3oneILb0ELb1EE"));
-
-  ASSERT_EQ("one(two<three<four>, false, true>)",
-            demangler.Parse("_ZN3oneE3twoI5threeI4fourELb0ELb1EE"));
-}
-
-TEST(DemangleTest, non_virtual_thunk) {
-  Demangler demangler;
-
-  ASSERT_EQ("non-virtual thunk to one", demangler.Parse("_ZThn0_N3oneE"));
-  ASSERT_EQ("non-virtual thunk to two", demangler.Parse("_ZThn0_3two"));
-  ASSERT_EQ("non-virtual thunk to three", demangler.Parse("_ZTh0_5three"));
-  ASSERT_EQ("non-virtual thunk to four", demangler.Parse("_ZTh_4four"));
-  ASSERT_EQ("non-virtual thunk to five", demangler.Parse("_ZTh0123456789_4five"));
-  ASSERT_EQ("non-virtual thunk to six", demangler.Parse("_ZThn0123456789_3six"));
-
-  ASSERT_EQ("_ZThn0N3oneE", demangler.Parse("_ZThn0N3oneE"));
-  ASSERT_EQ("_ZThn03two", demangler.Parse("_ZThn03two"));
-  ASSERT_EQ("_ZTh05three", demangler.Parse("_ZTh05three"));
-  ASSERT_EQ("_ZTh4four", demangler.Parse("_ZTh4four"));
-  ASSERT_EQ("_ZTh01234567894five", demangler.Parse("_ZTh01234567894five"));
-  ASSERT_EQ("_ZThn01234567893six", demangler.Parse("_ZThn01234567893six"));
-  ASSERT_EQ("_ZT_N3oneE", demangler.Parse("_ZT_N3oneE"));
-  ASSERT_EQ("_ZT0_N3oneE", demangler.Parse("_ZT0_N3oneE"));
-  ASSERT_EQ("_ZTH_N3oneE", demangler.Parse("_ZTH_N3oneE"));
-}
-
-TEST(DemangleTest, r_value_reference) {
-  Demangler demangler;
-  ASSERT_EQ(
-      "android::SurfaceComposerClient::Transaction::merge(android::SurfaceComposerClient::"
-      "Transaction&&)",
-      demangler.Parse("_ZN7android21SurfaceComposerClient11Transaction5mergeEOS1_"));
-}
-
-TEST(DemangleTest, initial_St) {
-  Demangler demangler;
-  EXPECT_EQ("std::state", demangler.Parse("_ZSt5state"));
-  EXPECT_EQ("std::_In::ward", demangler.Parse("_ZNSt3_In4wardE"));
-  EXPECT_EQ("std::__terminate(void (*)())", demangler.Parse("_ZSt11__terminatePFvvE"));
-}
-
-TEST(DemangleTest, cfi) {
-  Demangler demangler;
-  EXPECT_EQ("nfa_sys_ptim_timer_update(tPTIM_CB*)",
-            demangler.Parse("_Z25nfa_sys_ptim_timer_updateP8tPTIM_CB"));
-  EXPECT_EQ("nfa_sys_ptim_timer_update(tPTIM_CB*) [clone .cfi]",
-            demangler.Parse("_Z25nfa_sys_ptim_timer_updateP8tPTIM_CB.cfi"));
-}
-
-TEST(DemangleTest, demangle) {
-  std::string str;
-
-  str = demangle("_ZN1a1b1cES0_");
-  ASSERT_EQ("a::b::c(a::b)", str);
-
-  str = demangle("_");
-  ASSERT_EQ("_", str);
-
-  str = demangle("_Z");
-  ASSERT_EQ("_Z", str);
-
-  str = demangle("_Za");
-  ASSERT_EQ("_Za", str);
-
-  str = demangle("_Zaa");
-  ASSERT_EQ("operator&&", str);
-
-  str = demangle("Xa");
-  ASSERT_EQ("Xa", str);
-}
diff --git a/demangle/Demangler.cpp b/demangle/Demangler.cpp
deleted file mode 100644
index 7bae356..0000000
--- a/demangle/Demangler.cpp
+++ /dev/null
@@ -1,925 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <assert.h>
-#include <string.h>
-
-#include <cctype>
-#include <stack>
-#include <string>
-#include <vector>
-
-#include "Demangler.h"
-
-constexpr const char* Demangler::kTypes[];
-constexpr const char* Demangler::kDTypes[];
-constexpr const char* Demangler::kSTypes[];
-
-void Demangler::Save(const std::string& str, bool is_name) {
-  saves_.push_back(str);
-  last_save_name_ = is_name;
-}
-
-std::string Demangler::GetArgumentsString() {
-  size_t num_args = cur_state_.args.size();
-  std::string arg_str;
-  if (num_args > 0) {
-    arg_str = cur_state_.args[0];
-    for (size_t i = 1; i < num_args; i++) {
-      arg_str += ", " + cur_state_.args[i];
-    }
-  }
-  return arg_str;
-}
-
-const char* Demangler::AppendOperatorString(const char* name) {
-  const char* oper = nullptr;
-  switch (*name) {
-  case 'a':
-    name++;
-    switch (*name) {
-    case 'a':
-      oper = "operator&&";
-      break;
-    case 'd':
-    case 'n':
-      oper = "operator&";
-      break;
-    case 'N':
-      oper = "operator&=";
-      break;
-    case 'S':
-      oper = "operator=";
-      break;
-    }
-    break;
-  case 'c':
-    name++;
-    switch (*name) {
-    case 'l':
-      oper = "operator()";
-      break;
-    case 'm':
-      oper = "operator,";
-      break;
-    case 'o':
-      oper = "operator~";
-      break;
-    }
-    break;
-  case 'd':
-    name++;
-    switch (*name) {
-    case 'a':
-      oper = "operator delete[]";
-      break;
-    case 'e':
-      oper = "operator*";
-      break;
-    case 'l':
-      oper = "operator delete";
-      break;
-    case 'v':
-      oper = "operator/";
-      break;
-    case 'V':
-      oper = "operator/=";
-      break;
-    }
-    break;
-  case 'e':
-    name++;
-    switch (*name) {
-    case 'o':
-      oper = "operator^";
-      break;
-    case 'O':
-      oper = "operator^=";
-      break;
-    case 'q':
-      oper = "operator==";
-      break;
-    }
-    break;
-  case 'g':
-    name++;
-    switch (*name) {
-    case 'e':
-      oper = "operator>=";
-      break;
-    case 't':
-      oper = "operator>";
-      break;
-    }
-    break;
-  case 'i':
-    name++;
-    switch (*name) {
-    case 'x':
-      oper = "operator[]";
-      break;
-    }
-    break;
-  case 'l':
-    name++;
-    switch (*name) {
-    case 'e':
-      oper = "operator<=";
-      break;
-    case 's':
-      oper = "operator<<";
-      break;
-    case 'S':
-      oper = "operator<<=";
-      break;
-    case 't':
-      oper = "operator<";
-      break;
-    }
-    break;
-  case 'm':
-    name++;
-    switch (*name) {
-    case 'i':
-      oper = "operator-";
-      break;
-    case 'I':
-      oper = "operator-=";
-      break;
-    case 'l':
-      oper = "operator*";
-      break;
-    case 'L':
-      oper = "operator*=";
-      break;
-    case 'm':
-      oper = "operator--";
-      break;
-    }
-    break;
-  case 'n':
-    name++;
-    switch (*name) {
-    case 'a':
-      oper = "operator new[]";
-      break;
-    case 'e':
-      oper = "operator!=";
-      break;
-    case 'g':
-      oper = "operator-";
-      break;
-    case 't':
-      oper = "operator!";
-      break;
-    case 'w':
-      oper = "operator new";
-      break;
-    }
-    break;
-  case 'o':
-    name++;
-    switch (*name) {
-    case 'o':
-      oper = "operator||";
-      break;
-    case 'r':
-      oper = "operator|";
-      break;
-    case 'R':
-      oper = "operator|=";
-      break;
-    }
-    break;
-  case 'p':
-    name++;
-    switch (*name) {
-    case 'm':
-      oper = "operator->*";
-      break;
-    case 'l':
-      oper = "operator+";
-      break;
-    case 'L':
-      oper = "operator+=";
-      break;
-    case 'p':
-      oper = "operator++";
-      break;
-    case 's':
-      oper = "operator+";
-      break;
-    case 't':
-      oper = "operator->";
-      break;
-    }
-    break;
-  case 'q':
-    name++;
-    switch (*name) {
-    case 'u':
-      oper = "operator?";
-      break;
-    }
-    break;
-  case 'r':
-    name++;
-    switch (*name) {
-    case 'm':
-      oper = "operator%";
-      break;
-    case 'M':
-      oper = "operator%=";
-      break;
-    case 's':
-      oper = "operator>>";
-      break;
-    case 'S':
-      oper = "operator>>=";
-      break;
-    }
-    break;
-  }
-  if (oper == nullptr) {
-    return nullptr;
-  }
-  AppendCurrent(oper);
-  cur_state_.last_save = oper;
-  return name + 1;
-}
-
-const char* Demangler::GetStringFromLength(const char* name, std::string* str) {
-  assert(std::isdigit(*name));
-
-  size_t length = *name - '0';
-  name++;
-  while (*name != '\0' && std::isdigit(*name)) {
-    length = length * 10 + *name - '0';
-    name++;
-  }
-
-  std::string read_str;
-  while (*name != '\0' && length != 0) {
-    read_str += *name;
-    name++;
-    length--;
-  }
-  if (length != 0) {
-    return nullptr;
-  }
-  // Special replacement of _GLOBAL__N_1 to (anonymous namespace).
-  if (read_str == "_GLOBAL__N_1") {
-    *str += "(anonymous namespace)";
-  } else {
-    *str += read_str;
-  }
-  return name;
-}
-
-void Demangler::AppendCurrent(const std::string& str) {
-  if (!cur_state_.str.empty()) {
-    cur_state_.str += "::";
-  }
-  cur_state_.str += str;
-}
-
-void Demangler::AppendCurrent(const char* str) {
-  if (!cur_state_.str.empty()) {
-    cur_state_.str += "::";
-  }
-  cur_state_.str += str;
-}
-
-const char* Demangler::ParseS(const char* name) {
-  if (std::islower(*name)) {
-    const char* type = kSTypes[*name - 'a'];
-    if (type == nullptr) {
-      return nullptr;
-    }
-    AppendCurrent(type);
-    return name + 1;
-  }
-
-  if (saves_.empty()) {
-    return nullptr;
-  }
-
-  if (*name == '_') {
-    last_save_name_ = false;
-    AppendCurrent(saves_[0]);
-    return name + 1;
-  }
-
-  bool isdigit = std::isdigit(*name);
-  if (!isdigit && !std::isupper(*name)) {
-    return nullptr;
-  }
-
-  size_t index;
-  if (isdigit) {
-    index = *name - '0' + 1;
-  } else {
-    index = *name - 'A' + 11;
-  }
-  name++;
-  if (*name != '_') {
-    return nullptr;
-  }
-
-  if (index >= saves_.size()) {
-    return nullptr;
-  }
-
-  last_save_name_ = false;
-  AppendCurrent(saves_[index]);
-  return name + 1;
-}
-
-const char* Demangler::ParseT(const char* name) {
-  if (template_saves_.empty()) {
-    return nullptr;
-  }
-
-  if (*name == '_') {
-    last_save_name_ = false;
-    AppendCurrent(template_saves_[0]);
-    return name + 1;
-  }
-
-  // Need to get the total number.
-  char* end;
-  unsigned long int index = strtoul(name, &end, 10) + 1;
-  if (name == end || *end != '_') {
-    return nullptr;
-  }
-
-  if (index >= template_saves_.size()) {
-    return nullptr;
-  }
-
-  last_save_name_ = false;
-  AppendCurrent(template_saves_[index]);
-  return end + 1;
-}
-
-const char* Demangler::ParseFunctionName(const char* name) {
-  if (*name == 'E') {
-    if (parse_funcs_.empty()) {
-      return nullptr;
-    }
-    parse_func_ = parse_funcs_.back();
-    parse_funcs_.pop_back();
-
-    // Remove the last saved part so that the full function name is not saved.
-    // But only if the last save was not something like a substitution.
-    if (!saves_.empty() && last_save_name_) {
-      saves_.pop_back();
-    }
-
-    function_name_ += cur_state_.str;
-    while (!cur_state_.suffixes.empty()) {
-      function_suffix_ += cur_state_.suffixes.back();
-      cur_state_.suffixes.pop_back();
-    }
-    cur_state_.Clear();
-
-    return name + 1;
-  }
-
-  if (*name == 'I') {
-    state_stack_.push(cur_state_);
-    cur_state_.Clear();
-
-    parse_funcs_.push_back(parse_func_);
-    parse_func_ = &Demangler::ParseFunctionNameTemplate;
-    return name + 1;
-  }
-
-  return ParseComplexString(name);
-}
-
-const char* Demangler::ParseFunctionNameTemplate(const char* name) {
-  if (*name == 'E' && name[1] == 'E') {
-    // Only consider this a template with saves if it is right before
-    // the end of the name.
-    template_found_ = true;
-    template_saves_ = cur_state_.args;
-  }
-  return ParseTemplateArgumentsComplex(name);
-}
-
-const char* Demangler::ParseComplexArgument(const char* name) {
-  if (*name == 'E') {
-    if (parse_funcs_.empty()) {
-      return nullptr;
-    }
-    parse_func_ = parse_funcs_.back();
-    parse_funcs_.pop_back();
-
-    AppendArgument(cur_state_.str);
-    cur_state_.str.clear();
-
-    return name + 1;
-  }
-
-  return ParseComplexString(name);
-}
-
-void Demangler::FinalizeTemplate() {
-  std::string arg_str(GetArgumentsString());
-  cur_state_ = state_stack_.top();
-  state_stack_.pop();
-  cur_state_.str += '<' + arg_str + '>';
-}
-
-const char* Demangler::ParseComplexString(const char* name) {
-  if (*name == 'S') {
-    name++;
-    if (*name == 't') {
-      AppendCurrent("std");
-      return name + 1;
-    }
-    return ParseS(name);
-  }
-  if (*name == 'L') {
-    name++;
-    if (!std::isdigit(*name)) {
-      return nullptr;
-    }
-  }
-  if (std::isdigit(*name)) {
-    std::string str;
-    name = GetStringFromLength(name, &str);
-    if (name == nullptr) {
-      return name;
-    }
-    AppendCurrent(str);
-    Save(cur_state_.str, true);
-    cur_state_.last_save = std::move(str);
-    return name;
-  }
-  if (*name == 'D') {
-    name++;
-    if (saves_.empty() || (*name != '0' && *name != '1' && *name != '2'
-        && *name != '5')) {
-      return nullptr;
-    }
-    last_save_name_ = false;
-    AppendCurrent("~" + cur_state_.last_save);
-    return name + 1;
-  }
-  if (*name == 'C') {
-    name++;
-    if (saves_.empty() || (*name != '1' && *name != '2' && *name != '3'
-        && *name != '5')) {
-      return nullptr;
-    }
-    last_save_name_ = false;
-    AppendCurrent(cur_state_.last_save);
-    return name + 1;
-  }
-  if (*name == 'K') {
-    cur_state_.suffixes.push_back(" const");
-    return name + 1;
-  }
-  if (*name == 'V') {
-    cur_state_.suffixes.push_back(" volatile");
-    return name + 1;
-  }
-  if (*name == 'I') {
-    // Save the current argument state.
-    state_stack_.push(cur_state_);
-    cur_state_.Clear();
-
-    parse_funcs_.push_back(parse_func_);
-    parse_func_ = &Demangler::ParseTemplateArgumentsComplex;
-    return name + 1;
-  }
-  name = AppendOperatorString(name);
-  if (name != nullptr) {
-    Save(cur_state_.str, true);
-  }
-  return name;
-}
-
-void Demangler::AppendArgument(const std::string& str) {
-  std::string arg(str);
-  while (!cur_state_.suffixes.empty()) {
-    arg += cur_state_.suffixes.back();
-    cur_state_.suffixes.pop_back();
-    Save(arg, false);
-  }
-  cur_state_.args.push_back(arg);
-}
-
-const char* Demangler::ParseFunctionArgument(const char* name) {
-  if (*name == 'E') {
-    // The first argument is the function modifier.
-    // The second argument is the function type.
-    // The third argument is the return type of the function.
-    // The rest of the arguments are the function arguments.
-    size_t num_args = cur_state_.args.size();
-    if (num_args < 4) {
-      return nullptr;
-    }
-    std::string function_modifier = cur_state_.args[0];
-    std::string function_type = cur_state_.args[1];
-
-    std::string str = cur_state_.args[2] + ' ';
-    if (!cur_state_.args[1].empty()) {
-      str += '(' + cur_state_.args[1] + ')';
-    }
-
-    if (num_args == 4 && cur_state_.args[3] == "void") {
-      str += "()";
-    } else {
-      str += '(' + cur_state_.args[3];
-      for (size_t i = 4; i < num_args; i++) {
-        str += ", " + cur_state_.args[i];
-      }
-      str += ')';
-    }
-    str += cur_state_.args[0];
-
-    cur_state_ = state_stack_.top();
-    state_stack_.pop();
-    cur_state_.args.emplace_back(std::move(str));
-
-    parse_func_ = parse_funcs_.back();
-    parse_funcs_.pop_back();
-    return name + 1;
-  }
-  return ParseArguments(name);
-}
-
-const char* Demangler::ParseArguments(const char* name) {
-  switch (*name) {
-  case 'P':
-    cur_state_.suffixes.push_back("*");
-    return name + 1;
-
-  case 'R':
-    // This should always be okay because the string is guaranteed to have
-    // at least two characters before this. A mangled string always starts
-    // with _Z.
-    if (name[-1] != 'R') {
-      // Multiple 'R's in a row only add a single &.
-      cur_state_.suffixes.push_back("&");
-    }
-    return name + 1;
-
-  case 'O':
-    cur_state_.suffixes.push_back("&&");
-    return name + 1;
-
-  case 'K':
-  case 'V': {
-    const char* suffix;
-    if (*name == 'K') {
-      suffix = " const";
-    } else {
-      suffix = " volatile";
-    }
-    if (!cur_state_.suffixes.empty() && (name[-1] == 'K' || name[-1] == 'V')) {
-      // Special case, const/volatile apply as a single entity.
-      size_t index = cur_state_.suffixes.size();
-      cur_state_.suffixes[index-1].insert(0, suffix);
-    } else {
-      cur_state_.suffixes.push_back(suffix);
-    }
-    return name + 1;
-  }
-
-  case 'F': {
-    std::string function_modifier;
-    std::string function_type;
-    if (!cur_state_.suffixes.empty()) {
-      // If the first element starts with a ' ', then this modifies the
-      // function itself.
-      if (cur_state_.suffixes.back()[0] == ' ') {
-        function_modifier = cur_state_.suffixes.back();
-        cur_state_.suffixes.pop_back();
-      }
-      while (!cur_state_.suffixes.empty()) {
-        function_type += cur_state_.suffixes.back();
-        cur_state_.suffixes.pop_back();
-      }
-    }
-
-    state_stack_.push(cur_state_);
-
-    cur_state_.Clear();
-
-    // The function parameter has this format:
-    //   First argument is the function modifier.
-    //   Second argument is the function type.
-    //   Third argument will be the return function type but has not
-    //     been parsed yet.
-    //   Any other parameters are the arguments to the function. There
-    //     must be at least one or this isn't valid.
-    cur_state_.args.push_back(function_modifier);
-    cur_state_.args.push_back(function_type);
-
-    parse_funcs_.push_back(parse_func_);
-    parse_func_ = &Demangler::ParseFunctionArgument;
-    return name + 1;
-  }
-
-  case 'N':
-    parse_funcs_.push_back(parse_func_);
-    parse_func_ = &Demangler::ParseComplexArgument;
-    return name + 1;
-
-  case 'S':
-    name++;
-    if (*name == 't') {
-      cur_state_.str = "std::";
-      return name + 1;
-    }
-    name = ParseS(name);
-    if (name == nullptr) {
-      return nullptr;
-    }
-    AppendArgument(cur_state_.str);
-    cur_state_.str.clear();
-    return name;
-
-  case 'D':
-    name++;
-    if (*name >= 'a' && *name <= 'z') {
-      const char* arg = Demangler::kDTypes[*name - 'a'];
-      if (arg == nullptr) {
-        return nullptr;
-      }
-      AppendArgument(arg);
-      return name + 1;
-    }
-    return nullptr;
-
-  case 'I':
-    // Save the current argument state.
-    state_stack_.push(cur_state_);
-    cur_state_.Clear();
-
-    parse_funcs_.push_back(parse_func_);
-    parse_func_ = &Demangler::ParseTemplateArguments;
-    return name + 1;
-
-  case 'v':
-    AppendArgument("void");
-    return name + 1;
-
-  default:
-    if (*name >= 'a' && *name <= 'z') {
-      const char* arg = Demangler::kTypes[*name - 'a'];
-      if (arg == nullptr) {
-        return nullptr;
-      }
-      AppendArgument(arg);
-      return name + 1;
-    } else if (std::isdigit(*name)) {
-      std::string arg = cur_state_.str;
-      name = GetStringFromLength(name, &arg);
-      if (name == nullptr) {
-        return nullptr;
-      }
-      Save(arg, true);
-      if (*name == 'I') {
-        // There is one case where this argument is not complete, and that's
-        // where this is a template argument.
-        cur_state_.str = arg;
-      } else {
-        AppendArgument(arg);
-        cur_state_.str.clear();
-      }
-      return name;
-    } else if (strcmp(name, ".cfi") == 0) {
-      function_suffix_ += " [clone .cfi]";
-      return name + 4;
-    }
-  }
-  return nullptr;
-}
-
-const char* Demangler::ParseTemplateLiteral(const char* name) {
-  if (*name == 'E') {
-    parse_func_ = parse_funcs_.back();
-    parse_funcs_.pop_back();
-    return name + 1;
-  }
-  // Only understand boolean values with 0 or 1.
-  if (*name == 'b') {
-    name++;
-    if (*name == '0') {
-      AppendArgument("false");
-      cur_state_.str.clear();
-    } else if (*name == '1') {
-      AppendArgument("true");
-      cur_state_.str.clear();
-    } else {
-      return nullptr;
-    }
-    return name + 1;
-  }
-  return nullptr;
-}
-
-const char* Demangler::ParseTemplateArgumentsComplex(const char* name) {
-  if (*name == 'E') {
-    if (parse_funcs_.empty()) {
-      return nullptr;
-    }
-    parse_func_ = parse_funcs_.back();
-    parse_funcs_.pop_back();
-
-    FinalizeTemplate();
-    Save(cur_state_.str, false);
-    return name + 1;
-  } else if (*name == 'L') {
-    // Literal value for a template.
-    parse_funcs_.push_back(parse_func_);
-    parse_func_ = &Demangler::ParseTemplateLiteral;
-    return name + 1;
-  }
-
-  return ParseArguments(name);
-}
-
-const char* Demangler::ParseTemplateArguments(const char* name) {
-  if (*name == 'E') {
-    if (parse_funcs_.empty()) {
-      return nullptr;
-    }
-    parse_func_ = parse_funcs_.back();
-    parse_funcs_.pop_back();
-    FinalizeTemplate();
-    AppendArgument(cur_state_.str);
-    cur_state_.str.clear();
-    return name + 1;
-  } else if (*name == 'L') {
-    // Literal value for a template.
-    parse_funcs_.push_back(parse_func_);
-    parse_func_ = &Demangler::ParseTemplateLiteral;
-    return name + 1;
-  }
-
-  return ParseArguments(name);
-}
-
-const char* Demangler::ParseFunctionTemplateArguments(const char* name) {
-  if (*name == 'E') {
-    parse_func_ = parse_funcs_.back();
-    parse_funcs_.pop_back();
-
-    function_name_ += '<' + GetArgumentsString() + '>';
-    template_found_ = true;
-    template_saves_ = cur_state_.args;
-    cur_state_.Clear();
-    return name + 1;
-  }
-  return ParseTemplateArgumentsComplex(name);
-}
-
-const char* Demangler::FindFunctionName(const char* name) {
-  if (*name == 'T') {
-    // non-virtual thunk, verify that it matches one of these patterns:
-    //   Thn[0-9]+_
-    //   Th[0-9]+_
-    //   Thn_
-    //   Th_
-    name++;
-    if (*name != 'h') {
-      return nullptr;
-    }
-    name++;
-    if (*name == 'n') {
-      name++;
-    }
-    while (std::isdigit(*name)) {
-      name++;
-    }
-    if (*name != '_') {
-      return nullptr;
-    }
-    function_name_ = "non-virtual thunk to ";
-    return name + 1;
-  }
-
-  if (*name == 'N') {
-    parse_funcs_.push_back(&Demangler::ParseArgumentsAtTopLevel);
-    parse_func_ = &Demangler::ParseFunctionName;
-    return name + 1;
-  }
-
-  if (*name == 'S') {
-    name++;
-    if (*name == 't') {
-      function_name_ = "std::";
-      name++;
-    } else {
-      return nullptr;
-    }
-  }
-
-  if (std::isdigit(*name)) {
-    name = GetStringFromLength(name, &function_name_);
-  } else if (*name == 'L' && std::isdigit(name[1])) {
-    name = GetStringFromLength(name + 1, &function_name_);
-  } else {
-    name = AppendOperatorString(name);
-    function_name_ = cur_state_.str;
-  }
-  cur_state_.Clear();
-
-  // Check for a template argument, which will still be part of the function
-  // name.
-  if (name != nullptr && *name == 'I') {
-    parse_funcs_.push_back(&Demangler::ParseArgumentsAtTopLevel);
-    parse_func_ = &Demangler::ParseFunctionTemplateArguments;
-    return name + 1;
-  }
-  parse_func_ = &Demangler::ParseArgumentsAtTopLevel;
-  return name;
-}
-
-const char* Demangler::ParseArgumentsAtTopLevel(const char* name) {
-  // At the top level is the only place where T is allowed.
-  if (*name == 'T') {
-    name++;
-    name = ParseT(name);
-    if (name == nullptr) {
-      return nullptr;
-    }
-    AppendArgument(cur_state_.str);
-    cur_state_.str.clear();
-    return name;
-  }
-
-  return Demangler::ParseArguments(name);
-}
-
-std::string Demangler::Parse(const char* name, size_t max_length) {
-  if (name[0] == '\0' || name[0] != '_' || name[1] == '\0' || name[1] != 'Z') {
-    // Name is not mangled.
-    return name;
-  }
-
-  Clear();
-
-  parse_func_ = &Demangler::FindFunctionName;
-  parse_funcs_.push_back(&Demangler::Fail);
-  const char* cur_name = name + 2;
-  while (cur_name != nullptr && *cur_name != '\0'
-      && static_cast<size_t>(cur_name - name) < max_length) {
-    cur_name = (this->*parse_func_)(cur_name);
-  }
-  if (cur_name == nullptr || *cur_name != '\0' || function_name_.empty() ||
-      !cur_state_.suffixes.empty()) {
-    return name;
-  }
-
-  std::string return_type;
-  if (template_found_) {
-    // Only a single argument with a template is not allowed.
-    if (cur_state_.args.size() == 1) {
-      return name;
-    }
-
-    // If there are at least two arguments, this template has a return type.
-    if (cur_state_.args.size() > 1) {
-      // The first argument will be the return value.
-      return_type = cur_state_.args[0] + ' ';
-      cur_state_.args.erase(cur_state_.args.begin());
-    }
-  }
-
-  std::string arg_str;
-  if (cur_state_.args.size() == 1 && cur_state_.args[0] == "void") {
-    // If the only argument is void, then don't print any args.
-    arg_str = "()";
-  } else {
-    arg_str = GetArgumentsString();
-    if (!arg_str.empty()) {
-      arg_str = '(' + arg_str + ')';
-    }
-  }
-  return return_type + function_name_ + arg_str + function_suffix_;
-}
-
-std::string demangle(const char* name) {
-  Demangler demangler;
-  return demangler.Parse(name);
-}
diff --git a/demangle/Demangler.h b/demangle/Demangler.h
deleted file mode 100644
index 3b7d44e..0000000
--- a/demangle/Demangler.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __LIB_DEMANGLE_DEMANGLER_H
-#define __LIB_DEMANGLE_DEMANGLER_H
-
-#include <assert.h>
-
-#include <stack>
-#include <string>
-#include <vector>
-
-class Demangler {
- public:
-  Demangler() = default;
-
-  // NOTE: The max_length is not guaranteed to be the absolute max length
-  // of a string that will be rejected. Under certain circumstances the
-  // length check will not occur until after the second letter of a pair
-  // is checked.
-  std::string Parse(const char* name, size_t max_length = kMaxDefaultLength);
-
-  void AppendCurrent(const std::string& str);
-  void AppendCurrent(const char* str);
-  void AppendArgument(const std::string& str);
-  std::string GetArgumentsString();
-  void FinalizeTemplate();
-  const char* ParseS(const char* name);
-  const char* ParseT(const char* name);
-  const char* AppendOperatorString(const char* name);
-  void Save(const std::string& str, bool is_name);
-
- private:
-  void Clear() {
-    parse_funcs_.clear();
-    function_name_.clear();
-    function_suffix_.clear();
-    first_save_.clear();
-    cur_state_.Clear();
-    saves_.clear();
-    template_saves_.clear();
-    while (!state_stack_.empty()) {
-      state_stack_.pop();
-    }
-    last_save_name_ = false;
-    template_found_ = false;
-  }
-
-  using parse_func_type = const char* (Demangler::*)(const char*);
-  parse_func_type parse_func_;
-  std::vector<parse_func_type> parse_funcs_;
-  std::vector<std::string> saves_;
-  std::vector<std::string> template_saves_;
-  bool last_save_name_;
-  bool template_found_;
-
-  std::string function_name_;
-  std::string function_suffix_;
-
-  struct StateData {
-    void Clear() {
-      str.clear();
-      args.clear();
-      prefix.clear();
-      suffixes.clear();
-      last_save.clear();
-    }
-
-    std::string str;
-    std::vector<std::string> args;
-    std::string prefix;
-    std::vector<std::string> suffixes;
-    std::string last_save;
-  };
-  std::stack<StateData> state_stack_;
-  std::string first_save_;
-  StateData cur_state_;
-
-  static const char* GetStringFromLength(const char* name, std::string* str);
-
-  // Parsing functions.
-  const char* ParseComplexString(const char* name);
-  const char* ParseComplexArgument(const char* name);
-  const char* ParseArgumentsAtTopLevel(const char* name);
-  const char* ParseArguments(const char* name);
-  const char* ParseTemplateArguments(const char* name);
-  const char* ParseTemplateArgumentsComplex(const char* name);
-  const char* ParseTemplateLiteral(const char* name);
-  const char* ParseFunctionArgument(const char* name);
-  const char* ParseFunctionName(const char* name);
-  const char* ParseFunctionNameTemplate(const char* name);
-  const char* ParseFunctionTemplateArguments(const char* name);
-  const char* FindFunctionName(const char* name);
-  const char* Fail(const char*) { return nullptr; }
-
-  // The default maximum string length string to process.
-  static constexpr size_t kMaxDefaultLength = 2048;
-
-  static constexpr const char* kTypes[] = {
-    "signed char",        // a
-    "bool",               // b
-    "char",               // c
-    "double",             // d
-    "long double",        // e
-    "float",              // f
-    "__float128",         // g
-    "unsigned char",      // h
-    "int",                // i
-    "unsigned int",       // j
-    nullptr,              // k
-    "long",               // l
-    "unsigned long",      // m
-    "__int128",           // n
-    "unsigned __int128",  // o
-    nullptr,              // p
-    nullptr,              // q
-    nullptr,              // r
-    "short",              // s
-    "unsigned short",     // t
-    nullptr,              // u
-    "void",               // v
-    "wchar_t",            // w
-    "long long",          // x
-    "unsigned long long", // y
-    "...",                // z
-  };
-
-  static constexpr const char* kDTypes[] = {
-    "auto",               // a
-    nullptr,              // b
-    nullptr,              // c
-    "decimal64",          // d
-    "decimal128",         // e
-    "decimal32",          // f
-    nullptr,              // g
-    "half",               // h
-    "char32_t",           // i
-    nullptr,              // j
-    nullptr,              // k
-    nullptr,              // l
-    nullptr,              // m
-    "decltype(nullptr)",  // n
-    nullptr,              // o
-    nullptr,              // p
-    nullptr,              // q
-    nullptr,              // r
-    "char16_t",           // s
-    nullptr,              // t
-    nullptr,              // u
-    nullptr,              // v
-    nullptr,              // w
-    nullptr,              // x
-    nullptr,              // y
-    nullptr,              // z
-  };
-
-  static constexpr const char* kSTypes[] = {
-    "std::allocator",     // a
-    "std::basic_string",  // b
-    nullptr,              // c
-    "std::iostream",      // d
-    nullptr,              // e
-    nullptr,              // f
-    nullptr,              // g
-    nullptr,              // h
-    "std::istream",       // i
-    nullptr,              // j
-    nullptr,              // k
-    nullptr,              // l
-    nullptr,              // m
-    nullptr,              // n
-    "std::ostream",       // o
-    nullptr,              // p
-    nullptr,              // q
-    nullptr,              // r
-    "std::string",        // s
-    nullptr,              // t
-    nullptr,              // u
-    nullptr,              // v
-    nullptr,              // w
-    nullptr,              // x
-    nullptr,              // y
-    nullptr,              // z
-  };
-};
-
-#endif  // __LIB_DEMANGLE_DEMANGLER_H
diff --git a/demangle/OWNERS b/demangle/OWNERS
deleted file mode 100644
index 6f7e4a3..0000000
--- a/demangle/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-cferris@google.com
diff --git a/demangle/demangle.cpp b/demangle/demangle.cpp
deleted file mode 100644
index 66e5e58..0000000
--- a/demangle/demangle.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <cctype>
-#include <string>
-
-#include <demangle.h>
-
-extern "C" char* __cxa_demangle(const char*, char*, size_t*, int*);
-
-static void Usage(const char* prog_name) {
-  printf("usage: %s [-c] [NAME_TO_DEMANGLE...]\n", prog_name);
-  printf("\n");
-  printf("Demangles C++ mangled names if supplied on the command-line, or found\n");
-  printf("reading from stdin otherwise.\n");
-  printf("\n");
-  printf("-c\tCompare against __cxa_demangle\n");
-  printf("\n");
-}
-
-static std::string DemangleWithCxa(const char* name) {
-  const char* cxa_demangle = __cxa_demangle(name, nullptr, nullptr, nullptr);
-  if (cxa_demangle == nullptr) {
-    return name;
-  }
-
-  // The format of our demangler is slightly different from the cxa demangler
-  // so modify the cxa demangler output. Specifically, for templates, remove
-  // the spaces between '>' and '>'.
-  std::string demangled_str;
-  for (size_t i = 0; i < strlen(cxa_demangle); i++) {
-    if (i > 2 && cxa_demangle[i] == '>' && std::isspace(cxa_demangle[i - 1]) &&
-        cxa_demangle[i - 2] == '>') {
-      demangled_str.resize(demangled_str.size() - 1);
-    }
-    demangled_str += cxa_demangle[i];
-  }
-  return demangled_str;
-}
-
-static void Compare(const char* name, const std::string& demangled_name) {
-  std::string cxa_demangled_name(DemangleWithCxa(name));
-  if (cxa_demangled_name != demangled_name) {
-    printf("\nMismatch!\n");
-    printf("\tmangled name: %s\n", name);
-    printf("\tour demangle: %s\n", demangled_name.c_str());
-    printf("\tcxa demangle: %s\n", cxa_demangled_name.c_str());
-    exit(1);
-  }
-}
-
-static int Filter(bool compare) {
-  char* line = nullptr;
-  size_t line_length = 0;
-
-  while ((getline(&line, &line_length, stdin)) != -1) {
-    char* p = line;
-    char* name;
-    while ((name = strstr(p, "_Z")) != nullptr) {
-      // Output anything before the identifier.
-      *name = 0;
-      printf("%s", p);
-      *name = '_';
-
-      // Extract the identifier.
-      p = name;
-      while (*p && (std::isalnum(*p) || *p == '_' || *p == '.' || *p == '$')) ++p;
-
-      // Demangle and output.
-      std::string identifier(name, p);
-      std::string demangled_name = demangle(identifier.c_str());
-      printf("%s", demangled_name.c_str());
-
-      if (compare) Compare(identifier.c_str(), demangled_name);
-    }
-    // Output anything after the last identifier.
-    printf("%s", p);
-  }
-
-  free(line);
-  return 0;
-}
-
-int main(int argc, char** argv) {
-#ifdef __BIONIC__
-  const char* prog_name = getprogname();
-#else
-  const char* prog_name = argv[0];
-#endif
-
-  bool compare = false;
-  int opt_char;
-  while ((opt_char = getopt(argc, argv, "c")) != -1) {
-    if (opt_char == 'c') {
-      compare = true;
-    } else {
-      Usage(prog_name);
-      return 1;
-    }
-  }
-
-  // With no arguments, act as a filter.
-  if (optind == argc) return Filter(compare);
-
-  // Otherwise demangle each argument.
-  while (optind < argc) {
-    const char* name = argv[optind++];
-    std::string demangled_name = demangle(name);
-    printf("%s\n", demangled_name.c_str());
-
-    if (compare) Compare(name, demangled_name);
-  }
-  return 0;
-}
diff --git a/demangle/demangle_fuzzer.cpp b/demangle/demangle_fuzzer.cpp
deleted file mode 100644
index 83fafc2..0000000
--- a/demangle/demangle_fuzzer.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <string>
-
-#include "Demangler.h"
-
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  std::vector<char> data_str(size + 1);
-  memcpy(data_str.data(), data, size);
-  data_str[size] = '\0';
-
-  Demangler demangler;
-  std::string demangled_name = demangler.Parse(data_str.data());
-  if (size != 0 && data_str[0] != '\0' && demangled_name.empty()) {
-    abort();
-  }
-}
diff --git a/demangle/include/demangle.h b/demangle/include/demangle.h
deleted file mode 100644
index 01f1b80..0000000
--- a/demangle/include/demangle.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __LIB_DEMANGLE_H_
-#define __LIB_DEMANGLE_H_
-
-#include <string>
-
-// If the name cannot be demangled, the original name will be returned as
-// a std::string. If the name can be demangled, then the demangled name
-// will be returned as a std::string.
-std::string demangle(const char* name);
-
-#endif  // __LIB_DEMANGLE_H_
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/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 39abc4a..8923f40 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -144,14 +144,13 @@
     { "dts",      "dt.img",           "dt.sig",       "dts",      true,  ImageType::BootCritical },
     { "odm",      "odm.img",          "odm.sig",      "odm",      true,  ImageType::Normal },
     { "product",  "product.img",      "product.sig",  "product",  true,  ImageType::Normal },
-    { "product_services",
-                  "product_services.img",
-                                      "product_services.sig",
-                                                      "product_services",
-                                                                  true,  ImageType::Normal },
     { "recovery", "recovery.img",     "recovery.sig", "recovery", true,  ImageType::BootCritical },
     { "super",    "super.img",        "super.sig",    "super",    true,  ImageType::Extra },
     { "system",   "system.img",       "system.sig",   "system",   false, ImageType::Normal },
+    { "system_ext",
+                  "system_ext.img",   "system_ext.sig",
+                                                      "system_ext",
+                                                                  true,  ImageType::Normal },
     { nullptr,    "system_other.img", "system.sig",   "system",   true,  ImageType::Normal },
     { "userdata", "userdata.img",     "userdata.sig", "userdata", true,  ImageType::Extra },
     { "vbmeta",   "vbmeta.img",       "vbmeta.sig",   "vbmeta",   true,  ImageType::BootCritical },
@@ -389,6 +388,8 @@
             " set_active SLOT            Set the active slot.\n"
             " oem [COMMAND...]           Execute OEM-specific command.\n"
             " gsi wipe|disable           Wipe or disable a GSI installation (fastbootd only).\n"
+            " wipe-super [SUPER_EMPTY]   Wipe the super partition. This will reset it to\n"
+            "                            contain an empty set of default dynamic partitions.\n"
             "\n"
             "boot image:\n"
             " boot KERNEL [RAMDISK [SECOND]]\n"
@@ -1582,6 +1583,76 @@
     return false;
 }
 
+static bool wipe_super(const android::fs_mgr::LpMetadata& metadata, const std::string& slot,
+                       std::string* message) {
+    auto super_device = GetMetadataSuperBlockDevice(metadata);
+    auto block_size = metadata.geometry.logical_block_size;
+    auto super_bdev_name = android::fs_mgr::GetBlockDevicePartitionName(*super_device);
+
+    if (super_bdev_name != "super") {
+        // retrofit devices do not allow flashing to the retrofit partitions,
+        // so enable it if we can.
+        fb->RawCommand("oem allow-flash-super");
+    }
+
+    // Note: do not use die() in here, since we want TemporaryDir's destructor
+    // to be called.
+    TemporaryDir temp_dir;
+
+    bool ok;
+    if (metadata.block_devices.size() > 1) {
+        ok = WriteSplitImageFiles(temp_dir.path, metadata, block_size, {}, true);
+    } else {
+        auto image_path = temp_dir.path + "/"s + super_bdev_name + ".img";
+        ok = WriteToImageFile(image_path, metadata, block_size, {}, true);
+    }
+    if (!ok) {
+        *message = "Could not generate a flashable super image file";
+        return false;
+    }
+
+    for (const auto& block_device : metadata.block_devices) {
+        auto partition = android::fs_mgr::GetBlockDevicePartitionName(block_device);
+        bool force_slot = !!(block_device.flags & LP_BLOCK_DEVICE_SLOT_SUFFIXED);
+
+        std::string image_name;
+        if (metadata.block_devices.size() > 1) {
+            image_name = "super_" + partition + ".img";
+        } else {
+            image_name = partition + ".img";
+        }
+
+        auto image_path = temp_dir.path + "/"s + image_name;
+        auto flash = [&](const std::string& partition_name) {
+            do_flash(partition_name.c_str(), image_path.c_str());
+        };
+        do_for_partitions(partition, slot, flash, force_slot);
+
+        unlink(image_path.c_str());
+    }
+    return true;
+}
+
+static void do_wipe_super(const std::string& image, const std::string& slot_override) {
+    if (access(image.c_str(), R_OK) != 0) {
+        die("Could not read image: %s", image.c_str());
+    }
+    auto metadata = android::fs_mgr::ReadFromImageFile(image);
+    if (!metadata) {
+        die("Could not parse image: %s", image.c_str());
+    }
+
+    auto slot = slot_override;
+    if (slot.empty()) {
+        slot = get_current_slot();
+    }
+
+    std::string message;
+    if (!wipe_super(*metadata.get(), slot, &message)) {
+        die(message);
+    }
+}
+
 int FastBootTool::Main(int argc, char* argv[]) {
     bool wants_wipe = false;
     bool wants_reboot = false;
@@ -1958,6 +2029,14 @@
             } else {
                 syntax_error("expected 'wipe' or 'disable'");
             }
+        } else if (command == "wipe-super") {
+            std::string image;
+            if (args.empty()) {
+                image = find_item_given_name("super_empty.img");
+            } else {
+                image = next_arg(&args);
+            }
+            do_wipe_super(image, slot_override);
         } else {
             syntax_error("unknown command %s", command.c_str());
         }
diff --git a/fastboot/util.cpp b/fastboot/util.cpp
index d02b37f..900d6ea 100644
--- a/fastboot/util.cpp
+++ b/fastboot/util.cpp
@@ -53,6 +53,10 @@
     exit(EXIT_FAILURE);
 }
 
+void die(const std::string& str) {
+    die("%s", str.c_str());
+}
+
 void set_verbose() {
     g_verbose = true;
 }
diff --git a/fastboot/util.h b/fastboot/util.h
index 2535414..c719df2 100644
--- a/fastboot/util.h
+++ b/fastboot/util.h
@@ -15,4 +15,7 @@
 // use the same attribute for compile-time format string checking.
 void die(const char* fmt, ...) __attribute__((__noreturn__))
 __attribute__((__format__(__printf__, 1, 2)));
+
 void verbose(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
+
+void die(const std::string& str) __attribute__((__noreturn__));
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..4cdea71 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -27,8 +27,12 @@
         "dm_target.cpp",
         "dm.cpp",
         "loop_control.cpp",
+        "utility.cpp",
     ],
 
+    static_libs: [
+        "libext2_uuid",
+    ],
     header_libs: [
         "libbase_headers",
         "liblog_headers",
@@ -46,6 +50,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..0ad8d9d 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -20,12 +20,22 @@
 #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>
+
+#include "utility.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 +47,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 +61,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 +80,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 +96,58 @@
     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;
+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;
+    }
+    if (!WaitForFile(unique_path, 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 +163,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..b28a8f2 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_;
 };
 
@@ -124,9 +103,9 @@
     ASSERT_TRUE(android::base::WriteFully(tmp1, message1, sizeof(message1)));
     ASSERT_TRUE(android::base::WriteFully(tmp2, message2, sizeof(message2)));
 
-    LoopDevice loop_a(tmp1);
+    LoopDevice loop_a(tmp1, 10s);
     ASSERT_TRUE(loop_a.valid());
-    LoopDevice loop_b(tmp2);
+    LoopDevice loop_b(tmp2, 10s);
     ASSERT_TRUE(loop_b.valid());
 
     // Define a 2-sector device, with each sector mapping to the first sector
@@ -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();
 
@@ -277,9 +255,9 @@
     cow_fd_ = CreateTempFile("cow_device", kCowDeviceSize);
     ASSERT_GE(cow_fd_, 0);
 
-    base_loop_ = std::make_unique<LoopDevice>(base_fd_);
+    base_loop_ = std::make_unique<LoopDevice>(base_fd_, 10s);
     ASSERT_TRUE(base_loop_->valid());
-    cow_loop_ = std::make_unique<LoopDevice>(cow_fd_);
+    cow_loop_ = std::make_unique<LoopDevice>(cow_fd_, 10s);
     ASSERT_TRUE(cow_loop_->valid());
 
     DmTable origin_table;
@@ -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 afcb090..9c0c2f3 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>
@@ -38,7 +39,7 @@
 #define DM_VERSION2 (0)
 
 #define DM_ALIGN_MASK (7)
-#define DM_ALIGN(x) ((x + DM_ALIGN_MASK) & ~DM_ALIGN_MASK)
+#define DM_ALIGN(x) (((x) + DM_ALIGN_MASK) & ~DM_ALIGN_MASK)
 
 namespace android {
 namespace dm {
@@ -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/libdm/include/libdm/loop_control.h b/fs_mgr/libdm/include/libdm/loop_control.h
index 6b4c2d8..eeed6b5 100644
--- a/fs_mgr/libdm/include/libdm/loop_control.h
+++ b/fs_mgr/libdm/include/libdm/loop_control.h
@@ -17,6 +17,7 @@
 #ifndef _LIBDM_LOOP_CONTROL_H_
 #define _LIBDM_LOOP_CONTROL_H_
 
+#include <chrono>
 #include <string>
 
 #include <android-base/unique_fd.h>
@@ -29,8 +30,15 @@
     LoopControl();
 
     // Attaches the file specified by 'file_fd' to the loop device specified
-    // by 'loopdev'
-    bool Attach(int file_fd, std::string* loopdev) const;
+    // by 'loopdev'. It is possible that in between allocating and attaching
+    // a loop device, another process attaches to the chosen loop device. If
+    // this happens, Attach() will retry for up to |timeout_ms|. The timeout
+    // should not be zero.
+    //
+    // The caller does not have to call WaitForFile(); it is implicitly called.
+    // The given |timeout_ms| covers both potential sources of timeout.
+    bool Attach(int file_fd, const std::chrono::milliseconds& timeout_ms,
+                std::string* loopdev) const;
 
     // Detach the loop device given by 'loopdev' from the attached backing file.
     bool Detach(const std::string& loopdev) const;
@@ -56,13 +64,13 @@
   public:
     // Create a loop device for the given file descriptor. It is closed when
     // LoopDevice is destroyed only if auto_close is true.
-    LoopDevice(int fd, bool auto_close = false);
+    LoopDevice(int fd, const std::chrono::milliseconds& timeout_ms, bool auto_close = false);
     // Create a loop device for the given file path. It will be opened for
     // reading and writing and closed when the loop device is detached.
-    explicit LoopDevice(const std::string& path);
+    LoopDevice(const std::string& path, const std::chrono::milliseconds& timeout_ms);
     ~LoopDevice();
 
-    bool valid() const { return fd_ != -1 && !device_.empty(); }
+    bool valid() const { return valid_; }
     const std::string& device() const { return device_; }
 
     LoopDevice(const LoopDevice&) = delete;
@@ -71,12 +79,13 @@
     LoopDevice(LoopDevice&&) = default;
 
   private:
-    void Init();
+    void Init(const std::chrono::milliseconds& timeout_ms);
 
     android::base::unique_fd fd_;
     bool owns_fd_;
     std::string device_;
     LoopControl control_;
+    bool valid_ = false;
 };
 
 }  // namespace dm
diff --git a/fs_mgr/libdm/loop_control.cpp b/fs_mgr/libdm/loop_control.cpp
index 16bf4b0..edc9a45 100644
--- a/fs_mgr/libdm/loop_control.cpp
+++ b/fs_mgr/libdm/loop_control.cpp
@@ -27,6 +27,8 @@
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
 
+#include "utility.h"
+
 namespace android {
 namespace dm {
 
@@ -37,21 +39,40 @@
     }
 }
 
-bool LoopControl::Attach(int file_fd, std::string* loopdev) const {
-    if (!FindFreeLoopDevice(loopdev)) {
-        LOG(ERROR) << "Failed to attach, no free loop devices";
-        return false;
-    }
+bool LoopControl::Attach(int file_fd, const std::chrono::milliseconds& timeout_ms,
+                         std::string* loopdev) const {
+    auto start_time = std::chrono::steady_clock::now();
+    auto condition = [&]() -> WaitResult {
+        if (!FindFreeLoopDevice(loopdev)) {
+            LOG(ERROR) << "Failed to attach, no free loop devices";
+            return WaitResult::Fail;
+        }
 
-    android::base::unique_fd loop_fd(TEMP_FAILURE_RETRY(open(loopdev->c_str(), O_RDWR | O_CLOEXEC)));
-    if (loop_fd < 0) {
-        PLOG(ERROR) << "Failed to open: " << *loopdev;
-        return false;
-    }
+        auto now = std::chrono::steady_clock::now();
+        auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
+        if (!WaitForFile(*loopdev, timeout_ms - time_elapsed)) {
+            LOG(ERROR) << "Timed out waiting for path: " << *loopdev;
+            return WaitResult::Fail;
+        }
 
-    int rc = ioctl(loop_fd, LOOP_SET_FD, file_fd);
-    if (rc < 0) {
-        PLOG(ERROR) << "Failed LOOP_SET_FD";
+        android::base::unique_fd loop_fd(
+                TEMP_FAILURE_RETRY(open(loopdev->c_str(), O_RDWR | O_CLOEXEC)));
+        if (loop_fd < 0) {
+            PLOG(ERROR) << "Failed to open: " << *loopdev;
+            return WaitResult::Fail;
+        }
+
+        if (int rc = ioctl(loop_fd, LOOP_SET_FD, file_fd); rc == 0) {
+            return WaitResult::Done;
+        }
+        if (errno != EBUSY) {
+            PLOG(ERROR) << "Failed LOOP_SET_FD";
+            return WaitResult::Fail;
+        }
+        return WaitResult::Wait;
+    };
+    if (!WaitForCondition(condition, timeout_ms)) {
+        LOG(ERROR) << "Timed out trying to acquire a loop device";
         return false;
     }
     return true;
@@ -112,17 +133,19 @@
     return true;
 }
 
-LoopDevice::LoopDevice(int fd, bool auto_close) : fd_(fd), owns_fd_(auto_close) {
-    Init();
+LoopDevice::LoopDevice(int fd, const std::chrono::milliseconds& timeout_ms, bool auto_close)
+    : fd_(fd), owns_fd_(auto_close) {
+    Init(timeout_ms);
 }
 
-LoopDevice::LoopDevice(const std::string& path) : fd_(-1), owns_fd_(true) {
+LoopDevice::LoopDevice(const std::string& path, const std::chrono::milliseconds& timeout_ms)
+    : fd_(-1), owns_fd_(true) {
     fd_.reset(open(path.c_str(), O_RDWR | O_CLOEXEC));
     if (fd_ < -1) {
         PLOG(ERROR) << "open failed for " << path;
         return;
     }
-    Init();
+    Init(timeout_ms);
 }
 
 LoopDevice::~LoopDevice() {
@@ -134,8 +157,8 @@
     }
 }
 
-void LoopDevice::Init() {
-    control_.Attach(fd_, &device_);
+void LoopDevice::Init(const std::chrono::milliseconds& timeout_ms) {
+    valid_ = control_.Attach(fd_, timeout_ms, &device_);
 }
 
 }  // namespace dm
diff --git a/fs_mgr/libdm/loop_control_test.cpp b/fs_mgr/libdm/loop_control_test.cpp
index 08bdc00..0749f26 100644
--- a/fs_mgr/libdm/loop_control_test.cpp
+++ b/fs_mgr/libdm/loop_control_test.cpp
@@ -53,7 +53,7 @@
     unique_fd fd = TempFile();
     ASSERT_GE(fd, 0);
 
-    LoopDevice loop(fd);
+    LoopDevice loop(fd, 10s);
     ASSERT_TRUE(loop.valid());
 
     char buffer[6];
diff --git a/fs_mgr/libdm/utility.cpp b/fs_mgr/libdm/utility.cpp
new file mode 100644
index 0000000..eccf2fb
--- /dev/null
+++ b/fs_mgr/libdm/utility.cpp
@@ -0,0 +1,56 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "utility.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <thread>
+
+using namespace std::literals;
+
+namespace android {
+namespace dm {
+
+bool WaitForCondition(const std::function<WaitResult()>& condition,
+                      const std::chrono::milliseconds& timeout_ms) {
+    auto start_time = std::chrono::steady_clock::now();
+    while (true) {
+        auto result = condition();
+        if (result == WaitResult::Done) return true;
+        if (result == WaitResult::Fail) return false;
+
+        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;
+    }
+}
+
+bool WaitForFile(const std::string& path, const std::chrono::milliseconds& timeout_ms) {
+    auto condition = [&]() -> WaitResult {
+        // If the file exists but returns EPERM or something, we consider the
+        // condition met.
+        if (access(path.c_str(), F_OK) != 0) {
+            if (errno == ENOENT) return WaitResult::Wait;
+        }
+        return WaitResult::Done;
+    };
+    return WaitForCondition(condition, timeout_ms);
+}
+
+}  // namespace dm
+}  // namespace android
diff --git a/fs_mgr/libdm/utility.h b/fs_mgr/libdm/utility.h
new file mode 100644
index 0000000..f1dce9e
--- /dev/null
+++ b/fs_mgr/libdm/utility.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <chrono>
+#include <functional>
+
+namespace android {
+namespace dm {
+
+enum class WaitResult { Wait, Done, Fail };
+
+bool WaitForFile(const std::string& path, const std::chrono::milliseconds& timeout_ms);
+bool WaitForCondition(const std::function<WaitResult()>& condition,
+                      const std::chrono::milliseconds& timeout_ms);
+
+}  // namespace dm
+}  // namespace android
diff --git a/fs_mgr/libfiemap_writer/.clang-format b/fs_mgr/libfiemap_writer/.clang-format
deleted file mode 120000
index 8b770a1..0000000
--- a/fs_mgr/libfiemap_writer/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-../../.clang-format-4
\ No newline at end of file
diff --git a/fs_mgr/libfiemap_writer/Android.bp b/fs_mgr/libfiemap_writer/Android.bp
deleted file mode 100644
index ed209aa..0000000
--- a/fs_mgr/libfiemap_writer/Android.bp
+++ /dev/null
@@ -1,64 +0,0 @@
-//
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-cc_library_static {
-    name: "libfiemap_writer",
-    defaults: ["fs_mgr_defaults"],
-    recovery_available: true,
-    export_include_dirs: ["include"],
-    cflags: [
-        "-D_FILE_OFFSET_BITS=64",
-    ],
-
-    srcs: [
-        "fiemap_writer.cpp",
-        "split_fiemap_writer.cpp",
-        "utility.cpp",
-    ],
-
-    static_libs: [
-        "libdm",
-        "libext4_utils",
-    ],
-
-    header_libs: [
-        "libbase_headers",
-        "liblog_headers",
-    ],
-}
-
-cc_test {
-    name: "fiemap_writer_test",
-    cflags: [
-        "-D_FILE_OFFSET_BITS=64",
-    ],
-    static_libs: [
-        "libbase",
-        "libdm",
-        "libfiemap_writer",
-        "liblog",
-    ],
-
-    data: [
-        "testdata/unaligned_file",
-        "testdata/file_4k",
-        "testdata/file_32k",
-    ],
-
-    srcs: [
-        "fiemap_writer_test.cpp",
-    ],
-}
diff --git a/fs_mgr/libfiemap_writer/Android.mk b/fs_mgr/libfiemap_writer/Android.mk
deleted file mode 100644
index 3c07b8e..0000000
--- a/fs_mgr/libfiemap_writer/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := VtsFiemapWriterTest
--include test/vts/tools/build/Android.host_config.mk
diff --git a/fs_mgr/libfiemap_writer/AndroidTest.xml b/fs_mgr/libfiemap_writer/AndroidTest.xml
deleted file mode 100644
index 08cff0e..0000000
--- a/fs_mgr/libfiemap_writer/AndroidTest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<configuration description="Config for VTS VtsFiemapWriterTest">
-    <option name="config-descriptor:metadata" key="plan" value="vts-kernel" />
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
-        <option name="abort-on-push-failure" value="false"/>
-        <option name="push-group" value="HostDrivenTest.push"/>
-    </target_preparer>
-    <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
-      <option name="test-module-name" value="VtsFiemapWriterTest"/>
-        <option name="binary-test-source" value="_32bit::DATA/nativetest/fiemap_writer_test/fiemap_writer_test" />
-        <option name="binary-test-source" value="_64bit::DATA/nativetest64/fiemap_writer_test/fiemap_writer_test" />
-        <option name="binary-test-type" value="gtest"/>
-        <option name="test-timeout" value="1m"/>
-    </test>
-</configuration>
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer.cpp b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
deleted file mode 100644
index 0a3ba6c..0000000
--- a/fs_mgr/libfiemap_writer/fiemap_writer.cpp
+++ /dev/null
@@ -1,745 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <libfiemap_writer/fiemap_writer.h>
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <linux/fs.h>
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/sysmacros.h>
-#include <sys/types.h>
-#include <sys/vfs.h>
-#include <unistd.h>
-
-#include <limits>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <libdm/dm.h>
-
-namespace android {
-namespace fiemap_writer {
-
-using namespace android::dm;
-
-// We are expecting no more than 512 extents in a fiemap of the file we create.
-// If we find more, then it is treated as error for now.
-static constexpr const uint32_t kMaxExtents = 512;
-
-// TODO: Fallback to using fibmap if FIEMAP_EXTENT_MERGED is set.
-static constexpr const uint32_t kUnsupportedExtentFlags =
-        FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_UNWRITTEN | FIEMAP_EXTENT_DELALLOC |
-        FIEMAP_EXTENT_NOT_ALIGNED | FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_DATA_TAIL |
-        FIEMAP_EXTENT_UNWRITTEN | FIEMAP_EXTENT_SHARED | FIEMAP_EXTENT_MERGED;
-
-// Large file support must be enabled.
-static_assert(sizeof(off_t) == sizeof(uint64_t));
-
-static inline void cleanup(const std::string& file_path, bool created) {
-    if (created) {
-        unlink(file_path.c_str());
-    }
-}
-
-static bool BlockDeviceToName(uint32_t major, uint32_t minor, std::string* bdev_name) {
-    // The symlinks in /sys/dev/block point to the block device node under /sys/device/..
-    // The directory name in the target corresponds to the name of the block device. We use
-    // that to extract the block device name.
-    // e.g for block device name 'ram0', there exists a symlink named '1:0' in /sys/dev/block as
-    // follows.
-    //    1:0 -> ../../devices/virtual/block/ram0
-    std::string sysfs_path = ::android::base::StringPrintf("/sys/dev/block/%u:%u", major, minor);
-    std::string sysfs_bdev;
-
-    if (!::android::base::Readlink(sysfs_path, &sysfs_bdev)) {
-        PLOG(ERROR) << "Failed to read link at: " << sysfs_path;
-        return false;
-    }
-
-    *bdev_name = ::android::base::Basename(sysfs_bdev);
-    // Paranoid sanity check to make sure we just didn't get the
-    // input in return as-is.
-    if (sysfs_bdev == *bdev_name) {
-        LOG(ERROR) << "Malformed symlink for block device: " << sysfs_bdev;
-        return false;
-    }
-
-    return true;
-}
-
-static bool ValidateDmTarget(const DeviceMapper::TargetInfo& target) {
-    const auto& entry = target.spec;
-    if (entry.sector_start != 0) {
-        LOG(INFO) << "Stopping at target with non-zero starting sector";
-        return false;
-    }
-
-    auto target_type = DeviceMapper::GetTargetType(entry);
-    if (target_type == "bow" || target_type == "default-key" || target_type == "crypt") {
-        return true;
-    }
-    if (target_type == "linear") {
-        auto pieces = android::base::Split(target.data, " ");
-        if (pieces[1] != "0") {
-            LOG(INFO) << "Stopping at complex linear target with non-zero starting sector: "
-                      << pieces[1];
-            return false;
-        }
-        return true;
-    }
-
-    LOG(INFO) << "Stopping at complex target type " << target_type;
-    return false;
-}
-
-static bool DeviceMapperStackPop(const std::string& bdev, std::string* bdev_raw) {
-    *bdev_raw = bdev;
-
-    if (!::android::base::StartsWith(bdev, "dm-")) {
-        // We are at the bottom of the device mapper stack.
-        return true;
-    }
-
-    // Get the device name.
-    auto dm_name_file = "/sys/block/" + bdev + "/dm/name";
-    std::string dm_name;
-    if (!android::base::ReadFileToString(dm_name_file, &dm_name)) {
-        PLOG(ERROR) << "Could not read file: " << dm_name_file;
-        return false;
-    }
-    dm_name = android::base::Trim(dm_name);
-
-    auto& dm = DeviceMapper::Instance();
-    std::vector<DeviceMapper::TargetInfo> table;
-    if (!dm.GetTableInfo(dm_name, &table)) {
-        LOG(ERROR) << "Could not read device-mapper table for " << dm_name << " at " << bdev;
-        return false;
-    }
-
-    // The purpose of libfiemap_writer is to provide an extent-based view into
-    // a file. This is difficult if devices are not layered in a 1:1 manner;
-    // we would have to translate and break up extents based on the actual
-    // block mapping. Since this is too complex, we simply stop processing
-    // the device-mapper stack if we encounter a complex case.
-    //
-    // It is up to the caller to decide whether stopping at a virtual block
-    // device is allowable. In most cases it is not, because we want either
-    // "userdata" or an external volume. It is useful for tests however.
-    // Callers can check by comparing the device number to that of userdata,
-    // or by checking whether is a device-mapper node.
-    if (table.size() > 1) {
-        LOG(INFO) << "Stopping at complex table for " << dm_name << " at " << bdev;
-        return true;
-    }
-    if (!ValidateDmTarget(table[0])) {
-        return true;
-    }
-
-    auto dm_leaf_dir = "/sys/block/" + bdev + "/slaves";
-    auto d = std::unique_ptr<DIR, decltype(&closedir)>(opendir(dm_leaf_dir.c_str()), closedir);
-    if (d == nullptr) {
-        PLOG(ERROR) << "Failed to open: " << dm_leaf_dir;
-        return false;
-    }
-
-    struct dirent* de;
-    uint32_t num_leaves = 0;
-    std::string bdev_next = "";
-    while ((de = readdir(d.get())) != nullptr) {
-        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
-            continue;
-        }
-
-        // We set the first name we find here
-        if (bdev_next.empty()) {
-            bdev_next = de->d_name;
-        }
-        num_leaves++;
-    }
-
-    // if we have more than one leaves, we return immediately. We can't continue to create the
-    // file since we don't know how to write it out using fiemap, so it will be readable via the
-    // underlying block devices later. The reader will also have to construct the same device mapper
-    // target in order read the file out.
-    if (num_leaves > 1) {
-        LOG(ERROR) << "Found " << num_leaves << " leaf block devices under device mapper device "
-                   << bdev;
-        return false;
-    }
-
-    // recursively call with the block device we found in order to pop the device mapper stack.
-    return DeviceMapperStackPop(bdev_next, bdev_raw);
-}
-
-bool FiemapWriter::GetBlockDeviceForFile(const std::string& file_path, std::string* bdev_path,
-                                         bool* uses_dm) {
-    struct stat sb;
-    if (stat(file_path.c_str(), &sb)) {
-        PLOG(ERROR) << "Failed to get stat for: " << file_path;
-        return false;
-    }
-
-    std::string bdev;
-    if (!BlockDeviceToName(major(sb.st_dev), minor(sb.st_dev), &bdev)) {
-        LOG(ERROR) << "Failed to get block device name for " << major(sb.st_dev) << ":"
-                   << minor(sb.st_dev);
-        return false;
-    }
-
-    std::string bdev_raw;
-    if (!DeviceMapperStackPop(bdev, &bdev_raw)) {
-        LOG(ERROR) << "Failed to get the bottom of the device mapper stack for device: " << bdev;
-        return false;
-    }
-
-    if (uses_dm) {
-        *uses_dm = (bdev_raw != bdev);
-    }
-
-    LOG(DEBUG) << "Popped device (" << bdev_raw << ") from device mapper stack starting with ("
-               << bdev << ")";
-
-    *bdev_path = ::android::base::StringPrintf("/dev/block/%s", bdev_raw.c_str());
-
-    // Make sure we are talking to a block device before calling it a success.
-    if (stat(bdev_path->c_str(), &sb)) {
-        PLOG(ERROR) << "Failed to get stat for block device: " << *bdev_path;
-        return false;
-    }
-
-    if ((sb.st_mode & S_IFMT) != S_IFBLK) {
-        PLOG(ERROR) << "File: " << *bdev_path << " is not a block device";
-        return false;
-    }
-
-    return true;
-}
-
-static bool GetBlockDeviceSize(int bdev_fd, const std::string& bdev_path, uint64_t* bdev_size) {
-    uint64_t size_in_bytes = 0;
-    if (ioctl(bdev_fd, BLKGETSIZE64, &size_in_bytes)) {
-        PLOG(ERROR) << "Failed to get total size for: " << bdev_path;
-        return false;
-    }
-
-    *bdev_size = size_in_bytes;
-
-    return true;
-}
-
-static uint64_t GetFileSize(const std::string& file_path) {
-    struct stat sb;
-    if (stat(file_path.c_str(), &sb)) {
-        PLOG(ERROR) << "Failed to get size for file: " << file_path;
-        return 0;
-    }
-
-    return sb.st_size;
-}
-
-static bool PerformFileChecks(const std::string& file_path, uint64_t file_size, uint64_t* blocksz,
-                              uint32_t* fs_type) {
-    struct statfs64 sfs;
-    if (statfs64(file_path.c_str(), &sfs)) {
-        PLOG(ERROR) << "Failed to read file system status at: " << file_path;
-        return false;
-    }
-
-    if (!sfs.f_bsize) {
-        LOG(ERROR) << "Unsupported block size: " << sfs.f_bsize;
-        return false;
-    }
-
-    // Check if the filesystem is of supported types.
-    // Only ext4, f2fs, and vfat are tested and supported.
-    switch (sfs.f_type) {
-        case EXT4_SUPER_MAGIC:
-        case F2FS_SUPER_MAGIC:
-        case MSDOS_SUPER_MAGIC:
-            break;
-        default:
-            LOG(ERROR) << "Unsupported file system type: 0x" << std::hex << sfs.f_type;
-            return false;
-    }
-
-    uint64_t available_bytes = sfs.f_bsize * sfs.f_bavail;
-    if (available_bytes <= file_size) {
-        LOG(ERROR) << "Not enough free space in file system to create file of size : " << file_size;
-        return false;
-    }
-
-    *blocksz = sfs.f_bsize;
-    *fs_type = sfs.f_type;
-    return true;
-}
-
-static bool FallocateFallback(int file_fd, uint64_t block_size, uint64_t file_size,
-                              const std::string& file_path,
-                              const std::function<bool(uint64_t, uint64_t)>& on_progress) {
-    // Even though this is much faster than writing zeroes, it is still slow
-    // enough that we need to fire the progress callback periodically. To
-    // easily achieve this, we seek in chunks. We use 1000 chunks since
-    // normally we only fire the callback on 1/1000th increments.
-    uint64_t bytes_per_chunk = std::max(file_size / 1000, block_size);
-
-    // Seek just to the end of each chunk and write a single byte, causing
-    // the filesystem to allocate blocks.
-    off_t cursor = 0;
-    off_t end = static_cast<off_t>(file_size);
-    while (cursor < end) {
-        cursor = std::min(static_cast<off_t>(cursor + bytes_per_chunk), end);
-        auto rv = TEMP_FAILURE_RETRY(lseek(file_fd, cursor - 1, SEEK_SET));
-        if (rv < 0) {
-            PLOG(ERROR) << "Failed to lseek " << file_path;
-            return false;
-        }
-        if (rv != cursor - 1) {
-            LOG(ERROR) << "Seek returned wrong offset " << rv << " for file " << file_path;
-            return false;
-        }
-        char buffer[] = {0};
-        if (!android::base::WriteFully(file_fd, buffer, 1)) {
-            PLOG(ERROR) << "Write failed: " << file_path;
-            return false;
-        }
-        if (on_progress && !on_progress(cursor, file_size)) {
-            return false;
-        }
-    }
-    return true;
-}
-
-static bool AllocateFile(int file_fd, const std::string& file_path, uint64_t blocksz,
-                         uint64_t file_size, unsigned int fs_type,
-                         std::function<bool(uint64_t, uint64_t)> on_progress) {
-    // Reserve space for the file on the file system and write it out to make sure the extents
-    // don't come back unwritten. Return from this function with the kernel file offset set to 0.
-    // If the filesystem is f2fs, then we also PIN the file on disk to make sure the blocks
-    // aren't moved around.
-    switch (fs_type) {
-        case EXT4_SUPER_MAGIC:
-        case F2FS_SUPER_MAGIC:
-            if (fallocate(file_fd, FALLOC_FL_ZERO_RANGE, 0, file_size)) {
-                PLOG(ERROR) << "Failed to allocate space for file: " << file_path
-                            << " size: " << file_size;
-                return false;
-            }
-            break;
-        case MSDOS_SUPER_MAGIC:
-            // fallocate() is not supported, and not needed, since VFAT does not support holes.
-            // Instead we can perform a much faster allocation.
-            return FallocateFallback(file_fd, blocksz, file_size, file_path, on_progress);
-        default:
-            LOG(ERROR) << "Missing fallocate() support for file system " << fs_type;
-            return false;
-    }
-
-    // write zeroes in 'blocksz' byte increments until we reach file_size to make sure the data
-    // blocks are actually written to by the file system and thus getting rid of the holes in the
-    // file.
-    auto buffer = std::unique_ptr<void, decltype(&free)>(calloc(1, blocksz), free);
-    if (buffer == nullptr) {
-        LOG(ERROR) << "failed to allocate memory for writing file";
-        return false;
-    }
-
-    off64_t offset = lseek64(file_fd, 0, SEEK_SET);
-    if (offset < 0) {
-        PLOG(ERROR) << "Failed to seek at the beginning of : " << file_path;
-        return false;
-    }
-
-    int permille = -1;
-    while (offset < file_size) {
-        if (!::android::base::WriteFully(file_fd, buffer.get(), blocksz)) {
-            PLOG(ERROR) << "Failed to write" << blocksz << " bytes at offset" << offset
-                        << " in file " << file_path;
-            return false;
-        }
-
-        offset += blocksz;
-
-        // Don't invoke the callback every iteration - wait until a significant
-        // chunk (here, 1/1000th) of the data has been processed.
-        int new_permille = (static_cast<uint64_t>(offset) * 1000) / file_size;
-        if (new_permille != permille && static_cast<uint64_t>(offset) != file_size) {
-            if (on_progress && !on_progress(offset, file_size)) {
-                return false;
-            }
-            permille = new_permille;
-        }
-    }
-
-    if (lseek64(file_fd, 0, SEEK_SET) < 0) {
-        PLOG(ERROR) << "Failed to reset offset at the beginning of : " << file_path;
-        return false;
-    }
-
-    // flush all writes here ..
-    if (fsync(file_fd)) {
-        PLOG(ERROR) << "Failed to synchronize written file:" << file_path;
-        return false;
-    }
-
-    // Send one last progress notification.
-    if (on_progress && !on_progress(file_size, file_size)) {
-        return false;
-    }
-    return true;
-}
-
-static bool PinFile(int file_fd, const std::string& file_path, uint32_t fs_type) {
-    if (fs_type != F2FS_SUPER_MAGIC) {
-        // No pinning necessary for ext4/msdos. The blocks, once allocated, are
-        // expected to be fixed.
-        return true;
-    }
-
-// F2FS-specific ioctl
-// It requires the below kernel commit merged in v4.16-rc1.
-//   1ad71a27124c ("f2fs: add an ioctl to disable GC for specific file")
-// In android-4.4,
-//   56ee1e817908 ("f2fs: updates on v4.16-rc1")
-// In android-4.9,
-//   2f17e34672a8 ("f2fs: updates on v4.16-rc1")
-// In android-4.14,
-//   ce767d9a55bc ("f2fs: updates on v4.16-rc1")
-#ifndef F2FS_IOC_SET_PIN_FILE
-#ifndef F2FS_IOCTL_MAGIC
-#define F2FS_IOCTL_MAGIC 0xf5
-#endif
-#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32)
-#endif
-
-    uint32_t pin_status = 1;
-    int error = ioctl(file_fd, F2FS_IOC_SET_PIN_FILE, &pin_status);
-    if (error < 0) {
-        if ((errno == ENOTTY) || (errno == ENOTSUP)) {
-            PLOG(ERROR) << "Failed to pin file, not supported by kernel: " << file_path;
-        } else {
-            PLOG(ERROR) << "Failed to pin file: " << file_path;
-        }
-        return false;
-    }
-
-    return true;
-}
-
-static bool IsFilePinned(int file_fd, const std::string& file_path, uint32_t fs_type) {
-    if (fs_type != F2FS_SUPER_MAGIC) {
-        // No pinning necessary for ext4 or vfat. The blocks, once allocated,
-        // are expected to be fixed.
-        return true;
-    }
-
-// F2FS-specific ioctl
-// It requires the below kernel commit merged in v4.16-rc1.
-//   1ad71a27124c ("f2fs: add an ioctl to disable GC for specific file")
-// In android-4.4,
-//   56ee1e817908 ("f2fs: updates on v4.16-rc1")
-// In android-4.9,
-//   2f17e34672a8 ("f2fs: updates on v4.16-rc1")
-// In android-4.14,
-//   ce767d9a55bc ("f2fs: updates on v4.16-rc1")
-#ifndef F2FS_IOC_GET_PIN_FILE
-#ifndef F2FS_IOCTL_MAGIC
-#define F2FS_IOCTL_MAGIC 0xf5
-#endif
-#define F2FS_IOC_GET_PIN_FILE _IOR(F2FS_IOCTL_MAGIC, 14, __u32)
-#endif
-
-    // f2fs: export FS_NOCOW_FL flag to user
-    uint32_t flags;
-    int error = ioctl(file_fd, FS_IOC_GETFLAGS, &flags);
-    if (error < 0) {
-        if ((errno == ENOTTY) || (errno == ENOTSUP)) {
-            PLOG(ERROR) << "Failed to get flags, not supported by kernel: " << file_path;
-        } else {
-            PLOG(ERROR) << "Failed to get flags: " << file_path;
-        }
-        return false;
-    }
-    if (!(flags & FS_NOCOW_FL)) {
-        LOG(ERROR) << "It is not pinned: " << file_path;
-        return false;
-    }
-
-    // F2FS_IOC_GET_PIN_FILE returns the number of blocks moved.
-    uint32_t moved_blocks_nr;
-    error = ioctl(file_fd, F2FS_IOC_GET_PIN_FILE, &moved_blocks_nr);
-    if (error < 0) {
-        if ((errno == ENOTTY) || (errno == ENOTSUP)) {
-            PLOG(ERROR) << "Failed to get file pin status, not supported by kernel: " << file_path;
-        } else {
-            PLOG(ERROR) << "Failed to get file pin status: " << file_path;
-        }
-        return false;
-    }
-
-    if (moved_blocks_nr) {
-        LOG(ERROR) << moved_blocks_nr << " blocks moved in file " << file_path;
-    }
-    return moved_blocks_nr == 0;
-}
-
-bool FiemapWriter::HasPinnedExtents(const std::string& file_path) {
-    android::base::unique_fd fd(open(file_path.c_str(), O_NOFOLLOW | O_CLOEXEC | O_RDONLY));
-    if (fd < 0) {
-        PLOG(ERROR) << "open: " << file_path;
-        return false;
-    }
-
-    struct statfs64 sfs;
-    if (fstatfs64(fd, &sfs)) {
-        PLOG(ERROR) << "fstatfs64: " << file_path;
-        return false;
-    }
-    return IsFilePinned(fd, file_path, sfs.f_type);
-}
-
-static bool ReadFiemap(int file_fd, const std::string& file_path,
-                       std::vector<struct fiemap_extent>* extents) {
-    uint64_t fiemap_size =
-            sizeof(struct fiemap_extent) + kMaxExtents * sizeof(struct fiemap_extent);
-    auto buffer = std::unique_ptr<void, decltype(&free)>(calloc(1, fiemap_size), free);
-    if (buffer == nullptr) {
-        LOG(ERROR) << "Failed to allocate memory for fiemap";
-        return false;
-    }
-
-    struct fiemap* fiemap = reinterpret_cast<struct fiemap*>(buffer.get());
-    fiemap->fm_start = 0;
-    fiemap->fm_length = UINT64_MAX;
-    // make sure file is synced to disk before we read the fiemap
-    fiemap->fm_flags = FIEMAP_FLAG_SYNC;
-    fiemap->fm_extent_count = kMaxExtents;
-
-    if (ioctl(file_fd, FS_IOC_FIEMAP, fiemap)) {
-        PLOG(ERROR) << "Failed to get FIEMAP from the kernel for file: " << file_path;
-        return false;
-    }
-
-    if (fiemap->fm_mapped_extents == 0) {
-        LOG(ERROR) << "File " << file_path << " has zero extents";
-        return false;
-    }
-
-    // Iterate through each extent read and make sure its valid before adding it to the vector
-    bool last_extent_seen = false;
-    struct fiemap_extent* extent = &fiemap->fm_extents[0];
-    for (uint32_t i = 0; i < fiemap->fm_mapped_extents; i++, extent++) {
-        // LogExtent(i + 1, *extent);
-        if (extent->fe_flags & kUnsupportedExtentFlags) {
-            LOG(ERROR) << "Extent " << i + 1 << " of file " << file_path
-                       << " has unsupported flags";
-            extents->clear();
-            return false;
-        }
-
-        if (extent->fe_flags & FIEMAP_EXTENT_LAST) {
-            last_extent_seen = true;
-            if (i != (fiemap->fm_mapped_extents - 1)) {
-                LOG(WARNING) << "Extents are being received out-of-order";
-            }
-        }
-        extents->emplace_back(std::move(*extent));
-    }
-
-    if (!last_extent_seen) {
-        // The file is possibly too fragmented.
-        if (fiemap->fm_mapped_extents == kMaxExtents) {
-            LOG(ERROR) << "File is too fragmented, needs more than " << kMaxExtents << " extents.";
-        }
-        extents->clear();
-    }
-
-    return last_extent_seen;
-}
-
-static bool ReadFibmap(int file_fd, const std::string& file_path,
-                       std::vector<struct fiemap_extent>* extents) {
-    struct stat s;
-    if (fstat(file_fd, &s)) {
-        PLOG(ERROR) << "Failed to stat " << file_path;
-        return false;
-    }
-
-    unsigned int blksize;
-    if (ioctl(file_fd, FIGETBSZ, &blksize) < 0) {
-        PLOG(ERROR) << "Failed to get FIGETBSZ for " << file_path;
-        return false;
-    }
-    if (!blksize) {
-        LOG(ERROR) << "Invalid filesystem block size: " << blksize;
-        return false;
-    }
-
-    uint64_t num_blocks = (s.st_size + blksize - 1) / blksize;
-    if (num_blocks > std::numeric_limits<uint32_t>::max()) {
-        LOG(ERROR) << "Too many blocks for FIBMAP (" << num_blocks << ")";
-        return false;
-    }
-
-    for (uint32_t last_block, block_number = 0; block_number < num_blocks; block_number++) {
-        uint32_t block = block_number;
-        if (ioctl(file_fd, FIBMAP, &block)) {
-            PLOG(ERROR) << "Failed to get FIBMAP for file " << file_path;
-            return false;
-        }
-        if (!block) {
-            LOG(ERROR) << "Logical block " << block_number << " is a hole, which is not supported";
-            return false;
-        }
-
-        if (!extents->empty() && block == last_block + 1) {
-            extents->back().fe_length += blksize;
-        } else {
-            extents->push_back(fiemap_extent{.fe_logical = block_number,
-                                             .fe_physical = static_cast<uint64_t>(block) * blksize,
-                                             .fe_length = static_cast<uint64_t>(blksize),
-                                             .fe_flags = 0});
-        }
-        last_block = block;
-    }
-    return true;
-}
-
-FiemapUniquePtr FiemapWriter::Open(const std::string& file_path, uint64_t file_size, bool create,
-                                   std::function<bool(uint64_t, uint64_t)> progress) {
-    // if 'create' is false, open an existing file and do not truncate.
-    int open_flags = O_RDWR | O_CLOEXEC;
-    if (create) {
-        if (access(file_path.c_str(), F_OK) == 0) {
-            LOG(WARNING) << "File " << file_path << " already exists, truncating";
-        }
-        open_flags |= O_CREAT | O_TRUNC;
-    }
-    ::android::base::unique_fd file_fd(
-            TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags, S_IRUSR | S_IWUSR)));
-    if (file_fd < 0) {
-        PLOG(ERROR) << "Failed to create file at: " << file_path;
-        return nullptr;
-    }
-
-    std::string abs_path;
-    if (!::android::base::Realpath(file_path, &abs_path)) {
-        PLOG(ERROR) << "Invalid file path: " << file_path;
-        cleanup(file_path, create);
-        return nullptr;
-    }
-
-    std::string bdev_path;
-    if (!GetBlockDeviceForFile(abs_path, &bdev_path)) {
-        LOG(ERROR) << "Failed to get block dev path for file: " << file_path;
-        cleanup(abs_path, create);
-        return nullptr;
-    }
-
-    ::android::base::unique_fd bdev_fd(
-            TEMP_FAILURE_RETRY(open(bdev_path.c_str(), O_RDONLY | O_CLOEXEC)));
-    if (bdev_fd < 0) {
-        PLOG(ERROR) << "Failed to open block device: " << bdev_path;
-        cleanup(file_path, create);
-        return nullptr;
-    }
-
-    uint64_t bdevsz;
-    if (!GetBlockDeviceSize(bdev_fd, bdev_path, &bdevsz)) {
-        LOG(ERROR) << "Failed to get block device size for : " << bdev_path;
-        cleanup(file_path, create);
-        return nullptr;
-    }
-
-    if (!create) {
-        file_size = GetFileSize(abs_path);
-        if (file_size == 0) {
-            LOG(ERROR) << "Invalid file size of zero bytes for file: " << abs_path;
-            return nullptr;
-        }
-    }
-
-    uint64_t blocksz;
-    uint32_t fs_type;
-    if (!PerformFileChecks(abs_path, file_size, &blocksz, &fs_type)) {
-        LOG(ERROR) << "Failed to validate file or file system for file:" << abs_path;
-        cleanup(abs_path, create);
-        return nullptr;
-    }
-
-    // Align up to the nearest block size.
-    if (file_size % blocksz) {
-        file_size += blocksz - (file_size % blocksz);
-    }
-
-    if (create) {
-        if (!AllocateFile(file_fd, abs_path, blocksz, file_size, fs_type, std::move(progress))) {
-            LOG(ERROR) << "Failed to allocate file: " << abs_path << " of size: " << file_size
-                       << " bytes";
-            cleanup(abs_path, create);
-            return nullptr;
-        }
-    }
-
-    // f2fs may move the file blocks around.
-    if (!PinFile(file_fd, abs_path, fs_type)) {
-        cleanup(abs_path, create);
-        LOG(ERROR) << "Failed to pin the file in storage";
-        return nullptr;
-    }
-
-    // now allocate the FiemapWriter and start setting it up
-    FiemapUniquePtr fmap(new FiemapWriter());
-    switch (fs_type) {
-        case EXT4_SUPER_MAGIC:
-        case F2FS_SUPER_MAGIC:
-            if (!ReadFiemap(file_fd, abs_path, &fmap->extents_)) {
-                LOG(ERROR) << "Failed to read fiemap of file: " << abs_path;
-                cleanup(abs_path, create);
-                return nullptr;
-            }
-            break;
-        case MSDOS_SUPER_MAGIC:
-            if (!ReadFibmap(file_fd, abs_path, &fmap->extents_)) {
-                LOG(ERROR) << "Failed to read fibmap of file: " << abs_path;
-                cleanup(abs_path, create);
-                return nullptr;
-            }
-            break;
-    }
-
-    fmap->file_path_ = abs_path;
-    fmap->bdev_path_ = bdev_path;
-    fmap->file_size_ = file_size;
-    fmap->bdev_size_ = bdevsz;
-    fmap->fs_type_ = fs_type;
-    fmap->block_size_ = blocksz;
-
-    LOG(VERBOSE) << "Successfully created FiemapWriter for file " << abs_path << " on block device "
-                 << bdev_path;
-    return fmap;
-}
-
-}  // namespace fiemap_writer
-}  // namespace android
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
deleted file mode 100644
index dda7dfd..0000000
--- a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/vfs.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <gtest/gtest.h>
-#include <libdm/loop_control.h>
-#include <libfiemap_writer/fiemap_writer.h>
-#include <libfiemap_writer/split_fiemap_writer.h>
-
-#include "utility.h"
-
-namespace android {
-namespace fiemap_writer {
-
-using namespace std;
-using namespace std::string_literals;
-using namespace android::fiemap_writer;
-using unique_fd = android::base::unique_fd;
-using LoopDevice = android::dm::LoopDevice;
-
-std::string gTestDir;
-uint64_t testfile_size = 536870912;  // default of 512MiB
-size_t gBlockSize = 0;
-
-class FiemapWriterTest : public ::testing::Test {
-  protected:
-    void SetUp() override {
-        const ::testing::TestInfo* tinfo = ::testing::UnitTest::GetInstance()->current_test_info();
-        testfile = gTestDir + "/"s + tinfo->name();
-    }
-
-    void TearDown() override { unlink(testfile.c_str()); }
-
-    // name of the file we use for testing
-    std::string testfile;
-};
-
-class SplitFiemapTest : public ::testing::Test {
-  protected:
-    void SetUp() override {
-        const ::testing::TestInfo* tinfo = ::testing::UnitTest::GetInstance()->current_test_info();
-        testfile = gTestDir + "/"s + tinfo->name();
-    }
-
-    void TearDown() override {
-        std::string message;
-        if (!SplitFiemap::RemoveSplitFiles(testfile, &message)) {
-            cerr << "Could not remove all split files: " << message;
-        }
-    }
-
-    // name of the file we use for testing
-    std::string testfile;
-};
-
-TEST_F(FiemapWriterTest, CreateImpossiblyLargeFile) {
-    // Try creating a file of size ~100TB but aligned to
-    // 512 byte to make sure block alignment tests don't
-    // fail.
-    FiemapUniquePtr fptr = FiemapWriter::Open(testfile, 1099511627997184);
-    EXPECT_EQ(fptr, nullptr);
-    EXPECT_EQ(access(testfile.c_str(), F_OK), -1);
-    EXPECT_EQ(errno, ENOENT);
-}
-
-TEST_F(FiemapWriterTest, CreateUnalignedFile) {
-    // Try creating a file of size 4097 bytes which is guaranteed
-    // to be unaligned to all known block sizes.
-    FiemapUniquePtr fptr = FiemapWriter::Open(testfile, gBlockSize + 1);
-    ASSERT_NE(fptr, nullptr);
-    ASSERT_EQ(fptr->size(), gBlockSize * 2);
-}
-
-TEST_F(FiemapWriterTest, CheckFilePath) {
-    FiemapUniquePtr fptr = FiemapWriter::Open(testfile, gBlockSize);
-    ASSERT_NE(fptr, nullptr);
-    EXPECT_EQ(fptr->size(), gBlockSize);
-    EXPECT_EQ(fptr->file_path(), testfile);
-    EXPECT_EQ(access(testfile.c_str(), F_OK), 0);
-}
-
-TEST_F(FiemapWriterTest, CheckFileSize) {
-    // Create a large-ish file and test that the expected size matches.
-    FiemapUniquePtr fptr = FiemapWriter::Open(testfile, 1024 * 1024 * 16);
-    ASSERT_NE(fptr, nullptr);
-
-    struct stat s;
-    ASSERT_EQ(stat(testfile.c_str(), &s), 0);
-    EXPECT_EQ(static_cast<uint64_t>(s.st_size), fptr->size());
-}
-
-TEST_F(FiemapWriterTest, CheckProgress) {
-    std::vector<uint64_t> expected;
-    size_t invocations = 0;
-    auto callback = [&](uint64_t done, uint64_t total) -> bool {
-        if (invocations >= expected.size()) {
-            return false;
-        }
-        EXPECT_EQ(done, expected[invocations]);
-        EXPECT_EQ(total, gBlockSize);
-        invocations++;
-        return true;
-    };
-
-    expected.push_back(gBlockSize);
-
-    auto ptr = FiemapWriter::Open(testfile, gBlockSize, true, std::move(callback));
-    EXPECT_NE(ptr, nullptr);
-    EXPECT_EQ(invocations, expected.size());
-}
-
-TEST_F(FiemapWriterTest, CheckPinning) {
-    auto ptr = FiemapWriter::Open(testfile, 4096);
-    ASSERT_NE(ptr, nullptr);
-    EXPECT_TRUE(FiemapWriter::HasPinnedExtents(testfile));
-}
-
-TEST_F(FiemapWriterTest, CheckBlockDevicePath) {
-    FiemapUniquePtr fptr = FiemapWriter::Open(testfile, gBlockSize);
-    EXPECT_EQ(fptr->size(), gBlockSize);
-    EXPECT_EQ(fptr->bdev_path().find("/dev/block/"), size_t(0));
-    EXPECT_EQ(fptr->bdev_path().find("/dev/block/dm-"), string::npos);
-}
-
-TEST_F(FiemapWriterTest, CheckFileCreated) {
-    FiemapUniquePtr fptr = FiemapWriter::Open(testfile, 32768);
-    ASSERT_NE(fptr, nullptr);
-    unique_fd fd(open(testfile.c_str(), O_RDONLY));
-    EXPECT_GT(fd, -1);
-}
-
-TEST_F(FiemapWriterTest, CheckFileSizeActual) {
-    FiemapUniquePtr fptr = FiemapWriter::Open(testfile, testfile_size);
-    ASSERT_NE(fptr, nullptr);
-
-    struct stat sb;
-    ASSERT_EQ(stat(testfile.c_str(), &sb), 0);
-    EXPECT_GE(sb.st_size, testfile_size);
-}
-
-TEST_F(FiemapWriterTest, CheckFileExtents) {
-    FiemapUniquePtr fptr = FiemapWriter::Open(testfile, testfile_size);
-    ASSERT_NE(fptr, nullptr);
-    EXPECT_GT(fptr->extents().size(), 0);
-}
-
-TEST_F(FiemapWriterTest, ExistingFile) {
-    // Create the file.
-    { ASSERT_NE(FiemapWriter::Open(testfile, gBlockSize), nullptr); }
-    // Test that we can still open it.
-    {
-        auto ptr = FiemapWriter::Open(testfile, 0, false);
-        ASSERT_NE(ptr, nullptr);
-        EXPECT_GT(ptr->extents().size(), 0);
-    }
-}
-
-TEST_F(FiemapWriterTest, FileDeletedOnError) {
-    auto callback = [](uint64_t, uint64_t) -> bool { return false; };
-    auto ptr = FiemapWriter::Open(testfile, gBlockSize, true, std::move(callback));
-    EXPECT_EQ(ptr, nullptr);
-    EXPECT_EQ(access(testfile.c_str(), F_OK), -1);
-    EXPECT_EQ(errno, ENOENT);
-}
-
-TEST_F(FiemapWriterTest, MaxBlockSize) {
-    ASSERT_GT(DetermineMaximumFileSize(testfile), 0);
-}
-
-TEST_F(FiemapWriterTest, FibmapBlockAddressing) {
-    FiemapUniquePtr fptr = FiemapWriter::Open(testfile, gBlockSize);
-    ASSERT_NE(fptr, nullptr);
-
-    switch (fptr->fs_type()) {
-        case F2FS_SUPER_MAGIC:
-        case EXT4_SUPER_MAGIC:
-            // Skip the test for FIEMAP supported filesystems. This is really
-            // because f2fs/ext4 have caches that seem to defeat reading back
-            // directly from the block device, and writing directly is too
-            // dangerous.
-            std::cout << "Skipping test, filesystem does not use FIBMAP\n";
-            return;
-    }
-
-    bool uses_dm;
-    std::string bdev_path;
-    ASSERT_TRUE(FiemapWriter::GetBlockDeviceForFile(testfile, &bdev_path, &uses_dm));
-
-    if (uses_dm) {
-        // We could use a device-mapper wrapper here to bypass encryption, but
-        // really this test is for FIBMAP correctness on VFAT (where encryption
-        // is never used), so we don't bother.
-        std::cout << "Skipping test, block device is metadata encrypted\n";
-        return;
-    }
-
-    std::string data(fptr->size(), '\0');
-    for (size_t i = 0; i < data.size(); i++) {
-        data[i] = 'A' + static_cast<char>(data.size() % 26);
-    }
-
-    {
-        unique_fd fd(open(testfile.c_str(), O_WRONLY | O_CLOEXEC));
-        ASSERT_GE(fd, 0);
-        ASSERT_TRUE(android::base::WriteFully(fd, data.data(), data.size()));
-        ASSERT_EQ(fsync(fd), 0);
-    }
-
-    ASSERT_FALSE(fptr->extents().empty());
-    const auto& first_extent = fptr->extents()[0];
-
-    unique_fd bdev(open(fptr->bdev_path().c_str(), O_RDONLY | O_CLOEXEC));
-    ASSERT_GE(bdev, 0);
-
-    off_t where = first_extent.fe_physical;
-    ASSERT_EQ(lseek(bdev, where, SEEK_SET), where);
-
-    // Note: this will fail on encrypted folders.
-    std::string actual(data.size(), '\0');
-    ASSERT_GE(first_extent.fe_length, data.size());
-    ASSERT_TRUE(android::base::ReadFully(bdev, actual.data(), actual.size()));
-    EXPECT_EQ(memcmp(actual.data(), data.data(), data.size()), 0);
-}
-
-TEST_F(SplitFiemapTest, Create) {
-    auto ptr = SplitFiemap::Create(testfile, 1024 * 768, 1024 * 32);
-    ASSERT_NE(ptr, nullptr);
-
-    auto extents = ptr->extents();
-
-    // Destroy the fiemap, closing file handles. This should not delete them.
-    ptr = nullptr;
-
-    std::vector<std::string> files;
-    ASSERT_TRUE(SplitFiemap::GetSplitFileList(testfile, &files));
-    for (const auto& path : files) {
-        EXPECT_EQ(access(path.c_str(), F_OK), 0);
-    }
-
-    ASSERT_GE(extents.size(), files.size());
-}
-
-TEST_F(SplitFiemapTest, Open) {
-    {
-        auto ptr = SplitFiemap::Create(testfile, 1024 * 768, 1024 * 32);
-        ASSERT_NE(ptr, nullptr);
-    }
-
-    auto ptr = SplitFiemap::Open(testfile);
-    ASSERT_NE(ptr, nullptr);
-
-    auto extents = ptr->extents();
-    ASSERT_GE(extents.size(), 24);
-}
-
-TEST_F(SplitFiemapTest, DeleteOnFail) {
-    auto ptr = SplitFiemap::Create(testfile, 1024 * 1024 * 100, 1);
-    ASSERT_EQ(ptr, nullptr);
-
-    std::string first_file = testfile + ".0001";
-    ASSERT_NE(access(first_file.c_str(), F_OK), 0);
-    ASSERT_EQ(errno, ENOENT);
-    ASSERT_NE(access(testfile.c_str(), F_OK), 0);
-    ASSERT_EQ(errno, ENOENT);
-}
-
-static string ReadSplitFiles(const std::string& base_path, size_t num_files) {
-    std::string result;
-    for (int i = 0; i < num_files; i++) {
-        std::string path = base_path + android::base::StringPrintf(".%04d", i);
-        std::string data;
-        if (!android::base::ReadFileToString(path, &data)) {
-            return {};
-        }
-        result += data;
-    }
-    return result;
-}
-
-TEST_F(SplitFiemapTest, WriteWholeFile) {
-    static constexpr size_t kChunkSize = 32768;
-    static constexpr size_t kSize = kChunkSize * 3;
-    auto ptr = SplitFiemap::Create(testfile, kSize, kChunkSize);
-    ASSERT_NE(ptr, nullptr);
-
-    auto buffer = std::make_unique<int[]>(kSize / sizeof(int));
-    for (size_t i = 0; i < kSize / sizeof(int); i++) {
-        buffer[i] = i;
-    }
-    ASSERT_TRUE(ptr->Write(buffer.get(), kSize));
-
-    std::string expected(reinterpret_cast<char*>(buffer.get()), kSize);
-    auto actual = ReadSplitFiles(testfile, 3);
-    ASSERT_EQ(expected.size(), actual.size());
-    EXPECT_EQ(memcmp(expected.data(), actual.data(), actual.size()), 0);
-}
-
-TEST_F(SplitFiemapTest, WriteFileInChunks1) {
-    static constexpr size_t kChunkSize = 32768;
-    static constexpr size_t kSize = kChunkSize * 3;
-    auto ptr = SplitFiemap::Create(testfile, kSize, kChunkSize);
-    ASSERT_NE(ptr, nullptr);
-
-    auto buffer = std::make_unique<int[]>(kSize / sizeof(int));
-    for (size_t i = 0; i < kSize / sizeof(int); i++) {
-        buffer[i] = i;
-    }
-
-    // Write in chunks of 1000 (so some writes straddle the boundary of two
-    // files).
-    size_t bytes_written = 0;
-    while (bytes_written < kSize) {
-        size_t to_write = std::min(kSize - bytes_written, (size_t)1000);
-        char* data = reinterpret_cast<char*>(buffer.get()) + bytes_written;
-        ASSERT_TRUE(ptr->Write(data, to_write));
-        bytes_written += to_write;
-    }
-
-    std::string expected(reinterpret_cast<char*>(buffer.get()), kSize);
-    auto actual = ReadSplitFiles(testfile, 3);
-    ASSERT_EQ(expected.size(), actual.size());
-    EXPECT_EQ(memcmp(expected.data(), actual.data(), actual.size()), 0);
-}
-
-TEST_F(SplitFiemapTest, WriteFileInChunks2) {
-    static constexpr size_t kChunkSize = 32768;
-    static constexpr size_t kSize = kChunkSize * 3;
-    auto ptr = SplitFiemap::Create(testfile, kSize, kChunkSize);
-    ASSERT_NE(ptr, nullptr);
-
-    auto buffer = std::make_unique<int[]>(kSize / sizeof(int));
-    for (size_t i = 0; i < kSize / sizeof(int); i++) {
-        buffer[i] = i;
-    }
-
-    // Write in chunks of 32KiB so every write is exactly at the end of the
-    // current file.
-    size_t bytes_written = 0;
-    while (bytes_written < kSize) {
-        size_t to_write = std::min(kSize - bytes_written, kChunkSize);
-        char* data = reinterpret_cast<char*>(buffer.get()) + bytes_written;
-        ASSERT_TRUE(ptr->Write(data, to_write));
-        bytes_written += to_write;
-    }
-
-    std::string expected(reinterpret_cast<char*>(buffer.get()), kSize);
-    auto actual = ReadSplitFiles(testfile, 3);
-    ASSERT_EQ(expected.size(), actual.size());
-    EXPECT_EQ(memcmp(expected.data(), actual.data(), actual.size()), 0);
-}
-
-TEST_F(SplitFiemapTest, WritePastEnd) {
-    static constexpr size_t kChunkSize = 32768;
-    static constexpr size_t kSize = kChunkSize * 3;
-    auto ptr = SplitFiemap::Create(testfile, kSize, kChunkSize);
-    ASSERT_NE(ptr, nullptr);
-
-    auto buffer = std::make_unique<int[]>(kSize / sizeof(int));
-    for (size_t i = 0; i < kSize / sizeof(int); i++) {
-        buffer[i] = i;
-    }
-    ASSERT_TRUE(ptr->Write(buffer.get(), kSize));
-    ASSERT_FALSE(ptr->Write(buffer.get(), kSize));
-}
-
-class VerifyBlockWritesExt4 : public ::testing::Test {
-    // 2GB Filesystem and 4k block size by default
-    static constexpr uint64_t block_size = 4096;
-    static constexpr uint64_t fs_size = 2147483648;
-
-  protected:
-    void SetUp() override {
-        fs_path = std::string(getenv("TMPDIR")) + "/ext4_2G.img";
-        uint64_t count = fs_size / block_size;
-        std::string dd_cmd =
-                ::android::base::StringPrintf("/system/bin/dd if=/dev/zero of=%s bs=%" PRIu64
-                                              " count=%" PRIu64 " > /dev/null 2>&1",
-                                              fs_path.c_str(), block_size, count);
-        std::string mkfs_cmd =
-                ::android::base::StringPrintf("/system/bin/mkfs.ext4 -q %s", fs_path.c_str());
-        // create mount point
-        mntpoint = std::string(getenv("TMPDIR")) + "/fiemap_mnt";
-        ASSERT_EQ(mkdir(mntpoint.c_str(), S_IRWXU), 0);
-        // create file for the file system
-        int ret = system(dd_cmd.c_str());
-        ASSERT_EQ(ret, 0);
-        // Get and attach a loop device to the filesystem we created
-        LoopDevice loop_dev(fs_path);
-        ASSERT_TRUE(loop_dev.valid());
-        // create file system
-        ret = system(mkfs_cmd.c_str());
-        ASSERT_EQ(ret, 0);
-
-        // mount the file system
-        ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint.c_str(), "ext4", 0, nullptr), 0);
-    }
-
-    void TearDown() override {
-        umount(mntpoint.c_str());
-        rmdir(mntpoint.c_str());
-        unlink(fs_path.c_str());
-    }
-
-    std::string mntpoint;
-    std::string fs_path;
-};
-
-class VerifyBlockWritesF2fs : public ::testing::Test {
-    // 2GB Filesystem and 4k block size by default
-    static constexpr uint64_t block_size = 4096;
-    static constexpr uint64_t fs_size = 2147483648;
-
-  protected:
-    void SetUp() override {
-        fs_path = std::string(getenv("TMPDIR")) + "/f2fs_2G.img";
-        uint64_t count = fs_size / block_size;
-        std::string dd_cmd =
-                ::android::base::StringPrintf("/system/bin/dd if=/dev/zero of=%s bs=%" PRIu64
-                                              " count=%" PRIu64 " > /dev/null 2>&1",
-                                              fs_path.c_str(), block_size, count);
-        std::string mkfs_cmd =
-                ::android::base::StringPrintf("/system/bin/make_f2fs -q %s", fs_path.c_str());
-        // create mount point
-        mntpoint = std::string(getenv("TMPDIR")) + "/fiemap_mnt";
-        ASSERT_EQ(mkdir(mntpoint.c_str(), S_IRWXU), 0);
-        // create file for the file system
-        int ret = system(dd_cmd.c_str());
-        ASSERT_EQ(ret, 0);
-        // Get and attach a loop device to the filesystem we created
-        LoopDevice loop_dev(fs_path);
-        ASSERT_TRUE(loop_dev.valid());
-        // create file system
-        ret = system(mkfs_cmd.c_str());
-        ASSERT_EQ(ret, 0);
-
-        // mount the file system
-        ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint.c_str(), "f2fs", 0, nullptr), 0);
-    }
-
-    void TearDown() override {
-        umount(mntpoint.c_str());
-        rmdir(mntpoint.c_str());
-        unlink(fs_path.c_str());
-    }
-
-    std::string mntpoint;
-    std::string fs_path;
-};
-
-bool DetermineBlockSize() {
-    struct statfs s;
-    if (statfs(gTestDir.c_str(), &s)) {
-        std::cerr << "Could not call statfs: " << strerror(errno) << "\n";
-        return false;
-    }
-    if (!s.f_bsize) {
-        std::cerr << "Invalid block size: " << s.f_bsize << "\n";
-        return false;
-    }
-
-    gBlockSize = s.f_bsize;
-    return true;
-}
-
-}  // namespace fiemap_writer
-}  // namespace android
-
-using namespace android::fiemap_writer;
-
-int main(int argc, char** argv) {
-    ::testing::InitGoogleTest(&argc, argv);
-    if (argc > 1 && argv[1] == "-h"s) {
-        cerr << "Usage: [test_dir] [file_size]\n";
-        cerr << "\n";
-        cerr << "Note: test_dir must be a writable, unencrypted directory.\n";
-        exit(EXIT_FAILURE);
-    }
-    ::android::base::InitLogging(argv, ::android::base::StderrLogger);
-
-    std::string root_dir = "/data/local/unencrypted";
-    if (access(root_dir.c_str(), F_OK)) {
-        root_dir = "/data";
-    }
-
-    std::string tempdir = root_dir + "/XXXXXX"s;
-    if (!mkdtemp(tempdir.data())) {
-        cerr << "unable to create tempdir on " << root_dir << "\n";
-        exit(EXIT_FAILURE);
-    }
-    if (!android::base::Realpath(tempdir, &gTestDir)) {
-        cerr << "unable to find realpath for " << tempdir;
-        exit(EXIT_FAILURE);
-    }
-
-    if (argc > 2) {
-        testfile_size = strtoull(argv[2], NULL, 0);
-        if (testfile_size == ULLONG_MAX) {
-            testfile_size = 512 * 1024 * 1024;
-        }
-    }
-
-    if (!DetermineBlockSize()) {
-        exit(EXIT_FAILURE);
-    }
-
-    auto result = RUN_ALL_TESTS();
-
-    std::string cmd = "rm -rf " + gTestDir;
-    system(cmd.c_str());
-
-    return result;
-}
diff --git a/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h b/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
deleted file mode 100644
index ee79262..0000000
--- a/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <linux/fiemap.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <functional>
-#include <string>
-#include <vector>
-
-#include <android-base/unique_fd.h>
-
-namespace android {
-namespace fiemap_writer {
-
-class FiemapWriter;
-using FiemapUniquePtr = std::unique_ptr<FiemapWriter>;
-
-class FiemapWriter final {
-  public:
-    // Factory method for FiemapWriter.
-    // The method returns FiemapUniquePtr that contains all the data necessary to be able to write
-    // to the given file directly using raw block i/o. The optional progress callback will be
-    // invoked, if create is true, while the file is being initialized. It receives the bytes
-    // written and the number of total bytes. If the callback returns false, the operation will
-    // fail.
-    //
-    // Note: when create is true, the file size will be aligned up to the nearest file system
-    // block.
-    static FiemapUniquePtr Open(const std::string& file_path, uint64_t file_size,
-                                bool create = true,
-                                std::function<bool(uint64_t, uint64_t)> progress = {});
-
-    // Check that a file still has the same extents since it was last opened with FiemapWriter,
-    // assuming the file was not resized outside of FiemapWriter. Returns false either on error
-    // or if the file was not pinned.
-    //
-    // This will always return true on Ext4. On F2FS, it will return true if either of the
-    // following cases are true:
-    //   - The file was never pinned.
-    //   - The file is pinned and has not been moved by the GC.
-    // Thus, this method should only be called for pinned files (such as those returned by
-    // FiemapWriter::Open).
-    static bool HasPinnedExtents(const std::string& file_path);
-
-    // Returns the underlying block device of a file. This will look past device-mapper layers
-    // as long as each layer would not change block mappings (i.e., dm-crypt, dm-bow, and dm-
-    // default-key tables are okay; dm-linear is not). If a mapping such as dm-linear is found,
-    // it will be returned in place of any physical block device.
-    //
-    // It is the caller's responsibility to check whether the returned block device is acceptable.
-    // Gsid, for example, will only accept /dev/block/by-name/userdata as the bottom device.
-    // Callers can check the device name (dm- or loop prefix), inspect sysfs, or compare the major
-    // number against a boot device.
-    //
-    // If device-mapper nodes were encountered, then |uses_dm| will be set to true.
-    static bool GetBlockDeviceForFile(const std::string& file_path, std::string* bdev_path,
-                                      bool* uses_dm = nullptr);
-
-    ~FiemapWriter() = default;
-
-    const std::string& file_path() const { return file_path_; };
-    uint64_t size() const { return file_size_; };
-    const std::string& bdev_path() const { return bdev_path_; };
-    uint64_t block_size() const { return block_size_; };
-    const std::vector<struct fiemap_extent>& extents() { return extents_; };
-    uint32_t fs_type() const { return fs_type_; }
-
-    // Non-copyable & Non-movable
-    FiemapWriter(const FiemapWriter&) = delete;
-    FiemapWriter& operator=(const FiemapWriter&) = delete;
-    FiemapWriter& operator=(FiemapWriter&&) = delete;
-    FiemapWriter(FiemapWriter&&) = delete;
-
-  private:
-    // Name of the file managed by this class.
-    std::string file_path_;
-    // Block device on which we have created the file.
-    std::string bdev_path_;
-
-    // Size in bytes of the file this class is writing
-    uint64_t file_size_;
-
-    // total size in bytes of the block device
-    uint64_t bdev_size_;
-
-    // Filesystem type where the file is being created.
-    // See: <uapi/linux/magic.h> for filesystem magic numbers
-    uint32_t fs_type_;
-
-    // block size as reported by the kernel of the underlying block device;
-    uint64_t block_size_;
-
-    // This file's fiemap
-    std::vector<struct fiemap_extent> extents_;
-
-    FiemapWriter() = default;
-};
-
-}  // namespace fiemap_writer
-}  // namespace android
diff --git a/fs_mgr/libfiemap_writer/include/libfiemap_writer/split_fiemap_writer.h b/fs_mgr/libfiemap_writer/include/libfiemap_writer/split_fiemap_writer.h
deleted file mode 100644
index 7b977e1..0000000
--- a/fs_mgr/libfiemap_writer/include/libfiemap_writer/split_fiemap_writer.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <stdint.h>
-
-#include <functional>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <android-base/unique_fd.h>
-
-#include "fiemap_writer.h"
-
-namespace android {
-namespace fiemap_writer {
-
-// Wrapper around FiemapWriter that is able to split images across files if
-// necessary.
-class SplitFiemap final {
-  public:
-    using ProgressCallback = std::function<bool(uint64_t, uint64_t)>;
-
-    // Create a new split fiemap file. If |max_piece_size| is 0, the number of
-    // pieces will be determined automatically by detecting the filesystem.
-    // Otherwise, the file will be split evenly (with the remainder in the
-    // final file).
-    static std::unique_ptr<SplitFiemap> Create(const std::string& file_path, uint64_t file_size,
-                                               uint64_t max_piece_size,
-                                               ProgressCallback progress = {});
-
-    // Open an existing split fiemap file.
-    static std::unique_ptr<SplitFiemap> Open(const std::string& file_path);
-
-    ~SplitFiemap();
-
-    // Return a list of all files created for a split file.
-    static bool GetSplitFileList(const std::string& file_path, std::vector<std::string>* list);
-
-    // Destroy all components of a split file. If the root file does not exist,
-    // this returns true and does not report an error.
-    static bool RemoveSplitFiles(const std::string& file_path, std::string* message = nullptr);
-
-    // Return whether all components of a split file still have pinned extents.
-    bool HasPinnedExtents() const;
-
-    // Helper method for writing data that spans files. Note there is no seek
-    // method (yet); this starts at 0 and increments the position by |bytes|.
-    bool Write(const void* data, uint64_t bytes);
-
-    // Flush all writes to all split files.
-    bool Flush();
-
-    const std::vector<struct fiemap_extent>& extents();
-    uint32_t block_size() const;
-    uint64_t size() const { return total_size_; }
-    const std::string& bdev_path() const;
-
-    // Non-copyable & Non-movable
-    SplitFiemap(const SplitFiemap&) = delete;
-    SplitFiemap& operator=(const SplitFiemap&) = delete;
-    SplitFiemap& operator=(SplitFiemap&&) = delete;
-    SplitFiemap(SplitFiemap&&) = delete;
-
-  private:
-    SplitFiemap() = default;
-    void AddFile(FiemapUniquePtr&& file);
-
-    bool creating_ = false;
-    std::string list_file_;
-    std::vector<FiemapUniquePtr> files_;
-    std::vector<struct fiemap_extent> extents_;
-    uint64_t total_size_ = 0;
-
-    // Most recently open file and position for Write().
-    size_t cursor_index_ = 0;
-    uint64_t cursor_file_pos_ = 0;
-    android::base::unique_fd cursor_fd_;
-};
-
-}  // namespace fiemap_writer
-}  // namespace android
diff --git a/fs_mgr/libfiemap_writer/split_fiemap_writer.cpp b/fs_mgr/libfiemap_writer/split_fiemap_writer.cpp
deleted file mode 100644
index a0ccc10..0000000
--- a/fs_mgr/libfiemap_writer/split_fiemap_writer.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * 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 <libfiemap_writer/split_fiemap_writer.h>
-
-#include <fcntl.h>
-#include <stdint.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-
-#include "utility.h"
-
-namespace android {
-namespace fiemap_writer {
-
-using android::base::unique_fd;
-
-// We use a four-digit suffix at the end of filenames.
-static const size_t kMaxFilePieces = 500;
-
-std::unique_ptr<SplitFiemap> SplitFiemap::Create(const std::string& file_path, uint64_t file_size,
-                                                 uint64_t max_piece_size,
-                                                 ProgressCallback progress) {
-    if (!file_size) {
-        LOG(ERROR) << "Cannot create a fiemap for a 0-length file: " << file_path;
-        return nullptr;
-    }
-
-    if (!max_piece_size) {
-        max_piece_size = DetermineMaximumFileSize(file_path);
-        if (!max_piece_size) {
-            LOG(ERROR) << "Could not determine maximum file size for " << file_path;
-            return nullptr;
-        }
-    }
-
-    // Call |progress| only when the total percentage would significantly change.
-    int permille = -1;
-    uint64_t total_bytes_written = 0;
-    auto on_progress = [&](uint64_t written, uint64_t) -> bool {
-        uint64_t actual_written = total_bytes_written + written;
-        int new_permille = (actual_written * 1000) / file_size;
-        if (new_permille != permille && actual_written < file_size) {
-            if (progress && !progress(actual_written, file_size)) {
-                return false;
-            }
-            permille = new_permille;
-        }
-        return true;
-    };
-
-    std::unique_ptr<SplitFiemap> out(new SplitFiemap());
-    out->creating_ = true;
-    out->list_file_ = file_path;
-
-    // Create the split files.
-    uint64_t remaining_bytes = file_size;
-    while (remaining_bytes) {
-        if (out->files_.size() >= kMaxFilePieces) {
-            LOG(ERROR) << "Requested size " << file_size << " created too many split files";
-            return nullptr;
-        }
-        std::string chunk_path =
-                android::base::StringPrintf("%s.%04d", file_path.c_str(), (int)out->files_.size());
-        uint64_t chunk_size = std::min(max_piece_size, remaining_bytes);
-        auto writer = FiemapWriter::Open(chunk_path, chunk_size, true, on_progress);
-        if (!writer) {
-            return nullptr;
-        }
-
-        // To make sure the alignment doesn't create too much inconsistency, we
-        // account the *actual* size, not the requested size.
-        total_bytes_written += writer->size();
-        remaining_bytes -= writer->size();
-
-        out->AddFile(std::move(writer));
-    }
-
-    // Create the split file list.
-    unique_fd fd(open(out->list_file_.c_str(), O_CREAT | O_WRONLY | O_CLOEXEC, 0660));
-    if (fd < 0) {
-        PLOG(ERROR) << "Failed to open " << file_path;
-        return nullptr;
-    }
-
-    for (const auto& writer : out->files_) {
-        std::string line = android::base::Basename(writer->file_path()) + "\n";
-        if (!android::base::WriteFully(fd, line.data(), line.size())) {
-            PLOG(ERROR) << "Write failed " << file_path;
-            return nullptr;
-        }
-    }
-
-    // Unset this bit, so we don't unlink on destruction.
-    out->creating_ = false;
-    return out;
-}
-
-std::unique_ptr<SplitFiemap> SplitFiemap::Open(const std::string& file_path) {
-    std::vector<std::string> files;
-    if (!GetSplitFileList(file_path, &files)) {
-        return nullptr;
-    }
-
-    std::unique_ptr<SplitFiemap> out(new SplitFiemap());
-    out->list_file_ = file_path;
-
-    for (const auto& file : files) {
-        auto writer = FiemapWriter::Open(file, 0, false);
-        if (!writer) {
-            // Error was logged in Open().
-            return nullptr;
-        }
-        out->AddFile(std::move(writer));
-    }
-    return out;
-}
-
-bool SplitFiemap::GetSplitFileList(const std::string& file_path, std::vector<std::string>* list) {
-    // This is not the most efficient thing, but it is simple and recovering
-    // the fiemap/fibmap is much more expensive.
-    std::string contents;
-    if (!android::base::ReadFileToString(file_path, &contents, true)) {
-        PLOG(ERROR) << "Error reading file: " << file_path;
-        return false;
-    }
-
-    std::vector<std::string> names = android::base::Split(contents, "\n");
-    std::string dir = android::base::Dirname(file_path);
-    for (const auto& name : names) {
-        if (!name.empty()) {
-            list->emplace_back(dir + "/" + name);
-        }
-    }
-    return true;
-}
-
-bool SplitFiemap::RemoveSplitFiles(const std::string& file_path, std::string* message) {
-    // Early exit if this does not exist, and do not report an error.
-    if (access(file_path.c_str(), F_OK) && errno == ENOENT) {
-        return true;
-    }
-
-    bool ok = true;
-    std::vector<std::string> files;
-    if (GetSplitFileList(file_path, &files)) {
-        for (const auto& file : files) {
-            ok &= android::base::RemoveFileIfExists(file, message);
-        }
-    }
-    ok &= android::base::RemoveFileIfExists(file_path, message);
-    return ok;
-}
-
-bool SplitFiemap::HasPinnedExtents() const {
-    for (const auto& file : files_) {
-        if (!FiemapWriter::HasPinnedExtents(file->file_path())) {
-            return false;
-        }
-    }
-    return true;
-}
-
-const std::vector<struct fiemap_extent>& SplitFiemap::extents() {
-    if (extents_.empty()) {
-        for (const auto& file : files_) {
-            const auto& extents = file->extents();
-            extents_.insert(extents_.end(), extents.begin(), extents.end());
-        }
-    }
-    return extents_;
-}
-
-bool SplitFiemap::Write(const void* data, uint64_t bytes) {
-    // Open the current file.
-    FiemapWriter* file = files_[cursor_index_].get();
-
-    const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(data);
-    uint64_t bytes_remaining = bytes;
-    while (bytes_remaining) {
-        // How many bytes can we write into the current file?
-        uint64_t file_bytes_left = file->size() - cursor_file_pos_;
-        if (!file_bytes_left) {
-            if (cursor_index_ == files_.size() - 1) {
-                LOG(ERROR) << "write past end of file requested";
-                return false;
-            }
-
-            // No space left in the current file, but we have more files to
-            // use, so prep the next one.
-            cursor_fd_ = {};
-            cursor_file_pos_ = 0;
-            file = files_[++cursor_index_].get();
-            file_bytes_left = file->size();
-        }
-
-        // Open the current file if it's not open.
-        if (cursor_fd_ < 0) {
-            cursor_fd_.reset(open(file->file_path().c_str(), O_CLOEXEC | O_WRONLY));
-            if (cursor_fd_ < 0) {
-                PLOG(ERROR) << "open failed: " << file->file_path();
-                return false;
-            }
-            CHECK(cursor_file_pos_ == 0);
-        }
-
-        if (!FiemapWriter::HasPinnedExtents(file->file_path())) {
-            LOG(ERROR) << "file is no longer pinned: " << file->file_path();
-            return false;
-        }
-
-        uint64_t bytes_to_write = std::min(file_bytes_left, bytes_remaining);
-        if (!android::base::WriteFully(cursor_fd_, data_ptr, bytes_to_write)) {
-            PLOG(ERROR) << "write failed: " << file->file_path();
-            return false;
-        }
-        data_ptr += bytes_to_write;
-        bytes_remaining -= bytes_to_write;
-        cursor_file_pos_ += bytes_to_write;
-    }
-
-    // If we've reached the end of the current file, close it for sanity.
-    if (cursor_file_pos_ == file->size()) {
-        cursor_fd_ = {};
-    }
-    return true;
-}
-
-bool SplitFiemap::Flush() {
-    for (const auto& file : files_) {
-        unique_fd fd(open(file->file_path().c_str(), O_RDONLY | O_CLOEXEC));
-        if (fd < 0) {
-            PLOG(ERROR) << "open failed: " << file->file_path();
-            return false;
-        }
-        if (fsync(fd)) {
-            PLOG(ERROR) << "fsync failed: " << file->file_path();
-            return false;
-        }
-    }
-    return true;
-}
-
-SplitFiemap::~SplitFiemap() {
-    if (!creating_) {
-        return;
-    }
-
-    // We failed to finish creating, so unlink everything.
-    unlink(list_file_.c_str());
-    for (auto&& file : files_) {
-        std::string path = file->file_path();
-        file = nullptr;
-
-        unlink(path.c_str());
-    }
-}
-
-void SplitFiemap::AddFile(FiemapUniquePtr&& file) {
-    total_size_ += file->size();
-    files_.emplace_back(std::move(file));
-}
-
-uint32_t SplitFiemap::block_size() const {
-    return files_[0]->block_size();
-}
-
-const std::string& SplitFiemap::bdev_path() const {
-    return files_[0]->bdev_path();
-}
-
-}  // namespace fiemap_writer
-}  // namespace android
diff --git a/fs_mgr/libfiemap_writer/testdata/file_32k b/fs_mgr/libfiemap_writer/testdata/file_32k
deleted file mode 100644
index 12f3be4..0000000
--- a/fs_mgr/libfiemap_writer/testdata/file_32k
+++ /dev/null
Binary files differ
diff --git a/fs_mgr/libfiemap_writer/testdata/file_4k b/fs_mgr/libfiemap_writer/testdata/file_4k
deleted file mode 100644
index 08e7df1..0000000
--- a/fs_mgr/libfiemap_writer/testdata/file_4k
+++ /dev/null
Binary files differ
diff --git a/fs_mgr/libfiemap_writer/testdata/unaligned_file b/fs_mgr/libfiemap_writer/testdata/unaligned_file
deleted file mode 100644
index c107c26..0000000
--- a/fs_mgr/libfiemap_writer/testdata/unaligned_file
+++ /dev/null
Binary files differ
diff --git a/fs_mgr/libfiemap_writer/utility.cpp b/fs_mgr/libfiemap_writer/utility.cpp
deleted file mode 100644
index 192ec16..0000000
--- a/fs_mgr/libfiemap_writer/utility.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "utility.h"
-
-#include <stdint.h>
-#include <sys/vfs.h>
-#include <unistd.h>
-
-#include <android-base/logging.h>
-#include <libfiemap_writer/fiemap_writer.h>
-
-namespace android {
-namespace fiemap_writer {
-
-uint64_t DetermineMaximumFileSize(const std::string& file_path) {
-    // Create the smallest file possible (one block).
-    auto writer = FiemapWriter::Open(file_path, 1);
-    if (!writer) {
-        return 0;
-    }
-
-    uint64_t result = 0;
-    switch (writer->fs_type()) {
-        case EXT4_SUPER_MAGIC:
-            // The minimum is 16GiB, so just report that. If we wanted we could parse the
-            // superblock and figure out if 64-bit support is enabled.
-            result = 17179869184ULL;
-            break;
-        case F2FS_SUPER_MAGIC:
-            // Formula is from https://www.kernel.org/doc/Documentation/filesystems/f2fs.txt
-            // 4KB * (923 + 2 * 1018 + 2 * 1018 * 1018 + 1018 * 1018 * 1018) := 3.94TB.
-            result = 4329690886144ULL;
-            break;
-        case MSDOS_SUPER_MAGIC:
-            // 4GB-1, which we want aligned to the block size.
-            result = 4294967295;
-            result -= (result % writer->block_size());
-            break;
-        default:
-            LOG(ERROR) << "Unknown file system type: " << writer->fs_type();
-            break;
-    }
-
-    // Close and delete the temporary file.
-    writer = nullptr;
-    unlink(file_path.c_str());
-
-    return result;
-}
-
-}  // namespace fiemap_writer
-}  // namespace android
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/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
new file mode 100644
index 0000000..3a08049
--- /dev/null
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library {
+    name: "libsnapshot",
+    recovery_available: true,
+    defaults: ["fs_mgr_defaults"],
+    cppflags: [
+        "-D_FILE_OFFSET_BITS=64",
+    ],
+    srcs: [
+        "snapshot.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+    static_libs: [
+        "libdm",
+        "libext2_uuid",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/fs_mgr/libsnapshot/OWNERS b/fs_mgr/libsnapshot/OWNERS
new file mode 100644
index 0000000..0cfa7e4
--- /dev/null
+++ b/fs_mgr/libsnapshot/OWNERS
@@ -0,0 +1,2 @@
+dvander@google.com
+elsk@google.com
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
new file mode 100644
index 0000000..5cfd7fa
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -0,0 +1,88 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <stdint.h>
+
+#include <chrono>
+#include <memory>
+#include <string>
+
+namespace android {
+namespace snapshot {
+
+enum class UpdateStatus {
+    // No update or merge is in progress.
+    None,
+
+    // An update is pending, but has not been successfully booted yet.
+    Unverified,
+
+    // The kernel is merging in the background.
+    Merging,
+
+    // Merging is complete, and needs to be acknowledged.
+    MergeCompleted
+};
+
+class SnapshotManager final {
+  public:
+    // Return a new SnapshotManager instance, or null on error.
+    static std::unique_ptr<SnapshotManager> New();
+
+    // Create a new snapshot device with the given name, base device, and COW device
+    // size. The new device path will be returned in |dev_path|. If timeout_ms is
+    // greater than zero, this function will wait the given amount of time for
+    // |dev_path| to become available, and fail otherwise. If timeout_ms is 0, then
+    // no wait will occur and |dev_path| may not yet exist on return.
+    bool CreateSnapshot(const std::string& name, const std::string& base_device, uint64_t cow_size,
+                        std::string* dev_path, const std::chrono::milliseconds& timeout_ms);
+
+    // Map a snapshot device that was previously created with CreateSnapshot.
+    // If a merge was previously initiated, the device-mapper table will have a
+    // snapshot-merge target instead of a snapshot target. The timeout parameter
+    // is the same as in CreateSnapshotDevice.
+    bool MapSnapshotDevice(const std::string& name, const std::string& base_device,
+                           const std::chrono::milliseconds& timeout_ms, std::string* dev_path);
+
+    // Unmap a snapshot device previously mapped with MapSnapshotDevice().
+    bool UnmapSnapshotDevice(const std::string& name);
+
+    // Remove the backing copy-on-write image for the named snapshot. If the
+    // device is still mapped, this will attempt an Unmap, and fail if the
+    // unmap fails.
+    bool DeleteSnapshot(const std::string& name);
+
+    // Initiate a merge on all snapshot devices. This should only be used after an
+    // update has been marked successful after booting.
+    bool InitiateMerge();
+
+    // Wait for the current merge to finish, then perform cleanup when it
+    // completes. It is necessary to call this after InitiateMerge(), or when
+    // a merge is detected for the first time after boot.
+    bool WaitForMerge();
+
+    // Find the status of the current update, if any.
+    //
+    // |progress| depends on the returned status:
+    //   None: 0
+    //   Unverified: 0
+    //   Merging: Value in the range [0, 100)
+    //   MergeCompleted: 100
+    UpdateStatus GetUpdateStatus(double* progress);
+};
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
new file mode 100644
index 0000000..3e80239
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -0,0 +1,72 @@
+// 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 <libsnapshot/snapshot.h>
+
+namespace android {
+namespace snapshot {
+
+std::unique_ptr<SnapshotManager> SnapshotManager::New() {
+    return std::make_unique<SnapshotManager>();
+}
+
+bool SnapshotManager::CreateSnapshot(const std::string& name, const std::string& base_device,
+                                     uint64_t cow_size, std::string* dev_path,
+                                     const std::chrono::milliseconds& timeout_ms) {
+    // (1) Create COW device using libgsi_image.
+    // (2) Create snapshot device using libdm + DmTargetSnapshot.
+    // (3) Record partition in /metadata/ota.
+    (void)name;
+    (void)base_device;
+    (void)cow_size;
+    (void)dev_path;
+    (void)timeout_ms;
+    return false;
+}
+
+bool SnapshotManager::MapSnapshotDevice(const std::string& name, const std::string& base_device,
+                                        const std::chrono::milliseconds& timeout_ms,
+                                        std::string* dev_path) {
+    (void)name;
+    (void)base_device;
+    (void)dev_path;
+    (void)timeout_ms;
+    return false;
+}
+
+bool SnapshotManager::UnmapSnapshotDevice(const std::string& name) {
+    (void)name;
+    return false;
+}
+
+bool SnapshotManager::DeleteSnapshot(const std::string& name) {
+    (void)name;
+    return false;
+}
+
+bool SnapshotManager::InitiateMerge() {
+    return false;
+}
+
+bool SnapshotManager::WaitForMerge() {
+    return false;
+}
+
+UpdateStatus SnapshotManager::GetUpdateStatus(double* progress) {
+    *progress = 0.0f;
+    return UpdateStatus::None;
+}
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/init/Android.bp b/init/Android.bp
index 6bc581d..ba60085 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -26,6 +26,7 @@
         "-Wextra",
         "-Wno-unused-parameter",
         "-Werror",
+        "-DALLOW_FIRST_STAGE_CONSOLE=0",
         "-DALLOW_LOCAL_PROP_OVERRIDE=0",
         "-DALLOW_PERMISSIVE_SELINUX=0",
         "-DREBOOT_BOOTLOADER_ON_PANIC=0",
@@ -36,6 +37,8 @@
     product_variables: {
         debuggable: {
             cppflags: [
+                "-UALLOW_FIRST_STAGE_CONSOLE",
+                "-DALLOW_FIRST_STAGE_CONSOLE=1",
                 "-UALLOW_LOCAL_PROP_OVERRIDE",
                 "-DALLOW_LOCAL_PROP_OVERRIDE=1",
                 "-UALLOW_PERMISSIVE_SELINUX",
@@ -71,7 +74,6 @@
     shared_libs: [
         "libbacktrace",
         "libbase",
-        "libbinder",
         "libbootloader_message",
         "libcutils",
         "libcrypto",
@@ -105,7 +107,6 @@
         "bootchart.cpp",
         "builtins.cpp",
         "capabilities.cpp",
-        "descriptors.cpp",
         "devices.cpp",
         "epoll.cpp",
         "firmware_handler.cpp",
@@ -157,6 +158,13 @@
     },
 }
 
+phony {
+    name: "init",
+    required: [
+        "init_second_stage",
+    ],
+}
+
 cc_binary {
     name: "init_second_stage",
     recovery_available: true,
@@ -240,18 +248,18 @@
     ],
     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",
         "action_manager.cpp",
         "action_parser.cpp",
         "capabilities.cpp",
-        "descriptors.cpp",
         "epoll.cpp",
         "keychords.cpp",
         "import_parser.cpp",
@@ -284,5 +292,3 @@
         },
     },
 }
-
-subdirs = ["*"]
diff --git a/init/Android.mk b/init/Android.mk
index b24f757..006e1bf 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -8,6 +8,7 @@
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
 init_options += \
+    -DALLOW_FIRST_STAGE_CONSOLE=1 \
     -DALLOW_LOCAL_PROP_OVERRIDE=1 \
     -DALLOW_PERMISSIVE_SELINUX=1 \
     -DREBOOT_BOOTLOADER_ON_PANIC=1 \
@@ -15,6 +16,7 @@
     -DDUMP_ON_UMOUNT_FAILURE=1
 else
 init_options += \
+    -DALLOW_FIRST_STAGE_CONSOLE=0 \
     -DALLOW_LOCAL_PROP_OVERRIDE=0 \
     -DALLOW_PERMISSIVE_SELINUX=0 \
     -DREBOOT_BOOTLOADER_ON_PANIC=0 \
@@ -111,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/README.md b/init/README.md
index 8179bff..2de76a9 100644
--- a/init/README.md
+++ b/init/README.md
@@ -300,7 +300,8 @@
 
 `socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]`
 > Create a UNIX domain socket named /dev/socket/_name_ and pass its fd to the
-  launched process.  _type_ must be "dgram", "stream" or "seqpacket".  User and
+  launched process.  _type_ must be "dgram", "stream" or "seqpacket".  _type_
+  may end with "+passcred" to enable SO_PASSCRED on the socket. User and
   group default to 0.  'seclabel' is the SELinux security context for the
   socket.  It defaults to the service security context, as specified by
   seclabel or computed based on the service executable file security context.
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 9de4085..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));
@@ -88,7 +88,8 @@
         current_command_ = 0;
         if (action->oneshot()) {
             auto eraser = [&action](std::unique_ptr<Action>& a) { return a.get() == action; };
-            actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser));
+            actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser),
+                           actions_.end());
         }
     }
 }
diff --git a/init/builtins.cpp b/init/builtins.cpp
index cc84aa0..ceab568 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -42,6 +42,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <ApexProperties.sysprop.h>
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -130,6 +131,13 @@
     if (args.context != kInitContext) {
         return Error() << "command 'class_start_post_data' only available in init context";
     }
+    static bool is_apex_updatable = android::sysprop::ApexProperties::updatable().value_or(false);
+
+    if (!is_apex_updatable) {
+        // No need to start these on devices that don't support APEX, since they're not
+        // stopped either.
+        return {};
+    }
     for (const auto& service : ServiceList::GetInstance()) {
         if (service->classnames().count(args[1])) {
             if (auto result = service->StartIfPostData(); !result) {
@@ -155,6 +163,11 @@
     if (args.context != kInitContext) {
         return Error() << "command 'class_reset_post_data' only available in init context";
     }
+    static bool is_apex_updatable = android::sysprop::ApexProperties::updatable().value_or(false);
+    if (!is_apex_updatable) {
+        // No need to stop these on devices that don't support APEX.
+        return {};
+    }
     ForEachServiceInClass(args[1], &Service::ResetIfPostData);
     return {};
 }
@@ -243,7 +256,7 @@
 
     strlcpy(ifr.ifr_name, args[1].c_str(), IFNAMSIZ);
 
-    unique_fd s(TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_DGRAM, 0)));
+    unique_fd s(TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)));
     if (s < 0) return ErrnoError() << "opening socket failed";
 
     if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
@@ -784,7 +797,7 @@
 }
 
 static Result<void> readahead_file(const std::string& filename, bool fully) {
-    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY)));
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY | O_CLOEXEC)));
     if (fd == -1) {
         return ErrnoError() << "Error opening file";
     }
@@ -1107,7 +1120,7 @@
         // /apex/<name> paths, so unless we filter them out, we will parse the
         // same file twice.
         std::vector<std::string> paths = android::base::Split(path, "/");
-        if (paths.size() >= 2 && paths[1].find('@') != std::string::npos) {
+        if (paths.size() >= 3 && paths[2].find('@') != std::string::npos) {
             continue;
         }
         configs.push_back(path);
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
deleted file mode 100644
index 6265687..0000000
--- a/init/descriptors.cpp
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2016 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 "descriptors.h"
-
-#include <ctype.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <cutils/android_get_control_file.h>
-#include <cutils/sockets.h>
-
-#include "util.h"
-
-namespace android {
-namespace init {
-
-DescriptorInfo::DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
-                               gid_t gid, int perm, const std::string& context)
-        : name_(name), type_(type), uid_(uid), gid_(gid), perm_(perm), context_(context) {
-}
-
-DescriptorInfo::~DescriptorInfo() {
-}
-
-std::ostream& operator<<(std::ostream& os, const DescriptorInfo& info) {
-  return os << "  descriptors " << info.name_ << " " << info.type_ << " " << std::oct << info.perm_;
-}
-
-bool DescriptorInfo::operator==(const DescriptorInfo& other) const {
-  return name_ == other.name_ && type_ == other.type_ && key() == other.key();
-}
-
-void DescriptorInfo::CreateAndPublish(const std::string& globalContext) const {
-  // Create
-  const std::string& contextStr = context_.empty() ? globalContext : context_;
-  int fd = Create(contextStr);
-  if (fd < 0) return;
-
-  // Publish
-  std::string publishedName = key() + name_;
-  std::for_each(publishedName.begin(), publishedName.end(),
-                [] (char& c) { c = isalnum(c) ? c : '_'; });
-
-  std::string val = std::to_string(fd);
-  setenv(publishedName.c_str(), val.c_str(), 1);
-
-  // make sure we don't close on exec
-  fcntl(fd, F_SETFD, 0);
-}
-
-void DescriptorInfo::Clean() const {
-}
-
-SocketInfo::SocketInfo(const std::string& name, const std::string& type, uid_t uid,
-                       gid_t gid, int perm, const std::string& context)
-        : DescriptorInfo(name, type, uid, gid, perm, context) {
-}
-
-void SocketInfo::Clean() const {
-    std::string path = android::base::StringPrintf("%s/%s", ANDROID_SOCKET_DIR, name().c_str());
-    unlink(path.c_str());
-}
-
-int SocketInfo::Create(const std::string& context) const {
-    auto types = android::base::Split(type(), "+");
-    int flags =
-        ((types[0] == "stream" ? SOCK_STREAM : (types[0] == "dgram" ? SOCK_DGRAM : SOCK_SEQPACKET)));
-    bool passcred = types.size() > 1 && types[1] == "passcred";
-    return CreateSocket(name().c_str(), flags, passcred, perm(), uid(), gid(), context.c_str());
-}
-
-const std::string SocketInfo::key() const {
-  return ANDROID_SOCKET_ENV_PREFIX;
-}
-
-FileInfo::FileInfo(const std::string& name, const std::string& type, uid_t uid,
-                   gid_t gid, int perm, const std::string& context)
-        // defaults OK for uid,..., they are ignored for this class.
-        : DescriptorInfo(name, type, uid, gid, perm, context) {
-}
-
-int FileInfo::Create(const std::string&) const {
-  int flags = (type() == "r") ? O_RDONLY :
-              (type() == "w") ? O_WRONLY :
-                                O_RDWR;
-
-  // Make sure we do not block on open (eg: devices can chose to block on
-  // carrier detect).  Our intention is never to delay launch of a service
-  // for such a condition.  The service can perform its own blocking on
-  // carrier detect.
-  android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(name().c_str(),
-                                                      flags | O_NONBLOCK)));
-
-  if (fd < 0) {
-    PLOG(ERROR) << "Failed to open file '" << name().c_str() << "'";
-    return -1;
-  }
-
-  // Fixup as we set O_NONBLOCK for open, the intent for fd is to block reads.
-  fcntl(fd, F_SETFL, flags);
-
-  LOG(INFO) << "Opened file '" << name().c_str() << "'"
-            << ", flags " << std::oct << flags << std::dec;
-
-  return fd.release();
-}
-
-const std::string FileInfo::key() const {
-  return ANDROID_FILE_ENV_PREFIX;
-}
-
-}  // namespace init
-}  // namespace android
diff --git a/init/descriptors.h b/init/descriptors.h
deleted file mode 100644
index 3bdddfe..0000000
--- a/init/descriptors.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2016 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 _INIT_DESCRIPTORS_H
-#define _INIT_DESCRIPTORS_H
-
-#include <sys/types.h>
-
-#include <string>
-
-namespace android {
-namespace init {
-
-class DescriptorInfo {
- public:
-  DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
-                 gid_t gid, int perm, const std::string& context);
-  virtual ~DescriptorInfo();
-
-  friend std::ostream& operator<<(std::ostream& os, const class DescriptorInfo& info);
-  bool operator==(const DescriptorInfo& other) const;
-
-  void CreateAndPublish(const std::string& globalContext) const;
-  virtual void Clean() const;
-
- protected:
-  const std::string& name() const { return name_; }
-  const std::string& type() const { return type_; }
-  uid_t uid() const { return uid_; }
-  gid_t gid() const { return gid_; }
-  int perm() const { return perm_; }
-  const std::string& context() const { return context_; }
-
- private:
-  std::string name_;
-  std::string type_;
-  uid_t uid_;
-  gid_t gid_;
-  int perm_;
-  std::string context_;
-
-  virtual int Create(const std::string& globalContext) const = 0;
-  virtual const std::string key() const = 0;
-};
-
-std::ostream& operator<<(std::ostream& os, const DescriptorInfo& info);
-
-class SocketInfo : public DescriptorInfo {
- public:
-  SocketInfo(const std::string& name, const std::string& type, uid_t uid,
-             gid_t gid, int perm, const std::string& context);
-  void Clean() const override;
- private:
-  virtual int Create(const std::string& context) const override;
-  virtual const std::string key() const override;
-};
-
-class FileInfo : public DescriptorInfo {
- public:
-  FileInfo(const std::string& name, const std::string& type, uid_t uid,
-           gid_t gid, int perm, const std::string& context);
- private:
-  virtual int Create(const std::string& context) const override;
-  virtual const std::string key() const override;
-};
-
-}  // namespace init
-}  // namespace android
-
-#endif
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/first_stage_init.cpp b/init/first_stage_init.cpp
index 17387e2..b60c450 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -24,10 +24,12 @@
 #include <sys/stat.h>
 #include <sys/sysmacros.h>
 #include <sys/types.h>
+#include <sys/wait.h>
 #include <unistd.h>
 
 #include <filesystem>
 #include <string>
+#include <thread>
 #include <vector>
 
 #include <android-base/chrono_utils.h>
@@ -76,7 +78,7 @@
 
             if (S_ISDIR(info.st_mode)) {
                 is_dir = true;
-                auto fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
+                auto fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
                 if (fd >= 0) {
                     auto subdir =
                             std::unique_ptr<DIR, decltype(&closedir)>{fdopendir(fd), closedir};
@@ -92,9 +94,50 @@
     }
 }
 
-bool ForceNormalBoot() {
-    std::string cmdline;
-    android::base::ReadFileToString("/proc/cmdline", &cmdline);
+void StartConsole() {
+    if (mknod("/dev/console", S_IFCHR | 0600, makedev(5, 1))) {
+        PLOG(ERROR) << "unable to create /dev/console";
+        return;
+    }
+    pid_t pid = fork();
+    if (pid != 0) {
+        int status;
+        waitpid(pid, &status, 0);
+        LOG(ERROR) << "console shell exited with status " << status;
+        return;
+    }
+    int fd = -1;
+    int tries = 10;
+    // The device driver for console may not be ready yet so retry for a while in case of failure.
+    while (tries--) {
+        fd = open("/dev/console", O_RDWR);
+        if (fd != -1) {
+            break;
+        }
+        std::this_thread::sleep_for(100ms);
+    }
+    if (fd == -1) {
+        LOG(ERROR) << "Could not open /dev/console, errno = " << errno;
+        _exit(127);
+    }
+    ioctl(fd, TIOCSCTTY, 0);
+    dup2(fd, 0);
+    dup2(fd, 1);
+    dup2(fd, 2);
+    close(fd);
+
+    const char* path = "/system/bin/sh";
+    const char* args[] = {path, nullptr};
+    int rv = execv(path, const_cast<char**>(args));
+    LOG(ERROR) << "unable to execv, returned " << rv << " errno " << errno;
+    _exit(127);
+}
+
+bool FirstStageConsole(const std::string& cmdline) {
+    return cmdline.find("androidboot.first_stage_console=1") != std::string::npos;
+}
+
+bool ForceNormalBoot(const std::string& cmdline) {
     return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos;
 }
 
@@ -109,7 +152,7 @@
 
     std::vector<std::pair<std::string, int>> errors;
 #define CHECKCALL(x) \
-    if (x != 0) errors.emplace_back(#x " failed", errno);
+    if ((x) != 0) errors.emplace_back(#x " failed", errno);
 
     // Clear the umask.
     umask(0);
@@ -127,6 +170,8 @@
 #undef MAKE_STR
     // Don't expose the raw commandline to unprivileged processes.
     CHECKCALL(chmod("/proc/cmdline", 0440));
+    std::string cmdline;
+    android::base::ReadFileToString("/proc/cmdline", &cmdline);
     gid_t groups[] = {AID_READPROC};
     CHECKCALL(setgroups(arraysize(groups), groups));
     CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
@@ -198,7 +243,11 @@
         LOG(FATAL) << "Failed to load kernel modules";
     }
 
-    if (ForceNormalBoot()) {
+    if (ALLOW_FIRST_STAGE_CONSOLE && FirstStageConsole(cmdline)) {
+        StartConsole();
+    }
+
+    if (ForceNormalBoot(cmdline)) {
         mkdir("/first_stage_ramdisk", 0755);
         // SwitchRoot() must be called with a mount point as the target, so we bind mount the
         // target directory to itself here.
diff --git a/init/host_init_verifier.cpp b/init/host_init_verifier.cpp
index 9323aa0..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,6 +131,35 @@
     return nullptr;
 }
 
+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 {};
+    }
+
+    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 {};
+    }
+
+    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 {
 namespace init {
 
@@ -139,11 +170,12 @@
 #include "generated_stub_builtin_function_map.h"
 
 void PrintUsage() {
-    std::cout << "usage: host_init_verifier [-p FILE] <init rc file>\n"
+    std::cout << "usage: host_init_verifier [-p FILE] -k FILE <init rc file>\n"
                  "\n"
                  "Tests an init script for correctness\n"
                  "\n"
                  "-p FILE\tSearch this passwd file for users and groups\n"
+                 "-k FILE\tUse this file as a space-separated list of known interfaces\n"
               << std::endl;
 }
 
@@ -151,13 +183,15 @@
     android::base::InitLogging(argv, &android::base::StdioLogger);
     android::base::SetMinimumLogSeverity(android::base::ERROR);
 
+    std::string interface_inheritance_hierarchy_file;
+
     while (true) {
         static const struct option long_options[] = {
                 {"help", no_argument, nullptr, 'h'},
                 {nullptr, 0, nullptr, 0},
         };
 
-        int arg = getopt_long(argc, argv, "p:", long_options, nullptr);
+        int arg = getopt_long(argc, argv, "p:i:", long_options, nullptr);
 
         if (arg == -1) {
             break;
@@ -170,6 +204,9 @@
             case 'p':
                 passwd_files.emplace_back(optarg);
                 break;
+            case 'i':
+                interface_inheritance_hierarchy_file = optarg;
+                break;
             default:
                 std::cerr << "getprop: getopt returned invalid result: " << arg << std::endl;
                 return EXIT_FAILURE;
@@ -189,7 +226,11 @@
     ActionManager& am = ActionManager::GetInstance();
     ServiceList& sl = ServiceList::GetInstance();
     Parser parser;
-    parser.AddSectionParser("service", std::make_unique<ServiceParser>(&sl, nullptr));
+    parser.AddSectionParser(
+            "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 b6911e5..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"
@@ -113,7 +109,8 @@
 Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
     Parser parser;
 
-    parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, subcontexts));
+    parser.AddSectionParser(
+            "service", std::make_unique<ServiceParser>(&service_list, subcontexts, std::nullopt));
     parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, subcontexts));
     parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
 
@@ -124,7 +121,8 @@
 Parser CreateServiceOnlyParser(ServiceList& service_list) {
     Parser parser;
 
-    parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, subcontexts));
+    parser.AddSectionParser(
+            "service", std::make_unique<ServiceParser>(&service_list, subcontexts, std::nullopt));
     return parser;
 }
 
@@ -137,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");
         }
@@ -451,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.
@@ -764,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/init_test.cpp b/init/init_test.cpp
index 1bcc5ef..a09db18 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -44,7 +44,8 @@
     Action::set_function_map(&test_function_map);
 
     Parser parser;
-    parser.AddSectionParser("service", std::make_unique<ServiceParser>(service_list, nullptr));
+    parser.AddSectionParser("service",
+                            std::make_unique<ServiceParser>(service_list, nullptr, std::nullopt));
     parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, nullptr));
     parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
 
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/persistent_properties.cpp b/init/persistent_properties.cpp
index 73787b9..baa9ad4 100644
--- a/init/persistent_properties.cpp
+++ b/init/persistent_properties.cpp
@@ -69,7 +69,7 @@
             continue;
         }
 
-        unique_fd fd(openat(dirfd(dir.get()), entry->d_name, O_RDONLY | O_NOFOLLOW));
+        unique_fd fd(openat(dirfd(dir.get()), entry->d_name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
         if (fd == -1) {
             PLOG(ERROR) << "Unable to open persistent property file \"" << entry->d_name << "\"";
             continue;
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 1520c9f..3761750 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -667,9 +667,9 @@
 
             if (flen > 0) {
                 if (filter[flen - 1] == '*') {
-                    if (strncmp(key, filter, flen - 1)) continue;
+                    if (strncmp(key, filter, flen - 1) != 0) continue;
                 } else {
-                    if (strcmp(key, filter)) continue;
+                    if (strcmp(key, filter) != 0) continue;
                 }
             }
 
@@ -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) {
@@ -995,10 +994,11 @@
 void StartPropertyService(Epoll* epoll) {
     property_set("ro.property_service.version", "2");
 
-    property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
-                                   false, 0666, 0, 0, nullptr);
-    if (property_set_fd == -1) {
-        PLOG(FATAL) << "start_property_service socket creation failed";
+    if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+                                   false, 0666, 0, 0, {})) {
+        property_set_fd = *result;
+    } else {
+        PLOG(FATAL) << "start_property_service socket creation failed: " << result.error();
     }
 
     listen(property_set_fd, 8);
diff --git a/init/reboot.cpp b/init/reboot.cpp
index d9d885c..b0b5b54 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,20 @@
                                   "bootloader_message: "
                                << err;
                 }
+            } else if (reboot_target == "recovery") {
+                bootloader_message boot = {};
+                if (std::string err; !read_bootloader_message(&boot, &err)) {
+                    LOG(ERROR) << "Failed to read bootloader message: " << err;
+                }
+                // Update the boot command field if it's empty, and preserve
+                // the other arguments in the bootloader message.
+                if (boot.command[0] == '\0') {
+                    strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
+                    if (std::string err; !write_bootloader_message(boot, &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 +698,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.cpp b/init/service.cpp
index cd08f3d..47f4db9 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -31,6 +31,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <cutils/sockets.h>
 #include <processgroup/processgroup.h>
 #include <selinux/selinux.h>
 
@@ -126,7 +127,7 @@
     : Service(name, 0, 0, 0, {}, 0, "", subcontext_for_restart_commands, args) {}
 
 Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
-                 const std::vector<gid_t>& supp_gids, unsigned namespace_flags,
+                 const std::vector<gid_t>& supp_gids, int namespace_flags,
                  const std::string& seclabel, Subcontext* subcontext_for_restart_commands,
                  const std::vector<std::string>& args)
     : name_(name),
@@ -227,9 +228,11 @@
         KillProcessGroup(SIGKILL);
     }
 
-    // Remove any descriptor resources we may have created.
-    std::for_each(descriptors_.begin(), descriptors_.end(),
-                  std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
+    // Remove any socket resources we may have created.
+    for (const auto& socket : sockets_) {
+        auto path = ANDROID_SOCKET_DIR "/" + socket.name;
+        unlink(path.c_str());
+    }
 
     for (const auto& f : reap_callbacks_) {
         f(siginfo);
@@ -300,8 +303,12 @@
     LOG(INFO) << "service " << name_;
     LOG(INFO) << "  class '" << Join(classnames_, " ") << "'";
     LOG(INFO) << "  exec " << Join(args_, " ");
-    std::for_each(descriptors_.begin(), descriptors_.end(),
-                  [] (const auto& info) { LOG(INFO) << *info; });
+    for (const auto& socket : sockets_) {
+        LOG(INFO) << "  socket " << socket.name;
+    }
+    for (const auto& file : files_) {
+        LOG(INFO) << "  file " << file.name;
+    }
 }
 
 
@@ -419,8 +426,17 @@
             setenv(key.c_str(), value.c_str(), 1);
         }
 
-        std::for_each(descriptors_.begin(), descriptors_.end(),
-                      std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon));
+        for (const auto& socket : sockets_) {
+            if (auto result = socket.CreateAndPublish(scon); !result) {
+                LOG(INFO) << "Could not create socket '" << socket.name << "': " << result.error();
+            }
+        }
+
+        for (const auto& file : files_) {
+            if (auto result = file.CreateAndPublish(); !result) {
+                LOG(INFO) << "Could not open file '" << file.name << "': " << result.error();
+            }
+        }
 
         if (auto result = WritePidToFiles(&writepid_files_); !result) {
             LOG(ERROR) << "failed to write pid to files: " << result.error();
diff --git a/init/service.h b/init/service.h
index 78f94ce..cdf31bb 100644
--- a/init/service.h
+++ b/init/service.h
@@ -31,7 +31,6 @@
 
 #include "action.h"
 #include "capabilities.h"
-#include "descriptors.h"
 #include "keyword_map.h"
 #include "parser.h"
 #include "service_utils.h"
@@ -69,9 +68,8 @@
             const std::vector<std::string>& args);
 
     Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
-            const std::vector<gid_t>& supp_gids, unsigned namespace_flags,
-            const std::string& seclabel, Subcontext* subcontext_for_restart_commands,
-            const std::vector<std::string>& args);
+            const std::vector<gid_t>& supp_gids, int namespace_flags, const std::string& seclabel,
+            Subcontext* subcontext_for_restart_commands, const std::vector<std::string>& args);
 
     static std::unique_ptr<Service> MakeTemporaryOneshotService(const std::vector<std::string>& args);
 
@@ -109,7 +107,7 @@
     int crash_count() const { return crash_count_; }
     uid_t uid() const { return proc_attr_.uid; }
     gid_t gid() const { return proc_attr_.gid; }
-    unsigned namespace_flags() const { return namespaces_.flags; }
+    int namespace_flags() const { return namespaces_.flags; }
     const std::vector<gid_t>& supp_gids() const { return proc_attr_.supp_gids; }
     const std::string& seclabel() const { return seclabel_; }
     const std::vector<int>& keycodes() const { return keycodes_; }
@@ -152,7 +150,8 @@
 
     std::string seclabel_;
 
-    std::vector<std::unique_ptr<DescriptorInfo>> descriptors_;
+    std::vector<SocketDescriptor> sockets_;
+    std::vector<FileDescriptor> files_;
     std::vector<std::pair<std::string, std::string>> environment_vars_;
 
     Action onrestart_;  // Commands to execute on restart.
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 33ed050..0fbbeb8 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -17,6 +17,11 @@
 #include "service_parser.h"
 
 #include <linux/input.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+
+#include <algorithm>
+#include <sstream>
 
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
@@ -25,6 +30,7 @@
 #include <system/thread_defs.h>
 
 #include "rlimit_parser.h"
+#include "service_utils.h"
 #include "util.h"
 
 #if defined(__ANDROID__)
@@ -341,64 +347,98 @@
     return {};
 }
 
-template <typename T>
-Result<void> ServiceParser::AddDescriptor(std::vector<std::string>&& args) {
-    int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
-    Result<uid_t> uid = 0;
-    Result<gid_t> gid = 0;
-    std::string context = args.size() > 6 ? args[6] : "";
+// name type perm [ uid gid context ]
+Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) {
+    SocketDescriptor socket;
+    socket.name = std::move(args[1]);
+
+    auto types = Split(args[2], "+");
+    if (types[0] == "stream") {
+        socket.type = SOCK_STREAM;
+    } else if (types[0] == "dgram") {
+        socket.type = SOCK_DGRAM;
+    } else if (types[0] == "seqpacket") {
+        socket.type = SOCK_SEQPACKET;
+    } else {
+        return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket', got '" << types[0]
+                       << "' instead.";
+    }
+
+    if (types.size() > 1) {
+        if (types.size() == 2 && types[1] == "passcred") {
+            socket.passcred = true;
+        } else {
+            return Error() << "Only 'passcred' may be used to modify the socket type";
+        }
+    }
+
+    errno = 0;
+    char* end = nullptr;
+    socket.perm = strtol(args[3].c_str(), &end, 8);
+    if (errno != 0) {
+        return ErrnoError() << "Unable to parse permissions '" << args[3] << "'";
+    }
+    if (end == args[3].c_str() || *end != '\0') {
+        errno = EINVAL;
+        return ErrnoError() << "Unable to parse permissions '" << args[3] << "'";
+    }
 
     if (args.size() > 4) {
-        uid = DecodeUid(args[4]);
+        auto uid = DecodeUid(args[4]);
         if (!uid) {
             return Error() << "Unable to find UID for '" << args[4] << "': " << uid.error();
         }
+        socket.uid = *uid;
     }
 
     if (args.size() > 5) {
-        gid = DecodeUid(args[5]);
+        auto gid = DecodeUid(args[5]);
         if (!gid) {
             return Error() << "Unable to find GID for '" << args[5] << "': " << gid.error();
         }
+        socket.gid = *gid;
     }
 
-    auto descriptor = std::make_unique<T>(args[1], args[2], *uid, *gid, perm, context);
+    socket.context = args.size() > 6 ? args[6] : "";
 
-    auto old = std::find_if(
-            service_->descriptors_.begin(), service_->descriptors_.end(),
-            [&descriptor](const auto& other) { return descriptor.get() == other.get(); });
+    auto old = std::find_if(service_->sockets_.begin(), service_->sockets_.end(),
+                            [&socket](const auto& other) { return socket.name == other.name; });
 
-    if (old != service_->descriptors_.end()) {
-        return Error() << "duplicate descriptor " << args[1] << " " << args[2];
+    if (old != service_->sockets_.end()) {
+        return Error() << "duplicate socket descriptor '" << socket.name << "'";
     }
 
-    service_->descriptors_.emplace_back(std::move(descriptor));
+    service_->sockets_.emplace_back(std::move(socket));
+
     return {};
 }
 
-// name type perm [ uid gid context ]
-Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) {
-    if (!StartsWith(args[2], "dgram") && !StartsWith(args[2], "stream") &&
-        !StartsWith(args[2], "seqpacket")) {
-        return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket'";
-    }
-    return AddDescriptor<SocketInfo>(std::move(args));
-}
-
-// name type perm [ uid gid context ]
+// name type
 Result<void> ServiceParser::ParseFile(std::vector<std::string>&& args) {
     if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
         return Error() << "file type must be 'r', 'w' or 'rw'";
     }
-    std::string expanded;
-    if (!expand_props(args[1], &expanded)) {
+
+    FileDescriptor file;
+    file.type = args[2];
+
+    if (!expand_props(args[1], &file.name)) {
         return Error() << "Could not expand property in file path '" << args[1] << "'";
     }
-    args[1] = std::move(expanded);
-    if ((args[1][0] != '/') || (args[1].find("../") != std::string::npos)) {
+    if (file.name[0] != '/' || file.name.find("../") != std::string::npos) {
         return Error() << "file name must not be relative";
     }
-    return AddDescriptor<FileInfo>(std::move(args));
+
+    auto old = std::find_if(service_->files_.begin(), service_->files_.end(),
+                            [&file](const auto& other) { return other.name == file.name; });
+
+    if (old != service_->files_.end()) {
+        return Error() << "duplicate file descriptor '" << file.name << "'";
+    }
+
+    service_->files_.emplace_back(std::move(file));
+
+    return {};
 }
 
 Result<void> ServiceParser::ParseUser(std::vector<std::string>&& args) {
@@ -534,6 +574,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 0a5b291..bca0739 100644
--- a/init/service_parser.h
+++ b/init/service_parser.h
@@ -26,10 +26,17 @@
 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)
-        : service_list_(service_list), subcontexts_(subcontexts), service_(nullptr) {}
+    ServiceParser(
+            ServiceList* service_list, std::vector<Subcontext>* subcontexts,
+            const std::optional<InterfaceInheritanceHierarchyMap>& interface_inheritance_hierarchy)
+        : service_list_(service_list),
+          subcontexts_(subcontexts),
+          interface_inheritance_hierarchy_(interface_inheritance_hierarchy),
+          service_(nullptr) {}
     Result<void> ParseSection(std::vector<std::string>&& args, const std::string& filename,
                               int line) override;
     Result<void> ParseLineSection(std::vector<std::string>&& args, int line) override;
@@ -74,13 +81,11 @@
     Result<void> ParseWritepid(std::vector<std::string>&& args);
     Result<void> ParseUpdatable(std::vector<std::string>&& args);
 
-    template <typename T>
-    Result<void> AddDescriptor(std::vector<std::string>&& args);
-
     bool IsValidName(const std::string& name) const;
 
     ServiceList* service_list_;
     std::vector<Subcontext>* subcontexts_;
+    std::optional<InterfaceInheritanceHierarchyMap> interface_inheritance_hierarchy_;
     std::unique_ptr<Service> service_;
     std::string filename_;
 };
diff --git a/init/service_test.cpp b/init/service_test.cpp
index 4bfaa6b..6a34acc 100644
--- a/init/service_test.cpp
+++ b/init/service_test.cpp
@@ -30,7 +30,7 @@
 
 TEST(service, pod_initialized) {
     constexpr auto memory_size = sizeof(Service);
-    alignas(alignof(Service)) char old_memory[memory_size];
+    alignas(alignof(Service)) unsigned char old_memory[memory_size];
 
     for (std::size_t i = 0; i < memory_size; ++i) {
         old_memory[i] = 0xFF;
@@ -45,7 +45,7 @@
     EXPECT_EQ(0, service_in_old_memory->crash_count());
     EXPECT_EQ(0U, service_in_old_memory->uid());
     EXPECT_EQ(0U, service_in_old_memory->gid());
-    EXPECT_EQ(0U, service_in_old_memory->namespace_flags());
+    EXPECT_EQ(0, service_in_old_memory->namespace_flags());
     EXPECT_EQ(IoSchedClass_NONE, service_in_old_memory->ioprio_class());
     EXPECT_EQ(0, service_in_old_memory->ioprio_pri());
     EXPECT_EQ(0, service_in_old_memory->priority());
@@ -64,7 +64,7 @@
     EXPECT_EQ(0, service_in_old_memory2->crash_count());
     EXPECT_EQ(0U, service_in_old_memory2->uid());
     EXPECT_EQ(0U, service_in_old_memory2->gid());
-    EXPECT_EQ(0U, service_in_old_memory2->namespace_flags());
+    EXPECT_EQ(0, service_in_old_memory2->namespace_flags());
     EXPECT_EQ(IoSchedClass_NONE, service_in_old_memory2->ioprio_class());
     EXPECT_EQ(0, service_in_old_memory2->ioprio_pri());
     EXPECT_EQ(0, service_in_old_memory2->priority());
diff --git a/init/service_utils.cpp b/init/service_utils.cpp
index f88ea97..836145d 100644
--- a/init/service_utils.cpp
+++ b/init/service_utils.cpp
@@ -27,9 +27,12 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <cutils/android_get_control_file.h>
+#include <cutils/sockets.h>
 #include <processgroup/processgroup.h>
 
 #include "mount_namespace.h"
+#include "util.h"
 
 using android::base::GetProperty;
 using android::base::StartsWith;
@@ -120,26 +123,67 @@
 }
 
 void ZapStdio() {
-    int fd;
-    fd = open("/dev/null", O_RDWR);
+    auto fd = unique_fd{open("/dev/null", O_RDWR | O_CLOEXEC)};
     dup2(fd, 0);
     dup2(fd, 1);
     dup2(fd, 2);
-    close(fd);
 }
 
 void OpenConsole(const std::string& console) {
-    int fd = open(console.c_str(), O_RDWR);
-    if (fd == -1) fd = open("/dev/null", O_RDWR);
+    auto fd = unique_fd{open(console.c_str(), O_RDWR | O_CLOEXEC)};
+    if (fd == -1) fd.reset(open("/dev/null", O_RDWR | O_CLOEXEC));
     ioctl(fd, TIOCSCTTY, 0);
     dup2(fd, 0);
     dup2(fd, 1);
     dup2(fd, 2);
-    close(fd);
+}
+
+void PublishDescriptor(const std::string& key, const std::string& name, int fd) {
+    std::string published_name = key + name;
+    for (auto& c : published_name) {
+        c = isalnum(c) ? c : '_';
+    }
+
+    std::string val = std::to_string(fd);
+    setenv(published_name.c_str(), val.c_str(), 1);
 }
 
 }  // namespace
 
+Result<void> SocketDescriptor::CreateAndPublish(const std::string& global_context) const {
+    const auto& socket_context = context.empty() ? global_context : context;
+    auto result = CreateSocket(name, type, passcred, perm, uid, gid, socket_context);
+    if (!result) {
+        return result.error();
+    }
+
+    PublishDescriptor(ANDROID_SOCKET_ENV_PREFIX, name, *result);
+
+    return {};
+}
+
+Result<void> FileDescriptor::CreateAndPublish() const {
+    int flags = (type == "r") ? O_RDONLY : (type == "w") ? O_WRONLY : O_RDWR;
+
+    // Make sure we do not block on open (eg: devices can chose to block on carrier detect).  Our
+    // intention is never to delay launch of a service for such a condition.  The service can
+    // perform its own blocking on carrier detect.
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(name.c_str(), flags | O_NONBLOCK)));
+
+    if (fd < 0) {
+        return ErrnoError() << "Failed to open file '" << name << "'";
+    }
+
+    // Fixup as we set O_NONBLOCK for open, the intent for fd is to block reads.
+    fcntl(fd, F_SETFL, flags);
+
+    LOG(INFO) << "Opened file '" << name << "', flags " << flags;
+
+    PublishDescriptor(ANDROID_FILE_ENV_PREFIX, name, fd.release());
+
+    return {};
+}
+
 Result<void> EnterNamespaces(const NamespaceInfo& info, const std::string& name, bool pre_apexd) {
     for (const auto& [nstype, path] : info.namespaces_to_enter) {
         if (auto result = EnterNamespace(nstype, path.c_str()); !result) {
diff --git a/init/service_utils.h b/init/service_utils.h
index c26b123..befce25 100644
--- a/init/service_utils.h
+++ b/init/service_utils.h
@@ -29,8 +29,27 @@
 namespace android {
 namespace init {
 
+struct SocketDescriptor {
+    std::string name;
+    int type = 0;
+    uid_t uid = 0;
+    gid_t gid = 0;
+    int perm = 0;
+    std::string context;
+    bool passcred = false;
+
+    Result<void> CreateAndPublish(const std::string& global_context) const;
+};
+
+struct FileDescriptor {
+    std::string name;
+    std::string type;
+
+    Result<void> CreateAndPublish() const;
+};
+
 struct NamespaceInfo {
-    unsigned flags;
+    int flags;
     // Pair of namespace type, path to name.
     std::vector<std::pair<int, std::string>> namespaces_to_enter;
 };
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 02ed507..2f9541b 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -246,7 +246,7 @@
 
         // We explicitly do not use O_CLOEXEC here, such that we can reference this FD by number
         // in the subcontext process after we exec.
-        int child_fd = dup(subcontext_socket);
+        int child_fd = dup(subcontext_socket);  // NOLINT(android-cloexec-dup)
         if (child_fd < 0) {
             PLOG(FATAL) << "Could not dup child_fd";
         }
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/tokenizer_test.cpp b/init/tokenizer_test.cpp
index acfc7c7..6b31683 100644
--- a/init/tokenizer_test.cpp
+++ b/init/tokenizer_test.cpp
@@ -46,6 +46,7 @@
                 return;
             case T_NEWLINE:
                 tokens.emplace_back(std::move(current_line));
+                current_line.clear();
                 break;
             case T_TEXT:
                 current_line.emplace_back(state.text);
diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp
index 62cd2be..ac633776 100644
--- a/init/uevent_listener.cpp
+++ b/init/uevent_listener.cpp
@@ -131,7 +131,7 @@
                                                        const ListenerCallback& callback) const {
     int dfd = dirfd(d);
 
-    int fd = openat(dfd, "uevent", O_WRONLY);
+    int fd = openat(dfd, "uevent", O_WRONLY | O_CLOEXEC);
     if (fd >= 0) {
         write(fd, "add\n", 4);
         close(fd);
@@ -146,7 +146,7 @@
     while ((de = readdir(d)) != nullptr) {
         if (de->d_type != DT_DIR || de->d_name[0] == '.') continue;
 
-        fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
+        fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
         if (fd < 0) continue;
 
         std::unique_ptr<DIR, decltype(&closedir)> d2(fdopendir(fd), closedir);
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/init/util.cpp b/init/util.cpp
index 2b34242..8bfb755 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -34,6 +34,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
+#include <android-base/scopeguard.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <cutils/sockets.h>
@@ -77,32 +78,28 @@
  * daemon. We communicate the file descriptor's value via the environment
  * variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
  */
-int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
-                 const char* socketcon) {
-    if (socketcon) {
-        if (setsockcreatecon(socketcon) == -1) {
-            PLOG(ERROR) << "setsockcreatecon(\"" << socketcon << "\") failed";
-            return -1;
+Result<int> CreateSocket(const std::string& name, int type, bool passcred, mode_t perm, uid_t uid,
+                         gid_t gid, const std::string& socketcon) {
+    if (!socketcon.empty()) {
+        if (setsockcreatecon(socketcon.c_str()) == -1) {
+            return ErrnoError() << "setsockcreatecon(\"" << socketcon << "\") failed";
         }
     }
 
     android::base::unique_fd fd(socket(PF_UNIX, type, 0));
     if (fd < 0) {
-        PLOG(ERROR) << "Failed to open socket '" << name << "'";
-        return -1;
+        return ErrnoError() << "Failed to open socket '" << name << "'";
     }
 
-    if (socketcon) setsockcreatecon(NULL);
+    if (!socketcon.empty()) setsockcreatecon(nullptr);
 
     struct sockaddr_un addr;
     memset(&addr, 0 , sizeof(addr));
     addr.sun_family = AF_UNIX;
-    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
-             name);
+    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR "/%s", name.c_str());
 
     if ((unlink(addr.sun_path) != 0) && (errno != ENOENT)) {
-        PLOG(ERROR) << "Failed to unlink old socket '" << name << "'";
-        return -1;
+        return ErrnoError() << "Failed to unlink old socket '" << name << "'";
     }
 
     std::string secontext;
@@ -113,8 +110,7 @@
     if (passcred) {
         int on = 1;
         if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
-            PLOG(ERROR) << "Failed to set SO_PASSCRED '" << name << "'";
-            return -1;
+            return ErrnoError() << "Failed to set SO_PASSCRED '" << name << "'";
         }
     }
 
@@ -125,19 +121,18 @@
         setfscreatecon(nullptr);
     }
 
+    auto guard = android::base::make_scope_guard([&addr] { unlink(addr.sun_path); });
+
     if (ret) {
         errno = savederrno;
-        PLOG(ERROR) << "Failed to bind socket '" << name << "'";
-        goto out_unlink;
+        return ErrnoError() << "Failed to bind socket '" << name << "'";
     }
 
     if (lchown(addr.sun_path, uid, gid)) {
-        PLOG(ERROR) << "Failed to lchown socket '" << addr.sun_path << "'";
-        goto out_unlink;
+        return ErrnoError() << "Failed to lchown socket '" << addr.sun_path << "'";
     }
     if (fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW)) {
-        PLOG(ERROR) << "Failed to fchmodat socket '" << addr.sun_path << "'";
-        goto out_unlink;
+        return ErrnoError() << "Failed to fchmodat socket '" << addr.sun_path << "'";
     }
 
     LOG(INFO) << "Created socket '" << addr.sun_path << "'"
@@ -145,11 +140,8 @@
               << ", user " << uid
               << ", group " << gid;
 
+    guard.Disable();
     return fd.release();
-
-out_unlink:
-    unlink(addr.sun_path);
-    return -1;
 }
 
 Result<std::string> ReadFile(const std::string& path) {
@@ -450,7 +442,7 @@
 // SetStdioToDevNull() must be called again in second stage init.
 void SetStdioToDevNull(char** argv) {
     // Make stdin/stdout/stderr all point to /dev/null.
-    int fd = open("/dev/null", O_RDWR);
+    int fd = open("/dev/null", O_RDWR);  // NOLINT(android-cloexec-open)
     if (fd == -1) {
         int saved_errno = errno;
         android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
diff --git a/init/util.h b/init/util.h
index 1929cb5..6a12fb6 100644
--- a/init/util.h
+++ b/init/util.h
@@ -38,8 +38,8 @@
 
 static const char kColdBootDoneProp[] = "ro.cold_boot_done";
 
-int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
-                 const char* socketcon);
+Result<int> CreateSocket(const std::string& name, int type, bool passcred, mode_t perm, uid_t uid,
+                         gid_t gid, const std::string& socketcon);
 
 Result<std::string> ReadFile(const std::string& path);
 Result<void> WriteFile(const std::string& path, const std::string& content);
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 9ece847..565f2c3 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -97,7 +97,6 @@
             cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
         },
     },
-    whole_static_libs: ["libdemangle"],
 }
 
 cc_test_library {
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 71980d7..3e050ab 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -28,13 +28,13 @@
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
-#include <demangle.h>
-
 #include "BacktraceLog.h"
 #include "UnwindStack.h"
 
 using android::base::StringPrintf;
 
+extern "C" char* __cxa_demangle(const char*, char*, size_t*, int*);
+
 //-------------------------------------------------------------------------
 // Backtrace functions.
 //-------------------------------------------------------------------------
@@ -63,7 +63,14 @@
   if (map->start == 0 || (map->flags & PROT_DEVICE_MAP)) {
     return "";
   }
-  return demangle(GetFunctionNameRaw(pc, offset).c_str());
+  std::string name(GetFunctionNameRaw(pc, offset));
+  char* demangled_name = __cxa_demangle(name.c_str(), nullptr, nullptr, nullptr);
+  if (demangled_name != nullptr) {
+    name = demangled_name;
+    free(demangled_name);
+    return name;
+  }
+  return name;
 }
 
 bool Backtrace::VerifyReadWordArgs(uint64_t ptr, word_t* out_value) {
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index a128623..624711f 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -24,7 +24,6 @@
 #include <string>
 
 #include <backtrace/Backtrace.h>
-#include <demangle.h>
 #include <unwindstack/Elf.h>
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Maps.h>
@@ -41,6 +40,8 @@
 #include "UnwindStack.h"
 #include "UnwindStackMap.h"
 
+extern "C" char* __cxa_demangle(const char*, char*, size_t*, int*);
+
 bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
                        std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
                        std::vector<std::string>* skip_names, BacktraceUnwindError* error) {
@@ -115,7 +116,13 @@
     back_frame->pc = frame->pc;
     back_frame->sp = frame->sp;
 
-    back_frame->func_name = demangle(frame->function_name.c_str());
+    char* demangled_name = __cxa_demangle(frame->function_name.c_str(), nullptr, nullptr, nullptr);
+    if (demangled_name != nullptr) {
+      back_frame->func_name = demangled_name;
+      free(demangled_name);
+    } else {
+      back_frame->func_name = frame->function_name;
+    }
     back_frame->func_offset = frame->function_offset;
 
     back_frame->map.name = frame->map_name;
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/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 63c3793..ae9dab5 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -28,17 +28,10 @@
  *   mediadrm
  * Whose friendly names do not match the #define statements.
  *
- * Additionally, AID_OEM_RESERVED_START and AID_OEM_RESERVED_END
- * can be used to define reserved OEM ranges used for sanity checks
- * during the build process. The rules are, they must end with START/END
- * The proper convention is incrementing a number like so:
- * AID_OEM_RESERVED_START
- * AID_OEM_RESERVED_1_START
- * AID_OEM_RESERVED_2_START
- * ...
- * The same applies to the END.
- * They are not required to be in order, but must not overlap each other and
- * must define a START and END'ing range. START must be smaller than END.
+ * This file must only be used for platform (Google managed, and submitted through AOSP), AIDs.  3rd
+ * party AIDs must be added via config.fs, which will place them in the corresponding partition's
+ * passwd and group files.  There are ranges in this file reserved for AIDs for each 3rd party
+ * partition, from which the system reads passwd and group files.
  */
 
 #ifndef _ANDROID_FILESYSTEM_CONFIG_H_
@@ -141,8 +134,12 @@
 #define AID_CACHE 2001 /* cache access */
 #define AID_DIAG 2002  /* access to diagnostic resources */
 
-/* The range 2900-2999 is reserved for OEM, and must never be
- * used here */
+/* The range 2900-2999 is reserved for the vendor partition */
+/* Note that the two 'OEM' ranges pre-dated the vendor partition, so they take the legacy 'OEM'
+ * name. Additionally, they pre-dated passwd/group files, so there are users and groups named oem_#
+ * created automatically for all values in these ranges.  If there is a user/group in a passwd/group
+ * file corresponding to this range, both the oem_# and user/group names will resolve to the same
+ * value. */
 #define AID_OEM_RESERVED_START 2900
 #define AID_OEM_RESERVED_END 2999
 
@@ -159,10 +156,26 @@
 #define AID_WAKELOCK 3010     /* Allow system wakelock read/write access */
 #define AID_UHID 3011         /* Allow read/write to /dev/uhid node */
 
-/* The range 5000-5999 is also reserved for OEM, and must never be used here. */
+/* The range 5000-5999 is also reserved for vendor partition. */
 #define AID_OEM_RESERVED_2_START 5000
 #define AID_OEM_RESERVED_2_END 5999
 
+/* The range 6000-6499 is reserved for the system partition. */
+#define AID_SYSTEM_RESERVED_START 6000
+#define AID_SYSTEM_RESERVED_END 6499
+
+/* The range 6500-6999 is reserved for the odm partition. */
+#define AID_ODM_RESERVED_START 6500
+#define AID_ODM_RESERVED_END 6999
+
+/* The range 7000-7499 is reserved for the product partition. */
+#define AID_PRODUCT_RESERVED_START 7000
+#define AID_PRODUCT_RESERVED_END 7499
+
+/* The range 7500-7999 is reserved for the system_ext partition. */
+#define AID_SYSTEM_EXT_RESERVED_START 7500
+#define AID_SYSTEM_EXT_RESERVED_END 7999
+
 #define AID_EVERYBODY 9997 /* shared between all apps in the same profile */
 #define AID_MISC 9998      /* access to misc storage */
 #define AID_NOBODY 9999
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/libmeminfo/Android.bp b/libmeminfo/Android.bp
index fc022bd..8dcc77b 100644
--- a/libmeminfo/Android.bp
+++ b/libmeminfo/Android.bp
@@ -26,10 +26,17 @@
         "liblog",
         "libprocinfo",
     ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+
+    },
 }
 
 cc_library {
     name: "libmeminfo",
+    host_supported: true,
     defaults: ["libmeminfo_defaults"],
     export_include_dirs: ["include"],
     export_shared_lib_headers: ["libbase"],
diff --git a/libmeminfo/include/meminfo/procmeminfo.h b/libmeminfo/include/meminfo/procmeminfo.h
index 1fb4151..f782ec5 100644
--- a/libmeminfo/include/meminfo/procmeminfo.h
+++ b/libmeminfo/include/meminfo/procmeminfo.h
@@ -45,6 +45,9 @@
     // vector.
     const std::vector<Vma>& MapsWithPageIdle();
 
+    // Same as Maps() except, do not read the usage stats for each map.
+    const std::vector<Vma>& MapsWithoutUsageStats();
+
     // Collect all 'vma' or 'maps' from /proc/<pid>/smaps and store them in 'maps_'. Returns a
     // constant reference to the vma vector after the collection is done.
     //
@@ -88,7 +91,7 @@
     ~ProcMemInfo() = default;
 
   private:
-    bool ReadMaps(bool get_wss, bool use_pageidle = false);
+    bool ReadMaps(bool get_wss, bool use_pageidle = false, bool get_usage_stats = true);
     bool ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss, bool use_pageidle);
 
     pid_t pid_;
diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp
index 5451ca3..4c2be91 100644
--- a/libmeminfo/libmeminfo_test.cpp
+++ b/libmeminfo/libmeminfo_test.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
@@ -60,6 +61,103 @@
     EXPECT_FALSE(maps.empty());
 }
 
+TEST(ProcMemInfo, MapsUsageNotEmpty) {
+    ProcMemInfo proc_mem(pid);
+    const std::vector<Vma>& maps = proc_mem.Maps();
+    EXPECT_FALSE(maps.empty());
+    uint64_t total_pss = 0;
+    uint64_t total_rss = 0;
+    uint64_t total_uss = 0;
+    for (auto& map : maps) {
+        ASSERT_NE(0, map.usage.vss);
+        total_rss += map.usage.rss;
+        total_pss += map.usage.pss;
+        total_uss += map.usage.uss;
+    }
+
+    // Crude check that stats are actually being read.
+    EXPECT_NE(0, total_rss) << "RSS zero for all maps, that is not possible.";
+    EXPECT_NE(0, total_pss) << "PSS zero for all maps, that is not possible.";
+    EXPECT_NE(0, total_uss) << "USS zero for all maps, that is not possible.";
+}
+
+TEST(ProcMemInfo, MapsUsageEmpty) {
+    ProcMemInfo proc_mem(pid);
+    const std::vector<Vma>& maps = proc_mem.MapsWithoutUsageStats();
+    EXPECT_FALSE(maps.empty());
+    // Verify that all usage stats are zero in every map.
+    for (auto& map : maps) {
+        ASSERT_EQ(0, map.usage.vss);
+        ASSERT_EQ(0, map.usage.rss);
+        ASSERT_EQ(0, map.usage.pss);
+        ASSERT_EQ(0, map.usage.uss);
+        ASSERT_EQ(0, map.usage.swap);
+        ASSERT_EQ(0, map.usage.swap_pss);
+        ASSERT_EQ(0, map.usage.private_clean);
+        ASSERT_EQ(0, map.usage.private_dirty);
+        ASSERT_EQ(0, map.usage.shared_clean);
+        ASSERT_EQ(0, map.usage.shared_dirty);
+    }
+}
+
+TEST(ProcMemInfo, PageMapPresent) {
+    static constexpr size_t kNumPages = 20;
+    size_t pagesize = getpagesize();
+    void* ptr = mmap(nullptr, pagesize * (kNumPages + 2), PROT_READ | PROT_WRITE,
+                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+    ASSERT_NE(MAP_FAILED, ptr);
+
+    // Unmap the first page and the last page so that we guarantee this
+    // map is in a map by itself.
+    ASSERT_EQ(0, munmap(ptr, pagesize));
+    uintptr_t addr = reinterpret_cast<uintptr_t>(ptr) + pagesize;
+    ASSERT_EQ(0, munmap(reinterpret_cast<void*>(addr + kNumPages * pagesize), pagesize));
+
+    ProcMemInfo proc_mem(getpid());
+    const std::vector<Vma>& maps = proc_mem.MapsWithoutUsageStats();
+    ASSERT_FALSE(maps.empty());
+
+    // Find the vma associated with our previously created map.
+    const Vma* test_vma = nullptr;
+    for (const Vma& vma : maps) {
+        if (vma.start == addr) {
+            test_vma = &vma;
+            break;
+        }
+    }
+    ASSERT_TRUE(test_vma != nullptr) << "Cannot find test map.";
+
+    // Verify that none of the pages are listed as present.
+    std::vector<uint64_t> pagemap;
+    ASSERT_TRUE(proc_mem.PageMap(*test_vma, &pagemap));
+    ASSERT_EQ(kNumPages, pagemap.size());
+    for (size_t i = 0; i < pagemap.size(); i++) {
+        EXPECT_FALSE(android::meminfo::page_present(pagemap[i]))
+                << "Page " << i << " is present and it should not be.";
+    }
+
+    // Make some of the pages present and verify that we see them
+    // as present.
+    uint8_t* data = reinterpret_cast<uint8_t*>(addr);
+    data[0] = 1;
+    data[pagesize * 5] = 1;
+    data[pagesize * 11] = 1;
+
+    ASSERT_TRUE(proc_mem.PageMap(*test_vma, &pagemap));
+    ASSERT_EQ(kNumPages, pagemap.size());
+    for (size_t i = 0; i < pagemap.size(); i++) {
+        if (i == 0 || i == 5 || i == 11) {
+            EXPECT_TRUE(android::meminfo::page_present(pagemap[i]))
+                    << "Page " << i << " is not present and it should be.";
+        } else {
+            EXPECT_FALSE(android::meminfo::page_present(pagemap[i]))
+                    << "Page " << i << " is present and it should not be.";
+        }
+    }
+
+    ASSERT_EQ(0, munmap(reinterpret_cast<void*>(addr), kNumPages * pagesize));
+}
+
 TEST(ProcMemInfo, WssEmpty) {
     // If we created the object for getting usage,
     // the working set must be empty
diff --git a/libmeminfo/procmeminfo.cpp b/libmeminfo/procmeminfo.cpp
index caf6e86..6f68ab4 100644
--- a/libmeminfo/procmeminfo.cpp
+++ b/libmeminfo/procmeminfo.cpp
@@ -130,6 +130,14 @@
     return maps_;
 }
 
+const std::vector<Vma>& ProcMemInfo::MapsWithoutUsageStats() {
+    if (maps_.empty() && !ReadMaps(get_wss_, false, false)) {
+        LOG(ERROR) << "Failed to read maps for Process " << pid_;
+    }
+
+    return maps_;
+}
+
 const std::vector<Vma>& ProcMemInfo::Smaps(const std::string& path) {
     if (!maps_.empty()) {
         return maps_;
@@ -213,29 +221,30 @@
     std::string pagemap_file = ::android::base::StringPrintf("/proc/%d/pagemap", pid_);
     ::android::base::unique_fd pagemap_fd(
             TEMP_FAILURE_RETRY(open(pagemap_file.c_str(), O_RDONLY | O_CLOEXEC)));
-    if (pagemap_fd < 0) {
+    if (pagemap_fd == -1) {
         PLOG(ERROR) << "Failed to open " << pagemap_file;
         return false;
     }
 
     uint64_t nr_pages = (vma.end - vma.start) / getpagesize();
-    pagemap->reserve(nr_pages);
+    pagemap->resize(nr_pages);
 
-    uint64_t idx = vma.start / getpagesize();
-    uint64_t last = idx + nr_pages;
-    uint64_t val;
-    for (; idx < last; idx++) {
-        if (pread64(pagemap_fd, &val, sizeof(uint64_t), idx * sizeof(uint64_t)) < 0) {
-            PLOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_;
-            return false;
-        }
-        pagemap->emplace_back(val);
+    size_t bytes_to_read = sizeof(uint64_t) * nr_pages;
+    off64_t start_addr = (vma.start / getpagesize()) * sizeof(uint64_t);
+    ssize_t bytes_read = pread64(pagemap_fd, pagemap->data(), bytes_to_read, start_addr);
+    if (bytes_read == -1) {
+        PLOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_;
+        return false;
+    } else if (static_cast<size_t>(bytes_read) != bytes_to_read) {
+        LOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_
+                   << ": read bytes " << bytes_read << " expected bytes " << bytes_to_read;
+        return false;
     }
 
     return true;
 }
 
-bool ProcMemInfo::ReadMaps(bool get_wss, bool use_pageidle) {
+bool ProcMemInfo::ReadMaps(bool get_wss, bool use_pageidle, bool get_usage_stats) {
     // Each object reads /proc/<pid>/maps only once. This is done to make sure programs that are
     // running for the lifetime of the system can recycle the objects and don't have to
     // unnecessarily retain and update this object in memory (which can get significantly large).
@@ -256,6 +265,10 @@
         return false;
     }
 
+    if (!get_usage_stats) {
+        return true;
+    }
+
     std::string pagemap_file = ::android::base::StringPrintf("/proc/%d/pagemap", pid_);
     ::android::base::unique_fd pagemap_fd(
             TEMP_FAILURE_RETRY(open(pagemap_file.c_str(), O_RDONLY | O_CLOEXEC)));
@@ -312,12 +325,12 @@
                                     cur_page * sizeof(uint64_t));
             if (bytes != total_bytes) {
                 if (bytes == -1) {
-                    PLOG(ERROR) << "Failed to read page data at offset "
+                    PLOG(ERROR) << "Failed to read page data at offset 0x" << std::hex
                                 << cur_page * sizeof(uint64_t);
                 } else {
-                    LOG(ERROR) << "Failed to read page data at offset "
-                               << cur_page * sizeof(uint64_t) << " read bytes " << sizeof(uint64_t)
-                               << " expected bytes " << bytes;
+                    LOG(ERROR) << "Failed to read page data at offset 0x" << std::hex
+                               << cur_page * sizeof(uint64_t) << std::dec << " read bytes " << bytes
+                               << " expected bytes " << total_bytes;
                 }
                 return false;
             }
diff --git a/libmeminfo/tools/Android.bp b/libmeminfo/tools/Android.bp
index 2e89c41..3968c09 100644
--- a/libmeminfo/tools/Android.bp
+++ b/libmeminfo/tools/Android.bp
@@ -56,6 +56,7 @@
 
 cc_binary {
     name: "showmap",
+    host_supported: true,
     cflags: [
         "-Wall",
         "-Werror",
@@ -66,6 +67,12 @@
         "libbase",
         "libmeminfo",
     ],
+
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
 }
 
 cc_binary {
diff --git a/libmeminfo/tools/showmap.cpp b/libmeminfo/tools/showmap.cpp
index a80fa76..8ea2108 100644
--- a/libmeminfo/tools/showmap.cpp
+++ b/libmeminfo/tools/showmap.cpp
@@ -18,6 +18,7 @@
 #include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/signal.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -56,7 +57,7 @@
 static VmaInfo g_total;
 static std::vector<VmaInfo> g_vmas;
 
-[[noreturn]] static void usage(int exit_status) {
+[[noreturn]] static void usage(const char* progname, int exit_status) {
     fprintf(stderr,
             "%s [-aqtv] [-f FILE] PID\n"
             "-a\taddresses (show virtual memory map)\n"
@@ -64,7 +65,7 @@
             "-t\tterse (show only items with private pages)\n"
             "-v\tverbose (don't coalesce maps with the same name)\n"
             "-f\tFILE (read from input from FILE instead of PID)\n",
-            getprogname());
+            progname);
 
     exit(exit_status);
 }
@@ -239,22 +240,22 @@
                 g_filename = optarg;
                 break;
             case 'h':
-                usage(EXIT_SUCCESS);
+                usage(argv[0], EXIT_SUCCESS);
             default:
-                usage(EXIT_FAILURE);
+                usage(argv[0], EXIT_FAILURE);
         }
     }
 
     if (g_filename.empty()) {
         if ((argc - 1) < optind) {
             fprintf(stderr, "Invalid arguments: Must provide <pid> at the end\n");
-            usage(EXIT_FAILURE);
+            usage(argv[0], EXIT_FAILURE);
         }
 
         g_pid = atoi(argv[optind]);
         if (g_pid <= 0) {
             fprintf(stderr, "Invalid process id %s\n", argv[optind]);
-            usage(EXIT_FAILURE);
+            usage(argv[0], EXIT_FAILURE);
         }
 
         g_filename = ::android::base::StringPrintf("/proc/%d/smaps", g_pid);
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index debc43f..b860db9 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -70,3 +70,27 @@
     host_supported: true,
     export_include_dirs: ["include"],
 }
+
+cc_test {
+    name: "libnativeloader_test",
+    srcs: [
+        "native_loader_test.cpp",
+        "native_loader.cpp",
+        "library_namespaces.cpp",
+        "native_loader_namespace.cpp",
+        "public_libraries.cpp",
+    ],
+    cflags: ["-DANDROID"],
+    static_libs: [
+        "libbase",
+        "liblog",
+        "libnativehelper",
+        "libgmock",
+    ],
+    header_libs: [
+        "libnativebridge-headers",
+        "libnativeloader-headers",
+    ],
+    system_shared_libs: ["libc", "libm"],
+    test_suites: ["device-tests"],
+}
diff --git a/libnativeloader/TEST_MAPPING b/libnativeloader/TEST_MAPPING
new file mode 100644
index 0000000..7becb77
--- /dev/null
+++ b/libnativeloader/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "libnativeloader_test"
+    }
+  ],
+  "imports": [
+    {
+      "path": "cts/tests/tests/jni"
+    }
+  ]
+}
diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp
index f7f972f..c22ce8a 100644
--- a/libnativeloader/library_namespaces.cpp
+++ b/libnativeloader/library_namespaces.cpp
@@ -43,6 +43,7 @@
 constexpr const char* kVendorNamespaceName = "sphal";
 constexpr const char* kVndkNamespaceName = "vndk";
 constexpr const char* kRuntimeNamespaceName = "runtime";
+constexpr const char* kNeuralNetworksNamespaceName = "neuralnetworks";
 
 // classloader-namespace is a linker namespace that is created for the loaded
 // app. To be specific, it is created for the app classloader. When
@@ -238,6 +239,14 @@
     }
   }
 
+  // Give access to NNAPI libraries (apex-updated LLNDK library).
+  auto nnapi_ns =
+      NativeLoaderNamespace::GetExportedNamespace(kNeuralNetworksNamespaceName, is_bridged);
+  if (!app_ns.Link(nnapi_ns, neuralnetworks_public_libraries())) {
+    *error_msg = app_ns.GetError();
+    return nullptr;
+  }
+
   // Give access to VNDK-SP libraries from the 'vndk' namespace.
   if (unbundled_vendor_or_product_app && !vndksp_libraries().empty()) {
     auto vndk_ns = NativeLoaderNamespace::GetExportedNamespace(kVndkNamespaceName, is_bridged);
diff --git a/libnativeloader/library_namespaces.h b/libnativeloader/library_namespaces.h
index fd46cdc..6e9a190 100644
--- a/libnativeloader/library_namespaces.h
+++ b/libnativeloader/library_namespaces.h
@@ -42,7 +42,10 @@
   LibraryNamespaces& operator=(const LibraryNamespaces&) = delete;
 
   void Initialize();
-  void Reset() { namespaces_.clear(); }
+  void Reset() {
+    namespaces_.clear();
+    initialized_ = false;
+  }
   NativeLoaderNamespace* Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader,
                                 bool is_shared, jstring dex_path, jstring java_library_path,
                                 jstring java_permitted_path, std::string* error_msg);
diff --git a/libnativeloader/native_loader_test.cpp b/libnativeloader/native_loader_test.cpp
new file mode 100644
index 0000000..614188b
--- /dev/null
+++ b/libnativeloader/native_loader_test.cpp
@@ -0,0 +1,566 @@
+/*
+ * 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 <dlfcn.h>
+#include <memory>
+#include <unordered_map>
+
+#include <android-base/strings.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <jni.h>
+
+#include "native_loader_namespace.h"
+#include "nativeloader/dlext_namespaces.h"
+#include "nativeloader/native_loader.h"
+#include "public_libraries.h"
+
+using namespace ::testing;
+
+namespace android {
+namespace nativeloader {
+
+// gmock interface that represents interested platform APIs on libdl and libnativebridge
+class Platform {
+ public:
+  virtual ~Platform() {}
+
+  // libdl APIs
+  virtual void* dlopen(const char* filename, int flags) = 0;
+  virtual int dlclose(void* handle) = 0;
+  virtual char* dlerror(void) = 0;
+
+  // These mock_* are the APIs semantically the same across libdl and libnativebridge.
+  // Instead of having two set of mock APIs for the two, define only one set with an additional
+  // argument 'bool bridged' to identify the context (i.e., called for libdl or libnativebridge).
+  typedef char* mock_namespace_handle;
+  virtual bool mock_init_anonymous_namespace(bool bridged, const char* sonames,
+                                             const char* search_paths) = 0;
+  virtual mock_namespace_handle mock_create_namespace(
+      bool bridged, const char* name, const char* ld_library_path, const char* default_library_path,
+      uint64_t type, const char* permitted_when_isolated_path, mock_namespace_handle parent) = 0;
+  virtual bool mock_link_namespaces(bool bridged, mock_namespace_handle from,
+                                    mock_namespace_handle to, const char* sonames) = 0;
+  virtual mock_namespace_handle mock_get_exported_namespace(bool bridged, const char* name) = 0;
+  virtual void* mock_dlopen_ext(bool bridged, const char* filename, int flags,
+                                mock_namespace_handle ns) = 0;
+
+  // libnativebridge APIs for which libdl has no corresponding APIs
+  virtual bool NativeBridgeInitialized() = 0;
+  virtual const char* NativeBridgeGetError() = 0;
+  virtual bool NativeBridgeIsPathSupported(const char*) = 0;
+  virtual bool NativeBridgeIsSupported(const char*) = 0;
+
+  // To mock "ClassLoader Object.getParent()"
+  virtual const char* JniObject_getParent(const char*) = 0;
+};
+
+// The mock does not actually create a namespace object. But simply casts the pointer to the
+// string for the namespace name as the handle to the namespace object.
+#define TO_ANDROID_NAMESPACE(str) \
+  reinterpret_cast<struct android_namespace_t*>(const_cast<char*>(str))
+
+#define TO_BRIDGED_NAMESPACE(str) \
+  reinterpret_cast<struct native_bridge_namespace_t*>(const_cast<char*>(str))
+
+#define TO_MOCK_NAMESPACE(ns) reinterpret_cast<Platform::mock_namespace_handle>(ns)
+
+// These represents built-in namespaces created by the linker according to ld.config.txt
+static std::unordered_map<std::string, Platform::mock_namespace_handle> namespaces = {
+    {"platform", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("platform"))},
+    {"default", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("default"))},
+    {"runtime", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("runtime"))},
+    {"sphal", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("sphal"))},
+    {"vndk", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("vndk"))},
+};
+
+// The actual gmock object
+class MockPlatform : public Platform {
+ public:
+  MockPlatform(bool is_bridged) : is_bridged_(is_bridged) {
+    ON_CALL(*this, NativeBridgeIsSupported(_)).WillByDefault(Return(is_bridged_));
+    ON_CALL(*this, NativeBridgeIsPathSupported(_)).WillByDefault(Return(is_bridged_));
+    ON_CALL(*this, mock_get_exported_namespace(_, _))
+        .WillByDefault(Invoke([](bool, const char* name) -> mock_namespace_handle {
+          if (namespaces.find(name) != namespaces.end()) {
+            return namespaces[name];
+          }
+          return nullptr;
+        }));
+  }
+
+  // Mocking libdl APIs
+  MOCK_METHOD2(dlopen, void*(const char*, int));
+  MOCK_METHOD1(dlclose, int(void*));
+  MOCK_METHOD0(dlerror, char*());
+
+  // Mocking the common APIs
+  MOCK_METHOD3(mock_init_anonymous_namespace, bool(bool, const char*, const char*));
+  MOCK_METHOD7(mock_create_namespace,
+               mock_namespace_handle(bool, const char*, const char*, const char*, uint64_t,
+                                     const char*, mock_namespace_handle));
+  MOCK_METHOD4(mock_link_namespaces,
+               bool(bool, mock_namespace_handle, mock_namespace_handle, const char*));
+  MOCK_METHOD2(mock_get_exported_namespace, mock_namespace_handle(bool, const char*));
+  MOCK_METHOD4(mock_dlopen_ext, void*(bool, const char*, int, mock_namespace_handle));
+
+  // Mocking libnativebridge APIs
+  MOCK_METHOD0(NativeBridgeInitialized, bool());
+  MOCK_METHOD0(NativeBridgeGetError, const char*());
+  MOCK_METHOD1(NativeBridgeIsPathSupported, bool(const char*));
+  MOCK_METHOD1(NativeBridgeIsSupported, bool(const char*));
+
+  // Mocking "ClassLoader Object.getParent()"
+  MOCK_METHOD1(JniObject_getParent, const char*(const char*));
+
+ private:
+  bool is_bridged_;
+};
+
+static std::unique_ptr<MockPlatform> mock;
+
+// Provide C wrappers for the mock object.
+extern "C" {
+void* dlopen(const char* file, int flag) {
+  return mock->dlopen(file, flag);
+}
+
+int dlclose(void* handle) {
+  return mock->dlclose(handle);
+}
+
+char* dlerror(void) {
+  return mock->dlerror();
+}
+
+bool android_init_anonymous_namespace(const char* sonames, const char* search_path) {
+  return mock->mock_init_anonymous_namespace(false, sonames, search_path);
+}
+
+struct android_namespace_t* android_create_namespace(const char* name, const char* ld_library_path,
+                                                     const char* default_library_path,
+                                                     uint64_t type,
+                                                     const char* permitted_when_isolated_path,
+                                                     struct android_namespace_t* parent) {
+  return TO_ANDROID_NAMESPACE(
+      mock->mock_create_namespace(false, name, ld_library_path, default_library_path, type,
+                                  permitted_when_isolated_path, TO_MOCK_NAMESPACE(parent)));
+}
+
+bool android_link_namespaces(struct android_namespace_t* from, struct android_namespace_t* to,
+                             const char* sonames) {
+  return mock->mock_link_namespaces(false, TO_MOCK_NAMESPACE(from), TO_MOCK_NAMESPACE(to), sonames);
+}
+
+struct android_namespace_t* android_get_exported_namespace(const char* name) {
+  return TO_ANDROID_NAMESPACE(mock->mock_get_exported_namespace(false, name));
+}
+
+void* android_dlopen_ext(const char* filename, int flags, const android_dlextinfo* info) {
+  return mock->mock_dlopen_ext(false, filename, flags, TO_MOCK_NAMESPACE(info->library_namespace));
+}
+
+// libnativebridge APIs
+bool NativeBridgeIsSupported(const char* libpath) {
+  return mock->NativeBridgeIsSupported(libpath);
+}
+
+struct native_bridge_namespace_t* NativeBridgeGetExportedNamespace(const char* name) {
+  return TO_BRIDGED_NAMESPACE(mock->mock_get_exported_namespace(true, name));
+}
+
+struct native_bridge_namespace_t* NativeBridgeCreateNamespace(
+    const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type,
+    const char* permitted_when_isolated_path, struct native_bridge_namespace_t* parent) {
+  return TO_BRIDGED_NAMESPACE(
+      mock->mock_create_namespace(true, name, ld_library_path, default_library_path, type,
+                                  permitted_when_isolated_path, TO_MOCK_NAMESPACE(parent)));
+}
+
+bool NativeBridgeLinkNamespaces(struct native_bridge_namespace_t* from,
+                                struct native_bridge_namespace_t* to, const char* sonames) {
+  return mock->mock_link_namespaces(true, TO_MOCK_NAMESPACE(from), TO_MOCK_NAMESPACE(to), sonames);
+}
+
+void* NativeBridgeLoadLibraryExt(const char* libpath, int flag,
+                                 struct native_bridge_namespace_t* ns) {
+  return mock->mock_dlopen_ext(true, libpath, flag, TO_MOCK_NAMESPACE(ns));
+}
+
+bool NativeBridgeInitialized() {
+  return mock->NativeBridgeInitialized();
+}
+
+bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
+                                        const char* anon_ns_library_path) {
+  return mock->mock_init_anonymous_namespace(true, public_ns_sonames, anon_ns_library_path);
+}
+
+const char* NativeBridgeGetError() {
+  return mock->NativeBridgeGetError();
+}
+
+bool NativeBridgeIsPathSupported(const char* path) {
+  return mock->NativeBridgeIsPathSupported(path);
+}
+
+}  // extern "C"
+
+// A very simple JNI mock.
+// jstring is a pointer to utf8 char array. We don't need utf16 char here.
+// jobject, jclass, and jmethodID are also a pointer to utf8 char array
+// Only a few JNI methods that are actually used in libnativeloader are mocked.
+JNINativeInterface* CreateJNINativeInterface() {
+  JNINativeInterface* inf = new JNINativeInterface();
+  memset(inf, 0, sizeof(JNINativeInterface));
+
+  inf->GetStringUTFChars = [](JNIEnv*, jstring s, jboolean*) -> const char* {
+    return reinterpret_cast<const char*>(s);
+  };
+
+  inf->ReleaseStringUTFChars = [](JNIEnv*, jstring, const char*) -> void { return; };
+
+  inf->NewStringUTF = [](JNIEnv*, const char* bytes) -> jstring {
+    return reinterpret_cast<jstring>(const_cast<char*>(bytes));
+  };
+
+  inf->FindClass = [](JNIEnv*, const char* name) -> jclass {
+    return reinterpret_cast<jclass>(const_cast<char*>(name));
+  };
+
+  inf->CallObjectMethodV = [](JNIEnv*, jobject obj, jmethodID mid, va_list) -> jobject {
+    if (strcmp("getParent", reinterpret_cast<const char*>(mid)) == 0) {
+      // JniObject_getParent can be a valid jobject or nullptr if there is
+      // no parent classloader.
+      const char* ret = mock->JniObject_getParent(reinterpret_cast<const char*>(obj));
+      return reinterpret_cast<jobject>(const_cast<char*>(ret));
+    }
+    return nullptr;
+  };
+
+  inf->GetMethodID = [](JNIEnv*, jclass, const char* name, const char*) -> jmethodID {
+    return reinterpret_cast<jmethodID>(const_cast<char*>(name));
+  };
+
+  inf->NewWeakGlobalRef = [](JNIEnv*, jobject obj) -> jobject { return obj; };
+
+  inf->IsSameObject = [](JNIEnv*, jobject a, jobject b) -> jboolean {
+    return strcmp(reinterpret_cast<const char*>(a), reinterpret_cast<const char*>(b)) == 0;
+  };
+
+  return inf;
+}
+
+static void* const any_nonnull = reinterpret_cast<void*>(0x12345678);
+
+// Custom matcher for comparing namespace handles
+MATCHER_P(NsEq, other, "") {
+  *result_listener << "comparing " << reinterpret_cast<const char*>(arg) << " and " << other;
+  return strcmp(reinterpret_cast<const char*>(arg), reinterpret_cast<const char*>(other)) == 0;
+}
+
+/////////////////////////////////////////////////////////////////
+
+// Test fixture
+class NativeLoaderTest : public ::testing::TestWithParam<bool> {
+ protected:
+  bool IsBridged() { return GetParam(); }
+
+  void SetUp() override {
+    mock = std::make_unique<NiceMock<MockPlatform>>(IsBridged());
+
+    env = std::make_unique<JNIEnv>();
+    env->functions = CreateJNINativeInterface();
+  }
+
+  void SetExpectations() {
+    std::vector<std::string> default_public_libs =
+        android::base::Split(default_public_libraries(), ":");
+    for (auto l : default_public_libs) {
+      EXPECT_CALL(*mock, dlopen(StrEq(l.c_str()), RTLD_NOW | RTLD_NODELETE))
+          .WillOnce(Return(any_nonnull));
+    }
+  }
+
+  void RunTest() { InitializeNativeLoader(); }
+
+  void TearDown() override {
+    ResetNativeLoader();
+    delete env->functions;
+    mock.reset();
+  }
+
+  std::unique_ptr<JNIEnv> env;
+};
+
+/////////////////////////////////////////////////////////////////
+
+TEST_P(NativeLoaderTest, InitializeLoadsDefaultPublicLibraries) {
+  SetExpectations();
+  RunTest();
+}
+
+INSTANTIATE_TEST_SUITE_P(NativeLoaderTests, NativeLoaderTest, testing::Bool());
+
+/////////////////////////////////////////////////////////////////
+
+class NativeLoaderTest_Create : public NativeLoaderTest {
+ protected:
+  // Test inputs (initialized to the default values). Overriding these
+  // must be done before calling SetExpectations() and RunTest().
+  uint32_t target_sdk_version = 29;
+  std::string class_loader = "my_classloader";
+  bool is_shared = false;
+  std::string dex_path = "/data/app/foo/classes.dex";
+  std::string library_path = "/data/app/foo/lib/arm";
+  std::string permitted_path = "/data/app/foo/lib";
+
+  // expected output (.. for the default test inputs)
+  std::string expected_namespace_name = "classloader-namespace";
+  uint64_t expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
+  std::string expected_library_path = library_path;
+  std::string expected_permitted_path = std::string("/data:/mnt/expand:") + permitted_path;
+  std::string expected_parent_namespace = "platform";
+  bool expected_link_with_platform_ns = true;
+  bool expected_link_with_runtime_ns = true;
+  bool expected_link_with_sphal_ns = !vendor_public_libraries().empty();
+  bool expected_link_with_vndk_ns = false;
+  bool expected_link_with_default_ns = false;
+  std::string expected_shared_libs_to_platform_ns = default_public_libraries();
+  std::string expected_shared_libs_to_runtime_ns = runtime_public_libraries();
+  std::string expected_shared_libs_to_sphal_ns = vendor_public_libraries();
+  std::string expected_shared_libs_to_vndk_ns = vndksp_libraries();
+  std::string expected_shared_libs_to_default_ns = default_public_libraries();
+
+  void SetExpectations() {
+    NativeLoaderTest::SetExpectations();
+
+    ON_CALL(*mock, JniObject_getParent(StrEq(class_loader))).WillByDefault(Return(nullptr));
+
+    EXPECT_CALL(*mock, NativeBridgeIsPathSupported(_)).Times(AnyNumber());
+    EXPECT_CALL(*mock, NativeBridgeInitialized()).Times(AnyNumber());
+
+    if (IsBridged()) {
+      EXPECT_CALL(*mock,
+                  mock_init_anonymous_namespace(false, StrEq(default_public_libraries()), nullptr))
+          .WillOnce(Return(true));
+
+      EXPECT_CALL(*mock, NativeBridgeInitialized()).WillOnce(Return(true));
+    }
+
+    EXPECT_CALL(*mock, mock_init_anonymous_namespace(
+                           Eq(IsBridged()), StrEq(default_public_libraries()), StrEq(library_path)))
+        .WillOnce(Return(true));
+    EXPECT_CALL(*mock, mock_create_namespace(
+                           Eq(IsBridged()), StrEq(expected_namespace_name), nullptr,
+                           StrEq(expected_library_path), expected_namespace_flags,
+                           StrEq(expected_permitted_path), NsEq(expected_parent_namespace.c_str())))
+        .WillOnce(Return(TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(dex_path.c_str()))));
+    if (expected_link_with_platform_ns) {
+      EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("platform"),
+                                              StrEq(expected_shared_libs_to_platform_ns)))
+          .WillOnce(Return(true));
+    }
+    if (expected_link_with_runtime_ns) {
+      EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("runtime"),
+                                              StrEq(expected_shared_libs_to_runtime_ns)))
+          .WillOnce(Return(true));
+    }
+    if (expected_link_with_sphal_ns) {
+      EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("sphal"),
+                                              StrEq(expected_shared_libs_to_sphal_ns)))
+          .WillOnce(Return(true));
+    }
+    if (expected_link_with_vndk_ns) {
+      EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("vndk"),
+                                              StrEq(expected_shared_libs_to_vndk_ns)))
+          .WillOnce(Return(true));
+    }
+    if (expected_link_with_default_ns) {
+      EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("default"),
+                                              StrEq(expected_shared_libs_to_default_ns)))
+          .WillOnce(Return(true));
+    }
+  }
+
+  void RunTest() {
+    NativeLoaderTest::RunTest();
+
+    jstring err = CreateClassLoaderNamespace(
+        env(), target_sdk_version, env()->NewStringUTF(class_loader.c_str()), is_shared,
+        env()->NewStringUTF(dex_path.c_str()), env()->NewStringUTF(library_path.c_str()),
+        env()->NewStringUTF(permitted_path.c_str()));
+
+    // no error
+    EXPECT_EQ(err, nullptr);
+
+    if (!IsBridged()) {
+      struct android_namespace_t* ns =
+          FindNamespaceByClassLoader(env(), env()->NewStringUTF(class_loader.c_str()));
+
+      // The created namespace is for this apk
+      EXPECT_EQ(dex_path.c_str(), reinterpret_cast<const char*>(ns));
+    } else {
+      struct NativeLoaderNamespace* ns =
+          FindNativeLoaderNamespaceByClassLoader(env(), env()->NewStringUTF(class_loader.c_str()));
+
+      // The created namespace is for the this apk
+      EXPECT_STREQ(dex_path.c_str(),
+                   reinterpret_cast<const char*>(ns->ToRawNativeBridgeNamespace()));
+    }
+  }
+
+  JNIEnv* env() { return NativeLoaderTest::env.get(); }
+};
+
+TEST_P(NativeLoaderTest_Create, DownloadedApp) {
+  SetExpectations();
+  RunTest();
+}
+
+TEST_P(NativeLoaderTest_Create, BundledSystemApp) {
+  dex_path = "/system/app/foo/foo.apk";
+  is_shared = true;
+
+  expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED;
+  SetExpectations();
+  RunTest();
+}
+
+TEST_P(NativeLoaderTest_Create, BundledVendorApp) {
+  dex_path = "/vendor/app/foo/foo.apk";
+  is_shared = true;
+
+  expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED;
+  SetExpectations();
+  RunTest();
+}
+
+TEST_P(NativeLoaderTest_Create, UnbundledVendorApp) {
+  dex_path = "/vendor/app/foo/foo.apk";
+  is_shared = false;
+
+  expected_namespace_name = "vendor-classloader-namespace";
+  expected_library_path = expected_library_path + ":/vendor/lib";
+  expected_permitted_path = expected_permitted_path + ":/vendor/lib";
+  expected_shared_libs_to_platform_ns =
+      expected_shared_libs_to_platform_ns + ":" + llndk_libraries();
+  expected_link_with_vndk_ns = true;
+  SetExpectations();
+  RunTest();
+}
+
+TEST_P(NativeLoaderTest_Create, BundledProductApp_pre30) {
+  dex_path = "/product/app/foo/foo.apk";
+  is_shared = true;
+
+  expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED;
+  SetExpectations();
+  RunTest();
+}
+
+TEST_P(NativeLoaderTest_Create, BundledProductApp_post30) {
+  dex_path = "/product/app/foo/foo.apk";
+  is_shared = true;
+  target_sdk_version = 30;
+
+  expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED;
+  SetExpectations();
+  RunTest();
+}
+
+TEST_P(NativeLoaderTest_Create, UnbundledProductApp_pre30) {
+  dex_path = "/product/app/foo/foo.apk";
+  is_shared = false;
+  SetExpectations();
+  RunTest();
+}
+
+TEST_P(NativeLoaderTest_Create, UnbundledProductApp_post30) {
+  dex_path = "/product/app/foo/foo.apk";
+  is_shared = false;
+  target_sdk_version = 30;
+
+  expected_namespace_name = "vendor-classloader-namespace";
+  expected_library_path = expected_library_path + ":/product/lib:/system/product/lib";
+  expected_permitted_path = expected_permitted_path + ":/product/lib:/system/product/lib";
+  expected_shared_libs_to_platform_ns =
+      expected_shared_libs_to_platform_ns + ":" + llndk_libraries();
+  expected_link_with_vndk_ns = true;
+  SetExpectations();
+  RunTest();
+}
+
+TEST_P(NativeLoaderTest_Create, TwoApks) {
+  SetExpectations();
+  const uint32_t second_app_target_sdk_version = 29;
+  const std::string second_app_class_loader = "second_app_classloader";
+  const bool second_app_is_shared = false;
+  const std::string second_app_dex_path = "/data/app/bar/classes.dex";
+  const std::string second_app_library_path = "/data/app/bar/lib/arm";
+  const std::string second_app_permitted_path = "/data/app/bar/lib";
+  const std::string expected_second_app_permitted_path =
+      std::string("/data:/mnt/expand:") + second_app_permitted_path;
+  const std::string expected_second_app_parent_namespace = "classloader-namespace";
+
+  // The scenario is that second app is loaded by the first app.
+  // So the first app's classloader (`classloader`) is parent of the second
+  // app's classloader.
+  ON_CALL(*mock, JniObject_getParent(StrEq(second_app_class_loader)))
+      .WillByDefault(Return(class_loader.c_str()));
+
+  // namespace for the second app is created. Its parent is set to the namespace
+  // of the first app.
+  EXPECT_CALL(*mock, mock_create_namespace(Eq(IsBridged()), StrEq(expected_namespace_name), nullptr,
+                                           StrEq(second_app_library_path), expected_namespace_flags,
+                                           StrEq(expected_second_app_permitted_path),
+                                           NsEq(dex_path.c_str())))
+      .WillOnce(Return(TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(second_app_dex_path.c_str()))));
+  EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), NsEq(second_app_dex_path.c_str()), _, _))
+      .WillRepeatedly(Return(true));
+
+  RunTest();
+  jstring err = CreateClassLoaderNamespace(
+      env(), second_app_target_sdk_version, env()->NewStringUTF(second_app_class_loader.c_str()),
+      second_app_is_shared, env()->NewStringUTF(second_app_dex_path.c_str()),
+      env()->NewStringUTF(second_app_library_path.c_str()),
+      env()->NewStringUTF(second_app_permitted_path.c_str()));
+
+  // success
+  EXPECT_EQ(err, nullptr);
+
+  if (!IsBridged()) {
+    struct android_namespace_t* ns =
+        FindNamespaceByClassLoader(env(), env()->NewStringUTF(second_app_class_loader.c_str()));
+
+    // The created namespace is for the second apk
+    EXPECT_EQ(second_app_dex_path.c_str(), reinterpret_cast<const char*>(ns));
+  } else {
+    struct NativeLoaderNamespace* ns = FindNativeLoaderNamespaceByClassLoader(
+        env(), env()->NewStringUTF(second_app_class_loader.c_str()));
+
+    // The created namespace is for the second apk
+    EXPECT_STREQ(second_app_dex_path.c_str(),
+                 reinterpret_cast<const char*>(ns->ToRawNativeBridgeNamespace()));
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(NativeLoaderTests_Create, NativeLoaderTest_Create, testing::Bool());
+
+// TODO(b/130388701#comment22) add a test for anonymous namespace
+
+}  // namespace nativeloader
+}  // namespace android
diff --git a/libnativeloader/public_libraries.cpp b/libnativeloader/public_libraries.cpp
index c205eb1..10e23fd 100644
--- a/libnativeloader/public_libraries.cpp
+++ b/libnativeloader/public_libraries.cpp
@@ -51,6 +51,8 @@
 
 constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/" LIB;
 
+constexpr const char* kNeuralNetworksApexPublicLibrary = "libneuralnetworks.so";
+
 // TODO(b/130388701): do we need this?
 std::string root_dir() {
   static const char* android_root_env = getenv("ANDROID_ROOT");
@@ -219,6 +221,12 @@
       sonames.erase(it);
     }
   }
+
+  // Remove the public libs in the nnapi namespace.
+  auto it = std::find(sonames.begin(), sonames.end(), kNeuralNetworksApexPublicLibrary);
+  if (it != sonames.end()) {
+    sonames.erase(it);
+  }
   return android::base::Join(sonames, ':');
 }
 
@@ -267,6 +275,10 @@
   return android::base::Join(sonames, ':');
 }
 
+static std::string InitNeuralNetworksPublicLibraries() {
+  return kNeuralNetworksApexPublicLibrary;
+}
+
 }  // namespace
 
 const std::string& default_public_libraries() {
@@ -289,6 +301,11 @@
   return list;
 }
 
+const std::string& neuralnetworks_public_libraries() {
+  static std::string list = InitNeuralNetworksPublicLibraries();
+  return list;
+}
+
 const std::string& llndk_libraries() {
   static std::string list = InitLlndkLibraries();
   return list;
diff --git a/libnativeloader/public_libraries.h b/libnativeloader/public_libraries.h
index 9b6dea8..9bb3366 100644
--- a/libnativeloader/public_libraries.h
+++ b/libnativeloader/public_libraries.h
@@ -26,6 +26,7 @@
 const std::string& runtime_public_libraries();
 const std::string& vendor_public_libraries();
 const std::string& extended_public_libraries();
+const std::string& neuralnetworks_public_libraries();
 const std::string& llndk_libraries();
 const std::string& vndksp_libraries();
 
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 5423de5..73237e6 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -125,10 +125,6 @@
         },
     },
 
-    whole_static_libs: [
-        "libdemangle"
-    ],
-
     static_libs: [
         "libprocinfo",
     ],
@@ -162,6 +158,7 @@
 cc_test {
     name: "libunwindstack_test",
     defaults: ["libunwindstack_flags"],
+    isolated: true,
 
     srcs: [
         "tests/ArmExidxDecodeTest.cpp",
@@ -184,6 +181,7 @@
         "tests/ElfInterfaceTest.cpp",
         "tests/ElfTest.cpp",
         "tests/ElfTestUtils.cpp",
+        "tests/IsolatedSettings.cpp",
         "tests/JitDebugTest.cpp",
         "tests/LocalUnwinderTest.cpp",
         "tests/LogFake.cpp",
@@ -246,6 +244,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/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index c95f852..7556482 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -27,8 +27,6 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 
-#include <demangle.h>
-
 #include <unwindstack/Elf.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/MapInfo.h>
@@ -40,6 +38,9 @@
 #include <unwindstack/DexFiles.h>
 #endif
 
+// Use the demangler from libc++.
+extern "C" char* __cxa_demangle(const char*, char*, size_t*, int* status);
+
 namespace unwindstack {
 
 // Inject extra 'virtual' frame that represents the dex pc data.
@@ -330,7 +331,14 @@
   }
 
   if (!frame.function_name.empty()) {
-    data += " (" + demangle(frame.function_name.c_str());
+    char* demangled_name = __cxa_demangle(frame.function_name.c_str(), nullptr, nullptr, nullptr);
+    if (demangled_name == nullptr) {
+      data += " (" + frame.function_name;
+    } else {
+      data += " (";
+      data += demangled_name;
+      free(demangled_name);
+    }
     if (frame.function_offset != 0) {
       data += android::base::StringPrintf("+%" PRId64, frame.function_offset);
     }
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/logd/LogBufferInterface.cpp b/libunwindstack/tests/IsolatedSettings.cpp
similarity index 60%
rename from logd/LogBufferInterface.cpp
rename to libunwindstack/tests/IsolatedSettings.cpp
index 4b6d363..dbd8bd6 100644
--- a/logd/LogBufferInterface.cpp
+++ b/libunwindstack/tests/IsolatedSettings.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -14,16 +14,13 @@
  * limitations under the License.
  */
 
-#include "LogBufferInterface.h"
-#include "LogUtils.h"
+#include <stdint.h>
+#include <stdio.h>
 
-LogBufferInterface::LogBufferInterface() {
-}
-LogBufferInterface::~LogBufferInterface() {
-}
-uid_t LogBufferInterface::pidToUid(pid_t pid) {
-    return android::pidToUid(pid);
-}
-pid_t LogBufferInterface::tidToPid(pid_t tid) {
-    return android::tidToPid(tid);
+extern "C" bool GetInitialArgs(const char*** args, size_t* num_args) {
+  static const char* initial_args[2] = {"--slow_threshold_ms=90000",
+                                        "--deadline_threshold_ms=120000"};
+  *args = initial_args;
+  *num_args = 2;
+  return true;
 }
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 5b4ca7c..6c1cfa2 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -58,7 +58,7 @@
     ASSERT_TRUE(android::base::WriteFully(fd, buffer.data(), buffer.size()));
   }
 
-  static void SetUpTestSuite() {
+  void SetUp() override {
     std::vector<uint8_t> buffer(12288, 0);
     memcpy(buffer.data(), ELFMAG, SELFMAG);
     buffer[EI_CLASS] = ELFCLASS32;
@@ -72,9 +72,7 @@
 
     InitElf<Elf32_Ehdr, Elf32_Shdr>(elf32_at_map_.fd, 0x1000, 0x2000, ELFCLASS32);
     InitElf<Elf64_Ehdr, Elf64_Shdr>(elf64_at_map_.fd, 0x2000, 0x3000, ELFCLASS64);
-  }
 
-  void SetUp() override {
     memory_ = new MemoryFake;
     process_memory_.reset(memory_);
   }
@@ -82,17 +80,13 @@
   MemoryFake* memory_;
   std::shared_ptr<Memory> process_memory_;
 
-  static TemporaryFile elf_;
+  TemporaryFile elf_;
 
-  static TemporaryFile elf_at_1000_;
+  TemporaryFile elf_at_1000_;
 
-  static TemporaryFile elf32_at_map_;
-  static TemporaryFile elf64_at_map_;
+  TemporaryFile elf32_at_map_;
+  TemporaryFile elf64_at_map_;
 };
-TemporaryFile MapInfoCreateMemoryTest::elf_;
-TemporaryFile MapInfoCreateMemoryTest::elf_at_1000_;
-TemporaryFile MapInfoCreateMemoryTest::elf32_at_map_;
-TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_;
 
 TEST_F(MapInfoCreateMemoryTest, end_le_start) {
   MapInfo info(nullptr, 0x100, 0x100, 0, 0, elf_.path);
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index baada82..bded57a 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -1457,4 +1457,81 @@
   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 "
+      "(bool "
+      "testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, "
+      "bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char "
+      "const*)+131)\n"
+      "  #11 pc 0000000000ee2a21  perfetto_unittests "
+      "(bool "
+      "testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, "
+      "bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char "
+      "const*)+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/String8.cpp b/libutils/String8.cpp
index 0025c56..d13548e 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -468,21 +468,6 @@
     unlockBuffer(len);
 }
 
-size_t String8::getUtf32Length() const
-{
-    return utf8_to_utf32_length(mString, length());
-}
-
-int32_t String8::getUtf32At(size_t index, size_t *next_index) const
-{
-    return utf32_from_utf8_at(mString, length(), index, next_index);
-}
-
-void String8::getUtf32(char32_t* dst) const
-{
-    utf8_to_utf32(mString, length(), dst);
-}
-
 // ---------------------------------------------------------------------------
 // Path functions
 
diff --git a/libutils/include/utils/LightRefBase.h b/libutils/include/utils/LightRefBase.h
index e488e60..b04e5c1 100644
--- a/libutils/include/utils/LightRefBase.h
+++ b/libutils/include/utils/LightRefBase.h
@@ -47,8 +47,6 @@
         return mCount.load(std::memory_order_relaxed);
     }
 
-    typedef LightRefBase<T> basetype;
-
 protected:
     inline ~LightRefBase() { }
 
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index a105474..42c6efb 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_)                                      \
@@ -299,8 +296,6 @@
         getWeakRefs()->trackMe(enable, retain); 
     }
 
-    typedef RefBase basetype;
-
 protected:
                             RefBase();
     virtual                 ~RefBase();
@@ -459,9 +454,6 @@
     weakref_type*   m_refs;
 };
 
-template <typename T>
-TextOutput& operator<<(TextOutput& to, const wp<T>& val);
-
 #undef COMPARE_WEAK
 
 // ---------------------------------------------------------------------------
@@ -635,12 +627,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/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index c8f584e..0ddcbb2 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -95,13 +95,6 @@
                     __attribute__((format (printf, 2, 3)));
             status_t            appendFormatV(const char* fmt, va_list args);
 
-            // Note that this function takes O(N) time to calculate the value.
-            // No cache value is stored.
-            size_t              getUtf32Length() const;
-            int32_t             getUtf32At(size_t index,
-                                           size_t *next_index) const;
-            void                getUtf32(char32_t* dst) const;
-
     inline  String8&            operator=(const String8& other);
     inline  String8&            operator=(const char* other);
 
diff --git a/libvndksupport/Android.bp b/libvndksupport/Android.bp
index e5b536c..f4544a1 100644
--- a/libvndksupport/Android.bp
+++ b/libvndksupport/Android.bp
@@ -3,7 +3,7 @@
 cc_library {
     name: "libvndksupport",
     native_bridge_supported: true,
-    srcs: ["linker.c"],
+    srcs: ["linker.cpp"],
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/libvndksupport/linker.c b/libvndksupport/linker.c
deleted file mode 100644
index 84c2132..0000000
--- a/libvndksupport/linker.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "linker.h"
-
-#include <android/dlext.h>
-#include <dlfcn.h>
-
-#define LOG_TAG "vndksupport"
-#include <log/log.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-__attribute__((weak)) extern struct android_namespace_t* android_get_exported_namespace(const char*);
-__attribute__((weak)) extern void* android_dlopen_ext(const char*, int, const android_dlextinfo*);
-
-static const char* namespace_name = NULL;
-
-static struct android_namespace_t* get_vendor_namespace() {
-    const char* namespace_names[] = {"sphal", "default", NULL};
-    static struct android_namespace_t* vendor_namespace = NULL;
-    if (vendor_namespace == NULL) {
-        int name_idx = 0;
-        while (namespace_names[name_idx] != NULL) {
-            if (android_get_exported_namespace != NULL) {
-                vendor_namespace = android_get_exported_namespace(namespace_names[name_idx]);
-            }
-            if (vendor_namespace != NULL) {
-                namespace_name = namespace_names[name_idx];
-                break;
-            }
-            name_idx++;
-        }
-    }
-    return vendor_namespace;
-}
-
-int android_is_in_vendor_process() {
-    // Special case init, since when init runs, ld.config.<ver>.txt hasn't been
-    // loaded (sysprop service isn't up for init to know <ver>).
-    if (getpid() == 1) {
-        return 0;
-    }
-    if (android_get_exported_namespace == NULL) {
-        ALOGD("android_get_exported_namespace() not available. Assuming system process.");
-        return 0;
-    }
-
-    // In vendor process, 'vndk' namespace is not visible, whereas in system
-    // process, it is.
-    return android_get_exported_namespace("vndk") == NULL;
-}
-
-void* android_load_sphal_library(const char* name, int flag) {
-    struct android_namespace_t* vendor_namespace = get_vendor_namespace();
-    if (vendor_namespace != NULL) {
-        const android_dlextinfo dlextinfo = {
-            .flags = ANDROID_DLEXT_USE_NAMESPACE, .library_namespace = vendor_namespace,
-        };
-        void* handle = NULL;
-        if (android_dlopen_ext != NULL) {
-            handle = android_dlopen_ext(name, flag, &dlextinfo);
-        }
-        if (!handle) {
-            ALOGE("Could not load %s from %s namespace: %s.", name, namespace_name, dlerror());
-        }
-        return handle;
-    } else {
-        ALOGD("Loading %s from current namespace instead of sphal namespace.", name);
-        return dlopen(name, flag);
-    }
-}
-
-int android_unload_sphal_library(void* handle) {
-    return dlclose(handle);
-}
diff --git a/libvndksupport/linker.cpp b/libvndksupport/linker.cpp
new file mode 100644
index 0000000..cf0f618
--- /dev/null
+++ b/libvndksupport/linker.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "vndksupport"
+
+#include "linker.h"
+
+#include <android/dlext.h>
+#include <dlfcn.h>
+#include <log/log.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <initializer_list>
+
+__attribute__((weak)) extern "C" android_namespace_t* android_get_exported_namespace(const char*);
+__attribute__((weak)) extern "C" void* android_dlopen_ext(const char*, int,
+                                                          const android_dlextinfo*);
+
+namespace {
+
+struct VendorNamespace {
+    android_namespace_t* ptr = nullptr;
+    const char* name = nullptr;
+};
+
+}  // anonymous namespace
+
+static VendorNamespace get_vendor_namespace() {
+    static VendorNamespace result = ([] {
+        for (const char* name : {"sphal", "default"}) {
+            if (android_get_exported_namespace != nullptr) {
+                if (android_namespace_t* ns = android_get_exported_namespace(name)) {
+                    return VendorNamespace{ns, name};
+                }
+            }
+        }
+        return VendorNamespace{};
+    })();
+    return result;
+}
+
+int android_is_in_vendor_process() {
+    // Special case init, since when init runs, ld.config.<ver>.txt hasn't been
+    // loaded (sysprop service isn't up for init to know <ver>).
+    if (getpid() == 1) {
+        return 0;
+    }
+    if (android_get_exported_namespace == nullptr) {
+        ALOGD("android_get_exported_namespace() not available. Assuming system process.");
+        return 0;
+    }
+
+    // In vendor process, 'vndk' namespace is not visible, whereas in system
+    // process, it is.
+    return android_get_exported_namespace("vndk") == nullptr;
+}
+
+void* android_load_sphal_library(const char* name, int flag) {
+    VendorNamespace vendor_namespace = get_vendor_namespace();
+    if (vendor_namespace.ptr != nullptr) {
+        const android_dlextinfo dlextinfo = {
+                .flags = ANDROID_DLEXT_USE_NAMESPACE,
+                .library_namespace = vendor_namespace.ptr,
+        };
+        void* handle = nullptr;
+        if (android_dlopen_ext != nullptr) {
+            handle = android_dlopen_ext(name, flag, &dlextinfo);
+        }
+        if (!handle) {
+            ALOGE("Could not load %s from %s namespace: %s.", name, vendor_namespace.name,
+                  dlerror());
+        }
+        return handle;
+    } else {
+        ALOGD("Loading %s from current namespace instead of sphal namespace.", name);
+        return dlopen(name, flag);
+    }
+}
+
+int android_unload_sphal_library(void* handle) {
+    return dlclose(handle);
+}
diff --git a/libvndksupport/tests/linker_test.cpp b/libvndksupport/tests/linker_test.cpp
index 7ce27d4..d0c8ef7 100644
--- a/libvndksupport/tests/linker_test.cpp
+++ b/libvndksupport/tests/linker_test.cpp
@@ -21,11 +21,6 @@
 #include <vndksupport/linker.h>
 #include <string>
 
-// Since the test executable will be in /data and ld.config.txt does not
-// configure sphal namespace for executables in /data, the call to
-// android_load_sphal_library will always fallback to the plain dlopen from the
-// default namespace.
-
 // Let's use libEGL_<chipset>.so as a SP-HAL in test
 static std::string find_sphal_lib() {
     const char* path =
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 3843252..0253f2f 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -76,6 +76,10 @@
         "liblog",
     ],
 
+    // for FRIEND_TEST
+    static_libs: ["libgtest_prod"],
+    export_static_lib_headers: ["libgtest_prod"],
+
     export_include_dirs: ["include"],
 }
 
diff --git a/libziparchive/include/ziparchive/zip_writer.h b/libziparchive/include/ziparchive/zip_writer.h
index a2a0dbf..d68683d 100644
--- a/libziparchive/include/ziparchive/zip_writer.h
+++ b/libziparchive/include/ziparchive/zip_writer.h
@@ -19,6 +19,7 @@
 #include <cstdio>
 #include <ctime>
 
+#include <gtest/gtest_prod.h>
 #include <memory>
 #include <string>
 #include <string_view>
@@ -165,6 +166,7 @@
   int32_t StoreBytes(FileEntry* file, const void* data, uint32_t len);
   int32_t CompressBytes(FileEntry* file, const void* data, uint32_t len);
   int32_t FlushCompressedBytes(FileEntry* file);
+  bool ShouldUseDataDescriptor() const;
 
   enum class State {
     kWritingZip,
@@ -182,4 +184,6 @@
 
   std::unique_ptr<z_stream, void (*)(z_stream*)> z_stream_;
   std::vector<uint8_t> buffer_;
+
+  FRIEND_TEST(zipwriter, WriteToUnseekableFile);
 };
diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc
index 198154b..67279a6 100644
--- a/libziparchive/zip_writer.cc
+++ b/libziparchive/zip_writer.cc
@@ -455,6 +455,11 @@
   return kNoError;
 }
 
+bool ZipWriter::ShouldUseDataDescriptor() const {
+  // Only use a trailing "data descriptor" if the output isn't seekable.
+  return !seekable_;
+}
+
 int32_t ZipWriter::FinishEntry() {
   if (state_ != State::kWritingEntry) {
     return kInvalidState;
@@ -467,7 +472,7 @@
     }
   }
 
-  if ((current_file_entry_.compression_method & kCompressDeflated) || !seekable_) {
+  if (ShouldUseDataDescriptor()) {
     // Some versions of ZIP don't allow STORED data to have a trailing DataDescriptor.
     // If this file is not seekable, or if the data is compressed, write a DataDescriptor.
     const uint32_t sig = DataDescriptor::kOptSignature;
@@ -515,7 +520,7 @@
   for (FileEntry& file : files_) {
     CentralDirectoryRecord cdr = {};
     cdr.record_signature = CentralDirectoryRecord::kSignature;
-    if ((file.compression_method & kCompressDeflated) || !seekable_) {
+    if (ShouldUseDataDescriptor()) {
       cdr.gpb_flags |= kGPBDDFlagMask;
     }
     cdr.compression_method = file.compression_method;
diff --git a/libziparchive/zip_writer_test.cc b/libziparchive/zip_writer_test.cc
index c3da23c..d324d4b 100644
--- a/libziparchive/zip_writer_test.cc
+++ b/libziparchive/zip_writer_test.cc
@@ -243,6 +243,7 @@
   ZipEntry data;
   ASSERT_EQ(0, FindEntry(handle, "file.txt", &data));
   EXPECT_EQ(kCompressDeflated, data.method);
+  EXPECT_EQ(0u, data.has_data_descriptor);
   ASSERT_EQ(4u, data.uncompressed_length);
   ASSERT_TRUE(AssertFileEntryContentsEq("helo", handle, &data));
 
@@ -351,6 +352,29 @@
   CloseArchive(handle);
 }
 
+TEST_F(zipwriter, WriteToUnseekableFile) {
+  const char* expected = "hello";
+  ZipWriter writer(file_);
+  writer.seekable_ = false;
+
+  ASSERT_EQ(0, writer.StartEntry("file.txt", 0));
+  ASSERT_EQ(0, writer.WriteBytes(expected, strlen(expected)));
+  ASSERT_EQ(0, writer.FinishEntry());
+  ASSERT_EQ(0, writer.Finish());
+  ASSERT_GE(0, lseek(fd_, 0, SEEK_SET));
+
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
+  ZipEntry data;
+  ASSERT_EQ(0, FindEntry(handle, "file.txt", &data));
+  EXPECT_EQ(kCompressStored, data.method);
+  EXPECT_EQ(1u, data.has_data_descriptor);
+  EXPECT_EQ(strlen(expected), data.compressed_length);
+  ASSERT_EQ(strlen(expected), data.uncompressed_length);
+  ASSERT_TRUE(AssertFileEntryContentsEq(expected, handle, &data));
+  CloseArchive(handle);
+}
+
 TEST_F(zipwriter, TruncateFileAfterBackup) {
   ZipWriter writer(file_);
 
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/logcat/logcat.cpp b/logcat/logcat.cpp
index 15e07fe..6e38d95 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -483,7 +483,8 @@
                     "                  Additionally, 'kernel' for userdebug and eng builds, and\n"
                     "                  'security' for Device Owner installations.\n"
                     "                  Multiple -b parameters or comma separated list of buffers are\n"
-                    "                  allowed. Buffers interleaved. Default -b main,system,crash.\n"
+                    "                  allowed. Buffers interleaved.\n"
+                    "                  Default -b main,system,crash,kernel.\n"
                     "  -B, --binary    Output the log in binary.\n"
                     "  -S, --statistics                       Output statistics.\n"
                     "  -p, --prune     Print prune white and ~black list. Service is specified as\n"
@@ -1312,6 +1313,10 @@
             dev = dev->next = new log_device_t("crash", false);
             context->devCount++;
         }
+        if (android_name_to_log_id("kernel") == LOG_ID_KERNEL) {
+            dev = dev->next = new log_device_t("kernel", false);
+            context->devCount++;
+        }
     }
 
     if (!!context->logRotateSizeKBytes && !context->outputFileName) {
diff --git a/logd/Android.bp b/logd/Android.bp
index 9b86258..b337b7c 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -39,7 +39,6 @@
         "FlushCommand.cpp",
         "LogBuffer.cpp",
         "LogBufferElement.cpp",
-        "LogBufferInterface.cpp",
         "LogTimes.cpp",
         "LogStatistics.cpp",
         "LogWhiteBlackList.cpp",
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 774d4ab..c2d5b97 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -27,7 +27,6 @@
 #include <sysutils/SocketClient.h>
 
 #include "LogBufferElement.h"
-#include "LogBufferInterface.h"
 #include "LogStatistics.h"
 #include "LogTags.h"
 #include "LogTimes.h"
@@ -75,7 +74,7 @@
 
 typedef std::list<LogBufferElement*> LogBufferElementCollection;
 
-class LogBuffer : public LogBufferInterface {
+class LogBuffer {
     LogBufferElementCollection mLogElements;
     pthread_rwlock_t mLogElementsLock;
 
@@ -108,14 +107,14 @@
     LastLogTimes& mTimes;
 
     explicit LogBuffer(LastLogTimes* times);
-    ~LogBuffer() override;
+    ~LogBuffer();
     void init();
     bool isMonotonic() {
         return monotonic;
     }
 
-    int log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
-            const char* msg, uint16_t len) override;
+    int log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, const char* msg,
+            uint16_t len);
     // lastTid is an optional context to help detect if the last previous
     // valid message was from the same source so we can differentiate chatty
     // filter types (identical or expired)
@@ -159,12 +158,7 @@
     const char* pidToName(pid_t pid) {
         return stats.pidToName(pid);
     }
-    virtual uid_t pidToUid(pid_t pid) override {
-        return stats.pidToUid(pid);
-    }
-    virtual pid_t tidToPid(pid_t tid) override {
-        return stats.tidToPid(tid);
-    }
+    uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); }
     const char* uidToName(uid_t uid) {
         return stats.uidToName(uid);
     }
diff --git a/logd/LogBufferInterface.h b/logd/LogBufferInterface.h
deleted file mode 100644
index f31e244..0000000
--- a/logd/LogBufferInterface.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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 _LOGD_LOG_BUFFER_INTERFACE_H__
-#define _LOGD_LOG_BUFFER_INTERFACE_H__
-
-#include <sys/types.h>
-
-#include <android-base/macros.h>
-#include <log/log_id.h>
-#include <log/log_time.h>
-
-// Abstract interface that handles log when log available.
-class LogBufferInterface {
-   public:
-    LogBufferInterface();
-    virtual ~LogBufferInterface();
-    // Handles a log entry when available in LogListener.
-    // Returns the size of the handled log message.
-    virtual int log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
-                    pid_t tid, const char* msg, uint16_t len) = 0;
-
-    virtual uid_t pidToUid(pid_t pid);
-    virtual pid_t tidToPid(pid_t tid);
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(LogBufferInterface);
-};
-
-#endif  // _LOGD_LOG_BUFFER_INTERFACE_H__
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 2f22778..443570f 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-#include <ctype.h>
 #include <limits.h>
-#include <stdio.h>
 #include <sys/cdefs.h>
 #include <sys/prctl.h>
 #include <sys/socket.h>
@@ -32,9 +30,8 @@
 #include "LogListener.h"
 #include "LogUtils.h"
 
-LogListener::LogListener(LogBufferInterface* buf, LogReader* reader)
-    : SocketListener(getLogSocket(), false), logbuf(buf), reader(reader) {
-}
+LogListener::LogListener(LogBuffer* buf, LogReader* reader)
+    : SocketListener(getLogSocket(), false), logbuf(buf), reader(reader) {}
 
 bool LogListener::onDataAvailable(SocketClient* cli) {
     static bool name_set;
@@ -78,11 +75,8 @@
         cmsg = CMSG_NXTHDR(&hdr, cmsg);
     }
 
-    struct ucred fake_cred;
     if (cred == nullptr) {
-        cred = &fake_cred;
-        cred->pid = 0;
-        cred->uid = DEFAULT_OVERFLOWUID;
+        return false;
     }
 
     if (cred->uid == AID_LOGD) {
@@ -106,40 +100,16 @@
         return false;
     }
 
-    // Check credential validity, acquire corrected details if not supplied.
-    if (cred->pid == 0) {
-        cred->pid = logbuf ? logbuf->tidToPid(header->tid)
-                           : android::tidToPid(header->tid);
-        if (cred->pid == getpid()) {
-            // We expect that /proc/<tid>/ is accessible to self even without
-            // readproc group, so that we will always drop messages that come
-            // from any of our logd threads and their library calls.
-            return false;  // ignore self
-        }
-    }
-    if (cred->uid == DEFAULT_OVERFLOWUID) {
-        uid_t uid =
-            logbuf ? logbuf->pidToUid(cred->pid) : android::pidToUid(cred->pid);
-        if (uid == AID_LOGD) {
-            uid = logbuf ? logbuf->pidToUid(header->tid)
-                         : android::pidToUid(cred->pid);
-        }
-        if (uid != AID_LOGD) cred->uid = uid;
-    }
-
     char* msg = ((char*)buffer) + sizeof(android_log_header_t);
     n -= sizeof(android_log_header_t);
 
     // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
     // truncated message to the logs.
 
-    if (logbuf != nullptr) {
-        int res = logbuf->log(
-            logId, header->realtime, cred->uid, cred->pid, header->tid, msg,
-            ((size_t)n <= UINT16_MAX) ? (uint16_t)n : UINT16_MAX);
-        if (res > 0 && reader != nullptr) {
-            reader->notifyNewLog(static_cast<log_mask_t>(1 << logId));
-        }
+    int res = logbuf->log(logId, header->realtime, cred->uid, cred->pid, header->tid, msg,
+                          ((size_t)n <= UINT16_MAX) ? (uint16_t)n : UINT16_MAX);
+    if (res > 0) {
+        reader->notifyNewLog(static_cast<log_mask_t>(1 << logId));
     }
 
     return true;
diff --git a/logd/LogListener.h b/logd/LogListener.h
index a562a54..8fe3da4 100644
--- a/logd/LogListener.h
+++ b/logd/LogListener.h
@@ -20,22 +20,12 @@
 #include <sysutils/SocketListener.h>
 #include "LogReader.h"
 
-// DEFAULT_OVERFLOWUID is defined in linux/highuid.h, which is not part of
-// the uapi headers for userspace to use.  This value is filled in on the
-// out-of-band socket credentials if the OS fails to find one available.
-// One of the causes of this is if SO_PASSCRED is set, all the packets before
-// that point will have this value.  We also use it in a fake credential if
-// no socket credentials are supplied.
-#ifndef DEFAULT_OVERFLOWUID
-#define DEFAULT_OVERFLOWUID 65534
-#endif
-
 class LogListener : public SocketListener {
-    LogBufferInterface* logbuf;
+    LogBuffer* logbuf;
     LogReader* reader;
 
    public:
-    LogListener(LogBufferInterface* buf, LogReader* reader /* nullable */);
+     LogListener(LogBuffer* buf, LogReader* reader);
 
    protected:
     virtual bool onDataAvailable(SocketClient* cli);
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 116e08e..431b778 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -837,35 +837,12 @@
     }
     return AID_LOGD;  // associate this with the logger
 }
-
-pid_t tidToPid(pid_t tid) {
-    char buffer[512];
-    snprintf(buffer, sizeof(buffer), "/proc/%u/status", tid);
-    FILE* fp = fopen(buffer, "r");
-    if (fp) {
-        while (fgets(buffer, sizeof(buffer), fp)) {
-            int pid = tid;
-            char space = 0;
-            if ((sscanf(buffer, "Tgid: %d%c", &pid, &space) == 2) &&
-                isspace(space)) {
-                fclose(fp);
-                return pid;
-            }
-        }
-        fclose(fp);
-    }
-    return tid;
-}
 }
 
 uid_t LogStatistics::pidToUid(pid_t pid) {
     return pidTable.add(pid)->second.getUid();
 }
 
-pid_t LogStatistics::tidToPid(pid_t tid) {
-    return tidTable.add(tid)->second.getPid();
-}
-
 // caller must free character string
 const char* LogStatistics::pidToName(pid_t pid) const {
     // An inconvenient truth ... getName() can alter the object
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 469f6dc..0782de3 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -306,6 +306,10 @@
     std::string format(const LogStatistics& stat, log_id_t id) const;
 };
 
+namespace android {
+uid_t pidToUid(pid_t pid);
+}
+
 struct PidEntry : public EntryBaseDropped {
     const pid_t pid;
     uid_t uid;
@@ -385,13 +389,6 @@
           uid(android::pidToUid(tid)),
           name(android::tidToName(tid)) {
     }
-    TidEntry(pid_t tid)
-        : EntryBaseDropped(),
-          tid(tid),
-          pid(android::tidToPid(tid)),
-          uid(android::pidToUid(tid)),
-          name(android::tidToName(tid)) {
-    }
     explicit TidEntry(const LogBufferElement* element)
         : EntryBaseDropped(element),
           tid(element->getTid()),
@@ -787,7 +784,6 @@
     // helper (must be locked directly or implicitly by mLogElementsLock)
     const char* pidToName(pid_t pid) const;
     uid_t pidToUid(pid_t pid);
-    pid_t tidToPid(pid_t tid);
     const char* uidToName(uid_t uid) const;
 };
 
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index 4dcd3e7..fa9f398 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -38,8 +38,6 @@
 // Caller must own and free returned value
 char* pidToName(pid_t pid);
 char* tidToName(pid_t tid);
-uid_t pidToUid(pid_t pid);
-pid_t tidToPid(pid_t tid);
 
 // Furnished in LogTags.cpp. Thread safe.
 const char* tagToName(uint32_t tag);
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index f084cd2..246f9ac 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -113,10 +113,10 @@
 else
   LOCAL_POST_INSTALL_CMD += ; ln -sf /system/product $(TARGET_ROOT_OUT)/product
 endif
-ifdef BOARD_USES_PRODUCT_SERVICESIMAGE
-  LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/product_services
+ifdef BOARD_USES_SYSTEM_EXTIMAGE
+  LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/system_ext
 else
-  LOCAL_POST_INSTALL_CMD += ; ln -sf /system/product_services $(TARGET_ROOT_OUT)/product_services
+  LOCAL_POST_INSTALL_CMD += ; ln -sf /system/system_ext $(TARGET_ROOT_OUT)/system_ext
 endif
 ifdef BOARD_USES_METADATA_PARTITION
   LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/metadata
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index ad14493..f0b1fd2 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -42,7 +42,7 @@
 # APEX related namespaces.
 ###############################################################################
 
-additional.namespaces = runtime,conscrypt,media,resolv
+additional.namespaces = runtime,conscrypt,media,neuralnetworks,resolv
 
 # 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
@@ -51,8 +51,8 @@
 # shared library cannot be loaded from the runtime namespace either, the
 # dynamic linker tries to load the shared library from the resolv namespace.
 # Finally, if all attempts fail, the dynamic linker returns an error.
-namespace.default.links = runtime,resolv
-namespace.default.asan.links = runtime,resolv
+namespace.default.links = runtime,resolv,neuralnetworks
+namespace.default.asan.links = runtime,resolv,neuralnetworks
 namespace.default.link.runtime.shared_libs  = libandroidicu.so
 namespace.default.link.runtime.shared_libs += libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libdexfiled_external.so
@@ -71,6 +71,9 @@
 # to be loaded in the default namespace.
 namespace.default.link.resolv.shared_libs = libnetd_resolv.so
 
+# LLNDK library moved into apex
+namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
 ###############################################################################
 # "runtime" APEX namespace
 #
@@ -159,6 +162,27 @@
 namespace.resolv.link.default.shared_libs += libvndksupport.so
 
 ###############################################################################
+# "neuralnetworks" APEX namespace
+#
+# This namespace is for libraries within the NNAPI APEX.
+###############################################################################
+namespace.neuralnetworks.isolated = true
+namespace.neuralnetworks.visible = true
+
+namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
+namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
+namespace.neuralnetworks.links = default
+namespace.neuralnetworks.link.default.shared_libs  = libc.so
+namespace.neuralnetworks.link.default.shared_libs += libcgrouprc.so
+namespace.neuralnetworks.link.default.shared_libs += libdl.so
+namespace.neuralnetworks.link.default.shared_libs += liblog.so
+namespace.neuralnetworks.link.default.shared_libs += libm.so
+namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
+namespace.neuralnetworks.link.default.shared_libs += libsync.so
+namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
+
+
+###############################################################################
 # Namespace config for binaries under /postinstall.
 # Only one default namespace is defined and it has no directories other than
 # /system/lib and /product/lib in the search paths. This is because linker
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index b1616d3..3321425 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/
@@ -34,7 +35,7 @@
 dir.system = /data
 
 [system]
-additional.namespaces = runtime,conscrypt,media,resolv,sphal,vndk,rs
+additional.namespaces = runtime,conscrypt,media,neuralnetworks,resolv,sphal,vndk,rs
 
 ###############################################################################
 # "default" namespace
@@ -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
@@ -131,7 +132,7 @@
 # shared library cannot be loaded from the runtime namespace either, the
 # dynamic linker tries to load the shared library from the resolv namespace.
 # Finally, if all attempts fail, the dynamic linker returns an error.
-namespace.default.links = runtime,resolv
+namespace.default.links = runtime,resolv,neuralnetworks
 namespace.default.link.runtime.shared_libs  = libandroidicu.so
 namespace.default.link.runtime.shared_libs += libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libdexfiled_external.so
@@ -151,6 +152,9 @@
 # to be loaded in the default namespace.
 namespace.default.link.resolv.shared_libs = libnetd_resolv.so
 
+# LLNDK library moved into apex
+namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
 ###############################################################################
 # "runtime" APEX namespace
 #
@@ -184,13 +188,16 @@
 
 namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
 
-namespace.media.links = default
+namespace.media.links = default,neuralnetworks
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
 namespace.media.link.default.shared_libs += libbinder_ndk.so
 namespace.media.link.default.shared_libs += libcgrouprc.so
 namespace.media.link.default.shared_libs += libmediametrics.so
 namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
 
+# LLNDK library moved into apex
+namespace.media.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
 ###############################################################################
 # "conscrypt" APEX namespace
 #
@@ -268,7 +275,7 @@
 # libs listed here can be used. Order is important here as the namespaces are
 # tried in this order. rs should be before vndk because both are capable
 # of loading libRS_internal.so
-namespace.sphal.links = rs,default,vndk
+namespace.sphal.links = rs,default,vndk,neuralnetworks
 
 # Renderscript gets separate namespace
 namespace.sphal.link.rs.shared_libs = libRS_internal.so
@@ -278,6 +285,10 @@
 
 namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
 
+# LLNDK library moved into apex
+namespace.sphal.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
+
 ###############################################################################
 # "rs" namespace
 #
@@ -317,7 +328,7 @@
 namespace.rs.asan.permitted.paths +=           /vendor/${LIB}
 namespace.rs.asan.permitted.paths += /data
 
-namespace.rs.links = default,vndk
+namespace.rs.links = default,vndk,neuralnetworks
 
 namespace.rs.link.default.shared_libs  = %LLNDK_LIBRARIES%
 namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
@@ -327,6 +338,10 @@
 
 namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
 
+# LLNDK library moved into apex
+namespace.rs.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
+
 ###############################################################################
 # "vndk" namespace
 #
@@ -372,7 +387,7 @@
 # The "vndk" namespace links to "default" namespace for LLNDK libs and links to
 # "sphal" namespace for vendor libs.  The ordering matters.  The "default"
 # namespace has higher priority than the "sphal" namespace.
-namespace.vndk.links = default,sphal,runtime
+namespace.vndk.links = default,sphal,runtime,neuralnetworks
 
 # When these NDK libs are required inside this namespace, then it is redirected
 # to the default namespace. This is possible since their ABI is stable across
@@ -385,6 +400,28 @@
 # Allow VNDK-SP extensions to use vendor libraries
 namespace.vndk.link.sphal.allow_all_shared_libs = true
 
+# LLNDK library moved into apex
+namespace.vndk.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
+###############################################################################
+# "neuralnetworks" APEX namespace
+#
+# This namespace is for libraries within the NNAPI APEX.
+###############################################################################
+namespace.neuralnetworks.isolated = true
+namespace.neuralnetworks.visible = true
+
+namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
+namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
+namespace.neuralnetworks.links = default
+namespace.neuralnetworks.link.default.shared_libs  = libc.so
+namespace.neuralnetworks.link.default.shared_libs += libcgrouprc.so
+namespace.neuralnetworks.link.default.shared_libs += libdl.so
+namespace.neuralnetworks.link.default.shared_libs += liblog.so
+namespace.neuralnetworks.link.default.shared_libs += libm.so
+namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
+namespace.neuralnetworks.link.default.shared_libs += libsync.so
+namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
 
 ###############################################################################
 # Namespace config for vendor processes. In O, no restriction is enforced for
@@ -393,7 +430,7 @@
 # (LL-NDK only) access.
 ###############################################################################
 [vendor]
-additional.namespaces = runtime,system,vndk%VNDK_IN_SYSTEM_NS%
+additional.namespaces = runtime,system,neuralnetworks,vndk%VNDK_IN_SYSTEM_NS%
 
 ###############################################################################
 # "default" namespace
@@ -434,7 +471,7 @@
 namespace.default.asan.permitted.paths += /data/asan/vendor
 namespace.default.asan.permitted.paths +=           /vendor
 
-namespace.default.links = system,vndk%VNDK_IN_SYSTEM_NS%,runtime
+namespace.default.links = system,vndk%VNDK_IN_SYSTEM_NS%,runtime,neuralnetworks
 namespace.default.link.runtime.shared_libs = %SANITIZER_RUNTIME_LIBRARIES%
 namespace.default.link.system.shared_libs  = %LLNDK_LIBRARIES%
 namespace.default.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
@@ -442,6 +479,9 @@
 namespace.default.link.vndk.shared_libs  = %VNDK_SAMEPROCESS_LIBRARIES%
 namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
 
+# LLNDK library moved into apex
+namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
 ###############################################################################
 # "runtime" APEX namespace
 #
@@ -457,6 +497,7 @@
 # classloader-namespace for oat files, and tighten this up.
 namespace.runtime.link.system.allow_all_shared_libs = true
 
+
 ###############################################################################
 # "vndk" namespace
 #
@@ -490,7 +531,7 @@
 # Android releases.  The links here should be identical to that of the
 # 'vndk_in_system' namespace, except for the link between 'vndk' and
 # 'vndk_in_system'.
-namespace.vndk.links = system,default%VNDK_IN_SYSTEM_NS%,runtime
+namespace.vndk.links = system,default%VNDK_IN_SYSTEM_NS%,runtime,neuralnetworks
 
 namespace.vndk.link.system.shared_libs  = %LLNDK_LIBRARIES%
 namespace.vndk.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
@@ -501,6 +542,9 @@
 
 namespace.vndk.link.vndk_in_system.shared_libs = %VNDK_USING_CORE_VARIANT_LIBRARIES%
 
+# LLNDK library moved into apex
+namespace.vndk.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
 ###############################################################################
 # "system" namespace
 #
@@ -510,15 +554,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 +597,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%
 
@@ -570,14 +614,34 @@
 #   1. 'vndk_in_system' needs to be freely linked back to 'vndk'.
 #   2. 'vndk_in_system' does not need to link to 'default', as any library that
 #      requires anything vendor would not be a vndk_in_system library.
-namespace.vndk_in_system.links = vndk,system,runtime
+namespace.vndk_in_system.links = vndk,system,runtime,neuralnetworks
 namespace.vndk_in_system.link.runtime.shared_libs = %SANITIZER_RUNTIME_LIBRARIES%
 
 namespace.vndk_in_system.link.system.shared_libs  = %LLNDK_LIBRARIES%
 namespace.vndk_in_system.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
 
 namespace.vndk_in_system.link.vndk.allow_all_shared_libs = true
+namespace.vndk_in_system.link.neuralnetworks.shared_libs = libneuralnetworks.so
 
+###############################################################################
+# "neuralnetworks" APEX namespace
+#
+# This namespace is for libraries within the NNAPI APEX.
+###############################################################################
+namespace.neuralnetworks.isolated = true
+namespace.neuralnetworks.visible = true
+
+namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
+namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
+namespace.neuralnetworks.links = default
+namespace.neuralnetworks.link.default.shared_libs  = libc.so
+namespace.neuralnetworks.link.default.shared_libs += libcgrouprc.so
+namespace.neuralnetworks.link.default.shared_libs += libdl.so
+namespace.neuralnetworks.link.default.shared_libs += liblog.so
+namespace.neuralnetworks.link.default.shared_libs += libm.so
+namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
+namespace.neuralnetworks.link.default.shared_libs += libsync.so
+namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
 
 ###############################################################################
 # Namespace config for native tests that need access to both system and vendor
@@ -586,7 +650,7 @@
 # includes the requisite namespace setup for APEXes.
 ###############################################################################
 [unrestricted]
-additional.namespaces = runtime,media,conscrypt,resolv
+additional.namespaces = runtime,media,conscrypt,resolv,neuralnetworks
 
 # Visible to allow links to be created at runtime, e.g. through
 # android_link_namespaces in libnativeloader.
@@ -604,7 +668,7 @@
 namespace.default.asan.search.paths +=           /vendor/${LIB}
 
 # Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
-namespace.default.links = runtime,resolv
+namespace.default.links = runtime,resolv,neuralnetworks
 namespace.default.link.runtime.shared_libs  = libandroidicu.so
 namespace.default.link.runtime.shared_libs += libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libdexfiled_external.so
@@ -620,6 +684,7 @@
 namespace.default.link.runtime.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
 
 namespace.default.link.resolv.shared_libs = libnetd_resolv.so
+namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
 
 ###############################################################################
 # "runtime" APEX namespace
@@ -652,12 +717,16 @@
 
 namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
 
-namespace.media.links = default
+namespace.media.links = default,neuralnetworks
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
 namespace.media.link.default.shared_libs += libbinder_ndk.so
 namespace.media.link.default.shared_libs += libmediametrics.so
 namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
 
+# LLNDK library moved into apex
+namespace.media.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
+
 ###############################################################################
 # "conscrypt" APEX namespace
 #
@@ -693,6 +762,25 @@
 namespace.resolv.link.default.shared_libs += libbinder_ndk.so
 namespace.resolv.link.default.shared_libs += liblog.so
 
+###############################################################################
+# "neuralnetworks" APEX namespace
+#
+# This namespace is for libraries within the NNAPI APEX.
+###############################################################################
+namespace.neuralnetworks.isolated = true
+namespace.neuralnetworks.visible = true
+
+namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
+namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
+namespace.neuralnetworks.links = default
+namespace.neuralnetworks.link.default.shared_libs  = libc.so
+namespace.neuralnetworks.link.default.shared_libs += libcgrouprc.so
+namespace.neuralnetworks.link.default.shared_libs += libdl.so
+namespace.neuralnetworks.link.default.shared_libs += liblog.so
+namespace.neuralnetworks.link.default.shared_libs += libm.so
+namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
+namespace.neuralnetworks.link.default.shared_libs += libsync.so
+namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
 
 ###############################################################################
 # Namespace config for binaries under /postinstall.
@@ -705,7 +793,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..0bb60ab 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/
@@ -34,7 +35,7 @@
 dir.system = /data
 
 [system]
-additional.namespaces = runtime,conscrypt,media,resolv,sphal,vndk,rs
+additional.namespaces = runtime,conscrypt,media,neuralnetworks,resolv,sphal,vndk,rs
 
 ###############################################################################
 # "default" namespace
@@ -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
@@ -71,7 +72,7 @@
 # shared library cannot be loaded from the runtime namespace either, the
 # dynamic linker tries to load the shared library from the resolv namespace.
 # Finally, if all attempts fail, the dynamic linker returns an error.
-namespace.default.links = runtime,resolv
+namespace.default.links = runtime,resolv,neuralnetworks
 namespace.default.link.runtime.shared_libs  = libandroidicu.so
 namespace.default.link.runtime.shared_libs += libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libdexfiled_external.so
@@ -90,6 +91,9 @@
 # to be loaded in the default namespace.
 namespace.default.link.resolv.shared_libs = libnetd_resolv.so
 
+# LLNDK library moved into apex
+namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
 ###############################################################################
 # "runtime" APEX namespace
 #
@@ -123,12 +127,15 @@
 
 namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
 
-namespace.media.links = default
+namespace.media.links = default,neuralnetworks
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
 namespace.media.link.default.shared_libs += libbinder_ndk.so
 namespace.media.link.default.shared_libs += libmediametrics.so
 namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
 
+# LLNDK library moved into apex
+namespace.media.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
 ###############################################################################
 # "conscrypt" APEX namespace
 #
@@ -206,7 +213,7 @@
 # libs listed here can be used. Order is important here as the namespaces are
 # tried in this order. rs should be before vndk because both are capable
 # of loading libRS_internal.so
-namespace.sphal.links = rs,default,vndk
+namespace.sphal.links = rs,default,vndk,neuralnetworks
 
 # Renderscript gets separate namespace
 namespace.sphal.link.rs.shared_libs = libRS_internal.so
@@ -216,6 +223,9 @@
 
 namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
 
+# LLNDK library moved into apex
+namespace.sphal.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
 ###############################################################################
 # "rs" namespace
 #
@@ -255,7 +265,7 @@
 namespace.rs.asan.permitted.paths +=           /vendor/${LIB}
 namespace.rs.asan.permitted.paths += /data
 
-namespace.rs.links = default,vndk
+namespace.rs.links = default,vndk,neuralnetworks
 
 namespace.rs.link.default.shared_libs  = %LLNDK_LIBRARIES%
 namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
@@ -265,6 +275,9 @@
 
 namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
 
+# LLNDK library moved into apex
+namespace.rs.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
 ###############################################################################
 # "vndk" namespace
 #
@@ -309,10 +322,31 @@
 # When these NDK libs are required inside this namespace, then it is redirected
 # to the default namespace. This is possible since their ABI is stable across
 # Android releases.
-namespace.vndk.links = default
+namespace.vndk.links = default,neuralnetworks
 
 namespace.vndk.link.default.shared_libs  = %LLNDK_LIBRARIES%
 namespace.vndk.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+namespace.vndk.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
+###############################################################################
+# "neuralnetworks" APEX namespace
+#
+# This namespace is for libraries within the NNAPI APEX.
+###############################################################################
+namespace.neuralnetworks.isolated = true
+namespace.neuralnetworks.visible = true
+
+namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
+namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
+namespace.neuralnetworks.links = default
+namespace.neuralnetworks.link.default.shared_libs  = libc.so
+namespace.neuralnetworks.link.default.shared_libs += libcgrouprc.so
+namespace.neuralnetworks.link.default.shared_libs += libdl.so
+namespace.neuralnetworks.link.default.shared_libs += liblog.so
+namespace.neuralnetworks.link.default.shared_libs += libm.so
+namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
+namespace.neuralnetworks.link.default.shared_libs += libsync.so
+namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
 
 
 ###############################################################################
@@ -322,7 +356,7 @@
 # (LL-NDK only) access.
 ###############################################################################
 [vendor]
-additional.namespaces = runtime
+additional.namespaces = runtime,neuralnetworks
 
 namespace.default.isolated = false
 
@@ -336,8 +370,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,14 +391,14 @@
 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%
 
-namespace.default.links = runtime
+namespace.default.links = runtime,neuralnetworks
 namespace.default.link.runtime.shared_libs  = libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libdexfiled_external.so
 # TODO(b/120786417 or b/134659294): libicuuc.so and libicui18n.so are kept for app compat.
@@ -375,6 +410,9 @@
 # Workaround for b/124772622
 namespace.default.link.runtime.shared_libs += libandroidicu.so
 
+# LLNDK library moved into apex
+namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
 ###############################################################################
 # "runtime" APEX namespace
 #
@@ -391,13 +429,34 @@
 namespace.runtime.link.default.allow_all_shared_libs = true
 
 ###############################################################################
+# "neuralnetworks" APEX namespace
+#
+# This namespace is for libraries within the NNAPI APEX.
+###############################################################################
+namespace.neuralnetworks.isolated = true
+namespace.neuralnetworks.visible = true
+
+namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
+namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
+namespace.neuralnetworks.links = default
+namespace.neuralnetworks.link.default.shared_libs  = libc.so
+namespace.neuralnetworks.link.default.shared_libs += libcgrouprc.so
+namespace.neuralnetworks.link.default.shared_libs += libdl.so
+namespace.neuralnetworks.link.default.shared_libs += liblog.so
+namespace.neuralnetworks.link.default.shared_libs += libm.so
+namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
+namespace.neuralnetworks.link.default.shared_libs += libsync.so
+namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
+
+
+###############################################################################
 # Namespace config for native tests that need access to both system and vendor
 # libraries. This replicates the default linker config (done by
 # init_default_namespace_no_config in bionic/linker/linker.cpp), except that it
 # includes the requisite namespace setup for APEXes.
 ###############################################################################
 [unrestricted]
-additional.namespaces = runtime,media,conscrypt,resolv
+additional.namespaces = runtime,media,conscrypt,resolv,neuralnetworks
 
 # Visible to allow links to be created at runtime, e.g. through
 # android_link_namespaces in libnativeloader.
@@ -415,7 +474,7 @@
 namespace.default.asan.search.paths +=           /vendor/${LIB}
 
 # Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
-namespace.default.links = runtime,resolv
+namespace.default.links = runtime,resolv,neuralnetworks
 namespace.default.link.runtime.shared_libs  = libandroidicu.so
 namespace.default.link.runtime.shared_libs += libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libdexfiled_external.so
@@ -432,6 +491,9 @@
 
 namespace.default.link.resolv.shared_libs = libnetd_resolv.so
 
+# LLNDK library moved into apex
+namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
 ###############################################################################
 # "runtime" APEX namespace
 #
@@ -448,7 +510,6 @@
 namespace.runtime.links = default
 # TODO(b/130340935): Use a dynamically created linker namespace similar to
 # classloader-namespace for oat files, and tighten this up.
-namespace.runtime.link.default.allow_all_shared_libs = true
 
 ###############################################################################
 # "media" APEX namespace
@@ -463,12 +524,15 @@
 
 namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
 
-namespace.media.links = default
+namespace.media.links = default,neuralnetworks
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
 namespace.media.link.default.shared_libs += libbinder_ndk.so
 namespace.media.link.default.shared_libs += libmediametrics.so
 namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
 
+# LLNDK library moved into apex
+namespace.media.link.neuralnetworks.shared_libs = libneuralnetworks.so
+
 ###############################################################################
 # "conscrypt" APEX namespace
 #
@@ -504,6 +568,27 @@
 namespace.resolv.link.default.shared_libs += libbinder_ndk.so
 
 ###############################################################################
+# "neuralnetworks" APEX namespace
+#
+# This namespace is for libraries within the NNAPI APEX.
+###############################################################################
+namespace.neuralnetworks.isolated = true
+namespace.neuralnetworks.visible = true
+
+namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
+namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
+namespace.neuralnetworks.links = default
+namespace.neuralnetworks.link.default.shared_libs  = libc.so
+namespace.neuralnetworks.link.default.shared_libs += libcgrouprc.so
+namespace.neuralnetworks.link.default.shared_libs += libdl.so
+namespace.neuralnetworks.link.default.shared_libs += liblog.so
+namespace.neuralnetworks.link.default.shared_libs += libm.so
+namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
+namespace.neuralnetworks.link.default.shared_libs += libsync.so
+namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
+
+
+###############################################################################
 # Namespace config for binaries under /postinstall.
 # Only default namespace is defined and default has no directories
 # other than /system/lib in the search paths. This is because linker calls
@@ -514,5 +599,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..d22e9a7 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -38,6 +38,13 @@
     # Allow up to 32K FDs per process
     setrlimit nofile 32768 32768
 
+    # Create directory to keep ld.config.txt
+    mkdir /dev/linkerconfig 0755
+
+    # Generate ld.config.txt for early executed processes
+    exec -- /system/bin/linkerconfig --target /dev/linkerconfig/ld.config.txt
+    chmod 444 /dev/linkerconfig/ld.config.txt
+
     start ueventd
 
     # Run apexd-bootstrap so that APEXes that provide critical libraries
@@ -288,6 +295,11 @@
     chown system system /sys/power/wakeup_count
     chmod 0660 /sys/power/state
 
+    chown radio wakelock /sys/power/wake_lock
+    chown radio wakelock /sys/power/wake_unlock
+    chmod 0660 /sys/power/wake_lock
+    chmod 0660 /sys/power/wake_unlock
+
     # Start logd before any other services run to ensure we capture all of their logs.
     start logd
 
@@ -402,6 +414,7 @@
     mkdir /metadata/vold
     chmod 0700 /metadata/vold
     mkdir /metadata/password_slots 0771 root system
+    mkdir /metadata/ota 0700 root system
 
     mkdir /metadata/apex 0700 root system
     mkdir /metadata/apex/sessions 0700 root system
@@ -413,6 +426,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
 
@@ -495,7 +512,6 @@
     mkdir /data/misc/ethernet 0770 system system
     mkdir /data/misc/dhcp 0770 dhcp dhcp
     mkdir /data/misc/user 0771 root root
-    mkdir /data/misc/perfprofd 0775 root root
     # give system access to wpa_supplicant.conf for backup and restore
     chmod 0660 /data/misc/wifi/wpa_supplicant.conf
     mkdir /data/local 0751 root root
@@ -628,22 +644,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
@@ -684,10 +694,6 @@
     chown radio system /sys/android_power/acquire_partial_wake_lock
     chown radio system /sys/android_power/release_wake_lock
     chown system system /sys/power/autosleep
-    chown radio wakelock /sys/power/wake_lock
-    chown radio wakelock /sys/power/wake_unlock
-    chmod 0660 /sys/power/wake_lock
-    chmod 0660 /sys/power/wake_unlock
 
     chown system system /sys/devices/system/cpu/cpufreq/interactive/timer_rate
     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/timer_rate
@@ -770,8 +776,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..dbe60e5 100644
--- a/rootdir/update_and_install_ld_config.mk
+++ b/rootdir/update_and_install_ld_config.mk
@@ -40,6 +40,7 @@
 vndksp_libraries_file := $(library_lists_dir)/vndksp.libraries.$(vndk_version).txt
 vndkcore_libraries_file := $(library_lists_dir)/vndkcore.libraries.txt
 vndkprivate_libraries_file := $(library_lists_dir)/vndkprivate.libraries.txt
+llndk_moved_to_apex_libraries_file := $(library_lists_dir)/llndkinapex.libraries.txt
 ifeq ($(my_vndk_use_core_variant),true)
 vndk_using_core_variant_libraries_file := $(library_lists_dir)/vndk_using_core_variant.libraries.$(vndk_version).txt
 endif
@@ -65,6 +66,10 @@
   vndksp_libraries_list := $(VNDK_SAMEPROCESS_LIBRARIES)
 endif
 
+# LLNDK libraries that has been moved to an apex package and no longer are present on
+# /system image.
+llndk_libraries_moved_to_apex_list:=$(LLNDK_MOVED_TO_APEX_LIBRARIES)
+
 # $(1): list of libraries
 # $(2): output file to write the list of libraries to
 define write-libs-to-file
@@ -88,9 +93,17 @@
 # $(2): output file with the filtered list of lib names
 $(LOCAL_BUILT_MODULE): private-filter-out-private-libs = \
   paste -sd ":" $(1) > $(2) && \
-  cat $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) | xargs -n 1 -I privatelib bash -c "sed -i.bak 's/privatelib//' $(2)" && \
+  while read -r privatelib; do sed -i.bak "s/$$privatelib//" $(2) ; done < $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) && \
   sed -i.bak -e 's/::\+/:/g ; s/^:\+// ; s/:\+$$//' $(2) && \
   rm -f $(2).bak
+
+# # Given a file with a list of libs in "a:b:c" format, filter-out the LLNDK libraries migrated into apex file
+# # and write resulting list to a new file in "a:b:c" format
+ $(LOCAL_BUILT_MODULE): private-filter-out-llndk-in-apex-libs = \
+   for lib in $(PRIVATE_LLNDK_LIBRARIES_MOVED_TO_APEX_LIST); do sed -i.bak s/$$lib.so// $(1); done && \
+   sed -i.bak -e 's/::\+/:/g ; s/^:\+// ; s/:\+$$//' $(1) && \
+   rm -f $(1).bak
+
 $(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES_FILE := $(llndk_libraries_file)
 $(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SP_LIBRARIES_FILE := $(vndksp_libraries_file)
 $(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES_FILE := $(vndkcore_libraries_file)
@@ -100,6 +113,7 @@
 $(LOCAL_BUILT_MODULE): PRIVATE_INTERMEDIATES_DIR := $(intermediates_dir)
 $(LOCAL_BUILT_MODULE): PRIVATE_COMP_CHECK_SCRIPT := $(compatibility_check_script)
 $(LOCAL_BUILT_MODULE): PRIVATE_VNDK_VERSION_TAG := \#VNDK$(vndk_version)\#
+$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES_MOVED_TO_APEX_LIST := $(llndk_libraries_moved_to_apex_list)
 deps := $(llndk_libraries_file) $(vndksp_libraries_file) $(vndkcore_libraries_file) \
   $(vndkprivate_libraries_file)
 ifeq ($(check_backward_compatibility),true)
@@ -118,6 +132,7 @@
 endif
 	@mkdir -p $(dir $@)
 	$(call private-filter-out-private-libs,$(PRIVATE_LLNDK_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/llndk_filtered)
+	$(call private-filter-out-llndk-in-apex-libs,$(PRIVATE_INTERMEDIATES_DIR)/llndk_filtered)
 	$(hide) sed -e "s?%LLNDK_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/llndk_filtered)?g" $< >$@
 	$(call private-filter-out-private-libs,$(PRIVATE_VNDK_SP_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/vndksp_filtered)
 	$(hide) sed -i.bak -e "s?%VNDK_SAMEPROCESS_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndksp_filtered)?g" $@
@@ -139,20 +154,16 @@
 endif
 
 	$(hide) echo -n > $(PRIVATE_INTERMEDIATES_DIR)/private_llndk && \
-	cat $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) | \
-	xargs -n 1 -I privatelib bash -c "(grep privatelib $(PRIVATE_LLNDK_LIBRARIES_FILE) || true) >> $(PRIVATE_INTERMEDIATES_DIR)/private_llndk" && \
+	while read -r privatelib; \
+	do (grep $$privatelib $(PRIVATE_LLNDK_LIBRARIES_FILE) || true) >> $(PRIVATE_INTERMEDIATES_DIR)/private_llndk ; \
+	done < $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) && \
 	paste -sd ":" $(PRIVATE_INTERMEDIATES_DIR)/private_llndk | \
 	sed -i.bak -e "s?%PRIVATE_LLNDK_LIBRARIES%?$$(cat -)?g" $@
 
 	$(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
@@ -166,6 +177,7 @@
 intermediates_dir :=
 library_lists_dir :=
 llndk_libraries_file :=
+llndk_moved_to_apex_libraries_file :=
 vndksp_libraries_file :=
 vndkcore_libraries_file :=
 vndkprivate_libraries_file :=
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index 3bc3883..bac3dc3 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -13,7 +13,6 @@
         "auditctl",
         "awk",
         "bzip2",
-        "grep",
         "logwrapper",
         "mini-keyctl",
         "mkshrc",
@@ -32,7 +31,6 @@
 phony {
     name: "shell_and_utilities_recovery",
     required: [
-        "grep.recovery",
         "sh.recovery",
         "toolbox.recovery",
         "toybox.recovery",
@@ -44,7 +42,6 @@
     name: "shell_and_utilities_vendor",
     required: [
         "awk_vendor",
-        "grep_vendor",
         "logwrapper_vendor",
         "mkshrc_vendor",
         "sh_vendor",
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
 
diff --git a/toolbox/Android.bp b/toolbox/Android.bp
index 9ca5607..0cc603a 100644
--- a/toolbox/Android.bp
+++ b/toolbox/Android.bp
@@ -1,14 +1,10 @@
 cc_defaults {
     name: "toolbox_defaults",
-
     cflags: [
         "-Werror",
         "-Wno-unused-parameter",
         "-Wno-unused-const-variable",
         "-D_FILE_OFFSET_BITS=64",
-        "-DWITHOUT_NLS",
-        "-DWITHOUT_BZ2",
-        "-DWITHOUT_GZIP",
     ],
 }
 
@@ -60,39 +56,3 @@
     vendor: true,
     defaults: ["toolbox_binary_defaults"],
 }
-
-// We build BSD grep separately (but see http://b/111849261).
-cc_defaults {
-    name: "grep_common",
-    defaults: ["toolbox_defaults"],
-    srcs: [
-        "upstream-netbsd/usr.bin/grep/fastgrep.c",
-        "upstream-netbsd/usr.bin/grep/file.c",
-        "upstream-netbsd/usr.bin/grep/grep.c",
-        "upstream-netbsd/usr.bin/grep/queue.c",
-        "upstream-netbsd/usr.bin/grep/util.c",
-    ],
-    symlinks: [
-        "egrep",
-        "fgrep",
-    ],
-    sanitize: {
-        integer_overflow: false,
-    },
-}
-
-cc_binary {
-    name: "grep",
-    defaults: ["grep_common"],
-    recovery_available: true,
-}
-
-// Build vendor grep.
-// TODO: Add vendor_available to "grep" module and remove "grep_vendor" module
-//       when vendor_available is fully supported.
-cc_binary {
-    name: "grep_vendor",
-    stem: "grep",
-    vendor: true,
-    defaults: ["grep_common"],
-}
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/fastgrep.c b/toolbox/upstream-netbsd/usr.bin/grep/fastgrep.c
deleted file mode 100644
index 2fcd864..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/fastgrep.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*	$OpenBSD: util.c,v 1.36 2007/10/02 17:59:18 otto Exp $	*/
-/*	$FreeBSD: head/usr.bin/grep/fastgrep.c 211496 2010-08-19 09:28:59Z des $ */
-
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * Copyright (C) 2008 Gabor Kovesdan <gabor@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * XXX: This file is a speed up for grep to cover the defects of the
- * regex library.  These optimizations should practically be implemented
- * there keeping this code clean.  This is a future TODO, but for the
- * meantime, we need to use this workaround.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: fastgrep.c,v 1.5 2011/04/18 03:27:40 joerg Exp $");
-
-#include <limits.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wchar.h>
-#include <wctype.h>
-
-#include "grep.h"
-
-static inline int	grep_cmp(const unsigned char *, const unsigned char *, size_t);
-static inline void	grep_revstr(unsigned char *, int);
-
-void
-fgrepcomp(fastgrep_t *fg, const char *pat)
-{
-	unsigned int i;
-
-	/* Initialize. */
-	fg->len = strlen(pat);
-	fg->bol = false;
-	fg->eol = false;
-	fg->reversed = false;
-
-	fg->pattern = (unsigned char *)grep_strdup(pat);
-
-	/* Preprocess pattern. */
-	for (i = 0; i <= UCHAR_MAX; i++)
-		fg->qsBc[i] = fg->len;
-	for (i = 1; i < fg->len; i++)
-		fg->qsBc[fg->pattern[i]] = fg->len - i;
-}
-
-/*
- * Returns: -1 on failure, 0 on success
- */
-int
-fastcomp(fastgrep_t *fg, const char *pat)
-{
-	unsigned int i;
-	int firstHalfDot = -1;
-	int firstLastHalfDot = -1;
-	int hasDot = 0;
-	int lastHalfDot = 0;
-	int shiftPatternLen;
-
-	/* Initialize. */
-	fg->len = strlen(pat);
-	fg->bol = false;
-	fg->eol = false;
-	fg->reversed = false;
-	fg->word = wflag;
-
-	/* Remove end-of-line character ('$'). */
-	if (fg->len > 0 && pat[fg->len - 1] == '$') {
-		fg->eol = true;
-		fg->len--;
-	}
-
-	/* Remove beginning-of-line character ('^'). */
-	if (pat[0] == '^') {
-		fg->bol = true;
-		fg->len--;
-		pat++;
-	}
-
-	if (fg->len >= 14 &&
-	    memcmp(pat, "[[:<:]]", 7) == 0 &&
-	    memcmp(pat + fg->len - 7, "[[:>:]]", 7) == 0) {
-		fg->len -= 14;
-		pat += 7;
-		/* Word boundary is handled separately in util.c */
-		fg->word = true;
-	}
-
-	/*
-	 * pat has been adjusted earlier to not include '^', '$' or
-	 * the word match character classes at the beginning and ending
-	 * of the string respectively.
-	 */
-	fg->pattern = grep_malloc(fg->len + 1);
-	memcpy(fg->pattern, pat, fg->len);
-	fg->pattern[fg->len] = '\0';
-
-	/* Look for ways to cheat...er...avoid the full regex engine. */
-	for (i = 0; i < fg->len; i++) {
-		/* Can still cheat? */
-		if (fg->pattern[i] == '.') {
-			hasDot = i;
-			if (i < fg->len / 2) {
-				if (firstHalfDot < 0)
-					/* Closest dot to the beginning */
-					firstHalfDot = i;
-			} else {
-				/* Closest dot to the end of the pattern. */
-				lastHalfDot = i;
-				if (firstLastHalfDot < 0)
-					firstLastHalfDot = i;
-			}
-		} else {
-			/* Free memory and let others know this is empty. */
-			free(fg->pattern);
-			fg->pattern = NULL;
-			return (-1);
-		}
-	}
-
-	/*
-	 * Determine if a reverse search would be faster based on the placement
-	 * of the dots.
-	 */
-	if ((!(lflag || cflag)) && ((!(fg->bol || fg->eol)) &&
-	    ((lastHalfDot) && ((firstHalfDot < 0) ||
-	    ((fg->len - (lastHalfDot + 1)) < (size_t)firstHalfDot)))) &&
-	    !oflag && !color) {
-		fg->reversed = true;
-		hasDot = fg->len - (firstHalfDot < 0 ?
-		    firstLastHalfDot : firstHalfDot) - 1;
-		grep_revstr(fg->pattern, fg->len);
-	}
-
-	/*
-	 * Normal Quick Search would require a shift based on the position the
-	 * next character after the comparison is within the pattern.  With
-	 * wildcards, the position of the last dot effects the maximum shift
-	 * distance.
-	 * The closer to the end the wild card is the slower the search.  A
-	 * reverse version of this algorithm would be useful for wildcards near
-	 * the end of the string.
-	 *
-	 * Examples:
-	 * Pattern	Max shift
-	 * -------	---------
-	 * this		5
-	 * .his		4
-	 * t.is		3
-	 * th.s		2
-	 * thi.		1
-	 */
-
-	/* Adjust the shift based on location of the last dot ('.'). */
-	shiftPatternLen = fg->len - hasDot;
-
-	/* Preprocess pattern. */
-	for (i = 0; i <= (signed)UCHAR_MAX; i++)
-		fg->qsBc[i] = shiftPatternLen;
-	for (i = hasDot + 1; i < fg->len; i++) {
-		fg->qsBc[fg->pattern[i]] = fg->len - i;
-	}
-
-	/*
-	 * Put pattern back to normal after pre-processing to allow for easy
-	 * comparisons later.
-	 */
-	if (fg->reversed)
-		grep_revstr(fg->pattern, fg->len);
-
-	return (0);
-}
-
-int
-grep_search(fastgrep_t *fg, const unsigned char *data, size_t len, regmatch_t *pmatch)
-{
-	unsigned int j;
-	int ret = REG_NOMATCH;
-
-	if (pmatch->rm_so == (ssize_t)len)
-		return (ret);
-
-	if (fg->bol && pmatch->rm_so != 0) {
-		pmatch->rm_so = len;
-		pmatch->rm_eo = len;
-		return (ret);
-	}
-
-	/* No point in going farther if we do not have enough data. */
-	if (len < fg->len)
-		return (ret);
-
-	/* Only try once at the beginning or ending of the line. */
-	if (fg->bol || fg->eol) {
-		/* Simple text comparison. */
-		/* Verify data is >= pattern length before searching on it. */
-		if (len >= fg->len) {
-			/* Determine where in data to start search at. */
-			j = fg->eol ? len - fg->len : 0;
-			if (!((fg->bol && fg->eol) && (len != fg->len)))
-				if (grep_cmp(fg->pattern, data + j,
-				    fg->len) == -1) {
-					pmatch->rm_so = j;
-					pmatch->rm_eo = j + fg->len;
-						ret = 0;
-				}
-		}
-	} else if (fg->reversed) {
-		/* Quick Search algorithm. */
-		j = len;
-		do {
-			if (grep_cmp(fg->pattern, data + j - fg->len,
-				fg->len) == -1) {
-				pmatch->rm_so = j - fg->len;
-				pmatch->rm_eo = j;
-				ret = 0;
-				break;
-			}
-			/* Shift if within bounds, otherwise, we are done. */
-			if (j == fg->len)
-				break;
-			j -= fg->qsBc[data[j - fg->len - 1]];
-		} while (j >= fg->len);
-	} else {
-		/* Quick Search algorithm. */
-		j = pmatch->rm_so;
-		do {
-			if (grep_cmp(fg->pattern, data + j, fg->len) == -1) {
-				pmatch->rm_so = j;
-				pmatch->rm_eo = j + fg->len;
-				ret = 0;
-				break;
-			}
-
-			/* Shift if within bounds, otherwise, we are done. */
-			if (j + fg->len == len)
-				break;
-			else
-				j += fg->qsBc[data[j + fg->len]];
-		} while (j <= (len - fg->len));
-	}
-
-	return (ret);
-}
-
-/*
- * Returns:	i >= 0 on failure (position that it failed)
- *		-1 on success
- */
-static inline int
-grep_cmp(const unsigned char *pat, const unsigned char *data, size_t len)
-{
-	size_t size;
-	wchar_t *wdata, *wpat;
-	unsigned int i;
-
-	if (iflag) {
-		if ((size = mbstowcs(NULL, (const char *)data, 0)) ==
-		    ((size_t) - 1))
-			return (-1);
-
-		wdata = grep_malloc(size * sizeof(wint_t));
-
-		if (mbstowcs(wdata, (const char *)data, size) ==
-		    ((size_t) - 1))
-			return (-1);
-
-		if ((size = mbstowcs(NULL, (const char *)pat, 0)) ==
-		    ((size_t) - 1))
-			return (-1);
-
-		wpat = grep_malloc(size * sizeof(wint_t));
-
-		if (mbstowcs(wpat, (const char *)pat, size) == ((size_t) - 1))
-			return (-1);
-		for (i = 0; i < len; i++) {
-			if ((towlower(wpat[i]) == towlower(wdata[i])) ||
-			    ((grepbehave != GREP_FIXED) && wpat[i] == L'.'))
-				continue;
-			free(wpat);
-			free(wdata);
-				return (i);
-		}
-	} else {
-		for (i = 0; i < len; i++) {
-			if ((pat[i] == data[i]) || ((grepbehave != GREP_FIXED) &&
-			    pat[i] == '.'))
-				continue;
-			return (i);
-		}
-	}
-	return (-1);
-}
-
-static inline void
-grep_revstr(unsigned char *str, int len)
-{
-	int i;
-	char c;
-
-	for (i = 0; i < len / 2; i++) {
-		c = str[i];
-		str[i] = str[len - i - 1];
-		str[len - i - 1] = c;
-	}
-}
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/file.c b/toolbox/upstream-netbsd/usr.bin/grep/file.c
deleted file mode 100644
index 428bf58..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/file.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*	$NetBSD: file.c,v 1.10 2018/08/12 09:03:21 christos Exp $	*/
-/*	$FreeBSD: head/usr.bin/grep/file.c 211496 2010-08-19 09:28:59Z des $	*/
-/*	$OpenBSD: file.c,v 1.11 2010/07/02 20:48:48 nicm Exp $	*/
-
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
- * Copyright (C) 2010 Dimitry Andric <dimitry@andric.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: file.c,v 1.10 2018/08/12 09:03:21 christos Exp $");
-
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <wchar.h>
-#include <wctype.h>
-
-#include "grep.h"
-
-#define	MAXBUFSIZ	(32 * 1024)
-#define	LNBUFBUMP	80
-
-#ifndef WITHOUT_GZIP
-static gzFile gzbufdesc;
-#endif
-#ifndef WITHOUT_BZ2
-static BZFILE* bzbufdesc;
-#endif
-
-static unsigned char buffer[MAXBUFSIZ + 1];
-static unsigned char *bufpos;
-static size_t bufrem;
-
-static unsigned char *lnbuf;
-static size_t lnbuflen;
-
-static inline int
-grep_refill(struct file *f)
-{
-	ssize_t nr = -1;
-	int bzerr;
-
-	bufpos = buffer;
-	bufrem = 0;
-
-#ifndef WITHOUT_GZIP
-	if (filebehave == FILE_GZIP) {
-		nr = gzread(gzbufdesc, buffer, MAXBUFSIZ);
-		if (nr == -1)
-			return -1;
-	}
-#endif
-#ifndef WITHOUT_BZ2
-	if (filebehave == FILE_BZIP && bzbufdesc != NULL) {
-		nr = BZ2_bzRead(&bzerr, bzbufdesc, buffer, MAXBUFSIZ);
-		switch (bzerr) {
-		case BZ_OK:
-		case BZ_STREAM_END:
-			/* No problem, nr will be okay */
-			break;
-		case BZ_DATA_ERROR_MAGIC:
-			/*
-			 * As opposed to gzread(), which simply returns the
-			 * plain file data, if it is not in the correct
-			 * compressed format, BZ2_bzRead() instead aborts.
-			 *
-			 * So, just restart at the beginning of the file again,
-			 * and use plain reads from now on.
-			 */
-			BZ2_bzReadClose(&bzerr, bzbufdesc);
-			bzbufdesc = NULL;
-			if (lseek(f->fd, 0, SEEK_SET) == -1)
-				return (-1);
-			nr = read(f->fd, buffer, MAXBUFSIZ);
-			break;
-		default:
-			/* Make sure we exit with an error */
-			nr = -1;
-		}
-		if (nr == -1)
-			return -1;
-	}
-#endif
-	if (nr == -1) {
-		nr = read(f->fd, buffer, MAXBUFSIZ);
-	}
-
-	if (nr < 0)
-		return (-1);
-
-	bufrem = nr;
-	return (0);
-}
-
-static inline void
-grep_lnbufgrow(size_t newlen)
-{
-
-	if (lnbuflen < newlen) {
-		lnbuf = grep_realloc(lnbuf, newlen);
-		lnbuflen = newlen;
-	}
-}
-
-char *
-grep_fgetln(struct file *f, size_t *lenp)
-{
-	unsigned char *p;
-	char *ret;
-	size_t len;
-	size_t off;
-	ptrdiff_t diff;
-
-	/* Fill the buffer, if necessary */
-	if (bufrem == 0 && grep_refill(f) != 0)
-		goto error;
-
-	if (bufrem == 0) {
-		/* Return zero length to indicate EOF */
-		*lenp = 0;
-		return ((char *)bufpos);
-	}
-
-	/* Look for a newline in the remaining part of the buffer */
-	if ((p = memchr(bufpos, line_sep, bufrem)) != NULL) {
-		++p; /* advance over newline */
-		len = p - bufpos;
-		grep_lnbufgrow(len + 1);
-		memcpy(lnbuf, bufpos, len);
-		lnbuf[len] = '\0';
-		*lenp = len;
-		bufrem -= len;
-		bufpos = p;
-		return ((char *)lnbuf);
-	}
-
-	/* We have to copy the current buffered data to the line buffer */
-	for (len = bufrem, off = 0; ; len += bufrem) {
-		/* Make sure there is room for more data */
-		grep_lnbufgrow(len + LNBUFBUMP);
-		memcpy(lnbuf + off, bufpos, len - off);
-		lnbuf[len] = '\0';
-		off = len;
-		if (grep_refill(f) != 0)
-			goto error;
-		if (bufrem == 0)
-			/* EOF: return partial line */
-			break;
-		if ((p = memchr(bufpos, line_sep, bufrem)) == NULL)
-			continue;
-		/* got it: finish up the line (like code above) */
-		++p;
-		diff = p - bufpos;
-		len += diff;
-		grep_lnbufgrow(len + 1);
-		memcpy(lnbuf + off, bufpos, diff);
-		lnbuf[off + diff] = '\0';
-		bufrem -= diff;
-		bufpos = p;
-		break;
-	}
-	*lenp = len;
-	return ((char *)lnbuf);
-
-error:
-	*lenp = 0;
-	return (NULL);
-}
-
-static inline struct file *
-grep_file_init(struct file *f)
-{
-
-#ifndef WITHOUT_GZIP
-	if (filebehave == FILE_GZIP &&
-	    (gzbufdesc = gzdopen(f->fd, "r")) == NULL)
-		goto error;
-#endif
-
-#ifndef WITHOUT_BZ2
-	if (filebehave == FILE_BZIP &&
-	    (bzbufdesc = BZ2_bzdopen(f->fd, "r")) == NULL)
-		goto error;
-#endif
-
-	/* Fill read buffer, also catches errors early */
-	if (grep_refill(f) != 0)
-		goto error;
-
-	/* Check for binary stuff, if necessary */
-	if (!nulldataflag && binbehave != BINFILE_TEXT &&
-	    memchr(bufpos, '\0', bufrem) != NULL)
-		f->binary = true;
-
-	return (f);
-error:
-	close(f->fd);
-	free(f);
-	return (NULL);
-}
-
-/*
- * Opens a file for processing.
- */
-struct file *
-grep_open(const char *path)
-{
-	struct file *f;
-
-	f = grep_malloc(sizeof *f);
-	memset(f, 0, sizeof *f);
-	if (path == NULL) {
-		/* Processing stdin implies --line-buffered. */
-		lbflag = true;
-		f->fd = STDIN_FILENO;
-	} else if ((f->fd = open(path, O_RDONLY)) == -1) {
-		free(f);
-		return (NULL);
-	}
-
-	return (grep_file_init(f));
-}
-
-/*
- * Closes a file.
- */
-void
-grep_close(struct file *f)
-{
-
-	close(f->fd);
-
-	/* Reset read buffer and line buffer */
-	bufpos = buffer;
-	bufrem = 0;
-
-	free(lnbuf);
-	lnbuf = NULL;
-	lnbuflen = 0;
-}
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/grep.c b/toolbox/upstream-netbsd/usr.bin/grep/grep.c
deleted file mode 100644
index bad2a73..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/grep.c
+++ /dev/null
@@ -1,722 +0,0 @@
-/*	$NetBSD: grep.c,v 1.15 2018/08/12 09:03:21 christos Exp $	*/
-/* 	$FreeBSD: head/usr.bin/grep/grep.c 211519 2010-08-19 22:55:17Z delphij $	*/
-/*	$OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $	*/
-
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: grep.c,v 1.15 2018/08/12 09:03:21 christos Exp $");
-
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <getopt.h>
-#include <limits.h>
-#include <libgen.h>
-#include <locale.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "grep.h"
-
-#ifndef WITHOUT_NLS
-#include <nl_types.h>
-nl_catd	 catalog;
-#endif
-
-/*
- * Default messags to use when NLS is disabled or no catalogue
- * is found.
- */
-const char	*errstr[] = {
-	"",
-/* 1*/	"(standard input)",
-/* 2*/	"cannot read bzip2 compressed file",
-/* 3*/	"unknown %s option",
-/* 4*/	"usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A num] [-B num] [-C[num]]\n",
-/* 5*/	"\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n",
-/* 6*/	"\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n",
-/* 7*/	"\t[pattern] [file ...]\n",
-/* 8*/	"Binary file %s matches\n",
-/* 9*/	"%s (BSD grep) %s\n",
-};
-
-/* Flags passed to regcomp() and regexec() */
-int		 cflags = 0;
-int		 eflags = REG_STARTEND;
-
-/* Searching patterns */
-unsigned int	 patterns, pattern_sz;
-char		**pattern;
-regex_t		*r_pattern;
-fastgrep_t	*fg_pattern;
-
-/* Filename exclusion/inclusion patterns */
-unsigned int	 fpatterns, fpattern_sz;
-unsigned int	 dpatterns, dpattern_sz;
-struct epat	*dpattern, *fpattern;
-
-/* For regex errors  */
-char	 re_error[RE_ERROR_BUF + 1];
-
-/* Command-line flags */
-unsigned long long Aflag;	/* -A x: print x lines trailing each match */
-unsigned long long Bflag;	/* -B x: print x lines leading each match */
-bool	 Hflag;		/* -H: always print file name */
-bool	 Lflag;		/* -L: only show names of files with no matches */
-bool	 bflag;		/* -b: show block numbers for each match */
-bool	 cflag;		/* -c: only show a count of matching lines */
-bool	 hflag;		/* -h: don't print filename headers */
-bool	 iflag;		/* -i: ignore case */
-bool	 lflag;		/* -l: only show names of files with matches */
-bool	 mflag;		/* -m x: stop reading the files after x matches */
-unsigned long long mcount;	/* count for -m */
-bool	 nflag;		/* -n: show line numbers in front of matching lines */
-bool	 oflag;		/* -o: print only matching part */
-bool	 qflag;		/* -q: quiet mode (don't output anything) */
-bool	 sflag;		/* -s: silent mode (ignore errors) */
-bool	 vflag;		/* -v: only show non-matching lines */
-bool	 wflag;		/* -w: pattern must start and end on word boundaries */
-bool	 xflag;		/* -x: pattern must match entire line */
-bool	 lbflag;	/* --line-buffered */
-bool	 nullflag;	/* --null */
-bool	 nulldataflag;	/* --null-data */
-unsigned char line_sep = '\n';	/* 0 for --null-data */
-char	*label;		/* --label */
-const char *color;	/* --color */
-int	 grepbehave = GREP_BASIC;	/* -EFGP: type of the regex */
-int	 binbehave = BINFILE_BIN;	/* -aIU: handling of binary files */
-int	 filebehave = FILE_STDIO;	/* -JZ: normal, gzip or bzip2 file */
-int	 devbehave = DEV_READ;		/* -D: handling of devices */
-int	 dirbehave = DIR_READ;		/* -dRr: handling of directories */
-int	 linkbehave = LINK_READ;	/* -OpS: handling of symlinks */
-
-bool	 dexclude, dinclude;	/* --exclude-dir and --include-dir */
-bool	 fexclude, finclude;	/* --exclude and --include */
-
-enum {
-	BIN_OPT = CHAR_MAX + 1,
-	COLOR_OPT,
-	DECOMPRESS_OPT,
-	HELP_OPT,
-	MMAP_OPT,
-	LINEBUF_OPT,
-	LABEL_OPT,
-	R_EXCLUDE_OPT,
-	R_INCLUDE_OPT,
-	R_DEXCLUDE_OPT,
-	R_DINCLUDE_OPT
-};
-
-static inline const char	*init_color(const char *);
-
-/* Housekeeping */
-int	 tail;		/* lines left to print */
-bool	 notfound;	/* file not found */
-
-extern char	*__progname;
-
-/*
- * Prints usage information and returns 2.
- */
-__dead static void
-usage(void)
-{
-	fprintf(stderr, getstr(4), __progname);
-	fprintf(stderr, "%s", getstr(5));
-	fprintf(stderr, "%s", getstr(6));
-	fprintf(stderr, "%s", getstr(7));
-	exit(2);
-}
-
-static const char optstr[] =
-    "0123456789A:B:C:D:EFGHIJLOPSRUVZabcd:e:f:hilm:nopqrsuvwxyz";
-
-struct option long_options[] =
-{
-	{"binary-files",	required_argument,	NULL, BIN_OPT},
-#ifndef WITHOUT_GZIP
-	{"decompress",          no_argument,            NULL, DECOMPRESS_OPT},
-#endif
-	{"help",		no_argument,		NULL, HELP_OPT},
-	{"mmap",		no_argument,		NULL, MMAP_OPT},
-	{"line-buffered",	no_argument,		NULL, LINEBUF_OPT},
-	{"label",		required_argument,	NULL, LABEL_OPT},
-	{"color",		optional_argument,	NULL, COLOR_OPT},
-	{"colour",		optional_argument,	NULL, COLOR_OPT},
-	{"exclude",		required_argument,	NULL, R_EXCLUDE_OPT},
-	{"include",		required_argument,	NULL, R_INCLUDE_OPT},
-	{"exclude-dir",		required_argument,	NULL, R_DEXCLUDE_OPT},
-	{"include-dir",		required_argument,	NULL, R_DINCLUDE_OPT},
-	{"after-context",	required_argument,	NULL, 'A'},
-	{"text",		no_argument,		NULL, 'a'},
-	{"before-context",	required_argument,	NULL, 'B'},
-	{"byte-offset",		no_argument,		NULL, 'b'},
-	{"context",		optional_argument,	NULL, 'C'},
-	{"count",		no_argument,		NULL, 'c'},
-	{"devices",		required_argument,	NULL, 'D'},
-        {"directories",		required_argument,	NULL, 'd'},
-	{"extended-regexp",	no_argument,		NULL, 'E'},
-	{"regexp",		required_argument,	NULL, 'e'},
-	{"fixed-strings",	no_argument,		NULL, 'F'},
-	{"file",		required_argument,	NULL, 'f'},
-	{"basic-regexp",	no_argument,		NULL, 'G'},
-	{"no-filename",		no_argument,		NULL, 'h'},
-	{"with-filename",	no_argument,		NULL, 'H'},
-	{"ignore-case",		no_argument,		NULL, 'i'},
-#ifndef WITHOUT_BZ2
-	{"bz2decompress",	no_argument,		NULL, 'J'},
-#endif
-	{"files-with-matches",	no_argument,		NULL, 'l'},
-	{"files-without-match", no_argument,            NULL, 'L'},
-	{"max-count",		required_argument,	NULL, 'm'},
-	{"line-number",		no_argument,		NULL, 'n'},
-	{"only-matching",	no_argument,		NULL, 'o'},
-	{"quiet",		no_argument,		NULL, 'q'},
-	{"silent",		no_argument,		NULL, 'q'},
-	{"recursive",		no_argument,		NULL, 'r'},
-	{"no-messages",		no_argument,		NULL, 's'},
-	{"binary",		no_argument,		NULL, 'U'},
-	{"unix-byte-offsets",	no_argument,		NULL, 'u'},
-	{"invert-match",	no_argument,		NULL, 'v'},
-	{"version",		no_argument,		NULL, 'V'},
-	{"word-regexp",		no_argument,		NULL, 'w'},
-	{"line-regexp",		no_argument,		NULL, 'x'},
-	{"null",		no_argument,		NULL, 'Z'},
-	{"null-data",		no_argument,		NULL, 'z'},
-	{NULL,			no_argument,		NULL, 0}
-};
-
-/*
- * Adds a searching pattern to the internal array.
- */
-static void
-add_pattern(char *pat, size_t len)
-{
-
-	/* TODO: Check for empty patterns and shortcut */
-
-	/* Increase size if necessary */
-	if (patterns == pattern_sz) {
-		pattern_sz *= 2;
-		pattern = grep_realloc(pattern, ++pattern_sz *
-		    sizeof(*pattern));
-	}
-	if (len > 0 && pat[len - 1] == '\n')
-		--len;
-	/* pat may not be NUL-terminated */
-	pattern[patterns] = grep_malloc(len + 1);
-	memcpy(pattern[patterns], pat, len);
-	pattern[patterns][len] = '\0';
-	++patterns;
-}
-
-/*
- * Adds a file include/exclude pattern to the internal array.
- */
-static void
-add_fpattern(const char *pat, int mode)
-{
-
-	/* Increase size if necessary */
-	if (fpatterns == fpattern_sz) {
-		fpattern_sz *= 2;
-		fpattern = grep_realloc(fpattern, ++fpattern_sz *
-		    sizeof(struct epat));
-	}
-	fpattern[fpatterns].pat = grep_strdup(pat);
-	fpattern[fpatterns].mode = mode;
-	++fpatterns;
-}
-
-/*
- * Adds a directory include/exclude pattern to the internal array.
- */
-static void
-add_dpattern(const char *pat, int mode)
-{
-
-	/* Increase size if necessary */
-	if (dpatterns == dpattern_sz) {
-		dpattern_sz *= 2;
-		dpattern = grep_realloc(dpattern, ++dpattern_sz *
-		    sizeof(struct epat));
-	}
-	dpattern[dpatterns].pat = grep_strdup(pat);
-	dpattern[dpatterns].mode = mode;
-	++dpatterns;
-}
-
-/*
- * Reads searching patterns from a file and adds them with add_pattern().
- */
-static void
-read_patterns(const char *fn)
-{
-	FILE *f;
-	char *line;
-	size_t len;
-	ssize_t rlen;
-
-	if ((f = fopen(fn, "r")) == NULL)
-		err(2, "%s", fn);
-	line = NULL;
-	len = 0;
-	while ((rlen = getline(&line, &len, f)) != -1)
-		add_pattern(line, *line == '\n' ? 0 : (size_t)rlen);
-	free(line);
-	if (ferror(f))
-		err(2, "%s", fn);
-	fclose(f);
-}
-
-static inline const char *
-init_color(const char *d)
-{
-	char *c;
-
-	c = getenv("GREP_COLOR");
-	return (c != NULL ? c : d);
-}
-
-int
-main(int argc, char *argv[])
-{
-	char **aargv, **eargv, *eopts;
-	char *ep;
-	unsigned long long l;
-	unsigned int aargc, eargc, i, j;
-	int c, lastc, needpattern, newarg, prevoptind;
-
-	setlocale(LC_ALL, "");
-
-#ifndef WITHOUT_NLS
-	catalog = catopen("grep", NL_CAT_LOCALE);
-#endif
-
-	/* Check what is the program name of the binary.  In this
-	   way we can have all the funcionalities in one binary
-	   without the need of scripting and using ugly hacks. */
-	switch (__progname[0]) {
-	case 'e':
-		grepbehave = GREP_EXTENDED;
-		break;
-	case 'f':
-		grepbehave = GREP_FIXED;
-		break;
-	case 'g':
-		grepbehave = GREP_BASIC;
-		break;
-#ifndef WITHOUT_GZIP
-	case 'z':
-		filebehave = FILE_GZIP;
-		switch(__progname[1]) {
-		case 'e':
-			grepbehave = GREP_EXTENDED;
-			break;
-		case 'f':
-			grepbehave = GREP_FIXED;
-			break;
-		case 'g':
-			grepbehave = GREP_BASIC;
-			break;
-		}
-		break;
-#endif
-	}
-
-	lastc = '\0';
-	newarg = 1;
-	prevoptind = 1;
-	needpattern = 1;
-
-	eopts = getenv("GREP_OPTIONS");
-
-	/* support for extra arguments in GREP_OPTIONS */
-	eargc = 0;
-	if (eopts != NULL) {
-		char *str;
-
-		/* make an estimation of how many extra arguments we have */
-		for (j = 0; j < strlen(eopts); j++)
-			if (eopts[j] == ' ')
-				eargc++;
-
-		eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
-
-		eargc = 0;
-		/* parse extra arguments */
-		while ((str = strsep(&eopts, " ")) != NULL)
-			eargv[eargc++] = grep_strdup(str);
-
-		aargv = (char **)grep_calloc(eargc + argc + 1,
-		    sizeof(char *));
-
-		aargv[0] = argv[0];
-		for (i = 0; i < eargc; i++)
-			aargv[i + 1] = eargv[i];
-		for (j = 1; j < (unsigned int)argc; j++, i++)
-			aargv[i + 1] = argv[j];
-
-		aargc = eargc + argc;
-	} else {
-		aargv = argv;
-		aargc = argc;
-	}
-
-	while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
-	    -1)) {
-		switch (c) {
-		case '0': case '1': case '2': case '3': case '4':
-		case '5': case '6': case '7': case '8': case '9':
-			if (newarg || !isdigit(lastc))
-				Aflag = 0;
-			else if (Aflag > LLONG_MAX / 10) {
-				errno = ERANGE;
-				err(2, NULL);
-			}
-			Aflag = Bflag = (Aflag * 10) + (c - '0');
-			break;
-		case 'C':
-			if (optarg == NULL) {
-				Aflag = Bflag = 2;
-				break;
-			}
-			/* FALLTHROUGH */
-		case 'A':
-			/* FALLTHROUGH */
-		case 'B':
-			errno = 0;
-			l = strtoull(optarg, &ep, 10);
-			if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
-			    ((errno == EINVAL) && (l == 0)))
-				err(2, NULL);
-			else if (ep[0] != '\0') {
-				errno = EINVAL;
-				err(2, NULL);
-			}
-			if (c == 'A')
-				Aflag = l;
-			else if (c == 'B')
-				Bflag = l;
-			else
-				Aflag = Bflag = l;
-			break;
-		case 'a':
-			binbehave = BINFILE_TEXT;
-			break;
-		case 'b':
-			bflag = true;
-			break;
-		case 'c':
-			cflag = true;
-			break;
-		case 'D':
-			if (strcasecmp(optarg, "skip") == 0)
-				devbehave = DEV_SKIP;
-			else if (strcasecmp(optarg, "read") == 0)
-				devbehave = DEV_READ;
-			else
-				errx(2, getstr(3), "--devices");
-			break;
-		case 'd':
-			if (strcasecmp("recurse", optarg) == 0) {
-				Hflag = true;
-				dirbehave = DIR_RECURSE;
-			} else if (strcasecmp("skip", optarg) == 0)
-				dirbehave = DIR_SKIP;
-			else if (strcasecmp("read", optarg) == 0)
-				dirbehave = DIR_READ;
-			else
-				errx(2, getstr(3), "--directories");
-			break;
-		case 'E':
-			grepbehave = GREP_EXTENDED;
-			break;
-		case 'e':
-			add_pattern(optarg, strlen(optarg));
-			needpattern = 0;
-			break;
-		case 'F':
-			grepbehave = GREP_FIXED;
-			break;
-		case 'f':
-			read_patterns(optarg);
-			needpattern = 0;
-			break;
-		case 'G':
-			grepbehave = GREP_BASIC;
-			break;
-		case 'H':
-			Hflag = true;
-			break;
-		case 'h':
-			Hflag = false;
-			hflag = true;
-			break;
-		case 'I':
-			binbehave = BINFILE_SKIP;
-			break;
-		case 'i':
-		case 'y':
-			iflag =  true;
-			cflags |= REG_ICASE;
-			break;
-#ifndef WITHOUT_BZ2
-		case 'J':
-			filebehave = FILE_BZIP;
-			break;
-#endif
-		case 'L':
-			lflag = false;
-			Lflag = true;
-			break;
-		case 'l':
-			Lflag = false;
-			lflag = true;
-			break;
-		case 'm':
-			mflag = true;
-			errno = 0;
-			mcount = strtoull(optarg, &ep, 10);
-			if (((errno == ERANGE) && (mcount == ULLONG_MAX)) ||
-			    ((errno == EINVAL) && (mcount == 0)))
-				err(2, NULL);
-			else if (ep[0] != '\0') {
-				errno = EINVAL;
-				err(2, NULL);
-			}
-			break;
-		case 'n':
-			nflag = true;
-			break;
-		case 'O':
-			linkbehave = LINK_EXPLICIT;
-			break;
-		case 'o':
-			oflag = true;
-			break;
-		case 'p':
-			linkbehave = LINK_SKIP;
-			break;
-		case 'q':
-			qflag = true;
-			break;
-		case 'S':
-			linkbehave = LINK_READ;
-			break;
-		case 'R':
-		case 'r':
-			dirbehave = DIR_RECURSE;
-			Hflag = true;
-			break;
-		case 's':
-			sflag = true;
-			break;
-		case 'U':
-			binbehave = BINFILE_BIN;
-			break;
-		case 'u':
-		case MMAP_OPT:
-			/* noop, compatibility */
-			break;
-		case 'V':
-			printf(getstr(9), __progname, VERSION);
-			exit(0);
-		case 'v':
-			vflag = true;
-			break;
-		case 'w':
-			wflag = true;
-			break;
-		case 'x':
-			xflag = true;
-			break;
-		case 'Z':
-			nullflag = true;
-			break;
-		case 'z':
-			nulldataflag = true;
-			line_sep = '\0';
-			break;
-		case BIN_OPT:
-			if (strcasecmp("binary", optarg) == 0)
-				binbehave = BINFILE_BIN;
-			else if (strcasecmp("without-match", optarg) == 0)
-				binbehave = BINFILE_SKIP;
-			else if (strcasecmp("text", optarg) == 0)
-				binbehave = BINFILE_TEXT;
-			else
-				errx(2, getstr(3), "--binary-files");
-			break;
-		case COLOR_OPT:
-			color = NULL;
-			if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
-			    strcasecmp("tty", optarg) == 0 ||
-			    strcasecmp("if-tty", optarg) == 0) {
-				char *term;
-
-				term = getenv("TERM");
-				if (isatty(STDOUT_FILENO) && term != NULL &&
-				    strcasecmp(term, "dumb") != 0)
-					color = init_color("01;31");
-			} else if (strcasecmp("always", optarg) == 0 ||
-			    strcasecmp("yes", optarg) == 0 ||
-			    strcasecmp("force", optarg) == 0) {
-				color = init_color("01;31");
-			} else if (strcasecmp("never", optarg) != 0 &&
-			    strcasecmp("none", optarg) != 0 &&
-			    strcasecmp("no", optarg) != 0)
-				errx(2, getstr(3), "--color");
-			break;
-#ifndef WITHOUT_GZIP
-		case DECOMPRESS_OPT:
-			filebehave = FILE_GZIP;
-			break;
-#endif
-		case LABEL_OPT:
-			label = optarg;
-			break;
-		case LINEBUF_OPT:
-			lbflag = true;
-			break;
-		case R_INCLUDE_OPT:
-			finclude = true;
-			add_fpattern(optarg, INCL_PAT);
-			break;
-		case R_EXCLUDE_OPT:
-			fexclude = true;
-			add_fpattern(optarg, EXCL_PAT);
-			break;
-		case R_DINCLUDE_OPT:
-			dinclude = true;
-			add_dpattern(optarg, INCL_PAT);
-			break;
-		case R_DEXCLUDE_OPT:
-			dexclude = true;
-			add_dpattern(optarg, EXCL_PAT);
-			break;
-		case HELP_OPT:
-		default:
-			usage();
-		}
-		lastc = c;
-		newarg = optind != prevoptind;
-		prevoptind = optind;
-	}
-	aargc -= optind;
-	aargv += optind;
-
-	/* Fail if we don't have any pattern */
-	if (aargc == 0 && needpattern)
-		usage();
-
-	/* Process patterns from command line */
-	if (aargc != 0 && needpattern) {
-		add_pattern(*aargv, strlen(*aargv));
-		--aargc;
-		++aargv;
-	}
-
-	switch (grepbehave) {
-	case GREP_FIXED:
-	case GREP_BASIC:
-		break;
-	case GREP_EXTENDED:
-		cflags |= REG_EXTENDED;
-		break;
-	default:
-		/* NOTREACHED */
-		usage();
-	}
-
-	fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern));
-	r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
-/*
- * XXX: fgrepcomp() and fastcomp() are workarounds for regexec() performance.
- * Optimizations should be done there.
- */
-		/* Check if cheating is allowed (always is for fgrep). */
-	if (grepbehave == GREP_FIXED) {
-		for (i = 0; i < patterns; ++i)
-			fgrepcomp(&fg_pattern[i], pattern[i]);
-	} else {
-		for (i = 0; i < patterns; ++i) {
-			if (fastcomp(&fg_pattern[i], pattern[i])) {
-				/* Fall back to full regex library */
-				c = regcomp(&r_pattern[i], pattern[i], cflags);
-				if (c != 0) {
-					regerror(c, &r_pattern[i], re_error,
-					    RE_ERROR_BUF);
-					errx(2, "%s", re_error);
-				}
-			}
-		}
-	}
-
-	if (lbflag) {
-#ifdef _IOLBF
-		setvbuf(stdout, NULL, _IOLBF, 0);
-#else
-		setlinebuf(stdout);
-#endif
-	}
-
-	if ((aargc == 0 || aargc == 1) && !Hflag)
-		hflag = true;
-
-	if (aargc == 0)
-		exit(!procfile("-"));
-
-	if (dirbehave == DIR_RECURSE)
-		c = grep_tree(aargv);
-	else
-		for (c = 0; aargc--; ++aargv) {
-			if ((finclude || fexclude) && !file_matching(*aargv))
-				continue;
-			c+= procfile(*aargv);
-		}
-
-#ifndef WITHOUT_NLS
-	catclose(catalog);
-#endif
-
-	/* Find out the correct return value according to the
-	   results and the command line option. */
-	exit(c ? (notfound ? (qflag ? 0 : 2) : 0) : (notfound ? 2 : 1));
-}
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/grep.h b/toolbox/upstream-netbsd/usr.bin/grep/grep.h
deleted file mode 100644
index b7ef7fa..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/grep.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*	$NetBSD: grep.h,v 1.10 2018/08/12 09:03:21 christos Exp $	*/
-/*	$OpenBSD: grep.h,v 1.15 2010/04/05 03:03:55 tedu Exp $	*/
-/*	$FreeBSD: head/usr.bin/grep/grep.h 211496 2010-08-19 09:28:59Z des $	*/
-
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * Copyright (c) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef WITHOUT_BZ2
-#include <bzlib.h>
-#endif
-#include <limits.h>
-#include <regex.h>
-#include <stdbool.h>
-#include <stdio.h>
-#ifndef WITHOUT_GZIP
-#include <zlib.h>
-#endif
-
-#ifdef WITHOUT_NLS
-#define getstr(n)	 errstr[n]
-#else
-#include <nl_types.h>
-
-extern nl_catd		 catalog;
-#define getstr(n)	 catgets(catalog, 1, n, errstr[n])
-#endif
-
-extern const char		*errstr[];
-
-#define VERSION		"2.5.1-FreeBSD"
-
-#define GREP_FIXED	0
-#define GREP_BASIC	1
-#define GREP_EXTENDED	2
-
-#define BINFILE_BIN	0
-#define BINFILE_SKIP	1
-#define BINFILE_TEXT	2
-
-#define FILE_STDIO	0
-#define FILE_GZIP	1
-#define FILE_BZIP	2
-
-#define DIR_READ	0
-#define DIR_SKIP	1
-#define DIR_RECURSE	2
-
-#define DEV_READ	0
-#define DEV_SKIP	1
-
-#define LINK_READ	0
-#define LINK_EXPLICIT	1
-#define LINK_SKIP	2
-
-#define EXCL_PAT	0
-#define INCL_PAT	1
-
-#define MAX_LINE_MATCHES	32
-
-struct file {
-	int		 fd;
-	bool		 binary;
-};
-
-struct str {
-	off_t		 off;
-	size_t		 len;
-	char		*dat;
-	char		*file;
-	int		 line_no;
-};
-
-struct epat {
-	char		*pat;
-	int		 mode;
-};
-
-typedef struct {
-	size_t		 len;
-	unsigned char	*pattern;
-	int		 qsBc[UCHAR_MAX + 1];
-	/* flags */
-	bool		 bol;
-	bool		 eol;
-	bool		 reversed;
-	bool		 word;
-} fastgrep_t;
-
-/* Flags passed to regcomp() and regexec() */
-extern int	 cflags, eflags;
-
-/* Command line flags */
-extern bool	 Eflag, Fflag, Gflag, Hflag, Lflag,
-		 bflag, cflag, hflag, iflag, lflag, mflag, nflag, oflag,
-		 qflag, sflag, vflag, wflag, xflag;
-extern bool	 dexclude, dinclude, fexclude, finclude, lbflag, nullflag, nulldataflag;
-extern unsigned char line_sep;
-extern unsigned long long Aflag, Bflag, mcount;
-extern char	*label;
-extern const char *color;
-extern int	 binbehave, devbehave, dirbehave, filebehave, grepbehave, linkbehave;
-
-extern bool	 notfound;
-extern int	 tail;
-extern unsigned int dpatterns, fpatterns, patterns;
-extern char    **pattern;
-extern struct epat *dpattern, *fpattern;
-extern regex_t	*er_pattern, *r_pattern;
-extern fastgrep_t *fg_pattern;
-
-/* For regex errors  */
-#define RE_ERROR_BUF	512
-extern char	 re_error[RE_ERROR_BUF + 1];	/* Seems big enough */
-
-/* util.c */
-bool	 file_matching(const char *fname);
-int	 procfile(const char *fn);
-int	 grep_tree(char **argv);
-void	*grep_malloc(size_t size);
-void	*grep_calloc(size_t nmemb, size_t size);
-void	*grep_realloc(void *ptr, size_t size);
-char	*grep_strdup(const char *str);
-void	 printline(struct str *line, int sep, regmatch_t *matches, int m);
-
-/* queue.c */
-void	 enqueue(struct str *x);
-void	 printqueue(void);
-void	 clearqueue(void);
-
-/* file.c */
-void		 grep_close(struct file *f);
-struct file	*grep_open(const char *path);
-char		*grep_fgetln(struct file *f, size_t *len);
-
-/* fastgrep.c */
-int		 fastcomp(fastgrep_t *, const char *);
-void		 fgrepcomp(fastgrep_t *, const char *);
-int		 grep_search(fastgrep_t *, const unsigned char *, size_t, regmatch_t *);
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/queue.c b/toolbox/upstream-netbsd/usr.bin/grep/queue.c
deleted file mode 100644
index e3c6be1..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/queue.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*	$NetBSD: queue.c,v 1.5 2011/08/31 16:24:57 plunky Exp $	*/
-/*	$FreeBSD: head/usr.bin/grep/queue.c 211496 2010-08-19 09:28:59Z des $	*/
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * A really poor man's queue.  It does only what it has to and gets out of
- * Dodge.  It is used in place of <sys/queue.h> to get a better performance.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: queue.c,v 1.5 2011/08/31 16:24:57 plunky Exp $");
-
-#include <sys/param.h>
-#include <sys/queue.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "grep.h"
-
-struct qentry {
-	STAILQ_ENTRY(qentry)	list;
-	struct str	 	data;
-};
-
-static STAILQ_HEAD(, qentry)	queue = STAILQ_HEAD_INITIALIZER(queue);
-static unsigned long long	count;
-
-static struct qentry	*dequeue(void);
-
-void
-enqueue(struct str *x)
-{
-	struct qentry *item;
-
-	item = grep_malloc(sizeof(struct qentry));
-	item->data.dat = grep_malloc(sizeof(char) * x->len);
-	item->data.len = x->len;
-	item->data.line_no = x->line_no;
-	item->data.off = x->off;
-	memcpy(item->data.dat, x->dat, x->len);
-	item->data.file = x->file;
-
-	STAILQ_INSERT_TAIL(&queue, item, list);
-
-	if (++count > Bflag) {
-		item = dequeue();
-		free(item->data.dat);
-		free(item);
-	}
-}
-
-static struct qentry *
-dequeue(void)
-{
-	struct qentry *item;
-
-	item = STAILQ_FIRST(&queue);
-	if (item == NULL)
-		return (NULL);
-
-	STAILQ_REMOVE_HEAD(&queue, list);
-	--count;
-	return (item);
-}
-
-void
-printqueue(void)
-{
-	struct qentry *item;
-
-	while ((item = dequeue()) != NULL) {
-		printline(&item->data, '-', NULL, 0);
-		free(item->data.dat);
-		free(item);
-	}
-}
-
-void
-clearqueue(void)
-{
-	struct qentry *item;
-
-	while ((item = dequeue()) != NULL) {
-		free(item->data.dat);
-		free(item);
-	}
-}
diff --git a/toolbox/upstream-netbsd/usr.bin/grep/util.c b/toolbox/upstream-netbsd/usr.bin/grep/util.c
deleted file mode 100644
index a3c9e4c..0000000
--- a/toolbox/upstream-netbsd/usr.bin/grep/util.c
+++ /dev/null
@@ -1,500 +0,0 @@
-/*	$NetBSD: util.c,v 1.19 2018/02/05 22:14:26 mrg Exp $	*/
-/*	$FreeBSD: head/usr.bin/grep/util.c 211496 2010-08-19 09:28:59Z des $	*/
-/*	$OpenBSD: util.c,v 1.39 2010/07/02 22:18:03 tedu Exp $	*/
-
-/*-
- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
- * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if HAVE_NBTOOL_CONFIG_H
-#include "nbtool_config.h"
-#endif
-
-#include <sys/cdefs.h>
-__RCSID("$NetBSD: util.c,v 1.19 2018/02/05 22:14:26 mrg Exp $");
-
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <fnmatch.h>
-#include <fts.h>
-#include <libgen.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <wchar.h>
-#include <wctype.h>
-
-#include "grep.h"
-
-static bool	 first, first_global = true;
-static unsigned long long since_printed;
-
-static int	 procline(struct str *l, int);
-
-bool
-file_matching(const char *fname)
-{
-	char *fname_base, *fname_copy;
-	unsigned int i;
-	bool ret;
-
-	ret = finclude ? false : true;
-	fname_copy = grep_strdup(fname);
-	fname_base = basename(fname_copy);
-
-	for (i = 0; i < fpatterns; ++i) {
-		if (fnmatch(fpattern[i].pat, fname, 0) == 0 ||
-		    fnmatch(fpattern[i].pat, fname_base, 0) == 0) {
-			if (fpattern[i].mode == EXCL_PAT) {
-				free(fname_copy);
-				return (false);
-			} else
-				ret = true;
-		}
-	}
-	free(fname_copy);
-	return (ret);
-}
-
-static inline bool
-dir_matching(const char *dname)
-{
-	unsigned int i;
-	bool ret;
-
-	ret = dinclude ? false : true;
-
-	for (i = 0; i < dpatterns; ++i) {
-		if (dname != NULL &&
-		    fnmatch(dname, dpattern[i].pat, 0) == 0) {
-			if (dpattern[i].mode == EXCL_PAT)
-				return (false);
-			else
-				ret = true;
-		}
-	}
-	return (ret);
-}
-
-/*
- * Processes a directory when a recursive search is performed with
- * the -R option.  Each appropriate file is passed to procfile().
- */
-int
-grep_tree(char **argv)
-{
-	FTS *fts;
-	FTSENT *p;
-	char *d, *dir = NULL;
-	int c, fts_flags;
-	bool ok;
-
-	c = fts_flags = 0;
-
-	switch(linkbehave) {
-	case LINK_EXPLICIT:
-		fts_flags = FTS_COMFOLLOW;
-		break;
-	case LINK_SKIP:
-		fts_flags = FTS_PHYSICAL;
-		break;
-	default:
-		fts_flags = FTS_LOGICAL;
-			
-	}
-
-	fts_flags |= FTS_NOSTAT | FTS_NOCHDIR;
-
-	if (!(fts = fts_open(argv, fts_flags, NULL)))
-		err(2, "fts_open");
-	while ((p = fts_read(fts)) != NULL) {
-		switch (p->fts_info) {
-		case FTS_DNR:
-			/* FALLTHROUGH */
-		case FTS_ERR:
-			errx(2, "%s: %s", p->fts_path, strerror(p->fts_errno));
-			break;
-		case FTS_D:
-			/* FALLTHROUGH */
-		case FTS_DP:
-			break;
-		case FTS_DC:
-			/* Print a warning for recursive directory loop */
-			warnx("warning: %s: recursive directory loop",
-				p->fts_path);
-			break;
-		default:
-			/* Check for file exclusion/inclusion */
-			ok = true;
-			if (dexclude || dinclude) {
-				if ((d = strrchr(p->fts_path, '/')) != NULL) {
-					dir = grep_malloc(sizeof(char) *
-					    (d - p->fts_path + 1));
-					memcpy(dir, p->fts_path,
-					    d - p->fts_path);
-					dir[d - p->fts_path] = '\0';
-				}
-				ok = dir_matching(dir);
-				free(dir);
-				dir = NULL;
-			}
-			if (fexclude || finclude)
-				ok &= file_matching(p->fts_path);
-
-			if (ok)
-				c += procfile(p->fts_path);
-			break;
-		}
-	}
-
-	fts_close(fts);
-	return (c);
-}
-
-/*
- * Opens a file and processes it.  Each file is processed line-by-line
- * passing the lines to procline().
- */
-int
-procfile(const char *fn)
-{
-	struct file *f;
-	struct stat sb;
-	struct str ln;
-	mode_t s;
-	int c, t;
-
-	if (mflag && (mcount <= 0))
-		return (0);
-
-	if (strcmp(fn, "-") == 0) {
-		fn = label != NULL ? label : getstr(1);
-		f = grep_open(NULL);
-	} else {
-		if (!stat(fn, &sb)) {
-			/* Check if we need to process the file */
-			s = sb.st_mode & S_IFMT;
-			if (s == S_IFDIR && dirbehave == DIR_SKIP)
-				return (0);
-			if ((s == S_IFIFO || s == S_IFCHR || s == S_IFBLK
-				|| s == S_IFSOCK) && devbehave == DEV_SKIP)
-					return (0);
-		}
-		f = grep_open(fn);
-	}
-	if (f == NULL) {
-		if (!sflag)
-			warn("%s", fn);
-		if (errno == ENOENT)
-			notfound = true;
-		return (0);
-	}
-
-	ln.file = grep_malloc(strlen(fn) + 1);
-	strcpy(ln.file, fn);
-	ln.line_no = 0;
-	ln.len = 0;
-	tail = 0;
-	ln.off = -1;
-
-	for (first = true, c = 0;  c == 0 || !(lflag || qflag); ) {
-		ln.off += ln.len + 1;
-		if ((ln.dat = grep_fgetln(f, &ln.len)) == NULL || ln.len == 0)
-			break;
-		if (ln.len > 0 && ln.dat[ln.len - 1] == line_sep)
-			--ln.len;
-		ln.line_no++;
-
-		/* Return if we need to skip a binary file */
-		if (f->binary && binbehave == BINFILE_SKIP) {
-			grep_close(f);
-			free(ln.file);
-			free(f);
-			return (0);
-		}
-		/* Process the file line-by-line */
-		t = procline(&ln, f->binary);
-		c += t;
-
-		/* Count the matches if we have a match limit */
-		if (mflag) {
-			mcount -= t;
-			if (mcount <= 0)
-				break;
-		}
-	}
-	if (Bflag > 0)
-		clearqueue();
-	grep_close(f);
-
-	if (cflag) {
-		if (!hflag)
-			printf("%s:", ln.file);
-		printf("%u%c", c, line_sep);
-	}
-	if (lflag && !qflag && c != 0)
-		printf("%s%c", fn, line_sep);
-	if (Lflag && !qflag && c == 0)
-		printf("%s%c", fn, line_sep);
-	if (c && !cflag && !lflag && !Lflag &&
-	    binbehave == BINFILE_BIN && f->binary && !qflag)
-		printf(getstr(8), fn);
-
-	free(ln.file);
-	free(f);
-	return (c);
-}
-
-#define iswword(x)	(iswalnum((x)) || (x) == L'_')
-
-/*
- * Processes a line comparing it with the specified patterns.  Each pattern
- * is looped to be compared along with the full string, saving each and every
- * match, which is necessary to colorize the output and to count the
- * matches.  The matching lines are passed to printline() to display the
- * appropriate output.
- */
-static int
-procline(struct str *l, int nottext)
-{
-	regmatch_t matches[MAX_LINE_MATCHES];
-	regmatch_t pmatch;
-	size_t st = 0;
-	unsigned int i;
-	int c = 0, m = 0, r = 0;
-
-	/* Loop to process the whole line */
-	while (st <= l->len) {
-		pmatch.rm_so = st;
-		pmatch.rm_eo = l->len;
-
-		/* Loop to compare with all the patterns */
-		for (i = 0; i < patterns; i++) {
-/*
- * XXX: grep_search() is a workaround for speed up and should be
- * removed in the future.  See fastgrep.c.
- */
-			if (fg_pattern[i].pattern) {
-				r = grep_search(&fg_pattern[i],
-				    (unsigned char *)l->dat,
-				    l->len, &pmatch);
-				r = (r == 0) ? 0 : REG_NOMATCH;
-				st = pmatch.rm_eo;
-			} else {
-				r = regexec(&r_pattern[i], l->dat, 1,
-				    &pmatch, eflags);
-				r = (r == 0) ? 0 : REG_NOMATCH;
-				st = pmatch.rm_eo;
-			}
-			if (r == REG_NOMATCH)
-				continue;
-			/* Check for full match */
-			if (xflag &&
-			    (pmatch.rm_so != 0 ||
-			     (size_t)pmatch.rm_eo != l->len))
-				continue;
-			/* Check for whole word match */
-			if (fg_pattern[i].word && pmatch.rm_so != 0) {
-				wchar_t wbegin, wend;
-
-				wbegin = wend = L' ';
-				if (pmatch.rm_so != 0 &&
-				    sscanf(&l->dat[pmatch.rm_so - 1],
-				    "%lc", &wbegin) != 1)
-					continue;
-				if ((size_t)pmatch.rm_eo != l->len &&
-				    sscanf(&l->dat[pmatch.rm_eo],
-				    "%lc", &wend) != 1)
-					continue;
-				if (iswword(wbegin) || iswword(wend))
-					continue;
-			}
-			c = 1;
-			if (m < MAX_LINE_MATCHES)
-				matches[m++] = pmatch;
-			/* matches - skip further patterns */
-			if ((color != NULL && !oflag) || qflag || lflag)
-				break;
-		}
-
-		if (vflag) {
-			c = !c;
-			break;
-		}
-		/* One pass if we are not recording matches */
-		if ((color != NULL && !oflag) || qflag || lflag)
-			break;
-
-		if (st == (size_t)pmatch.rm_so)
-			break; 	/* No matches */
-	}
-
-	if (c && binbehave == BINFILE_BIN && nottext)
-		return (c); /* Binary file */
-
-	/* Dealing with the context */
-	if ((tail || c) && !cflag && !qflag && !lflag && !Lflag) {
-		if (c) {
-			if ((Aflag || Bflag) && !first_global &&
-			    (first || since_printed > Bflag))
-				printf("--\n");
-			tail = Aflag;
-			if (Bflag > 0)
-				printqueue();
-			printline(l, ':', matches, m);
-		} else {
-			printline(l, '-', matches, m);
-			tail--;
-		}
-		first = false;
-		first_global = false;
-		since_printed = 0;
-	} else {
-		if (Bflag)
-			enqueue(l);
-		since_printed++;
-	}
-	return (c);
-}
-
-/*
- * Safe malloc() for internal use.
- */
-void *
-grep_malloc(size_t size)
-{
-	void *ptr;
-
-	if ((ptr = malloc(size)) == NULL)
-		err(2, "malloc");
-	return (ptr);
-}
-
-/*
- * Safe calloc() for internal use.
- */
-void *
-grep_calloc(size_t nmemb, size_t size)
-{
-	void *ptr;
-
-	if ((ptr = calloc(nmemb, size)) == NULL)
-		err(2, "calloc");
-	return (ptr);
-}
-
-/*
- * Safe realloc() for internal use.
- */
-void *
-grep_realloc(void *ptr, size_t size)
-{
-
-	if ((ptr = realloc(ptr, size)) == NULL)
-		err(2, "realloc");
-	return (ptr);
-}
-
-/*
- * Safe strdup() for internal use.
- */
-char *
-grep_strdup(const char *str)
-{
-	char *ret;
-
-	if ((ret = strdup(str)) == NULL)
-		err(2, "strdup");
-	return (ret);
-}
-
-/*
- * Prints a matching line according to the command line options.
- */
-void
-printline(struct str *line, int sep, regmatch_t *matches, int m)
-{
-	size_t a = 0;
-	int i, n = 0;
-
-	if (!hflag) {
-		if (nullflag == 0)
-			fputs(line->file, stdout);
-		else {
-			printf("%s", line->file);
-			putchar(0);
-		}
-		++n;
-	}
-	if (nflag) {
-		if (n > 0)
-			putchar(sep);
-		printf("%d", line->line_no);
-		++n;
-	}
-	if (bflag) {
-		if (n > 0)
-			putchar(sep);
-		printf("%lld", (long long)line->off);
-		++n;
-	}
-	if (n)
-		putchar(sep);
-	/* --color and -o */
-	if ((oflag || color) && m > 0) {
-		for (i = 0; i < m; i++) {
-			if (!oflag)
-				fwrite(line->dat + a, matches[i].rm_so - a, 1,
-				    stdout);
-			if (color) 
-				fprintf(stdout, "\33[%sm\33[K", color);
-
-			fwrite(line->dat + matches[i].rm_so, 
-			    matches[i].rm_eo - matches[i].rm_so, 1,
-			    stdout);
-
-			if (color) 
-				fprintf(stdout, "\33[m\33[K");
-			a = matches[i].rm_eo;
-			if (oflag)
-				putchar('\n');
-		}
-		if (!oflag) {
-			if (line->len - a > 0)
-				fwrite(line->dat + a, line->len - a, 1, stdout);
-			putchar(line_sep);
-		}
-	} else {
-		fwrite(line->dat, line->len, 1, stdout);
-		putchar(line_sep);
-	}
-}