Merge "Snap for 6533464 from 37e8b5e58770102168086e05546003f16c6b5613 to sdk-release" into sdk-release
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..d97975c
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,3 @@
+third_party {
+  license_type: NOTICE
+}
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 9b6213a..7933629 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -28,12 +28,6 @@
       "name": "fs_mgr_vendor_overlay_test"
     },
     {
-      "name": "init_kill_services_test"
-    },
-    {
-      "name": "libbase_test"
-    },
-    {
       "name": "libpackagelistparser_test"
     },
     {
@@ -63,15 +57,6 @@
     },
     {
       "name": "propertyinfoserializer_tests"
-    },
-    {
-      "name": "ziparchive-tests"
-    }
-  ],
-
-  "postsubmit": [
-    {
-      "name": "ziparchive_tests_large"
     }
   ]
 }
diff --git a/adb/Android.bp b/adb/Android.bp
index 432770c..9db151d 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -218,6 +218,7 @@
         "client/usb_dispatch.cpp",
         "client/transport_local.cpp",
         "client/transport_mdns.cpp",
+        "client/mdns_utils.cpp",
         "client/transport_usb.cpp",
         "client/pairing/pairing_client.cpp",
     ],
@@ -264,7 +265,10 @@
 cc_test_host {
     name: "adb_test",
     defaults: ["adb_defaults"],
-    srcs: libadb_test_srcs,
+    srcs: libadb_test_srcs + [
+        "client/mdns_utils_test.cpp",
+    ],
+
     static_libs: [
         "libadb_crypto_static",
         "libadb_host",
diff --git a/adb/adb.cpp b/adb/adb.cpp
index dcec0ba..08986b7 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -109,7 +109,9 @@
 {
     D("adb: online");
     t->online = 1;
+#if ADB_HOST
     t->SetConnectionEstablished(true);
+#endif
 }
 
 void handle_offline(atransport *t)
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index 43a9252..124e2d8 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -73,6 +73,7 @@
 typedef std::list<std::unique_ptr<alistener>> ListenerList;
 static ListenerList& listener_list GUARDED_BY(listener_list_mutex) = *new ListenerList();
 
+#if ADB_HOST
 static void ss_listener_event_func(int _fd, unsigned ev, void *_l) {
     if (ev & FDE_READ) {
         unique_fd fd(adb_socket_accept(_fd, nullptr, nullptr));
@@ -88,6 +89,7 @@
         }
     }
 }
+#endif
 
 static void listener_event_func(int _fd, unsigned ev, void* _l)
 {
@@ -164,7 +166,7 @@
     }
 }
 
-void enable_daemon_sockets() EXCLUDES(listener_list_mutex) {
+void enable_server_sockets() EXCLUDES(listener_list_mutex) {
     std::lock_guard<std::mutex> lock(listener_list_mutex);
     for (auto& l : listener_list) {
         if (l->connect_to == "*smartsocket*") {
@@ -173,6 +175,7 @@
     }
 }
 
+#if ADB_HOST
 void close_smartsockets() EXCLUDES(listener_list_mutex) {
     std::lock_guard<std::mutex> lock(listener_list_mutex);
     auto pred = [](const std::unique_ptr<alistener>& listener) {
@@ -180,6 +183,7 @@
     };
     listener_list.remove_if(pred);
 }
+#endif
 
 InstallStatus install_listener(const std::string& local_name, const char* connect_to,
                                atransport* transport, int flags, int* resolved_tcp_port,
@@ -188,7 +192,7 @@
     for (auto& l : listener_list) {
         if (local_name == l->local_name) {
             // Can't repurpose a smartsocket.
-            if(l->connect_to[0] == '*') {
+            if (l->connect_to[0] == '*') {
                 *error = "cannot repurpose smartsocket";
                 return INSTALL_STATUS_INTERNAL_ERROR;
             }
@@ -227,7 +231,11 @@
 
     close_on_exec(listener->fd);
     if (listener->connect_to == "*smartsocket*") {
+#if ADB_HOST
         listener->fde = fdevent_create(listener->fd, ss_listener_event_func, listener.get());
+#else
+        LOG(FATAL) << "attempted to connect to *smartsocket* in daemon";
+#endif
     } else {
         listener->fde = fdevent_create(listener->fd, listener_event_func, listener.get());
     }
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index 354dcc5..0aa774a 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef __ADB_LISTENERS_H
-#define __ADB_LISTENERS_H
+#pragma once
 
 #include "adb.h"
 
@@ -44,7 +43,7 @@
 InstallStatus remove_listener(const char* local_name, atransport* transport);
 void remove_all_listeners(void);
 
-void enable_daemon_sockets();
+#if ADB_HOST
+void enable_server_sockets();
 void close_smartsockets();
-
-#endif /* __ADB_LISTENERS_H */
+#endif
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index c579dde..210241c 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -90,7 +90,7 @@
 int adb_trace_mask;
 
 std::string get_trace_setting() {
-#if ADB_HOST
+#if ADB_HOST || !defined(__ANDROID__)
     const char* setting = getenv("ADB_TRACE");
     if (setting == nullptr) {
         setting = "";
diff --git a/adb/adb_wifi.h b/adb/adb_wifi.h
index 3a6b0b1..42f414b 100644
--- a/adb/adb_wifi.h
+++ b/adb/adb_wifi.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <optional>
 #include <string>
 
 #include "adb.h"
@@ -30,6 +31,19 @@
 std::string mdns_check();
 std::string mdns_list_discovered_services();
 
+struct MdnsInfo {
+    std::string service_name;
+    std::string service_type;
+    std::string addr;
+    uint16_t port = 0;
+
+    MdnsInfo(std::string_view name, std::string_view type, std::string_view addr, uint16_t port)
+        : service_name(name), service_type(type), addr(addr), port(port) {}
+};
+
+std::optional<MdnsInfo> mdns_get_connect_service_info(std::string_view name);
+std::optional<MdnsInfo> mdns_get_pairing_service_info(std::string_view name);
+
 #else  // !ADB_HOST
 
 struct AdbdAuthContext;
diff --git a/adb/client/adb_client.cpp b/adb/client/adb_client.cpp
index 31c938c..a308732 100644
--- a/adb/client/adb_client.cpp
+++ b/adb/client/adb_client.cpp
@@ -417,17 +417,19 @@
 }
 
 const std::optional<FeatureSet>& adb_get_feature_set(std::string* error) {
-    static std::string cached_error [[clang::no_destroy]];
-    static const std::optional<FeatureSet> features
-            [[clang::no_destroy]] ([]() -> std::optional<FeatureSet> {
-                std::string result;
-                if (adb_query(format_host_command("features"), &result, &cached_error)) {
-                    return StringToFeatureSet(result);
-                }
-                return std::nullopt;
-            }());
-    if (!features && error) {
-        *error = cached_error;
+    static std::mutex feature_mutex [[clang::no_destroy]];
+    static std::optional<FeatureSet> features [[clang::no_destroy]] GUARDED_BY(feature_mutex);
+    std::lock_guard<std::mutex> lock(feature_mutex);
+    if (!features) {
+        std::string result;
+        std::string err;
+        if (adb_query(format_host_command("features"), &result, &err)) {
+            features = StringToFeatureSet(result);
+        } else {
+            if (error) {
+                *error = err;
+            }
+        }
     }
     return features;
 }
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index e562f8b..d6f536e 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -301,7 +301,7 @@
 }
 
 template <class TimePoint>
-static int msBetween(TimePoint start, TimePoint end) {
+static int ms_between(TimePoint start, TimePoint end) {
     return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
 }
 
@@ -310,7 +310,7 @@
     const auto start = clock::now();
     int first_apk = -1;
     int last_apk = -1;
-    std::vector<std::string_view> args = {"package"sv};
+    incremental::Args passthrough_args = {};
     for (int i = 0; i < argc; ++i) {
         const auto arg = std::string_view(argv[i]);
         if (android::base::EndsWithIgnoreCase(arg, ".apk"sv)) {
@@ -318,12 +318,11 @@
             if (first_apk == -1) {
                 first_apk = i;
             }
-        } else if (arg.starts_with("install-"sv)) {
+        } else if (arg.starts_with("install"sv)) {
             // incremental installation command on the device is the same for all its variations in
             // the adb, e.g. install-multiple or install-multi-package
-            args.push_back("install"sv);
         } else {
-            args.push_back(arg);
+            passthrough_args.push_back(arg);
         }
     }
 
@@ -344,13 +343,13 @@
     }
 
     printf("Performing Incremental Install\n");
-    auto server_process = incremental::install(files, silent);
+    auto server_process = incremental::install(files, passthrough_args, silent);
     if (!server_process) {
         return -1;
     }
 
     const auto end = clock::now();
-    printf("Install command complete in %d ms\n", msBetween(start, end));
+    printf("Install command complete in %d ms\n", ms_between(start, end));
 
     if (wait) {
         (*server_process).wait();
@@ -359,9 +358,9 @@
     return 0;
 }
 
-static std::pair<InstallMode, std::optional<InstallMode>> calculateInstallMode(
-        InstallMode modeFromArgs, bool fastdeploy, CmdlineOption incrementalRequest) {
-    if (incrementalRequest == CmdlineOption::Enable) {
+static std::pair<InstallMode, std::optional<InstallMode>> calculate_install_mode(
+        InstallMode modeFromArgs, bool fastdeploy, CmdlineOption incremental_request) {
+    if (incremental_request == CmdlineOption::Enable) {
         if (fastdeploy) {
             error_exit(
                     "--incremental and --fast-deploy options are incompatible. "
@@ -370,30 +369,30 @@
     }
 
     if (modeFromArgs != INSTALL_DEFAULT) {
-        if (incrementalRequest == CmdlineOption::Enable) {
+        if (incremental_request == CmdlineOption::Enable) {
             error_exit("--incremental is not compatible with other installation modes");
         }
         return {modeFromArgs, std::nullopt};
     }
 
-    if (incrementalRequest != CmdlineOption::Disable && !is_abb_exec_supported()) {
-        if (incrementalRequest == CmdlineOption::None) {
-            incrementalRequest = CmdlineOption::Disable;
+    if (incremental_request != CmdlineOption::Disable && !is_abb_exec_supported()) {
+        if (incremental_request == CmdlineOption::None) {
+            incremental_request = CmdlineOption::Disable;
         } else {
             error_exit("Device doesn't support incremental installations");
         }
     }
-    if (incrementalRequest == CmdlineOption::None) {
+    if (incremental_request == CmdlineOption::None) {
         // check if the host is ok with incremental by default
         if (const char* incrementalFromEnv = getenv("ADB_INSTALL_DEFAULT_INCREMENTAL")) {
             using namespace android::base;
             auto val = ParseBool(incrementalFromEnv);
             if (val == ParseBoolResult::kFalse) {
-                incrementalRequest = CmdlineOption::Disable;
+                incremental_request = CmdlineOption::Disable;
             }
         }
     }
-    if (incrementalRequest == CmdlineOption::None) {
+    if (incremental_request == CmdlineOption::None) {
         // still ok: let's see if the device allows using incremental by default
         // it starts feeling like we're looking for an excuse to not to use incremental...
         std::string error;
@@ -409,17 +408,17 @@
             using namespace android::base;
             auto val = ParseBool(buf);
             if (val == ParseBoolResult::kFalse) {
-                incrementalRequest = CmdlineOption::Disable;
+                incremental_request = CmdlineOption::Disable;
             }
         }
     }
 
-    if (incrementalRequest == CmdlineOption::Enable) {
+    if (incremental_request == CmdlineOption::Enable) {
         // explicitly requested - no fallback
         return {INSTALL_INCREMENTAL, std::nullopt};
     }
     const auto bestMode = best_install_mode();
-    if (incrementalRequest == CmdlineOption::None) {
+    if (incremental_request == CmdlineOption::None) {
         // no opinion - use incremental, fallback to regular on a failure.
         return {INSTALL_INCREMENTAL, bestMode};
     }
@@ -427,57 +426,75 @@
     return {bestMode, std::nullopt};
 }
 
-int install_app(int argc, const char** argv) {
-    std::vector<int> processedArgIndices;
-    InstallMode installMode = INSTALL_DEFAULT;
-    bool use_fastdeploy = false;
-    bool is_reinstall = false;
-    bool wait = false;
-    auto incremental_request = CmdlineOption::None;
-    FastDeploy_AgentUpdateStrategy agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
+static std::vector<const char*> parse_install_mode(std::vector<const char*> argv,
+                                                   InstallMode* install_mode,
+                                                   CmdlineOption* incremental_request,
+                                                   bool* incremental_wait) {
+    *install_mode = INSTALL_DEFAULT;
+    *incremental_request = CmdlineOption::None;
+    *incremental_wait = false;
 
-    for (int i = 1; i < argc; i++) {
-        if (argv[i] == "--streaming"sv) {
-            processedArgIndices.push_back(i);
-            installMode = INSTALL_STREAM;
-        } else if (argv[i] == "--no-streaming"sv) {
-            processedArgIndices.push_back(i);
-            installMode = INSTALL_PUSH;
-        } else if (argv[i] == "-r"sv) {
-            // Note that this argument is not added to processedArgIndices because it
-            // must be passed through to pm
-            is_reinstall = true;
-        } else if (argv[i] == "--fastdeploy"sv) {
-            processedArgIndices.push_back(i);
-            use_fastdeploy = true;
-        } else if (argv[i] == "--no-fastdeploy"sv) {
-            processedArgIndices.push_back(i);
-            use_fastdeploy = false;
-        } else if (argv[i] == "--force-agent"sv) {
-            processedArgIndices.push_back(i);
-            agent_update_strategy = FastDeploy_AgentUpdateAlways;
-        } else if (argv[i] == "--date-check-agent"sv) {
-            processedArgIndices.push_back(i);
-            agent_update_strategy = FastDeploy_AgentUpdateNewerTimeStamp;
-        } else if (argv[i] == "--version-check-agent"sv) {
-            processedArgIndices.push_back(i);
-            agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
-        } else if (strlen(argv[i]) >= "--incr"sv.size() && "--incremental"sv.starts_with(argv[i])) {
-            processedArgIndices.push_back(i);
-            incremental_request = CmdlineOption::Enable;
-        } else if (strlen(argv[i]) >= "--no-incr"sv.size() &&
-                   "--no-incremental"sv.starts_with(argv[i])) {
-            processedArgIndices.push_back(i);
-            incremental_request = CmdlineOption::Disable;
-        } else if (argv[i] == "--wait"sv) {
-            processedArgIndices.push_back(i);
-            wait = true;
+    std::vector<const char*> passthrough;
+    for (auto&& arg : argv) {
+        if (arg == "--streaming"sv) {
+            *install_mode = INSTALL_STREAM;
+        } else if (arg == "--no-streaming"sv) {
+            *install_mode = INSTALL_PUSH;
+        } else if (strlen(arg) >= "--incr"sv.size() && "--incremental"sv.starts_with(arg)) {
+            *incremental_request = CmdlineOption::Enable;
+        } else if (strlen(arg) >= "--no-incr"sv.size() && "--no-incremental"sv.starts_with(arg)) {
+            *incremental_request = CmdlineOption::Disable;
+        } else if (arg == "--wait"sv) {
+            *incremental_wait = true;
+        } else {
+            passthrough.push_back(arg);
         }
     }
+    return passthrough;
+}
 
-    auto [primaryMode, fallbackMode] =
-            calculateInstallMode(installMode, use_fastdeploy, incremental_request);
-    if ((primaryMode == INSTALL_STREAM || fallbackMode.value_or(INSTALL_PUSH) == INSTALL_STREAM) &&
+static std::vector<const char*> parse_fast_deploy_mode(
+        std::vector<const char*> argv, bool* use_fastdeploy,
+        FastDeploy_AgentUpdateStrategy* agent_update_strategy) {
+    *use_fastdeploy = false;
+    *agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
+
+    std::vector<const char*> passthrough;
+    for (auto&& arg : argv) {
+        if (arg == "--fastdeploy"sv) {
+            *use_fastdeploy = true;
+        } else if (arg == "--no-fastdeploy"sv) {
+            *use_fastdeploy = false;
+        } else if (arg == "--force-agent"sv) {
+            *agent_update_strategy = FastDeploy_AgentUpdateAlways;
+        } else if (arg == "--date-check-agent"sv) {
+            *agent_update_strategy = FastDeploy_AgentUpdateNewerTimeStamp;
+        } else if (arg == "--version-check-agent"sv) {
+            *agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
+        } else {
+            passthrough.push_back(arg);
+        }
+    }
+    return passthrough;
+}
+
+int install_app(int argc, const char** argv) {
+    InstallMode install_mode = INSTALL_DEFAULT;
+    auto incremental_request = CmdlineOption::None;
+    bool incremental_wait = false;
+
+    bool use_fastdeploy = false;
+    FastDeploy_AgentUpdateStrategy agent_update_strategy = FastDeploy_AgentUpdateDifferentVersion;
+
+    auto unused_argv = parse_install_mode({argv, argv + argc}, &install_mode, &incremental_request,
+                                          &incremental_wait);
+    auto passthrough_argv =
+            parse_fast_deploy_mode(std::move(unused_argv), &use_fastdeploy, &agent_update_strategy);
+
+    auto [primary_mode, fallback_mode] =
+            calculate_install_mode(install_mode, use_fastdeploy, incremental_request);
+    if ((primary_mode == INSTALL_STREAM ||
+         fallback_mode.value_or(INSTALL_PUSH) == INSTALL_STREAM) &&
         best_install_mode() == INSTALL_PUSH) {
         error_exit("Attempting to use streaming install on unsupported device");
     }
@@ -491,19 +508,12 @@
     }
     fastdeploy_set_agent_update_strategy(agent_update_strategy);
 
-    std::vector<const char*> passthrough_argv;
-    for (int i = 0; i < argc; i++) {
-        if (std::find(processedArgIndices.begin(), processedArgIndices.end(), i) ==
-            processedArgIndices.end()) {
-            passthrough_argv.push_back(argv[i]);
-        }
-    }
     if (passthrough_argv.size() < 2) {
         error_exit("install requires an apk argument");
     }
 
-    auto runInstallMode = [&](InstallMode installMode, bool silent) {
-        switch (installMode) {
+    auto run_install_mode = [&](InstallMode install_mode, bool silent) {
+        switch (install_mode) {
             case INSTALL_PUSH:
                 return install_app_legacy(passthrough_argv.size(), passthrough_argv.data(),
                                           use_fastdeploy);
@@ -512,20 +522,20 @@
                                             use_fastdeploy);
             case INSTALL_INCREMENTAL:
                 return install_app_incremental(passthrough_argv.size(), passthrough_argv.data(),
-                                               wait, silent);
+                                               incremental_wait, silent);
             case INSTALL_DEFAULT:
             default:
-                return 1;
+                error_exit("invalid install mode");
         }
     };
-    auto res = runInstallMode(primaryMode, fallbackMode.has_value());
-    if (res && fallbackMode.value_or(primaryMode) != primaryMode) {
-        res = runInstallMode(*fallbackMode, false);
+    auto res = run_install_mode(primary_mode, fallback_mode.has_value());
+    if (res && fallback_mode.value_or(primary_mode) != primary_mode) {
+        res = run_install_mode(*fallback_mode, false);
     }
     return res;
 }
 
-int install_multiple_app(int argc, const char** argv) {
+static int install_multiple_app_streamed(int argc, const char** argv) {
     // Find all APK arguments starting at end.
     // All other arguments passed through verbatim.
     int first_apk = -1;
@@ -551,7 +561,6 @@
     if (first_apk == -1) error_exit("need APK file on command line");
 
     const bool use_abb_exec = is_abb_exec_supported();
-
     const std::string install_cmd =
             use_abb_exec ? "package"
                          : best_install_mode() == INSTALL_PUSH ? "exec:pm" : "exec:cmd package";
@@ -674,6 +683,44 @@
     return EXIT_SUCCESS;
 }
 
+int install_multiple_app(int argc, const char** argv) {
+    InstallMode install_mode = INSTALL_DEFAULT;
+    auto incremental_request = CmdlineOption::None;
+    bool incremental_wait = false;
+    bool use_fastdeploy = false;
+
+    auto passthrough_argv = parse_install_mode({argv + 1, argv + argc}, &install_mode,
+                                               &incremental_request, &incremental_wait);
+
+    auto [primary_mode, fallback_mode] =
+            calculate_install_mode(install_mode, use_fastdeploy, incremental_request);
+    if ((primary_mode == INSTALL_STREAM ||
+         fallback_mode.value_or(INSTALL_PUSH) == INSTALL_STREAM) &&
+        best_install_mode() == INSTALL_PUSH) {
+        error_exit("Attempting to use streaming install on unsupported device");
+    }
+
+    auto run_install_mode = [&](InstallMode install_mode, bool silent) {
+        switch (install_mode) {
+            case INSTALL_PUSH:
+            case INSTALL_STREAM:
+                return install_multiple_app_streamed(passthrough_argv.size(),
+                                                     passthrough_argv.data());
+            case INSTALL_INCREMENTAL:
+                return install_app_incremental(passthrough_argv.size(), passthrough_argv.data(),
+                                               incremental_wait, silent);
+            case INSTALL_DEFAULT:
+            default:
+                error_exit("invalid install mode");
+        }
+    };
+    auto res = run_install_mode(primary_mode, fallback_mode.has_value());
+    if (res && fallback_mode.value_or(primary_mode) != primary_mode) {
+        res = run_install_mode(*fallback_mode, false);
+    }
+    return res;
+}
+
 int install_multi_package(int argc, const char** argv) {
     // Find all APK arguments starting at end.
     // All other arguments passed through verbatim.
@@ -698,23 +745,31 @@
         fprintf(stderr, "adb: multi-package install is not supported on this device\n");
         return EXIT_FAILURE;
     }
-    std::string install_cmd = "exec:cmd package";
 
-    std::string multi_package_cmd =
-            android::base::StringPrintf("%s install-create --multi-package", install_cmd.c_str());
+    const bool use_abb_exec = is_abb_exec_supported();
+    const std::string install_cmd = use_abb_exec ? "package" : "exec:cmd package";
+
+    std::vector<std::string> multi_package_cmd_args = {install_cmd, "install-create",
+                                                       "--multi-package"};
+
+    multi_package_cmd_args.reserve(first_package + 4);
     for (int i = 1; i < first_package; i++) {
-        multi_package_cmd += " " + escape_arg(argv[i]);
+        if (use_abb_exec) {
+            multi_package_cmd_args.push_back(argv[i]);
+        } else {
+            multi_package_cmd_args.push_back(escape_arg(argv[i]));
+        }
     }
 
     if (apex_found) {
-        multi_package_cmd += " --staged";
+        multi_package_cmd_args.emplace_back("--staged");
     }
 
     // Create multi-package install session
     std::string error;
     char buf[BUFSIZ];
     {
-        unique_fd fd(adb_connect(multi_package_cmd, &error));
+        unique_fd fd = send_command(multi_package_cmd_args, &error);
         if (fd < 0) {
             fprintf(stderr, "adb: connect error for create multi-package: %s\n", error.c_str());
             return EXIT_FAILURE;
@@ -736,6 +791,7 @@
         fputs(buf, stderr);
         return EXIT_FAILURE;
     }
+    const auto parent_session_id_str = std::to_string(parent_session_id);
 
     fprintf(stdout, "Created parent session ID %d.\n", parent_session_id);
 
@@ -743,17 +799,30 @@
 
     // Valid session, now create the individual sessions and stream the APKs
     int success = EXIT_FAILURE;
-    std::string individual_cmd =
-            android::base::StringPrintf("%s install-create", install_cmd.c_str());
-    std::string all_session_ids = "";
+    std::vector<std::string> individual_cmd_args = {install_cmd, "install-create"};
     for (int i = 1; i < first_package; i++) {
-        individual_cmd += " " + escape_arg(argv[i]);
+        if (use_abb_exec) {
+            individual_cmd_args.push_back(argv[i]);
+        } else {
+            individual_cmd_args.push_back(escape_arg(argv[i]));
+        }
     }
     if (apex_found) {
-        individual_cmd += " --staged";
+        individual_cmd_args.emplace_back("--staged");
     }
-    std::string individual_apex_cmd = individual_cmd + " --apex";
-    std::string cmd = "";
+
+    std::vector<std::string> individual_apex_cmd_args;
+    if (apex_found) {
+        individual_apex_cmd_args = individual_cmd_args;
+        individual_apex_cmd_args.emplace_back("--apex");
+    }
+
+    std::vector<std::string> add_session_cmd_args = {
+            install_cmd,
+            "install-add-session",
+            parent_session_id_str,
+    };
+
     for (int i = first_package; i < argc; i++) {
         const char* file = argv[i];
         char buf[BUFSIZ];
@@ -761,9 +830,9 @@
             unique_fd fd;
             // Create individual install session
             if (android::base::EndsWithIgnoreCase(file, ".apex")) {
-                fd.reset(adb_connect(individual_apex_cmd, &error));
+                fd = send_command(individual_apex_cmd_args, &error);
             } else {
-                fd.reset(adb_connect(individual_cmd, &error));
+                fd = send_command(individual_cmd_args, &error);
             }
             if (fd < 0) {
                 fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
@@ -786,6 +855,7 @@
             fputs(buf, stderr);
             goto finalize_multi_package_session;
         }
+        const auto session_id_str = std::to_string(session_id);
 
         fprintf(stdout, "Created child session ID %d.\n", session_id);
         session_ids.push_back(session_id);
@@ -800,10 +870,15 @@
                 goto finalize_multi_package_session;
             }
 
-            std::string cmd = android::base::StringPrintf(
-                    "%s install-write -S %" PRIu64 " %d %d_%s -", install_cmd.c_str(),
-                    static_cast<uint64_t>(sb.st_size), session_id, i,
-                    android::base::Basename(split).c_str());
+            std::vector<std::string> cmd_args = {
+                    install_cmd,
+                    "install-write",
+                    "-S",
+                    std::to_string(sb.st_size),
+                    session_id_str,
+                    android::base::StringPrintf("%d_%s", i, android::base::Basename(file).c_str()),
+                    "-",
+            };
 
             unique_fd local_fd(adb_open(split.c_str(), O_RDONLY | O_CLOEXEC));
             if (local_fd < 0) {
@@ -812,7 +887,7 @@
             }
 
             std::string error;
-            unique_fd remote_fd(adb_connect(cmd, &error));
+            unique_fd remote_fd = send_command(cmd_args, &error);
             if (remote_fd < 0) {
                 fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
                 goto finalize_multi_package_session;
@@ -831,13 +906,11 @@
                 goto finalize_multi_package_session;
             }
         }
-        all_session_ids += android::base::StringPrintf(" %d", session_id);
+        add_session_cmd_args.push_back(std::to_string(session_id));
     }
 
-    cmd = android::base::StringPrintf("%s install-add-session %d%s", install_cmd.c_str(),
-                                      parent_session_id, all_session_ids.c_str());
     {
-        unique_fd fd(adb_connect(cmd, &error));
+        unique_fd fd = send_command(add_session_cmd_args, &error);
         if (fd < 0) {
             fprintf(stderr, "adb: connect error for install-add-session: %s\n", error.c_str());
             goto finalize_multi_package_session;
@@ -846,7 +919,8 @@
     }
 
     if (strncmp("Success", buf, 7)) {
-        fprintf(stderr, "adb: failed to link sessions (%s)\n", cmd.c_str());
+        fprintf(stderr, "adb: failed to link sessions (%s)\n",
+                android::base::Join(add_session_cmd_args, " ").c_str());
         fputs(buf, stderr);
         goto finalize_multi_package_session;
     }
@@ -856,11 +930,14 @@
 
 finalize_multi_package_session:
     // Commit session if we streamed everything okay; otherwise abandon
-    std::string service =
-            android::base::StringPrintf("%s install-%s %d", install_cmd.c_str(),
-                                        success == 0 ? "commit" : "abandon", parent_session_id);
+    std::vector<std::string> service_args = {
+            install_cmd,
+            success == 0 ? "install-commit" : "install-abandon",
+            parent_session_id_str,
+    };
+
     {
-        unique_fd fd(adb_connect(service, &error));
+        unique_fd fd = send_command(service_args, &error);
         if (fd < 0) {
             fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
             return EXIT_FAILURE;
@@ -881,10 +958,13 @@
     session_ids.push_back(parent_session_id);
     // try to abandon all remaining sessions
     for (std::size_t i = 0; i < session_ids.size(); i++) {
-        service = android::base::StringPrintf("%s install-abandon %d", install_cmd.c_str(),
-                                              session_ids[i]);
+        std::vector<std::string> service_args = {
+                install_cmd,
+                "install-abandon",
+                std::to_string(session_ids[i]),
+        };
         fprintf(stderr, "Attempting to abandon session ID %d\n", session_ids[i]);
-        unique_fd fd(adb_connect(service, &error));
+        unique_fd fd = send_command(service_args, &error);
         if (fd < 0) {
             fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
             continue;
diff --git a/adb/client/adb_wifi.cpp b/adb/client/adb_wifi.cpp
index fa71028..61a9a48 100644
--- a/adb/client/adb_wifi.cpp
+++ b/adb/client/adb_wifi.cpp
@@ -179,17 +179,21 @@
 
 void adb_wifi_pair_device(const std::string& host, const std::string& password,
                           std::string& response) {
-    // Check the address for a valid address and port.
-    std::string parsed_host;
-    std::string err;
-    int port = -1;
-    if (!android::base::ParseNetAddress(host, &parsed_host, &port, nullptr, &err)) {
-        response = "Failed to parse address for pairing: " + err;
-        return;
-    }
-    if (port <= 0 || port > 65535) {
-        response = "Invalid port while parsing address [" + host + "]";
-        return;
+    auto mdns_info = mdns_get_pairing_service_info(host);
+
+    if (!mdns_info.has_value()) {
+        // Check the address for a valid address and port.
+        std::string parsed_host;
+        std::string err;
+        int port = -1;
+        if (!android::base::ParseNetAddress(host, &parsed_host, &port, nullptr, &err)) {
+            response = "Failed to parse address for pairing: " + err;
+            return;
+        }
+        if (port <= 0 || port > 65535) {
+            response = "Invalid port while parsing address [" + host + "]";
+            return;
+        }
     }
 
     auto priv_key = adb_auth_get_user_privkey();
@@ -220,7 +224,11 @@
 
     PairingResultWaiter waiter;
     std::unique_lock<std::mutex> lock(waiter.mutex_);
-    if (!client->Start(host, waiter.OnResult, &waiter)) {
+    if (!client->Start(mdns_info.has_value()
+                               ? android::base::StringPrintf("%s:%d", mdns_info->addr.c_str(),
+                                                             mdns_info->port)
+                               : host,
+                       waiter.OnResult, &waiter)) {
         response = "Failed: Unable to start pairing client.";
         return;
     }
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index f0a287d..eaa32e5 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -104,7 +104,8 @@
         " connect HOST[:PORT]      connect to a device via TCP/IP [default port=5555]\n"
         " disconnect [HOST[:PORT]]\n"
         "     disconnect from given TCP/IP device [default port=5555], or all\n"
-        " pair HOST[:PORT]         pair with a device for secure TCP/IP communication\n"
+        " pair HOST[:PORT] [PAIRING CODE]\n"
+        "     pair with a device for secure TCP/IP communication\n"
         " forward --list           list all forward socket connections\n"
         " forward [--no-rebind] LOCAL REMOTE\n"
         "     forward socket connection using:\n"
@@ -1712,14 +1713,21 @@
         }
         printf("List of devices attached\n");
         return adb_query_command(query);
-    }
-    else if (!strcmp(argv[0], "connect")) {
+    } else if (!strcmp(argv[0], "transport-id")) {
+        TransportId transport_id;
+        std::string error;
+        unique_fd fd(adb_connect(&transport_id, "host:features", &error, true));
+        if (fd == -1) {
+            error_exit("%s", error.c_str());
+        }
+        printf("%" PRIu64 "\n", transport_id);
+        return 0;
+    } else if (!strcmp(argv[0], "connect")) {
         if (argc != 2) error_exit("usage: adb connect HOST[:PORT]");
 
         std::string query = android::base::StringPrintf("host:connect:%s", argv[1]);
         return adb_query_command(query);
-    }
-    else if (!strcmp(argv[0], "disconnect")) {
+    } else if (!strcmp(argv[0], "disconnect")) {
         if (argc > 2) error_exit("usage: adb disconnect [HOST[:PORT]]");
 
         std::string query = android::base::StringPrintf("host:disconnect:%s",
@@ -1728,13 +1736,17 @@
     } else if (!strcmp(argv[0], "abb")) {
         return adb_abb(argc, argv);
     } else if (!strcmp(argv[0], "pair")) {
-        if (argc != 2) error_exit("usage: adb pair <host>[:<port>]");
+        if (argc < 2 || argc > 3) error_exit("usage: adb pair HOST[:PORT] [PAIRING CODE]");
 
         std::string password;
-        printf("Enter pairing code: ");
-        fflush(stdout);
-        if (!std::getline(std::cin, password) || password.empty()) {
-            error_exit("No pairing code provided");
+        if (argc == 2) {
+            printf("Enter pairing code: ");
+            fflush(stdout);
+            if (!std::getline(std::cin, password) || password.empty()) {
+                error_exit("No pairing code provided");
+            }
+        } else {
+            password = argv[2];
         }
         std::string query =
                 android::base::StringPrintf("host:pair:%s:%s", password.c_str(), argv[1]);
diff --git a/adb/client/incremental.cpp b/adb/client/incremental.cpp
index 2814932..a8b0ab3 100644
--- a/adb/client/incremental.cpp
+++ b/adb/client/incremental.cpp
@@ -93,12 +93,10 @@
 
 // Send install-incremental to the device along with properly configured file descriptors in
 // streaming format. Once connection established, send all fs-verity tree bytes.
-static unique_fd start_install(const Files& files, bool silent) {
+static unique_fd start_install(const Files& files, const Args& passthrough_args, bool silent) {
     std::vector<std::string> command_args{"package", "install-incremental"};
+    command_args.insert(command_args.end(), passthrough_args.begin(), passthrough_args.end());
 
-    // fd's with positions at the beginning of fs-verity
-    std::vector<unique_fd> signature_fds;
-    signature_fds.reserve(files.size());
     for (int i = 0, size = files.size(); i < size; ++i) {
         const auto& file = files[i];
 
@@ -118,8 +116,6 @@
         auto file_desc = StringPrintf("%s:%lld:%d:%s:1", android::base::Basename(file).c_str(),
                                       (long long)st.st_size, i, signature.c_str());
         command_args.push_back(std::move(file_desc));
-
-        signature_fds.push_back(std::move(signature_fd));
     }
 
     std::string error;
@@ -150,8 +146,8 @@
     return true;
 }
 
-std::optional<Process> install(const Files& files, bool silent) {
-    auto connection_fd = start_install(files, silent);
+std::optional<Process> install(const Files& files, const Args& passthrough_args, bool silent) {
+    auto connection_fd = start_install(files, passthrough_args, silent);
     if (connection_fd < 0) {
         if (!silent) {
             fprintf(stderr, "adb: failed to initiate installation on device.\n");
diff --git a/adb/client/incremental.h b/adb/client/incremental.h
index 1fb1e0b..40e928a 100644
--- a/adb/client/incremental.h
+++ b/adb/client/incremental.h
@@ -26,9 +26,10 @@
 namespace incremental {
 
 using Files = std::vector<std::string>;
+using Args = std::vector<std::string_view>;
 
 bool can_install(const Files& files);
-std::optional<Process> install(const Files& files, bool silent);
+std::optional<Process> install(const Files& files, const Args& passthrough_args, bool silent);
 
 enum class Result { Success, Failure, None };
 Result wait_for_installation(int read_fd);
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 05e210f..a19bd6d 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -206,7 +206,7 @@
         // We don't accept() client connections until this point: this way, clients
         // can't see wonky state early in startup even if they're connecting directly
         // to the server instead of going through the adb program.
-        fdevent_run_on_main_thread([] { enable_daemon_sockets(); });
+        fdevent_run_on_main_thread([] { enable_server_sockets(); });
     });
     notify_thread.detach();
 
diff --git a/adb/client/mdns_utils.cpp b/adb/client/mdns_utils.cpp
new file mode 100644
index 0000000..8666b18
--- /dev/null
+++ b/adb/client/mdns_utils.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 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 "client/mdns_utils.h"
+
+#include <android-base/strings.h>
+
+namespace mdns {
+
+// <Instance>.<Service>.<Domain>
+std::optional<MdnsInstance> mdns_parse_instance_name(std::string_view name) {
+    CHECK(!name.empty());
+
+    // Return the whole name if it doesn't fall under <Instance>.<Service>.<Domain> or
+    // <Instance>.<Service>
+    bool has_local_suffix = false;
+    // Strip the local suffix, if any
+    {
+        std::string local_suffix = ".local";
+        local_suffix += android::base::EndsWith(name, ".") ? "." : "";
+
+        if (android::base::ConsumeSuffix(&name, local_suffix)) {
+            if (name.empty()) {
+                return std::nullopt;
+            }
+            has_local_suffix = true;
+        }
+    }
+
+    std::string transport;
+    // Strip the transport suffix, if any
+    {
+        std::string add_dot = (!has_local_suffix && android::base::EndsWith(name, ".")) ? "." : "";
+        std::array<std::string, 2> transport_suffixes{"._tcp", "._udp"};
+
+        for (const auto& t : transport_suffixes) {
+            if (android::base::ConsumeSuffix(&name, t + add_dot)) {
+                if (name.empty()) {
+                    return std::nullopt;
+                }
+                transport = t.substr(1);
+                break;
+            }
+        }
+
+        if (has_local_suffix && transport.empty()) {
+            return std::nullopt;
+        }
+    }
+
+    if (!has_local_suffix && transport.empty()) {
+        return std::make_optional<MdnsInstance>(name, "", "");
+    }
+
+    // Split the service name from the instance name
+    auto pos = name.rfind(".");
+    if (pos == 0 || pos == std::string::npos || pos == name.size() - 1) {
+        return std::nullopt;
+    }
+
+    return std::make_optional<MdnsInstance>(name.substr(0, pos), name.substr(pos + 1), transport);
+}
+
+}  // namespace mdns
diff --git a/adb/client/mdns_utils.h b/adb/client/mdns_utils.h
new file mode 100644
index 0000000..40d095d
--- /dev/null
+++ b/adb/client/mdns_utils.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 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 <optional>
+#include <string_view>
+
+#include "adb_wifi.h"
+
+namespace mdns {
+
+struct MdnsInstance {
+    std::string instance_name;   // "my name"
+    std::string service_name;    // "_adb-tls-connect"
+    std::string transport_type;  // either "_tcp" or "_udp"
+
+    MdnsInstance(std::string_view inst, std::string_view serv, std::string_view trans)
+        : instance_name(inst), service_name(serv), transport_type(trans) {}
+};
+
+// This parser is based on https://tools.ietf.org/html/rfc6763#section-4.1 for
+// structured service instance names, where the whole name is in the format
+// <Instance>.<Service>.<Domain>.
+//
+// In our case, we ignore <Domain> portion of the name, which
+// we always assume to be ".local", or link-local mDNS.
+//
+// The string can be in one of the following forms:
+//   - <Instance>.<Service>.<Domain>.?
+//     - e.g. "instance._service._tcp.local" (or "...local.")
+//   - <Instance>.<Service>.? (must contain either "_tcp" or "_udp" at the end)
+//     - e.g. "instance._service._tcp" (or "..._tcp.)
+//   - <Instance> (can contain dots '.')
+//     - e.g. "myname", "name.", "my.name."
+//
+// Returns an MdnsInstance with the appropriate fields filled in (instance name is never empty),
+// otherwise returns std::nullopt.
+std::optional<MdnsInstance> mdns_parse_instance_name(std::string_view name);
+
+}  // namespace mdns
diff --git a/adb/client/mdns_utils_test.cpp b/adb/client/mdns_utils_test.cpp
new file mode 100644
index 0000000..ec71529
--- /dev/null
+++ b/adb/client/mdns_utils_test.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2020 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 "client/mdns_utils.h"
+
+#include <gtest/gtest.h>
+
+namespace mdns {
+
+TEST(mdns_utils, mdns_parse_instance_name) {
+    // Just the instance name
+    {
+        std::string str = ".";
+        auto res = mdns_parse_instance_name(str);
+        ASSERT_TRUE(res.has_value());
+        EXPECT_EQ(str, res->instance_name);
+        EXPECT_TRUE(res->service_name.empty());
+        EXPECT_TRUE(res->transport_type.empty());
+    }
+    {
+        std::string str = "my.name";
+        auto res = mdns_parse_instance_name(str);
+        ASSERT_TRUE(res.has_value());
+        EXPECT_EQ(str, res->instance_name);
+        EXPECT_TRUE(res->service_name.empty());
+        EXPECT_TRUE(res->transport_type.empty());
+    }
+    {
+        std::string str = "my.name.";
+        auto res = mdns_parse_instance_name(str);
+        ASSERT_TRUE(res.has_value());
+        EXPECT_EQ(str, res->instance_name);
+        EXPECT_TRUE(res->service_name.empty());
+        EXPECT_TRUE(res->transport_type.empty());
+    }
+
+    // With "_tcp", "_udp" transport type
+    for (const std::string_view transport : {"._tcp", "._udp"}) {
+        {
+            std::string str = android::base::StringPrintf("%s", transport.data());
+            auto res = mdns_parse_instance_name(str);
+            EXPECT_FALSE(res.has_value());
+        }
+        {
+            std::string str = android::base::StringPrintf("%s.", transport.data());
+            auto res = mdns_parse_instance_name(str);
+            EXPECT_FALSE(res.has_value());
+        }
+        {
+            std::string str = android::base::StringPrintf("service%s", transport.data());
+            auto res = mdns_parse_instance_name(str);
+            EXPECT_FALSE(res.has_value());
+        }
+        {
+            std::string str = android::base::StringPrintf(".service%s", transport.data());
+            auto res = mdns_parse_instance_name(str);
+            EXPECT_FALSE(res.has_value());
+        }
+        {
+            std::string str = android::base::StringPrintf("service.%s", transport.data());
+            auto res = mdns_parse_instance_name(str);
+            EXPECT_FALSE(res.has_value());
+        }
+        {
+            std::string str = android::base::StringPrintf("my.service%s", transport.data());
+            auto res = mdns_parse_instance_name(str);
+            ASSERT_TRUE(res.has_value());
+            EXPECT_EQ(res->instance_name, "my");
+            EXPECT_EQ(res->service_name, "service");
+            EXPECT_EQ(res->transport_type, transport.substr(1));
+        }
+        {
+            std::string str = android::base::StringPrintf("my.service%s.", transport.data());
+            auto res = mdns_parse_instance_name(str);
+            ASSERT_TRUE(res.has_value());
+            EXPECT_EQ(res->instance_name, "my");
+            EXPECT_EQ(res->service_name, "service");
+            EXPECT_EQ(res->transport_type, transport.substr(1));
+        }
+        {
+            std::string str = android::base::StringPrintf("my..service%s", transport.data());
+            auto res = mdns_parse_instance_name(str);
+            ASSERT_TRUE(res.has_value());
+            EXPECT_EQ(res->instance_name, "my.");
+            EXPECT_EQ(res->service_name, "service");
+            EXPECT_EQ(res->transport_type, transport.substr(1));
+        }
+        {
+            std::string str = android::base::StringPrintf("my.name.service%s.", transport.data());
+            auto res = mdns_parse_instance_name(str);
+            ASSERT_TRUE(res.has_value());
+            EXPECT_EQ(res->instance_name, "my.name");
+            EXPECT_EQ(res->service_name, "service");
+            EXPECT_EQ(res->transport_type, transport.substr(1));
+        }
+        {
+            std::string str = android::base::StringPrintf("name.service.%s.", transport.data());
+            auto res = mdns_parse_instance_name(str);
+            EXPECT_FALSE(res.has_value());
+        }
+
+        // With ".local" domain
+        {
+            std::string str = ".local";
+            auto res = mdns_parse_instance_name(str);
+            EXPECT_FALSE(res.has_value());
+        }
+        {
+            std::string str = ".local.";
+            auto res = mdns_parse_instance_name(str);
+            EXPECT_FALSE(res.has_value());
+        }
+        {
+            std::string str = "name.local";
+            auto res = mdns_parse_instance_name(str);
+            EXPECT_FALSE(res.has_value());
+        }
+        {
+            std::string str = android::base::StringPrintf("%s.local", transport.data());
+            auto res = mdns_parse_instance_name(str);
+            EXPECT_FALSE(res.has_value());
+        }
+        {
+            std::string str = android::base::StringPrintf("service%s.local", transport.data());
+            auto res = mdns_parse_instance_name(str);
+            EXPECT_FALSE(res.has_value());
+        }
+        {
+            std::string str = android::base::StringPrintf("name.service%s.local", transport.data());
+            auto res = mdns_parse_instance_name(str);
+            ASSERT_TRUE(res.has_value());
+            EXPECT_EQ(res->instance_name, "name");
+            EXPECT_EQ(res->service_name, "service");
+            EXPECT_EQ(res->transport_type, transport.substr(1));
+        }
+        {
+            std::string str =
+                    android::base::StringPrintf("name.service%s.local.", transport.data());
+            auto res = mdns_parse_instance_name(str);
+            ASSERT_TRUE(res.has_value());
+            EXPECT_EQ(res->instance_name, "name");
+            EXPECT_EQ(res->service_name, "service");
+            EXPECT_EQ(res->transport_type, transport.substr(1));
+        }
+        {
+            std::string str =
+                    android::base::StringPrintf("name.service%s..local.", transport.data());
+            auto res = mdns_parse_instance_name(str);
+            EXPECT_FALSE(res.has_value());
+        }
+        {
+            std::string str =
+                    android::base::StringPrintf("name.service.%s.local.", transport.data());
+            auto res = mdns_parse_instance_name(str);
+            EXPECT_FALSE(res.has_value());
+        }
+    }
+}
+
+}  // namespace mdns
diff --git a/adb/client/transport_mdns.cpp b/adb/client/transport_mdns.cpp
index 2b6aa7c..9db2453 100644
--- a/adb/client/transport_mdns.cpp
+++ b/adb/client/transport_mdns.cpp
@@ -38,6 +38,7 @@
 #include "adb_trace.h"
 #include "adb_utils.h"
 #include "adb_wifi.h"
+#include "client/mdns_utils.h"
 #include "fdevent/fdevent.h"
 #include "sysdeps.h"
 
@@ -144,7 +145,7 @@
         return initialized_;
     }
 
-    virtual ~AsyncServiceRef() {
+    void DestroyServiceRef() {
         if (!initialized_) {
             return;
         }
@@ -152,9 +153,13 @@
         // Order matters here! Must destroy the fdevent first since it has a
         // reference to |sdRef_|.
         fdevent_destroy(fde_);
+        D("DNSServiceRefDeallocate(sdRef=%p)", sdRef_);
         DNSServiceRefDeallocate(sdRef_);
+        initialized_ = false;
     }
 
+    virtual ~AsyncServiceRef() { DestroyServiceRef(); }
+
   protected:
     DNSServiceRef sdRef_;
 
@@ -203,6 +208,7 @@
         if (ret != kDNSServiceErr_NoError) {
             D("Got %d from DNSServiceGetAddrInfo.", ret);
         } else {
+            D("DNSServiceGetAddrInfo(sdRef=%p, hosttarget=%s)", sdRef_, hosttarget);
             Initialize();
         }
 
@@ -216,14 +222,14 @@
         }
 
         std::string response;
-        connect_device(android::base::StringPrintf(addr_format_.c_str(), ip_addr_, port_),
+        connect_device(android::base::StringPrintf("%s.%s", serviceName_.c_str(), regType_.c_str()),
                        &response);
         D("Secure connect to %s regtype %s (%s:%hu) : %s", serviceName_.c_str(), regType_.c_str(),
           ip_addr_, port_, response.c_str());
         return true;
     }
 
-    void Connect(const sockaddr* address) {
+    bool AddToServiceRegistry(const sockaddr* address) {
         sa_family_ = address->sa_family;
 
         if (sa_family_ == AF_INET) {
@@ -234,26 +240,53 @@
             addr_format_ = "[%s]:%hu";
         } else {  // Should be impossible
             D("mDNS resolved non-IP address.");
-            return;
+            return false;
         }
 
         // Winsock version requires the const cast Because Microsoft.
         if (!inet_ntop(sa_family_, const_cast<void*>(ip_addr_data_), ip_addr_, sizeof(ip_addr_))) {
             D("Could not convert IP address to string.");
-            return;
+            return false;
         }
 
-        // adb secure service needs to do something different from just
-        // connecting here.
+        // Add to the service registry before trying to auto-connect, since socket_spec_connect will
+        // check these registries for the ip address when connecting via mdns instance name.
+        int adbSecureServiceType = serviceIndex();
+        ServiceRegistry* services = nullptr;
+        switch (adbSecureServiceType) {
+            case kADBTransportServiceRefIndex:
+                services = sAdbTransportServices;
+                break;
+            case kADBSecurePairingServiceRefIndex:
+                services = sAdbSecurePairingServices;
+                break;
+            case kADBSecureConnectServiceRefIndex:
+                services = sAdbSecureConnectServices;
+                break;
+            default:
+                LOG(WARNING) << "No registry available for reg_type=[" << regType_ << "]";
+                return false;
+        }
+
+        if (!services->empty()) {
+            // Remove the previous resolved service, if any.
+            services->erase(std::remove_if(services->begin(), services->end(),
+                                           [&](std::unique_ptr<ResolvedService>& service) {
+                                               return (serviceName_ == service->serviceName());
+                                           }));
+        }
+        services->push_back(std::unique_ptr<ResolvedService>(this));
+
         if (adb_DNSServiceShouldAutoConnect(regType_.c_str(), serviceName_.c_str())) {
             std::string response;
-            D("Attempting to serviceName=[%s], regtype=[%s] ipaddr=(%s:%hu)", serviceName_.c_str(),
-              regType_.c_str(), ip_addr_, port_);
+            D("Attempting to connect serviceName=[%s], regtype=[%s] ipaddr=(%s:%hu)",
+              serviceName_.c_str(), regType_.c_str(), ip_addr_, port_);
             int index = adb_DNSServiceIndexByName(regType_.c_str());
             if (index == kADBSecureConnectServiceRefIndex) {
                 ConnectSecureWifiDevice();
             } else {
-                connect_device(android::base::StringPrintf(addr_format_.c_str(), ip_addr_, port_),
+                connect_device(android::base::StringPrintf("%s.%s", serviceName_.c_str(),
+                                                           regType_.c_str()),
                                &response);
                 D("Connect to %s regtype %s (%s:%hu) : %s", serviceName_.c_str(), regType_.c_str(),
                   ip_addr_, port_, response.c_str());
@@ -263,20 +296,7 @@
               serviceName_.c_str(), regType_.c_str(), ip_addr_, port_);
         }
 
-        int adbSecureServiceType = serviceIndex();
-        switch (adbSecureServiceType) {
-            case kADBTransportServiceRefIndex:
-                sAdbTransportServices->push_back(this);
-                break;
-            case kADBSecurePairingServiceRefIndex:
-                sAdbSecurePairingServices->push_back(this);
-                break;
-            case kADBSecureConnectServiceRefIndex:
-                sAdbSecureConnectServices->push_back(this);
-                break;
-            default:
-                break;
-        }
+        return true;
     }
 
     int serviceIndex() const { return adb_DNSServiceIndexByName(regType_.c_str()); }
@@ -291,7 +311,7 @@
 
     uint16_t port() const { return port_; }
 
-    using ServiceRegistry = std::vector<ResolvedService*>;
+    using ServiceRegistry = std::vector<std::unique_ptr<ResolvedService>>;
 
     // unencrypted tcp connections
     static ServiceRegistry* sAdbTransportServices;
@@ -301,7 +321,7 @@
 
     static void initAdbServiceRegistries();
 
-    static void forEachService(const ServiceRegistry& services, const std::string& hostname,
+    static void forEachService(const ServiceRegistry& services, std::string_view hostname,
                                adb_secure_foreach_service_callback cb);
 
     static bool connectByServiceName(const ServiceRegistry& services,
@@ -321,13 +341,13 @@
 };
 
 // static
-std::vector<ResolvedService*>* ResolvedService::sAdbTransportServices = NULL;
+ResolvedService::ServiceRegistry* ResolvedService::sAdbTransportServices = NULL;
 
 // static
-std::vector<ResolvedService*>* ResolvedService::sAdbSecurePairingServices = NULL;
+ResolvedService::ServiceRegistry* ResolvedService::sAdbSecurePairingServices = NULL;
 
 // static
-std::vector<ResolvedService*>* ResolvedService::sAdbSecureConnectServices = NULL;
+ResolvedService::ServiceRegistry* ResolvedService::sAdbSecureConnectServices = NULL;
 
 // static
 void ResolvedService::initAdbServiceRegistries() {
@@ -344,17 +364,17 @@
 
 // static
 void ResolvedService::forEachService(const ServiceRegistry& services,
-                                     const std::string& wanted_service_name,
+                                     std::string_view wanted_service_name,
                                      adb_secure_foreach_service_callback cb) {
     initAdbServiceRegistries();
 
-    for (auto service : services) {
+    for (const auto& service : services) {
         auto service_name = service->serviceName();
         auto reg_type = service->regType();
         auto ip = service->ipAddress();
         auto port = service->port();
 
-        if (wanted_service_name == "") {
+        if (wanted_service_name.empty()) {
             cb(service_name.c_str(), reg_type.c_str(), ip.c_str(), port);
         } else if (service_name == wanted_service_name) {
             cb(service_name.c_str(), reg_type.c_str(), ip.c_str(), port);
@@ -366,7 +386,7 @@
 bool ResolvedService::connectByServiceName(const ServiceRegistry& services,
                                            const std::string& service_name) {
     initAdbServiceRegistries();
-    for (auto service : services) {
+    for (const auto& service : services) {
         if (service_name == service->serviceName()) {
             D("Got service_name match [%s]", service->serviceName().c_str());
             return service->ConnectSecureWifiDevice();
@@ -378,14 +398,12 @@
 
 void adb_secure_foreach_pairing_service(const char* service_name,
                                         adb_secure_foreach_service_callback cb) {
-    ResolvedService::forEachService(*ResolvedService::sAdbSecurePairingServices,
-                                    service_name ? service_name : "", cb);
+    ResolvedService::forEachService(*ResolvedService::sAdbSecurePairingServices, service_name, cb);
 }
 
 void adb_secure_foreach_connect_service(const char* service_name,
                                         adb_secure_foreach_service_callback cb) {
-    ResolvedService::forEachService(*ResolvedService::sAdbSecureConnectServices,
-                                    service_name ? service_name : "", cb);
+    ResolvedService::forEachService(*ResolvedService::sAdbSecureConnectServices, service_name, cb);
 }
 
 bool adb_secure_connect_by_service_name(const char* service_name) {
@@ -393,23 +411,28 @@
                                                  service_name);
 }
 
-static void DNSSD_API register_service_ip(DNSServiceRef /*sdRef*/,
-                                          DNSServiceFlags /*flags*/,
+static void DNSSD_API register_service_ip(DNSServiceRef sdRef, DNSServiceFlags flags,
                                           uint32_t /*interfaceIndex*/,
-                                          DNSServiceErrorType /*errorCode*/,
-                                          const char* /*hostname*/,
-                                          const sockaddr* address,
-                                          uint32_t /*ttl*/,
-                                          void* context) {
-    D("Got IP for service.");
+                                          DNSServiceErrorType errorCode, const char* hostname,
+                                          const sockaddr* address, uint32_t ttl, void* context) {
+    D("%s: sdRef=%p flags=0x%08x errorCode=%u ttl=%u", __func__, sdRef, flags, errorCode, ttl);
     std::unique_ptr<ResolvedService> data(
         reinterpret_cast<ResolvedService*>(context));
-    data->Connect(address);
+    // Only resolve the address once. If the address or port changes, we'll just get another
+    // registration.
+    data->DestroyServiceRef();
 
-    // For ADB Secure services, keep those ResolvedService's around
-    // for later processing with secure connection establishment.
-    if (data->serviceIndex() != kADBTransportServiceRefIndex) {
-        data.release();
+    if (errorCode != kDNSServiceErr_NoError) {
+        D("Got error while looking up ipaddr [%u]", errorCode);
+        return;
+    }
+
+    if (flags & kDNSServiceFlagsAdd) {
+        D("Resolved IP address for [%s]. Adding to service registry.", hostname);
+        auto* ptr = data.release();
+        if (!ptr->AddToServiceRegistry(address)) {
+            data.reset(ptr);
+        }
     }
 }
 
@@ -459,6 +482,7 @@
 };
 
 static void adb_RemoveDNSService(const char* regType, const char* serviceName) {
+    D("%s: regType=[%s] serviceName=[%s]", __func__, regType, serviceName);
     int index = adb_DNSServiceIndexByName(regType);
     ResolvedService::ServiceRegistry* services;
     switch (index) {
@@ -475,10 +499,15 @@
             return;
     }
 
+    if (services->empty()) {
+        return;
+    }
+
     std::string sName(serviceName);
-    services->erase(std::remove_if(
-            services->begin(), services->end(),
-            [&sName](ResolvedService* service) { return (sName == service->serviceName()); }));
+    services->erase(std::remove_if(services->begin(), services->end(),
+                                   [&sName](std::unique_ptr<ResolvedService>& service) {
+                                       return (sName == service->serviceName());
+                                   }));
 }
 
 // Returns the version the device wanted to advertise,
@@ -647,3 +676,79 @@
     ResolvedService::forEachService(*ResolvedService::sAdbSecurePairingServices, "", cb);
     return result;
 }
+
+std::optional<MdnsInfo> mdns_get_connect_service_info(std::string_view name) {
+    CHECK(!name.empty());
+
+    auto mdns_instance = mdns::mdns_parse_instance_name(name);
+    if (!mdns_instance.has_value()) {
+        D("Failed to parse mDNS name [%s]", name.data());
+        return std::nullopt;
+    }
+
+    std::optional<MdnsInfo> info;
+    auto cb = [&](const char* service_name, const char* reg_type, const char* ip_addr,
+                  uint16_t port) { info.emplace(service_name, reg_type, ip_addr, port); };
+
+    std::string reg_type;
+    if (!mdns_instance->service_name.empty()) {
+        reg_type = android::base::StringPrintf("%s.%s", mdns_instance->service_name.data(),
+                                               mdns_instance->transport_type.data());
+        int index = adb_DNSServiceIndexByName(reg_type);
+        switch (index) {
+            case kADBTransportServiceRefIndex:
+                ResolvedService::forEachService(*ResolvedService::sAdbTransportServices,
+                                                mdns_instance->instance_name, cb);
+                break;
+            case kADBSecureConnectServiceRefIndex:
+                ResolvedService::forEachService(*ResolvedService::sAdbSecureConnectServices,
+                                                mdns_instance->instance_name, cb);
+                break;
+            default:
+                D("Unknown reg_type [%s]", reg_type.data());
+                return std::nullopt;
+        }
+        return info;
+    }
+
+    for (const auto& service :
+         {ResolvedService::sAdbTransportServices, ResolvedService::sAdbSecureConnectServices}) {
+        ResolvedService::forEachService(*service, name, cb);
+        if (info.has_value()) {
+            return info;
+        }
+    }
+
+    return std::nullopt;
+}
+
+std::optional<MdnsInfo> mdns_get_pairing_service_info(std::string_view name) {
+    CHECK(!name.empty());
+
+    auto mdns_instance = mdns::mdns_parse_instance_name(name);
+    if (!mdns_instance.has_value()) {
+        D("Failed to parse mDNS pairing name [%s]", name.data());
+        return std::nullopt;
+    }
+
+    std::optional<MdnsInfo> info;
+    auto cb = [&](const char* service_name, const char* reg_type, const char* ip_addr,
+                  uint16_t port) { info.emplace(service_name, reg_type, ip_addr, port); };
+
+    // Verify it's a pairing service if user explicitly inputs it.
+    if (!mdns_instance->service_name.empty()) {
+        auto reg_type = android::base::StringPrintf("%s.%s", mdns_instance->service_name.data(),
+                                                    mdns_instance->transport_type.data());
+        int index = adb_DNSServiceIndexByName(reg_type);
+        switch (index) {
+            case kADBSecurePairingServiceRefIndex:
+                break;
+            default:
+                D("Not an adb pairing reg_type [%s]", reg_type.data());
+                return std::nullopt;
+        }
+    }
+
+    ResolvedService::forEachService(*ResolvedService::sAdbSecurePairingServices, name, cb);
+    return info;
+}
diff --git a/adb/coverage/gen_coverage.sh b/adb/coverage/gen_coverage.sh
index cced62a..43d45f0 100755
--- a/adb/coverage/gen_coverage.sh
+++ b/adb/coverage/gen_coverage.sh
@@ -17,10 +17,10 @@
 
 # Check that we can connect to it.
 adb disconnect
-adb tcpip $REMOTE_PORT
 
-# TODO: Add `adb transport-id` and wait-for-offline on it.
-sleep 5
+TRANSPORT_ID=$(adb transport-id)
+adb tcpip $REMOTE_PORT
+adb -t $TRANSPORT_ID wait-for-disconnect
 
 adb connect $REMOTE
 
@@ -32,13 +32,16 @@
 fi
 
 # Back to USB, and make sure adbd is root.
+adb -s $REMOTE usb
 adb disconnect $REMOTE
 
+adb wait-for-device root
 adb root
-adb wait-for-device usb
+adb wait-for-device
 
-# TODO: Add `adb transport-id` and wait-for-offline on it.
-sleep 5
+TRANSPORT_ID=$(adb transport-id)
+adb usb
+adb -t $TRANSPORT_ID wait-for-disconnect
 
 adb wait-for-device
 
@@ -61,10 +64,9 @@
 adb shell setprop persist.adb.trace_mask 1
 
 ### Run test_device.py over USB.
+TRANSPORT_ID=$(adb transport-id)
 adb shell killall adbd
-
-# TODO: Add `adb transport-id` and wait-for-offline on it.
-sleep 5
+adb -t $TRANSPORT_ID wait-for-disconnect
 
 adb wait-for-device shell rm -rf "/data/misc/trace/*" /data/local/tmp/adb_coverage/
 "$OUTPUT_DIR"/../test_device.py
@@ -80,13 +82,16 @@
 sleep 5
 
 # Restart adbd in tcp mode.
+TRANSPORT_ID=$(adb transport-id)
 adb tcpip $REMOTE_PORT
-sleep 5
+adb -t $TRANSPORT_ID wait-for-disconnect
+
 adb connect $REMOTE
 adb -s $REMOTE wait-for-device
 
-# Run test_device.py again.
-ANDROID_SERIAL=$REMOTE "$OUTPUT_DIR"/../test_device.py
+# Instead of running test_device.py again, which takes forever, do some I/O back and forth instead.
+dd if=/dev/zero bs=1024 count=10240 | adb -s $REMOTE raw sink:10485760
+adb -s $REMOTE raw source:10485760 | dd of=/dev/null bs=1024 count=10240
 
 # Dump traces again.
 adb disconnect $REMOTE
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 55b7783..db8f07b 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -173,12 +173,6 @@
                 LOG(FATAL) << "Could not set SELinux context";
             }
         }
-        std::string error;
-        std::string local_name =
-            android::base::StringPrintf("tcp:%d", server_port);
-        if (install_listener(local_name, "*smartsocket*", nullptr, 0, nullptr, &error)) {
-            LOG(FATAL) << "Could not install *smartsocket* listener: " << error;
-        }
     }
 }
 #endif
diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp
index fbfae1e..dbca4ad 100644
--- a/adb/daemon/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -646,15 +646,21 @@
         }
 
         // After handling all of the events we've received, check to see if any fds have died.
-        if (stdinout_pfd.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) {
+        auto poll_finished = [](int events) {
+            // Don't return failure until we've read out all of the fd's incoming data.
+            return (events & POLLIN) == 0 &&
+                   (events & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) != 0;
+        };
+
+        if (poll_finished(stdinout_pfd.revents)) {
             return &stdinout_sfd_;
         }
 
-        if (stderr_pfd.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) {
+        if (poll_finished(stderr_pfd.revents)) {
             return &stderr_sfd_;
         }
 
-        if (protocol_pfd.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) {
+        if (poll_finished(protocol_pfd.revents)) {
             return &protocol_sfd_;
         }
     }  // while (!dead_sfd)
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 7fff05a..a663871 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -231,7 +231,14 @@
                 offset += write_size;
             }
         }
-        SubmitWrites();
+
+        // Wake up the worker thread to submit writes.
+        uint64_t notify = 1;
+        ssize_t rc = adb_write(worker_event_fd_.get(), &notify, sizeof(notify));
+        if (rc < 0) {
+            PLOG(FATAL) << "failed to notify worker eventfd to submit writes";
+        }
+
         return true;
     }
 
@@ -443,6 +450,9 @@
                 }
 
                 ReadEvents();
+
+                std::lock_guard<std::mutex> lock(write_mutex_);
+                SubmitWrites();
             }
         });
     }
@@ -626,8 +636,6 @@
         write_requests_.erase(it);
         size_t outstanding_writes = --writes_submitted_;
         LOG(DEBUG) << "USB write: reaped, down to " << outstanding_writes;
-
-        SubmitWrites();
     }
 
     IoWriteBlock CreateWriteBlock(std::shared_ptr<Block> payload, size_t offset, size_t len,
diff --git a/adb/fastdeploy/proto/ApkEntry.proto b/adb/fastdeploy/proto/ApkEntry.proto
index d84c5a5..ed5056e 100644
--- a/adb/fastdeploy/proto/ApkEntry.proto
+++ b/adb/fastdeploy/proto/ApkEntry.proto
@@ -5,7 +5,6 @@
 option java_package = "com.android.fastdeploy";
 option java_outer_classname = "ApkEntryProto";
 option java_multiple_files = true;
-option optimize_for = LITE_RUNTIME;
 
 message APKDump {
     string name = 1;
diff --git a/adb/fdevent/fdevent.h b/adb/fdevent/fdevent.h
index 9fc3b2c..bb3af74 100644
--- a/adb/fdevent/fdevent.h
+++ b/adb/fdevent/fdevent.h
@@ -79,8 +79,8 @@
     unique_fd Destroy(fdevent* fde);
 
   protected:
-    virtual void Register(fdevent*) {}
-    virtual void Unregister(fdevent*) {}
+    virtual void Register(fdevent*) = 0;
+    virtual void Unregister(fdevent*) = 0;
 
   public:
     // Change which events should cause notifications.
diff --git a/adb/fdevent/fdevent_poll.cpp b/adb/fdevent/fdevent_poll.cpp
index ac86c08..21c1ba0 100644
--- a/adb/fdevent/fdevent_poll.cpp
+++ b/adb/fdevent/fdevent_poll.cpp
@@ -211,3 +211,7 @@
         PLOG(FATAL) << "failed to write to fdevent interrupt fd";
     }
 }
+
+void fdevent_context_poll::Register(fdevent*) {}
+
+void fdevent_context_poll::Unregister(fdevent*) {}
diff --git a/adb/fdevent/fdevent_poll.h b/adb/fdevent/fdevent_poll.h
index 98abab2..8803e3e 100644
--- a/adb/fdevent/fdevent_poll.h
+++ b/adb/fdevent/fdevent_poll.h
@@ -48,6 +48,9 @@
     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;
diff --git a/adb/libs/adbconnection/include/adbconnection/process_info.h b/adb/libs/adbconnection/include/adbconnection/process_info.h
index 86d3259..d226699 100644
--- a/adb/libs/adbconnection/include/adbconnection/process_info.h
+++ b/adb/libs/adbconnection/include/adbconnection/process_info.h
@@ -21,7 +21,7 @@
 #include <string>
 
 struct ProcessInfo {
-  const static size_t kMaxArchNameLength = 16;
+  static constexpr size_t kMaxArchNameLength = 16;
 
   uint64_t pid;
   bool debuggable;
diff --git a/adb/socket.h b/adb/socket.h
index 4276851..0623204 100644
--- a/adb/socket.h
+++ b/adb/socket.h
@@ -108,7 +108,10 @@
 
 asocket *create_remote_socket(unsigned id, atransport *t);
 void connect_to_remote(asocket* s, std::string_view destination);
+
+#if ADB_HOST
 void connect_to_smartsocket(asocket *s);
+#endif
 
 // Internal functions that are only made available here for testing purposes.
 namespace internal {
diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp
index d17036c..5cad70d 100644
--- a/adb/socket_spec.cpp
+++ b/adb/socket_spec.cpp
@@ -30,6 +30,7 @@
 
 #include "adb.h"
 #include "adb_utils.h"
+#include "adb_wifi.h"
 #include "sysdeps.h"
 
 using namespace std::string_literals;
@@ -103,12 +104,6 @@
         if (!android::base::ParseNetAddress(addr, &hostname_value, &port_value, serial, error)) {
             return false;
         }
-
-        if (port_value == -1) {
-            *error = "missing port in specification: ";
-            *error += spec;
-            return false;
-        }
     }
 
     if (hostname) {
@@ -201,7 +196,24 @@
             fd->reset(network_loopback_client(port_value, SOCK_STREAM, error));
         } else {
 #if ADB_HOST
-            fd->reset(network_connect(hostname, port_value, SOCK_STREAM, 0, error));
+            // Check if the address is an mdns service we can connect to.
+            if (auto mdns_info = mdns_get_connect_service_info(address.substr(4));
+                mdns_info != std::nullopt) {
+                fd->reset(network_connect(mdns_info->addr, mdns_info->port, SOCK_STREAM, 0, error));
+                if (fd->get() != -1) {
+                    // TODO(joshuaduong): We still show the ip address for the serial. Change it to
+                    // use the mdns instance name, so we can adjust to address changes on
+                    // reconnects.
+                    port_value = mdns_info->port;
+                    if (serial) {
+                        *serial = android::base::StringPrintf("%s.%s",
+                                                              mdns_info->service_name.c_str(),
+                                                              mdns_info->service_type.c_str());
+                    }
+                }
+            } else {
+                fd->reset(network_connect(hostname, port_value, SOCK_STREAM, 0, error));
+            }
 #else
             // Disallow arbitrary connections in adbd.
             *error = "adbd does not support arbitrary tcp connections";
diff --git a/adb/socket_spec_test.cpp b/adb/socket_spec_test.cpp
index e9d5270..e83c34c 100644
--- a/adb/socket_spec_test.cpp
+++ b/adb/socket_spec_test.cpp
@@ -24,6 +24,13 @@
 #include <android-base/stringprintf.h>
 #include <gtest/gtest.h>
 
+TEST(socket_spec, parse_tcp_socket_spec_failure) {
+    std::string hostname, error, serial;
+    int port;
+    EXPECT_FALSE(parse_tcp_socket_spec("sneakernet:5037", &hostname, &port, &serial, &error));
+    EXPECT_TRUE(error.find("sneakernet") != std::string::npos);
+}
+
 TEST(socket_spec, parse_tcp_socket_spec_just_port) {
     std::string hostname, error, serial;
     int port;
@@ -134,6 +141,19 @@
     EXPECT_NE(client_fd.get(), -1);
 }
 
+TEST(socket_spec, socket_spec_connect_failure) {
+    std::string error, serial;
+    int port;
+    unique_fd client_fd;
+    EXPECT_FALSE(socket_spec_connect(&client_fd, "tcp:", &port, &serial, &error));
+    EXPECT_FALSE(socket_spec_connect(&client_fd, "acceptfd:", &port, &serial, &error));
+    EXPECT_FALSE(socket_spec_connect(&client_fd, "vsock:", &port, &serial, &error));
+    EXPECT_FALSE(socket_spec_connect(&client_fd, "vsock:x", &port, &serial, &error));
+    EXPECT_FALSE(socket_spec_connect(&client_fd, "vsock:5", &port, &serial, &error));
+    EXPECT_FALSE(socket_spec_connect(&client_fd, "vsock:5:x", &port, &serial, &error));
+    EXPECT_FALSE(socket_spec_connect(&client_fd, "sneakernet:", &port, &serial, &error));
+}
+
 TEST(socket_spec, socket_spec_listen_connect_localfilesystem) {
     std::string error, serial;
     int port;
@@ -152,3 +172,16 @@
         EXPECT_NE(client_fd.get(), -1);
     }
 }
+
+TEST(socket_spec, is_socket_spec) {
+    EXPECT_TRUE(is_socket_spec("tcp:blah"));
+    EXPECT_TRUE(is_socket_spec("acceptfd:blah"));
+    EXPECT_TRUE(is_socket_spec("local:blah"));
+    EXPECT_TRUE(is_socket_spec("localreserved:blah"));
+}
+
+TEST(socket_spec, is_local_socket_spec) {
+    EXPECT_TRUE(is_local_socket_spec("local:blah"));
+    EXPECT_TRUE(is_local_socket_spec("tcp:localhost"));
+    EXPECT_FALSE(is_local_socket_spec("tcp:www.google.com"));
+}
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 423af67..13a4737 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -520,6 +520,7 @@
     send_packet(p, s->transport);
 }
 
+#if ADB_HOST
 /* this is used by magic sockets to rig local sockets to
    send the go-ahead message when they connect */
 static void local_socket_ready_notify(asocket* s) {
@@ -584,8 +585,6 @@
     return n;
 }
 
-#if ADB_HOST
-
 namespace internal {
 
 // Parses a host service string of the following format:
@@ -714,15 +713,11 @@
 
 }  // namespace internal
 
-#endif  // ADB_HOST
-
 static int smart_socket_enqueue(asocket* s, apacket::payload_type data) {
-#if ADB_HOST
     std::string_view service;
     std::string_view serial;
     TransportId transport_id = 0;
     TransportType type = kTransportAny;
-#endif
 
     D("SS(%d): enqueue %zu", s->id, data.size());
 
@@ -755,7 +750,6 @@
 
     D("SS(%d): '%s'", s->id, (char*)(s->smart_socket_data.data() + 4));
 
-#if ADB_HOST
     service = std::string_view(s->smart_socket_data).substr(4);
 
     // TODO: These should be handled in handle_host_request.
@@ -841,16 +835,6 @@
         s2->ready(s2);
         return 0;
     }
-#else /* !ADB_HOST */
-    if (s->transport == nullptr) {
-        std::string error_msg = "unknown failure";
-        s->transport = acquire_one_transport(kTransportAny, nullptr, 0, nullptr, &error_msg);
-        if (s->transport == nullptr) {
-            SendFail(s->peer->fd, error_msg);
-            goto fail;
-        }
-    }
-#endif
 
     if (!s->transport) {
         SendFail(s->peer->fd, "device offline (no transport)");
@@ -922,6 +906,7 @@
     ss->peer = s;
     s->ready(s);
 }
+#endif
 
 size_t asocket::get_max_payload() const {
     size_t max_payload = MAX_PAYLOAD;
diff --git a/adb/test_adb.py b/adb/test_adb.py
index 03bdcbd..4b99411 100755
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -25,6 +25,7 @@
 import random
 import select
 import socket
+import string
 import struct
 import subprocess
 import sys
@@ -628,21 +629,49 @@
 class MdnsTest(unittest.TestCase):
     """Tests for adb mdns."""
 
+    @staticmethod
+    def _mdns_services(port):
+        output = subprocess.check_output(["adb", "-P", str(port), "mdns", "services"])
+        return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
+
+    @staticmethod
+    def _devices(port):
+        output = subprocess.check_output(["adb", "-P", str(port), "devices"])
+        return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
+
+    @contextlib.contextmanager
+    def _adb_mdns_connect(self, server_port, mdns_instance, serial, should_connect):
+        """Context manager for an ADB connection.
+
+        This automatically disconnects when done with the connection.
+        """
+
+        output = subprocess.check_output(["adb", "-P", str(server_port), "connect", mdns_instance])
+        if should_connect:
+            self.assertEqual(output.strip(), "connected to {}".format(serial).encode("utf8"))
+        else:
+            self.assertTrue(output.startswith("failed to resolve host: '{}'"
+                .format(mdns_instance).encode("utf8")))
+
+        try:
+            yield
+        finally:
+            # Perform best-effort disconnection. Discard the output.
+            subprocess.Popen(["adb", "disconnect", serial],
+                             stdout=subprocess.PIPE,
+                             stderr=subprocess.PIPE).communicate()
+
+
     @unittest.skipIf(not is_zeroconf_installed(), "zeroconf library not installed")
     def test_mdns_services_register_unregister(self):
         """Ensure that `adb mdns services` correctly adds and removes a service
         """
         from zeroconf import IPVersion, ServiceInfo
- 
-        def _mdns_services(port):
-            output = subprocess.check_output(["adb", "-P", str(port), "mdns", "services"])
-            return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
 
         with adb_server() as server_port:
             output = subprocess.check_output(["adb", "-P", str(server_port),
                                               "mdns", "services"]).strip()
             self.assertTrue(output.startswith(b"List of discovered mdns services"))
-            print(f"services={_mdns_services(server_port)}")
 
             """TODO(joshuaduong): Add ipv6 tests once we have it working in adb"""
             """Register/Unregister a service"""
@@ -656,20 +685,52 @@
                         name=serv_instance + "." + serv_type + "local.",
                         addresses=[serv_ipaddr],
                         port=serv_port)
-                print(f"Registering {serv_instance}.{serv_type} ...")
                 with zeroconf_register_service(zc, service_info) as info:
                     """Give adb some time to register the service"""
-                    time.sleep(0.25)
-                    print(f"services={_mdns_services(server_port)}")
+                    time.sleep(1)
                     self.assertTrue(any((serv_instance in line and serv_type in line)
-                        for line in _mdns_services(server_port)))
+                        for line in MdnsTest._mdns_services(server_port)))
 
                 """Give adb some time to unregister the service"""
-                print("Unregistering mdns service...")
-                time.sleep(0.25)
-                print(f"services={_mdns_services(server_port)}")
+                time.sleep(1)
                 self.assertFalse(any((serv_instance in line and serv_type in line)
-                    for line in _mdns_services(server_port)))
+                    for line in MdnsTest._mdns_services(server_port)))
+
+    @unittest.skipIf(not is_zeroconf_installed(), "zeroconf library not installed")
+    def test_mdns_connect(self):
+        """Ensure that `adb connect` by mdns instance name works (for non-pairing services)
+        """
+        from zeroconf import IPVersion, ServiceInfo
+
+        with adb_server() as server_port:
+            with zeroconf_context(IPVersion.V4Only) as zc:
+                serv_instance = "fakeadbd-" + ''.join(
+                        random.choice(string.ascii_letters) for i in range(4))
+                serv_type = "_" + self.service_name + "._tcp."
+                serv_ipaddr = socket.inet_aton("127.0.0.1")
+                should_connect = self.service_name != "adb-tls-pairing"
+                with fake_adbd() as (port, _):
+                    service_info = ServiceInfo(
+                            serv_type + "local.",
+                            name=serv_instance + "." + serv_type + "local.",
+                            addresses=[serv_ipaddr],
+                            port=port)
+                    with zeroconf_register_service(zc, service_info) as info:
+                        """Give adb some time to register the service"""
+                        time.sleep(1)
+                        self.assertTrue(any((serv_instance in line and serv_type in line)
+                            for line in MdnsTest._mdns_services(server_port)))
+                        full_name = '.'.join([serv_instance, serv_type])
+                        with self._adb_mdns_connect(server_port, serv_instance, full_name,
+                                should_connect):
+                            if should_connect:
+                                self.assertEqual(MdnsTest._devices(server_port),
+                                        [[full_name, "device"]])
+
+                    """Give adb some time to unregister the service"""
+                    time.sleep(1)
+                    self.assertFalse(any((serv_instance in line and serv_type in line)
+                        for line in MdnsTest._mdns_services(server_port)))
 
 def main():
     """Main entrypoint."""
diff --git a/adb/test_device.py b/adb/test_device.py
index f5e4cbb..9f1f403 100755
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -82,10 +82,13 @@
 
 class AbbTest(DeviceTest):
     def test_smoke(self):
-        result = subprocess.run(['adb', 'abb'], capture_output=True)
-        self.assertEqual(1, result.returncode)
-        expected_output = b"cmd: No service specified; use -l to list all services\n"
-        self.assertEqual(expected_output, result.stderr)
+        abb = subprocess.run(['adb', 'abb'], capture_output=True)
+        cmd = subprocess.run(['adb', 'shell', 'cmd'], capture_output=True)
+
+        # abb squashes all failures to 1.
+        self.assertEqual(abb.returncode == 0, cmd.returncode == 0)
+        self.assertEqual(abb.stdout, cmd.stdout)
+        self.assertEqual(abb.stderr, cmd.stderr)
 
 class ForwardReverseTest(DeviceTest):
     def _test_no_rebind(self, description, direction_list, direction,
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 25ed366..1667011 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -928,6 +928,7 @@
     remove_transport(t);
 }
 
+#if ADB_HOST
 static int qual_match(const std::string& to_test, const char* prefix, const std::string& qual,
                       bool sanitize_qual) {
     if (to_test.empty()) /* Return true if both the qual and to_test are empty strings. */
@@ -1083,10 +1084,13 @@
     }
     cv_.notify_one();
 }
+#endif
 
 atransport::~atransport() {
+#if ADB_HOST
     // If the connection callback had not been run before, run it now.
     SetConnectionEstablished(false);
+#endif
 }
 
 int atransport::Write(apacket* p) {
@@ -1240,6 +1244,7 @@
     disconnects_.clear();
 }
 
+#if ADB_HOST
 bool atransport::MatchesTarget(const std::string& target) const {
     if (!serial.empty()) {
         if (target == serial) {
@@ -1283,8 +1288,6 @@
     return reconnect_(this);
 }
 
-#if ADB_HOST
-
 // We use newline as our delimiter, make sure to never output it.
 static std::string sanitize(std::string str, bool alphanumeric) {
     auto pred = alphanumeric ? [](const char c) { return !isalnum(c); }
@@ -1366,7 +1369,7 @@
 void close_usb_devices(bool reset) {
     close_usb_devices([](const atransport*) { return true; }, reset);
 }
-#endif  // ADB_HOST
+#endif
 
 bool register_socket_transport(unique_fd s, std::string serial, int port, int local,
                                atransport::ReconnectCallback reconnect, bool use_tls, int* error) {
@@ -1406,7 +1409,9 @@
 
     lock.unlock();
 
+#if ADB_HOST
     auto waitable = t->connection_waitable();
+#endif
     register_transport(t);
 
     if (local == 1) {
@@ -1414,6 +1419,7 @@
         return true;
     }
 
+#if ADB_HOST
     if (!waitable->WaitForConnection(std::chrono::seconds(10))) {
         if (error) *error = ETIMEDOUT;
         return false;
@@ -1423,6 +1429,7 @@
         if (error) *error = EPERM;
         return false;
     }
+#endif
 
     return true;
 }
@@ -1453,14 +1460,9 @@
             t->Kick();
         }
     }
-#if ADB_HOST
     reconnect_handler.CheckForKicked();
-#endif
 }
 
-#endif
-
-#if ADB_HOST
 void register_usb_transport(usb_handle* usb, const char* serial, const char* devpath,
                             unsigned writeable) {
     atransport* t = new atransport(writeable ? kCsOffline : kCsNoPerm);
@@ -1482,9 +1484,7 @@
 
     register_transport(t);
 }
-#endif
 
-#if ADB_HOST
 // This should only be used for transports with connection_state == kCsNoPerm.
 void unregister_usb_transport(usb_handle* usb) {
     std::lock_guard<std::recursive_mutex> lock(transport_lock);
diff --git a/adb/transport.h b/adb/transport.h
index e93c31c..2ac21cf 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -262,9 +262,12 @@
         : id(NextTransportId()),
           kicked_(false),
           connection_state_(state),
-          connection_waitable_(std::make_shared<ConnectionWaitable>()),
           connection_(nullptr),
           reconnect_(std::move(reconnect)) {
+#if ADB_HOST
+        connection_waitable_ = std::make_shared<ConnectionWaitable>();
+#endif
+
         // Initialize protocol to min version for compatibility with older versions.
         // Version will be updated post-connect.
         protocol_version = A_VERSION_MIN;
@@ -350,6 +353,7 @@
     void RemoveDisconnect(adisconnect* disconnect);
     void RunDisconnects();
 
+#if ADB_HOST
     // Returns true if |target| matches this transport. A matching |target| can be any of:
     //   * <serial>
     //   * <devpath>
@@ -374,6 +378,7 @@
 
     // Attempts to reconnect with the underlying Connection.
     ReconnectResult Reconnect();
+#endif
 
   private:
     std::atomic<bool> kicked_;
@@ -392,9 +397,11 @@
     std::deque<std::shared_ptr<RSA>> keys_;
 #endif
 
+#if ADB_HOST
     // A sharable object that can be used to wait for the atransport's
     // connection to be established.
     std::shared_ptr<ConnectionWaitable> connection_waitable_;
+#endif
 
     // The underlying connection object.
     std::shared_ptr<Connection> connection_ GUARDED_BY(mutex_);
@@ -434,10 +441,17 @@
 void init_transport_registration(void);
 void init_mdns_transport_discovery(void);
 std::string list_transports(bool long_listing);
+
+#if ADB_HOST
 atransport* find_transport(const char* serial);
+
 void kick_all_tcp_devices();
+#endif
+
 void kick_all_transports();
+
 void kick_all_tcp_tls_transports();
+
 #if !ADB_HOST
 void kick_all_transports_by_auth_key(std::string_view auth_key);
 #endif
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index a9ada4a..8579ff4 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -127,6 +127,7 @@
     ASSERT_EQ(std::string("baz"), t.device);
 }
 
+#if ADB_HOST
 TEST_F(TransportTest, test_matches_target) {
     std::string serial = "foo";
     std::string devpath = "/path/to/bar";
@@ -183,3 +184,4 @@
         EXPECT_FALSE(t.MatchesTarget("abc:100.100.100.100"));
     }
 }
+#endif
diff --git a/base b/base
new file mode 120000
index 0000000..622c552
--- /dev/null
+++ b/base
@@ -0,0 +1 @@
+../libbase
\ No newline at end of file
diff --git a/base/.clang-format b/base/.clang-format
deleted file mode 120000
index fd0645f..0000000
--- a/base/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-../.clang-format-2
\ No newline at end of file
diff --git a/base/Android.bp b/base/Android.bp
deleted file mode 100644
index 58af2eb..0000000
--- a/base/Android.bp
+++ /dev/null
@@ -1,240 +0,0 @@
-//
-// Copyright (C) 2015 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: "libbase_cflags_defaults",
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wextra",
-    ],
-    target: {
-        android: {
-            cflags: [
-                "-D_FILE_OFFSET_BITS=64",
-            ],
-        },
-    },
-}
-
-cc_library_headers {
-    name: "libbase_headers",
-    vendor_available: true,
-    ramdisk_available: true,
-    recovery_available: true,
-    host_supported: true,
-    native_bridge_supported: true,
-    export_include_dirs: ["include"],
-
-    target: {
-        linux_bionic: {
-            enabled: true,
-        },
-        windows: {
-            enabled: true,
-        },
-    },
-    apex_available: [
-        "//apex_available:anyapex",
-        "//apex_available:platform",
-    ],
-}
-
-cc_defaults {
-    name: "libbase_defaults",
-    defaults: ["libbase_cflags_defaults"],
-    srcs: [
-        "abi_compatibility.cpp",
-        "chrono_utils.cpp",
-        "cmsg.cpp",
-        "file.cpp",
-        "liblog_symbols.cpp",
-        "logging.cpp",
-        "mapped_file.cpp",
-        "parsebool.cpp",
-        "parsenetaddress.cpp",
-        "process.cpp",
-        "properties.cpp",
-        "stringprintf.cpp",
-        "strings.cpp",
-        "threads.cpp",
-        "test_utils.cpp",
-    ],
-
-    cppflags: ["-Wexit-time-destructors"],
-    shared_libs: ["liblog"],
-    target: {
-        android: {
-            sanitize: {
-                misc_undefined: ["integer"],
-            },
-
-        },
-        linux: {
-            srcs: [
-                "errors_unix.cpp",
-            ],
-        },
-        darwin: {
-            srcs: [
-                "errors_unix.cpp",
-            ],
-        },
-        linux_bionic: {
-            enabled: true,
-        },
-        windows: {
-            srcs: [
-                "errors_windows.cpp",
-                "utf8.cpp",
-            ],
-            exclude_srcs: [
-                "cmsg.cpp",
-            ],
-            enabled: true,
-        },
-    },
-}
-
-cc_library {
-    name: "libbase",
-    defaults: ["libbase_defaults"],
-    vendor_available: true,
-    ramdisk_available: true,
-    recovery_available: true,
-    host_supported: true,
-    native_bridge_supported: true,
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
-    header_libs: [
-        "libbase_headers",
-    ],
-    export_header_lib_headers: ["libbase_headers"],
-    static_libs: ["fmtlib"],
-    whole_static_libs: ["fmtlib"],
-    export_static_lib_headers: ["fmtlib"],
-    apex_available: [
-        "//apex_available:anyapex",
-        "//apex_available:platform",
-    ],
-}
-
-cc_library_static {
-    name: "libbase_ndk",
-    defaults: ["libbase_defaults"],
-    sdk_version: "current",
-    stl: "c++_static",
-    export_include_dirs: ["include"],
-    static_libs: ["fmtlib_ndk"],
-    whole_static_libs: ["fmtlib_ndk"],
-    export_static_lib_headers: ["fmtlib_ndk"],
-}
-
-// Tests
-// ------------------------------------------------------------------------------
-cc_test {
-    name: "libbase_test",
-    defaults: ["libbase_cflags_defaults"],
-    host_supported: true,
-    srcs: [
-        "cmsg_test.cpp",
-        "endian_test.cpp",
-        "errors_test.cpp",
-        "expected_test.cpp",
-        "file_test.cpp",
-        "logging_splitters_test.cpp",
-        "logging_test.cpp",
-        "macros_test.cpp",
-        "mapped_file_test.cpp",
-        "no_destructor_test.cpp",
-        "parsedouble_test.cpp",
-        "parsebool_test.cpp",
-        "parseint_test.cpp",
-        "parsenetaddress_test.cpp",
-        "process_test.cpp",
-        "properties_test.cpp",
-        "result_test.cpp",
-        "scopeguard_test.cpp",
-        "stringprintf_test.cpp",
-        "strings_test.cpp",
-        "test_main.cpp",
-        "test_utils_test.cpp",
-    ],
-    target: {
-        android: {
-            sanitize: {
-                misc_undefined: ["integer"],
-            },
-        },
-        linux: {
-            srcs: ["chrono_utils_test.cpp"],
-        },
-        windows: {
-            srcs: ["utf8_test.cpp"],
-            cflags: ["-Wno-unused-parameter"],
-            enabled: true,
-        },
-    },
-    local_include_dirs: ["."],
-    shared_libs: ["libbase"],
-    compile_multilib: "both",
-    multilib: {
-        lib32: {
-            suffix: "32",
-        },
-        lib64: {
-            suffix: "64",
-        },
-    },
-    test_suites: ["device-tests"],
-}
-
-cc_test {
-    name: "libbase_tidy_test",
-    defaults: ["libbase_cflags_defaults"],
-    host_supported: true,
-
-    tidy: true,
-    tidy_checks_as_errors: ["bugprone-use-after-move"],
-
-    srcs: [
-        "tidy/unique_fd_test.cpp",
-        "tidy/unique_fd_test2.cpp",
-    ],
-
-    shared_libs: ["libbase"],
-    test_suites: ["device_tests"],
-}
-
-cc_benchmark {
-    name: "libbase_benchmark",
-    defaults: ["libbase_cflags_defaults"],
-
-    srcs: ["format_benchmark.cpp"],
-    shared_libs: ["libbase"],
-
-    compile_multilib: "both",
-    multilib: {
-        lib32: {
-            suffix: "32",
-        },
-        lib64: {
-            suffix: "64",
-        },
-    },
-}
diff --git a/base/CPPLINT.cfg b/base/CPPLINT.cfg
deleted file mode 100644
index d94a89c..0000000
--- a/base/CPPLINT.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-set noparent
-filter=-build/header_guard,-build/include,-build/c++11,-whitespace/operators
diff --git a/base/OWNERS b/base/OWNERS
deleted file mode 100644
index 97777f7..0000000
--- a/base/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-enh@google.com
-jmgao@google.com
-tomcherry@google.com
diff --git a/base/README.md b/base/README.md
deleted file mode 100644
index 2ef5c10..0000000
--- a/base/README.md
+++ /dev/null
@@ -1,42 +0,0 @@
-# libbase
-
-## Who is this library for?
-
-This library is a collection of convenience functions to make common tasks
-easier and less error-prone.
-
-In this context, "error-prone" covers both "hard to do correctly" and
-"hard to do with good performance", but as a general purpose library,
-libbase's primary focus is on making it easier to do things easily and
-correctly when a compromise has to be made between "simplest API" on the
-one hand and "fastest implementation" on the other. Though obviously
-the ideal is to have both.
-
-## Should my routine be added?
-
-The intention is to cover the 80% use cases, not be all things to all users.
-
-If you have a routine that's really useful in your project,
-congratulations. But that doesn't mean it should be here rather than
-just in your project.
-
-The question for libbase is "should everyone be doing this?"/"does this
-make everyone's code cleaner/safer?". Historically we've considered the
-bar for inclusion to be "are there at least three *unrelated* projects
-that would be cleaned up by doing so".
-
-If your routine is actually something from a future C++ standard (that
-isn't yet in libc++), or it's widely used in another library, that helps
-show that there's precedent. Being able to say "so-and-so has used this
-API for n years" is a good way to reduce concerns about API choices.
-
-## Any other restrictions?
-
-Unlike most Android code, code in libbase has to build for Mac and
-Windows too.
-
-Code here is also expected to have good test coverage.
-
-By its nature, it's difficult to change libbase API. It's often best
-to start using your routine just in your project, and let it "graduate"
-after you're certain that the API is solid.
diff --git a/base/abi_compatibility.cpp b/base/abi_compatibility.cpp
deleted file mode 100644
index 06a7801..0000000
--- a/base/abi_compatibility.cpp
+++ /dev/null
@@ -1,77 +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 <memory>
-
-#include "android-base/cmsg.h"
-#include "android-base/file.h"
-#include "android-base/mapped_file.h"
-#include "android-base/unique_fd.h"
-
-namespace android {
-namespace base {
-
-// These ABI-compatibility shims are in a separate file for two reasons:
-//   1. If they were in the file with the actual functions, it prevents calls to
-//      those functions by other functions in the file, due to ambiguity.
-//   2. We will hopefully be able to delete these quickly.
-
-#if !defined(_WIN32)
-ssize_t SendFileDescriptorVector(int sockfd, const void* data, size_t len,
-                                 const std::vector<int>& fds) {
-  return SendFileDescriptorVector(borrowed_fd(sockfd), data, len, fds);
-}
-
-ssize_t ReceiveFileDescriptorVector(int sockfd, void* data, size_t len, size_t max_fds,
-                                    std::vector<unique_fd>* fds) {
-  return ReceiveFileDescriptorVector(borrowed_fd(sockfd), data, len, max_fds, fds);
-}
-#endif
-
-bool ReadFdToString(int fd, std::string* content) {
-  return ReadFdToString(borrowed_fd(fd), content);
-}
-
-bool WriteStringToFd(const std::string& content, int fd) {
-  return WriteStringToFd(content, borrowed_fd(fd));
-}
-
-bool ReadFully(int fd, void* data, size_t byte_count) {
-  return ReadFully(borrowed_fd(fd), data, byte_count);
-}
-
-bool ReadFullyAtOffset(int fd, void* data, size_t byte_count, off64_t offset) {
-  return ReadFullyAtOffset(borrowed_fd(fd), data, byte_count, offset);
-}
-
-bool WriteFully(int fd, const void* data, size_t byte_count) {
-  return WriteFully(borrowed_fd(fd), data, byte_count);
-}
-
-#if defined(__LP64__)
-#define MAPPEDFILE_FROMFD _ZN10MappedFile6FromFdEilmi
-#else
-#define MAPPEDFILE_FROMFD _ZN10MappedFile6FromFdEixmi
-#endif
-
-#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
-extern "C" std::unique_ptr<MappedFile> MAPPEDFILE_FROMFD(int fd, off64_t offset, size_t length,
-                                                         int prot) {
-  return MappedFile::FromFd(fd, offset, length, prot);
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/chrono_utils.cpp b/base/chrono_utils.cpp
deleted file mode 100644
index 19080a5..0000000
--- a/base/chrono_utils.cpp
+++ /dev/null
@@ -1,42 +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 "android-base/chrono_utils.h"
-
-#include <time.h>
-
-namespace android {
-namespace base {
-
-boot_clock::time_point boot_clock::now() {
-#ifdef __linux__
-  timespec ts;
-  clock_gettime(CLOCK_BOOTTIME, &ts);
-  return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) +
-                                std::chrono::nanoseconds(ts.tv_nsec));
-#else
-  // Darwin and Windows do not support clock_gettime.
-  return boot_clock::time_point();
-#endif  // __linux__
-}
-
-std::ostream& operator<<(std::ostream& os, const Timer& t) {
-  os << t.duration().count() << "ms";
-  return os;
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/chrono_utils_test.cpp b/base/chrono_utils_test.cpp
deleted file mode 100644
index da442f4..0000000
--- a/base/chrono_utils_test.cpp
+++ /dev/null
@@ -1,80 +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 "android-base/chrono_utils.h"
-
-#include <time.h>
-
-#include <chrono>
-#include <sstream>
-#include <string>
-#include <thread>
-
-#include <gtest/gtest.h>
-
-namespace android {
-namespace base {
-
-std::chrono::seconds GetBootTimeSeconds() {
-  struct timespec now;
-  clock_gettime(CLOCK_BOOTTIME, &now);
-
-  auto now_tp = boot_clock::time_point(std::chrono::seconds(now.tv_sec) +
-                                       std::chrono::nanoseconds(now.tv_nsec));
-  return std::chrono::duration_cast<std::chrono::seconds>(now_tp.time_since_epoch());
-}
-
-// Tests (at least) the seconds accuracy of the boot_clock::now() method.
-TEST(ChronoUtilsTest, BootClockNowSeconds) {
-  auto now = GetBootTimeSeconds();
-  auto boot_seconds =
-      std::chrono::duration_cast<std::chrono::seconds>(boot_clock::now().time_since_epoch());
-  EXPECT_EQ(now, boot_seconds);
-}
-
-template <typename T>
-void ExpectAboutEqual(T expected, T actual) {
-  auto expected_upper_bound = expected * 1.05f;
-  auto expected_lower_bound = expected * .95;
-  EXPECT_GT(expected_upper_bound, actual);
-  EXPECT_LT(expected_lower_bound, actual);
-}
-
-TEST(ChronoUtilsTest, TimerDurationIsSane) {
-  auto start = boot_clock::now();
-  Timer t;
-  std::this_thread::sleep_for(50ms);
-  auto stop = boot_clock::now();
-  auto stop_timer = t.duration();
-
-  auto expected = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
-  ExpectAboutEqual(expected, stop_timer);
-}
-
-TEST(ChronoUtilsTest, TimerOstream) {
-  Timer t;
-  std::this_thread::sleep_for(50ms);
-  auto stop_timer = t.duration().count();
-  std::stringstream os;
-  os << t;
-  decltype(stop_timer) stop_timer_from_stream;
-  os >> stop_timer_from_stream;
-  EXPECT_NE(0, stop_timer);
-  ExpectAboutEqual(stop_timer, stop_timer_from_stream);
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/cmsg.cpp b/base/cmsg.cpp
deleted file mode 100644
index 1fa873c..0000000
--- a/base/cmsg.cpp
+++ /dev/null
@@ -1,173 +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 <android-base/cmsg.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/user.h>
-
-#include <memory>
-
-#include <android-base/logging.h>
-
-namespace android {
-namespace base {
-
-ssize_t SendFileDescriptorVector(borrowed_fd sockfd, const void* data, size_t len,
-                                 const std::vector<int>& fds) {
-  size_t cmsg_space = CMSG_SPACE(sizeof(int) * fds.size());
-  size_t cmsg_len = CMSG_LEN(sizeof(int) * fds.size());
-  if (cmsg_space >= PAGE_SIZE) {
-    errno = ENOMEM;
-    return -1;
-  }
-
-  alignas(struct cmsghdr) char cmsg_buf[cmsg_space];
-  iovec iov = {.iov_base = const_cast<void*>(data), .iov_len = len};
-  msghdr msg = {
-      .msg_name = nullptr,
-      .msg_namelen = 0,
-      .msg_iov = &iov,
-      .msg_iovlen = 1,
-      .msg_control = cmsg_buf,
-      // We can't cast to the actual type of the field, because it's different across platforms.
-      .msg_controllen = static_cast<unsigned int>(cmsg_space),
-      .msg_flags = 0,
-  };
-
-  struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
-  cmsg->cmsg_level = SOL_SOCKET;
-  cmsg->cmsg_type = SCM_RIGHTS;
-  cmsg->cmsg_len = cmsg_len;
-
-  int* cmsg_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
-  for (size_t i = 0; i < fds.size(); ++i) {
-    cmsg_fds[i] = fds[i];
-  }
-
-#if defined(__linux__)
-  int flags = MSG_NOSIGNAL;
-#else
-  int flags = 0;
-#endif
-
-  return TEMP_FAILURE_RETRY(sendmsg(sockfd.get(), &msg, flags));
-}
-
-ssize_t ReceiveFileDescriptorVector(borrowed_fd sockfd, void* data, size_t len, size_t max_fds,
-                                    std::vector<unique_fd>* fds) {
-  fds->clear();
-
-  size_t cmsg_space = CMSG_SPACE(sizeof(int) * max_fds);
-  if (cmsg_space >= PAGE_SIZE) {
-    errno = ENOMEM;
-    return -1;
-  }
-
-  alignas(struct cmsghdr) char cmsg_buf[cmsg_space];
-  iovec iov = {.iov_base = const_cast<void*>(data), .iov_len = len};
-  msghdr msg = {
-      .msg_name = nullptr,
-      .msg_namelen = 0,
-      .msg_iov = &iov,
-      .msg_iovlen = 1,
-      .msg_control = cmsg_buf,
-      // We can't cast to the actual type of the field, because it's different across platforms.
-      .msg_controllen = static_cast<unsigned int>(cmsg_space),
-      .msg_flags = 0,
-  };
-
-  int flags = MSG_TRUNC | MSG_CTRUNC;
-#if defined(__linux__)
-  flags |= MSG_CMSG_CLOEXEC | MSG_NOSIGNAL;
-#endif
-
-  ssize_t rc = TEMP_FAILURE_RETRY(recvmsg(sockfd.get(), &msg, flags));
-
-  if (rc == -1) {
-    return -1;
-  }
-
-  int error = 0;
-  if ((msg.msg_flags & MSG_TRUNC)) {
-    LOG(ERROR) << "message was truncated when receiving file descriptors";
-    error = EMSGSIZE;
-  } else if ((msg.msg_flags & MSG_CTRUNC)) {
-    LOG(ERROR) << "control message was truncated when receiving file descriptors";
-    error = EMSGSIZE;
-  }
-
-  std::vector<unique_fd> received_fds;
-  struct cmsghdr* cmsg;
-  for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
-    if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
-      LOG(ERROR) << "received unexpected cmsg: [" << cmsg->cmsg_level << ", " << cmsg->cmsg_type
-                 << "]";
-      error = EBADMSG;
-      continue;
-    }
-
-    // There isn't a macro that does the inverse of CMSG_LEN, so hack around it ourselves, with
-    // some asserts to ensure that CMSG_LEN behaves as we expect.
-#if defined(__linux__)
-#define CMSG_ASSERT static_assert
-#else
-// CMSG_LEN is somehow not constexpr on darwin.
-#define CMSG_ASSERT CHECK
-#endif
-    CMSG_ASSERT(CMSG_LEN(0) + 1 * sizeof(int) == CMSG_LEN(1 * sizeof(int)));
-    CMSG_ASSERT(CMSG_LEN(0) + 2 * sizeof(int) == CMSG_LEN(2 * sizeof(int)));
-    CMSG_ASSERT(CMSG_LEN(0) + 3 * sizeof(int) == CMSG_LEN(3 * sizeof(int)));
-    CMSG_ASSERT(CMSG_LEN(0) + 4 * sizeof(int) == CMSG_LEN(4 * sizeof(int)));
-
-    if (cmsg->cmsg_len % sizeof(int) != 0) {
-      LOG(FATAL) << "cmsg_len(" << cmsg->cmsg_len << ") not aligned to sizeof(int)";
-    } else if (cmsg->cmsg_len <= CMSG_LEN(0)) {
-      LOG(FATAL) << "cmsg_len(" << cmsg->cmsg_len << ") not long enough to hold any data";
-    }
-
-    int* cmsg_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
-    size_t cmsg_fdcount = static_cast<size_t>(cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
-    for (size_t i = 0; i < cmsg_fdcount; ++i) {
-#if !defined(__linux__)
-      // Linux uses MSG_CMSG_CLOEXEC instead of doing this manually.
-      fcntl(cmsg_fds[i], F_SETFD, FD_CLOEXEC);
-#endif
-      received_fds.emplace_back(cmsg_fds[i]);
-    }
-  }
-
-  if (error != 0) {
-    errno = error;
-    return -1;
-  }
-
-  if (received_fds.size() > max_fds) {
-    LOG(ERROR) << "received too many file descriptors, expected " << fds->size() << ", received "
-               << received_fds.size();
-    errno = EMSGSIZE;
-    return -1;
-  }
-
-  *fds = std::move(received_fds);
-  return rc;
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/cmsg_test.cpp b/base/cmsg_test.cpp
deleted file mode 100644
index 9ee5c82..0000000
--- a/base/cmsg_test.cpp
+++ /dev/null
@@ -1,202 +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 <android-base/cmsg.h>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/unique_fd.h>
-#include <gtest/gtest.h>
-
-#if !defined(_WIN32)
-
-using android::base::ReceiveFileDescriptors;
-using android::base::SendFileDescriptors;
-using android::base::unique_fd;
-
-static ino_t GetInode(int fd) {
-  struct stat st;
-  if (fstat(fd, &st) != 0) {
-    PLOG(FATAL) << "fstat failed";
-  }
-
-  return st.st_ino;
-}
-
-struct CmsgTest : ::testing::TestWithParam<bool> {
-  bool Seqpacket() { return GetParam(); }
-
-  void SetUp() override {
-    ASSERT_TRUE(
-        android::base::Socketpair(Seqpacket() ? SOCK_SEQPACKET : SOCK_STREAM, &send, &recv));
-    int dup1 = dup(tmp1.fd);
-    ASSERT_NE(-1, dup1);
-    int dup2 = dup(tmp2.fd);
-    ASSERT_NE(-1, dup2);
-
-    fd1.reset(dup1);
-    fd2.reset(dup2);
-
-    ino1 = GetInode(dup1);
-    ino2 = GetInode(dup2);
-  }
-
-  unique_fd send;
-  unique_fd recv;
-
-  TemporaryFile tmp1;
-  TemporaryFile tmp2;
-
-  unique_fd fd1;
-  unique_fd fd2;
-
-  ino_t ino1;
-  ino_t ino2;
-};
-
-TEST_P(CmsgTest, smoke) {
-  ASSERT_EQ(1, SendFileDescriptors(send.get(), "x", 1, fd1.get()));
-
-  char buf[2];
-  unique_fd received;
-  ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 2, &received));
-  ASSERT_EQ('x', buf[0]);
-  ASSERT_NE(-1, received.get());
-
-  ASSERT_EQ(ino1, GetInode(received.get()));
-}
-
-TEST_P(CmsgTest, msg_trunc) {
-  ASSERT_EQ(2, SendFileDescriptors(send.get(), "ab", 2, fd1.get(), fd2.get()));
-
-  char buf[2];
-  unique_fd received1, received2;
-
-  ssize_t rc = ReceiveFileDescriptors(recv.get(), buf, 1, &received1, &received2);
-  if (Seqpacket()) {
-    ASSERT_EQ(-1, rc);
-    ASSERT_EQ(EMSGSIZE, errno);
-    ASSERT_EQ(-1, received1.get());
-    ASSERT_EQ(-1, received2.get());
-  } else {
-    ASSERT_EQ(1, rc);
-    ASSERT_NE(-1, received1.get());
-    ASSERT_NE(-1, received2.get());
-    ASSERT_EQ(ino1, GetInode(received1.get()));
-    ASSERT_EQ(ino2, GetInode(received2.get()));
-    ASSERT_EQ(1, read(recv.get(), buf, 2));
-  }
-}
-
-TEST_P(CmsgTest, msg_ctrunc) {
-  ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get(), fd2.get()));
-
-  char buf[2];
-  unique_fd received;
-  ASSERT_EQ(-1, ReceiveFileDescriptors(recv.get(), buf, 1, &received));
-  ASSERT_EQ(EMSGSIZE, errno);
-  ASSERT_EQ(-1, received.get());
-}
-
-TEST_P(CmsgTest, peek) {
-  ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get()));
-
-  char buf[2];
-  ASSERT_EQ(1, ::recv(recv.get(), buf, sizeof(buf), MSG_PEEK));
-  ASSERT_EQ('a', buf[0]);
-
-  unique_fd received;
-  ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received));
-  ASSERT_EQ(ino1, GetInode(received.get()));
-}
-
-TEST_P(CmsgTest, stream_fd_association) {
-  if (Seqpacket()) {
-    return;
-  }
-
-  // fds are associated with the first byte of the write.
-  ASSERT_EQ(1, TEMP_FAILURE_RETRY(write(send.get(), "a", 1)));
-  ASSERT_EQ(2, SendFileDescriptors(send.get(), "bc", 2, fd1.get()));
-  ASSERT_EQ(1, SendFileDescriptors(send.get(), "d", 1, fd2.get()));
-  char buf[2];
-  ASSERT_EQ(2, TEMP_FAILURE_RETRY(read(recv.get(), buf, 2)));
-  ASSERT_EQ(0, memcmp(buf, "ab", 2));
-
-  std::vector<unique_fd> received1;
-  ssize_t rc = ReceiveFileDescriptorVector(recv.get(), buf, 1, 1, &received1);
-  ASSERT_EQ(1, rc);
-  ASSERT_EQ('c', buf[0]);
-  ASSERT_TRUE(received1.empty());
-
-  unique_fd received2;
-  rc = ReceiveFileDescriptors(recv.get(), buf, 1, &received2);
-  ASSERT_EQ(1, rc);
-  ASSERT_EQ('d', buf[0]);
-  ASSERT_EQ(ino2, GetInode(received2.get()));
-}
-
-TEST_P(CmsgTest, multiple_fd_ordering) {
-  ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get(), fd2.get()));
-
-  char buf[2];
-  unique_fd received1, received2;
-  ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received1, &received2));
-
-  ASSERT_NE(-1, received1.get());
-  ASSERT_NE(-1, received2.get());
-
-  ASSERT_EQ(ino1, GetInode(received1.get()));
-  ASSERT_EQ(ino2, GetInode(received2.get()));
-}
-
-TEST_P(CmsgTest, separate_fd_ordering) {
-  ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get()));
-  ASSERT_EQ(1, SendFileDescriptors(send.get(), "b", 1, fd2.get()));
-
-  char buf[2];
-  unique_fd received1, received2;
-  ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received1));
-  ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received2));
-
-  ASSERT_NE(-1, received1.get());
-  ASSERT_NE(-1, received2.get());
-
-  ASSERT_EQ(ino1, GetInode(received1.get()));
-  ASSERT_EQ(ino2, GetInode(received2.get()));
-}
-
-TEST_P(CmsgTest, separate_fds_no_coalescing) {
-  unique_fd sent1(dup(tmp1.fd));
-  unique_fd sent2(dup(tmp2.fd));
-
-  ASSERT_EQ(1, SendFileDescriptors(send.get(), "", 1, fd1.get()));
-  ASSERT_EQ(1, SendFileDescriptors(send.get(), "", 1, fd2.get()));
-
-  char buf[2];
-  std::vector<unique_fd> received;
-  ASSERT_EQ(1, ReceiveFileDescriptorVector(recv.get(), buf, 2, 2, &received));
-  ASSERT_EQ(1U, received.size());
-  ASSERT_EQ(ino1, GetInode(received[0].get()));
-
-  ASSERT_EQ(1, ReceiveFileDescriptorVector(recv.get(), buf, 2, 2, &received));
-  ASSERT_EQ(1U, received.size());
-  ASSERT_EQ(ino2, GetInode(received[0].get()));
-}
-
-INSTANTIATE_TEST_CASE_P(CmsgTest, CmsgTest, testing::Bool());
-
-#endif
diff --git a/base/endian_test.cpp b/base/endian_test.cpp
deleted file mode 100644
index 963ab13..0000000
--- a/base/endian_test.cpp
+++ /dev/null
@@ -1,69 +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 "android-base/endian.h"
-
-#include <gtest/gtest.h>
-
-TEST(endian, constants) {
-  ASSERT_TRUE(__LITTLE_ENDIAN == LITTLE_ENDIAN);
-  ASSERT_TRUE(__BIG_ENDIAN == BIG_ENDIAN);
-  ASSERT_TRUE(__BYTE_ORDER == BYTE_ORDER);
-
-  ASSERT_EQ(__LITTLE_ENDIAN, __BYTE_ORDER);
-}
-
-TEST(endian, smoke) {
-  static constexpr uint16_t le16 = 0x1234;
-  static constexpr uint32_t le32 = 0x12345678;
-  static constexpr uint64_t le64 = 0x123456789abcdef0;
-
-  static constexpr uint16_t be16 = 0x3412;
-  static constexpr uint32_t be32 = 0x78563412;
-  static constexpr uint64_t be64 = 0xf0debc9a78563412;
-
-  ASSERT_EQ(be16, htons(le16));
-  ASSERT_EQ(be32, htonl(le32));
-  ASSERT_EQ(be64, htonq(le64));
-
-  ASSERT_EQ(le16, ntohs(be16));
-  ASSERT_EQ(le32, ntohl(be32));
-  ASSERT_EQ(le64, ntohq(be64));
-
-  ASSERT_EQ(be16, htobe16(le16));
-  ASSERT_EQ(be32, htobe32(le32));
-  ASSERT_EQ(be64, htobe64(le64));
-
-  ASSERT_EQ(le16, betoh16(be16));
-  ASSERT_EQ(le32, betoh32(be32));
-  ASSERT_EQ(le64, betoh64(be64));
-
-  ASSERT_EQ(le16, htole16(le16));
-  ASSERT_EQ(le32, htole32(le32));
-  ASSERT_EQ(le64, htole64(le64));
-
-  ASSERT_EQ(le16, letoh16(le16));
-  ASSERT_EQ(le32, letoh32(le32));
-  ASSERT_EQ(le64, letoh64(le64));
-
-  ASSERT_EQ(le16, be16toh(be16));
-  ASSERT_EQ(le32, be32toh(be32));
-  ASSERT_EQ(le64, be64toh(be64));
-
-  ASSERT_EQ(le16, le16toh(le16));
-  ASSERT_EQ(le32, le32toh(le32));
-  ASSERT_EQ(le64, le64toh(le64));
-}
diff --git a/base/errors_test.cpp b/base/errors_test.cpp
deleted file mode 100644
index 8e7cdd1..0000000
--- a/base/errors_test.cpp
+++ /dev/null
@@ -1,34 +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 "android-base/errors.h"
-
-#include <gtest/gtest.h>
-
-namespace android {
-namespace base {
-
-// Error strings aren't consistent enough across systems to test the output,
-// just make sure we can compile correctly and nothing crashes even if we send
-// it possibly bogus error codes.
-TEST(ErrorsTest, TestSystemErrorString) {
-  SystemErrorCodeToString(-1);
-  SystemErrorCodeToString(0);
-  SystemErrorCodeToString(1);
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/errors_unix.cpp b/base/errors_unix.cpp
deleted file mode 100644
index 48269b6..0000000
--- a/base/errors_unix.cpp
+++ /dev/null
@@ -1,30 +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 "android-base/errors.h"
-
-#include <errno.h>
-#include <string.h>
-
-namespace android {
-namespace base {
-
-std::string SystemErrorCodeToString(int error_code) {
-  return strerror(error_code);
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/errors_windows.cpp b/base/errors_windows.cpp
deleted file mode 100644
index a5ff511..0000000
--- a/base/errors_windows.cpp
+++ /dev/null
@@ -1,68 +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 "android-base/errors.h"
-
-#include <windows.h>
-
-#include "android-base/stringprintf.h"
-#include "android-base/strings.h"
-#include "android-base/utf8.h"
-
-// A Windows error code is a DWORD. It's simpler to use an int error code for
-// both Unix and Windows if possible, but if this fails we'll need a different
-// function signature for each.
-static_assert(sizeof(int) >= sizeof(DWORD),
-              "Windows system error codes are too large to fit in an int.");
-
-namespace android {
-namespace base {
-
-static constexpr DWORD kErrorMessageBufferSize = 256;
-
-std::string SystemErrorCodeToString(int int_error_code) {
-  WCHAR msgbuf[kErrorMessageBufferSize];
-  DWORD error_code = int_error_code;
-  DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
-  DWORD len = FormatMessageW(flags, nullptr, error_code, 0, msgbuf,
-                             kErrorMessageBufferSize, nullptr);
-  if (len == 0) {
-    return android::base::StringPrintf(
-        "Error %lu while retrieving message for error %lu", GetLastError(),
-        error_code);
-  }
-
-  // Convert UTF-16 to UTF-8.
-  std::string msg;
-  if (!android::base::WideToUTF8(msgbuf, &msg)) {
-    return android::base::StringPrintf(
-        "Error %lu while converting message for error %lu from UTF-16 to UTF-8",
-        GetLastError(), error_code);
-  }
-
-  // Messages returned by the system end with line breaks.
-  msg = android::base::Trim(msg);
-
-  // There are many Windows error messages compared to POSIX, so include the
-  // numeric error code for easier, quicker, accurate identification. Use
-  // decimal instead of hex because there are decimal ranges like 10000-11999
-  // for Winsock.
-  android::base::StringAppendF(&msg, " (%lu)", error_code);
-  return msg;
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/expected_test.cpp b/base/expected_test.cpp
deleted file mode 100644
index 47e396a..0000000
--- a/base/expected_test.cpp
+++ /dev/null
@@ -1,876 +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 "android-base/expected.h"
-
-#include <cstdio>
-#include <memory>
-#include <string>
-
-#include <gtest/gtest.h>
-
-using android::base::expected;
-using android::base::unexpected;
-
-typedef expected<int, int> exp_int;
-typedef expected<double, double> exp_double;
-typedef expected<std::string, std::string> exp_string;
-typedef expected<std::pair<std::string, int>, int> exp_pair;
-typedef expected<void, int> exp_void;
-
-struct T {
-  int a;
-  int b;
-  T() = default;
-  T(int a, int b) noexcept : a(a), b(b) {}
-};
-bool operator==(const T& x, const T& y) {
-  return x.a == y.a && x.b == y.b;
-}
-bool operator!=(const T& x, const T& y) {
-  return x.a != y.a || x.b != y.b;
-}
-
-struct E {
-    std::string message;
-    int cause;
-    E(const std::string& message, int cause) : message(message), cause(cause) {}
-};
-
-typedef expected<T,E> exp_complex;
-
-TEST(Expected, testDefaultConstructible) {
-  exp_int e;
-  EXPECT_TRUE(e.has_value());
-  EXPECT_EQ(0, e.value());
-
-  exp_complex e2;
-  EXPECT_TRUE(e2.has_value());
-  EXPECT_EQ(T(0,0), e2.value());
-
-  exp_void e3;
-  EXPECT_TRUE(e3.has_value());
-}
-
-TEST(Expected, testCopyConstructible) {
-  exp_int e;
-  exp_int e2 = e;
-
-  EXPECT_TRUE(e.has_value());
-  EXPECT_TRUE(e2.has_value());
-  EXPECT_EQ(0, e.value());
-  EXPECT_EQ(0, e2.value());
-
-  exp_void e3;
-  exp_void e4 = e3;
-  EXPECT_TRUE(e3.has_value());
-  EXPECT_TRUE(e4.has_value());
-}
-
-TEST(Expected, testMoveConstructible) {
-  exp_int e;
-  exp_int e2 = std::move(e);
-
-  EXPECT_TRUE(e.has_value());
-  EXPECT_TRUE(e2.has_value());
-  EXPECT_EQ(0, e.value());
-  EXPECT_EQ(0, e2.value());
-
-  exp_string e3(std::string("hello"));
-  exp_string e4 = std::move(e3);
-
-  EXPECT_TRUE(e3.has_value());
-  EXPECT_TRUE(e4.has_value());
-  EXPECT_EQ("", e3.value()); // e3 is moved
-  EXPECT_EQ("hello", e4.value());
-
-  exp_void e5;
-  exp_void e6 = std::move(e5);
-  EXPECT_TRUE(e5.has_value());
-  EXPECT_TRUE(e6.has_value());
-}
-
-TEST(Expected, testCopyConstructibleFromConvertibleType) {
-  exp_double e = 3.3f;
-  exp_int e2 = e;
-
-  EXPECT_TRUE(e.has_value());
-  EXPECT_TRUE(e2.has_value());
-  EXPECT_EQ(3.3f, e.value());
-  EXPECT_EQ(3, e2.value());
-}
-
-TEST(Expected, testMoveConstructibleFromConvertibleType) {
-  exp_double e = 3.3f;
-  exp_int e2 = std::move(e);
-
-  EXPECT_TRUE(e.has_value());
-  EXPECT_TRUE(e2.has_value());
-  EXPECT_EQ(3.3f, e.value());
-  EXPECT_EQ(3, e2.value());
-}
-
-TEST(Expected, testConstructibleFromValue) {
-  exp_int e = 3;
-  exp_double e2 = 5.5f;
-  exp_string e3 = std::string("hello");
-  exp_complex e4 = T(10, 20);
-  exp_void e5 = {};
-
-  EXPECT_TRUE(e.has_value());
-  EXPECT_TRUE(e2.has_value());
-  EXPECT_TRUE(e3.has_value());
-  EXPECT_TRUE(e4.has_value());
-  EXPECT_TRUE(e5.has_value());
-  EXPECT_EQ(3, e.value());
-  EXPECT_EQ(5.5f, e2.value());
-  EXPECT_EQ("hello", e3.value());
-  EXPECT_EQ(T(10,20), e4.value());
-}
-
-TEST(Expected, testConstructibleFromMovedValue) {
-  std::string hello = "hello";
-  exp_string e = std::move(hello);
-
-  EXPECT_TRUE(e.has_value());
-  EXPECT_EQ("hello", e.value());
-  EXPECT_EQ("", hello);
-}
-
-TEST(Expected, testConstructibleFromConvertibleValue) {
-  exp_int e = 3.3f; // double to int
-  exp_string e2 = "hello"; // char* to std::string
-  EXPECT_TRUE(e.has_value());
-  EXPECT_EQ(3, e.value());
-
-  EXPECT_TRUE(e2.has_value());
-  EXPECT_EQ("hello", e2.value());
-}
-
-TEST(Expected, testConstructibleFromUnexpected) {
-  exp_int::unexpected_type unexp = unexpected(10);
-  exp_int e = unexp;
-
-  exp_double::unexpected_type unexp2 = unexpected(10.5f);
-  exp_double e2 = unexp2;
-
-  exp_string::unexpected_type unexp3 = unexpected(std::string("error"));
-  exp_string e3 = unexp3;
-
-  exp_void::unexpected_type unexp4 = unexpected(10);
-  exp_void e4 = unexp4;
-
-  EXPECT_FALSE(e.has_value());
-  EXPECT_FALSE(e2.has_value());
-  EXPECT_FALSE(e3.has_value());
-  EXPECT_FALSE(e4.has_value());
-  EXPECT_EQ(10, e.error());
-  EXPECT_EQ(10.5f, e2.error());
-  EXPECT_EQ("error", e3.error());
-  EXPECT_EQ(10, e4.error());
-}
-
-TEST(Expected, testMoveConstructibleFromUnexpected) {
-  exp_int e = unexpected(10);
-  exp_double e2 = unexpected(10.5f);
-  exp_string e3 = unexpected(std::string("error"));
-  exp_void e4 = unexpected(10);
-
-  EXPECT_FALSE(e.has_value());
-  EXPECT_FALSE(e2.has_value());
-  EXPECT_FALSE(e3.has_value());
-  EXPECT_FALSE(e4.has_value());
-  EXPECT_EQ(10, e.error());
-  EXPECT_EQ(10.5f, e2.error());
-  EXPECT_EQ("error", e3.error());
-  EXPECT_EQ(10, e4.error());
-}
-
-TEST(Expected, testConstructibleByForwarding) {
-  exp_string e(std::in_place, 5, 'a');
-  EXPECT_TRUE(e.has_value());
-  EXPECT_EQ("aaaaa", e.value());
-
-  exp_string e2({'a', 'b', 'c'});
-  EXPECT_TRUE(e2.has_value());
-  EXPECT_EQ("abc", e2.value());
-
-  exp_pair e3({"hello", 30});
-  EXPECT_TRUE(e3.has_value());
-  EXPECT_EQ("hello",e3->first);
-  EXPECT_EQ(30,e3->second);
-
-  exp_void e4({});
-  EXPECT_TRUE(e4.has_value());
-}
-
-TEST(Expected, testDestructible) {
-  bool destroyed = false;
-  struct T {
-    bool* flag_;
-    T(bool* flag) : flag_(flag) {}
-    ~T() { *flag_ = true; }
-  };
-  {
-    expected<T, int> exp = T(&destroyed);
-  }
-  EXPECT_TRUE(destroyed);
-}
-
-TEST(Expected, testAssignable) {
-  exp_int e = 10;
-  exp_int e2 = 20;
-  e = e2;
-
-  EXPECT_EQ(20, e.value());
-  EXPECT_EQ(20, e2.value());
-
-  exp_int e3 = 10;
-  exp_int e4 = 20;
-  e3 = std::move(e4);
-
-  EXPECT_EQ(20, e3.value());
-  EXPECT_EQ(20, e4.value());
-
-  exp_void e5 = unexpected(10);
-  ASSERT_FALSE(e5.has_value());
-  exp_void e6;
-  e5 = e6;
-
-  EXPECT_TRUE(e5.has_value());
-  EXPECT_TRUE(e6.has_value());
-}
-
-TEST(Expected, testAssignableFromValue) {
-  exp_int e = 10;
-  e = 20;
-  EXPECT_EQ(20, e.value());
-
-  exp_double e2 = 3.5f;
-  e2 = 10.5f;
-  EXPECT_EQ(10.5f, e2.value());
-
-  exp_string e3 = "hello";
-  e3 = "world";
-  EXPECT_EQ("world", e3.value());
-
-  exp_void e4 = unexpected(10);
-  ASSERT_FALSE(e4.has_value());
-  e4 = {};
-  EXPECT_TRUE(e4.has_value());
-}
-
-TEST(Expected, testAssignableFromUnexpected) {
-  exp_int e = 10;
-  e = unexpected(30);
-  EXPECT_FALSE(e.has_value());
-  EXPECT_EQ(30, e.error());
-
-  exp_double e2 = 3.5f;
-  e2 = unexpected(10.5f);
-  EXPECT_FALSE(e2.has_value());
-  EXPECT_EQ(10.5f, e2.error());
-
-  exp_string e3 = "hello";
-  e3 = unexpected("world");
-  EXPECT_FALSE(e3.has_value());
-  EXPECT_EQ("world", e3.error());
-
-  exp_void e4 = {};
-  e4 = unexpected(10);
-  EXPECT_FALSE(e4.has_value());
-  EXPECT_EQ(10, e4.error());
-}
-
-TEST(Expected, testAssignableFromMovedValue) {
-  std::string world = "world";
-  exp_string e = "hello";
-  e = std::move(world);
-
-  EXPECT_TRUE(e.has_value());
-  EXPECT_EQ("world", e.value());
-  EXPECT_EQ("", world);
-}
-
-TEST(Expected, testAssignableFromMovedUnexpected) {
-  std::string world = "world";
-  exp_string e = "hello";
-  e = unexpected(std::move(world));
-
-  EXPECT_FALSE(e.has_value());
-  EXPECT_EQ("world", e.error());
-  EXPECT_EQ("", world);
-}
-
-TEST(Expected, testEmplace) {
-  struct T {
-    int a;
-    double b;
-    T() {}
-    T(int a, double b) noexcept : a(a), b(b) {}
-  };
-  expected<T, int> exp;
-  T& t = exp.emplace(3, 10.5f);
-
-  EXPECT_TRUE(exp.has_value());
-  EXPECT_EQ(3, t.a);
-  EXPECT_EQ(10.5f, t.b);
-  EXPECT_EQ(3, exp.value().a);
-  EXPECT_EQ(10.5, exp.value().b);
-
-  exp_void e = unexpected(10);
-  ASSERT_FALSE(e.has_value());
-  e.emplace();
-  EXPECT_TRUE(e.has_value());
-}
-
-TEST(Expected, testSwapExpectedExpected) {
-  exp_int e = 10;
-  exp_int e2 = 20;
-  e.swap(e2);
-
-  EXPECT_TRUE(e.has_value());
-  EXPECT_TRUE(e2.has_value());
-  EXPECT_EQ(20, e.value());
-  EXPECT_EQ(10, e2.value());
-
-  exp_void e3;
-  exp_void e4;
-  e3.swap(e4);
-
-  EXPECT_TRUE(e3.has_value());
-  EXPECT_TRUE(e4.has_value());
-}
-
-TEST(Expected, testSwapUnexpectedUnexpected) {
-  exp_int e = unexpected(10);
-  exp_int e2 = unexpected(20);
-  e.swap(e2);
-  EXPECT_FALSE(e.has_value());
-  EXPECT_FALSE(e2.has_value());
-  EXPECT_EQ(20, e.error());
-  EXPECT_EQ(10, e2.error());
-
-  exp_void e3 = unexpected(10);
-  exp_void e4 = unexpected(20);
-  e3.swap(e4);
-  EXPECT_FALSE(e3.has_value());
-  EXPECT_FALSE(e4.has_value());
-  EXPECT_EQ(20, e3.error());
-  EXPECT_EQ(10, e4.error());
-}
-
-TEST(Expected, testSwapExpectedUnepected) {
-  exp_int e = 10;
-  exp_int e2 = unexpected(30);
-  e.swap(e2);
-  EXPECT_FALSE(e.has_value());
-  EXPECT_TRUE(e2.has_value());
-  EXPECT_EQ(30, e.error());
-  EXPECT_EQ(10, e2.value());
-
-  exp_void e3;
-  exp_void e4 = unexpected(10);
-  e3.swap(e4);
-  EXPECT_FALSE(e3.has_value());
-  EXPECT_TRUE(e4.has_value());
-  EXPECT_EQ(10, e3.error());
-}
-
-TEST(Expected, testDereference) {
-  struct T {
-    int a;
-    double b;
-    T() {}
-    T(int a, double b) : a(a), b(b) {}
-  };
-  expected<T, int> exp = T(3, 10.5f);
-
-  EXPECT_EQ(3, exp->a);
-  EXPECT_EQ(10.5f, exp->b);
-
-  EXPECT_EQ(3, (*exp).a);
-  EXPECT_EQ(10.5f, (*exp).b);
-}
-
-TEST(Expected, testTest) {
-  exp_int e = 10;
-  EXPECT_TRUE(e.ok());
-  EXPECT_TRUE(e.has_value());
-
-  exp_int e2 = unexpected(10);
-  EXPECT_FALSE(e2.ok());
-  EXPECT_FALSE(e2.has_value());
-}
-
-TEST(Expected, testGetValue) {
-  exp_int e = 10;
-  EXPECT_EQ(10, e.value());
-  EXPECT_EQ(10, e.value_or(20));
-
-  exp_int e2 = unexpected(10);
-  EXPECT_EQ(10, e2.error());
-  EXPECT_EQ(20, e2.value_or(20));
-}
-
-TEST(Expected, testSameValues) {
-  exp_int e = 10;
-  exp_int e2 = 10;
-  EXPECT_TRUE(e == e2);
-  EXPECT_TRUE(e2 == e);
-  EXPECT_FALSE(e != e2);
-  EXPECT_FALSE(e2 != e);
-
-  exp_void e3;
-  exp_void e4;
-  EXPECT_TRUE(e3 == e4);
-  EXPECT_TRUE(e4 == e3);
-  EXPECT_FALSE(e3 != e4);
-  EXPECT_FALSE(e4 != e3);
-}
-
-TEST(Expected, testDifferentValues) {
-  exp_int e = 10;
-  exp_int e2 = 20;
-  EXPECT_FALSE(e == e2);
-  EXPECT_FALSE(e2 == e);
-  EXPECT_TRUE(e != e2);
-  EXPECT_TRUE(e2 != e);
-}
-
-TEST(Expected, testValueWithError) {
-  exp_int e = 10;
-  exp_int e2 = unexpected(10);
-  EXPECT_FALSE(e == e2);
-  EXPECT_FALSE(e2 == e);
-  EXPECT_TRUE(e != e2);
-  EXPECT_TRUE(e2 != e);
-
-  exp_void e3;
-  exp_void e4 = unexpected(10);
-  EXPECT_FALSE(e3 == e4);
-  EXPECT_FALSE(e4 == e3);
-  EXPECT_TRUE(e3 != e4);
-  EXPECT_TRUE(e4 != e3);
-}
-
-TEST(Expected, testSameErrors) {
-  exp_int e = unexpected(10);
-  exp_int e2 = unexpected(10);
-  EXPECT_TRUE(e == e2);
-  EXPECT_TRUE(e2 == e);
-  EXPECT_FALSE(e != e2);
-  EXPECT_FALSE(e2 != e);
-
-  exp_void e3 = unexpected(10);
-  exp_void e4 = unexpected(10);
-  EXPECT_TRUE(e3 == e4);
-  EXPECT_TRUE(e4 == e3);
-  EXPECT_FALSE(e3 != e4);
-  EXPECT_FALSE(e4 != e3);
-}
-
-TEST(Expected, testDifferentErrors) {
-  exp_int e = unexpected(10);
-  exp_int e2 = unexpected(20);
-  EXPECT_FALSE(e == e2);
-  EXPECT_FALSE(e2 == e);
-  EXPECT_TRUE(e != e2);
-  EXPECT_TRUE(e2 != e);
-
-  exp_void e3 = unexpected(10);
-  exp_void e4 = unexpected(20);
-  EXPECT_FALSE(e3 == e4);
-  EXPECT_FALSE(e4 == e3);
-  EXPECT_TRUE(e3 != e4);
-  EXPECT_TRUE(e4 != e3);
-}
-
-TEST(Expected, testCompareWithSameError) {
-  exp_int e = unexpected(10);
-  exp_int::unexpected_type error = 10;
-  EXPECT_TRUE(e == error);
-  EXPECT_TRUE(error == e);
-  EXPECT_FALSE(e != error);
-  EXPECT_FALSE(error != e);
-
-  exp_void e2 = unexpected(10);
-  exp_void::unexpected_type error2 = 10;
-  EXPECT_TRUE(e2 == error2);
-  EXPECT_TRUE(error2 == e2);
-  EXPECT_FALSE(e2 != error2);
-  EXPECT_FALSE(error2 != e2);
-}
-
-TEST(Expected, testCompareWithDifferentError) {
-  exp_int e = unexpected(10);
-  exp_int::unexpected_type error = 20;
-  EXPECT_FALSE(e == error);
-  EXPECT_FALSE(error == e);
-  EXPECT_TRUE(e != error);
-  EXPECT_TRUE(error != e);
-
-  exp_void e2 = unexpected(10);
-  exp_void::unexpected_type error2 = 20;
-  EXPECT_FALSE(e2 == error2);
-  EXPECT_FALSE(error2 == e2);
-  EXPECT_TRUE(e2 != error2);
-  EXPECT_TRUE(error2 != e2);
-}
-
-TEST(Expected, testCompareDifferentType) {
-  expected<int,int> e = 10;
-  expected<int32_t, int> e2 = 10;
-  EXPECT_TRUE(e == e2);
-  e2 = 20;
-  EXPECT_FALSE(e == e2);
-
-  expected<std::string_view,int> e3 = "hello";
-  expected<std::string,int> e4 = "hello";
-  EXPECT_TRUE(e3 == e4);
-  e4 = "world";
-  EXPECT_FALSE(e3 == e4);
-
-  expected<void,int> e5;
-  expected<int,int> e6 = 10;
-  EXPECT_FALSE(e5 == e6);
-  EXPECT_FALSE(e6 == e5);
-}
-
-TEST(Expected, testDivideExample) {
-  struct QR {
-    int quotient;
-    int remainder;
-    QR(int q, int r) noexcept : quotient(q), remainder(r) {}
-    bool operator==(const QR& rhs) const {
-      return quotient == rhs.quotient && remainder == rhs.remainder;
-    }
-    bool operator!=(const QR& rhs) const {
-      return quotient != rhs.quotient || remainder == rhs.remainder;
-    }
-  };
-
-  auto divide = [](int x, int y) -> expected<QR,E> {
-    if (y == 0) {
-      return unexpected(E("divide by zero", -1));
-    } else {
-      return QR(x / y, x % y);
-    }
-  };
-
-  EXPECT_FALSE(divide(10, 0).ok());
-  EXPECT_EQ("divide by zero", divide(10, 0).error().message);
-  EXPECT_EQ(-1, divide(10, 0).error().cause);
-
-  EXPECT_TRUE(divide(10, 3).ok());
-  EXPECT_EQ(QR(3, 1), *divide(10, 3));
-}
-
-TEST(Expected, testPair) {
-  auto test = [](bool yes) -> exp_pair {
-    if (yes) {
-      return exp_pair({"yes", 42});
-    } else {
-      return unexpected(42);
-    }
-  };
-
-  auto r = test(true);
-  EXPECT_TRUE(r.ok());
-  EXPECT_EQ("yes", r->first);
-}
-
-TEST(Expected, testVoid) {
-  auto test = [](bool ok) -> exp_void {
-    if (ok) {
-      return {};
-    } else {
-      return unexpected(10);
-    }
-  };
-
-  auto r = test(true);
-  EXPECT_TRUE(r.ok());
-  r = test(false);
-  EXPECT_FALSE(r.ok());
-  EXPECT_EQ(10, r.error());
-}
-
-// copied from result_test.cpp
-struct ConstructorTracker {
-  static size_t constructor_called;
-  static size_t copy_constructor_called;
-  static size_t move_constructor_called;
-  static size_t copy_assignment_called;
-  static size_t move_assignment_called;
-
-  template <typename T,
-    typename std::enable_if_t<std::is_convertible_v<T, std::string>>* = nullptr>
-  ConstructorTracker(T&& string) : string(string) {
-    ++constructor_called;
-  }
-  ConstructorTracker(const ConstructorTracker& ct) {
-    ++copy_constructor_called;
-    string = ct.string;
-  }
-  ConstructorTracker(ConstructorTracker&& ct) noexcept {
-    ++move_constructor_called;
-    string = std::move(ct.string);
-  }
-  ConstructorTracker& operator=(const ConstructorTracker& ct) {
-    ++copy_assignment_called;
-    string = ct.string;
-    return *this;
-  }
-  ConstructorTracker& operator=(ConstructorTracker&& ct) noexcept {
-    ++move_assignment_called;
-    string = std::move(ct.string);
-    return *this;
-  }
-  static void Reset() {
-    constructor_called = 0;
-    copy_constructor_called = 0;
-    move_constructor_called = 0;
-    copy_assignment_called = 0;
-    move_assignment_called = 0;
-  }
-  std::string string;
-};
-
-size_t ConstructorTracker::constructor_called = 0;
-size_t ConstructorTracker::copy_constructor_called = 0;
-size_t ConstructorTracker::move_constructor_called = 0;
-size_t ConstructorTracker::copy_assignment_called = 0;
-size_t ConstructorTracker::move_assignment_called = 0;
-
-typedef expected<ConstructorTracker, int> exp_track;
-
-TEST(Expected, testNumberOfCopies) {
-  // default constructor
-  ConstructorTracker::Reset();
-  exp_track e("hello");
-  EXPECT_EQ(1U, ConstructorTracker::constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
-
-  // copy constructor
-  ConstructorTracker::Reset();
-  exp_track e2 = e;
-  EXPECT_EQ(0U, ConstructorTracker::constructor_called);
-  EXPECT_EQ(1U, ConstructorTracker::copy_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
-
-  // move constructor
-  ConstructorTracker::Reset();
-  exp_track e3 = std::move(e);
-  EXPECT_EQ(0U, ConstructorTracker::constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
-  EXPECT_EQ(1U, ConstructorTracker::move_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
-
-  // construct from lvalue
-  ConstructorTracker::Reset();
-  ConstructorTracker ct = "hello";
-  exp_track e4(ct);
-  EXPECT_EQ(1U, ConstructorTracker::constructor_called);
-  EXPECT_EQ(1U, ConstructorTracker::copy_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
-
-  // construct from rvalue
-  ConstructorTracker::Reset();
-  ConstructorTracker ct2 = "hello";
-  exp_track e5(std::move(ct2));
-  EXPECT_EQ(1U, ConstructorTracker::constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
-  EXPECT_EQ(1U, ConstructorTracker::move_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
-
-  // copy assignment
-  ConstructorTracker::Reset();
-  exp_track e6 = "hello";
-  exp_track e7 = "world";
-  e7 = e6;
-  EXPECT_EQ(2U, ConstructorTracker::constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_constructor_called);
-  EXPECT_EQ(1U, ConstructorTracker::copy_assignment_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
-
-  // move assignment
-  ConstructorTracker::Reset();
-  exp_track e8 = "hello";
-  exp_track e9 = "world";
-  e9 = std::move(e8);
-  EXPECT_EQ(2U, ConstructorTracker::constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
-  EXPECT_EQ(1U, ConstructorTracker::move_assignment_called);
-
-  // swap
-  ConstructorTracker::Reset();
-  exp_track e10 = "hello";
-  exp_track e11 = "world";
-  std::swap(e10, e11);
-  EXPECT_EQ(2U, ConstructorTracker::constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
-  EXPECT_EQ(1U, ConstructorTracker::move_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
-  EXPECT_EQ(2U, ConstructorTracker::move_assignment_called);
-}
-
-TEST(Expected, testNoCopyOnReturn) {
-  auto test = [](const std::string& in) -> exp_track {
-    if (in.empty()) {
-      return "literal string";
-    }
-    if (in == "test2") {
-      return ConstructorTracker(in + in + "2");
-    }
-    ConstructorTracker result(in + " " + in);
-    return result;
-  };
-
-  ConstructorTracker::Reset();
-  auto result1 = test("");
-  ASSERT_TRUE(result1.ok());
-  EXPECT_EQ("literal string", result1->string);
-  EXPECT_EQ(1U, ConstructorTracker::constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
-
-  ConstructorTracker::Reset();
-  auto result2 = test("test2");
-  ASSERT_TRUE(result2.ok());
-  EXPECT_EQ("test2test22", result2->string);
-  EXPECT_EQ(1U, ConstructorTracker::constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
-  EXPECT_EQ(1U, ConstructorTracker::move_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
-
-  ConstructorTracker::Reset();
-  auto result3 = test("test3");
-  ASSERT_TRUE(result3.ok());
-  EXPECT_EQ("test3 test3", result3->string);
-  EXPECT_EQ(1U, ConstructorTracker::constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
-  EXPECT_EQ(1U, ConstructorTracker::move_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
-}
-
-TEST(Expected, testNested) {
-  expected<exp_string, std::string> e = "hello";
-
-  EXPECT_TRUE(e.ok());
-  EXPECT_TRUE(e.has_value());
-  EXPECT_TRUE(e.value().has_value());
-  EXPECT_TRUE(e->ok());
-  EXPECT_EQ("hello", e.value().value());
-
-  expected<exp_string, std::string> e2 = unexpected("world");
-  EXPECT_FALSE(e2.has_value());
-  EXPECT_FALSE(e2.ok());
-  EXPECT_EQ("world", e2.error());
-
-  expected<exp_string, std::string> e3 = exp_string(unexpected("world"));
-  EXPECT_TRUE(e3.has_value());
-  EXPECT_FALSE(e3.value().has_value());
-  EXPECT_TRUE(e3.ok());
-  EXPECT_FALSE(e3->ok());
-  EXPECT_EQ("world", e3.value().error());
-}
-
-constexpr bool equals(const char* a, const char* b) {
-  return (a == nullptr && b == nullptr) ||
-      (a != nullptr && b != nullptr && *a == *b &&
-       (*a == '\0' || equals(a + 1, b + 1)));
-}
-
-TEST(Expected, testConstexpr) {
-  // Compliation error will occur if these expressions can't be
-  // evaluated at compile time
-  constexpr exp_int e(3);
-  constexpr exp_int::unexpected_type err(3);
-  constexpr int i = 4;
-
-  // default constructor
-  static_assert(exp_int().value() == 0);
-  // copy constructor
-  static_assert(exp_int(e).value() == 3);
-  // move constructor
-  static_assert(exp_int(exp_int(4)).value() == 4);
-  // copy construct from value
-  static_assert(exp_int(i).value() == 4);
-  // copy construct from unexpected
-  static_assert(exp_int(err).error() == 3);
-  // move costruct from unexpected
-  static_assert(exp_int(unexpected(3)).error() == 3);
-  // observers
-  static_assert(*exp_int(3) == 3);
-  static_assert(exp_int(3).has_value() == true);
-  static_assert(exp_int(3).value_or(4) == 3);
-
-  typedef expected<const char*, int> exp_s;
-  constexpr exp_s s("hello");
-  constexpr const char* c = "hello";
-  static_assert(equals(exp_s().value(), nullptr));
-  static_assert(equals(exp_s(s).value(), "hello"));
-  static_assert(equals(exp_s(exp_s("hello")).value(), "hello"));
-  static_assert(equals(exp_s("hello").value(), "hello"));
-  static_assert(equals(exp_s(c).value(), "hello"));
-}
-
-TEST(Expected, testWithNonConstructible) {
-   struct AssertNotConstructed {
-     AssertNotConstructed() = delete;
-   };
-
-   expected<int, AssertNotConstructed> v(42);
-   EXPECT_TRUE(v.has_value());
-   EXPECT_EQ(42, v.value());
-
-   expected<AssertNotConstructed, int> e(unexpected(42));
-   EXPECT_FALSE(e.has_value());
-   EXPECT_EQ(42, e.error());
-}
-
-TEST(Expected, testWithMoveOnlyType) {
-  typedef expected<std::unique_ptr<int>,std::unique_ptr<int>> exp_ptr;
-  exp_ptr e(std::make_unique<int>(3));
-  exp_ptr e2(unexpected(std::make_unique<int>(4)));
-
-  EXPECT_TRUE(e.has_value());
-  EXPECT_FALSE(e2.has_value());
-  EXPECT_EQ(3, *(e.value()));
-  EXPECT_EQ(4, *(e2.error()));
-
-  e2 = std::move(e);
-  EXPECT_TRUE(e.has_value());
-  EXPECT_TRUE(e2.has_value());
-  EXPECT_EQ(3, *(e2.value()));
-}
diff --git a/base/file.cpp b/base/file.cpp
deleted file mode 100644
index 6321fc6..0000000
--- a/base/file.cpp
+++ /dev/null
@@ -1,522 +0,0 @@
-/*
- * Copyright (C) 2015 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 "android-base/file.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <ftw.h>
-#include <libgen.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <memory>
-#include <mutex>
-#include <string>
-#include <vector>
-
-#if defined(__APPLE__)
-#include <mach-o/dyld.h>
-#endif
-#if defined(_WIN32)
-#include <direct.h>
-#include <windows.h>
-#define O_NOFOLLOW 0
-#define OS_PATH_SEPARATOR '\\'
-#else
-#define OS_PATH_SEPARATOR '/'
-#endif
-
-#include "android-base/logging.h"  // and must be after windows.h for ERROR
-#include "android-base/macros.h"   // For TEMP_FAILURE_RETRY on Darwin.
-#include "android-base/unique_fd.h"
-#include "android-base/utf8.h"
-
-namespace {
-
-#ifdef _WIN32
-static int mkstemp(char* name_template, size_t size_in_chars) {
-  std::wstring path;
-  CHECK(android::base::UTF8ToWide(name_template, &path))
-      << "path can't be converted to wchar: " << name_template;
-  if (_wmktemp_s(path.data(), path.size() + 1) != 0) {
-    return -1;
-  }
-
-  // Use open() to match the close() that TemporaryFile's destructor does.
-  // Use O_BINARY to match base file APIs.
-  int fd = _wopen(path.c_str(), O_CREAT | O_EXCL | O_RDWR | O_BINARY, S_IRUSR | S_IWUSR);
-  if (fd < 0) {
-    return -1;
-  }
-
-  std::string path_utf8;
-  CHECK(android::base::WideToUTF8(path, &path_utf8)) << "path can't be converted to utf8";
-  CHECK(strcpy_s(name_template, size_in_chars, path_utf8.c_str()) == 0)
-      << "utf8 path can't be assigned back to name_template";
-
-  return fd;
-}
-
-static char* mkdtemp(char* name_template, size_t size_in_chars) {
-  std::wstring path;
-  CHECK(android::base::UTF8ToWide(name_template, &path))
-      << "path can't be converted to wchar: " << name_template;
-
-  if (_wmktemp_s(path.data(), path.size() + 1) != 0) {
-    return nullptr;
-  }
-
-  if (_wmkdir(path.c_str()) != 0) {
-    return nullptr;
-  }
-
-  std::string path_utf8;
-  CHECK(android::base::WideToUTF8(path, &path_utf8)) << "path can't be converted to utf8";
-  CHECK(strcpy_s(name_template, size_in_chars, path_utf8.c_str()) == 0)
-      << "utf8 path can't be assigned back to name_template";
-
-  return name_template;
-}
-#endif
-
-std::string GetSystemTempDir() {
-#if defined(__ANDROID__)
-  const auto* tmpdir = getenv("TMPDIR");
-  if (tmpdir == nullptr) tmpdir = "/data/local/tmp";
-  if (access(tmpdir, R_OK | W_OK | X_OK) == 0) {
-    return tmpdir;
-  }
-  // Tests running in app context can't access /data/local/tmp,
-  // so try current directory if /data/local/tmp is not accessible.
-  return ".";
-#elif defined(_WIN32)
-  wchar_t tmp_dir_w[MAX_PATH];
-  DWORD result = GetTempPathW(std::size(tmp_dir_w), tmp_dir_w);  // checks TMP env
-  CHECK_NE(result, 0ul) << "GetTempPathW failed, error: " << GetLastError();
-  CHECK_LT(result, std::size(tmp_dir_w)) << "path truncated to: " << result;
-
-  // GetTempPath() returns a path with a trailing slash, but init()
-  // does not expect that, so remove it.
-  if (tmp_dir_w[result - 1] == L'\\') {
-    tmp_dir_w[result - 1] = L'\0';
-  }
-
-  std::string tmp_dir;
-  CHECK(android::base::WideToUTF8(tmp_dir_w, &tmp_dir)) << "path can't be converted to utf8";
-
-  return tmp_dir;
-#else
-  const auto* tmpdir = getenv("TMPDIR");
-  if (tmpdir == nullptr) tmpdir = "/tmp";
-  return tmpdir;
-#endif
-}
-
-}  // namespace
-
-TemporaryFile::TemporaryFile() {
-  init(GetSystemTempDir());
-}
-
-TemporaryFile::TemporaryFile(const std::string& tmp_dir) {
-  init(tmp_dir);
-}
-
-TemporaryFile::~TemporaryFile() {
-  if (fd != -1) {
-    close(fd);
-  }
-  if (remove_file_) {
-    unlink(path);
-  }
-}
-
-int TemporaryFile::release() {
-  int result = fd;
-  fd = -1;
-  return result;
-}
-
-void TemporaryFile::init(const std::string& tmp_dir) {
-  snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(), OS_PATH_SEPARATOR);
-#if defined(_WIN32)
-  fd = mkstemp(path, sizeof(path));
-#else
-  fd = mkstemp(path);
-#endif
-}
-
-TemporaryDir::TemporaryDir() {
-  init(GetSystemTempDir());
-}
-
-TemporaryDir::~TemporaryDir() {
-  if (!remove_dir_and_contents_) return;
-
-  auto callback = [](const char* child, const struct stat*, int file_type, struct FTW*) -> int {
-    switch (file_type) {
-      case FTW_D:
-      case FTW_DP:
-      case FTW_DNR:
-        if (rmdir(child) == -1) {
-          PLOG(ERROR) << "rmdir " << child;
-        }
-        break;
-      case FTW_NS:
-      default:
-        if (rmdir(child) != -1) break;
-        // FALLTHRU (for gcc, lint, pcc, etc; and following for clang)
-        FALLTHROUGH_INTENDED;
-      case FTW_F:
-      case FTW_SL:
-      case FTW_SLN:
-        if (unlink(child) == -1) {
-          PLOG(ERROR) << "unlink " << child;
-        }
-        break;
-    }
-    return 0;
-  };
-
-  nftw(path, callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
-}
-
-bool TemporaryDir::init(const std::string& tmp_dir) {
-  snprintf(path, sizeof(path), "%s%cTemporaryDir-XXXXXX", tmp_dir.c_str(), OS_PATH_SEPARATOR);
-#if defined(_WIN32)
-  return (mkdtemp(path, sizeof(path)) != nullptr);
-#else
-  return (mkdtemp(path) != nullptr);
-#endif
-}
-
-namespace android {
-namespace base {
-
-// Versions of standard library APIs that support UTF-8 strings.
-using namespace android::base::utf8;
-
-bool ReadFdToString(borrowed_fd fd, std::string* content) {
-  content->clear();
-
-  // Although original we had small files in mind, this code gets used for
-  // very large files too, where the std::string growth heuristics might not
-  // be suitable. https://code.google.com/p/android/issues/detail?id=258500.
-  struct stat sb;
-  if (fstat(fd.get(), &sb) != -1 && sb.st_size > 0) {
-    content->reserve(sb.st_size);
-  }
-
-  char buf[BUFSIZ];
-  ssize_t n;
-  while ((n = TEMP_FAILURE_RETRY(read(fd.get(), &buf[0], sizeof(buf)))) > 0) {
-    content->append(buf, n);
-  }
-  return (n == 0) ? true : false;
-}
-
-bool ReadFileToString(const std::string& path, std::string* content, bool follow_symlinks) {
-  content->clear();
-
-  int flags = O_RDONLY | O_CLOEXEC | O_BINARY | (follow_symlinks ? 0 : O_NOFOLLOW);
-  android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags)));
-  if (fd == -1) {
-    return false;
-  }
-  return ReadFdToString(fd, content);
-}
-
-bool WriteStringToFd(const std::string& content, borrowed_fd fd) {
-  const char* p = content.data();
-  size_t left = content.size();
-  while (left > 0) {
-    ssize_t n = TEMP_FAILURE_RETRY(write(fd.get(), p, left));
-    if (n == -1) {
-      return false;
-    }
-    p += n;
-    left -= n;
-  }
-  return true;
-}
-
-static bool CleanUpAfterFailedWrite(const std::string& path) {
-  // Something went wrong. Let's not leave a corrupt file lying around.
-  int saved_errno = errno;
-  unlink(path.c_str());
-  errno = saved_errno;
-  return false;
-}
-
-#if !defined(_WIN32)
-bool WriteStringToFile(const std::string& content, const std::string& path,
-                       mode_t mode, uid_t owner, gid_t group,
-                       bool follow_symlinks) {
-  int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY |
-              (follow_symlinks ? 0 : O_NOFOLLOW);
-  android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode)));
-  if (fd == -1) {
-    PLOG(ERROR) << "android::WriteStringToFile open failed";
-    return false;
-  }
-
-  // We do an explicit fchmod here because we assume that the caller really
-  // meant what they said and doesn't want the umask-influenced mode.
-  if (fchmod(fd, mode) == -1) {
-    PLOG(ERROR) << "android::WriteStringToFile fchmod failed";
-    return CleanUpAfterFailedWrite(path);
-  }
-  if (fchown(fd, owner, group) == -1) {
-    PLOG(ERROR) << "android::WriteStringToFile fchown failed";
-    return CleanUpAfterFailedWrite(path);
-  }
-  if (!WriteStringToFd(content, fd)) {
-    PLOG(ERROR) << "android::WriteStringToFile write failed";
-    return CleanUpAfterFailedWrite(path);
-  }
-  return true;
-}
-#endif
-
-bool WriteStringToFile(const std::string& content, const std::string& path,
-                       bool follow_symlinks) {
-  int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY |
-              (follow_symlinks ? 0 : O_NOFOLLOW);
-  android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags, 0666)));
-  if (fd == -1) {
-    return false;
-  }
-  return WriteStringToFd(content, fd) || CleanUpAfterFailedWrite(path);
-}
-
-bool ReadFully(borrowed_fd fd, void* data, size_t byte_count) {
-  uint8_t* p = reinterpret_cast<uint8_t*>(data);
-  size_t remaining = byte_count;
-  while (remaining > 0) {
-    ssize_t n = TEMP_FAILURE_RETRY(read(fd.get(), p, remaining));
-    if (n <= 0) return false;
-    p += n;
-    remaining -= n;
-  }
-  return true;
-}
-
-#if defined(_WIN32)
-// Windows implementation of pread. Note that this DOES move the file descriptors read position,
-// but it does so atomically.
-static ssize_t pread(borrowed_fd fd, void* data, size_t byte_count, off64_t offset) {
-  DWORD bytes_read;
-  OVERLAPPED overlapped;
-  memset(&overlapped, 0, sizeof(OVERLAPPED));
-  overlapped.Offset = static_cast<DWORD>(offset);
-  overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
-  if (!ReadFile(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), data,
-                static_cast<DWORD>(byte_count), &bytes_read, &overlapped)) {
-    // In case someone tries to read errno (since this is masquerading as a POSIX call)
-    errno = EIO;
-    return -1;
-  }
-  return static_cast<ssize_t>(bytes_read);
-}
-#endif
-
-bool ReadFullyAtOffset(borrowed_fd fd, void* data, size_t byte_count, off64_t offset) {
-  uint8_t* p = reinterpret_cast<uint8_t*>(data);
-  while (byte_count > 0) {
-    ssize_t n = TEMP_FAILURE_RETRY(pread(fd.get(), p, byte_count, offset));
-    if (n <= 0) return false;
-    p += n;
-    byte_count -= n;
-    offset += n;
-  }
-  return true;
-}
-
-bool WriteFully(borrowed_fd fd, const void* data, size_t byte_count) {
-  const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
-  size_t remaining = byte_count;
-  while (remaining > 0) {
-    ssize_t n = TEMP_FAILURE_RETRY(write(fd.get(), p, remaining));
-    if (n == -1) return false;
-    p += n;
-    remaining -= n;
-  }
-  return true;
-}
-
-bool RemoveFileIfExists(const std::string& path, std::string* err) {
-  struct stat st;
-#if defined(_WIN32)
-  // TODO: Windows version can't handle symbolic links correctly.
-  int result = stat(path.c_str(), &st);
-  bool file_type_removable = (result == 0 && S_ISREG(st.st_mode));
-#else
-  int result = lstat(path.c_str(), &st);
-  bool file_type_removable = (result == 0 && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)));
-#endif
-  if (result == -1) {
-    if (errno == ENOENT || errno == ENOTDIR) return true;
-    if (err != nullptr) *err = strerror(errno);
-    return false;
-  }
-
-  if (result == 0) {
-    if (!file_type_removable) {
-      if (err != nullptr) {
-        *err = "is not a regular file or symbolic link";
-      }
-      return false;
-    }
-    if (unlink(path.c_str()) == -1) {
-      if (err != nullptr) {
-        *err = strerror(errno);
-      }
-      return false;
-    }
-  }
-  return true;
-}
-
-#if !defined(_WIN32)
-bool Readlink(const std::string& path, std::string* result) {
-  result->clear();
-
-  // Most Linux file systems (ext2 and ext4, say) limit symbolic links to
-  // 4095 bytes. Since we'll copy out into the string anyway, it doesn't
-  // waste memory to just start there. We add 1 so that we can recognize
-  // whether it actually fit (rather than being truncated to 4095).
-  std::vector<char> buf(4095 + 1);
-  while (true) {
-    ssize_t size = readlink(path.c_str(), &buf[0], buf.size());
-    // Unrecoverable error?
-    if (size == -1) return false;
-    // It fit! (If size == buf.size(), it may have been truncated.)
-    if (static_cast<size_t>(size) < buf.size()) {
-      result->assign(&buf[0], size);
-      return true;
-    }
-    // Double our buffer and try again.
-    buf.resize(buf.size() * 2);
-  }
-}
-#endif
-
-#if !defined(_WIN32)
-bool Realpath(const std::string& path, std::string* result) {
-  result->clear();
-
-  // realpath may exit with EINTR. Retry if so.
-  char* realpath_buf = nullptr;
-  do {
-    realpath_buf = realpath(path.c_str(), nullptr);
-  } while (realpath_buf == nullptr && errno == EINTR);
-
-  if (realpath_buf == nullptr) {
-    return false;
-  }
-  result->assign(realpath_buf);
-  free(realpath_buf);
-  return true;
-}
-#endif
-
-std::string GetExecutablePath() {
-#if defined(__linux__)
-  std::string path;
-  android::base::Readlink("/proc/self/exe", &path);
-  return path;
-#elif defined(__APPLE__)
-  char path[PATH_MAX + 1];
-  uint32_t path_len = sizeof(path);
-  int rc = _NSGetExecutablePath(path, &path_len);
-  if (rc < 0) {
-    std::unique_ptr<char> path_buf(new char[path_len]);
-    _NSGetExecutablePath(path_buf.get(), &path_len);
-    return path_buf.get();
-  }
-  return path;
-#elif defined(_WIN32)
-  char path[PATH_MAX + 1];
-  DWORD result = GetModuleFileName(NULL, path, sizeof(path) - 1);
-  if (result == 0 || result == sizeof(path) - 1) return "";
-  path[PATH_MAX - 1] = 0;
-  return path;
-#else
-#error unknown OS
-#endif
-}
-
-std::string GetExecutableDirectory() {
-  return Dirname(GetExecutablePath());
-}
-
-std::string Basename(const std::string& path) {
-  // Copy path because basename may modify the string passed in.
-  std::string result(path);
-
-#if !defined(__BIONIC__)
-  // Use lock because basename() may write to a process global and return a
-  // pointer to that. Note that this locking strategy only works if all other
-  // callers to basename in the process also grab this same lock, but its
-  // better than nothing.  Bionic's basename returns a thread-local buffer.
-  static std::mutex& basename_lock = *new std::mutex();
-  std::lock_guard<std::mutex> lock(basename_lock);
-#endif
-
-  // Note that if std::string uses copy-on-write strings, &str[0] will cause
-  // the copy to be made, so there is no chance of us accidentally writing to
-  // the storage for 'path'.
-  char* name = basename(&result[0]);
-
-  // In case basename returned a pointer to a process global, copy that string
-  // before leaving the lock.
-  result.assign(name);
-
-  return result;
-}
-
-std::string Dirname(const std::string& path) {
-  // Copy path because dirname may modify the string passed in.
-  std::string result(path);
-
-#if !defined(__BIONIC__)
-  // Use lock because dirname() may write to a process global and return a
-  // pointer to that. Note that this locking strategy only works if all other
-  // callers to dirname in the process also grab this same lock, but its
-  // better than nothing.  Bionic's dirname returns a thread-local buffer.
-  static std::mutex& dirname_lock = *new std::mutex();
-  std::lock_guard<std::mutex> lock(dirname_lock);
-#endif
-
-  // Note that if std::string uses copy-on-write strings, &str[0] will cause
-  // the copy to be made, so there is no chance of us accidentally writing to
-  // the storage for 'path'.
-  char* parent = dirname(&result[0]);
-
-  // In case dirname returned a pointer to a process global, copy that string
-  // before leaving the lock.
-  result.assign(parent);
-
-  return result;
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/file_test.cpp b/base/file_test.cpp
deleted file mode 100644
index 120228d..0000000
--- a/base/file_test.cpp
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * Copyright (C) 2013 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 "android-base/file.h"
-
-#include "android-base/utf8.h"
-
-#include <gtest/gtest.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <wchar.h>
-
-#include <string>
-
-#if !defined(_WIN32)
-#include <pwd.h>
-#else
-#include <windows.h>
-#endif
-
-#include "android-base/logging.h"  // and must be after windows.h for ERROR
-
-TEST(file, ReadFileToString_ENOENT) {
-  std::string s("hello");
-  errno = 0;
-  ASSERT_FALSE(android::base::ReadFileToString("/proc/does-not-exist", &s));
-  EXPECT_EQ(ENOENT, errno);
-  EXPECT_EQ("", s);  // s was cleared.
-}
-
-TEST(file, ReadFileToString_WriteStringToFile) {
-  TemporaryFile tf;
-  ASSERT_NE(tf.fd, -1) << tf.path;
-  ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path))
-    << strerror(errno);
-  std::string s;
-  ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
-    << strerror(errno);
-  EXPECT_EQ("abc", s);
-}
-
-// symlinks require elevated privileges on Windows.
-#if !defined(_WIN32)
-TEST(file, ReadFileToString_WriteStringToFile_symlink) {
-  TemporaryFile target, link;
-  ASSERT_EQ(0, unlink(link.path));
-  ASSERT_EQ(0, symlink(target.path, link.path));
-  ASSERT_FALSE(android::base::WriteStringToFile("foo", link.path, false));
-  ASSERT_EQ(ELOOP, errno);
-  ASSERT_TRUE(android::base::WriteStringToFile("foo", link.path, true));
-
-  std::string s;
-  ASSERT_FALSE(android::base::ReadFileToString(link.path, &s));
-  ASSERT_EQ(ELOOP, errno);
-  ASSERT_TRUE(android::base::ReadFileToString(link.path, &s, true));
-  ASSERT_EQ("foo", s);
-}
-#endif
-
-// WriteStringToFile2 is explicitly for setting Unix permissions, which make no
-// sense on Windows.
-#if !defined(_WIN32)
-TEST(file, WriteStringToFile2) {
-  TemporaryFile tf;
-  ASSERT_NE(tf.fd, -1) << tf.path;
-  ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path, 0660,
-                                               getuid(), getgid()))
-      << strerror(errno);
-  struct stat sb;
-  ASSERT_EQ(0, stat(tf.path, &sb));
-  ASSERT_EQ(0660U, static_cast<unsigned int>(sb.st_mode & ~S_IFMT));
-  ASSERT_EQ(getuid(), sb.st_uid);
-  ASSERT_EQ(getgid(), sb.st_gid);
-  std::string s;
-  ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
-    << strerror(errno);
-  EXPECT_EQ("abc", s);
-}
-#endif
-
-#if defined(_WIN32)
-TEST(file, NonUnicodeCharsWindows) {
-  constexpr auto kMaxEnvVariableValueSize = 32767;
-  std::wstring old_tmp;
-  old_tmp.resize(kMaxEnvVariableValueSize);
-  old_tmp.resize(GetEnvironmentVariableW(L"TMP", old_tmp.data(), old_tmp.size()));
-  if (old_tmp.empty()) {
-    // Can't continue with empty TMP folder.
-    return;
-  }
-
-  std::wstring new_tmp = old_tmp;
-  if (new_tmp.back() != L'\\') {
-    new_tmp.push_back(L'\\');
-  }
-
-  {
-    auto path(new_tmp + L"锦绣成都\\");
-    _wmkdir(path.c_str());
-    ASSERT_TRUE(SetEnvironmentVariableW(L"TMP", path.c_str()));
-
-    TemporaryFile tf;
-    ASSERT_NE(tf.fd, -1) << tf.path;
-    ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
-
-    ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
-
-    std::string s;
-    ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
-    EXPECT_EQ("abc", s);
-  }
-  {
-    auto path(new_tmp + L"директория с длинным именем\\");
-    _wmkdir(path.c_str());
-    ASSERT_TRUE(SetEnvironmentVariableW(L"TMP", path.c_str()));
-
-    TemporaryFile tf;
-    ASSERT_NE(tf.fd, -1) << tf.path;
-    ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
-
-    ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
-
-    std::string s;
-    ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
-    EXPECT_EQ("abc", s);
-  }
-  {
-    auto path(new_tmp + L"äüöß weiß\\");
-    _wmkdir(path.c_str());
-    ASSERT_TRUE(SetEnvironmentVariableW(L"TMP", path.c_str()));
-
-    TemporaryFile tf;
-    ASSERT_NE(tf.fd, -1) << tf.path;
-    ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
-
-    ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
-
-    std::string s;
-    ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
-    EXPECT_EQ("abc", s);
-  }
-
-  SetEnvironmentVariableW(L"TMP", old_tmp.c_str());
-}
-
-TEST(file, RootDirectoryWindows) {
-  constexpr auto kMaxEnvVariableValueSize = 32767;
-  std::wstring old_tmp;
-  bool tmp_is_empty = false;
-  old_tmp.resize(kMaxEnvVariableValueSize);
-  old_tmp.resize(GetEnvironmentVariableW(L"TMP", old_tmp.data(), old_tmp.size()));
-  if (old_tmp.empty()) {
-    tmp_is_empty = (GetLastError() == ERROR_ENVVAR_NOT_FOUND);
-  }
-  SetEnvironmentVariableW(L"TMP", L"C:");
-
-  TemporaryFile tf;
-  ASSERT_NE(tf.fd, -1) << tf.path;
-
-  SetEnvironmentVariableW(L"TMP", tmp_is_empty ? nullptr : old_tmp.c_str());
-}
-#endif
-
-TEST(file, WriteStringToFd) {
-  TemporaryFile tf;
-  ASSERT_NE(tf.fd, -1) << tf.path;
-  ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
-
-  ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
-
-  std::string s;
-  ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
-  EXPECT_EQ("abc", s);
-}
-
-TEST(file, WriteFully) {
-  TemporaryFile tf;
-  ASSERT_NE(tf.fd, -1) << tf.path;
-  ASSERT_TRUE(android::base::WriteFully(tf.fd, "abc", 3));
-
-  ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
-
-  std::string s;
-  s.resize(3);
-  ASSERT_TRUE(android::base::ReadFully(tf.fd, &s[0], s.size()))
-    << strerror(errno);
-  EXPECT_EQ("abc", s);
-
-  ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
-
-  s.resize(1024);
-  ASSERT_FALSE(android::base::ReadFully(tf.fd, &s[0], s.size()));
-}
-
-TEST(file, RemoveFileIfExists) {
-  TemporaryFile tf;
-  ASSERT_NE(tf.fd, -1) << tf.path;
-  close(tf.fd);
-  tf.fd = -1;
-  std::string err;
-  ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path, &err)) << err;
-  ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path));
-  TemporaryDir td;
-  ASSERT_FALSE(android::base::RemoveFileIfExists(td.path));
-  ASSERT_FALSE(android::base::RemoveFileIfExists(td.path, &err));
-  ASSERT_EQ("is not a regular file or symbolic link", err);
-}
-
-TEST(file, RemoveFileIfExists_ENOTDIR) {
-  TemporaryFile tf;
-  close(tf.fd);
-  tf.fd = -1;
-  std::string err{"xxx"};
-  ASSERT_TRUE(android::base::RemoveFileIfExists(std::string{tf.path} + "/abc", &err));
-  ASSERT_EQ("xxx", err);
-}
-
-#if !defined(_WIN32)
-TEST(file, RemoveFileIfExists_EACCES) {
-  // EACCES -- one of the directories in the path has no search permission
-  // root can bypass permission restrictions, so drop root.
-  if (getuid() == 0) {
-    passwd* shell = getpwnam("shell");
-    setgid(shell->pw_gid);
-    setuid(shell->pw_uid);
-  }
-
-  TemporaryDir td;
-  TemporaryFile tf(td.path);
-  close(tf.fd);
-  tf.fd = -1;
-  std::string err{"xxx"};
-  // Remove dir's search permission.
-  ASSERT_TRUE(chmod(td.path, S_IRUSR | S_IWUSR) == 0);
-  ASSERT_FALSE(android::base::RemoveFileIfExists(tf.path, &err));
-  ASSERT_EQ("Permission denied", err);
-  // Set dir's search permission again.
-  ASSERT_TRUE(chmod(td.path, S_IRWXU) == 0);
-  ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path, &err));
-}
-#endif
-
-TEST(file, Readlink) {
-#if !defined(_WIN32)
-  // Linux doesn't allow empty symbolic links.
-  std::string min("x");
-  // ext2 and ext4 both have PAGE_SIZE limits.
-  // If file encryption is enabled, there's extra overhead to store the
-  // size of the encrypted symlink target. There's also an off-by-one
-  // in current kernels (and marlin/sailfish where we're seeing this
-  // failure are still on 3.18, far from current). http://b/33306057.
-  std::string max(static_cast<size_t>(4096 - 2 - 1 - 1), 'x');
-
-  TemporaryDir td;
-  std::string min_path{std::string(td.path) + "/" + "min"};
-  std::string max_path{std::string(td.path) + "/" + "max"};
-
-  ASSERT_EQ(0, symlink(min.c_str(), min_path.c_str()));
-  ASSERT_EQ(0, symlink(max.c_str(), max_path.c_str()));
-
-  std::string result;
-
-  result = "wrong";
-  ASSERT_TRUE(android::base::Readlink(min_path, &result));
-  ASSERT_EQ(min, result);
-
-  result = "wrong";
-  ASSERT_TRUE(android::base::Readlink(max_path, &result));
-  ASSERT_EQ(max, result);
-#endif
-}
-
-TEST(file, Realpath) {
-#if !defined(_WIN32)
-  TemporaryDir td;
-  std::string basename = android::base::Basename(td.path);
-  std::string dir_name = android::base::Dirname(td.path);
-  std::string base_dir_name = android::base::Basename(dir_name);
-
-  {
-    std::string path = dir_name + "/../" + base_dir_name + "/" + basename;
-    std::string result;
-    ASSERT_TRUE(android::base::Realpath(path, &result));
-    ASSERT_EQ(td.path, result);
-  }
-
-  {
-    std::string path = std::string(td.path) + "/..";
-    std::string result;
-    ASSERT_TRUE(android::base::Realpath(path, &result));
-    ASSERT_EQ(dir_name, result);
-  }
-
-  {
-    errno = 0;
-    std::string path = std::string(td.path) + "/foo.noent";
-    std::string result = "wrong";
-    ASSERT_TRUE(!android::base::Realpath(path, &result));
-    ASSERT_TRUE(result.empty());
-    ASSERT_EQ(ENOENT, errno);
-  }
-#endif
-}
-
-TEST(file, GetExecutableDirectory) {
-  std::string path = android::base::GetExecutableDirectory();
-  ASSERT_NE("", path);
-  ASSERT_NE(android::base::GetExecutablePath(), path);
-  ASSERT_EQ('/', path[0]);
-  ASSERT_NE('/', path[path.size() - 1]);
-}
-
-TEST(file, GetExecutablePath) {
-  ASSERT_NE("", android::base::GetExecutablePath());
-}
-
-TEST(file, Basename) {
-  EXPECT_EQ("sh", android::base::Basename("/system/bin/sh"));
-  EXPECT_EQ("sh", android::base::Basename("sh"));
-  EXPECT_EQ("sh", android::base::Basename("/system/bin/sh/"));
-}
-
-TEST(file, Dirname) {
-  EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh"));
-  EXPECT_EQ(".", android::base::Dirname("sh"));
-  EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh/"));
-}
-
-TEST(file, ReadFileToString_capacity) {
-  TemporaryFile tf;
-  ASSERT_NE(tf.fd, -1) << tf.path;
-
-  // For a huge file, the overhead should still be small.
-  std::string s;
-  size_t size = 16 * 1024 * 1024;
-  ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
-  ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
-  EXPECT_EQ(size, s.size());
-  EXPECT_LT(s.capacity(), size + 16);
-
-  // Even for weird badly-aligned sizes.
-  size += 12345;
-  ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
-  ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
-  EXPECT_EQ(size, s.size());
-  EXPECT_LT(s.capacity(), size + 16);
-
-  // We'll shrink an enormous string if you read a small file into it.
-  size = 64;
-  ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
-  ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
-  EXPECT_EQ(size, s.size());
-  EXPECT_LT(s.capacity(), size + 16);
-}
-
-TEST(file, ReadFileToString_capacity_0) {
-  TemporaryFile tf;
-  ASSERT_NE(tf.fd, -1) << tf.path;
-
-  // Because /proc reports its files as zero-length, we don't actually trust
-  // any file that claims to be zero-length. Rather than add increasingly
-  // complex heuristics for shrinking the passed-in string in that case, we
-  // currently leave it alone.
-  std::string s;
-  size_t initial_capacity = s.capacity();
-  ASSERT_TRUE(android::base::WriteStringToFile("", tf.path));
-  ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
-  EXPECT_EQ(0U, s.size());
-  EXPECT_EQ(initial_capacity, s.capacity());
-}
diff --git a/base/format_benchmark.cpp b/base/format_benchmark.cpp
deleted file mode 100644
index 9590b23..0000000
--- a/base/format_benchmark.cpp
+++ /dev/null
@@ -1,80 +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 "android-base/format.h"
-
-#include <limits>
-
-#include <benchmark/benchmark.h>
-
-#include "android-base/stringprintf.h"
-
-using android::base::StringPrintf;
-
-static void BenchmarkFormatInt(benchmark::State& state) {
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(fmt::format("{} {} {}", 42, std::numeric_limits<int>::min(),
-                                         std::numeric_limits<int>::max()));
-  }
-}
-
-BENCHMARK(BenchmarkFormatInt);
-
-static void BenchmarkStringPrintfInt(benchmark::State& state) {
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(StringPrintf("%d %d %d", 42, std::numeric_limits<int>::min(),
-                                          std::numeric_limits<int>::max()));
-  }
-}
-
-BENCHMARK(BenchmarkStringPrintfInt);
-
-static void BenchmarkFormatFloat(benchmark::State& state) {
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(fmt::format("{} {} {}", 42.42, std::numeric_limits<float>::min(),
-                                         std::numeric_limits<float>::max()));
-  }
-}
-
-BENCHMARK(BenchmarkFormatFloat);
-
-static void BenchmarkStringPrintfFloat(benchmark::State& state) {
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(StringPrintf("%f %f %f", 42.42, std::numeric_limits<float>::min(),
-                                          std::numeric_limits<float>::max()));
-  }
-}
-
-BENCHMARK(BenchmarkStringPrintfFloat);
-
-static void BenchmarkFormatStrings(benchmark::State& state) {
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(fmt::format("{} hello there {}", "hi,", "!!"));
-  }
-}
-
-BENCHMARK(BenchmarkFormatStrings);
-
-static void BenchmarkStringPrintfStrings(benchmark::State& state) {
-  for (auto _ : state) {
-    benchmark::DoNotOptimize(StringPrintf("%s hello there %s", "hi,", "!!"));
-  }
-}
-
-BENCHMARK(BenchmarkStringPrintfStrings);
-
-// Run the benchmark
-BENCHMARK_MAIN();
diff --git a/base/include/android-base/chrono_utils.h b/base/include/android-base/chrono_utils.h
deleted file mode 100644
index 11fcf71..0000000
--- a/base/include/android-base/chrono_utils.h
+++ /dev/null
@@ -1,53 +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.
- */
-
-#pragma once
-
-#include <chrono>
-#include <sstream>
-
-#if __cplusplus > 201103L && !defined(__WIN32)  // C++14
-using namespace std::chrono_literals;
-#endif
-
-namespace android {
-namespace base {
-
-// A std::chrono clock based on CLOCK_BOOTTIME.
-class boot_clock {
- public:
-  typedef std::chrono::nanoseconds duration;
-  typedef std::chrono::time_point<boot_clock, duration> time_point;
-
-  static time_point now();
-};
-
-class Timer {
- public:
-  Timer() : start_(boot_clock::now()) {}
-
-  std::chrono::milliseconds duration() const {
-    return std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() - start_);
-  }
-
- private:
-  boot_clock::time_point start_;
-};
-
-std::ostream& operator<<(std::ostream& os, const Timer& t);
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/cmsg.h b/base/include/android-base/cmsg.h
deleted file mode 100644
index e4197b1..0000000
--- a/base/include/android-base/cmsg.h
+++ /dev/null
@@ -1,106 +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 <sys/stat.h>
-#include <sys/types.h>
-
-#include <type_traits>
-#include <vector>
-
-#include <android-base/collections.h>
-#include <android-base/macros.h>
-#include <android-base/unique_fd.h>
-
-namespace android {
-namespace base {
-
-#if !defined(_WIN32)
-
-// Helpers for sending and receiving file descriptors across Unix domain sockets.
-//
-// The cmsg(3) API is very hard to get right, with multiple landmines that can
-// lead to death. Almost all of the uses of cmsg in Android make at least one of
-// the following mistakes:
-//
-//   - not aligning the cmsg buffer
-//   - leaking fds if more fds are received than expected
-//   - blindly dereferencing CMSG_DATA without checking the header
-//   - using CMSG_SPACE instead of CMSG_LEN for .cmsg_len
-//   - using CMSG_LEN instead of CMSG_SPACE for .msg_controllen
-//   - using a length specified in number of fds instead of bytes
-//
-// These functions wrap the hard-to-use cmsg API with an easier to use abstraction.
-
-// Send file descriptors across a Unix domain socket.
-//
-// Note that the write can return short if the socket type is SOCK_STREAM. When
-// this happens, file descriptors are still sent to the other end, but with
-// truncated data. For this reason, using SOCK_SEQPACKET or SOCK_DGRAM is recommended.
-ssize_t SendFileDescriptorVector(borrowed_fd sock, const void* data, size_t len,
-                                 const std::vector<int>& fds);
-
-// Receive file descriptors from a Unix domain socket.
-//
-// If more FDs (or bytes, for datagram sockets) are received than expected,
-// -1 is returned with errno set to EMSGSIZE, and all received FDs are thrown away.
-ssize_t ReceiveFileDescriptorVector(borrowed_fd sock, void* data, size_t len, size_t max_fds,
-                                    std::vector<android::base::unique_fd>* fds);
-
-// Helper for SendFileDescriptorVector that constructs a std::vector for you, e.g.:
-//   SendFileDescriptors(sock, "foo", 3, std::move(fd1), std::move(fd2))
-template <typename... Args>
-ssize_t SendFileDescriptors(borrowed_fd sock, const void* data, size_t len, Args&&... sent_fds) {
-  // Do not allow implicit conversion to int: people might try to do something along the lines of:
-  //   SendFileDescriptors(..., std::move(a_unique_fd))
-  // and be surprised when the unique_fd isn't closed afterwards.
-  AssertType<int>(std::forward<Args>(sent_fds)...);
-  std::vector<int> fds;
-  Append(fds, std::forward<Args>(sent_fds)...);
-  return SendFileDescriptorVector(sock, data, len, fds);
-}
-
-// Helper for ReceiveFileDescriptorVector that receives an exact number of file descriptors.
-// If more file descriptors are received than requested, -1 is returned with errno set to EMSGSIZE.
-// If fewer file descriptors are received than requested, -1 is returned with errno set to ENOMSG.
-// In both cases, all arguments are cleared and any received FDs are thrown away.
-template <typename... Args>
-ssize_t ReceiveFileDescriptors(borrowed_fd sock, void* data, size_t len, Args&&... received_fds) {
-  std::vector<unique_fd*> fds;
-  Append(fds, std::forward<Args>(received_fds)...);
-
-  std::vector<unique_fd> result;
-  ssize_t rc = ReceiveFileDescriptorVector(sock, data, len, fds.size(), &result);
-  if (rc == -1 || result.size() != fds.size()) {
-    int err = rc == -1 ? errno : ENOMSG;
-    for (unique_fd* fd : fds) {
-      fd->reset();
-    }
-    errno = err;
-    return -1;
-  }
-
-  for (size_t i = 0; i < fds.size(); ++i) {
-    *fds[i] = std::move(result[i]);
-  }
-  return rc;
-}
-
-#endif
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/collections.h b/base/include/android-base/collections.h
deleted file mode 100644
index be0683a..0000000
--- a/base/include/android-base/collections.h
+++ /dev/null
@@ -1,60 +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 <utility>
-
-namespace android {
-namespace base {
-
-// Helpers for converting a variadic template parameter pack to a homogeneous collection.
-// Parameters must be implictly convertible to the contained type (including via move/copy ctors).
-//
-// Use as follows:
-//
-//   template <typename... Args>
-//   std::vector<int> CreateVector(Args&&... args) {
-//     std::vector<int> result;
-//     Append(result, std::forward<Args>(args)...);
-//     return result;
-//   }
-template <typename CollectionType, typename T>
-void Append(CollectionType& collection, T&& arg) {
-  collection.push_back(std::forward<T>(arg));
-}
-
-template <typename CollectionType, typename T, typename... Args>
-void Append(CollectionType& collection, T&& arg, Args&&... args) {
-  collection.push_back(std::forward<T>(arg));
-  return Append(collection, std::forward<Args>(args)...);
-}
-
-// Assert that all of the arguments in a variadic template parameter pack are of a given type
-// after std::decay.
-template <typename T, typename Arg, typename... Args>
-void AssertType(Arg&&) {
-  static_assert(std::is_same<T, typename std::decay<Arg>::type>::value);
-}
-
-template <typename T, typename Arg, typename... Args>
-void AssertType(Arg&&, Args&&... args) {
-  static_assert(std::is_same<T, typename std::decay<Arg>::type>::value);
-  AssertType<T>(std::forward<Args>(args)...);
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/endian.h b/base/include/android-base/endian.h
deleted file mode 100644
index 8fa6365..0000000
--- a/base/include/android-base/endian.h
+++ /dev/null
@@ -1,98 +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.
- */
-
-#pragma once
-
-/* A cross-platform equivalent of bionic's <sys/endian.h>. */
-
-/* For __BIONIC__ and __GLIBC__ */
-#include <sys/cdefs.h>
-
-#if defined(__BIONIC__)
-
-#include <sys/endian.h>
-
-#elif defined(__GLIBC__)
-
-/* glibc's <endian.h> is like bionic's <sys/endian.h>. */
-#include <endian.h>
-
-/* glibc keeps htons and htonl in <netinet/in.h>. */
-#include <netinet/in.h>
-
-/* glibc doesn't have the 64-bit variants. */
-#define htonq(x) htobe64(x)
-#define ntohq(x) be64toh(x)
-
-/* glibc has different names to BSD for these. */
-#define betoh16(x) be16toh(x)
-#define betoh32(x) be32toh(x)
-#define betoh64(x) be64toh(x)
-#define letoh16(x) le16toh(x)
-#define letoh32(x) le32toh(x)
-#define letoh64(x) le64toh(x)
-
-#else
-
-#if defined(__APPLE__)
-/* macOS has some of the basics. */
-#include <sys/_endian.h>
-#else
-/* Windows has some of the basics as well. */
-#include <sys/param.h>
-#include <winsock2.h>
-/* winsock2.h *must* be included before the following four macros. */
-#define htons(x) __builtin_bswap16(x)
-#define htonl(x) __builtin_bswap32(x)
-#define ntohs(x) __builtin_bswap16(x)
-#define ntohl(x) __builtin_bswap32(x)
-#endif
-
-/* Neither macOS nor Windows have the rest. */
-
-#define __LITTLE_ENDIAN 1234
-#define __BIG_ENDIAN 4321
-#define __BYTE_ORDER __LITTLE_ENDIAN
-
-#define htonq(x) __builtin_bswap64(x)
-
-#define ntohq(x) __builtin_bswap64(x)
-
-#define htobe16(x) __builtin_bswap16(x)
-#define htobe32(x) __builtin_bswap32(x)
-#define htobe64(x) __builtin_bswap64(x)
-
-#define betoh16(x) __builtin_bswap16(x)
-#define betoh32(x) __builtin_bswap32(x)
-#define betoh64(x) __builtin_bswap64(x)
-
-#define htole16(x) (x)
-#define htole32(x) (x)
-#define htole64(x) (x)
-
-#define letoh16(x) (x)
-#define letoh32(x) (x)
-#define letoh64(x) (x)
-
-#define be16toh(x) __builtin_bswap16(x)
-#define be32toh(x) __builtin_bswap32(x)
-#define be64toh(x) __builtin_bswap64(x)
-
-#define le16toh(x) (x)
-#define le32toh(x) (x)
-#define le64toh(x) (x)
-
-#endif
diff --git a/base/include/android-base/errno_restorer.h b/base/include/android-base/errno_restorer.h
deleted file mode 100644
index 1c8597c..0000000
--- a/base/include/android-base/errno_restorer.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2020 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 "errno.h"
-
-#include "android-base/macros.h"
-
-namespace android {
-namespace base {
-
-class ErrnoRestorer {
- public:
-  ErrnoRestorer() : saved_errno_(errno) {}
-
-  ~ErrnoRestorer() { errno = saved_errno_; }
-
-  // Allow this object to be used as part of && operation.
-  operator bool() const { return true; }
-
- private:
-  const int saved_errno_;
-
-  DISALLOW_COPY_AND_ASSIGN(ErrnoRestorer);
-};
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/errors.h b/base/include/android-base/errors.h
deleted file mode 100644
index 06f29fc..0000000
--- a/base/include/android-base/errors.h
+++ /dev/null
@@ -1,43 +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.
- */
-
-// Portable error handling functions. This is only necessary for host-side
-// code that needs to be cross-platform; code that is only run on Unix should
-// just use errno and strerror() for simplicity.
-//
-// There is some complexity since Windows has (at least) three different error
-// numbers, not all of which share the same type:
-//   * errno: for C runtime errors.
-//   * GetLastError(): Windows non-socket errors.
-//   * WSAGetLastError(): Windows socket errors.
-// errno can be passed to strerror() on all platforms, but the other two require
-// special handling to get the error string. Refer to Microsoft documentation
-// to determine which error code to check for each function.
-
-#pragma once
-
-#include <string>
-
-namespace android {
-namespace base {
-
-// Returns a string describing the given system error code. |error_code| must
-// be errno on Unix or GetLastError()/WSAGetLastError() on Windows. Passing
-// errno on Windows has undefined behavior.
-std::string SystemErrorCodeToString(int error_code);
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/expected.h b/base/include/android-base/expected.h
deleted file mode 100644
index 9470344..0000000
--- a/base/include/android-base/expected.h
+++ /dev/null
@@ -1,744 +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 <algorithm>
-#include <initializer_list>
-#include <type_traits>
-#include <utility>
-#include <variant>
-
-// android::base::expected is an Android implementation of the std::expected
-// proposal.
-// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0323r7.html
-//
-// Usage:
-// using android::base::expected;
-// using android::base::unexpected;
-//
-// expected<double,std::string> safe_divide(double i, double j) {
-//   if (j == 0) return unexpected("divide by zero");
-//   else return i / j;
-// }
-//
-// void test() {
-//   auto q = safe_divide(10, 0);
-//   if (q) { printf("%f\n", q.value()); }
-//   else { printf("%s\n", q.error().c_str()); }
-// }
-//
-// When the proposal becomes part of the standard and is implemented by
-// libcxx, this will be removed and android::base::expected will be
-// type alias to std::expected.
-//
-
-namespace android {
-namespace base {
-
-// Synopsis
-template<class T, class E>
-    class expected;
-
-template<class E>
-    class unexpected;
-template<class E>
-  unexpected(E) -> unexpected<E>;
-
-template<class E>
-   class bad_expected_access;
-
-template<>
-   class bad_expected_access<void>;
-
-struct unexpect_t {
-   explicit unexpect_t() = default;
-};
-inline constexpr unexpect_t unexpect{};
-
-// macros for SFINAE
-#define _ENABLE_IF(...) \
-  , std::enable_if_t<(__VA_ARGS__)>* = nullptr
-
-// Define NODISCARD_EXPECTED to prevent expected<T,E> from being
-// ignored when used as a return value. This is off by default.
-#ifdef NODISCARD_EXPECTED
-#define _NODISCARD_ [[nodiscard]]
-#else
-#define _NODISCARD_
-#endif
-
-// Class expected
-template<class T, class E>
-class _NODISCARD_ expected {
- public:
-  using value_type = T;
-  using error_type = E;
-  using unexpected_type = unexpected<E>;
-
-  template<class U>
-  using rebind = expected<U, error_type>;
-
-  // constructors
-  constexpr expected() = default;
-  constexpr expected(const expected& rhs) = default;
-  constexpr expected(expected&& rhs) noexcept = default;
-
-  template<class U, class G _ENABLE_IF(
-    std::is_constructible_v<T, const U&> &&
-    std::is_constructible_v<E, const G&> &&
-    !std::is_constructible_v<T, expected<U, G>&> &&
-    !std::is_constructible_v<T, expected<U, G>&&> &&
-    !std::is_constructible_v<T, const expected<U, G>&> &&
-    !std::is_constructible_v<T, const expected<U, G>&&> &&
-    !std::is_convertible_v<expected<U, G>&, T> &&
-    !std::is_convertible_v<expected<U, G>&&, T> &&
-    !std::is_convertible_v<const expected<U, G>&, T> &&
-    !std::is_convertible_v<const expected<U, G>&&, T> &&
-    !(!std::is_convertible_v<const U&, T> ||
-     !std::is_convertible_v<const G&, E>) /* non-explicit */
-  )>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr expected(const expected<U, G>& rhs) {
-    if (rhs.has_value()) var_ = rhs.value();
-    else var_ = unexpected(rhs.error());
-  }
-
-  template<class U, class G _ENABLE_IF(
-    std::is_constructible_v<T, const U&> &&
-    std::is_constructible_v<E, const G&> &&
-    !std::is_constructible_v<T, expected<U, G>&> &&
-    !std::is_constructible_v<T, expected<U, G>&&> &&
-    !std::is_constructible_v<T, const expected<U, G>&> &&
-    !std::is_constructible_v<T, const expected<U, G>&&> &&
-    !std::is_convertible_v<expected<U, G>&, T> &&
-    !std::is_convertible_v<expected<U, G>&&, T> &&
-    !std::is_convertible_v<const expected<U, G>&, T> &&
-    !std::is_convertible_v<const expected<U, G>&&, T> &&
-    (!std::is_convertible_v<const U&, T> ||
-     !std::is_convertible_v<const G&, E>) /* explicit */
-  )>
-  constexpr explicit expected(const expected<U, G>& rhs) {
-    if (rhs.has_value()) var_ = rhs.value();
-    else var_ = unexpected(rhs.error());
-  }
-
-  template<class U, class G _ENABLE_IF(
-    std::is_constructible_v<T, const U&> &&
-    std::is_constructible_v<E, const G&> &&
-    !std::is_constructible_v<T, expected<U, G>&> &&
-    !std::is_constructible_v<T, expected<U, G>&&> &&
-    !std::is_constructible_v<T, const expected<U, G>&> &&
-    !std::is_constructible_v<T, const expected<U, G>&&> &&
-    !std::is_convertible_v<expected<U, G>&, T> &&
-    !std::is_convertible_v<expected<U, G>&&, T> &&
-    !std::is_convertible_v<const expected<U, G>&, T> &&
-    !std::is_convertible_v<const expected<U, G>&&, T> &&
-    !(!std::is_convertible_v<const U&, T> ||
-     !std::is_convertible_v<const G&, E>) /* non-explicit */
-  )>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr expected(expected<U, G>&& rhs) {
-    if (rhs.has_value()) var_ = std::move(rhs.value());
-    else var_ = unexpected(std::move(rhs.error()));
-  }
-
-  template<class U, class G _ENABLE_IF(
-    std::is_constructible_v<T, const U&> &&
-    std::is_constructible_v<E, const G&> &&
-    !std::is_constructible_v<T, expected<U, G>&> &&
-    !std::is_constructible_v<T, expected<U, G>&&> &&
-    !std::is_constructible_v<T, const expected<U, G>&> &&
-    !std::is_constructible_v<T, const expected<U, G>&&> &&
-    !std::is_convertible_v<expected<U, G>&, T> &&
-    !std::is_convertible_v<expected<U, G>&&, T> &&
-    !std::is_convertible_v<const expected<U, G>&, T> &&
-    !std::is_convertible_v<const expected<U, G>&&, T> &&
-    (!std::is_convertible_v<const U&, T> ||
-     !std::is_convertible_v<const G&, E>) /* explicit */
-  )>
-  constexpr explicit expected(expected<U, G>&& rhs) {
-    if (rhs.has_value()) var_ = std::move(rhs.value());
-    else var_ = unexpected(std::move(rhs.error()));
-  }
-
-  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 */
-                )>
-  // NOLINTNEXTLINE(google-explicit-constructor,bugprone-forwarding-reference-overload)
-  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> /* explicit */
-                )>
-  // NOLINTNEXTLINE(bugprone-forwarding-reference-overload)
-  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&> &&
-    std::is_convertible_v<const G&, E> /* non-explicit */
-  )>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr expected(const unexpected<G>& e)
-  : var_(std::in_place_index<1>, e.value()) {}
-
-  template<class G = E _ENABLE_IF(
-    std::is_constructible_v<E, const G&> &&
-    !std::is_convertible_v<const G&, E> /* explicit */
-  )>
-  constexpr explicit expected(const unexpected<G>& e)
-  : var_(std::in_place_index<1>, E(e.value())) {}
-
-  template<class G = E _ENABLE_IF(
-    std::is_constructible_v<E, G&&> &&
-    std::is_convertible_v<G&&, E> /* non-explicit */
-  )>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr expected(unexpected<G>&& e)
-  : var_(std::in_place_index<1>, std::move(e.value())) {}
-
-  template<class G = E _ENABLE_IF(
-    std::is_constructible_v<E, G&&> &&
-    !std::is_convertible_v<G&&, E> /* explicit */
-  )>
-  constexpr explicit expected(unexpected<G>&& e)
-  : var_(std::in_place_index<1>, E(std::move(e.value()))) {}
-
-  template<class... Args _ENABLE_IF(
-    std::is_constructible_v<T, Args&&...>
-  )>
-  constexpr explicit expected(std::in_place_t, Args&&... args)
-  : var_(std::in_place_index<0>, std::forward<Args>(args)...) {}
-
-  template<class U, class... Args _ENABLE_IF(
-    std::is_constructible_v<T, std::initializer_list<U>&, Args...>
-  )>
-  constexpr explicit expected(std::in_place_t, std::initializer_list<U> il, Args&&... args)
-  : var_(std::in_place_index<0>, il, std::forward<Args>(args)...) {}
-
-  template<class... Args _ENABLE_IF(
-    std::is_constructible_v<E, Args...>
-  )>
-  constexpr explicit expected(unexpect_t, Args&&... args)
-  : var_(unexpected_type(std::forward<Args>(args)...)) {}
-
-  template<class U, class... Args _ENABLE_IF(
-    std::is_constructible_v<E, std::initializer_list<U>&, Args...>
-  )>
-  constexpr explicit expected(unexpect_t, std::initializer_list<U> il, Args&&... args)
-  : var_(unexpected_type(il, std::forward<Args>(args)...)) {}
-
-  // destructor
-  ~expected() = default;
-
-  // assignment
-  // Note: SFNAIE doesn't work here because assignment operator should be
-  // non-template. We could workaround this by defining a templated parent class
-  // having the assignment operator. This incomplete implementation however
-  // doesn't allow us to copy assign expected<T,E> even when T is non-copy
-  // assignable. The copy assignment will fail by the underlying std::variant
-  // anyway though the error message won't be clear.
-  expected& operator=(const expected& rhs) = default;
-
-  // Note for SFNAIE above applies to here as well
-  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>, 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;
-  }
-
-  template<class G = E>
-  expected& operator=(const unexpected<G>& rhs) {
-    var_ = rhs;
-    return *this;
-  }
-
-  template<class G = E _ENABLE_IF(
-    std::is_nothrow_move_constructible_v<G> &&
-    std::is_move_assignable_v<G>
-  )>
-  expected& operator=(unexpected<G>&& rhs) {
-    var_ = std::move(rhs);
-    return *this;
-  }
-
-  // modifiers
-  template<class... Args _ENABLE_IF(
-    std::is_nothrow_constructible_v<T, Args...>
-  )>
-  T& emplace(Args&&... args) {
-    expected(std::in_place, std::forward<Args>(args)...).swap(*this);
-    return value();
-  }
-
-  template<class U, class... Args _ENABLE_IF(
-    std::is_nothrow_constructible_v<T, std::initializer_list<U>&, Args...>
-  )>
-  T& emplace(std::initializer_list<U> il, Args&&... args) {
-    expected(std::in_place, il, std::forward<Args>(args)...).swap(*this);
-    return value();
-  }
-
-  // swap
-  template<typename U = T, typename = std::enable_if_t<(
-    std::is_swappable_v<U> &&
-    std::is_swappable_v<E> &&
-    (std::is_move_constructible_v<U> ||
-     std::is_move_constructible_v<E>))>>
-  void swap(expected& rhs) noexcept(
-    std::is_nothrow_move_constructible_v<T> &&
-    std::is_nothrow_swappable_v<T> &&
-    std::is_nothrow_move_constructible_v<E> &&
-    std::is_nothrow_swappable_v<E>) {
-    var_.swap(rhs.var_);
-  }
-
-  // observers
-  constexpr const T* operator->() const { return std::addressof(value()); }
-  constexpr T* operator->() { return std::addressof(value()); }
-  constexpr const T& operator*() const& { return value(); }
-  constexpr T& operator*() & { return value(); }
-  constexpr const T&& operator*() const&& { return std::move(std::get<T>(var_)); }
-  constexpr T&& operator*() && { return std::move(std::get<T>(var_)); }
-
-  constexpr explicit operator bool() const noexcept { return has_value(); }
-  constexpr bool has_value() const noexcept { return var_.index() == 0; }
-  constexpr bool ok() const noexcept { return has_value(); }
-
-  constexpr const T& value() const& { return std::get<T>(var_); }
-  constexpr T& value() & { return std::get<T>(var_); }
-  constexpr const T&& value() const&& { return std::move(std::get<T>(var_)); }
-  constexpr T&& value() && { return std::move(std::get<T>(var_)); }
-
-  constexpr const E& error() const& { return std::get<unexpected_type>(var_).value(); }
-  constexpr E& error() & { return std::get<unexpected_type>(var_).value(); }
-  constexpr const E&& error() const&& { return std::move(std::get<unexpected_type>(var_)).value(); }
-  constexpr E&& error() && { return std::move(std::get<unexpected_type>(var_)).value(); }
-
-  template<class U _ENABLE_IF(
-    std::is_copy_constructible_v<T> &&
-    std::is_convertible_v<U, T>
-  )>
-  constexpr T value_or(U&& v) const& {
-    if (has_value()) return value();
-    else return static_cast<T>(std::forward<U>(v));
-  }
-
-  template<class U _ENABLE_IF(
-    std::is_move_constructible_v<T> &&
-    std::is_convertible_v<U, T>
-  )>
-  constexpr T value_or(U&& v) && {
-    if (has_value()) return std::move(value());
-    else return static_cast<T>(std::forward<U>(v));
-  }
-
-  // expected equality operators
-  template<class T1, class E1, class T2, class E2>
-  friend constexpr bool operator==(const expected<T1, E1>& x, const expected<T2, E2>& y);
-  template<class T1, class E1, class T2, class E2>
-  friend constexpr bool operator!=(const expected<T1, E1>& x, const expected<T2, E2>& y);
-
-  // Comparison with unexpected<E>
-  template<class T1, class E1, class E2>
-  friend constexpr bool operator==(const expected<T1, E1>&, const unexpected<E2>&);
-  template<class T1, class E1, class E2>
-  friend constexpr bool operator==(const unexpected<E2>&, const expected<T1, E1>&);
-  template<class T1, class E1, class E2>
-  friend constexpr bool operator!=(const expected<T1, E1>&, const unexpected<E2>&);
-  template<class T1, class E1, class E2>
-  friend constexpr bool operator!=(const unexpected<E2>&, const expected<T1, E1>&);
-
-  // Specialized algorithms
-  template<class T1, class E1>
-  friend void swap(expected<T1, E1>&, expected<T1, E1>&) noexcept;
-
- private:
-  std::variant<value_type, unexpected_type> var_;
-};
-
-template<class T1, class E1, class T2, class E2>
-constexpr bool operator==(const expected<T1, E1>& x, const expected<T2, E2>& y) {
-  if (x.has_value() != y.has_value()) return false;
-  if (!x.has_value()) return x.error() == y.error();
-  return *x == *y;
-}
-
-template<class T1, class E1, class T2, class E2>
-constexpr bool operator!=(const expected<T1, E1>& x, const expected<T2, E2>& y) {
-  return !(x == y);
-}
-
-// Comparison with unexpected<E>
-template<class T1, class E1, class E2>
-constexpr bool operator==(const expected<T1, E1>& x, const unexpected<E2>& y) {
-  return !x.has_value() && (x.error() == y.value());
-}
-template<class T1, class E1, class E2>
-constexpr bool operator==(const unexpected<E2>& x, const expected<T1, E1>& y) {
-  return !y.has_value() && (x.value() == y.error());
-}
-template<class T1, class E1, class E2>
-constexpr bool operator!=(const expected<T1, E1>& x, const unexpected<E2>& y) {
-  return x.has_value() || (x.error() != y.value());
-}
-template<class T1, class E1, class E2>
-constexpr bool operator!=(const unexpected<E2>& x, const expected<T1, E1>& y) {
-  return y.has_value() || (x.value() != y.error());
-}
-
-template<class E>
-class _NODISCARD_ expected<void, E> {
- public:
-  using value_type = void;
-  using error_type = E;
-  using unexpected_type = unexpected<E>;
-
-  // constructors
-  constexpr expected() = default;
-  constexpr expected(const expected& rhs) = default;
-  constexpr expected(expected&& rhs) noexcept = default;
-
-  template<class U, class G _ENABLE_IF(
-    std::is_void_v<U> &&
-    std::is_convertible_v<const G&, E> /* non-explicit */
-  )>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr expected(const expected<U, G>& rhs) {
-    if (!rhs.has_value()) var_ = unexpected(rhs.error());
-  }
-
-  template<class U, class G _ENABLE_IF(
-    std::is_void_v<U> &&
-    !std::is_convertible_v<const G&, E> /* explicit */
-  )>
-  constexpr explicit expected(const expected<U, G>& rhs) {
-    if (!rhs.has_value()) var_ = unexpected(rhs.error());
-  }
-
-  template<class U, class G _ENABLE_IF(
-    std::is_void_v<U> &&
-    std::is_convertible_v<const G&&, E> /* non-explicit */
-  )>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr expected(expected<U, G>&& rhs) {
-    if (!rhs.has_value()) var_ = unexpected(std::move(rhs.error()));
-  }
-
-  template<class U, class G _ENABLE_IF(
-    std::is_void_v<U> &&
-    !std::is_convertible_v<const G&&, E> /* explicit */
-  )>
-  constexpr explicit expected(expected<U, G>&& rhs) {
-    if (!rhs.has_value()) var_ = unexpected(std::move(rhs.error()));
-  }
-
-  template<class G = E _ENABLE_IF(
-    std::is_constructible_v<E, const G&> &&
-    std::is_convertible_v<const G&, E> /* non-explicit */
-  )>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr expected(const unexpected<G>& e)
-  : var_(std::in_place_index<1>, e.value()) {}
-
-  template<class G = E _ENABLE_IF(
-    std::is_constructible_v<E, const G&> &&
-    !std::is_convertible_v<const G&, E> /* explicit */
-  )>
-  constexpr explicit expected(const unexpected<G>& e)
-  : var_(std::in_place_index<1>, E(e.value())) {}
-
-  template<class G = E _ENABLE_IF(
-    std::is_constructible_v<E, G&&> &&
-    std::is_convertible_v<G&&, E> /* non-explicit */
-  )>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr expected(unexpected<G>&& e)
-  : var_(std::in_place_index<1>, std::move(e.value())) {}
-
-  template<class G = E _ENABLE_IF(
-    std::is_constructible_v<E, G&&> &&
-    !std::is_convertible_v<G&&, E> /* explicit */
-  )>
-  constexpr explicit expected(unexpected<G>&& e)
-  : var_(std::in_place_index<1>, E(std::move(e.value()))) {}
-
-  template<class... Args _ENABLE_IF(
-    sizeof...(Args) == 0
-  )>
-  constexpr explicit expected(std::in_place_t, Args&&...) {}
-
-  template<class... Args _ENABLE_IF(
-    std::is_constructible_v<E, Args...>
-  )>
-  constexpr explicit expected(unexpect_t, Args&&... args)
-  : var_(unexpected_type(std::forward<Args>(args)...)) {}
-
-  template<class U, class... Args _ENABLE_IF(
-    std::is_constructible_v<E, std::initializer_list<U>&, Args...>
-  )>
-  constexpr explicit expected(unexpect_t, std::initializer_list<U> il, Args&&... args)
-  : var_(unexpected_type(il, std::forward<Args>(args)...)) {}
-
-  // destructor
-  ~expected() = default;
-
-  // assignment
-  // Note: SFNAIE doesn't work here because assignment operator should be
-  // non-template. We could workaround this by defining a templated parent class
-  // having the assignment operator. This incomplete implementation however
-  // doesn't allow us to copy assign expected<T,E> even when T is non-copy
-  // assignable. The copy assignment will fail by the underlying std::variant
-  // anyway though the error message won't be clear.
-  expected& operator=(const expected& rhs) = default;
-
-  // Note for SFNAIE above applies to here as well
-  expected& operator=(expected&& rhs) noexcept(std::is_nothrow_move_assignable_v<E>) = default;
-
-  template<class G = E>
-  expected& operator=(const unexpected<G>& rhs) {
-    var_ = rhs;
-    return *this;
-  }
-
-  template<class G = E _ENABLE_IF(
-    std::is_nothrow_move_constructible_v<G> &&
-    std::is_move_assignable_v<G>
-  )>
-  expected& operator=(unexpected<G>&& rhs) {
-    var_ = std::move(rhs);
-    return *this;
-  }
-
-  // modifiers
-  void emplace() {
-    var_ = std::monostate();
-  }
-
-  // swap
-  template<typename = std::enable_if_t<
-    std::is_swappable_v<E>>
-  >
-  void swap(expected& rhs) noexcept(std::is_nothrow_move_constructible_v<E>) {
-    var_.swap(rhs.var_);
-  }
-
-  // observers
-  constexpr explicit operator bool() const noexcept { return has_value(); }
-  constexpr bool has_value() const noexcept { return var_.index() == 0; }
-  constexpr bool ok() const noexcept { return has_value(); }
-
-  constexpr void value() const& { if (!has_value()) std::get<0>(var_); }
-
-  constexpr const E& error() const& { return std::get<unexpected_type>(var_).value(); }
-  constexpr E& error() & { return std::get<unexpected_type>(var_).value(); }
-  constexpr const E&& error() const&& { return std::move(std::get<unexpected_type>(var_)).value(); }
-  constexpr E&& error() && { return std::move(std::get<unexpected_type>(var_)).value(); }
-
-  // expected equality operators
-  template<class E1, class E2>
-  friend constexpr bool operator==(const expected<void, E1>& x, const expected<void, E2>& y);
-
-  // Specialized algorithms
-  template<class T1, class E1>
-  friend void swap(expected<T1, E1>&, expected<T1, E1>&) noexcept;
-
- private:
-  std::variant<std::monostate, unexpected_type> var_;
-};
-
-template<class E1, class E2>
-constexpr bool operator==(const expected<void, E1>& x, const expected<void, E2>& y) {
-  if (x.has_value() != y.has_value()) return false;
-  if (!x.has_value()) return x.error() == y.error();
-  return true;
-}
-
-template<class T1, class E1, class E2>
-constexpr bool operator==(const expected<T1, E1>& x, const expected<void, E2>& y) {
-  if (x.has_value() != y.has_value()) return false;
-  if (!x.has_value()) return x.error() == y.error();
-  return false;
-}
-
-template<class E1, class T2, class E2>
-constexpr bool operator==(const expected<void, E1>& x, const expected<T2, E2>& y) {
-  if (x.has_value() != y.has_value()) return false;
-  if (!x.has_value()) return x.error() == y.error();
-  return false;
-}
-
-template<class E>
-class unexpected {
- public:
-  // constructors
-  constexpr unexpected(const 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<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>)>
-  // NOLINTNEXTLINE(google-explicit-constructor,bugprone-forwarding-reference-overload)
-  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...>
-  )>
-  constexpr explicit unexpected(std::in_place_t, std::initializer_list<U> il, Args&&... args)
-  : val_(il, std::forward<Args>(args)...) {}
-
-  template<class Err _ENABLE_IF(
-    std::is_constructible_v<E, Err> &&
-    !std::is_constructible_v<E, unexpected<Err>&> &&
-    !std::is_constructible_v<E, unexpected<Err>> &&
-    !std::is_constructible_v<E, const unexpected<Err>&> &&
-    !std::is_constructible_v<E, const unexpected<Err>> &&
-    !std::is_convertible_v<unexpected<Err>&, E> &&
-    !std::is_convertible_v<unexpected<Err>, E> &&
-    !std::is_convertible_v<const unexpected<Err>&, E> &&
-    !std::is_convertible_v<const unexpected<Err>, E> &&
-    std::is_convertible_v<Err, E> /* non-explicit */
-  )>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr unexpected(const unexpected<Err>& rhs)
-  : val_(rhs.value()) {}
-
-  template<class Err _ENABLE_IF(
-    std::is_constructible_v<E, Err> &&
-    !std::is_constructible_v<E, unexpected<Err>&> &&
-    !std::is_constructible_v<E, unexpected<Err>> &&
-    !std::is_constructible_v<E, const unexpected<Err>&> &&
-    !std::is_constructible_v<E, const unexpected<Err>> &&
-    !std::is_convertible_v<unexpected<Err>&, E> &&
-    !std::is_convertible_v<unexpected<Err>, E> &&
-    !std::is_convertible_v<const unexpected<Err>&, E> &&
-    !std::is_convertible_v<const unexpected<Err>, E> &&
-    !std::is_convertible_v<Err, E> /* explicit */
-  )>
-  constexpr explicit unexpected(const unexpected<Err>& rhs)
-  : val_(E(rhs.value())) {}
-
-  template<class Err _ENABLE_IF(
-    std::is_constructible_v<E, Err> &&
-    !std::is_constructible_v<E, unexpected<Err>&> &&
-    !std::is_constructible_v<E, unexpected<Err>> &&
-    !std::is_constructible_v<E, const unexpected<Err>&> &&
-    !std::is_constructible_v<E, const unexpected<Err>> &&
-    !std::is_convertible_v<unexpected<Err>&, E> &&
-    !std::is_convertible_v<unexpected<Err>, E> &&
-    !std::is_convertible_v<const unexpected<Err>&, E> &&
-    !std::is_convertible_v<const unexpected<Err>, E> &&
-    std::is_convertible_v<Err, E> /* non-explicit */
-  )>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  constexpr unexpected(unexpected<Err>&& rhs)
-  : val_(std::move(rhs.value())) {}
-
-  template<class Err _ENABLE_IF(
-    std::is_constructible_v<E, Err> &&
-    !std::is_constructible_v<E, unexpected<Err>&> &&
-    !std::is_constructible_v<E, unexpected<Err>> &&
-    !std::is_constructible_v<E, const unexpected<Err>&> &&
-    !std::is_constructible_v<E, const unexpected<Err>> &&
-    !std::is_convertible_v<unexpected<Err>&, E> &&
-    !std::is_convertible_v<unexpected<Err>, E> &&
-    !std::is_convertible_v<const unexpected<Err>&, E> &&
-    !std::is_convertible_v<const unexpected<Err>, E> &&
-    !std::is_convertible_v<Err, E> /* explicit */
-  )>
-  constexpr explicit unexpected(unexpected<Err>&& rhs)
-  : val_(E(std::move(rhs.value()))) {}
-
-  // assignment
-  constexpr unexpected& operator=(const 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();
-    return *this;
-  }
-  template<class Err = E>
-  constexpr unexpected& operator=(unexpected<Err>&& rhs) {
-    val_ = std::forward<E>(rhs.value());
-    return *this;
-  }
-
-  // observer
-  constexpr const E& value() const& noexcept { return val_; }
-  constexpr E& value() & noexcept { return val_; }
-  constexpr const E&& value() const&& noexcept { return std::move(val_); }
-  constexpr E&& value() && noexcept { return std::move(val_); }
-
-  void swap(unexpected& other) noexcept(std::is_nothrow_swappable_v<E>) {
-    std::swap(val_, other.val_);
-  }
-
-  template<class E1, class E2>
-  friend constexpr bool
-  operator==(const unexpected<E1>& e1, const unexpected<E2>& e2);
-  template<class E1, class E2>
-  friend constexpr bool
-  operator!=(const unexpected<E1>& e1, const unexpected<E2>& e2);
-
-  template<class E1>
-  friend void swap(unexpected<E1>& x, unexpected<E1>& y) noexcept(noexcept(x.swap(y)));
-
- private:
-  E val_;
-};
-
-template<class E1, class E2>
-constexpr bool
-operator==(const unexpected<E1>& e1, const unexpected<E2>& e2) {
-  return e1.value() == e2.value();
-}
-
-template<class E1, class E2>
-constexpr bool
-operator!=(const unexpected<E1>& e1, const unexpected<E2>& e2) {
-  return e1.value() != e2.value();
-}
-
-template<class E1>
-void swap(unexpected<E1>& x, unexpected<E1>& y) noexcept(noexcept(x.swap(y))) {
-  x.swap(y);
-}
-
-// TODO: bad_expected_access class
-
-#undef _ENABLE_IF
-#undef _NODISCARD_
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/file.h b/base/include/android-base/file.h
deleted file mode 100644
index c622562..0000000
--- a/base/include/android-base/file.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2015 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 <sys/stat.h>
-#include <sys/types.h>
-
-#include <string>
-
-#include "android-base/macros.h"
-#include "android-base/off64_t.h"
-#include "android-base/unique_fd.h"
-
-#if !defined(_WIN32) && !defined(O_BINARY)
-/** Windows needs O_BINARY, but Unix never mangles line endings. */
-#define O_BINARY 0
-#endif
-
-#if defined(_WIN32) && !defined(O_CLOEXEC)
-/** Windows has O_CLOEXEC but calls it O_NOINHERIT for some reason. */
-#define O_CLOEXEC O_NOINHERIT
-#endif
-
-class TemporaryFile {
- public:
-  TemporaryFile();
-  explicit TemporaryFile(const std::string& tmp_dir);
-  ~TemporaryFile();
-
-  // Release the ownership of fd, caller is reponsible for closing the
-  // fd or stream properly.
-  int release();
-  // Don't remove the temporary file in the destructor.
-  void DoNotRemove() { remove_file_ = false; }
-
-  int fd;
-  char path[1024];
-
- private:
-  void init(const std::string& tmp_dir);
-
-  bool remove_file_ = true;
-
-  DISALLOW_COPY_AND_ASSIGN(TemporaryFile);
-};
-
-class TemporaryDir {
- public:
-  TemporaryDir();
-  ~TemporaryDir();
-  // Don't remove the temporary dir in the destructor.
-  void DoNotRemove() { remove_dir_and_contents_ = false; }
-
-  char path[1024];
-
- private:
-  bool init(const std::string& tmp_dir);
-
-  bool remove_dir_and_contents_ = true;
-
-  DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
-};
-
-namespace android {
-namespace base {
-
-bool ReadFdToString(borrowed_fd fd, std::string* content);
-bool ReadFileToString(const std::string& path, std::string* content,
-                      bool follow_symlinks = false);
-
-bool WriteStringToFile(const std::string& content, const std::string& path,
-                       bool follow_symlinks = false);
-bool WriteStringToFd(const std::string& content, borrowed_fd fd);
-
-#if !defined(_WIN32)
-bool WriteStringToFile(const std::string& content, const std::string& path,
-                       mode_t mode, uid_t owner, gid_t group,
-                       bool follow_symlinks = false);
-#endif
-
-bool ReadFully(borrowed_fd fd, void* data, size_t byte_count);
-
-// Reads `byte_count` bytes from the file descriptor at the specified offset.
-// Returns false if there was an IO error or EOF was reached before reading `byte_count` bytes.
-//
-// NOTE: On Linux/Mac, this function wraps pread, which provides atomic read support without
-// modifying the read pointer of the file descriptor. On Windows, however, the read pointer does
-// get modified. This means that ReadFullyAtOffset can be used concurrently with other calls to the
-// same function, but concurrently seeking or reading incrementally can lead to unexpected
-// behavior.
-bool ReadFullyAtOffset(borrowed_fd fd, void* data, size_t byte_count, off64_t offset);
-
-bool WriteFully(borrowed_fd fd, const void* data, size_t byte_count);
-
-bool RemoveFileIfExists(const std::string& path, std::string* err = nullptr);
-
-#if !defined(_WIN32)
-bool Realpath(const std::string& path, std::string* result);
-bool Readlink(const std::string& path, std::string* result);
-#endif
-
-std::string GetExecutablePath();
-std::string GetExecutableDirectory();
-
-// Like the regular basename and dirname, but thread-safe on all
-// platforms and capable of correctly handling exotic Windows paths.
-std::string Basename(const std::string& path);
-std::string Dirname(const std::string& path);
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/format.h b/base/include/android-base/format.h
deleted file mode 100644
index 330040d..0000000
--- a/base/include/android-base/format.h
+++ /dev/null
@@ -1,28 +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
-
-// We include fmtlib here as an alias, since libbase will have fmtlib statically linked already.
-// It is accessed through its normal fmt:: namespace.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wshadow"
-#include <fmt/chrono.h>
-#pragma clang diagnostic pop
-#include <fmt/core.h>
-#include <fmt/format.h>
-#include <fmt/ostream.h>
-#include <fmt/printf.h>
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
deleted file mode 100644
index 26827fb..0000000
--- a/base/include/android-base/logging.h
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * Copyright (C) 2015 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
-
-//
-// Google-style C++ logging.
-//
-
-// This header provides a C++ stream interface to logging.
-//
-// To log:
-//
-//   LOG(INFO) << "Some text; " << some_value;
-//
-// Replace `INFO` with any severity from `enum LogSeverity`.
-//
-// To log the result of a failed function and include the string
-// representation of `errno` at the end:
-//
-//   PLOG(ERROR) << "Write failed";
-//
-// The output will be something like `Write failed: I/O error`.
-// Remember this as 'P' as in perror(3).
-//
-// To output your own types, simply implement operator<< as normal.
-//
-// By default, output goes to logcat on Android and stderr on the host.
-// A process can use `SetLogger` to decide where all logging goes.
-// Implementations are provided for logcat, stderr, and dmesg.
-//
-// By default, the process' name is used as the log tag.
-// Code can choose a specific log tag by defining LOG_TAG
-// before including this header.
-
-// This header also provides assertions:
-//
-//   CHECK(must_be_true);
-//   CHECK_EQ(a, b) << z_is_interesting_too;
-
-// NOTE: For Windows, you must include logging.h after windows.h to allow the
-// following code to suppress the evil ERROR macro:
-#ifdef _WIN32
-// windows.h includes wingdi.h which defines an evil macro ERROR.
-#ifdef ERROR
-#undef ERROR
-#endif
-#endif
-
-#include <functional>
-#include <memory>
-#include <ostream>
-
-#include "android-base/errno_restorer.h"
-#include "android-base/macros.h"
-
-// Note: DO NOT USE DIRECTLY. Use LOG_TAG instead.
-#ifdef _LOG_TAG_INTERNAL
-#error "_LOG_TAG_INTERNAL must not be defined"
-#endif
-#ifdef LOG_TAG
-#define _LOG_TAG_INTERNAL LOG_TAG
-#else
-#define _LOG_TAG_INTERNAL nullptr
-#endif
-
-namespace android {
-namespace base {
-
-enum LogSeverity {
-  VERBOSE,
-  DEBUG,
-  INFO,
-  WARNING,
-  ERROR,
-  FATAL_WITHOUT_ABORT,  // For loggability tests, this is considered identical to FATAL.
-  FATAL,
-};
-
-enum LogId {
-  DEFAULT,
-  MAIN,
-  SYSTEM,
-  RADIO,
-  CRASH,
-};
-
-using LogFunction = std::function<void(LogId, LogSeverity, const char*, const char*,
-                                       unsigned int, const char*)>;
-using AbortFunction = std::function<void(const char*)>;
-
-// Loggers for use with InitLogging/SetLogger.
-
-// Log to the kernel log (dmesg).
-void KernelLogger(LogId, LogSeverity, const char*, const char*, unsigned int, const char*);
-// Log to stderr in the full logcat format (with pid/tid/time/tag details).
-void StderrLogger(LogId, LogSeverity, const char*, const char*, unsigned int, const char*);
-// Log just the message to stdout/stderr (without pid/tid/time/tag details).
-// The choice of stdout versus stderr is based on the severity.
-// Errors are also prefixed by the program name (as with err(3)/error(3)).
-// Useful for replacing printf(3)/perror(3)/err(3)/error(3) in command-line tools.
-void StdioLogger(LogId, LogSeverity, const char*, const char*, unsigned int, const char*);
-
-void DefaultAborter(const char* abort_message);
-
-void SetDefaultTag(const std::string& tag);
-
-// The LogdLogger sends chunks of up to ~4000 bytes at a time to logd.  It does not prevent other
-// threads from writing to logd between sending each chunk, so other threads may interleave their
-// messages.  If preventing interleaving is required, then a custom logger that takes a lock before
-// calling this logger should be provided.
-class LogdLogger {
- public:
-  explicit LogdLogger(LogId default_log_id = android::base::MAIN);
-
-  void operator()(LogId, LogSeverity, const char* tag, const char* file,
-                  unsigned int line, const char* message);
-
- private:
-  LogId default_log_id_;
-};
-
-// Configure logging based on ANDROID_LOG_TAGS environment variable.
-// We need to parse a string that looks like
-//
-//      *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i
-//
-// The tag (or '*' for the global level) comes first, followed by a colon and a
-// letter indicating the minimum priority level we're expected to log.  This can
-// be used to reveal or conceal logs with specific tags.
-#ifdef __ANDROID__
-#define INIT_LOGGING_DEFAULT_LOGGER LogdLogger()
-#else
-#define INIT_LOGGING_DEFAULT_LOGGER StderrLogger
-#endif
-void InitLogging(char* argv[],
-                 LogFunction&& logger = INIT_LOGGING_DEFAULT_LOGGER,
-                 AbortFunction&& aborter = DefaultAborter);
-#undef INIT_LOGGING_DEFAULT_LOGGER
-
-// Replace the current logger.
-void SetLogger(LogFunction&& logger);
-
-// Replace the current aborter.
-void SetAborter(AbortFunction&& aborter);
-
-// A helper macro that produces an expression that accepts both a qualified name and an
-// unqualified name for a LogSeverity, and returns a LogSeverity value.
-// Note: DO NOT USE DIRECTLY. This is an implementation detail.
-#define SEVERITY_LAMBDA(severity) ([&]() {    \
-  using ::android::base::VERBOSE;             \
-  using ::android::base::DEBUG;               \
-  using ::android::base::INFO;                \
-  using ::android::base::WARNING;             \
-  using ::android::base::ERROR;               \
-  using ::android::base::FATAL_WITHOUT_ABORT; \
-  using ::android::base::FATAL;               \
-  return (severity); }())
-
-#ifdef __clang_analyzer__
-// Clang's static analyzer does not see the conditional statement inside
-// LogMessage's destructor that will abort on FATAL severity.
-#define ABORT_AFTER_LOG_FATAL for (;; abort())
-
-struct LogAbortAfterFullExpr {
-  ~LogAbortAfterFullExpr() __attribute__((noreturn)) { abort(); }
-  explicit operator bool() const { return false; }
-};
-// Provides an expression that evaluates to the truthiness of `x`, automatically
-// aborting if `c` is true.
-#define ABORT_AFTER_LOG_EXPR_IF(c, x) (((c) && ::android::base::LogAbortAfterFullExpr()) || (x))
-// Note to the static analyzer that we always execute FATAL logs in practice.
-#define MUST_LOG_MESSAGE(severity) (SEVERITY_LAMBDA(severity) == ::android::base::FATAL)
-#else
-#define ABORT_AFTER_LOG_FATAL
-#define ABORT_AFTER_LOG_EXPR_IF(c, x) (x)
-#define MUST_LOG_MESSAGE(severity) false
-#endif
-#define ABORT_AFTER_LOG_FATAL_EXPR(x) ABORT_AFTER_LOG_EXPR_IF(true, x)
-
-// Defines whether the given severity will be logged or silently swallowed.
-#define WOULD_LOG(severity)                                                              \
-  (UNLIKELY(::android::base::ShouldLog(SEVERITY_LAMBDA(severity), _LOG_TAG_INTERNAL)) || \
-   MUST_LOG_MESSAGE(severity))
-
-// Get an ostream that can be used for logging at the given severity and to the default
-// destination.
-//
-// Notes:
-// 1) This will not check whether the severity is high enough. One should use WOULD_LOG to filter
-//    usage manually.
-// 2) This does not save and restore errno.
-#define LOG_STREAM(severity)                                                                    \
-  ::android::base::LogMessage(__FILE__, __LINE__, SEVERITY_LAMBDA(severity), _LOG_TAG_INTERNAL, \
-                              -1)                                                               \
-      .stream()
-
-// Logs a message to logcat on Android otherwise to stderr. If the severity is
-// FATAL it also causes an abort. For example:
-//
-//     LOG(FATAL) << "We didn't expect to reach here";
-#define LOG(severity) LOGGING_PREAMBLE(severity) && LOG_STREAM(severity)
-
-// Checks if we want to log something, and sets up appropriate RAII objects if
-// so.
-// Note: DO NOT USE DIRECTLY. This is an implementation detail.
-#define LOGGING_PREAMBLE(severity)                                                         \
-  (WOULD_LOG(severity) &&                                                                  \
-   ABORT_AFTER_LOG_EXPR_IF((SEVERITY_LAMBDA(severity)) == ::android::base::FATAL, true) && \
-   ::android::base::ErrnoRestorer())
-
-// A variant of LOG that also logs the current errno value. To be used when
-// library calls fail.
-#define PLOG(severity)                                                           \
-  LOGGING_PREAMBLE(severity) &&                                                  \
-      ::android::base::LogMessage(__FILE__, __LINE__, SEVERITY_LAMBDA(severity), \
-                                  _LOG_TAG_INTERNAL, errno)                      \
-          .stream()
-
-// Marker that code is yet to be implemented.
-#define UNIMPLEMENTED(level) \
-  LOG(level) << __PRETTY_FUNCTION__ << " unimplemented "
-
-// Check whether condition x holds and LOG(FATAL) if not. The value of the
-// expression x is only evaluated once. Extra logging can be appended using <<
-// after. For example:
-//
-//     CHECK(false == true) results in a log message of
-//       "Check failed: false == true".
-#define CHECK(x)                                                                                 \
-  LIKELY((x)) || ABORT_AFTER_LOG_FATAL_EXPR(false) ||                                            \
-      ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::FATAL, _LOG_TAG_INTERNAL, \
-                                  -1)                                                            \
-              .stream()                                                                          \
-          << "Check failed: " #x << " "
-
-// clang-format off
-// Helper for CHECK_xx(x,y) macros.
-#define CHECK_OP(LHS, RHS, OP)                                                                   \
-  for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS);                             \
-       UNLIKELY(!(_values.lhs OP _values.rhs));                                                  \
-       /* empty */)                                                                              \
-  ABORT_AFTER_LOG_FATAL                                                                          \
-  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::FATAL, _LOG_TAG_INTERNAL, -1) \
-          .stream()                                                                              \
-      << "Check failed: " << #LHS << " " << #OP << " " << #RHS << " (" #LHS "=" << _values.lhs   \
-      << ", " #RHS "=" << _values.rhs << ") "
-// clang-format on
-
-// Check whether a condition holds between x and y, LOG(FATAL) if not. The value
-// of the expressions x and y is evaluated once. Extra logging can be appended
-// using << after. For example:
-//
-//     CHECK_NE(0 == 1, false) results in
-//       "Check failed: false != false (0==1=false, false=false) ".
-#define CHECK_EQ(x, y) CHECK_OP(x, y, == )
-#define CHECK_NE(x, y) CHECK_OP(x, y, != )
-#define CHECK_LE(x, y) CHECK_OP(x, y, <= )
-#define CHECK_LT(x, y) CHECK_OP(x, y, < )
-#define CHECK_GE(x, y) CHECK_OP(x, y, >= )
-#define CHECK_GT(x, y) CHECK_OP(x, y, > )
-
-// clang-format off
-// Helper for CHECK_STRxx(s1,s2) macros.
-#define CHECK_STROP(s1, s2, sense)                                             \
-  while (UNLIKELY((strcmp(s1, s2) == 0) != (sense)))                           \
-    ABORT_AFTER_LOG_FATAL                                                      \
-    ::android::base::LogMessage(__FILE__, __LINE__,  ::android::base::FATAL,   \
-                                 _LOG_TAG_INTERNAL, -1)                        \
-        .stream()                                                              \
-        << "Check failed: " << "\"" << (s1) << "\""                            \
-        << ((sense) ? " == " : " != ") << "\"" << (s2) << "\""
-// clang-format on
-
-// Check for string (const char*) equality between s1 and s2, LOG(FATAL) if not.
-#define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true)
-#define CHECK_STRNE(s1, s2) CHECK_STROP(s1, s2, false)
-
-// Perform the pthread function call(args), LOG(FATAL) on error.
-#define CHECK_PTHREAD_CALL(call, args, what)                           \
-  do {                                                                 \
-    int rc = call args;                                                \
-    if (rc != 0) {                                                     \
-      errno = rc;                                                      \
-      ABORT_AFTER_LOG_FATAL                                            \
-      PLOG(FATAL) << #call << " failed for " << (what);                \
-    }                                                                  \
-  } while (false)
-
-// CHECK that can be used in a constexpr function. For example:
-//
-//    constexpr int half(int n) {
-//      return
-//          DCHECK_CONSTEXPR(n >= 0, , 0)
-//          CHECK_CONSTEXPR((n & 1) == 0),
-//              << "Extra debugging output: n = " << n, 0)
-//          n / 2;
-//    }
-#define CHECK_CONSTEXPR(x, out, dummy)                                     \
-  (UNLIKELY(!(x)))                                                         \
-      ? (LOG(FATAL) << "Check failed: " << #x out, dummy) \
-      :
-
-// DCHECKs are debug variants of CHECKs only enabled in debug builds. Generally
-// CHECK should be used unless profiling identifies a CHECK as being in
-// performance critical code.
-#if defined(NDEBUG) && !defined(__clang_analyzer__)
-static constexpr bool kEnableDChecks = false;
-#else
-static constexpr bool kEnableDChecks = true;
-#endif
-
-#define DCHECK(x) \
-  if (::android::base::kEnableDChecks) CHECK(x)
-#define DCHECK_EQ(x, y) \
-  if (::android::base::kEnableDChecks) CHECK_EQ(x, y)
-#define DCHECK_NE(x, y) \
-  if (::android::base::kEnableDChecks) CHECK_NE(x, y)
-#define DCHECK_LE(x, y) \
-  if (::android::base::kEnableDChecks) CHECK_LE(x, y)
-#define DCHECK_LT(x, y) \
-  if (::android::base::kEnableDChecks) CHECK_LT(x, y)
-#define DCHECK_GE(x, y) \
-  if (::android::base::kEnableDChecks) CHECK_GE(x, y)
-#define DCHECK_GT(x, y) \
-  if (::android::base::kEnableDChecks) CHECK_GT(x, y)
-#define DCHECK_STREQ(s1, s2) \
-  if (::android::base::kEnableDChecks) CHECK_STREQ(s1, s2)
-#define DCHECK_STRNE(s1, s2) \
-  if (::android::base::kEnableDChecks) CHECK_STRNE(s1, s2)
-#if defined(NDEBUG) && !defined(__clang_analyzer__)
-#define DCHECK_CONSTEXPR(x, out, dummy)
-#else
-#define DCHECK_CONSTEXPR(x, out, dummy) CHECK_CONSTEXPR(x, out, dummy)
-#endif
-
-// Temporary class created to evaluate the LHS and RHS, used with
-// MakeEagerEvaluator to infer the types of LHS and RHS.
-template <typename LHS, typename RHS>
-struct EagerEvaluator {
-  constexpr EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) {
-  }
-  LHS lhs;
-  RHS rhs;
-};
-
-// Helper function for CHECK_xx.
-template <typename LHS, typename RHS>
-constexpr EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
-  return EagerEvaluator<LHS, RHS>(lhs, rhs);
-}
-
-// Explicitly instantiate EagerEvalue for pointers so that char*s aren't treated
-// as strings. To compare strings use CHECK_STREQ and CHECK_STRNE. We rely on
-// signed/unsigned warnings to protect you against combinations not explicitly
-// listed below.
-#define EAGER_PTR_EVALUATOR(T1, T2)               \
-  template <>                                     \
-  struct EagerEvaluator<T1, T2> {                 \
-    EagerEvaluator(T1 l, T2 r)                    \
-        : lhs(reinterpret_cast<const void*>(l)),  \
-          rhs(reinterpret_cast<const void*>(r)) { \
-    }                                             \
-    const void* lhs;                              \
-    const void* rhs;                              \
-  }
-EAGER_PTR_EVALUATOR(const char*, const char*);
-EAGER_PTR_EVALUATOR(const char*, char*);
-EAGER_PTR_EVALUATOR(char*, const char*);
-EAGER_PTR_EVALUATOR(char*, char*);
-EAGER_PTR_EVALUATOR(const unsigned char*, const unsigned char*);
-EAGER_PTR_EVALUATOR(const unsigned char*, unsigned char*);
-EAGER_PTR_EVALUATOR(unsigned char*, const unsigned char*);
-EAGER_PTR_EVALUATOR(unsigned char*, unsigned char*);
-EAGER_PTR_EVALUATOR(const signed char*, const signed char*);
-EAGER_PTR_EVALUATOR(const signed char*, signed char*);
-EAGER_PTR_EVALUATOR(signed char*, const signed char*);
-EAGER_PTR_EVALUATOR(signed char*, signed char*);
-
-// Data for the log message, not stored in LogMessage to avoid increasing the
-// stack size.
-class LogMessageData;
-
-// A LogMessage is a temporarily scoped object used by LOG and the unlikely part
-// of a CHECK. The destructor will abort if the severity is FATAL.
-class LogMessage {
- public:
-  // LogId has been deprecated, but this constructor must exist for prebuilts.
-  LogMessage(const char* file, unsigned int line, LogId, LogSeverity severity, const char* tag,
-             int error);
-  LogMessage(const char* file, unsigned int line, LogSeverity severity, const char* tag, int error);
-
-  ~LogMessage();
-
-  // Returns the stream associated with the message, the LogMessage performs
-  // output when it goes out of scope.
-  std::ostream& stream();
-
-  // The routine that performs the actual logging.
-  static void LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag,
-                      const char* msg);
-
- private:
-  const std::unique_ptr<LogMessageData> data_;
-
-  DISALLOW_COPY_AND_ASSIGN(LogMessage);
-};
-
-// Get the minimum severity level for logging.
-LogSeverity GetMinimumLogSeverity();
-
-// Set the minimum severity level for logging, returning the old severity.
-LogSeverity SetMinimumLogSeverity(LogSeverity new_severity);
-
-// Return whether or not a log message with the associated tag should be logged.
-bool ShouldLog(LogSeverity severity, const char* tag);
-
-// Allows to temporarily change the minimum severity level for logging.
-class ScopedLogSeverity {
- public:
-  explicit ScopedLogSeverity(LogSeverity level);
-  ~ScopedLogSeverity();
-
- private:
-  LogSeverity old_;
-};
-
-}  // namespace base
-}  // namespace android
-
-namespace std {  // NOLINT(cert-dcl58-cpp)
-
-// Emit a warning of ostream<< with std::string*. The intention was most likely to print *string.
-//
-// Note: for this to work, we need to have this in a namespace.
-// Note: using a pragma because "-Wgcc-compat" (included in "-Weverything") complains about
-//       diagnose_if.
-// Note: to print the pointer, use "<< static_cast<const void*>(string_pointer)" instead.
-// Note: a not-recommended alternative is to let Clang ignore the warning by adding
-//       -Wno-user-defined-warnings to CPPFLAGS.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wgcc-compat"
-#define OSTREAM_STRING_POINTER_USAGE_WARNING \
-    __attribute__((diagnose_if(true, "Unexpected logging of string pointer", "warning")))
-inline OSTREAM_STRING_POINTER_USAGE_WARNING
-std::ostream& operator<<(std::ostream& stream, const std::string* string_pointer) {
-  return stream << static_cast<const void*>(string_pointer);
-}
-#pragma clang diagnostic pop
-
-}  // namespace std
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
deleted file mode 100644
index 546b2ec..0000000
--- a/base/include/android-base/macros.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2015 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 <stddef.h>  // for size_t
-#include <unistd.h>  // for TEMP_FAILURE_RETRY
-
-#include <utility>
-
-// bionic and glibc both have TEMP_FAILURE_RETRY, but eg Mac OS' libc doesn't.
-#ifndef TEMP_FAILURE_RETRY
-#define TEMP_FAILURE_RETRY(exp)            \
-  ({                                       \
-    decltype(exp) _rc;                     \
-    do {                                   \
-      _rc = (exp);                         \
-    } while (_rc == -1 && errno == EINTR); \
-    _rc;                                   \
-  })
-#endif
-
-// A macro to disallow the copy constructor and operator= functions
-// This must be placed in the private: declarations for a class.
-//
-// For disallowing only assign or copy, delete the relevant operator or
-// constructor, for example:
-// void operator=(const TypeName&) = delete;
-// Note, that most uses of DISALLOW_ASSIGN and DISALLOW_COPY are broken
-// semantically, one should either use disallow both or neither. Try to
-// avoid these in new code.
-#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
-  TypeName(const TypeName&) = delete;      \
-  void operator=(const TypeName&) = delete
-
-// A macro to disallow all the implicit constructors, namely the
-// default constructor, copy constructor and operator= functions.
-//
-// This should be used in the private: declarations for a class
-// that wants to prevent anyone from instantiating it. This is
-// especially useful for classes containing only static methods.
-#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
-  TypeName() = delete;                           \
-  DISALLOW_COPY_AND_ASSIGN(TypeName)
-
-// The arraysize(arr) macro returns the # of elements in an array arr.
-// The expression is a compile-time constant, and therefore can be
-// used in defining new arrays, for example.  If you use arraysize on
-// a pointer by mistake, you will get a compile-time error.
-//
-// One caveat is that arraysize() doesn't accept any array of an
-// anonymous type or a type defined inside a function.  In these rare
-// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below.  This is
-// due to a limitation in C++'s template system.  The limitation might
-// eventually be removed, but it hasn't happened yet.
-
-// This template function declaration is used in defining arraysize.
-// Note that the function doesn't need an implementation, as we only
-// use its type.
-template <typename T, size_t N>
-char(&ArraySizeHelper(T(&array)[N]))[N];  // NOLINT(readability/casting)
-
-#define arraysize(array) (sizeof(ArraySizeHelper(array)))
-
-#define SIZEOF_MEMBER(t, f) sizeof(std::declval<t>().f)
-
-// Changing this definition will cause you a lot of pain.  A majority of
-// vendor code defines LIKELY and UNLIKELY this way, and includes
-// this header through an indirect path.
-#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
-#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
-
-#define WARN_UNUSED __attribute__((warn_unused_result))
-
-// A deprecated function to call to create a false use of the parameter, for
-// example:
-//   int foo(int x) { UNUSED(x); return 10; }
-// to avoid compiler warnings. Going forward we prefer ATTRIBUTE_UNUSED.
-template <typename... T>
-void UNUSED(const T&...) {
-}
-
-// An attribute to place on a parameter to a function, for example:
-//   int foo(int x ATTRIBUTE_UNUSED) { return 10; }
-// to avoid compiler warnings.
-#define ATTRIBUTE_UNUSED __attribute__((__unused__))
-
-// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through
-// between switch labels:
-//  switch (x) {
-//    case 40:
-//    case 41:
-//      if (truth_is_out_there) {
-//        ++x;
-//        FALLTHROUGH_INTENDED;  // Use instead of/along with annotations in
-//                               // comments.
-//      } else {
-//        return x;
-//      }
-//    case 42:
-//      ...
-//
-// As shown in the example above, the FALLTHROUGH_INTENDED macro should be
-// followed by a semicolon. It is designed to mimic control-flow statements
-// like 'break;', so it can be placed in most places where 'break;' can, but
-// only if there are no statements on the execution path between it and the
-// next switch label.
-//
-// When compiled with clang, the FALLTHROUGH_INTENDED macro is expanded to
-// [[clang::fallthrough]] attribute, which is analysed when performing switch
-// labels fall-through diagnostic ('-Wimplicit-fallthrough'). See clang
-// documentation on language extensions for details:
-// http://clang.llvm.org/docs/LanguageExtensions.html#clang__fallthrough
-//
-// When used with unsupported compilers, the FALLTHROUGH_INTENDED macro has no
-// effect on diagnostics.
-//
-// In either case this macro has no effect on runtime behavior and performance
-// of code.
-#ifndef FALLTHROUGH_INTENDED
-#define FALLTHROUGH_INTENDED [[clang::fallthrough]]  // NOLINT
-#endif
-
-// Current ABI string
-#if defined(__arm__)
-#define ABI_STRING "arm"
-#elif defined(__aarch64__)
-#define ABI_STRING "arm64"
-#elif defined(__i386__)
-#define ABI_STRING "x86"
-#elif defined(__x86_64__)
-#define ABI_STRING "x86_64"
-#endif
diff --git a/base/include/android-base/mapped_file.h b/base/include/android-base/mapped_file.h
deleted file mode 100644
index 8c37f43..0000000
--- a/base/include/android-base/mapped_file.h
+++ /dev/null
@@ -1,93 +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 <sys/types.h>
-
-#include <memory>
-
-#include "android-base/macros.h"
-#include "android-base/off64_t.h"
-#include "android-base/unique_fd.h"
-
-#if defined(_WIN32)
-#include <windows.h>
-#define PROT_READ 1
-#define PROT_WRITE 2
-using os_handle = HANDLE;
-#else
-#include <sys/mman.h>
-using os_handle = int;
-#endif
-
-namespace android {
-namespace base {
-
-/**
- * A region of a file mapped into memory (for grepping: also known as MmapFile or file mapping).
- */
-class MappedFile {
- public:
-  /**
-   * Creates a new mapping of the file pointed to by `fd`. Unlike the underlying OS primitives,
-   * `offset` does not need to be page-aligned. If `PROT_WRITE` is set in `prot`, the mapping
-   * will be writable, otherwise it will be read-only. Mappings are always `MAP_SHARED`.
-   */
-  static std::unique_ptr<MappedFile> FromFd(borrowed_fd fd, off64_t offset, size_t length,
-                                            int prot);
-
-  /**
-   * Same thing, but using the raw OS file handle instead of a CRT wrapper.
-   */
-  static std::unique_ptr<MappedFile> FromOsHandle(os_handle h, off64_t offset, size_t length,
-                                                  int prot);
-
-  /**
-   * Removes the mapping.
-   */
-  ~MappedFile();
-
-  /**
-   * Not copyable but movable.
-   */
-  MappedFile(MappedFile&& other);
-  MappedFile& operator=(MappedFile&& other);
-
-  char* data() const { return base_ + offset_; }
-  size_t size() const { return size_; }
-
- private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(MappedFile);
-
-  void Close();
-
-  char* base_;
-  size_t size_;
-
-  size_t offset_;
-
-#if defined(_WIN32)
-  MappedFile(char* base, size_t size, size_t offset, HANDLE handle)
-      : base_(base), size_(size), offset_(offset), handle_(handle) {}
-  HANDLE handle_;
-#else
-  MappedFile(char* base, size_t size, size_t offset) : base_(base), size_(size), offset_(offset) {}
-#endif
-};
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/memory.h b/base/include/android-base/memory.h
deleted file mode 100644
index 0277a03..0000000
--- a/base/include/android-base/memory.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2015 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
-
-namespace android {
-namespace base {
-
-// Use memcpy for access to unaligned data on targets with alignment
-// restrictions.  The compiler will generate appropriate code to access these
-// structures without generating alignment exceptions.
-template <typename T>
-static inline T get_unaligned(const void* address) {
-  T result;
-  memcpy(&result, address, sizeof(T));
-  return result;
-}
-
-template <typename T>
-static inline void put_unaligned(void* address, T v) {
-  memcpy(address, &v, sizeof(T));
-}
-
-} // namespace base
-} // namespace android
diff --git a/base/include/android-base/no_destructor.h b/base/include/android-base/no_destructor.h
deleted file mode 100644
index ce0dc9f..0000000
--- a/base/include/android-base/no_destructor.h
+++ /dev/null
@@ -1,94 +0,0 @@
-#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 <utility>
-
-#include "android-base/macros.h"
-
-namespace android {
-namespace base {
-
-// A wrapper that makes it easy to create an object of type T with static
-// storage duration that:
-// - is only constructed on first access
-// - never invokes the destructor
-// in order to satisfy the styleguide ban on global constructors and
-// destructors.
-//
-// Runtime constant example:
-// const std::string& GetLineSeparator() {
-//  // Forwards to std::string(size_t, char, const Allocator&) constructor.
-//   static const base::NoDestructor<std::string> s(5, '-');
-//   return *s;
-// }
-//
-// More complex initialization with a lambda:
-// const std::string& GetSessionNonce() {
-//   static const base::NoDestructor<std::string> nonce([] {
-//     std::string s(16);
-//     crypto::RandString(s.data(), s.size());
-//     return s;
-//   }());
-//   return *nonce;
-// }
-//
-// NoDestructor<T> stores the object inline, so it also avoids a pointer
-// indirection and a malloc. Also note that since C++11 static local variable
-// initialization is thread-safe and so is this pattern. Code should prefer to
-// use NoDestructor<T> over:
-// - A function scoped static T* or T& that is dynamically initialized.
-// - A global base::LazyInstance<T>.
-//
-// Note that since the destructor is never run, this *will* leak memory if used
-// as a stack or member variable. Furthermore, a NoDestructor<T> should never
-// have global scope as that may require a static initializer.
-template <typename T>
-class NoDestructor {
- public:
-  // Not constexpr; just write static constexpr T x = ...; if the value should
-  // be a constexpr.
-  template <typename... Args>
-  explicit NoDestructor(Args&&... args) {
-    new (storage_) T(std::forward<Args>(args)...);
-  }
-
-  // Allows copy and move construction of the contained type, to allow
-  // construction from an initializer list, e.g. for std::vector.
-  explicit NoDestructor(const T& x) { new (storage_) T(x); }
-  explicit NoDestructor(T&& x) { new (storage_) T(std::move(x)); }
-
-  NoDestructor(const NoDestructor&) = delete;
-  NoDestructor& operator=(const NoDestructor&) = delete;
-
-  ~NoDestructor() = default;
-
-  const T& operator*() const { return *get(); }
-  T& operator*() { return *get(); }
-
-  const T* operator->() const { return get(); }
-  T* operator->() { return get(); }
-
-  const T* get() const { return reinterpret_cast<const T*>(storage_); }
-  T* get() { return reinterpret_cast<T*>(storage_); }
-
- private:
-  alignas(T) char storage_[sizeof(T)];
-};
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/off64_t.h b/base/include/android-base/off64_t.h
deleted file mode 100644
index e6b71b8..0000000
--- a/base/include/android-base/off64_t.h
+++ /dev/null
@@ -1,22 +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
-
-#if defined(__APPLE__)
-/** Mac OS has always had a 64-bit off_t, so it doesn't have off64_t. */
-typedef off_t off64_t;
-#endif
diff --git a/base/include/android-base/parsebool.h b/base/include/android-base/parsebool.h
deleted file mode 100644
index b2bd021..0000000
--- a/base/include/android-base/parsebool.h
+++ /dev/null
@@ -1,58 +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 <string_view>
-
-namespace android {
-namespace base {
-
-// Parse the given string as yes or no inactivation of some sort. Return one of the
-// ParseBoolResult enumeration values.
-//
-// The following values parse as true:
-//
-//   1
-//   on
-//   true
-//   y
-//   yes
-//
-//
-// The following values parse as false:
-//
-//   0
-//   false
-//   n
-//   no
-//   off
-//
-// Anything else is a parse error.
-//
-// The purpose of this function is to have a single canonical parser for yes-or-no indications
-// throughout the system.
-
-enum class ParseBoolResult {
-  kError,
-  kFalse,
-  kTrue,
-};
-
-ParseBoolResult ParseBool(std::string_view s);
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/parsedouble.h b/base/include/android-base/parsedouble.h
deleted file mode 100644
index ccffba2..0000000
--- a/base/include/android-base/parsedouble.h
+++ /dev/null
@@ -1,77 +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.
- */
-
-#pragma once
-
-#include <errno.h>
-#include <stdlib.h>
-
-#include <limits>
-#include <string>
-
-namespace android {
-namespace base {
-
-// Parse floating value in the string 's' and sets 'out' to that value if it exists.
-// Optionally allows the caller to define a 'min' and 'max' beyond which
-// otherwise valid values will be rejected. Returns boolean success.
-template <typename T, T (*strtox)(const char* str, char** endptr)>
-static inline bool ParseFloatingPoint(const char* s, T* out, T min, T max) {
-  errno = 0;
-  char* end;
-  T result = strtox(s, &end);
-  if (errno != 0 || s == end || *end != '\0') {
-    return false;
-  }
-  if (result < min || max < result) {
-    return false;
-  }
-  if (out != nullptr) {
-    *out = result;
-  }
-  return true;
-}
-
-// Parse double value in the string 's' and sets 'out' to that value if it exists.
-// Optionally allows the caller to define a 'min' and 'max' beyond which
-// otherwise valid values will be rejected. Returns boolean success.
-static inline bool ParseDouble(const char* s, double* out,
-                               double min = std::numeric_limits<double>::lowest(),
-                               double max = std::numeric_limits<double>::max()) {
-  return ParseFloatingPoint<double, strtod>(s, out, min, max);
-}
-static inline bool ParseDouble(const std::string& s, double* out,
-                               double min = std::numeric_limits<double>::lowest(),
-                               double max = std::numeric_limits<double>::max()) {
-  return ParseFloatingPoint<double, strtod>(s.c_str(), out, min, max);
-}
-
-// Parse float value in the string 's' and sets 'out' to that value if it exists.
-// Optionally allows the caller to define a 'min' and 'max' beyond which
-// otherwise valid values will be rejected. Returns boolean success.
-static inline bool ParseFloat(const char* s, float* out,
-                              float min = std::numeric_limits<float>::lowest(),
-                              float max = std::numeric_limits<float>::max()) {
-  return ParseFloatingPoint<float, strtof>(s, out, min, max);
-}
-static inline bool ParseFloat(const std::string& s, float* out,
-                              float min = std::numeric_limits<float>::lowest(),
-                              float max = std::numeric_limits<float>::max()) {
-  return ParseFloatingPoint<float, strtof>(s.c_str(), out, min, max);
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
deleted file mode 100644
index be8b97b..0000000
--- a/base/include/android-base/parseint.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2015 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 <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <limits>
-#include <string>
-#include <type_traits>
-
-namespace android {
-namespace base {
-
-// Parses the unsigned decimal or hexadecimal integer in the string 's' and sets
-// 'out' to that value if it is specified. Optionally allows the caller to define
-// a 'max' beyond which otherwise valid values will be rejected. Returns boolean
-// success; 'out' is untouched if parsing fails.
-template <typename T>
-bool ParseUint(const char* s, T* out, T max = std::numeric_limits<T>::max(),
-               bool allow_suffixes = false) {
-  static_assert(std::is_unsigned<T>::value, "ParseUint can only be used with unsigned types");
-  while (isspace(*s)) {
-    s++;
-  }
-
-  if (s[0] == '-') {
-    errno = EINVAL;
-    return false;
-  }
-
-  int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
-  errno = 0;
-  char* end;
-  unsigned long long int result = strtoull(s, &end, base);
-  if (errno != 0) return false;
-  if (end == s) {
-    errno = EINVAL;
-    return false;
-  }
-  if (*end != '\0') {
-    const char* suffixes = "bkmgtpe";
-    const char* suffix;
-    if ((!allow_suffixes || (suffix = strchr(suffixes, tolower(*end))) == nullptr) ||
-        __builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) {
-      errno = EINVAL;
-      return false;
-    }
-  }
-  if (max < result) {
-    errno = ERANGE;
-    return false;
-  }
-  if (out != nullptr) {
-    *out = static_cast<T>(result);
-  }
-  return true;
-}
-
-// TODO: string_view
-template <typename T>
-bool ParseUint(const std::string& s, T* out, T max = std::numeric_limits<T>::max(),
-               bool allow_suffixes = false) {
-  return ParseUint(s.c_str(), out, max, allow_suffixes);
-}
-
-template <typename T>
-bool ParseByteCount(const char* s, T* out, T max = std::numeric_limits<T>::max()) {
-  return ParseUint(s, out, max, true);
-}
-
-// TODO: string_view
-template <typename T>
-bool ParseByteCount(const std::string& s, T* out, T max = std::numeric_limits<T>::max()) {
-  return ParseByteCount(s.c_str(), out, max);
-}
-
-// Parses the signed decimal or hexadecimal integer in the string 's' and sets
-// 'out' to that value if it is specified. Optionally allows the caller to define
-// a 'min' and 'max' beyond which otherwise valid values will be rejected. Returns
-// boolean success; 'out' is untouched if parsing fails.
-template <typename T>
-bool ParseInt(const char* s, T* out,
-              T min = std::numeric_limits<T>::min(),
-              T max = std::numeric_limits<T>::max()) {
-  static_assert(std::is_signed<T>::value, "ParseInt can only be used with signed types");
-  while (isspace(*s)) {
-    s++;
-  }
-
-  int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
-  errno = 0;
-  char* end;
-  long long int result = strtoll(s, &end, base);
-  if (errno != 0) {
-    return false;
-  }
-  if (s == end || *end != '\0') {
-    errno = EINVAL;
-    return false;
-  }
-  if (result < min || max < result) {
-    errno = ERANGE;
-    return false;
-  }
-  if (out != nullptr) {
-    *out = static_cast<T>(result);
-  }
-  return true;
-}
-
-// TODO: string_view
-template <typename T>
-bool ParseInt(const std::string& s, T* out,
-              T min = std::numeric_limits<T>::min(),
-              T max = std::numeric_limits<T>::max()) {
-  return ParseInt(s.c_str(), out, min, max);
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/parsenetaddress.h b/base/include/android-base/parsenetaddress.h
deleted file mode 100644
index 47f8b5f..0000000
--- a/base/include/android-base/parsenetaddress.h
+++ /dev/null
@@ -1,35 +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.
- */
-
-#pragma once
-
-#include <string>
-
-namespace android {
-namespace base {
-
-// Parses |address| into |host| and |port|.
-//
-// If |address| doesn't contain a port number, the default value is taken from
-// |port|. If |canonical_address| is non-null it will be set to "host:port" or
-// "[host]:port" as appropriate.
-//
-// On failure, returns false and fills |error|.
-bool ParseNetAddress(const std::string& address, std::string* host, int* port,
-                     std::string* canonical_address, std::string* error);
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/process.h b/base/include/android-base/process.h
deleted file mode 100644
index 69ed3fb..0000000
--- a/base/include/android-base/process.h
+++ /dev/null
@@ -1,60 +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 <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/properties.h b/base/include/android-base/properties.h
deleted file mode 100644
index 49f1f31..0000000
--- a/base/include/android-base/properties.h
+++ /dev/null
@@ -1,101 +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.
- */
-
-#pragma once
-
-#include <sys/cdefs.h>
-
-#include <chrono>
-#include <limits>
-#include <optional>
-#include <string>
-
-struct prop_info;
-
-namespace android {
-namespace base {
-
-// Returns the current value of the system property `key`,
-// or `default_value` if the property is empty or doesn't exist.
-std::string GetProperty(const std::string& key, const std::string& default_value);
-
-// Returns true if the system property `key` has the value "1", "y", "yes", "on", or "true",
-// false for "0", "n", "no", "off", or "false", or `default_value` otherwise.
-bool GetBoolProperty(const std::string& key, bool default_value);
-
-// Returns the signed integer corresponding to the system property `key`.
-// If the property is empty, doesn't exist, doesn't have an integer value, or is outside
-// the optional bounds, returns `default_value`.
-template <typename T> T GetIntProperty(const std::string& key,
-                                       T default_value,
-                                       T min = std::numeric_limits<T>::min(),
-                                       T max = std::numeric_limits<T>::max());
-
-// Returns the unsigned integer corresponding to the system property `key`.
-// If the property is empty, doesn't exist, doesn't have an integer value, or is outside
-// the optional bound, returns `default_value`.
-template <typename T> T GetUintProperty(const std::string& key,
-                                        T default_value,
-                                        T max = std::numeric_limits<T>::max());
-
-// Sets the system property `key` to `value`.
-bool SetProperty(const std::string& key, const std::string& value);
-
-// Waits for the system property `key` to have the value `expected_value`.
-// Times out after `relative_timeout`.
-// Returns true on success, false on timeout.
-#if defined(__BIONIC__)
-bool WaitForProperty(const std::string& key, const std::string& expected_value,
-                     std::chrono::milliseconds relative_timeout = std::chrono::milliseconds::max());
-#endif
-
-// Waits for the system property `key` to be created.
-// Times out after `relative_timeout`.
-// Returns true on success, false on timeout.
-#if defined(__BIONIC__)
-bool WaitForPropertyCreation(const std::string& key, std::chrono::milliseconds relative_timeout =
-                                                         std::chrono::milliseconds::max());
-#endif
-
-#if defined(__BIONIC__) && __cplusplus >= 201703L
-// Cached system property lookup. For code that needs to read the same property multiple times,
-// this class helps optimize those lookups.
-class CachedProperty {
- public:
-  explicit CachedProperty(const char* property_name);
-
-  // Returns the current value of the underlying system property as cheaply as possible.
-  // The returned pointer is valid until the next call to Get. Because most callers are going
-  // to want to parse the string returned here and cached that as well, this function performs
-  // no locking, and is completely thread unsafe. It is the caller's responsibility to provide a
-  // lock for thread-safety.
-  //
-  // Note: *changed can be set to true even if the contents of the property remain the same.
-  const char* Get(bool* changed = nullptr);
-
- private:
-  std::string property_name_;
-  const prop_info* prop_info_;
-  std::optional<uint32_t> cached_area_serial_;
-  std::optional<uint32_t> cached_property_serial_;
-  char cached_value_[92];
-  bool is_read_only_;
-  const char* read_only_property_;
-};
-#endif
-
-} // namespace base
-} // namespace android
diff --git a/base/include/android-base/result.h b/base/include/android-base/result.h
deleted file mode 100644
index 56a4f3e..0000000
--- a/base/include/android-base/result.h
+++ /dev/null
@@ -1,235 +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.
- */
-
-// This file contains classes for returning a successful result along with an optional
-// arbitrarily typed return value or for returning a failure result along with an optional string
-// indicating why the function failed.
-
-// There are 3 classes that implement this functionality and one additional helper type.
-//
-// Result<T> either contains a member of type T that can be accessed using similar semantics as
-// std::optional<T> or it contains a ResultError describing an error, which can be accessed via
-// Result<T>::error().
-//
-// ResultError is a type that contains both a std::string describing the error and a copy of errno
-// from when the error occurred.  ResultError can be used in an ostream directly to print its
-// string value.
-//
-// Result<void> is the correct return type for a function that either returns successfully or
-// returns an error value.  Returning {} from a function that returns Result<void> is the
-// correct way to indicate that a function without a return type has completed successfully.
-//
-// A successful Result<T> is constructed implicitly from any type that can be implicitly converted
-// to T or from the constructor arguments for T.  This allows you to return a type T directly from
-// a function that returns Result<T>.
-//
-// Error and ErrnoError are used to construct a Result<T> that has failed.  The Error class takes
-// an ostream as an input and are implicitly cast to a Result<T> containing that failure.
-// ErrnoError() is a helper function to create an Error class that appends ": " + strerror(errno)
-// to the end of the failure string to aid in interacting with C APIs.  Alternatively, an errno
-// value can be directly specified via the Error() constructor.
-//
-// Errorf and ErrnoErrorf accept the format string syntax of the fmblib (https://fmt.dev).
-// Errorf("{} errors", num) is equivalent to Error() << num << " errors".
-//
-// ResultError can be used in the ostream and when using Error/Errorf to construct a Result<T>.
-// In this case, the string that the ResultError takes is passed through the stream normally, but
-// the errno is passed to the Result<T>. This can be used to pass errno from a failing C function up
-// multiple callers. Note that when the outer Result<T> is created with ErrnoError/ErrnoErrorf then
-// the errno from the inner ResultError is not passed. Also when multiple ResultError objects are
-// used, the errno of the last one is respected.
-//
-// ResultError can also directly construct a Result<T>.  This is particularly useful if you have a
-// function that return Result<T> but you have a Result<U> and want to return its error.  In this
-// case, you can return the .error() from the Result<U> to construct the Result<T>.
-
-// An example of how to use these is below:
-// Result<U> CalculateResult(const T& input) {
-//   U output;
-//   if (!SomeOtherCppFunction(input, &output)) {
-//     return Errorf("SomeOtherCppFunction {} failed", input);
-//   }
-//   if (!c_api_function(output)) {
-//     return ErrnoErrorf("c_api_function {} failed", output);
-//   }
-//   return output;
-// }
-//
-// auto output = CalculateResult(input);
-// if (!output) return Error() << "CalculateResult failed: " << output.error();
-// UseOutput(*output);
-
-#pragma once
-
-#include <errno.h>
-
-#include <sstream>
-#include <string>
-
-#include "android-base/expected.h"
-#include "android-base/format.h"
-
-namespace android {
-namespace base {
-
-struct ResultError {
-  template <typename T>
-  ResultError(T&& message, int code) : message_(std::forward<T>(message)), code_(code) {}
-
-  template <typename T>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  operator android::base::expected<T, ResultError>() {
-    return android::base::unexpected(ResultError(message_, code_));
-  }
-
-  std::string message() const { return message_; }
-  int code() const { return code_; }
-
- private:
-  std::string message_;
-  int code_;
-};
-
-inline bool operator==(const ResultError& lhs, const ResultError& rhs) {
-  return lhs.message() == rhs.message() && lhs.code() == rhs.code();
-}
-
-inline bool operator!=(const ResultError& lhs, const ResultError& rhs) {
-  return !(lhs == rhs);
-}
-
-inline std::ostream& operator<<(std::ostream& os, const ResultError& t) {
-  os << t.message();
-  return os;
-}
-
-class Error {
- public:
-  Error() : errno_(0), append_errno_(false) {}
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  Error(int errno_to_append) : errno_(errno_to_append), append_errno_(true) {}
-
-  template <typename T>
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  operator android::base::expected<T, ResultError>() {
-    return android::base::unexpected(ResultError(str(), errno_));
-  }
-
-  template <typename T>
-  Error& operator<<(T&& t) {
-    // NOLINTNEXTLINE(bugprone-suspicious-semicolon)
-    if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, ResultError>) {
-      errno_ = t.code();
-      return (*this) << t.message();
-    }
-    int saved = errno;
-    ss_ << t;
-    errno = saved;
-    return *this;
-  }
-
-  const std::string str() const {
-    std::string str = ss_.str();
-    if (append_errno_) {
-      if (str.empty()) {
-        return strerror(errno_);
-      }
-      return std::move(str) + ": " + strerror(errno_);
-    }
-    return str;
-  }
-
-  Error(const Error&) = delete;
-  Error(Error&&) = delete;
-  Error& operator=(const Error&) = delete;
-  Error& operator=(Error&&) = delete;
-
-  template <typename T, typename... Args>
-  friend Error ErrorfImpl(const T&& fmt, const Args&... args);
-
-  template <typename T, typename... Args>
-  friend Error ErrnoErrorfImpl(const T&& fmt, const Args&... args);
-
- private:
-  Error(bool append_errno, int errno_to_append, const std::string& message)
-      : errno_(errno_to_append), append_errno_(append_errno) {
-    (*this) << message;
-  }
-
-  std::stringstream ss_;
-  int errno_;
-  const bool append_errno_;
-};
-
-inline Error ErrnoError() {
-  return Error(errno);
-}
-
-inline int ErrorCode(int code) {
-  return code;
-}
-
-// Return the error code of the last ResultError object, if any.
-// Otherwise, return `code` as it is.
-template <typename T, typename... Args>
-inline int ErrorCode(int code, T&& t, const Args&... args) {
-  if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, ResultError>) {
-    return ErrorCode(t.code(), args...);
-  }
-  return ErrorCode(code, args...);
-}
-
-template <typename T, typename... Args>
-inline Error ErrorfImpl(const T&& fmt, const Args&... args) {
-  return Error(false, ErrorCode(0, args...), fmt::format(fmt, args...));
-}
-
-template <typename T, typename... Args>
-inline Error ErrnoErrorfImpl(const T&& fmt, const Args&... args) {
-  return Error(true, errno, fmt::format(fmt, args...));
-}
-
-#define Errorf(fmt, ...) android::base::ErrorfImpl(FMT_STRING(fmt), ##__VA_ARGS__)
-#define ErrnoErrorf(fmt, ...) android::base::ErrnoErrorfImpl(FMT_STRING(fmt), ##__VA_ARGS__)
-
-template <typename T>
-using Result = android::base::expected<T, ResultError>;
-
-// Macros for testing the results of functions that return android::base::Result.
-// These also work with base::android::expected.
-
-#define CHECK_RESULT_OK(stmt)       \
-  do {                              \
-    const auto& tmp = (stmt);       \
-    CHECK(tmp.ok()) << tmp.error(); \
-  } while (0)
-
-#define ASSERT_RESULT_OK(stmt)            \
-  do {                                    \
-    const auto& tmp = (stmt);             \
-    ASSERT_TRUE(tmp.ok()) << tmp.error(); \
-  } while (0)
-
-#define EXPECT_RESULT_OK(stmt)            \
-  do {                                    \
-    auto tmp = (stmt);                    \
-    EXPECT_TRUE(tmp.ok()) << tmp.error(); \
-  } while (0)
-
-// TODO: Maybe add RETURN_IF_ERROR() and ASSIGN_OR_RETURN()
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/scopeguard.h b/base/include/android-base/scopeguard.h
deleted file mode 100644
index 5a224d6..0000000
--- a/base/include/android-base/scopeguard.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#pragma once
-
-#include <utility>  // for std::move, std::forward
-
-namespace android {
-namespace base {
-
-// ScopeGuard ensures that the specified functor is executed no matter how the
-// current scope exits.
-template <typename F>
-class ScopeGuard {
- public:
-  ScopeGuard(F&& f) : f_(std::forward<F>(f)), active_(true) {}
-
-  ScopeGuard(ScopeGuard&& that) noexcept : f_(std::move(that.f_)), active_(that.active_) {
-    that.active_ = false;
-  }
-
-  template <typename Functor>
-  ScopeGuard(ScopeGuard<Functor>&& that) : f_(std::move(that.f_)), active_(that.active_) {
-    that.active_ = false;
-  }
-
-  ~ScopeGuard() {
-    if (active_) f_();
-  }
-
-  ScopeGuard() = delete;
-  ScopeGuard(const ScopeGuard&) = delete;
-  void operator=(const ScopeGuard&) = delete;
-  void operator=(ScopeGuard&& that) = delete;
-
-  void Disable() { active_ = false; }
-
-  bool active() const { return active_; }
-
- private:
-  template <typename Functor>
-  friend class ScopeGuard;
-
-  F f_;
-  bool active_;
-};
-
-template <typename F>
-ScopeGuard<F> make_scope_guard(F&& f) {
-  return ScopeGuard<F>(std::forward<F>(f));
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/stringprintf.h b/base/include/android-base/stringprintf.h
deleted file mode 100644
index 93c56af..0000000
--- a/base/include/android-base/stringprintf.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2011 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 <stdarg.h>
-#include <string>
-
-namespace android {
-namespace base {
-
-// These printf-like functions are implemented in terms of vsnprintf, so they
-// use the same attribute for compile-time format string checking.
-
-// Returns a string corresponding to printf-like formatting of the arguments.
-std::string StringPrintf(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
-
-// Appends a printf-like formatting of the arguments to 'dst'.
-void StringAppendF(std::string* dst, const char* fmt, ...)
-    __attribute__((__format__(__printf__, 2, 3)));
-
-// Appends a printf-like formatting of the arguments to 'dst'.
-void StringAppendV(std::string* dst, const char* format, va_list ap)
-    __attribute__((__format__(__printf__, 2, 0)));
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h
deleted file mode 100644
index 14d534a..0000000
--- a/base/include/android-base/strings.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2015 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 <sstream>
-#include <string>
-#include <string_view>
-#include <vector>
-
-namespace android {
-namespace base {
-
-// Splits a string into a vector of strings.
-//
-// The string is split at each occurrence of a character in delimiters.
-//
-// The empty string is not a valid delimiter list.
-std::vector<std::string> Split(const std::string& s,
-                               const std::string& delimiters);
-
-// Trims whitespace off both ends of the given string.
-std::string Trim(const std::string& s);
-
-// Joins a container of things into a single string, using the given separator.
-template <typename ContainerT, typename SeparatorT>
-std::string Join(const ContainerT& things, SeparatorT separator) {
-  if (things.empty()) {
-    return "";
-  }
-
-  std::ostringstream result;
-  result << *things.begin();
-  for (auto it = std::next(things.begin()); it != things.end(); ++it) {
-    result << separator << *it;
-  }
-  return result.str();
-}
-
-// We instantiate the common cases in strings.cpp.
-extern template std::string Join(const std::vector<std::string>&, char);
-extern template std::string Join(const std::vector<const char*>&, char);
-extern template std::string Join(const std::vector<std::string>&, const std::string&);
-extern template std::string Join(const std::vector<const char*>&, const std::string&);
-
-// Tests whether 's' starts with 'prefix'.
-bool StartsWith(std::string_view s, std::string_view prefix);
-bool StartsWith(std::string_view s, char prefix);
-bool StartsWithIgnoreCase(std::string_view s, std::string_view prefix);
-
-// Tests whether 's' ends with 'suffix'.
-bool EndsWith(std::string_view s, std::string_view suffix);
-bool EndsWith(std::string_view s, char suffix);
-bool EndsWithIgnoreCase(std::string_view s, std::string_view suffix);
-
-// Tests whether 'lhs' equals 'rhs', ignoring case.
-bool EqualsIgnoreCase(std::string_view lhs, std::string_view rhs);
-
-// Removes `prefix` from the start of the given string and returns true (if
-// it was present), false otherwise.
-inline bool ConsumePrefix(std::string_view* s, std::string_view prefix) {
-  if (!StartsWith(*s, prefix)) return false;
-  s->remove_prefix(prefix.size());
-  return true;
-}
-
-// Removes `suffix` from the end of the given string and returns true (if
-// it was present), false otherwise.
-inline bool ConsumeSuffix(std::string_view* s, std::string_view suffix) {
-  if (!EndsWith(*s, suffix)) return false;
-  s->remove_suffix(suffix.size());
-  return true;
-}
-
-// Replaces `from` with `to` in `s`, once if `all == false`, or as many times as
-// there are matches if `all == true`.
-[[nodiscard]] std::string StringReplace(std::string_view s, std::string_view from,
-                                        std::string_view to, bool all);
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/test_utils.h b/base/include/android-base/test_utils.h
deleted file mode 100644
index f3d7cb0..0000000
--- a/base/include/android-base/test_utils.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2015 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 <regex>
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/macros.h>
-
-class CapturedStdFd {
- public:
-  CapturedStdFd(int std_fd);
-  ~CapturedStdFd();
-
-  std::string str();
-
-  void Start();
-  void Stop();
-  void Reset();
-
- private:
-  int fd() const;
-
-  TemporaryFile temp_file_;
-  int std_fd_;
-  int old_fd_ = -1;
-
-  DISALLOW_COPY_AND_ASSIGN(CapturedStdFd);
-};
-
-class CapturedStderr : public CapturedStdFd {
- public:
-  CapturedStderr() : CapturedStdFd(STDERR_FILENO) {}
-};
-
-class CapturedStdout : public CapturedStdFd {
- public:
-  CapturedStdout() : CapturedStdFd(STDOUT_FILENO) {}
-};
-
-#define ASSERT_MATCH(str, pattern)                                           \
-  do {                                                                       \
-    auto __s = (str);                                                        \
-    if (!std::regex_search(__s, std::regex((pattern)))) {                    \
-      FAIL() << "regex mismatch: expected " << (pattern) << " in:\n" << __s; \
-    }                                                                        \
-  } while (0)
-
-#define ASSERT_NOT_MATCH(str, pattern)                                                   \
-  do {                                                                                   \
-    auto __s = (str);                                                                    \
-    if (std::regex_search(__s, std::regex((pattern)))) {                                 \
-      FAIL() << "regex mismatch: expected to not find " << (pattern) << " in:\n" << __s; \
-    }                                                                                    \
-  } while (0)
-
-#define EXPECT_MATCH(str, pattern)                                                  \
-  do {                                                                              \
-    auto __s = (str);                                                               \
-    if (!std::regex_search(__s, std::regex((pattern)))) {                           \
-      ADD_FAILURE() << "regex mismatch: expected " << (pattern) << " in:\n" << __s; \
-    }                                                                               \
-  } while (0)
-
-#define EXPECT_NOT_MATCH(str, pattern)                                                          \
-  do {                                                                                          \
-    auto __s = (str);                                                                           \
-    if (std::regex_search(__s, std::regex((pattern)))) {                                        \
-      ADD_FAILURE() << "regex mismatch: expected to not find " << (pattern) << " in:\n" << __s; \
-    }                                                                                           \
-  } while (0)
diff --git a/base/include/android-base/thread_annotations.h b/base/include/android-base/thread_annotations.h
deleted file mode 100644
index 53fe6da..0000000
--- a/base/include/android-base/thread_annotations.h
+++ /dev/null
@@ -1,144 +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.
- */
-
-#pragma once
-
-#include <mutex>
-
-#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
-
-#define CAPABILITY(x) \
-      THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
-
-#define SCOPED_CAPABILITY \
-      THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
-
-#define SHARED_CAPABILITY(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(shared_capability(__VA_ARGS__))
-
-#define GUARDED_BY(x) \
-      THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
-
-#define PT_GUARDED_BY(x) \
-      THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
-
-#define EXCLUSIVE_LOCKS_REQUIRED(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
-
-#define SHARED_LOCKS_REQUIRED(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
-
-#define ACQUIRED_BEFORE(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
-
-#define ACQUIRED_AFTER(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
-
-#define REQUIRES(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
-
-#define REQUIRES_SHARED(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
-
-#define ACQUIRE(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
-
-#define ACQUIRE_SHARED(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
-
-#define RELEASE(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
-
-#define RELEASE_SHARED(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
-
-#define TRY_ACQUIRE(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
-
-#define TRY_ACQUIRE_SHARED(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
-
-#define EXCLUDES(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
-
-#define ASSERT_CAPABILITY(x) \
-      THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
-
-#define ASSERT_SHARED_CAPABILITY(x) \
-      THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
-
-#define RETURN_CAPABILITY(x) \
-      THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
-
-#define EXCLUSIVE_LOCK_FUNCTION(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
-
-#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
-
-#define SHARED_LOCK_FUNCTION(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
-
-#define SHARED_TRYLOCK_FUNCTION(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
-
-#define UNLOCK_FUNCTION(...) \
-      THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
-
-#define SCOPED_LOCKABLE \
-      THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
-
-#define LOCK_RETURNED(x) \
-      THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
-
-#define NO_THREAD_SAFETY_ANALYSIS \
-      THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
-
-namespace android {
-namespace base {
-
-// A class to help thread safety analysis deal with std::unique_lock and condition_variable.
-//
-// Clang's thread safety analysis currently doesn't perform alias analysis, so movable types
-// like std::unique_lock can't be marked with thread safety annotations. This helper allows
-// for manual assertion of lock state in a scope.
-//
-// For example:
-//
-//   std::mutex mutex;
-//   std::condition_variable cv;
-//   std::vector<int> vec GUARDED_BY(mutex);
-//
-//   int pop() {
-//     std::unique_lock lock(mutex);
-//     ScopedLockAssertion lock_assertion(mutex);
-//     cv.wait(lock, []() {
-//       ScopedLockAssertion lock_assertion(mutex);
-//       return !vec.empty();
-//     });
-//
-//     int result = vec.back();
-//     vec.pop_back();
-//     return result;
-//   }
-class SCOPED_CAPABILITY ScopedLockAssertion {
- public:
-  ScopedLockAssertion(std::mutex& mutex) ACQUIRE(mutex) {}
-  ~ScopedLockAssertion() RELEASE() {}
-};
-
-}  // namespace base
-}  // namespace android
diff --git a/base/include/android-base/threads.h b/base/include/android-base/threads.h
deleted file mode 100644
index dba1fc6..0000000
--- a/base/include/android-base/threads.h
+++ /dev/null
@@ -1,30 +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 <stdint.h>
-
-namespace android {
-namespace base {
-uint64_t GetThreadId();
-}
-}  // namespace android
-
-#if defined(__GLIBC__)
-// bionic has this Linux-specifix call, but glibc doesn't.
-extern "C" int tgkill(int tgid, int tid, int sig);
-#endif
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
deleted file mode 100644
index 9ceb5db..0000000
--- a/base/include/android-base/unique_fd.h
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2015 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 <errno.h>
-#include <fcntl.h>
-
-#if !defined(_WIN32)
-#include <sys/socket.h>
-#endif
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-// DO NOT INCLUDE OTHER LIBBASE HEADERS!
-// This file gets used in libbinder, and libbinder is used everywhere.
-// Including other headers from libbase frequently results in inclusion of
-// android-base/macros.h, which causes macro collisions.
-
-// Container for a file descriptor that automatically closes the descriptor as
-// it goes out of scope.
-//
-//      unique_fd ufd(open("/some/path", "r"));
-//      if (ufd.get() == -1) return error;
-//
-//      // Do something useful, possibly including 'return'.
-//
-//      return 0; // Descriptor is closed for you.
-//
-// unique_fd is also known as ScopedFd/ScopedFD/scoped_fd; mentioned here to help
-// you find this class if you're searching for one of those names.
-
-#if defined(__BIONIC__)
-#include <android/fdsan.h>
-#endif
-
-namespace android {
-namespace base {
-
-struct DefaultCloser {
-#if defined(__BIONIC__)
-  static void Tag(int fd, void* old_addr, void* new_addr) {
-    if (android_fdsan_exchange_owner_tag) {
-      uint64_t old_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
-                                                        reinterpret_cast<uint64_t>(old_addr));
-      uint64_t new_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
-                                                        reinterpret_cast<uint64_t>(new_addr));
-      android_fdsan_exchange_owner_tag(fd, old_tag, new_tag);
-    }
-  }
-  static void Close(int fd, void* addr) {
-    if (android_fdsan_close_with_tag) {
-      uint64_t tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
-                                                    reinterpret_cast<uint64_t>(addr));
-      android_fdsan_close_with_tag(fd, tag);
-    } else {
-      close(fd);
-    }
-  }
-#else
-  static void Close(int fd) {
-    // Even if close(2) fails with EINTR, the fd will have been closed.
-    // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone
-    // else's fd.
-    // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
-    ::close(fd);
-  }
-#endif
-};
-
-template <typename Closer>
-class unique_fd_impl final {
- public:
-  unique_fd_impl() {}
-
-  explicit unique_fd_impl(int fd) { reset(fd); }
-  ~unique_fd_impl() { reset(); }
-
-  unique_fd_impl(const unique_fd_impl&) = delete;
-  void operator=(const unique_fd_impl&) = delete;
-  unique_fd_impl(unique_fd_impl&& other) noexcept { reset(other.release()); }
-  unique_fd_impl& operator=(unique_fd_impl&& s) noexcept {
-    int fd = s.fd_;
-    s.fd_ = -1;
-    reset(fd, &s);
-    return *this;
-  }
-
-  [[clang::reinitializes]] void reset(int new_value = -1) { reset(new_value, nullptr); }
-
-  int get() const { return fd_; }
-
-#if !defined(ANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION)
-  // unique_fd's operator int is dangerous, but we have way too much code that
-  // depends on it, so make this opt-in at first.
-  operator int() const { return get(); }  // NOLINT
-#endif
-
-  bool operator>=(int rhs) const { return get() >= rhs; }
-  bool operator<(int rhs) const { return get() < rhs; }
-  bool operator==(int rhs) const { return get() == rhs; }
-  bool operator!=(int rhs) const { return get() != rhs; }
-  bool operator==(const unique_fd_impl& rhs) const { return get() == rhs.get(); }
-  bool operator!=(const unique_fd_impl& rhs) const { return get() != rhs.get(); }
-
-  // Catch bogus error checks (i.e.: "!fd" instead of "fd != -1").
-  bool operator!() const = delete;
-
-  bool ok() const { return get() >= 0; }
-
-  int release() __attribute__((warn_unused_result)) {
-    tag(fd_, this, nullptr);
-    int ret = fd_;
-    fd_ = -1;
-    return ret;
-  }
-
- private:
-  void reset(int new_value, void* previous_tag) {
-    int previous_errno = errno;
-
-    if (fd_ != -1) {
-      close(fd_, this);
-    }
-
-    fd_ = new_value;
-    if (new_value != -1) {
-      tag(new_value, previous_tag, this);
-    }
-
-    errno = previous_errno;
-  }
-
-  int fd_ = -1;
-
-  // Template magic to use Closer::Tag if available, and do nothing if not.
-  // If Closer::Tag exists, this implementation is preferred, because int is a better match.
-  // If not, this implementation is SFINAEd away, and the no-op below is the only one that exists.
-  template <typename T = Closer>
-  static auto tag(int fd, void* old_tag, void* new_tag)
-      -> decltype(T::Tag(fd, old_tag, new_tag), void()) {
-    T::Tag(fd, old_tag, new_tag);
-  }
-
-  template <typename T = Closer>
-  static void tag(long, void*, void*) {
-    // No-op.
-  }
-
-  // Same as above, to select between Closer::Close(int) and Closer::Close(int, void*).
-  template <typename T = Closer>
-  static auto close(int fd, void* tag_value) -> decltype(T::Close(fd, tag_value), void()) {
-    T::Close(fd, tag_value);
-  }
-
-  template <typename T = Closer>
-  static auto close(int fd, void*) -> decltype(T::Close(fd), void()) {
-    T::Close(fd);
-  }
-};
-
-using unique_fd = unique_fd_impl<DefaultCloser>;
-
-#if !defined(_WIN32)
-
-// Inline functions, so that they can be used header-only.
-template <typename Closer>
-inline bool Pipe(unique_fd_impl<Closer>* read, unique_fd_impl<Closer>* write,
-                 int flags = O_CLOEXEC) {
-  int pipefd[2];
-
-#if defined(__linux__)
-  if (pipe2(pipefd, flags) != 0) {
-    return false;
-  }
-#else  // defined(__APPLE__)
-  if (flags & ~(O_CLOEXEC | O_NONBLOCK)) {
-    return false;
-  }
-  if (pipe(pipefd) != 0) {
-    return false;
-  }
-
-  if (flags & O_CLOEXEC) {
-    if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) != 0 || fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) != 0) {
-      close(pipefd[0]);
-      close(pipefd[1]);
-      return false;
-    }
-  }
-  if (flags & O_NONBLOCK) {
-    if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) != 0 || fcntl(pipefd[1], F_SETFL, O_NONBLOCK) != 0) {
-      close(pipefd[0]);
-      close(pipefd[1]);
-      return false;
-    }
-  }
-#endif
-
-  read->reset(pipefd[0]);
-  write->reset(pipefd[1]);
-  return true;
-}
-
-template <typename Closer>
-inline bool Socketpair(int domain, int type, int protocol, unique_fd_impl<Closer>* left,
-                       unique_fd_impl<Closer>* right) {
-  int sockfd[2];
-  if (socketpair(domain, type, protocol, sockfd) != 0) {
-    return false;
-  }
-  left->reset(sockfd[0]);
-  right->reset(sockfd[1]);
-  return true;
-}
-
-template <typename Closer>
-inline bool Socketpair(int type, unique_fd_impl<Closer>* left, unique_fd_impl<Closer>* right) {
-  return Socketpair(AF_UNIX, type, 0, left, right);
-}
-
-// Using fdopen with unique_fd correctly is more annoying than it should be,
-// because fdopen doesn't close the file descriptor received upon failure.
-inline FILE* Fdopen(unique_fd&& ufd, const char* mode) {
-  int fd = ufd.release();
-  FILE* file = fdopen(fd, mode);
-  if (!file) {
-    close(fd);
-  }
-  return file;
-}
-
-// Using fdopendir with unique_fd correctly is more annoying than it should be,
-// because fdopen doesn't close the file descriptor received upon failure.
-inline DIR* Fdopendir(unique_fd&& ufd) {
-  int fd = ufd.release();
-  DIR* dir = fdopendir(fd);
-  if (dir == nullptr) {
-    close(fd);
-  }
-  return dir;
-}
-
-#endif  // !defined(_WIN32)
-
-// A wrapper type that can be implicitly constructed from either int or unique_fd.
-struct borrowed_fd {
-  /* implicit */ borrowed_fd(int fd) : fd_(fd) {}  // NOLINT
-  template <typename T>
-  /* implicit */ borrowed_fd(const unique_fd_impl<T>& ufd) : fd_(ufd.get()) {}  // NOLINT
-
-  int get() const { return fd_; }
-
-  bool operator>=(int rhs) const { return get() >= rhs; }
-  bool operator<(int rhs) const { return get() < rhs; }
-  bool operator==(int rhs) const { return get() == rhs; }
-  bool operator!=(int rhs) const { return get() != rhs; }
-
- private:
-  int fd_ = -1;
-};
-}  // namespace base
-}  // namespace android
-
-template <typename T>
-int close(const android::base::unique_fd_impl<T>&)
-    __attribute__((__unavailable__("close called on unique_fd")));
-
-template <typename T>
-FILE* fdopen(const android::base::unique_fd_impl<T>&, const char* mode)
-    __attribute__((__unavailable__("fdopen takes ownership of the fd passed in; either dup the "
-                                   "unique_fd, or use android::base::Fdopen to pass ownership")));
-
-template <typename T>
-DIR* fdopendir(const android::base::unique_fd_impl<T>&) __attribute__((
-    __unavailable__("fdopendir takes ownership of the fd passed in; either dup the "
-                    "unique_fd, or use android::base::Fdopendir to pass ownership")));
diff --git a/base/include/android-base/utf8.h b/base/include/android-base/utf8.h
deleted file mode 100644
index 1a414ec..0000000
--- a/base/include/android-base/utf8.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2015 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
-
-#ifdef _WIN32
-#include <sys/types.h>
-#include <string>
-#else
-// Bring in prototypes for standard APIs so that we can import them into the utf8 namespace.
-#include <fcntl.h>      // open
-#include <stdio.h>      // fopen
-#include <sys/stat.h>   // mkdir
-#include <unistd.h>     // unlink
-#endif
-
-namespace android {
-namespace base {
-
-// Only available on Windows because this is only needed on Windows.
-#ifdef _WIN32
-// Convert size number of UTF-16 wchar_t's to UTF-8. Returns whether the
-// conversion was done successfully.
-bool WideToUTF8(const wchar_t* utf16, const size_t size, std::string* utf8);
-
-// Convert a NULL-terminated string of UTF-16 characters to UTF-8. Returns
-// whether the conversion was done successfully.
-bool WideToUTF8(const wchar_t* utf16, std::string* utf8);
-
-// Convert a UTF-16 std::wstring (including any embedded NULL characters) to
-// UTF-8. Returns whether the conversion was done successfully.
-bool WideToUTF8(const std::wstring& utf16, std::string* utf8);
-
-// Convert size number of UTF-8 char's to UTF-16. Returns whether the conversion
-// was done successfully.
-bool UTF8ToWide(const char* utf8, const size_t size, std::wstring* utf16);
-
-// Convert a NULL-terminated string of UTF-8 characters to UTF-16. Returns
-// whether the conversion was done successfully.
-bool UTF8ToWide(const char* utf8, std::wstring* utf16);
-
-// Convert a UTF-8 std::string (including any embedded NULL characters) to
-// UTF-16. Returns whether the conversion was done successfully.
-bool UTF8ToWide(const std::string& utf8, std::wstring* utf16);
-
-// Convert a file system path, represented as a NULL-terminated string of
-// UTF-8 characters, to a UTF-16 string representing the same file system
-// path using the Windows extended-lengh path representation.
-//
-// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#MAXPATH:
-//   ```The Windows API has many functions that also have Unicode versions to
-//   permit an extended-length path for a maximum total path length of 32,767
-//   characters. To specify an extended-length path, use the "\\?\" prefix.
-//   For example, "\\?\D:\very long path".```
-//
-// Returns whether the conversion was done successfully.
-bool UTF8PathToWindowsLongPath(const char* utf8, std::wstring* utf16);
-#endif
-
-// The functions in the utf8 namespace take UTF-8 strings. For Windows, these
-// are wrappers, for non-Windows these just expose existing APIs. To call these
-// functions, use:
-//
-// // anonymous namespace to avoid conflict with existing open(), unlink(), etc.
-// namespace {
-//   // Import functions into anonymous namespace.
-//   using namespace android::base::utf8;
-//
-//   void SomeFunction(const char* name) {
-//     int fd = open(name, ...);  // Calls android::base::utf8::open().
-//     ...
-//     unlink(name);              // Calls android::base::utf8::unlink().
-//   }
-// }
-namespace utf8 {
-
-#ifdef _WIN32
-FILE* fopen(const char* name, const char* mode);
-int mkdir(const char* name, mode_t mode);
-int open(const char* name, int flags, ...);
-int unlink(const char* name);
-#else
-using ::fopen;
-using ::mkdir;
-using ::open;
-using ::unlink;
-#endif
-
-}  // namespace utf8
-}  // namespace base
-}  // namespace android
diff --git a/base/liblog_symbols.cpp b/base/liblog_symbols.cpp
deleted file mode 100644
index 1f4b69b..0000000
--- a/base/liblog_symbols.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2020 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 "liblog_symbols.h"
-
-#if defined(__ANDROID_SDK_VERSION__) && (__ANDROID_SDK_VERSION__ <= 29)
-#define USE_DLSYM
-#endif
-
-#ifdef USE_DLSYM
-#include <dlfcn.h>
-#endif
-
-namespace android {
-namespace base {
-
-#ifdef USE_DLSYM
-
-const std::optional<LibLogFunctions>& GetLibLogFunctions() {
-  static std::optional<LibLogFunctions> liblog_functions = []() -> std::optional<LibLogFunctions> {
-    void* liblog_handle = dlopen("liblog.so", RTLD_NOW);
-    if (liblog_handle == nullptr) {
-      return {};
-    }
-
-    LibLogFunctions real_liblog_functions = {};
-
-#define DLSYM(name)                                                                   \
-  real_liblog_functions.name =                                                        \
-      reinterpret_cast<decltype(LibLogFunctions::name)>(dlsym(liblog_handle, #name)); \
-  if (real_liblog_functions.name == nullptr) {                                        \
-    return {};                                                                        \
-  }
-
-    DLSYM(__android_log_set_logger)
-    DLSYM(__android_log_write_log_message)
-    DLSYM(__android_log_logd_logger)
-    DLSYM(__android_log_stderr_logger)
-    DLSYM(__android_log_set_aborter)
-    DLSYM(__android_log_call_aborter)
-    DLSYM(__android_log_default_aborter)
-    DLSYM(__android_log_set_minimum_priority);
-    DLSYM(__android_log_get_minimum_priority);
-    DLSYM(__android_log_set_default_tag);
-#undef DLSYM
-
-    return real_liblog_functions;
-  }();
-
-  return liblog_functions;
-}
-
-#else
-
-const std::optional<LibLogFunctions>& GetLibLogFunctions() {
-  static std::optional<LibLogFunctions> liblog_functions = []() -> std::optional<LibLogFunctions> {
-    return LibLogFunctions{
-        .__android_log_set_logger = __android_log_set_logger,
-        .__android_log_write_log_message = __android_log_write_log_message,
-        .__android_log_logd_logger = __android_log_logd_logger,
-        .__android_log_stderr_logger = __android_log_stderr_logger,
-        .__android_log_set_aborter = __android_log_set_aborter,
-        .__android_log_call_aborter = __android_log_call_aborter,
-        .__android_log_default_aborter = __android_log_default_aborter,
-        .__android_log_set_minimum_priority = __android_log_set_minimum_priority,
-        .__android_log_get_minimum_priority = __android_log_get_minimum_priority,
-        .__android_log_set_default_tag = __android_log_set_default_tag,
-    };
-  }();
-  return liblog_functions;
-}
-
-#endif
-
-}  // namespace base
-}  // namespace android
diff --git a/base/liblog_symbols.h b/base/liblog_symbols.h
deleted file mode 100644
index 2e6b47f..0000000
--- a/base/liblog_symbols.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2020 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 <optional>
-
-#include <android/log.h>
-
-namespace android {
-namespace base {
-
-struct LibLogFunctions {
-  void (*__android_log_set_logger)(__android_logger_function logger);
-  void (*__android_log_write_log_message)(struct __android_log_message* log_message);
-
-  void (*__android_log_logd_logger)(const struct __android_log_message* log_message);
-  void (*__android_log_stderr_logger)(const struct __android_log_message* log_message);
-
-  void (*__android_log_set_aborter)(__android_aborter_function aborter);
-  void (*__android_log_call_aborter)(const char* abort_message);
-  void (*__android_log_default_aborter)(const char* abort_message);
-  int32_t (*__android_log_set_minimum_priority)(int32_t priority);
-  int32_t (*__android_log_get_minimum_priority)();
-  void (*__android_log_set_default_tag)(const char* tag);
-};
-
-const std::optional<LibLogFunctions>& GetLibLogFunctions();
-
-}  // namespace base
-}  // namespace android
diff --git a/base/logging.cpp b/base/logging.cpp
deleted file mode 100644
index 6e9c67f..0000000
--- a/base/logging.cpp
+++ /dev/null
@@ -1,585 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#if defined(_WIN32)
-#include <windows.h>
-#endif
-
-#include "android-base/logging.h"
-
-#include <fcntl.h>
-#include <inttypes.h>
-#include <libgen.h>
-#include <time.h>
-
-// For getprogname(3) or program_invocation_short_name.
-#if defined(__ANDROID__) || defined(__APPLE__)
-#include <stdlib.h>
-#elif defined(__GLIBC__)
-#include <errno.h>
-#endif
-
-#if defined(__linux__)
-#include <sys/uio.h>
-#endif
-
-#include <atomic>
-#include <iostream>
-#include <limits>
-#include <mutex>
-#include <optional>
-#include <sstream>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <android/log.h>
-#ifdef __ANDROID__
-#include <android/set_abort_message.h>
-#else
-#include <sys/types.h>
-#include <unistd.h>
-#endif
-
-#include <android-base/file.h>
-#include <android-base/macros.h>
-#include <android-base/parseint.h>
-#include <android-base/strings.h>
-#include <android-base/threads.h>
-
-#include "liblog_symbols.h"
-#include "logging_splitters.h"
-
-namespace android {
-namespace base {
-
-// BSD-based systems like Android/macOS have getprogname(). Others need us to provide one.
-#if defined(__GLIBC__) || defined(_WIN32)
-static const char* getprogname() {
-#if defined(__GLIBC__)
-  return program_invocation_short_name;
-#elif defined(_WIN32)
-  static bool first = true;
-  static char progname[MAX_PATH] = {};
-
-  if (first) {
-    snprintf(progname, sizeof(progname), "%s",
-             android::base::Basename(android::base::GetExecutablePath()).c_str());
-    first = false;
-  }
-
-  return progname;
-#endif
-}
-#endif
-
-static const char* GetFileBasename(const char* file) {
-  // We can't use basename(3) even on Unix because the Mac doesn't
-  // have a non-modifying basename.
-  const char* last_slash = strrchr(file, '/');
-  if (last_slash != nullptr) {
-    return last_slash + 1;
-  }
-#if defined(_WIN32)
-  const char* last_backslash = strrchr(file, '\\');
-  if (last_backslash != nullptr) {
-    return last_backslash + 1;
-  }
-#endif
-  return file;
-}
-
-#if defined(__linux__)
-static int OpenKmsg() {
-#if defined(__ANDROID__)
-  // pick up 'file w /dev/kmsg' environment from daemon's init rc file
-  const auto val = getenv("ANDROID_FILE__dev_kmsg");
-  if (val != nullptr) {
-    int fd;
-    if (android::base::ParseInt(val, &fd, 0)) {
-      auto flags = fcntl(fd, F_GETFL);
-      if ((flags != -1) && ((flags & O_ACCMODE) == O_WRONLY)) return fd;
-    }
-  }
-#endif
-  return TEMP_FAILURE_RETRY(open("/dev/kmsg", O_WRONLY | O_CLOEXEC));
-}
-#endif
-
-static LogId log_id_tToLogId(int32_t buffer_id) {
-  switch (buffer_id) {
-    case LOG_ID_MAIN:
-      return MAIN;
-    case LOG_ID_SYSTEM:
-      return SYSTEM;
-    case LOG_ID_RADIO:
-      return RADIO;
-    case LOG_ID_CRASH:
-      return CRASH;
-    case LOG_ID_DEFAULT:
-    default:
-      return DEFAULT;
-  }
-}
-
-static int32_t LogIdTolog_id_t(LogId log_id) {
-  switch (log_id) {
-    case MAIN:
-      return LOG_ID_MAIN;
-    case SYSTEM:
-      return LOG_ID_SYSTEM;
-    case RADIO:
-      return LOG_ID_RADIO;
-    case CRASH:
-      return LOG_ID_CRASH;
-    case DEFAULT:
-    default:
-      return LOG_ID_DEFAULT;
-  }
-}
-
-static LogSeverity PriorityToLogSeverity(int priority) {
-  switch (priority) {
-    case ANDROID_LOG_DEFAULT:
-      return INFO;
-    case ANDROID_LOG_VERBOSE:
-      return VERBOSE;
-    case ANDROID_LOG_DEBUG:
-      return DEBUG;
-    case ANDROID_LOG_INFO:
-      return INFO;
-    case ANDROID_LOG_WARN:
-      return WARNING;
-    case ANDROID_LOG_ERROR:
-      return ERROR;
-    case ANDROID_LOG_FATAL:
-      return FATAL;
-    default:
-      return FATAL;
-  }
-}
-
-static int32_t LogSeverityToPriority(LogSeverity severity) {
-  switch (severity) {
-    case VERBOSE:
-      return ANDROID_LOG_VERBOSE;
-    case DEBUG:
-      return ANDROID_LOG_DEBUG;
-    case INFO:
-      return ANDROID_LOG_INFO;
-    case WARNING:
-      return ANDROID_LOG_WARN;
-    case ERROR:
-      return ANDROID_LOG_ERROR;
-    case FATAL_WITHOUT_ABORT:
-    case FATAL:
-    default:
-      return ANDROID_LOG_FATAL;
-  }
-}
-
-static LogFunction& Logger() {
-#ifdef __ANDROID__
-  static auto& logger = *new LogFunction(LogdLogger());
-#else
-  static auto& logger = *new LogFunction(StderrLogger);
-#endif
-  return logger;
-}
-
-static AbortFunction& Aborter() {
-  static auto& aborter = *new AbortFunction(DefaultAborter);
-  return aborter;
-}
-
-// Only used for Q fallback.
-static std::recursive_mutex& TagLock() {
-  static auto& tag_lock = *new std::recursive_mutex();
-  return tag_lock;
-}
-// Only used for Q fallback.
-static std::string* gDefaultTag;
-
-void SetDefaultTag(const std::string& tag) {
-  static auto& liblog_functions = GetLibLogFunctions();
-  if (liblog_functions) {
-    liblog_functions->__android_log_set_default_tag(tag.c_str());
-  } else {
-    std::lock_guard<std::recursive_mutex> lock(TagLock());
-    if (gDefaultTag != nullptr) {
-      delete gDefaultTag;
-      gDefaultTag = nullptr;
-    }
-    if (!tag.empty()) {
-      gDefaultTag = new std::string(tag);
-    }
-  }
-}
-
-static bool gInitialized = false;
-
-// Only used for Q fallback.
-static LogSeverity gMinimumLogSeverity = INFO;
-
-#if defined(__linux__)
-static void KernelLogLine(const char* msg, int length, android::base::LogSeverity severity,
-                          const char* tag) {
-  // clang-format off
-  static constexpr int kLogSeverityToKernelLogLevel[] = {
-      [android::base::VERBOSE] = 7,              // KERN_DEBUG (there is no verbose kernel log
-                                                 //             level)
-      [android::base::DEBUG] = 7,                // KERN_DEBUG
-      [android::base::INFO] = 6,                 // KERN_INFO
-      [android::base::WARNING] = 4,              // KERN_WARNING
-      [android::base::ERROR] = 3,                // KERN_ERROR
-      [android::base::FATAL_WITHOUT_ABORT] = 2,  // KERN_CRIT
-      [android::base::FATAL] = 2,                // KERN_CRIT
-  };
-  // clang-format on
-  static_assert(arraysize(kLogSeverityToKernelLogLevel) == android::base::FATAL + 1,
-                "Mismatch in size of kLogSeverityToKernelLogLevel and values in LogSeverity");
-
-  static int klog_fd = OpenKmsg();
-  if (klog_fd == -1) return;
-
-  int level = kLogSeverityToKernelLogLevel[severity];
-
-  // The kernel's printk buffer is only 1024 bytes.
-  // TODO: should we automatically break up long lines into multiple lines?
-  // Or we could log but with something like "..." at the end?
-  char buf[1024];
-  size_t size = snprintf(buf, sizeof(buf), "<%d>%s: %.*s\n", level, tag, length, msg);
-  if (size > sizeof(buf)) {
-    size = snprintf(buf, sizeof(buf), "<%d>%s: %zu-byte message too long for printk\n",
-                    level, tag, size);
-  }
-
-  iovec iov[1];
-  iov[0].iov_base = buf;
-  iov[0].iov_len = size;
-  TEMP_FAILURE_RETRY(writev(klog_fd, iov, 1));
-}
-
-void KernelLogger(android::base::LogId, android::base::LogSeverity severity, const char* tag,
-                  const char*, unsigned int, const char* full_message) {
-  SplitByLines(full_message, KernelLogLine, severity, tag);
-}
-#endif
-
-void StderrLogger(LogId, LogSeverity severity, const char* tag, const char* file, unsigned int line,
-                  const char* message) {
-  struct tm now;
-  time_t t = time(nullptr);
-
-#if defined(_WIN32)
-  localtime_s(&now, &t);
-#else
-  localtime_r(&t, &now);
-#endif
-  auto output_string =
-      StderrOutputGenerator(now, getpid(), GetThreadId(), severity, tag, file, line, message);
-
-  fputs(output_string.c_str(), stderr);
-}
-
-void StdioLogger(LogId, LogSeverity severity, const char* /*tag*/, const char* /*file*/,
-                 unsigned int /*line*/, const char* message) {
-  if (severity >= WARNING) {
-    fflush(stdout);
-    fprintf(stderr, "%s: %s\n", GetFileBasename(getprogname()), message);
-  } else {
-    fprintf(stdout, "%s\n", message);
-  }
-}
-
-void DefaultAborter(const char* abort_message) {
-#ifdef __ANDROID__
-  android_set_abort_message(abort_message);
-#else
-  UNUSED(abort_message);
-#endif
-  abort();
-}
-
-static void LogdLogChunk(LogId id, LogSeverity severity, const char* tag, const char* message) {
-  int32_t lg_id = LogIdTolog_id_t(id);
-  int32_t priority = LogSeverityToPriority(severity);
-
-  static auto& liblog_functions = GetLibLogFunctions();
-  if (liblog_functions) {
-    __android_log_message log_message = {sizeof(__android_log_message),     lg_id, priority, tag,
-                                         static_cast<const char*>(nullptr), 0,     message};
-    liblog_functions->__android_log_logd_logger(&log_message);
-  } else {
-    __android_log_buf_print(lg_id, priority, tag, "%s", message);
-  }
-}
-
-LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) {}
-
-void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag, const char* file,
-                            unsigned int line, const char* message) {
-  if (id == DEFAULT) {
-    id = default_log_id_;
-  }
-
-  SplitByLogdChunks(id, severity, tag, file, line, message, LogdLogChunk);
-}
-
-void InitLogging(char* argv[], LogFunction&& logger, AbortFunction&& aborter) {
-  SetLogger(std::forward<LogFunction>(logger));
-  SetAborter(std::forward<AbortFunction>(aborter));
-
-  if (gInitialized) {
-    return;
-  }
-
-  gInitialized = true;
-
-  // Stash the command line for later use. We can use /proc/self/cmdline on
-  // Linux to recover this, but we don't have that luxury on the Mac/Windows,
-  // and there are a couple of argv[0] variants that are commonly used.
-  if (argv != nullptr) {
-    SetDefaultTag(basename(argv[0]));
-  }
-
-  const char* tags = getenv("ANDROID_LOG_TAGS");
-  if (tags == nullptr) {
-    return;
-  }
-
-  std::vector<std::string> specs = Split(tags, " ");
-  for (size_t i = 0; i < specs.size(); ++i) {
-    // "tag-pattern:[vdiwefs]"
-    std::string spec(specs[i]);
-    if (spec.size() == 3 && StartsWith(spec, "*:")) {
-      switch (spec[2]) {
-        case 'v':
-          SetMinimumLogSeverity(VERBOSE);
-          continue;
-        case 'd':
-          SetMinimumLogSeverity(DEBUG);
-          continue;
-        case 'i':
-          SetMinimumLogSeverity(INFO);
-          continue;
-        case 'w':
-          SetMinimumLogSeverity(WARNING);
-          continue;
-        case 'e':
-          SetMinimumLogSeverity(ERROR);
-          continue;
-        case 'f':
-          SetMinimumLogSeverity(FATAL_WITHOUT_ABORT);
-          continue;
-        // liblog will even suppress FATAL if you say 's' for silent, but that's
-        // crazy!
-        case 's':
-          SetMinimumLogSeverity(FATAL_WITHOUT_ABORT);
-          continue;
-      }
-    }
-    LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags
-               << ")";
-  }
-}
-
-void SetLogger(LogFunction&& logger) {
-  Logger() = std::move(logger);
-
-  static auto& liblog_functions = GetLibLogFunctions();
-  if (liblog_functions) {
-    liblog_functions->__android_log_set_logger([](const struct __android_log_message* log_message) {
-      auto log_id = log_id_tToLogId(log_message->buffer_id);
-      auto severity = PriorityToLogSeverity(log_message->priority);
-
-      Logger()(log_id, severity, log_message->tag, log_message->file, log_message->line,
-               log_message->message);
-    });
-  }
-}
-
-void SetAborter(AbortFunction&& aborter) {
-  Aborter() = std::move(aborter);
-
-  static auto& liblog_functions = GetLibLogFunctions();
-  if (liblog_functions) {
-    liblog_functions->__android_log_set_aborter(
-        [](const char* abort_message) { Aborter()(abort_message); });
-  }
-}
-
-// This indirection greatly reduces the stack impact of having lots of
-// checks/logging in a function.
-class LogMessageData {
- public:
-  LogMessageData(const char* file, unsigned int line, LogSeverity severity, const char* tag,
-                 int error)
-      : file_(GetFileBasename(file)),
-        line_number_(line),
-        severity_(severity),
-        tag_(tag),
-        error_(error) {}
-
-  const char* GetFile() const {
-    return file_;
-  }
-
-  unsigned int GetLineNumber() const {
-    return line_number_;
-  }
-
-  LogSeverity GetSeverity() const {
-    return severity_;
-  }
-
-  const char* GetTag() const { return tag_; }
-
-  int GetError() const {
-    return error_;
-  }
-
-  std::ostream& GetBuffer() {
-    return buffer_;
-  }
-
-  std::string ToString() const {
-    return buffer_.str();
-  }
-
- private:
-  std::ostringstream buffer_;
-  const char* const file_;
-  const unsigned int line_number_;
-  const LogSeverity severity_;
-  const char* const tag_;
-  const int error_;
-
-  DISALLOW_COPY_AND_ASSIGN(LogMessageData);
-};
-
-LogMessage::LogMessage(const char* file, unsigned int line, LogId, LogSeverity severity,
-                       const char* tag, int error)
-    : LogMessage(file, line, severity, tag, error) {}
-
-LogMessage::LogMessage(const char* file, unsigned int line, LogSeverity severity, const char* tag,
-                       int error)
-    : data_(new LogMessageData(file, line, severity, tag, error)) {}
-
-LogMessage::~LogMessage() {
-  // Check severity again. This is duplicate work wrt/ LOG macros, but not LOG_STREAM.
-  if (!WOULD_LOG(data_->GetSeverity())) {
-    return;
-  }
-
-  // Finish constructing the message.
-  if (data_->GetError() != -1) {
-    data_->GetBuffer() << ": " << strerror(data_->GetError());
-  }
-  std::string msg(data_->ToString());
-
-  if (data_->GetSeverity() == FATAL) {
-#ifdef __ANDROID__
-    // Set the bionic abort message early to avoid liblog doing it
-    // with the individual lines, so that we get the whole message.
-    android_set_abort_message(msg.c_str());
-#endif
-  }
-
-  LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), data_->GetTag(),
-          msg.c_str());
-
-  // Abort if necessary.
-  if (data_->GetSeverity() == FATAL) {
-    static auto& liblog_functions = GetLibLogFunctions();
-    if (liblog_functions) {
-      liblog_functions->__android_log_call_aborter(msg.c_str());
-    } else {
-      Aborter()(msg.c_str());
-    }
-  }
-}
-
-std::ostream& LogMessage::stream() {
-  return data_->GetBuffer();
-}
-
-void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag,
-                         const char* message) {
-  static auto& liblog_functions = GetLibLogFunctions();
-  int32_t priority = LogSeverityToPriority(severity);
-  if (liblog_functions) {
-    __android_log_message log_message = {
-        sizeof(__android_log_message), LOG_ID_DEFAULT, priority, tag, file, line, message};
-    liblog_functions->__android_log_write_log_message(&log_message);
-  } else {
-    if (tag == nullptr) {
-      std::lock_guard<std::recursive_mutex> lock(TagLock());
-      if (gDefaultTag == nullptr) {
-        gDefaultTag = new std::string(getprogname());
-      }
-
-      Logger()(DEFAULT, severity, gDefaultTag->c_str(), file, line, message);
-    } else {
-      Logger()(DEFAULT, severity, tag, file, line, message);
-    }
-  }
-}
-
-LogSeverity GetMinimumLogSeverity() {
-  static auto& liblog_functions = GetLibLogFunctions();
-  if (liblog_functions) {
-    return PriorityToLogSeverity(liblog_functions->__android_log_get_minimum_priority());
-  } else {
-    return gMinimumLogSeverity;
-  }
-}
-
-bool ShouldLog(LogSeverity severity, const char* tag) {
-  static auto& liblog_functions = GetLibLogFunctions();
-  // Even though we're not using the R liblog functions in this function, if we're running on Q,
-  // we need to fall back to using gMinimumLogSeverity, since __android_log_is_loggable() will not
-  // take into consideration the value from SetMinimumLogSeverity().
-  if (liblog_functions) {
-    int32_t priority = LogSeverityToPriority(severity);
-    return __android_log_is_loggable(priority, tag, ANDROID_LOG_INFO);
-  } else {
-    return severity >= gMinimumLogSeverity;
-  }
-}
-
-LogSeverity SetMinimumLogSeverity(LogSeverity new_severity) {
-  static auto& liblog_functions = GetLibLogFunctions();
-  if (liblog_functions) {
-    int32_t priority = LogSeverityToPriority(new_severity);
-    return PriorityToLogSeverity(liblog_functions->__android_log_set_minimum_priority(priority));
-  } else {
-    LogSeverity old_severity = gMinimumLogSeverity;
-    gMinimumLogSeverity = new_severity;
-    return old_severity;
-  }
-}
-
-ScopedLogSeverity::ScopedLogSeverity(LogSeverity new_severity) {
-  old_ = SetMinimumLogSeverity(new_severity);
-}
-
-ScopedLogSeverity::~ScopedLogSeverity() {
-  SetMinimumLogSeverity(old_);
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/logging_splitters.h b/base/logging_splitters.h
deleted file mode 100644
index 2ec2b20..0000000
--- a/base/logging_splitters.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2020 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 <inttypes.h>
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-
-#define LOGGER_ENTRY_MAX_PAYLOAD 4068  // This constant is not in the NDK.
-
-namespace android {
-namespace base {
-
-// This splits the message up line by line, by calling log_function with a pointer to the start of
-// each line and the size up to the newline character.  It sends size = -1 for the final line.
-template <typename F, typename... Args>
-static void SplitByLines(const char* msg, const F& log_function, Args&&... args) {
-  const char* newline = strchr(msg, '\n');
-  while (newline != nullptr) {
-    log_function(msg, newline - msg, args...);
-    msg = newline + 1;
-    newline = strchr(msg, '\n');
-  }
-
-  log_function(msg, -1, args...);
-}
-
-// This splits the message up into chunks that logs can process delimited by new lines.  It calls
-// log_function with the exact null terminated message that should be sent to logd.
-// Note, despite the loops and snprintf's, if severity is not fatal and there are no new lines,
-// this function simply calls log_function with msg without any extra overhead.
-template <typename F>
-static void SplitByLogdChunks(LogId log_id, LogSeverity severity, const char* tag, const char* file,
-                              unsigned int line, const char* msg, const F& log_function) {
-  // The maximum size of a payload, after the log header that logd will accept is
-  // LOGGER_ENTRY_MAX_PAYLOAD, so subtract the other elements in the payload to find the size of
-  // the string that we can log in each pass.
-  // The protocol is documented in liblog/README.protocol.md.
-  // Specifically we subtract a byte for the priority, the length of the tag + its null terminator,
-  // and an additional byte for the null terminator on the payload.  We subtract an additional 32
-  // bytes for slack, similar to java/android/util/Log.java.
-  ptrdiff_t max_size = LOGGER_ENTRY_MAX_PAYLOAD - strlen(tag) - 35;
-  if (max_size <= 0) {
-    abort();
-  }
-  // If we're logging a fatal message, we'll append the file and line numbers.
-  bool add_file = file != nullptr && (severity == FATAL || severity == FATAL_WITHOUT_ABORT);
-
-  std::string file_header;
-  if (add_file) {
-    file_header = StringPrintf("%s:%u] ", file, line);
-  }
-  int file_header_size = file_header.size();
-
-  __attribute__((uninitialized)) char logd_chunk[max_size + 1];
-  ptrdiff_t chunk_position = 0;
-
-  auto call_log_function = [&]() {
-    log_function(log_id, severity, tag, logd_chunk);
-    chunk_position = 0;
-  };
-
-  auto write_to_logd_chunk = [&](const char* message, int length) {
-    int size_written = 0;
-    const char* new_line = chunk_position > 0 ? "\n" : "";
-    if (add_file) {
-      size_written = snprintf(logd_chunk + chunk_position, sizeof(logd_chunk) - chunk_position,
-                              "%s%s%.*s", new_line, file_header.c_str(), length, message);
-    } else {
-      size_written = snprintf(logd_chunk + chunk_position, sizeof(logd_chunk) - chunk_position,
-                              "%s%.*s", new_line, length, message);
-    }
-
-    // This should never fail, if it does and we set size_written to 0, which will skip this line
-    // and move to the next one.
-    if (size_written < 0) {
-      size_written = 0;
-    }
-    chunk_position += size_written;
-  };
-
-  const char* newline = strchr(msg, '\n');
-  while (newline != nullptr) {
-    // If we have data in the buffer and this next line doesn't fit, write the buffer.
-    if (chunk_position != 0 && chunk_position + (newline - msg) + 1 + file_header_size > max_size) {
-      call_log_function();
-    }
-
-    // Otherwise, either the next line fits or we have any empty buffer and too large of a line to
-    // ever fit, in both cases, we add it to the buffer and continue.
-    write_to_logd_chunk(msg, newline - msg);
-
-    msg = newline + 1;
-    newline = strchr(msg, '\n');
-  }
-
-  // If we have left over data in the buffer and we can fit the rest of msg, add it to the buffer
-  // then write the buffer.
-  if (chunk_position != 0 &&
-      chunk_position + static_cast<int>(strlen(msg)) + 1 + file_header_size <= max_size) {
-    write_to_logd_chunk(msg, -1);
-    call_log_function();
-  } else {
-    // If the buffer is not empty and we can't fit the rest of msg into it, write its contents.
-    if (chunk_position != 0) {
-      call_log_function();
-    }
-    // Then write the rest of the msg.
-    if (add_file) {
-      snprintf(logd_chunk, sizeof(logd_chunk), "%s%s", file_header.c_str(), msg);
-      log_function(log_id, severity, tag, logd_chunk);
-    } else {
-      log_function(log_id, severity, tag, msg);
-    }
-  }
-}
-
-static std::pair<int, int> CountSizeAndNewLines(const char* message) {
-  int size = 0;
-  int new_lines = 0;
-  while (*message != '\0') {
-    size++;
-    if (*message == '\n') {
-      ++new_lines;
-    }
-    ++message;
-  }
-  return {size, new_lines};
-}
-
-// This adds the log header to each line of message and returns it as a string intended to be
-// written to stderr.
-static std::string StderrOutputGenerator(const struct tm& now, int pid, uint64_t tid,
-                                         LogSeverity severity, const char* tag, const char* file,
-                                         unsigned int line, const char* message) {
-  char timestamp[32];
-  strftime(timestamp, sizeof(timestamp), "%m-%d %H:%M:%S", &now);
-
-  static const char log_characters[] = "VDIWEFF";
-  static_assert(arraysize(log_characters) - 1 == FATAL + 1,
-                "Mismatch in size of log_characters and values in LogSeverity");
-  char severity_char = log_characters[severity];
-  std::string line_prefix;
-  if (file != nullptr) {
-    line_prefix = StringPrintf("%s %c %s %5d %5" PRIu64 " %s:%u] ", tag ? tag : "nullptr",
-                               severity_char, timestamp, pid, tid, file, line);
-  } else {
-    line_prefix = StringPrintf("%s %c %s %5d %5" PRIu64 " ", tag ? tag : "nullptr", severity_char,
-                               timestamp, pid, tid);
-  }
-
-  auto [size, new_lines] = CountSizeAndNewLines(message);
-  std::string output_string;
-  output_string.reserve(size + new_lines * line_prefix.size() + 1);
-
-  auto concat_lines = [&](const char* message, int size) {
-    output_string.append(line_prefix);
-    if (size == -1) {
-      output_string.append(message);
-    } else {
-      output_string.append(message, size);
-    }
-    output_string.append("\n");
-  };
-  SplitByLines(message, concat_lines);
-  return output_string;
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/logging_splitters_test.cpp b/base/logging_splitters_test.cpp
deleted file mode 100644
index 679d19e..0000000
--- a/base/logging_splitters_test.cpp
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright (C) 2020 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 "logging_splitters.h"
-
-#include <string>
-#include <vector>
-
-#include <android-base/strings.h>
-#include <gtest/gtest.h>
-
-namespace android {
-namespace base {
-
-void TestNewlineSplitter(const std::string& input,
-                         const std::vector<std::string>& expected_output) {
-  std::vector<std::string> output;
-  auto logger_function = [&](const char* msg, int length) {
-    if (length == -1) {
-      output.push_back(msg);
-    } else {
-      output.push_back(std::string(msg, length));
-    }
-  };
-  SplitByLines(input.c_str(), logger_function);
-
-  EXPECT_EQ(expected_output, output);
-}
-
-TEST(logging_splitters, NewlineSplitter_EmptyString) {
-  TestNewlineSplitter("", std::vector<std::string>{""});
-}
-
-TEST(logging_splitters, NewlineSplitter_BasicString) {
-  TestNewlineSplitter("normal string", std::vector<std::string>{"normal string"});
-}
-
-TEST(logging_splitters, NewlineSplitter_ormalBasicStringTrailingNewline) {
-  TestNewlineSplitter("normal string\n", std::vector<std::string>{"normal string", ""});
-}
-
-TEST(logging_splitters, NewlineSplitter_MultilineTrailing) {
-  TestNewlineSplitter("normal string\nsecond string\nthirdstring",
-                      std::vector<std::string>{"normal string", "second string", "thirdstring"});
-}
-
-TEST(logging_splitters, NewlineSplitter_MultilineTrailingNewline) {
-  TestNewlineSplitter(
-      "normal string\nsecond string\nthirdstring\n",
-      std::vector<std::string>{"normal string", "second string", "thirdstring", ""});
-}
-
-TEST(logging_splitters, NewlineSplitter_MultilineEmbeddedNewlines) {
-  TestNewlineSplitter(
-      "normal string\n\n\nsecond string\n\nthirdstring\n",
-      std::vector<std::string>{"normal string", "", "", "second string", "", "thirdstring", ""});
-}
-
-void TestLogdChunkSplitter(const std::string& tag, const std::string& file,
-                           const std::string& input,
-                           const std::vector<std::string>& expected_output) {
-  std::vector<std::string> output;
-  auto logger_function = [&](LogId, LogSeverity, const char*, const char* msg) {
-    output.push_back(msg);
-  };
-
-  SplitByLogdChunks(MAIN, FATAL, tag.c_str(), file.empty() ? nullptr : file.c_str(), 1000,
-                    input.c_str(), logger_function);
-
-  auto return_lengths = [&] {
-    std::string sizes;
-    sizes += "expected_output sizes:";
-    for (const auto& string : expected_output) {
-      sizes += " " + std::to_string(string.size());
-    }
-    sizes += "\noutput sizes:";
-    for (const auto& string : output) {
-      sizes += " " + std::to_string(string.size());
-    }
-    return sizes;
-  };
-
-  EXPECT_EQ(expected_output, output) << return_lengths();
-}
-
-TEST(logging_splitters, LogdChunkSplitter_EmptyString) {
-  TestLogdChunkSplitter("tag", "", "", std::vector<std::string>{""});
-}
-
-TEST(logging_splitters, LogdChunkSplitter_BasicString) {
-  TestLogdChunkSplitter("tag", "", "normal string", std::vector<std::string>{"normal string"});
-}
-
-TEST(logging_splitters, LogdChunkSplitter_NormalBasicStringTrailingNewline) {
-  TestLogdChunkSplitter("tag", "", "normal string\n", std::vector<std::string>{"normal string\n"});
-}
-
-TEST(logging_splitters, LogdChunkSplitter_MultilineTrailing) {
-  TestLogdChunkSplitter("tag", "", "normal string\nsecond string\nthirdstring",
-                        std::vector<std::string>{"normal string\nsecond string\nthirdstring"});
-}
-
-TEST(logging_splitters, LogdChunkSplitter_MultilineTrailingNewline) {
-  TestLogdChunkSplitter("tag", "", "normal string\nsecond string\nthirdstring\n",
-                        std::vector<std::string>{"normal string\nsecond string\nthirdstring\n"});
-}
-
-TEST(logging_splitters, LogdChunkSplitter_MultilineEmbeddedNewlines) {
-  TestLogdChunkSplitter(
-      "tag", "", "normal string\n\n\nsecond string\n\nthirdstring\n",
-      std::vector<std::string>{"normal string\n\n\nsecond string\n\nthirdstring\n"});
-}
-
-// This test should return the same string, the logd logger itself will truncate down to size.
-// This has historically been the behavior both in libbase and liblog.
-TEST(logging_splitters, LogdChunkSplitter_HugeLineNoNewline) {
-  auto long_string = std::string(LOGGER_ENTRY_MAX_PAYLOAD, 'x');
-  ASSERT_EQ(LOGGER_ENTRY_MAX_PAYLOAD, static_cast<int>(long_string.size()));
-
-  TestLogdChunkSplitter("tag", "", long_string, std::vector{long_string});
-}
-
-std::string ReduceToMaxSize(const std::string& tag, const std::string& string) {
-  return string.substr(0, LOGGER_ENTRY_MAX_PAYLOAD - tag.size() - 35);
-}
-
-TEST(logging_splitters, LogdChunkSplitter_MultipleHugeLineNoNewline) {
-  auto long_string_x = std::string(LOGGER_ENTRY_MAX_PAYLOAD, 'x');
-  auto long_string_y = std::string(LOGGER_ENTRY_MAX_PAYLOAD, 'y');
-  auto long_string_z = std::string(LOGGER_ENTRY_MAX_PAYLOAD, 'z');
-
-  auto long_strings = long_string_x + '\n' + long_string_y + '\n' + long_string_z;
-
-  std::string tag = "tag";
-  std::vector expected = {ReduceToMaxSize(tag, long_string_x), ReduceToMaxSize(tag, long_string_y),
-                          long_string_z};
-
-  TestLogdChunkSplitter(tag, "", long_strings, expected);
-}
-
-// With a ~4k buffer, we should print 2 long strings per logger call.
-TEST(logging_splitters, LogdChunkSplitter_Multiple2kLines) {
-  std::vector expected = {
-      std::string(2000, 'a') + '\n' + std::string(2000, 'b'),
-      std::string(2000, 'c') + '\n' + std::string(2000, 'd'),
-      std::string(2000, 'e') + '\n' + std::string(2000, 'f'),
-  };
-
-  auto long_strings = Join(expected, '\n');
-
-  TestLogdChunkSplitter("tag", "", long_strings, expected);
-}
-
-TEST(logging_splitters, LogdChunkSplitter_ExactSizedLines) {
-  const char* tag = "tag";
-  ptrdiff_t max_size = LOGGER_ENTRY_MAX_PAYLOAD - strlen(tag) - 35;
-  auto long_string_a = std::string(max_size, 'a');
-  auto long_string_b = std::string(max_size, 'b');
-  auto long_string_c = std::string(max_size, 'c');
-
-  auto long_strings = long_string_a + '\n' + long_string_b + '\n' + long_string_c;
-
-  TestLogdChunkSplitter(tag, "", long_strings,
-                        std::vector{long_string_a, long_string_b, long_string_c});
-}
-
-TEST(logging_splitters, LogdChunkSplitter_UnderEqualOver) {
-  std::string tag = "tag";
-  ptrdiff_t max_size = LOGGER_ENTRY_MAX_PAYLOAD - tag.size() - 35;
-
-  auto first_string_size = 1000;
-  auto first_string = std::string(first_string_size, 'a');
-  auto second_string_size = max_size - first_string_size - 1;
-  auto second_string = std::string(second_string_size, 'b');
-
-  auto exact_string = std::string(max_size, 'c');
-
-  auto large_string = std::string(max_size + 50, 'd');
-
-  auto final_string = std::string("final string!\n\nfinal \n \n final \n");
-
-  std::vector expected = {first_string + '\n' + second_string, exact_string,
-                          ReduceToMaxSize(tag, large_string), final_string};
-
-  std::vector input_strings = {first_string + '\n' + second_string, exact_string, large_string,
-                               final_string};
-  auto long_strings = Join(input_strings, '\n');
-
-  TestLogdChunkSplitter(tag, "", long_strings, expected);
-}
-
-TEST(logging_splitters, LogdChunkSplitter_WithFile) {
-  std::string tag = "tag";
-  std::string file = "/path/to/myfile.cpp";
-  int line = 1000;
-  auto file_header = StringPrintf("%s:%d] ", file.c_str(), line);
-  ptrdiff_t max_size = LOGGER_ENTRY_MAX_PAYLOAD - tag.size() - 35;
-
-  auto first_string_size = 1000;
-  auto first_string = std::string(first_string_size, 'a');
-  auto second_string_size = max_size - first_string_size - 1 - 2 * file_header.size();
-  auto second_string = std::string(second_string_size, 'b');
-
-  auto exact_string = std::string(max_size - file_header.size(), 'c');
-
-  auto large_string = std::string(max_size + 50, 'd');
-
-  auto final_string = std::string("final string!");
-
-  std::vector expected = {
-      file_header + first_string + '\n' + file_header + second_string, file_header + exact_string,
-      file_header + ReduceToMaxSize(file_header + tag, large_string), file_header + final_string};
-
-  std::vector input_strings = {first_string + '\n' + second_string, exact_string, large_string,
-                               final_string};
-  auto long_strings = Join(input_strings, '\n');
-
-  TestLogdChunkSplitter(tag, file, long_strings, expected);
-}
-
-// We set max_size based off of tag, so if it's too large, the buffer will be sized wrong.
-// We could recover from this, but it's certainly an error for someone to attempt to use a tag this
-// large, so we abort instead.
-TEST(logging_splitters, LogdChunkSplitter_TooLongTag) {
-  auto long_tag = std::string(5000, 'x');
-  auto logger_function = [](LogId, LogSeverity, const char*, const char*) {};
-  ASSERT_DEATH(
-      SplitByLogdChunks(MAIN, ERROR, long_tag.c_str(), nullptr, 0, "message", logger_function), "");
-}
-
-// We do handle excessively large file names correctly however.
-TEST(logging_splitters, LogdChunkSplitter_TooLongFile) {
-  auto long_file = std::string(5000, 'x');
-  std::string tag = "tag";
-
-  std::vector expected = {ReduceToMaxSize(tag, long_file), ReduceToMaxSize(tag, long_file)};
-
-  TestLogdChunkSplitter(tag, long_file, "can't see me\nor me", expected);
-}
-
-void TestStderrOutputGenerator(const char* tag, const char* file, int line, const char* message,
-                               const std::string& expected) {
-  // All log messages will show "01-01 00:00:00"
-  struct tm now = {
-      .tm_sec = 0,
-      .tm_min = 0,
-      .tm_hour = 0,
-      .tm_mday = 1,
-      .tm_mon = 0,
-      .tm_year = 1970,
-  };
-
-  int pid = 1234;       // All log messages will have 1234 for their PID.
-  uint64_t tid = 4321;  // All log messages will have 4321 for their TID.
-
-  auto result = StderrOutputGenerator(now, pid, tid, ERROR, tag, file, line, message);
-  EXPECT_EQ(expected, result);
-}
-
-TEST(logging_splitters, StderrOutputGenerator_Basic) {
-  TestStderrOutputGenerator(nullptr, nullptr, 0, "simple message",
-                            "nullptr E 01-01 00:00:00  1234  4321 simple message\n");
-  TestStderrOutputGenerator("tag", nullptr, 0, "simple message",
-                            "tag E 01-01 00:00:00  1234  4321 simple message\n");
-  TestStderrOutputGenerator(
-      "tag", "/path/to/some/file", 0, "simple message",
-      "tag E 01-01 00:00:00  1234  4321 /path/to/some/file:0] simple message\n");
-}
-
-TEST(logging_splitters, StderrOutputGenerator_NewlineTagAndFile) {
-  TestStderrOutputGenerator("tag\n\n", nullptr, 0, "simple message",
-                            "tag\n\n E 01-01 00:00:00  1234  4321 simple message\n");
-  TestStderrOutputGenerator(
-      "tag", "/path/to/some/file\n\n", 0, "simple message",
-      "tag E 01-01 00:00:00  1234  4321 /path/to/some/file\n\n:0] simple message\n");
-}
-
-TEST(logging_splitters, StderrOutputGenerator_TrailingNewLine) {
-  TestStderrOutputGenerator(
-      "tag", nullptr, 0, "simple message\n",
-      "tag E 01-01 00:00:00  1234  4321 simple message\ntag E 01-01 00:00:00  1234  4321 \n");
-}
-
-TEST(logging_splitters, StderrOutputGenerator_MultiLine) {
-  const char* expected_result =
-      "tag E 01-01 00:00:00  1234  4321 simple message\n"
-      "tag E 01-01 00:00:00  1234  4321 \n"
-      "tag E 01-01 00:00:00  1234  4321 \n"
-      "tag E 01-01 00:00:00  1234  4321 another message \n"
-      "tag E 01-01 00:00:00  1234  4321 \n"
-      "tag E 01-01 00:00:00  1234  4321  final message \n"
-      "tag E 01-01 00:00:00  1234  4321 \n"
-      "tag E 01-01 00:00:00  1234  4321 \n"
-      "tag E 01-01 00:00:00  1234  4321 \n";
-
-  TestStderrOutputGenerator("tag", nullptr, 0,
-                            "simple message\n\n\nanother message \n\n final message \n\n\n",
-                            expected_result);
-}
-
-TEST(logging_splitters, StderrOutputGenerator_MultiLineLong) {
-  auto long_string_a = std::string(4000, 'a');
-  auto long_string_b = std::string(4000, 'b');
-
-  auto message = long_string_a + '\n' + long_string_b;
-  auto expected_result = "tag E 01-01 00:00:00  1234  4321 " + long_string_a + '\n' +
-                         "tag E 01-01 00:00:00  1234  4321 " + long_string_b + '\n';
-  TestStderrOutputGenerator("tag", nullptr, 0, message.c_str(), expected_result);
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
deleted file mode 100644
index 593e2c1..0000000
--- a/base/logging_test.cpp
+++ /dev/null
@@ -1,673 +0,0 @@
-/*
- * Copyright (C) 2015 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 "android-base/logging.h"
-
-#include <libgen.h>
-
-#if defined(_WIN32)
-#include <signal.h>
-#endif
-
-#include <regex>
-#include <string>
-#include <thread>
-
-#include "android-base/file.h"
-#include "android-base/scopeguard.h"
-#include "android-base/stringprintf.h"
-#include "android-base/test_utils.h"
-
-#include <gtest/gtest.h>
-
-#ifdef __ANDROID__
-#define HOST_TEST(suite, name) TEST(suite, DISABLED_ ## name)
-#else
-#define HOST_TEST(suite, name) TEST(suite, name)
-#endif
-
-#if defined(_WIN32)
-static void ExitSignalAbortHandler(int) {
-  _exit(3);
-}
-#endif
-
-static void SuppressAbortUI() {
-#if defined(_WIN32)
-  // We really just want to call _set_abort_behavior(0, _CALL_REPORTFAULT) to
-  // suppress the Windows Error Reporting dialog box, but that API is not
-  // available in the OS-supplied C Runtime, msvcrt.dll, that we currently
-  // use (it is available in the Visual Studio C runtime).
-  //
-  // Instead, we setup a SIGABRT handler, which is called in abort() right
-  // before calling Windows Error Reporting. In the handler, we exit the
-  // process just like abort() does.
-  ASSERT_NE(SIG_ERR, signal(SIGABRT, ExitSignalAbortHandler));
-#endif
-}
-
-TEST(logging, CHECK) {
-  ASSERT_DEATH({SuppressAbortUI(); CHECK(false);}, "Check failed: false ");
-  CHECK(true);
-
-  ASSERT_DEATH({SuppressAbortUI(); CHECK_EQ(0, 1);}, "Check failed: 0 == 1 ");
-  CHECK_EQ(0, 0);
-
-  ASSERT_DEATH({SuppressAbortUI(); CHECK_STREQ("foo", "bar");},
-               R"(Check failed: "foo" == "bar")");
-  CHECK_STREQ("foo", "foo");
-
-  // Test whether CHECK() and CHECK_STREQ() have a dangling if with no else.
-  bool flag = false;
-  if (true)
-    CHECK(true);
-  else
-    flag = true;
-  EXPECT_FALSE(flag) << "CHECK macro probably has a dangling if with no else";
-
-  flag = false;
-  if (true)
-    CHECK_STREQ("foo", "foo");
-  else
-    flag = true;
-  EXPECT_FALSE(flag) << "CHECK_STREQ probably has a dangling if with no else";
-}
-
-TEST(logging, DCHECK) {
-  if (android::base::kEnableDChecks) {
-    ASSERT_DEATH({SuppressAbortUI(); DCHECK(false);}, "DCheck failed: false ");
-  }
-  DCHECK(true);
-
-  if (android::base::kEnableDChecks) {
-    ASSERT_DEATH({SuppressAbortUI(); DCHECK_EQ(0, 1);}, "DCheck failed: 0 == 1 ");
-  }
-  DCHECK_EQ(0, 0);
-
-  if (android::base::kEnableDChecks) {
-    ASSERT_DEATH({SuppressAbortUI(); DCHECK_STREQ("foo", "bar");},
-                 R"(DCheck failed: "foo" == "bar")");
-  }
-  DCHECK_STREQ("foo", "foo");
-
-  // No testing whether we have a dangling else, possibly. That's inherent to the if (constexpr)
-  // setup we intentionally chose to force type-checks of debug code even in release builds (so
-  // we don't get more bit-rot).
-}
-
-
-#define CHECK_WOULD_LOG_DISABLED(severity)                                               \
-  static_assert(android::base::severity < android::base::FATAL, "Bad input");            \
-  for (size_t i = static_cast<size_t>(android::base::severity) + 1;                      \
-       i <= static_cast<size_t>(android::base::FATAL);                                   \
-       ++i) {                                                                            \
-    {                                                                                    \
-      android::base::ScopedLogSeverity sls2(static_cast<android::base::LogSeverity>(i)); \
-      EXPECT_FALSE(WOULD_LOG(severity)) << i;                                            \
-    }                                                                                    \
-    {                                                                                    \
-      android::base::ScopedLogSeverity sls2(static_cast<android::base::LogSeverity>(i)); \
-      EXPECT_FALSE(WOULD_LOG(::android::base::severity)) << i;                           \
-    }                                                                                    \
-  }                                                                                      \
-
-#define CHECK_WOULD_LOG_ENABLED(severity)                                                \
-  for (size_t i = static_cast<size_t>(android::base::VERBOSE);                           \
-       i <= static_cast<size_t>(android::base::severity);                                \
-       ++i) {                                                                            \
-    {                                                                                    \
-      android::base::ScopedLogSeverity sls2(static_cast<android::base::LogSeverity>(i)); \
-      EXPECT_TRUE(WOULD_LOG(severity)) << i;                                             \
-    }                                                                                    \
-    {                                                                                    \
-      android::base::ScopedLogSeverity sls2(static_cast<android::base::LogSeverity>(i)); \
-      EXPECT_TRUE(WOULD_LOG(::android::base::severity)) << i;                            \
-    }                                                                                    \
-  }                                                                                      \
-
-TEST(logging, WOULD_LOG_FATAL) {
-  CHECK_WOULD_LOG_ENABLED(FATAL);
-}
-
-TEST(logging, WOULD_LOG_FATAL_WITHOUT_ABORT_enabled) {
-  CHECK_WOULD_LOG_ENABLED(FATAL_WITHOUT_ABORT);
-}
-
-TEST(logging, WOULD_LOG_ERROR_disabled) {
-  CHECK_WOULD_LOG_DISABLED(ERROR);
-}
-
-TEST(logging, WOULD_LOG_ERROR_enabled) {
-  CHECK_WOULD_LOG_ENABLED(ERROR);
-}
-
-TEST(logging, WOULD_LOG_WARNING_disabled) {
-  CHECK_WOULD_LOG_DISABLED(WARNING);
-}
-
-TEST(logging, WOULD_LOG_WARNING_enabled) {
-  CHECK_WOULD_LOG_ENABLED(WARNING);
-}
-
-TEST(logging, WOULD_LOG_INFO_disabled) {
-  CHECK_WOULD_LOG_DISABLED(INFO);
-}
-
-TEST(logging, WOULD_LOG_INFO_enabled) {
-  CHECK_WOULD_LOG_ENABLED(INFO);
-}
-
-TEST(logging, WOULD_LOG_DEBUG_disabled) {
-  CHECK_WOULD_LOG_DISABLED(DEBUG);
-}
-
-TEST(logging, WOULD_LOG_DEBUG_enabled) {
-  CHECK_WOULD_LOG_ENABLED(DEBUG);
-}
-
-TEST(logging, WOULD_LOG_VERBOSE_disabled) {
-  CHECK_WOULD_LOG_DISABLED(VERBOSE);
-}
-
-TEST(logging, WOULD_LOG_VERBOSE_enabled) {
-  CHECK_WOULD_LOG_ENABLED(VERBOSE);
-}
-
-#undef CHECK_WOULD_LOG_DISABLED
-#undef CHECK_WOULD_LOG_ENABLED
-
-
-#if !defined(_WIN32)
-static std::string make_log_pattern(android::base::LogSeverity severity,
-                                    const char* message) {
-  static const char log_characters[] = "VDIWEFF";
-  static_assert(arraysize(log_characters) - 1 == android::base::FATAL + 1,
-                "Mismatch in size of log_characters and values in LogSeverity");
-  char log_char = log_characters[severity];
-  std::string holder(__FILE__);
-  return android::base::StringPrintf(
-      "%c \\d+-\\d+ \\d+:\\d+:\\d+ \\s*\\d+ \\s*\\d+ %s:\\d+] %s",
-      log_char, basename(&holder[0]), message);
-}
-#endif
-
-static void CheckMessage(const std::string& output, android::base::LogSeverity severity,
-                         const char* expected, const char* expected_tag = nullptr) {
-  // We can't usefully check the output of any of these on Windows because we
-  // don't have std::regex, but we can at least make sure we printed at least as
-  // many characters are in the log message.
-  ASSERT_GT(output.length(), strlen(expected));
-  ASSERT_NE(nullptr, strstr(output.c_str(), expected)) << output;
-  if (expected_tag != nullptr) {
-    ASSERT_NE(nullptr, strstr(output.c_str(), expected_tag)) << output;
-  }
-
-#if !defined(_WIN32)
-  std::string regex_str;
-  if (expected_tag != nullptr) {
-    regex_str.append(expected_tag);
-    regex_str.append(" ");
-  }
-  regex_str.append(make_log_pattern(severity, expected));
-  std::regex message_regex(regex_str);
-  ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
-#endif
-}
-
-static void CheckMessage(CapturedStderr& cap, android::base::LogSeverity severity,
-                         const char* expected, const char* expected_tag = nullptr) {
-  cap.Stop();
-  std::string output = cap.str();
-  return CheckMessage(output, severity, expected, expected_tag);
-}
-
-#define CHECK_LOG_STREAM_DISABLED(severity)                      \
-  {                                                              \
-    android::base::ScopedLogSeverity sls1(android::base::FATAL); \
-    CapturedStderr cap1;                                         \
-    LOG_STREAM(severity) << "foo bar";                           \
-    cap1.Stop();                                                 \
-    ASSERT_EQ("", cap1.str());                                   \
-  }                                                              \
-  {                                                              \
-    android::base::ScopedLogSeverity sls1(android::base::FATAL); \
-    CapturedStderr cap1;                                         \
-    LOG_STREAM(::android::base::severity) << "foo bar";          \
-    cap1.Stop();                                                 \
-    ASSERT_EQ("", cap1.str());                                   \
-  }
-
-#define CHECK_LOG_STREAM_ENABLED(severity) \
-  { \
-    android::base::ScopedLogSeverity sls2(android::base::severity); \
-    CapturedStderr cap2; \
-    LOG_STREAM(severity) << "foobar"; \
-    CheckMessage(cap2, android::base::severity, "foobar"); \
-  } \
-  { \
-    android::base::ScopedLogSeverity sls2(android::base::severity); \
-    CapturedStderr cap2; \
-    LOG_STREAM(::android::base::severity) << "foobar"; \
-    CheckMessage(cap2, android::base::severity, "foobar"); \
-  } \
-
-TEST(logging, LOG_STREAM_FATAL_WITHOUT_ABORT_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(FATAL_WITHOUT_ABORT));
-}
-
-TEST(logging, LOG_STREAM_ERROR_disabled) {
-  CHECK_LOG_STREAM_DISABLED(ERROR);
-}
-
-TEST(logging, LOG_STREAM_ERROR_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(ERROR));
-}
-
-TEST(logging, LOG_STREAM_WARNING_disabled) {
-  CHECK_LOG_STREAM_DISABLED(WARNING);
-}
-
-TEST(logging, LOG_STREAM_WARNING_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(WARNING));
-}
-
-TEST(logging, LOG_STREAM_INFO_disabled) {
-  CHECK_LOG_STREAM_DISABLED(INFO);
-}
-
-TEST(logging, LOG_STREAM_INFO_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(INFO));
-}
-
-TEST(logging, LOG_STREAM_DEBUG_disabled) {
-  CHECK_LOG_STREAM_DISABLED(DEBUG);
-}
-
-TEST(logging, LOG_STREAM_DEBUG_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(DEBUG));
-}
-
-TEST(logging, LOG_STREAM_VERBOSE_disabled) {
-  CHECK_LOG_STREAM_DISABLED(VERBOSE);
-}
-
-TEST(logging, LOG_STREAM_VERBOSE_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(VERBOSE));
-}
-
-#undef CHECK_LOG_STREAM_DISABLED
-#undef CHECK_LOG_STREAM_ENABLED
-
-#define CHECK_LOG_DISABLED(severity)                             \
-  {                                                              \
-    android::base::ScopedLogSeverity sls1(android::base::FATAL); \
-    CapturedStderr cap1;                                         \
-    LOG(severity) << "foo bar";                                  \
-    cap1.Stop();                                                 \
-    ASSERT_EQ("", cap1.str());                                   \
-  }                                                              \
-  {                                                              \
-    android::base::ScopedLogSeverity sls1(android::base::FATAL); \
-    CapturedStderr cap1;                                         \
-    LOG(::android::base::severity) << "foo bar";                 \
-    cap1.Stop();                                                 \
-    ASSERT_EQ("", cap1.str());                                   \
-  }
-
-#define CHECK_LOG_ENABLED(severity) \
-  { \
-    android::base::ScopedLogSeverity sls2(android::base::severity); \
-    CapturedStderr cap2; \
-    LOG(severity) << "foobar"; \
-    CheckMessage(cap2, android::base::severity, "foobar"); \
-  } \
-  { \
-    android::base::ScopedLogSeverity sls2(android::base::severity); \
-    CapturedStderr cap2; \
-    LOG(::android::base::severity) << "foobar"; \
-    CheckMessage(cap2, android::base::severity, "foobar"); \
-  } \
-
-TEST(logging, LOG_FATAL) {
-  ASSERT_DEATH({SuppressAbortUI(); LOG(FATAL) << "foobar";}, "foobar");
-  ASSERT_DEATH({SuppressAbortUI(); LOG(::android::base::FATAL) << "foobar";}, "foobar");
-}
-
-TEST(logging, LOG_FATAL_WITHOUT_ABORT_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(FATAL_WITHOUT_ABORT));
-}
-
-TEST(logging, LOG_ERROR_disabled) {
-  CHECK_LOG_DISABLED(ERROR);
-}
-
-TEST(logging, LOG_ERROR_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(ERROR));
-}
-
-TEST(logging, LOG_WARNING_disabled) {
-  CHECK_LOG_DISABLED(WARNING);
-}
-
-TEST(logging, LOG_WARNING_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(WARNING));
-}
-
-TEST(logging, LOG_INFO_disabled) {
-  CHECK_LOG_DISABLED(INFO);
-}
-
-TEST(logging, LOG_INFO_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(INFO));
-}
-
-TEST(logging, LOG_DEBUG_disabled) {
-  CHECK_LOG_DISABLED(DEBUG);
-}
-
-TEST(logging, LOG_DEBUG_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(DEBUG));
-}
-
-TEST(logging, LOG_VERBOSE_disabled) {
-  CHECK_LOG_DISABLED(VERBOSE);
-}
-
-TEST(logging, LOG_VERBOSE_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(VERBOSE));
-}
-
-#undef CHECK_LOG_DISABLED
-#undef CHECK_LOG_ENABLED
-
-TEST(logging, LOG_complex_param) {
-#define CHECK_LOG_COMBINATION(use_scoped_log_severity_info, use_logging_severity_info)         \
-  {                                                                                            \
-    android::base::ScopedLogSeverity sls(                                                      \
-        (use_scoped_log_severity_info) ? ::android::base::INFO : ::android::base::WARNING);    \
-    CapturedStderr cap;                                                                        \
-    LOG((use_logging_severity_info) ? ::android::base::INFO : ::android::base::WARNING)        \
-        << "foobar";                                                                           \
-    if ((use_scoped_log_severity_info) || !(use_logging_severity_info)) {                      \
-      ASSERT_NO_FATAL_FAILURE(CheckMessage(                                                    \
-          cap, (use_logging_severity_info) ? ::android::base::INFO : ::android::base::WARNING, \
-          "foobar"));                                                                          \
-    } else {                                                                                   \
-      cap.Stop();                                                                              \
-      ASSERT_EQ("", cap.str());                                                                \
-    }                                                                                          \
-  }
-
-  CHECK_LOG_COMBINATION(false,false);
-  CHECK_LOG_COMBINATION(false,true);
-  CHECK_LOG_COMBINATION(true,false);
-  CHECK_LOG_COMBINATION(true,true);
-
-#undef CHECK_LOG_COMBINATION
-}
-
-
-TEST(logging, LOG_does_not_clobber_errno) {
-  CapturedStderr cap;
-  errno = 12345;
-  LOG(INFO) << (errno = 67890);
-  EXPECT_EQ(12345, errno) << "errno was not restored";
-
-  ASSERT_NO_FATAL_FAILURE(CheckMessage(cap, android::base::INFO, "67890"));
-}
-
-TEST(logging, PLOG_does_not_clobber_errno) {
-  CapturedStderr cap;
-  errno = 12345;
-  PLOG(INFO) << (errno = 67890);
-  EXPECT_EQ(12345, errno) << "errno was not restored";
-
-  ASSERT_NO_FATAL_FAILURE(CheckMessage(cap, android::base::INFO, "67890"));
-}
-
-TEST(logging, LOG_does_not_have_dangling_if) {
-  CapturedStderr cap; // So the logging below has no side-effects.
-
-  // Do the test two ways: once where we hypothesize that LOG()'s if
-  // will evaluate to true (when severity is high enough) and once when we
-  // expect it to evaluate to false (when severity is not high enough).
-  bool flag = false;
-  if (true)
-    LOG(INFO) << "foobar";
-  else
-    flag = true;
-
-  EXPECT_FALSE(flag) << "LOG macro probably has a dangling if with no else";
-
-  flag = false;
-  if (true)
-    LOG(VERBOSE) << "foobar";
-  else
-    flag = true;
-
-  EXPECT_FALSE(flag) << "LOG macro probably has a dangling if with no else";
-}
-
-#define CHECK_PLOG_DISABLED(severity)                            \
-  {                                                              \
-    android::base::ScopedLogSeverity sls1(android::base::FATAL); \
-    CapturedStderr cap1;                                         \
-    PLOG(severity) << "foo bar";                                 \
-    cap1.Stop();                                                 \
-    ASSERT_EQ("", cap1.str());                                   \
-  }                                                              \
-  {                                                              \
-    android::base::ScopedLogSeverity sls1(android::base::FATAL); \
-    CapturedStderr cap1;                                         \
-    PLOG(severity) << "foo bar";                                 \
-    cap1.Stop();                                                 \
-    ASSERT_EQ("", cap1.str());                                   \
-  }
-
-#define CHECK_PLOG_ENABLED(severity) \
-  { \
-    android::base::ScopedLogSeverity sls2(android::base::severity); \
-    CapturedStderr cap2; \
-    errno = ENOENT; \
-    PLOG(severity) << "foobar"; \
-    CheckMessage(cap2, android::base::severity, "foobar: No such file or directory"); \
-  } \
-  { \
-    android::base::ScopedLogSeverity sls2(android::base::severity); \
-    CapturedStderr cap2; \
-    errno = ENOENT; \
-    PLOG(severity) << "foobar"; \
-    CheckMessage(cap2, android::base::severity, "foobar: No such file or directory"); \
-  } \
-
-TEST(logging, PLOG_FATAL) {
-  ASSERT_DEATH({SuppressAbortUI(); PLOG(FATAL) << "foobar";}, "foobar");
-  ASSERT_DEATH({SuppressAbortUI(); PLOG(::android::base::FATAL) << "foobar";}, "foobar");
-}
-
-TEST(logging, PLOG_FATAL_WITHOUT_ABORT_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(FATAL_WITHOUT_ABORT));
-}
-
-TEST(logging, PLOG_ERROR_disabled) {
-  CHECK_PLOG_DISABLED(ERROR);
-}
-
-TEST(logging, PLOG_ERROR_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(ERROR));
-}
-
-TEST(logging, PLOG_WARNING_disabled) {
-  CHECK_PLOG_DISABLED(WARNING);
-}
-
-TEST(logging, PLOG_WARNING_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(WARNING));
-}
-
-TEST(logging, PLOG_INFO_disabled) {
-  CHECK_PLOG_DISABLED(INFO);
-}
-
-TEST(logging, PLOG_INFO_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(INFO));
-}
-
-TEST(logging, PLOG_DEBUG_disabled) {
-  CHECK_PLOG_DISABLED(DEBUG);
-}
-
-TEST(logging, PLOG_DEBUG_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(DEBUG));
-}
-
-TEST(logging, PLOG_VERBOSE_disabled) {
-  CHECK_PLOG_DISABLED(VERBOSE);
-}
-
-TEST(logging, PLOG_VERBOSE_enabled) {
-  ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(VERBOSE));
-}
-
-#undef CHECK_PLOG_DISABLED
-#undef CHECK_PLOG_ENABLED
-
-
-TEST(logging, UNIMPLEMENTED) {
-  std::string expected = android::base::StringPrintf("%s unimplemented ", __PRETTY_FUNCTION__);
-
-  CapturedStderr cap;
-  errno = ENOENT;
-  UNIMPLEMENTED(ERROR);
-  ASSERT_NO_FATAL_FAILURE(CheckMessage(cap, android::base::ERROR, expected.c_str()));
-}
-
-static void NoopAborter(const char* msg ATTRIBUTE_UNUSED) {
-  LOG(ERROR) << "called noop";
-}
-
-TEST(logging, LOG_FATAL_NOOP_ABORTER) {
-  CapturedStderr cap;
-  {
-    android::base::SetAborter(NoopAborter);
-
-    android::base::ScopedLogSeverity sls(android::base::ERROR);
-    LOG(FATAL) << "foobar";
-    cap.Stop();
-
-    android::base::SetAborter(android::base::DefaultAborter);
-  }
-  std::string output = cap.str();
-  ASSERT_NO_FATAL_FAILURE(CheckMessage(output, android::base::FATAL, "foobar"));
-  ASSERT_NO_FATAL_FAILURE(CheckMessage(output, android::base::ERROR, "called noop"));
-
-  ASSERT_DEATH({SuppressAbortUI(); LOG(FATAL) << "foobar";}, "foobar");
-}
-
-struct CountLineAborter {
-  static void CountLineAborterFunction(const char* msg) {
-    while (*msg != 0) {
-      if (*msg == '\n') {
-        newline_count++;
-      }
-      msg++;
-    }
-  }
-  static size_t newline_count;
-};
-size_t CountLineAborter::newline_count = 0;
-
-TEST(logging, LOG_FATAL_ABORTER_MESSAGE) {
-  CountLineAborter::newline_count = 0;
-  android::base::SetAborter(CountLineAborter::CountLineAborterFunction);
-
-  android::base::ScopedLogSeverity sls(android::base::ERROR);
-  CapturedStderr cap;
-  LOG(FATAL) << "foo\nbar";
-
-  EXPECT_EQ(CountLineAborter::newline_count, 1U);
-}
-
-__attribute__((constructor)) void TestLoggingInConstructor() {
-  LOG(ERROR) << "foobar";
-}
-
-TEST(logging, StdioLogger) {
-  CapturedStderr cap_err;
-  CapturedStdout cap_out;
-  android::base::SetLogger(android::base::StdioLogger);
-  LOG(INFO) << "out";
-  LOG(ERROR) << "err";
-  cap_err.Stop();
-  cap_out.Stop();
-
-  // For INFO we expect just the literal "out\n".
-  ASSERT_EQ("out\n", cap_out.str());
-  // Whereas ERROR logging includes the program name.
-  ASSERT_EQ(android::base::Basename(android::base::GetExecutablePath()) + ": err\n", cap_err.str());
-}
-
-TEST(logging, ForkSafe) {
-#if !defined(_WIN32)
-  using namespace android::base;
-  SetLogger(
-      [&](LogId, LogSeverity, const char*, const char*, unsigned int, const char*) { sleep(3); });
-
-  auto guard = make_scope_guard([&] {
-#ifdef __ANDROID__
-    SetLogger(LogdLogger());
-#else
-    SetLogger(StderrLogger);
-#endif
-  });
-
-  auto thread = std::thread([] {
-    LOG(ERROR) << "This should sleep for 3 seconds, long enough to fork another process, if there "
-                  "is no intervention";
-  });
-  thread.detach();
-
-  auto pid = fork();
-  ASSERT_NE(-1, pid);
-
-  if (pid == 0) {
-    // Reset the logger, so the next message doesn't sleep().
-    SetLogger([](LogId, LogSeverity, const char*, const char*, unsigned int, const char*) {});
-    LOG(ERROR) << "This should succeed in the child, only if libbase is forksafe.";
-    _exit(EXIT_SUCCESS);
-  }
-
-  // Wait for up to 3 seconds for the child to exit.
-  int tries = 3;
-  bool found_child = false;
-  while (tries-- > 0) {
-    auto result = waitpid(pid, nullptr, WNOHANG);
-    EXPECT_NE(-1, result);
-    if (result == pid) {
-      found_child = true;
-      break;
-    }
-    sleep(1);
-  }
-
-  EXPECT_TRUE(found_child);
-
-  // Kill the child if it did not exit.
-  if (!found_child) {
-    kill(pid, SIGKILL);
-  }
-#endif
-}
diff --git a/base/macros_test.cpp b/base/macros_test.cpp
deleted file mode 100644
index 2b522db..0000000
--- a/base/macros_test.cpp
+++ /dev/null
@@ -1,30 +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 "android-base/macros.h"
-
-#include <stdint.h>
-
-#include <gtest/gtest.h>
-
-TEST(macros, SIZEOF_MEMBER_macro) {
-  struct S {
-    int32_t i32;
-    double d;
-  };
-  ASSERT_EQ(4U, SIZEOF_MEMBER(S, i32));
-  ASSERT_EQ(8U, SIZEOF_MEMBER(S, d));
-}
diff --git a/base/mapped_file.cpp b/base/mapped_file.cpp
deleted file mode 100644
index fff3453..0000000
--- a/base/mapped_file.cpp
+++ /dev/null
@@ -1,128 +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 "android-base/mapped_file.h"
-
-#include <utility>
-
-#include <errno.h>
-
-namespace android {
-namespace base {
-
-static constexpr char kEmptyBuffer[] = {'0'};
-
-static off64_t InitPageSize() {
-#if defined(_WIN32)
-  SYSTEM_INFO si;
-  GetSystemInfo(&si);
-  return si.dwAllocationGranularity;
-#else
-  return sysconf(_SC_PAGE_SIZE);
-#endif
-}
-
-std::unique_ptr<MappedFile> MappedFile::FromFd(borrowed_fd fd, off64_t offset, size_t length,
-                                               int prot) {
-#if defined(_WIN32)
-  return FromOsHandle(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), offset, length, prot);
-#else
-  return FromOsHandle(fd.get(), offset, length, prot);
-#endif
-}
-
-std::unique_ptr<MappedFile> MappedFile::FromOsHandle(os_handle h, off64_t offset, size_t length,
-                                                     int prot) {
-  static const off64_t page_size = InitPageSize();
-  size_t slop = offset % page_size;
-  off64_t file_offset = offset - slop;
-  off64_t file_length = length + slop;
-
-#if defined(_WIN32)
-  HANDLE handle = CreateFileMappingW(
-      h, nullptr, (prot & PROT_WRITE) ? PAGE_READWRITE : PAGE_READONLY, 0, 0, nullptr);
-  if (handle == nullptr) {
-    // http://b/119818070 "app crashes when reading asset of zero length".
-    // Return a MappedFile that's only valid for reading the size.
-    if (length == 0 && ::GetLastError() == ERROR_FILE_INVALID) {
-      return std::unique_ptr<MappedFile>(
-          new MappedFile(const_cast<char*>(kEmptyBuffer), 0, 0, nullptr));
-    }
-    return nullptr;
-  }
-  void* base = MapViewOfFile(handle, (prot & PROT_WRITE) ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ, 0,
-                             file_offset, file_length);
-  if (base == nullptr) {
-    CloseHandle(handle);
-    return nullptr;
-  }
-  return std::unique_ptr<MappedFile>(
-      new MappedFile(static_cast<char*>(base), length, slop, handle));
-#else
-  void* base = mmap(nullptr, file_length, prot, MAP_SHARED, h, file_offset);
-  if (base == MAP_FAILED) {
-    // http://b/119818070 "app crashes when reading asset of zero length".
-    // mmap fails with EINVAL for a zero length region.
-    if (errno == EINVAL && length == 0) {
-      return std::unique_ptr<MappedFile>(new MappedFile(const_cast<char*>(kEmptyBuffer), 0, 0));
-    }
-    return nullptr;
-  }
-  return std::unique_ptr<MappedFile>(new MappedFile(static_cast<char*>(base), length, slop));
-#endif
-}
-
-MappedFile::MappedFile(MappedFile&& other)
-    : base_(std::exchange(other.base_, nullptr)),
-      size_(std::exchange(other.size_, 0)),
-      offset_(std::exchange(other.offset_, 0))
-#ifdef _WIN32
-      ,
-      handle_(std::exchange(other.handle_, nullptr))
-#endif
-{
-}
-
-MappedFile& MappedFile::operator=(MappedFile&& other) {
-  Close();
-  base_ = std::exchange(other.base_, nullptr);
-  size_ = std::exchange(other.size_, 0);
-  offset_ = std::exchange(other.offset_, 0);
-#ifdef _WIN32
-  handle_ = std::exchange(other.handle_, nullptr);
-#endif
-  return *this;
-}
-
-MappedFile::~MappedFile() {
-  Close();
-}
-
-void MappedFile::Close() {
-#if defined(_WIN32)
-  if (base_ != nullptr && size_ != 0) UnmapViewOfFile(base_);
-  if (handle_ != nullptr) CloseHandle(handle_);
-  handle_ = nullptr;
-#else
-  if (base_ != nullptr && size_ != 0) munmap(base_, size_ + offset_);
-#endif
-
-  base_ = nullptr;
-  offset_ = size_ = 0;
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/mapped_file_test.cpp b/base/mapped_file_test.cpp
deleted file mode 100644
index d21703c..0000000
--- a/base/mapped_file_test.cpp
+++ /dev/null
@@ -1,49 +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 "android-base/mapped_file.h"
-
-#include <gtest/gtest.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <string>
-
-#include "android-base/file.h"
-
-TEST(mapped_file, smoke) {
-  TemporaryFile tf;
-  ASSERT_TRUE(tf.fd != -1);
-  ASSERT_TRUE(android::base::WriteStringToFd("hello world", tf.fd));
-
-  auto m = android::base::MappedFile::FromFd(tf.fd, 3, 2, PROT_READ);
-  ASSERT_EQ(2u, m->size());
-  ASSERT_EQ('l', m->data()[0]);
-  ASSERT_EQ('o', m->data()[1]);
-}
-
-TEST(mapped_file, zero_length_mapping) {
-  // http://b/119818070 "app crashes when reading asset of zero length".
-  // mmap fails with EINVAL for a zero length region.
-  TemporaryFile tf;
-  ASSERT_TRUE(tf.fd != -1);
-
-  auto m = android::base::MappedFile::FromFd(tf.fd, 4096, 0, PROT_READ);
-  EXPECT_EQ(0u, m->size());
-  EXPECT_NE(nullptr, m->data());
-}
diff --git a/base/no_destructor_test.cpp b/base/no_destructor_test.cpp
deleted file mode 100644
index f19468a..0000000
--- a/base/no_destructor_test.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 "android-base/no_destructor.h"
-
-#include <gtest/gtest.h>
-
-struct __attribute__((packed)) Bomb {
-  Bomb() : magic_(123) {}
-
-  ~Bomb() { exit(42); }
-
-  int get() const { return magic_; }
-
- private:
-  [[maybe_unused]] char padding_;
-  int magic_;
-};
-
-TEST(no_destructor, bomb) {
-  ASSERT_EXIT(({
-                {
-                  Bomb b;
-                  if (b.get() != 123) exit(1);
-                }
-
-                exit(0);
-              }),
-              ::testing::ExitedWithCode(42), "");
-}
-
-TEST(no_destructor, defused) {
-  ASSERT_EXIT(({
-                {
-                  android::base::NoDestructor<Bomb> b;
-                  if (b->get() != 123) exit(1);
-                }
-
-                exit(0);
-              }),
-              ::testing::ExitedWithCode(0), "");
-}
-
-TEST(no_destructor, operators) {
-  android::base::NoDestructor<Bomb> b;
-  const android::base::NoDestructor<Bomb>& c = b;
-  ASSERT_EQ(123, b.get()->get());
-  ASSERT_EQ(123, b->get());
-  ASSERT_EQ(123, (*b).get());
-  ASSERT_EQ(123, c.get()->get());
-  ASSERT_EQ(123, c->get());
-  ASSERT_EQ(123, (*c).get());
-}
diff --git a/base/parsebool.cpp b/base/parsebool.cpp
deleted file mode 100644
index ff96fe9..0000000
--- a/base/parsebool.cpp
+++ /dev/null
@@ -1,34 +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 "android-base/parsebool.h"
-#include <errno.h>
-
-namespace android {
-namespace base {
-
-ParseBoolResult ParseBool(std::string_view s) {
-  if (s == "1" || s == "y" || s == "yes" || s == "on" || s == "true") {
-    return ParseBoolResult::kTrue;
-  }
-  if (s == "0" || s == "n" || s == "no" || s == "off" || s == "false") {
-    return ParseBoolResult::kFalse;
-  }
-  return ParseBoolResult::kError;
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/parsebool_test.cpp b/base/parsebool_test.cpp
deleted file mode 100644
index a081994..0000000
--- a/base/parsebool_test.cpp
+++ /dev/null
@@ -1,48 +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 "android-base/parsebool.h"
-
-#include <errno.h>
-
-#include <gtest/gtest.h>
-#include <string_view>
-
-using android::base::ParseBool;
-using android::base::ParseBoolResult;
-
-TEST(parsebool, true_) {
-  static const char* yes[] = {
-      "1", "on", "true", "y", "yes",
-  };
-  for (const char* s : yes) {
-    ASSERT_EQ(ParseBoolResult::kTrue, ParseBool(s));
-  }
-}
-
-TEST(parsebool, false_) {
-  static const char* no[] = {
-      "0", "false", "n", "no", "off",
-  };
-  for (const char* s : no) {
-    ASSERT_EQ(ParseBoolResult::kFalse, ParseBool(s));
-  }
-}
-
-TEST(parsebool, invalid) {
-  ASSERT_EQ(ParseBoolResult::kError, ParseBool("blarg"));
-  ASSERT_EQ(ParseBoolResult::kError, ParseBool(""));
-}
diff --git a/base/parsedouble_test.cpp b/base/parsedouble_test.cpp
deleted file mode 100644
index ec3c10c..0000000
--- a/base/parsedouble_test.cpp
+++ /dev/null
@@ -1,67 +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 "android-base/parsedouble.h"
-
-#include <gtest/gtest.h>
-
-TEST(parsedouble, double_smoke) {
-  double d;
-  ASSERT_FALSE(android::base::ParseDouble("", &d));
-  ASSERT_FALSE(android::base::ParseDouble("x", &d));
-  ASSERT_FALSE(android::base::ParseDouble("123.4x", &d));
-
-  ASSERT_TRUE(android::base::ParseDouble("123.4", &d));
-  ASSERT_DOUBLE_EQ(123.4, d);
-  ASSERT_TRUE(android::base::ParseDouble("-123.4", &d));
-  ASSERT_DOUBLE_EQ(-123.4, d);
-
-  ASSERT_TRUE(android::base::ParseDouble("0", &d, 0.0));
-  ASSERT_DOUBLE_EQ(0.0, d);
-  ASSERT_FALSE(android::base::ParseDouble("0", &d, 1e-9));
-  ASSERT_FALSE(android::base::ParseDouble("3.0", &d, -1.0, 2.0));
-  ASSERT_TRUE(android::base::ParseDouble("1.0", &d, 0.0, 2.0));
-  ASSERT_DOUBLE_EQ(1.0, d);
-
-  ASSERT_FALSE(android::base::ParseDouble("123.4x", nullptr));
-  ASSERT_TRUE(android::base::ParseDouble("-123.4", nullptr));
-  ASSERT_FALSE(android::base::ParseDouble("3.0", nullptr, -1.0, 2.0));
-  ASSERT_TRUE(android::base::ParseDouble("1.0", nullptr, 0.0, 2.0));
-}
-
-TEST(parsedouble, float_smoke) {
-  float f;
-  ASSERT_FALSE(android::base::ParseFloat("", &f));
-  ASSERT_FALSE(android::base::ParseFloat("x", &f));
-  ASSERT_FALSE(android::base::ParseFloat("123.4x", &f));
-
-  ASSERT_TRUE(android::base::ParseFloat("123.4", &f));
-  ASSERT_FLOAT_EQ(123.4, f);
-  ASSERT_TRUE(android::base::ParseFloat("-123.4", &f));
-  ASSERT_FLOAT_EQ(-123.4, f);
-
-  ASSERT_TRUE(android::base::ParseFloat("0", &f, 0.0));
-  ASSERT_FLOAT_EQ(0.0, f);
-  ASSERT_FALSE(android::base::ParseFloat("0", &f, 1e-9));
-  ASSERT_FALSE(android::base::ParseFloat("3.0", &f, -1.0, 2.0));
-  ASSERT_TRUE(android::base::ParseFloat("1.0", &f, 0.0, 2.0));
-  ASSERT_FLOAT_EQ(1.0, f);
-
-  ASSERT_FALSE(android::base::ParseFloat("123.4x", nullptr));
-  ASSERT_TRUE(android::base::ParseFloat("-123.4", nullptr));
-  ASSERT_FALSE(android::base::ParseFloat("3.0", nullptr, -1.0, 2.0));
-  ASSERT_TRUE(android::base::ParseFloat("1.0", nullptr, 0.0, 2.0));
-}
diff --git a/base/parseint_test.cpp b/base/parseint_test.cpp
deleted file mode 100644
index e449c33..0000000
--- a/base/parseint_test.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2015 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 "android-base/parseint.h"
-
-#include <errno.h>
-
-#include <gtest/gtest.h>
-
-TEST(parseint, signed_smoke) {
-  errno = 0;
-  int i = 0;
-  ASSERT_FALSE(android::base::ParseInt("x", &i));
-  ASSERT_EQ(EINVAL, errno);
-  errno = 0;
-  ASSERT_FALSE(android::base::ParseInt("123x", &i));
-  ASSERT_EQ(EINVAL, errno);
-
-  ASSERT_TRUE(android::base::ParseInt("123", &i));
-  ASSERT_EQ(123, i);
-  ASSERT_EQ(0, errno);
-  i = 0;
-  EXPECT_TRUE(android::base::ParseInt("  123", &i));
-  EXPECT_EQ(123, i);
-  ASSERT_TRUE(android::base::ParseInt("-123", &i));
-  ASSERT_EQ(-123, i);
-  i = 0;
-  EXPECT_TRUE(android::base::ParseInt("  -123", &i));
-  EXPECT_EQ(-123, i);
-
-  short s = 0;
-  ASSERT_TRUE(android::base::ParseInt("1234", &s));
-  ASSERT_EQ(1234, s);
-
-  ASSERT_TRUE(android::base::ParseInt("12", &i, 0, 15));
-  ASSERT_EQ(12, i);
-  errno = 0;
-  ASSERT_FALSE(android::base::ParseInt("-12", &i, 0, 15));
-  ASSERT_EQ(ERANGE, errno);
-  errno = 0;
-  ASSERT_FALSE(android::base::ParseInt("16", &i, 0, 15));
-  ASSERT_EQ(ERANGE, errno);
-
-  errno = 0;
-  ASSERT_FALSE(android::base::ParseInt<int>("x", nullptr));
-  ASSERT_EQ(EINVAL, errno);
-  errno = 0;
-  ASSERT_FALSE(android::base::ParseInt<int>("123x", nullptr));
-  ASSERT_EQ(EINVAL, errno);
-  ASSERT_TRUE(android::base::ParseInt<int>("1234", nullptr));
-}
-
-TEST(parseint, unsigned_smoke) {
-  errno = 0;
-  unsigned int i = 0u;
-  ASSERT_FALSE(android::base::ParseUint("x", &i));
-  ASSERT_EQ(EINVAL, errno);
-  errno = 0;
-  ASSERT_FALSE(android::base::ParseUint("123x", &i));
-  ASSERT_EQ(EINVAL, errno);
-
-  ASSERT_TRUE(android::base::ParseUint("123", &i));
-  ASSERT_EQ(123u, i);
-  ASSERT_EQ(0, errno);
-  i = 0u;
-  EXPECT_TRUE(android::base::ParseUint("  123", &i));
-  EXPECT_EQ(123u, i);
-  errno = 0;
-  ASSERT_FALSE(android::base::ParseUint("-123", &i));
-  EXPECT_EQ(EINVAL, errno);
-  errno = 0;
-  EXPECT_FALSE(android::base::ParseUint("  -123", &i));
-  EXPECT_EQ(EINVAL, errno);
-
-  unsigned short s = 0u;
-  ASSERT_TRUE(android::base::ParseUint("1234", &s));
-  ASSERT_EQ(1234u, s);
-
-  ASSERT_TRUE(android::base::ParseUint("12", &i, 15u));
-  ASSERT_EQ(12u, i);
-  errno = 0;
-  ASSERT_FALSE(android::base::ParseUint("-12", &i, 15u));
-  ASSERT_EQ(EINVAL, errno);
-  errno = 0;
-  ASSERT_FALSE(android::base::ParseUint("16", &i, 15u));
-  ASSERT_EQ(ERANGE, errno);
-
-  errno = 0;
-  ASSERT_FALSE(android::base::ParseUint<unsigned short>("x", nullptr));
-  ASSERT_EQ(EINVAL, errno);
-  errno = 0;
-  ASSERT_FALSE(android::base::ParseUint<unsigned short>("123x", nullptr));
-  ASSERT_EQ(EINVAL, errno);
-  ASSERT_TRUE(android::base::ParseUint<unsigned short>("1234", nullptr));
-
-  errno = 0;
-  unsigned long long int lli;
-  EXPECT_FALSE(android::base::ParseUint("-123", &lli));
-  EXPECT_EQ(EINVAL, errno);
-  errno = 0;
-  EXPECT_FALSE(android::base::ParseUint("  -123", &lli));
-  EXPECT_EQ(EINVAL, errno);
-}
-
-TEST(parseint, no_implicit_octal) {
-  int i = 0;
-  ASSERT_TRUE(android::base::ParseInt("0123", &i));
-  ASSERT_EQ(123, i);
-
-  unsigned int u = 0u;
-  ASSERT_TRUE(android::base::ParseUint("0123", &u));
-  ASSERT_EQ(123u, u);
-}
-
-TEST(parseint, explicit_hex) {
-  int i = 0;
-  ASSERT_TRUE(android::base::ParseInt("0x123", &i));
-  ASSERT_EQ(0x123, i);
-  i = 0;
-  EXPECT_TRUE(android::base::ParseInt("  0x123", &i));
-  EXPECT_EQ(0x123, i);
-
-  unsigned int u = 0u;
-  ASSERT_TRUE(android::base::ParseUint("0x123", &u));
-  ASSERT_EQ(0x123u, u);
-  u = 0u;
-  EXPECT_TRUE(android::base::ParseUint("  0x123", &u));
-  EXPECT_EQ(0x123u, u);
-}
-
-TEST(parseint, string) {
-  int i = 0;
-  ASSERT_TRUE(android::base::ParseInt(std::string("123"), &i));
-  ASSERT_EQ(123, i);
-
-  unsigned int u = 0u;
-  ASSERT_TRUE(android::base::ParseUint(std::string("123"), &u));
-  ASSERT_EQ(123u, u);
-}
-
-TEST(parseint, untouched_on_failure) {
-  int i = 123;
-  ASSERT_FALSE(android::base::ParseInt("456x", &i));
-  ASSERT_EQ(123, i);
-
-  unsigned int u = 123u;
-  ASSERT_FALSE(android::base::ParseUint("456x", &u));
-  ASSERT_EQ(123u, u);
-}
-
-TEST(parseint, ParseByteCount) {
-  uint64_t i = 0;
-  ASSERT_TRUE(android::base::ParseByteCount("123b", &i));
-  ASSERT_EQ(123ULL, i);
-
-  ASSERT_TRUE(android::base::ParseByteCount("8k", &i));
-  ASSERT_EQ(8ULL * 1024, i);
-
-  ASSERT_TRUE(android::base::ParseByteCount("8M", &i));
-  ASSERT_EQ(8ULL * 1024 * 1024, i);
-
-  ASSERT_TRUE(android::base::ParseByteCount("6g", &i));
-  ASSERT_EQ(6ULL * 1024 * 1024 * 1024, i);
-
-  ASSERT_TRUE(android::base::ParseByteCount("1T", &i));
-  ASSERT_EQ(1ULL * 1024 * 1024 * 1024 * 1024, i);
-
-  ASSERT_TRUE(android::base::ParseByteCount("2p", &i));
-  ASSERT_EQ(2ULL * 1024 * 1024 * 1024 * 1024 * 1024, i);
-
-  ASSERT_TRUE(android::base::ParseByteCount("4e", &i));
-  ASSERT_EQ(4ULL * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, i);
-}
-
-TEST(parseint, ParseByteCount_invalid_suffix) {
-  unsigned u;
-  ASSERT_FALSE(android::base::ParseByteCount("1x", &u));
-}
-
-TEST(parseint, ParseByteCount_overflow) {
-  uint64_t u64;
-  ASSERT_FALSE(android::base::ParseByteCount("4294967295E", &u64));
-
-  uint16_t u16;
-  ASSERT_TRUE(android::base::ParseByteCount("63k", &u16));
-  ASSERT_EQ(63U * 1024, u16);
-  ASSERT_TRUE(android::base::ParseByteCount("65535b", &u16));
-  ASSERT_EQ(65535U, u16);
-  ASSERT_FALSE(android::base::ParseByteCount("65k", &u16));
-}
diff --git a/base/parsenetaddress.cpp b/base/parsenetaddress.cpp
deleted file mode 100644
index dd80f6d..0000000
--- a/base/parsenetaddress.cpp
+++ /dev/null
@@ -1,82 +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 "android-base/parsenetaddress.h"
-
-#include <algorithm>
-
-#include "android-base/stringprintf.h"
-#include "android-base/strings.h"
-
-namespace android {
-namespace base {
-
-bool ParseNetAddress(const std::string& address, std::string* host, int* port,
-                     std::string* canonical_address, std::string* error) {
-  host->clear();
-
-  bool ipv6 = true;
-  bool saw_port = false;
-  size_t colons = std::count(address.begin(), address.end(), ':');
-  size_t dots = std::count(address.begin(), address.end(), '.');
-  std::string port_str;
-  if (address[0] == '[') {
-    // [::1]:123
-    if (address.rfind("]:") == std::string::npos) {
-      *error = StringPrintf("bad IPv6 address '%s'", address.c_str());
-      return false;
-    }
-    *host = address.substr(1, (address.find("]:") - 1));
-    port_str = address.substr(address.rfind("]:") + 2);
-    saw_port = true;
-  } else if (dots == 0 && colons >= 2 && colons <= 7) {
-    // ::1
-    *host = address;
-  } else if (colons <= 1) {
-    // 1.2.3.4 or some.accidental.domain.com
-    ipv6 = false;
-    std::vector<std::string> pieces = Split(address, ":");
-    *host = pieces[0];
-    if (pieces.size() > 1) {
-      port_str = pieces[1];
-      saw_port = true;
-    }
-  }
-
-  if (host->empty()) {
-    *error = StringPrintf("no host in '%s'", address.c_str());
-    return false;
-  }
-
-  if (saw_port) {
-    if (sscanf(port_str.c_str(), "%d", port) != 1 || *port <= 0 ||
-        *port > 65535) {
-      *error = StringPrintf("bad port number '%s' in '%s'", port_str.c_str(),
-                            address.c_str());
-      return false;
-    }
-  }
-
-  if (canonical_address != nullptr) {
-    *canonical_address =
-        StringPrintf(ipv6 ? "[%s]:%d" : "%s:%d", host->c_str(), *port);
-  }
-
-  return true;
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/parsenetaddress_test.cpp b/base/parsenetaddress_test.cpp
deleted file mode 100644
index a3bfac8..0000000
--- a/base/parsenetaddress_test.cpp
+++ /dev/null
@@ -1,127 +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 "android-base/parsenetaddress.h"
-
-#include <gtest/gtest.h>
-
-using android::base::ParseNetAddress;
-
-TEST(ParseNetAddressTest, TestUrl) {
-  std::string canonical, host, error;
-  int port = 123;
-
-  EXPECT_TRUE(
-      ParseNetAddress("www.google.com", &host, &port, &canonical, &error));
-  EXPECT_EQ("www.google.com:123", canonical);
-  EXPECT_EQ("www.google.com", host);
-  EXPECT_EQ(123, port);
-
-  EXPECT_TRUE(
-      ParseNetAddress("www.google.com:666", &host, &port, &canonical, &error));
-  EXPECT_EQ("www.google.com:666", canonical);
-  EXPECT_EQ("www.google.com", host);
-  EXPECT_EQ(666, port);
-}
-
-TEST(ParseNetAddressTest, TestIpv4) {
-  std::string canonical, host, error;
-  int port = 123;
-
-  EXPECT_TRUE(ParseNetAddress("1.2.3.4", &host, &port, &canonical, &error));
-  EXPECT_EQ("1.2.3.4:123", canonical);
-  EXPECT_EQ("1.2.3.4", host);
-  EXPECT_EQ(123, port);
-
-  EXPECT_TRUE(ParseNetAddress("1.2.3.4:666", &host, &port, &canonical, &error));
-  EXPECT_EQ("1.2.3.4:666", canonical);
-  EXPECT_EQ("1.2.3.4", host);
-  EXPECT_EQ(666, port);
-}
-
-TEST(ParseNetAddressTest, TestIpv6) {
-  std::string canonical, host, error;
-  int port = 123;
-
-  EXPECT_TRUE(ParseNetAddress("::1", &host, &port, &canonical, &error));
-  EXPECT_EQ("[::1]:123", canonical);
-  EXPECT_EQ("::1", host);
-  EXPECT_EQ(123, port);
-
-  EXPECT_TRUE(ParseNetAddress("fe80::200:5aee:feaa:20a2", &host, &port,
-                              &canonical, &error));
-  EXPECT_EQ("[fe80::200:5aee:feaa:20a2]:123", canonical);
-  EXPECT_EQ("fe80::200:5aee:feaa:20a2", host);
-  EXPECT_EQ(123, port);
-
-  EXPECT_TRUE(ParseNetAddress("[::1]:666", &host, &port, &canonical, &error));
-  EXPECT_EQ("[::1]:666", canonical);
-  EXPECT_EQ("::1", host);
-  EXPECT_EQ(666, port);
-
-  EXPECT_TRUE(ParseNetAddress("[fe80::200:5aee:feaa:20a2]:666", &host, &port,
-                              &canonical, &error));
-  EXPECT_EQ("[fe80::200:5aee:feaa:20a2]:666", canonical);
-  EXPECT_EQ("fe80::200:5aee:feaa:20a2", host);
-  EXPECT_EQ(666, port);
-}
-
-TEST(ParseNetAddressTest, TestInvalidAddress) {
-  std::string canonical, host;
-  int port;
-
-  std::string failure_cases[] = {
-      // Invalid IPv4.
-      "1.2.3.4:",
-      "1.2.3.4::",
-      ":123",
-
-      // Invalid IPv6.
-      ":1",
-      "::::::::1",
-      "[::1",
-      "[::1]",
-      "[::1]:",
-      "[::1]::",
-
-      // Invalid port.
-      "1.2.3.4:-1",
-      "1.2.3.4:0",
-      "1.2.3.4:65536"
-      "1.2.3.4:hello",
-      "[::1]:-1",
-      "[::1]:0",
-      "[::1]:65536",
-      "[::1]:hello",
-  };
-
-  for (const auto& address : failure_cases) {
-    // Failure should give some non-empty error string.
-    std::string error;
-    EXPECT_FALSE(ParseNetAddress(address, &host, &port, &canonical, &error));
-    EXPECT_NE("", error);
-  }
-}
-
-// Null canonical address argument.
-TEST(ParseNetAddressTest, TestNullCanonicalAddress) {
-  std::string host, error;
-  int port = 42;
-
-  EXPECT_TRUE(ParseNetAddress("www.google.com", &host, &port, nullptr, &error));
-  EXPECT_TRUE(ParseNetAddress("1.2.3.4", &host, &port, nullptr, &error));
-  EXPECT_TRUE(ParseNetAddress("::1", &host, &port, nullptr, &error));
-}
diff --git a/base/process.cpp b/base/process.cpp
deleted file mode 100644
index b8cabf6..0000000
--- a/base/process.cpp
+++ /dev/null
@@ -1,39 +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 "android-base/process.h"
-
-namespace android {
-namespace base {
-
-void AllPids::PidIterator::Increment() {
-  if (!dir_) {
-    return;
-  }
-
-  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/base/process_test.cpp b/base/process_test.cpp
deleted file mode 100644
index 056f667..0000000
--- a/base/process_test.cpp
+++ /dev/null
@@ -1,35 +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 "android-base/process.h"
-
-#include <unistd.h>
-
-#include <gtest/gtest.h>
-
-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;
-    }
-  }
-
-  EXPECT_TRUE(found_our_pid);
-
-#endif
-}
diff --git a/base/properties.cpp b/base/properties.cpp
deleted file mode 100644
index 5c9ec7e..0000000
--- a/base/properties.cpp
+++ /dev/null
@@ -1,257 +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 "android-base/properties.h"
-
-#if defined(__BIONIC__)
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/system_properties.h>
-#include <sys/_system_properties.h>
-#endif
-
-#include <algorithm>
-#include <chrono>
-#include <limits>
-#include <map>
-#include <string>
-
-#include <android-base/parsebool.h>
-#include <android-base/parseint.h>
-#include <android-base/strings.h>
-
-namespace android {
-namespace base {
-
-bool GetBoolProperty(const std::string& key, bool default_value) {
-  switch (ParseBool(GetProperty(key, ""))) {
-    case ParseBoolResult::kError:
-      return default_value;
-    case ParseBoolResult::kFalse:
-      return false;
-    case ParseBoolResult::kTrue:
-      return true;
-  }
-  __builtin_unreachable();
-}
-
-template <typename T>
-T GetIntProperty(const std::string& key, T default_value, T min, T max) {
-  T result;
-  std::string value = GetProperty(key, "");
-  if (!value.empty() && android::base::ParseInt(value, &result, min, max)) return result;
-  return default_value;
-}
-
-template <typename T>
-T GetUintProperty(const std::string& key, T default_value, T max) {
-  T result;
-  std::string value = GetProperty(key, "");
-  if (!value.empty() && android::base::ParseUint(value, &result, max)) return result;
-  return default_value;
-}
-
-template int8_t GetIntProperty(const std::string&, int8_t, int8_t, int8_t);
-template int16_t GetIntProperty(const std::string&, int16_t, int16_t, int16_t);
-template int32_t GetIntProperty(const std::string&, int32_t, int32_t, int32_t);
-template int64_t GetIntProperty(const std::string&, int64_t, int64_t, int64_t);
-
-template uint8_t GetUintProperty(const std::string&, uint8_t, uint8_t);
-template uint16_t GetUintProperty(const std::string&, uint16_t, uint16_t);
-template uint32_t GetUintProperty(const std::string&, uint32_t, uint32_t);
-template uint64_t GetUintProperty(const std::string&, uint64_t, uint64_t);
-
-#if !defined(__BIONIC__)
-static std::map<std::string, std::string>& g_properties = *new std::map<std::string, std::string>;
-static int __system_property_set(const char* key, const char* value) {
-  g_properties[key] = value;
-  return 0;
-}
-#endif
-
-std::string GetProperty(const std::string& key, const std::string& default_value) {
-  std::string property_value;
-#if defined(__BIONIC__)
-  const prop_info* pi = __system_property_find(key.c_str());
-  if (pi == nullptr) return default_value;
-
-  __system_property_read_callback(pi,
-                                  [](void* cookie, const char*, const char* value, unsigned) {
-                                    auto property_value = reinterpret_cast<std::string*>(cookie);
-                                    *property_value = value;
-                                  },
-                                  &property_value);
-#else
-  auto it = g_properties.find(key);
-  if (it == g_properties.end()) return default_value;
-  property_value = it->second;
-#endif
-  // If the property exists but is empty, also return the default value.
-  // Since we can't remove system properties, "empty" is traditionally
-  // the same as "missing" (this was true for cutils' property_get).
-  return property_value.empty() ? default_value : property_value;
-}
-
-bool SetProperty(const std::string& key, const std::string& value) {
-  return (__system_property_set(key.c_str(), value.c_str()) == 0);
-}
-
-#if defined(__BIONIC__)
-
-struct WaitForPropertyData {
-  bool done;
-  const std::string* expected_value;
-  unsigned last_read_serial;
-};
-
-static void WaitForPropertyCallback(void* data_ptr, const char*, const char* value, unsigned serial) {
-  WaitForPropertyData* data = reinterpret_cast<WaitForPropertyData*>(data_ptr);
-  if (*data->expected_value == value) {
-    data->done = true;
-  } else {
-    data->last_read_serial = serial;
-  }
-}
-
-// TODO: chrono_utils?
-static void DurationToTimeSpec(timespec& ts, const std::chrono::milliseconds d) {
-  auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
-  auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(d - s);
-  ts.tv_sec = std::min<std::chrono::seconds::rep>(s.count(), std::numeric_limits<time_t>::max());
-  ts.tv_nsec = ns.count();
-}
-
-using AbsTime = std::chrono::time_point<std::chrono::steady_clock>;
-
-static void UpdateTimeSpec(timespec& ts, std::chrono::milliseconds relative_timeout,
-                           const AbsTime& start_time) {
-  auto now = std::chrono::steady_clock::now();
-  auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
-  if (time_elapsed >= relative_timeout) {
-    ts = { 0, 0 };
-  } else {
-    auto remaining_timeout = relative_timeout - time_elapsed;
-    DurationToTimeSpec(ts, remaining_timeout);
-  }
-}
-
-// Waits for the system property `key` to be created.
-// Times out after `relative_timeout`.
-// Sets absolute_timeout which represents absolute time for the timeout.
-// Returns nullptr on timeout.
-static const prop_info* WaitForPropertyCreation(const std::string& key,
-                                                const std::chrono::milliseconds& relative_timeout,
-                                                const AbsTime& start_time) {
-  // Find the property's prop_info*.
-  const prop_info* pi;
-  unsigned global_serial = 0;
-  while ((pi = __system_property_find(key.c_str())) == nullptr) {
-    // The property doesn't even exist yet.
-    // Wait for a global change and then look again.
-    timespec ts;
-    UpdateTimeSpec(ts, relative_timeout, start_time);
-    if (!__system_property_wait(nullptr, global_serial, &global_serial, &ts)) return nullptr;
-  }
-  return pi;
-}
-
-bool WaitForProperty(const std::string& key, const std::string& expected_value,
-                     std::chrono::milliseconds relative_timeout) {
-  auto start_time = std::chrono::steady_clock::now();
-  const prop_info* pi = WaitForPropertyCreation(key, relative_timeout, start_time);
-  if (pi == nullptr) return false;
-
-  WaitForPropertyData data;
-  data.expected_value = &expected_value;
-  data.done = false;
-  while (true) {
-    timespec ts;
-    // Check whether the property has the value we're looking for?
-    __system_property_read_callback(pi, WaitForPropertyCallback, &data);
-    if (data.done) return true;
-
-    // It didn't, so wait for the property to change before checking again.
-    UpdateTimeSpec(ts, relative_timeout, start_time);
-    uint32_t unused;
-    if (!__system_property_wait(pi, data.last_read_serial, &unused, &ts)) return false;
-  }
-}
-
-bool WaitForPropertyCreation(const std::string& key,
-                             std::chrono::milliseconds relative_timeout) {
-  auto start_time = std::chrono::steady_clock::now();
-  return (WaitForPropertyCreation(key, relative_timeout, start_time) != nullptr);
-}
-
-CachedProperty::CachedProperty(const char* property_name)
-    : property_name_(property_name),
-      prop_info_(nullptr),
-      cached_area_serial_(0),
-      cached_property_serial_(0),
-      is_read_only_(android::base::StartsWith(property_name, "ro.")),
-      read_only_property_(nullptr) {
-  static_assert(sizeof(cached_value_) == PROP_VALUE_MAX);
-}
-
-const char* CachedProperty::Get(bool* changed) {
-  std::optional<uint32_t> initial_property_serial_ = cached_property_serial_;
-
-  // Do we have a `struct prop_info` yet?
-  if (prop_info_ == nullptr) {
-    // `__system_property_find` is expensive, so only retry if a property
-    // has been created since last time we checked.
-    uint32_t property_area_serial = __system_property_area_serial();
-    if (property_area_serial != cached_area_serial_) {
-      prop_info_ = __system_property_find(property_name_.c_str());
-      cached_area_serial_ = property_area_serial;
-    }
-  }
-
-  if (prop_info_ != nullptr) {
-    // Only bother re-reading the property if it's actually changed since last time.
-    uint32_t property_serial = __system_property_serial(prop_info_);
-    if (property_serial != cached_property_serial_) {
-      __system_property_read_callback(
-          prop_info_,
-          [](void* data, const char*, const char* value, uint32_t serial) {
-            CachedProperty* instance = reinterpret_cast<CachedProperty*>(data);
-            instance->cached_property_serial_ = serial;
-            // Read only properties can be larger than PROP_VALUE_MAX, but also never change value
-            // or location, thus we return the pointer from the shared memory directly.
-            if (instance->is_read_only_) {
-              instance->read_only_property_ = value;
-            } else {
-              strlcpy(instance->cached_value_, value, PROP_VALUE_MAX);
-            }
-          },
-          this);
-    }
-  }
-
-  if (changed) {
-    *changed = cached_property_serial_ != initial_property_serial_;
-  }
-
-  if (is_read_only_) {
-    return read_only_property_;
-  } else {
-    return cached_value_;
-  }
-}
-
-#endif
-
-}  // namespace base
-}  // namespace android
diff --git a/base/properties_test.cpp b/base/properties_test.cpp
deleted file mode 100644
index c30c41e..0000000
--- a/base/properties_test.cpp
+++ /dev/null
@@ -1,257 +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 "android-base/properties.h"
-
-#include <gtest/gtest.h>
-
-#include <atomic>
-#include <chrono>
-#include <string>
-#include <thread>
-
-#if !defined(_WIN32)
-using namespace std::literals;
-#endif
-
-TEST(properties, smoke) {
-  android::base::SetProperty("debug.libbase.property_test", "hello");
-
-  std::string s = android::base::GetProperty("debug.libbase.property_test", "");
-  ASSERT_EQ("hello", s);
-
-  android::base::SetProperty("debug.libbase.property_test", "world");
-  s = android::base::GetProperty("debug.libbase.property_test", "");
-  ASSERT_EQ("world", s);
-
-  s = android::base::GetProperty("this.property.does.not.exist", "");
-  ASSERT_EQ("", s);
-
-  s = android::base::GetProperty("this.property.does.not.exist", "default");
-  ASSERT_EQ("default", s);
-}
-
-TEST(properties, empty) {
-  // Because you can't delete a property, people "delete" them by
-  // setting them to the empty string. In that case we'd want to
-  // keep the default value (like cutils' property_get did).
-  android::base::SetProperty("debug.libbase.property_test", "");
-  std::string s = android::base::GetProperty("debug.libbase.property_test", "default");
-  ASSERT_EQ("default", s);
-}
-
-static void CheckGetBoolProperty(bool expected, const std::string& value, bool default_value) {
-  android::base::SetProperty("debug.libbase.property_test", value.c_str());
-  ASSERT_EQ(expected, android::base::GetBoolProperty("debug.libbase.property_test", default_value));
-}
-
-TEST(properties, GetBoolProperty_true) {
-  CheckGetBoolProperty(true, "1", false);
-  CheckGetBoolProperty(true, "y", false);
-  CheckGetBoolProperty(true, "yes", false);
-  CheckGetBoolProperty(true, "on", false);
-  CheckGetBoolProperty(true, "true", false);
-}
-
-TEST(properties, GetBoolProperty_false) {
-  CheckGetBoolProperty(false, "0", true);
-  CheckGetBoolProperty(false, "n", true);
-  CheckGetBoolProperty(false, "no", true);
-  CheckGetBoolProperty(false, "off", true);
-  CheckGetBoolProperty(false, "false", true);
-}
-
-TEST(properties, GetBoolProperty_default) {
-  CheckGetBoolProperty(true, "burp", true);
-  CheckGetBoolProperty(false, "burp", false);
-}
-
-template <typename T> void CheckGetIntProperty() {
-  // Positive and negative.
-  android::base::SetProperty("debug.libbase.property_test", "-12");
-  EXPECT_EQ(T(-12), android::base::GetIntProperty<T>("debug.libbase.property_test", 45));
-  android::base::SetProperty("debug.libbase.property_test", "12");
-  EXPECT_EQ(T(12), android::base::GetIntProperty<T>("debug.libbase.property_test", 45));
-
-  // Default value.
-  android::base::SetProperty("debug.libbase.property_test", "");
-  EXPECT_EQ(T(45), android::base::GetIntProperty<T>("debug.libbase.property_test", 45));
-
-  // Bounds checks.
-  android::base::SetProperty("debug.libbase.property_test", "0");
-  EXPECT_EQ(T(45), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
-  android::base::SetProperty("debug.libbase.property_test", "1");
-  EXPECT_EQ(T(1), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
-  android::base::SetProperty("debug.libbase.property_test", "2");
-  EXPECT_EQ(T(2), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
-  android::base::SetProperty("debug.libbase.property_test", "3");
-  EXPECT_EQ(T(45), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
-}
-
-template <typename T> void CheckGetUintProperty() {
-  // Positive.
-  android::base::SetProperty("debug.libbase.property_test", "12");
-  EXPECT_EQ(T(12), android::base::GetUintProperty<T>("debug.libbase.property_test", 45));
-
-  // Default value.
-  android::base::SetProperty("debug.libbase.property_test", "");
-  EXPECT_EQ(T(45), android::base::GetUintProperty<T>("debug.libbase.property_test", 45));
-
-  // Bounds checks.
-  android::base::SetProperty("debug.libbase.property_test", "12");
-  EXPECT_EQ(T(12), android::base::GetUintProperty<T>("debug.libbase.property_test", 33, 22));
-  android::base::SetProperty("debug.libbase.property_test", "12");
-  EXPECT_EQ(T(5), android::base::GetUintProperty<T>("debug.libbase.property_test", 5, 10));
-}
-
-TEST(properties, GetIntProperty_int8_t) { CheckGetIntProperty<int8_t>(); }
-TEST(properties, GetIntProperty_int16_t) { CheckGetIntProperty<int16_t>(); }
-TEST(properties, GetIntProperty_int32_t) { CheckGetIntProperty<int32_t>(); }
-TEST(properties, GetIntProperty_int64_t) { CheckGetIntProperty<int64_t>(); }
-
-TEST(properties, GetUintProperty_uint8_t) { CheckGetUintProperty<uint8_t>(); }
-TEST(properties, GetUintProperty_uint16_t) { CheckGetUintProperty<uint16_t>(); }
-TEST(properties, GetUintProperty_uint32_t) { CheckGetUintProperty<uint32_t>(); }
-TEST(properties, GetUintProperty_uint64_t) { CheckGetUintProperty<uint64_t>(); }
-
-TEST(properties, WaitForProperty) {
-#if defined(__BIONIC__)
-  std::atomic<bool> flag{false};
-  std::thread thread([&]() {
-    std::this_thread::sleep_for(100ms);
-    android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
-    while (!flag) std::this_thread::yield();
-    android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
-  });
-
-  ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s));
-  flag = true;
-  ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b", 1s));
-  thread.join();
-#else
-  GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
-#endif
-}
-
-TEST(properties, WaitForProperty_timeout) {
-#if defined(__BIONIC__)
-  auto t0 = std::chrono::steady_clock::now();
-  ASSERT_FALSE(android::base::WaitForProperty("debug.libbase.WaitForProperty_timeout_test", "a",
-                                              200ms));
-  auto t1 = std::chrono::steady_clock::now();
-
-  ASSERT_GE(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 200ms);
-  // Upper bounds on timing are inherently flaky, but let's try...
-  ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 600ms);
-#else
-  GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
-#endif
-}
-
-TEST(properties, WaitForProperty_MaxTimeout) {
-#if defined(__BIONIC__)
-  std::atomic<bool> flag{false};
-  std::thread thread([&]() {
-    android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
-    while (!flag) std::this_thread::yield();
-    std::this_thread::sleep_for(500ms);
-    android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
-  });
-
-  ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s));
-  flag = true;
-  // Test that this does not immediately return false due to overflow issues with the timeout.
-  ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b"));
-  thread.join();
-#else
-  GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
-#endif
-}
-
-TEST(properties, WaitForProperty_NegativeTimeout) {
-#if defined(__BIONIC__)
-  std::atomic<bool> flag{false};
-  std::thread thread([&]() {
-    android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
-    while (!flag) std::this_thread::yield();
-    std::this_thread::sleep_for(500ms);
-    android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
-  });
-
-  ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s));
-  flag = true;
-  // Assert that this immediately returns with a negative timeout
-  ASSERT_FALSE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b", -100ms));
-  thread.join();
-#else
-  GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
-#endif
-}
-
-TEST(properties, WaitForPropertyCreation) {
-#if defined(__BIONIC__)
-  std::thread thread([&]() {
-    std::this_thread::sleep_for(100ms);
-    android::base::SetProperty("debug.libbase.WaitForPropertyCreation_test", "a");
-  });
-
-  ASSERT_TRUE(android::base::WaitForPropertyCreation(
-          "debug.libbase.WaitForPropertyCreation_test", 1s));
-  thread.join();
-#else
-  GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
-#endif
-}
-
-TEST(properties, WaitForPropertyCreation_timeout) {
-#if defined(__BIONIC__)
-  auto t0 = std::chrono::steady_clock::now();
-  ASSERT_FALSE(android::base::WaitForPropertyCreation(
-          "debug.libbase.WaitForPropertyCreation_timeout_test", 200ms));
-  auto t1 = std::chrono::steady_clock::now();
-
-  ASSERT_GE(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 200ms);
-  // Upper bounds on timing are inherently flaky, but let's try...
-  ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 600ms);
-#else
-  GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
-#endif
-}
-
-TEST(properties, CachedProperty) {
-#if defined(__BIONIC__)
-  android::base::CachedProperty cached_property("debug.libbase.CachedProperty_test");
-  bool changed;
-  cached_property.Get(&changed);
-
-  android::base::SetProperty("debug.libbase.CachedProperty_test", "foo");
-  ASSERT_STREQ("foo", cached_property.Get(&changed));
-  ASSERT_TRUE(changed);
-
-  ASSERT_STREQ("foo", cached_property.Get(&changed));
-  ASSERT_FALSE(changed);
-
-  android::base::SetProperty("debug.libbase.CachedProperty_test", "bar");
-  ASSERT_STREQ("bar", cached_property.Get(&changed));
-  ASSERT_TRUE(changed);
-
-  ASSERT_STREQ("bar", cached_property.Get(&changed));
-  ASSERT_FALSE(changed);
-
-#else
-  GTEST_LOG_(INFO) << "This test does nothing on the host.\n";
-#endif
-}
diff --git a/base/result_test.cpp b/base/result_test.cpp
deleted file mode 100644
index c0ac0fd..0000000
--- a/base/result_test.cpp
+++ /dev/null
@@ -1,422 +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 "android-base/result.h"
-
-#include "errno.h"
-
-#include <istream>
-#include <string>
-
-#include <gtest/gtest.h>
-
-using namespace std::string_literals;
-
-namespace android {
-namespace base {
-
-TEST(result, result_accessors) {
-  Result<std::string> result = "success";
-  ASSERT_RESULT_OK(result);
-  ASSERT_TRUE(result.has_value());
-
-  EXPECT_EQ("success", *result);
-  EXPECT_EQ("success", result.value());
-
-  EXPECT_EQ('s', result->data()[0]);
-}
-
-TEST(result, result_accessors_rvalue) {
-  ASSERT_TRUE(Result<std::string>("success").ok());
-  ASSERT_TRUE(Result<std::string>("success").has_value());
-
-  EXPECT_EQ("success", *Result<std::string>("success"));
-  EXPECT_EQ("success", Result<std::string>("success").value());
-
-  EXPECT_EQ('s', Result<std::string>("success")->data()[0]);
-}
-
-TEST(result, result_void) {
-  Result<void> ok = {};
-  EXPECT_RESULT_OK(ok);
-  ok.value();  // should not crash
-  ASSERT_DEATH(ok.error(), "");
-
-  Result<void> fail = Error() << "failure" << 1;
-  EXPECT_FALSE(fail.ok());
-  EXPECT_EQ("failure1", fail.error().message());
-  EXPECT_EQ(0, fail.error().code());
-  EXPECT_TRUE(ok != fail);
-  ASSERT_DEATH(fail.value(), "");
-
-  auto test = [](bool ok) -> Result<void> {
-    if (ok) return {};
-    else return Error() << "failure" << 1;
-  };
-  EXPECT_TRUE(test(true).ok());
-  EXPECT_FALSE(test(false).ok());
-  test(true).value();  // should not crash
-  ASSERT_DEATH(test(true).error(), "");
-  ASSERT_DEATH(test(false).value(), "");
-  EXPECT_EQ("failure1", test(false).error().message());
-}
-
-TEST(result, result_error) {
-  Result<void> result = Error() << "failure" << 1;
-  ASSERT_FALSE(result.ok());
-  ASSERT_FALSE(result.has_value());
-
-  EXPECT_EQ(0, result.error().code());
-  EXPECT_EQ("failure1", result.error().message());
-}
-
-TEST(result, result_error_empty) {
-  Result<void> result = Error();
-  ASSERT_FALSE(result.ok());
-  ASSERT_FALSE(result.has_value());
-
-  EXPECT_EQ(0, result.error().code());
-  EXPECT_EQ("", result.error().message());
-}
-
-TEST(result, result_error_rvalue) {
-  // Error() and ErrnoError() aren't actually used to create a Result<T> object.
-  // Under the hood, they are an intermediate class that can be implicitly constructed into a
-  // Result<T>.  This is needed both to create the ostream and because Error() itself, by
-  // definition will not know what the type, T, of the underlying Result<T> object that it would
-  // create is.
-
-  auto MakeRvalueErrorResult = []() -> Result<void> { return Error() << "failure" << 1; };
-  ASSERT_FALSE(MakeRvalueErrorResult().ok());
-  ASSERT_FALSE(MakeRvalueErrorResult().has_value());
-
-  EXPECT_EQ(0, MakeRvalueErrorResult().error().code());
-  EXPECT_EQ("failure1", MakeRvalueErrorResult().error().message());
-}
-
-TEST(result, result_errno_error) {
-  constexpr int test_errno = 6;
-  errno = test_errno;
-  Result<void> result = ErrnoError() << "failure" << 1;
-
-  ASSERT_FALSE(result.ok());
-  ASSERT_FALSE(result.has_value());
-
-  EXPECT_EQ(test_errno, result.error().code());
-  EXPECT_EQ("failure1: "s + strerror(test_errno), result.error().message());
-}
-
-TEST(result, result_errno_error_no_text) {
-  constexpr int test_errno = 6;
-  errno = test_errno;
-  Result<void> result = ErrnoError();
-
-  ASSERT_FALSE(result.ok());
-  ASSERT_FALSE(result.has_value());
-
-  EXPECT_EQ(test_errno, result.error().code());
-  EXPECT_EQ(strerror(test_errno), result.error().message());
-}
-
-TEST(result, result_error_from_other_result) {
-  auto error_text = "test error"s;
-  Result<void> result = Error() << error_text;
-
-  ASSERT_FALSE(result.ok());
-  ASSERT_FALSE(result.has_value());
-
-  Result<std::string> result2 = result.error();
-
-  ASSERT_FALSE(result2.ok());
-  ASSERT_FALSE(result2.has_value());
-
-  EXPECT_EQ(0, result2.error().code());
-  EXPECT_EQ(error_text, result2.error().message());
-}
-
-TEST(result, result_error_through_ostream) {
-  auto error_text = "test error"s;
-  Result<void> result = Error() << error_text;
-
-  ASSERT_FALSE(result.ok());
-  ASSERT_FALSE(result.has_value());
-
-  Result<std::string> result2 = Error() << result.error();
-
-  ASSERT_FALSE(result2.ok());
-  ASSERT_FALSE(result2.has_value());
-
-  EXPECT_EQ(0, result2.error().code());
-  EXPECT_EQ(error_text, result2.error().message());
-}
-
-TEST(result, result_errno_error_through_ostream) {
-  auto error_text = "test error"s;
-  constexpr int test_errno = 6;
-  errno = 6;
-  Result<void> result = ErrnoError() << error_text;
-
-  errno = 0;
-
-  ASSERT_FALSE(result.ok());
-  ASSERT_FALSE(result.has_value());
-
-  Result<std::string> result2 = Error() << result.error();
-
-  ASSERT_FALSE(result2.ok());
-  ASSERT_FALSE(result2.has_value());
-
-  EXPECT_EQ(test_errno, result2.error().code());
-  EXPECT_EQ(error_text + ": " + strerror(test_errno), result2.error().message());
-}
-
-TEST(result, constructor_forwarding) {
-  auto result = Result<std::string>(std::in_place, 5, 'a');
-
-  ASSERT_RESULT_OK(result);
-  ASSERT_TRUE(result.has_value());
-
-  EXPECT_EQ("aaaaa", *result);
-}
-
-struct ConstructorTracker {
-  static size_t constructor_called;
-  static size_t copy_constructor_called;
-  static size_t move_constructor_called;
-  static size_t copy_assignment_called;
-  static size_t move_assignment_called;
-
-  template <typename T>
-  ConstructorTracker(T&& string) : string(string) {
-    ++constructor_called;
-  }
-
-  ConstructorTracker(const ConstructorTracker& ct) {
-    ++copy_constructor_called;
-    string = ct.string;
-  }
-  ConstructorTracker(ConstructorTracker&& ct) noexcept {
-    ++move_constructor_called;
-    string = std::move(ct.string);
-  }
-  ConstructorTracker& operator=(const ConstructorTracker& ct) {
-    ++copy_assignment_called;
-    string = ct.string;
-    return *this;
-  }
-  ConstructorTracker& operator=(ConstructorTracker&& ct) noexcept {
-    ++move_assignment_called;
-    string = std::move(ct.string);
-    return *this;
-  }
-
-  std::string string;
-};
-
-size_t ConstructorTracker::constructor_called = 0;
-size_t ConstructorTracker::copy_constructor_called = 0;
-size_t ConstructorTracker::move_constructor_called = 0;
-size_t ConstructorTracker::copy_assignment_called = 0;
-size_t ConstructorTracker::move_assignment_called = 0;
-
-Result<ConstructorTracker> ReturnConstructorTracker(const std::string& in) {
-  if (in.empty()) {
-    return "literal string";
-  }
-  if (in == "test2") {
-    return ConstructorTracker(in + in + "2");
-  }
-  ConstructorTracker result(in + " " + in);
-  return result;
-};
-
-TEST(result, no_copy_on_return) {
-  // If returning parameters that may be used to implicitly construct the type T of Result<T>,
-  // then those parameters are forwarded to the construction of Result<T>.
-
-  // If returning an prvalue or xvalue, it will be move constructed during the construction of
-  // Result<T>.
-
-  // This check ensures that that is the case, and particularly that no copy constructors
-  // are called.
-
-  auto result1 = ReturnConstructorTracker("");
-  ASSERT_RESULT_OK(result1);
-  EXPECT_EQ("literal string", result1->string);
-  EXPECT_EQ(1U, ConstructorTracker::constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
-
-  auto result2 = ReturnConstructorTracker("test2");
-  ASSERT_RESULT_OK(result2);
-  EXPECT_EQ("test2test22", result2->string);
-  EXPECT_EQ(2U, ConstructorTracker::constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
-  EXPECT_EQ(1U, ConstructorTracker::move_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
-
-  auto result3 = ReturnConstructorTracker("test3");
-  ASSERT_RESULT_OK(result3);
-  EXPECT_EQ("test3 test3", result3->string);
-  EXPECT_EQ(3U, ConstructorTracker::constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
-  EXPECT_EQ(2U, ConstructorTracker::move_constructor_called);
-  EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
-  EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
-}
-
-// Below two tests require that we do not hide the move constructor with our forwarding reference
-// constructor.  This is done with by disabling the forwarding reference constructor if its first
-// and only type is Result<T>.
-TEST(result, result_result_with_success) {
-  auto return_result_result_with_success = []() -> Result<Result<void>> { return Result<void>(); };
-  auto result = return_result_result_with_success();
-  ASSERT_RESULT_OK(result);
-  ASSERT_RESULT_OK(*result);
-
-  auto inner_result = result.value();
-  ASSERT_RESULT_OK(inner_result);
-}
-
-TEST(result, result_result_with_failure) {
-  auto return_result_result_with_error = []() -> Result<Result<void>> {
-    return Result<void>(ResultError("failure string", 6));
-  };
-  auto result = return_result_result_with_error();
-  ASSERT_RESULT_OK(result);
-  ASSERT_FALSE(result->ok());
-  EXPECT_EQ("failure string", (*result).error().message());
-  EXPECT_EQ(6, (*result).error().code());
-}
-
-// This test requires that we disable the forwarding reference constructor if Result<T> is the
-// *only* type that we are forwarding.  In otherwords, if we are forwarding Result<T>, int to
-// construct a Result<T>, then we still need the constructor.
-TEST(result, result_two_parameter_constructor_same_type) {
-  struct TestStruct {
-    TestStruct(int value) : value_(value) {}
-    TestStruct(Result<TestStruct> result, int value) : value_(result->value_ * value) {}
-    int value_;
-  };
-
-  auto return_test_struct = []() -> Result<TestStruct> {
-    return Result<TestStruct>(std::in_place, Result<TestStruct>(std::in_place, 6), 6);
-  };
-
-  auto result = return_test_struct();
-  ASSERT_RESULT_OK(result);
-  EXPECT_EQ(36, result->value_);
-}
-
-TEST(result, die_on_access_failed_result) {
-  Result<std::string> result = Error();
-  ASSERT_DEATH(*result, "");
-}
-
-TEST(result, die_on_get_error_succesful_result) {
-  Result<std::string> result = "success";
-  ASSERT_DEATH(result.error(), "");
-}
-
-template <class CharT>
-std::basic_ostream<CharT>& SetErrnoToTwo(std::basic_ostream<CharT>& ss) {
-  errno = 2;
-  return ss;
-}
-
-TEST(result, preserve_errno) {
-  errno = 1;
-  int old_errno = errno;
-  Result<int> result = Error() << "Failed" << SetErrnoToTwo<char>;
-  ASSERT_FALSE(result.ok());
-  EXPECT_EQ(old_errno, errno);
-
-  errno = 1;
-  old_errno = errno;
-  Result<int> result2 = ErrnoError() << "Failed" << SetErrnoToTwo<char>;
-  ASSERT_FALSE(result2.ok());
-  EXPECT_EQ(old_errno, errno);
-  EXPECT_EQ(old_errno, result2.error().code());
-}
-
-TEST(result, error_with_fmt) {
-  Result<int> result = Errorf("{} {}!", "hello", "world");
-  EXPECT_EQ("hello world!", result.error().message());
-
-  result = Errorf("{} {}!", std::string("hello"), std::string("world"));
-  EXPECT_EQ("hello world!", result.error().message());
-
-  result = Errorf("{1} {0}!", "world", "hello");
-  EXPECT_EQ("hello world!", result.error().message());
-
-  result = Errorf("hello world!");
-  EXPECT_EQ("hello world!", result.error().message());
-
-  Result<int> result2 = Errorf("error occurred with {}", result.error());
-  EXPECT_EQ("error occurred with hello world!", result2.error().message());
-
-  constexpr int test_errno = 6;
-  errno = test_errno;
-  result = ErrnoErrorf("{} {}!", "hello", "world");
-  EXPECT_EQ(test_errno, result.error().code());
-  EXPECT_EQ("hello world!: "s + strerror(test_errno), result.error().message());
-}
-
-TEST(result, error_with_fmt_carries_errno) {
-  constexpr int inner_errno = 6;
-  errno = inner_errno;
-  Result<int> inner_result = ErrnoErrorf("inner failure");
-  errno = 0;
-  EXPECT_EQ(inner_errno, inner_result.error().code());
-
-  // outer_result is created with Errorf, but its error code is got from inner_result.
-  Result<int> outer_result = Errorf("outer failure caused by {}", inner_result.error());
-  EXPECT_EQ(inner_errno, outer_result.error().code());
-  EXPECT_EQ("outer failure caused by inner failure: "s + strerror(inner_errno),
-            outer_result.error().message());
-
-  // now both result objects are created with ErrnoErrorf. errno from the inner_result
-  // is not passed to outer_result.
-  constexpr int outer_errno = 10;
-  errno = outer_errno;
-  outer_result = ErrnoErrorf("outer failure caused by {}", inner_result.error());
-  EXPECT_EQ(outer_errno, outer_result.error().code());
-  EXPECT_EQ("outer failure caused by inner failure: "s + strerror(inner_errno) + ": "s +
-                strerror(outer_errno),
-            outer_result.error().message());
-}
-
-TEST(result, errno_chaining_multiple) {
-  constexpr int errno1 = 6;
-  errno = errno1;
-  Result<int> inner1 = ErrnoErrorf("error1");
-
-  constexpr int errno2 = 10;
-  errno = errno2;
-  Result<int> inner2 = ErrnoErrorf("error2");
-
-  // takes the error code of inner2 since its the last one.
-  Result<int> outer = Errorf("two errors: {}, {}", inner1.error(), inner2.error());
-  EXPECT_EQ(errno2, outer.error().code());
-  EXPECT_EQ("two errors: error1: "s + strerror(errno1) + ", error2: "s + strerror(errno2),
-            outer.error().message());
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/scopeguard_test.cpp b/base/scopeguard_test.cpp
deleted file mode 100644
index 9236d7b..0000000
--- a/base/scopeguard_test.cpp
+++ /dev/null
@@ -1,59 +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 "android-base/scopeguard.h"
-
-#include <utility>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-TEST(scopeguard, normal) {
-  bool guarded_var = true;
-  {
-    auto scopeguard = android::base::make_scope_guard([&guarded_var] { guarded_var = false; });
-  }
-  ASSERT_FALSE(guarded_var);
-}
-
-TEST(scopeguard, disabled) {
-  bool guarded_var = true;
-  {
-    auto scopeguard = android::base::make_scope_guard([&guarded_var] { guarded_var = false; });
-    scopeguard.Disable();
-  }
-  ASSERT_TRUE(guarded_var);
-}
-
-TEST(scopeguard, moved) {
-  int guarded_var = true;
-  auto scopeguard = android::base::make_scope_guard([&guarded_var] { guarded_var = false; });
-  { decltype(scopeguard) new_guard(std::move(scopeguard)); }
-  EXPECT_FALSE(scopeguard.active());
-  ASSERT_FALSE(guarded_var);
-}
-
-TEST(scopeguard, vector) {
-  int guarded_var = 0;
-  {
-    std::vector<android::base::ScopeGuard<std::function<void()>>> scopeguards;
-    scopeguards.emplace_back(android::base::make_scope_guard(
-        std::bind([](int& guarded_var) { guarded_var++; }, std::ref(guarded_var))));
-    scopeguards.emplace_back(android::base::make_scope_guard(
-        std::bind([](int& guarded_var) { guarded_var++; }, std::ref(guarded_var))));
-  }
-  ASSERT_EQ(guarded_var, 2);
-}
diff --git a/base/stringprintf.cpp b/base/stringprintf.cpp
deleted file mode 100644
index 78e1e8d..0000000
--- a/base/stringprintf.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2011 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 "android-base/stringprintf.h"
-
-#include <stdio.h>
-
-#include <string>
-
-namespace android {
-namespace base {
-
-void StringAppendV(std::string* dst, const char* format, va_list ap) {
-  // First try with a small fixed size buffer
-  char space[1024];
-
-  // It's possible for methods that use a va_list to invalidate
-  // the data in it upon use.  The fix is to make a copy
-  // of the structure before using it and use that copy instead.
-  va_list backup_ap;
-  va_copy(backup_ap, ap);
-  int result = vsnprintf(space, sizeof(space), format, backup_ap);
-  va_end(backup_ap);
-
-  if (result < static_cast<int>(sizeof(space))) {
-    if (result >= 0) {
-      // Normal case -- everything fit.
-      dst->append(space, result);
-      return;
-    }
-
-    if (result < 0) {
-      // Just an error.
-      return;
-    }
-  }
-
-  // Increase the buffer size to the size requested by vsnprintf,
-  // plus one for the closing \0.
-  int length = result + 1;
-  char* buf = new char[length];
-
-  // Restore the va_list before we use it again
-  va_copy(backup_ap, ap);
-  result = vsnprintf(buf, length, format, backup_ap);
-  va_end(backup_ap);
-
-  if (result >= 0 && result < length) {
-    // It fit
-    dst->append(buf, result);
-  }
-  delete[] buf;
-}
-
-std::string StringPrintf(const char* fmt, ...) {
-  va_list ap;
-  va_start(ap, fmt);
-  std::string result;
-  StringAppendV(&result, fmt, ap);
-  va_end(ap);
-  return result;
-}
-
-void StringAppendF(std::string* dst, const char* format, ...) {
-  va_list ap;
-  va_start(ap, format);
-  StringAppendV(dst, format, ap);
-  va_end(ap);
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/stringprintf_test.cpp b/base/stringprintf_test.cpp
deleted file mode 100644
index fc009b1..0000000
--- a/base/stringprintf_test.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2011 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 "android-base/stringprintf.h"
-
-#include <gtest/gtest.h>
-
-#include <string>
-
-TEST(StringPrintfTest, HexSizeT) {
-  size_t size = 0x00107e59;
-  EXPECT_EQ("00107e59", android::base::StringPrintf("%08zx", size));
-  EXPECT_EQ("0x00107e59", android::base::StringPrintf("0x%08zx", size));
-}
-
-TEST(StringPrintfTest, StringAppendF) {
-  std::string s("a");
-  android::base::StringAppendF(&s, "b");
-  EXPECT_EQ("ab", s);
-}
-
-TEST(StringPrintfTest, Errno) {
-  errno = 123;
-  android::base::StringPrintf("hello %s", "world");
-  EXPECT_EQ(123, errno);
-}
-
-void TestN(size_t n) {
-  char* buf = new char[n + 1];
-  memset(buf, 'x', n);
-  buf[n] = '\0';
-  std::string s(android::base::StringPrintf("%s", buf));
-  EXPECT_EQ(buf, s);
-  delete[] buf;
-}
-
-TEST(StringPrintfTest, At1023) {
-  TestN(1023);
-}
-
-TEST(StringPrintfTest, At1024) {
-  TestN(1024);
-}
-
-TEST(StringPrintfTest, At1025) {
-  TestN(1025);
-}
diff --git a/base/strings.cpp b/base/strings.cpp
deleted file mode 100644
index 40b2bf2..0000000
--- a/base/strings.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2015 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 "android-base/strings.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <string>
-#include <vector>
-
-namespace android {
-namespace base {
-
-#define CHECK_NE(a, b) \
-  if ((a) == (b)) abort();
-
-std::vector<std::string> Split(const std::string& s,
-                               const std::string& delimiters) {
-  CHECK_NE(delimiters.size(), 0U);
-
-  std::vector<std::string> result;
-
-  size_t base = 0;
-  size_t found;
-  while (true) {
-    found = s.find_first_of(delimiters, base);
-    result.push_back(s.substr(base, found - base));
-    if (found == s.npos) break;
-    base = found + 1;
-  }
-
-  return result;
-}
-
-std::string Trim(const std::string& s) {
-  std::string result;
-
-  if (s.size() == 0) {
-    return result;
-  }
-
-  size_t start_index = 0;
-  size_t end_index = s.size() - 1;
-
-  // Skip initial whitespace.
-  while (start_index < s.size()) {
-    if (!isspace(s[start_index])) {
-      break;
-    }
-    start_index++;
-  }
-
-  // Skip terminating whitespace.
-  while (end_index >= start_index) {
-    if (!isspace(s[end_index])) {
-      break;
-    }
-    end_index--;
-  }
-
-  // All spaces, no beef.
-  if (end_index < start_index) {
-    return "";
-  }
-  // Start_index is the first non-space, end_index is the last one.
-  return s.substr(start_index, end_index - start_index + 1);
-}
-
-// These cases are probably the norm, so we mark them extern in the header to
-// aid compile time and binary size.
-template std::string Join(const std::vector<std::string>&, char);
-template std::string Join(const std::vector<const char*>&, char);
-template std::string Join(const std::vector<std::string>&, const std::string&);
-template std::string Join(const std::vector<const char*>&, const std::string&);
-
-bool StartsWith(std::string_view s, std::string_view prefix) {
-  return s.substr(0, prefix.size()) == prefix;
-}
-
-bool StartsWith(std::string_view s, char prefix) {
-  return !s.empty() && s.front() == prefix;
-}
-
-bool StartsWithIgnoreCase(std::string_view s, std::string_view prefix) {
-  return s.size() >= prefix.size() && strncasecmp(s.data(), prefix.data(), prefix.size()) == 0;
-}
-
-bool EndsWith(std::string_view s, std::string_view suffix) {
-  return s.size() >= suffix.size() && s.substr(s.size() - suffix.size(), suffix.size()) == suffix;
-}
-
-bool EndsWith(std::string_view s, char suffix) {
-  return !s.empty() && s.back() == suffix;
-}
-
-bool EndsWithIgnoreCase(std::string_view s, std::string_view suffix) {
-  return s.size() >= suffix.size() &&
-         strncasecmp(s.data() + (s.size() - suffix.size()), suffix.data(), suffix.size()) == 0;
-}
-
-bool EqualsIgnoreCase(std::string_view lhs, std::string_view rhs) {
-  return lhs.size() == rhs.size() && strncasecmp(lhs.data(), rhs.data(), lhs.size()) == 0;
-}
-
-std::string StringReplace(std::string_view s, std::string_view from, std::string_view to,
-                          bool all) {
-  if (from.empty()) return std::string(s);
-
-  std::string result;
-  std::string_view::size_type start_pos = 0;
-  do {
-    std::string_view::size_type pos = s.find(from, start_pos);
-    if (pos == std::string_view::npos) break;
-
-    result.append(s.data() + start_pos, pos - start_pos);
-    result.append(to.data(), to.size());
-
-    start_pos = pos + from.size();
-  } while (all);
-  result.append(s.data() + start_pos, s.size() - start_pos);
-  return result;
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
deleted file mode 100644
index 5ae3094..0000000
--- a/base/strings_test.cpp
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Copyright (C) 2015 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 "android-base/strings.h"
-
-#include <gtest/gtest.h>
-
-#include <string>
-#include <vector>
-#include <set>
-#include <unordered_set>
-
-TEST(strings, split_empty) {
-  std::vector<std::string> parts = android::base::Split("", ",");
-  ASSERT_EQ(1U, parts.size());
-  ASSERT_EQ("", parts[0]);
-}
-
-TEST(strings, split_single) {
-  std::vector<std::string> parts = android::base::Split("foo", ",");
-  ASSERT_EQ(1U, parts.size());
-  ASSERT_EQ("foo", parts[0]);
-}
-
-TEST(strings, split_simple) {
-  std::vector<std::string> parts = android::base::Split("foo,bar,baz", ",");
-  ASSERT_EQ(3U, parts.size());
-  ASSERT_EQ("foo", parts[0]);
-  ASSERT_EQ("bar", parts[1]);
-  ASSERT_EQ("baz", parts[2]);
-}
-
-TEST(strings, split_with_empty_part) {
-  std::vector<std::string> parts = android::base::Split("foo,,bar", ",");
-  ASSERT_EQ(3U, parts.size());
-  ASSERT_EQ("foo", parts[0]);
-  ASSERT_EQ("", parts[1]);
-  ASSERT_EQ("bar", parts[2]);
-}
-
-TEST(strings, split_with_trailing_empty_part) {
-  std::vector<std::string> parts = android::base::Split("foo,bar,", ",");
-  ASSERT_EQ(3U, parts.size());
-  ASSERT_EQ("foo", parts[0]);
-  ASSERT_EQ("bar", parts[1]);
-  ASSERT_EQ("", parts[2]);
-}
-
-TEST(strings, split_null_char) {
-  std::vector<std::string> parts =
-      android::base::Split(std::string("foo\0bar", 7), std::string("\0", 1));
-  ASSERT_EQ(2U, parts.size());
-  ASSERT_EQ("foo", parts[0]);
-  ASSERT_EQ("bar", parts[1]);
-}
-
-TEST(strings, split_any) {
-  std::vector<std::string> parts = android::base::Split("foo:bar,baz", ",:");
-  ASSERT_EQ(3U, parts.size());
-  ASSERT_EQ("foo", parts[0]);
-  ASSERT_EQ("bar", parts[1]);
-  ASSERT_EQ("baz", parts[2]);
-}
-
-TEST(strings, split_any_with_empty_part) {
-  std::vector<std::string> parts = android::base::Split("foo:,bar", ",:");
-  ASSERT_EQ(3U, parts.size());
-  ASSERT_EQ("foo", parts[0]);
-  ASSERT_EQ("", parts[1]);
-  ASSERT_EQ("bar", parts[2]);
-}
-
-TEST(strings, trim_empty) {
-  ASSERT_EQ("", android::base::Trim(""));
-}
-
-TEST(strings, trim_already_trimmed) {
-  ASSERT_EQ("foo", android::base::Trim("foo"));
-}
-
-TEST(strings, trim_left) {
-  ASSERT_EQ("foo", android::base::Trim(" foo"));
-}
-
-TEST(strings, trim_right) {
-  ASSERT_EQ("foo", android::base::Trim("foo "));
-}
-
-TEST(strings, trim_both) {
-  ASSERT_EQ("foo", android::base::Trim(" foo "));
-}
-
-TEST(strings, trim_no_trim_middle) {
-  ASSERT_EQ("foo bar", android::base::Trim("foo bar"));
-}
-
-TEST(strings, trim_other_whitespace) {
-  ASSERT_EQ("foo", android::base::Trim("\v\tfoo\n\f"));
-}
-
-TEST(strings, join_nothing) {
-  std::vector<std::string> list = {};
-  ASSERT_EQ("", android::base::Join(list, ','));
-}
-
-TEST(strings, join_single) {
-  std::vector<std::string> list = {"foo"};
-  ASSERT_EQ("foo", android::base::Join(list, ','));
-}
-
-TEST(strings, join_simple) {
-  std::vector<std::string> list = {"foo", "bar", "baz"};
-  ASSERT_EQ("foo,bar,baz", android::base::Join(list, ','));
-}
-
-TEST(strings, join_separator_in_vector) {
-  std::vector<std::string> list = {",", ","};
-  ASSERT_EQ(",,,", android::base::Join(list, ','));
-}
-
-TEST(strings, join_simple_ints) {
-  std::set<int> list = {1, 2, 3};
-  ASSERT_EQ("1,2,3", android::base::Join(list, ','));
-}
-
-TEST(strings, join_unordered_set) {
-  std::unordered_set<int> list = {1, 2};
-  ASSERT_TRUE("1,2" == android::base::Join(list, ',') ||
-              "2,1" == android::base::Join(list, ','));
-}
-
-TEST(strings, StartsWith_empty) {
-  ASSERT_FALSE(android::base::StartsWith("", "foo"));
-  ASSERT_TRUE(android::base::StartsWith("", ""));
-}
-
-TEST(strings, StartsWithIgnoreCase_empty) {
-  ASSERT_FALSE(android::base::StartsWithIgnoreCase("", "foo"));
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("", ""));
-}
-
-TEST(strings, StartsWith_simple) {
-  ASSERT_TRUE(android::base::StartsWith("foo", ""));
-  ASSERT_TRUE(android::base::StartsWith("foo", "f"));
-  ASSERT_TRUE(android::base::StartsWith("foo", "fo"));
-  ASSERT_TRUE(android::base::StartsWith("foo", "foo"));
-}
-
-TEST(strings, StartsWithIgnoreCase_simple) {
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", ""));
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "f"));
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "F"));
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fo"));
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fO"));
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "Fo"));
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FO"));
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "foo"));
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "foO"));
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fOo"));
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fOO"));
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "Foo"));
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FoO"));
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FOo"));
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FOO"));
-}
-
-TEST(strings, StartsWith_prefix_too_long) {
-  ASSERT_FALSE(android::base::StartsWith("foo", "foobar"));
-}
-
-TEST(strings, StartsWithIgnoreCase_prefix_too_long) {
-  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foo", "foobar"));
-  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foo", "FOOBAR"));
-}
-
-TEST(strings, StartsWith_contains_prefix) {
-  ASSERT_FALSE(android::base::StartsWith("foobar", "oba"));
-  ASSERT_FALSE(android::base::StartsWith("foobar", "bar"));
-}
-
-TEST(strings, StartsWithIgnoreCase_contains_prefix) {
-  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "oba"));
-  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "OBA"));
-  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "bar"));
-  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "BAR"));
-}
-
-TEST(strings, StartsWith_char) {
-  ASSERT_FALSE(android::base::StartsWith("", 'f'));
-  ASSERT_TRUE(android::base::StartsWith("foo", 'f'));
-  ASSERT_FALSE(android::base::StartsWith("foo", 'o'));
-}
-
-TEST(strings, EndsWith_empty) {
-  ASSERT_FALSE(android::base::EndsWith("", "foo"));
-  ASSERT_TRUE(android::base::EndsWith("", ""));
-}
-
-TEST(strings, EndsWithIgnoreCase_empty) {
-  ASSERT_FALSE(android::base::EndsWithIgnoreCase("", "foo"));
-  ASSERT_FALSE(android::base::EndsWithIgnoreCase("", "FOO"));
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("", ""));
-}
-
-TEST(strings, EndsWith_simple) {
-  ASSERT_TRUE(android::base::EndsWith("foo", ""));
-  ASSERT_TRUE(android::base::EndsWith("foo", "o"));
-  ASSERT_TRUE(android::base::EndsWith("foo", "oo"));
-  ASSERT_TRUE(android::base::EndsWith("foo", "foo"));
-}
-
-TEST(strings, EndsWithIgnoreCase_simple) {
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", ""));
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "o"));
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "O"));
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "oo"));
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "oO"));
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "Oo"));
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "OO"));
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "foo"));
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "foO"));
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "fOo"));
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "fOO"));
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "Foo"));
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FoO"));
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FOo"));
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FOO"));
-}
-
-TEST(strings, EndsWith_prefix_too_long) {
-  ASSERT_FALSE(android::base::EndsWith("foo", "foobar"));
-}
-
-TEST(strings, EndsWithIgnoreCase_prefix_too_long) {
-  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foo", "foobar"));
-  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foo", "FOOBAR"));
-}
-
-TEST(strings, EndsWith_contains_prefix) {
-  ASSERT_FALSE(android::base::EndsWith("foobar", "oba"));
-  ASSERT_FALSE(android::base::EndsWith("foobar", "foo"));
-}
-
-TEST(strings, EndsWithIgnoreCase_contains_prefix) {
-  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "OBA"));
-  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "FOO"));
-}
-
-TEST(strings, StartsWith_std_string) {
-  ASSERT_TRUE(android::base::StartsWith("hello", std::string{"hell"}));
-  ASSERT_FALSE(android::base::StartsWith("goodbye", std::string{"hell"}));
-}
-
-TEST(strings, StartsWithIgnoreCase_std_string) {
-  ASSERT_TRUE(android::base::StartsWithIgnoreCase("HeLlO", std::string{"hell"}));
-  ASSERT_FALSE(android::base::StartsWithIgnoreCase("GoOdByE", std::string{"hell"}));
-}
-
-TEST(strings, EndsWith_std_string) {
-  ASSERT_TRUE(android::base::EndsWith("hello", std::string{"lo"}));
-  ASSERT_FALSE(android::base::EndsWith("goodbye", std::string{"lo"}));
-}
-
-TEST(strings, EndsWithIgnoreCase_std_string) {
-  ASSERT_TRUE(android::base::EndsWithIgnoreCase("HeLlO", std::string{"lo"}));
-  ASSERT_FALSE(android::base::EndsWithIgnoreCase("GoOdByE", std::string{"lo"}));
-}
-
-TEST(strings, EndsWith_char) {
-  ASSERT_FALSE(android::base::EndsWith("", 'o'));
-  ASSERT_TRUE(android::base::EndsWith("foo", 'o'));
-  ASSERT_FALSE(android::base::EndsWith("foo", "f"));
-}
-
-TEST(strings, EqualsIgnoreCase) {
-  ASSERT_TRUE(android::base::EqualsIgnoreCase("foo", "FOO"));
-  ASSERT_TRUE(android::base::EqualsIgnoreCase("FOO", "foo"));
-  ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "bar"));
-  ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "fool"));
-}
-
-TEST(strings, ubsan_28729303) {
-  android::base::Split("/dev/null", ":");
-}
-
-TEST(strings, ConsumePrefix) {
-  std::string_view s{"foo.bar"};
-  ASSERT_FALSE(android::base::ConsumePrefix(&s, "bar."));
-  ASSERT_EQ("foo.bar", s);
-  ASSERT_TRUE(android::base::ConsumePrefix(&s, "foo."));
-  ASSERT_EQ("bar", s);
-}
-
-TEST(strings, ConsumeSuffix) {
-  std::string_view s{"foo.bar"};
-  ASSERT_FALSE(android::base::ConsumeSuffix(&s, ".foo"));
-  ASSERT_EQ("foo.bar", s);
-  ASSERT_TRUE(android::base::ConsumeSuffix(&s, ".bar"));
-  ASSERT_EQ("foo", s);
-}
-
-TEST(strings, StringReplace_false) {
-  // No change.
-  ASSERT_EQ("abcabc", android::base::StringReplace("abcabc", "z", "Z", false));
-  ASSERT_EQ("", android::base::StringReplace("", "z", "Z", false));
-  ASSERT_EQ("abcabc", android::base::StringReplace("abcabc", "", "Z", false));
-
-  // Equal lengths.
-  ASSERT_EQ("Abcabc", android::base::StringReplace("abcabc", "a", "A", false));
-  ASSERT_EQ("aBcabc", android::base::StringReplace("abcabc", "b", "B", false));
-  ASSERT_EQ("abCabc", android::base::StringReplace("abcabc", "c", "C", false));
-
-  // Longer replacement.
-  ASSERT_EQ("foobcabc", android::base::StringReplace("abcabc", "a", "foo", false));
-  ASSERT_EQ("afoocabc", android::base::StringReplace("abcabc", "b", "foo", false));
-  ASSERT_EQ("abfooabc", android::base::StringReplace("abcabc", "c", "foo", false));
-
-  // Shorter replacement.
-  ASSERT_EQ("xxyz", android::base::StringReplace("abcxyz", "abc", "x", false));
-  ASSERT_EQ("axyz", android::base::StringReplace("abcxyz", "bcx", "x", false));
-  ASSERT_EQ("abcx", android::base::StringReplace("abcxyz", "xyz", "x", false));
-}
-
-TEST(strings, StringReplace_true) {
-  // No change.
-  ASSERT_EQ("abcabc", android::base::StringReplace("abcabc", "z", "Z", true));
-  ASSERT_EQ("", android::base::StringReplace("", "z", "Z", true));
-  ASSERT_EQ("abcabc", android::base::StringReplace("abcabc", "", "Z", true));
-
-  // Equal lengths.
-  ASSERT_EQ("AbcAbc", android::base::StringReplace("abcabc", "a", "A", true));
-  ASSERT_EQ("aBcaBc", android::base::StringReplace("abcabc", "b", "B", true));
-  ASSERT_EQ("abCabC", android::base::StringReplace("abcabc", "c", "C", true));
-
-  // Longer replacement.
-  ASSERT_EQ("foobcfoobc", android::base::StringReplace("abcabc", "a", "foo", true));
-  ASSERT_EQ("afoocafooc", android::base::StringReplace("abcabc", "b", "foo", true));
-  ASSERT_EQ("abfooabfoo", android::base::StringReplace("abcabc", "c", "foo", true));
-
-  // Shorter replacement.
-  ASSERT_EQ("xxyzx", android::base::StringReplace("abcxyzabc", "abc", "x", true));
-  ASSERT_EQ("<xx>", android::base::StringReplace("<abcabc>", "abc", "x", true));
-}
diff --git a/base/test_main.cpp b/base/test_main.cpp
deleted file mode 100644
index 7fa6a84..0000000
--- a/base/test_main.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2015 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 <gtest/gtest.h>
-
-#include "android-base/logging.h"
-
-int main(int argc, char** argv) {
-  ::testing::InitGoogleTest(&argc, argv);
-  android::base::InitLogging(argv, android::base::StderrLogger);
-  return RUN_ALL_TESTS();
-}
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
deleted file mode 100644
index 36b4cdf..0000000
--- a/base/test_utils.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2015 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 "android-base/test_utils.h"
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-
-CapturedStdFd::CapturedStdFd(int std_fd) : std_fd_(std_fd), old_fd_(-1) {
-  Start();
-}
-
-CapturedStdFd::~CapturedStdFd() {
-  if (old_fd_ != -1) {
-    Stop();
-  }
-}
-
-int CapturedStdFd::fd() const {
-  return temp_file_.fd;
-}
-
-std::string CapturedStdFd::str() {
-  std::string result;
-  CHECK_EQ(0, TEMP_FAILURE_RETRY(lseek(fd(), 0, SEEK_SET)));
-  android::base::ReadFdToString(fd(), &result);
-  return result;
-}
-
-void CapturedStdFd::Reset() {
-  // Do not reset while capturing.
-  CHECK_EQ(-1, old_fd_);
-  CHECK_EQ(0, TEMP_FAILURE_RETRY(lseek(fd(), 0, SEEK_SET)));
-  CHECK_EQ(0, ftruncate(fd(), 0));
-}
-
-void CapturedStdFd::Start() {
-#if defined(_WIN32)
-  // On Windows, stderr is often buffered, so make sure it is unbuffered so
-  // that we can immediately read back what was written to stderr.
-  if (std_fd_ == STDERR_FILENO) CHECK_EQ(0, setvbuf(stderr, nullptr, _IONBF, 0));
-#endif
-  old_fd_ = dup(std_fd_);
-  CHECK_NE(-1, old_fd_);
-  CHECK_NE(-1, dup2(fd(), std_fd_));
-}
-
-void CapturedStdFd::Stop() {
-  CHECK_NE(-1, old_fd_);
-  CHECK_NE(-1, dup2(old_fd_, std_fd_));
-  close(old_fd_);
-  old_fd_ = -1;
-  // Note: cannot restore prior setvbuf() setting.
-}
diff --git a/base/test_utils_test.cpp b/base/test_utils_test.cpp
deleted file mode 100644
index 15a79dd..0000000
--- a/base/test_utils_test.cpp
+++ /dev/null
@@ -1,86 +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 <stdio.h>
-
-#include "android-base/test_utils.h"
-
-#include <gtest/gtest-spi.h>
-#include <gtest/gtest.h>
-
-namespace android {
-namespace base {
-
-TEST(TestUtilsTest, AssertMatch) {
-  ASSERT_MATCH("foobar", R"(fo+baz?r)");
-  EXPECT_FATAL_FAILURE(ASSERT_MATCH("foobar", R"(foobaz)"), "regex mismatch");
-}
-
-TEST(TestUtilsTest, AssertNotMatch) {
-  ASSERT_NOT_MATCH("foobar", R"(foobaz)");
-  EXPECT_FATAL_FAILURE(ASSERT_NOT_MATCH("foobar", R"(foobar)"), "regex mismatch");
-}
-
-TEST(TestUtilsTest, ExpectMatch) {
-  EXPECT_MATCH("foobar", R"(fo+baz?r)");
-  EXPECT_NONFATAL_FAILURE(EXPECT_MATCH("foobar", R"(foobaz)"), "regex mismatch");
-}
-
-TEST(TestUtilsTest, ExpectNotMatch) {
-  EXPECT_NOT_MATCH("foobar", R"(foobaz)");
-  EXPECT_NONFATAL_FAILURE(EXPECT_NOT_MATCH("foobar", R"(foobar)"), "regex mismatch");
-}
-
-TEST(TestUtilsTest, CaptureStdout_smoke) {
-  CapturedStdout cap;
-  printf("This should be captured.\n");
-  cap.Stop();
-  printf("This will not be captured.\n");
-  ASSERT_EQ("This should be captured.\n", cap.str());
-
-  cap.Start();
-  printf("And this text should be captured too.\n");
-  cap.Stop();
-  ASSERT_EQ("This should be captured.\nAnd this text should be captured too.\n", cap.str());
-
-  printf("Still not going to be captured.\n");
-  cap.Reset();
-  cap.Start();
-  printf("Only this will be captured.\n");
-  ASSERT_EQ("Only this will be captured.\n", cap.str());
-}
-
-TEST(TestUtilsTest, CaptureStderr_smoke) {
-  CapturedStderr cap;
-  fprintf(stderr, "This should be captured.\n");
-  cap.Stop();
-  fprintf(stderr, "This will not be captured.\n");
-  ASSERT_EQ("This should be captured.\n", cap.str());
-
-  cap.Start();
-  fprintf(stderr, "And this text should be captured too.\n");
-  cap.Stop();
-  ASSERT_EQ("This should be captured.\nAnd this text should be captured too.\n", cap.str());
-
-  fprintf(stderr, "Still not going to be captured.\n");
-  cap.Reset();
-  cap.Start();
-  fprintf(stderr, "Only this will be captured.\n");
-  ASSERT_EQ("Only this will be captured.\n", cap.str());
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/threads.cpp b/base/threads.cpp
deleted file mode 100644
index 48f6197..0000000
--- a/base/threads.cpp
+++ /dev/null
@@ -1,54 +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 <android-base/threads.h>
-
-#include <stdint.h>
-#include <unistd.h>
-
-#if defined(__APPLE__)
-#include <pthread.h>
-#elif defined(__linux__) && !defined(__ANDROID__)
-#include <syscall.h>
-#elif defined(_WIN32)
-#include <windows.h>
-#endif
-
-namespace android {
-namespace base {
-
-uint64_t GetThreadId() {
-#if defined(__BIONIC__)
-  return gettid();
-#elif defined(__APPLE__)
-  uint64_t tid;
-  pthread_threadid_np(NULL, &tid);
-  return tid;
-#elif defined(__linux__)
-  return syscall(__NR_gettid);
-#elif defined(_WIN32)
-  return GetCurrentThreadId();
-#endif
-}
-
-}  // namespace base
-}  // namespace android
-
-#if defined(__GLIBC__)
-int tgkill(int tgid, int tid, int sig) {
-  return syscall(__NR_tgkill, tgid, tid, sig);
-}
-#endif
diff --git a/base/tidy/unique_fd_test.cpp b/base/tidy/unique_fd_test.cpp
deleted file mode 100644
index b3a99fc..0000000
--- a/base/tidy/unique_fd_test.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2020 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 "android-base/unique_fd.h"
-
-#include <utility>
-
-#include <gtest/gtest.h>
-
-extern void consume_unique_fd(android::base::unique_fd fd);
-
-TEST(unique_fd, bugprone_use_after_move) {
-  // Compile time test for clang-tidy's bugprone-use-after-move check.
-  android::base::unique_fd ufd(open("/dev/null", O_RDONLY | O_CLOEXEC));
-  consume_unique_fd(std::move(ufd));
-  ufd.reset(open("/dev/null", O_RDONLY | O_CLOEXEC));
-  ufd.get();
-  consume_unique_fd(std::move(ufd));
-}
diff --git a/base/tidy/unique_fd_test2.cpp b/base/tidy/unique_fd_test2.cpp
deleted file mode 100644
index b0c71e2..0000000
--- a/base/tidy/unique_fd_test2.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2020 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 "android-base/unique_fd.h"
-
-void consume_unique_fd(android::base::unique_fd) {}
diff --git a/base/utf8.cpp b/base/utf8.cpp
deleted file mode 100644
index adb46d0..0000000
--- a/base/utf8.cpp
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (C) 2015 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 <windows.h>
-
-#include "android-base/utf8.h"
-
-#include <fcntl.h>
-#include <stdio.h>
-
-#include <algorithm>
-#include <string>
-
-#include "android-base/logging.h"
-
-namespace android {
-namespace base {
-
-// Helper to set errno based on GetLastError() after WideCharToMultiByte()/MultiByteToWideChar().
-static void SetErrnoFromLastError() {
-  switch (GetLastError()) {
-    case ERROR_NO_UNICODE_TRANSLATION:
-      errno = EILSEQ;
-      break;
-    default:
-      errno = EINVAL;
-      break;
-  }
-}
-
-bool WideToUTF8(const wchar_t* utf16, const size_t size, std::string* utf8) {
-  utf8->clear();
-
-  if (size == 0) {
-    return true;
-  }
-
-  // TODO: Consider using std::wstring_convert once libcxx is supported on
-  // Windows.
-
-  // Only Vista or later has this flag that causes WideCharToMultiByte() to
-  // return an error on invalid characters.
-  const DWORD flags =
-#if (WINVER >= 0x0600)
-    WC_ERR_INVALID_CHARS;
-#else
-    0;
-#endif
-
-  const int chars_required = WideCharToMultiByte(CP_UTF8, flags, utf16, size,
-                                                 NULL, 0, NULL, NULL);
-  if (chars_required <= 0) {
-    SetErrnoFromLastError();
-    return false;
-  }
-
-  // This could potentially throw a std::bad_alloc exception.
-  utf8->resize(chars_required);
-
-  const int result = WideCharToMultiByte(CP_UTF8, flags, utf16, size,
-                                         &(*utf8)[0], chars_required, NULL,
-                                         NULL);
-  if (result != chars_required) {
-    SetErrnoFromLastError();
-    CHECK_LE(result, chars_required) << "WideCharToMultiByte wrote " << result
-        << " chars to buffer of " << chars_required << " chars";
-    utf8->clear();
-    return false;
-  }
-
-  return true;
-}
-
-bool WideToUTF8(const wchar_t* utf16, std::string* utf8) {
-  // Compute string length of NULL-terminated string with wcslen().
-  return WideToUTF8(utf16, wcslen(utf16), utf8);
-}
-
-bool WideToUTF8(const std::wstring& utf16, std::string* utf8) {
-  // Use the stored length of the string which allows embedded NULL characters
-  // to be converted.
-  return WideToUTF8(utf16.c_str(), utf16.length(), utf8);
-}
-
-// Internal helper function that takes MultiByteToWideChar() flags.
-static bool UTF8ToWideWithFlags(const char* utf8, const size_t size, std::wstring* utf16,
-                                const DWORD flags) {
-  utf16->clear();
-
-  if (size == 0) {
-    return true;
-  }
-
-  // TODO: Consider using std::wstring_convert once libcxx is supported on
-  // Windows.
-  const int chars_required = MultiByteToWideChar(CP_UTF8, flags, utf8, size,
-                                                 NULL, 0);
-  if (chars_required <= 0) {
-    SetErrnoFromLastError();
-    return false;
-  }
-
-  // This could potentially throw a std::bad_alloc exception.
-  utf16->resize(chars_required);
-
-  const int result = MultiByteToWideChar(CP_UTF8, flags, utf8, size,
-                                         &(*utf16)[0], chars_required);
-  if (result != chars_required) {
-    SetErrnoFromLastError();
-    CHECK_LE(result, chars_required) << "MultiByteToWideChar wrote " << result
-        << " chars to buffer of " << chars_required << " chars";
-    utf16->clear();
-    return false;
-  }
-
-  return true;
-}
-
-bool UTF8ToWide(const char* utf8, const size_t size, std::wstring* utf16) {
-  // If strictly interpreting as UTF-8 succeeds, return success.
-  if (UTF8ToWideWithFlags(utf8, size, utf16, MB_ERR_INVALID_CHARS)) {
-    return true;
-  }
-
-  const int saved_errno = errno;
-
-  // Fallback to non-strict interpretation, allowing invalid characters and
-  // converting as best as possible, and return false to signify a problem.
-  (void)UTF8ToWideWithFlags(utf8, size, utf16, 0);
-  errno = saved_errno;
-  return false;
-}
-
-bool UTF8ToWide(const char* utf8, std::wstring* utf16) {
-  // Compute string length of NULL-terminated string with strlen().
-  return UTF8ToWide(utf8, strlen(utf8), utf16);
-}
-
-bool UTF8ToWide(const std::string& utf8, std::wstring* utf16) {
-  // Use the stored length of the string which allows embedded NULL characters
-  // to be converted.
-  return UTF8ToWide(utf8.c_str(), utf8.length(), utf16);
-}
-
-static bool isDriveLetter(wchar_t c) {
-  return (c >= L'a' && c <= L'z') || (c >= L'A' && c <= L'Z');
-}
-
-bool UTF8PathToWindowsLongPath(const char* utf8, std::wstring* utf16) {
-  if (!UTF8ToWide(utf8, utf16)) {
-    return false;
-  }
-  // Note: Although most Win32 File I/O API are limited to MAX_PATH (260
-  //       characters), the CreateDirectory API is limited to 248 characters.
-  if (utf16->length() >= 248) {
-    // If path is of the form "x:\" or "x:/"
-    if (isDriveLetter((*utf16)[0]) && (*utf16)[1] == L':' &&
-        ((*utf16)[2] == L'\\' || (*utf16)[2] == L'/')) {
-      // Append long path prefix, and make sure there are no unix-style
-      // separators to ensure a fully compliant Win32 long path string.
-      utf16->insert(0, LR"(\\?\)");
-      std::replace(utf16->begin(), utf16->end(), L'/', L'\\');
-    }
-  }
-  return true;
-}
-
-// Versions of standard library APIs that support UTF-8 strings.
-namespace utf8 {
-
-FILE* fopen(const char* name, const char* mode) {
-  std::wstring name_utf16;
-  if (!UTF8PathToWindowsLongPath(name, &name_utf16)) {
-    return nullptr;
-  }
-
-  std::wstring mode_utf16;
-  if (!UTF8ToWide(mode, &mode_utf16)) {
-    return nullptr;
-  }
-
-  return _wfopen(name_utf16.c_str(), mode_utf16.c_str());
-}
-
-int mkdir(const char* name, mode_t) {
-  std::wstring name_utf16;
-  if (!UTF8PathToWindowsLongPath(name, &name_utf16)) {
-    return -1;
-  }
-
-  return _wmkdir(name_utf16.c_str());
-}
-
-int open(const char* name, int flags, ...) {
-  std::wstring name_utf16;
-  if (!UTF8PathToWindowsLongPath(name, &name_utf16)) {
-    return -1;
-  }
-
-  int mode = 0;
-  if ((flags & O_CREAT) != 0) {
-    va_list args;
-    va_start(args, flags);
-    mode = va_arg(args, int);
-    va_end(args);
-  }
-
-  return _wopen(name_utf16.c_str(), flags, mode);
-}
-
-int unlink(const char* name) {
-  std::wstring name_utf16;
-  if (!UTF8PathToWindowsLongPath(name, &name_utf16)) {
-    return -1;
-  }
-
-  return _wunlink(name_utf16.c_str());
-}
-
-}  // namespace utf8
-}  // namespace base
-}  // namespace android
diff --git a/base/utf8_test.cpp b/base/utf8_test.cpp
deleted file mode 100644
index 472e82c..0000000
--- a/base/utf8_test.cpp
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
-* Copyright (C) 2015 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 "android-base/utf8.h"
-
-#include <gtest/gtest.h>
-
-#include <fcntl.h>
-#include <stdlib.h>
-
-#include "android-base/file.h"
-#include "android-base/macros.h"
-#include "android-base/unique_fd.h"
-
-namespace android {
-namespace base {
-
-TEST(UTFStringConversionsTest, ConvertInvalidUTF8) {
-  std::wstring wide;
-
-  errno = 0;
-
-  // Standalone \xa2 is an invalid UTF-8 sequence, so this should return an
-  // error. Concatenate two C/C++ literal string constants to prevent the
-  // compiler from giving an error about "\xa2af" containing a "hex escape
-  // sequence out of range".
-  EXPECT_FALSE(android::base::UTF8ToWide("before\xa2" "after", &wide));
-
-  EXPECT_EQ(EILSEQ, errno);
-
-  // Even if an invalid character is encountered, UTF8ToWide() should still do
-  // its best to convert the rest of the string. sysdeps_win32.cpp:
-  // _console_write_utf8() depends on this behavior.
-  //
-  // Thus, we verify that the valid characters are converted, but we ignore the
-  // specific replacement character that UTF8ToWide() may replace the invalid
-  // UTF-8 characters with because we want to allow that to change if the
-  // implementation changes.
-  EXPECT_EQ(0U, wide.find(L"before"));
-  const wchar_t after_wide[] = L"after";
-  EXPECT_EQ(wide.length() - (arraysize(after_wide) - 1), wide.find(after_wide));
-}
-
-// Below is adapted from https://chromium.googlesource.com/chromium/src/+/master/base/strings/utf_string_conversions_unittest.cc
-
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// The tests below from utf_string_conversions_unittest.cc check for this
-// preprocessor symbol, so define it, as it is appropriate for Windows.
-#define WCHAR_T_IS_UTF16
-static_assert(sizeof(wchar_t) == 2, "wchar_t is not 2 bytes");
-
-// The tests below from utf_string_conversions_unittest.cc call versions of
-// UTF8ToWide() and WideToUTF8() that don't return success/failure, so these are
-// stub implementations with that signature. These are just for testing and
-// should not be moved to base because they assert/expect no errors which is
-// probably not a good idea (or at least it is something that should be left
-// up to the caller, not a base library).
-
-static std::wstring UTF8ToWide(const std::string& utf8) {
-  std::wstring utf16;
-  EXPECT_TRUE(UTF8ToWide(utf8, &utf16));
-  return utf16;
-}
-
-static std::string WideToUTF8(const std::wstring& utf16) {
-  std::string utf8;
-  EXPECT_TRUE(WideToUTF8(utf16, &utf8));
-  return utf8;
-}
-
-namespace {
-
-const wchar_t* const kConvertRoundtripCases[] = {
-  L"Google Video",
-  // "网页 图片 资讯更多 »"
-  L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb",
-  //  "Παγκόσμιος Ιστός"
-  L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
-  L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2",
-  // "Поиск страниц на русском"
-  L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442"
-  L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430"
-  L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c",
-  // "전체서비스"
-  L"\xc804\xccb4\xc11c\xbe44\xc2a4",
-
-  // Test characters that take more than 16 bits. This will depend on whether
-  // wchar_t is 16 or 32 bits.
-#if defined(WCHAR_T_IS_UTF16)
-  L"\xd800\xdf00",
-  // ?????  (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
-  L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44",
-#elif defined(WCHAR_T_IS_UTF32)
-  L"\x10300",
-  // ?????  (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
-  L"\x11d40\x11d41\x11d42\x11d43\x11d44",
-#endif
-};
-
-}  // namespace
-
-TEST(UTFStringConversionsTest, ConvertUTF8AndWide) {
-  // we round-trip all the wide strings through UTF-8 to make sure everything
-  // agrees on the conversion. This uses the stream operators to test them
-  // simultaneously.
-  for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
-    std::ostringstream utf8;
-    utf8 << WideToUTF8(kConvertRoundtripCases[i]);
-    std::wostringstream wide;
-    wide << UTF8ToWide(utf8.str());
-
-    EXPECT_EQ(kConvertRoundtripCases[i], wide.str());
-  }
-}
-
-TEST(UTFStringConversionsTest, ConvertUTF8AndWideEmptyString) {
-  // An empty std::wstring should be converted to an empty std::string,
-  // and vice versa.
-  std::wstring wempty;
-  std::string empty;
-  EXPECT_EQ(empty, WideToUTF8(wempty));
-  EXPECT_EQ(wempty, UTF8ToWide(empty));
-}
-
-TEST(UTFStringConversionsTest, ConvertUTF8ToWide) {
-  struct UTF8ToWideCase {
-    const char* utf8;
-    const wchar_t* wide;
-    bool success;
-  } convert_cases[] = {
-    // Regular UTF-8 input.
-    {"\xe4\xbd\xa0\xe5\xa5\xbd", L"\x4f60\x597d", true},
-    // Non-character is passed through.
-    {"\xef\xbf\xbfHello", L"\xffffHello", true},
-    // Truncated UTF-8 sequence.
-    {"\xe4\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false},
-    // Truncated off the end.
-    {"\xe5\xa5\xbd\xe4\xa0", L"\x597d\xfffd", false},
-    // Non-shortest-form UTF-8.
-    {"\xf0\x84\xbd\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false},
-    // This UTF-8 character decodes to a UTF-16 surrogate, which is illegal.
-    // Note that for whatever reason, this test fails on Windows XP.
-    {"\xed\xb0\x80", L"\xfffd", false},
-    // Non-BMP characters. The second is a non-character regarded as valid.
-    // The result will either be in UTF-16 or UTF-32.
-#if defined(WCHAR_T_IS_UTF16)
-    {"A\xF0\x90\x8C\x80z", L"A\xd800\xdf00z", true},
-    {"A\xF4\x8F\xBF\xBEz", L"A\xdbff\xdffez", true},
-#elif defined(WCHAR_T_IS_UTF32)
-    {"A\xF0\x90\x8C\x80z", L"A\x10300z", true},
-    {"A\xF4\x8F\xBF\xBEz", L"A\x10fffez", true},
-#endif
-  };
-
-  for (size_t i = 0; i < arraysize(convert_cases); i++) {
-    std::wstring converted;
-    errno = 0;
-    const bool success = UTF8ToWide(convert_cases[i].utf8,
-                                    strlen(convert_cases[i].utf8),
-                                    &converted);
-    EXPECT_EQ(convert_cases[i].success, success);
-    // The original test always compared expected and converted, but don't do
-    // that because our implementation of UTF8ToWide() does not guarantee to
-    // produce the same output in error situations.
-    if (success) {
-      std::wstring expected(convert_cases[i].wide);
-      EXPECT_EQ(expected, converted);
-    } else {
-      EXPECT_EQ(EILSEQ, errno);
-    }
-  }
-
-  // Manually test an embedded NULL.
-  std::wstring converted;
-  EXPECT_TRUE(UTF8ToWide("\00Z\t", 3, &converted));
-  ASSERT_EQ(3U, converted.length());
-  EXPECT_EQ(static_cast<wchar_t>(0), converted[0]);
-  EXPECT_EQ('Z', converted[1]);
-  EXPECT_EQ('\t', converted[2]);
-
-  // Make sure that conversion replaces, not appends.
-  EXPECT_TRUE(UTF8ToWide("B", 1, &converted));
-  ASSERT_EQ(1U, converted.length());
-  EXPECT_EQ('B', converted[0]);
-}
-
-#if defined(WCHAR_T_IS_UTF16)
-// This test is only valid when wchar_t == UTF-16.
-TEST(UTFStringConversionsTest, ConvertUTF16ToUTF8) {
-  struct WideToUTF8Case {
-    const wchar_t* utf16;
-    const char* utf8;
-    bool success;
-  } convert_cases[] = {
-    // Regular UTF-16 input.
-    {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true},
-    // Test a non-BMP character.
-    {L"\xd800\xdf00", "\xF0\x90\x8C\x80", true},
-    // Non-characters are passed through.
-    {L"\xffffHello", "\xEF\xBF\xBFHello", true},
-    {L"\xdbff\xdffeHello", "\xF4\x8F\xBF\xBEHello", true},
-    // The first character is a truncated UTF-16 character.
-    // Note that for whatever reason, this test fails on Windows XP.
-    {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd",
-#if (WINVER >= 0x0600)
-    // Only Vista and later has a new API/flag that correctly returns false.
-    false
-#else
-    true
-#endif
-    },
-    // Truncated at the end.
-    // Note that for whatever reason, this test fails on Windows XP.
-    {L"\x597d\xd800", "\xe5\xa5\xbd\xef\xbf\xbd",
-#if (WINVER >= 0x0600)
-    // Only Vista and later has a new API/flag that correctly returns false.
-    false
-#else
-    true
-#endif
-    },
-  };
-
-  for (size_t i = 0; i < arraysize(convert_cases); i++) {
-    std::string converted;
-    errno = 0;
-    const bool success = WideToUTF8(convert_cases[i].utf16,
-                                    wcslen(convert_cases[i].utf16),
-                                    &converted);
-    EXPECT_EQ(convert_cases[i].success, success);
-    // The original test always compared expected and converted, but don't do
-    // that because our implementation of WideToUTF8() does not guarantee to
-    // produce the same output in error situations.
-    if (success) {
-      std::string expected(convert_cases[i].utf8);
-      EXPECT_EQ(expected, converted);
-    } else {
-      EXPECT_EQ(EILSEQ, errno);
-    }
-  }
-}
-
-#elif defined(WCHAR_T_IS_UTF32)
-// This test is only valid when wchar_t == UTF-32.
-TEST(UTFStringConversionsTest, ConvertUTF32ToUTF8) {
-  struct WideToUTF8Case {
-    const wchar_t* utf32;
-    const char* utf8;
-    bool success;
-  } convert_cases[] = {
-    // Regular 16-bit input.
-    {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true},
-    // Test a non-BMP character.
-    {L"A\x10300z", "A\xF0\x90\x8C\x80z", true},
-    // Non-characters are passed through.
-    {L"\xffffHello", "\xEF\xBF\xBFHello", true},
-    {L"\x10fffeHello", "\xF4\x8F\xBF\xBEHello", true},
-    // Invalid Unicode code points.
-    {L"\xfffffffHello", "\xEF\xBF\xBDHello", false},
-    // The first character is a truncated UTF-16 character.
-    {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", false},
-    {L"\xdc01Hello", "\xef\xbf\xbdHello", false},
-  };
-
-  for (size_t i = 0; i < arraysize(convert_cases); i++) {
-    std::string converted;
-    EXPECT_EQ(convert_cases[i].success,
-              WideToUTF8(convert_cases[i].utf32,
-                         wcslen(convert_cases[i].utf32),
-                         &converted));
-    std::string expected(convert_cases[i].utf8);
-    EXPECT_EQ(expected, converted);
-  }
-}
-#endif  // defined(WCHAR_T_IS_UTF32)
-
-// The test below uses these types and functions, so just do enough to get the
-// test running.
-typedef wchar_t char16;
-typedef std::wstring string16;
-
-template<typename T>
-static void* WriteInto(T* t, size_t size) {
-  // std::(w)string::resize() already includes space for a NULL terminator.
-  t->resize(size - 1);
-  return &(*t)[0];
-}
-
-// A stub implementation that calls a helper from above, just to get the test
-// below working. This is just for testing and should not be moved to base
-// because this ignores errors which is probably not a good idea, plus it takes
-// a string16 type which we don't really have.
-static std::string UTF16ToUTF8(const string16& utf16) {
-  return WideToUTF8(utf16);
-}
-
-TEST(UTFStringConversionsTest, ConvertMultiString) {
-  static char16 multi16[] = {
-    'f', 'o', 'o', '\0',
-    'b', 'a', 'r', '\0',
-    'b', 'a', 'z', '\0',
-    '\0'
-  };
-  static char multi[] = {
-    'f', 'o', 'o', '\0',
-    'b', 'a', 'r', '\0',
-    'b', 'a', 'z', '\0',
-    '\0'
-  };
-  string16 multistring16;
-  memcpy(WriteInto(&multistring16, arraysize(multi16)), multi16,
-                   sizeof(multi16));
-  EXPECT_EQ(arraysize(multi16) - 1, multistring16.length());
-  std::string expected;
-  memcpy(WriteInto(&expected, arraysize(multi)), multi, sizeof(multi));
-  EXPECT_EQ(arraysize(multi) - 1, expected.length());
-  const std::string& converted = UTF16ToUTF8(multistring16);
-  EXPECT_EQ(arraysize(multi) - 1, converted.length());
-  EXPECT_EQ(expected, converted);
-}
-
-// The tests below from sys_string_conversions_unittest.cc call SysWideToUTF8()
-// and SysUTF8ToWide(), so these are stub implementations that call the helpers
-// above. These are just for testing and should not be moved to base because
-// they ignore errors which is probably not a good idea.
-
-static std::string SysWideToUTF8(const std::wstring& utf16) {
-  return WideToUTF8(utf16);
-}
-
-static std::wstring SysUTF8ToWide(const std::string& utf8) {
-  return UTF8ToWide(utf8);
-}
-
-// Below is adapted from https://chromium.googlesource.com/chromium/src/+/master/base/strings/sys_string_conversions_unittest.cc
-
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifdef WCHAR_T_IS_UTF32
-static const std::wstring kSysWideOldItalicLetterA = L"\x10300";
-#else
-static const std::wstring kSysWideOldItalicLetterA = L"\xd800\xdf00";
-#endif
-
-TEST(SysStrings, SysWideToUTF8) {
-  EXPECT_EQ("Hello, world", SysWideToUTF8(L"Hello, world"));
-  EXPECT_EQ("\xe4\xbd\xa0\xe5\xa5\xbd", SysWideToUTF8(L"\x4f60\x597d"));
-
-  // >16 bits
-  EXPECT_EQ("\xF0\x90\x8C\x80", SysWideToUTF8(kSysWideOldItalicLetterA));
-
-  // Error case. When Windows finds a UTF-16 character going off the end of
-  // a string, it just converts that literal value to UTF-8, even though this
-  // is invalid.
-  //
-  // This is what XP does, but Vista has different behavior, so we don't bother
-  // verifying it:
-  // EXPECT_EQ("\xE4\xBD\xA0\xED\xA0\x80zyxw",
-  //           SysWideToUTF8(L"\x4f60\xd800zyxw"));
-
-  // Test embedded NULLs.
-  std::wstring wide_null(L"a");
-  wide_null.push_back(0);
-  wide_null.push_back('b');
-
-  std::string expected_null("a");
-  expected_null.push_back(0);
-  expected_null.push_back('b');
-
-  EXPECT_EQ(expected_null, SysWideToUTF8(wide_null));
-}
-
-TEST(SysStrings, SysUTF8ToWide) {
-  EXPECT_EQ(L"Hello, world", SysUTF8ToWide("Hello, world"));
-  EXPECT_EQ(L"\x4f60\x597d", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5\xbd"));
-  // >16 bits
-  EXPECT_EQ(kSysWideOldItalicLetterA, SysUTF8ToWide("\xF0\x90\x8C\x80"));
-
-  // Error case. When Windows finds an invalid UTF-8 character, it just skips
-  // it. This seems weird because it's inconsistent with the reverse conversion.
-  //
-  // This is what XP does, but Vista has different behavior, so we don't bother
-  // verifying it:
-  // EXPECT_EQ(L"\x4f60zyxw", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5zyxw"));
-
-  // Test embedded NULLs.
-  std::string utf8_null("a");
-  utf8_null.push_back(0);
-  utf8_null.push_back('b');
-
-  std::wstring expected_null(L"a");
-  expected_null.push_back(0);
-  expected_null.push_back('b');
-
-  EXPECT_EQ(expected_null, SysUTF8ToWide(utf8_null));
-}
-
-TEST(UTF8PathToWindowsLongPathTest, DontAddPrefixIfShorterThanMaxPath) {
-  std::string utf8 = "c:\\mypath\\myfile.txt";
-
-  std::wstring wide;
-  EXPECT_TRUE(UTF8PathToWindowsLongPath(utf8.c_str(), &wide));
-
-  EXPECT_EQ(std::string::npos, wide.find(LR"(\\?\)"));
-}
-
-TEST(UTF8PathToWindowsLongPathTest, AddPrefixIfLongerThanMaxPath) {
-  std::string utf8 = "c:\\mypath";
-  while (utf8.length() < 300 /* MAX_PATH is 260 */) {
-    utf8 += "\\mypathsegment";
-  }
-
-  std::wstring wide;
-  EXPECT_TRUE(UTF8PathToWindowsLongPath(utf8.c_str(), &wide));
-
-  EXPECT_EQ(0U, wide.find(LR"(\\?\)"));
-  EXPECT_EQ(std::string::npos, wide.find(L"/"));
-}
-
-TEST(UTF8PathToWindowsLongPathTest, AddPrefixAndFixSeparatorsIfLongerThanMaxPath) {
-  std::string utf8 = "c:/mypath";
-  while (utf8.length() < 300 /* MAX_PATH is 260 */) {
-    utf8 += "/mypathsegment";
-  }
-
-  std::wstring wide;
-  EXPECT_TRUE(UTF8PathToWindowsLongPath(utf8.c_str(), &wide));
-
-  EXPECT_EQ(0U, wide.find(LR"(\\?\)"));
-  EXPECT_EQ(std::string::npos, wide.find(L"/"));
-}
-
-namespace utf8 {
-
-TEST(Utf8FilesTest, CanCreateOpenAndDeleteFileWithLongPath) {
-  TemporaryDir td;
-
-  // Create long directory path
-  std::string utf8 = td.path;
-  while (utf8.length() < 300 /* MAX_PATH is 260 */) {
-    utf8 += "\\mypathsegment";
-    EXPECT_EQ(0, mkdir(utf8.c_str(), 0));
-  }
-
-  // Create file
-  utf8 += "\\test-file.bin";
-  int flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
-  int mode = 0666;
-  android::base::unique_fd fd(open(utf8.c_str(), flags, mode));
-  EXPECT_NE(-1, fd.get());
-
-  // Close file
-  fd.reset();
-  EXPECT_EQ(-1, fd.get());
-
-  // Open file with fopen
-  FILE* file = fopen(utf8.c_str(), "rb");
-  EXPECT_NE(nullptr, file);
-
-  if (file) {
-    fclose(file);
-  }
-
-  // Delete file
-  EXPECT_EQ(0, unlink(utf8.c_str()));
-}
-
-}  // namespace utf8
-}  // namespace base
-}  // namespace android
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index d67b522..31c2d5d 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -169,6 +169,7 @@
         "libdebuggerd/backtrace.cpp",
         "libdebuggerd/gwp_asan.cpp",
         "libdebuggerd/open_files_list.cpp",
+        "libdebuggerd/scudo.cpp",
         "libdebuggerd/tombstone.cpp",
         "libdebuggerd/utility.cpp",
     ],
@@ -176,8 +177,13 @@
     local_include_dirs: ["libdebuggerd/include"],
     export_include_dirs: ["libdebuggerd/include"],
 
-    // Needed for private/bionic_fdsan.h
-    include_dirs: ["bionic/libc"],
+    include_dirs: [
+        // Needed for private/bionic_fdsan.h
+        "bionic/libc",
+
+        // Needed for scudo/interface.h
+        "external/scudo/standalone/include",
+    ],
     header_libs: [
         "bionic_libc_platform_headers",
         "gwp_asan_headers",
@@ -192,7 +198,10 @@
         "liblog",
     ],
 
-    whole_static_libs: ["gwp_asan_crash_handler"],
+    whole_static_libs: [
+        "gwp_asan_crash_handler",
+        "libscudo",
+    ],
 
     target: {
         recovery: {
@@ -206,6 +215,9 @@
         debuggable: {
             cflags: ["-DROOT_POSSIBLE"],
         },
+        experimental_mte: {
+            cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
+        },
     },
 }
 
@@ -256,6 +268,10 @@
         "gwp_asan_headers",
     ],
 
+    include_dirs: [
+        "external/scudo/standalone/include",
+    ],
+
     local_include_dirs: [
         "libdebuggerd",
     ],
@@ -271,6 +287,12 @@
     },
 
     test_suites: ["device-tests"],
+
+    product_variables: {
+        experimental_mte: {
+            cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
+        },
+    },
 }
 
 cc_benchmark {
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 0cd2350..d7cb972 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -289,6 +289,8 @@
       process_info->fdsan_table_address = crash_info->data.d.fdsan_table_address;
       process_info->gwp_asan_state = crash_info->data.d.gwp_asan_state;
       process_info->gwp_asan_metadata = crash_info->data.d.gwp_asan_metadata;
+      process_info->scudo_stack_depot = crash_info->data.d.scudo_stack_depot;
+      process_info->scudo_region_info = crash_info->data.d.scudo_region_info;
       FALLTHROUGH_INTENDED;
     case 1:
     case 2:
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 054f836..9d7658e 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -31,6 +31,9 @@
 
 #include <android/fdsan.h>
 #include <android/set_abort_message.h>
+#include <bionic/malloc.h>
+#include <bionic/mte.h>
+#include <bionic/mte_kernel.h>
 #include <bionic/reserved_signals.h>
 
 #include <android-base/cmsg.h>
@@ -331,6 +334,184 @@
       R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr (0x100000000000dead|0xdead))");
 }
 
+#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
+static void SetTagCheckingLevelSync() {
+  int tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
+  if (tagged_addr_ctrl < 0) {
+    abort();
+  }
+
+  tagged_addr_ctrl = (tagged_addr_ctrl & ~PR_MTE_TCF_MASK) | PR_MTE_TCF_SYNC;
+  if (prctl(PR_SET_TAGGED_ADDR_CTRL, tagged_addr_ctrl, 0, 0, 0) != 0) {
+    abort();
+  }
+
+  HeapTaggingLevel heap_tagging_level = M_HEAP_TAGGING_LEVEL_SYNC;
+  if (!android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &heap_tagging_level, sizeof(heap_tagging_level))) {
+    abort();
+  }
+}
+#endif
+
+TEST_F(CrasherTest, mte_uaf) {
+#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
+  if (!mte_supported()) {
+    GTEST_SKIP() << "Requires MTE";
+  }
+
+  int intercept_result;
+  unique_fd output_fd;
+  StartProcess([]() {
+    SetTagCheckingLevelSync();
+    volatile int* p = (volatile int*)malloc(16);
+    free((void *)p);
+    p[0] = 42;
+  });
+
+  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"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
+  ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a 16-byte allocation.*
+
+allocated by thread .*
+      #00 pc)");
+  ASSERT_MATCH(result, R"(deallocated by thread .*
+      #00 pc)");
+#else
+  GTEST_SKIP() << "Requires aarch64 + ANDROID_EXPERIMENTAL_MTE";
+#endif
+}
+
+TEST_F(CrasherTest, mte_overflow) {
+#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
+  if (!mte_supported()) {
+    GTEST_SKIP() << "Requires MTE";
+  }
+
+  int intercept_result;
+  unique_fd output_fd;
+  StartProcess([]() {
+    SetTagCheckingLevelSync();
+    volatile int* p = (volatile int*)malloc(16);
+    p[4] = 42;
+  });
+
+  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"(signal 11 \(SIGSEGV\))");
+  ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation.*
+
+allocated by thread .*
+      #00 pc)");
+#else
+  GTEST_SKIP() << "Requires aarch64 + ANDROID_EXPERIMENTAL_MTE";
+#endif
+}
+
+TEST_F(CrasherTest, mte_underflow) {
+#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
+  if (!mte_supported()) {
+    GTEST_SKIP() << "Requires MTE";
+  }
+
+  int intercept_result;
+  unique_fd output_fd;
+  StartProcess([]() {
+    SetTagCheckingLevelSync();
+    volatile int* p = (volatile int*)malloc(16);
+    p[-1] = 42;
+  });
+
+  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"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
+  ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a 16-byte allocation.*
+
+allocated by thread .*
+      #00 pc)");
+#else
+  GTEST_SKIP() << "Requires aarch64 + ANDROID_EXPERIMENTAL_MTE";
+#endif
+}
+
+TEST_F(CrasherTest, mte_multiple_causes) {
+#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
+  if (!mte_supported()) {
+    GTEST_SKIP() << "Requires MTE";
+  }
+
+  int intercept_result;
+  unique_fd output_fd;
+  StartProcess([]() {
+    SetTagCheckingLevelSync();
+
+    // Make two allocations with the same tag and close to one another. Check for both properties
+    // with a bounds check -- this relies on the fact that only if the allocations have the same tag
+    // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
+    // (some non-zero value << 56) apart.
+    //
+    // The out-of-bounds access will be considered either an overflow of one or an underflow of the
+    // other.
+    std::set<uintptr_t> allocs;
+    for (int i = 0; i != 4096; ++i) {
+      uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
+      auto it = allocs.insert(alloc).first;
+      if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
+        *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
+      }
+      if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
+        *reinterpret_cast<int*>(alloc + 16) = 42;
+      }
+    }
+  });
+
+  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"(signal 11 \(SIGSEGV\))");
+  ASSERT_MATCH(
+      result,
+      R"(Note: multiple potential causes for this crash were detected, listing them in decreasing order of probability.)");
+
+  // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
+  // overflows), so we can't match explicitly for an underflow message.
+  ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
+#else
+  GTEST_SKIP() << "Requires aarch64 + ANDROID_EXPERIMENTAL_MTE";
+#endif
+}
+
 TEST_F(CrasherTest, LD_PRELOAD) {
   int intercept_result;
   unique_fd output_fd;
diff --git a/debuggerd/include/debuggerd/handler.h b/debuggerd/include/debuggerd/handler.h
index 6650294..254ed4f 100644
--- a/debuggerd/include/debuggerd/handler.h
+++ b/debuggerd/include/debuggerd/handler.h
@@ -40,6 +40,8 @@
   void* fdsan_table;
   const gwp_asan::AllocatorState* gwp_asan_state;
   const gwp_asan::AllocationMetadata* gwp_asan_metadata;
+  const char* scudo_stack_depot;
+  const char* scudo_region_info;
 };
 
 // These callbacks are called in a signal handler, and thus must be async signal safe.
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h b/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h
new file mode 100644
index 0000000..4d00ece
--- /dev/null
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 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 "types.h"
+#include "utility.h"
+
+#include <memory.h>
+
+#include "scudo/interface.h"
+
+class ScudoCrashData {
+ public:
+  ScudoCrashData() = delete;
+  ~ScudoCrashData() = default;
+  ScudoCrashData(unwindstack::Memory* process_memory, const ProcessInfo& process_info);
+
+  bool CrashIsMine() const;
+
+  void DumpCause(log_t* log, unwindstack::Unwinder* unwinder) const;
+
+ private:
+  scudo_error_info error_info_ = {};
+  uintptr_t untagged_fault_addr_;
+
+  void DumpReport(const scudo_error_report* report, log_t* log,
+                  unwindstack::Unwinder* unwinder) const;
+};
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
index 35c3fd6..04c4b5c 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
@@ -41,6 +41,8 @@
   uintptr_t fdsan_table_address = 0;
   uintptr_t gwp_asan_state = 0;
   uintptr_t gwp_asan_metadata = 0;
+  uintptr_t scudo_stack_depot = 0;
+  uintptr_t scudo_region_info = 0;
 
   bool has_fault_address = false;
   uintptr_t fault_address = 0;
diff --git a/debuggerd/libdebuggerd/scudo.cpp b/debuggerd/libdebuggerd/scudo.cpp
new file mode 100644
index 0000000..f8bfe07
--- /dev/null
+++ b/debuggerd/libdebuggerd/scudo.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2020 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 "libdebuggerd/scudo.h"
+#include "libdebuggerd/gwp_asan.h"
+
+#include "unwindstack/Memory.h"
+#include "unwindstack/Unwinder.h"
+
+#include <bionic/macros.h>
+
+std::unique_ptr<char[]> AllocAndReadFully(unwindstack::Memory* process_memory, uint64_t addr,
+                                          size_t size) {
+  auto buf = std::make_unique<char[]>(size);
+  if (!process_memory->ReadFully(addr, buf.get(), size)) {
+    return std::unique_ptr<char[]>();
+  }
+  return buf;
+}
+
+static const uintptr_t kTagGranuleSize = 16;
+
+ScudoCrashData::ScudoCrashData(unwindstack::Memory* process_memory,
+                               const ProcessInfo& process_info) {
+  if (!process_info.has_fault_address) {
+    return;
+  }
+
+  auto stack_depot = AllocAndReadFully(process_memory, process_info.scudo_stack_depot,
+                                       __scudo_get_stack_depot_size());
+  auto region_info = AllocAndReadFully(process_memory, process_info.scudo_region_info,
+                                       __scudo_get_region_info_size());
+
+  untagged_fault_addr_ = untag_address(process_info.fault_address);
+  uintptr_t fault_page = untagged_fault_addr_ & ~(PAGE_SIZE - 1);
+
+  uintptr_t memory_begin = fault_page - PAGE_SIZE * 16;
+  if (memory_begin > fault_page) {
+    return;
+  }
+
+  uintptr_t memory_end = fault_page + PAGE_SIZE * 16;
+  if (memory_end < fault_page) {
+    return;
+  }
+
+  auto memory = std::make_unique<char[]>(memory_end - memory_begin);
+  for (auto i = memory_begin; i != memory_end; i += PAGE_SIZE) {
+    process_memory->ReadFully(i, memory.get() + i - memory_begin, PAGE_SIZE);
+  }
+
+  auto memory_tags = std::make_unique<char[]>((memory_end - memory_begin) / kTagGranuleSize);
+  for (auto i = memory_begin; i != memory_end; i += kTagGranuleSize) {
+    memory_tags[(i - memory_begin) / kTagGranuleSize] = process_memory->ReadTag(i);
+  }
+
+  __scudo_get_error_info(&error_info_, process_info.fault_address, stack_depot.get(),
+                         region_info.get(), memory.get(), memory_tags.get(), memory_begin,
+                         memory_end - memory_begin);
+}
+
+bool ScudoCrashData::CrashIsMine() const {
+  return error_info_.reports[0].error_type != UNKNOWN;
+}
+
+void ScudoCrashData::DumpCause(log_t* log, unwindstack::Unwinder* unwinder) const {
+  if (error_info_.reports[1].error_type != UNKNOWN) {
+    _LOG(log, logtype::HEADER,
+         "\nNote: multiple potential causes for this crash were detected, listing them in "
+         "decreasing order of probability.\n");
+  }
+
+  size_t report_num = 0;
+  while (report_num < sizeof(error_info_.reports) / sizeof(error_info_.reports[0]) &&
+         error_info_.reports[report_num].error_type != UNKNOWN) {
+    DumpReport(&error_info_.reports[report_num++], log, unwinder);
+  }
+}
+
+void ScudoCrashData::DumpReport(const scudo_error_report* report, log_t* log,
+                                unwindstack::Unwinder* unwinder) const {
+  const char *error_type_str;
+  switch (report->error_type) {
+    case USE_AFTER_FREE:
+      error_type_str = "Use After Free";
+      break;
+    case BUFFER_OVERFLOW:
+      error_type_str = "Buffer Overflow";
+      break;
+    case BUFFER_UNDERFLOW:
+      error_type_str = "Buffer Underflow";
+      break;
+    default:
+      error_type_str = "Unknown";
+      break;
+  }
+
+  uintptr_t diff;
+  const char* location_str;
+
+  if (untagged_fault_addr_ < report->allocation_address) {
+    // Buffer Underflow, 6 bytes left of a 41-byte allocation at 0xdeadbeef.
+    location_str = "left of";
+    diff = report->allocation_address - untagged_fault_addr_;
+  } else if (untagged_fault_addr_ - report->allocation_address < report->allocation_size) {
+    // Use After Free, 40 bytes into a 41-byte allocation at 0xdeadbeef.
+    location_str = "into";
+    diff = untagged_fault_addr_ - report->allocation_address;
+  } else {
+    // Buffer Overflow, 6 bytes right of a 41-byte allocation at 0xdeadbeef.
+    location_str = "right of";
+    diff = untagged_fault_addr_ - report->allocation_address - report->allocation_size;
+  }
+
+  // Suffix of 'bytes', i.e. 4 bytes' vs. '1 byte'.
+  const char* byte_suffix = "s";
+  if (diff == 1) {
+    byte_suffix = "";
+  }
+  _LOG(log, logtype::HEADER,
+       "\nCause: [MTE]: %s, %" PRIuPTR " byte%s %s a %zu-byte allocation at 0x%" PRIxPTR "\n",
+       error_type_str, diff, byte_suffix, location_str, report->allocation_size,
+       report->allocation_address);
+
+  if (report->allocation_trace[0]) {
+    _LOG(log, logtype::BACKTRACE, "\nallocated by thread %u:\n", report->allocation_tid);
+    unwinder->SetDisplayBuildID(true);
+    for (size_t i = 0; i < 64 && report->allocation_trace[i]; ++i) {
+      unwindstack::FrameData frame_data =
+          unwinder->BuildFrameFromPcOnly(report->allocation_trace[i]);
+      frame_data.num = i;
+      _LOG(log, logtype::BACKTRACE, "    %s\n", unwinder->FormatFrame(frame_data).c_str());
+    }
+  }
+
+  if (report->deallocation_trace[0]) {
+    _LOG(log, logtype::BACKTRACE, "\ndeallocated by thread %u:\n", report->deallocation_tid);
+    unwinder->SetDisplayBuildID(true);
+    for (size_t i = 0; i < 64 && report->deallocation_trace[i]; ++i) {
+      unwindstack::FrameData frame_data =
+          unwinder->BuildFrameFromPcOnly(report->deallocation_trace[i]);
+      frame_data.num = i;
+      _LOG(log, logtype::BACKTRACE, "    %s\n", unwinder->FormatFrame(frame_data).c_str());
+    }
+  }
+}
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index d6b2e25..ab65dd1 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -56,6 +56,7 @@
 #include "libdebuggerd/backtrace.h"
 #include "libdebuggerd/gwp_asan.h"
 #include "libdebuggerd/open_files_list.h"
+#include "libdebuggerd/scudo.h"
 #include "libdebuggerd/utility.h"
 
 #include "gwp_asan/common.h"
@@ -389,14 +390,17 @@
   }
 
   std::unique_ptr<GwpAsanCrashData> gwp_asan_crash_data;
+  std::unique_ptr<ScudoCrashData> scudo_crash_data;
   if (primary_thread) {
     gwp_asan_crash_data = std::make_unique<GwpAsanCrashData>(unwinder->GetProcessMemory().get(),
                                                              process_info, thread_info);
+    scudo_crash_data =
+        std::make_unique<ScudoCrashData>(unwinder->GetProcessMemory().get(), process_info);
   }
 
   if (primary_thread && gwp_asan_crash_data->CrashIsMine()) {
     gwp_asan_crash_data->DumpCause(log);
-  } else if (thread_info.siginfo) {
+  } else if (thread_info.siginfo && !(primary_thread && scudo_crash_data->CrashIsMine())) {
     dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps(),
                         thread_info.registers.get());
   }
@@ -427,6 +431,8 @@
       gwp_asan_crash_data->DumpAllocationTrace(log, unwinder);
     }
 
+    scudo_crash_data->DumpCause(log, unwinder);
+
     unwindstack::Maps* maps = unwinder->GetMaps();
     dump_memory_and_code(log, maps, unwinder->GetProcessMemory().get(),
                          thread_info.registers.get());
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 3bf28b6..c8a3431 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -35,6 +35,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <bionic/mte_kernel.h>
 #include <bionic/reserved_signals.h>
 #include <debuggerd/handler.h>
 #include <log/log.h>
@@ -374,6 +375,12 @@
           return "SEGV_ADIDERR";
         case SEGV_ADIPERR:
           return "SEGV_ADIPERR";
+#if defined(ANDROID_EXPERIMENTAL_MTE)
+        case SEGV_MTEAERR:
+          return "SEGV_MTEAERR";
+        case SEGV_MTESERR:
+          return "SEGV_MTESERR";
+#endif
       }
       static_assert(NSIGSEGV == SEGV_ADIPERR, "missing SEGV_* si_code");
       break;
diff --git a/debuggerd/protocol.h b/debuggerd/protocol.h
index e85660c..53a76ea 100644
--- a/debuggerd/protocol.h
+++ b/debuggerd/protocol.h
@@ -95,6 +95,8 @@
   uintptr_t fdsan_table_address;
   uintptr_t gwp_asan_state;
   uintptr_t gwp_asan_metadata;
+  uintptr_t scudo_stack_depot;
+  uintptr_t scudo_region_info;
 };
 
 struct __attribute__((__packed__)) CrashInfo {
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 3a2deb7..bdb786c 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -117,8 +117,10 @@
         "device/main.cpp",
         "device/usb.cpp",
         "device/usb_client.cpp",
+        "device/tcp_client.cpp",
         "device/utility.cpp",
         "device/variables.cpp",
+        "socket.cpp",
     ],
 
     shared_libs: [
@@ -143,12 +145,14 @@
     ],
 
     static_libs: [
+        "libgtest_prod",
         "libhealthhalutils",
         "libsnapshot_nobinder",
         "update_metadata-protos",
     ],
 
     header_libs: [
+        "avb_headers",
         "libsnapshot_headers",
     ]
 }
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index b8eee4a..2553353 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -625,7 +625,7 @@
         if (!sm) {
             return device->WriteFail("Unable to create SnapshotManager");
         }
-        if (!sm->HandleImminentDataWipe()) {
+        if (!sm->FinishMergeInRecovery()) {
             return device->WriteFail("Unable to finish snapshot merge");
         }
     } else {
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index bb085c5..1b0859f 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -19,6 +19,7 @@
 #include <algorithm>
 
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <android/hardware/boot/1.0/IBootControl.h>
 #include <android/hardware/fastboot/1.0/IFastboot.h>
@@ -28,6 +29,7 @@
 
 #include "constants.h"
 #include "flashing.h"
+#include "tcp_client.h"
 #include "usb_client.h"
 
 using android::fs_mgr::EnsurePathUnmounted;
@@ -60,11 +62,16 @@
               {FB_CMD_GSI, GsiHandler},
               {FB_CMD_SNAPSHOT_UPDATE, SnapshotUpdateHandler},
       }),
-      transport_(std::make_unique<ClientUsbTransport>()),
       boot_control_hal_(IBootControl::getService()),
       health_hal_(get_health_service()),
       fastboot_hal_(IFastboot::getService()),
       active_slot_("") {
+    if (android::base::GetProperty("fastbootd.protocol", "usb") == "tcp") {
+        transport_ = std::make_unique<ClientTcpTransport>();
+    } else {
+        transport_ = std::make_unique<ClientUsbTransport>();
+    }
+
     if (boot_control_hal_) {
         boot1_1_ = android::hardware::boot::V1_1::IBootControl::castFrom(boot_control_hal_);
     }
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index fd6ff8e..1bf4c9c 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -31,6 +31,7 @@
 #include <ext4_utils/ext4_utils.h>
 #include <fs_mgr_overlayfs.h>
 #include <fstab/fstab.h>
+#include <libavb/libavb.h>
 #include <liblp/builder.h>
 #include <liblp/liblp.h>
 #include <libsnapshot/snapshot.h>
@@ -122,6 +123,27 @@
     }
 }
 
+static void CopyAVBFooter(std::vector<char>* data, const uint64_t block_device_size) {
+    if (data->size() < AVB_FOOTER_SIZE) {
+        return;
+    }
+    std::string footer;
+    uint64_t footer_offset = data->size() - AVB_FOOTER_SIZE;
+    for (int idx = 0; idx < AVB_FOOTER_MAGIC_LEN; idx++) {
+        footer.push_back(data->at(footer_offset + idx));
+    }
+    if (0 != footer.compare(AVB_FOOTER_MAGIC)) {
+        return;
+    }
+
+    // copy AVB footer from end of data to end of block device
+    uint64_t original_data_size = data->size();
+    data->resize(block_device_size, 0);
+    for (int idx = 0; idx < AVB_FOOTER_SIZE; idx++) {
+        data->at(block_device_size - 1 - idx) = data->at(original_data_size - 1 - idx);
+    }
+}
+
 int Flash(FastbootDevice* device, const std::string& partition_name) {
     PartitionHandle handle;
     if (!OpenPartition(device, partition_name, &handle)) {
@@ -131,8 +153,14 @@
     std::vector<char> data = std::move(device->download_data());
     if (data.size() == 0) {
         return -EINVAL;
-    } else if (data.size() > get_block_device_size(handle.fd())) {
+    }
+    uint64_t block_device_size = get_block_device_size(handle.fd());
+    if (data.size() > block_device_size) {
         return -EOVERFLOW;
+    } else if (data.size() < block_device_size &&
+               (partition_name == "boot" || partition_name == "boot_a" ||
+                partition_name == "boot_b")) {
+        CopyAVBFooter(&data, block_device_size);
     }
     WipeOverlayfsForPartition(device, partition_name);
     int result = FlashBlockDevice(handle.fd(), data);
diff --git a/fastboot/device/tcp_client.cpp b/fastboot/device/tcp_client.cpp
new file mode 100644
index 0000000..ec5e1e3
--- /dev/null
+++ b/fastboot/device/tcp_client.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2020 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 "tcp_client.h"
+#include "constants.h"
+
+#include <android-base/errors.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+static constexpr int kDefaultPort = 5554;
+static constexpr int kProtocolVersion = 1;
+static constexpr int kHandshakeTimeoutMs = 2000;
+static constexpr size_t kHandshakeLength = 4;
+
+// Extract the big-endian 8-byte message length into a 64-bit number.
+static uint64_t ExtractMessageLength(const void* buffer) {
+    uint64_t ret = 0;
+    for (int i = 0; i < 8; ++i) {
+        ret |= uint64_t{reinterpret_cast<const uint8_t*>(buffer)[i]} << (56 - i * 8);
+    }
+    return ret;
+}
+
+// Encode the 64-bit number into a big-endian 8-byte message length.
+static void EncodeMessageLength(uint64_t length, void* buffer) {
+    for (int i = 0; i < 8; ++i) {
+        reinterpret_cast<uint8_t*>(buffer)[i] = length >> (56 - i * 8);
+    }
+}
+
+ClientTcpTransport::ClientTcpTransport() {
+    service_ = Socket::NewServer(Socket::Protocol::kTcp, kDefaultPort);
+
+    // A workaround to notify recovery to continue its work.
+    android::base::SetProperty("sys.usb.ffs.ready", "1");
+}
+
+ssize_t ClientTcpTransport::Read(void* data, size_t len) {
+    if (len > SSIZE_MAX) {
+        return -1;
+    }
+
+    size_t total_read = 0;
+    do {
+        // Read a new message
+        while (message_bytes_left_ == 0) {
+            if (socket_ == nullptr) {
+                ListenFastbootSocket();
+            }
+
+            char buffer[8];
+            if (socket_->ReceiveAll(buffer, 8, 0) == 8) {
+                message_bytes_left_ = ExtractMessageLength(buffer);
+            } else {
+                // If connection is closed by host, Receive will return 0 immediately.
+                socket_.reset(nullptr);
+                // In DATA phase, return error.
+                if (downloading_) {
+                    return -1;
+                }
+            }
+        }
+
+        size_t read_length = len - total_read;
+        if (read_length > message_bytes_left_) {
+            read_length = message_bytes_left_;
+        }
+        ssize_t bytes_read =
+                socket_->ReceiveAll(reinterpret_cast<char*>(data) + total_read, read_length, 0);
+        if (bytes_read == -1) {
+            socket_.reset(nullptr);
+            return -1;
+        } else {
+            message_bytes_left_ -= bytes_read;
+            total_read += bytes_read;
+        }
+    // There are more than one DATA phases if the downloading buffer is too
+    // large, like a very big system image. All of data phases should be
+    // received until the whole buffer is filled in that case.
+    } while (downloading_ && total_read < len);
+
+    return total_read;
+}
+
+ssize_t ClientTcpTransport::Write(const void* data, size_t len) {
+    if (socket_ == nullptr || len > SSIZE_MAX) {
+        return -1;
+    }
+
+    // Use multi-buffer writes for better performance.
+    char header[8];
+    EncodeMessageLength(len, header);
+
+    if (!socket_->Send(std::vector<cutils_socket_buffer_t>{{header, 8}, {data, len}})) {
+        socket_.reset(nullptr);
+        return -1;
+    }
+
+    // In DATA phase
+    if (android::base::StartsWith(reinterpret_cast<const char*>(data), RESPONSE_DATA)) {
+        downloading_ = true;
+    } else {
+        downloading_ = false;
+    }
+
+    return len;
+}
+
+int ClientTcpTransport::Close() {
+    if (socket_ == nullptr) {
+        return -1;
+    }
+    socket_.reset(nullptr);
+
+    return 0;
+}
+
+int ClientTcpTransport::Reset() {
+    return Close();
+}
+
+void ClientTcpTransport::ListenFastbootSocket() {
+    while (true) {
+        socket_ = service_->Accept();
+
+        // Handshake
+        char buffer[kHandshakeLength + 1];
+        buffer[kHandshakeLength] = '\0';
+        if (socket_->ReceiveAll(buffer, kHandshakeLength, kHandshakeTimeoutMs) !=
+            kHandshakeLength) {
+            PLOG(ERROR) << "No Handshake message received";
+            socket_.reset(nullptr);
+            continue;
+        }
+
+        if (memcmp(buffer, "FB", 2) != 0) {
+            PLOG(ERROR) << "Unrecognized initialization message";
+            socket_.reset(nullptr);
+            continue;
+        }
+
+        int version = 0;
+        if (!android::base::ParseInt(buffer + 2, &version) || version < kProtocolVersion) {
+            LOG(ERROR) << "Unknown TCP protocol version " << buffer + 2
+                       << ", our version: " << kProtocolVersion;
+            socket_.reset(nullptr);
+            continue;
+        }
+
+        std::string handshake_message(android::base::StringPrintf("FB%02d", kProtocolVersion));
+        if (!socket_->Send(handshake_message.c_str(), kHandshakeLength)) {
+            PLOG(ERROR) << "Failed to send initialization message";
+            socket_.reset(nullptr);
+            continue;
+        }
+
+        break;
+    }
+}
diff --git a/fastboot/device/tcp_client.h b/fastboot/device/tcp_client.h
new file mode 100644
index 0000000..32e9834
--- /dev/null
+++ b/fastboot/device/tcp_client.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 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 <memory>
+
+#include "socket.h"
+#include "transport.h"
+
+class ClientTcpTransport : public Transport {
+  public:
+    ClientTcpTransport();
+    ~ClientTcpTransport() override = default;
+
+    ssize_t Read(void* data, size_t len) override;
+    ssize_t Write(const void* data, size_t len) override;
+    int Close() override;
+    int Reset() override;
+
+  private:
+    void ListenFastbootSocket();
+
+    std::unique_ptr<Socket> service_;
+    std::unique_ptr<Socket> socket_;
+    uint64_t message_bytes_left_ = 0;
+    bool downloading_ = false;
+
+    DISALLOW_COPY_AND_ASSIGN(ClientTcpTransport);
+};
diff --git a/fastboot/socket.cpp b/fastboot/socket.cpp
index e56ffcf..5a14b63 100644
--- a/fastboot/socket.cpp
+++ b/fastboot/socket.cpp
@@ -54,7 +54,9 @@
     while (total < length) {
         ssize_t bytes = Receive(reinterpret_cast<char*>(data) + total, length - total, timeout_ms);
 
-        if (bytes == -1) {
+        // Returns 0 only when the peer has disconnected because our requested length is not 0. So
+        // we return immediately to avoid dead loop here.
+        if (bytes <= 0) {
             if (total == 0) {
                 return -1;
             }
diff --git a/fs_mgr/README.overlayfs.md b/fs_mgr/README.overlayfs.md
index f579078..ca782b9 100644
--- a/fs_mgr/README.overlayfs.md
+++ b/fs_mgr/README.overlayfs.md
@@ -42,7 +42,7 @@
     $ adb push <source> <destination>
     $ adb reboot
 
-Note that you can replace these two lines:
+Note that you can replace these two lines in the above sequence:
 
     $ adb disable-verity
     $ adb reboot
@@ -51,7 +51,7 @@
 
     $ adb remount -R
 
-**Note:** _adb reboot -R_ won’t reboot if the device is already in the adb remount state.
+**Note:** _adb remount -R_ won’t reboot if the device is already in the adb remount state.
 
 None of this changes if OverlayFS needs to be engaged.
 The decisions whether to use traditional direct file-system remount,
diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING
index 676f446..6cd0430 100644
--- a/fs_mgr/TEST_MAPPING
+++ b/fs_mgr/TEST_MAPPING
@@ -14,6 +14,9 @@
     },
     {
       "name": "vts_libsnapshot_test"
+    },
+    {
+      "name": "libsnapshot_fuzzer_test"
     }
   ]
 }
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index d2daaa1..8c2e001 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -454,7 +454,8 @@
                << entry.encryption_options;
         return;
     }
-    if ((options.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) != 0) {
+    if ((options.flags &
+         (FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 | FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) != 0) {
         // We can only use this policy on ext4 if the "stable_inodes" feature
         // is set on the filesystem, otherwise shrinking will break encrypted files.
         if ((sb->s_feature_compat & cpu_to_le32(EXT4_FEATURE_COMPAT_STABLE_INODES)) == 0) {
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index ea9c957..9046132 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -52,17 +52,27 @@
 using DmTargetZero = android::dm::DmTargetZero;
 using DmTargetLinear = android::dm::DmTargetLinear;
 
-static bool GetPhysicalPartitionDevicePath(const IPartitionOpener& opener,
-                                           const LpMetadata& metadata,
+static bool GetPhysicalPartitionDevicePath(const CreateLogicalPartitionParams& params,
                                            const LpMetadataBlockDevice& block_device,
                                            const std::string& super_device, std::string* result) {
     // If the super device is the source of this block device's metadata,
     // make sure we use the correct super device (and not just "super",
     // which might not exist.)
     std::string name = GetBlockDevicePartitionName(block_device);
-    std::string dev_string = opener.GetDeviceString(name);
-    if (GetMetadataSuperBlockDevice(metadata) == &block_device) {
-        dev_string = opener.GetDeviceString(super_device);
+    if (android::base::StartsWith(name, "dm-")) {
+        // Device-mapper nodes are not normally allowed in LpMetadata, since
+        // they are not consistent across reboots. However for the purposes of
+        // testing it's useful to handle them. For example when running DSUs,
+        // userdata is a device-mapper device, and some stacking will result
+        // when using libfiemap.
+        *result = "/dev/block/" + name;
+        return true;
+    }
+
+    auto opener = params.partition_opener;
+    std::string dev_string = opener->GetDeviceString(name);
+    if (GetMetadataSuperBlockDevice(*params.metadata) == &block_device) {
+        dev_string = opener->GetDeviceString(super_device);
     }
 
     // Note: device-mapper will not accept symlinks, so we must use realpath
@@ -93,8 +103,8 @@
             case LP_TARGET_TYPE_LINEAR: {
                 const auto& block_device = params.metadata->block_devices[extent.target_source];
                 std::string dev_string;
-                if (!GetPhysicalPartitionDevicePath(*params.partition_opener, *params.metadata,
-                                                    block_device, super_device, &dev_string)) {
+                if (!GetPhysicalPartitionDevicePath(params, block_device, super_device,
+                                                    &dev_string)) {
                     LOG(ERROR) << "Unable to complete device-mapper table, unknown block device";
                     return false;
                 }
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 24cbad7..052efa7 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -105,20 +105,23 @@
 
 }  // namespace
 
+enum RemountStatus {
+    REMOUNT_SUCCESS = 0,
+    NOT_USERDEBUG,
+    BADARG,
+    NOT_ROOT,
+    NO_FSTAB,
+    UNKNOWN_PARTITION,
+    INVALID_PARTITION,
+    VERITY_PARTITION,
+    BAD_OVERLAY,
+    NO_MOUNTS,
+    REMOUNT_FAILED,
+    MUST_REBOOT
+};
+
 static int do_remount(int argc, char* argv[]) {
-    enum {
-        SUCCESS = 0,
-        NOT_USERDEBUG,
-        BADARG,
-        NOT_ROOT,
-        NO_FSTAB,
-        UNKNOWN_PARTITION,
-        INVALID_PARTITION,
-        VERITY_PARTITION,
-        BAD_OVERLAY,
-        NO_MOUNTS,
-        REMOUNT_FAILED,
-    } retval = SUCCESS;
+    RemountStatus retval = REMOUNT_SUCCESS;
 
     // If somehow this executable is delivered on a "user" build, it can
     // not function, so providing a clear message to the caller rather than
@@ -304,8 +307,7 @@
     if (partitions.empty() || just_disabled_verity) {
         if (reboot_later) reboot(setup_overlayfs);
         if (user_please_reboot_later) {
-            LOG(INFO) << "Now reboot your device for settings to take effect";
-            return 0;
+            return MUST_REBOOT;
         }
         LOG(WARNING) << "No partitions to remount";
         return retval;
@@ -394,6 +396,12 @@
 int main(int argc, char* argv[]) {
     android::base::InitLogging(argv, MyLogger);
     int result = do_remount(argc, argv);
-    printf("remount %s\n", result ? "failed" : "succeeded");
+    if (result == MUST_REBOOT) {
+        LOG(INFO) << "Now reboot your device for settings to take effect";
+    } else if (result == REMOUNT_SUCCESS) {
+        printf("remount succeeded\n");
+    } else {
+        printf("remount failed\n");
+    }
     return result;
 }
diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp
index 9d18a44..cae43e6 100644
--- a/fs_mgr/libfiemap/Android.bp
+++ b/fs_mgr/libfiemap/Android.bp
@@ -69,6 +69,7 @@
         "libdm",
         "libfs_mgr",
         "liblog",
+        "libgsi",
     ],
 
     data: [
@@ -90,6 +91,7 @@
 cc_test {
     name: "fiemap_image_test",
     static_libs: [
+        "libcrypto_utils",
         "libdm",
         "libext4_utils",
         "libfs_mgr",
@@ -98,7 +100,6 @@
     shared_libs: [
         "libbase",
         "libcrypto",
-        "libcrypto_utils",
         "libcutils",
         "liblog",
     ],
@@ -117,6 +118,7 @@
         "-DSKIP_TEST_IN_PRESUBMIT",
     ],
     static_libs: [
+        "libcrypto_utils",
         "libdm",
         "libext4_utils",
         "libfs_mgr",
@@ -125,7 +127,6 @@
     shared_libs: [
         "libbase",
         "libcrypto",
-        "libcrypto_utils",
         "libcutils",
         "liblog",
     ],
diff --git a/fs_mgr/libfiemap/fiemap_writer_test.cpp b/fs_mgr/libfiemap/fiemap_writer_test.cpp
index 22a3722..3c8ab42 100644
--- a/fs_mgr/libfiemap/fiemap_writer_test.cpp
+++ b/fs_mgr/libfiemap/fiemap_writer_test.cpp
@@ -35,6 +35,7 @@
 #include <libdm/loop_control.h>
 #include <libfiemap/fiemap_writer.h>
 #include <libfiemap/split_fiemap_writer.h>
+#include <libgsi/libgsi.h>
 
 #include "utility.h"
 
@@ -148,7 +149,10 @@
     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);
+
+    if (!android::gsi::IsGsiRunning()) {
+        EXPECT_EQ(fptr->bdev_path().find("/dev/block/dm-"), string::npos);
+    }
 }
 
 TEST_F(FiemapWriterTest, CheckFileCreated) {
diff --git a/fs_mgr/libfiemap/image_manager.cpp b/fs_mgr/libfiemap/image_manager.cpp
index 6717922..3ee742f 100644
--- a/fs_mgr/libfiemap/image_manager.cpp
+++ b/fs_mgr/libfiemap/image_manager.cpp
@@ -51,6 +51,7 @@
 using android::fs_mgr::GetPartitionName;
 
 static constexpr char kTestImageMetadataDir[] = "/metadata/gsi/test";
+static constexpr char kOtaTestImageMetadataDir[] = "/metadata/gsi/ota/test";
 
 std::unique_ptr<ImageManager> ImageManager::Open(const std::string& dir_prefix) {
     auto metadata_dir = "/metadata/gsi/" + dir_prefix;
@@ -135,10 +136,13 @@
     return !!FindPartition(*metadata.get(), name);
 }
 
+static bool IsTestDir(const std::string& path) {
+    return android::base::StartsWith(path, kTestImageMetadataDir) ||
+           android::base::StartsWith(path, kOtaTestImageMetadataDir);
+}
+
 static bool IsUnreliablePinningAllowed(const std::string& path) {
-    return android::base::StartsWith(path, "/data/gsi/dsu/") ||
-           android::base::StartsWith(path, "/data/gsi/test/") ||
-           android::base::StartsWith(path, "/data/gsi/ota/test/");
+    return android::base::StartsWith(path, "/data/gsi/dsu/") || IsTestDir(path);
 }
 
 FiemapStatus ImageManager::CreateBackingImage(
@@ -174,8 +178,7 @@
     // if device-mapper is stacked in some complex way not supported by
     // FiemapWriter.
     auto device_path = GetDevicePathForFile(fw.get());
-    if (android::base::StartsWith(device_path, "/dev/block/dm-") &&
-        !android::base::StartsWith(metadata_dir_, kTestImageMetadataDir)) {
+    if (android::base::StartsWith(device_path, "/dev/block/dm-") && !IsTestDir(metadata_dir_)) {
         LOG(ERROR) << "Cannot persist images against device-mapper device: " << device_path;
 
         fw = {};
diff --git a/fs_mgr/libfiemap/image_test.cpp b/fs_mgr/libfiemap/image_test.cpp
index 5388b44..6663391 100644
--- a/fs_mgr/libfiemap/image_test.cpp
+++ b/fs_mgr/libfiemap/image_test.cpp
@@ -131,132 +131,6 @@
     ASSERT_TRUE(manager_->UnmapImageDevice(base_name_));
 }
 
-// This fixture is for tests against a simulated device environment. Rather
-// than use /data, we create an image and then layer a new filesystem within
-// it. Each test then decides how to mount and create layered images. This
-// allows us to test FBE vs FDE configurations.
-class ImageTest : public ::testing::Test {
-  public:
-    ImageTest() : dm_(DeviceMapper::Instance()) {}
-
-    void SetUp() override {
-        manager_ = ImageManager::Open(kMetadataPath, gDataPath);
-        ASSERT_NE(manager_, nullptr);
-
-        manager_->set_partition_opener(std::make_unique<TestPartitionOpener>());
-
-        submanager_ = ImageManager::Open(kMetadataPath + "/mnt"s, gDataPath + "/mnt"s);
-        ASSERT_NE(submanager_, nullptr);
-
-        submanager_->set_partition_opener(std::make_unique<TestPartitionOpener>());
-
-        // Ensure that metadata is cleared in between runs.
-        submanager_->RemoveAllImages();
-        manager_->RemoveAllImages();
-
-        const ::testing::TestInfo* tinfo = ::testing::UnitTest::GetInstance()->current_test_info();
-        base_name_ = tinfo->name();
-        test_image_name_ = base_name_ + "-base";
-        wrapper_device_name_ = base_name_ + "-wrapper";
-
-        ASSERT_TRUE(manager_->CreateBackingImage(base_name_, kTestImageSize * 16, false, nullptr));
-        ASSERT_TRUE(manager_->MapImageDevice(base_name_, 5s, &base_device_));
-    }
-
-    void TearDown() override {
-        submanager_->UnmapImageDevice(test_image_name_);
-        umount(gDataMountPath.c_str());
-        dm_.DeleteDeviceIfExists(wrapper_device_name_);
-        manager_->UnmapImageDevice(base_name_);
-        manager_->DeleteBackingImage(base_name_);
-    }
-
-  protected:
-    bool DoFormat(const std::string& device) {
-        // clang-format off
-        std::vector<std::string> mkfs_args = {
-            "/system/bin/mke2fs",
-            "-F",
-            "-b 4096",
-            "-t ext4",
-            "-m 0",
-            "-O has_journal",
-            device,
-            ">/dev/null",
-            "2>/dev/null",
-            "</dev/null",
-        };
-        // clang-format on
-        auto command = android::base::Join(mkfs_args, " ");
-        return system(command.c_str()) == 0;
-    }
-
-    std::unique_ptr<ImageManager> manager_;
-    std::unique_ptr<ImageManager> submanager_;
-
-    DeviceMapper& dm_;
-    std::string base_name_;
-    std::string base_device_;
-    std::string test_image_name_;
-    std::string wrapper_device_name_;
-};
-
-TEST_F(ImageTest, DirectMount) {
-    ASSERT_TRUE(DoFormat(base_device_));
-    ASSERT_EQ(mount(base_device_.c_str(), gDataMountPath.c_str(), "ext4", 0, nullptr), 0);
-    ASSERT_TRUE(submanager_->CreateBackingImage(test_image_name_, kTestImageSize, false, nullptr));
-
-    std::string path;
-    ASSERT_TRUE(submanager_->MapImageDevice(test_image_name_, 5s, &path));
-    ASSERT_TRUE(android::base::StartsWith(path, "/dev/block/loop"));
-}
-
-TEST_F(ImageTest, IndirectMount) {
-#ifdef SKIP_TEST_IN_PRESUBMIT
-    GTEST_SKIP() << "WIP failure b/148874852";
-#endif
-    // Create a simple wrapper around the base device that we'll mount from
-    // instead. This will simulate the code paths for dm-crypt/default-key/bow
-    // and force us to use device-mapper rather than loop devices.
-    uint64_t device_size = 0;
-    {
-        unique_fd fd(open(base_device_.c_str(), O_RDWR | O_CLOEXEC));
-        ASSERT_GE(fd, 0);
-        device_size = get_block_device_size(fd);
-        ASSERT_EQ(device_size, kTestImageSize * 16);
-    }
-    uint64_t num_sectors = device_size / 512;
-
-    auto& dm = DeviceMapper::Instance();
-
-    DmTable table;
-    table.Emplace<DmTargetLinear>(0, num_sectors, base_device_, 0);
-    ASSERT_TRUE(dm.CreateDevice(wrapper_device_name_, table));
-
-    // Format and mount.
-    std::string wrapper_device;
-    ASSERT_TRUE(dm.GetDmDevicePathByName(wrapper_device_name_, &wrapper_device));
-    ASSERT_TRUE(WaitForFile(wrapper_device, 5s));
-    ASSERT_TRUE(DoFormat(wrapper_device));
-    ASSERT_EQ(mount(wrapper_device.c_str(), gDataMountPath.c_str(), "ext4", 0, nullptr), 0);
-
-    ASSERT_TRUE(submanager_->CreateBackingImage(test_image_name_, kTestImageSize, false, nullptr));
-
-    std::set<std::string> backing_devices;
-    auto init = [&](std::set<std::string> devices) -> bool {
-        backing_devices = std::move(devices);
-        return true;
-    };
-
-    std::string path;
-    ASSERT_TRUE(submanager_->MapImageDevice(test_image_name_, 5s, &path));
-    ASSERT_TRUE(android::base::StartsWith(path, "/dev/block/dm-"));
-    ASSERT_TRUE(submanager_->UnmapImageDevice(test_image_name_));
-    ASSERT_TRUE(submanager_->MapAllImages(init));
-    ASSERT_FALSE(backing_devices.empty());
-    ASSERT_TRUE(submanager_->UnmapImageDevice(test_image_name_));
-}
-
 bool Mkdir(const std::string& path) {
     if (mkdir(path.c_str(), 0700) && errno != EEXIST) {
         std::cerr << "Could not mkdir " << path << ": " << strerror(errno) << std::endl;
diff --git a/fs_mgr/libfs_avb/avb_util.cpp b/fs_mgr/libfs_avb/avb_util.cpp
index 4505382..2288674 100644
--- a/fs_mgr/libfs_avb/avb_util.cpp
+++ b/fs_mgr/libfs_avb/avb_util.cpp
@@ -124,6 +124,64 @@
     return true;
 }
 
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(
+        const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images) {
+    bool found = false;
+    const uint8_t* desc_partition_name;
+    auto hash_desc = std::make_unique<FsAvbHashDescriptor>();
+
+    for (const auto& vbmeta : vbmeta_images) {
+        size_t num_descriptors;
+        std::unique_ptr<const AvbDescriptor*[], decltype(&avb_free)> descriptors(
+                avb_descriptor_get_all(vbmeta.data(), vbmeta.size(), &num_descriptors), avb_free);
+
+        if (!descriptors || num_descriptors < 1) {
+            continue;
+        }
+
+        for (size_t n = 0; n < num_descriptors && !found; n++) {
+            AvbDescriptor desc;
+            if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
+                LWARNING << "Descriptor[" << n << "] is invalid";
+                continue;
+            }
+            if (desc.tag == AVB_DESCRIPTOR_TAG_HASH) {
+                desc_partition_name = (const uint8_t*)descriptors[n] + sizeof(AvbHashDescriptor);
+                if (!avb_hash_descriptor_validate_and_byteswap((AvbHashDescriptor*)descriptors[n],
+                                                               hash_desc.get())) {
+                    continue;
+                }
+                if (hash_desc->partition_name_len != partition_name.length()) {
+                    continue;
+                }
+                // Notes that desc_partition_name is not NUL-terminated.
+                std::string hash_partition_name((const char*)desc_partition_name,
+                                                hash_desc->partition_name_len);
+                if (hash_partition_name == partition_name) {
+                    found = true;
+                }
+            }
+        }
+
+        if (found) break;
+    }
+
+    if (!found) {
+        LERROR << "Hash descriptor not found: " << partition_name;
+        return nullptr;
+    }
+
+    hash_desc->partition_name = partition_name;
+
+    const uint8_t* desc_salt = desc_partition_name + hash_desc->partition_name_len;
+    hash_desc->salt = BytesToHex(desc_salt, hash_desc->salt_len);
+
+    const uint8_t* desc_digest = desc_salt + hash_desc->salt_len;
+    hash_desc->digest = BytesToHex(desc_digest, hash_desc->digest_len);
+
+    return hash_desc;
+}
+
 std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
         const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images) {
     bool found = false;
diff --git a/fs_mgr/libfs_avb/avb_util.h b/fs_mgr/libfs_avb/avb_util.h
index 09c786a..e8f7c39 100644
--- a/fs_mgr/libfs_avb/avb_util.h
+++ b/fs_mgr/libfs_avb/avb_util.h
@@ -40,6 +40,9 @@
 std::string GetAvbPropertyDescriptor(const std::string& key,
                                      const std::vector<VBMetaData>& vbmeta_images);
 
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(
+        const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images);
+
 // AvbHashtreeDescriptor to dm-verity table setup.
 std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
         const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images);
diff --git a/fs_mgr/libfs_avb/fs_avb_util.cpp b/fs_mgr/libfs_avb/fs_avb_util.cpp
index f82f83d..1c14cc0 100644
--- a/fs_mgr/libfs_avb/fs_avb_util.cpp
+++ b/fs_mgr/libfs_avb/fs_avb_util.cpp
@@ -74,5 +74,15 @@
     return GetHashtreeDescriptor(avb_partition_name, vbmeta_images);
 }
 
+// Given a path, loads and verifies the vbmeta, to extract the Avb Hash descriptor.
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(const std::string& avb_partition_name,
+                                                       VBMetaData&& vbmeta) {
+    if (!vbmeta.size()) return nullptr;
+
+    std::vector<VBMetaData> vbmeta_images;
+    vbmeta_images.emplace_back(std::move(vbmeta));
+    return GetHashDescriptor(avb_partition_name, vbmeta_images);
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
index ec8badb..3f37bd7 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb_util.h
@@ -32,9 +32,20 @@
                                                 std::string* out_avb_partition_name,
                                                 VBMetaVerifyResult* out_verify_result);
 
+// Loads the single vbmeta from a given path.
+std::unique_ptr<VBMetaData> LoadAndVerifyVbmetaByPath(
+        const std::string& image_path, const std::string& partition_name,
+        const std::string& expected_public_key_blob, bool allow_verification_error,
+        bool rollback_protection, bool is_chained_vbmeta, std::string* out_public_key_data,
+        bool* out_verification_disabled, VBMetaVerifyResult* out_verify_result);
+
 // Gets the hashtree descriptor for avb_partition_name from the vbmeta.
 std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
         const std::string& avb_partition_name, VBMetaData&& vbmeta);
 
+// Gets the hash descriptor for avb_partition_name from the vbmeta.
+std::unique_ptr<FsAvbHashDescriptor> GetHashDescriptor(const std::string& avb_partition_name,
+                                                       VBMetaData&& vbmeta);
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/libfs_avb/include/fs_avb/types.h b/fs_mgr/libfs_avb/include/fs_avb/types.h
index bd638e6..f2aa7cc 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/types.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/types.h
@@ -55,6 +55,12 @@
 
 std::ostream& operator<<(std::ostream& os, AvbHandleStatus status);
 
+struct FsAvbHashDescriptor : AvbHashDescriptor {
+    std::string partition_name;
+    std::string salt;
+    std::string digest;
+};
+
 struct FsAvbHashtreeDescriptor : AvbHashtreeDescriptor {
     std::string partition_name;
     std::string salt;
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 2f516fa..c37d70e 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -19,6 +19,7 @@
 #include <string.h>
 
 #include <algorithm>
+#include <limits>
 
 #include <android-base/unique_fd.h>
 
@@ -369,7 +370,10 @@
     }
 
     // Align the metadata size up to the nearest sector.
-    metadata_max_size = AlignTo(metadata_max_size, LP_SECTOR_SIZE);
+    if (!AlignTo(metadata_max_size, LP_SECTOR_SIZE, &metadata_max_size)) {
+        LERROR << "Max metadata size " << metadata_max_size << " is too large.";
+        return false;
+    }
 
     // Validate and build the block device list.
     uint32_t logical_block_size = 0;
@@ -401,10 +405,15 @@
         // untouched to be compatible code that looks for an MBR. Thus we
         // start counting free sectors at sector 1, not 0.
         uint64_t free_area_start = LP_SECTOR_SIZE;
-        if (out.alignment || out.alignment_offset) {
-            free_area_start = AlignTo(free_area_start, out.alignment, out.alignment_offset);
+        bool ok;
+        if (out.alignment) {
+            ok = AlignTo(free_area_start, out.alignment, &free_area_start);
         } else {
-            free_area_start = AlignTo(free_area_start, logical_block_size);
+            ok = AlignTo(free_area_start, logical_block_size, &free_area_start);
+        }
+        if (!ok) {
+            LERROR << "Integer overflow computing free area start";
+            return false;
         }
         out.first_logical_sector = free_area_start / LP_SECTOR_SIZE;
 
@@ -441,10 +450,15 @@
 
     // Compute the first free sector, factoring in alignment.
     uint64_t free_area_start = total_reserved;
+    bool ok;
     if (super.alignment || super.alignment_offset) {
-        free_area_start = AlignTo(free_area_start, super.alignment, super.alignment_offset);
+        ok = AlignTo(free_area_start, super.alignment, &free_area_start);
     } else {
-        free_area_start = AlignTo(free_area_start, logical_block_size);
+        ok = AlignTo(free_area_start, logical_block_size, &free_area_start);
+    }
+    if (!ok) {
+        LERROR << "Integer overflow computing free area start";
+        return false;
     }
     super.first_logical_sector = free_area_start / LP_SECTOR_SIZE;
 
@@ -544,7 +558,11 @@
         const Interval& current = extents[i];
         DCHECK(previous.device_index == current.device_index);
 
-        uint64_t aligned = AlignSector(block_devices_[current.device_index], previous.end);
+        uint64_t aligned;
+        if (!AlignSector(block_devices_[current.device_index], previous.end, &aligned)) {
+            LERROR << "Sector " << previous.end << " caused integer overflow.";
+            continue;
+        }
         if (aligned >= current.start) {
             // There is no gap between these two extents, try the next one.
             // Note that we check with >= instead of >, since alignment may
@@ -730,7 +748,10 @@
     // Choose an aligned sector for the midpoint. This could lead to one half
     // being slightly larger than the other, but this will not restrict the
     // size of partitions (it might lead to one extra extent if "B" overflows).
-    midpoint = AlignSector(super, midpoint);
+    if (!AlignSector(super, midpoint, &midpoint)) {
+        LERROR << "Unexpected integer overflow aligning midpoint " << midpoint;
+        return free_list;
+    }
 
     std::vector<Interval> first_half;
     std::vector<Interval> second_half;
@@ -768,7 +789,11 @@
     // If the sector ends where the next aligned chunk begins, then there's
     // no missing gap to try and allocate.
     const auto& block_device = block_devices_[extent->device_index()];
-    uint64_t next_aligned_sector = AlignSector(block_device, extent->end_sector());
+    uint64_t next_aligned_sector;
+    if (!AlignSector(block_device, extent->end_sector(), &next_aligned_sector)) {
+        LERROR << "Integer overflow aligning sector " << extent->end_sector();
+        return nullptr;
+    }
     if (extent->end_sector() == next_aligned_sector) {
         return nullptr;
     }
@@ -925,13 +950,19 @@
     return size;
 }
 
-uint64_t MetadataBuilder::AlignSector(const LpMetadataBlockDevice& block_device,
-                                      uint64_t sector) const {
+bool MetadataBuilder::AlignSector(const LpMetadataBlockDevice& block_device, uint64_t sector,
+                                  uint64_t* out) const {
     // Note: when reading alignment info from the Kernel, we don't assume it
     // is aligned to the sector size, so we round up to the nearest sector.
     uint64_t lba = sector * LP_SECTOR_SIZE;
-    uint64_t aligned = AlignTo(lba, block_device.alignment, block_device.alignment_offset);
-    return AlignTo(aligned, LP_SECTOR_SIZE) / LP_SECTOR_SIZE;
+    if (!AlignTo(lba, block_device.alignment, out)) {
+        return false;
+    }
+    if (!AlignTo(*out, LP_SECTOR_SIZE, out)) {
+        return false;
+    }
+    *out /= LP_SECTOR_SIZE;
+    return true;
 }
 
 bool MetadataBuilder::FindBlockDeviceByName(const std::string& partition_name,
@@ -1005,7 +1036,12 @@
 bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_size,
                                       const std::vector<Interval>& free_region_hint) {
     // Align the space needed up to the nearest sector.
-    uint64_t aligned_size = AlignTo(requested_size, geometry_.logical_block_size);
+    uint64_t aligned_size;
+    if (!AlignTo(requested_size, geometry_.logical_block_size, &aligned_size)) {
+        LERROR << "Cannot resize partition " << partition->name() << " to " << requested_size
+               << " bytes; integer overflow.";
+        return false;
+    }
     uint64_t old_size = partition->size();
 
     if (!ValidatePartitionSizeChange(partition, old_size, aligned_size, false)) {
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 977ebe3..1a3250a 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -174,7 +174,7 @@
     ASSERT_NE(exported, nullptr);
     super_device = GetMetadataSuperBlockDevice(*exported.get());
     ASSERT_NE(super_device, nullptr);
-    EXPECT_EQ(super_device->first_logical_sector, 1472);
+    EXPECT_EQ(super_device->first_logical_sector, 1536);
 
     // Alignment offset without alignment doesn't mean anything.
     device_info.alignment = 0;
@@ -190,7 +190,7 @@
     ASSERT_NE(exported, nullptr);
     super_device = GetMetadataSuperBlockDevice(*exported.get());
     ASSERT_NE(super_device, nullptr);
-    EXPECT_EQ(super_device->first_logical_sector, 174);
+    EXPECT_EQ(super_device->first_logical_sector, 168);
 
     // Test a small alignment with no alignment offset.
     device_info.alignment = 11 * 1024;
@@ -200,7 +200,7 @@
     ASSERT_NE(exported, nullptr);
     super_device = GetMetadataSuperBlockDevice(*exported.get());
     ASSERT_NE(super_device, nullptr);
-    EXPECT_EQ(super_device->first_logical_sector, 160);
+    EXPECT_EQ(super_device->first_logical_sector, 154);
 }
 
 TEST_F(BuilderTest, InternalPartitionAlignment) {
@@ -228,13 +228,14 @@
         ASSERT_EQ(extent.target_type, LP_TARGET_TYPE_LINEAR);
         EXPECT_EQ(extent.num_sectors, 80);
 
+        uint64_t aligned_lba;
         uint64_t lba = extent.target_data * LP_SECTOR_SIZE;
-        uint64_t aligned_lba = AlignTo(lba, device_info.alignment, device_info.alignment_offset);
+        ASSERT_TRUE(AlignTo(lba, device_info.alignment, &aligned_lba));
         EXPECT_EQ(lba, aligned_lba);
     }
 
     // Sanity check one extent.
-    EXPECT_EQ(exported->extents.back().target_data, 3008);
+    EXPECT_EQ(exported->extents.back().target_data, 3072);
 }
 
 TEST_F(BuilderTest, UseAllDiskSpace) {
@@ -652,7 +653,7 @@
     };
     unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(partitions, "system_a", 65536, 2);
     ASSERT_NE(builder, nullptr);
-    EXPECT_EQ(builder->AllocatableSpace(), 467238912);
+    EXPECT_EQ(builder->AllocatableSpace(), 467402752);
 
     // Create a partition that spans 3 devices.
     Partition* p = builder->AddPartition("system_a", 0);
@@ -675,17 +676,17 @@
     EXPECT_EQ(metadata->block_devices[2].alignment, 786432);
     EXPECT_EQ(metadata->block_devices[2].alignment_offset, 753664);
     ASSERT_EQ(metadata->extents.size(), 3);
-    EXPECT_EQ(metadata->extents[0].num_sectors, 522304);
+    EXPECT_EQ(metadata->extents[0].num_sectors, 522752);
     EXPECT_EQ(metadata->extents[0].target_type, LP_TARGET_TYPE_LINEAR);
-    EXPECT_EQ(metadata->extents[0].target_data, 1984);
+    EXPECT_EQ(metadata->extents[0].target_data, 1536);
     EXPECT_EQ(metadata->extents[0].target_source, 0);
-    EXPECT_EQ(metadata->extents[1].num_sectors, 260672);
+    EXPECT_EQ(metadata->extents[1].num_sectors, 260608);
     EXPECT_EQ(metadata->extents[1].target_type, LP_TARGET_TYPE_LINEAR);
-    EXPECT_EQ(metadata->extents[1].target_data, 1472);
+    EXPECT_EQ(metadata->extents[1].target_data, 1536);
     EXPECT_EQ(metadata->extents[1].target_source, 1);
-    EXPECT_EQ(metadata->extents[2].num_sectors, 129088);
+    EXPECT_EQ(metadata->extents[2].num_sectors, 128704);
     EXPECT_EQ(metadata->extents[2].target_type, LP_TARGET_TYPE_LINEAR);
-    EXPECT_EQ(metadata->extents[2].target_data, 1472);
+    EXPECT_EQ(metadata->extents[2].target_data, 1536);
     EXPECT_EQ(metadata->extents[2].target_source, 2);
 }
 
@@ -1019,3 +1020,49 @@
     EXPECT_FALSE(extent.OverlapsWith(LinearExtent{20, 1, 15}));
     EXPECT_FALSE(extent.OverlapsWith(LinearExtent{20, 1, 10}));
 }
+
+TEST_F(BuilderTest, AlignFreeRegion) {
+    BlockDeviceInfo super("super", 8_GiB, 786432, 0, 4096);
+    std::vector<BlockDeviceInfo> block_devices = {super};
+
+    unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(block_devices, "super", 65536, 2);
+    ASSERT_NE(builder, nullptr);
+
+    Partition* p = builder->AddPartition("system", "default", 0);
+    ASSERT_NE(p, nullptr);
+    ASSERT_TRUE(builder->AddLinearExtent(p, "super", 64, (super.alignment + 4096) / 512));
+
+    p = builder->AddPartition("vendor", "default", 0);
+    ASSERT_NE(p, nullptr);
+    ASSERT_TRUE(builder->ResizePartition(p, 2_GiB));
+
+    const auto& extents = p->extents();
+    ASSERT_EQ(extents.size(), 2);
+
+    LinearExtent* e1 = extents[0]->AsLinearExtent();
+    ASSERT_NE(e1, nullptr);
+    LinearExtent* e2 = extents[1]->AsLinearExtent();
+    ASSERT_NE(e2, nullptr);
+
+    // The misaligned partition starting at sector 1544 should not cause any
+    // overlap with previous extents. We should see vendor punch a hole where
+    // "system" is, extending the hole up to the next aligned block.
+    EXPECT_EQ(e1->physical_sector(), 1536);
+    EXPECT_EQ(e1->end_sector(), 1544);
+    EXPECT_EQ(e2->physical_sector(), 3072);
+    EXPECT_EQ(e2->end_sector(), 4197368);
+}
+
+TEST_F(BuilderTest, ResizeOverflow) {
+    BlockDeviceInfo super("super", 8_GiB, 786432, 229376, 4096);
+    std::vector<BlockDeviceInfo> block_devices = {super};
+
+    unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(block_devices, "super", 65536, 2);
+    ASSERT_NE(builder, nullptr);
+
+    ASSERT_TRUE(builder->AddGroup("group", 0));
+
+    Partition* p = builder->AddPartition("system", "default", 0);
+    ASSERT_NE(p, nullptr);
+    ASSERT_FALSE(builder->ResizePartition(p, 18446744073709551615ULL));
+}
diff --git a/fs_mgr/liblp/device_test.cpp b/fs_mgr/liblp/device_test.cpp
index 99bff6e..6af9d94 100644
--- a/fs_mgr/liblp/device_test.cpp
+++ b/fs_mgr/liblp/device_test.cpp
@@ -50,16 +50,7 @@
     // Sanity check that the device doesn't give us some weird inefficient
     // alignment.
     EXPECT_EQ(device_info.alignment % LP_SECTOR_SIZE, 0);
-    EXPECT_EQ(device_info.alignment_offset % LP_SECTOR_SIZE, 0);
-    EXPECT_LE(device_info.alignment_offset, INT_MAX);
     EXPECT_EQ(device_info.logical_block_size % LP_SECTOR_SIZE, 0);
-
-    // Having an alignment offset > alignment doesn't really make sense.
-    EXPECT_LT(device_info.alignment_offset, device_info.alignment);
-
-    if (IPropertyFetcher::GetInstance()->GetBoolProperty("ro.virtual_ab.enabled", false)) {
-        EXPECT_EQ(device_info.alignment_offset, 0);
-    }
 }
 
 TEST_F(DeviceTest, ReadSuperPartitionCurrentSlot) {
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index bd39150..89a47b1 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -144,7 +144,6 @@
     std::vector<std::unique_ptr<Extent>> extents_;
     uint32_t attributes_;
     uint64_t size_;
-    bool disabled_;
 };
 
 // An interval in the metadata. This is similar to a LinearExtent with one difference.
@@ -321,9 +320,6 @@
     // Set the LP_HEADER_FLAG_VIRTUAL_AB_DEVICE flag.
     void SetVirtualABDeviceFlag();
 
-    // If set, checks for slot suffixes will be ignored internally.
-    void IgnoreSlotSuffixing();
-
     bool GetBlockDeviceInfo(const std::string& partition_name, BlockDeviceInfo* info) const;
     bool UpdateBlockDeviceInfo(const std::string& partition_name, const BlockDeviceInfo& info);
 
@@ -359,7 +355,7 @@
     bool GrowPartition(Partition* partition, uint64_t aligned_size,
                        const std::vector<Interval>& free_region_hint);
     void ShrinkPartition(Partition* partition, uint64_t aligned_size);
-    uint64_t AlignSector(const LpMetadataBlockDevice& device, uint64_t sector) const;
+    bool AlignSector(const LpMetadataBlockDevice& device, uint64_t sector, uint64_t* out) const;
     uint64_t TotalSizeOfGroup(PartitionGroup* group) const;
     bool UpdateBlockDeviceInfo(size_t index, const BlockDeviceInfo& info);
     bool FindBlockDeviceByName(const std::string& partition_name, uint32_t* index) const;
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index 0661769..c4fe3ed 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <limits>
 #include <string>
 #include <string_view>
 
@@ -66,27 +67,26 @@
 void SHA256(const void* data, size_t length, uint8_t out[32]);
 
 // Align |base| such that it is evenly divisible by |alignment|, which does not
-// have to be a power of two.
-constexpr uint64_t AlignTo(uint64_t base, uint32_t alignment) {
+// have to be a power of two. Return false on overflow.
+template <typename T>
+bool AlignTo(T base, uint32_t alignment, T* out) {
+    static_assert(std::numeric_limits<T>::is_integer);
+    static_assert(!std::numeric_limits<T>::is_signed);
     if (!alignment) {
-        return base;
+        *out = base;
+        return true;
     }
-    uint64_t remainder = base % alignment;
+    T remainder = base % alignment;
     if (remainder == 0) {
-        return base;
+        *out = base;
+        return true;
     }
-    return base + (alignment - remainder);
-}
-
-// Same as the above |AlignTo|, except that |base| is only aligned when added to
-// |alignment_offset|.
-constexpr uint64_t AlignTo(uint64_t base, uint32_t alignment, uint32_t alignment_offset) {
-    uint64_t aligned = AlignTo(base, alignment) + alignment_offset;
-    if (aligned - alignment >= base) {
-        // We overaligned (base < alignment_offset).
-        return aligned - alignment;
+    T to_add = alignment - remainder;
+    if (to_add > std::numeric_limits<T>::max() - base) {
+        return false;
     }
-    return aligned;
+    *out = base + to_add;
+    return true;
 }
 
 // Update names from C++ strings.
diff --git a/fs_mgr/liblp/utility_test.cpp b/fs_mgr/liblp/utility_test.cpp
index cac3989..fc90872 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <optional>
+
 #include <gtest/gtest.h>
 #include <liblp/builder.h>
 #include <liblp/liblp.h>
@@ -58,15 +60,28 @@
     EXPECT_EQ(GetBackupMetadataOffset(geometry, 0), backup_start + 16384 * 0);
 }
 
+std::optional<uint64_t> AlignTo(uint64_t base, uint32_t alignment) {
+    uint64_t r;
+    if (!AlignTo(base, alignment, &r)) {
+        return {};
+    }
+    return {r};
+}
+
 TEST(liblp, AlignTo) {
-    EXPECT_EQ(AlignTo(37, 0), 37);
-    EXPECT_EQ(AlignTo(1024, 1024), 1024);
-    EXPECT_EQ(AlignTo(555, 1024), 1024);
-    EXPECT_EQ(AlignTo(555, 1000), 1000);
-    EXPECT_EQ(AlignTo(0, 1024), 0);
-    EXPECT_EQ(AlignTo(54, 32, 30), 62);
-    EXPECT_EQ(AlignTo(32, 32, 30), 62);
-    EXPECT_EQ(AlignTo(17, 32, 30), 30);
+    EXPECT_EQ(AlignTo(37, 0), std::optional<uint64_t>(37));
+    EXPECT_EQ(AlignTo(1024, 1024), std::optional<uint64_t>(1024));
+    EXPECT_EQ(AlignTo(555, 1024), std::optional<uint64_t>(1024));
+    EXPECT_EQ(AlignTo(555, 1000), std::optional<uint64_t>(1000));
+    EXPECT_EQ(AlignTo(0, 1024), std::optional<uint64_t>(0));
+    EXPECT_EQ(AlignTo(54, 32), std::optional<uint64_t>(64));
+    EXPECT_EQ(AlignTo(32, 32), std::optional<uint64_t>(32));
+    EXPECT_EQ(AlignTo(17, 32), std::optional<uint64_t>(32));
+
+    auto u32limit = std::numeric_limits<uint32_t>::max();
+    auto u64limit = std::numeric_limits<uint64_t>::max();
+    EXPECT_EQ(AlignTo(u64limit - u32limit + 1, u32limit), std::optional<uint64_t>{u64limit});
+    EXPECT_EQ(AlignTo(std::numeric_limits<uint64_t>::max(), 2), std::optional<uint64_t>{});
 }
 
 TEST(liblp, GetPartitionSlotSuffix) {
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 384595d..95301ff 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -100,6 +100,7 @@
 
 cc_library_static {
     name: "libsnapshot_init",
+    native_coverage : true,
     defaults: ["libsnapshot_defaults"],
     srcs: [":libsnapshot_sources"],
     recovery_available: true,
@@ -160,23 +161,23 @@
         "snapshot_test.cpp",
     ],
     shared_libs: [
-        "android.hardware.boot@1.0",
-        "android.hardware.boot@1.1",
         "libbinder",
         "libcrypto",
         "libhidlbase",
         "libprotobuf-cpp-lite",
-        "libsparse",
         "libutils",
         "libz",
     ],
     static_libs: [
+        "android.hardware.boot@1.0",
+        "android.hardware.boot@1.1",
         "libfs_mgr",
         "libgsi",
         "libgmock",
         "liblp",
         "libsnapshot",
         "libsnapshot_test_helpers",
+        "libsparse",
     ],
     header_libs: [
         "libstorage_literals_headers",
@@ -244,3 +245,68 @@
     ],
     gtest: false,
 }
+
+cc_defaults {
+    name: "libsnapshot_fuzzer_defaults",
+    native_coverage : true,
+    srcs: [
+        // Compile the protobuf definition again with type full.
+        "android/snapshot/snapshot_fuzz.proto",
+        "update_engine/update_metadata.proto",
+        "fuzz_utils.cpp",
+        "snapshot_fuzz.cpp",
+        "snapshot_fuzz_utils.cpp",
+
+        // Compile libsnapshot sources directly to avoid dependency
+        // to update_metadata-protos
+        ":libsnapshot_sources",
+    ],
+    static_libs: [
+        "libbase",
+        "libcrypto_static",
+        "libcutils",
+        "libext2_uuid",
+        "libext4_utils",
+        "libfstab",
+        "libfs_mgr",
+        "libgtest", // from libsnapshot_test_helpers
+        "libgmock", // from libsnapshot_test_helpers
+        "liblog",
+        "liblp",
+        "libsnapshot_test_helpers",
+        "libprotobuf-mutator",
+    ],
+    header_libs: [
+        "libfiemap_headers",
+        "libstorage_literals_headers",
+    ],
+    proto: {
+        type: "full",
+        canonical_path_from_root: false,
+        local_include_dirs: ["."],
+    },
+}
+
+cc_fuzz {
+    name: "libsnapshot_fuzzer",
+    defaults: ["libsnapshot_fuzzer_defaults"],
+    corpus: ["corpus/*"],
+    fuzz_config: {
+        cc: ["android-virtual-ab+bugs@google.com"],
+        componentid: 30545,
+        hotlists: ["1646452"],
+        fuzz_on_haiku_host: false,
+        fuzz_on_haiku_device: true,
+    },
+}
+
+cc_test {
+    name: "libsnapshot_fuzzer_test",
+    defaults: ["libsnapshot_fuzzer_defaults"],
+    data: ["corpus/*"],
+    test_suites: [
+        "device-tests",
+    ],
+    auto_gen_config: true,
+    require_root: true,
+}
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot_fuzz.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot_fuzz.proto
new file mode 100644
index 0000000..a55b42a
--- /dev/null
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot_fuzz.proto
@@ -0,0 +1,110 @@
+// Copyright (C) 2020 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.
+
+syntax = "proto3";
+package android.snapshot;
+
+import "update_engine/update_metadata.proto";
+
+// Controls the behavior of IDeviceInfo.
+// Next: 6
+message FuzzDeviceInfoData {
+    bool slot_suffix_is_a = 1;
+    bool is_overlayfs_setup = 2;
+    bool allow_set_boot_control_merge_status = 3;
+    bool allow_set_slot_as_unbootable = 4;
+    bool is_recovery = 5;
+}
+
+// Controls the behavior of the test SnapshotManager.
+// Next: 2
+message FuzzSnapshotManagerData {
+    bool is_local_image_manager = 1;
+}
+
+// A simplified version of CreateLogicalPartitionParams for fuzzing.
+// Next: 9
+message CreateLogicalPartitionParamsProto {
+    bool use_correct_super = 1;
+    string block_device = 2;
+    bool has_metadata_slot = 3;
+    uint32 metadata_slot = 4;
+    string partition_name = 5;
+    bool force_writable = 6;
+    int64 timeout_millis = 7;
+    string device_name = 8;
+}
+
+// Mimics the API of ISnapshotManager. Defines one action on the snapshot
+// manager.
+// Next: 18
+message SnapshotManagerActionProto {
+    message NoArgs {}
+    message ProcessUpdateStateArgs {
+        bool has_before_cancel = 1;
+        bool fail_before_cancel = 2;
+    }
+    message CreateLogicalAndSnapshotPartitionsArgs {
+        bool use_correct_super = 1;
+        string super = 2;
+        int64 timeout_millis = 3;
+    }
+    message RecoveryCreateSnapshotDevicesArgs {
+        bool has_metadata_device_object = 1;
+        bool metadata_mounted = 2;
+    }
+    reserved 18 to 9999;
+    oneof value {
+        NoArgs begin_update = 1;
+        NoArgs cancel_update = 2;
+        bool finished_snapshot_writes = 3;
+        NoArgs initiate_merge = 4;
+        ProcessUpdateStateArgs process_update_state = 5;
+        bool get_update_state = 6;
+        chromeos_update_engine.DeltaArchiveManifest create_update_snapshots = 7;
+        CreateLogicalPartitionParamsProto map_update_snapshot = 8;
+        string unmap_update_snapshot = 9;
+        NoArgs need_snapshots_in_first_stage_mount = 10;
+        CreateLogicalAndSnapshotPartitionsArgs create_logical_and_snapshot_partitions = 11;
+        bool handle_imminent_data_wipe = 12;
+        NoArgs recovery_create_snapshot_devices = 13;
+        RecoveryCreateSnapshotDevicesArgs recovery_create_snapshot_devices_with_metadata = 14;
+        NoArgs dump = 15;
+        NoArgs ensure_metadata_mounted = 16;
+        NoArgs get_snapshot_merge_stats_instance = 17;
+
+        // Test directives that has nothing to do with ISnapshotManager API surface.
+        NoArgs switch_slot = 10000;
+    }
+}
+
+// Includes all data that needs to be fuzzed.
+message SnapshotFuzzData {
+    FuzzDeviceInfoData device_info_data = 1;
+    FuzzSnapshotManagerData manager_data = 2;
+
+    // If true:
+    // - if super_data is empty, create empty super partition metadata.
+    // - otherwise, create super partition metadata accordingly.
+    // If false, no valid super partition metadata (it is zeroed)
+    bool is_super_metadata_valid = 3;
+    chromeos_update_engine.DeltaArchiveManifest super_data = 4;
+
+    // Whether the directory that mocks /metadata/ota/snapshot is created.
+    bool has_metadata_snapshots_dir = 5;
+
+    // More data used to prep the test before running actions.
+    reserved 6 to 9999;
+    repeated SnapshotManagerActionProto actions = 10000;
+}
diff --git a/fs_mgr/libsnapshot/corpus/launch_device.txt b/fs_mgr/libsnapshot/corpus/launch_device.txt
new file mode 100644
index 0000000..55a7f2c
--- /dev/null
+++ b/fs_mgr/libsnapshot/corpus/launch_device.txt
@@ -0,0 +1,161 @@
+device_info_data {
+  slot_suffix_is_a: true
+  is_overlayfs_setup: false
+  allow_set_boot_control_merge_status: true
+  allow_set_slot_as_unbootable: true
+  is_recovery: false
+}
+manager_data {
+  is_local_image_manager: false
+}
+is_super_metadata_valid: true
+super_data {
+  partitions {
+    partition_name: "sys_a"
+    new_partition_info {
+      size: 3145728
+    }
+  }
+  partitions {
+    partition_name: "vnd_a"
+    new_partition_info {
+      size: 3145728
+    }
+  }
+  partitions {
+    partition_name: "prd_a"
+    new_partition_info {
+      size: 3145728
+    }
+  }
+  dynamic_partition_metadata {
+    groups {
+      name: "group_google_dp_a"
+      size: 15728640
+      partition_names: "sys_a"
+      partition_names: "vnd_a"
+      partition_names: "prd_a"
+    }
+  }
+}
+has_metadata_snapshots_dir: true
+actions {
+  begin_update {
+  }
+}
+actions {
+  create_update_snapshots {
+    partitions {
+      partition_name: "sys"
+      new_partition_info {
+        size: 3878912
+      }
+      operations {
+        type: ZERO,
+        dst_extents {
+          start_block: 0
+          num_blocks: 947
+        }
+      }
+    }
+    partitions {
+      partition_name: "vnd"
+      new_partition_info {
+        size: 3878912
+      }
+      operations {
+        type: ZERO,
+        dst_extents {
+          start_block: 0
+          num_blocks: 947
+        }
+      }
+    }
+    partitions {
+      partition_name: "prd"
+      new_partition_info {
+        size: 3878912
+      }
+      operations {
+        type: ZERO,
+        dst_extents {
+          start_block: 0
+          num_blocks: 947
+        }
+      }
+    }
+    dynamic_partition_metadata {
+      groups {
+        name: "group_google_dp"
+        size: 15728640
+        partition_names: "sys"
+        partition_names: "vnd"
+        partition_names: "prd"
+      }
+    }
+  }
+}
+actions {
+  map_update_snapshot {
+    use_correct_super: true
+    has_metadata_slot: true
+    metadata_slot: 1
+    partition_name: "sys_b"
+    force_writable: true
+    timeout_millis: 3000
+  }
+}
+actions {
+  map_update_snapshot {
+    use_correct_super: true
+    has_metadata_slot: true
+    metadata_slot: 1
+    partition_name: "vnd_b"
+    force_writable: true
+    timeout_millis: 3000
+  }
+}
+actions {
+  map_update_snapshot {
+    use_correct_super: true
+    has_metadata_slot: true
+    metadata_slot: 1
+    partition_name: "prd_b"
+    force_writable: true
+    timeout_millis: 3000
+  }
+}
+actions {
+  finished_snapshot_writes: false
+}
+actions {
+  unmap_update_snapshot: "sys_b"
+}
+actions {
+  unmap_update_snapshot: "vnd_b"
+}
+actions {
+  unmap_update_snapshot: "prd_b"
+}
+actions {
+  switch_slot {
+  }
+}
+actions {
+  need_snapshots_in_first_stage_mount {
+  }
+}
+actions {
+  create_logical_and_snapshot_partitions {
+    use_correct_super: true
+    timeout_millis: 5000
+  }
+}
+actions {
+  initiate_merge {
+  }
+}
+actions {
+  process_update_state {
+  }
+}
diff --git a/fs_mgr/libsnapshot/fuzz.sh b/fs_mgr/libsnapshot/fuzz.sh
new file mode 100755
index 0000000..0e57674
--- /dev/null
+++ b/fs_mgr/libsnapshot/fuzz.sh
@@ -0,0 +1,90 @@
+#!/bin/bash
+PROJECT_PATH=system/core/fs_mgr/libsnapshot
+FUZZ_TARGET=libsnapshot_fuzzer
+TARGET_ARCH=$(get_build_var TARGET_ARCH)
+FUZZ_BINARY=/data/fuzz/${TARGET_ARCH}/${FUZZ_TARGET}/${FUZZ_TARGET}
+DEVICE_INIT_CORPUS_DIR=/data/fuzz/${TARGET_ARCH}/${FUZZ_TARGET}/corpus
+DEVICE_GENERATED_CORPUS_DIR=/data/local/tmp/${FUZZ_TARGET}/corpus
+DEVICE_GCOV_DIR=/data/local/tmp/${FUZZ_TARGET}/gcov
+HOST_SCRATCH_DIR=/tmp/${FUZZ_TARGET}
+GCOV_TOOL=${HOST_SCRATCH_DIR}/llvm-gcov
+
+build_normal() (
+    pushd $(gettop)
+    NATIVE_COVERAGE="" NATIVE_LINE_COVERAGE="" COVERAGE_PATHS="" m ${FUZZ_TARGET}
+    ret=$?
+    popd
+    return ${ret}
+)
+
+build_cov() {
+    pushd $(gettop)
+    NATIVE_COVERAGE="true" NATIVE_LINE_COVERAGE="true" COVERAGE_PATHS="${PROJECT_PATH}" m ${FUZZ_TARGET}
+    ret=$?
+    popd
+    return ${ret}
+}
+
+prepare_device() {
+    adb root && adb remount &&
+    adb shell mkdir -p ${DEVICE_GENERATED_CORPUS_DIR} &&
+    adb shell rm -rf ${DEVICE_GCOV_DIR} &&
+    adb shell mkdir -p ${DEVICE_GCOV_DIR}
+}
+
+push_binary() {
+    adb push ${ANDROID_PRODUCT_OUT}/${FUZZ_BINARY} ${FUZZ_BINARY} &&
+    adb push ${ANDROID_PRODUCT_OUT}/${DEVICE_INIT_CORPUS_DIR} $(dirname ${FUZZ_BINARY})
+}
+
+prepare_host() {
+    which lcov || {
+        echo "please run:";
+        echo "   sudo apt-get install lcov ";
+        return 1;
+    }
+    rm -rf ${HOST_SCRATCH_DIR} &&
+    mkdir -p ${HOST_SCRATCH_DIR}
+}
+
+# run_snapshot_fuzz -runs=10000
+generate_corpus() {
+    [[ "$@" ]] || { echo "run with -runs=X"; return 1; }
+
+    prepare_device &&
+    build_normal &&
+    push_binary &&
+    adb shell ${FUZZ_BINARY} "$@" ${DEVICE_INIT_CORPUS_DIR} ${DEVICE_GENERATED_CORPUS_DIR}
+}
+
+run_snapshot_fuzz() {
+    prepare_device &&
+    build_cov &&
+    push_binary &&
+    adb shell GCOV_PREFIX=${DEVICE_GCOV_DIR} GCOV_PREFIX_STRIP=3 \
+        ${FUZZ_BINARY} \
+        -runs=0 \
+        ${DEVICE_INIT_CORPUS_DIR} ${DEVICE_GENERATED_CORPUS_DIR}
+}
+
+show_fuzz_result() {
+    prepare_host &&
+    unzip -o -j -d ${HOST_SCRATCH_DIR} ${ANDROID_PRODUCT_OUT}/coverage/data/fuzz/${TARGET_ARCH}/${FUZZ_TARGET}/${FUZZ_TARGET}.zip &&
+    adb shell find ${DEVICE_GCOV_DIR} -type f | xargs -I {} adb pull {} ${HOST_SCRATCH_DIR} &&
+    ls ${HOST_SCRATCH_DIR} &&
+    cat > ${GCOV_TOOL} <<< '
+#!/bin/bash
+exec llvm-cov gcov "$@"
+' &&
+    chmod +x ${GCOV_TOOL} &&
+    lcov --directory ${HOST_SCRATCH_DIR} --base-directory $(gettop) --gcov-tool ${GCOV_TOOL} --capture -o ${HOST_SCRATCH_DIR}/report.cov &&
+    genhtml ${HOST_SCRATCH_DIR}/report.cov -o ${HOST_SCRATCH_DIR}/html &&
+    echo file://$(realpath ${HOST_SCRATCH_DIR}/html/index.html)
+}
+
+# run_snapshot_fuzz -runs=10000
+run_snapshot_fuzz_all() {
+    generate_corpus "$@" &&
+    run_snapshot_fuzz &&
+    show_fuzz_result
+}
diff --git a/fs_mgr/libsnapshot/fuzz_utils.cpp b/fs_mgr/libsnapshot/fuzz_utils.cpp
new file mode 100644
index 0000000..0263f7e
--- /dev/null
+++ b/fs_mgr/libsnapshot/fuzz_utils.cpp
@@ -0,0 +1,38 @@
+// Copyright (C) 2020 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 "fuzz_utils.h"
+
+#include <android-base/logging.h>
+
+namespace android::fuzz {
+
+void CheckInternal(bool value, std::string_view msg) {
+    CHECK(value) << msg;
+}
+
+const google::protobuf::OneofDescriptor* GetProtoValueDescriptor(
+        const google::protobuf::Descriptor* action_desc) {
+    CHECK(action_desc);
+    CHECK(action_desc->oneof_decl_count() == 1)
+            << action_desc->oneof_decl_count() << " oneof fields found in " << action_desc->name()
+            << "; only one is expected.";
+    auto* oneof_value_desc = action_desc->oneof_decl(0);
+    CHECK(oneof_value_desc);
+    CHECK(oneof_value_desc->name() == "value")
+            << "oneof field has name " << oneof_value_desc->name();
+    return oneof_value_desc;
+}
+
+}  // namespace android::fuzz
diff --git a/fs_mgr/libsnapshot/fuzz_utils.h b/fs_mgr/libsnapshot/fuzz_utils.h
new file mode 100644
index 0000000..20b13b2
--- /dev/null
+++ b/fs_mgr/libsnapshot/fuzz_utils.h
@@ -0,0 +1,285 @@
+// Copyright (C) 2020 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 <map>
+#include <string>
+#include <string_view>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+
+// Utilities for using a protobuf definition to fuzz APIs in a class.
+// Terms:
+// The "fuzzed class" is the C++ class definition whose functions are fuzzed.
+// The "fuzzed object" is an instantiated object of the fuzzed class. It is
+//   typically created and destroyed for each test run.
+// An "action" is an operation on the fuzzed object that may mutate its state.
+//   This typically involves one function call into the fuzzed object.
+
+namespace android::fuzz {
+
+// CHECK(value) << msg
+void CheckInternal(bool value, std::string_view msg);
+
+// Get the oneof descriptor inside Action
+const google::protobuf::OneofDescriptor* GetProtoValueDescriptor(
+        const google::protobuf::Descriptor* action_desc);
+
+template <typename Class>
+using FunctionMapImpl =
+        std::map<int, std::function<void(Class*, const google::protobuf::Message& action_proto,
+                                         const google::protobuf::FieldDescriptor* field_desc)>>;
+
+template <typename Class>
+class FunctionMap : public FunctionMapImpl<Class> {
+  public:
+    void CheckEmplace(typename FunctionMapImpl<Class>::key_type key,
+                      typename FunctionMapImpl<Class>::mapped_type&& value) {
+        auto [it, inserted] = this->emplace(key, std::move(value));
+        CheckInternal(inserted,
+                      "Multiple implementation registered for tag number " + std::to_string(key));
+    }
+};
+
+template <typename Action>
+int CheckConsistency() {
+    const auto* function_map = Action::GetFunctionMap();
+    const auto* action_value_desc = GetProtoValueDescriptor(Action::Proto::GetDescriptor());
+
+    for (int field_index = 0; field_index < action_value_desc->field_count(); ++field_index) {
+        const auto* field_desc = action_value_desc->field(field_index);
+        CheckInternal(function_map->find(field_desc->number()) != function_map->end(),
+                      "Missing impl for function " + field_desc->camelcase_name());
+    }
+    return 0;
+}
+
+// Get the field descriptor for the oneof field in the action message. If no oneof field is set,
+// return nullptr.
+template <typename Action>
+const google::protobuf::FieldDescriptor* GetValueFieldDescriptor(
+        const typename Action::Proto& action_proto) {
+    static auto* action_value_desc = GetProtoValueDescriptor(Action::Proto::GetDescriptor());
+
+    auto* action_refl = Action::Proto::GetReflection();
+    if (!action_refl->HasOneof(action_proto, action_value_desc)) {
+        return nullptr;
+    }
+    return action_refl->GetOneofFieldDescriptor(action_proto, action_value_desc);
+}
+
+template <typename Action>
+void ExecuteActionProto(typename Action::ClassType* module,
+                        const typename Action::Proto& action_proto) {
+    const auto* field_desc = GetValueFieldDescriptor<Action>(action_proto);
+    if (field_desc == nullptr) return;
+    auto number = field_desc->number();
+    const auto& map = *Action::GetFunctionMap();
+    auto it = map.find(number);
+    CheckInternal(it != map.end(), "Missing impl for function " + field_desc->camelcase_name());
+    const auto& func = it->second;
+    func(module, action_proto, field_desc);
+}
+
+template <typename Action>
+void ExecuteAllActionProtos(
+        typename Action::ClassType* module,
+        const google::protobuf::RepeatedPtrField<typename Action::Proto>& action_protos) {
+    for (const auto& proto : action_protos) {
+        ExecuteActionProto<Action>(module, proto);
+    }
+}
+
+// Safely cast message to T. Returns a pointer to message if cast successfully, otherwise nullptr.
+template <typename T>
+const T* SafeCast(const google::protobuf::Message& message) {
+    if (message.GetDescriptor() != T::GetDescriptor()) {
+        return nullptr;
+    }
+    return static_cast<const T*>(&message);
+}
+
+// Cast message to const T&. Abort if type mismatch.
+template <typename T>
+const T& CheckedCast(const google::protobuf::Message& message) {
+    const auto* ptr = SafeCast<T>(message);
+    CheckInternal(ptr, "Cannot cast " + message.GetDescriptor()->name() + " to " +
+                               T::GetDescriptor()->name());
+    return *ptr;
+}
+
+// A templated way to a primitive field from a message using reflection.
+template <typename T>
+struct PrimitiveGetter;
+#define FUZZ_DEFINE_PRIMITIVE_GETTER(type, func_name)                              \
+    template <>                                                                    \
+    struct PrimitiveGetter<type> {                                                 \
+        static constexpr const auto fp = &google::protobuf::Reflection::func_name; \
+    }
+
+FUZZ_DEFINE_PRIMITIVE_GETTER(bool, GetBool);
+FUZZ_DEFINE_PRIMITIVE_GETTER(uint32_t, GetUInt32);
+FUZZ_DEFINE_PRIMITIVE_GETTER(int32_t, GetInt32);
+FUZZ_DEFINE_PRIMITIVE_GETTER(uint64_t, GetUInt64);
+FUZZ_DEFINE_PRIMITIVE_GETTER(int64_t, GetInt64);
+FUZZ_DEFINE_PRIMITIVE_GETTER(double, GetDouble);
+FUZZ_DEFINE_PRIMITIVE_GETTER(float, GetFloat);
+
+// ActionPerformer extracts arguments from the protobuf message, and then call FuzzFunction
+// with these arguments.
+template <typename FuzzFunction, typename Signature, typename Enabled = void>
+struct ActionPerformerImpl;  // undefined
+
+template <typename FuzzFunction, typename MessageProto>
+struct ActionPerformerImpl<
+        FuzzFunction, void(const MessageProto&),
+        typename std::enable_if_t<std::is_base_of_v<google::protobuf::Message, MessageProto>>> {
+    static typename FuzzFunction::ReturnType Invoke(
+            typename FuzzFunction::ClassType* module, const google::protobuf::Message& action_proto,
+            const google::protobuf::FieldDescriptor* field_desc) {
+        const MessageProto& arg = CheckedCast<std::remove_reference_t<MessageProto>>(
+                action_proto.GetReflection()->GetMessage(action_proto, field_desc));
+        return FuzzFunction::ImplBody(module, arg);
+    }
+};
+
+template <typename FuzzFunction, typename Primitive>
+struct ActionPerformerImpl<FuzzFunction, void(Primitive),
+                           typename std::enable_if_t<std::is_arithmetic_v<Primitive>>> {
+    static typename FuzzFunction::ReturnType Invoke(
+            typename FuzzFunction::ClassType* module, const google::protobuf::Message& action_proto,
+            const google::protobuf::FieldDescriptor* field_desc) {
+        Primitive arg = std::invoke(PrimitiveGetter<Primitive>::fp, action_proto.GetReflection(),
+                                    action_proto, field_desc);
+        return FuzzFunction::ImplBody(module, arg);
+    }
+};
+
+template <typename FuzzFunction>
+struct ActionPerformerImpl<FuzzFunction, void()> {
+    static typename FuzzFunction::ReturnType Invoke(typename FuzzFunction::ClassType* module,
+                                                    const google::protobuf::Message&,
+                                                    const google::protobuf::FieldDescriptor*) {
+        return FuzzFunction::ImplBody(module);
+    }
+};
+
+template <typename FuzzFunction>
+struct ActionPerformerImpl<FuzzFunction, void(const std::string&)> {
+    static typename FuzzFunction::ReturnType Invoke(
+            typename FuzzFunction::ClassType* module, const google::protobuf::Message& action_proto,
+            const google::protobuf::FieldDescriptor* field_desc) {
+        std::string scratch;
+        const std::string& arg = action_proto.GetReflection()->GetStringReference(
+                action_proto, field_desc, &scratch);
+        return FuzzFunction::ImplBody(module, arg);
+    }
+};
+
+template <typename FuzzFunction>
+struct ActionPerformer : ActionPerformerImpl<FuzzFunction, typename FuzzFunction::Signature> {};
+
+}  // namespace android::fuzz
+
+// Fuzz existing C++ class, ClassType, with a collection of functions under the name Action.
+//
+// Prerequisite: ActionProto must be defined in Protobuf to describe possible actions:
+// message FooActionProto {
+//     message NoArgs {}
+//     oneof value {
+//         bool do_foo = 1;
+//         NoArgs do_bar = 1;
+//     }
+// }
+// Use it to fuzz a C++ class Foo by doing the following:
+//   FUZZ_CLASS(Foo, FooAction)
+// After linking functions of Foo to FooAction, execute all actions by:
+//   FooAction::ExecuteAll(foo_object, action_protos)
+#define FUZZ_CLASS(Class, Action)                                                                \
+    class Action {                                                                               \
+      public:                                                                                    \
+        using Proto = Action##Proto;                                                             \
+        using ClassType = Class;                                                                 \
+        using FunctionMap = android::fuzz::FunctionMap<Class>;                                   \
+        static FunctionMap* GetFunctionMap() {                                                   \
+            static Action::FunctionMap map;                                                      \
+            return &map;                                                                         \
+        }                                                                                        \
+        static void ExecuteAll(Class* module,                                                    \
+                               const google::protobuf::RepeatedPtrField<Proto>& action_protos) { \
+            [[maybe_unused]] static int consistent = android::fuzz::CheckConsistency<Action>();  \
+            android::fuzz::ExecuteAllActionProtos<Action>(module, action_protos);                \
+        }                                                                                        \
+    }
+
+#define FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName) Action##_##FunctionName
+#define FUZZ_FUNCTION_TAG_NAME(FunctionName) k##FunctionName
+
+// Implement an action defined in protobuf. Example:
+// message FooActionProto {
+//     oneof value {
+//         bool do_foo = 1;
+//     }
+// }
+// class Foo { public: void DoAwesomeFoo(bool arg); };
+// FUZZ_OBJECT(FooAction, Foo);
+// FUZZ_FUNCTION(FooAction, DoFoo, void, IFoo* module, bool arg) {
+//   module->DoAwesomeFoo(arg);
+// }
+// The name DoFoo is the camel case name of the action in protobuf definition of FooActionProto.
+#define FUZZ_FUNCTION(Action, FunctionName, Return, ModuleArg, ...)             \
+    class FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName) {                      \
+      public:                                                                   \
+        using ActionType = Action;                                              \
+        using ClassType = Action::ClassType;                                    \
+        using ReturnType = Return;                                              \
+        using Signature = void(__VA_ARGS__);                                    \
+        static constexpr const char name[] = #FunctionName;                     \
+        static constexpr const auto tag =                                       \
+                Action::Proto::ValueCase::FUZZ_FUNCTION_TAG_NAME(FunctionName); \
+        static ReturnType ImplBody(ModuleArg, ##__VA_ARGS__);                   \
+                                                                                \
+      private:                                                                  \
+        static bool registered_;                                                \
+    };                                                                          \
+    auto FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::registered_ = ([] {    \
+        auto tag = FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::tag;         \
+        auto func = &::android::fuzz::ActionPerformer<FUZZ_FUNCTION_CLASS_NAME( \
+                Action, FunctionName)>::Invoke;                                 \
+        Action::GetFunctionMap()->CheckEmplace(tag, func);                      \
+        return true;                                                            \
+    })();                                                                       \
+    Return FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::ImplBody(ModuleArg, ##__VA_ARGS__)
+
+// Implement a simple action by linking it to the function with the same name. Example:
+// message FooActionProto {
+//     message NoArgs {}
+//     oneof value {
+//         NoArgs do_bar = 1;
+//     }
+// }
+// class Foo { public void DoBar(); };
+// FUZZ_OBJECT(FooAction, Foo);
+// FUZZ_FUNCTION(FooAction, DoBar);
+// The name DoBar is the camel case name of the action in protobuf definition of FooActionProto, and
+// also the name of the function of Foo.
+#define FUZZ_SIMPLE_FUNCTION(Action, FunctionName)                            \
+    FUZZ_FUNCTION(Action, FunctionName,                                       \
+                  decltype(std::declval<Action::ClassType>().FunctionName()), \
+                  Action::ClassType* module) {                                \
+        return module->FunctionName();                                        \
+    }
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
index 758d66c..cf0b085 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
@@ -43,6 +43,7 @@
                 (const std::string& super_device, const std::chrono::milliseconds& timeout_ms),
                 (override));
     MOCK_METHOD(bool, HandleImminentDataWipe, (const std::function<void()>& callback), (override));
+    MOCK_METHOD(bool, FinishMergeInRecovery, (), (override));
     MOCK_METHOD(CreateResult, RecoveryCreateSnapshotDevices, (), (override));
     MOCK_METHOD(CreateResult, RecoveryCreateSnapshotDevices,
                 (const std::unique_ptr<AutoDevice>& metadata_device), (override));
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index fff667e..2d6071f 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -173,6 +173,7 @@
 
     // Map a snapshotted partition for OTA clients to write to. Write-protected regions are
     // determined previously in CreateSnapshots.
+    // |snapshot_path| must not be nullptr.
     virtual bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
                                    std::string* snapshot_path) = 0;
 
@@ -201,6 +202,10 @@
     // optional callback fires periodically to query progress via GetUpdateState.
     virtual bool HandleImminentDataWipe(const std::function<void()>& callback = {}) = 0;
 
+    // Force a merge to complete in recovery. This is similar to HandleImminentDataWipe
+    // but does not expect a data wipe after.
+    virtual bool FinishMergeInRecovery() = 0;
+
     // This method is only allowed in recovery and is used as a helper to
     // initialize the snapshot devices as a requirement to mount a snapshotted
     // /system in recovery.
@@ -289,6 +294,7 @@
             const std::string& super_device,
             const std::chrono::milliseconds& timeout_ms = {}) override;
     bool HandleImminentDataWipe(const std::function<void()>& callback = {}) override;
+    bool FinishMergeInRecovery() override;
     CreateResult RecoveryCreateSnapshotDevices() override;
     CreateResult RecoveryCreateSnapshotDevices(
             const std::unique_ptr<AutoDevice>& metadata_device) override;
@@ -318,6 +324,7 @@
     friend class SnapshotUpdateTest;
     friend class FlashAfterUpdateTest;
     friend class LockTestConsumer;
+    friend class SnapshotFuzzEnv;
     friend struct AutoDeleteCowImage;
     friend struct AutoDeleteSnapshot;
     friend struct PartitionCowCreator;
@@ -573,11 +580,16 @@
     bool ProcessUpdateStateOnDataWipe(bool allow_forward_merge,
                                       const std::function<bool()>& callback);
 
+    // Return device string of a mapped image, or if it is not available, the mapped image path.
+    bool GetMappedImageDeviceStringOrPath(const std::string& device_name,
+                                          std::string* device_string_or_mapped_path);
+
     std::string gsid_dir_;
     std::string metadata_dir_;
     std::unique_ptr<IDeviceInfo> device_;
     std::unique_ptr<IImageManager> images_;
     bool has_local_image_manager_ = false;
+    bool in_factory_data_reset_ = false;
 };
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
index 9b2590c..9c82906 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
@@ -41,6 +41,7 @@
             const std::string& super_device,
             const std::chrono::milliseconds& timeout_ms = {}) override;
     bool HandleImminentDataWipe(const std::function<void()>& callback = {}) override;
+    bool FinishMergeInRecovery() override;
     CreateResult RecoveryCreateSnapshotDevices() override;
     CreateResult RecoveryCreateSnapshotDevices(
             const std::unique_ptr<AutoDevice>& metadata_device) override;
diff --git a/fs_mgr/libsnapshot/partition_cow_creator.cpp b/fs_mgr/libsnapshot/partition_cow_creator.cpp
index efdb59f..0df5664 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator.cpp
@@ -181,6 +181,13 @@
     ret.snapshot_status.set_device_size(target_partition->size());
     ret.snapshot_status.set_snapshot_size(target_partition->size());
 
+    if (ret.snapshot_status.snapshot_size() == 0) {
+        LOG(INFO) << "Not creating snapshot for partition " << ret.snapshot_status.name();
+        ret.snapshot_status.set_cow_partition_size(0);
+        ret.snapshot_status.set_cow_file_size(0);
+        return ret;
+    }
+
     // Being the COW partition virtual, its size doesn't affect the storage
     // memory that will be occupied by the target.
     // The actual storage space is affected by the COW file, whose size depends
diff --git a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
index 526f874..adfb975 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
@@ -46,20 +46,20 @@
 };
 
 TEST_F(PartitionCowCreatorTest, IntersectSelf) {
-    constexpr uint64_t initial_size = 1_MiB;
-    constexpr uint64_t final_size = 40_KiB;
+    constexpr uint64_t super_size = 1_MiB;
+    constexpr uint64_t partition_size = 40_KiB;
 
-    auto builder_a = MetadataBuilder::New(initial_size, 1_KiB, 2);
+    auto builder_a = MetadataBuilder::New(super_size, 1_KiB, 2);
     ASSERT_NE(builder_a, nullptr);
     auto system_a = builder_a->AddPartition("system_a", LP_PARTITION_ATTR_READONLY);
     ASSERT_NE(system_a, nullptr);
-    ASSERT_TRUE(builder_a->ResizePartition(system_a, final_size));
+    ASSERT_TRUE(builder_a->ResizePartition(system_a, partition_size));
 
-    auto builder_b = MetadataBuilder::New(initial_size, 1_KiB, 2);
+    auto builder_b = MetadataBuilder::New(super_size, 1_KiB, 2);
     ASSERT_NE(builder_b, nullptr);
     auto system_b = builder_b->AddPartition("system_b", LP_PARTITION_ATTR_READONLY);
     ASSERT_NE(system_b, nullptr);
-    ASSERT_TRUE(builder_b->ResizePartition(system_b, final_size));
+    ASSERT_TRUE(builder_b->ResizePartition(system_b, partition_size));
 
     PartitionCowCreator creator{.target_metadata = builder_b.get(),
                                 .target_suffix = "_b",
@@ -68,8 +68,8 @@
                                 .current_suffix = "_a"};
     auto ret = creator.Run();
     ASSERT_TRUE(ret.has_value());
-    ASSERT_EQ(final_size, ret->snapshot_status.device_size());
-    ASSERT_EQ(final_size, ret->snapshot_status.snapshot_size());
+    ASSERT_EQ(partition_size, ret->snapshot_status.device_size());
+    ASSERT_EQ(partition_size, ret->snapshot_status.snapshot_size());
 }
 
 TEST_F(PartitionCowCreatorTest, Holes) {
@@ -118,20 +118,20 @@
     using RepeatedInstallOperationPtr = google::protobuf::RepeatedPtrField<InstallOperation>;
     using Extent = chromeos_update_engine::Extent;
 
-    constexpr uint64_t initial_size = 50_MiB;
-    constexpr uint64_t final_size = 40_MiB;
+    constexpr uint64_t super_size = 50_MiB;
+    constexpr uint64_t partition_size = 40_MiB;
 
-    auto builder_a = MetadataBuilder::New(initial_size, 1_KiB, 2);
+    auto builder_a = MetadataBuilder::New(super_size, 1_KiB, 2);
     ASSERT_NE(builder_a, nullptr);
     auto system_a = builder_a->AddPartition("system_a", LP_PARTITION_ATTR_READONLY);
     ASSERT_NE(system_a, nullptr);
-    ASSERT_TRUE(builder_a->ResizePartition(system_a, final_size));
+    ASSERT_TRUE(builder_a->ResizePartition(system_a, partition_size));
 
-    auto builder_b = MetadataBuilder::New(initial_size, 1_KiB, 2);
+    auto builder_b = MetadataBuilder::New(super_size, 1_KiB, 2);
     ASSERT_NE(builder_b, nullptr);
     auto system_b = builder_b->AddPartition("system_b", LP_PARTITION_ATTR_READONLY);
     ASSERT_NE(system_b, nullptr);
-    ASSERT_TRUE(builder_b->ResizePartition(system_b, final_size));
+    ASSERT_TRUE(builder_b->ResizePartition(system_b, partition_size));
 
     const uint64_t block_size = builder_b->logical_block_size();
     const uint64_t chunk_size = kSnapshotChunkSize * dm::kSectorSize;
@@ -197,6 +197,31 @@
     ASSERT_EQ(6 * chunk_size, cow_device_size(iopv, builder_a.get(), builder_b.get(), system_b));
 }
 
+TEST_F(PartitionCowCreatorTest, Zero) {
+    constexpr uint64_t super_size = 1_MiB;
+    auto builder_a = MetadataBuilder::New(super_size, 1_KiB, 2);
+    ASSERT_NE(builder_a, nullptr);
+
+    auto builder_b = MetadataBuilder::New(super_size, 1_KiB, 2);
+    ASSERT_NE(builder_b, nullptr);
+    auto system_b = builder_b->AddPartition("system_b", LP_PARTITION_ATTR_READONLY);
+    ASSERT_NE(system_b, nullptr);
+
+    PartitionCowCreator creator{.target_metadata = builder_b.get(),
+                                .target_suffix = "_b",
+                                .target_partition = system_b,
+                                .current_metadata = builder_a.get(),
+                                .current_suffix = "_a",
+                                .operations = nullptr};
+
+    auto ret = creator.Run();
+
+    ASSERT_EQ(0u, ret->snapshot_status.device_size());
+    ASSERT_EQ(0u, ret->snapshot_status.snapshot_size());
+    ASSERT_EQ(0u, ret->snapshot_status.cow_file_size());
+    ASSERT_EQ(0u, ret->snapshot_status.cow_partition_size());
+}
+
 TEST(DmSnapshotInternals, CowSizeCalculator) {
     DmSnapCowSizeCalculator cc(512, 8);
     unsigned long int b;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index eafeea2..488009a 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -577,8 +577,16 @@
         return false;
     }
 
+    auto other_suffix = device_->GetOtherSlotSuffix();
+
     auto& dm = DeviceMapper::Instance();
     for (const auto& snapshot : snapshots) {
+        if (android::base::EndsWith(snapshot, other_suffix)) {
+            // Allow the merge to continue, but log this unexpected case.
+            LOG(ERROR) << "Unexpected snapshot found during merge: " << snapshot;
+            continue;
+        }
+
         // The device has to be mapped, since everything should be merged at
         // the same time. This is a fairly serious error. We could forcefully
         // map everything here, but it should have been mapped during first-
@@ -1008,6 +1016,15 @@
 }
 
 void SnapshotManager::AcknowledgeMergeSuccess(LockedFile* lock) {
+    // It's not possible to remove update state in recovery, so write an
+    // indicator that cleanup is needed on reboot. If a factory data reset
+    // was requested, it doesn't matter, everything will get wiped anyway.
+    // To make testing easier we consider a /data wipe as cleaned up.
+    if (device_->IsRecovery() && !in_factory_data_reset_) {
+        WriteUpdateState(lock, UpdateState::MergeCompleted);
+        return;
+    }
+
     RemoveAllUpdateState(lock);
 }
 
@@ -1674,7 +1691,7 @@
         return false;
     }
     std::string cow_device;
-    if (!dm.GetDeviceString(cow_name, &cow_device)) {
+    if (!GetMappedImageDeviceStringOrPath(cow_name, &cow_device)) {
         LOG(ERROR) << "Could not determine major/minor for: " << cow_name;
         return false;
     }
@@ -1771,7 +1788,7 @@
     // If the COW image exists, append it as the last extent.
     if (snapshot_status.cow_file_size() > 0) {
         std::string cow_image_device;
-        if (!dm.GetDeviceString(cow_image_name, &cow_image_device)) {
+        if (!GetMappedImageDeviceStringOrPath(cow_image_name, &cow_image_device)) {
             LOG(ERROR) << "Cannot determine major/minor for: " << cow_image_name;
             return false;
         }
@@ -2347,7 +2364,6 @@
         const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
     CHECK(lock);
 
-    auto& dm = DeviceMapper::Instance();
     CreateLogicalPartitionParams cow_params{
             .block_device = LP_METADATA_DEFAULT_PARTITION_NAME,
             .metadata = exported_target_metadata,
@@ -2372,7 +2388,7 @@
         }
 
         std::string cow_path;
-        if (!dm.GetDmDevicePathByName(cow_name, &cow_path)) {
+        if (!images_->GetMappedImageDevice(cow_name, &cow_path)) {
             LOG(ERROR) << "Cannot determine path for " << cow_name;
             return Return::Error();
         }
@@ -2528,7 +2544,43 @@
         }
         return true;
     };
-    if (!ProcessUpdateStateOnDataWipe(true /* allow_forward_merge */, process_callback)) {
+
+    in_factory_data_reset_ = true;
+    bool ok = ProcessUpdateStateOnDataWipe(true /* allow_forward_merge */, process_callback);
+    in_factory_data_reset_ = false;
+
+    if (!ok) {
+        return false;
+    }
+
+    // Nothing should be depending on partitions now, so unmap them all.
+    if (!UnmapAllPartitions()) {
+        LOG(ERROR) << "Unable to unmap all partitions; fastboot may fail to flash.";
+    }
+    return true;
+}
+
+bool SnapshotManager::FinishMergeInRecovery() {
+    if (!device_->IsRecovery()) {
+        LOG(ERROR) << "Data wipes are only allowed in recovery.";
+        return false;
+    }
+
+    auto mount = EnsureMetadataMounted();
+    if (!mount || !mount->HasDevice()) {
+        return false;
+    }
+
+    auto slot_number = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
+    auto super_path = device_->GetSuperDevice(slot_number);
+    if (!CreateLogicalAndSnapshotPartitions(super_path)) {
+        LOG(ERROR) << "Unable to map partitions to complete merge.";
+        return false;
+    }
+
+    UpdateState state = ProcessUpdateState();
+    if (state != UpdateState::MergeCompleted) {
+        LOG(ERROR) << "Merge returned unexpected status: " << state;
         return false;
     }
 
@@ -2689,5 +2741,24 @@
     return SnapshotMergeStats::GetInstance(*this);
 }
 
+bool SnapshotManager::GetMappedImageDeviceStringOrPath(const std::string& device_name,
+                                                       std::string* device_string_or_mapped_path) {
+    auto& dm = DeviceMapper::Instance();
+    // Try getting the device string if it is a device mapper device.
+    if (dm.GetState(device_name) != DmDeviceState::INVALID) {
+        return dm.GetDeviceString(device_name, device_string_or_mapped_path);
+    }
+
+    // Otherwise, get path from IImageManager.
+    if (!images_->GetMappedImageDevice(device_name, device_string_or_mapped_path)) {
+        return false;
+    }
+
+    LOG(WARNING) << "Calling GetMappedImageDevice with local image manager; device "
+                 << (device_string_or_mapped_path ? *device_string_or_mapped_path : "(nullptr)")
+                 << "may not be available in first stage init! ";
+    return true;
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz.cpp b/fs_mgr/libsnapshot/snapshot_fuzz.cpp
new file mode 100644
index 0000000..5b145c3
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_fuzz.cpp
@@ -0,0 +1,352 @@
+// Copyright (C) 2020 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 <sysexits.h>
+
+#include <functional>
+#include <sstream>
+#include <tuple>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/result.h>
+#include <gtest/gtest.h>
+#include <src/libfuzzer/libfuzzer_macro.h>
+#include <storage_literals/storage_literals.h>
+
+#include "fuzz_utils.h"
+#include "snapshot_fuzz_utils.h"
+
+using android::base::Error;
+using android::base::GetBoolProperty;
+using android::base::LogId;
+using android::base::LogSeverity;
+using android::base::ReadFileToString;
+using android::base::Result;
+using android::base::SetLogger;
+using android::base::StderrLogger;
+using android::base::StdioLogger;
+using android::fs_mgr::CreateLogicalPartitionParams;
+using android::fuzz::CheckedCast;
+using android::snapshot::SnapshotFuzzData;
+using android::snapshot::SnapshotFuzzEnv;
+using chromeos_update_engine::DeltaArchiveManifest;
+using google::protobuf::FieldDescriptor;
+using google::protobuf::Message;
+using google::protobuf::RepeatedPtrField;
+
+// Avoid linking to libgsi since it needs disk I/O.
+namespace android::gsi {
+bool IsGsiRunning() {
+    LOG(FATAL) << "Called IsGsiRunning";
+    __builtin_unreachable();
+}
+std::string GetDsuSlot(const std::string& install_dir) {
+    LOG(FATAL) << "Called GetDsuSlot(" << install_dir << ")";
+    __builtin_unreachable();
+}
+}  // namespace android::gsi
+
+namespace android::snapshot {
+
+const SnapshotFuzzData* current_data = nullptr;
+const SnapshotTestModule* current_module = nullptr;
+
+SnapshotFuzzEnv* GetSnapshotFuzzEnv();
+
+FUZZ_CLASS(ISnapshotManager, SnapshotManagerAction);
+
+using ProcessUpdateStateArgs = SnapshotManagerAction::Proto::ProcessUpdateStateArgs;
+using CreateLogicalAndSnapshotPartitionsArgs =
+        SnapshotManagerAction::Proto::CreateLogicalAndSnapshotPartitionsArgs;
+using RecoveryCreateSnapshotDevicesArgs =
+        SnapshotManagerAction::Proto::RecoveryCreateSnapshotDevicesArgs;
+
+FUZZ_SIMPLE_FUNCTION(SnapshotManagerAction, BeginUpdate);
+FUZZ_SIMPLE_FUNCTION(SnapshotManagerAction, CancelUpdate);
+FUZZ_SIMPLE_FUNCTION(SnapshotManagerAction, InitiateMerge);
+FUZZ_SIMPLE_FUNCTION(SnapshotManagerAction, NeedSnapshotsInFirstStageMount);
+FUZZ_SIMPLE_FUNCTION(SnapshotManagerAction, RecoveryCreateSnapshotDevices);
+FUZZ_SIMPLE_FUNCTION(SnapshotManagerAction, EnsureMetadataMounted);
+FUZZ_SIMPLE_FUNCTION(SnapshotManagerAction, GetSnapshotMergeStatsInstance);
+
+#define SNAPSHOT_FUZZ_FUNCTION(FunctionName, ReturnType, ...)                                  \
+    FUZZ_FUNCTION(SnapshotManagerAction, FunctionName, ReturnType, ISnapshotManager* snapshot, \
+                  ##__VA_ARGS__)
+
+SNAPSHOT_FUZZ_FUNCTION(FinishedSnapshotWrites, bool, bool wipe) {
+    return snapshot->FinishedSnapshotWrites(wipe);
+}
+
+SNAPSHOT_FUZZ_FUNCTION(ProcessUpdateState, bool, const ProcessUpdateStateArgs& args) {
+    std::function<bool()> before_cancel;
+    if (args.has_before_cancel()) {
+        before_cancel = [&]() { return args.fail_before_cancel(); };
+    }
+    return snapshot->ProcessUpdateState({}, before_cancel);
+}
+
+SNAPSHOT_FUZZ_FUNCTION(GetUpdateState, UpdateState, bool has_progress_arg) {
+    double progress;
+    return snapshot->GetUpdateState(has_progress_arg ? &progress : nullptr);
+}
+
+SNAPSHOT_FUZZ_FUNCTION(HandleImminentDataWipe, bool, bool has_callback) {
+    std::function<void()> callback;
+    if (has_callback) {
+        callback = []() {};
+    }
+    return snapshot->HandleImminentDataWipe(callback);
+}
+
+SNAPSHOT_FUZZ_FUNCTION(Dump, bool) {
+    std::stringstream ss;
+    return snapshot->Dump(ss);
+}
+
+SNAPSHOT_FUZZ_FUNCTION(CreateUpdateSnapshots, bool, const DeltaArchiveManifest& manifest) {
+    return snapshot->CreateUpdateSnapshots(manifest);
+}
+
+SNAPSHOT_FUZZ_FUNCTION(UnmapUpdateSnapshot, bool, const std::string& name) {
+    return snapshot->UnmapUpdateSnapshot(name);
+}
+
+SNAPSHOT_FUZZ_FUNCTION(CreateLogicalAndSnapshotPartitions, bool,
+                       const CreateLogicalAndSnapshotPartitionsArgs& args) {
+    const std::string* super;
+    if (args.use_correct_super()) {
+        super = &GetSnapshotFuzzEnv()->super();
+    } else {
+        super = &args.super();
+    }
+    return snapshot->CreateLogicalAndSnapshotPartitions(
+            *super, std::chrono::milliseconds(args.timeout_millis()));
+}
+
+SNAPSHOT_FUZZ_FUNCTION(RecoveryCreateSnapshotDevicesWithMetadata, CreateResult,
+                       const RecoveryCreateSnapshotDevicesArgs& args) {
+    std::unique_ptr<AutoDevice> device;
+    if (args.has_metadata_device_object()) {
+        device = std::make_unique<DummyAutoDevice>(args.metadata_mounted());
+    }
+    return snapshot->RecoveryCreateSnapshotDevices(device);
+}
+
+SNAPSHOT_FUZZ_FUNCTION(MapUpdateSnapshot, bool,
+                       const CreateLogicalPartitionParamsProto& params_proto) {
+    auto partition_opener = std::make_unique<TestPartitionOpener>(GetSnapshotFuzzEnv()->super());
+    CreateLogicalPartitionParams params;
+    if (params_proto.use_correct_super()) {
+        params.block_device = GetSnapshotFuzzEnv()->super();
+    } else {
+        params.block_device = params_proto.block_device();
+    }
+    if (params_proto.has_metadata_slot()) {
+        params.metadata_slot = params_proto.metadata_slot();
+    }
+    params.partition_name = params_proto.partition_name();
+    params.force_writable = params_proto.force_writable();
+    params.timeout_ms = std::chrono::milliseconds(params_proto.timeout_millis());
+    params.device_name = params_proto.device_name();
+    params.partition_opener = partition_opener.get();
+    std::string path;
+    return snapshot->MapUpdateSnapshot(params, &path);
+}
+
+SNAPSHOT_FUZZ_FUNCTION(SwitchSlot, void) {
+    (void)snapshot;
+    CHECK(current_module != nullptr);
+    CHECK(current_module->device_info != nullptr);
+    current_module->device_info->SwitchSlot();
+}
+
+// During global init, log all messages to stdio. This is only done once.
+int AllowLoggingDuringGlobalInit() {
+    SetLogger(&StdioLogger);
+    return 0;
+}
+
+// Only log fatal messages during tests.
+void FatalOnlyLogger(LogId logid, LogSeverity severity, const char* tag, const char* file,
+                     unsigned int line, const char* message) {
+    if (severity == LogSeverity::FATAL) {
+        StderrLogger(logid, severity, tag, file, line, message);
+
+        // If test fails by a LOG(FATAL) or CHECK(), log the corpus. If it abort()'s, there's
+        // nothing else we can do.
+        StderrLogger(logid, severity, tag, __FILE__, __LINE__,
+                     "Attempting to dump current corpus:");
+        if (current_data == nullptr) {
+            StderrLogger(logid, severity, tag, __FILE__, __LINE__, "Current corpus is nullptr.");
+        } else {
+            std::string content;
+            if (!google::protobuf::TextFormat::PrintToString(*current_data, &content)) {
+                StderrLogger(logid, severity, tag, __FILE__, __LINE__,
+                             "Failed to print corpus to string.");
+            } else {
+                StderrLogger(logid, severity, tag, __FILE__, __LINE__, content.c_str());
+            }
+        }
+    }
+}
+// Stop logging (except fatal messages) after global initialization. This is only done once.
+int StopLoggingAfterGlobalInit() {
+    (void)GetSnapshotFuzzEnv();
+    [[maybe_unused]] static protobuf_mutator::protobuf::LogSilencer log_silencer;
+    SetLogger(&FatalOnlyLogger);
+    return 0;
+}
+
+SnapshotFuzzEnv* GetSnapshotFuzzEnv() {
+    [[maybe_unused]] static auto allow_logging = AllowLoggingDuringGlobalInit();
+    static SnapshotFuzzEnv env;
+    return &env;
+}
+
+SnapshotTestModule SetUpTest(const SnapshotFuzzData& snapshot_fuzz_data) {
+    current_data = &snapshot_fuzz_data;
+
+    auto env = GetSnapshotFuzzEnv();
+    env->CheckSoftReset();
+
+    auto test_module = env->CheckCreateSnapshotManager(snapshot_fuzz_data);
+    current_module = &test_module;
+    CHECK(test_module.snapshot);
+    return test_module;
+}
+
+void TearDownTest() {
+    current_module = nullptr;
+    current_data = nullptr;
+}
+
+}  // namespace android::snapshot
+
+DEFINE_PROTO_FUZZER(const SnapshotFuzzData& snapshot_fuzz_data) {
+    using namespace android::snapshot;
+
+    [[maybe_unused]] static auto stop_logging = StopLoggingAfterGlobalInit();
+    auto test_module = SetUpTest(snapshot_fuzz_data);
+    SnapshotManagerAction::ExecuteAll(test_module.snapshot.get(), snapshot_fuzz_data.actions());
+    TearDownTest();
+}
+
+namespace android::snapshot {
+
+// Work-around to cast a 'void' value to Result<void>.
+template <typename T>
+struct GoodResult {
+    template <typename F>
+    static Result<T> Cast(F&& f) {
+        return f();
+    }
+};
+
+template <>
+struct GoodResult<void> {
+    template <typename F>
+    static Result<void> Cast(F&& f) {
+        f();
+        return {};
+    }
+};
+
+class LibsnapshotFuzzerTest : public ::testing::Test {
+  protected:
+    static void SetUpTestCase() {
+        // Do initialization once.
+        (void)GetSnapshotFuzzEnv();
+    }
+    void SetUp() override {
+        bool is_virtual_ab = GetBoolProperty("ro.virtual_ab.enabled", false);
+        if (!is_virtual_ab) GTEST_SKIP() << "Test only runs on Virtual A/B devices.";
+    }
+    void SetUpFuzzData(const std::string& fn) {
+        auto path = android::base::GetExecutableDirectory() + "/corpus/"s + fn;
+        std::string proto_text;
+        ASSERT_TRUE(ReadFileToString(path, &proto_text));
+        snapshot_fuzz_data_ = std::make_unique<SnapshotFuzzData>();
+        ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(proto_text,
+                                                                  snapshot_fuzz_data_.get()));
+        test_module_ = android::snapshot::SetUpTest(*snapshot_fuzz_data_);
+    }
+    void TearDown() override { android::snapshot::TearDownTest(); }
+    template <typename FuzzFunction>
+    Result<typename FuzzFunction::ReturnType> Execute(int action_index) {
+        if (action_index >= snapshot_fuzz_data_->actions_size()) {
+            return Error() << "Index " << action_index << " is out of bounds ("
+                           << snapshot_fuzz_data_->actions_size() << " actions in corpus";
+        }
+        const auto& action_proto = snapshot_fuzz_data_->actions(action_index);
+        const auto* field_desc =
+                android::fuzz::GetValueFieldDescriptor<typename FuzzFunction::ActionType>(
+                        action_proto);
+        if (field_desc == nullptr) {
+            return Error() << "Action at index " << action_index << " has no value defined.";
+        }
+        if (FuzzFunction::tag != field_desc->number()) {
+            return Error() << "Action at index " << action_index << " is expected to be "
+                           << FuzzFunction::name << ", but it is " << field_desc->name()
+                           << " in corpus.";
+        }
+        return GoodResult<typename FuzzFunction::ReturnType>::Cast([&]() {
+            return android::fuzz::ActionPerformer<FuzzFunction>::Invoke(test_module_.snapshot.get(),
+                                                                        action_proto, field_desc);
+        });
+    }
+
+    std::unique_ptr<SnapshotFuzzData> snapshot_fuzz_data_;
+    SnapshotTestModule test_module_;
+};
+
+#define SNAPSHOT_FUZZ_FN_NAME(name) FUZZ_FUNCTION_CLASS_NAME(SnapshotManagerAction, name)
+
+MATCHER_P(ResultIs, expected, "") {
+    if (!arg.ok()) {
+        *result_listener << arg.error();
+        return false;
+    }
+    *result_listener << "expected: " << expected;
+    return arg.value() == expected;
+}
+
+#define ASSERT_RESULT_TRUE(actual) ASSERT_THAT(actual, ResultIs(true))
+
+// Check that launch_device.txt is executed correctly.
+TEST_F(LibsnapshotFuzzerTest, LaunchDevice) {
+    SetUpFuzzData("launch_device.txt");
+
+    int i = 0;
+    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(BeginUpdate)>(i++));
+    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(CreateUpdateSnapshots)>(i++));
+    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(MapUpdateSnapshot)>(i++)) << "sys_b";
+    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(MapUpdateSnapshot)>(i++)) << "vnd_b";
+    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(MapUpdateSnapshot)>(i++)) << "prd_b";
+    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(FinishedSnapshotWrites)>(i++));
+    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(UnmapUpdateSnapshot)>(i++)) << "sys_b";
+    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(UnmapUpdateSnapshot)>(i++)) << "vnd_b";
+    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(UnmapUpdateSnapshot)>(i++)) << "prd_b";
+    ASSERT_RESULT_OK(Execute<SNAPSHOT_FUZZ_FN_NAME(SwitchSlot)>(i++));
+    ASSERT_EQ("_b", test_module_.device_info->GetSlotSuffix());
+    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(NeedSnapshotsInFirstStageMount)>(i++));
+    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(CreateLogicalAndSnapshotPartitions)>(i++));
+    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(InitiateMerge)>(i++));
+    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(ProcessUpdateState)>(i++));
+    ASSERT_EQ(i, snapshot_fuzz_data_->actions_size()) << "Not all actions are executed.";
+}
+
+}  // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp b/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
new file mode 100644
index 0000000..8926535
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
@@ -0,0 +1,516 @@
+// Copyright (C) 2020 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 <ftw.h>
+#include <inttypes.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sysexits.h>
+
+#include <chrono>
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <fs_mgr.h>
+#include <libsnapshot/auto_device.h>
+#include <libsnapshot/snapshot.h>
+#include <storage_literals/storage_literals.h>
+
+#include "snapshot_fuzz_utils.h"
+#include "utility.h"
+
+// Prepends the errno string, but it is good enough.
+#ifndef PCHECK
+#define PCHECK(x) CHECK(x) << strerror(errno) << ": "
+#endif
+
+using namespace android::storage_literals;
+using namespace std::chrono_literals;
+using namespace std::string_literals;
+
+using android::base::Basename;
+using android::base::ReadFileToString;
+using android::base::SetProperty;
+using android::base::Split;
+using android::base::StartsWith;
+using android::base::StringPrintf;
+using android::base::unique_fd;
+using android::base::WriteStringToFile;
+using android::dm::DeviceMapper;
+using android::dm::DmTarget;
+using android::dm::LoopControl;
+using android::fiemap::IImageManager;
+using android::fiemap::ImageManager;
+using android::fs_mgr::BlockDeviceInfo;
+using android::fs_mgr::FstabEntry;
+using android::fs_mgr::IPartitionOpener;
+using chromeos_update_engine::DynamicPartitionMetadata;
+
+static const char MNT_DIR[] = "/mnt";
+static const char BLOCK_SYSFS[] = "/sys/block";
+
+static const char FAKE_ROOT_NAME[] = "snapshot_fuzz";
+static const auto SUPER_IMAGE_SIZE = 16_MiB;
+static const auto DATA_IMAGE_SIZE = 16_MiB;
+static const auto FAKE_ROOT_SIZE = 64_MiB;
+
+namespace android::snapshot {
+
+bool Mkdir(const std::string& path) {
+    if (mkdir(path.c_str(), 0750) == -1 && errno != EEXIST) {
+        PLOG(ERROR) << "Cannot create " << path;
+        return false;
+    }
+    return true;
+}
+
+bool RmdirRecursive(const std::string& path) {
+    auto callback = [](const char* child, const struct stat*, int file_type, struct FTW*) -> int {
+        switch (file_type) {
+            case FTW_D:
+            case FTW_DP:
+            case FTW_DNR:
+                if (rmdir(child) == -1) {
+                    PLOG(ERROR) << "rmdir " << child;
+                    return -1;
+                }
+                return 0;
+            case FTW_NS:
+            default:
+                if (rmdir(child) != -1) break;
+                [[fallthrough]];
+            case FTW_F:
+            case FTW_SL:
+            case FTW_SLN:
+                if (unlink(child) == -1) {
+                    PLOG(ERROR) << "unlink " << child;
+                    return -1;
+                }
+                return 0;
+        }
+        return 0;
+    };
+
+    return nftw(path.c_str(), callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS) == 0;
+}
+
+std::string GetLinearBaseDeviceString(const DeviceMapper::TargetInfo& target) {
+    if (target.spec.target_type != "linear"s) return {};
+    auto tokens = Split(target.data, " ");
+    CHECK_EQ(2, tokens.size());
+    return tokens[0];
+}
+
+std::vector<std::string> GetSnapshotBaseDeviceStrings(const DeviceMapper::TargetInfo& target) {
+    if (target.spec.target_type != "snapshot"s && target.spec.target_type != "snapshot-merge"s)
+        return {};
+    auto tokens = Split(target.data, " ");
+    CHECK_EQ(4, tokens.size());
+    return {tokens[0], tokens[1]};
+}
+
+bool ShouldDeleteLoopDevice(const std::string& node) {
+    std::string backing_file;
+    if (ReadFileToString(StringPrintf("%s/loop/backing_file", node.data()), &backing_file)) {
+        if (StartsWith(backing_file, std::string(MNT_DIR) + "/" + FAKE_ROOT_NAME)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+std::vector<DeviceMapper::TargetInfo> GetTableInfoIfExists(const std::string& dev_name) {
+    auto& dm = DeviceMapper::Instance();
+    std::vector<DeviceMapper::TargetInfo> table;
+    if (!dm.GetTableInfo(dev_name, &table)) {
+        PCHECK(errno == ENODEV);
+        return {};
+    }
+    return table;
+}
+
+std::set<std::string> GetAllBaseDeviceStrings(const std::string& child_dev) {
+    std::set<std::string> ret;
+    for (const auto& child_target : GetTableInfoIfExists(child_dev)) {
+        auto snapshot_bases = GetSnapshotBaseDeviceStrings(child_target);
+        ret.insert(snapshot_bases.begin(), snapshot_bases.end());
+
+        auto linear_base = GetLinearBaseDeviceString(child_target);
+        if (!linear_base.empty()) {
+            ret.insert(linear_base);
+        }
+    }
+    return ret;
+}
+
+using PropertyList = std::set<std::string>;
+void InsertProperty(const char* key, const char* /*name*/, void* cookie) {
+    reinterpret_cast<PropertyList*>(cookie)->insert(key);
+}
+
+// Attempt to delete all devices that is based on dev_name, including itself.
+void CheckDeleteDeviceMapperTree(const std::string& dev_name, bool known_allow_delete = false,
+                                 uint64_t depth = 100) {
+    CHECK(depth > 0) << "Reaching max depth when deleting " << dev_name
+                     << ". There may be devices referencing itself. Check `dmctl list devices -v`.";
+
+    auto& dm = DeviceMapper::Instance();
+    auto table = GetTableInfoIfExists(dev_name);
+    if (table.empty()) {
+        PCHECK(dm.DeleteDeviceIfExists(dev_name)) << dev_name;
+        return;
+    }
+
+    if (!known_allow_delete) {
+        for (const auto& target : table) {
+            auto base_device_string = GetLinearBaseDeviceString(target);
+            if (base_device_string.empty()) continue;
+            if (ShouldDeleteLoopDevice(
+                        StringPrintf("/sys/dev/block/%s", base_device_string.data()))) {
+                known_allow_delete = true;
+                break;
+            }
+        }
+    }
+    if (!known_allow_delete) {
+        return;
+    }
+
+    std::string dev_string;
+    PCHECK(dm.GetDeviceString(dev_name, &dev_string));
+
+    std::vector<DeviceMapper::DmBlockDevice> devices;
+    PCHECK(dm.GetAvailableDevices(&devices));
+    for (const auto& child_dev : devices) {
+        auto child_bases = GetAllBaseDeviceStrings(child_dev.name());
+        if (child_bases.find(dev_string) != child_bases.end()) {
+            CheckDeleteDeviceMapperTree(child_dev.name(), true /* known_allow_delete */, depth - 1);
+        }
+    }
+
+    PCHECK(dm.DeleteDeviceIfExists(dev_name)) << dev_name;
+}
+
+// Attempt to clean up residues from previous runs.
+void CheckCleanupDeviceMapperDevices() {
+    auto& dm = DeviceMapper::Instance();
+    std::vector<DeviceMapper::DmBlockDevice> devices;
+    PCHECK(dm.GetAvailableDevices(&devices));
+
+    for (const auto& dev : devices) {
+        CheckDeleteDeviceMapperTree(dev.name());
+    }
+}
+
+void CheckUmount(const std::string& path) {
+    PCHECK(TEMP_FAILURE_RETRY(umount(path.data()) == 0) || errno == ENOENT || errno == EINVAL)
+            << path;
+}
+
+void CheckDetachLoopDevices(const std::set<std::string>& exclude_names = {}) {
+    // ~SnapshotFuzzEnv automatically does the following.
+    std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(BLOCK_SYSFS), closedir);
+    PCHECK(dir != nullptr) << BLOCK_SYSFS;
+    LoopControl loop_control;
+    dirent* dp;
+    while ((dp = readdir(dir.get())) != nullptr) {
+        if (exclude_names.find(dp->d_name) != exclude_names.end()) {
+            continue;
+        }
+        if (!ShouldDeleteLoopDevice(StringPrintf("%s/%s", BLOCK_SYSFS, dp->d_name).data())) {
+            continue;
+        }
+        PCHECK(loop_control.Detach(StringPrintf("/dev/block/%s", dp->d_name).data()));
+    }
+}
+
+void CheckUmountAll() {
+    CheckUmount(std::string(MNT_DIR) + "/snapshot_fuzz_data");
+    CheckUmount(std::string(MNT_DIR) + "/" + FAKE_ROOT_NAME);
+}
+
+class AutoDeleteDir : public AutoDevice {
+  public:
+    static std::unique_ptr<AutoDeleteDir> New(const std::string& path) {
+        if (!Mkdir(path)) {
+            return std::unique_ptr<AutoDeleteDir>(new AutoDeleteDir(""));
+        }
+        return std::unique_ptr<AutoDeleteDir>(new AutoDeleteDir(path));
+    }
+    ~AutoDeleteDir() {
+        if (!HasDevice()) return;
+        PCHECK(rmdir(name_.c_str()) == 0 || errno == ENOENT) << name_;
+    }
+
+  private:
+    AutoDeleteDir(const std::string& path) : AutoDevice(path) {}
+};
+
+class AutoUnmount : public AutoDevice {
+  public:
+    ~AutoUnmount() {
+        if (!HasDevice()) return;
+        CheckUmount(name_);
+    }
+    AutoUnmount(const std::string& path) : AutoDevice(path) {}
+};
+
+class AutoUnmountTmpfs : public AutoUnmount {
+  public:
+    static std::unique_ptr<AutoUnmount> New(const std::string& path, uint64_t size) {
+        if (mount("tmpfs", path.c_str(), "tmpfs", 0,
+                  (void*)StringPrintf("size=%" PRIu64, size).data()) == -1) {
+            PLOG(ERROR) << "Cannot mount " << path;
+            return std::unique_ptr<AutoUnmount>(new AutoUnmount(""));
+        }
+        return std::unique_ptr<AutoUnmount>(new AutoUnmount(path));
+    }
+  private:
+    using AutoUnmount::AutoUnmount;
+};
+
+// A directory on tmpfs. Upon destruct, it is unmounted and deleted.
+class AutoMemBasedDir : public AutoDevice {
+  public:
+    static std::unique_ptr<AutoMemBasedDir> New(const std::string& name, uint64_t size) {
+        auto ret = std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(name));
+        ret->auto_delete_mount_dir_ = AutoDeleteDir::New(ret->mount_path());
+        if (!ret->auto_delete_mount_dir_->HasDevice()) {
+            return std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(""));
+        }
+        ret->auto_umount_mount_point_ = AutoUnmountTmpfs::New(ret->mount_path(), size);
+        if (!ret->auto_umount_mount_point_->HasDevice()) {
+            return std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(""));
+        }
+        // tmp_path() and persist_path does not need to be deleted upon destruction, hence it is
+        // not wrapped with AutoDeleteDir.
+        if (!Mkdir(ret->tmp_path())) {
+            return std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(""));
+        }
+        if (!Mkdir(ret->persist_path())) {
+            return std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(""));
+        }
+        return ret;
+    }
+    // Return the temporary scratch directory.
+    std::string tmp_path() const {
+        CHECK(HasDevice());
+        return mount_path() + "/tmp";
+    }
+    // Return the temporary scratch directory.
+    std::string persist_path() const {
+        CHECK(HasDevice());
+        return mount_path() + "/persist";
+    }
+    // Delete all contents in tmp_path() and start over. tmp_path() itself is re-created.
+    void CheckSoftReset() {
+        PCHECK(RmdirRecursive(tmp_path()));
+        PCHECK(Mkdir(tmp_path()));
+    }
+
+  private:
+    AutoMemBasedDir(const std::string& name) : AutoDevice(name) {}
+    std::string mount_path() const {
+        CHECK(HasDevice());
+        return MNT_DIR + "/"s + name_;
+    }
+    std::unique_ptr<AutoDeleteDir> auto_delete_mount_dir_;
+    std::unique_ptr<AutoUnmount> auto_umount_mount_point_;
+};
+
+SnapshotFuzzEnv::SnapshotFuzzEnv() {
+    CheckCleanupDeviceMapperDevices();
+    CheckDetachLoopDevices();
+    CheckUmountAll();
+
+    fake_root_ = AutoMemBasedDir::New(FAKE_ROOT_NAME, FAKE_ROOT_SIZE);
+    CHECK(fake_root_ != nullptr);
+    CHECK(fake_root_->HasDevice());
+    loop_control_ = std::make_unique<LoopControl>();
+
+    fake_data_mount_point_ = MNT_DIR + "/snapshot_fuzz_data"s;
+    auto_delete_data_mount_point_ = AutoDeleteDir::New(fake_data_mount_point_);
+    CHECK(auto_delete_data_mount_point_ != nullptr);
+    CHECK(auto_delete_data_mount_point_->HasDevice());
+
+    const auto& fake_persist_path = fake_root_->persist_path();
+    mapped_super_ = CheckMapImage(fake_persist_path + "/super.img", SUPER_IMAGE_SIZE,
+                                  loop_control_.get(), &fake_super_);
+    mapped_data_ = CheckMapImage(fake_persist_path + "/data.img", DATA_IMAGE_SIZE,
+                                 loop_control_.get(), &fake_data_block_device_);
+    mounted_data_ = CheckMountFormatData(fake_data_block_device_, fake_data_mount_point_);
+}
+
+SnapshotFuzzEnv::~SnapshotFuzzEnv() {
+    CheckCleanupDeviceMapperDevices();
+    mounted_data_ = nullptr;
+    auto_delete_data_mount_point_ = nullptr;
+    mapped_data_ = nullptr;
+    mapped_super_ = nullptr;
+    CheckDetachLoopDevices();
+    loop_control_ = nullptr;
+    fake_root_ = nullptr;
+    CheckUmountAll();
+}
+
+void CheckZeroFill(const std::string& file, size_t size) {
+    std::string zeros(size, '\0');
+    PCHECK(WriteStringToFile(zeros, file)) << "Cannot write zeros to " << file;
+}
+
+void SnapshotFuzzEnv::CheckSoftReset() {
+    fake_root_->CheckSoftReset();
+    CheckZeroFill(super(), SUPER_IMAGE_SIZE);
+    CheckCleanupDeviceMapperDevices();
+    CheckDetachLoopDevices({Basename(fake_super_), Basename(fake_data_block_device_)});
+}
+
+std::unique_ptr<IImageManager> SnapshotFuzzEnv::CheckCreateFakeImageManager(
+        const std::string& metadata_dir, const std::string& data_dir) {
+    PCHECK(Mkdir(metadata_dir));
+    PCHECK(Mkdir(data_dir));
+    return SnapshotFuzzImageManager::Open(metadata_dir, data_dir);
+}
+
+// Helper to create a loop device for a file.
+static void CheckCreateLoopDevice(LoopControl* control, const std::string& file,
+                                  const std::chrono::milliseconds& timeout_ms, std::string* path) {
+    static constexpr int kOpenFlags = O_RDWR | O_NOFOLLOW | O_CLOEXEC;
+    android::base::unique_fd file_fd(open(file.c_str(), kOpenFlags));
+    PCHECK(file_fd >= 0) << "Could not open file: " << file;
+    CHECK(control->Attach(file_fd, timeout_ms, path))
+            << "Could not create loop device for: " << file;
+}
+
+class AutoDetachLoopDevice : public AutoDevice {
+  public:
+    AutoDetachLoopDevice(LoopControl* control, const std::string& device)
+        : AutoDevice(device), control_(control) {}
+    ~AutoDetachLoopDevice() { PCHECK(control_->Detach(name_)) << name_; }
+
+  private:
+    LoopControl* control_;
+};
+
+std::unique_ptr<AutoDevice> SnapshotFuzzEnv::CheckMapImage(const std::string& img_path,
+                                                           uint64_t size, LoopControl* control,
+                                                           std::string* mapped_path) {
+    CheckZeroFill(img_path, size);
+    CheckCreateLoopDevice(control, img_path, 1s, mapped_path);
+
+    return std::make_unique<AutoDetachLoopDevice>(control, *mapped_path);
+}
+
+SnapshotTestModule SnapshotFuzzEnv::CheckCreateSnapshotManager(const SnapshotFuzzData& data) {
+    SnapshotTestModule ret;
+    auto partition_opener = std::make_unique<TestPartitionOpener>(super());
+    ret.opener = partition_opener.get();
+    CheckWriteSuperMetadata(data, *partition_opener);
+    auto metadata_dir = fake_root_->tmp_path() + "/snapshot_metadata";
+    PCHECK(Mkdir(metadata_dir));
+    if (data.has_metadata_snapshots_dir()) {
+        PCHECK(Mkdir(metadata_dir + "/snapshots"));
+    }
+
+    ret.device_info = new SnapshotFuzzDeviceInfo(data.device_info_data(),
+                                                 std::move(partition_opener), metadata_dir);
+    auto snapshot = SnapshotManager::New(ret.device_info /* takes ownership */);
+    snapshot->images_ =
+            CheckCreateFakeImageManager(fake_root_->tmp_path() + "/images_manager_metadata",
+                                        fake_data_mount_point_ + "/image_manager_data");
+    snapshot->has_local_image_manager_ = data.manager_data().is_local_image_manager();
+    ret.snapshot = std::move(snapshot);
+
+    return ret;
+}
+
+const std::string& SnapshotFuzzEnv::super() const {
+    return fake_super_;
+}
+
+void SnapshotFuzzEnv::CheckWriteSuperMetadata(const SnapshotFuzzData& data,
+                                              const IPartitionOpener& opener) {
+    if (!data.is_super_metadata_valid()) {
+        // Leave it zero.
+        return;
+    }
+
+    BlockDeviceInfo super_device("super", SUPER_IMAGE_SIZE, 0, 0, 4096);
+    std::vector<BlockDeviceInfo> devices = {super_device};
+    auto builder = MetadataBuilder::New(devices, "super", 65536, 2);
+    CHECK(builder != nullptr);
+
+    // Attempt to create a super partition metadata using proto. All errors are ignored.
+    for (const auto& group_proto : data.super_data().dynamic_partition_metadata().groups()) {
+        (void)builder->AddGroup(group_proto.name(), group_proto.size());
+        for (const auto& partition_name : group_proto.partition_names()) {
+            (void)builder->AddPartition(partition_name, group_proto.name(),
+                                        LP_PARTITION_ATTR_READONLY);
+        }
+    }
+
+    for (const auto& partition_proto : data.super_data().partitions()) {
+        auto p = builder->FindPartition(partition_proto.partition_name());
+        if (p == nullptr) continue;
+        (void)builder->ResizePartition(p, partition_proto.new_partition_info().size());
+    }
+
+    auto metadata = builder->Export();
+    // metadata may be nullptr if it is not valid (e.g. partition name too long).
+    // In this case, just use empty super partition data.
+    if (metadata == nullptr) {
+        builder = MetadataBuilder::New(devices, "super", 65536, 2);
+        CHECK(builder != nullptr);
+        metadata = builder->Export();
+        CHECK(metadata != nullptr);
+    }
+    CHECK(FlashPartitionTable(opener, super(), *metadata.get()));
+}
+
+std::unique_ptr<AutoDevice> SnapshotFuzzEnv::CheckMountFormatData(const std::string& blk_device,
+                                                                  const std::string& mount_point) {
+    FstabEntry entry{
+            .blk_device = blk_device,
+            .length = static_cast<off64_t>(DATA_IMAGE_SIZE),
+            .fs_type = "ext4",
+            .mount_point = mount_point,
+    };
+    CHECK(0 == fs_mgr_do_format(entry, false /* crypt_footer */));
+    CHECK(0 == fs_mgr_do_mount_one(entry));
+    return std::make_unique<AutoUnmount>(mount_point);
+}
+
+SnapshotFuzzImageManager::~SnapshotFuzzImageManager() {
+    // Remove relevant gsid.mapped_images.* props.
+    for (const auto& name : mapped_) {
+        CHECK(UnmapImageIfExists(name)) << "Cannot unmap " << name;
+    }
+}
+
+bool SnapshotFuzzImageManager::MapImageDevice(const std::string& name,
+                                              const std::chrono::milliseconds& timeout_ms,
+                                              std::string* path) {
+    if (impl_->MapImageDevice(name, timeout_ms, path)) {
+        mapped_.insert(name);
+        return true;
+    }
+    return false;
+}
+
+}  // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
new file mode 100644
index 0000000..fa327b8
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
@@ -0,0 +1,203 @@
+// Copyright (C) 2020 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 <memory>
+#include <set>
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android/snapshot/snapshot_fuzz.pb.h>
+#include <libdm/loop_control.h>
+#include <libfiemap/image_manager.h>
+#include <liblp/liblp.h>
+#include <libsnapshot/auto_device.h>
+#include <libsnapshot/test_helpers.h>
+
+// libsnapshot-specific code for fuzzing. Defines fake classes that are depended
+// by SnapshotManager.
+
+#include "android/snapshot/snapshot_fuzz.pb.h"
+
+namespace android::snapshot {
+
+class AutoMemBasedDir;
+class SnapshotFuzzDeviceInfo;
+
+class DummyAutoDevice : public AutoDevice {
+  public:
+    DummyAutoDevice(bool mounted) : AutoDevice(mounted ? "dummy" : "") {}
+};
+
+struct SnapshotTestModule {
+    std::unique_ptr<ISnapshotManager> snapshot;
+    SnapshotFuzzDeviceInfo* device_info = nullptr;
+    TestPartitionOpener* opener = nullptr;
+};
+
+// Prepare test environment. This has a heavy overhead and should be done once.
+class SnapshotFuzzEnv {
+  public:
+    // Check if test should run at all.
+    static bool ShouldSkipTest();
+
+    // Initialize the environment.
+    SnapshotFuzzEnv();
+    ~SnapshotFuzzEnv();
+
+    // Soft reset part of the environment before running the next test.
+    // Abort if fails.
+    void CheckSoftReset();
+
+    // Create a snapshot manager for this test run.
+    // Client is responsible for maintaining the lifetime of |data| over the life time of
+    // ISnapshotManager.
+    SnapshotTestModule CheckCreateSnapshotManager(const SnapshotFuzzData& data);
+
+    // Return path to super partition.
+    const std::string& super() const;
+
+  private:
+    std::unique_ptr<AutoMemBasedDir> fake_root_;
+    std::unique_ptr<android::dm::LoopControl> loop_control_;
+    std::string fake_data_mount_point_;
+    std::unique_ptr<AutoDevice> auto_delete_data_mount_point_;
+    std::unique_ptr<AutoDevice> mapped_super_;
+    std::string fake_super_;
+    std::unique_ptr<AutoDevice> mapped_data_;
+    std::string fake_data_block_device_;
+    std::unique_ptr<AutoDevice> mounted_data_;
+
+    static std::unique_ptr<android::fiemap::IImageManager> CheckCreateFakeImageManager(
+            const std::string& metadata_dir, const std::string& data_dir);
+    static std::unique_ptr<AutoDevice> CheckMapImage(const std::string& fake_persist_path,
+                                                     uint64_t size,
+                                                     android::dm::LoopControl* control,
+                                                     std::string* mapped_path);
+    static std::unique_ptr<AutoDevice> CheckMountFormatData(const std::string& blk_device,
+                                                            const std::string& mount_point);
+
+    void CheckWriteSuperMetadata(const SnapshotFuzzData& proto,
+                                 const android::fs_mgr::IPartitionOpener& opener);
+};
+
+class SnapshotFuzzDeviceInfo : public ISnapshotManager::IDeviceInfo {
+  public:
+    // Client is responsible for maintaining the lifetime of |data|.
+    SnapshotFuzzDeviceInfo(const FuzzDeviceInfoData& data,
+                           std::unique_ptr<TestPartitionOpener>&& partition_opener,
+                           const std::string& metadata_dir)
+        : data_(&data),
+          partition_opener_(std::move(partition_opener)),
+          metadata_dir_(metadata_dir) {}
+
+    // Following APIs are mocked.
+    std::string GetGsidDir() const override { return "fuzz_ota"; }
+    std::string GetMetadataDir() const override { return metadata_dir_; }
+    std::string GetSuperDevice(uint32_t) const override {
+        // TestPartitionOpener can recognize this.
+        return "super";
+    }
+    const android::fs_mgr::IPartitionOpener& GetPartitionOpener() const override {
+        return *partition_opener_;
+    }
+
+    // Following APIs are fuzzed.
+    std::string GetSlotSuffix() const override { return CurrentSlotIsA() ? "_a" : "_b"; }
+    std::string GetOtherSlotSuffix() const override { return CurrentSlotIsA() ? "_b" : "_a"; }
+    bool IsOverlayfsSetup() const override { return data_->is_overlayfs_setup(); }
+    bool SetBootControlMergeStatus(android::hardware::boot::V1_1::MergeStatus) override {
+        return data_->allow_set_boot_control_merge_status();
+    }
+    bool SetSlotAsUnbootable(unsigned int) override {
+        return data_->allow_set_slot_as_unbootable();
+    }
+    bool IsRecovery() const override { return data_->is_recovery(); }
+
+    void SwitchSlot() { switched_slot_ = !switched_slot_; }
+
+  private:
+    const FuzzDeviceInfoData* data_;
+    std::unique_ptr<TestPartitionOpener> partition_opener_;
+    std::string metadata_dir_;
+    bool switched_slot_ = false;
+
+    bool CurrentSlotIsA() const { return data_->slot_suffix_is_a() != switched_slot_; }
+};
+
+// A spy class on ImageManager implementation. Upon destruction, unmaps all images
+// map through this object.
+class SnapshotFuzzImageManager : public android::fiemap::IImageManager {
+  public:
+    static std::unique_ptr<SnapshotFuzzImageManager> Open(const std::string& metadata_dir,
+                                                          const std::string& data_dir) {
+        auto impl = android::fiemap::ImageManager::Open(metadata_dir, data_dir);
+        if (impl == nullptr) return nullptr;
+        return std::unique_ptr<SnapshotFuzzImageManager>(
+                new SnapshotFuzzImageManager(std::move(impl)));
+    }
+
+    ~SnapshotFuzzImageManager();
+
+    // Spied APIs.
+    bool MapImageDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms,
+                        std::string* path) override;
+
+    // Other functions call through.
+    android::fiemap::FiemapStatus CreateBackingImage(
+            const std::string& name, uint64_t size, int flags,
+            std::function<bool(uint64_t, uint64_t)>&& on_progress) override {
+        return impl_->CreateBackingImage(name, size, flags, std::move(on_progress));
+    }
+    bool DeleteBackingImage(const std::string& name) override {
+        return impl_->DeleteBackingImage(name);
+    }
+    bool UnmapImageDevice(const std::string& name) override {
+        return impl_->UnmapImageDevice(name);
+    }
+    bool BackingImageExists(const std::string& name) override {
+        return impl_->BackingImageExists(name);
+    }
+    bool IsImageMapped(const std::string& name) override { return impl_->IsImageMapped(name); }
+    bool MapImageWithDeviceMapper(const IPartitionOpener& opener, const std::string& name,
+                                  std::string* dev) override {
+        return impl_->MapImageWithDeviceMapper(opener, name, dev);
+    }
+    bool GetMappedImageDevice(const std::string& name, std::string* device) override {
+        return impl_->GetMappedImageDevice(name, device);
+    }
+    bool MapAllImages(const std::function<bool(std::set<std::string>)>& init) override {
+        return impl_->MapAllImages(init);
+    }
+    bool DisableImage(const std::string& name) override { return impl_->DisableImage(name); }
+    bool RemoveDisabledImages() override { return impl_->RemoveDisabledImages(); }
+    std::vector<std::string> GetAllBackingImages() override { return impl_->GetAllBackingImages(); }
+    android::fiemap::FiemapStatus ZeroFillNewImage(const std::string& name,
+                                                   uint64_t bytes) override {
+        return impl_->ZeroFillNewImage(name, bytes);
+    }
+    bool RemoveAllImages() override { return impl_->RemoveAllImages(); }
+    bool UnmapImageIfExists(const std::string& name) override {
+        return impl_->UnmapImageIfExists(name);
+    }
+
+  private:
+    std::unique_ptr<android::fiemap::IImageManager> impl_;
+    std::set<std::string> mapped_;
+
+    SnapshotFuzzImageManager(std::unique_ptr<android::fiemap::IImageManager>&& impl)
+        : impl_(std::move(impl)) {}
+};
+
+}  // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot_stub.cpp b/fs_mgr/libsnapshot/snapshot_stub.cpp
index 2747b03..2aaa78c 100644
--- a/fs_mgr/libsnapshot/snapshot_stub.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stub.cpp
@@ -89,6 +89,11 @@
     return false;
 }
 
+bool SnapshotManagerStub::FinishMergeInRecovery() {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return false;
+}
+
 CreateResult SnapshotManagerStub::RecoveryCreateSnapshotDevices() {
     LOG(ERROR) << __FUNCTION__ << " should never be called.";
     return CreateResult::ERROR;
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 53a37be..2bd0135 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1459,6 +1459,52 @@
     ASSERT_EQ(new_sm->GetUpdateState(), UpdateState::None);
 }
 
+// Test that a merge does not clear the snapshot state in fastboot.
+TEST_F(SnapshotUpdateTest, MergeInFastboot) {
+    // Execute the first update.
+    ASSERT_TRUE(sm->BeginUpdate());
+    ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
+    ASSERT_TRUE(MapUpdateSnapshots());
+    ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
+
+    // Simulate shutting down the device.
+    ASSERT_TRUE(UnmapAll());
+
+    // After reboot, init does first stage mount.
+    auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
+    ASSERT_NE(init, nullptr);
+    ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
+    init = nullptr;
+
+    // Initiate the merge and then immediately stop it to simulate a reboot.
+    auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
+    ASSERT_TRUE(new_sm->InitiateMerge());
+    ASSERT_TRUE(UnmapAll());
+
+    // Simulate a reboot into recovery.
+    auto test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
+    test_device->set_recovery(true);
+    new_sm = SnapshotManager::NewForFirstStageMount(test_device.release());
+
+    ASSERT_TRUE(new_sm->FinishMergeInRecovery());
+
+    auto mount = new_sm->EnsureMetadataMounted();
+    ASSERT_TRUE(mount && mount->HasDevice());
+    ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::MergeCompleted);
+
+    // Finish the merge in a normal boot.
+    test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
+    init = SnapshotManager::NewForFirstStageMount(test_device.release());
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
+    init = nullptr;
+
+    test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
+    new_sm = SnapshotManager::NewForFirstStageMount(test_device.release());
+    ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::MergeCompleted);
+    ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::None);
+}
+
 // Test that after an OTA, before a merge, we can wipe data in recovery.
 TEST_F(SnapshotUpdateTest, DataWipeRollbackInRecovery) {
     // Execute the first update.
diff --git a/fs_mgr/libsnapshot/test_helpers.cpp b/fs_mgr/libsnapshot/test_helpers.cpp
index b036606..f82a602 100644
--- a/fs_mgr/libsnapshot/test_helpers.cpp
+++ b/fs_mgr/libsnapshot/test_helpers.cpp
@@ -212,8 +212,8 @@
         return AssertionFailure() << strerror(errno);
     }
     bsize_ = buf.f_bsize;
-    free_space_ = buf.f_bsize * buf.f_bfree;
-    available_space_ = buf.f_bsize * buf.f_bavail;
+    free_space_ = bsize_ * buf.f_bfree;
+    available_space_ = bsize_ * buf.f_bavail;
     return AssertionSuccess();
 }
 
diff --git a/fs_mgr/libsnapshot/update_engine/update_metadata.proto b/fs_mgr/libsnapshot/update_engine/update_metadata.proto
new file mode 100644
index 0000000..8a11eaa
--- /dev/null
+++ b/fs_mgr/libsnapshot/update_engine/update_metadata.proto
@@ -0,0 +1,80 @@
+//
+// Copyright (C) 2020 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.
+//
+
+// A subset of system/update_engine/update_metadata.proto. A separate file is
+// used here because:
+// - The original file is optimized for LITE_RUNTIME, but fuzzing needs
+// reflection.
+// - The definition here has less fields. libsnapshot only uses fields declared
+// here, and all fields declared here are fuzzed by libsnapshot_fuzzer. If
+// libsnapshot uses more fields in system/update_engine/update_metadata.proto
+// in the future, they must be added here too, otherwise it will fail to
+// compile.
+//
+// It is okay that this file is older than
+// system/update_engine/update_metadata.proto as long as the messages defined
+// here can also be parsed by protobuf defined there. However, it is not
+// okay to add fields here without adding them to
+// system/update_engine/update_metadata.proto. Doing so will cause a compiler
+// error when libsnapshot code starts to use these dangling fields.
+
+syntax = "proto2";
+
+package chromeos_update_engine;
+
+message Extent {
+    optional uint64 start_block = 1;
+    optional uint64 num_blocks = 2;
+}
+
+message PartitionInfo {
+    optional uint64 size = 1;
+}
+
+message InstallOperation {
+    enum Type {
+        SOURCE_COPY = 4;
+        // Not used by libsnapshot. Declared here so that the fuzzer has an
+        // alternative value to use for |type|.
+        ZERO = 6;
+    }
+    required Type type = 1;
+    repeated Extent src_extents = 4;
+    repeated Extent dst_extents = 6;
+}
+
+message PartitionUpdate {
+    required string partition_name = 1;
+    optional PartitionInfo new_partition_info = 7;
+    repeated InstallOperation operations = 8;
+    optional Extent hash_tree_extent = 11;
+    optional Extent fec_extent = 15;
+}
+
+message DynamicPartitionGroup {
+    required string name = 1;
+    optional uint64 size = 2;
+    repeated string partition_names = 3;
+}
+
+message DynamicPartitionMetadata {
+    repeated DynamicPartitionGroup groups = 1;
+}
+
+message DeltaArchiveManifest {
+    repeated PartitionUpdate partitions = 13;
+    optional DynamicPartitionMetadata dynamic_partition_metadata = 15;
+}
diff --git a/init/README.md b/init/README.md
index 13f1bac..b70366b 100644
--- a/init/README.md
+++ b/init/README.md
@@ -322,6 +322,10 @@
   This is mutually exclusive with the console option, which additionally connects stdin to the
   given console.
 
+`task_profiles <profile> [ <profile>\* ]`
+> Set task profiles for the process when it forks. This is designed to replace the use of
+  writepid option for moving a process into a cgroup.
+
 `timeout_period <seconds>`
 > Provide a timeout after which point the service will be killed. The oneshot keyword is respected
   here, so oneshot services do not automatically restart, however all other services will.
@@ -356,6 +360,8 @@
   cgroup/cpuset usage. If no files under /dev/cpuset/ are specified, but the
   system property 'ro.cpuset.default' is set to a non-empty cpuset name (e.g.
   '/foreground'), then the pid is written to file /dev/cpuset/_cpuset\_name_/tasks.
+  The use of this option for moving a process into a cgroup is obsolete. Please
+  use task_profiles option instead.
 
 
 Triggers
@@ -638,7 +644,8 @@
 `wait <path> [ <timeout> ]`
 > Poll for the existence of the given file and return when found,
   or the timeout has been reached. If timeout is not specified it
-  currently defaults to five seconds.
+  currently defaults to five seconds. The timeout value can be
+  fractional seconds, specified in floating point notation.
 
 `wait_for_prop <name> <value>`
 > Wait for system property _name_ to be _value_. Properties are expanded
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 200bfff..149a766 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -49,6 +49,7 @@
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/parsedouble.h>
 #include <android-base/parseint.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
@@ -1065,11 +1066,12 @@
 static Result<void> do_wait(const BuiltinArguments& args) {
     auto timeout = kCommandRetryTimeout;
     if (args.size() == 3) {
-        int timeout_int;
-        if (!android::base::ParseInt(args[2], &timeout_int)) {
+        double timeout_double;
+        if (!android::base::ParseDouble(args[2], &timeout_double, 0)) {
             return Error() << "failed to parse timeout";
         }
-        timeout = std::chrono::seconds(timeout_int);
+        timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(
+                std::chrono::duration<double>(timeout_double));
     }
 
     if (wait_for_file(args[1].c_str(), timeout) != 0) {
diff --git a/init/check_builtins.cpp b/init/check_builtins.cpp
index d62ecb0..d1a84f3 100644
--- a/init/check_builtins.cpp
+++ b/init/check_builtins.cpp
@@ -25,6 +25,7 @@
 #include <sys/time.h>
 
 #include <android-base/logging.h>
+#include <android-base/parsedouble.h>
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
 
@@ -205,8 +206,8 @@
 
 Result<void> check_wait(const BuiltinArguments& args) {
     if (args.size() == 3 && !args[2].empty()) {
-        int timeout_int;
-        if (!android::base::ParseInt(args[2], &timeout_int)) {
+        double timeout_double;
+        if (!android::base::ParseDouble(args[2], &timeout_double, 0)) {
             return Error() << "failed to parse timeout";
         }
     }
diff --git a/init/first_stage_console.cpp b/init/first_stage_console.cpp
index cae53f4..cfa0d99 100644
--- a/init/first_stage_console.cpp
+++ b/init/first_stage_console.cpp
@@ -16,6 +16,7 @@
 
 #include "first_stage_console.h"
 
+#include <stdio.h>
 #include <sys/stat.h>
 #include <sys/sysmacros.h>
 #include <sys/types.h>
@@ -87,8 +88,18 @@
     _exit(127);
 }
 
-bool FirstStageConsole(const std::string& cmdline) {
-    return cmdline.find("androidboot.first_stage_console=1") != std::string::npos;
+int FirstStageConsole(const std::string& cmdline) {
+    auto pos = cmdline.find("androidboot.first_stage_console=");
+    if (pos != std::string::npos) {
+        int val = 0;
+        if (sscanf(cmdline.c_str() + pos, "androidboot.first_stage_console=%d", &val) != 1) {
+            return FirstStageConsoleParam::DISABLED;
+        }
+        if (val <= FirstStageConsoleParam::MAX_PARAM_VALUE && val >= 0) {
+            return val;
+        }
+    }
+    return FirstStageConsoleParam::DISABLED;
 }
 
 }  // namespace init
diff --git a/init/first_stage_console.h b/init/first_stage_console.h
index 7485339..8f36a7c 100644
--- a/init/first_stage_console.h
+++ b/init/first_stage_console.h
@@ -21,8 +21,15 @@
 namespace android {
 namespace init {
 
+enum FirstStageConsoleParam {
+    DISABLED = 0,
+    CONSOLE_ON_FAILURE = 1,
+    IGNORE_FAILURE = 2,
+    MAX_PARAM_VALUE = IGNORE_FAILURE,
+};
+
 void StartConsole();
-bool FirstStageConsole(const std::string& cmdline);
+int FirstStageConsole(const std::string& cmdline);
 
 }  // namespace init
 }  // namespace android
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index 5eca644..1a608f6 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -200,16 +200,16 @@
     }
 
     Modprobe m({"/lib/modules"}, module_load_file);
-    auto want_console = ALLOW_FIRST_STAGE_CONSOLE && FirstStageConsole(cmdline);
+    auto want_console = ALLOW_FIRST_STAGE_CONSOLE ? FirstStageConsole(cmdline) : 0;
     if (!m.LoadListedModules(!want_console)) {
-        if (want_console) {
+        if (want_console != FirstStageConsoleParam::DISABLED) {
             LOG(ERROR) << "Failed to load kernel modules, starting console";
         } else {
             LOG(FATAL) << "Failed to load kernel modules";
         }
     }
 
-    if (want_console) {
+    if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) {
         StartConsole();
     }
 
diff --git a/init/init.cpp b/init/init.cpp
index a9d6301..631db8e 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -76,6 +76,7 @@
 #include "service.h"
 #include "service_parser.h"
 #include "sigchld_handler.h"
+#include "subcontext.h"
 #include "system/core/init/property_service.pb.h"
 #include "util.h"
 
@@ -100,8 +101,6 @@
 static int signal_fd = -1;
 static int property_fd = -1;
 
-static std::unique_ptr<Subcontext> subcontext;
-
 struct PendingControlMessage {
     std::string message;
     std::string name;
@@ -216,16 +215,6 @@
     prop_waiter_state.ResetWaitForProp();
 }
 
-static void UnwindMainThreadStack() {
-    std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, 1));
-    if (!backtrace->Unwind(0)) {
-        LOG(ERROR) << __FUNCTION__ << ": Failed to unwind callstack.";
-    }
-    for (size_t i = 0; i < backtrace->NumFrames(); i++) {
-        LOG(ERROR) << backtrace->FormatFrameData(i);
-    }
-}
-
 static class ShutdownState {
   public:
     void TriggerShutdown(const std::string& command) {
@@ -243,13 +232,13 @@
     std::optional<std::string> CheckShutdown() {
         auto lock = std::lock_guard{shutdown_command_lock_};
         if (do_shutdown_ && !IsShuttingDown()) {
-            do_shutdown_ = false;
             return shutdown_command_;
         }
         return {};
     }
 
     bool do_shutdown() const { return do_shutdown_; }
+    void set_do_shutdown(bool value) { do_shutdown_ = value; }
 
   private:
     std::mutex shutdown_command_lock_;
@@ -257,16 +246,28 @@
     bool do_shutdown_ = false;
 } shutdown_state;
 
+static void UnwindMainThreadStack() {
+    std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, 1));
+    if (!backtrace->Unwind(0)) {
+        LOG(ERROR) << __FUNCTION__ << "sys.powerctl: Failed to unwind callstack.";
+    }
+    for (size_t i = 0; i < backtrace->NumFrames(); i++) {
+        LOG(ERROR) << "sys.powerctl: " << backtrace->FormatFrameData(i);
+    }
+}
+
 void DebugRebootLogging() {
-    LOG(INFO) << "do_shutdown: " << shutdown_state.do_shutdown()
+    LOG(INFO) << "sys.powerctl: do_shutdown: " << shutdown_state.do_shutdown()
               << " IsShuttingDown: " << IsShuttingDown();
     if (shutdown_state.do_shutdown()) {
         LOG(ERROR) << "sys.powerctl set while a previous shutdown command has not been handled";
         UnwindMainThreadStack();
+        DumpShutdownDebugInformation();
     }
     if (IsShuttingDown()) {
         LOG(ERROR) << "sys.powerctl set while init is already shutting down";
         UnwindMainThreadStack();
+        DumpShutdownDebugInformation();
     }
 }
 
@@ -279,9 +280,8 @@
     Parser parser;
 
     parser.AddSectionParser("service", std::make_unique<ServiceParser>(
-                                               &service_list, subcontext.get(), std::nullopt));
-    parser.AddSectionParser("on",
-                            std::make_unique<ActionParser>(&action_manager, subcontext.get()));
+                                               &service_list, GetSubcontext(), std::nullopt));
+    parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, GetSubcontext()));
     parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
 
     return parser;
@@ -291,9 +291,9 @@
 Parser CreateServiceOnlyParser(ServiceList& service_list, bool from_apex) {
     Parser parser;
 
-    parser.AddSectionParser("service",
-                            std::make_unique<ServiceParser>(&service_list, subcontext.get(),
-                                                            std::nullopt, from_apex));
+    parser.AddSectionParser(
+            "service", std::make_unique<ServiceParser>(&service_list, GetSubcontext(), std::nullopt,
+                                                       from_apex));
     return parser;
 }
 
@@ -537,7 +537,9 @@
 // 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.
-static void set_usb_controller() {
+static void SetUsbController() {
+    static auto controller_set = false;
+    if (controller_set) return;
     std::unique_ptr<DIR, decltype(&closedir)>dir(opendir("/sys/class/udc"), closedir);
     if (!dir) return;
 
@@ -546,6 +548,7 @@
         if (dp->d_name[0] == '.') continue;
 
         SetProperty("sys.usb.controller", dp->d_name);
+        controller_set = true;
         break;
     }
 }
@@ -721,7 +724,7 @@
     trigger_shutdown = [](const std::string& command) { shutdown_state.TriggerShutdown(command); };
 
     SetStdioToDevNull(argv);
-    InitKernelLogging(argv);
+    InitSecondStageLogging(argv);
     LOG(INFO) << "init second stage started!";
 
     // Init should not crash because of a dependence on any other process, therefore we ignore
@@ -800,7 +803,7 @@
     fs_mgr_vendor_overlay_mount_all();
     export_oem_lock_status();
     MountHandler mount_handler(&epoll);
-    set_usb_controller();
+    SetUsbController();
 
     const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
     Action::set_function_map(&function_map);
@@ -809,7 +812,7 @@
         PLOG(FATAL) << "SetupMountNamespaces failed";
     }
 
-    subcontext = InitializeSubcontext();
+    InitializeSubcontext();
 
     ActionManager& am = ActionManager::GetInstance();
     ServiceList& sm = ServiceList::GetInstance();
@@ -874,6 +877,7 @@
             LOG(INFO) << "Got shutdown_command '" << *shutdown_command
                       << "' Calling HandlePowerctlMessage()";
             HandlePowerctlMessage(*shutdown_command);
+            shutdown_state.set_do_shutdown(false);
         }
 
         if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
@@ -909,6 +913,7 @@
         }
         if (!IsShuttingDown()) {
             HandleControlMessages();
+            SetUsbController();
         }
     }
 
diff --git a/init/init_test.cpp b/init/init_test.cpp
index caf3e03..07b4724 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -239,6 +239,28 @@
     EXPECT_EQ(6, num_executed);
 }
 
+TEST(init, RejectsCriticalAndOneshotService) {
+    std::string init_script =
+            R"init(
+service A something
+  class first
+  critical
+  oneshot
+)init";
+
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    ASSERT_TRUE(android::base::WriteStringToFd(init_script, tf.fd));
+
+    ServiceList service_list;
+    Parser parser;
+    parser.AddSectionParser("service",
+                            std::make_unique<ServiceParser>(&service_list, nullptr, std::nullopt));
+
+    ASSERT_TRUE(parser.ParseConfig(tf.path));
+    ASSERT_EQ(1u, parser.parse_error_count());
+}
+
 }  // namespace init
 }  // namespace android
 
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 842b2e5..82f5b8c 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -877,28 +877,32 @@
 }
 
 void PropertyLoadBootDefaults() {
-    // TODO(b/117892318): merge prop.default and build.prop files into one
     // We read the properties and their values into a map, in order to always allow properties
     // loaded in the later property files to override the properties in loaded in the earlier
     // property files, regardless of if they are "ro." properties or not.
     std::map<std::string, std::string> properties;
-    if (!load_properties_from_file("/system/etc/prop.default", nullptr, &properties)) {
-        // Try recovery path
-        if (!load_properties_from_file("/prop.default", nullptr, &properties)) {
-            // Try legacy path
-            load_properties_from_file("/default.prop", nullptr, &properties);
-        }
+
+    if (IsRecoveryMode()) {
+        load_properties_from_file("/prop.default", nullptr, &properties);
     }
+
     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);
+
+    // TODO(b/117892318): uncomment the following condition when vendor.imgs for
+    // aosp_* targets are all updated.
+//    if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_R__) {
+        load_properties_from_file("/vendor/default.prop", nullptr, &properties);
+//    }
     load_properties_from_file("/vendor/build.prop", nullptr, &properties);
+
     if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) {
         load_properties_from_file("/odm/etc/build.prop", nullptr, &properties);
     } else {
         load_properties_from_file("/odm/default.prop", nullptr, &properties);
         load_properties_from_file("/odm/build.prop", nullptr, &properties);
     }
+
     load_properties_from_file("/product/build.prop", nullptr, &properties);
     load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
 
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 72f0450..ffd58a3 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -66,8 +66,6 @@
 #include "sigchld_handler.h"
 #include "util.h"
 
-#define PROC_SYSRQ "/proc/sysrq-trigger"
-
 using namespace std::literals;
 
 using android::base::boot_clock;
@@ -758,20 +756,24 @@
 
 static Result<void> DoUserspaceReboot() {
     LOG(INFO) << "Userspace reboot initiated";
-    auto guard = android::base::make_scope_guard([] {
+    // An ugly way to pass a more precise reason on why fallback to hard reboot was triggered.
+    std::string sub_reason = "";
+    auto guard = android::base::make_scope_guard([&sub_reason] {
         // Leave shutdown so that we can handle a full reboot.
         LeaveShutdown();
-        trigger_shutdown("reboot,userspace_failed,shutdown_aborted");
+        trigger_shutdown("reboot,userspace_failed,shutdown_aborted," + sub_reason);
     });
     // Triggering userspace-reboot-requested will result in a bunch of setprop
     // actions. We should make sure, that all of them are propagated before
     // proceeding with userspace reboot. Synchronously setting sys.init.userspace_reboot.in_progress
     // property is not perfect, but it should do the trick.
     if (!android::sysprop::InitProperties::userspace_reboot_in_progress(true)) {
+        sub_reason = "setprop";
         return Error() << "Failed to set sys.init.userspace_reboot.in_progress property";
     }
     EnterShutdown();
     if (!SetProperty("sys.powerctl", "")) {
+        sub_reason = "resetprop";
         return Error() << "Failed to reset sys.powerctl property";
     }
     std::vector<Service*> stop_first;
@@ -800,18 +802,22 @@
     StopServicesAndLogViolations(stop_first, sigterm_timeout, true /* SIGTERM */);
     if (int r = StopServicesAndLogViolations(stop_first, sigkill_timeout, false /* SIGKILL */);
         r > 0) {
+        sub_reason = "sigkill";
         // TODO(b/135984674): store information about offending services for debugging.
         return Error() << r << " post-data services are still running";
     }
     if (auto result = KillZramBackingDevice(); !result.ok()) {
+        sub_reason = "zram";
         return result;
     }
     if (auto result = CallVdc("volume", "reset"); !result.ok()) {
+        sub_reason = "vold_reset";
         return result;
     }
     if (int r = StopServicesAndLogViolations(GetDebuggingServices(true /* only_post_data */),
                                              sigkill_timeout, false /* SIGKILL */);
         r > 0) {
+        sub_reason = "sigkill_debug";
         // TODO(b/135984674): store information about offending services for debugging.
         return Error() << r << " debugging services are still running";
     }
@@ -822,9 +828,11 @@
         LOG(INFO) << "sync() took " << sync_timer;
     }
     if (auto result = UnmountAllApexes(); !result.ok()) {
+        sub_reason = "apex";
         return result;
     }
     if (!SwitchToBootstrapMountNamespaceIfNeeded()) {
+        sub_reason = "ns_switch";
         return Error() << "Failed to switch to bootstrap namespace";
     }
     // Remove services that were defined in an APEX.
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
index 485188b..76460a5 100644
--- a/init/reboot_utils.cpp
+++ b/init/reboot_utils.cpp
@@ -29,6 +29,7 @@
 #include <cutils/android_reboot.h>
 
 #include "capabilities.h"
+#include "reboot_utils.h"
 
 namespace android {
 namespace init {
@@ -138,6 +139,9 @@
         LOG(ERROR) << backtrace->FormatFrameData(i);
     }
     if (init_fatal_panic) {
+        LOG(ERROR) << __FUNCTION__ << ": Trigger crash";
+        android::base::WriteStringToFile("c", PROC_SYSRQ);
+        LOG(ERROR) << __FUNCTION__ << ": Sys-Rq failed to crash the system; fallback to exit().";
         _exit(signal_number);
     }
     RebootSystem(ANDROID_RB_RESTART2, init_fatal_reboot_target);
diff --git a/init/reboot_utils.h b/init/reboot_utils.h
index 878ad96..05bb9ae 100644
--- a/init/reboot_utils.h
+++ b/init/reboot_utils.h
@@ -18,6 +18,8 @@
 
 #include <string>
 
+#define PROC_SYSRQ "/proc/sysrq-trigger"
+
 namespace android {
 namespace init {
 
diff --git a/init/service.cpp b/init/service.cpp
index 20400a0..165b848 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -513,6 +513,10 @@
             LOG(ERROR) << "failed to write pid to files: " << result.error();
         }
 
+        if (task_profiles_.size() > 0 && !SetTaskProfiles(getpid(), task_profiles_)) {
+            LOG(ERROR) << "failed to set task profiles";
+        }
+
         // As requested, set our gid, supplemental gids, uid, context, and
         // priority. Aborts on failure.
         SetProcessAttributesAndCaps();
diff --git a/init/service.h b/init/service.h
index 9f1d697..34ed5ef 100644
--- a/init/service.h
+++ b/init/service.h
@@ -170,6 +170,8 @@
 
     std::vector<std::string> writepid_files_;
 
+    std::vector<std::string> task_profiles_;
+
     std::set<std::string> interfaces_;  // e.g. some.package.foo@1.0::IBaz/instance-name
 
     // keycodes for triggering this service via /dev/input/input*
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 560f693..bdac077 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -360,6 +360,12 @@
     return Error() << "Invalid shutdown option";
 }
 
+Result<void> ServiceParser::ParseTaskProfiles(std::vector<std::string>&& args) {
+    args.erase(args.begin());
+    service_->task_profiles_ = std::move(args);
+    return {};
+}
+
 Result<void> ServiceParser::ParseTimeoutPeriod(std::vector<std::string>&& args) {
     int period;
     if (!ParseInt(args[1], &period, 1)) {
@@ -529,6 +535,7 @@
         {"sigstop",                 {0,     0,    &ServiceParser::ParseSigstop}},
         {"socket",                  {3,     6,    &ServiceParser::ParseSocket}},
         {"stdio_to_kmsg",           {0,     0,    &ServiceParser::ParseStdioToKmsg}},
+        {"task_profiles",           {1,     kMax, &ServiceParser::ParseTaskProfiles}},
         {"timeout_period",          {1,     1,    &ServiceParser::ParseTimeoutPeriod}},
         {"updatable",               {0,     0,    &ServiceParser::ParseUpdatable}},
         {"user",                    {1,     1,    &ServiceParser::ParseUser}},
@@ -598,6 +605,13 @@
         }
     }
 
+    if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_R__) {
+        if ((service_->flags() & SVC_CRITICAL) != 0 && (service_->flags() & SVC_ONESHOT) != 0) {
+            return Error() << "service '" << service_->name()
+                           << "' can't be both critical and oneshot";
+        }
+    }
+
     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 7bb0cc0..0fd2da5 100644
--- a/init/service_parser.h
+++ b/init/service_parser.h
@@ -78,6 +78,7 @@
     Result<void> ParseSigstop(std::vector<std::string>&& args);
     Result<void> ParseSocket(std::vector<std::string>&& args);
     Result<void> ParseStdioToKmsg(std::vector<std::string>&& args);
+    Result<void> ParseTaskProfiles(std::vector<std::string>&& args);
     Result<void> ParseTimeoutPeriod(std::vector<std::string>&& args);
     Result<void> ParseFile(std::vector<std::string>&& args);
     Result<void> ParseUser(std::vector<std::string>&& args);
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 5263c14..f3dd538 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -52,6 +52,8 @@
 namespace {
 
 std::string shutdown_command;
+static bool subcontext_terminated_by_shutdown;
+static std::unique_ptr<Subcontext> subcontext;
 
 class SubcontextProcess {
   public:
@@ -323,34 +325,30 @@
     return expanded_args;
 }
 
-static std::vector<Subcontext> subcontexts;
-static bool shutting_down;
-
-std::unique_ptr<Subcontext> InitializeSubcontext() {
+void InitializeSubcontext() {
     if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
-        return std::make_unique<Subcontext>(std::vector<std::string>{"/vendor", "/odm"},
-                                            kVendorContext);
+        subcontext.reset(
+                new Subcontext(std::vector<std::string>{"/vendor", "/odm"}, kVendorContext));
     }
-    return nullptr;
+}
+
+Subcontext* GetSubcontext() {
+    return subcontext.get();
 }
 
 bool SubcontextChildReap(pid_t pid) {
-    for (auto& subcontext : subcontexts) {
-        if (subcontext.pid() == pid) {
-            if (!shutting_down) {
-                subcontext.Restart();
-            }
-            return true;
+    if (subcontext->pid() == pid) {
+        if (!subcontext_terminated_by_shutdown) {
+            subcontext->Restart();
         }
+        return true;
     }
     return false;
 }
 
 void SubcontextTerminate() {
-    shutting_down = true;
-    for (auto& subcontext : subcontexts) {
-        kill(subcontext.pid(), SIGTERM);
-    }
+    subcontext_terminated_by_shutdown = true;
+    kill(subcontext->pid(), SIGTERM);
 }
 
 }  // namespace init
diff --git a/init/subcontext.h b/init/subcontext.h
index 5e1d8a8..788d3be 100644
--- a/init/subcontext.h
+++ b/init/subcontext.h
@@ -60,7 +60,8 @@
 };
 
 int SubcontextMain(int argc, char** argv, const BuiltinFunctionMap* function_map);
-std::unique_ptr<Subcontext> InitializeSubcontext();
+void InitializeSubcontext();
+Subcontext* GetSubcontext();
 bool SubcontextChildReap(pid_t pid);
 void SubcontextTerminate();
 
diff --git a/init/test_kill_services/AndroidTest.xml b/init/test_kill_services/AndroidTest.xml
index c1dcd59..8018efa 100644
--- a/init/test_kill_services/AndroidTest.xml
+++ b/init/test_kill_services/AndroidTest.xml
@@ -18,7 +18,16 @@
     <option name="test-suite-tag" value="apct-native" />
 
     <!-- cannot be autogenerated: b/153565474 -->
-    <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer" />
+    <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer">
+        <!-- flake mitigation, in case device is in bad state-->
+        <option name="pre-reboot" value="true" />
+        <!-- sometimes device gets into bad state, and we don't detect it in this test,
+          so the test succeeds and the next test fails. This is a really bad result, so
+          to avoid that, making sure we reboot the device again before running any more
+          tests.
+          TODO(b/152556737): add metrics for successful device recovery -->
+        <option name="post-reboot" value="true" />
+    </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
 
diff --git a/init/util.cpp b/init/util.cpp
index 24f94ec..f9be055 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -30,7 +30,9 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <mutex>
 #include <thread>
+#include <vector>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -660,5 +662,50 @@
     return access("/system/bin/recovery", F_OK) == 0;
 }
 
+// TODO(b/155203339): remove this
+// Devices in the lab seem to be stuck during shutdown, but the logs don't capture the last actions
+// before shutdown started, so we record those lines, ignoring requests to shutdown, and replay them
+// if we identify that the device is stuck.
+constexpr size_t kRecordedLogsSize = 30;
+std::string recorded_logs[kRecordedLogsSize];
+size_t recorded_log_position = 0;
+std::mutex recorded_logs_lock;
+
+void InitSecondStageLogging(char** argv) {
+    SetFatalRebootTarget();
+    auto second_stage_logger = [](android::base::LogId log_id, android::base::LogSeverity severity,
+                                  const char* tag, const char* file, unsigned int line,
+                                  const char* message) {
+        // We only store logs for init, not its children, and only if they're not related to
+        // sys.powerctl.
+        if (getpid() == 1 && strstr(message, "sys.powerctl") == nullptr) {
+            auto lock = std::lock_guard{recorded_logs_lock};
+            recorded_logs[recorded_log_position++] = message;
+            if (recorded_log_position == kRecordedLogsSize) {
+                recorded_log_position = 0;
+            }
+        }
+        android::base::KernelLogger(log_id, severity, tag, file, line, message);
+    };
+    android::base::InitLogging(argv, second_stage_logger, InitAborter);
+}
+
+void DumpShutdownDebugInformation() {
+    auto lock = std::lock_guard{recorded_logs_lock};
+    android::base::KernelLogger(
+            android::base::MAIN, android::base::ERROR, "init", nullptr, 0,
+            "===================== Dumping previous init lines =====================");
+    for (size_t i = recorded_log_position; i < kRecordedLogsSize; ++i) {
+        android::base::KernelLogger(android::base::MAIN, android::base::ERROR, "init", nullptr, 0,
+                                    recorded_logs[i].c_str());
+    }
+    for (size_t i = 0; i < recorded_log_position; ++i) {
+        android::base::KernelLogger(android::base::MAIN, android::base::ERROR, "init", nullptr, 0,
+                                    recorded_logs[i].c_str());
+    }
+    android::base::KernelLogger(android::base::MAIN, android::base::ERROR, "init", nullptr, 0,
+                                "===================== End of dump =====================");
+}
+
 }  // namespace init
 }  // namespace android
diff --git a/init/util.h b/init/util.h
index ad322d9..8167b02 100644
--- a/init/util.h
+++ b/init/util.h
@@ -78,6 +78,8 @@
 
 void SetStdioToDevNull(char** argv);
 void InitKernelLogging(char** argv);
+void InitSecondStageLogging(char** argv);
+void DumpShutdownDebugInformation();
 bool IsRecoveryMode();
 }  // namespace init
 }  // namespace android
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 96a5b55..565e7d4 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -61,8 +61,8 @@
 
 TEST(util, ReadFileSymbolicLink) {
     errno = 0;
-    // lrw------- 1 root root 23 2008-12-31 19:00 default.prop -> system/etc/prop.default
-    auto file_contents = ReadFile("/default.prop");
+    // lrwxr-xr-x 1 root shell 6 2009-01-01 09:00 /system/bin/ps -> toybox
+    auto file_contents = ReadFile("/system/bin/ps");
     EXPECT_EQ(ELOOP, errno);
     ASSERT_FALSE(file_contents.ok());
     EXPECT_EQ("open() failed: Too many symbolic links encountered",
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index dc989a0..c4cfa6f 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -48,6 +48,7 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    min_sdk_version: "apex_inherit",
 }
 
 cc_defaults {
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 175b2b7..60400c9 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -33,6 +33,7 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    min_sdk_version: "29",
     native_bridge_supported: true,
     export_include_dirs: ["include"],
     target: {
@@ -59,6 +60,7 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    min_sdk_version: "29",
 
     export_include_dirs: ["include"],
 
@@ -142,6 +144,7 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    min_sdk_version: "29",
     native_bridge_supported: true,
     srcs: [
         "config_utils.cpp",
@@ -149,6 +152,7 @@
         "iosched_policy.cpp",
         "load_file.cpp",
         "native_handle.cpp",
+        "properties.cpp",
         "record_stream.cpp",
         "strlcpy.c",
         "threads.cpp",
@@ -184,7 +188,6 @@
                 "fs_config.cpp",
                 "klog.cpp",
                 "partition_utils.cpp",
-                "properties.cpp",
                 "qtaguid.cpp",
                 "trace-dev.cpp",
                 "uevent.cpp",
@@ -265,6 +268,7 @@
     name: "libcutils_test_default",
     srcs: [
         "native_handle_test.cpp",
+        "properties_test.cpp",
         "sockets_test.cpp",
     ],
 
@@ -277,7 +281,6 @@
                 "fs_config_test.cpp",
                 "memset_test.cpp",
                 "multiuser_test.cpp",
-                "properties_test.cpp",
                 "sched_policy_test.cpp",
                 "str_parms_test.cpp",
                 "trace-dev_test.cpp",
diff --git a/libcutils/include/cutils/ashmem.h b/libcutils/include/cutils/ashmem.h
index d80caa6..1913c1e 100644
--- a/libcutils/include/cutils/ashmem.h
+++ b/libcutils/include/cutils/ashmem.h
@@ -1,14 +1,20 @@
-/* cutils/ashmem.h
- **
- ** Copyright 2008 The Android Open Source Project
- **
- ** This file is dual licensed.  It may be redistributed and/or modified
- ** under the terms of the Apache 2.0 License OR version 2 of the GNU
- ** General Public License.
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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 _CUTILS_ASHMEM_H
-#define _CUTILS_ASHMEM_H
+#pragma once
 
 #include <stddef.h>
 
@@ -30,5 +36,3 @@
 #ifdef __cplusplus
 }
 #endif
-
-#endif	/* _CUTILS_ASHMEM_H */
diff --git a/libcutils/include/cutils/properties.h b/libcutils/include/cutils/properties.h
index d2e0871..78d8bc6 100644
--- a/libcutils/include/cutils/properties.h
+++ b/libcutils/include/cutils/properties.h
@@ -14,27 +14,30 @@
  * limitations under the License.
  */
 
-#ifndef __CUTILS_PROPERTIES_H
-#define __CUTILS_PROPERTIES_H
+#pragma once
 
 #include <sys/cdefs.h>
 #include <stddef.h>
-#include <sys/system_properties.h>
 #include <stdint.h>
 
+#if __has_include(<sys/system_properties.h>)
+#include <sys/system_properties.h>
+#else
+#define PROP_VALUE_MAX 92
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/* System properties are *small* name value pairs managed by the
-** property service.  If your data doesn't fit in the provided
-** space it is not appropriate for a system property.
-**
-** WARNING: system/bionic/include/sys/system_properties.h also defines
-**          these, but with different names.  (TODO: fix that)
-*/
-#define PROPERTY_KEY_MAX   PROP_NAME_MAX
-#define PROPERTY_VALUE_MAX  PROP_VALUE_MAX
+//
+// Deprecated.
+//
+// See <android-base/properties.h> for better API.
+//
+
+#define PROPERTY_KEY_MAX PROP_NAME_MAX
+#define PROPERTY_VALUE_MAX PROP_VALUE_MAX
 
 /* property_get: returns the length of the value which will never be
 ** greater than PROPERTY_VALUE_MAX - 1 and will always be zero terminated.
@@ -146,5 +149,3 @@
 #ifdef __cplusplus
 }
 #endif
-
-#endif
diff --git a/libcutils/properties.cpp b/libcutils/properties.cpp
index 5dbbeba..03f0496 100644
--- a/libcutils/properties.cpp
+++ b/libcutils/properties.cpp
@@ -16,27 +16,19 @@
 
 #include <cutils/properties.h>
 
-#define LOG_TAG "properties"
-// #define LOG_NDEBUG 0
-
-#include <assert.h>
-#include <ctype.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-#include <cutils/sockets.h>
-#include <log/log.h>
+#include <android-base/properties.h>
 
-int8_t property_get_bool(const char *key, int8_t default_value) {
-    if (!key) {
-        return default_value;
-    }
+int8_t property_get_bool(const char* key, int8_t default_value) {
+    if (!key) return default_value;
 
     int8_t result = default_value;
-    char buf[PROPERTY_VALUE_MAX] = {'\0'};
+    char buf[PROPERTY_VALUE_MAX] = {};
 
     int len = property_get(key, buf, "");
     if (len == 1) {
@@ -57,73 +49,53 @@
     return result;
 }
 
-// Convert string property to int (default if fails); return default value if out of bounds
-static intmax_t property_get_imax(const char *key, intmax_t lower_bound, intmax_t upper_bound,
-                                  intmax_t default_value) {
-    if (!key) {
-        return default_value;
+template <typename T>
+static T property_get_int(const char* key, T default_value) {
+    if (!key) return default_value;
+
+    char value[PROPERTY_VALUE_MAX] = {};
+    if (property_get(key, value, "") < 1) return default_value;
+
+    // libcutils unwisely allows octal, which libbase doesn't.
+    T result = default_value;
+    int saved_errno = errno;
+    errno = 0;
+    char* end = nullptr;
+    intmax_t v = strtoimax(value, &end, 0);
+    if (errno != ERANGE && end != value && v >= std::numeric_limits<T>::min() &&
+        v <= std::numeric_limits<T>::max()) {
+        result = v;
     }
-
-    intmax_t result = default_value;
-    char buf[PROPERTY_VALUE_MAX] = {'\0'};
-    char *end = NULL;
-
-    int len = property_get(key, buf, "");
-    if (len > 0) {
-        int tmp = errno;
-        errno = 0;
-
-        // Infer base automatically
-        result = strtoimax(buf, &end, /*base*/ 0);
-        if ((result == INTMAX_MIN || result == INTMAX_MAX) && errno == ERANGE) {
-            // Over or underflow
-            result = default_value;
-            ALOGV("%s(%s,%" PRIdMAX ") - overflow", __FUNCTION__, key, default_value);
-        } else if (result < lower_bound || result > upper_bound) {
-            // Out of range of requested bounds
-            result = default_value;
-            ALOGV("%s(%s,%" PRIdMAX ") - out of range", __FUNCTION__, key, default_value);
-        } else if (end == buf) {
-            // Numeric conversion failed
-            result = default_value;
-            ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed", __FUNCTION__, key,
-                  default_value);
-        }
-
-        errno = tmp;
-    }
-
+    errno = saved_errno;
     return result;
 }
 
-int64_t property_get_int64(const char *key, int64_t default_value) {
-    return (int64_t)property_get_imax(key, INT64_MIN, INT64_MAX, default_value);
+int64_t property_get_int64(const char* key, int64_t default_value) {
+    return property_get_int<int64_t>(key, default_value);
 }
 
-int32_t property_get_int32(const char *key, int32_t default_value) {
-    return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value);
+int32_t property_get_int32(const char* key, int32_t default_value) {
+    return property_get_int<int32_t>(key, default_value);
 }
 
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
-int property_set(const char *key, const char *value) {
+int property_set(const char* key, const char* value) {
     return __system_property_set(key, value);
 }
 
-int property_get(const char *key, char *value, const char *default_value) {
+int property_get(const char* key, char* value, const char* default_value) {
     int len = __system_property_get(key, value);
-    if (len > 0) {
-        return len;
-    }
-    if (default_value) {
-        len = strnlen(default_value, PROPERTY_VALUE_MAX - 1);
-        memcpy(value, default_value, len);
-        value[len] = '\0';
+    if (len < 1 && default_value) {
+        snprintf(value, PROPERTY_VALUE_MAX, "%s", default_value);
+        return strlen(value);
     }
     return len;
 }
 
+#if __has_include(<sys/system_properties.h>)
+
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
 struct callback_data {
     void (*callback)(const char* name, const char* value, void* cookie);
     void* cookie;
@@ -139,6 +111,8 @@
 }
 
 int property_list(void (*fn)(const char* name, const char* value, void* cookie), void* cookie) {
-    callback_data data = { fn, cookie };
+    callback_data data = {fn, cookie};
     return __system_property_foreach(property_list_callback, &data);
 }
+
+#endif
diff --git a/libcutils/properties_test.cpp b/libcutils/properties_test.cpp
index 7921972..efc0183 100644
--- a/libcutils/properties_test.cpp
+++ b/libcutils/properties_test.cpp
@@ -93,160 +93,179 @@
     }
 };
 
-TEST_F(PropertiesTest, SetString) {
-
+TEST_F(PropertiesTest, property_set_null_key) {
     // Null key -> unsuccessful set
-    {
-        // Null key -> fails
-        EXPECT_GT(0, property_set(/*key*/NULL, PROPERTY_TEST_VALUE_DEFAULT));
-    }
+    EXPECT_GT(0, property_set(/*key*/ NULL, PROPERTY_TEST_VALUE_DEFAULT));
+}
 
-    // Null value -> returns default value
-    {
-        // Null value -> OK , and it clears the value
-        EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
-        ResetValue();
+TEST_F(PropertiesTest, property_set_null_value) {
+    // Null value -> OK, and it clears the value
+    EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/ NULL));
+    ResetValue();
 
-        // Since the value is null, default value will be returned
-        size_t len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
-        EXPECT_EQ(strlen(PROPERTY_TEST_VALUE_DEFAULT), len);
-        EXPECT_STREQ(PROPERTY_TEST_VALUE_DEFAULT, mValue);
-    }
+    // Since the value is null, default value will be returned
+    size_t len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+    EXPECT_EQ(strlen(PROPERTY_TEST_VALUE_DEFAULT), len);
+    EXPECT_STREQ(PROPERTY_TEST_VALUE_DEFAULT, mValue);
+}
 
+TEST_F(PropertiesTest, property_set) {
     // Trivial case => get returns what was set
-    {
-        size_t len = SetAndGetProperty("hello_world");
-        EXPECT_EQ(strlen("hello_world"), len) << "hello_world key";
-        EXPECT_STREQ("hello_world", mValue);
-        ResetValue();
-    }
+    size_t len = SetAndGetProperty("hello_world");
+    EXPECT_EQ(strlen("hello_world"), len) << "hello_world key";
+    EXPECT_STREQ("hello_world", mValue);
+    ResetValue();
+}
 
+TEST_F(PropertiesTest, property_set_empty) {
     // Set to empty string => get returns default always
-    {
-        const char* EMPTY_STRING_DEFAULT = "EMPTY_STRING";
-        size_t len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
-        EXPECT_EQ(strlen(EMPTY_STRING_DEFAULT), len) << "empty key";
-        EXPECT_STREQ(EMPTY_STRING_DEFAULT, mValue);
-        ResetValue();
-    }
+    const char* EMPTY_STRING_DEFAULT = "EMPTY_STRING";
+    size_t len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
+    EXPECT_EQ(strlen(EMPTY_STRING_DEFAULT), len) << "empty key";
+    EXPECT_STREQ(EMPTY_STRING_DEFAULT, mValue);
+    ResetValue();
+}
 
+TEST_F(PropertiesTest, property_set_max_length) {
     // Set to max length => get returns what was set
-    {
-        std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a');
+    std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'a');
 
-        int len = SetAndGetProperty(maxLengthString.c_str());
-        EXPECT_EQ(PROPERTY_VALUE_MAX-1, len) << "max length key";
-        EXPECT_STREQ(maxLengthString.c_str(), mValue);
-        ResetValue();
-    }
+    int len = SetAndGetProperty(maxLengthString.c_str());
+    EXPECT_EQ(PROPERTY_VALUE_MAX - 1, len) << "max length key";
+    EXPECT_STREQ(maxLengthString.c_str(), mValue);
+    ResetValue();
+}
 
+TEST_F(PropertiesTest, property_set_too_long) {
     // Set to max length + 1 => set fails
-    {
-        const char* VALID_TEST_VALUE = "VALID_VALUE";
-        ASSERT_OK(property_set(PROPERTY_TEST_KEY, VALID_TEST_VALUE));
+    const char* VALID_TEST_VALUE = "VALID_VALUE";
+    ASSERT_OK(property_set(PROPERTY_TEST_KEY, VALID_TEST_VALUE));
 
-        std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
+    std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
 
-        // Expect that the value set fails since it's too long
-        EXPECT_GT(0, property_set(PROPERTY_TEST_KEY, oneLongerString.c_str()));
-        size_t len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+    // Expect that the value set fails since it's too long
+    EXPECT_GT(0, property_set(PROPERTY_TEST_KEY, oneLongerString.c_str()));
+    size_t len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
 
-        EXPECT_EQ(strlen(VALID_TEST_VALUE), len) << "set should've failed";
-        EXPECT_STREQ(VALID_TEST_VALUE, mValue);
-        ResetValue();
-    }
+    EXPECT_EQ(strlen(VALID_TEST_VALUE), len) << "set should've failed";
+    EXPECT_STREQ(VALID_TEST_VALUE, mValue);
+    ResetValue();
 }
 
-TEST_F(PropertiesTest, GetString) {
-
+TEST_F(PropertiesTest, property_get_too_long) {
     // Try to use a default value that's too long => get truncates the value
-    {
-        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+    ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
 
-        std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'a');
-        std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
+    std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'a');
+    std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
 
-        // Expect that the value is truncated since it's too long (by 1)
-        int len = property_get(PROPERTY_TEST_KEY, mValue, oneLongerString.c_str());
-        EXPECT_EQ(PROPERTY_VALUE_MAX - 1, len);
-        EXPECT_STREQ(maxLengthString.c_str(), mValue);
-        ResetValue();
-    }
-
-    // Try to use a default value that's the max length => get succeeds
-    {
-        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
-
-        std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'b');
-
-        // Expect that the value matches maxLengthString
-        int len = property_get(PROPERTY_TEST_KEY, mValue, maxLengthString.c_str());
-        EXPECT_EQ(PROPERTY_VALUE_MAX - 1, len);
-        EXPECT_STREQ(maxLengthString.c_str(), mValue);
-        ResetValue();
-    }
-
-    // Try to use a default value of length one => get succeeds
-    {
-        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
-
-        std::string oneCharString = std::string(1, 'c');
-
-        // Expect that the value matches oneCharString
-        int len = property_get(PROPERTY_TEST_KEY, mValue, oneCharString.c_str());
-        EXPECT_EQ(1, len);
-        EXPECT_STREQ(oneCharString.c_str(), mValue);
-        ResetValue();
-    }
-
-    // Try to use a default value of length zero => get succeeds
-    {
-        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
-
-        std::string zeroCharString = std::string(0, 'd');
-
-        // Expect that the value matches oneCharString
-        int len = property_get(PROPERTY_TEST_KEY, mValue, zeroCharString.c_str());
-        EXPECT_EQ(0, len);
-        EXPECT_STREQ(zeroCharString.c_str(), mValue);
-        ResetValue();
-    }
-
-    // Try to use a NULL default value => get returns 0
-    {
-        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
-
-        // Expect a return value of 0
-        int len = property_get(PROPERTY_TEST_KEY, mValue, NULL);
-        EXPECT_EQ(0, len);
-        ResetValue();
-    }
+    // Expect that the value is truncated since it's too long (by 1)
+    int len = property_get(PROPERTY_TEST_KEY, mValue, oneLongerString.c_str());
+    EXPECT_EQ(PROPERTY_VALUE_MAX - 1, len);
+    EXPECT_STREQ(maxLengthString.c_str(), mValue);
+    ResetValue();
 }
 
-TEST_F(PropertiesTest, GetBool) {
-    /**
-     * TRUE
-     */
-    const char *valuesTrue[] = { "1", "true", "y", "yes", "on", };
-    for (size_t i = 0; i < arraysize(valuesTrue); ++i) {
-        ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesTrue[i]));
-        bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
-        EXPECT_TRUE(val) << "Property should've been TRUE for value: '" << valuesTrue[i] << "'";
-    }
+TEST_F(PropertiesTest, property_get_default_too_long) {
+    // Try to use a default value that's the max length => get succeeds
+    ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
 
-    /**
-     * FALSE
-     */
-    const char *valuesFalse[] = { "0", "false", "n", "no", "off", };
-    for (size_t i = 0; i < arraysize(valuesFalse); ++i) {
-        ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesFalse[i]));
-        bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
-        EXPECT_FALSE(val) << "Property shoud've been FALSE For string value: '" << valuesFalse[i] << "'";
-    }
+    std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'b');
 
-    /**
-     * NEITHER
-     */
+    // Expect that the value matches maxLengthString
+    int len = property_get(PROPERTY_TEST_KEY, mValue, maxLengthString.c_str());
+    EXPECT_EQ(PROPERTY_VALUE_MAX - 1, len);
+    EXPECT_STREQ(maxLengthString.c_str(), mValue);
+    ResetValue();
+}
+
+TEST_F(PropertiesTest, property_get_default_okay) {
+    // Try to use a default value of length one => get succeeds
+    ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+
+    std::string oneCharString = std::string(1, 'c');
+
+    // Expect that the value matches oneCharString
+    int len = property_get(PROPERTY_TEST_KEY, mValue, oneCharString.c_str());
+    EXPECT_EQ(1, len);
+    EXPECT_STREQ(oneCharString.c_str(), mValue);
+    ResetValue();
+}
+
+TEST_F(PropertiesTest, property_get_default_empty) {
+    // Try to use a default value of length zero => get succeeds
+    ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+
+    std::string zeroCharString = std::string(0, 'd');
+
+    // Expect that the value matches oneCharString
+    int len = property_get(PROPERTY_TEST_KEY, mValue, zeroCharString.c_str());
+    EXPECT_EQ(0, len);
+    EXPECT_STREQ(zeroCharString.c_str(), mValue);
+    ResetValue();
+}
+
+TEST_F(PropertiesTest, property_get_default_NULL) {
+    // Try to use a NULL default value => get returns 0
+    ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+
+    // Expect a return value of 0
+    int len = property_get(PROPERTY_TEST_KEY, mValue, NULL);
+    EXPECT_EQ(0, len);
+    ResetValue();
+}
+
+TEST_F(PropertiesTest, property_get_bool_0) {
+    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "0"));
+    ASSERT_FALSE(property_get_bool(PROPERTY_TEST_KEY, true));
+}
+
+TEST_F(PropertiesTest, property_get_bool_1) {
+    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "1"));
+    ASSERT_TRUE(property_get_bool(PROPERTY_TEST_KEY, false));
+}
+
+TEST_F(PropertiesTest, property_get_bool_false) {
+    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "false"));
+    ASSERT_FALSE(property_get_bool(PROPERTY_TEST_KEY, true));
+}
+
+TEST_F(PropertiesTest, property_get_bool_n) {
+    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "n"));
+    ASSERT_FALSE(property_get_bool(PROPERTY_TEST_KEY, true));
+}
+
+TEST_F(PropertiesTest, property_get_bool_no) {
+    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "no"));
+    ASSERT_FALSE(property_get_bool(PROPERTY_TEST_KEY, true));
+}
+
+TEST_F(PropertiesTest, property_get_bool_off) {
+    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "off"));
+    ASSERT_FALSE(property_get_bool(PROPERTY_TEST_KEY, true));
+}
+
+TEST_F(PropertiesTest, property_get_bool_on) {
+    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "on"));
+    ASSERT_TRUE(property_get_bool(PROPERTY_TEST_KEY, false));
+}
+
+TEST_F(PropertiesTest, property_get_bool_true) {
+    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "true"));
+    ASSERT_TRUE(property_get_bool(PROPERTY_TEST_KEY, false));
+}
+
+TEST_F(PropertiesTest, property_get_bool_y) {
+    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "y"));
+    ASSERT_TRUE(property_get_bool(PROPERTY_TEST_KEY, false));
+}
+
+TEST_F(PropertiesTest, property_get_bool_yes) {
+    ASSERT_OK(property_set(PROPERTY_TEST_KEY, "yes"));
+    ASSERT_TRUE(property_get_bool(PROPERTY_TEST_KEY, false));
+}
+
+TEST_F(PropertiesTest, property_get_bool_neither) {
     const char *valuesNeither[] = { "x0", "x1", "2", "-2", "True", "False", "garbage", "", " ",
             "+1", "  1  ", "  true", "  true  ", "  y  ", "  yes", "yes  ",
             "+0", "-0", "00", "  00  ", "  false", "false  ",
@@ -263,7 +282,7 @@
     }
 }
 
-TEST_F(PropertiesTest, GetInt64) {
+TEST_F(PropertiesTest, property_get_int64) {
     const int64_t DEFAULT_VALUE = INT64_C(0xDEADBEEFBEEFDEAD);
 
     const std::string longMaxString = ToString(INT64_MAX);
@@ -310,7 +329,7 @@
     }
 }
 
-TEST_F(PropertiesTest, GetInt32) {
+TEST_F(PropertiesTest, property_get_int32) {
     const int32_t DEFAULT_VALUE = INT32_C(0xDEADBEEF);
 
     const std::string intMaxString = ToString(INT32_MAX);
diff --git a/libgrallocusage/Android.bp b/libgrallocusage/Android.bp
index ce0c3c8..33ae13d 100644
--- a/libgrallocusage/Android.bp
+++ b/libgrallocusage/Android.bp
@@ -26,4 +26,5 @@
     export_include_dirs: ["include"],
     shared_libs: ["android.hardware.graphics.allocator@2.0"],
     header_libs: ["libhardware_headers"],
+    min_sdk_version: "29",
 }
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 0b98e1a..6051ac7 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -42,6 +42,7 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    min_sdk_version: "29",
     native_bridge_supported: true,
     export_include_dirs: ["include"],
     system_shared_libs: [],
diff --git a/liblog/README.md b/liblog/README.md
index f64f376..74a2cd7 100644
--- a/liblog/README.md
+++ b/liblog/README.md
@@ -60,8 +60,6 @@
     LOG_EVENT_INT(tag, value)
     LOG_EVENT_LONG(tag, value)
 
-    clockid_t android_log_clockid()
-
     log_id_t android_logger_get_id(struct logger *logger)
     int android_logger_clear(struct logger *logger)
     int android_logger_get_log_size(struct logger *logger)
@@ -119,7 +117,7 @@
 multiple logs can be opened with `android_logger_list_alloc()`, calling in turn the
 `android_logger_open()` for each log id.  Each entry can be retrieved with
 `android_logger_list_read()`.  The log(s) can be closed with `android_logger_list_free()`.
-`ANDROID_LOG_NONBLOCK` mode will report when the log reading is done with an `EAGAIN` error return 
+`ANDROID_LOG_NONBLOCK` mode will report when the log reading is done with an `EAGAIN` error return
 code, otherwise the `android_logger_list_read()` call will block for new entries.
 
 The `ANDROID_LOG_WRAP` mode flag to the `android_logger_list_alloc_time()` signals logd to quiesce
diff --git a/liblog/include/log/log.h b/liblog/include/log/log.h
index f27b8e6..d7e9b7d 100644
--- a/liblog/include/log/log.h
+++ b/liblog/include/log/log.h
@@ -133,19 +133,16 @@
   (void)__android_log_bswrite(_tag, _value);
 #endif
 
-#ifdef __linux__
-
-clockid_t android_log_clockid(void);
-
-#endif /* __linux__ */
-
 /* --------------------------------------------------------------------- */
 
 /*
  * Release any logger resources (a new log write will immediately re-acquire)
  *
- * May be used to clean up File descriptors after a Fork, the resources are
- * all O_CLOEXEC so wil self clean on exec().
+ * This is specifically meant to be used by Zygote to close open file descriptors after fork()
+ * and before specialization.  O_CLOEXEC is used on file descriptors, so they will be closed upon
+ * exec() in normal use cases.
+ *
+ * Note that this is not safe to call from a multi-threaded program.
  */
 void __android_log_close(void);
 
diff --git a/liblog/include/log/log_id.h b/liblog/include/log/log_id.h
index c8fafe7..8e4faeb 100644
--- a/liblog/include/log/log_id.h
+++ b/liblog/include/log/log_id.h
@@ -23,14 +23,6 @@
 #endif
 
 /*
- * Send a simple string to the log.
- */
-int __android_log_buf_write(int bufID, int prio, const char* tag,
-                            const char* text);
-int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...)
-    __attribute__((__format__(printf, 4, 5)));
-
-/*
  * log_id_t helpers
  */
 log_id_t android_name_to_log_id(const char* logName);
diff --git a/liblog/include/log/log_properties.h b/liblog/include/log/log_properties.h
index 3a8af6d..3497d63 100644
--- a/liblog/include/log/log_properties.h
+++ b/liblog/include/log/log_properties.h
@@ -1,11 +1,18 @@
 /*
-**
-** Copyright 2017, The Android Open Source Project
-**
-** This file is dual licensed.  It may be redistributed and/or modified
-** under the terms of the Apache 2.0 License OR version 2 of the GNU
-** General Public License.
-*/
+ * 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.
+ */
 
 #pragma once
 
diff --git a/liblog/include/log/log_radio.h b/liblog/include/log/log_radio.h
index 8b8a362..f5525c1 100644
--- a/liblog/include/log/log_radio.h
+++ b/liblog/include/log/log_radio.h
@@ -17,7 +17,6 @@
 #pragma once
 
 #include <android/log.h>
-#include <log/log_id.h>
 
 /*
  * Normally we strip the effects of ALOGV (VERBOSE messages),
diff --git a/liblog/include/log/log_read.h b/liblog/include/log/log_read.h
index ffd3b52..23d76f4 100644
--- a/liblog/include/log/log_read.h
+++ b/liblog/include/log/log_read.h
@@ -19,7 +19,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <log/log_id.h>
+#include <android/log.h>
 #include <log/log_time.h>
 
 #ifdef __cplusplus
@@ -112,7 +112,6 @@
 
 /* Multiple log_id_t opens */
 struct logger* android_logger_open(struct logger_list* logger_list, log_id_t id);
-#define android_logger_close android_logger_free
 /* Single log_id_t open */
 struct logger_list* android_logger_list_open(log_id_t id, int mode,
                                              unsigned int tail, pid_t pid);
diff --git a/liblog/include/log/log_safetynet.h b/liblog/include/log/log_safetynet.h
index d3e9b19..b2604b5 100644
--- a/liblog/include/log/log_safetynet.h
+++ b/liblog/include/log/log_safetynet.h
@@ -1,11 +1,18 @@
 /*
-**
-** Copyright 2017, The Android Open Source Project
-**
-** This file is dual licensed.  It may be redistributed and/or modified
-** under the terms of the Apache 2.0 License OR version 2 of the GNU
-** General Public License.
-*/
+ * 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.
+ */
 
 #pragma once
 
diff --git a/liblog/include/log/log_system.h b/liblog/include/log/log_system.h
index eaec741..6f40515 100644
--- a/liblog/include/log/log_system.h
+++ b/liblog/include/log/log_system.h
@@ -17,7 +17,6 @@
 #pragma once
 
 #include <android/log.h>
-#include <log/log_id.h>
 
 /*
  * Normally we strip the effects of ALOGV (VERBOSE messages),
diff --git a/liblog/include/log/log_time.h b/liblog/include/log/log_time.h
index 6b4458c..f50764d 100644
--- a/liblog/include/log/log_time.h
+++ b/liblog/include/log/log_time.h
@@ -37,9 +37,7 @@
   uint32_t tv_sec = 0; /* good to Feb 5 2106 */
   uint32_t tv_nsec = 0;
 
-  static const uint32_t tv_sec_max = 0xFFFFFFFFUL;
-  static const uint32_t tv_nsec_max = 999999999UL;
-  static const timespec EPOCH;
+  static constexpr timespec EPOCH = {0, 0};
 
   log_time() {}
   explicit log_time(const timespec& T)
@@ -55,16 +53,6 @@
     tv_nsec = static_cast<uint32_t>(T.tv_nsec);
   }
 #endif
-  explicit log_time(const char* T) {
-    const uint8_t* c = reinterpret_cast<const uint8_t*>(T);
-    tv_sec = c[0] | (static_cast<uint32_t>(c[1]) << 8) |
-             (static_cast<uint32_t>(c[2]) << 16) |
-             (static_cast<uint32_t>(c[3]) << 24);
-    tv_nsec = c[4] | (static_cast<uint32_t>(c[5]) << 8) |
-              (static_cast<uint32_t>(c[6]) << 16) |
-              (static_cast<uint32_t>(c[7]) << 24);
-  }
-
   /* timespec */
   bool operator==(const timespec& T) const {
     return (tv_sec == static_cast<uint32_t>(T.tv_sec)) &&
@@ -90,17 +78,6 @@
     return !(*this > T);
   }
 
-  log_time operator-=(const timespec& T);
-  log_time operator-(const timespec& T) const {
-    log_time local(*this);
-    return local -= T;
-  }
-  log_time operator+=(const timespec& T);
-  log_time operator+(const timespec& T) const {
-    log_time local(*this);
-    return local += T;
-  }
-
   /* log_time */
   bool operator==(const log_time& T) const {
     return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
@@ -123,12 +100,36 @@
     return !(*this > T);
   }
 
-  log_time operator-=(const log_time& T);
+  log_time operator-=(const log_time& T) {
+    // No concept of negative time, clamp to EPOCH
+    if (*this <= T) {
+      return *this = log_time(EPOCH);
+    }
+
+    if (this->tv_nsec < T.tv_nsec) {
+      --this->tv_sec;
+      this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
+    } else {
+      this->tv_nsec -= T.tv_nsec;
+    }
+    this->tv_sec -= T.tv_sec;
+
+    return *this;
+  }
   log_time operator-(const log_time& T) const {
     log_time local(*this);
     return local -= T;
   }
-  log_time operator+=(const log_time& T);
+  log_time operator+=(const log_time& T) {
+    this->tv_nsec += T.tv_nsec;
+    if (this->tv_nsec >= NS_PER_SEC) {
+      this->tv_nsec -= NS_PER_SEC;
+      ++this->tv_sec;
+    }
+    this->tv_sec += T.tv_sec;
+
+    return *this;
+  }
   log_time operator+(const log_time& T) const {
     log_time local(*this);
     return local += T;
@@ -146,10 +147,8 @@
            tv_nsec / (NS_PER_SEC / MS_PER_SEC);
   }
 
-  static const char default_format[];
-
   /* Add %#q for the fraction of a second to the standard library functions */
-  char* strptime(const char* s, const char* format = default_format);
+  char* strptime(const char* s, const char* format);
 } __attribute__((__packed__));
 }
 
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
index 3fbe1cb..14c408c 100644
--- a/liblog/log_time.cpp
+++ b/liblog/log_time.cpp
@@ -21,11 +21,7 @@
 
 #include <private/android_logger.h>
 
-const char log_time::default_format[] = "%m-%d %H:%M:%S.%q";
-const timespec log_time::EPOCH = {0, 0};
-
 // Add %#q for fractional seconds to standard strptime function
-
 char* log_time::strptime(const char* s, const char* format) {
   time_t now;
 #ifdef __linux__
@@ -131,59 +127,3 @@
 #endif
   return ret;
 }
-
-log_time log_time::operator-=(const timespec& T) {
-  // No concept of negative time, clamp to EPOCH
-  if (*this <= T) {
-    return *this = log_time(EPOCH);
-  }
-
-  if (this->tv_nsec < (unsigned long int)T.tv_nsec) {
-    --this->tv_sec;
-    this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
-  } else {
-    this->tv_nsec -= T.tv_nsec;
-  }
-  this->tv_sec -= T.tv_sec;
-
-  return *this;
-}
-
-log_time log_time::operator+=(const timespec& T) {
-  this->tv_nsec += (unsigned long int)T.tv_nsec;
-  if (this->tv_nsec >= NS_PER_SEC) {
-    this->tv_nsec -= NS_PER_SEC;
-    ++this->tv_sec;
-  }
-  this->tv_sec += T.tv_sec;
-
-  return *this;
-}
-
-log_time log_time::operator-=(const log_time& T) {
-  // No concept of negative time, clamp to EPOCH
-  if (*this <= T) {
-    return *this = log_time(EPOCH);
-  }
-
-  if (this->tv_nsec < T.tv_nsec) {
-    --this->tv_sec;
-    this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
-  } else {
-    this->tv_nsec -= T.tv_nsec;
-  }
-  this->tv_sec -= T.tv_sec;
-
-  return *this;
-}
-
-log_time log_time::operator+=(const log_time& T) {
-  this->tv_nsec += T.tv_nsec;
-  if (this->tv_nsec >= NS_PER_SEC) {
-    this->tv_nsec -= NS_PER_SEC;
-    ++this->tv_sec;
-  }
-  this->tv_sec += T.tv_sec;
-
-  return *this;
-}
diff --git a/liblog/logd_writer.cpp b/liblog/logd_writer.cpp
index 67376f4..a230749 100644
--- a/liblog/logd_writer.cpp
+++ b/liblog/logd_writer.cpp
@@ -32,58 +32,53 @@
 #include <time.h>
 #include <unistd.h>
 
-#include <shared_mutex>
-
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
 #include "logger.h"
-#include "rwlock.h"
 #include "uio.h"
 
-static int logd_socket;
-static RwLock logd_socket_lock;
+static atomic_int logd_socket;
 
-static void OpenSocketLocked() {
-  logd_socket = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
-  if (logd_socket <= 0) {
-    return;
-  }
-
+// Note that it is safe to call connect() multiple times on DGRAM Unix domain sockets, so this
+// function is used to reconnect to logd without requiring a new socket.
+static void LogdConnect() {
   sockaddr_un un = {};
   un.sun_family = AF_UNIX;
   strcpy(un.sun_path, "/dev/socket/logdw");
-
-  if (TEMP_FAILURE_RETRY(
-          connect(logd_socket, reinterpret_cast<sockaddr*>(&un), sizeof(sockaddr_un))) < 0) {
-    close(logd_socket);
-    logd_socket = 0;
-  }
+  TEMP_FAILURE_RETRY(connect(logd_socket, reinterpret_cast<sockaddr*>(&un), sizeof(sockaddr_un)));
 }
 
-static void OpenSocket() {
-  auto lock = std::unique_lock{logd_socket_lock};
-  if (logd_socket > 0) {
-    // Someone raced us and opened the socket already.
+// logd_socket should only be opened once.  If we see that logd_socket is uninitialized, we create a
+// new socket and attempt to exchange it into the atomic logd_socket.  If the compare/exchange was
+// successful, then that will be the socket used for the duration of the program, otherwise a
+// different thread has already opened and written the socket to the atomic, so close the new socket
+// and return.
+static void GetSocket() {
+  if (logd_socket != 0) {
     return;
   }
 
-  OpenSocketLocked();
-}
-
-static void ResetSocket(int old_socket) {
-  auto lock = std::unique_lock{logd_socket_lock};
-  if (old_socket != logd_socket) {
-    // Someone raced us and reset the socket already.
+  int new_socket =
+      TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
+  if (new_socket <= 0) {
     return;
   }
-  close(logd_socket);
-  logd_socket = 0;
-  OpenSocketLocked();
+
+  int uninitialized_value = 0;
+  if (!logd_socket.compare_exchange_strong(uninitialized_value, new_socket)) {
+    close(new_socket);
+    return;
+  }
+
+  LogdConnect();
 }
 
+// This is the one exception to the above.  Zygote uses this to clean up open FD's after fork() and
+// before specialization.  It is single threaded at this point and therefore this function is
+// explicitly not thread safe.  It sets logd_socket to 0, so future logs will be safely initialized
+// whenever they happen.
 void LogdClose() {
-  auto lock = std::unique_lock{logd_socket_lock};
   if (logd_socket > 0) {
     close(logd_socket);
   }
@@ -99,12 +94,7 @@
   static atomic_int dropped;
   static atomic_int droppedSecurity;
 
-  auto lock = std::shared_lock{logd_socket_lock};
-  if (logd_socket <= 0) {
-    lock.unlock();
-    OpenSocket();
-    lock.lock();
-  }
+  GetSocket();
 
   if (logd_socket <= 0) {
     return -EBADF;
@@ -183,10 +173,7 @@
   // the connection, so we reset it and try again.
   ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i));
   if (ret < 0 && errno != EAGAIN) {
-    int old_socket = logd_socket;
-    lock.unlock();
-    ResetSocket(old_socket);
-    lock.lock();
+    LogdConnect();
 
     ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i));
   }
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index 3a75fa3..22c7eca 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -192,7 +192,7 @@
     return -EINVAL;
   }
 
-  clock_gettime(android_log_clockid(), &ts);
+  clock_gettime(CLOCK_REALTIME, &ts);
 
   if (log_id == LOG_ID_SECURITY) {
     if (vec[0].iov_len < 4) {
diff --git a/liblog/logprint.cpp b/liblog/logprint.cpp
index 9e8d277..238431f 100644
--- a/liblog/logprint.cpp
+++ b/liblog/logprint.cpp
@@ -216,11 +216,7 @@
   p_ret->year_output = false;
   p_ret->zone_output = false;
   p_ret->epoch_output = false;
-#ifdef __ANDROID__
-  p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC;
-#else
   p_ret->monotonic_output = false;
-#endif
   p_ret->uid_output = false;
   p_ret->descriptive_output = false;
   descriptive_output = false;
@@ -1465,13 +1461,10 @@
   nsec = entry->tv_nsec;
 #if __ANDROID__
   if (p_format->monotonic_output) {
-    /* prevent convertMonotonic from being called if logd is monotonic */
-    if (android_log_clockid() != CLOCK_MONOTONIC) {
-      struct timespec time;
-      convertMonotonic(&time, entry);
-      now = time.tv_sec;
-      nsec = time.tv_nsec;
-    }
+    struct timespec time;
+    convertMonotonic(&time, entry);
+    now = time.tv_sec;
+    nsec = time.tv_nsec;
   }
 #endif
   if (now < 0) {
diff --git a/liblog/pmsg_writer.cpp b/liblog/pmsg_writer.cpp
index 06e5e04..8e676bd 100644
--- a/liblog/pmsg_writer.cpp
+++ b/liblog/pmsg_writer.cpp
@@ -23,30 +23,36 @@
 #include <sys/types.h>
 #include <time.h>
 
-#include <shared_mutex>
-
 #include <log/log_properties.h>
 #include <private/android_logger.h>
 
 #include "logger.h"
-#include "rwlock.h"
 #include "uio.h"
 
-static int pmsg_fd;
-static RwLock pmsg_fd_lock;
+static atomic_int pmsg_fd;
 
-static void PmsgOpen() {
-  auto lock = std::unique_lock{pmsg_fd_lock};
-  if (pmsg_fd > 0) {
-    // Someone raced us and opened the socket already.
+// pmsg_fd should only beopened once.  If we see that pmsg_fd is uninitialized, we open "/dev/pmsg0"
+// then attempt to compare/exchange it into pmsg_fd.  If the compare/exchange was successful, then
+// that will be the fd used for the duration of the program, otherwise a different thread has
+// already opened and written the fd to the atomic, so close the new fd and return.
+static void GetPmsgFd() {
+  if (pmsg_fd != 0) {
     return;
   }
 
-  pmsg_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
+  int new_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
+  if (new_fd <= 0) {
+    return;
+  }
+
+  int uninitialized_value = 0;
+  if (!pmsg_fd.compare_exchange_strong(uninitialized_value, new_fd)) {
+    close(new_fd);
+    return;
+  }
 }
 
 void PmsgClose() {
-  auto lock = std::unique_lock{pmsg_fd_lock};
   if (pmsg_fd > 0) {
     close(pmsg_fd);
   }
@@ -77,13 +83,7 @@
     }
   }
 
-  auto lock = std::shared_lock{pmsg_fd_lock};
-
-  if (pmsg_fd <= 0) {
-    lock.unlock();
-    PmsgOpen();
-    lock.lock();
-  }
+  GetPmsgFd();
 
   if (pmsg_fd <= 0) {
     return -EBADF;
@@ -188,7 +188,7 @@
     return -EINVAL;
   }
 
-  clock_gettime(android_log_clockid(), &ts);
+  clock_gettime(CLOCK_REALTIME, &ts);
 
   cp = strdup(filename);
   if (!cp) {
diff --git a/liblog/properties.cpp b/liblog/properties.cpp
index 37670ec..f5e060c 100644
--- a/liblog/properties.cpp
+++ b/liblog/properties.cpp
@@ -365,29 +365,6 @@
   return c;
 }
 
-static unsigned char evaluate_persist_ro(const struct cache2_char* self) {
-  unsigned char c = self->cache_persist.c;
-
-  if (c) {
-    return c;
-  }
-
-  return self->cache_ro.c;
-}
-
-/*
- * Timestamp state generally remains constant, but can change at any time
- * to handle developer requirements.
- */
-clockid_t android_log_clockid() {
-  static struct cache2_char clockid = {PTHREAD_MUTEX_INITIALIZER, 0,
-                                       "persist.logd.timestamp",  {{NULL, 0xFFFFFFFF}, '\0'},
-                                       "ro.logd.timestamp",       {{NULL, 0xFFFFFFFF}, '\0'},
-                                       evaluate_persist_ro};
-
-  return (tolower(do_cache2_char(&clockid)) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME;
-}
-
 /*
  * Security state generally remains constant, but the DO must be able
  * to turn off logging should it become spammy after an attack is detected.
diff --git a/liblog/rwlock.h b/liblog/rwlock.h
deleted file mode 100644
index 00f1806..0000000
--- a/liblog/rwlock.h
+++ /dev/null
@@ -1,39 +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 <pthread.h>
-
-// As of the end of Dec 2019, std::shared_mutex is *not* simply a pthread_rwlock, but rather a
-// combination of std::mutex and std::condition variable, which is obviously less efficient.  This
-// immitates what std::shared_mutex should be doing and is compatible with std::shared_lock and
-// std::unique_lock.
-
-class RwLock {
- public:
-  RwLock() {}
-  ~RwLock() {}
-
-  void lock() { pthread_rwlock_wrlock(&rwlock_); }
-  void unlock() { pthread_rwlock_unlock(&rwlock_); }
-
-  void lock_shared() { pthread_rwlock_rdlock(&rwlock_); }
-  void unlock_shared() { pthread_rwlock_unlock(&rwlock_); }
-
- private:
-  pthread_rwlock_t rwlock_ = PTHREAD_RWLOCK_INITIALIZER;
-};
diff --git a/liblog/tests/Android.bp b/liblog/tests/Android.bp
index 385b079..2a6424b 100644
--- a/liblog/tests/Android.bp
+++ b/liblog/tests/Android.bp
@@ -63,8 +63,8 @@
         "log_system_test.cpp",
         "log_time_test.cpp",
         "log_wrap_test.cpp",
+        "logd_writer_test.cpp",
         "logprint_test.cpp",
-        "rwlock_test.cpp",
     ],
     shared_libs: [
         "libcutils",
@@ -72,6 +72,7 @@
     ],
     static_libs: ["liblog"],
     isolated: true,
+    require_root: true,
 }
 
 // Build tests for the device (with .so). Run with:
@@ -108,7 +109,6 @@
         "liblog_host_test.cpp",
         "liblog_default_tag.cpp",
         "liblog_global_state.cpp",
-        "rwlock_test.cpp",
     ],
     isolated: true,
 }
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index f4734b9..3bd5cf2 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -184,7 +184,7 @@
    */
 
   struct timespec ts;
-  clock_gettime(android_log_clockid(), &ts);
+  clock_gettime(CLOCK_REALTIME, &ts);
 
   android_pmsg_log_header_t pmsg_header;
   pmsg_header.magic = LOGGER_MAGIC;
@@ -260,7 +260,7 @@
    */
 
   struct timespec ts;
-  clock_gettime(android_log_clockid(), &ts);
+  clock_gettime(CLOCK_REALTIME, &ts);
 
   struct packet {
     android_pmsg_log_header_t pmsg_header;
@@ -335,7 +335,7 @@
    */
 
   struct timespec ts;
-  clock_gettime(android_log_clockid(), &ts);
+  clock_gettime(CLOCK_REALTIME, &ts);
 
   struct packet {
     android_pmsg_log_header_t pmsg_header;
@@ -410,7 +410,7 @@
    */
 
   struct timespec ts;
-  clock_gettime(android_log_clockid(), &ts);
+  clock_gettime(CLOCK_REALTIME, &ts);
 
   struct packet {
     android_pmsg_log_header_t pmsg_header;
@@ -483,7 +483,7 @@
    */
 
   struct timespec ts;
-  clock_gettime(android_log_clockid(), &ts);
+  clock_gettime(CLOCK_REALTIME, &ts);
 
   struct packet {
     android_pmsg_log_header_t pmsg_header;
@@ -684,8 +684,8 @@
       if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
         continue;
       }
-      log_time tx(eventData + 4 + 1);
-      if (ts != tx) {
+      log_time* tx = reinterpret_cast<log_time*>(eventData + 4 + 1);
+      if (ts != *tx) {
         if (0xDEADBEEFA55A5AA5ULL == caught_convert(eventData + 4 + 1)) {
           state.SkipWithError("signal");
           break;
@@ -757,8 +757,8 @@
       if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
         continue;
       }
-      log_time tx(eventData + 4 + 1);
-      if (ts != tx) {
+      log_time* tx = reinterpret_cast<log_time*>(eventData + 4 + 1);
+      if (ts != *tx) {
         if (0xDEADBEEFA55A5AA6ULL == caught_convert(eventData + 4 + 1)) {
           state.SkipWithError("signal");
           break;
@@ -792,16 +792,6 @@
 BENCHMARK(BM_is_loggable);
 
 /*
- *	Measure the time it takes for android_log_clockid.
- */
-static void BM_clockid(benchmark::State& state) {
-  while (state.KeepRunning()) {
-    android_log_clockid();
-  }
-}
-BENCHMARK(BM_clockid);
-
-/*
  *	Measure the time it takes for __android_log_security.
  */
 static void BM_security(benchmark::State& state) {
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index d3d8e91..fbc3d7a 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -270,10 +270,10 @@
       return;
     }
 
-    log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
-    if (ts == tx) {
+    log_time* tx = reinterpret_cast<log_time*>(&eventData->payload.data);
+    if (ts == *tx) {
       ++count;
-    } else if (ts1 == tx) {
+    } else if (ts1 == *tx) {
       ++second_count;
     }
 
@@ -329,8 +329,6 @@
 #ifdef __ANDROID__
   pid_t pid = getpid();
 
-  log_time ts(android_log_clockid());
-
   size_t num_lines = 1, size = 0, length = 0, total = 0;
   const char* cp = message;
   while (*cp) {
@@ -432,7 +430,6 @@
   pid_t pid = getpid();
 
   static const char tag[] = "TEST__android_log_buf_write";
-  log_time ts(android_log_clockid());
 
   auto write_function = [&] {
     EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO, tag, message));
diff --git a/liblog/tests/logd_writer_test.cpp b/liblog/tests/logd_writer_test.cpp
new file mode 100644
index 0000000..b8e4726
--- /dev/null
+++ b/liblog/tests/logd_writer_test.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2020 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 <sys/un.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+
+using android::base::StringPrintf;
+using android::base::unique_fd;
+
+// logd_writer takes advantage of the fact that connect() can be called multiple times for a DGRAM
+// socket.  This tests for that behavior.
+TEST(liblog, multi_connect_dgram_socket) {
+#ifdef __ANDROID__
+  if (getuid() != 0) {
+    GTEST_SKIP() << "Skipping test, must be run as root.";
+    return;
+  }
+  auto temp_dir = TemporaryDir();
+  auto socket_path = StringPrintf("%s/test_socket", temp_dir.path);
+
+  unique_fd server_socket;
+
+  auto open_server_socket = [&] {
+    server_socket.reset(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)));
+    ASSERT_TRUE(server_socket.ok());
+
+    sockaddr_un server_sockaddr = {};
+    server_sockaddr.sun_family = AF_UNIX;
+    strlcpy(server_sockaddr.sun_path, socket_path.c_str(), sizeof(server_sockaddr.sun_path));
+    ASSERT_EQ(0,
+              TEMP_FAILURE_RETRY(bind(server_socket, reinterpret_cast<sockaddr*>(&server_sockaddr),
+                                      sizeof(server_sockaddr))));
+  };
+
+  // Open the server socket.
+  open_server_socket();
+
+  // Open the client socket.
+  auto client_socket =
+      unique_fd{TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0))};
+  ASSERT_TRUE(client_socket.ok());
+  sockaddr_un client_sockaddr = {};
+  client_sockaddr.sun_family = AF_UNIX;
+  strlcpy(client_sockaddr.sun_path, socket_path.c_str(), sizeof(client_sockaddr.sun_path));
+  ASSERT_EQ(0,
+            TEMP_FAILURE_RETRY(connect(client_socket, reinterpret_cast<sockaddr*>(&client_sockaddr),
+                                       sizeof(client_sockaddr))));
+
+  // Ensure that communication works.
+  constexpr static char kSmoke[] = "smoke test";
+  ssize_t smoke_len = sizeof(kSmoke);
+  ASSERT_EQ(smoke_len, TEMP_FAILURE_RETRY(write(client_socket, kSmoke, sizeof(kSmoke))));
+  char read_buf[512];
+  ASSERT_EQ(smoke_len, TEMP_FAILURE_RETRY(read(server_socket, read_buf, sizeof(read_buf))));
+  ASSERT_STREQ(kSmoke, read_buf);
+
+  // Close the server socket.
+  server_socket.reset();
+  ASSERT_EQ(0, unlink(socket_path.c_str())) << strerror(errno);
+
+  // Ensure that write() from the client returns an error since the server is closed.
+  ASSERT_EQ(-1, TEMP_FAILURE_RETRY(write(client_socket, kSmoke, sizeof(kSmoke))));
+  ASSERT_EQ(errno, ECONNREFUSED) << strerror(errno);
+
+  // Open the server socket again.
+  open_server_socket();
+
+  // Reconnect the same client socket.
+  ASSERT_EQ(0,
+            TEMP_FAILURE_RETRY(connect(client_socket, reinterpret_cast<sockaddr*>(&client_sockaddr),
+                                       sizeof(client_sockaddr))))
+      << strerror(errno);
+
+  // Ensure that communication works.
+  ASSERT_EQ(smoke_len, TEMP_FAILURE_RETRY(write(client_socket, kSmoke, sizeof(kSmoke))));
+  ASSERT_EQ(smoke_len, TEMP_FAILURE_RETRY(read(server_socket, read_buf, sizeof(read_buf))));
+  ASSERT_STREQ(kSmoke, read_buf);
+#else
+  GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
\ No newline at end of file
diff --git a/liblog/tests/rwlock_test.cpp b/liblog/tests/rwlock_test.cpp
deleted file mode 100644
index 617d5c4..0000000
--- a/liblog/tests/rwlock_test.cpp
+++ /dev/null
@@ -1,91 +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 "../rwlock.h"
-
-#include <chrono>
-#include <shared_mutex>
-#include <thread>
-
-#include <gtest/gtest.h>
-
-using namespace std::literals;
-
-TEST(rwlock, reader_then_reader_lock) {
-  RwLock lock;
-
-  bool thread_ran = false;
-  auto read_guard = std::shared_lock{lock};
-
-  auto reader_thread = std::thread([&] {
-    auto read_guard = std::shared_lock{lock};
-    thread_ran = true;
-  });
-
-  auto end_time = std::chrono::steady_clock::now() + 1s;
-
-  while (std::chrono::steady_clock::now() < end_time) {
-    if (thread_ran) {
-      break;
-    }
-  }
-
-  EXPECT_EQ(true, thread_ran);
-
-  // Unlock the lock in case something went wrong, to ensure that we can still join() the thread.
-  read_guard.unlock();
-  reader_thread.join();
-}
-
-template <template <typename> typename L1, template <typename> typename L2>
-void TestBlockingLocks() {
-  RwLock lock;
-
-  bool thread_ran = false;
-  auto read_guard = L1{lock};
-
-  auto reader_thread = std::thread([&] {
-    auto read_guard = L2{lock};
-    thread_ran = true;
-  });
-
-  auto end_time = std::chrono::steady_clock::now() + 1s;
-
-  while (std::chrono::steady_clock::now() < end_time) {
-    if (thread_ran) {
-      break;
-    }
-  }
-
-  EXPECT_EQ(false, thread_ran);
-
-  read_guard.unlock();
-  reader_thread.join();
-
-  EXPECT_EQ(true, thread_ran);
-}
-
-TEST(rwlock, reader_then_writer_lock) {
-  TestBlockingLocks<std::shared_lock, std::unique_lock>();
-}
-
-TEST(rwlock, writer_then_reader_lock) {
-  TestBlockingLocks<std::unique_lock, std::shared_lock>();
-}
-
-TEST(rwlock, writer_then_writer_lock) {
-  TestBlockingLocks<std::unique_lock, std::unique_lock>();
-}
diff --git a/libnetutils/packet.c b/libnetutils/packet.c
index 9ecdd4f..64de00e 100644
--- a/libnetutils/packet.c
+++ b/libnetutils/packet.c
@@ -37,25 +37,22 @@
 
 #include "dhcpmsg.h"
 
-int fatal();
+int fatal(const char*);
 
-int open_raw_socket(const char *ifname __attribute__((unused)), uint8_t *hwaddr, int if_index)
-{
-    int s;
-    struct sockaddr_ll bindaddr;
+int open_raw_socket(const char* ifname __unused, uint8_t hwaddr[ETH_ALEN], int if_index) {
+    int s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+    if (s < 0) return fatal("socket(PF_PACKET)");
 
-    if((s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
-        return fatal("socket(PF_PACKET)");
-    }
-
-    memset(&bindaddr, 0, sizeof(bindaddr));
-    bindaddr.sll_family = AF_PACKET;
-    bindaddr.sll_protocol = htons(ETH_P_IP);
-    bindaddr.sll_halen = ETH_ALEN;
+    struct sockaddr_ll bindaddr = {
+            .sll_family = AF_PACKET,
+            .sll_protocol = htons(ETH_P_IP),
+            .sll_ifindex = if_index,
+            .sll_halen = ETH_ALEN,
+    };
     memcpy(bindaddr.sll_addr, hwaddr, ETH_ALEN);
-    bindaddr.sll_ifindex = if_index;
 
     if (bind(s, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
+        close(s);
         return fatal("Cannot bind raw socket to interface");
     }
 
diff --git a/libnetutils/packet.h b/libnetutils/packet.h
index aade392..66186fc 100644
--- a/libnetutils/packet.h
+++ b/libnetutils/packet.h
@@ -17,7 +17,9 @@
 #ifndef _WIFI_PACKET_H_
 #define _WIFI_PACKET_H_
 
-int open_raw_socket(const char *ifname, uint8_t *hwaddr, int if_index);
+#include <linux/if_ether.h>
+
+int open_raw_socket(const char* ifname, uint8_t hwaddr[ETH_ALEN], int if_index);
 int send_packet(int s, int if_index, struct dhcp_msg *msg, int size,
                 uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport);
 int receive_packet(int s, struct dhcp_msg *msg);
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index 2c1b255..bda11e9 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -17,6 +17,7 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    min_sdk_version: "29",
 }
 
 cc_library {
@@ -60,4 +61,5 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    min_sdk_version: "29",
 }
diff --git a/libprocessgroup/profiles/Android.bp b/libprocessgroup/profiles/Android.bp
index 12474f1..ccc6f62 100644
--- a/libprocessgroup/profiles/Android.bp
+++ b/libprocessgroup/profiles/Android.bp
@@ -89,24 +89,23 @@
         "test_vendor.cpp",
     ],
     static_libs: [
+        "libbase",
         "libgmock",
+        "liblog",
+        "libjsoncpp",
         "libjsonpbverify",
         "libjsonpbparse",
         "libprocessgroup_proto",
     ],
     shared_libs: [
-        "libbase",
-        "liblog",
-        "libjsoncpp",
         "libprotobuf-cpp-full",
     ],
-    target: {
-        android: {
-            test_config: "vts_processgroup_validate_test.xml",
-        },
-    },
+    test_suites: [
+        "vts",
+    ],
 }
 
 vts_config {
     name: "VtsProcessgroupValidateTest",
+    test_config: "vts_processgroup_validate_test.xml",
 }
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 3f08535..a515e58 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -144,6 +144,19 @@
         }
       ]
     },
+    {
+      "Name": "CameraServicePerformance",
+      "Actions": [
+        {
+          "Name": "JoinCgroup",
+          "Params":
+          {
+            "Controller": "schedtune",
+            "Path": "camera-daemon"
+          }
+        }
+      ]
+    },
 
     {
       "Name": "CpuPolicySpread",
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
index 0c9a2b8..15b0d89 100644
--- a/libprocinfo/Android.bp
+++ b/libprocinfo/Android.bp
@@ -51,6 +51,12 @@
             enabled: false,
         },
     },
+
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.art.debug",
+        "com.android.art.release",
+    ],
 }
 
 // Tests
diff --git a/libsparse/output_file.cpp b/libsparse/output_file.cpp
index e35cb0d..b883c13 100644
--- a/libsparse/output_file.cpp
+++ b/libsparse/output_file.cpp
@@ -35,8 +35,9 @@
 #include "sparse_crc32.h"
 #include "sparse_format.h"
 
+#include <android-base/mapped_file.h>
+
 #ifndef _WIN32
-#include <sys/mman.h>
 #define O_BINARY 0
 #else
 #define ftruncate64 ftruncate
@@ -45,7 +46,6 @@
 #if defined(__APPLE__) && defined(__MACH__)
 #define lseek64 lseek
 #define ftruncate64 ftruncate
-#define mmap64 mmap
 #define off64_t off_t
 #endif
 
@@ -649,52 +649,10 @@
 }
 
 int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset) {
-  int ret;
-  int64_t aligned_offset;
-  int aligned_diff;
-  uint64_t buffer_size;
-  char* ptr;
+  auto m = android::base::MappedFile::FromFd(fd, offset, len, PROT_READ);
+  if (!m) return -errno;
 
-  aligned_offset = offset & ~(4096 - 1);
-  aligned_diff = offset - aligned_offset;
-  buffer_size = (uint64_t)len + (uint64_t)aligned_diff;
-
-#ifndef _WIN32
-  if (buffer_size > SIZE_MAX) return -E2BIG;
-  char* data =
-      reinterpret_cast<char*>(mmap64(nullptr, buffer_size, PROT_READ, MAP_SHARED, fd, aligned_offset));
-  if (data == MAP_FAILED) {
-    return -errno;
-  }
-  ptr = data + aligned_diff;
-#else
-  off64_t pos;
-  char* data = reinterpret_cast<char*>(malloc(len));
-  if (!data) {
-    return -errno;
-  }
-  pos = lseek64(fd, offset, SEEK_SET);
-  if (pos < 0) {
-    free(data);
-    return -errno;
-  }
-  ret = read_all(fd, data, len);
-  if (ret < 0) {
-    free(data);
-    return ret;
-  }
-  ptr = data;
-#endif
-
-  ret = out->sparse_ops->write_data_chunk(out, len, ptr);
-
-#ifndef _WIN32
-  munmap(data, buffer_size);
-#else
-  free(data);
-#endif
-
-  return ret;
+  return out->sparse_ops->write_data_chunk(out, m->size(), m->data());
 }
 
 /* Write a contiguous region of data blocks from a file */
diff --git a/libstats/push_compat/Android.bp b/libstats/push_compat/Android.bp
index caea048..cbc65ff 100644
--- a/libstats/push_compat/Android.bp
+++ b/libstats/push_compat/Android.bp
@@ -48,6 +48,7 @@
     export_include_dirs: ["include"],
     static_libs: ["libgtest_prod"],
     apex_available: ["com.android.resolv"],
+    min_sdk_version: "29",
 }
 
 cc_test {
diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp
index 690dc94..6882ab2 100644
--- a/libstats/socket/Android.bp
+++ b/libstats/socket/Android.bp
@@ -55,6 +55,7 @@
     export_include_dirs: ["include"],
     host_supported: true,
     apex_available: ["com.android.resolv"],
+    min_sdk_version: "29",
 }
 
 cc_benchmark {
diff --git a/libsystem/Android.bp b/libsystem/Android.bp
index ff886fd..db61669 100644
--- a/libsystem/Android.bp
+++ b/libsystem/Android.bp
@@ -8,6 +8,7 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    min_sdk_version: "apex_inherit",
     export_include_dirs: ["include"],
 
     target: {
diff --git a/libsysutils/Android.bp b/libsysutils/Android.bp
index 627f0d4..3b98bab 100644
--- a/libsysutils/Android.bp
+++ b/libsysutils/Android.bp
@@ -43,6 +43,7 @@
         "//apex_available:anyapex",
         "//apex_available:platform",
     ],
+    min_sdk_version: "apex_inherit",
 }
 
 cc_test {
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 5efe03f..9c1621b 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -180,6 +180,7 @@
     struct ifa_cacheinfo *cacheinfo = nullptr;
     char addrstr[INET6_ADDRSTRLEN] = "";
     char ifname[IFNAMSIZ] = "";
+    uint32_t flags;
 
     if (!checkRtNetlinkLength(nh, sizeof(*ifaddr)))
         return false;
@@ -194,6 +195,9 @@
     // For log messages.
     const char *msgtype = rtMessageName(type);
 
+    // First 8 bits of flags. In practice will always be overridden when parsing IFA_FLAGS below.
+    flags = ifaddr->ifa_flags;
+
     struct rtattr *rta;
     int len = IFA_PAYLOAD(nh);
     for (rta = IFA_RTA(ifaddr); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
@@ -242,6 +246,9 @@
             }
 
             cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta);
+
+        } else if (rta->rta_type == IFA_FLAGS) {
+            flags = *(uint32_t*)RTA_DATA(rta);
         }
     }
 
@@ -256,7 +263,7 @@
     mSubsystem = strdup("net");
     asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr, ifaddr->ifa_prefixlen);
     asprintf(&mParams[1], "INTERFACE=%s", ifname);
-    asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
+    asprintf(&mParams[2], "FLAGS=%u", flags);
     asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
     asprintf(&mParams[4], "IFINDEX=%u", ifaddr->ifa_index);
 
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index bf7d69e..3c44534 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -75,13 +75,29 @@
     ],
 
     target: {
-        // Always disable optimizations for host to make it easier to debug.
         host: {
+            // Always disable optimizations for host to make it easier to debug.
             cflags: [
                 "-O0",
                 "-g",
             ],
         },
+        android: {
+            header_libs: ["bionic_libc_platform_headers"],
+            product_variables: {
+                experimental_mte: {
+                    cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
+                },
+            },
+        },
+        linux_bionic: {
+            header_libs: ["bionic_libc_platform_headers"],
+            product_variables: {
+                experimental_mte: {
+                    cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
+                },
+            },
+        },
     },
 
     arch: {
@@ -102,16 +118,6 @@
         "liblog",
         "liblzma",
     ],
-
-    header_libs: [
-        "bionic_libc_platform_headers",
-    ],
-
-    product_variables: {
-        experimental_mte: {
-            cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
-        },
-    },
 }
 
 cc_library {
@@ -140,6 +146,12 @@
             exclude_shared_libs: ["libdexfile_support"],
         },
     },
+
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.art.debug",
+        "com.android.art.release",
+    ],
 }
 
 // Static library without DEX support to avoid dependencies on the ART APEX.
@@ -281,13 +293,22 @@
         "tests/files/offline/straddle_arm64/*",
     ],
 
-    header_libs: [
-        "bionic_libc_platform_headers",
-    ],
-
-    product_variables: {
-        experimental_mte: {
-            cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
+    target: {
+        android: {
+            header_libs: ["bionic_libc_platform_headers"],
+            product_variables: {
+                experimental_mte: {
+                    cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
+                },
+            },
+        },
+        linux_bionic: {
+            header_libs: ["bionic_libc_platform_headers"],
+            product_variables: {
+                experimental_mte: {
+                    cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
+                },
+            },
         },
     },
 }
@@ -396,6 +417,7 @@
     srcs: [
         "benchmarks/unwind_benchmarks.cpp",
         "benchmarks/ElfBenchmark.cpp",
+        "benchmarks/MapsBenchmark.cpp",
         "benchmarks/SymbolBenchmark.cpp",
         "benchmarks/Utils.cpp",
     ],
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index f01b092..286febc 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -124,6 +124,12 @@
     return false;
   }
 
+  if (arch() == ARCH_ARM64) {
+    // Tagged pointer after Android R would lead top byte to have random values
+    // https://source.android.com/devices/tech/debug/tagged-pointers
+    vaddr &= (1ULL << 56) - 1;
+  }
+
   // Check the .data section.
   uint64_t vaddr_start = interface_->data_vaddr_start();
   if (vaddr >= vaddr_start && vaddr < interface_->data_vaddr_end()) {
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index 8f49ad9..670d904 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -159,6 +159,8 @@
         search_map_idx = old_map_idx + 1;
         if (new_map_idx + 1 < maps_.size()) {
           maps_[new_map_idx + 1]->prev_map = info.get();
+          maps_[new_map_idx + 1]->prev_real_map =
+              info->IsBlank() ? info->prev_real_map : info.get();
         }
         maps_[new_map_idx] = nullptr;
         total_entries--;
diff --git a/libunwindstack/MemoryMte.cpp b/libunwindstack/MemoryMte.cpp
index d1d0ebc..46a546e 100644
--- a/libunwindstack/MemoryMte.cpp
+++ b/libunwindstack/MemoryMte.cpp
@@ -17,6 +17,7 @@
 #if defined(ANDROID_EXPERIMENTAL_MTE)
 
 #include <sys/ptrace.h>
+#include <sys/uio.h>
 
 #include <bionic/mte.h>
 #include <bionic/mte_kernel.h>
@@ -28,7 +29,13 @@
 
 long MemoryRemote::ReadTag(uint64_t addr) {
 #if defined(__aarch64__)
-  return ptrace(PTRACE_PEEKTAG, pid_, (void*)addr, nullptr);
+  char tag;
+  iovec iov = {&tag, 1};
+  if (ptrace(PTRACE_PEEKMTETAGS, pid_, reinterpret_cast<void*>(addr), &iov) != 0 ||
+      iov.iov_len != 1) {
+    return -1;
+  }
+  return tag;
 #else
   (void)addr;
   return -1;
diff --git a/libunwindstack/benchmarks/ElfBenchmark.cpp b/libunwindstack/benchmarks/ElfBenchmark.cpp
index c108a2a..a46bd7a 100644
--- a/libunwindstack/benchmarks/ElfBenchmark.cpp
+++ b/libunwindstack/benchmarks/ElfBenchmark.cpp
@@ -23,7 +23,9 @@
 #include <benchmark/benchmark.h>
 
 #include <unwindstack/Elf.h>
+#include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
 
 #include "Utils.h"
 
@@ -75,3 +77,66 @@
   BenchmarkElfCreate(state, GetCompressedElfFile());
 }
 BENCHMARK(BM_elf_create_compressed);
+
+static void InitializeBuildId(benchmark::State& state, unwindstack::Maps& maps,
+                              unwindstack::MapInfo** build_id_map_info) {
+  if (!maps.Parse()) {
+    state.SkipWithError("Failed to parse local maps.");
+    return;
+  }
+
+  // Find the libc.so share library and use that for benchmark purposes.
+  *build_id_map_info = nullptr;
+  for (auto& map_info : maps) {
+    if (map_info->offset == 0 && map_info->GetBuildID() != "") {
+      *build_id_map_info = map_info.get();
+      break;
+    }
+  }
+
+  if (*build_id_map_info == nullptr) {
+    state.SkipWithError("Failed to find a map with a BuildID.");
+  }
+}
+
+static void BM_elf_get_build_id_from_object(benchmark::State& state) {
+  unwindstack::LocalMaps maps;
+  unwindstack::MapInfo* build_id_map_info;
+  InitializeBuildId(state, maps, &build_id_map_info);
+
+  unwindstack::Elf* elf = build_id_map_info->GetElf(std::shared_ptr<unwindstack::Memory>(),
+                                                    unwindstack::Regs::CurrentArch());
+  if (!elf->valid()) {
+    state.SkipWithError("Cannot get valid elf from map.");
+  }
+
+  for (auto _ : state) {
+    state.PauseTiming();
+    uintptr_t id = build_id_map_info->build_id;
+    if (id != 0) {
+      delete reinterpret_cast<std::string*>(id);
+      build_id_map_info->build_id = 0;
+    }
+    state.ResumeTiming();
+    benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
+  }
+}
+BENCHMARK(BM_elf_get_build_id_from_object);
+
+static void BM_elf_get_build_id_from_file(benchmark::State& state) {
+  unwindstack::LocalMaps maps;
+  unwindstack::MapInfo* build_id_map_info;
+  InitializeBuildId(state, maps, &build_id_map_info);
+
+  for (auto _ : state) {
+    state.PauseTiming();
+    uintptr_t id = build_id_map_info->build_id;
+    if (id != 0) {
+      delete reinterpret_cast<std::string*>(id);
+      build_id_map_info->build_id = 0;
+    }
+    state.ResumeTiming();
+    benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
+  }
+}
+BENCHMARK(BM_elf_get_build_id_from_file);
diff --git a/libunwindstack/benchmarks/MapsBenchmark.cpp b/libunwindstack/benchmarks/MapsBenchmark.cpp
new file mode 100644
index 0000000..5df1491
--- /dev/null
+++ b/libunwindstack/benchmarks/MapsBenchmark.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2020 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 <err.h>
+#include <stdint.h>
+
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+
+#include <benchmark/benchmark.h>
+
+#include <unwindstack/Maps.h>
+
+class BenchmarkLocalUpdatableMaps : public unwindstack::LocalUpdatableMaps {
+ public:
+  BenchmarkLocalUpdatableMaps() : unwindstack::LocalUpdatableMaps() {}
+  virtual ~BenchmarkLocalUpdatableMaps() = default;
+
+  const std::string GetMapsFile() const override { return maps_file_; }
+
+  void BenchmarkSetMapsFile(const std::string& maps_file) { maps_file_ = maps_file; }
+
+ private:
+  std::string maps_file_;
+};
+
+static constexpr size_t kNumSmallMaps = 100;
+static constexpr size_t kNumLargeMaps = 10000;
+
+static void CreateMap(const char* filename, size_t num_maps, size_t increment = 1) {
+  std::string maps;
+  for (size_t i = 0; i < num_maps; i += increment) {
+    maps += android::base::StringPrintf("%zu-%zu r-xp 0000 00:00 0 name%zu\n", i * 1000,
+                                        (i + 1) * 1000 * increment, i * increment);
+  }
+  if (!android::base::WriteStringToFile(maps, filename)) {
+    errx(1, "WriteStringToFile failed");
+  }
+}
+
+static void ReparseBenchmark(benchmark::State& state, const char* maps1, size_t maps1_total,
+                             const char* maps2, size_t maps2_total) {
+  for (auto _ : state) {
+    BenchmarkLocalUpdatableMaps maps;
+    maps.BenchmarkSetMapsFile(maps1);
+    if (!maps.Reparse()) {
+      errx(1, "Internal Error: reparse of initial maps filed.");
+    }
+    if (maps.Total() != maps1_total) {
+      errx(1, "Internal Error: Incorrect total number of maps %zu, expected %zu.", maps.Total(),
+           maps1_total);
+    }
+    maps.BenchmarkSetMapsFile(maps2);
+    if (!maps.Reparse()) {
+      errx(1, "Internal Error: reparse of second set of maps filed.");
+    }
+    if (maps.Total() != maps2_total) {
+      errx(1, "Internal Error: Incorrect total number of maps %zu, expected %zu.", maps.Total(),
+           maps2_total);
+    }
+  }
+}
+
+void BM_local_updatable_maps_reparse_double_initial_small(benchmark::State& state) {
+  TemporaryFile initial_maps;
+  CreateMap(initial_maps.path, kNumSmallMaps, 2);
+
+  TemporaryFile reparse_maps;
+  CreateMap(reparse_maps.path, kNumSmallMaps);
+
+  ReparseBenchmark(state, initial_maps.path, kNumSmallMaps / 2, reparse_maps.path, kNumSmallMaps);
+}
+BENCHMARK(BM_local_updatable_maps_reparse_double_initial_small);
+
+void BM_local_updatable_maps_reparse_double_initial_large(benchmark::State& state) {
+  TemporaryFile initial_maps;
+  CreateMap(initial_maps.path, kNumLargeMaps, 2);
+
+  TemporaryFile reparse_maps;
+  CreateMap(reparse_maps.path, kNumLargeMaps);
+
+  ReparseBenchmark(state, initial_maps.path, kNumLargeMaps / 2, reparse_maps.path, kNumLargeMaps);
+}
+BENCHMARK(BM_local_updatable_maps_reparse_double_initial_large);
+
+void BM_local_updatable_maps_reparse_same_maps_small(benchmark::State& state) {
+  static constexpr size_t kNumSmallMaps = 100;
+  TemporaryFile maps;
+  CreateMap(maps.path, kNumSmallMaps);
+
+  ReparseBenchmark(state, maps.path, kNumSmallMaps, maps.path, kNumSmallMaps);
+}
+BENCHMARK(BM_local_updatable_maps_reparse_same_maps_small);
+
+void BM_local_updatable_maps_reparse_same_maps_large(benchmark::State& state) {
+  TemporaryFile maps;
+  CreateMap(maps.path, kNumLargeMaps);
+
+  ReparseBenchmark(state, maps.path, kNumLargeMaps, maps.path, kNumLargeMaps);
+}
+BENCHMARK(BM_local_updatable_maps_reparse_same_maps_large);
+
+void BM_local_updatable_maps_reparse_few_extra_small(benchmark::State& state) {
+  TemporaryFile maps1;
+  CreateMap(maps1.path, kNumSmallMaps - 4);
+
+  TemporaryFile maps2;
+  CreateMap(maps2.path, kNumSmallMaps);
+
+  ReparseBenchmark(state, maps1.path, kNumSmallMaps - 4, maps2.path, kNumSmallMaps);
+}
+BENCHMARK(BM_local_updatable_maps_reparse_few_extra_small);
+
+void BM_local_updatable_maps_reparse_few_extra_large(benchmark::State& state) {
+  TemporaryFile maps1;
+  CreateMap(maps1.path, kNumLargeMaps - 4);
+
+  TemporaryFile maps2;
+  CreateMap(maps2.path, kNumLargeMaps);
+
+  ReparseBenchmark(state, maps1.path, kNumLargeMaps - 4, maps2.path, kNumLargeMaps);
+}
+BENCHMARK(BM_local_updatable_maps_reparse_few_extra_large);
+
+void BM_local_updatable_maps_reparse_few_less_small(benchmark::State& state) {
+  TemporaryFile maps1;
+  CreateMap(maps1.path, kNumSmallMaps);
+
+  TemporaryFile maps2;
+  CreateMap(maps2.path, kNumSmallMaps - 4);
+
+  ReparseBenchmark(state, maps1.path, kNumSmallMaps, maps2.path, kNumSmallMaps - 4);
+}
+BENCHMARK(BM_local_updatable_maps_reparse_few_less_small);
+
+void BM_local_updatable_maps_reparse_few_less_large(benchmark::State& state) {
+  TemporaryFile maps1;
+  CreateMap(maps1.path, kNumLargeMaps);
+
+  TemporaryFile maps2;
+  CreateMap(maps2.path, kNumLargeMaps - 4);
+
+  ReparseBenchmark(state, maps1.path, kNumLargeMaps, maps2.path, kNumLargeMaps - 4);
+}
+BENCHMARK(BM_local_updatable_maps_reparse_few_less_large);
diff --git a/libunwindstack/benchmarks/unwind_benchmarks.cpp b/libunwindstack/benchmarks/unwind_benchmarks.cpp
index de9137a..0bee6ef 100644
--- a/libunwindstack/benchmarks/unwind_benchmarks.cpp
+++ b/libunwindstack/benchmarks/unwind_benchmarks.cpp
@@ -22,7 +22,6 @@
 
 #include <android-base/strings.h>
 
-#include <unwindstack/Elf.h>
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
@@ -83,63 +82,4 @@
 }
 BENCHMARK(BM_cached_unwind);
 
-static void Initialize(benchmark::State& state, unwindstack::Maps& maps,
-                       unwindstack::MapInfo** build_id_map_info) {
-  if (!maps.Parse()) {
-    state.SkipWithError("Failed to parse local maps.");
-    return;
-  }
-
-  // Find the libc.so share library and use that for benchmark purposes.
-  *build_id_map_info = nullptr;
-  for (auto& map_info : maps) {
-    if (map_info->offset == 0 && map_info->GetBuildID() != "") {
-      *build_id_map_info = map_info.get();
-      break;
-    }
-  }
-
-  if (*build_id_map_info == nullptr) {
-    state.SkipWithError("Failed to find a map with a BuildID.");
-  }
-}
-
-static void BM_get_build_id_from_elf(benchmark::State& state) {
-  unwindstack::LocalMaps maps;
-  unwindstack::MapInfo* build_id_map_info;
-  Initialize(state, maps, &build_id_map_info);
-
-  unwindstack::Elf* elf = build_id_map_info->GetElf(std::shared_ptr<unwindstack::Memory>(),
-                                                    unwindstack::Regs::CurrentArch());
-  if (!elf->valid()) {
-    state.SkipWithError("Cannot get valid elf from map.");
-  }
-
-  for (auto _ : state) {
-    uintptr_t id = build_id_map_info->build_id;
-    if (id != 0) {
-      delete reinterpret_cast<std::string*>(id);
-      build_id_map_info->build_id = 0;
-    }
-    benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
-  }
-}
-BENCHMARK(BM_get_build_id_from_elf);
-
-static void BM_get_build_id_from_file(benchmark::State& state) {
-  unwindstack::LocalMaps maps;
-  unwindstack::MapInfo* build_id_map_info;
-  Initialize(state, maps, &build_id_map_info);
-
-  for (auto _ : state) {
-    uintptr_t id = build_id_map_info->build_id;
-    if (id != 0) {
-      delete reinterpret_cast<std::string*>(id);
-      build_id_map_info->build_id = 0;
-    }
-    benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
-  }
-}
-BENCHMARK(BM_get_build_id_from_file);
-
 BENCHMARK_MAIN();
diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h
index fc90dab..3b6cb80 100644
--- a/libunwindstack/tests/ElfFake.h
+++ b/libunwindstack/tests/ElfFake.h
@@ -55,6 +55,8 @@
 
   void FakeSetLoadBias(uint64_t load_bias) { load_bias_ = load_bias; }
 
+  void FakeSetArch(ArchEnum arch) { arch_ = arch; }
+
   void FakeSetInterface(ElfInterface* interface) { interface_.reset(interface); }
   void FakeSetGnuDebugdataInterface(ElfInterface* interface) {
     gnu_debugdata_interface_.reset(interface);
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 1f3ed81..f0852a4 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -438,6 +438,48 @@
   EXPECT_EQ(0xc080U, offset);
 }
 
+TEST_F(ElfTest, get_global_vaddr_with_tagged_pointer) {
+  ElfFake elf(memory_);
+  elf.FakeSetValid(true);
+  elf.FakeSetArch(ARCH_ARM64);
+
+  ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
+  elf.FakeSetInterface(interface);
+  interface->MockSetDataVaddrStart(0x500);
+  interface->MockSetDataVaddrEnd(0x600);
+  interface->MockSetDataOffset(0xa000);
+
+  std::string global("something");
+  EXPECT_CALL(*interface, GetGlobalVariable(global, ::testing::_))
+      .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x8800000000000580),
+                                 ::testing::Return(true)));
+
+  uint64_t offset;
+  ASSERT_TRUE(elf.GetGlobalVariableOffset(global, &offset));
+  EXPECT_EQ(0xa080U, offset);
+}
+
+TEST_F(ElfTest, get_global_vaddr_without_tagged_pointer) {
+  ElfFake elf(memory_);
+  elf.FakeSetValid(true);
+  elf.FakeSetArch(ARCH_X86_64);
+
+  ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
+  elf.FakeSetInterface(interface);
+  interface->MockSetDataVaddrStart(0x8800000000000500);
+  interface->MockSetDataVaddrEnd(0x8800000000000600);
+  interface->MockSetDataOffset(0x880000000000a000);
+
+  std::string global("something");
+  EXPECT_CALL(*interface, GetGlobalVariable(global, ::testing::_))
+      .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x8800000000000580),
+                                 ::testing::Return(true)));
+
+  uint64_t offset;
+  ASSERT_TRUE(elf.GetGlobalVariableOffset(global, &offset));
+  EXPECT_EQ(0x880000000000a080U, offset);
+}
+
 TEST_F(ElfTest, is_valid_pc_elf_invalid) {
   ElfFake elf(memory_);
   elf.FakeSetValid(false);
diff --git a/libunwindstack/tests/LocalUpdatableMapsTest.cpp b/libunwindstack/tests/LocalUpdatableMapsTest.cpp
index b816b9a..99afb0b 100644
--- a/libunwindstack/tests/LocalUpdatableMapsTest.cpp
+++ b/libunwindstack/tests/LocalUpdatableMapsTest.cpp
@@ -271,4 +271,103 @@
   EXPECT_TRUE(map_info->name.empty());
 }
 
+TEST_F(LocalUpdatableMapsTest, add_map_prev_name_updated) {
+  TemporaryFile tf;
+  ASSERT_TRUE(
+      android::base::WriteStringToFile("3000-4000 rwxp 00000 00:00 0\n"
+                                       "8000-9000 r-xp 00000 00:00 0\n"
+                                       "9000-a000 r-xp 00000 00:00 0\n",
+                                       tf.path));
+
+  maps_.TestSetMapsFile(tf.path);
+  ASSERT_TRUE(maps_.Reparse());
+  ASSERT_EQ(3U, maps_.Total());
+
+  MapInfo* map_info = maps_.Get(2);
+  ASSERT_TRUE(map_info != nullptr);
+  EXPECT_EQ(0x9000U, map_info->start);
+  EXPECT_EQ(0xA000U, map_info->end);
+  EXPECT_EQ(0U, map_info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
+  EXPECT_TRUE(map_info->name.empty());
+  EXPECT_EQ(maps_.Get(1), map_info->prev_map);
+}
+
+TEST_F(LocalUpdatableMapsTest, add_map_prev_real_name_updated) {
+  TemporaryFile tf;
+  ASSERT_TRUE(
+      android::base::WriteStringToFile("3000-4000 r-xp 00000 00:00 0 /fake/lib.so\n"
+                                       "4000-5000 ---p 00000 00:00 0\n"
+                                       "7000-8000 r-xp 00000 00:00 0 /fake/lib1.so\n"
+                                       "8000-9000 ---p 00000 00:00 0\n",
+                                       tf.path));
+
+  maps_.TestSetMapsFile(tf.path);
+  ASSERT_TRUE(maps_.Reparse());
+  ASSERT_EQ(4U, maps_.Total());
+
+  MapInfo* map_info = maps_.Get(2);
+  ASSERT_TRUE(map_info != nullptr);
+  EXPECT_EQ(0x7000U, map_info->start);
+  EXPECT_EQ(0x8000U, map_info->end);
+  EXPECT_EQ(0U, map_info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
+  EXPECT_EQ(maps_.Get(0), map_info->prev_real_map);
+  EXPECT_EQ(maps_.Get(1), map_info->prev_map);
+  EXPECT_EQ("/fake/lib1.so", map_info->name);
+
+  map_info = maps_.Get(3);
+  ASSERT_TRUE(map_info != nullptr);
+  EXPECT_EQ(0x8000U, map_info->start);
+  EXPECT_EQ(0x9000U, map_info->end);
+  EXPECT_EQ(0U, map_info->offset);
+  EXPECT_TRUE(map_info->IsBlank());
+  EXPECT_EQ(maps_.Get(2), map_info->prev_real_map);
+  EXPECT_EQ(maps_.Get(2), map_info->prev_map);
+  EXPECT_TRUE(map_info->name.empty());
+
+  ASSERT_TRUE(
+      android::base::WriteStringToFile("3000-4000 r-xp 00000 00:00 0 /fake/lib.so\n"
+                                       "4000-5000 ---p 00000 00:00 0\n"
+                                       "7000-8000 r-xp 00000 00:00 0 /fake/lib1.so\n"
+                                       "8000-9000 ---p 00000 00:00 0\n"
+                                       "9000-a000 r-xp 00000 00:00 0 /fake/lib2.so\n"
+                                       "a000-b000 r-xp 00000 00:00 0 /fake/lib3.so\n",
+                                       tf.path));
+
+  maps_.TestSetMapsFile(tf.path);
+  ASSERT_TRUE(maps_.Reparse());
+  ASSERT_EQ(6U, maps_.Total());
+
+  map_info = maps_.Get(2);
+  ASSERT_TRUE(map_info != nullptr);
+  EXPECT_EQ(0x7000U, map_info->start);
+  EXPECT_EQ(0x8000U, map_info->end);
+  EXPECT_EQ(0U, map_info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
+  EXPECT_EQ("/fake/lib1.so", map_info->name);
+  EXPECT_EQ(maps_.Get(1), map_info->prev_map);
+  EXPECT_EQ(maps_.Get(0), map_info->prev_real_map);
+
+  map_info = maps_.Get(4);
+  ASSERT_TRUE(map_info != nullptr);
+  EXPECT_EQ(0x9000U, map_info->start);
+  EXPECT_EQ(0xA000U, map_info->end);
+  EXPECT_EQ(0U, map_info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
+  EXPECT_EQ("/fake/lib2.so", map_info->name);
+  EXPECT_EQ(maps_.Get(3), map_info->prev_map);
+  EXPECT_EQ(maps_.Get(2), map_info->prev_real_map);
+
+  map_info = maps_.Get(5);
+  ASSERT_TRUE(map_info != nullptr);
+  EXPECT_EQ(0xA000U, map_info->start);
+  EXPECT_EQ(0xB000U, map_info->end);
+  EXPECT_EQ(0U, map_info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
+  EXPECT_EQ("/fake/lib3.so", map_info->name);
+  EXPECT_EQ(maps_.Get(4), map_info->prev_map);
+  EXPECT_EQ(maps_.Get(4), map_info->prev_real_map);
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index 385078d..621893b 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -28,8 +28,6 @@
 
 #include <android-base/file.h>
 #include <android-base/test_utils.h>
-#include <bionic/mte.h>
-#include <bionic/mte_kernel.h>
 #include <gtest/gtest.h>
 
 #include "MemoryRemote.h"
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 3ab619b..0f7044a 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -22,6 +22,7 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
+    min_sdk_version: "apex_inherit",
 
     header_libs: [
         "liblog_headers",
@@ -162,6 +163,7 @@
         "//apex_available:anyapex",
         "//apex_available:platform",
     ],
+    min_sdk_version: "apex_inherit",
 }
 
 cc_library {
@@ -173,8 +175,8 @@
     ],
 
     shared_libs: [
-         "libutils",
-         "libbacktrace",
+        "libutils",
+        "libbacktrace",
     ],
 
     target: {
@@ -192,6 +194,45 @@
     },
 }
 
+cc_defaults {
+    name: "libutils_fuzz_defaults",
+    host_supported: true,
+    shared_libs: [
+        "libutils",
+        "libbase",
+    ],
+}
+
+cc_fuzz {
+    name: "libutils_fuzz_bitset",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["BitSet_fuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "libutils_fuzz_filemap",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["FileMap_fuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "libutils_fuzz_string8",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["String8_fuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "libutils_fuzz_string16",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["String16_fuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "libutils_fuzz_vector",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["Vector_fuzz.cpp"],
+}
+
 cc_test {
     name: "libutils_test",
     host_supported: true,
diff --git a/libutils/BitSet_fuzz.cpp b/libutils/BitSet_fuzz.cpp
new file mode 100644
index 0000000..2e6043c
--- /dev/null
+++ b/libutils/BitSet_fuzz.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2020 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 <functional>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/BitSet.h"
+static constexpr uint8_t MAX_OPERATIONS = 50;
+
+// We need to handle both 32 and 64 bit bitsets, so we use a function template
+// here. Sadly, std::function can't be generic, so we generate a vector of
+// std::functions using this function.
+template <typename T>
+std::vector<std::function<void(T, uint32_t)>> getOperationsForType() {
+    return {
+            [](T bs, uint32_t val) -> void { bs.markBit(val); },
+            [](T bs, uint32_t val) -> void { bs.valueForBit(val); },
+            [](T bs, uint32_t val) -> void { bs.hasBit(val); },
+            [](T bs, uint32_t val) -> void { bs.clearBit(val); },
+            [](T bs, uint32_t val) -> void { bs.getIndexOfBit(val); },
+            [](T bs, uint32_t) -> void { bs.clearFirstMarkedBit(); },
+            [](T bs, uint32_t) -> void { bs.markFirstUnmarkedBit(); },
+            [](T bs, uint32_t) -> void { bs.clearLastMarkedBit(); },
+            [](T bs, uint32_t) -> void { bs.clear(); },
+            [](T bs, uint32_t) -> void { bs.count(); },
+            [](T bs, uint32_t) -> void { bs.isEmpty(); },
+            [](T bs, uint32_t) -> void { bs.isFull(); },
+            [](T bs, uint32_t) -> void { bs.firstMarkedBit(); },
+            [](T bs, uint32_t) -> void { bs.lastMarkedBit(); },
+    };
+}
+
+// Our operations for 32 and 64 bit bitsets
+static const std::vector<std::function<void(android::BitSet32, uint32_t)>> thirtyTwoBitOps =
+        getOperationsForType<android::BitSet32>();
+static const std::vector<std::function<void(android::BitSet64, uint32_t)>> sixtyFourBitOps =
+        getOperationsForType<android::BitSet64>();
+
+void runOperationFor32Bit(android::BitSet32 bs, uint32_t bit, uint8_t operation) {
+    thirtyTwoBitOps[operation](bs, bit);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    uint32_t thirty_two_base = dataProvider.ConsumeIntegral<uint32_t>();
+    uint64_t sixty_four_base = dataProvider.ConsumeIntegral<uint64_t>();
+    android::BitSet32 b1 = android::BitSet32(thirty_two_base);
+    android::BitSet64 b2 = android::BitSet64(sixty_four_base);
+
+    size_t opsRun = 0;
+    while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
+        uint32_t bit = dataProvider.ConsumeIntegral<uint32_t>();
+        uint8_t op = dataProvider.ConsumeIntegral<uint8_t>();
+        thirtyTwoBitOps[op % thirtyTwoBitOps.size()](b1, bit);
+        sixtyFourBitOps[op % sixtyFourBitOps.size()](b2, bit);
+    }
+    return 0;
+}
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 1202c15..0abb861 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -189,13 +189,17 @@
 
     int adjust = offset % mPageSize;
     off64_t adjOffset = offset - adjust;
-    size_t adjLength = length + adjust;
+    size_t adjLength;
+    if (__builtin_add_overflow(length, adjust, &adjLength)) {
+        ALOGE("adjusted length overflow: length %zu adjust %d", length, adjust);
+        return false;
+    }
 
     int flags = MAP_SHARED;
     int prot = PROT_READ;
     if (!readOnly) prot |= PROT_WRITE;
 
-    void* ptr = mmap(nullptr, adjLength, prot, flags, fd, adjOffset);
+    void* ptr = mmap64(nullptr, adjLength, prot, flags, fd, adjOffset);
     if (ptr == MAP_FAILED) {
         if (errno == EINVAL && length == 0) {
             ptr = nullptr;
diff --git a/libutils/FileMap_fuzz.cpp b/libutils/FileMap_fuzz.cpp
new file mode 100644
index 0000000..d800564
--- /dev/null
+++ b/libutils/FileMap_fuzz.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020 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 <iostream>
+
+#include "android-base/file.h"
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/FileMap.h"
+
+static constexpr uint16_t MAX_STR_SIZE = 256;
+static constexpr uint8_t MAX_FILENAME_SIZE = 32;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    TemporaryFile tf;
+    // Generate file contents
+    std::string contents = dataProvider.ConsumeRandomLengthString(MAX_STR_SIZE);
+    // If we have string contents, dump them into the file.
+    // Otherwise, just leave it as an empty file.
+    if (contents.length() > 0) {
+        const char* bytes = contents.c_str();
+        android::base::WriteStringToFd(bytes, tf.fd);
+    }
+    android::FileMap m;
+    // Generate create() params
+    std::string orig_name = dataProvider.ConsumeRandomLengthString(MAX_FILENAME_SIZE);
+    size_t length = dataProvider.ConsumeIntegralInRange<size_t>(1, SIZE_MAX);
+    off64_t offset = dataProvider.ConsumeIntegralInRange<off64_t>(1, INT64_MAX);
+    bool read_only = dataProvider.ConsumeBool();
+    m.create(orig_name.c_str(), tf.fd, offset, length, read_only);
+    m.getDataOffset();
+    m.getFileName();
+    m.getDataLength();
+    m.getDataPtr();
+    int enum_index = dataProvider.ConsumeIntegral<int>();
+    m.advise(static_cast<android::FileMap::MapAdvice>(enum_index));
+    return 0;
+}
diff --git a/libutils/FileMap_test.cpp b/libutils/FileMap_test.cpp
index 576d89b..fd1c9b0 100644
--- a/libutils/FileMap_test.cpp
+++ b/libutils/FileMap_test.cpp
@@ -32,3 +32,36 @@
     ASSERT_EQ(0u, m.getDataLength());
     ASSERT_EQ(4096, m.getDataOffset());
 }
+
+TEST(FileMap, large_offset) {
+    // Make sure that an offset > INT32_MAX will not fail the create
+    // function. See http://b/155662887.
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+
+    off64_t offset = INT32_MAX + 1024LL;
+
+    // Make the temporary file large enough to pass the mmap.
+    ASSERT_EQ(offset, lseek64(tf.fd, offset, SEEK_SET));
+    char value = 0;
+    ASSERT_EQ(1, write(tf.fd, &value, 1));
+
+    android::FileMap m;
+    ASSERT_TRUE(m.create("test", tf.fd, offset, 0, true));
+    ASSERT_STREQ("test", m.getFileName());
+    ASSERT_EQ(0u, m.getDataLength());
+    ASSERT_EQ(offset, m.getDataOffset());
+}
+
+TEST(FileMap, offset_overflow) {
+    // Make sure that an end that overflows SIZE_MAX will not abort.
+    // See http://b/156997193.
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+
+    off64_t offset = 200;
+    size_t length = SIZE_MAX;
+
+    android::FileMap m;
+    ASSERT_FALSE(m.create("test", tf.fd, offset, length, true));
+}
diff --git a/libutils/String16_fuzz.cpp b/libutils/String16_fuzz.cpp
new file mode 100644
index 0000000..63c2800
--- /dev/null
+++ b/libutils/String16_fuzz.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2020 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 <iostream>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/String16.h"
+static constexpr int MAX_STRING_BYTES = 256;
+static constexpr uint8_t MAX_OPERATIONS = 50;
+
+std::vector<std::function<void(FuzzedDataProvider&, android::String16, android::String16)>>
+        operations = {
+
+                // Bytes and size
+                ([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void {
+                    str1.string();
+                }),
+                ([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void {
+                    str1.isStaticString();
+                }),
+                ([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void {
+                    str1.size();
+                }),
+
+                // Casing
+                ([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void {
+                    str1.makeLower();
+                }),
+
+                // Comparison
+                ([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
+                    str1.startsWith(str2);
+                }),
+                ([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
+                    str1.contains(str2.string());
+                }),
+                ([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
+                    str1.compare(str2);
+                }),
+
+                // Append and format
+                ([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
+                    str1.append(str2);
+                }),
+                ([](FuzzedDataProvider& dataProvider, android::String16 str1,
+                    android::String16 str2) -> void {
+                    int pos = dataProvider.ConsumeIntegralInRange<int>(0, str1.size());
+                    str1.insert(pos, str2.string());
+                }),
+
+                // Find and replace operations
+                ([](FuzzedDataProvider& dataProvider, android::String16 str1,
+                    android::String16) -> void {
+                    char16_t findChar = dataProvider.ConsumeIntegral<char16_t>();
+                    str1.findFirst(findChar);
+                }),
+                ([](FuzzedDataProvider& dataProvider, android::String16 str1,
+                    android::String16) -> void {
+                    char16_t findChar = dataProvider.ConsumeIntegral<char16_t>();
+                    str1.findLast(findChar);
+                }),
+                ([](FuzzedDataProvider& dataProvider, android::String16 str1,
+                    android::String16) -> void {
+                    char16_t findChar = dataProvider.ConsumeIntegral<char16_t>();
+                    char16_t replaceChar = dataProvider.ConsumeIntegral<char16_t>();
+                    str1.replaceAll(findChar, replaceChar);
+                }),
+                ([](FuzzedDataProvider& dataProvider, android::String16 str1,
+                    android::String16) -> void {
+                    size_t len = dataProvider.ConsumeIntegral<size_t>();
+                    size_t begin = dataProvider.ConsumeIntegral<size_t>();
+                    str1.remove(len, begin);
+                }),
+};
+
+void callFunc(uint8_t index, FuzzedDataProvider& dataProvider, android::String16 str1,
+              android::String16 str2) {
+    operations[index](dataProvider, str1, str2);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    // We're generating two char vectors.
+    // First, generate lengths.
+    const size_t kVecOneLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
+    const size_t kVecTwoLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
+
+    // Next, populate the vectors
+    std::vector<char> vec = dataProvider.ConsumeBytesWithTerminator<char>(kVecOneLen);
+    std::vector<char> vec_two = dataProvider.ConsumeBytesWithTerminator<char>(kVecTwoLen);
+
+    // Get pointers to their data
+    char* char_one = vec.data();
+    char* char_two = vec_two.data();
+
+    // Create UTF16 representations
+    android::String16 str_one_utf16 = android::String16(char_one);
+    android::String16 str_two_utf16 = android::String16(char_two);
+
+    // Run operations against strings
+    int opsRun = 0;
+    while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
+        uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
+        callFunc(op, dataProvider, str_one_utf16, str_two_utf16);
+    }
+
+    str_one_utf16.remove(0, str_one_utf16.size());
+    str_two_utf16.remove(0, str_two_utf16.size());
+    return 0;
+}
diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp
new file mode 100644
index 0000000..2adfe98
--- /dev/null
+++ b/libutils/String8_fuzz.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2020 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 <functional>
+#include <iostream>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/String8.h"
+
+static constexpr int MAX_STRING_BYTES = 256;
+static constexpr uint8_t MAX_OPERATIONS = 50;
+
+std::vector<std::function<void(FuzzedDataProvider&, android::String8, android::String8)>>
+        operations = {
+
+                // Bytes and size
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.bytes();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.isEmpty();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.length();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.size();
+                },
+
+                // Casing
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.toUpper();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.toLower();
+                },
+
+                [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
+                    str1.removeAll(str2.c_str());
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
+                    str1.compare(str2);
+                },
+
+                // Append and format
+                [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
+                    str1.append(str2);
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
+                    str1.appendFormat(str1.c_str(), str2.c_str());
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
+                    str1.format(str1.c_str(), str2.c_str());
+                },
+
+                // Find operation
+                [](FuzzedDataProvider& dataProvider, android::String8 str1,
+                   android::String8) -> void {
+                    // We need to get a value from our fuzzer here.
+                    int start_index = dataProvider.ConsumeIntegralInRange<int>(0, str1.size());
+                    str1.find(str1.c_str(), start_index);
+                },
+
+                // Path handling
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.getBasePath();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.getPathExtension();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.getPathLeaf();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.getPathDir();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    str1.convertToResPath();
+                },
+                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
+                    android::String8 path_out_str = android::String8();
+                    str1.walkPath(&path_out_str);
+                    path_out_str.clear();
+                },
+                [](FuzzedDataProvider& dataProvider, android::String8 str1,
+                   android::String8) -> void {
+                    str1.setPathName(dataProvider.ConsumeBytesWithTerminator<char>(5).data());
+                },
+                [](FuzzedDataProvider& dataProvider, android::String8 str1,
+                   android::String8) -> void {
+                    str1.appendPath(dataProvider.ConsumeBytesWithTerminator<char>(5).data());
+                },
+};
+
+void callFunc(uint8_t index, FuzzedDataProvider& dataProvider, android::String8 str1,
+              android::String8 str2) {
+    operations[index](dataProvider, str1, str2);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    // Generate vector lengths
+    const size_t kVecOneLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
+    const size_t kVecTwoLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
+    // Populate vectors
+    std::vector<char> vec = dataProvider.ConsumeBytesWithTerminator<char>(kVecOneLen);
+    std::vector<char> vec_two = dataProvider.ConsumeBytesWithTerminator<char>(kVecTwoLen);
+    // Create UTF-8 pointers
+    android::String8 str_one_utf8 = android::String8(vec.data());
+    android::String8 str_two_utf8 = android::String8(vec_two.data());
+
+    // Run operations against strings
+    int opsRun = 0;
+    while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
+        uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
+        callFunc(op, dataProvider, str_one_utf8, str_two_utf8);
+    }
+
+    // Just to be extra sure these can be freed, we're going to explicitly clear
+    // them
+    str_one_utf8.clear();
+    str_two_utf8.clear();
+    return 0;
+}
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 540dcf4..147db54 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -302,8 +302,7 @@
 }
 
 #if defined(__ANDROID__)
-int androidSetThreadPriority(pid_t tid, int pri)
-{
+int androidSetThreadPriority(pid_t tid, int pri, bool change_policy) {
     int rc = 0;
     int lasterr = 0;
     int curr_pri = getpriority(PRIO_PROCESS, tid);
@@ -312,17 +311,19 @@
         return rc;
     }
 
-    if (pri >= ANDROID_PRIORITY_BACKGROUND) {
-        rc = SetTaskProfiles(tid, {"SCHED_SP_BACKGROUND"}, true) ? 0 : -1;
-    } else if (curr_pri >= ANDROID_PRIORITY_BACKGROUND) {
-        SchedPolicy policy = SP_FOREGROUND;
-        // Change to the sched policy group of the process.
-        get_sched_policy(getpid(), &policy);
-        rc = SetTaskProfiles(tid, {get_sched_policy_profile_name(policy)}, true) ? 0 : -1;
-    }
+    if (change_policy) {
+        if (pri >= ANDROID_PRIORITY_BACKGROUND) {
+            rc = SetTaskProfiles(tid, {"SCHED_SP_BACKGROUND"}, true) ? 0 : -1;
+        } else if (curr_pri >= ANDROID_PRIORITY_BACKGROUND) {
+            SchedPolicy policy = SP_FOREGROUND;
+            // Change to the sched policy group of the process.
+            get_sched_policy(getpid(), &policy);
+            rc = SetTaskProfiles(tid, {get_sched_policy_profile_name(policy)}, true) ? 0 : -1;
+        }
 
-    if (rc) {
-        lasterr = errno;
+        if (rc) {
+            lasterr = errno;
+        }
     }
 
     if (setpriority(PRIO_PROCESS, tid, pri) < 0) {
diff --git a/libutils/Vector_fuzz.cpp b/libutils/Vector_fuzz.cpp
new file mode 100644
index 0000000..f6df051
--- /dev/null
+++ b/libutils/Vector_fuzz.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2020 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 "fuzzer/FuzzedDataProvider.h"
+#include "utils/Vector.h"
+static constexpr uint16_t MAX_VEC_SIZE = 5000;
+
+void runVectorFuzz(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    android::Vector<uint8_t> vec = android::Vector<uint8_t>();
+    // We want to test handling of sizeof as well.
+    android::Vector<uint32_t> vec32 = android::Vector<uint32_t>();
+
+    // We're going to generate two vectors of this size
+    size_t vectorSize = dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_VEC_SIZE);
+    vec.setCapacity(vectorSize);
+    vec32.setCapacity(vectorSize);
+    for (size_t i = 0; i < vectorSize; i++) {
+        uint8_t count = dataProvider.ConsumeIntegralInRange<uint8_t>(1, 5);
+        vec.insertAt((uint8_t)i, i, count);
+        vec32.insertAt((uint32_t)i, i, count);
+        vec.push_front(i);
+        vec32.push(i);
+    }
+
+    // Now we'll perform some test operations with any remaining data
+    // Index to perform operations at
+    size_t index = dataProvider.ConsumeIntegralInRange<size_t>(0, vec.size());
+    std::vector<uint8_t> remainingVec = dataProvider.ConsumeRemainingBytes<uint8_t>();
+    // Insert an array and vector
+    vec.insertArrayAt(remainingVec.data(), index, remainingVec.size());
+    android::Vector<uint8_t> vecCopy = android::Vector<uint8_t>(vec);
+    vec.insertVectorAt(vecCopy, index);
+    // Same thing for 32 bit vector
+    android::Vector<uint32_t> vec32Copy = android::Vector<uint32_t>(vec32);
+    vec32.insertArrayAt(vec32Copy.array(), index, vec32.size());
+    vec32.insertVectorAt(vec32Copy, index);
+    // Replace single character
+    if (remainingVec.size() > 0) {
+        vec.replaceAt(remainingVec[0], index);
+        vec32.replaceAt(static_cast<uint32_t>(remainingVec[0]), index);
+    } else {
+        vec.replaceAt(0, index);
+        vec32.replaceAt(0, index);
+    }
+    // Add any remaining bytes
+    for (uint8_t i : remainingVec) {
+        vec.add(i);
+        vec32.add(static_cast<uint32_t>(i));
+    }
+    // Shrink capactiy
+    vec.setCapacity(remainingVec.size());
+    vec32.setCapacity(remainingVec.size());
+    // Iterate through each pointer
+    size_t sum = 0;
+    for (auto& it : vec) {
+        sum += it;
+    }
+    for (auto& it : vec32) {
+        sum += it;
+    }
+    // Cleanup
+    vec.clear();
+    vecCopy.clear();
+    vec32.clear();
+    vec32Copy.clear();
+}
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    runVectorFuzz(data, size);
+    return 0;
+}
diff --git a/libutils/include/utils/AndroidThreads.h b/libutils/include/utils/AndroidThreads.h
index a8d7851..3c30a2a 100644
--- a/libutils/include/utils/AndroidThreads.h
+++ b/libutils/include/utils/AndroidThreads.h
@@ -78,7 +78,9 @@
 // should be one of the ANDROID_PRIORITY constants.  Returns INVALID_OPERATION
 // if the priority set failed, else another value if just the group set failed;
 // in either case errno is set.  Thread ID zero means current thread.
-extern int androidSetThreadPriority(pid_t tid, int prio);
+// Parameter "change_policy" indicates if sched policy should be changed. It needs
+// not be checked again if the change is done elsewhere like activity manager.
+extern int androidSetThreadPriority(pid_t tid, int prio, bool change_policy = true);
 
 // Get the current priority of a particular thread. Returns one of the
 // ANDROID_PRIORITY constants or a negative result in case of error.
diff --git a/libutils/include/utils/Compat.h b/libutils/include/utils/Compat.h
index dee577e..6002567 100644
--- a/libutils/include/utils/Compat.h
+++ b/libutils/include/utils/Compat.h
@@ -19,12 +19,20 @@
 
 #include <unistd.h>
 
+#if !defined(__MINGW32__)
+#include <sys/mman.h>
+#endif
+
 #if defined(__APPLE__)
 
 /* Mac OS has always had a 64-bit off_t, so it doesn't have off64_t. */
-
+static_assert(sizeof(off_t) >= 8, "This code requires that Mac OS have at least a 64-bit off_t.");
 typedef off_t off64_t;
 
+static inline void* mmap64(void* addr, size_t length, int prot, int flags, int fd, off64_t offset) {
+    return mmap(addr, length, prot, flags, fd, offset);
+}
+
 static inline off64_t lseek64(int fd, off64_t offset, int whence) {
     return lseek(fd, offset, whence);
 }
diff --git a/libziparchive/.clang-format b/libziparchive/.clang-format
deleted file mode 120000
index fd0645f..0000000
--- a/libziparchive/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-../.clang-format-2
\ No newline at end of file
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
deleted file mode 100644
index 786e7b3..0000000
--- a/libziparchive/Android.bp
+++ /dev/null
@@ -1,231 +0,0 @@
-//
-// Copyright (C) 2013 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: "libziparchive_flags",
-    cflags: [
-        // ZLIB_CONST turns on const for input buffers, which is pretty standard.
-        "-DZLIB_CONST",
-        "-Werror",
-        "-Wall",
-        "-D_FILE_OFFSET_BITS=64",
-    ],
-    cppflags: [
-        // Incorrectly warns when C++11 empty brace {} initializer is used.
-        // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61489
-        "-Wno-missing-field-initializers",
-        "-Wconversion",
-        "-Wno-sign-conversion",
-    ],
-
-    // Enable -Wold-style-cast only for non-Windows targets.  _islower_l,
-    // _isupper_l etc. in MinGW locale_win32.h (included from
-    // libcxx/include/__locale) has an old-style-cast.
-    target: {
-        not_windows: {
-            cppflags: [
-                "-Wold-style-cast",
-            ],
-        },
-    },
-    sanitize: {
-        misc_undefined: [
-            "signed-integer-overflow",
-            "unsigned-integer-overflow",
-            "shift",
-            "integer-divide-by-zero",
-            "implicit-signed-integer-truncation",
-            // TODO: Fix crash when we enable this option
-            // "implicit-unsigned-integer-truncation",
-            // TODO: not tested yet.
-            // "implicit-integer-sign-change",
-        ],
-    },
-}
-
-cc_defaults {
-    name: "libziparchive_defaults",
-    srcs: [
-        "zip_archive.cc",
-        "zip_archive_stream_entry.cc",
-        "zip_cd_entry_map.cc",
-        "zip_error.cpp",
-        "zip_writer.cc",
-    ],
-
-    target: {
-        windows: {
-            cflags: ["-mno-ms-bitfields"],
-
-            enabled: true,
-        },
-    },
-
-    shared_libs: [
-        "libbase",
-        "liblog",
-    ],
-
-    // for FRIEND_TEST
-    static_libs: ["libgtest_prod"],
-    export_static_lib_headers: ["libgtest_prod"],
-
-    export_include_dirs: ["include"],
-}
-
-cc_library {
-    name: "libziparchive",
-    host_supported: true,
-    vendor_available: true,
-    recovery_available: true,
-    native_bridge_supported: true,
-    vndk: {
-        enabled: true,
-    },
-    double_loadable: true,
-    export_shared_lib_headers: ["libbase"],
-
-    defaults: [
-        "libziparchive_defaults",
-        "libziparchive_flags",
-    ],
-    shared_libs: [
-        "liblog",
-        "libbase",
-        "libz",
-    ],
-    target: {
-        linux_bionic: {
-            enabled: true,
-        },
-    },
-}
-
-// Tests.
-cc_test {
-    name: "ziparchive-tests",
-    host_supported: true,
-    defaults: ["libziparchive_flags"],
-
-    data: [
-        "testdata/**/*",
-    ],
-
-    srcs: [
-        "entry_name_utils_test.cc",
-        "zip_archive_test.cc",
-        "zip_writer_test.cc",
-    ],
-    shared_libs: [
-        "libbase",
-        "liblog",
-    ],
-
-    static_libs: [
-        "libziparchive",
-        "libz",
-        "libutils",
-    ],
-
-    target: {
-        host: {
-            cppflags: ["-Wno-unnamed-type-template-args"],
-        },
-        windows: {
-            enabled: true,
-        },
-    },
-    test_suites: ["device-tests"],
-}
-
-// Performance benchmarks.
-cc_benchmark {
-    name: "ziparchive-benchmarks",
-    defaults: ["libziparchive_flags"],
-
-    srcs: [
-        "zip_archive_benchmark.cpp",
-    ],
-    shared_libs: [
-        "libbase",
-        "liblog",
-    ],
-
-    static_libs: [
-        "libziparchive",
-        "libz",
-        "libutils",
-    ],
-
-    target: {
-        host: {
-            cppflags: ["-Wno-unnamed-type-template-args"],
-        },
-    },
-}
-
-cc_binary {
-    name: "ziptool",
-    defaults: ["libziparchive_flags"],
-    srcs: ["ziptool.cpp"],
-    shared_libs: [
-        "libbase",
-        "libziparchive",
-    ],
-    recovery_available: true,
-    host_supported: true,
-    target: {
-        android: {
-            symlinks: ["unzip", "zipinfo"],
-        },
-    },
-}
-
-cc_fuzz {
-    name: "libziparchive_fuzzer",
-    srcs: ["libziparchive_fuzzer.cpp"],
-    static_libs: ["libziparchive", "libbase", "libz", "liblog"],
-    host_supported: true,
-    corpus: ["testdata/*"],
-}
-
-sh_test {
-    name: "ziptool-tests",
-    src: "run-ziptool-tests-on-android.sh",
-    filename: "run-ziptool-tests-on-android.sh",
-    test_suites: ["general-tests"],
-    host_supported: true,
-    device_supported: false,
-    test_config: "ziptool-tests.xml",
-    data: ["cli-tests/**/*"],
-    target_required: ["cli-test", "ziptool"],
-}
-
-python_test_host {
-    name: "ziparchive_tests_large",
-    srcs: ["test_ziparchive_large.py"],
-    main: "test_ziparchive_large.py",
-    version: {
-        py2: {
-            enabled: true,
-            embedded_launcher: false,
-        },
-        py3: {
-            enabled: false,
-            embedded_launcher: false,
-        },
-    },
-    test_suites: ["general-tests"],
-}
diff --git a/libziparchive/OWNERS b/libziparchive/OWNERS
deleted file mode 100644
index fcc567a..0000000
--- a/libziparchive/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-narayan@google.com
diff --git a/libziparchive/cli-tests/files/example.zip b/libziparchive/cli-tests/files/example.zip
deleted file mode 100644
index c3292e9..0000000
--- a/libziparchive/cli-tests/files/example.zip
+++ /dev/null
Binary files differ
diff --git a/libziparchive/cli-tests/unzip.test b/libziparchive/cli-tests/unzip.test
deleted file mode 100755
index 6e5cbf2..0000000
--- a/libziparchive/cli-tests/unzip.test
+++ /dev/null
@@ -1,148 +0,0 @@
-# unzip tests.
-
-# Note: since "master key", Android uses libziparchive for all zip file
-# handling, and that scans the whole central directory immediately. Not only
-# lookups by name but also iteration is implemented using the resulting hash
-# table, meaning that any test that makes assumptions about iteration order
-# will fail on Android.
-
-name: unzip -l
-command: unzip -l $FILES/example.zip d1/d2/x.txt
-after: [ ! -f d1/d2/x.txt ]
-expected-stdout:
-	Archive:  $FILES/example.zip
-	  Length      Date    Time    Name
-	---------  ---------- -----   ----
-	     1024  2017-06-04 08:45   d1/d2/x.txt
-	---------                     -------
-	     1024                     1 file
----
-
-name: unzip -lq
-command: unzip -lq $FILES/example.zip d1/d2/x.txt
-after: [ ! -f d1/d2/x.txt ]
-expected-stdout:
-	  Length      Date    Time    Name
-	---------  ---------- -----   ----
-	     1024  2017-06-04 08:45   d1/d2/x.txt
-	---------                     -------
-	     1024                     1 file
----
-
-name: unzip -lv
-command: unzip -lv $FILES/example.zip d1/d2/x.txt
-after: [ ! -f d1/d2/file ]
-expected-stdout:
-	Archive:  $FILES/example.zip
-	 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
-	--------  ------  ------- ---- ---------- ----- --------  ----
-	    1024  Defl:N       11  99% 2017-06-04 08:45 48d7f063  d1/d2/x.txt
-	--------          -------  ---                            -------
-	    1024               11  99%                            1 file
----
-
-name: unzip -v
-command: unzip -v $FILES/example.zip d1/d2/x.txt
-after: [ ! -f d1/d2/file ]
-expected-stdout:
-	Archive:  $FILES/example.zip
-	 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
-	--------  ------  ------- ---- ---------- ----- --------  ----
-	    1024  Defl:N       11  99% 2017-06-04 08:45 48d7f063  d1/d2/x.txt
-	--------          -------  ---                            -------
-	    1024               11  99%                            1 file
----
-
-name: unzip one file
-command: unzip -q $FILES/example.zip d1/d2/a.txt && cat d1/d2/a.txt
-after: [ ! -f d1/d2/b.txt ]
-expected-stdout:
-	a
----
-
-name: unzip all files
-command: unzip -q $FILES/example.zip
-after: [ -f d1/d2/a.txt ]
-after: [ -f d1/d2/b.txt ]
-after: [ -f d1/d2/c.txt ]
-after: [ -f d1/d2/empty.txt ]
-after: [ -f d1/d2/x.txt ]
-after: [ -d d1/d2/dir ]
-expected-stdout:
----
-
-name: unzip -o
-before: mkdir -p d1/d2
-before: echo b > d1/d2/a.txt
-command: unzip -q -o $FILES/example.zip d1/d2/a.txt && cat d1/d2/a.txt
-expected-stdout:
-	a
----
-
-name: unzip -n
-before: mkdir -p d1/d2
-before: echo b > d1/d2/a.txt
-command: unzip -q -n $FILES/example.zip d1/d2/a.txt && cat d1/d2/a.txt
-expected-stdout:
-	b
----
-
-# The reference implementation will create *one* level of missing directories,
-# so this succeeds.
-name: unzip -d shallow non-existent
-command: unzip -q -d will-be-created $FILES/example.zip d1/d2/a.txt
-after: [ -d will-be-created ]
-after: [ -f will-be-created/d1/d2/a.txt ]
----
-
-# The reference implementation will *only* create one level of missing
-# directories, so this fails.
-name: unzip -d deep non-existent
-command: unzip -q -d oh-no/will-not-be-created $FILES/example.zip d1/d2/a.txt 2> stderr ; echo $? > status
-after: [ ! -d oh-no ]
-after: [ ! -d oh-no/will-not-be-created ]
-after: [ ! -f oh-no/will-not-be-created/d1/d2/a.txt ]
-after: grep -q "oh-no/will-not-be-created" stderr
-after: grep -q "No such file or directory" stderr
-# The reference implementation has *lots* of non-zero exit values, but we stick to 0 and 1.
-after: [ $(cat status) -gt 0 ]
----
-
-name: unzip -d exists
-before: mkdir dir
-command: unzip -q -d dir $FILES/example.zip d1/d2/a.txt && cat dir/d1/d2/a.txt
-after: [ ! -f d1/d2/a.txt ]
-expected-stdout:
-	a
----
-
-name: unzip -p
-command: unzip -p $FILES/example.zip d1/d2/a.txt
-after: [ ! -f d1/d2/a.txt ]
-expected-stdout:
-	a
----
-
-name: unzip -x FILE...
-# Note: the RI ignores -x DIR for some reason, but it's not obvious we should.
-command: unzip -q $FILES/example.zip -x d1/d2/a.txt d1/d2/b.txt d1/d2/empty.txt d1/d2/x.txt && cat d1/d2/c.txt
-after: [ ! -f d1/d2/a.txt ]
-after: [ ! -f d1/d2/b.txt ]
-after: [ ! -f d1/d2/empty.txt ]
-after: [ ! -f d1/d2/x.txt ]
-after: [ -d d1/d2/dir ]
-expected-stdout:
-	ccc
----
-
-name: unzip FILE -x FILE...
-command: unzip -q $FILES/example.zip d1/d2/a.txt d1/d2/b.txt -x d1/d2/a.txt && cat d1/d2/b.txt
-after: [ ! -f d1/d2/a.txt ]
-after: [ -f d1/d2/b.txt ]
-after: [ ! -f d1/d2/c.txt ]
-after: [ ! -f d1/d2/empty.txt ]
-after: [ ! -f d1/d2/x.txt ]
-after: [ ! -d d1/d2/dir ]
-expected-stdout:
-	bb
----
diff --git a/libziparchive/cli-tests/zipinfo.test b/libziparchive/cli-tests/zipinfo.test
deleted file mode 100755
index d5bce1c..0000000
--- a/libziparchive/cli-tests/zipinfo.test
+++ /dev/null
@@ -1,53 +0,0 @@
-# zipinfo tests.
-
-# Note: since "master key", Android uses libziparchive for all zip file
-# handling, and that scans the whole central directory immediately. Not only
-# lookups by name but also iteration is implemented using the resulting hash
-# table, meaning that any test that makes assumptions about iteration order
-# will fail on Android.
-
-name: zipinfo -1
-command: zipinfo -1 $FILES/example.zip | sort
-expected-stdout:
-	d1/
-	d1/d2/a.txt
-	d1/d2/b.txt
-	d1/d2/c.txt
-	d1/d2/dir/
-	d1/d2/empty.txt
-	d1/d2/x.txt
----
-
-name: zipinfo header
-command: zipinfo $FILES/example.zip | head -2
-expected-stdout:
-	Archive:  $FILES/example.zip
-	Zip file size: 1082 bytes, number of entries: 7
----
-
-name: zipinfo footer
-command: zipinfo $FILES/example.zip | tail -1
-expected-stdout:
-	7 files, 1033 bytes uncompressed, 20 bytes compressed:  98.1%
----
-
-name: zipinfo directory
-# The RI doesn't use ISO dates.
-command: zipinfo $FILES/example.zip d1/ | sed s/17-Jun-/2017-06-/
-expected-stdout:
-	drwxr-x---  3.0 unx        0 bx stor 2017-06-04 08:40 d1/
----
-
-name: zipinfo stored
-# The RI doesn't use ISO dates.
-command: zipinfo $FILES/example.zip d1/d2/empty.txt | sed s/17-Jun-/2017-06-/
-expected-stdout:
-	-rw-r-----  3.0 unx        0 bx stor 2017-06-04 08:43 d1/d2/empty.txt
----
-
-name: zipinfo deflated
-# The RI doesn't use ISO dates.
-command: zipinfo $FILES/example.zip d1/d2/x.txt | sed s/17-Jun-/2017-06-/
-expected-stdout:
-	-rw-r-----  3.0 unx     1024 tx defN 2017-06-04 08:45 d1/d2/x.txt
----
diff --git a/libziparchive/entry_name_utils-inl.h b/libziparchive/entry_name_utils-inl.h
deleted file mode 100644
index 10311b5..0000000
--- a/libziparchive/entry_name_utils-inl.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 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 LIBZIPARCHIVE_ENTRY_NAME_UTILS_INL_H_
-#define LIBZIPARCHIVE_ENTRY_NAME_UTILS_INL_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <limits>
-
-// Check if |length| bytes at |entry_name| constitute a valid entry name.
-// Entry names must be valid UTF-8 and must not contain '0'. They also must
-// fit into the central directory record.
-inline bool IsValidEntryName(const uint8_t* entry_name, const size_t length) {
-  if (length > std::numeric_limits<uint16_t>::max()) {
-    return false;
-  }
-  for (size_t i = 0; i < length; ++i) {
-    const uint8_t byte = entry_name[i];
-    if (byte == 0) {
-      return false;
-    } else if ((byte & 0x80) == 0) {
-      // Single byte sequence.
-      continue;
-    } else if ((byte & 0xc0) == 0x80 || (byte & 0xfe) == 0xfe) {
-      // Invalid sequence.
-      return false;
-    } else {
-      // 2-5 byte sequences.
-      for (uint8_t first = static_cast<uint8_t>((byte & 0x7f) << 1); first & 0x80;
-           first = static_cast<uint8_t>((first & 0x7f) << 1)) {
-        ++i;
-
-        // Missing continuation byte..
-        if (i == length) {
-          return false;
-        }
-
-        // Invalid continuation byte.
-        const uint8_t continuation_byte = entry_name[i];
-        if ((continuation_byte & 0xc0) != 0x80) {
-          return false;
-        }
-      }
-    }
-  }
-
-  return true;
-}
-
-#endif  // LIBZIPARCHIVE_ENTRY_NAME_UTILS_INL_H_
diff --git a/libziparchive/entry_name_utils_test.cc b/libziparchive/entry_name_utils_test.cc
deleted file mode 100644
index d83d854..0000000
--- a/libziparchive/entry_name_utils_test.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#include "entry_name_utils-inl.h"
-
-#include <gtest/gtest.h>
-
-TEST(entry_name_utils, NullChars) {
-  // 'A', 'R', '\0', 'S', 'E'
-  const uint8_t zeroes[] = {0x41, 0x52, 0x00, 0x53, 0x45};
-  ASSERT_FALSE(IsValidEntryName(zeroes, sizeof(zeroes)));
-
-  const uint8_t zeroes_continuation_chars[] = {0xc2, 0xa1, 0xc2, 0x00};
-  ASSERT_FALSE(IsValidEntryName(zeroes_continuation_chars, sizeof(zeroes_continuation_chars)));
-}
-
-TEST(entry_name_utils, InvalidSequence) {
-  // 0xfe is an invalid start byte
-  const uint8_t invalid[] = {0x41, 0xfe};
-  ASSERT_FALSE(IsValidEntryName(invalid, sizeof(invalid)));
-
-  // 0x91 is an invalid start byte (it's a valid continuation byte).
-  const uint8_t invalid2[] = {0x41, 0x91};
-  ASSERT_FALSE(IsValidEntryName(invalid2, sizeof(invalid2)));
-}
-
-TEST(entry_name_utils, TruncatedContinuation) {
-  // Malayalam script with truncated bytes. There should be 2 bytes
-  // after 0xe0
-  const uint8_t truncated[] = {0xe0, 0xb4, 0x85, 0xe0, 0xb4};
-  ASSERT_FALSE(IsValidEntryName(truncated, sizeof(truncated)));
-
-  // 0xc2 is the start of a 2 byte sequence that we've subsequently
-  // dropped.
-  const uint8_t truncated2[] = {0xc2, 0xc2, 0xa1};
-  ASSERT_FALSE(IsValidEntryName(truncated2, sizeof(truncated2)));
-}
-
-TEST(entry_name_utils, BadContinuation) {
-  // 0x41 is an invalid continuation char, since it's MSBs
-  // aren't "10..." (are 01).
-  const uint8_t bad[] = {0xc2, 0xa1, 0xc2, 0x41};
-  ASSERT_FALSE(IsValidEntryName(bad, sizeof(bad)));
-
-  // 0x41 is an invalid continuation char, since it's MSBs
-  // aren't "10..." (are 11).
-  const uint8_t bad2[] = {0xc2, 0xa1, 0xc2, 0xfe};
-  ASSERT_FALSE(IsValidEntryName(bad2, sizeof(bad2)));
-}
diff --git a/libziparchive/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
deleted file mode 100644
index 005d697..0000000
--- a/libziparchive/include/ziparchive/zip_archive.h
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (C) 2013 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
-
-/*
- * Read-only access to Zip archives, with minimal heap allocation.
- */
-
-#include <stdint.h>
-#include <string.h>
-#include <sys/cdefs.h>
-#include <sys/types.h>
-
-#include <functional>
-#include <string>
-#include <string_view>
-
-#include "android-base/off64_t.h"
-
-/* Zip compression methods we support */
-enum {
-  kCompressStored = 0,    // no compression
-  kCompressDeflated = 8,  // standard deflate
-};
-
-// This struct holds the common information of a zip entry other than the
-// the entry size. The compressed and uncompressed length will be handled
-// separately in the derived class.
-struct ZipEntryCommon {
-  // Compression method. One of kCompressStored or kCompressDeflated.
-  // See also `gpbf` for deflate subtypes.
-  uint16_t method;
-
-  // Modification time. The zipfile format specifies
-  // that the first two little endian bytes contain the time
-  // and the last two little endian bytes contain the date.
-  // See `GetModificationTime`. Use signed integer to avoid the
-  // sub-overflow.
-  // TODO: should be overridden by extra time field, if present.
-  int32_t mod_time;
-
-  // Returns `mod_time` as a broken-down struct tm.
-  struct tm GetModificationTime() const;
-
-  // Suggested Unix mode for this entry, from the zip archive if created on
-  // Unix, or a default otherwise. See also `external_file_attributes`.
-  mode_t unix_mode;
-
-  // 1 if this entry contains a data descriptor segment, 0
-  // otherwise.
-  uint8_t has_data_descriptor;
-
-  // Crc32 value of this ZipEntry. This information might
-  // either be stored in the local file header or in a special
-  // Data descriptor footer at the end of the file entry.
-  uint32_t crc32;
-
-  // If the value of uncompressed length and compressed length are stored in
-  // the zip64 extended info of the extra field.
-  bool zip64_format_size{false};
-
-  // The offset to the start of data for this ZipEntry.
-  off64_t offset;
-
-  // The version of zip and the host file system this came from (for zipinfo).
-  uint16_t version_made_by;
-
-  // The raw attributes, whose interpretation depends on the host
-  // file system in `version_made_by` (for zipinfo). See also `unix_mode`.
-  uint32_t external_file_attributes;
-
-  // Specifics about the deflation (for zipinfo).
-  uint16_t gpbf;
-  // Whether this entry is believed to be text or binary (for zipinfo).
-  bool is_text;
-};
-
-struct ZipEntry64;
-// Many users of the library assume the entry size is capped at UNIT32_MAX. So we keep
-// the interface for the old ZipEntry here; and we could switch them over to the new
-// ZipEntry64 later.
-struct ZipEntry : public ZipEntryCommon {
-  // Compressed length of this ZipEntry. The maximum value is UNIT32_MAX.
-  // Might be present either in the local file header or in the data
-  // descriptor footer.
-  uint32_t compressed_length{0};
-
-  // Uncompressed length of this ZipEntry. The maximum value is UNIT32_MAX.
-  // Might be present either in the local file header or in the data
-  // descriptor footer.
-  uint32_t uncompressed_length{0};
-
-  // Copies the contents of a ZipEntry64 object to a 32 bits ZipEntry. Returns 0 if the
-  // size of the entry fits into uint32_t, returns a negative error code
-  // (kUnsupportedEntrySize) otherwise.
-  static int32_t CopyFromZipEntry64(ZipEntry* dst, const ZipEntry64* src);
-
- private:
-  ZipEntry& operator=(const ZipEntryCommon& other) {
-    ZipEntryCommon::operator=(other);
-    return *this;
-  }
-};
-
-// Represents information about a zip entry in a zip file.
-struct ZipEntry64 : public ZipEntryCommon {
-  // Compressed length of this ZipEntry. The maximum value is UNIT64_MAX.
-  // Might be present either in the local file header, the zip64 extended field,
-  // or in the data descriptor footer.
-  uint64_t compressed_length{0};
-
-  // Uncompressed length of this ZipEntry. The maximum value is UNIT64_MAX.
-  // Might be present either in the local file header, the zip64 extended field,
-  // or in the data descriptor footer.
-  uint64_t uncompressed_length{0};
-
-  explicit ZipEntry64() = default;
-  explicit ZipEntry64(const ZipEntry& zip_entry) : ZipEntryCommon(zip_entry) {
-    compressed_length = zip_entry.compressed_length;
-    uncompressed_length = zip_entry.uncompressed_length;
-  }
-};
-
-struct ZipArchive;
-typedef ZipArchive* ZipArchiveHandle;
-
-/*
- * Open a Zip archive, and sets handle to the value of the opaque
- * handle for the file. This handle must be released by calling
- * CloseArchive with this handle.
- *
- * Returns 0 on success, and negative values on failure.
- */
-int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle);
-
-/*
- * Like OpenArchive, but takes a file descriptor open for reading
- * at the start of the file.  The descriptor must be mappable (this does
- * not allow access to a stream).
- *
- * Sets handle to the value of the opaque handle for this file descriptor.
- * This handle must be released by calling CloseArchive with this handle.
- *
- * If assume_ownership parameter is 'true' calling CloseArchive will close
- * the file.
- *
- * This function maps and scans the central directory and builds a table
- * of entries for future lookups.
- *
- * "debugFileName" will appear in error messages, but is not otherwise used.
- *
- * Returns 0 on success, and negative values on failure.
- */
-int32_t OpenArchiveFd(const int fd, const char* debugFileName, ZipArchiveHandle* handle,
-                      bool assume_ownership = true);
-
-int32_t OpenArchiveFdRange(const int fd, const char* debugFileName, ZipArchiveHandle* handle,
-                           off64_t length, off64_t offset, bool assume_ownership = true);
-
-int32_t OpenArchiveFromMemory(const void* address, size_t length, const char* debugFileName,
-                              ZipArchiveHandle* handle);
-/*
- * Close archive, releasing resources associated with it. This will
- * unmap the central directory of the zipfile and free all internal
- * data structures associated with the file. It is an error to use
- * this handle for any further operations without an intervening
- * call to one of the OpenArchive variants.
- */
-void CloseArchive(ZipArchiveHandle archive);
-
-/** See GetArchiveInfo(). */
-struct ZipArchiveInfo {
-  /** The size in bytes of the archive itself. Used by zipinfo. */
-  off64_t archive_size;
-  /** The number of entries in the archive. */
-  uint64_t entry_count;
-};
-
-/**
- * Returns information about the given archive.
- */
-ZipArchiveInfo GetArchiveInfo(ZipArchiveHandle archive);
-
-/*
- * Find an entry in the Zip archive, by name. |data| must be non-null.
- *
- * Returns 0 if an entry is found, and populates |data| with information
- * about this entry. Returns negative values otherwise.
- *
- * It's important to note that |data->crc32|, |data->compLen| and
- * |data->uncompLen| might be set to values from the central directory
- * if this file entry contains a data descriptor footer. To verify crc32s
- * and length, a call to VerifyCrcAndLengths must be made after entry data
- * has been processed.
- *
- * On non-Windows platforms this method does not modify internal state and
- * can be called concurrently.
- */
-int32_t FindEntry(const ZipArchiveHandle archive, const std::string_view entryName,
-                  ZipEntry64* data);
-
-/*
- * Start iterating over all entries of a zip file. The order of iteration
- * is not guaranteed to be the same as the order of elements
- * in the central directory but is stable for a given zip file. |cookie| will
- * contain the value of an opaque cookie which can be used to make one or more
- * calls to Next. All calls to StartIteration must be matched by a call to
- * EndIteration to free any allocated memory.
- *
- * This method also accepts optional prefix and suffix to restrict iteration to
- * entry names that start with |optional_prefix| or end with |optional_suffix|.
- *
- * Returns 0 on success and negative values on failure.
- */
-int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
-                       const std::string_view optional_prefix = "",
-                       const std::string_view optional_suffix = "");
-
-/*
- * Start iterating over all entries of a zip file. Use the matcher functor to
- * restrict iteration to entry names that make the functor return true.
- *
- * Returns 0 on success and negative values on failure.
- */
-int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
-                       std::function<bool(std::string_view entry_name)> matcher);
-
-/*
- * Advance to the next element in the zipfile in iteration order.
- *
- * Returns 0 on success, -1 if there are no more elements in this
- * archive and lower negative values on failure.
- */
-int32_t Next(void* cookie, ZipEntry64* data, std::string_view* name);
-int32_t Next(void* cookie, ZipEntry64* data, std::string* name);
-
-/*
- * End iteration over all entries of a zip file and frees the memory allocated
- * in StartIteration.
- */
-void EndIteration(void* cookie);
-
-/*
- * Uncompress and write an entry to an open file identified by |fd|.
- * |entry->uncompressed_length| bytes will be written to the file at
- * its current offset, and the file will be truncated at the end of
- * the uncompressed data (no truncation if |fd| references a block
- * device).
- *
- * Returns 0 on success and negative values on failure.
- */
-int32_t ExtractEntryToFile(ZipArchiveHandle archive, const ZipEntry64* entry, int fd);
-
-/**
- * Uncompress a given zip entry to the memory region at |begin| and of
- * size |size|. This size is expected to be the same as the *declared*
- * uncompressed length of the zip entry. It is an error if the *actual*
- * number of uncompressed bytes differs from this number.
- *
- * Returns 0 on success and negative values on failure.
- */
-int32_t ExtractToMemory(ZipArchiveHandle archive, const ZipEntry64* entry, uint8_t* begin,
-                        size_t size);
-
-int GetFileDescriptor(const ZipArchiveHandle archive);
-
-/**
- * Returns the offset of the zip archive in the backing file descriptor, or 0 if the zip archive is
- * not backed by a file descriptor.
- */
-off64_t GetFileDescriptorOffset(const ZipArchiveHandle archive);
-
-const char* ErrorCodeString(int32_t error_code);
-
-// Many users of libziparchive assume the entry size to be 32 bits long. So we keep these
-// interfaces that use 32 bit ZipEntry to make old code work. TODO(xunchang) Remove the 32 bit
-// wrapper functions once we switch all users to recognize ZipEntry64.
-int32_t FindEntry(const ZipArchiveHandle archive, const std::string_view entryName, ZipEntry* data);
-int32_t Next(void* cookie, ZipEntry* data, std::string* name);
-int32_t Next(void* cookie, ZipEntry* data, std::string_view* name);
-int32_t ExtractEntryToFile(ZipArchiveHandle archive, const ZipEntry* entry, int fd);
-int32_t ExtractToMemory(ZipArchiveHandle archive, const ZipEntry* entry, uint8_t* begin,
-                        size_t size);
-
-#if !defined(_WIN32)
-typedef bool (*ProcessZipEntryFunction)(const uint8_t* buf, size_t buf_size, void* cookie);
-
-/*
- * Stream the uncompressed data through the supplied function,
- * passing cookie to it each time it gets called.
- */
-int32_t ProcessZipEntryContents(ZipArchiveHandle archive, const ZipEntry* entry,
-                                ProcessZipEntryFunction func, void* cookie);
-int32_t ProcessZipEntryContents(ZipArchiveHandle archive, const ZipEntry64* entry,
-                                ProcessZipEntryFunction func, void* cookie);
-#endif
-
-namespace zip_archive {
-
-class Writer {
- public:
-  virtual bool Append(uint8_t* buf, size_t buf_size) = 0;
-  virtual ~Writer();
-
- protected:
-  Writer() = default;
-
- private:
-  Writer(const Writer&) = delete;
-  void operator=(const Writer&) = delete;
-};
-
-class Reader {
- public:
-  virtual bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const = 0;
-  virtual ~Reader();
-
- protected:
-  Reader() = default;
-
- private:
-  Reader(const Reader&) = delete;
-  void operator=(const Reader&) = delete;
-};
-
-/*
- * Inflates the first |compressed_length| bytes of |reader| to a given |writer|.
- * |crc_out| is set to the CRC32 checksum of the uncompressed data.
- *
- * Returns 0 on success and negative values on failure, for example if |reader|
- * cannot supply the right amount of data, or if the number of bytes written to
- * data does not match |uncompressed_length|.
- *
- * If |crc_out| is not nullptr, it is set to the crc32 checksum of the
- * uncompressed data.
- */
-int32_t Inflate(const Reader& reader, const uint64_t compressed_length,
-                const uint64_t uncompressed_length, Writer* writer, uint64_t* crc_out);
-}  // namespace zip_archive
diff --git a/libziparchive/include/ziparchive/zip_archive_stream_entry.h b/libziparchive/include/ziparchive/zip_archive_stream_entry.h
deleted file mode 100644
index 8c6ca79..0000000
--- a/libziparchive/include/ziparchive/zip_archive_stream_entry.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-// Read-only stream access to Zip archives entries.
-#pragma once
-
-#include <ziparchive/zip_archive.h>
-
-#include <vector>
-
-#include "android-base/off64_t.h"
-
-class ZipArchiveStreamEntry {
- public:
-  virtual ~ZipArchiveStreamEntry() {}
-
-  virtual const std::vector<uint8_t>* Read() = 0;
-
-  virtual bool Verify() = 0;
-
-  static ZipArchiveStreamEntry* Create(ZipArchiveHandle handle, const ZipEntry& entry);
-  static ZipArchiveStreamEntry* CreateRaw(ZipArchiveHandle handle, const ZipEntry& entry);
-
- protected:
-  ZipArchiveStreamEntry(ZipArchiveHandle handle) : handle_(handle) {}
-
-  virtual bool Init(const ZipEntry& entry);
-
-  ZipArchiveHandle handle_;
-
-  off64_t offset_ = 0;
-  uint32_t crc32_ = 0u;
-};
diff --git a/libziparchive/include/ziparchive/zip_writer.h b/libziparchive/include/ziparchive/zip_writer.h
deleted file mode 100644
index d68683d..0000000
--- a/libziparchive/include/ziparchive/zip_writer.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2015 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 <cstdio>
-#include <ctime>
-
-#include <gtest/gtest_prod.h>
-#include <memory>
-#include <string>
-#include <string_view>
-#include <vector>
-
-#include "android-base/macros.h"
-#include "android-base/off64_t.h"
-
-struct z_stream_s;
-typedef struct z_stream_s z_stream;
-
-/**
- * Writes a Zip file via a stateful interface.
- *
- * Example:
- *
- *   FILE* file = fopen("path/to/zip.zip", "wb");
- *
- *   ZipWriter writer(file);
- *
- *   writer.StartEntry("test.txt", ZipWriter::kCompress | ZipWriter::kAlign);
- *   writer.WriteBytes(buffer, bufferLen);
- *   writer.WriteBytes(buffer2, bufferLen2);
- *   writer.FinishEntry();
- *
- *   writer.StartEntry("empty.txt", 0);
- *   writer.FinishEntry();
- *
- *   writer.Finish();
- *
- *   fclose(file);
- */
-class ZipWriter {
- public:
-  enum {
-    /**
-     * Flag to compress the zip entry using deflate.
-     */
-    kCompress = 0x01,
-
-    /**
-     * Flag to align the zip entry data on a 32bit boundary. Useful for
-     * mmapping the data at runtime.
-     */
-    kAlign32 = 0x02,
-  };
-
-  /**
-   * A struct representing a zip file entry.
-   */
-  struct FileEntry {
-    std::string path;
-    uint16_t compression_method;
-    uint32_t crc32;
-    uint32_t compressed_size;
-    uint32_t uncompressed_size;
-    uint16_t last_mod_time;
-    uint16_t last_mod_date;
-    uint16_t padding_length;
-    off64_t local_file_header_offset;
-  };
-
-  static const char* ErrorCodeString(int32_t error_code);
-
-  /**
-   * Create a ZipWriter that will write into a FILE stream. The file should be opened with
-   * open mode of "wb" or "w+b". ZipWriter does not take ownership of the file stream. The
-   * caller is responsible for closing the file.
-   */
-  explicit ZipWriter(FILE* f);
-
-  // Move constructor.
-  ZipWriter(ZipWriter&& zipWriter) noexcept;
-
-  // Move assignment.
-  ZipWriter& operator=(ZipWriter&& zipWriter) noexcept;
-
-  /**
-   * Starts a new zip entry with the given path and flags.
-   * Flags can be a bitwise OR of ZipWriter::kCompress and ZipWriter::kAlign.
-   * Subsequent calls to WriteBytes(const void*, size_t) will add data to this entry.
-   * Returns 0 on success, and an error value < 0 on failure.
-   */
-  int32_t StartEntry(std::string_view path, size_t flags);
-
-  /**
-   * Starts a new zip entry with the given path and flags, where the
-   * entry will be aligned to the given alignment.
-   * Flags can only be ZipWriter::kCompress. Using the flag ZipWriter::kAlign32
-   * will result in an error.
-   * Subsequent calls to WriteBytes(const void*, size_t) will add data to this entry.
-   * Returns 0 on success, and an error value < 0 on failure.
-   */
-  int32_t StartAlignedEntry(std::string_view path, size_t flags, uint32_t alignment);
-
-  /**
-   * Same as StartEntry(const char*, size_t), but sets a last modified time for the entry.
-   */
-  int32_t StartEntryWithTime(std::string_view path, size_t flags, time_t time);
-
-  /**
-   * Same as StartAlignedEntry(const char*, size_t), but sets a last modified time for the entry.
-   */
-  int32_t StartAlignedEntryWithTime(std::string_view path, size_t flags, time_t time, uint32_t alignment);
-
-  /**
-   * Writes bytes to the zip file for the previously started zip entry.
-   * Returns 0 on success, and an error value < 0 on failure.
-   */
-  int32_t WriteBytes(const void* data, size_t len);
-
-  /**
-   * Finish a zip entry started with StartEntry(const char*, size_t) or
-   * StartEntryWithTime(const char*, size_t, time_t). This must be called before
-   * any new zip entries are started, or before Finish() is called.
-   * Returns 0 on success, and an error value < 0 on failure.
-   */
-  int32_t FinishEntry();
-
-  /**
-   * Discards the last-written entry. Can only be called after an entry has been written using
-   * FinishEntry().
-   * Returns 0 on success, and an error value < 0 on failure.
-   */
-  int32_t DiscardLastEntry();
-
-  /**
-   * Sets `out_entry` to the last entry written after a call to FinishEntry().
-   * Returns 0 on success, and an error value < 0 if no entries have been written.
-   */
-  int32_t GetLastEntry(FileEntry* out_entry);
-
-  /**
-   * Writes the Central Directory Headers and flushes the zip file stream.
-   * Returns 0 on success, and an error value < 0 on failure.
-   */
-  int32_t Finish();
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ZipWriter);
-
-  int32_t HandleError(int32_t error_code);
-  int32_t PrepareDeflate();
-  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,
-    kWritingEntry,
-    kDone,
-    kError,
-  };
-
-  FILE* file_;
-  bool seekable_;
-  off64_t current_offset_;
-  State state_;
-  std::vector<FileEntry> files_;
-  FileEntry current_file_entry_;
-
-  std::unique_ptr<z_stream, void (*)(z_stream*)> z_stream_;
-  std::vector<uint8_t> buffer_;
-
-  FRIEND_TEST(zipwriter, WriteToUnseekableFile);
-};
diff --git a/libziparchive/libziparchive_fuzzer.cpp b/libziparchive/libziparchive_fuzzer.cpp
deleted file mode 100644
index 75e7939..0000000
--- a/libziparchive/libziparchive_fuzzer.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <ziparchive/zip_archive.h>
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  ZipArchiveHandle handle = nullptr;
-  OpenArchiveFromMemory(data, size, "fuzz", &handle);
-  CloseArchive(handle);
-  return 0;
-}
diff --git a/libziparchive/run-ziptool-tests-on-android.sh b/libziparchive/run-ziptool-tests-on-android.sh
deleted file mode 100755
index 3c23d43..0000000
--- a/libziparchive/run-ziptool-tests-on-android.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-
-# Copy the tests across.
-adb shell rm -rf /data/local/tmp/ziptool-tests/
-adb shell mkdir /data/local/tmp/ziptool-tests/
-adb push cli-tests/ /data/local/tmp/ziptool-tests/
-#adb push cli-test /data/local/tmp/ziptool-tests/
-
-if tty -s; then
-  dash_t="-t"
-else
-  dash_t=""
-fi
-
-exec adb shell $dash_t cli-test /data/local/tmp/ziptool-tests/cli-tests/*.test
diff --git a/libziparchive/test_ziparchive_large.py b/libziparchive/test_ziparchive_large.py
deleted file mode 100644
index 46d02aa..0000000
--- a/libziparchive/test_ziparchive_large.py
+++ /dev/null
@@ -1,147 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2020 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.
-#
-
-"""Unittests for parsing files in zip64 format"""
-
-import os
-import subprocess
-import tempfile
-import unittest
-import zipfile
-import time
-
-class Zip64Test(unittest.TestCase):
-  @staticmethod
-  def _WriteFile(path, size_in_kib):
-    contents = os.path.basename(path)[0] * 1024
-    with open(path, 'w') as f:
-      for it in range(0, size_in_kib):
-        f.write(contents)
-
-  @staticmethod
-  def _AddEntriesToZip(output_zip, entries_dict=None):
-    for name, size in entries_dict.items():
-      file_path = tempfile.NamedTemporaryFile()
-      Zip64Test._WriteFile(file_path.name, size)
-      output_zip.write(file_path.name, arcname = name)
-
-  def _getEntryNames(self, zip_name):
-    cmd = ['ziptool', 'zipinfo', '-1', zip_name]
-    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-    output, _ = proc.communicate()
-    self.assertEquals(0, proc.returncode)
-    self.assertNotEqual(None, output)
-    return output.split()
-
-  def _ExtractEntries(self, zip_name):
-    temp_dir = tempfile.mkdtemp()
-    cmd = ['ziptool', 'unzip', '-d', temp_dir, zip_name]
-    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-    proc.communicate()
-    self.assertEquals(0, proc.returncode)
-
-  def test_entriesSmallerThan2G(self):
-    zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
-    # Add a few entries with each of them smaller than 2GiB. But the entire zip file is larger
-    # than 4GiB in size.
-    with zipfile.ZipFile(zip_path, 'w', allowZip64=True) as output_zip:
-      entry_dict = {'a.txt': 1025 * 1024, 'b.txt': 1025 * 1024, 'c.txt': 1025 * 1024,
-                    'd.txt': 1025 * 1024, 'e.txt': 1024}
-      self._AddEntriesToZip(output_zip, entry_dict)
-
-    read_names = self._getEntryNames(zip_path.name)
-    self.assertEquals(sorted(entry_dict.keys()), sorted(read_names))
-    self._ExtractEntries(zip_path.name)
-
-
-  def test_largeNumberOfEntries(self):
-    zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
-    entry_dict = {}
-    # Add 100k entries (more than 65535|UINT16_MAX).
-    for num in range(0, 100 * 1024):
-      entry_dict[str(num)] = 50
-
-    with zipfile.ZipFile(zip_path, 'w', allowZip64=True) as output_zip:
-      self._AddEntriesToZip(output_zip, entry_dict)
-
-    read_names = self._getEntryNames(zip_path.name)
-    self.assertEquals(sorted(entry_dict.keys()), sorted(read_names))
-    self._ExtractEntries(zip_path.name)
-
-
-  def test_largeCompressedEntriesSmallerThan4G(self):
-    zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
-    with zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_DEFLATED,
-                         allowZip64=True) as output_zip:
-      # Add entries close to 4GiB in size. Somehow the python library will put the (un)compressed
-      # sizes in the extra field. Test if our ziptool should be able to parse it.
-      entry_dict = {'e.txt': 4095 * 1024, 'f.txt': 4095 * 1024}
-      self._AddEntriesToZip(output_zip, entry_dict)
-
-    read_names = self._getEntryNames(zip_path.name)
-    self.assertEquals(sorted(entry_dict.keys()), sorted(read_names))
-    self._ExtractEntries(zip_path.name)
-
-
-  def test_forceDataDescriptor(self):
-    file_path = tempfile.NamedTemporaryFile(suffix='.txt')
-    self._WriteFile(file_path.name, 5000 * 1024)
-
-    zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
-    with zipfile.ZipFile(zip_path, 'w', allowZip64=True) as output_zip:
-      pass
-    # The fd option force writes a data descriptor
-    cmd = ['zip', '-fd', zip_path.name, file_path.name]
-    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-    proc.communicate()
-    read_names = self._getEntryNames(zip_path.name)
-    self.assertEquals([file_path.name[1:]], read_names)
-    self._ExtractEntries(zip_path.name)
-
-
-  def test_largeUncompressedEntriesLargerThan4G(self):
-    zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
-    with zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_STORED,
-                         allowZip64=True) as output_zip:
-      # Add entries close to 4GiB in size. Somehow the python library will put the (un)compressed
-      # sizes in the extra field. Test if our ziptool should be able to parse it.
-      entry_dict = {'g.txt': 5000 * 1024, 'h.txt': 6000 * 1024}
-      self._AddEntriesToZip(output_zip, entry_dict)
-
-    read_names = self._getEntryNames(zip_path.name)
-    self.assertEquals(sorted(entry_dict.keys()), sorted(read_names))
-    self._ExtractEntries(zip_path.name)
-
-
-  def test_largeCompressedEntriesLargerThan4G(self):
-    zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
-    with zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_DEFLATED,
-                         allowZip64=True) as output_zip:
-      # Add entries close to 4GiB in size. Somehow the python library will put the (un)compressed
-      # sizes in the extra field. Test if our ziptool should be able to parse it.
-      entry_dict = {'i.txt': 4096 * 1024, 'j.txt': 7000 * 1024}
-      self._AddEntriesToZip(output_zip, entry_dict)
-
-    read_names = self._getEntryNames(zip_path.name)
-    self.assertEquals(sorted(entry_dict.keys()), sorted(read_names))
-    self._ExtractEntries(zip_path.name)
-
-
-if __name__ == '__main__':
-  testsuite = unittest.TestLoader().discover(
-      os.path.dirname(os.path.realpath(__file__)))
-  unittest.TextTestRunner(verbosity=2).run(testsuite)
diff --git a/libziparchive/testdata/bad_crc.zip b/libziparchive/testdata/bad_crc.zip
deleted file mode 100644
index e12ba07..0000000
--- a/libziparchive/testdata/bad_crc.zip
+++ /dev/null
Binary files differ
diff --git a/libziparchive/testdata/bad_filename.zip b/libziparchive/testdata/bad_filename.zip
deleted file mode 100644
index 294eaf5..0000000
--- a/libziparchive/testdata/bad_filename.zip
+++ /dev/null
Binary files differ
diff --git a/libziparchive/testdata/crash.apk b/libziparchive/testdata/crash.apk
deleted file mode 100644
index d6dd52d..0000000
--- a/libziparchive/testdata/crash.apk
+++ /dev/null
Binary files differ
diff --git a/libziparchive/testdata/declaredlength.zip b/libziparchive/testdata/declaredlength.zip
deleted file mode 100644
index 773380c..0000000
--- a/libziparchive/testdata/declaredlength.zip
+++ /dev/null
Binary files differ
diff --git a/libziparchive/testdata/dummy-update.zip b/libziparchive/testdata/dummy-update.zip
deleted file mode 100644
index 6976bf1..0000000
--- a/libziparchive/testdata/dummy-update.zip
+++ /dev/null
Binary files differ
diff --git a/libziparchive/testdata/empty.zip b/libziparchive/testdata/empty.zip
deleted file mode 100644
index 15cb0ec..0000000
--- a/libziparchive/testdata/empty.zip
+++ /dev/null
Binary files differ
diff --git a/libziparchive/testdata/large.zip b/libziparchive/testdata/large.zip
deleted file mode 100644
index 49659c8..0000000
--- a/libziparchive/testdata/large.zip
+++ /dev/null
Binary files differ
diff --git a/libziparchive/testdata/valid.zip b/libziparchive/testdata/valid.zip
deleted file mode 100644
index 9e7cb78..0000000
--- a/libziparchive/testdata/valid.zip
+++ /dev/null
Binary files differ
diff --git a/libziparchive/testdata/zero-size-cd.zip b/libziparchive/testdata/zero-size-cd.zip
deleted file mode 100644
index b6c8cbe..0000000
--- a/libziparchive/testdata/zero-size-cd.zip
+++ /dev/null
Binary files differ
diff --git a/libziparchive/testdata/zip64.zip b/libziparchive/testdata/zip64.zip
deleted file mode 100644
index 3f25a4c..0000000
--- a/libziparchive/testdata/zip64.zip
+++ /dev/null
Binary files differ
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
deleted file mode 100644
index 014f881..0000000
--- a/libziparchive/zip_archive.cc
+++ /dev/null
@@ -1,1586 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * 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.
- */
-
-/*
- * Read-only access to Zip archives, with minimal heap allocation.
- */
-
-#define LOG_TAG "ziparchive"
-
-#include "ziparchive/zip_archive.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <memory>
-#include <optional>
-#include <vector>
-
-#if defined(__APPLE__)
-#define lseek64 lseek
-#endif
-
-#if defined(__BIONIC__)
-#include <android/fdsan.h>
-#endif
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/macros.h>  // TEMP_FAILURE_RETRY may or may not be in unistd
-#include <android-base/mapped_file.h>
-#include <android-base/memory.h>
-#include <android-base/strings.h>
-#include <android-base/utf8.h>
-#include <log/log.h>
-#include "zlib.h"
-
-#include "entry_name_utils-inl.h"
-#include "zip_archive_common.h"
-#include "zip_archive_private.h"
-
-// Used to turn on crc checks - verify that the content CRC matches the values
-// specified in the local file header and the central directory.
-static constexpr bool kCrcChecksEnabled = false;
-
-// The maximum number of bytes to scan backwards for the EOCD start.
-static const uint32_t kMaxEOCDSearch = kMaxCommentLen + sizeof(EocdRecord);
-
-// Set a reasonable cap (256 GiB) for the zip file size. So the data is always valid when
-// we parse the fields in cd or local headers as 64 bits signed integers.
-static constexpr uint64_t kMaxFileLength = 256 * static_cast<uint64_t>(1u << 30u);
-
-/*
- * A Read-only Zip archive.
- *
- * We want "open" and "find entry by name" to be fast operations, and
- * we want to use as little memory as possible.  We memory-map the zip
- * central directory, and load a hash table with pointers to the filenames
- * (which aren't null-terminated).  The other fields are at a fixed offset
- * from the filename, so we don't need to extract those (but we do need
- * to byte-read and endian-swap them every time we want them).
- *
- * It's possible that somebody has handed us a massive (~1GB) zip archive,
- * so we can't expect to mmap the entire file.
- *
- * To speed comparisons when doing a lookup by name, we could make the mapping
- * "private" (copy-on-write) and null-terminate the filenames after verifying
- * the record structure.  However, this requires a private mapping of
- * every page that the Central Directory touches.  Easier to tuck a copy
- * of the string length into the hash table entry.
- */
-
-#if defined(__BIONIC__)
-uint64_t GetOwnerTag(const ZipArchive* archive) {
-  return android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_ZIPARCHIVE,
-                                        reinterpret_cast<uint64_t>(archive));
-}
-#endif
-
-ZipArchive::ZipArchive(MappedZipFile&& map, bool assume_ownership)
-    : mapped_zip(map),
-      close_file(assume_ownership),
-      directory_offset(0),
-      central_directory(),
-      directory_map(),
-      num_entries(0) {
-#if defined(__BIONIC__)
-  if (assume_ownership) {
-    CHECK(mapped_zip.HasFd());
-    android_fdsan_exchange_owner_tag(mapped_zip.GetFileDescriptor(), 0, GetOwnerTag(this));
-  }
-#endif
-}
-
-ZipArchive::ZipArchive(const void* address, size_t length)
-    : mapped_zip(address, length),
-      close_file(false),
-      directory_offset(0),
-      central_directory(),
-      directory_map(),
-      num_entries(0) {}
-
-ZipArchive::~ZipArchive() {
-  if (close_file && mapped_zip.GetFileDescriptor() >= 0) {
-#if defined(__BIONIC__)
-    android_fdsan_close_with_tag(mapped_zip.GetFileDescriptor(), GetOwnerTag(this));
-#else
-    close(mapped_zip.GetFileDescriptor());
-#endif
-  }
-}
-
-struct CentralDirectoryInfo {
-  uint64_t num_records;
-  // The size of the central directory (in bytes).
-  uint64_t cd_size;
-  // The offset of the start of the central directory, relative
-  // to the start of the file.
-  uint64_t cd_start_offset;
-};
-
-// Reads |T| at |readPtr| and increments |readPtr|. Returns std::nullopt if the boundary check
-// fails.
-template <typename T>
-static std::optional<T> TryConsumeUnaligned(uint8_t** readPtr, const uint8_t* bufStart,
-                                            size_t bufSize) {
-  if (bufSize < sizeof(T) || *readPtr - bufStart > bufSize - sizeof(T)) {
-    ALOGW("Zip: %zu byte read exceeds the boundary of allocated buf, offset %zu, bufSize %zu",
-          sizeof(T), *readPtr - bufStart, bufSize);
-    return std::nullopt;
-  }
-  return ConsumeUnaligned<T>(readPtr);
-}
-
-static ZipError FindCentralDirectoryInfoForZip64(const char* debugFileName, ZipArchive* archive,
-                                                 off64_t eocdOffset, CentralDirectoryInfo* cdInfo) {
-  if (eocdOffset <= sizeof(Zip64EocdLocator)) {
-    ALOGW("Zip: %s: Not enough space for zip64 eocd locator", debugFileName);
-    return kInvalidFile;
-  }
-  // We expect to find the zip64 eocd locator immediately before the zip eocd.
-  const int64_t locatorOffset = eocdOffset - sizeof(Zip64EocdLocator);
-  Zip64EocdLocator zip64EocdLocator{};
-  if (!archive->mapped_zip.ReadAtOffset(reinterpret_cast<uint8_t*>((&zip64EocdLocator)),
-                                        sizeof(Zip64EocdLocator), locatorOffset)) {
-    ALOGW("Zip: %s: Read %zu from offset %" PRId64 " failed %s", debugFileName,
-          sizeof(Zip64EocdLocator), locatorOffset, debugFileName);
-    return kIoError;
-  }
-
-  if (zip64EocdLocator.locator_signature != Zip64EocdLocator::kSignature) {
-    ALOGW("Zip: %s: Zip64 eocd locator signature not found at offset %" PRId64, debugFileName,
-          locatorOffset);
-    return kInvalidFile;
-  }
-
-  const int64_t zip64EocdOffset = zip64EocdLocator.zip64_eocd_offset;
-  if (locatorOffset <= sizeof(Zip64EocdRecord) ||
-      zip64EocdOffset > locatorOffset - sizeof(Zip64EocdRecord)) {
-    ALOGW("Zip: %s: Bad zip64 eocd offset %" PRId64 ", eocd locator offset %" PRId64, debugFileName,
-          zip64EocdOffset, locatorOffset);
-    return kInvalidOffset;
-  }
-
-  Zip64EocdRecord zip64EocdRecord{};
-  if (!archive->mapped_zip.ReadAtOffset(reinterpret_cast<uint8_t*>(&zip64EocdRecord),
-                                        sizeof(Zip64EocdRecord), zip64EocdOffset)) {
-    ALOGW("Zip: %s: read %zu from offset %" PRId64 " failed %s", debugFileName,
-          sizeof(Zip64EocdLocator), zip64EocdOffset, debugFileName);
-    return kIoError;
-  }
-
-  if (zip64EocdRecord.record_signature != Zip64EocdRecord::kSignature) {
-    ALOGW("Zip: %s: Zip64 eocd record signature not found at offset %" PRId64, debugFileName,
-          zip64EocdOffset);
-    return kInvalidFile;
-  }
-
-  if (zip64EocdOffset <= zip64EocdRecord.cd_size ||
-      zip64EocdRecord.cd_start_offset > zip64EocdOffset - zip64EocdRecord.cd_size) {
-    ALOGW("Zip: %s: Bad offset for zip64 central directory. cd offset %" PRIu64 ", cd size %" PRIu64
-          ", zip64 eocd offset %" PRIu64,
-          debugFileName, zip64EocdRecord.cd_start_offset, zip64EocdRecord.cd_size, zip64EocdOffset);
-    return kInvalidOffset;
-  }
-
-  *cdInfo = {.num_records = zip64EocdRecord.num_records,
-             .cd_size = zip64EocdRecord.cd_size,
-             .cd_start_offset = zip64EocdRecord.cd_start_offset};
-
-  return kSuccess;
-}
-
-static ZipError FindCentralDirectoryInfo(const char* debug_file_name, ZipArchive* archive,
-                                         off64_t file_length, uint32_t read_amount,
-                                         CentralDirectoryInfo* cdInfo) {
-  std::vector<uint8_t> scan_buffer(read_amount);
-  const off64_t search_start = file_length - read_amount;
-
-  if (!archive->mapped_zip.ReadAtOffset(scan_buffer.data(), read_amount, search_start)) {
-    ALOGE("Zip: read %" PRId64 " from offset %" PRId64 " failed", static_cast<int64_t>(read_amount),
-          static_cast<int64_t>(search_start));
-    return kIoError;
-  }
-
-  /*
-   * Scan backward for the EOCD magic.  In an archive without a trailing
-   * comment, we'll find it on the first try.  (We may want to consider
-   * doing an initial minimal read; if we don't find it, retry with a
-   * second read as above.)
-   */
-  CHECK_LE(read_amount, std::numeric_limits<int32_t>::max());
-  int32_t i = read_amount - sizeof(EocdRecord);
-  for (; i >= 0; i--) {
-    if (scan_buffer[i] == 0x50) {
-      uint32_t* sig_addr = reinterpret_cast<uint32_t*>(&scan_buffer[i]);
-      if (android::base::get_unaligned<uint32_t>(sig_addr) == EocdRecord::kSignature) {
-        ALOGV("+++ Found EOCD at buf+%d", i);
-        break;
-      }
-    }
-  }
-  if (i < 0) {
-    ALOGD("Zip: EOCD not found, %s is not zip", debug_file_name);
-    return kInvalidFile;
-  }
-
-  const off64_t eocd_offset = search_start + i;
-  auto eocd = reinterpret_cast<const EocdRecord*>(scan_buffer.data() + i);
-  /*
-   * Verify that there's no trailing space at the end of the central directory
-   * and its comment.
-   */
-  const off64_t calculated_length = eocd_offset + sizeof(EocdRecord) + eocd->comment_length;
-  if (calculated_length != file_length) {
-    ALOGW("Zip: %" PRId64 " extraneous bytes at the end of the central directory",
-          static_cast<int64_t>(file_length - calculated_length));
-    return kInvalidFile;
-  }
-
-  // One of the field is 0xFFFFFFFF, look for the zip64 EOCD instead.
-  if (eocd->cd_size == UINT32_MAX || eocd->cd_start_offset == UINT32_MAX) {
-    ALOGV("Looking for the zip64 EOCD, cd_size: %" PRIu32 "cd_start_offset: %" PRId32,
-          eocd->cd_size, eocd->cd_start_offset);
-    return FindCentralDirectoryInfoForZip64(debug_file_name, archive, eocd_offset, cdInfo);
-  }
-
-  /*
-   * Grab the CD offset and size, and the number of entries in the
-   * archive and verify that they look reasonable.
-   */
-  if (static_cast<off64_t>(eocd->cd_start_offset) + eocd->cd_size > eocd_offset) {
-    ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
-          eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
-    return kInvalidOffset;
-  }
-
-  *cdInfo = {.num_records = eocd->num_records,
-             .cd_size = eocd->cd_size,
-             .cd_start_offset = eocd->cd_start_offset};
-  return kSuccess;
-}
-
-/*
- * Find the zip Central Directory and memory-map it.
- *
- * On success, returns kSuccess after populating fields from the EOCD area:
- *   directory_offset
- *   directory_ptr
- *   num_entries
- */
-static ZipError MapCentralDirectory(const char* debug_file_name, ZipArchive* archive) {
-  // Test file length. We use lseek64 to make sure the file is small enough to be a zip file.
-  off64_t file_length = archive->mapped_zip.GetFileLength();
-  if (file_length == -1) {
-    return kInvalidFile;
-  }
-
-  if (file_length > kMaxFileLength) {
-    ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length));
-    return kInvalidFile;
-  }
-
-  if (file_length < static_cast<off64_t>(sizeof(EocdRecord))) {
-    ALOGV("Zip: length %" PRId64 " is too small to be zip", static_cast<int64_t>(file_length));
-    return kInvalidFile;
-  }
-
-  /*
-   * Perform the traditional EOCD snipe hunt.
-   *
-   * We're searching for the End of Central Directory magic number,
-   * which appears at the start of the EOCD block.  It's followed by
-   * 18 bytes of EOCD stuff and up to 64KB of archive comment.  We
-   * need to read the last part of the file into a buffer, dig through
-   * it to find the magic number, parse some values out, and use those
-   * to determine the extent of the CD.
-   *
-   * We start by pulling in the last part of the file.
-   */
-  uint32_t read_amount = kMaxEOCDSearch;
-  if (file_length < read_amount) {
-    read_amount = static_cast<uint32_t>(file_length);
-  }
-
-  CentralDirectoryInfo cdInfo = {};
-  if (auto result =
-          FindCentralDirectoryInfo(debug_file_name, archive, file_length, read_amount, &cdInfo);
-      result != kSuccess) {
-    return result;
-  }
-
-  if (cdInfo.num_records == 0) {
-#if defined(__ANDROID__)
-    ALOGW("Zip: empty archive?");
-#endif
-    return kEmptyArchive;
-  }
-
-  if (cdInfo.cd_size >= SIZE_MAX) {
-    ALOGW("Zip: The size of central directory doesn't fit in range of size_t: %" PRIu64,
-          cdInfo.cd_size);
-    return kInvalidFile;
-  }
-
-  ALOGV("+++ num_entries=%" PRIu64 " dir_size=%" PRIu64 " dir_offset=%" PRIu64, cdInfo.num_records,
-        cdInfo.cd_size, cdInfo.cd_start_offset);
-
-  // It all looks good.  Create a mapping for the CD, and set the fields in archive.
-  if (!archive->InitializeCentralDirectory(static_cast<off64_t>(cdInfo.cd_start_offset),
-                                           static_cast<size_t>(cdInfo.cd_size))) {
-    return kMmapFailed;
-  }
-
-  archive->num_entries = cdInfo.num_records;
-  archive->directory_offset = cdInfo.cd_start_offset;
-
-  return kSuccess;
-}
-
-static ZipError ParseZip64ExtendedInfoInExtraField(
-    const uint8_t* extraFieldStart, uint16_t extraFieldLength, uint32_t zip32UncompressedSize,
-    uint32_t zip32CompressedSize, std::optional<uint32_t> zip32LocalFileHeaderOffset,
-    Zip64ExtendedInfo* zip64Info) {
-  if (extraFieldLength <= 4) {
-    ALOGW("Zip: Extra field isn't large enough to hold zip64 info, size %" PRIu16,
-          extraFieldLength);
-    return kInvalidFile;
-  }
-
-  // Each header MUST consist of:
-  // Header ID - 2 bytes
-  // Data Size - 2 bytes
-  uint16_t offset = 0;
-  while (offset < extraFieldLength - 4) {
-    auto readPtr = const_cast<uint8_t*>(extraFieldStart + offset);
-    auto headerId = ConsumeUnaligned<uint16_t>(&readPtr);
-    auto dataSize = ConsumeUnaligned<uint16_t>(&readPtr);
-
-    offset += 4;
-    if (dataSize > extraFieldLength - offset) {
-      ALOGW("Zip: Data size exceeds the boundary of extra field, data size %" PRIu16, dataSize);
-      return kInvalidOffset;
-    }
-
-    // Skip the other types of extensible data fields. Details in
-    // https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT section 4.5
-    if (headerId != Zip64ExtendedInfo::kHeaderId) {
-      offset += dataSize;
-      continue;
-    }
-
-    std::optional<uint64_t> uncompressedFileSize;
-    std::optional<uint64_t> compressedFileSize;
-    std::optional<uint64_t> localHeaderOffset;
-    if (zip32UncompressedSize == UINT32_MAX) {
-      uncompressedFileSize =
-          TryConsumeUnaligned<uint64_t>(&readPtr, extraFieldStart, extraFieldLength);
-      if (!uncompressedFileSize.has_value()) return kInvalidOffset;
-    }
-    if (zip32CompressedSize == UINT32_MAX) {
-      compressedFileSize =
-          TryConsumeUnaligned<uint64_t>(&readPtr, extraFieldStart, extraFieldLength);
-      if (!compressedFileSize.has_value()) return kInvalidOffset;
-    }
-    if (zip32LocalFileHeaderOffset == UINT32_MAX) {
-      localHeaderOffset =
-          TryConsumeUnaligned<uint64_t>(&readPtr, extraFieldStart, extraFieldLength);
-      if (!localHeaderOffset.has_value()) return kInvalidOffset;
-    }
-
-    // calculate how many bytes we read after the data size field.
-    size_t bytesRead = readPtr - (extraFieldStart + offset);
-    if (bytesRead == 0) {
-      ALOGW("Zip: Data size should not be 0 in zip64 extended field");
-      return kInvalidFile;
-    }
-
-    if (dataSize != bytesRead) {
-      auto localOffsetString = zip32LocalFileHeaderOffset.has_value()
-                                   ? std::to_string(zip32LocalFileHeaderOffset.value())
-                                   : "missing";
-      ALOGW("Zip: Invalid data size in zip64 extended field, expect %zu , get %" PRIu16
-            ", uncompressed size %" PRIu32 ", compressed size %" PRIu32 ", local header offset %s",
-            bytesRead, dataSize, zip32UncompressedSize, zip32CompressedSize,
-            localOffsetString.c_str());
-      return kInvalidFile;
-    }
-
-    zip64Info->uncompressed_file_size = uncompressedFileSize;
-    zip64Info->compressed_file_size = compressedFileSize;
-    zip64Info->local_header_offset = localHeaderOffset;
-    return kSuccess;
-  }
-
-  ALOGW("Zip: zip64 extended info isn't found in the extra field.");
-  return kInvalidFile;
-}
-
-/*
- * Parses the Zip archive's Central Directory.  Allocates and populates the
- * hash table.
- *
- * Returns 0 on success.
- */
-static ZipError ParseZipArchive(ZipArchive* archive) {
-  const uint8_t* const cd_ptr = archive->central_directory.GetBasePtr();
-  const size_t cd_length = archive->central_directory.GetMapLength();
-  const uint64_t num_entries = archive->num_entries;
-
-  if (num_entries <= UINT16_MAX) {
-    archive->cd_entry_map = CdEntryMapZip32::Create(static_cast<uint16_t>(num_entries));
-  } else {
-    archive->cd_entry_map = CdEntryMapZip64::Create();
-  }
-  if (archive->cd_entry_map == nullptr) {
-    return kAllocationFailed;
-  }
-
-  /*
-   * Walk through the central directory, adding entries to the hash
-   * table and verifying values.
-   */
-  const uint8_t* const cd_end = cd_ptr + cd_length;
-  const uint8_t* ptr = cd_ptr;
-  for (uint64_t i = 0; i < num_entries; i++) {
-    if (ptr > cd_end - sizeof(CentralDirectoryRecord)) {
-      ALOGW("Zip: ran off the end (item #%" PRIu64 ", %zu bytes of central directory)", i,
-            cd_length);
-#if defined(__ANDROID__)
-      android_errorWriteLog(0x534e4554, "36392138");
-#endif
-      return kInvalidFile;
-    }
-
-    auto cdr = reinterpret_cast<const CentralDirectoryRecord*>(ptr);
-    if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
-      ALOGW("Zip: missed a central dir sig (at %" PRIu64 ")", i);
-      return kInvalidFile;
-    }
-
-    const uint16_t file_name_length = cdr->file_name_length;
-    const uint16_t extra_length = cdr->extra_field_length;
-    const uint16_t comment_length = cdr->comment_length;
-    const uint8_t* file_name = ptr + sizeof(CentralDirectoryRecord);
-
-    if (file_name_length >= cd_length || file_name > cd_end - file_name_length) {
-      ALOGW("Zip: file name for entry %" PRIu64
-            " exceeds the central directory range, file_name_length: %" PRIu16 ", cd_length: %zu",
-            i, file_name_length, cd_length);
-      return kInvalidEntryName;
-    }
-
-    const uint8_t* extra_field = file_name + file_name_length;
-    if (extra_length >= cd_length || extra_field > cd_end - extra_length) {
-      ALOGW("Zip: extra field for entry %" PRIu64
-            " exceeds the central directory range, file_name_length: %" PRIu16 ", cd_length: %zu",
-            i, extra_length, cd_length);
-      return kInvalidFile;
-    }
-
-    off64_t local_header_offset = cdr->local_file_header_offset;
-    if (local_header_offset == UINT32_MAX) {
-      Zip64ExtendedInfo zip64_info{};
-      if (auto status = ParseZip64ExtendedInfoInExtraField(
-              extra_field, extra_length, cdr->uncompressed_size, cdr->compressed_size,
-              cdr->local_file_header_offset, &zip64_info);
-          status != kSuccess) {
-        return status;
-      }
-      CHECK(zip64_info.local_header_offset.has_value());
-      local_header_offset = zip64_info.local_header_offset.value();
-    }
-
-    if (local_header_offset >= archive->directory_offset) {
-      ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu64,
-            static_cast<int64_t>(local_header_offset), i);
-      return kInvalidFile;
-    }
-
-    // Check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters.
-    if (!IsValidEntryName(file_name, file_name_length)) {
-      ALOGW("Zip: invalid file name at entry %" PRIu64, i);
-      return kInvalidEntryName;
-    }
-
-    // Add the CDE filename to the hash table.
-    std::string_view entry_name{reinterpret_cast<const char*>(file_name), file_name_length};
-    if (auto add_result =
-            archive->cd_entry_map->AddToMap(entry_name, archive->central_directory.GetBasePtr());
-        add_result != 0) {
-      ALOGW("Zip: Error adding entry to hash table %d", add_result);
-      return add_result;
-    }
-
-    ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length;
-    if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) {
-      ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu64, ptr - cd_ptr, cd_length, i);
-      return kInvalidFile;
-    }
-  }
-
-  uint32_t lfh_start_bytes;
-  if (!archive->mapped_zip.ReadAtOffset(reinterpret_cast<uint8_t*>(&lfh_start_bytes),
-                                        sizeof(uint32_t), 0)) {
-    ALOGW("Zip: Unable to read header for entry at offset == 0.");
-    return kInvalidFile;
-  }
-
-  if (lfh_start_bytes != LocalFileHeader::kSignature) {
-    ALOGW("Zip: Entry at offset zero has invalid LFH signature %" PRIx32, lfh_start_bytes);
-#if defined(__ANDROID__)
-    android_errorWriteLog(0x534e4554, "64211847");
-#endif
-    return kInvalidFile;
-  }
-
-  ALOGV("+++ zip good scan %" PRIu64 " entries", num_entries);
-
-  return kSuccess;
-}
-
-static int32_t OpenArchiveInternal(ZipArchive* archive, const char* debug_file_name) {
-  int32_t result = MapCentralDirectory(debug_file_name, archive);
-  return result != kSuccess ? result : ParseZipArchive(archive);
-}
-
-int32_t OpenArchiveFd(int fd, const char* debug_file_name, ZipArchiveHandle* handle,
-                      bool assume_ownership) {
-  ZipArchive* archive = new ZipArchive(MappedZipFile(fd), assume_ownership);
-  *handle = archive;
-  return OpenArchiveInternal(archive, debug_file_name);
-}
-
-int32_t OpenArchiveFdRange(int fd, const char* debug_file_name, ZipArchiveHandle* handle,
-                           off64_t length, off64_t offset, bool assume_ownership) {
-  ZipArchive* archive = new ZipArchive(MappedZipFile(fd, length, offset), assume_ownership);
-  *handle = archive;
-
-  if (length < 0) {
-    ALOGW("Invalid zip length %" PRId64, length);
-    return kIoError;
-  }
-
-  if (offset < 0) {
-    ALOGW("Invalid zip offset %" PRId64, offset);
-    return kIoError;
-  }
-
-  return OpenArchiveInternal(archive, debug_file_name);
-}
-
-int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
-  const int fd = ::android::base::utf8::open(fileName, O_RDONLY | O_BINARY | O_CLOEXEC, 0);
-  ZipArchive* archive = new ZipArchive(MappedZipFile(fd), true);
-  *handle = archive;
-
-  if (fd < 0) {
-    ALOGW("Unable to open '%s': %s", fileName, strerror(errno));
-    return kIoError;
-  }
-
-  return OpenArchiveInternal(archive, fileName);
-}
-
-int32_t OpenArchiveFromMemory(const void* address, size_t length, const char* debug_file_name,
-                              ZipArchiveHandle* handle) {
-  ZipArchive* archive = new ZipArchive(address, length);
-  *handle = archive;
-  return OpenArchiveInternal(archive, debug_file_name);
-}
-
-ZipArchiveInfo GetArchiveInfo(ZipArchiveHandle archive) {
-  ZipArchiveInfo result;
-  result.archive_size = archive->mapped_zip.GetFileLength();
-  result.entry_count = archive->num_entries;
-  return result;
-}
-
-/*
- * Close a ZipArchive, closing the file and freeing the contents.
- */
-void CloseArchive(ZipArchiveHandle archive) {
-  ALOGV("Closing archive %p", archive);
-  delete archive;
-}
-
-static int32_t ValidateDataDescriptor(MappedZipFile& mapped_zip, const ZipEntry64* entry) {
-  // Maximum possible size for data descriptor: 2 * 4 + 2 * 8 = 24 bytes
-  // The zip format doesn't specify the size of data descriptor. But we won't read OOB here even
-  // if the descriptor isn't present. Because the size cd + eocd in the end of the zipfile is
-  // larger than 24 bytes. And if the descriptor contains invalid data, we'll abort due to
-  // kInconsistentInformation.
-  uint8_t ddBuf[24];
-  off64_t offset = entry->offset;
-  if (entry->method != kCompressStored) {
-    offset += entry->compressed_length;
-  } else {
-    offset += entry->uncompressed_length;
-  }
-
-  if (!mapped_zip.ReadAtOffset(ddBuf, sizeof(ddBuf), offset)) {
-    return kIoError;
-  }
-
-  const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf));
-  uint8_t* ddReadPtr = (ddSignature == DataDescriptor::kOptSignature) ? ddBuf + 4 : ddBuf;
-  DataDescriptor descriptor{};
-  descriptor.crc32 = ConsumeUnaligned<uint32_t>(&ddReadPtr);
-  if (entry->zip64_format_size) {
-    descriptor.compressed_size = ConsumeUnaligned<uint64_t>(&ddReadPtr);
-    descriptor.uncompressed_size = ConsumeUnaligned<uint64_t>(&ddReadPtr);
-  } else {
-    descriptor.compressed_size = ConsumeUnaligned<uint32_t>(&ddReadPtr);
-    descriptor.uncompressed_size = ConsumeUnaligned<uint32_t>(&ddReadPtr);
-  }
-
-  // Validate that the values in the data descriptor match those in the central
-  // directory.
-  if (entry->compressed_length != descriptor.compressed_size ||
-      entry->uncompressed_length != descriptor.uncompressed_size ||
-      entry->crc32 != descriptor.crc32) {
-    ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu64 ", %" PRIu64 ", %" PRIx32
-          "}, was {%" PRIu64 ", %" PRIu64 ", %" PRIx32 "}",
-          entry->compressed_length, entry->uncompressed_length, entry->crc32,
-          descriptor.compressed_size, descriptor.uncompressed_size, descriptor.crc32);
-    return kInconsistentInformation;
-  }
-
-  return 0;
-}
-
-static int32_t FindEntry(const ZipArchive* archive, std::string_view entryName,
-                         const uint64_t nameOffset, ZipEntry64* data) {
-  // Recover the start of the central directory entry from the filename
-  // pointer.  The filename is the first entry past the fixed-size data,
-  // so we can just subtract back from that.
-  const uint8_t* base_ptr = archive->central_directory.GetBasePtr();
-  const uint8_t* ptr = base_ptr + nameOffset;
-  ptr -= sizeof(CentralDirectoryRecord);
-
-  // This is the base of our mmapped region, we have to sanity check that
-  // the name that's in the hash table is a pointer to a location within
-  // this mapped region.
-  if (ptr < base_ptr || ptr > base_ptr + archive->central_directory.GetMapLength()) {
-    ALOGW("Zip: Invalid entry pointer");
-    return kInvalidOffset;
-  }
-
-  auto cdr = reinterpret_cast<const CentralDirectoryRecord*>(ptr);
-
-  // The offset of the start of the central directory in the zipfile.
-  // We keep this lying around so that we can sanity check all our lengths
-  // and our per-file structures.
-  const off64_t cd_offset = archive->directory_offset;
-
-  // Fill out the compression method, modification time, crc32
-  // and other interesting attributes from the central directory. These
-  // will later be compared against values from the local file header.
-  data->method = cdr->compression_method;
-  data->mod_time = cdr->last_mod_date << 16 | cdr->last_mod_time;
-  data->crc32 = cdr->crc32;
-  data->compressed_length = cdr->compressed_size;
-  data->uncompressed_length = cdr->uncompressed_size;
-
-  // Figure out the local header offset from the central directory. The
-  // actual file data will begin after the local header and the name /
-  // extra comments.
-  off64_t local_header_offset = cdr->local_file_header_offset;
-  // One of the info field is UINT32_MAX, try to parse the real value in the zip64 extended info in
-  // the extra field.
-  if (cdr->uncompressed_size == UINT32_MAX || cdr->compressed_size == UINT32_MAX ||
-      cdr->local_file_header_offset == UINT32_MAX) {
-    const uint8_t* extra_field = ptr + sizeof(CentralDirectoryRecord) + cdr->file_name_length;
-    Zip64ExtendedInfo zip64_info{};
-    if (auto status = ParseZip64ExtendedInfoInExtraField(
-            extra_field, cdr->extra_field_length, cdr->uncompressed_size, cdr->compressed_size,
-            cdr->local_file_header_offset, &zip64_info);
-        status != kSuccess) {
-      return status;
-    }
-
-    data->uncompressed_length = zip64_info.uncompressed_file_size.value_or(cdr->uncompressed_size);
-    data->compressed_length = zip64_info.compressed_file_size.value_or(cdr->compressed_size);
-    local_header_offset = zip64_info.local_header_offset.value_or(local_header_offset);
-    data->zip64_format_size =
-        cdr->uncompressed_size == UINT32_MAX || cdr->compressed_size == UINT32_MAX;
-  }
-
-  if (local_header_offset + static_cast<off64_t>(sizeof(LocalFileHeader)) >= cd_offset) {
-    ALOGW("Zip: bad local hdr offset in zip");
-    return kInvalidOffset;
-  }
-
-  uint8_t lfh_buf[sizeof(LocalFileHeader)];
-  if (!archive->mapped_zip.ReadAtOffset(lfh_buf, sizeof(lfh_buf), local_header_offset)) {
-    ALOGW("Zip: failed reading lfh name from offset %" PRId64,
-          static_cast<int64_t>(local_header_offset));
-    return kIoError;
-  }
-
-  auto lfh = reinterpret_cast<const LocalFileHeader*>(lfh_buf);
-  if (lfh->lfh_signature != LocalFileHeader::kSignature) {
-    ALOGW("Zip: didn't find signature at start of lfh, offset=%" PRId64,
-          static_cast<int64_t>(local_header_offset));
-    return kInvalidOffset;
-  }
-
-  // Check that the local file header name matches the declared name in the central directory.
-  CHECK_LE(entryName.size(), UINT16_MAX);
-  auto nameLen = static_cast<uint16_t>(entryName.size());
-  if (lfh->file_name_length != nameLen) {
-    ALOGW("Zip: lfh name length did not match central directory for %s: %" PRIu16 " %" PRIu16,
-          std::string(entryName).c_str(), lfh->file_name_length, nameLen);
-    return kInconsistentInformation;
-  }
-  const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader);
-  if (name_offset > cd_offset - lfh->file_name_length) {
-    ALOGW("Zip: lfh name has invalid declared length");
-    return kInvalidOffset;
-  }
-
-  std::vector<uint8_t> name_buf(nameLen);
-  if (!archive->mapped_zip.ReadAtOffset(name_buf.data(), nameLen, name_offset)) {
-    ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
-    return kIoError;
-  }
-  if (memcmp(entryName.data(), name_buf.data(), nameLen) != 0) {
-    ALOGW("Zip: lfh name did not match central directory");
-    return kInconsistentInformation;
-  }
-
-  uint64_t lfh_uncompressed_size = lfh->uncompressed_size;
-  uint64_t lfh_compressed_size = lfh->compressed_size;
-  if (lfh_uncompressed_size == UINT32_MAX || lfh_compressed_size == UINT32_MAX) {
-    if (lfh_uncompressed_size != UINT32_MAX || lfh_compressed_size != UINT32_MAX) {
-      ALOGW(
-          "Zip: The zip64 extended field in the local header MUST include BOTH original and "
-          "compressed file size fields.");
-      return kInvalidFile;
-    }
-
-    const off64_t lfh_extra_field_offset = name_offset + lfh->file_name_length;
-    const uint16_t lfh_extra_field_size = lfh->extra_field_length;
-    if (lfh_extra_field_offset > cd_offset - lfh_extra_field_size) {
-      ALOGW("Zip: extra field has a bad size for entry %s", std::string(entryName).c_str());
-      return kInvalidOffset;
-    }
-
-    std::vector<uint8_t> local_extra_field(lfh_extra_field_size);
-    if (!archive->mapped_zip.ReadAtOffset(local_extra_field.data(), lfh_extra_field_size,
-                                          lfh_extra_field_offset)) {
-      ALOGW("Zip: failed reading lfh extra field from offset %" PRId64, lfh_extra_field_offset);
-      return kIoError;
-    }
-
-    Zip64ExtendedInfo zip64_info{};
-    if (auto status = ParseZip64ExtendedInfoInExtraField(
-            local_extra_field.data(), lfh_extra_field_size, lfh->uncompressed_size,
-            lfh->compressed_size, std::nullopt, &zip64_info);
-        status != kSuccess) {
-      return status;
-    }
-
-    CHECK(zip64_info.uncompressed_file_size.has_value());
-    CHECK(zip64_info.compressed_file_size.has_value());
-    lfh_uncompressed_size = zip64_info.uncompressed_file_size.value();
-    lfh_compressed_size = zip64_info.compressed_file_size.value();
-  }
-
-  // Paranoia: Match the values specified in the local file header
-  // to those specified in the central directory.
-
-  // Warn if central directory and local file header don't agree on the use
-  // of a trailing Data Descriptor. The reference implementation is inconsistent
-  // and appears to use the LFH value during extraction (unzip) but the CD value
-  // while displayng information about archives (zipinfo). The spec remains
-  // silent on this inconsistency as well.
-  //
-  // For now, always use the version from the LFH but make sure that the values
-  // specified in the central directory match those in the data descriptor.
-  //
-  // NOTE: It's also worth noting that unzip *does* warn about inconsistencies in
-  // bit 11 (EFS: The language encoding flag, marking that filename and comment are
-  // encoded using UTF-8). This implementation does not check for the presence of
-  // that flag and always enforces that entry names are valid UTF-8.
-  if ((lfh->gpb_flags & kGPBDDFlagMask) != (cdr->gpb_flags & kGPBDDFlagMask)) {
-    ALOGW("Zip: gpb flag mismatch at bit 3. expected {%04" PRIx16 "}, was {%04" PRIx16 "}",
-          cdr->gpb_flags, lfh->gpb_flags);
-  }
-
-  // If there is no trailing data descriptor, verify that the central directory and local file
-  // header agree on the crc, compressed, and uncompressed sizes of the entry.
-  if ((lfh->gpb_flags & kGPBDDFlagMask) == 0) {
-    data->has_data_descriptor = 0;
-    if (data->compressed_length != lfh_compressed_size ||
-        data->uncompressed_length != lfh_uncompressed_size || data->crc32 != lfh->crc32) {
-      ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu64 ", %" PRIu64 ", %" PRIx32
-            "}, was {%" PRIu64 ", %" PRIu64 ", %" PRIx32 "}",
-            data->compressed_length, data->uncompressed_length, data->crc32, lfh_compressed_size,
-            lfh_uncompressed_size, lfh->crc32);
-      return kInconsistentInformation;
-    }
-  } else {
-    data->has_data_descriptor = 1;
-  }
-
-  // 4.4.2.1: the upper byte of `version_made_by` gives the source OS. Unix is 3.
-  data->version_made_by = cdr->version_made_by;
-  data->external_file_attributes = cdr->external_file_attributes;
-  if ((data->version_made_by >> 8) == 3) {
-    data->unix_mode = (cdr->external_file_attributes >> 16) & 0xffff;
-  } else {
-    data->unix_mode = 0777;
-  }
-
-  // 4.4.4: general purpose bit flags.
-  data->gpbf = lfh->gpb_flags;
-
-  // 4.4.14: the lowest bit of the internal file attributes field indicates text.
-  // Currently only needed to implement zipinfo.
-  data->is_text = (cdr->internal_file_attributes & 1);
-
-  const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader) +
-                              lfh->file_name_length + lfh->extra_field_length;
-  if (data_offset > cd_offset) {
-    ALOGW("Zip: bad data offset %" PRId64 " in zip", static_cast<int64_t>(data_offset));
-    return kInvalidOffset;
-  }
-
-  if (data->compressed_length > cd_offset - data_offset) {
-    ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu64 " > %" PRId64 ")",
-          static_cast<int64_t>(data_offset), data->compressed_length,
-          static_cast<int64_t>(cd_offset));
-    return kInvalidOffset;
-  }
-
-  if (data->method == kCompressStored && data->uncompressed_length > cd_offset - data_offset) {
-    ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu64 " > %" PRId64 ")",
-          static_cast<int64_t>(data_offset), data->uncompressed_length,
-          static_cast<int64_t>(cd_offset));
-    return kInvalidOffset;
-  }
-
-  data->offset = data_offset;
-  return 0;
-}
-
-struct IterationHandle {
-  ZipArchive* archive;
-
-  std::function<bool(std::string_view)> matcher;
-
-  uint32_t position = 0;
-
-  IterationHandle(ZipArchive* archive, std::function<bool(std::string_view)> in_matcher)
-      : archive(archive), matcher(std::move(in_matcher)) {}
-
-  bool Match(std::string_view entry_name) const { return matcher(entry_name); }
-};
-
-int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
-                       const std::string_view optional_prefix,
-                       const std::string_view optional_suffix) {
-  if (optional_prefix.size() > static_cast<size_t>(UINT16_MAX) ||
-      optional_suffix.size() > static_cast<size_t>(UINT16_MAX)) {
-    ALOGW("Zip: prefix/suffix too long");
-    return kInvalidEntryName;
-  }
-  auto matcher = [prefix = std::string(optional_prefix),
-                  suffix = std::string(optional_suffix)](std::string_view name) mutable {
-    return android::base::StartsWith(name, prefix) && android::base::EndsWith(name, suffix);
-  };
-  return StartIteration(archive, cookie_ptr, std::move(matcher));
-}
-
-int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
-                       std::function<bool(std::string_view)> matcher) {
-  if (archive == nullptr || archive->cd_entry_map == nullptr) {
-    ALOGW("Zip: Invalid ZipArchiveHandle");
-    return kInvalidHandle;
-  }
-
-  archive->cd_entry_map->ResetIteration();
-  *cookie_ptr = new IterationHandle(archive, matcher);
-  return 0;
-}
-
-void EndIteration(void* cookie) {
-  delete reinterpret_cast<IterationHandle*>(cookie);
-}
-
-int32_t ZipEntry::CopyFromZipEntry64(ZipEntry* dst, const ZipEntry64* src) {
-  if (src->compressed_length > UINT32_MAX || src->uncompressed_length > UINT32_MAX) {
-    ALOGW(
-        "Zip: the entry size is too large to fit into the 32 bits ZipEntry, uncompressed "
-        "length %" PRIu64 ", compressed length %" PRIu64,
-        src->uncompressed_length, src->compressed_length);
-    return kUnsupportedEntrySize;
-  }
-
-  *dst = *src;
-  dst->uncompressed_length = static_cast<uint32_t>(src->uncompressed_length);
-  dst->compressed_length = static_cast<uint32_t>(src->compressed_length);
-  return kSuccess;
-}
-
-int32_t FindEntry(const ZipArchiveHandle archive, const std::string_view entryName,
-                  ZipEntry* data) {
-  ZipEntry64 entry64;
-  if (auto status = FindEntry(archive, entryName, &entry64); status != kSuccess) {
-    return status;
-  }
-
-  return ZipEntry::CopyFromZipEntry64(data, &entry64);
-}
-
-int32_t FindEntry(const ZipArchiveHandle archive, const std::string_view entryName,
-                  ZipEntry64* data) {
-  if (entryName.empty() || entryName.size() > static_cast<size_t>(UINT16_MAX)) {
-    ALOGW("Zip: Invalid filename of length %zu", entryName.size());
-    return kInvalidEntryName;
-  }
-
-  const auto [result, offset] =
-      archive->cd_entry_map->GetCdEntryOffset(entryName, archive->central_directory.GetBasePtr());
-  if (result != 0) {
-    ALOGV("Zip: Could not find entry %.*s", static_cast<int>(entryName.size()), entryName.data());
-    return static_cast<int32_t>(result);  // kEntryNotFound is safe to truncate.
-  }
-  // We know there are at most hash_table_size entries, safe to truncate.
-  return FindEntry(archive, entryName, offset, data);
-}
-
-int32_t Next(void* cookie, ZipEntry* data, std::string* name) {
-  ZipEntry64 entry64;
-  if (auto status = Next(cookie, &entry64, name); status != kSuccess) {
-    return status;
-  }
-
-  return ZipEntry::CopyFromZipEntry64(data, &entry64);
-}
-
-int32_t Next(void* cookie, ZipEntry* data, std::string_view* name) {
-  ZipEntry64 entry64;
-  if (auto status = Next(cookie, &entry64, name); status != kSuccess) {
-    return status;
-  }
-
-  return ZipEntry::CopyFromZipEntry64(data, &entry64);
-}
-
-int32_t Next(void* cookie, ZipEntry64* data, std::string* name) {
-  std::string_view sv;
-  int32_t result = Next(cookie, data, &sv);
-  if (result == 0 && name) {
-    *name = std::string(sv);
-  }
-  return result;
-}
-
-int32_t Next(void* cookie, ZipEntry64* data, std::string_view* name) {
-  IterationHandle* handle = reinterpret_cast<IterationHandle*>(cookie);
-  if (handle == nullptr) {
-    ALOGW("Zip: Null ZipArchiveHandle");
-    return kInvalidHandle;
-  }
-
-  ZipArchive* archive = handle->archive;
-  if (archive == nullptr || archive->cd_entry_map == nullptr) {
-    ALOGW("Zip: Invalid ZipArchiveHandle");
-    return kInvalidHandle;
-  }
-
-  auto entry = archive->cd_entry_map->Next(archive->central_directory.GetBasePtr());
-  while (entry != std::pair<std::string_view, uint64_t>()) {
-    const auto [entry_name, offset] = entry;
-    if (handle->Match(entry_name)) {
-      const int error = FindEntry(archive, entry_name, offset, data);
-      if (!error && name) {
-        *name = entry_name;
-      }
-      return error;
-    }
-    entry = archive->cd_entry_map->Next(archive->central_directory.GetBasePtr());
-  }
-
-  archive->cd_entry_map->ResetIteration();
-  return kIterationEnd;
-}
-
-// A Writer that writes data to a fixed size memory region.
-// The size of the memory region must be equal to the total size of
-// the data appended to it.
-class MemoryWriter : public zip_archive::Writer {
- public:
-  static std::unique_ptr<MemoryWriter> Create(uint8_t* buf, size_t size, const ZipEntry64* entry) {
-    const uint64_t declared_length = entry->uncompressed_length;
-    if (declared_length > size) {
-      ALOGW("Zip: file size %" PRIu64 " is larger than the buffer size %zu.", declared_length,
-            size);
-      return nullptr;
-    }
-
-    return std::unique_ptr<MemoryWriter>(new MemoryWriter(buf, size));
-  }
-
-  virtual bool Append(uint8_t* buf, size_t buf_size) override {
-    if (size_ < buf_size || bytes_written_ > size_ - buf_size) {
-      ALOGW("Zip: Unexpected size %zu (declared) vs %zu (actual)", size_,
-            bytes_written_ + buf_size);
-      return false;
-    }
-
-    memcpy(buf_ + bytes_written_, buf, buf_size);
-    bytes_written_ += buf_size;
-    return true;
-  }
-
- private:
-  MemoryWriter(uint8_t* buf, size_t size) : Writer(), buf_(buf), size_(size), bytes_written_(0) {}
-
-  uint8_t* const buf_{nullptr};
-  const size_t size_;
-  size_t bytes_written_;
-};
-
-// A Writer that appends data to a file |fd| at its current position.
-// The file will be truncated to the end of the written data.
-class FileWriter : public zip_archive::Writer {
- public:
-  // Creates a FileWriter for |fd| and prepare to write |entry| to it,
-  // guaranteeing that the file descriptor is valid and that there's enough
-  // space on the volume to write out the entry completely and that the file
-  // is truncated to the correct length (no truncation if |fd| references a
-  // block device).
-  //
-  // Returns a valid FileWriter on success, |nullptr| if an error occurred.
-  static std::unique_ptr<FileWriter> Create(int fd, const ZipEntry64* entry) {
-    const uint64_t declared_length = entry->uncompressed_length;
-    const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
-    if (current_offset == -1) {
-      ALOGW("Zip: unable to seek to current location on fd %d: %s", fd, strerror(errno));
-      return nullptr;
-    }
-
-    if (declared_length > SIZE_MAX || declared_length > INT64_MAX) {
-      ALOGW("Zip: file size %" PRIu64 " is too large to extract.", declared_length);
-      return nullptr;
-    }
-
-#if defined(__linux__)
-    if (declared_length > 0) {
-      // Make sure we have enough space on the volume to extract the compressed
-      // entry. Note that the call to ftruncate below will change the file size but
-      // will not allocate space on disk and this call to fallocate will not
-      // change the file size.
-      // Note: fallocate is only supported by the following filesystems -
-      // btrfs, ext4, ocfs2, and xfs. Therefore fallocate might fail with
-      // EOPNOTSUPP error when issued in other filesystems.
-      // Hence, check for the return error code before concluding that the
-      // disk does not have enough space.
-      long result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
-      if (result == -1 && errno == ENOSPC) {
-        ALOGW("Zip: unable to allocate %" PRIu64 " bytes at offset %" PRId64 ": %s",
-              declared_length, static_cast<int64_t>(current_offset), strerror(errno));
-        return nullptr;
-      }
-    }
-#endif  // __linux__
-
-    struct stat sb;
-    if (fstat(fd, &sb) == -1) {
-      ALOGW("Zip: unable to fstat file: %s", strerror(errno));
-      return nullptr;
-    }
-
-    // Block device doesn't support ftruncate(2).
-    if (!S_ISBLK(sb.st_mode)) {
-      long result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
-      if (result == -1) {
-        ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
-              static_cast<int64_t>(declared_length + current_offset), strerror(errno));
-        return nullptr;
-      }
-    }
-
-    return std::unique_ptr<FileWriter>(new FileWriter(fd, declared_length));
-  }
-
-  FileWriter(FileWriter&& other) noexcept
-      : fd_(other.fd_),
-        declared_length_(other.declared_length_),
-        total_bytes_written_(other.total_bytes_written_) {
-    other.fd_ = -1;
-  }
-
-  virtual bool Append(uint8_t* buf, size_t buf_size) override {
-    if (declared_length_ < buf_size || total_bytes_written_ > declared_length_ - buf_size) {
-      ALOGW("Zip: Unexpected size %zu  (declared) vs %zu (actual)", declared_length_,
-            total_bytes_written_ + buf_size);
-      return false;
-    }
-
-    const bool result = android::base::WriteFully(fd_, buf, buf_size);
-    if (result) {
-      total_bytes_written_ += buf_size;
-    } else {
-      ALOGW("Zip: unable to write %zu bytes to file; %s", buf_size, strerror(errno));
-    }
-
-    return result;
-  }
-
- private:
-  explicit FileWriter(const int fd = -1, const uint64_t declared_length = 0)
-      : Writer(),
-        fd_(fd),
-        declared_length_(static_cast<size_t>(declared_length)),
-        total_bytes_written_(0) {
-    CHECK_LE(declared_length, SIZE_MAX);
-  }
-
-  int fd_;
-  const size_t declared_length_;
-  size_t total_bytes_written_;
-};
-
-class EntryReader : public zip_archive::Reader {
- public:
-  EntryReader(const MappedZipFile& zip_file, const ZipEntry64* entry)
-      : Reader(), zip_file_(zip_file), entry_(entry) {}
-
-  virtual bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const {
-    return zip_file_.ReadAtOffset(buf, len, entry_->offset + offset);
-  }
-
-  virtual ~EntryReader() {}
-
- private:
-  const MappedZipFile& zip_file_;
-  const ZipEntry64* entry_;
-};
-
-// This method is using libz macros with old-style-casts
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-static inline int zlib_inflateInit2(z_stream* stream, int window_bits) {
-  return inflateInit2(stream, window_bits);
-}
-#pragma GCC diagnostic pop
-
-namespace zip_archive {
-
-// Moved out of line to avoid -Wweak-vtables.
-Reader::~Reader() {}
-Writer::~Writer() {}
-
-int32_t Inflate(const Reader& reader, const uint64_t compressed_length,
-                const uint64_t uncompressed_length, Writer* writer, uint64_t* crc_out) {
-  const size_t kBufSize = 32768;
-  std::vector<uint8_t> read_buf(kBufSize);
-  std::vector<uint8_t> write_buf(kBufSize);
-  z_stream zstream;
-  int zerr;
-
-  /*
-   * Initialize the zlib stream struct.
-   */
-  memset(&zstream, 0, sizeof(zstream));
-  zstream.zalloc = Z_NULL;
-  zstream.zfree = Z_NULL;
-  zstream.opaque = Z_NULL;
-  zstream.next_in = NULL;
-  zstream.avail_in = 0;
-  zstream.next_out = &write_buf[0];
-  zstream.avail_out = kBufSize;
-  zstream.data_type = Z_UNKNOWN;
-
-  /*
-   * Use the undocumented "negative window bits" feature to tell zlib
-   * that there's no zlib header waiting for it.
-   */
-  zerr = zlib_inflateInit2(&zstream, -MAX_WBITS);
-  if (zerr != Z_OK) {
-    if (zerr == Z_VERSION_ERROR) {
-      ALOGE("Installed zlib is not compatible with linked version (%s)", ZLIB_VERSION);
-    } else {
-      ALOGW("Call to inflateInit2 failed (zerr=%d)", zerr);
-    }
-
-    return kZlibError;
-  }
-
-  auto zstream_deleter = [](z_stream* stream) {
-    inflateEnd(stream); /* free up any allocated structures */
-  };
-
-  std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter);
-
-  const bool compute_crc = (crc_out != nullptr);
-  uLong crc = 0;
-  uint64_t remaining_bytes = compressed_length;
-  uint64_t total_output = 0;
-  do {
-    /* read as much as we can */
-    if (zstream.avail_in == 0) {
-      const uint32_t read_size =
-          (remaining_bytes > kBufSize) ? kBufSize : static_cast<uint32_t>(remaining_bytes);
-      const off64_t offset = (compressed_length - remaining_bytes);
-      // Make sure to read at offset to ensure concurrent access to the fd.
-      if (!reader.ReadAtOffset(read_buf.data(), read_size, offset)) {
-        ALOGW("Zip: inflate read failed, getSize = %u: %s", read_size, strerror(errno));
-        return kIoError;
-      }
-
-      remaining_bytes -= read_size;
-
-      zstream.next_in = &read_buf[0];
-      zstream.avail_in = read_size;
-    }
-
-    /* uncompress the data */
-    zerr = inflate(&zstream, Z_NO_FLUSH);
-    if (zerr != Z_OK && zerr != Z_STREAM_END) {
-      ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)", zerr, zstream.next_in,
-            zstream.avail_in, zstream.next_out, zstream.avail_out);
-      return kZlibError;
-    }
-
-    /* write when we're full or when we're done */
-    if (zstream.avail_out == 0 || (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
-      const size_t write_size = zstream.next_out - &write_buf[0];
-      if (!writer->Append(&write_buf[0], write_size)) {
-        return kIoError;
-      } else if (compute_crc) {
-        DCHECK_LE(write_size, kBufSize);
-        crc = crc32(crc, &write_buf[0], static_cast<uint32_t>(write_size));
-      }
-
-      total_output += kBufSize - zstream.avail_out;
-      zstream.next_out = &write_buf[0];
-      zstream.avail_out = kBufSize;
-    }
-  } while (zerr == Z_OK);
-
-  CHECK_EQ(zerr, Z_STREAM_END); /* other errors should've been caught */
-
-  // NOTE: zstream.adler is always set to 0, because we're using the -MAX_WBITS
-  // "feature" of zlib to tell it there won't be a zlib file header. zlib
-  // doesn't bother calculating the checksum in that scenario. We just do
-  // it ourselves above because there are no additional gains to be made by
-  // having zlib calculate it for us, since they do it by calling crc32 in
-  // the same manner that we have above.
-  if (compute_crc) {
-    *crc_out = crc;
-  }
-  if (total_output != uncompressed_length || remaining_bytes != 0) {
-    ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu64 ")", zstream.total_out,
-          uncompressed_length);
-    return kInconsistentInformation;
-  }
-
-  return 0;
-}
-}  // namespace zip_archive
-
-static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry64* entry,
-                                    zip_archive::Writer* writer, uint64_t* crc_out) {
-  const EntryReader reader(mapped_zip, entry);
-
-  return zip_archive::Inflate(reader, entry->compressed_length, entry->uncompressed_length, writer,
-                              crc_out);
-}
-
-static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry64* entry,
-                                 zip_archive::Writer* writer, uint64_t* crc_out) {
-  static const uint32_t kBufSize = 32768;
-  std::vector<uint8_t> buf(kBufSize);
-
-  const uint64_t length = entry->uncompressed_length;
-  uint64_t count = 0;
-  uLong crc = 0;
-  while (count < length) {
-    uint64_t remaining = length - count;
-    off64_t offset = entry->offset + count;
-
-    // Safe conversion because kBufSize is narrow enough for a 32 bit signed value.
-    const uint32_t block_size =
-        (remaining > kBufSize) ? kBufSize : static_cast<uint32_t>(remaining);
-
-    // Make sure to read at offset to ensure concurrent access to the fd.
-    if (!mapped_zip.ReadAtOffset(buf.data(), block_size, offset)) {
-      ALOGW("CopyFileToFile: copy read failed, block_size = %u, offset = %" PRId64 ": %s",
-            block_size, static_cast<int64_t>(offset), strerror(errno));
-      return kIoError;
-    }
-
-    if (!writer->Append(&buf[0], block_size)) {
-      return kIoError;
-    }
-    if (crc_out) {
-      crc = crc32(crc, &buf[0], block_size);
-    }
-    count += block_size;
-  }
-
-  if (crc_out) {
-    *crc_out = crc;
-  }
-
-  return 0;
-}
-
-int32_t ExtractToWriter(ZipArchiveHandle handle, const ZipEntry64* entry,
-                        zip_archive::Writer* writer) {
-  const uint16_t method = entry->method;
-
-  // this should default to kUnknownCompressionMethod.
-  int32_t return_value = -1;
-  uint64_t crc = 0;
-  if (method == kCompressStored) {
-    return_value =
-        CopyEntryToWriter(handle->mapped_zip, entry, writer, kCrcChecksEnabled ? &crc : nullptr);
-  } else if (method == kCompressDeflated) {
-    return_value =
-        InflateEntryToWriter(handle->mapped_zip, entry, writer, kCrcChecksEnabled ? &crc : nullptr);
-  }
-
-  if (!return_value && entry->has_data_descriptor) {
-    return_value = ValidateDataDescriptor(handle->mapped_zip, entry);
-    if (return_value) {
-      return return_value;
-    }
-  }
-
-  // Validate that the CRC matches the calculated value.
-  if (kCrcChecksEnabled && (entry->crc32 != static_cast<uint32_t>(crc))) {
-    ALOGW("Zip: crc mismatch: expected %" PRIu32 ", was %" PRIu64, entry->crc32, crc);
-    return kInconsistentInformation;
-  }
-
-  return return_value;
-}
-
-int32_t ExtractToMemory(ZipArchiveHandle archive, const ZipEntry* entry, uint8_t* begin,
-                        size_t size) {
-  ZipEntry64 entry64(*entry);
-  return ExtractToMemory(archive, &entry64, begin, size);
-}
-
-int32_t ExtractToMemory(ZipArchiveHandle archive, const ZipEntry64* entry, uint8_t* begin,
-                        size_t size) {
-  auto writer = MemoryWriter::Create(begin, size, entry);
-  if (!writer) {
-    return kIoError;
-  }
-
-  return ExtractToWriter(archive, entry, writer.get());
-}
-
-int32_t ExtractEntryToFile(ZipArchiveHandle archive, const ZipEntry* entry, int fd) {
-  ZipEntry64 entry64(*entry);
-  return ExtractEntryToFile(archive, &entry64, fd);
-}
-
-int32_t ExtractEntryToFile(ZipArchiveHandle archive, const ZipEntry64* entry, int fd) {
-  auto writer = FileWriter::Create(fd, entry);
-  if (!writer) {
-    return kIoError;
-  }
-
-  return ExtractToWriter(archive, entry, writer.get());
-}
-
-int GetFileDescriptor(const ZipArchiveHandle archive) {
-  return archive->mapped_zip.GetFileDescriptor();
-}
-
-off64_t GetFileDescriptorOffset(const ZipArchiveHandle archive) {
-  return archive->mapped_zip.GetFileOffset();
-}
-
-#if !defined(_WIN32)
-class ProcessWriter : public zip_archive::Writer {
- public:
-  ProcessWriter(ProcessZipEntryFunction func, void* cookie)
-      : Writer(), proc_function_(func), cookie_(cookie) {}
-
-  virtual bool Append(uint8_t* buf, size_t buf_size) override {
-    return proc_function_(buf, buf_size, cookie_);
-  }
-
- private:
-  ProcessZipEntryFunction proc_function_;
-  void* cookie_;
-};
-
-int32_t ProcessZipEntryContents(ZipArchiveHandle archive, const ZipEntry* entry,
-                                ProcessZipEntryFunction func, void* cookie) {
-  ZipEntry64 entry64(*entry);
-  return ProcessZipEntryContents(archive, &entry64, func, cookie);
-}
-
-int32_t ProcessZipEntryContents(ZipArchiveHandle archive, const ZipEntry64* entry,
-                                ProcessZipEntryFunction func, void* cookie) {
-  ProcessWriter writer(func, cookie);
-  return ExtractToWriter(archive, entry, &writer);
-}
-
-#endif  //! defined(_WIN32)
-
-int MappedZipFile::GetFileDescriptor() const {
-  if (!has_fd_) {
-    ALOGW("Zip: MappedZipFile doesn't have a file descriptor.");
-    return -1;
-  }
-  return fd_;
-}
-
-const void* MappedZipFile::GetBasePtr() const {
-  if (has_fd_) {
-    ALOGW("Zip: MappedZipFile doesn't have a base pointer.");
-    return nullptr;
-  }
-  return base_ptr_;
-}
-
-off64_t MappedZipFile::GetFileOffset() const {
-  return fd_offset_;
-}
-
-off64_t MappedZipFile::GetFileLength() const {
-  if (has_fd_) {
-    if (data_length_ != -1) {
-      return data_length_;
-    }
-    data_length_ = lseek64(fd_, 0, SEEK_END);
-    if (data_length_ == -1) {
-      ALOGE("Zip: lseek on fd %d failed: %s", fd_, strerror(errno));
-    }
-    return data_length_;
-  } else {
-    if (base_ptr_ == nullptr) {
-      ALOGE("Zip: invalid file map");
-      return -1;
-    }
-    return data_length_;
-  }
-}
-
-// Attempts to read |len| bytes into |buf| at offset |off|.
-bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) const {
-  if (has_fd_) {
-    if (off < 0) {
-      ALOGE("Zip: invalid offset %" PRId64, off);
-      return false;
-    }
-
-    off64_t read_offset;
-    if (__builtin_add_overflow(fd_offset_, off, &read_offset)) {
-      ALOGE("Zip: invalid read offset %" PRId64 " overflows, fd offset %" PRId64, off, fd_offset_);
-      return false;
-    }
-
-    if (data_length_ != -1) {
-      off64_t read_end;
-      if (len > std::numeric_limits<off64_t>::max() ||
-          __builtin_add_overflow(off, static_cast<off64_t>(len), &read_end)) {
-        ALOGE("Zip: invalid read length %" PRId64 " overflows, offset %" PRId64,
-              static_cast<off64_t>(len), off);
-        return false;
-      }
-
-      if (read_end > data_length_) {
-        ALOGE("Zip: invalid read length %" PRId64 " exceeds data length %" PRId64 ", offset %"
-              PRId64, static_cast<off64_t>(len), data_length_, off);
-        return false;
-      }
-    }
-
-    if (!android::base::ReadFullyAtOffset(fd_, buf, len, read_offset)) {
-      ALOGE("Zip: failed to read at offset %" PRId64, off);
-      return false;
-    }
-  } else {
-    if (off < 0 || data_length_ < len || off > data_length_ - len) {
-      ALOGE("Zip: invalid offset: %" PRId64 ", read length: %zu, data length: %" PRId64, off, len,
-            data_length_);
-      return false;
-    }
-    memcpy(buf, static_cast<const uint8_t*>(base_ptr_) + off, len);
-  }
-  return true;
-}
-
-void CentralDirectory::Initialize(const void* map_base_ptr, off64_t cd_start_offset,
-                                  size_t cd_size) {
-  base_ptr_ = static_cast<const uint8_t*>(map_base_ptr) + cd_start_offset;
-  length_ = cd_size;
-}
-
-bool ZipArchive::InitializeCentralDirectory(off64_t cd_start_offset, size_t cd_size) {
-  if (mapped_zip.HasFd()) {
-    directory_map = android::base::MappedFile::FromFd(mapped_zip.GetFileDescriptor(),
-                                                      mapped_zip.GetFileOffset() + cd_start_offset,
-                                                      cd_size, PROT_READ);
-    if (!directory_map) {
-      ALOGE("Zip: failed to map central directory (offset %" PRId64 ", size %zu): %s",
-            cd_start_offset, cd_size, strerror(errno));
-      return false;
-    }
-
-    CHECK_EQ(directory_map->size(), cd_size);
-    central_directory.Initialize(directory_map->data(), 0 /*offset*/, cd_size);
-  } else {
-    if (mapped_zip.GetBasePtr() == nullptr) {
-      ALOGE("Zip: Failed to map central directory, bad mapped_zip base pointer");
-      return false;
-    }
-    if (static_cast<off64_t>(cd_start_offset) + static_cast<off64_t>(cd_size) >
-        mapped_zip.GetFileLength()) {
-      ALOGE(
-          "Zip: Failed to map central directory, offset exceeds mapped memory region ("
-          "start_offset %" PRId64 ", cd_size %zu, mapped_region_size %" PRId64 ")",
-          static_cast<int64_t>(cd_start_offset), cd_size, mapped_zip.GetFileLength());
-      return false;
-    }
-
-    central_directory.Initialize(mapped_zip.GetBasePtr(), cd_start_offset, cd_size);
-  }
-  return true;
-}
-
-// This function returns the embedded timestamp as is; and doesn't perform validations.
-tm ZipEntryCommon::GetModificationTime() const {
-  tm t = {};
-
-  t.tm_hour = (mod_time >> 11) & 0x1f;
-  t.tm_min = (mod_time >> 5) & 0x3f;
-  t.tm_sec = (mod_time & 0x1f) << 1;
-
-  t.tm_year = ((mod_time >> 25) & 0x7f) + 80;
-  t.tm_mon = ((mod_time >> 21) & 0xf) - 1;
-  t.tm_mday = (mod_time >> 16) & 0x1f;
-
-  return t;
-}
diff --git a/libziparchive/zip_archive_benchmark.cpp b/libziparchive/zip_archive_benchmark.cpp
deleted file mode 100644
index cfa5912..0000000
--- a/libziparchive/zip_archive_benchmark.cpp
+++ /dev/null
@@ -1,135 +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 <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <string>
-#include <tuple>
-#include <vector>
-
-#include <android-base/test_utils.h>
-#include <benchmark/benchmark.h>
-#include <ziparchive/zip_archive.h>
-#include <ziparchive/zip_archive_stream_entry.h>
-#include <ziparchive/zip_writer.h>
-
-static std::unique_ptr<TemporaryFile> CreateZip(int size = 4, int count = 1000) {
-  auto result = std::make_unique<TemporaryFile>();
-  FILE* fp = fdopen(result->fd, "w");
-
-  ZipWriter writer(fp);
-  std::string lastName = "file";
-  for (size_t i = 0; i < count; i++) {
-    // Make file names longer and longer.
-    lastName = lastName + std::to_string(i);
-    writer.StartEntry(lastName.c_str(), ZipWriter::kCompress);
-    while (size > 0) {
-      writer.WriteBytes("helo", 4);
-      size -= 4;
-    }
-    writer.FinishEntry();
-  }
-  writer.Finish();
-  fclose(fp);
-
-  return result;
-}
-
-static void FindEntry_no_match(benchmark::State& state) {
-  // Create a temporary zip archive.
-  std::unique_ptr<TemporaryFile> temp_file(CreateZip());
-  ZipArchiveHandle handle;
-  ZipEntry data;
-
-  // In order to walk through all file names in the archive, look for a name
-  // that does not exist in the archive.
-  std::string_view name("thisFileNameDoesNotExist");
-
-  // Start the benchmark.
-  for (auto _ : state) {
-    OpenArchive(temp_file->path, &handle);
-    FindEntry(handle, name, &data);
-    CloseArchive(handle);
-  }
-}
-BENCHMARK(FindEntry_no_match);
-
-static void Iterate_all_files(benchmark::State& state) {
-  std::unique_ptr<TemporaryFile> temp_file(CreateZip());
-  ZipArchiveHandle handle;
-  void* iteration_cookie;
-  ZipEntry data;
-  std::string name;
-
-  for (auto _ : state) {
-    OpenArchive(temp_file->path, &handle);
-    StartIteration(handle, &iteration_cookie);
-    while (Next(iteration_cookie, &data, &name) == 0) {
-    }
-    EndIteration(iteration_cookie);
-    CloseArchive(handle);
-  }
-}
-BENCHMARK(Iterate_all_files);
-
-static void StartAlignedEntry(benchmark::State& state) {
-  TemporaryFile file;
-  FILE* fp = fdopen(file.fd, "w");
-
-  ZipWriter writer(fp);
-
-  auto alignment = uint32_t(state.range(0));
-  std::string name = "name";
-  int counter = 0;
-  for (auto _ : state) {
-    writer.StartAlignedEntry(name + std::to_string(counter++), 0, alignment);
-    state.PauseTiming();
-    writer.WriteBytes("hola", 4);
-    writer.FinishEntry();
-    state.ResumeTiming();
-  }
-
-  writer.Finish();
-  fclose(fp);
-}
-BENCHMARK(StartAlignedEntry)->Arg(2)->Arg(16)->Arg(1024)->Arg(4096);
-
-static void ExtractEntry(benchmark::State& state) {
-  std::unique_ptr<TemporaryFile> temp_file(CreateZip(1024 * 1024, 1));
-
-  ZipArchiveHandle handle;
-  ZipEntry data;
-  if (OpenArchive(temp_file->path, &handle)) {
-    state.SkipWithError("Failed to open archive");
-  }
-  if (FindEntry(handle, "file0", &data)) {
-    state.SkipWithError("Failed to find archive entry");
-  }
-
-  std::vector<uint8_t> buffer(1024 * 1024);
-  for (auto _ : state) {
-    if (ExtractToMemory(handle, &data, buffer.data(), uint32_t(buffer.size()))) {
-      state.SkipWithError("Failed to extract archive entry");
-      break;
-    }
-  }
-  CloseArchive(handle);
-}
-
-BENCHMARK(ExtractEntry)->Arg(2)->Arg(16)->Arg(1024);
-
-BENCHMARK_MAIN();
diff --git a/libziparchive/zip_archive_common.h b/libziparchive/zip_archive_common.h
deleted file mode 100644
index d461856..0000000
--- a/libziparchive/zip_archive_common.h
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright (C) 2015 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 LIBZIPARCHIVE_ZIPARCHIVECOMMON_H_
-#define LIBZIPARCHIVE_ZIPARCHIVECOMMON_H_
-
-#include "android-base/macros.h"
-
-#include <inttypes.h>
-
-#include <optional>
-
-// The "end of central directory" (EOCD) record. Each archive
-// contains exactly once such record which appears at the end of
-// the archive. It contains archive wide information like the
-// number of entries in the archive and the offset to the central
-// directory of the offset.
-struct EocdRecord {
-  static const uint32_t kSignature = 0x06054b50;
-
-  // End of central directory signature, should always be
-  // |kSignature|.
-  uint32_t eocd_signature;
-  // The number of the current "disk", i.e, the "disk" that this
-  // central directory is on.
-  //
-  // This implementation assumes that each archive spans a single
-  // disk only. i.e, that disk_num == 1.
-  uint16_t disk_num;
-  // The disk where the central directory starts.
-  //
-  // This implementation assumes that each archive spans a single
-  // disk only. i.e, that cd_start_disk == 1.
-  uint16_t cd_start_disk;
-  // The number of central directory records on this disk.
-  //
-  // This implementation assumes that each archive spans a single
-  // disk only. i.e, that num_records_on_disk == num_records.
-  uint16_t num_records_on_disk;
-  // The total number of central directory records.
-  uint16_t num_records;
-  // The size of the central directory (in bytes).
-  uint32_t cd_size;
-  // The offset of the start of the central directory, relative
-  // to the start of the file.
-  uint32_t cd_start_offset;
-  // Length of the central directory comment.
-  uint16_t comment_length;
-
- private:
-  EocdRecord() = default;
-  DISALLOW_COPY_AND_ASSIGN(EocdRecord);
-} __attribute__((packed));
-
-// A structure representing the fixed length fields for a single
-// record in the central directory of the archive. In addition to
-// the fixed length fields listed here, each central directory
-// record contains a variable length "file_name" and "extra_field"
-// whose lengths are given by |file_name_length| and |extra_field_length|
-// respectively.
-struct CentralDirectoryRecord {
-  static const uint32_t kSignature = 0x02014b50;
-
-  // The start of record signature. Must be |kSignature|.
-  uint32_t record_signature;
-  // Source tool version. Top byte gives source OS.
-  uint16_t version_made_by;
-  // Tool version. Ignored by this implementation.
-  uint16_t version_needed;
-  // The "general purpose bit flags" for this entry. The only
-  // flag value that we currently check for is the "data descriptor"
-  // flag.
-  uint16_t gpb_flags;
-  // The compression method for this entry, one of |kCompressStored|
-  // and |kCompressDeflated|.
-  uint16_t compression_method;
-  // The file modification time and date for this entry.
-  uint16_t last_mod_time;
-  uint16_t last_mod_date;
-  // The CRC-32 checksum for this entry.
-  uint32_t crc32;
-  // The compressed size (in bytes) of this entry.
-  uint32_t compressed_size;
-  // The uncompressed size (in bytes) of this entry.
-  uint32_t uncompressed_size;
-  // The length of the entry file name in bytes. The file name
-  // will appear immediately after this record.
-  uint16_t file_name_length;
-  // The length of the extra field info (in bytes). This data
-  // will appear immediately after the entry file name.
-  uint16_t extra_field_length;
-  // The length of the entry comment (in bytes). This data will
-  // appear immediately after the extra field.
-  uint16_t comment_length;
-  // The start disk for this entry. Ignored by this implementation).
-  uint16_t file_start_disk;
-  // File attributes. Ignored by this implementation.
-  uint16_t internal_file_attributes;
-  // File attributes. For archives created on Unix, the top bits are the mode.
-  uint32_t external_file_attributes;
-  // The offset to the local file header for this entry, from the
-  // beginning of this archive.
-  uint32_t local_file_header_offset;
-
- private:
-  CentralDirectoryRecord() = default;
-  DISALLOW_COPY_AND_ASSIGN(CentralDirectoryRecord);
-} __attribute__((packed));
-
-// The local file header for a given entry. This duplicates information
-// present in the central directory of the archive. It is an error for
-// the information here to be different from the central directory
-// information for a given entry.
-struct LocalFileHeader {
-  static const uint32_t kSignature = 0x04034b50;
-
-  // The local file header signature, must be |kSignature|.
-  uint32_t lfh_signature;
-  // Tool version. Ignored by this implementation.
-  uint16_t version_needed;
-  // The "general purpose bit flags" for this entry. The only
-  // flag value that we currently check for is the "data descriptor"
-  // flag.
-  uint16_t gpb_flags;
-  // The compression method for this entry, one of |kCompressStored|
-  // and |kCompressDeflated|.
-  uint16_t compression_method;
-  // The file modification time and date for this entry.
-  uint16_t last_mod_time;
-  uint16_t last_mod_date;
-  // The CRC-32 checksum for this entry.
-  uint32_t crc32;
-  // The compressed size (in bytes) of this entry.
-  uint32_t compressed_size;
-  // The uncompressed size (in bytes) of this entry.
-  uint32_t uncompressed_size;
-  // The length of the entry file name in bytes. The file name
-  // will appear immediately after this record.
-  uint16_t file_name_length;
-  // The length of the extra field info (in bytes). This data
-  // will appear immediately after the entry file name.
-  uint16_t extra_field_length;
-
- private:
-  LocalFileHeader() = default;
-  DISALLOW_COPY_AND_ASSIGN(LocalFileHeader);
-} __attribute__((packed));
-
-struct DataDescriptor {
-  // The *optional* data descriptor start signature.
-  static const uint32_t kOptSignature = 0x08074b50;
-
-  // CRC-32 checksum of the entry.
-  uint32_t crc32;
-
-  // For ZIP64 format archives, the compressed and uncompressed sizes are 8
-  // bytes each. Also, the ZIP64 format MAY be used regardless of the size
-  // of a file.  When extracting, if the zip64 extended information extra field
-  // is present for the file the compressed and uncompressed sizes will be 8
-  // byte values.
-
-  // Compressed size of the entry, the field can be either 4 bytes or 8 bytes
-  // in the zip file.
-  uint64_t compressed_size;
-  // Uncompressed size of the entry, the field can be either 4 bytes or 8 bytes
-  // in the zip file.
-  uint64_t uncompressed_size;
-
- private:
-  DataDescriptor() = default;
-  DISALLOW_COPY_AND_ASSIGN(DataDescriptor);
-};
-
-// The zip64 end of central directory locator helps to find the zip64 EOCD.
-struct Zip64EocdLocator {
-  static constexpr uint32_t kSignature = 0x07064b50;
-
-  // The signature of zip64 eocd locator, must be |kSignature|
-  uint32_t locator_signature;
-  // The start disk of the zip64 eocd. This implementation assumes that each
-  // archive spans a single disk only.
-  uint32_t eocd_start_disk;
-  // The offset offset of the zip64 end of central directory record.
-  uint64_t zip64_eocd_offset;
-  // The total number of disks. This implementation assumes that each archive
-  // spans a single disk only.
-  uint32_t num_of_disks;
-
- private:
-  Zip64EocdLocator() = default;
-  DISALLOW_COPY_AND_ASSIGN(Zip64EocdLocator);
-} __attribute__((packed));
-
-// The optional zip64 EOCD. If one of the fields in the end of central directory
-// record is too small to hold required data, the field SHOULD be  set to -1
-// (0xFFFF or 0xFFFFFFFF) and the ZIP64 format record SHOULD be created.
-struct Zip64EocdRecord {
-  static constexpr uint32_t kSignature = 0x06064b50;
-
-  // The signature of zip64 eocd record, must be |kSignature|
-  uint32_t record_signature;
-  // Size of zip64 end of central directory record. It SHOULD be the size of the
-  // remaining record and SHOULD NOT include the leading 12 bytes.
-  uint64_t record_size;
-  // The version of the tool that make this archive.
-  uint16_t version_made_by;
-  // Tool version needed to extract this archive.
-  uint16_t version_needed;
-  // Number of this disk.
-  uint32_t disk_num;
-  // Number of the disk with the start of the central directory.
-  uint32_t cd_start_disk;
-  // Total number of entries in the central directory on this disk.
-  // This implementation assumes that each archive spans a single
-  // disk only. i.e, that num_records_on_disk == num_records.
-  uint64_t num_records_on_disk;
-  // The total number of central directory records.
-  uint64_t num_records;
-  // The size of the central directory in bytes.
-  uint64_t cd_size;
-  // The offset of the start of the central directory, relative to the start of
-  // the file.
-  uint64_t cd_start_offset;
-
- private:
-  Zip64EocdRecord() = default;
-  DISALLOW_COPY_AND_ASSIGN(Zip64EocdRecord);
-} __attribute__((packed));
-
-// The possible contents of the Zip64 Extended Information Extra Field. It may appear in
-// the 'extra' field of a central directory record or local file header. The order of
-// the fields in the zip64 extended information record is fixed, but the fields MUST
-// only appear if the corresponding local or central directory record field is set to
-// 0xFFFF or 0xFFFFFFFF. And this entry in the Local header MUST include BOTH original
-// and compressed file size fields.
-struct Zip64ExtendedInfo {
-  static constexpr uint16_t kHeaderId = 0x0001;
-  // The header tag for this 'extra' block, should be |kHeaderId|.
-  uint16_t header_id;
-  // The size in bytes of the remaining data (excluding the top 4 bytes).
-  uint16_t data_size;
-  // Size in bytes of the uncompressed file.
-  std::optional<uint64_t> uncompressed_file_size;
-  // Size in bytes of the compressed file.
-  std::optional<uint64_t> compressed_file_size;
-  // Local file header offset relative to the start of the zip file.
-  std::optional<uint64_t> local_header_offset;
-
-  // This implementation assumes that each archive spans a single disk only. So
-  // the disk_number is not used.
-  // uint32_t disk_num;
- private:
-  Zip64ExtendedInfo() = default;
-  DISALLOW_COPY_AND_ASSIGN(Zip64ExtendedInfo);
-};
-
-// mask value that signifies that the entry has a DD
-static const uint32_t kGPBDDFlagMask = 0x0008;
-
-// The maximum size of a central directory or a file
-// comment in bytes.
-static const uint32_t kMaxCommentLen = 65535;
-
-#endif /* LIBZIPARCHIVE_ZIPARCHIVECOMMON_H_ */
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
deleted file mode 100644
index 4b43cba..0000000
--- a/libziparchive/zip_archive_private.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * 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 <ziparchive/zip_archive.h>
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "android-base/macros.h"
-#include "android-base/mapped_file.h"
-#include "android-base/memory.h"
-#include "zip_cd_entry_map.h"
-#include "zip_error.h"
-
-class MappedZipFile {
- public:
-  explicit MappedZipFile(const int fd)
-      : has_fd_(true), fd_(fd), fd_offset_(0), base_ptr_(nullptr), data_length_(-1) {}
-
-  explicit MappedZipFile(const int fd, off64_t length, off64_t offset)
-      : has_fd_(true), fd_(fd), fd_offset_(offset), base_ptr_(nullptr), data_length_(length) {}
-
-  explicit MappedZipFile(const void* address, size_t length)
-      : has_fd_(false), fd_(-1), fd_offset_(0), base_ptr_(address),
-        data_length_(static_cast<off64_t>(length)) {}
-
-  bool HasFd() const { return has_fd_; }
-
-  int GetFileDescriptor() const;
-
-  const void* GetBasePtr() const;
-
-  off64_t GetFileOffset() const;
-
-  off64_t GetFileLength() const;
-
-  bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off) const;
-
- private:
-  // If has_fd_ is true, fd is valid and we'll read contents of a zip archive
-  // from the file. Otherwise, we're opening the archive from a memory mapped
-  // file. In that case, base_ptr_ points to the start of the memory region and
-  // data_length_ defines the file length.
-  const bool has_fd_;
-
-  const int fd_;
-  const off64_t fd_offset_;
-
-  const void* const base_ptr_;
-  mutable off64_t data_length_;
-};
-
-class CentralDirectory {
- public:
-  CentralDirectory(void) : base_ptr_(nullptr), length_(0) {}
-
-  const uint8_t* GetBasePtr() const { return base_ptr_; }
-
-  size_t GetMapLength() const { return length_; }
-
-  void Initialize(const void* map_base_ptr, off64_t cd_start_offset, size_t cd_size);
-
- private:
-  const uint8_t* base_ptr_;
-  size_t length_;
-};
-
-struct ZipArchive {
-  // open Zip archive
-  mutable MappedZipFile mapped_zip;
-  const bool close_file;
-
-  // mapped central directory area
-  off64_t directory_offset;
-  CentralDirectory central_directory;
-  std::unique_ptr<android::base::MappedFile> directory_map;
-
-  // number of entries in the Zip archive
-  uint64_t num_entries;
-  std::unique_ptr<CdEntryMapInterface> cd_entry_map;
-
-  ZipArchive(MappedZipFile&& map, bool assume_ownership);
-  ZipArchive(const void* address, size_t length);
-  ~ZipArchive();
-
-  bool InitializeCentralDirectory(off64_t cd_start_offset, size_t cd_size);
-};
-
-int32_t ExtractToWriter(ZipArchiveHandle handle, const ZipEntry64* entry,
-                        zip_archive::Writer* writer);
-
-// Reads the unaligned data of type |T| and auto increment the offset.
-template <typename T>
-static T ConsumeUnaligned(uint8_t** address) {
-  auto ret = android::base::get_unaligned<T>(*address);
-  *address += sizeof(T);
-  return ret;
-}
-
-// Writes the unaligned data of type |T| and auto increment the offset.
-template <typename T>
-void EmitUnaligned(uint8_t** address, T data) {
-  android::base::put_unaligned<T>(*address, data);
-  *address += sizeof(T);
-}
diff --git a/libziparchive/zip_archive_stream_entry.cc b/libziparchive/zip_archive_stream_entry.cc
deleted file mode 100644
index 1ec95b6..0000000
--- a/libziparchive/zip_archive_stream_entry.cc
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright (C) 2015 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 "ZIPARCHIVE"
-
-// Read-only stream access to Zip Archive entries.
-#include <errno.h>
-#include <inttypes.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <memory>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <log/log.h>
-
-#include <ziparchive/zip_archive.h>
-#include <ziparchive/zip_archive_stream_entry.h>
-#include <zlib.h>
-
-#include "zip_archive_private.h"
-
-static constexpr size_t kBufSize = 65535;
-
-bool ZipArchiveStreamEntry::Init(const ZipEntry& entry) {
-  crc32_ = entry.crc32;
-  offset_ = entry.offset;
-  return true;
-}
-
-class ZipArchiveStreamEntryUncompressed : public ZipArchiveStreamEntry {
- public:
-  explicit ZipArchiveStreamEntryUncompressed(ZipArchiveHandle handle)
-      : ZipArchiveStreamEntry(handle) {}
-  virtual ~ZipArchiveStreamEntryUncompressed() {}
-
-  const std::vector<uint8_t>* Read() override;
-
-  bool Verify() override;
-
- protected:
-  bool Init(const ZipEntry& entry) override;
-
-  uint32_t length_ = 0u;
-
- private:
-  std::vector<uint8_t> data_;
-  uint32_t computed_crc32_ = 0u;
-};
-
-bool ZipArchiveStreamEntryUncompressed::Init(const ZipEntry& entry) {
-  if (!ZipArchiveStreamEntry::Init(entry)) {
-    return false;
-  }
-
-  length_ = entry.uncompressed_length;
-
-  data_.resize(kBufSize);
-  computed_crc32_ = 0;
-
-  return true;
-}
-
-const std::vector<uint8_t>* ZipArchiveStreamEntryUncompressed::Read() {
-  // Simple sanity check. The vector should *only* be handled by this code. A caller
-  // should not const-cast and modify the capacity. This may invalidate next_out.
-  //
-  // Note: it would be better to store the results of data() across Read calls.
-  CHECK_EQ(data_.capacity(), kBufSize);
-
-  if (length_ == 0) {
-    return nullptr;
-  }
-
-  size_t bytes = (length_ > data_.size()) ? data_.size() : length_;
-  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
-  errno = 0;
-  if (!archive->mapped_zip.ReadAtOffset(data_.data(), bytes, offset_)) {
-    if (errno != 0) {
-      ALOGE("Error reading from archive fd: %s", strerror(errno));
-    } else {
-      ALOGE("Short read of zip file, possibly corrupted zip?");
-    }
-    length_ = 0;
-    return nullptr;
-  }
-
-  if (bytes < data_.size()) {
-    data_.resize(bytes);
-  }
-  computed_crc32_ = static_cast<uint32_t>(
-      crc32(computed_crc32_, data_.data(), static_cast<uint32_t>(data_.size())));
-  length_ -= bytes;
-  offset_ += bytes;
-  return &data_;
-}
-
-bool ZipArchiveStreamEntryUncompressed::Verify() {
-  return length_ == 0 && crc32_ == computed_crc32_;
-}
-
-class ZipArchiveStreamEntryCompressed : public ZipArchiveStreamEntry {
- public:
-  explicit ZipArchiveStreamEntryCompressed(ZipArchiveHandle handle)
-      : ZipArchiveStreamEntry(handle) {}
-  virtual ~ZipArchiveStreamEntryCompressed();
-
-  const std::vector<uint8_t>* Read() override;
-
-  bool Verify() override;
-
- protected:
-  bool Init(const ZipEntry& entry) override;
-
- private:
-  bool z_stream_init_ = false;
-  z_stream z_stream_;
-  std::vector<uint8_t> in_;
-  std::vector<uint8_t> out_;
-  uint32_t uncompressed_length_ = 0u;
-  uint32_t compressed_length_ = 0u;
-  uint32_t computed_crc32_ = 0u;
-};
-
-// This method is using libz macros with old-style-casts
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-static inline int zlib_inflateInit2(z_stream* stream, int window_bits) {
-  return inflateInit2(stream, window_bits);
-}
-#pragma GCC diagnostic pop
-
-bool ZipArchiveStreamEntryCompressed::Init(const ZipEntry& entry) {
-  if (!ZipArchiveStreamEntry::Init(entry)) {
-    return false;
-  }
-
-  // Initialize the zlib stream struct.
-  memset(&z_stream_, 0, sizeof(z_stream_));
-  z_stream_.zalloc = Z_NULL;
-  z_stream_.zfree = Z_NULL;
-  z_stream_.opaque = Z_NULL;
-  z_stream_.next_in = nullptr;
-  z_stream_.avail_in = 0;
-  z_stream_.avail_out = 0;
-  z_stream_.data_type = Z_UNKNOWN;
-
-  // Use the undocumented "negative window bits" feature to tell zlib
-  // that there's no zlib header waiting for it.
-  int zerr = zlib_inflateInit2(&z_stream_, -MAX_WBITS);
-  if (zerr != Z_OK) {
-    if (zerr == Z_VERSION_ERROR) {
-      ALOGE("Installed zlib is not compatible with linked version (%s)", ZLIB_VERSION);
-    } else {
-      ALOGE("Call to inflateInit2 failed (zerr=%d)", zerr);
-    }
-
-    return false;
-  }
-
-  z_stream_init_ = true;
-
-  uncompressed_length_ = entry.uncompressed_length;
-  compressed_length_ = entry.compressed_length;
-
-  out_.resize(kBufSize);
-  in_.resize(kBufSize);
-
-  computed_crc32_ = 0;
-
-  return true;
-}
-
-ZipArchiveStreamEntryCompressed::~ZipArchiveStreamEntryCompressed() {
-  if (z_stream_init_) {
-    inflateEnd(&z_stream_);
-    z_stream_init_ = false;
-  }
-}
-
-bool ZipArchiveStreamEntryCompressed::Verify() {
-  return z_stream_init_ && uncompressed_length_ == 0 && compressed_length_ == 0 &&
-         crc32_ == computed_crc32_;
-}
-
-const std::vector<uint8_t>* ZipArchiveStreamEntryCompressed::Read() {
-  // Simple sanity check. The vector should *only* be handled by this code. A caller
-  // should not const-cast and modify the capacity. This may invalidate next_out.
-  //
-  // Note: it would be better to store the results of data() across Read calls.
-  CHECK_EQ(out_.capacity(), kBufSize);
-
-  if (z_stream_.avail_out == 0) {
-    z_stream_.next_out = out_.data();
-    z_stream_.avail_out = static_cast<uint32_t>(out_.size());
-    ;
-  }
-
-  while (true) {
-    if (z_stream_.avail_in == 0) {
-      if (compressed_length_ == 0) {
-        return nullptr;
-      }
-      DCHECK_LE(in_.size(), std::numeric_limits<uint32_t>::max());  // Should be buf size = 64k.
-      uint32_t bytes = (compressed_length_ > in_.size()) ? static_cast<uint32_t>(in_.size())
-                                                         : compressed_length_;
-      ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
-      errno = 0;
-      if (!archive->mapped_zip.ReadAtOffset(in_.data(), bytes, offset_)) {
-        if (errno != 0) {
-          ALOGE("Error reading from archive fd: %s", strerror(errno));
-        } else {
-          ALOGE("Short read of zip file, possibly corrupted zip?");
-        }
-        return nullptr;
-      }
-
-      compressed_length_ -= bytes;
-      offset_ += bytes;
-      z_stream_.next_in = in_.data();
-      z_stream_.avail_in = bytes;
-    }
-
-    int zerr = inflate(&z_stream_, Z_NO_FLUSH);
-    if (zerr != Z_OK && zerr != Z_STREAM_END) {
-      ALOGE("inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)", zerr, z_stream_.next_in,
-            z_stream_.avail_in, z_stream_.next_out, z_stream_.avail_out);
-      return nullptr;
-    }
-
-    if (z_stream_.avail_out == 0) {
-      uncompressed_length_ -= out_.size();
-      computed_crc32_ = static_cast<uint32_t>(
-          crc32(computed_crc32_, out_.data(), static_cast<uint32_t>(out_.size())));
-      return &out_;
-    }
-    if (zerr == Z_STREAM_END) {
-      if (z_stream_.avail_out != 0) {
-        // Resize the vector down to the actual size of the data.
-        out_.resize(out_.size() - z_stream_.avail_out);
-        computed_crc32_ = static_cast<uint32_t>(
-            crc32(computed_crc32_, out_.data(), static_cast<uint32_t>(out_.size())));
-        uncompressed_length_ -= out_.size();
-        return &out_;
-      }
-      return nullptr;
-    }
-  }
-  return nullptr;
-}
-
-class ZipArchiveStreamEntryRawCompressed : public ZipArchiveStreamEntryUncompressed {
- public:
-  explicit ZipArchiveStreamEntryRawCompressed(ZipArchiveHandle handle)
-      : ZipArchiveStreamEntryUncompressed(handle) {}
-  virtual ~ZipArchiveStreamEntryRawCompressed() {}
-
-  bool Verify() override;
-
- protected:
-  bool Init(const ZipEntry& entry) override;
-};
-
-bool ZipArchiveStreamEntryRawCompressed::Init(const ZipEntry& entry) {
-  if (!ZipArchiveStreamEntryUncompressed::Init(entry)) {
-    return false;
-  }
-  length_ = entry.compressed_length;
-
-  return true;
-}
-
-bool ZipArchiveStreamEntryRawCompressed::Verify() {
-  return length_ == 0;
-}
-
-ZipArchiveStreamEntry* ZipArchiveStreamEntry::Create(ZipArchiveHandle handle,
-                                                     const ZipEntry& entry) {
-  ZipArchiveStreamEntry* stream = nullptr;
-  if (entry.method != kCompressStored) {
-    stream = new ZipArchiveStreamEntryCompressed(handle);
-  } else {
-    stream = new ZipArchiveStreamEntryUncompressed(handle);
-  }
-  if (stream && !stream->Init(entry)) {
-    delete stream;
-    stream = nullptr;
-  }
-
-  return stream;
-}
-
-ZipArchiveStreamEntry* ZipArchiveStreamEntry::CreateRaw(ZipArchiveHandle handle,
-                                                        const ZipEntry& entry) {
-  ZipArchiveStreamEntry* stream = nullptr;
-  if (entry.method == kCompressStored) {
-    // Not compressed, don't need to do anything special.
-    stream = new ZipArchiveStreamEntryUncompressed(handle);
-  } else {
-    stream = new ZipArchiveStreamEntryRawCompressed(handle);
-  }
-  if (stream && !stream->Init(entry)) {
-    delete stream;
-    stream = nullptr;
-  }
-  return stream;
-}
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
deleted file mode 100644
index f5429be..0000000
--- a/libziparchive/zip_archive_test.cc
+++ /dev/null
@@ -1,1327 +0,0 @@
-/*
- * Copyright (C) 2013 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 <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string_view>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/mapped_file.h>
-#include <android-base/memory.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <gtest/gtest.h>
-#include <ziparchive/zip_archive.h>
-#include <ziparchive/zip_archive_stream_entry.h>
-
-#include "zip_archive_common.h"
-#include "zip_archive_private.h"
-
-static std::string test_data_dir = android::base::GetExecutableDirectory() + "/testdata";
-
-static const std::string kValidZip = "valid.zip";
-static const std::string kLargeZip = "large.zip";
-static const std::string kBadCrcZip = "bad_crc.zip";
-
-static const std::vector<uint8_t> kATxtContents{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'a',
-                                                'b', 'c', 'd', 'e', 'f', 'g', 'h', '\n'};
-
-static const std::vector<uint8_t> kATxtContentsCompressed{'K', 'L', 'J', 'N', 'I',  'M', 'K',
-                                                          207, 'H', 132, 210, '\\', '\0'};
-
-static const std::vector<uint8_t> kBTxtContents{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\n'};
-
-static int32_t OpenArchiveWrapper(const std::string& name, ZipArchiveHandle* handle) {
-  const std::string abs_path = test_data_dir + "/" + name;
-  return OpenArchive(abs_path.c_str(), handle);
-}
-
-class CdEntryMapTest : public ::testing::Test {
- protected:
-  void SetUp() override {
-    names_ = {
-        "a.txt", "b.txt", "b/", "b/c.txt", "b/d.txt",
-    };
-    separator_ = "separator";
-    header_ = "metadata";
-    joined_names_ = header_ + android::base::Join(names_, separator_);
-    base_ptr_ = reinterpret_cast<uint8_t*>(&joined_names_[0]);
-
-    entry_maps_.emplace_back(CdEntryMapZip32::Create(static_cast<uint16_t>(names_.size())));
-    entry_maps_.emplace_back(CdEntryMapZip64::Create());
-    for (auto& cd_map : entry_maps_) {
-      ASSERT_NE(nullptr, cd_map);
-      size_t offset = header_.size();
-      for (const auto& name : names_) {
-        auto status = cd_map->AddToMap(
-            std::string_view{joined_names_.c_str() + offset, name.size()}, base_ptr_);
-        ASSERT_EQ(0, status);
-        offset += name.size() + separator_.size();
-      }
-    }
-  }
-
-  std::vector<std::string> names_;
-  // A continuous region of memory serves as a mock of the central directory.
-  std::string joined_names_;
-  // We expect some metadata at the beginning of the central directory and between filenames.
-  std::string header_;
-  std::string separator_;
-
-  std::vector<std::unique_ptr<CdEntryMapInterface>> entry_maps_;
-  uint8_t* base_ptr_{nullptr};  // Points to the start of the central directory.
-};
-
-TEST_F(CdEntryMapTest, AddDuplicatedEntry) {
-  for (auto& cd_map : entry_maps_) {
-    std::string_view name = "b.txt";
-    ASSERT_NE(0, cd_map->AddToMap(name, base_ptr_));
-  }
-}
-
-TEST_F(CdEntryMapTest, FindEntry) {
-  for (auto& cd_map : entry_maps_) {
-    uint64_t expected_offset = header_.size();
-    for (const auto& name : names_) {
-      auto [status, offset] = cd_map->GetCdEntryOffset(name, base_ptr_);
-      ASSERT_EQ(status, kSuccess);
-      ASSERT_EQ(offset, expected_offset);
-      expected_offset += name.size() + separator_.size();
-    }
-  }
-}
-
-TEST_F(CdEntryMapTest, Iteration) {
-  std::set<std::string_view> expected(names_.begin(), names_.end());
-  for (auto& cd_map : entry_maps_) {
-    cd_map->ResetIteration();
-    std::set<std::string_view> entry_set;
-    auto ret = cd_map->Next(base_ptr_);
-    while (ret != std::pair<std::string_view, uint64_t>{}) {
-      auto [it, insert_status] = entry_set.insert(ret.first);
-      ASSERT_TRUE(insert_status);
-      ret = cd_map->Next(base_ptr_);
-    }
-    ASSERT_EQ(expected, entry_set);
-  }
-}
-
-TEST(ziparchive, Open) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
-  CloseArchive(handle);
-
-  ASSERT_EQ(kInvalidEntryName, OpenArchiveWrapper("bad_filename.zip", &handle));
-  CloseArchive(handle);
-}
-
-TEST(ziparchive, OutOfBound) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(kInvalidOffset, OpenArchiveWrapper("crash.apk", &handle));
-  CloseArchive(handle);
-}
-
-TEST(ziparchive, EmptyArchive) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(kEmptyArchive, OpenArchiveWrapper("empty.zip", &handle));
-  CloseArchive(handle);
-}
-
-TEST(ziparchive, ZeroSizeCentralDirectory) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(kInvalidFile, OpenArchiveWrapper("zero-size-cd.zip", &handle));
-  CloseArchive(handle);
-}
-
-TEST(ziparchive, OpenMissing) {
-  ZipArchiveHandle handle;
-  ASSERT_NE(0, OpenArchiveWrapper("missing.zip", &handle));
-
-  // Confirm the file descriptor is not going to be mistaken for a valid one.
-  ASSERT_EQ(-1, GetFileDescriptor(handle));
-}
-
-TEST(ziparchive, OpenAssumeFdOwnership) {
-  int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
-  ASSERT_NE(-1, fd);
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle));
-  CloseArchive(handle);
-  ASSERT_EQ(-1, lseek(fd, 0, SEEK_SET));
-  ASSERT_EQ(EBADF, errno);
-}
-
-TEST(ziparchive, OpenDoNotAssumeFdOwnership) {
-  int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
-  ASSERT_NE(-1, fd);
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle, false));
-  CloseArchive(handle);
-  ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
-  close(fd);
-}
-
-TEST(ziparchive, OpenAssumeFdRangeOwnership) {
-  int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
-  ASSERT_NE(-1, fd);
-  const off64_t length = lseek64(fd, 0, SEEK_END);
-  ASSERT_NE(-1, length);
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveFdRange(fd, "OpenWithAssumeFdOwnership", &handle,
-                                  static_cast<size_t>(length), 0));
-  CloseArchive(handle);
-  ASSERT_EQ(-1, lseek(fd, 0, SEEK_SET));
-  ASSERT_EQ(EBADF, errno);
-}
-
-TEST(ziparchive, OpenDoNotAssumeFdRangeOwnership) {
-  int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
-  ASSERT_NE(-1, fd);
-  const off64_t length = lseek(fd, 0, SEEK_END);
-  ASSERT_NE(-1, length);
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveFdRange(fd, "OpenWithAssumeFdOwnership", &handle,
-                                  static_cast<size_t>(length), 0, false));
-  CloseArchive(handle);
-  ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
-  close(fd);
-}
-
-TEST(ziparchive, Iteration_std_string_view) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
-
-  void* iteration_cookie;
-  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie));
-
-  ZipEntry64 data;
-  std::vector<std::string_view> names;
-  std::string_view name;
-  while (Next(iteration_cookie, &data, &name) == 0) names.push_back(name);
-
-  // Assert that the names are as expected.
-  std::vector<std::string_view> expected_names{"a.txt", "b.txt", "b/", "b/c.txt", "b/d.txt"};
-  std::sort(names.begin(), names.end());
-  ASSERT_EQ(expected_names, names);
-
-  CloseArchive(handle);
-}
-
-static void AssertIterationNames(void* iteration_cookie,
-                                 const std::vector<std::string>& expected_names_sorted) {
-  ZipEntry64 data;
-  std::vector<std::string> names;
-  std::string_view name;
-  for (size_t i = 0; i < expected_names_sorted.size(); ++i) {
-    ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
-    names.push_back(std::string(name));
-  }
-  // End of iteration.
-  ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
-  // Assert that the names are as expected.
-  std::sort(names.begin(), names.end());
-  ASSERT_EQ(expected_names_sorted, names);
-}
-
-static void AssertIterationOrder(const std::string_view prefix, const std::string_view suffix,
-                                 const std::vector<std::string>& expected_names_sorted) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
-
-  void* iteration_cookie;
-  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, prefix, suffix));
-  AssertIterationNames(iteration_cookie, expected_names_sorted);
-  CloseArchive(handle);
-}
-
-static void AssertIterationOrderWithMatcher(std::function<bool(std::string_view)> matcher,
-                                            const std::vector<std::string>& expected_names_sorted) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
-
-  void* iteration_cookie;
-  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, matcher));
-  AssertIterationNames(iteration_cookie, expected_names_sorted);
-  CloseArchive(handle);
-}
-
-TEST(ziparchive, Iteration) {
-  static const std::vector<std::string> kExpectedMatchesSorted = {"a.txt", "b.txt", "b/", "b/c.txt",
-                                                                  "b/d.txt"};
-
-  AssertIterationOrder("", "", kExpectedMatchesSorted);
-}
-
-TEST(ziparchive, IterationWithPrefix) {
-  static const std::vector<std::string> kExpectedMatchesSorted = {"b/", "b/c.txt", "b/d.txt"};
-
-  AssertIterationOrder("b/", "", kExpectedMatchesSorted);
-}
-
-TEST(ziparchive, IterationWithSuffix) {
-  static const std::vector<std::string> kExpectedMatchesSorted = {"a.txt", "b.txt", "b/c.txt",
-                                                                  "b/d.txt"};
-
-  AssertIterationOrder("", ".txt", kExpectedMatchesSorted);
-}
-
-TEST(ziparchive, IterationWithPrefixAndSuffix) {
-  static const std::vector<std::string> kExpectedMatchesSorted = {"b.txt", "b/c.txt", "b/d.txt"};
-
-  AssertIterationOrder("b", ".txt", kExpectedMatchesSorted);
-}
-
-TEST(ziparchive, IterationWithAdditionalMatchesExactly) {
-  static const std::vector<std::string> kExpectedMatchesSorted = {"a.txt"};
-  auto matcher = [](std::string_view name) { return name == "a.txt"; };
-  AssertIterationOrderWithMatcher(matcher, kExpectedMatchesSorted);
-}
-
-TEST(ziparchive, IterationWithAdditionalMatchesWithSuffix) {
-  static const std::vector<std::string> kExpectedMatchesSorted = {"a.txt", "b.txt", "b/c.txt",
-                                                                  "b/d.txt"};
-  auto matcher = [](std::string_view name) {
-    return name == "a.txt" || android::base::EndsWith(name, ".txt");
-  };
-  AssertIterationOrderWithMatcher(matcher, kExpectedMatchesSorted);
-}
-
-TEST(ziparchive, IterationWithAdditionalMatchesWithPrefixAndSuffix) {
-  static const std::vector<std::string> kExpectedMatchesSorted = {"a.txt", "b/c.txt", "b/d.txt"};
-  auto matcher = [](std::string_view name) {
-    return name == "a.txt" ||
-           (android::base::EndsWith(name, ".txt") && android::base::StartsWith(name, "b/"));
-  };
-  AssertIterationOrderWithMatcher(matcher, kExpectedMatchesSorted);
-}
-
-TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
-
-  void* iteration_cookie;
-  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, "x", "y"));
-
-  ZipEntry64 data;
-  std::string_view name;
-
-  // End of iteration.
-  ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
-
-  CloseArchive(handle);
-}
-
-TEST(ziparchive, FindEntry) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
-
-  ZipEntry64 data;
-  ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
-
-  // Known facts about a.txt, from zipinfo -v.
-  ASSERT_EQ(63, data.offset);
-  ASSERT_EQ(kCompressDeflated, data.method);
-  ASSERT_EQ(17u, data.uncompressed_length);
-  ASSERT_EQ(13u, data.compressed_length);
-  ASSERT_EQ(0x950821c5, data.crc32);
-  ASSERT_EQ(static_cast<uint32_t>(0x438a8005), data.mod_time);
-
-  // An entry that doesn't exist. Should be a negative return code.
-  ASSERT_LT(FindEntry(handle, "this file does not exist", &data), 0);
-
-  CloseArchive(handle);
-}
-
-TEST(ziparchive, FindEntry_empty) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
-
-  ZipEntry64 data;
-  ASSERT_EQ(kInvalidEntryName, FindEntry(handle, "", &data));
-
-  CloseArchive(handle);
-}
-
-TEST(ziparchive, FindEntry_too_long) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
-
-  std::string very_long_name(65536, 'x');
-  ZipEntry64 data;
-  ASSERT_EQ(kInvalidEntryName, FindEntry(handle, very_long_name, &data));
-
-  CloseArchive(handle);
-}
-
-TEST(ziparchive, TestInvalidDeclaredLength) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle));
-
-  void* iteration_cookie;
-  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie));
-
-  std::string_view name;
-  ZipEntry64 data;
-
-  ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
-  ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
-
-  CloseArchive(handle);
-}
-
-TEST(ziparchive, OpenArchiveFdRange) {
-  TemporaryFile tmp_file;
-  ASSERT_NE(-1, tmp_file.fd);
-
-  const std::string leading_garbage(21, 'x');
-  ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, leading_garbage.c_str(),
-                                        leading_garbage.size()));
-
-  std::string valid_content;
-  ASSERT_TRUE(android::base::ReadFileToString(test_data_dir + "/" + kValidZip, &valid_content));
-  ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, valid_content.c_str(), valid_content.size()));
-
-  const std::string ending_garbage(42, 'x');
-  ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, ending_garbage.c_str(),
-                                        ending_garbage.size()));
-
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, lseek(tmp_file.fd, 0, SEEK_SET));
-  ASSERT_EQ(0, OpenArchiveFdRange(tmp_file.fd, "OpenArchiveFdRange", &handle,
-                                  valid_content.size(),
-                                  static_cast<off64_t>(leading_garbage.size())));
-
-  // An entry that's deflated.
-  ZipEntry64 data;
-  ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
-  const auto a_size = static_cast<size_t>(data.uncompressed_length);
-  ASSERT_EQ(a_size, kATxtContents.size());
-  auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[a_size]);
-  ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer.get(), a_size));
-  ASSERT_EQ(0, memcmp(buffer.get(), kATxtContents.data(), a_size));
-
-  // An entry that's stored.
-  ASSERT_EQ(0, FindEntry(handle, "b.txt", &data));
-  const auto b_size = static_cast<size_t>(data.uncompressed_length);
-  ASSERT_EQ(b_size, kBTxtContents.size());
-  buffer = std::unique_ptr<uint8_t[]>(new uint8_t[b_size]);
-  ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer.get(), b_size));
-  ASSERT_EQ(0, memcmp(buffer.get(), kBTxtContents.data(), b_size));
-
-  CloseArchive(handle);
-}
-
-TEST(ziparchive, ExtractToMemory) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
-
-  // An entry that's deflated.
-  ZipEntry64 data;
-  ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
-  const auto a_size = static_cast<size_t>(data.uncompressed_length);
-  ASSERT_EQ(a_size, kATxtContents.size());
-  uint8_t* buffer = new uint8_t[a_size];
-  ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
-  ASSERT_EQ(0, memcmp(buffer, kATxtContents.data(), a_size));
-  delete[] buffer;
-
-  // An entry that's stored.
-  ASSERT_EQ(0, FindEntry(handle, "b.txt", &data));
-  const auto b_size = static_cast<size_t>(data.uncompressed_length);
-  ASSERT_EQ(b_size, kBTxtContents.size());
-  buffer = new uint8_t[b_size];
-  ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
-  ASSERT_EQ(0, memcmp(buffer, kBTxtContents.data(), b_size));
-  delete[] buffer;
-
-  CloseArchive(handle);
-}
-
-static const uint32_t kEmptyEntriesZip[] = {
-    0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000, 0x00090000,
-    0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13, 0x52e25c24, 0x000b7875,
-    0x42890401, 0x88040000, 0x50000013, 0x1e02014b, 0x00000a03, 0x60000000, 0x00443863,
-    0x00000000, 0x00000000, 0x09000000, 0x00001800, 0x00000000, 0xa0000000, 0x00000081,
-    0x706d6500, 0x742e7974, 0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904,
-    0x13880400, 0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000};
-
-// This is a zip file containing a single entry (ab.txt) that contains
-// 90072 repetitions of the string "ab\n" and has an uncompressed length
-// of 270216 bytes.
-static const uint16_t kAbZip[] = {
-    0x4b50, 0x0403, 0x0014, 0x0000, 0x0008, 0x51d2, 0x4698, 0xc4b0, 0x2cda, 0x011b, 0x0000, 0x1f88,
-    0x0004, 0x0006, 0x001c, 0x6261, 0x742e, 0x7478, 0x5455, 0x0009, 0x7c03, 0x3a09, 0x7c55, 0x3a09,
-    0x7555, 0x0b78, 0x0100, 0x8904, 0x0042, 0x0400, 0x1388, 0x0000, 0xc2ed, 0x0d31, 0x0000, 0x030c,
-    0x7fa0, 0x3b2e, 0x22ff, 0xa2aa, 0x841f, 0x45fc, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
-    0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
-    0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
-    0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
-    0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
-    0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
-    0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
-    0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
-    0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
-    0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
-    0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
-    0x5555, 0x5555, 0x5555, 0x5555, 0xdd55, 0x502c, 0x014b, 0x1e02, 0x1403, 0x0000, 0x0800, 0xd200,
-    0x9851, 0xb046, 0xdac4, 0x1b2c, 0x0001, 0x8800, 0x041f, 0x0600, 0x1800, 0x0000, 0x0000, 0x0100,
-    0x0000, 0xa000, 0x0081, 0x0000, 0x6100, 0x2e62, 0x7874, 0x5574, 0x0554, 0x0300, 0x097c, 0x553a,
-    0x7875, 0x000b, 0x0401, 0x4289, 0x0000, 0x8804, 0x0013, 0x5000, 0x054b, 0x0006, 0x0000, 0x0100,
-    0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000};
-
-static const std::string kAbTxtName("ab.txt");
-static const size_t kAbUncompressedSize = 270216;
-
-TEST(ziparchive, EmptyEntries) {
-  TemporaryFile tmp_file;
-  ASSERT_NE(-1, tmp_file.fd);
-  ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
-
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle, false));
-
-  ZipEntry64 entry;
-  ASSERT_EQ(0, FindEntry(handle, "empty.txt", &entry));
-  ASSERT_EQ(0u, entry.uncompressed_length);
-  // Extraction to a 1 byte buffer should succeed.
-  uint8_t buffer[1];
-  ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
-  // Extraction to an empty buffer should succeed.
-  ASSERT_EQ(0, ExtractToMemory(handle, &entry, nullptr, 0));
-
-  TemporaryFile tmp_output_file;
-  ASSERT_NE(-1, tmp_output_file.fd);
-  ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
-
-  struct stat stat_buf;
-  ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
-  ASSERT_EQ(0, stat_buf.st_size);
-}
-
-TEST(ziparchive, EntryLargerThan32K) {
-  TemporaryFile tmp_file;
-  ASSERT_NE(-1, tmp_file.fd);
-  ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, reinterpret_cast<const uint8_t*>(kAbZip),
-                                        sizeof(kAbZip) - 1));
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EntryLargerThan32KTest", &handle, false));
-
-  ZipEntry64 entry;
-  ASSERT_EQ(0, FindEntry(handle, kAbTxtName, &entry));
-  ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
-
-  // Extract the entry to memory.
-  std::vector<uint8_t> buffer(kAbUncompressedSize);
-  ASSERT_EQ(0, ExtractToMemory(handle, &entry, &buffer[0], static_cast<uint32_t>(buffer.size())));
-
-  // Extract the entry to a file.
-  TemporaryFile tmp_output_file;
-  ASSERT_NE(-1, tmp_output_file.fd);
-  ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
-
-  // Make sure the extracted file size is as expected.
-  struct stat stat_buf;
-  ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
-  ASSERT_EQ(kAbUncompressedSize, static_cast<size_t>(stat_buf.st_size));
-
-  // Read the file back to a buffer and make sure the contents are
-  // the same as the memory buffer we extracted directly to.
-  std::vector<uint8_t> file_contents(kAbUncompressedSize);
-  ASSERT_EQ(0, lseek(tmp_output_file.fd, 0, SEEK_SET));
-  ASSERT_TRUE(android::base::ReadFully(tmp_output_file.fd, &file_contents[0], file_contents.size()));
-  ASSERT_EQ(file_contents, buffer);
-
-  for (int i = 0; i < 90072; ++i) {
-    const uint8_t* line = &file_contents[0] + (3 * i);
-    ASSERT_EQ('a', line[0]);
-    ASSERT_EQ('b', line[1]);
-    ASSERT_EQ('\n', line[2]);
-  }
-}
-
-TEST(ziparchive, TrailerAfterEOCD) {
-  TemporaryFile tmp_file;
-  ASSERT_NE(-1, tmp_file.fd);
-
-  // Create a file with 8 bytes of random garbage.
-  static const uint8_t trailer[] = {'A', 'n', 'd', 'r', 'o', 'i', 'd', 'z'};
-  ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
-  ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, trailer, sizeof(trailer)));
-
-  ZipArchiveHandle handle;
-  ASSERT_GT(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle, false));
-}
-
-TEST(ziparchive, ExtractToFile) {
-  TemporaryFile tmp_file;
-  ASSERT_NE(-1, tmp_file.fd);
-  const uint8_t data[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};
-  const size_t data_size = sizeof(data);
-
-  ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, data, data_size));
-
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
-
-  ZipEntry64 entry;
-  ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry));
-  ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_file.fd));
-
-  // Assert that the first 8 bytes of the file haven't been clobbered.
-  uint8_t read_buffer[data_size];
-  ASSERT_EQ(0, lseek(tmp_file.fd, 0, SEEK_SET));
-  ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, read_buffer, data_size));
-  ASSERT_EQ(0, memcmp(read_buffer, data, data_size));
-
-  // Assert that the remainder of the file contains the incompressed data.
-  std::vector<uint8_t> uncompressed_data(static_cast<size_t>(entry.uncompressed_length));
-  ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, uncompressed_data.data(),
-                                       static_cast<size_t>(entry.uncompressed_length)));
-  ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents.data(), kATxtContents.size()));
-
-  // Assert that the total length of the file is sane
-  ASSERT_EQ(static_cast<ssize_t>(data_size + kATxtContents.size()),
-            lseek(tmp_file.fd, 0, SEEK_END));
-}
-
-#if !defined(_WIN32)
-TEST(ziparchive, OpenFromMemory) {
-  const std::string zip_path = test_data_dir + "/dummy-update.zip";
-  android::base::unique_fd fd(open(zip_path.c_str(), O_RDONLY | O_BINARY));
-  ASSERT_NE(-1, fd);
-  struct stat sb;
-  ASSERT_EQ(0, fstat(fd, &sb));
-
-  // Memory map the file first and open the archive from the memory region.
-  auto file_map{
-      android::base::MappedFile::FromFd(fd, 0, static_cast<size_t>(sb.st_size), PROT_READ)};
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0,
-            OpenArchiveFromMemory(file_map->data(), file_map->size(), zip_path.c_str(), &handle));
-
-  // Assert one entry can be found and extracted correctly.
-  ZipEntry64 binary_entry;
-  ASSERT_EQ(0, FindEntry(handle, "META-INF/com/google/android/update-binary", &binary_entry));
-  TemporaryFile tmp_binary;
-  ASSERT_NE(-1, tmp_binary.fd);
-  ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd));
-}
-#endif
-
-static void ZipArchiveStreamTest(ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
-                                 bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
-  ASSERT_EQ(0, FindEntry(handle, entry_name, entry));
-  std::unique_ptr<ZipArchiveStreamEntry> stream;
-  if (raw) {
-    stream.reset(ZipArchiveStreamEntry::CreateRaw(handle, *entry));
-    if (entry->method == kCompressStored) {
-      read_data->resize(static_cast<size_t>(entry->uncompressed_length));
-    } else {
-      read_data->resize(static_cast<size_t>(entry->compressed_length));
-    }
-  } else {
-    stream.reset(ZipArchiveStreamEntry::Create(handle, *entry));
-    read_data->resize(static_cast<size_t>(entry->uncompressed_length));
-  }
-  uint8_t* read_data_ptr = read_data->data();
-  ASSERT_TRUE(stream.get() != nullptr);
-  const std::vector<uint8_t>* data;
-  uint64_t total_size = 0;
-  while ((data = stream->Read()) != nullptr) {
-    total_size += data->size();
-    memcpy(read_data_ptr, data->data(), data->size());
-    read_data_ptr += data->size();
-  }
-  ASSERT_EQ(verified, stream->Verify());
-  ASSERT_EQ(total_size, read_data->size());
-}
-
-static void ZipArchiveStreamTestUsingContents(const std::string& zip_file,
-                                              const std::string& entry_name,
-                                              const std::vector<uint8_t>& contents, bool raw) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
-
-  ZipEntry entry;
-  std::vector<uint8_t> read_data;
-  ZipArchiveStreamTest(handle, entry_name, raw, true, &entry, &read_data);
-
-  ASSERT_EQ(contents.size(), read_data.size());
-  ASSERT_TRUE(memcmp(read_data.data(), contents.data(), read_data.size()) == 0);
-
-  CloseArchive(handle);
-}
-
-static void ZipArchiveStreamTestUsingMemory(const std::string& zip_file,
-                                            const std::string& entry_name) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
-
-  ZipEntry entry;
-  std::vector<uint8_t> read_data;
-  ZipArchiveStreamTest(handle, entry_name, false, true, &entry, &read_data);
-
-  std::vector<uint8_t> cmp_data(static_cast<size_t>(entry.uncompressed_length));
-  ASSERT_EQ(entry.uncompressed_length, read_data.size());
-  ASSERT_EQ(
-      0, ExtractToMemory(handle, &entry, cmp_data.data(), static_cast<uint32_t>(cmp_data.size())));
-  ASSERT_TRUE(memcmp(read_data.data(), cmp_data.data(), read_data.size()) == 0);
-
-  CloseArchive(handle);
-}
-
-TEST(ziparchive, StreamCompressed) {
-  ZipArchiveStreamTestUsingContents(kValidZip, "a.txt", kATxtContents, false);
-}
-
-TEST(ziparchive, StreamUncompressed) {
-  ZipArchiveStreamTestUsingContents(kValidZip, "b.txt", kBTxtContents, false);
-}
-
-TEST(ziparchive, StreamRawCompressed) {
-  ZipArchiveStreamTestUsingContents(kValidZip, "a.txt", kATxtContentsCompressed, true);
-}
-
-TEST(ziparchive, StreamRawUncompressed) {
-  ZipArchiveStreamTestUsingContents(kValidZip, "b.txt", kBTxtContents, true);
-}
-
-TEST(ziparchive, StreamLargeCompressed) {
-  ZipArchiveStreamTestUsingMemory(kLargeZip, "compress.txt");
-}
-
-TEST(ziparchive, StreamLargeUncompressed) {
-  ZipArchiveStreamTestUsingMemory(kLargeZip, "uncompress.txt");
-}
-
-TEST(ziparchive, StreamCompressedBadCrc) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
-
-  ZipEntry entry;
-  std::vector<uint8_t> read_data;
-  ZipArchiveStreamTest(handle, "a.txt", false, false, &entry, &read_data);
-
-  CloseArchive(handle);
-}
-
-TEST(ziparchive, StreamUncompressedBadCrc) {
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
-
-  ZipEntry entry;
-  std::vector<uint8_t> read_data;
-  ZipArchiveStreamTest(handle, "b.txt", false, false, &entry, &read_data);
-
-  CloseArchive(handle);
-}
-
-// Generated using the following Java program:
-//     public static void main(String[] foo) throws Exception {
-//       FileOutputStream fos = new
-//       FileOutputStream("/tmp/data_descriptor.zip");
-//       ZipOutputStream zos = new ZipOutputStream(fos);
-//       ZipEntry64 ze = new ZipEntry64("name");
-//       ze.setMethod(ZipEntry64.DEFLATED);
-//       zos.putNextEntry(ze);
-//       zos.write("abdcdefghijk".getBytes());
-//       zos.closeEntry();
-//       zos.close();
-//     }
-//
-// cat /tmp/data_descriptor.zip | xxd -i
-//
-static const std::vector<uint8_t> kDataDescriptorZipFile{
-    0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x30, 0x59, 0xce, 0x4a, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6e, 0x61,
-    0x6d, 0x65, 0x4b, 0x4c, 0x4a, 0x49, 0x4e, 0x49, 0x4d, 0x4b, 0xcf, 0xc8, 0xcc, 0xca, 0x06, 0x00,
-    //[sig---------------], [crc32---------------], [csize---------------], [size----------------]
-    0x50, 0x4b, 0x07, 0x08, 0x3d, 0x4e, 0x0e, 0xf9, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
-    0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x30, 0x59, 0xce, 0x4a,
-    0x3d, 0x4e, 0x0e, 0xf9, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x61,
-    0x6d, 0x65, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x32, 0x00,
-    0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00};
-
-// The offsets of the data descriptor in this file, so we can mess with
-// them later in the test.
-static constexpr uint32_t kDataDescriptorOffset = 48;
-static constexpr uint32_t kCSizeOffset = kDataDescriptorOffset + 8;
-static constexpr uint32_t kSizeOffset = kCSizeOffset + 4;
-
-static void ExtractEntryToMemory(const std::vector<uint8_t>& zip_data,
-                                 std::vector<uint8_t>* entry_out, int32_t* error_code_out) {
-  TemporaryFile tmp_file;
-  ASSERT_NE(-1, tmp_file.fd);
-  ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, &zip_data[0], zip_data.size()));
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "ExtractEntryToMemory", &handle, false));
-
-  // This function expects a variant of kDataDescriptorZipFile, for look for
-  // an entry whose name is "name" and whose size is 12 (contents =
-  // "abdcdefghijk").
-  ZipEntry64 entry;
-  ASSERT_EQ(0, FindEntry(handle, "name", &entry));
-  ASSERT_EQ(12u, entry.uncompressed_length);
-
-  entry_out->resize(12);
-  (*error_code_out) = ExtractToMemory(handle, &entry, &((*entry_out)[0]), 12);
-
-  CloseArchive(handle);
-}
-
-TEST(ziparchive, ValidDataDescriptors) {
-  std::vector<uint8_t> entry;
-  int32_t error_code = 0;
-  ExtractEntryToMemory(kDataDescriptorZipFile, &entry, &error_code);
-
-  ASSERT_EQ(0, error_code);
-  ASSERT_EQ(12u, entry.size());
-  ASSERT_EQ('a', entry[0]);
-  ASSERT_EQ('k', entry[11]);
-}
-
-TEST(ziparchive, InvalidDataDescriptors_csize) {
-  std::vector<uint8_t> invalid_csize = kDataDescriptorZipFile;
-  invalid_csize[kCSizeOffset] = 0xfe;
-
-  std::vector<uint8_t> entry;
-  int32_t error_code = 0;
-  ExtractEntryToMemory(invalid_csize, &entry, &error_code);
-
-  ASSERT_EQ(kInconsistentInformation, error_code);
-}
-
-TEST(ziparchive, InvalidDataDescriptors_size) {
-  std::vector<uint8_t> invalid_size = kDataDescriptorZipFile;
-  invalid_size[kSizeOffset] = 0xfe;
-
-  std::vector<uint8_t> entry;
-  int32_t error_code = 0;
-  ExtractEntryToMemory(invalid_size, &entry, &error_code);
-
-  ASSERT_EQ(kInconsistentInformation, error_code);
-}
-
-TEST(ziparchive, ErrorCodeString) {
-  ASSERT_STREQ("Success", ErrorCodeString(0));
-
-  // Out of bounds.
-  ASSERT_STREQ("Unknown return code", ErrorCodeString(1));
-  ASSERT_STRNE("Unknown return code", ErrorCodeString(kLastErrorCode));
-  ASSERT_STREQ("Unknown return code", ErrorCodeString(kLastErrorCode - 1));
-
-  ASSERT_STREQ("I/O error", ErrorCodeString(kIoError));
-}
-
-// A zip file whose local file header at offset zero is corrupted.
-//
-// ---------------
-// cat foo > a.txt
-// zip a.zip a.txt
-// cat a.zip | xxd -i
-//
-// Manual changes :
-// [2] = 0xff  // Corrupt the LFH signature of entry 0.
-// [3] = 0xff  // Corrupt the LFH signature of entry 0.
-static const std::vector<uint8_t> kZipFileWithBrokenLfhSignature{
-    //[lfh-sig-----------], [lfh contents---------------------------------
-    0x50, 0x4b, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x80,
-    //--------------------------------------------------------------------
-    0x09, 0x4b, 0xa8, 0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
-    //-------------------------------]  [file-name-----------------], [---
-    0x00, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x55,
-    // entry-contents------------------------------------------------------
-    0x54, 0x09, 0x00, 0x03, 0x51, 0x24, 0x8b, 0x59, 0x51, 0x24, 0x8b, 0x59,
-    //--------------------------------------------------------------------
-    0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0x89, 0x42, 0x00, 0x00, 0x04, 0x88,
-    //-------------------------------------], [cd-record-sig-------], [---
-    0x13, 0x00, 0x00, 0x66, 0x6f, 0x6f, 0x0a, 0x50, 0x4b, 0x01, 0x02, 0x1e,
-    // cd-record-----------------------------------------------------------
-    0x03, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x80, 0x09, 0x4b, 0xa8,
-    //--------------------------------------------------------------------
-    0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05,
-    //--------------------------------------------------------------------
-    0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0,
-    //-]  [lfh-file-header-off-], [file-name-----------------], [extra----
-    0x81, 0x00, 0x00, 0x00, 0x00, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x55, 0x54,
-    //--------------------------------------------------------------------
-    0x05, 0x00, 0x03, 0x51, 0x24, 0x8b, 0x59, 0x75, 0x78, 0x0b, 0x00, 0x01,
-    //-------------------------------------------------------], [eocd-sig-
-    0x04, 0x89, 0x42, 0x00, 0x00, 0x04, 0x88, 0x13, 0x00, 0x00, 0x50, 0x4b,
-    //-------], [---------------------------------------------------------
-    0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x4b, 0x00,
-    //-------------------------------------------]
-    0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00};
-
-TEST(ziparchive, BrokenLfhSignature) {
-  TemporaryFile tmp_file;
-  ASSERT_NE(-1, tmp_file.fd);
-  ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, &kZipFileWithBrokenLfhSignature[0],
-                                        kZipFileWithBrokenLfhSignature.size()));
-  ZipArchiveHandle handle;
-  ASSERT_EQ(kInvalidFile, OpenArchiveFd(tmp_file.fd, "LeadingNonZipBytes", &handle, false));
-}
-
-class VectorReader : public zip_archive::Reader {
- public:
-  VectorReader(const std::vector<uint8_t>& input) : Reader(), input_(input) {}
-
-  bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const {
-    if ((offset + len) < input_.size()) {
-      return false;
-    }
-
-    memcpy(buf, &input_[static_cast<size_t>(offset)], len);
-    return true;
-  }
-
- private:
-  const std::vector<uint8_t>& input_;
-};
-
-class VectorWriter : public zip_archive::Writer {
- public:
-  VectorWriter() : Writer() {}
-
-  bool Append(uint8_t* buf, size_t size) {
-    output_.insert(output_.end(), buf, buf + size);
-    return true;
-  }
-
-  std::vector<uint8_t>& GetOutput() { return output_; }
-
- private:
-  std::vector<uint8_t> output_;
-};
-
-class BadReader : public zip_archive::Reader {
- public:
-  BadReader() : Reader() {}
-
-  bool ReadAtOffset(uint8_t*, size_t, off64_t) const { return false; }
-};
-
-class BadWriter : public zip_archive::Writer {
- public:
-  BadWriter() : Writer() {}
-
-  bool Append(uint8_t*, size_t) { return false; }
-};
-
-TEST(ziparchive, Inflate) {
-  const uint32_t compressed_length = static_cast<uint32_t>(kATxtContentsCompressed.size());
-  const uint32_t uncompressed_length = static_cast<uint32_t>(kATxtContents.size());
-
-  const VectorReader reader(kATxtContentsCompressed);
-  {
-    VectorWriter writer;
-    uint64_t crc_out = 0;
-
-    int32_t ret =
-        zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, &crc_out);
-    ASSERT_EQ(0, ret);
-    ASSERT_EQ(kATxtContents, writer.GetOutput());
-    ASSERT_EQ(0x950821C5u, crc_out);
-  }
-
-  {
-    VectorWriter writer;
-    int32_t ret =
-        zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, nullptr);
-    ASSERT_EQ(0, ret);
-    ASSERT_EQ(kATxtContents, writer.GetOutput());
-  }
-
-  {
-    BadWriter writer;
-    int32_t ret =
-        zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, nullptr);
-    ASSERT_EQ(kIoError, ret);
-  }
-
-  {
-    BadReader reader;
-    VectorWriter writer;
-    int32_t ret =
-        zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, nullptr);
-    ASSERT_EQ(kIoError, ret);
-    ASSERT_EQ(0u, writer.GetOutput().size());
-  }
-}
-
-// The class constructs a zipfile with zip64 format, and test the parsing logic.
-class Zip64ParseTest : public ::testing::Test {
- protected:
-  struct LocalFileEntry {
-    std::vector<uint8_t> local_file_header;
-    std::string file_name;
-    std::vector<uint8_t> extended_field;
-    // Fake data to mimic the compressed bytes in the zipfile.
-    std::vector<uint8_t> compressed_bytes;
-    std::vector<uint8_t> data_descriptor;
-
-    size_t GetSize() const {
-      return local_file_header.size() + file_name.size() + extended_field.size() +
-             compressed_bytes.size() + data_descriptor.size();
-    }
-
-    void CopyToOutput(std::vector<uint8_t>* output) const {
-      std::copy(local_file_header.begin(), local_file_header.end(), std::back_inserter(*output));
-      std::copy(file_name.begin(), file_name.end(), std::back_inserter(*output));
-      std::copy(extended_field.begin(), extended_field.end(), std::back_inserter(*output));
-      std::copy(compressed_bytes.begin(), compressed_bytes.end(), std::back_inserter(*output));
-      std::copy(data_descriptor.begin(), data_descriptor.end(), std::back_inserter(*output));
-    }
-  };
-
-  struct CdRecordEntry {
-    std::vector<uint8_t> central_directory_record;
-    std::string file_name;
-    std::vector<uint8_t> extended_field;
-
-    size_t GetSize() const {
-      return central_directory_record.size() + file_name.size() + extended_field.size();
-    }
-
-    void CopyToOutput(std::vector<uint8_t>* output) const {
-      std::copy(central_directory_record.begin(), central_directory_record.end(),
-                std::back_inserter(*output));
-      std::copy(file_name.begin(), file_name.end(), std::back_inserter(*output));
-      std::copy(extended_field.begin(), extended_field.end(), std::back_inserter(*output));
-    }
-  };
-
-  static void ConstructLocalFileHeader(const std::string& name, std::vector<uint8_t>* output,
-                                       uint32_t uncompressed_size, uint32_t compressed_size) {
-    LocalFileHeader lfh = {};
-    lfh.lfh_signature = LocalFileHeader::kSignature;
-    lfh.compressed_size = compressed_size;
-    lfh.uncompressed_size = uncompressed_size;
-    lfh.file_name_length = static_cast<uint16_t>(name.size());
-    lfh.extra_field_length = 20;
-    *output = std::vector<uint8_t>(reinterpret_cast<uint8_t*>(&lfh),
-                                   reinterpret_cast<uint8_t*>(&lfh) + sizeof(LocalFileHeader));
-  }
-
-  // Put one zip64 extended info in the extended field.
-  static void ConstructExtendedField(const std::vector<uint64_t>& zip64_fields,
-                                     std::vector<uint8_t>* output) {
-    ASSERT_FALSE(zip64_fields.empty());
-    uint16_t data_size = 8 * static_cast<uint16_t>(zip64_fields.size());
-    std::vector<uint8_t> extended_field(data_size + 4);
-    android::base::put_unaligned(extended_field.data(), Zip64ExtendedInfo::kHeaderId);
-    android::base::put_unaligned(extended_field.data() + 2, data_size);
-    size_t offset = 4;
-    for (const auto& field : zip64_fields) {
-      android::base::put_unaligned(extended_field.data() + offset, field);
-      offset += 8;
-    }
-
-    *output = std::move(extended_field);
-  }
-
-  static void ConstructCentralDirectoryRecord(const std::string& name, uint32_t uncompressed_size,
-                                              uint32_t compressed_size, uint32_t local_offset,
-                                              std::vector<uint8_t>* output) {
-    CentralDirectoryRecord cdr = {};
-    cdr.record_signature = CentralDirectoryRecord::kSignature;
-    cdr.compressed_size = uncompressed_size;
-    cdr.uncompressed_size = compressed_size;
-    cdr.file_name_length = static_cast<uint16_t>(name.size());
-    cdr.extra_field_length = local_offset == UINT32_MAX ? 28 : 20;
-    cdr.local_file_header_offset = local_offset;
-    *output =
-        std::vector<uint8_t>(reinterpret_cast<uint8_t*>(&cdr),
-                             reinterpret_cast<uint8_t*>(&cdr) + sizeof(CentralDirectoryRecord));
-  }
-
-  // Add an entry to the zipfile, construct the corresponding local header and cd entry.
-  void AddEntry(const std::string& name, const std::vector<uint8_t>& content,
-                bool uncompressed_size_in_extended, bool compressed_size_in_extended,
-                bool local_offset_in_extended, bool include_data_descriptor = false) {
-    auto uncompressed_size = static_cast<uint32_t>(content.size());
-    auto compressed_size = static_cast<uint32_t>(content.size());
-    uint32_t local_file_header_offset = 0;
-    std::for_each(file_entries_.begin(), file_entries_.end(),
-                  [&local_file_header_offset](const LocalFileEntry& file_entry) {
-                    local_file_header_offset += file_entry.GetSize();
-                  });
-
-    std::vector<uint64_t> zip64_fields;
-    if (uncompressed_size_in_extended) {
-      zip64_fields.push_back(uncompressed_size);
-      uncompressed_size = UINT32_MAX;
-    }
-    if (compressed_size_in_extended) {
-      zip64_fields.push_back(compressed_size);
-      compressed_size = UINT32_MAX;
-    }
-    LocalFileEntry local_entry = {
-        .local_file_header = {},
-        .file_name = name,
-        .extended_field = {},
-        .compressed_bytes = content,
-    };
-    ConstructLocalFileHeader(name, &local_entry.local_file_header, uncompressed_size,
-                             compressed_size);
-    ConstructExtendedField(zip64_fields, &local_entry.extended_field);
-    if (include_data_descriptor) {
-      size_t descriptor_size = compressed_size_in_extended ? 24 : 16;
-      local_entry.data_descriptor.resize(descriptor_size);
-      uint8_t* write_ptr = local_entry.data_descriptor.data();
-      EmitUnaligned<uint32_t>(&write_ptr, DataDescriptor::kOptSignature);
-      EmitUnaligned<uint32_t>(&write_ptr, 0 /* crc */);
-      if (compressed_size_in_extended) {
-        EmitUnaligned<uint64_t>(&write_ptr, compressed_size_in_extended);
-        EmitUnaligned<uint64_t>(&write_ptr, uncompressed_size_in_extended);
-      } else {
-        EmitUnaligned<uint32_t>(&write_ptr, compressed_size_in_extended);
-        EmitUnaligned<uint32_t>(&write_ptr, uncompressed_size_in_extended);
-      }
-    }
-
-    file_entries_.push_back(std::move(local_entry));
-
-    if (local_offset_in_extended) {
-      zip64_fields.push_back(local_file_header_offset);
-      local_file_header_offset = UINT32_MAX;
-    }
-    CdRecordEntry cd_entry = {
-        .central_directory_record = {},
-        .file_name = name,
-        .extended_field = {},
-    };
-    ConstructCentralDirectoryRecord(name, uncompressed_size, compressed_size,
-                                    local_file_header_offset, &cd_entry.central_directory_record);
-    ConstructExtendedField(zip64_fields, &cd_entry.extended_field);
-    cd_entries_.push_back(std::move(cd_entry));
-  }
-
-  void ConstructEocd() {
-    ASSERT_EQ(file_entries_.size(), cd_entries_.size());
-    Zip64EocdRecord zip64_eocd = {};
-    zip64_eocd.record_signature = Zip64EocdRecord::kSignature;
-    zip64_eocd.num_records = file_entries_.size();
-    zip64_eocd.cd_size = 0;
-    std::for_each(
-        cd_entries_.begin(), cd_entries_.end(),
-        [&zip64_eocd](const CdRecordEntry& cd_entry) { zip64_eocd.cd_size += cd_entry.GetSize(); });
-    zip64_eocd.cd_start_offset = 0;
-    std::for_each(file_entries_.begin(), file_entries_.end(),
-                  [&zip64_eocd](const LocalFileEntry& file_entry) {
-                    zip64_eocd.cd_start_offset += file_entry.GetSize();
-                  });
-    zip64_eocd_record_ =
-        std::vector<uint8_t>(reinterpret_cast<uint8_t*>(&zip64_eocd),
-                             reinterpret_cast<uint8_t*>(&zip64_eocd) + sizeof(Zip64EocdRecord));
-
-    Zip64EocdLocator zip64_locator = {};
-    zip64_locator.locator_signature = Zip64EocdLocator::kSignature;
-    zip64_locator.zip64_eocd_offset = zip64_eocd.cd_start_offset + zip64_eocd.cd_size;
-    zip64_eocd_locator_ =
-        std::vector<uint8_t>(reinterpret_cast<uint8_t*>(&zip64_locator),
-                             reinterpret_cast<uint8_t*>(&zip64_locator) + sizeof(Zip64EocdLocator));
-
-    EocdRecord eocd = {};
-    eocd.eocd_signature = EocdRecord::kSignature,
-    eocd.num_records = file_entries_.size() > UINT16_MAX
-                           ? UINT16_MAX
-                           : static_cast<uint16_t>(file_entries_.size());
-    eocd.cd_size = UINT32_MAX;
-    eocd.cd_start_offset = UINT32_MAX;
-    eocd_record_ = std::vector<uint8_t>(reinterpret_cast<uint8_t*>(&eocd),
-                                        reinterpret_cast<uint8_t*>(&eocd) + sizeof(EocdRecord));
-  }
-
-  // Concatenate all the local file entries, cd entries, and eocd metadata.
-  void ConstructZipFile() {
-    for (const auto& file_entry : file_entries_) {
-      file_entry.CopyToOutput(&zip_content_);
-    }
-    for (const auto& cd_entry : cd_entries_) {
-      cd_entry.CopyToOutput(&zip_content_);
-    }
-    std::copy(zip64_eocd_record_.begin(), zip64_eocd_record_.end(),
-              std::back_inserter(zip_content_));
-    std::copy(zip64_eocd_locator_.begin(), zip64_eocd_locator_.end(),
-              std::back_inserter(zip_content_));
-    std::copy(eocd_record_.begin(), eocd_record_.end(), std::back_inserter(zip_content_));
-  }
-
-  std::vector<uint8_t> zip_content_;
-
-  std::vector<LocalFileEntry> file_entries_;
-  std::vector<CdRecordEntry> cd_entries_;
-  std::vector<uint8_t> zip64_eocd_record_;
-  std::vector<uint8_t> zip64_eocd_locator_;
-  std::vector<uint8_t> eocd_record_;
-};
-
-TEST_F(Zip64ParseTest, openFile) {
-  AddEntry("a.txt", std::vector<uint8_t>(100, 'a'), true, true, false);
-  ConstructEocd();
-  ConstructZipFile();
-
-  ZipArchiveHandle handle;
-  ASSERT_EQ(
-      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
-  CloseArchive(handle);
-}
-
-TEST_F(Zip64ParseTest, openFilelocalOffsetInExtendedField) {
-  AddEntry("a.txt", std::vector<uint8_t>(100, 'a'), true, true, true);
-  AddEntry("b.txt", std::vector<uint8_t>(200, 'b'), true, true, true);
-  ConstructEocd();
-  ConstructZipFile();
-
-  ZipArchiveHandle handle;
-  ASSERT_EQ(
-      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
-  CloseArchive(handle);
-}
-
-TEST_F(Zip64ParseTest, openFileCompressedNotInExtendedField) {
-  AddEntry("a.txt", std::vector<uint8_t>(100, 'a'), true, false, false);
-  ConstructEocd();
-  ConstructZipFile();
-
-  ZipArchiveHandle handle;
-  // Zip64 extended fields must include both uncompressed and compressed size.
-  ASSERT_NE(
-      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
-  CloseArchive(handle);
-}
-
-TEST_F(Zip64ParseTest, findEntry) {
-  AddEntry("a.txt", std::vector<uint8_t>(200, 'a'), true, true, true);
-  AddEntry("b.txt", std::vector<uint8_t>(300, 'b'), true, true, false);
-  ConstructEocd();
-  ConstructZipFile();
-
-  ZipArchiveHandle handle;
-  ASSERT_EQ(
-      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
-  ZipEntry64 entry;
-  ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry));
-  ASSERT_EQ(200, entry.uncompressed_length);
-  ASSERT_EQ(200, entry.compressed_length);
-
-  ASSERT_EQ(0, FindEntry(handle, "b.txt", &entry));
-  ASSERT_EQ(300, entry.uncompressed_length);
-  ASSERT_EQ(300, entry.compressed_length);
-  CloseArchive(handle);
-}
-
-TEST_F(Zip64ParseTest, openFileIncorrectDataSizeInLocalExtendedField) {
-  AddEntry("a.txt", std::vector<uint8_t>(100, 'a'), true, true, false);
-  ASSERT_EQ(1, file_entries_.size());
-  auto& extended_field = file_entries_[0].extended_field;
-  // data size exceeds the extended field size in local header.
-  android::base::put_unaligned<uint16_t>(extended_field.data() + 2, 30);
-  ConstructEocd();
-  ConstructZipFile();
-
-  ZipArchiveHandle handle;
-  ASSERT_EQ(
-      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
-  ZipEntry64 entry;
-  ASSERT_NE(0, FindEntry(handle, "a.txt", &entry));
-
-  CloseArchive(handle);
-}
-
-TEST_F(Zip64ParseTest, iterates) {
-  std::set<std::string_view> names{"a.txt", "b.txt", "c.txt", "d.txt", "e.txt"};
-  for (const auto& name : names) {
-    AddEntry(std::string(name), std::vector<uint8_t>(100, name[0]), true, true, true);
-  }
-  ConstructEocd();
-  ConstructZipFile();
-
-  ZipArchiveHandle handle;
-  ASSERT_EQ(
-      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
-
-  void* iteration_cookie;
-  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie));
-  std::set<std::string_view> result;
-  std::string_view name;
-  ZipEntry64 entry;
-  while (Next(iteration_cookie, &entry, &name) == 0) result.emplace(name);
-  ASSERT_EQ(names, result);
-
-  CloseArchive(handle);
-}
-
-TEST_F(Zip64ParseTest, zip64EocdWrongLocatorOffset) {
-  AddEntry("a.txt", std::vector<uint8_t>(1, 'a'), true, true, true);
-  ConstructEocd();
-  zip_content_.resize(20, 'a');
-  std::copy(zip64_eocd_locator_.begin(), zip64_eocd_locator_.end(),
-            std::back_inserter(zip_content_));
-  std::copy(eocd_record_.begin(), eocd_record_.end(), std::back_inserter(zip_content_));
-
-  ZipArchiveHandle handle;
-  ASSERT_NE(
-      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
-  CloseArchive(handle);
-}
-
-TEST_F(Zip64ParseTest, extract) {
-  std::vector<uint8_t> content(200, 'a');
-  AddEntry("a.txt", content, true, true, true);
-  ConstructEocd();
-  ConstructZipFile();
-
-  ZipArchiveHandle handle;
-  ASSERT_EQ(
-      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
-  ZipEntry64 entry;
-  ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry));
-
-  VectorWriter writer;
-  ASSERT_EQ(0, ExtractToWriter(handle, &entry, &writer));
-  ASSERT_EQ(content, writer.GetOutput());
-}
-
-TEST_F(Zip64ParseTest, extractWithDataDescriptor) {
-  std::vector<uint8_t> content(300, 'b');
-  AddEntry("a.txt", std::vector<uint8_t>(200, 'a'), true, true, true);
-  AddEntry("b.txt", content, true, true, true, true /* data descriptor */);
-  ConstructEocd();
-  ConstructZipFile();
-
-  ZipArchiveHandle handle;
-  ASSERT_EQ(
-      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
-  ZipEntry64 entry;
-  ASSERT_EQ(0, FindEntry(handle, "b.txt", &entry));
-
-  VectorWriter writer;
-  ASSERT_EQ(0, ExtractToWriter(handle, &entry, &writer));
-  ASSERT_EQ(content, writer.GetOutput());
-}
diff --git a/libziparchive/zip_cd_entry_map.cc b/libziparchive/zip_cd_entry_map.cc
deleted file mode 100644
index f187c06..0000000
--- a/libziparchive/zip_cd_entry_map.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2020 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 "zip_cd_entry_map.h"
-
-#include <android-base/logging.h>
-#include <log/log.h>
-
-/*
- * Round up to the next highest power of 2.
- *
- * Found on http://graphics.stanford.edu/~seander/bithacks.html.
- */
-static uint32_t RoundUpPower2(uint32_t val) {
-  val--;
-  val |= val >> 1;
-  val |= val >> 2;
-  val |= val >> 4;
-  val |= val >> 8;
-  val |= val >> 16;
-  val++;
-
-  return val;
-}
-
-static uint32_t ComputeHash(std::string_view name) {
-  return static_cast<uint32_t>(std::hash<std::string_view>{}(name));
-}
-
-// Convert a ZipEntry to a hash table index, verifying that it's in a valid range.
-std::pair<ZipError, uint64_t> CdEntryMapZip32::GetCdEntryOffset(std::string_view name,
-                                                                const uint8_t* start) const {
-  const uint32_t hash = ComputeHash(name);
-
-  // NOTE: (hash_table_size - 1) is guaranteed to be non-negative.
-  uint32_t ent = hash & (hash_table_size_ - 1);
-  while (hash_table_[ent].name_offset != 0) {
-    if (hash_table_[ent].ToStringView(start) == name) {
-      return {kSuccess, hash_table_[ent].name_offset};
-    }
-    ent = (ent + 1) & (hash_table_size_ - 1);
-  }
-
-  ALOGV("Zip: Unable to find entry %.*s", static_cast<int>(name.size()), name.data());
-  return {kEntryNotFound, 0};
-}
-
-ZipError CdEntryMapZip32::AddToMap(std::string_view name, const uint8_t* start) {
-  const uint64_t hash = ComputeHash(name);
-  uint32_t ent = hash & (hash_table_size_ - 1);
-
-  /*
-   * We over-allocated the table, so we're guaranteed to find an empty slot.
-   * Further, we guarantee that the hashtable size is not 0.
-   */
-  while (hash_table_[ent].name_offset != 0) {
-    if (hash_table_[ent].ToStringView(start) == name) {
-      // We've found a duplicate entry. We don't accept duplicates.
-      ALOGW("Zip: Found duplicate entry %.*s", static_cast<int>(name.size()), name.data());
-      return kDuplicateEntry;
-    }
-    ent = (ent + 1) & (hash_table_size_ - 1);
-  }
-
-  // `name` has already been validated before entry.
-  const char* start_char = reinterpret_cast<const char*>(start);
-  hash_table_[ent].name_offset = static_cast<uint32_t>(name.data() - start_char);
-  hash_table_[ent].name_length = static_cast<uint16_t>(name.size());
-  return kSuccess;
-}
-
-void CdEntryMapZip32::ResetIteration() {
-  current_position_ = 0;
-}
-
-std::pair<std::string_view, uint64_t> CdEntryMapZip32::Next(const uint8_t* cd_start) {
-  while (current_position_ < hash_table_size_) {
-    const auto& entry = hash_table_[current_position_];
-    current_position_ += 1;
-
-    if (entry.name_offset != 0) {
-      return {entry.ToStringView(cd_start), entry.name_offset};
-    }
-  }
-  // We have reached the end of the hash table.
-  return {};
-}
-
-CdEntryMapZip32::CdEntryMapZip32(uint16_t num_entries) {
-  /*
-   * Create hash table.  We have a minimum 75% load factor, possibly as
-   * low as 50% after we round off to a power of 2.  There must be at
-   * least one unused entry to avoid an infinite loop during creation.
-   */
-  hash_table_size_ = RoundUpPower2(1 + (num_entries * 4) / 3);
-  hash_table_ = {
-      reinterpret_cast<ZipStringOffset*>(calloc(hash_table_size_, sizeof(ZipStringOffset))), free};
-}
-
-std::unique_ptr<CdEntryMapInterface> CdEntryMapZip32::Create(uint16_t num_entries) {
-  auto entry_map = new CdEntryMapZip32(num_entries);
-  CHECK(entry_map->hash_table_ != nullptr)
-      << "Zip: unable to allocate the " << entry_map->hash_table_size_
-      << " entry hash_table, entry size: " << sizeof(ZipStringOffset);
-  return std::unique_ptr<CdEntryMapInterface>(entry_map);
-}
-
-std::unique_ptr<CdEntryMapInterface> CdEntryMapZip64::Create() {
-  return std::unique_ptr<CdEntryMapInterface>(new CdEntryMapZip64());
-}
-
-ZipError CdEntryMapZip64::AddToMap(std::string_view name, const uint8_t* start) {
-  const auto [it, added] =
-      entry_table_.insert({name, name.data() - reinterpret_cast<const char*>(start)});
-  if (!added) {
-    ALOGW("Zip: Found duplicate entry %.*s", static_cast<int>(name.size()), name.data());
-    return kDuplicateEntry;
-  }
-  return kSuccess;
-}
-
-std::pair<ZipError, uint64_t> CdEntryMapZip64::GetCdEntryOffset(std::string_view name,
-                                                                const uint8_t* /*cd_start*/) const {
-  const auto it = entry_table_.find(name);
-  if (it == entry_table_.end()) {
-    ALOGV("Zip: Could not find entry %.*s", static_cast<int>(name.size()), name.data());
-    return {kEntryNotFound, 0};
-  }
-
-  return {kSuccess, it->second};
-}
-
-void CdEntryMapZip64::ResetIteration() {
-  iterator_ = entry_table_.begin();
-}
-
-std::pair<std::string_view, uint64_t> CdEntryMapZip64::Next(const uint8_t* /*cd_start*/) {
-  if (iterator_ == entry_table_.end()) {
-    return {};
-  }
-
-  return *iterator_++;
-}
diff --git a/libziparchive/zip_cd_entry_map.h b/libziparchive/zip_cd_entry_map.h
deleted file mode 100644
index 4957f75..0000000
--- a/libziparchive/zip_cd_entry_map.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2020 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 <map>
-#include <memory>
-#include <string_view>
-#include <utility>
-
-#include "zip_error.h"
-
-// This class is the interface of the central directory entries map. The map
-// helps to locate a particular cd entry based on the filename.
-class CdEntryMapInterface {
- public:
-  virtual ~CdEntryMapInterface() = default;
-  // Adds an entry to the map. The |name| should internally points to the
-  // filename field of a cd entry. And |start| points to the beginning of the
-  // central directory. Returns 0 on success.
-  virtual ZipError AddToMap(std::string_view name, const uint8_t* start) = 0;
-  // For the zip entry |entryName|, finds the offset of its filename field in
-  // the central directory. Returns a pair of [status, offset]. The value of
-  // the status is 0 on success.
-  virtual std::pair<ZipError, uint64_t> GetCdEntryOffset(std::string_view name,
-                                                         const uint8_t* cd_start) const = 0;
-  // Resets the iterator to the beginning of the map.
-  virtual void ResetIteration() = 0;
-  // Returns the [name, cd offset] of the current element. Also increments the
-  // iterator to points to the next element. Returns an empty pair we have read
-  // past boundary.
-  virtual std::pair<std::string_view, uint64_t> Next(const uint8_t* cd_start) = 0;
-};
-
-/**
- * More space efficient string representation of strings in an mmaped zipped
- * file than std::string_view. Using std::string_view as an entry in the
- * ZipArchive hash table wastes space. std::string_view stores a pointer to a
- * string (on 64 bit, 8 bytes) and the length to read from that pointer,
- * 2 bytes. Because of alignment, the structure consumes 16 bytes, wasting
- * 6 bytes.
- *
- * ZipStringOffset stores a 4 byte offset from a fixed location in the memory
- * mapped file instead of the entire address, consuming 8 bytes with alignment.
- */
-struct ZipStringOffset {
-  uint32_t name_offset;
-  uint16_t name_length;
-
-  const std::string_view ToStringView(const uint8_t* start) const {
-    return std::string_view{reinterpret_cast<const char*>(start + name_offset), name_length};
-  }
-};
-
-// This implementation of CdEntryMap uses an array hash table. It uses less
-// memory than std::map; and it's used as the default implementation for zip
-// archives without zip64 extension.
-class CdEntryMapZip32 : public CdEntryMapInterface {
- public:
-  static std::unique_ptr<CdEntryMapInterface> Create(uint16_t num_entries);
-
-  ZipError AddToMap(std::string_view name, const uint8_t* start) override;
-  std::pair<ZipError, uint64_t> GetCdEntryOffset(std::string_view name,
-                                                 const uint8_t* cd_start) const override;
-  void ResetIteration() override;
-  std::pair<std::string_view, uint64_t> Next(const uint8_t* cd_start) override;
-
- private:
-  explicit CdEntryMapZip32(uint16_t num_entries);
-
-  // We know how many entries are in the Zip archive, so we can have a
-  // fixed-size hash table. We define a load factor of 0.75 and over
-  // allocate so the maximum number entries can never be higher than
-  // ((4 * UINT16_MAX) / 3 + 1) which can safely fit into a uint32_t.
-  uint32_t hash_table_size_{0};
-  std::unique_ptr<ZipStringOffset[], decltype(&free)> hash_table_{nullptr, free};
-
-  // The position of element for the current iteration.
-  uint32_t current_position_{0};
-};
-
-// This implementation of CdEntryMap uses a std::map
-class CdEntryMapZip64 : public CdEntryMapInterface {
- public:
-  static std::unique_ptr<CdEntryMapInterface> Create();
-
-  ZipError AddToMap(std::string_view name, const uint8_t* start) override;
-  std::pair<ZipError, uint64_t> GetCdEntryOffset(std::string_view name,
-                                                 const uint8_t* cd_start) const override;
-  void ResetIteration() override;
-  std::pair<std::string_view, uint64_t> Next(const uint8_t* cd_start) override;
-
- private:
-  CdEntryMapZip64() = default;
-
-  std::map<std::string_view, uint64_t> entry_table_;
-
-  std::map<std::string_view, uint64_t>::iterator iterator_;
-};
diff --git a/libziparchive/zip_error.cpp b/libziparchive/zip_error.cpp
deleted file mode 100644
index 14e49bb..0000000
--- a/libziparchive/zip_error.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * 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 "zip_error.h"
-
-#include <android-base/macros.h>
-
-static const char* kErrorMessages[] = {
-    "Success",
-    "Iteration ended",
-    "Zlib error",
-    "Invalid file",
-    "Invalid handle",
-    "Duplicate entries in archive",
-    "Empty archive",
-    "Entry not found",
-    "Invalid offset",
-    "Inconsistent information",
-    "Invalid entry name",
-    "I/O error",
-    "File mapping failed",
-    "Allocation failed",
-    "Unsupported zip entry size",
-};
-
-const char* ErrorCodeString(int32_t error_code) {
-  // Make sure that the number of entries in kErrorMessages and the ZipError
-  // enum match.
-  static_assert((-kLastErrorCode + 1) == arraysize(kErrorMessages),
-                "(-kLastErrorCode + 1) != arraysize(kErrorMessages)");
-
-  const uint32_t idx = -error_code;
-  if (idx < arraysize(kErrorMessages)) {
-    return kErrorMessages[idx];
-  }
-
-  return "Unknown return code";
-}
diff --git a/libziparchive/zip_error.h b/libziparchive/zip_error.h
deleted file mode 100644
index 3d7285d..0000000
--- a/libziparchive/zip_error.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2020 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>
-
-enum ZipError : int32_t {
-  kSuccess = 0,
-
-  kIterationEnd = -1,
-
-  // We encountered a Zlib error when inflating a stream from this file.
-  // Usually indicates file corruption.
-  kZlibError = -2,
-
-  // The input file cannot be processed as a zip archive. Usually because
-  // it's too small, too large or does not have a valid signature.
-  kInvalidFile = -3,
-
-  // An invalid iteration / ziparchive handle was passed in as an input
-  // argument.
-  kInvalidHandle = -4,
-
-  // The zip archive contained two (or possibly more) entries with the same
-  // name.
-  kDuplicateEntry = -5,
-
-  // The zip archive contains no entries.
-  kEmptyArchive = -6,
-
-  // The specified entry was not found in the archive.
-  kEntryNotFound = -7,
-
-  // The zip archive contained an invalid local file header pointer.
-  kInvalidOffset = -8,
-
-  // The zip archive contained inconsistent entry information. This could
-  // be because the central directory & local file header did not agree, or
-  // if the actual uncompressed length or crc32 do not match their declared
-  // values.
-  kInconsistentInformation = -9,
-
-  // An invalid entry name was encountered.
-  kInvalidEntryName = -10,
-
-  // An I/O related system call (read, lseek, ftruncate, map) failed.
-  kIoError = -11,
-
-  // We were not able to mmap the central directory or entry contents.
-  kMmapFailed = -12,
-
-  // An allocation failed.
-  kAllocationFailed = -13,
-
-  // The compressed or uncompressed size is larger than UINT32_MAX and
-  // doesn't fit into the 32 bits zip entry.
-  kUnsupportedEntrySize = -14,
-
-  kLastErrorCode = kUnsupportedEntrySize,
-};
diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc
deleted file mode 100644
index 25b1da4..0000000
--- a/libziparchive/zip_writer.cc
+++ /dev/null
@@ -1,579 +0,0 @@
-/*
- * Copyright (C) 2015 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 "ziparchive/zip_writer.h"
-
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <zlib.h>
-#include <cstdio>
-#define DEF_MEM_LEVEL 8  // normally in zutil.h?
-
-#include <memory>
-#include <vector>
-
-#include "android-base/logging.h"
-
-#include "entry_name_utils-inl.h"
-#include "zip_archive_common.h"
-
-#undef powerof2
-#define powerof2(x)                                               \
-  ({                                                              \
-    __typeof__(x) _x = (x);                                       \
-    __typeof__(x) _x2;                                            \
-    __builtin_add_overflow(_x, -1, &_x2) ? 1 : ((_x2 & _x) == 0); \
-  })
-
-/* Zip compression methods we support */
-enum {
-  kCompressStored = 0,    // no compression
-  kCompressDeflated = 8,  // standard deflate
-};
-
-// Size of the output buffer used for compression.
-static const size_t kBufSize = 32768u;
-
-// No error, operation completed successfully.
-static const int32_t kNoError = 0;
-
-// The ZipWriter is in a bad state.
-static const int32_t kInvalidState = -1;
-
-// There was an IO error while writing to disk.
-static const int32_t kIoError = -2;
-
-// The zip entry name was invalid.
-static const int32_t kInvalidEntryName = -3;
-
-// An error occurred in zlib.
-static const int32_t kZlibError = -4;
-
-// The start aligned function was called with the aligned flag.
-static const int32_t kInvalidAlign32Flag = -5;
-
-// The alignment parameter is not a power of 2.
-static const int32_t kInvalidAlignment = -6;
-
-static const char* sErrorCodes[] = {
-    "Invalid state", "IO error", "Invalid entry name", "Zlib error",
-};
-
-const char* ZipWriter::ErrorCodeString(int32_t error_code) {
-  if (error_code < 0 && (-error_code) < static_cast<int32_t>(arraysize(sErrorCodes))) {
-    return sErrorCodes[-error_code];
-  }
-  return nullptr;
-}
-
-static void DeleteZStream(z_stream* stream) {
-  deflateEnd(stream);
-  delete stream;
-}
-
-ZipWriter::ZipWriter(FILE* f)
-    : file_(f),
-      seekable_(false),
-      current_offset_(0),
-      state_(State::kWritingZip),
-      z_stream_(nullptr, DeleteZStream),
-      buffer_(kBufSize) {
-  // Check if the file is seekable (regular file). If fstat fails, that's fine, subsequent calls
-  // will fail as well.
-  struct stat file_stats;
-  if (fstat(fileno(f), &file_stats) == 0) {
-    seekable_ = S_ISREG(file_stats.st_mode);
-  }
-}
-
-ZipWriter::ZipWriter(ZipWriter&& writer) noexcept
-    : file_(writer.file_),
-      seekable_(writer.seekable_),
-      current_offset_(writer.current_offset_),
-      state_(writer.state_),
-      files_(std::move(writer.files_)),
-      z_stream_(std::move(writer.z_stream_)),
-      buffer_(std::move(writer.buffer_)) {
-  writer.file_ = nullptr;
-  writer.state_ = State::kError;
-}
-
-ZipWriter& ZipWriter::operator=(ZipWriter&& writer) noexcept {
-  file_ = writer.file_;
-  seekable_ = writer.seekable_;
-  current_offset_ = writer.current_offset_;
-  state_ = writer.state_;
-  files_ = std::move(writer.files_);
-  z_stream_ = std::move(writer.z_stream_);
-  buffer_ = std::move(writer.buffer_);
-  writer.file_ = nullptr;
-  writer.state_ = State::kError;
-  return *this;
-}
-
-int32_t ZipWriter::HandleError(int32_t error_code) {
-  state_ = State::kError;
-  z_stream_.reset();
-  return error_code;
-}
-
-int32_t ZipWriter::StartEntry(std::string_view path, size_t flags) {
-  uint32_t alignment = 0;
-  if (flags & kAlign32) {
-    flags &= ~kAlign32;
-    alignment = 4;
-  }
-  return StartAlignedEntryWithTime(path, flags, time_t(), alignment);
-}
-
-int32_t ZipWriter::StartAlignedEntry(std::string_view path, size_t flags, uint32_t alignment) {
-  return StartAlignedEntryWithTime(path, flags, time_t(), alignment);
-}
-
-int32_t ZipWriter::StartEntryWithTime(std::string_view path, size_t flags, time_t time) {
-  uint32_t alignment = 0;
-  if (flags & kAlign32) {
-    flags &= ~kAlign32;
-    alignment = 4;
-  }
-  return StartAlignedEntryWithTime(path, flags, time, alignment);
-}
-
-static void ExtractTimeAndDate(time_t when, uint16_t* out_time, uint16_t* out_date) {
-  /* round up to an even number of seconds */
-  when = static_cast<time_t>((static_cast<unsigned long>(when) + 1) & (~1));
-
-  struct tm* ptm;
-#if !defined(_WIN32)
-  struct tm tm_result;
-  ptm = localtime_r(&when, &tm_result);
-#else
-  ptm = localtime(&when);
-#endif
-
-  int year = ptm->tm_year;
-  if (year < 80) {
-    year = 80;
-  }
-
-  *out_date = static_cast<uint16_t>((year - 80) << 9 | (ptm->tm_mon + 1) << 5 | ptm->tm_mday);
-  *out_time = static_cast<uint16_t>(ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1);
-}
-
-static void CopyFromFileEntry(const ZipWriter::FileEntry& src, bool use_data_descriptor,
-                              LocalFileHeader* dst) {
-  dst->lfh_signature = LocalFileHeader::kSignature;
-  if (use_data_descriptor) {
-    // Set this flag to denote that a DataDescriptor struct will appear after the data,
-    // containing the crc and size fields.
-    dst->gpb_flags |= kGPBDDFlagMask;
-
-    // The size and crc fields must be 0.
-    dst->compressed_size = 0u;
-    dst->uncompressed_size = 0u;
-    dst->crc32 = 0u;
-  } else {
-    dst->compressed_size = src.compressed_size;
-    dst->uncompressed_size = src.uncompressed_size;
-    dst->crc32 = src.crc32;
-  }
-  dst->compression_method = src.compression_method;
-  dst->last_mod_time = src.last_mod_time;
-  dst->last_mod_date = src.last_mod_date;
-  DCHECK_LE(src.path.size(), std::numeric_limits<uint16_t>::max());
-  dst->file_name_length = static_cast<uint16_t>(src.path.size());
-  dst->extra_field_length = src.padding_length;
-}
-
-int32_t ZipWriter::StartAlignedEntryWithTime(std::string_view path, size_t flags, time_t time,
-                                             uint32_t alignment) {
-  if (state_ != State::kWritingZip) {
-    return kInvalidState;
-  }
-
-  // Can only have 16535 entries because of zip records.
-  if (files_.size() == std::numeric_limits<uint16_t>::max()) {
-    return HandleError(kIoError);
-  }
-
-  if (flags & kAlign32) {
-    return kInvalidAlign32Flag;
-  }
-
-  if (powerof2(alignment) == 0) {
-    return kInvalidAlignment;
-  }
-  if (alignment > std::numeric_limits<uint16_t>::max()) {
-    return kInvalidAlignment;
-  }
-
-  FileEntry file_entry = {};
-  file_entry.local_file_header_offset = current_offset_;
-  file_entry.path = path;
-  // No support for larger than 4GB files.
-  if (file_entry.local_file_header_offset > std::numeric_limits<uint32_t>::max()) {
-    return HandleError(kIoError);
-  }
-
-  if (!IsValidEntryName(reinterpret_cast<const uint8_t*>(file_entry.path.data()),
-                        file_entry.path.size())) {
-    return kInvalidEntryName;
-  }
-
-  if (flags & ZipWriter::kCompress) {
-    file_entry.compression_method = kCompressDeflated;
-
-    int32_t result = PrepareDeflate();
-    if (result != kNoError) {
-      return result;
-    }
-  } else {
-    file_entry.compression_method = kCompressStored;
-  }
-
-  ExtractTimeAndDate(time, &file_entry.last_mod_time, &file_entry.last_mod_date);
-
-  off_t offset = current_offset_ + sizeof(LocalFileHeader) + file_entry.path.size();
-  // prepare a pre-zeroed memory page in case when we need to pad some aligned data.
-  static constexpr auto kPageSize = 4096;
-  static constexpr char kSmallZeroPadding[kPageSize] = {};
-  // use this buffer if our preallocated one is too small
-  std::vector<char> zero_padding_big;
-  const char* zero_padding = nullptr;
-
-  if (alignment != 0 && (offset & (alignment - 1))) {
-    // Pad the extra field so the data will be aligned.
-    uint16_t padding = static_cast<uint16_t>(alignment - (offset % alignment));
-    file_entry.padding_length = padding;
-    offset += padding;
-    if (padding <= std::size(kSmallZeroPadding)) {
-        zero_padding = kSmallZeroPadding;
-    } else {
-        zero_padding_big.resize(padding, 0);
-        zero_padding = zero_padding_big.data();
-    }
-  }
-
-  LocalFileHeader header = {};
-  // Always start expecting a data descriptor. When the data has finished being written,
-  // if it is possible to seek back, the GPB flag will reset and the sizes written.
-  CopyFromFileEntry(file_entry, true /*use_data_descriptor*/, &header);
-
-  if (fwrite(&header, sizeof(header), 1, file_) != 1) {
-    return HandleError(kIoError);
-  }
-
-  if (fwrite(path.data(), 1, path.size(), file_) != path.size()) {
-    return HandleError(kIoError);
-  }
-
-  if (file_entry.padding_length != 0 && fwrite(zero_padding, 1, file_entry.padding_length,
-                                               file_) != file_entry.padding_length) {
-    return HandleError(kIoError);
-  }
-
-  current_file_entry_ = std::move(file_entry);
-  current_offset_ = offset;
-  state_ = State::kWritingEntry;
-  return kNoError;
-}
-
-int32_t ZipWriter::DiscardLastEntry() {
-  if (state_ != State::kWritingZip || files_.empty()) {
-    return kInvalidState;
-  }
-
-  FileEntry& last_entry = files_.back();
-  current_offset_ = last_entry.local_file_header_offset;
-  if (fseeko(file_, current_offset_, SEEK_SET) != 0) {
-    return HandleError(kIoError);
-  }
-  files_.pop_back();
-  return kNoError;
-}
-
-int32_t ZipWriter::GetLastEntry(FileEntry* out_entry) {
-  CHECK(out_entry != nullptr);
-
-  if (files_.empty()) {
-    return kInvalidState;
-  }
-  *out_entry = files_.back();
-  return kNoError;
-}
-
-int32_t ZipWriter::PrepareDeflate() {
-  CHECK(state_ == State::kWritingZip);
-
-  // Initialize the z_stream for compression.
-  z_stream_ = std::unique_ptr<z_stream, void (*)(z_stream*)>(new z_stream(), DeleteZStream);
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-  int zerr = deflateInit2(z_stream_.get(), Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
-                          DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
-#pragma GCC diagnostic pop
-
-  if (zerr != Z_OK) {
-    if (zerr == Z_VERSION_ERROR) {
-      LOG(ERROR) << "Installed zlib is not compatible with linked version (" << ZLIB_VERSION << ")";
-      return HandleError(kZlibError);
-    } else {
-      LOG(ERROR) << "deflateInit2 failed (zerr=" << zerr << ")";
-      return HandleError(kZlibError);
-    }
-  }
-
-  z_stream_->next_out = buffer_.data();
-  DCHECK_EQ(buffer_.size(), kBufSize);
-  z_stream_->avail_out = static_cast<uint32_t>(buffer_.size());
-  return kNoError;
-}
-
-int32_t ZipWriter::WriteBytes(const void* data, size_t len) {
-  if (state_ != State::kWritingEntry) {
-    return HandleError(kInvalidState);
-  }
-  // Need to be able to mark down data correctly.
-  if (len + static_cast<uint64_t>(current_file_entry_.uncompressed_size) >
-      std::numeric_limits<uint32_t>::max()) {
-    return HandleError(kIoError);
-  }
-  uint32_t len32 = static_cast<uint32_t>(len);
-
-  int32_t result = kNoError;
-  if (current_file_entry_.compression_method & kCompressDeflated) {
-    result = CompressBytes(&current_file_entry_, data, len32);
-  } else {
-    result = StoreBytes(&current_file_entry_, data, len32);
-  }
-
-  if (result != kNoError) {
-    return result;
-  }
-
-  current_file_entry_.crc32 = static_cast<uint32_t>(
-      crc32(current_file_entry_.crc32, reinterpret_cast<const Bytef*>(data), len32));
-  current_file_entry_.uncompressed_size += len32;
-  return kNoError;
-}
-
-int32_t ZipWriter::StoreBytes(FileEntry* file, const void* data, uint32_t len) {
-  CHECK(state_ == State::kWritingEntry);
-
-  if (fwrite(data, 1, len, file_) != len) {
-    return HandleError(kIoError);
-  }
-  file->compressed_size += len;
-  current_offset_ += len;
-  return kNoError;
-}
-
-int32_t ZipWriter::CompressBytes(FileEntry* file, const void* data, uint32_t len) {
-  CHECK(state_ == State::kWritingEntry);
-  CHECK(z_stream_);
-  CHECK(z_stream_->next_out != nullptr);
-  CHECK(z_stream_->avail_out != 0);
-
-  // Prepare the input.
-  z_stream_->next_in = reinterpret_cast<const uint8_t*>(data);
-  z_stream_->avail_in = len;
-
-  while (z_stream_->avail_in > 0) {
-    // We have more data to compress.
-    int zerr = deflate(z_stream_.get(), Z_NO_FLUSH);
-    if (zerr != Z_OK) {
-      return HandleError(kZlibError);
-    }
-
-    if (z_stream_->avail_out == 0) {
-      // The output is full, let's write it to disk.
-      size_t write_bytes = z_stream_->next_out - buffer_.data();
-      if (fwrite(buffer_.data(), 1, write_bytes, file_) != write_bytes) {
-        return HandleError(kIoError);
-      }
-      file->compressed_size += write_bytes;
-      current_offset_ += write_bytes;
-
-      // Reset the output buffer for the next input.
-      z_stream_->next_out = buffer_.data();
-      DCHECK_EQ(buffer_.size(), kBufSize);
-      z_stream_->avail_out = static_cast<uint32_t>(buffer_.size());
-    }
-  }
-  return kNoError;
-}
-
-int32_t ZipWriter::FlushCompressedBytes(FileEntry* file) {
-  CHECK(state_ == State::kWritingEntry);
-  CHECK(z_stream_);
-  CHECK(z_stream_->next_out != nullptr);
-  CHECK(z_stream_->avail_out != 0);
-
-  // Keep deflating while there isn't enough space in the buffer to
-  // to complete the compress.
-  int zerr;
-  while ((zerr = deflate(z_stream_.get(), Z_FINISH)) == Z_OK) {
-    CHECK(z_stream_->avail_out == 0);
-    size_t write_bytes = z_stream_->next_out - buffer_.data();
-    if (fwrite(buffer_.data(), 1, write_bytes, file_) != write_bytes) {
-      return HandleError(kIoError);
-    }
-    file->compressed_size += write_bytes;
-    current_offset_ += write_bytes;
-
-    z_stream_->next_out = buffer_.data();
-    DCHECK_EQ(buffer_.size(), kBufSize);
-    z_stream_->avail_out = static_cast<uint32_t>(buffer_.size());
-  }
-  if (zerr != Z_STREAM_END) {
-    return HandleError(kZlibError);
-  }
-
-  size_t write_bytes = z_stream_->next_out - buffer_.data();
-  if (write_bytes != 0) {
-    if (fwrite(buffer_.data(), 1, write_bytes, file_) != write_bytes) {
-      return HandleError(kIoError);
-    }
-    file->compressed_size += write_bytes;
-    current_offset_ += write_bytes;
-  }
-  z_stream_.reset();
-  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;
-  }
-
-  if (current_file_entry_.compression_method & kCompressDeflated) {
-    int32_t result = FlushCompressedBytes(&current_file_entry_);
-    if (result != kNoError) {
-      return result;
-    }
-  }
-
-  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.
-    // We haven't supported zip64 format yet. Write both uncompressed size and compressed
-    // size as uint32_t.
-    std::vector<uint32_t> dataDescriptor = {
-        DataDescriptor::kOptSignature, current_file_entry_.crc32,
-        current_file_entry_.compressed_size, current_file_entry_.uncompressed_size};
-    if (fwrite(dataDescriptor.data(), dataDescriptor.size() * sizeof(uint32_t), 1, file_) != 1) {
-      return HandleError(kIoError);
-    }
-
-    current_offset_ += sizeof(uint32_t) * dataDescriptor.size();
-  } else {
-    // Seek back to the header and rewrite to include the size.
-    if (fseeko(file_, current_file_entry_.local_file_header_offset, SEEK_SET) != 0) {
-      return HandleError(kIoError);
-    }
-
-    LocalFileHeader header = {};
-    CopyFromFileEntry(current_file_entry_, false /*use_data_descriptor*/, &header);
-
-    if (fwrite(&header, sizeof(header), 1, file_) != 1) {
-      return HandleError(kIoError);
-    }
-
-    if (fseeko(file_, current_offset_, SEEK_SET) != 0) {
-      return HandleError(kIoError);
-    }
-  }
-
-  files_.emplace_back(std::move(current_file_entry_));
-  state_ = State::kWritingZip;
-  return kNoError;
-}
-
-int32_t ZipWriter::Finish() {
-  if (state_ != State::kWritingZip) {
-    return kInvalidState;
-  }
-
-  off_t startOfCdr = current_offset_;
-  for (FileEntry& file : files_) {
-    CentralDirectoryRecord cdr = {};
-    cdr.record_signature = CentralDirectoryRecord::kSignature;
-    if (ShouldUseDataDescriptor()) {
-      cdr.gpb_flags |= kGPBDDFlagMask;
-    }
-    cdr.compression_method = file.compression_method;
-    cdr.last_mod_time = file.last_mod_time;
-    cdr.last_mod_date = file.last_mod_date;
-    cdr.crc32 = file.crc32;
-    cdr.compressed_size = file.compressed_size;
-    cdr.uncompressed_size = file.uncompressed_size;
-    // Checked in IsValidEntryName.
-    DCHECK_LE(file.path.size(), std::numeric_limits<uint16_t>::max());
-    cdr.file_name_length = static_cast<uint16_t>(file.path.size());
-    // Checked in StartAlignedEntryWithTime.
-    DCHECK_LE(file.local_file_header_offset, std::numeric_limits<uint32_t>::max());
-    cdr.local_file_header_offset = static_cast<uint32_t>(file.local_file_header_offset);
-    if (fwrite(&cdr, sizeof(cdr), 1, file_) != 1) {
-      return HandleError(kIoError);
-    }
-
-    if (fwrite(file.path.data(), 1, file.path.size(), file_) != file.path.size()) {
-      return HandleError(kIoError);
-    }
-
-    current_offset_ += sizeof(cdr) + file.path.size();
-  }
-
-  EocdRecord er = {};
-  er.eocd_signature = EocdRecord::kSignature;
-  er.disk_num = 0;
-  er.cd_start_disk = 0;
-  // Checked when adding entries.
-  DCHECK_LE(files_.size(), std::numeric_limits<uint16_t>::max());
-  er.num_records_on_disk = static_cast<uint16_t>(files_.size());
-  er.num_records = static_cast<uint16_t>(files_.size());
-  if (current_offset_ > std::numeric_limits<uint32_t>::max()) {
-    return HandleError(kIoError);
-  }
-  er.cd_size = static_cast<uint32_t>(current_offset_ - startOfCdr);
-  er.cd_start_offset = static_cast<uint32_t>(startOfCdr);
-
-  if (fwrite(&er, sizeof(er), 1, file_) != 1) {
-    return HandleError(kIoError);
-  }
-
-  current_offset_ += sizeof(er);
-
-  // Since we can BackUp() and potentially finish writing at an offset less than one we had
-  // already written at, we must truncate the file.
-
-  if (ftruncate(fileno(file_), current_offset_) != 0) {
-    return HandleError(kIoError);
-  }
-
-  if (fflush(file_) != 0) {
-    return HandleError(kIoError);
-  }
-
-  state_ = State::kDone;
-  return kNoError;
-}
diff --git a/libziparchive/zip_writer_test.cc b/libziparchive/zip_writer_test.cc
deleted file mode 100644
index d324d4b..0000000
--- a/libziparchive/zip_writer_test.cc
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * Copyright (C) 2015 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 "ziparchive/zip_writer.h"
-#include "ziparchive/zip_archive.h"
-
-#include <android-base/test_utils.h>
-#include <gtest/gtest.h>
-#include <time.h>
-#include <memory>
-#include <vector>
-
-static ::testing::AssertionResult AssertFileEntryContentsEq(const std::string& expected,
-                                                            ZipArchiveHandle handle,
-                                                            ZipEntry* zip_entry);
-
-struct zipwriter : public ::testing::Test {
-  TemporaryFile* temp_file_;
-  int fd_;
-  FILE* file_;
-
-  void SetUp() override {
-    temp_file_ = new TemporaryFile();
-    fd_ = temp_file_->fd;
-    file_ = fdopen(fd_, "w");
-    ASSERT_NE(file_, nullptr);
-  }
-
-  void TearDown() override {
-    fclose(file_);
-    delete temp_file_;
-  }
-};
-
-TEST_F(zipwriter, WriteUncompressedZipWithOneFile) {
-  ZipWriter writer(file_);
-
-  const char* expected = "hello";
-
-  ASSERT_EQ(0, writer.StartEntry("file.txt", 0));
-  ASSERT_EQ(0, writer.WriteBytes("he", 2));
-  ASSERT_EQ(0, writer.WriteBytes("llo", 3));
-  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(0u, 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, WriteUncompressedZipWithMultipleFiles) {
-  ZipWriter writer(file_);
-
-  ASSERT_EQ(0, writer.StartEntry("file.txt", 0));
-  ASSERT_EQ(0, writer.WriteBytes("he", 2));
-  ASSERT_EQ(0, writer.FinishEntry());
-
-  ASSERT_EQ(0, writer.StartEntry("file/file.txt", 0));
-  ASSERT_EQ(0, writer.WriteBytes("llo", 3));
-  ASSERT_EQ(0, writer.FinishEntry());
-
-  ASSERT_EQ(0, writer.StartEntry("file/file2.txt", 0));
-  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(2u, data.compressed_length);
-  ASSERT_EQ(2u, data.uncompressed_length);
-  ASSERT_TRUE(AssertFileEntryContentsEq("he", handle, &data));
-
-  ASSERT_EQ(0, FindEntry(handle, "file/file.txt", &data));
-  EXPECT_EQ(kCompressStored, data.method);
-  EXPECT_EQ(3u, data.compressed_length);
-  ASSERT_EQ(3u, data.uncompressed_length);
-  ASSERT_TRUE(AssertFileEntryContentsEq("llo", handle, &data));
-
-  ASSERT_EQ(0, FindEntry(handle, "file/file2.txt", &data));
-  EXPECT_EQ(kCompressStored, data.method);
-  EXPECT_EQ(0u, data.compressed_length);
-  EXPECT_EQ(0u, data.uncompressed_length);
-
-  CloseArchive(handle);
-}
-
-TEST_F(zipwriter, WriteUncompressedZipFileWithAlignedFlag) {
-  ZipWriter writer(file_);
-
-  ASSERT_EQ(0, writer.StartEntry("align.txt", ZipWriter::kAlign32));
-  ASSERT_EQ(0, writer.WriteBytes("he", 2));
-  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, "align.txt", &data));
-  EXPECT_EQ(0, data.offset & 0x03);
-
-  CloseArchive(handle);
-}
-
-static struct tm MakeTm() {
-  struct tm tm;
-  memset(&tm, 0, sizeof(struct tm));
-  tm.tm_year = 2001 - 1900;
-  tm.tm_mon = 1;
-  tm.tm_mday = 12;
-  tm.tm_hour = 18;
-  tm.tm_min = 30;
-  tm.tm_sec = 20;
-  return tm;
-}
-
-TEST_F(zipwriter, WriteUncompressedZipFileWithAlignedFlagAndTime) {
-  ZipWriter writer(file_);
-
-  struct tm tm = MakeTm();
-  time_t time = mktime(&tm);
-  ASSERT_EQ(0, writer.StartEntryWithTime("align.txt", ZipWriter::kAlign32, time));
-  ASSERT_EQ(0, writer.WriteBytes("he", 2));
-  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, "align.txt", &data));
-  EXPECT_EQ(0, data.offset & 0x03);
-
-  struct tm mod = data.GetModificationTime();
-  EXPECT_EQ(tm.tm_sec, mod.tm_sec);
-  EXPECT_EQ(tm.tm_min, mod.tm_min);
-  EXPECT_EQ(tm.tm_hour, mod.tm_hour);
-  EXPECT_EQ(tm.tm_mday, mod.tm_mday);
-  EXPECT_EQ(tm.tm_mon, mod.tm_mon);
-  EXPECT_EQ(tm.tm_year, mod.tm_year);
-
-  CloseArchive(handle);
-}
-
-TEST_F(zipwriter, WriteUncompressedZipFileWithAlignedValue) {
-  ZipWriter writer(file_);
-
-  ASSERT_EQ(0, writer.StartAlignedEntry("align.txt", 0, 4096));
-  ASSERT_EQ(0, writer.WriteBytes("he", 2));
-  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, "align.txt", &data));
-  EXPECT_EQ(0, data.offset & 0xfff);
-
-  CloseArchive(handle);
-}
-
-TEST_F(zipwriter, WriteUncompressedZipFileWithAlignedValueAndTime) {
-  ZipWriter writer(file_);
-
-  struct tm tm = MakeTm();
-  time_t time = mktime(&tm);
-  ASSERT_EQ(0, writer.StartAlignedEntryWithTime("align.txt", 0, time, 4096));
-  ASSERT_EQ(0, writer.WriteBytes("he", 2));
-  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, "align.txt", &data));
-  EXPECT_EQ(0, data.offset & 0xfff);
-
-  struct tm mod = data.GetModificationTime();
-  EXPECT_EQ(tm.tm_sec, mod.tm_sec);
-  EXPECT_EQ(tm.tm_min, mod.tm_min);
-  EXPECT_EQ(tm.tm_hour, mod.tm_hour);
-  EXPECT_EQ(tm.tm_mday, mod.tm_mday);
-  EXPECT_EQ(tm.tm_mon, mod.tm_mon);
-  EXPECT_EQ(tm.tm_year, mod.tm_year);
-
-  CloseArchive(handle);
-}
-
-TEST_F(zipwriter, WriteCompressedZipWithOneFile) {
-  ZipWriter writer(file_);
-
-  ASSERT_EQ(0, writer.StartEntry("file.txt", ZipWriter::kCompress));
-  ASSERT_EQ(0, writer.WriteBytes("helo", 4));
-  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(kCompressDeflated, data.method);
-  EXPECT_EQ(0u, data.has_data_descriptor);
-  ASSERT_EQ(4u, data.uncompressed_length);
-  ASSERT_TRUE(AssertFileEntryContentsEq("helo", handle, &data));
-
-  CloseArchive(handle);
-}
-
-TEST_F(zipwriter, WriteCompressedZipFlushFull) {
-  // This exact data will cause the Finish() to require multiple calls
-  // to deflate() because the ZipWriter buffer isn't big enough to hold
-  // the entire compressed data buffer.
-  constexpr size_t kBufSize = 10000000;
-  std::vector<uint8_t> buffer(kBufSize);
-  size_t prev = 1;
-  for (size_t i = 0; i < kBufSize; i++) {
-    buffer[i] = static_cast<uint8_t>(i + prev);
-    prev = i;
-  }
-
-  ZipWriter writer(file_);
-  ASSERT_EQ(0, writer.StartEntry("file.txt", ZipWriter::kCompress));
-  ASSERT_EQ(0, writer.WriteBytes(buffer.data(), buffer.size()));
-  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(kCompressDeflated, data.method);
-  EXPECT_EQ(kBufSize, data.uncompressed_length);
-
-  std::vector<uint8_t> decompress(kBufSize);
-  memset(decompress.data(), 0, kBufSize);
-  ASSERT_EQ(0, ExtractToMemory(handle, &data, decompress.data(),
-                               static_cast<uint32_t>(decompress.size())));
-  EXPECT_EQ(0, memcmp(decompress.data(), buffer.data(), kBufSize))
-      << "Input buffer and output buffer are different.";
-
-  CloseArchive(handle);
-}
-
-TEST_F(zipwriter, CheckStartEntryErrors) {
-  ZipWriter writer(file_);
-
-  ASSERT_EQ(-5, writer.StartAlignedEntry("align.txt", ZipWriter::kAlign32, 4096));
-  ASSERT_EQ(-6, writer.StartAlignedEntry("align.txt", 0, 3));
-}
-
-TEST_F(zipwriter, BackupRemovesTheLastFile) {
-  ZipWriter writer(file_);
-
-  const char* kKeepThis = "keep this";
-  const char* kDropThis = "drop this";
-  const char* kReplaceWithThis = "replace with this";
-
-  ZipWriter::FileEntry entry;
-  EXPECT_LT(writer.GetLastEntry(&entry), 0);
-
-  ASSERT_EQ(0, writer.StartEntry("keep.txt", 0));
-  ASSERT_EQ(0, writer.WriteBytes(kKeepThis, strlen(kKeepThis)));
-  ASSERT_EQ(0, writer.FinishEntry());
-
-  ASSERT_EQ(0, writer.GetLastEntry(&entry));
-  EXPECT_EQ("keep.txt", entry.path);
-
-  ASSERT_EQ(0, writer.StartEntry("drop.txt", 0));
-  ASSERT_EQ(0, writer.WriteBytes(kDropThis, strlen(kDropThis)));
-  ASSERT_EQ(0, writer.FinishEntry());
-
-  ASSERT_EQ(0, writer.GetLastEntry(&entry));
-  EXPECT_EQ("drop.txt", entry.path);
-
-  ASSERT_EQ(0, writer.DiscardLastEntry());
-
-  ASSERT_EQ(0, writer.GetLastEntry(&entry));
-  EXPECT_EQ("keep.txt", entry.path);
-
-  ASSERT_EQ(0, writer.StartEntry("replace.txt", 0));
-  ASSERT_EQ(0, writer.WriteBytes(kReplaceWithThis, strlen(kReplaceWithThis)));
-  ASSERT_EQ(0, writer.FinishEntry());
-
-  ASSERT_EQ(0, writer.GetLastEntry(&entry));
-  EXPECT_EQ("replace.txt", entry.path);
-
-  ASSERT_EQ(0, writer.Finish());
-
-  // Verify that "drop.txt" does not exist.
-
-  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, "keep.txt", &data));
-  ASSERT_TRUE(AssertFileEntryContentsEq(kKeepThis, handle, &data));
-
-  ASSERT_NE(0, FindEntry(handle, "drop.txt", &data));
-
-  ASSERT_EQ(0, FindEntry(handle, "replace.txt", &data));
-  ASSERT_TRUE(AssertFileEntryContentsEq(kReplaceWithThis, handle, &data));
-
-  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_);
-
-  const char* kSmall = "small";
-
-  ASSERT_EQ(0, writer.StartEntry("small.txt", 0));
-  ASSERT_EQ(0, writer.WriteBytes(kSmall, strlen(kSmall)));
-  ASSERT_EQ(0, writer.FinishEntry());
-
-  ASSERT_EQ(0, writer.StartEntry("large.txt", 0));
-  std::vector<uint8_t> data;
-  data.resize(1024 * 1024, 0xef);
-  ASSERT_EQ(0, writer.WriteBytes(data.data(), data.size()));
-  ASSERT_EQ(0, writer.FinishEntry());
-
-  off_t before_len = ftello(file_);
-
-  ZipWriter::FileEntry entry;
-  ASSERT_EQ(0, writer.GetLastEntry(&entry));
-  ASSERT_EQ(0, writer.DiscardLastEntry());
-
-  ASSERT_EQ(0, writer.Finish());
-
-  off_t after_len = ftello(file_);
-
-  ASSERT_GT(before_len, after_len);
-}
-
-static ::testing::AssertionResult AssertFileEntryContentsEq(const std::string& expected,
-                                                            ZipArchiveHandle handle,
-                                                            ZipEntry* zip_entry) {
-  if (expected.size() != zip_entry->uncompressed_length) {
-    return ::testing::AssertionFailure()
-           << "uncompressed entry size " << zip_entry->uncompressed_length
-           << " does not match expected size " << expected.size();
-  }
-
-  std::string actual;
-  actual.resize(expected.size());
-
-  uint8_t* buffer = reinterpret_cast<uint8_t*>(&*actual.begin());
-  if (ExtractToMemory(handle, zip_entry, buffer, static_cast<uint32_t>(actual.size())) != 0) {
-    return ::testing::AssertionFailure() << "failed to extract entry";
-  }
-
-  if (expected != actual) {
-    return ::testing::AssertionFailure() << "actual zip_entry data '" << actual
-                                         << "' does not match expected '" << expected << "'";
-  }
-  return ::testing::AssertionSuccess();
-}
diff --git a/libziparchive/ziptool-tests.xml b/libziparchive/ziptool-tests.xml
deleted file mode 100644
index 211119f..0000000
--- a/libziparchive/ziptool-tests.xml
+++ /dev/null
@@ -1,26 +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 running ziptool-tests through Atest or in Infra">
-    <option name="test-suite-tag" value="ziptool-tests" />
-    <!-- This test requires a device, so it's not annotated with a null-device. -->
-    <test class="com.android.tradefed.testtype.binary.ExecutableHostTest" >
-        <option name="binary" value="run-ziptool-tests-on-android.sh" />
-        <!-- Test script assumes a relative path with the cli-tests/ folders. -->
-        <option name="relative-path-execution" value="true" />
-        <!-- Tests shouldn't be that long but set 15m to be safe. -->
-        <option name="per-binary-timeout" value="15m" />
-    </test>
-</configuration>
diff --git a/libziparchive/ziptool.cpp b/libziparchive/ziptool.cpp
deleted file mode 100644
index a261535..0000000
--- a/libziparchive/ziptool.cpp
+++ /dev/null
@@ -1,532 +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 <errno.h>
-#include <fcntl.h>
-#include <fnmatch.h>
-#include <getopt.h>
-#include <inttypes.h>
-#include <libgen.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <set>
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/strings.h>
-#include <ziparchive/zip_archive.h>
-
-using android::base::EndsWith;
-using android::base::StartsWith;
-
-enum OverwriteMode {
-  kAlways,
-  kNever,
-  kPrompt,
-};
-
-enum Role {
-  kUnzip,
-  kZipinfo,
-};
-
-static Role role;
-static OverwriteMode overwrite_mode = kPrompt;
-static bool flag_1 = false;
-static std::string flag_d;
-static bool flag_l = false;
-static bool flag_p = false;
-static bool flag_q = false;
-static bool flag_v = false;
-static bool flag_x = false;
-static const char* archive_name = nullptr;
-static std::set<std::string> includes;
-static std::set<std::string> excludes;
-static uint64_t total_uncompressed_length = 0;
-static uint64_t total_compressed_length = 0;
-static size_t file_count = 0;
-
-static const char* g_progname;
-
-static void die(int error, const char* fmt, ...) {
-  va_list ap;
-
-  va_start(ap, fmt);
-  fprintf(stderr, "%s: ", g_progname);
-  vfprintf(stderr, fmt, ap);
-  if (error != 0) fprintf(stderr, ": %s", strerror(error));
-  fprintf(stderr, "\n");
-  va_end(ap);
-  exit(1);
-}
-
-static bool ShouldInclude(const std::string& name) {
-  // Explicitly excluded?
-  if (!excludes.empty()) {
-    for (const auto& exclude : excludes) {
-      if (!fnmatch(exclude.c_str(), name.c_str(), 0)) return false;
-    }
-  }
-
-  // Implicitly included?
-  if (includes.empty()) return true;
-
-  // Explicitly included?
-  for (const auto& include : includes) {
-    if (!fnmatch(include.c_str(), name.c_str(), 0)) return true;
-  }
-  return false;
-}
-
-static bool MakeDirectoryHierarchy(const std::string& path) {
-  // stat rather than lstat because a symbolic link to a directory is fine too.
-  struct stat sb;
-  if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) return true;
-
-  // Ensure the parent directories exist first.
-  if (!MakeDirectoryHierarchy(android::base::Dirname(path))) return false;
-
-  // Then try to create this directory.
-  return (mkdir(path.c_str(), 0777) != -1);
-}
-
-static float CompressionRatio(int64_t uncompressed, int64_t compressed) {
-  if (uncompressed == 0) return 0;
-  return static_cast<float>(100LL * (uncompressed - compressed)) /
-         static_cast<float>(uncompressed);
-}
-
-static void MaybeShowHeader(ZipArchiveHandle zah) {
-  if (role == kUnzip) {
-    // unzip has three formats.
-    if (!flag_q) printf("Archive:  %s\n", archive_name);
-    if (flag_v) {
-      printf(
-          " Length   Method    Size  Cmpr    Date    Time   CRC-32   Name\n"
-          "--------  ------  ------- ---- ---------- ----- --------  ----\n");
-    } else if (flag_l) {
-      printf(
-          "  Length      Date    Time    Name\n"
-          "---------  ---------- -----   ----\n");
-    }
-  } else {
-    // zipinfo.
-    if (!flag_1 && includes.empty() && excludes.empty()) {
-      ZipArchiveInfo info{GetArchiveInfo(zah)};
-      printf("Archive:  %s\n", archive_name);
-      printf("Zip file size: %" PRId64 " bytes, number of entries: %" PRIu64 "\n",
-             info.archive_size, info.entry_count);
-    }
-  }
-}
-
-static void MaybeShowFooter() {
-  if (role == kUnzip) {
-    if (flag_v) {
-      printf(
-          "--------          -------  ---                            -------\n"
-          "%8" PRId64 "         %8" PRId64 " %3.0f%%                            %zu file%s\n",
-          total_uncompressed_length, total_compressed_length,
-          CompressionRatio(total_uncompressed_length, total_compressed_length), file_count,
-          (file_count == 1) ? "" : "s");
-    } else if (flag_l) {
-      printf(
-          "---------                     -------\n"
-          "%9" PRId64 "                     %zu file%s\n",
-          total_uncompressed_length, file_count, (file_count == 1) ? "" : "s");
-    }
-  } else {
-    if (!flag_1 && includes.empty() && excludes.empty()) {
-      printf("%zu files, %" PRId64 " bytes uncompressed, %" PRId64 " bytes compressed:  %.1f%%\n",
-             file_count, total_uncompressed_length, total_compressed_length,
-             CompressionRatio(total_uncompressed_length, total_compressed_length));
-    }
-  }
-}
-
-static bool PromptOverwrite(const std::string& dst) {
-  // TODO: [r]ename not implemented because it doesn't seem useful.
-  printf("replace %s? [y]es, [n]o, [A]ll, [N]one: ", dst.c_str());
-  fflush(stdout);
-  while (true) {
-    char* line = nullptr;
-    size_t n;
-    if (getline(&line, &n, stdin) == -1) {
-      die(0, "(EOF/read error; assuming [N]one...)");
-      overwrite_mode = kNever;
-      return false;
-    }
-    if (n == 0) continue;
-    char cmd = line[0];
-    free(line);
-    switch (cmd) {
-      case 'y':
-        return true;
-      case 'n':
-        return false;
-      case 'A':
-        overwrite_mode = kAlways;
-        return true;
-      case 'N':
-        overwrite_mode = kNever;
-        return false;
-    }
-  }
-}
-
-static void ExtractToPipe(ZipArchiveHandle zah, const ZipEntry64& entry, const std::string& name) {
-  // We need to extract to memory because ExtractEntryToFile insists on
-  // being able to seek and truncate, and you can't do that with stdout.
-  if (entry.uncompressed_length > SIZE_MAX) {
-    die(0, "entry size %" PRIu64 " is too large to extract.", entry.uncompressed_length);
-  }
-  auto uncompressed_length = static_cast<size_t>(entry.uncompressed_length);
-  uint8_t* buffer = new uint8_t[uncompressed_length];
-  int err = ExtractToMemory(zah, &entry, buffer, uncompressed_length);
-  if (err < 0) {
-    die(0, "failed to extract %s: %s", name.c_str(), ErrorCodeString(err));
-  }
-  if (!android::base::WriteFully(1, buffer, uncompressed_length)) {
-    die(errno, "failed to write %s to stdout", name.c_str());
-  }
-  delete[] buffer;
-}
-
-static void ExtractOne(ZipArchiveHandle zah, const ZipEntry64& entry, const std::string& name) {
-  // Bad filename?
-  if (StartsWith(name, "/") || StartsWith(name, "../") || name.find("/../") != std::string::npos) {
-    die(0, "bad filename %s", name.c_str());
-  }
-
-  // Where are we actually extracting to (for human-readable output)?
-  // flag_d is the empty string if -d wasn't used, or has a trailing '/'
-  // otherwise.
-  std::string dst = flag_d + name;
-
-  // Ensure the directory hierarchy exists.
-  if (!MakeDirectoryHierarchy(android::base::Dirname(name))) {
-    die(errno, "couldn't create directory hierarchy for %s", dst.c_str());
-  }
-
-  // An entry in a zip file can just be a directory itself.
-  if (EndsWith(name, "/")) {
-    if (mkdir(name.c_str(), entry.unix_mode) == -1) {
-      // If the directory already exists, that's fine.
-      if (errno == EEXIST) {
-        struct stat sb;
-        if (stat(name.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) return;
-      }
-      die(errno, "couldn't extract directory %s", dst.c_str());
-    }
-    return;
-  }
-
-  // Create the file.
-  int fd = open(name.c_str(), O_CREAT | O_WRONLY | O_CLOEXEC | O_EXCL, entry.unix_mode);
-  if (fd == -1 && errno == EEXIST) {
-    if (overwrite_mode == kNever) return;
-    if (overwrite_mode == kPrompt && !PromptOverwrite(dst)) return;
-    // Either overwrite_mode is kAlways or the user consented to this specific case.
-    fd = open(name.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, entry.unix_mode);
-  }
-  if (fd == -1) die(errno, "couldn't create file %s", dst.c_str());
-
-  // Actually extract into the file.
-  if (!flag_q) printf("  inflating: %s\n", dst.c_str());
-  int err = ExtractEntryToFile(zah, &entry, fd);
-  if (err < 0) die(0, "failed to extract %s: %s", dst.c_str(), ErrorCodeString(err));
-  close(fd);
-}
-
-static void ListOne(const ZipEntry64& entry, const std::string& name) {
-  tm t = entry.GetModificationTime();
-  char time[32];
-  snprintf(time, sizeof(time), "%04d-%02d-%02d %02d:%02d", t.tm_year + 1900, t.tm_mon + 1,
-           t.tm_mday, t.tm_hour, t.tm_min);
-  if (flag_v) {
-    printf("%8" PRIu64 "  %s %8" PRIu64 " %3.0f%% %s %08x  %s\n", entry.uncompressed_length,
-           (entry.method == kCompressStored) ? "Stored" : "Defl:N", entry.compressed_length,
-           CompressionRatio(entry.uncompressed_length, entry.compressed_length), time, entry.crc32,
-           name.c_str());
-  } else {
-    printf("%9" PRIu64 "  %s   %s\n", entry.uncompressed_length, time, name.c_str());
-  }
-}
-
-static void InfoOne(const ZipEntry64& entry, const std::string& name) {
-  if (flag_1) {
-    // "android-ndk-r19b/sources/android/NOTICE"
-    printf("%s\n", name.c_str());
-    return;
-  }
-
-  int version = entry.version_made_by & 0xff;
-  int os = (entry.version_made_by >> 8) & 0xff;
-
-  // TODO: Support suid/sgid? Non-Unix/non-FAT host file system attributes?
-  const char* src_fs = "???";
-  char mode[] = "???       ";
-  if (os == 0) {
-    src_fs = "fat";
-    // https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
-    int attrs = entry.external_file_attributes & 0xff;
-    mode[0] = (attrs & 0x10) ? 'd' : '-';
-    mode[1] = 'r';
-    mode[2] = (attrs & 0x01) ? '-' : 'w';
-    // The man page also mentions ".btm", but that seems to be obsolete?
-    mode[3] = EndsWith(name, ".exe") || EndsWith(name, ".com") || EndsWith(name, ".bat") ||
-                      EndsWith(name, ".cmd")
-                  ? 'x'
-                  : '-';
-    mode[4] = (attrs & 0x20) ? 'a' : '-';
-    mode[5] = (attrs & 0x02) ? 'h' : '-';
-    mode[6] = (attrs & 0x04) ? 's' : '-';
-  } else if (os == 3) {
-    src_fs = "unx";
-    mode[0] = S_ISDIR(entry.unix_mode) ? 'd' : (S_ISREG(entry.unix_mode) ? '-' : '?');
-    mode[1] = entry.unix_mode & S_IRUSR ? 'r' : '-';
-    mode[2] = entry.unix_mode & S_IWUSR ? 'w' : '-';
-    mode[3] = entry.unix_mode & S_IXUSR ? 'x' : '-';
-    mode[4] = entry.unix_mode & S_IRGRP ? 'r' : '-';
-    mode[5] = entry.unix_mode & S_IWGRP ? 'w' : '-';
-    mode[6] = entry.unix_mode & S_IXGRP ? 'x' : '-';
-    mode[7] = entry.unix_mode & S_IROTH ? 'r' : '-';
-    mode[8] = entry.unix_mode & S_IWOTH ? 'w' : '-';
-    mode[9] = entry.unix_mode & S_IXOTH ? 'x' : '-';
-  }
-
-  char method[5] = "stor";
-  if (entry.method == kCompressDeflated) {
-    snprintf(method, sizeof(method), "def%c", "NXFS"[(entry.gpbf >> 1) & 0x3]);
-  }
-
-  // TODO: zipinfo (unlike unzip) sometimes uses time zone?
-  // TODO: this uses 4-digit years because we're not barbarians unless interoperability forces it.
-  tm t = entry.GetModificationTime();
-  char time[32];
-  snprintf(time, sizeof(time), "%04d-%02d-%02d %02d:%02d", t.tm_year + 1900, t.tm_mon + 1,
-           t.tm_mday, t.tm_hour, t.tm_min);
-
-  // "-rw-r--r--  3.0 unx      577 t- defX 19-Feb-12 16:09 android-ndk-r19b/sources/android/NOTICE"
-  printf("%s %2d.%d %s %8" PRIu64 " %c%c %s %s %s\n", mode, version / 10, version % 10, src_fs,
-         entry.uncompressed_length, entry.is_text ? 't' : 'b',
-         entry.has_data_descriptor ? 'X' : 'x', method, time, name.c_str());
-}
-
-static void ProcessOne(ZipArchiveHandle zah, const ZipEntry64& entry, const std::string& name) {
-  if (role == kUnzip) {
-    if (flag_l || flag_v) {
-      // -l or -lv or -lq or -v.
-      ListOne(entry, name);
-    } else {
-      // Actually extract.
-      if (flag_p) {
-        ExtractToPipe(zah, entry, name);
-      } else {
-        ExtractOne(zah, entry, name);
-      }
-    }
-  } else {
-    // zipinfo or zipinfo -1.
-    InfoOne(entry, name);
-  }
-  total_uncompressed_length += entry.uncompressed_length;
-  total_compressed_length += entry.compressed_length;
-  ++file_count;
-}
-
-static void ProcessAll(ZipArchiveHandle zah) {
-  MaybeShowHeader(zah);
-
-  // libziparchive iteration order doesn't match the central directory.
-  // We could sort, but that would cost extra and wouldn't match either.
-  void* cookie;
-  int err = StartIteration(zah, &cookie);
-  if (err != 0) {
-    die(0, "couldn't iterate %s: %s", archive_name, ErrorCodeString(err));
-  }
-
-  ZipEntry64 entry;
-  std::string name;
-  while ((err = Next(cookie, &entry, &name)) >= 0) {
-    if (ShouldInclude(name)) ProcessOne(zah, entry, name);
-  }
-
-  if (err < -1) die(0, "failed iterating %s: %s", archive_name, ErrorCodeString(err));
-  EndIteration(cookie);
-
-  MaybeShowFooter();
-}
-
-static void ShowHelp(bool full) {
-  if (role == kUnzip) {
-    fprintf(full ? stdout : stderr, "usage: unzip [-d DIR] [-lnopqv] ZIP [FILE...] [-x FILE...]\n");
-    if (!full) exit(EXIT_FAILURE);
-
-    printf(
-        "\n"
-        "Extract FILEs from ZIP archive. Default is all files. Both the include and\n"
-        "exclude (-x) lists use shell glob patterns.\n"
-        "\n"
-        "-d DIR	Extract into DIR\n"
-        "-l	List contents (-lq excludes archive name, -lv is verbose)\n"
-        "-n	Never overwrite files (default: prompt)\n"
-        "-o	Always overwrite files\n"
-        "-p	Pipe to stdout\n"
-        "-q	Quiet\n"
-        "-v	List contents verbosely\n"
-        "-x FILE	Exclude files\n");
-  } else {
-    fprintf(full ? stdout : stderr, "usage: zipinfo [-1] ZIP [FILE...] [-x FILE...]\n");
-    if (!full) exit(EXIT_FAILURE);
-
-    printf(
-        "\n"
-        "Show information about FILEs from ZIP archive. Default is all files.\n"
-        "Both the include and exclude (-x) lists use shell glob patterns.\n"
-        "\n"
-        "-1	Show filenames only, one per line\n"
-        "-x FILE	Exclude files\n");
-  }
-  exit(EXIT_SUCCESS);
-}
-
-static void HandleCommonOption(int opt) {
-  switch (opt) {
-    case 'h':
-      ShowHelp(true);
-      break;
-    case 'x':
-      flag_x = true;
-      break;
-    case 1:
-      // -x swallows all following arguments, so we use '-' in the getopt
-      // string and collect files here.
-      if (!archive_name) {
-        archive_name = optarg;
-      } else if (flag_x) {
-        excludes.insert(optarg);
-      } else {
-        includes.insert(optarg);
-      }
-      break;
-    default:
-      ShowHelp(false);
-      break;
-  }
-}
-
-int main(int argc, char* argv[]) {
-  // Who am I, and what am I doing?
-  g_progname = basename(argv[0]);
-  if (!strcmp(g_progname, "ziptool") && argc > 1) return main(argc - 1, argv + 1);
-  if (!strcmp(g_progname, "unzip")) {
-    role = kUnzip;
-  } else if (!strcmp(g_progname, "zipinfo")) {
-    role = kZipinfo;
-  } else {
-    die(0, "run as ziptool with unzip or zipinfo as the first argument, or symlink");
-  }
-
-  static const struct option opts[] = {
-      {"help", no_argument, 0, 'h'},
-      {},
-  };
-
-  if (role == kUnzip) {
-    // `unzip -Z` is "zipinfo mode", so in that case just restart...
-    if (argc > 1 && !strcmp(argv[1], "-Z")) {
-      argv[1] = const_cast<char*>("zipinfo");
-      return main(argc - 1, argv + 1);
-    }
-
-    int opt;
-    while ((opt = getopt_long(argc, argv, "-d:hlnopqvx", opts, nullptr)) != -1) {
-      switch (opt) {
-        case 'd':
-          flag_d = optarg;
-          if (!EndsWith(flag_d, "/")) flag_d += '/';
-          break;
-        case 'l':
-          flag_l = true;
-          break;
-        case 'n':
-          overwrite_mode = kNever;
-          break;
-        case 'o':
-          overwrite_mode = kAlways;
-          break;
-        case 'p':
-          flag_p = flag_q = true;
-          break;
-        case 'q':
-          flag_q = true;
-          break;
-        case 'v':
-          flag_v = true;
-          break;
-        default:
-          HandleCommonOption(opt);
-          break;
-      }
-    }
-  } else {
-    int opt;
-    while ((opt = getopt_long(argc, argv, "-1hx", opts, nullptr)) != -1) {
-      switch (opt) {
-        case '1':
-          flag_1 = true;
-          break;
-        default:
-          HandleCommonOption(opt);
-          break;
-      }
-    }
-  }
-
-  if (!archive_name) die(0, "missing archive filename");
-
-  // We can't support "-" to unzip from stdin because libziparchive relies on mmap.
-  ZipArchiveHandle zah;
-  int32_t err;
-  if ((err = OpenArchive(archive_name, &zah)) != 0) {
-    die(0, "couldn't open %s: %s", archive_name, ErrorCodeString(err));
-  }
-
-  // Implement -d by changing into that directory.
-  // We'll create implicit directories based on paths in the zip file, and we'll create
-  // the -d directory itself, but we require that *parents* of the -d directory already exists.
-  // This is pretty arbitrary, but it's the behavior of the original unzip.
-  if (!flag_d.empty()) {
-    if (mkdir(flag_d.c_str(), 0777) == -1 && errno != EEXIST) {
-      die(errno, "couldn't created %s", flag_d.c_str());
-    }
-    if (chdir(flag_d.c_str()) == -1) {
-      die(errno, "couldn't chdir to %s", flag_d.c_str());
-    }
-  }
-
-  ProcessAll(zah);
-
-  CloseArchive(zah);
-  return 0;
-}
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 8185f01..13023f2 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -459,7 +459,7 @@
                                             closedir);
     if (!dir.get()) return retval;
 
-    log_time now(android_log_clockid());
+    log_time now(CLOCK_REALTIME);
 
     size_t len = strlen(file);
     log_time modulo(0, NS_PER_SEC);
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index b32b437..f3fdfd7 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -174,11 +174,6 @@
 }
 
 TEST(logcat, year) {
-    if (android_log_clockid() == CLOCK_MONOTONIC) {
-        fprintf(stderr, "Skipping test, logd is monotonic time\n");
-        return;
-    }
-
     int count;
     int tries = 3;  // in case run too soon after system start or buffer clear
 
@@ -249,11 +244,6 @@
 }
 
 TEST(logcat, tz) {
-    if (android_log_clockid() == CLOCK_MONOTONIC) {
-        fprintf(stderr, "Skipping test, logd is monotonic time\n");
-        return;
-    }
-
     int tries = 4;  // in case run too soon after system start or buffer clear
     int count;
 
@@ -485,8 +475,8 @@
             continue;
         }
 
-        log_time tx((const char*)&t);
-        if (ts == tx) {
+        log_time* tx = reinterpret_cast<log_time*>(&t);
+        if (ts == *tx) {
             ++count;
         }
     }
@@ -531,8 +521,8 @@
                 continue;
             }
 
-            log_time tx((const char*)&t);
-            if (ts == tx) {
+            log_time* tx = reinterpret_cast<log_time*>(&t);
+            if (ts == *tx) {
                 ++count;
             }
         }
diff --git a/logd/Android.bp b/logd/Android.bp
index b337b7c..1f6ab34 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -28,39 +28,54 @@
     "-DLIBLOG_LOG_TAG=1006",
 ]
 
+cc_defaults {
+    name: "logd_defaults",
+
+    shared_libs: ["libbase"],
+    cflags: [
+        "-Wextra",
+        "-Wthread-safety",
+    ] + event_flag,
+
+    lto: {
+        thin: true,
+    },
+}
+
 cc_library_static {
     name: "liblogd",
-
+    defaults: ["logd_defaults"],
+    host_supported: true,
     srcs: [
-        "LogCommand.cpp",
-        "CommandListener.cpp",
-        "LogListener.cpp",
-        "LogReader.cpp",
-        "FlushCommand.cpp",
-        "LogBuffer.cpp",
+        "ChattyLogBuffer.cpp",
+        "LogReaderList.cpp",
+        "LogReaderThread.cpp",
         "LogBufferElement.cpp",
-        "LogTimes.cpp",
         "LogStatistics.cpp",
         "LogWhiteBlackList.cpp",
-        "libaudit.c",
-        "LogAudit.cpp",
-        "LogKlog.cpp",
         "LogTags.cpp",
+        "SimpleLogBuffer.cpp",
     ],
     logtags: ["event.logtags"],
 
-    shared_libs: ["libbase"],
-
     export_include_dirs: ["."],
-
-    cflags: ["-Werror"] + event_flag,
 }
 
 cc_binary {
     name: "logd",
+    defaults: ["logd_defaults"],
     init_rc: ["logd.rc"],
 
-    srcs: ["main.cpp"],
+    srcs: [
+        "main.cpp",
+        "LogPermissions.cpp",
+        "CommandListener.cpp",
+        "LogListener.cpp",
+        "LogReader.cpp",
+        "LogAudit.cpp",
+        "LogKlog.cpp",
+        "libaudit.cpp",
+    ],
 
     static_libs: [
         "liblog",
@@ -70,31 +85,24 @@
     shared_libs: [
         "libsysutils",
         "libcutils",
-        "libbase",
         "libpackagelistparser",
         "libprocessgroup",
         "libcap",
     ],
-
-    cflags: ["-Werror"],
 }
 
 cc_binary {
     name: "auditctl",
 
-    srcs: ["auditctl.cpp"],
-
-    static_libs: [
-        "liblogd",
+    srcs: [
+        "auditctl.cpp",
+        "libaudit.cpp",
     ],
 
     shared_libs: ["libbase"],
 
     cflags: [
-        "-Wall",
         "-Wextra",
-        "-Werror",
-        "-Wconversion"
     ],
 }
 
@@ -103,3 +111,59 @@
     src: "logtagd.rc",
     sub_dir: "init",
 }
+
+// -----------------------------------------------------------------------------
+// Unit tests.
+// -----------------------------------------------------------------------------
+
+cc_defaults {
+    name: "logd-unit-test-defaults",
+
+    cflags: [
+        "-fstack-protector-all",
+        "-g",
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-fno-builtin",
+    ] + event_flag,
+
+    srcs: [
+        "ChattyLogBufferTest.cpp",
+        "logd_test.cpp",
+        "LogBufferTest.cpp",
+    ],
+
+    static_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "liblogd",
+        "libselinux",
+    ],
+}
+
+// Build tests for the logger. Run with:
+//   adb shell /data/nativetest/logd-unit-tests/logd-unit-tests
+cc_test {
+    name: "logd-unit-tests",
+    host_supported: true,
+    defaults: ["logd-unit-test-defaults"],
+}
+
+cc_test {
+    name: "CtsLogdTestCases",
+    defaults: ["logd-unit-test-defaults"],
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+    test_suites: [
+        "cts",
+        "vts10",
+    ],
+}
diff --git a/logd/tests/AndroidTest.xml b/logd/AndroidTest.xml
similarity index 100%
rename from logd/tests/AndroidTest.xml
rename to logd/AndroidTest.xml
diff --git a/logd/ChattyLogBuffer.cpp b/logd/ChattyLogBuffer.cpp
new file mode 100644
index 0000000..0ba6025
--- /dev/null
+++ b/logd/ChattyLogBuffer.cpp
@@ -0,0 +1,625 @@
+/*
+ * 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.
+ */
+// for manual checking of stale entries during ChattyLogBuffer::erase()
+//#define DEBUG_CHECK_FOR_STALE_ENTRIES
+
+#include "ChattyLogBuffer.h"
+
+#include <ctype.h>
+#include <endian.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include <sys/user.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <limits>
+#include <unordered_map>
+#include <utility>
+
+#include <private/android_logger.h>
+
+#include "LogUtils.h"
+
+#ifndef __predict_false
+#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
+#endif
+
+ChattyLogBuffer::ChattyLogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune,
+                                 LogStatistics* stats)
+    : SimpleLogBuffer(reader_list, tags, stats), prune_(prune) {}
+
+ChattyLogBuffer::~ChattyLogBuffer() {}
+
+enum match_type { DIFFERENT, SAME, SAME_LIBLOG };
+
+static enum match_type Identical(LogBufferElement* elem, LogBufferElement* last) {
+    // is it mostly identical?
+    //  if (!elem) return DIFFERENT;
+    ssize_t lenl = elem->getMsgLen();
+    if (lenl <= 0) return DIFFERENT;  // value if this represents a chatty elem
+    //  if (!last) return DIFFERENT;
+    ssize_t lenr = last->getMsgLen();
+    if (lenr <= 0) return DIFFERENT;  // value if this represents a chatty elem
+    //  if (elem->getLogId() != last->getLogId()) return DIFFERENT;
+    if (elem->getUid() != last->getUid()) return DIFFERENT;
+    if (elem->getPid() != last->getPid()) return DIFFERENT;
+    if (elem->getTid() != last->getTid()) return DIFFERENT;
+
+    // last is more than a minute old, stop squashing identical messages
+    if (elem->getRealTime().nsec() > (last->getRealTime().nsec() + 60 * NS_PER_SEC))
+        return DIFFERENT;
+
+    // Identical message
+    const char* msgl = elem->getMsg();
+    const char* msgr = last->getMsg();
+    if (lenl == lenr) {
+        if (!fastcmp<memcmp>(msgl, msgr, lenl)) return SAME;
+        // liblog tagged messages (content gets summed)
+        if (elem->getLogId() == LOG_ID_EVENTS && lenl == sizeof(android_log_event_int_t) &&
+            !fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_int_t) - sizeof(int32_t)) &&
+            elem->getTag() == LIBLOG_LOG_TAG) {
+            return SAME_LIBLOG;
+        }
+    }
+
+    // audit message (except sequence number) identical?
+    if (last->isBinary() && lenl > static_cast<ssize_t>(sizeof(android_log_event_string_t)) &&
+        lenr > static_cast<ssize_t>(sizeof(android_log_event_string_t))) {
+        if (fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_string_t) - sizeof(int32_t))) {
+            return DIFFERENT;
+        }
+        msgl += sizeof(android_log_event_string_t);
+        lenl -= sizeof(android_log_event_string_t);
+        msgr += sizeof(android_log_event_string_t);
+        lenr -= sizeof(android_log_event_string_t);
+    }
+    static const char avc[] = "): avc: ";
+    const char* avcl = android::strnstr(msgl, lenl, avc);
+    if (!avcl) return DIFFERENT;
+    lenl -= avcl - msgl;
+    const char* avcr = android::strnstr(msgr, lenr, avc);
+    if (!avcr) return DIFFERENT;
+    lenr -= avcr - msgr;
+    if (lenl != lenr) return DIFFERENT;
+    if (fastcmp<memcmp>(avcl + strlen(avc), avcr + strlen(avc), lenl - strlen(avc))) {
+        return DIFFERENT;
+    }
+    return SAME;
+}
+
+void ChattyLogBuffer::LogInternal(LogBufferElement&& elem) {
+    // b/137093665: don't coalesce security messages.
+    if (elem.getLogId() == LOG_ID_SECURITY) {
+        SimpleLogBuffer::LogInternal(std::move(elem));
+        return;
+    }
+    int log_id = elem.getLogId();
+
+    // Initialize last_logged_elements_ to a copy of elem if logging the first element for a log_id.
+    if (!last_logged_elements_[log_id]) {
+        last_logged_elements_[log_id].emplace(elem);
+        SimpleLogBuffer::LogInternal(std::move(elem));
+        return;
+    }
+
+    LogBufferElement& current_last = *last_logged_elements_[log_id];
+    enum match_type match = Identical(&elem, &current_last);
+
+    if (match == DIFFERENT) {
+        if (duplicate_elements_[log_id]) {
+            // If we previously had 3+ identical messages, log the chatty message.
+            if (duplicate_elements_[log_id]->getDropped() > 0) {
+                SimpleLogBuffer::LogInternal(std::move(*duplicate_elements_[log_id]));
+            }
+            duplicate_elements_[log_id].reset();
+            // Log the saved copy of the last identical message seen.
+            SimpleLogBuffer::LogInternal(std::move(current_last));
+        }
+        last_logged_elements_[log_id].emplace(elem);
+        SimpleLogBuffer::LogInternal(std::move(elem));
+        return;
+    }
+
+    // 2 identical message: set duplicate_elements_ appropriately.
+    if (!duplicate_elements_[log_id]) {
+        duplicate_elements_[log_id].emplace(std::move(current_last));
+        last_logged_elements_[log_id].emplace(std::move(elem));
+        return;
+    }
+
+    // 3+ identical LIBLOG event messages: coalesce them into last_logged_elements_.
+    if (match == SAME_LIBLOG) {
+        const android_log_event_int_t* current_last_event =
+                reinterpret_cast<const android_log_event_int_t*>(current_last.getMsg());
+        int64_t current_last_count = current_last_event->payload.data;
+        android_log_event_int_t* elem_event =
+                reinterpret_cast<android_log_event_int_t*>(const_cast<char*>(elem.getMsg()));
+        int64_t elem_count = elem_event->payload.data;
+
+        int64_t total = current_last_count + elem_count;
+        if (total > std::numeric_limits<int32_t>::max()) {
+            SimpleLogBuffer::LogInternal(std::move(current_last));
+            last_logged_elements_[log_id].emplace(std::move(elem));
+            return;
+        }
+        stats()->AddTotal(current_last.getLogId(), current_last.getMsgLen());
+        elem_event->payload.data = total;
+        last_logged_elements_[log_id].emplace(std::move(elem));
+        return;
+    }
+
+    // 3+ identical messages (not LIBLOG) messages: increase the drop count.
+    uint16_t dropped_count = duplicate_elements_[log_id]->getDropped();
+    if (dropped_count == std::numeric_limits<uint16_t>::max()) {
+        SimpleLogBuffer::LogInternal(std::move(*duplicate_elements_[log_id]));
+        dropped_count = 0;
+    }
+    // We're dropping the current_last log so add its stats to the total.
+    stats()->AddTotal(current_last.getLogId(), current_last.getMsgLen());
+    // Use current_last for tracking the dropped count to always use the latest timestamp.
+    current_last.setDropped(dropped_count + 1);
+    duplicate_elements_[log_id].emplace(std::move(current_last));
+    last_logged_elements_[log_id].emplace(std::move(elem));
+}
+
+LogBufferElementCollection::iterator ChattyLogBuffer::Erase(LogBufferElementCollection::iterator it,
+                                                            bool coalesce) {
+    LogBufferElement& element = *it;
+    log_id_t id = element.getLogId();
+
+    // Remove iterator references in the various lists that will become stale
+    // after the element is erased from the main logging list.
+
+    {  // start of scope for found iterator
+        int key = (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element.getTag()
+                                                                 : element.getUid();
+        LogBufferIteratorMap::iterator found = mLastWorst[id].find(key);
+        if ((found != mLastWorst[id].end()) && (it == found->second)) {
+            mLastWorst[id].erase(found);
+        }
+    }
+
+    {  // start of scope for pid found iterator
+        // element->getUid() may not be AID_SYSTEM for next-best-watermark.
+        // will not assume id != LOG_ID_EVENTS or LOG_ID_SECURITY for KISS and
+        // long term code stability, find() check should be fast for those ids.
+        LogBufferPidIteratorMap::iterator found = mLastWorstPidOfSystem[id].find(element.getPid());
+        if (found != mLastWorstPidOfSystem[id].end() && it == found->second) {
+            mLastWorstPidOfSystem[id].erase(found);
+        }
+    }
+
+#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
+    LogBufferElementCollection::iterator bad = it;
+    int key =
+            (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element->getTag() : element->getUid();
+#endif
+
+    if (coalesce) {
+        stats()->Erase(&element);
+    } else {
+        stats()->Subtract(&element);
+    }
+
+    it = SimpleLogBuffer::Erase(it);
+
+#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
+    log_id_for_each(i) {
+        for (auto b : mLastWorst[i]) {
+            if (bad == b.second) {
+                android::prdebug("stale mLastWorst[%d] key=%d mykey=%d\n", i, b.first, key);
+            }
+        }
+        for (auto b : mLastWorstPidOfSystem[i]) {
+            if (bad == b.second) {
+                android::prdebug("stale mLastWorstPidOfSystem[%d] pid=%d\n", i, b.first);
+            }
+        }
+    }
+#endif
+    return it;
+}
+
+// Define a temporary mechanism to report the last LogBufferElement pointer
+// for the specified uid, pid and tid. Used below to help merge-sort when
+// pruning for worst UID.
+class LogBufferElementLast {
+    typedef std::unordered_map<uint64_t, LogBufferElement*> LogBufferElementMap;
+    LogBufferElementMap map;
+
+  public:
+    bool coalesce(LogBufferElement* element, uint16_t dropped) {
+        uint64_t key = LogBufferElementKey(element->getUid(), element->getPid(), element->getTid());
+        LogBufferElementMap::iterator it = map.find(key);
+        if (it != map.end()) {
+            LogBufferElement* found = it->second;
+            uint16_t moreDropped = found->getDropped();
+            if ((dropped + moreDropped) > USHRT_MAX) {
+                map.erase(it);
+            } else {
+                found->setDropped(dropped + moreDropped);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void add(LogBufferElement* element) {
+        uint64_t key = LogBufferElementKey(element->getUid(), element->getPid(), element->getTid());
+        map[key] = element;
+    }
+
+    void clear() { map.clear(); }
+
+    void clear(LogBufferElement* element) {
+        uint64_t current = element->getRealTime().nsec() - (EXPIRE_RATELIMIT * NS_PER_SEC);
+        for (LogBufferElementMap::iterator it = map.begin(); it != map.end();) {
+            LogBufferElement* mapElement = it->second;
+            if (mapElement->getDropped() >= EXPIRE_THRESHOLD &&
+                current > mapElement->getRealTime().nsec()) {
+                it = map.erase(it);
+            } else {
+                ++it;
+            }
+        }
+    }
+
+  private:
+    uint64_t LogBufferElementKey(uid_t uid, pid_t pid, pid_t tid) {
+        return uint64_t(uid) << 32 | uint64_t(pid) << 16 | uint64_t(tid);
+    }
+};
+
+// prune "pruneRows" of type "id" from the buffer.
+//
+// This garbage collection task is used to expire log entries. It is called to
+// remove all logs (clear), all UID logs (unprivileged clear), or every
+// 256 or 10% of the total logs (whichever is less) to prune the logs.
+//
+// First there is a prep phase where we discover the reader region lock that
+// acts as a backstop to any pruning activity to stop there and go no further.
+//
+// There are three major pruning loops that follow. All expire from the oldest
+// entries. Since there are multiple log buffers, the Android logging facility
+// will appear to drop entries 'in the middle' when looking at multiple log
+// sources and buffers. This effect is slightly more prominent when we prune
+// the worst offender by logging source. Thus the logs slowly loose content
+// and value as you move back in time. This is preferred since chatty sources
+// invariably move the logs value down faster as less chatty sources would be
+// expired in the noise.
+//
+// The first loop performs blacklisting and worst offender pruning. Falling
+// through when there are no notable worst offenders and have not hit the
+// region lock preventing further worst offender pruning. This loop also looks
+// after managing the chatty log entries and merging to help provide
+// statistical basis for blame. The chatty entries are not a notification of
+// how much logs you may have, but instead represent how much logs you would
+// have had in a virtual log buffer that is extended to cover all the in-memory
+// logs without loss. They last much longer than the represented pruned logs
+// since they get multiplied by the gains in the non-chatty log sources.
+//
+// The second loop get complicated because an algorithm of watermarks and
+// history is maintained to reduce the order and keep processing time
+// down to a minimum at scale. These algorithms can be costly in the face
+// of larger log buffers, or severly limited processing time granted to a
+// background task at lowest priority.
+//
+// This second loop does straight-up expiration from the end of the logs
+// (again, remember for the specified log buffer id) but does some whitelist
+// preservation. Thus whitelist is a Hail Mary low priority, blacklists and
+// spam filtration all take priority. This second loop also checks if a region
+// lock is causing us to buffer too much in the logs to help the reader(s),
+// and will tell the slowest reader thread to skip log entries, and if
+// persistent and hits a further threshold, kill the reader thread.
+//
+// The third thread is optional, and only gets hit if there was a whitelist
+// and more needs to be pruned against the backstop of the region lock.
+//
+bool ChattyLogBuffer::Prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
+    LogReaderThread* oldest = nullptr;
+    bool busy = false;
+    bool clearAll = pruneRows == ULONG_MAX;
+
+    auto reader_threads_lock = std::lock_guard{reader_list()->reader_threads_lock()};
+
+    // Region locked?
+    for (const auto& reader_thread : reader_list()->reader_threads()) {
+        if (!reader_thread->IsWatching(id)) {
+            continue;
+        }
+        if (!oldest || oldest->start() > reader_thread->start() ||
+            (oldest->start() == reader_thread->start() &&
+             reader_thread->deadline().time_since_epoch().count() != 0)) {
+            oldest = reader_thread.get();
+        }
+    }
+
+    LogBufferElementCollection::iterator it;
+
+    if (__predict_false(caller_uid != AID_ROOT)) {  // unlikely
+        // Only here if clear all request from non system source, so chatty
+        // filter logistics is not required.
+        it = GetOldest(id);
+        while (it != logs().end()) {
+            LogBufferElement& element = *it;
+
+            if (element.getLogId() != id || element.getUid() != caller_uid) {
+                ++it;
+                continue;
+            }
+
+            if (oldest && oldest->start() <= element.getSequence()) {
+                busy = true;
+                KickReader(oldest, id, pruneRows);
+                break;
+            }
+
+            it = Erase(it);
+            if (--pruneRows == 0) {
+                break;
+            }
+        }
+        return busy;
+    }
+
+    // prune by worst offenders; by blacklist, UID, and by PID of system UID
+    bool hasBlacklist = (id != LOG_ID_SECURITY) && prune_->naughty();
+    while (!clearAll && (pruneRows > 0)) {
+        // recalculate the worst offender on every batched pass
+        int worst = -1;  // not valid for getUid() or getKey()
+        size_t worst_sizes = 0;
+        size_t second_worst_sizes = 0;
+        pid_t worstPid = 0;  // POSIX guarantees PID != 0
+
+        if (worstUidEnabledForLogid(id) && prune_->worstUidEnabled()) {
+            // Calculate threshold as 12.5% of available storage
+            size_t threshold = max_size(id) / 8;
+
+            if (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) {
+                stats()->WorstTwoTags(threshold, &worst, &worst_sizes, &second_worst_sizes);
+                // per-pid filter for AID_SYSTEM sources is too complex
+            } else {
+                stats()->WorstTwoUids(id, threshold, &worst, &worst_sizes, &second_worst_sizes);
+
+                if (worst == AID_SYSTEM && prune_->worstPidOfSystemEnabled()) {
+                    stats()->WorstTwoSystemPids(id, worst_sizes, &worstPid, &second_worst_sizes);
+                }
+            }
+        }
+
+        // skip if we have neither worst nor naughty filters
+        if ((worst == -1) && !hasBlacklist) {
+            break;
+        }
+
+        bool kick = false;
+        bool leading = true;  // true if starting from the oldest log entry, false if starting from
+                              // a specific chatty entry.
+        // Perform at least one mandatory garbage collection cycle in following
+        // - clear leading chatty tags
+        // - coalesce chatty tags
+        // - check age-out of preserved logs
+        bool gc = pruneRows <= 1;
+        if (!gc && (worst != -1)) {
+            {  // begin scope for worst found iterator
+                LogBufferIteratorMap::iterator found = mLastWorst[id].find(worst);
+                if (found != mLastWorst[id].end() && found->second != logs().end()) {
+                    leading = false;
+                    it = found->second;
+                }
+            }
+            if (worstPid) {  // begin scope for pid worst found iterator
+                // FYI: worstPid only set if !LOG_ID_EVENTS and
+                //      !LOG_ID_SECURITY, not going to make that assumption ...
+                LogBufferPidIteratorMap::iterator found = mLastWorstPidOfSystem[id].find(worstPid);
+                if (found != mLastWorstPidOfSystem[id].end() && found->second != logs().end()) {
+                    leading = false;
+                    it = found->second;
+                }
+            }
+        }
+        if (leading) {
+            it = GetOldest(id);
+        }
+        static const log_time too_old{EXPIRE_HOUR_THRESHOLD * 60 * 60, 0};
+        LogBufferElementCollection::iterator lastt;
+        lastt = logs().end();
+        --lastt;
+        LogBufferElementLast last;
+        while (it != logs().end()) {
+            LogBufferElement& element = *it;
+
+            if (oldest && oldest->start() <= element.getSequence()) {
+                busy = true;
+                // Do not let chatty eliding trigger any reader mitigation
+                break;
+            }
+
+            if (element.getLogId() != id) {
+                ++it;
+                continue;
+            }
+            // below this point element->getLogId() == id
+
+            uint16_t dropped = element.getDropped();
+
+            // remove any leading drops
+            if (leading && dropped) {
+                it = Erase(it);
+                continue;
+            }
+
+            if (dropped && last.coalesce(&element, dropped)) {
+                it = Erase(it, true);
+                continue;
+            }
+
+            int key = (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element.getTag()
+                                                                     : element.getUid();
+
+            if (hasBlacklist && prune_->naughty(&element)) {
+                last.clear(&element);
+                it = Erase(it);
+                if (dropped) {
+                    continue;
+                }
+
+                pruneRows--;
+                if (pruneRows == 0) {
+                    break;
+                }
+
+                if (key == worst) {
+                    kick = true;
+                    if (worst_sizes < second_worst_sizes) {
+                        break;
+                    }
+                    worst_sizes -= element.getMsgLen();
+                }
+                continue;
+            }
+
+            if (element.getRealTime() < (lastt->getRealTime() - too_old) ||
+                element.getRealTime() > lastt->getRealTime()) {
+                break;
+            }
+
+            if (dropped) {
+                last.add(&element);
+                if (worstPid && ((!gc && element.getPid() == worstPid) ||
+                                 mLastWorstPidOfSystem[id].find(element.getPid()) ==
+                                         mLastWorstPidOfSystem[id].end())) {
+                    // element->getUid() may not be AID_SYSTEM, next best
+                    // watermark if current one empty. id is not LOG_ID_EVENTS
+                    // or LOG_ID_SECURITY because of worstPid check.
+                    mLastWorstPidOfSystem[id][element.getPid()] = it;
+                }
+                if ((!gc && !worstPid && (key == worst)) ||
+                    (mLastWorst[id].find(key) == mLastWorst[id].end())) {
+                    mLastWorst[id][key] = it;
+                }
+                ++it;
+                continue;
+            }
+
+            if (key != worst || (worstPid && element.getPid() != worstPid)) {
+                leading = false;
+                last.clear(&element);
+                ++it;
+                continue;
+            }
+            // key == worst below here
+            // If worstPid set, then element->getPid() == worstPid below here
+
+            pruneRows--;
+            if (pruneRows == 0) {
+                break;
+            }
+
+            kick = true;
+
+            uint16_t len = element.getMsgLen();
+
+            // do not create any leading drops
+            if (leading) {
+                it = Erase(it);
+            } else {
+                stats()->Drop(&element);
+                element.setDropped(1);
+                if (last.coalesce(&element, 1)) {
+                    it = Erase(it, true);
+                } else {
+                    last.add(&element);
+                    if (worstPid && (!gc || mLastWorstPidOfSystem[id].find(worstPid) ==
+                                                    mLastWorstPidOfSystem[id].end())) {
+                        // element->getUid() may not be AID_SYSTEM, next best
+                        // watermark if current one empty. id is not
+                        // LOG_ID_EVENTS or LOG_ID_SECURITY because of worstPid.
+                        mLastWorstPidOfSystem[id][worstPid] = it;
+                    }
+                    if ((!gc && !worstPid) || mLastWorst[id].find(worst) == mLastWorst[id].end()) {
+                        mLastWorst[id][worst] = it;
+                    }
+                    ++it;
+                }
+            }
+            if (worst_sizes < second_worst_sizes) {
+                break;
+            }
+            worst_sizes -= len;
+        }
+        last.clear();
+
+        if (!kick || !prune_->worstUidEnabled()) {
+            break;  // the following loop will ask bad clients to skip/drop
+        }
+    }
+
+    bool whitelist = false;
+    bool hasWhitelist = (id != LOG_ID_SECURITY) && prune_->nice() && !clearAll;
+    it = GetOldest(id);
+    while ((pruneRows > 0) && (it != logs().end())) {
+        LogBufferElement& element = *it;
+
+        if (element.getLogId() != id) {
+            it++;
+            continue;
+        }
+
+        if (oldest && oldest->start() <= element.getSequence()) {
+            busy = true;
+            if (!whitelist) KickReader(oldest, id, pruneRows);
+            break;
+        }
+
+        if (hasWhitelist && !element.getDropped() && prune_->nice(&element)) {
+            // WhiteListed
+            whitelist = true;
+            it++;
+            continue;
+        }
+
+        it = Erase(it);
+        pruneRows--;
+    }
+
+    // Do not save the whitelist if we are reader range limited
+    if (whitelist && (pruneRows > 0)) {
+        it = GetOldest(id);
+        while ((it != logs().end()) && (pruneRows > 0)) {
+            LogBufferElement& element = *it;
+
+            if (element.getLogId() != id) {
+                ++it;
+                continue;
+            }
+
+            if (oldest && oldest->start() <= element.getSequence()) {
+                busy = true;
+                KickReader(oldest, id, pruneRows);
+                break;
+            }
+
+            it = Erase(it);
+            pruneRows--;
+        }
+    }
+
+    return (pruneRows > 0) && busy;
+}
diff --git a/logd/ChattyLogBuffer.h b/logd/ChattyLogBuffer.h
new file mode 100644
index 0000000..6f60272
--- /dev/null
+++ b/logd/ChattyLogBuffer.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+
+#include <list>
+#include <optional>
+#include <string>
+
+#include <android-base/thread_annotations.h>
+#include <android/log.h>
+#include <private/android_filesystem_config.h>
+#include <sysutils/SocketClient.h>
+
+#include "LogBuffer.h"
+#include "LogBufferElement.h"
+#include "LogReaderList.h"
+#include "LogReaderThread.h"
+#include "LogStatistics.h"
+#include "LogTags.h"
+#include "LogWhiteBlackList.h"
+#include "LogWriter.h"
+#include "SimpleLogBuffer.h"
+#include "rwlock.h"
+
+typedef std::list<LogBufferElement> LogBufferElementCollection;
+
+class ChattyLogBuffer : public SimpleLogBuffer {
+    // watermark of any worst/chatty uid processing
+    typedef std::unordered_map<uid_t, LogBufferElementCollection::iterator> LogBufferIteratorMap;
+    LogBufferIteratorMap mLastWorst[LOG_ID_MAX] GUARDED_BY(lock_);
+    // watermark of any worst/chatty pid of system processing
+    typedef std::unordered_map<pid_t, LogBufferElementCollection::iterator> LogBufferPidIteratorMap;
+    LogBufferPidIteratorMap mLastWorstPidOfSystem[LOG_ID_MAX] GUARDED_BY(lock_);
+
+  public:
+    ChattyLogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune,
+                    LogStatistics* stats);
+    ~ChattyLogBuffer();
+
+  protected:
+    bool Prune(log_id_t id, unsigned long pruneRows, uid_t uid) REQUIRES(lock_) override;
+    void LogInternal(LogBufferElement&& elem) REQUIRES(lock_) override;
+
+  private:
+    LogBufferElementCollection::iterator Erase(LogBufferElementCollection::iterator it,
+                                               bool coalesce = false) REQUIRES(lock_);
+
+    PruneList* prune_;
+
+    // This always contains a copy of the last message logged, for deduplication.
+    std::optional<LogBufferElement> last_logged_elements_[LOG_ID_MAX] GUARDED_BY(lock_);
+    // This contains an element if duplicate messages are seen.
+    // Its `dropped` count is `duplicates seen - 1`.
+    std::optional<LogBufferElement> duplicate_elements_[LOG_ID_MAX] GUARDED_BY(lock_);
+};
diff --git a/logd/ChattyLogBufferTest.cpp b/logd/ChattyLogBufferTest.cpp
new file mode 100644
index 0000000..2e0c947
--- /dev/null
+++ b/logd/ChattyLogBufferTest.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2020 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 "LogBufferTest.h"
+
+class ChattyLogBufferTest : public LogBufferTest {};
+
+TEST_P(ChattyLogBufferTest, deduplication_simple) {
+    auto make_message = [&](uint32_t sec, const char* tag, const char* msg,
+                            bool regex = false) -> LogMessage {
+        logger_entry entry = {
+                .pid = 1, .tid = 1, .sec = sec, .nsec = 1, .lid = LOG_ID_MAIN, .uid = 0};
+        std::string message;
+        message.push_back(ANDROID_LOG_INFO);
+        message.append(tag);
+        message.push_back('\0');
+        message.append(msg);
+        message.push_back('\0');
+        return {entry, message, regex};
+    };
+
+    // clang-format off
+    std::vector<LogMessage> log_messages = {
+            make_message(0, "test_tag", "duplicate"),
+            make_message(1, "test_tag", "duplicate"),
+            make_message(2, "test_tag", "not_same"),
+            make_message(3, "test_tag", "duplicate"),
+            make_message(4, "test_tag", "duplicate"),
+            make_message(5, "test_tag", "not_same"),
+            make_message(6, "test_tag", "duplicate"),
+            make_message(7, "test_tag", "duplicate"),
+            make_message(8, "test_tag", "duplicate"),
+            make_message(9, "test_tag", "not_same"),
+            make_message(10, "test_tag", "duplicate"),
+            make_message(11, "test_tag", "duplicate"),
+            make_message(12, "test_tag", "duplicate"),
+            make_message(13, "test_tag", "duplicate"),
+            make_message(14, "test_tag", "duplicate"),
+            make_message(15, "test_tag", "duplicate"),
+            make_message(16, "test_tag", "not_same"),
+            make_message(100, "test_tag", "duplicate"),
+            make_message(200, "test_tag", "duplicate"),
+            make_message(300, "test_tag", "duplicate"),
+    };
+    // clang-format on
+    FixupMessages(&log_messages);
+    LogMessages(log_messages);
+
+    std::vector<LogMessage> read_log_messages;
+    std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, nullptr));
+    log_buffer_->FlushTo(test_writer.get(), 1, nullptr, nullptr);
+
+    std::vector<LogMessage> expected_log_messages = {
+            make_message(0, "test_tag", "duplicate"),
+            make_message(1, "test_tag", "duplicate"),
+            make_message(2, "test_tag", "not_same"),
+            make_message(3, "test_tag", "duplicate"),
+            make_message(4, "test_tag", "duplicate"),
+            make_message(5, "test_tag", "not_same"),
+            // 3 duplicate logs together print the first, a 1 count chatty message, then the last.
+            make_message(6, "test_tag", "duplicate"),
+            make_message(7, "chatty", "uid=0\\([^\\)]+\\) [^ ]+ expire 1 line", true),
+            make_message(8, "test_tag", "duplicate"),
+            make_message(9, "test_tag", "not_same"),
+            // 6 duplicate logs together print the first, a 4 count chatty message, then the last.
+            make_message(10, "test_tag", "duplicate"),
+            make_message(14, "chatty", "uid=0\\([^\\)]+\\) [^ ]+ expire 4 lines", true),
+            make_message(15, "test_tag", "duplicate"),
+            make_message(16, "test_tag", "not_same"),
+            // duplicate logs > 1 minute apart are not deduplicated.
+            make_message(100, "test_tag", "duplicate"),
+            make_message(200, "test_tag", "duplicate"),
+            make_message(300, "test_tag", "duplicate"),
+    };
+    FixupMessages(&expected_log_messages);
+    CompareLogMessages(expected_log_messages, read_log_messages);
+};
+
+TEST_P(ChattyLogBufferTest, deduplication_overflow) {
+    auto make_message = [&](uint32_t sec, const char* tag, const char* msg,
+                            bool regex = false) -> LogMessage {
+        logger_entry entry = {
+                .pid = 1, .tid = 1, .sec = sec, .nsec = 1, .lid = LOG_ID_MAIN, .uid = 0};
+        std::string message;
+        message.push_back(ANDROID_LOG_INFO);
+        message.append(tag);
+        message.push_back('\0');
+        message.append(msg);
+        message.push_back('\0');
+        return {entry, message, regex};
+    };
+
+    uint32_t sec = 0;
+    std::vector<LogMessage> log_messages = {
+            make_message(sec++, "test_tag", "normal"),
+    };
+    size_t expired_per_chatty_message = std::numeric_limits<uint16_t>::max();
+    for (size_t i = 0; i < expired_per_chatty_message + 3; ++i) {
+        log_messages.emplace_back(make_message(sec++, "test_tag", "duplicate"));
+    }
+    log_messages.emplace_back(make_message(sec++, "test_tag", "normal"));
+    FixupMessages(&log_messages);
+    LogMessages(log_messages);
+
+    std::vector<LogMessage> read_log_messages;
+    std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, nullptr));
+    log_buffer_->FlushTo(test_writer.get(), 1, nullptr, nullptr);
+
+    std::vector<LogMessage> expected_log_messages = {
+            make_message(0, "test_tag", "normal"),
+            make_message(1, "test_tag", "duplicate"),
+            make_message(expired_per_chatty_message + 1, "chatty",
+                         "uid=0\\([^\\)]+\\) [^ ]+ expire 65535 lines", true),
+            make_message(expired_per_chatty_message + 2, "chatty",
+                         "uid=0\\([^\\)]+\\) [^ ]+ expire 1 line", true),
+            make_message(expired_per_chatty_message + 3, "test_tag", "duplicate"),
+            make_message(expired_per_chatty_message + 4, "test_tag", "normal"),
+    };
+    FixupMessages(&expected_log_messages);
+    CompareLogMessages(expected_log_messages, read_log_messages);
+}
+
+TEST_P(ChattyLogBufferTest, deduplication_liblog) {
+    auto make_message = [&](uint32_t sec, int32_t tag, int32_t count) -> LogMessage {
+        logger_entry entry = {
+                .pid = 1, .tid = 1, .sec = sec, .nsec = 1, .lid = LOG_ID_EVENTS, .uid = 0};
+        android_log_event_int_t liblog_event = {
+                .header.tag = tag, .payload.type = EVENT_TYPE_INT, .payload.data = count};
+        return {entry, std::string(reinterpret_cast<char*>(&liblog_event), sizeof(liblog_event)),
+                false};
+    };
+
+    // LIBLOG_LOG_TAG
+    std::vector<LogMessage> log_messages = {
+            make_message(0, 1234, 1),
+            make_message(1, LIBLOG_LOG_TAG, 3),
+            make_message(2, 1234, 2),
+            make_message(3, LIBLOG_LOG_TAG, 3),
+            make_message(4, LIBLOG_LOG_TAG, 4),
+            make_message(5, 1234, 223),
+            make_message(6, LIBLOG_LOG_TAG, 2),
+            make_message(7, LIBLOG_LOG_TAG, 3),
+            make_message(8, LIBLOG_LOG_TAG, 4),
+            make_message(9, 1234, 227),
+            make_message(10, LIBLOG_LOG_TAG, 1),
+            make_message(11, LIBLOG_LOG_TAG, 3),
+            make_message(12, LIBLOG_LOG_TAG, 2),
+            make_message(13, LIBLOG_LOG_TAG, 3),
+            make_message(14, LIBLOG_LOG_TAG, 5),
+            make_message(15, 1234, 227),
+            make_message(16, LIBLOG_LOG_TAG, 2),
+            make_message(17, LIBLOG_LOG_TAG, std::numeric_limits<int32_t>::max()),
+            make_message(18, LIBLOG_LOG_TAG, 3),
+            make_message(19, LIBLOG_LOG_TAG, 5),
+            make_message(20, 1234, 227),
+    };
+    FixupMessages(&log_messages);
+    LogMessages(log_messages);
+
+    std::vector<LogMessage> read_log_messages;
+    std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, nullptr));
+    log_buffer_->FlushTo(test_writer.get(), 1, nullptr, nullptr);
+
+    std::vector<LogMessage> expected_log_messages = {
+            make_message(0, 1234, 1),
+            make_message(1, LIBLOG_LOG_TAG, 3),
+            make_message(2, 1234, 2),
+            make_message(3, LIBLOG_LOG_TAG, 3),
+            make_message(4, LIBLOG_LOG_TAG, 4),
+            make_message(5, 1234, 223),
+            // More than 2 liblog events (3 here), sum their value into the third message.
+            make_message(6, LIBLOG_LOG_TAG, 2),
+            make_message(8, LIBLOG_LOG_TAG, 7),
+            make_message(9, 1234, 227),
+            // More than 2 liblog events (5 here), sum their value into the third message.
+            make_message(10, LIBLOG_LOG_TAG, 1),
+            make_message(14, LIBLOG_LOG_TAG, 13),
+            make_message(15, 1234, 227),
+            // int32_t max is the max for a chatty message, beyond that we must use new messages.
+            make_message(16, LIBLOG_LOG_TAG, 2),
+            make_message(17, LIBLOG_LOG_TAG, std::numeric_limits<int32_t>::max()),
+            make_message(19, LIBLOG_LOG_TAG, 8),
+            make_message(20, 1234, 227),
+    };
+    FixupMessages(&expected_log_messages);
+    CompareLogMessages(expected_log_messages, read_log_messages);
+};
+
+INSTANTIATE_TEST_CASE_P(ChattyLogBufferTests, ChattyLogBufferTest, testing::Values("chatty"));
\ No newline at end of file
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 694b5fa..c6ab22d 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "CommandListener.h"
+
 #include <arpa/inet.h>
 #include <ctype.h>
 #include <dirent.h>
@@ -31,44 +33,27 @@
 
 #include <android-base/stringprintf.h>
 #include <cutils/sockets.h>
+#include <log/log_properties.h>
 #include <private/android_filesystem_config.h>
 #include <sysutils/SocketClient.h>
 
-#include "CommandListener.h"
-#include "LogCommand.h"
-#include "LogUtils.h"
+#include "LogPermissions.h"
 
-CommandListener::CommandListener(LogBuffer* buf, LogReader* /*reader*/,
-                                 LogListener* /*swl*/)
-    : FrameworkListener(getLogSocket()) {
-    // registerCmd(new ShutdownCmd(buf, writer, swl));
-    registerCmd(new ClearCmd(buf));
-    registerCmd(new GetBufSizeCmd(buf));
-    registerCmd(new SetBufSizeCmd(buf));
-    registerCmd(new GetBufSizeUsedCmd(buf));
-    registerCmd(new GetStatisticsCmd(buf));
-    registerCmd(new SetPruneListCmd(buf));
-    registerCmd(new GetPruneListCmd(buf));
-    registerCmd(new GetEventTagCmd(buf));
-    registerCmd(new ReinitCmd());
+CommandListener::CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune,
+                                 LogStatistics* stats)
+    : FrameworkListener(getLogSocket()), buf_(buf), tags_(tags), prune_(prune), stats_(stats) {
+    registerCmd(new ClearCmd(this));
+    registerCmd(new GetBufSizeCmd(this));
+    registerCmd(new SetBufSizeCmd(this));
+    registerCmd(new GetBufSizeUsedCmd(this));
+    registerCmd(new GetStatisticsCmd(this));
+    registerCmd(new SetPruneListCmd(this));
+    registerCmd(new GetPruneListCmd(this));
+    registerCmd(new GetEventTagCmd(this));
+    registerCmd(new ReinitCmd(this));
     registerCmd(new ExitCmd(this));
 }
 
-CommandListener::ShutdownCmd::ShutdownCmd(LogReader* reader, LogListener* swl)
-    : LogCommand("shutdown"), mReader(*reader), mSwl(*swl) {
-}
-
-int CommandListener::ShutdownCmd::runCommand(SocketClient* /*cli*/,
-                                             int /*argc*/, char** /*argv*/) {
-    mSwl.stopListener();
-    mReader.stopListener();
-    exit(0);
-}
-
-CommandListener::ClearCmd::ClearCmd(LogBuffer* buf)
-    : LogCommand("clear"), mBuf(*buf) {
-}
-
 static void setname() {
     static bool name_set;
     if (!name_set) {
@@ -96,14 +81,10 @@
         return 0;
     }
 
-    cli->sendMsg(mBuf.clear((log_id_t)id, uid) ? "busy" : "success");
+    cli->sendMsg(buf()->Clear((log_id_t)id, uid) ? "busy" : "success");
     return 0;
 }
 
-CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer* buf)
-    : LogCommand("getLogSize"), mBuf(*buf) {
-}
-
 int CommandListener::GetBufSizeCmd::runCommand(SocketClient* cli, int argc,
                                                char** argv) {
     setname();
@@ -118,17 +99,13 @@
         return 0;
     }
 
-    unsigned long size = mBuf.getSize((log_id_t)id);
+    unsigned long size = buf()->GetSize((log_id_t)id);
     char buf[512];
     snprintf(buf, sizeof(buf), "%lu", size);
     cli->sendMsg(buf);
     return 0;
 }
 
-CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer* buf)
-    : LogCommand("setLogSize"), mBuf(*buf) {
-}
-
 int CommandListener::SetBufSizeCmd::runCommand(SocketClient* cli, int argc,
                                                char** argv) {
     setname();
@@ -149,7 +126,7 @@
     }
 
     unsigned long size = atol(argv[2]);
-    if (mBuf.setSize((log_id_t)id, size)) {
+    if (buf()->SetSize((log_id_t)id, size)) {
         cli->sendMsg("Range Error");
         return 0;
     }
@@ -158,10 +135,6 @@
     return 0;
 }
 
-CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer* buf)
-    : LogCommand("getLogSizeUsed"), mBuf(*buf) {
-}
-
 int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient* cli, int argc,
                                                    char** argv) {
     setname();
@@ -176,17 +149,13 @@
         return 0;
     }
 
-    unsigned long size = mBuf.getSizeUsed((log_id_t)id);
+    unsigned long size = stats()->Sizes((log_id_t)id);
     char buf[512];
     snprintf(buf, sizeof(buf), "%lu", size);
     cli->sendMsg(buf);
     return 0;
 }
 
-CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer* buf)
-    : LogCommand("getStatistics"), mBuf(*buf) {
-}
-
 // This returns a string with a length prefix with the format <length>\n<data>\n\f.  The length
 // prefix includes the length of the prefix itself.
 static std::string PackageString(const std::string& str) {
@@ -241,25 +210,17 @@
         }
     }
 
-    cli->sendMsg(PackageString(mBuf.formatStatistics(uid, pid, logMask)).c_str());
+    cli->sendMsg(PackageString(stats()->Format(uid, pid, logMask)).c_str());
     return 0;
 }
 
-CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer* buf)
-    : LogCommand("getPruneList"), mBuf(*buf) {
-}
-
 int CommandListener::GetPruneListCmd::runCommand(SocketClient* cli,
                                                  int /*argc*/, char** /*argv*/) {
     setname();
-    cli->sendMsg(PackageString(mBuf.formatPrune()).c_str());
+    cli->sendMsg(PackageString(prune()->format()).c_str());
     return 0;
 }
 
-CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer* buf)
-    : LogCommand("setPruneList"), mBuf(*buf) {
-}
-
 int CommandListener::SetPruneListCmd::runCommand(SocketClient* cli, int argc,
                                                  char** argv) {
     setname();
@@ -276,7 +237,7 @@
         str += argv[i];
     }
 
-    int ret = mBuf.initPrune(str.c_str());
+    int ret = prune()->init(str.c_str());
 
     if (ret) {
         cli->sendMsg("Invalid");
@@ -288,10 +249,6 @@
     return 0;
 }
 
-CommandListener::GetEventTagCmd::GetEventTagCmd(LogBuffer* buf)
-    : LogCommand("getEventTag"), mBuf(*buf) {
-}
-
 int CommandListener::GetEventTagCmd::runCommand(SocketClient* cli, int argc,
                                                 char** argv) {
     setname();
@@ -328,39 +285,45 @@
             cli->sendMsg("can not mix id= with either format= or name=");
             return 0;
         }
-        cli->sendMsg(PackageString(mBuf.formatEntry(atoi(id), uid)).c_str());
+        cli->sendMsg(PackageString(tags()->formatEntry(atoi(id), uid)).c_str());
         return 0;
     }
 
-    cli->sendMsg(PackageString(mBuf.formatGetEventTag(uid, name, format)).c_str());
+    cli->sendMsg(PackageString(tags()->formatGetEventTag(uid, name, format)).c_str());
 
     return 0;
 }
 
-CommandListener::ReinitCmd::ReinitCmd() : LogCommand("reinit") {
-}
-
 int CommandListener::ReinitCmd::runCommand(SocketClient* cli, int /*argc*/,
                                            char** /*argv*/) {
     setname();
 
-    reinit_signal_handler(SIGHUP);
+    android::prdebug("logd reinit");
+    buf()->Init();
+    prune()->init(nullptr);
+
+    // This only works on userdebug and eng devices to re-read the
+    // /data/misc/logd/event-log-tags file right after /data is mounted.
+    // The operation is near to boot and should only happen once.  There
+    // are races associated with its use since it can trigger a Rebuild
+    // of the file, but that is a can-not-happen since the file was not
+    // read yet.  More dangerous if called later, but if all is well it
+    // should just skip over everything and not write any new entries.
+    if (__android_log_is_debuggable()) {
+        tags()->ReadFileEventLogTags(tags()->debug_event_log_tags);
+    }
 
     cli->sendMsg("success");
 
     return 0;
 }
 
-CommandListener::ExitCmd::ExitCmd(CommandListener* parent)
-    : LogCommand("EXIT"), mParent(*parent) {
-}
-
 int CommandListener::ExitCmd::runCommand(SocketClient* cli, int /*argc*/,
                                          char** /*argv*/) {
     setname();
 
     cli->sendMsg("success");
-    release(cli);
+    parent_->release(cli);
 
     return 0;
 }
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
index ed99419..a55a393 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -14,85 +14,55 @@
  * limitations under the License.
  */
 
-#ifndef _COMMANDLISTENER_H__
-#define _COMMANDLISTENER_H__
+#pragma once
 
+#include <sysutils/FrameworkCommand.h>
 #include <sysutils/FrameworkListener.h>
-#include "LogBuffer.h"
-#include "LogCommand.h"
-#include "LogListener.h"
-#include "LogReader.h"
 
-// See main.cpp for implementation
-void reinit_signal_handler(int /*signal*/);
+#include "LogBuffer.h"
+#include "LogListener.h"
+#include "LogStatistics.h"
+#include "LogTags.h"
+#include "LogWhiteBlackList.h"
 
 class CommandListener : public FrameworkListener {
-   public:
-    CommandListener(LogBuffer* buf, LogReader* reader, LogListener* swl);
-    virtual ~CommandListener() {
-    }
+  public:
+    CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune, LogStatistics* log_statistics);
+    virtual ~CommandListener() {}
 
-   private:
+  private:
     static int getLogSocket();
 
-    class ShutdownCmd : public LogCommand {
-        LogReader& mReader;
-        LogListener& mSwl;
+    LogBuffer* buf_;
+    LogTags* tags_;
+    PruneList* prune_;
+    LogStatistics* stats_;
 
-       public:
-        ShutdownCmd(LogReader* reader, LogListener* swl);
-        virtual ~ShutdownCmd() {
-        }
-        int runCommand(SocketClient* c, int argc, char** argv);
-    };
-
-#define LogBufferCmd(name)                                      \
-    class name##Cmd : public LogCommand {                       \
-        LogBuffer& mBuf;                                        \
-                                                                \
-       public:                                                  \
-        explicit name##Cmd(LogBuffer* buf);                     \
-        virtual ~name##Cmd() {                                  \
-        }                                                       \
-        int runCommand(SocketClient* c, int argc, char** argv); \
+#define LogCmd(name, command_string)                                \
+    class name##Cmd : public FrameworkCommand {                     \
+      public:                                                       \
+        explicit name##Cmd(CommandListener* parent)                 \
+            : FrameworkCommand(#command_string), parent_(parent) {} \
+        virtual ~name##Cmd() {}                                     \
+        int runCommand(SocketClient* c, int argc, char** argv);     \
+                                                                    \
+      private:                                                      \
+        LogBuffer* buf() const { return parent_->buf_; }            \
+        LogTags* tags() const { return parent_->tags_; }            \
+        PruneList* prune() const { return parent_->prune_; }        \
+        LogStatistics* stats() const { return parent_->stats_; }    \
+        CommandListener* parent_;                                   \
     }
 
-    LogBufferCmd(Clear);
-    LogBufferCmd(GetBufSize);
-    LogBufferCmd(SetBufSize);
-    LogBufferCmd(GetBufSizeUsed);
-    LogBufferCmd(GetStatistics);
-    LogBufferCmd(GetPruneList);
-    LogBufferCmd(SetPruneList);
-    LogBufferCmd(GetEventTag);
-
-#define LogCmd(name)                                            \
-    class name##Cmd : public LogCommand {                       \
-       public:                                                  \
-        name##Cmd();                                            \
-        virtual ~name##Cmd() {                                  \
-        }                                                       \
-        int runCommand(SocketClient* c, int argc, char** argv); \
-    }
-
-    LogCmd(Reinit);
-
-#define LogParentCmd(name)                                      \
-    class name##Cmd : public LogCommand {                       \
-        CommandListener& mParent;                               \
-                                                                \
-       public:                                                  \
-        name##Cmd();                                            \
-        explicit name##Cmd(CommandListener* parent);            \
-        virtual ~name##Cmd() {                                  \
-        }                                                       \
-        int runCommand(SocketClient* c, int argc, char** argv); \
-        void release(SocketClient* c) {                         \
-            mParent.release(c);                                 \
-        }                                                       \
-    }
-
-    LogParentCmd(Exit);
+    LogCmd(Clear, clear);
+    LogCmd(GetBufSize, getLogSize);
+    LogCmd(SetBufSize, setLogSize);
+    LogCmd(GetBufSizeUsed, getLogSizeUsed);
+    LogCmd(GetStatistics, getStatistics);
+    LogCmd(GetPruneList, getPruneList);
+    LogCmd(SetPruneList, setPruneList);
+    LogCmd(GetEventTag, getEventTag);
+    LogCmd(Reinit, reinit);
+    LogCmd(Exit, EXIT);
+#undef LogCmd
 };
-
-#endif
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
deleted file mode 100644
index 0845504..0000000
--- a/logd/FlushCommand.cpp
+++ /dev/null
@@ -1,75 +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.
- */
-
-#include <stdlib.h>
-
-#include <private/android_filesystem_config.h>
-
-#include "FlushCommand.h"
-#include "LogBuffer.h"
-#include "LogBufferElement.h"
-#include "LogCommand.h"
-#include "LogReader.h"
-#include "LogTimes.h"
-#include "LogUtils.h"
-
-// runSocketCommand is called once for every open client on the
-// log reader socket. Here we manage and associated the reader
-// client tracking and log region locks LastLogTimes list of
-// LogTimeEntrys, and spawn a transitory per-client thread to
-// work at filing data to the  socket.
-//
-// global LogTimeEntry::wrlock() is used to protect access,
-// reference counts are used to ensure that individual
-// LogTimeEntry lifetime is managed when not protected.
-void FlushCommand::runSocketCommand(SocketClient* client) {
-    LogTimeEntry* entry = nullptr;
-    LastLogTimes& times = mReader.logbuf().mTimes;
-
-    LogTimeEntry::wrlock();
-    LastLogTimes::iterator it = times.begin();
-    while (it != times.end()) {
-        entry = it->get();
-        if (entry->mClient == client) {
-            if (!entry->isWatchingMultiple(mLogMask)) {
-                LogTimeEntry::unlock();
-                return;
-            }
-            if (entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec) {
-                LogTimeEntry::unlock();
-                return;
-            }
-            entry->triggerReader_Locked();
-            LogTimeEntry::unlock();
-            return;
-        }
-        it++;
-    }
-
-    LogTimeEntry::unlock();
-}
-
-bool FlushCommand::hasReadLogs(SocketClient* client) {
-    return clientHasLogCredentials(client);
-}
-
-static bool clientHasSecurityCredentials(SocketClient* client) {
-    return (client->getUid() == AID_SYSTEM) || (client->getGid() == AID_SYSTEM);
-}
-
-bool FlushCommand::hasSecurityLogs(SocketClient* client) {
-    return clientHasSecurityCredentials(client);
-}
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
deleted file mode 100644
index a69d439..0000000
--- a/logd/FlushCommand.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2012-2013 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 _FLUSH_COMMAND_H
-#define _FLUSH_COMMAND_H
-
-#include <android/log.h>
-#include <sysutils/SocketClientCommand.h>
-
-class LogBufferElement;
-
-#include "LogTimes.h"
-
-class LogReader;
-
-class FlushCommand : public SocketClientCommand {
-    LogReader& mReader;
-    log_mask_t mLogMask;
-
-   public:
-    explicit FlushCommand(LogReader& reader, log_mask_t logMask)
-        : mReader(reader), mLogMask(logMask) {
-    }
-
-    virtual void runSocketCommand(SocketClient* client);
-
-    static bool hasReadLogs(SocketClient* client);
-    static bool hasSecurityLogs(SocketClient* client);
-};
-
-#endif
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index d9cc0db..0ce9796 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "LogAudit.h"
+
 #include <ctype.h>
 #include <endian.h>
 #include <errno.h>
@@ -34,10 +36,7 @@
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
-#include "LogAudit.h"
-#include "LogBuffer.h"
 #include "LogKlog.h"
-#include "LogReader.h"
 #include "LogUtils.h"
 #include "libaudit.h"
 
@@ -45,16 +44,14 @@
     '<', '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \
         '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, '>'
 
-LogAudit::LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg)
+LogAudit::LogAudit(LogBuffer* buf, int fdDmesg, LogStatistics* stats)
     : SocketListener(getLogSocket(), false),
       logbuf(buf),
-      reader(reader),
       fdDmesg(fdDmesg),
-      main(__android_logger_property_get_bool("ro.logd.auditd.main",
-                                              BOOL_DEFAULT_TRUE)),
-      events(__android_logger_property_get_bool("ro.logd.auditd.events",
-                                                BOOL_DEFAULT_TRUE)),
-      initialized(false) {
+      main(__android_logger_property_get_bool("ro.logd.auditd.main", BOOL_DEFAULT_TRUE)),
+      events(__android_logger_property_get_bool("ro.logd.auditd.events", BOOL_DEFAULT_TRUE)),
+      initialized(false),
+      stats_(stats) {
     static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
                                            'l',
                                            'o',
@@ -211,9 +208,7 @@
             ++cp;
         }
         tid = pid;
-        logbuf->wrlock();
-        uid = logbuf->pidToUid(pid);
-        logbuf->unlock();
+        uid = stats_->PidToUid(pid);
         memmove(pidptr, cp, strlen(cp) + 1);
     }
 
@@ -247,22 +242,10 @@
 
     static const char audit_str[] = " audit(";
     char* timeptr = strstr(str, audit_str);
-    if (timeptr &&
-        ((cp = now.strptime(timeptr + sizeof(audit_str) - 1, "%s.%q"))) &&
+    if (timeptr && ((cp = now.strptime(timeptr + sizeof(audit_str) - 1, "%s.%q"))) &&
         (*cp == ':')) {
         memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
         memmove(timeptr + sizeof(audit_str) - 1 + 3, cp, strlen(cp) + 1);
-        if (!isMonotonic()) {
-            if (android::isMonotonic(now)) {
-                LogKlog::convertMonotonicToReal(now);
-            }
-        } else {
-            if (!android::isMonotonic(now)) {
-                LogKlog::convertRealToMonotonic(now);
-            }
-        }
-    } else if (isMonotonic()) {
-        now = log_time(CLOCK_MONOTONIC);
     } else {
         now = log_time(CLOCK_REALTIME);
     }
@@ -277,7 +260,7 @@
                   : LOGGER_ENTRY_MAX_PAYLOAD;
     size_t message_len = str_len + sizeof(android_log_event_string_t);
 
-    log_mask_t notify = 0;
+    unsigned int notify = 0;
 
     if (events) {  // begin scope for event buffer
         uint32_t buffer[(message_len + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
@@ -291,9 +274,8 @@
         memcpy(event->data + str_len - denial_metadata.length(),
                denial_metadata.c_str(), denial_metadata.length());
 
-        rc = logbuf->log(
-            LOG_ID_EVENTS, now, uid, pid, tid, reinterpret_cast<char*>(event),
-            (message_len <= UINT16_MAX) ? (uint16_t)message_len : UINT16_MAX);
+        rc = logbuf->Log(LOG_ID_EVENTS, now, uid, pid, tid, reinterpret_cast<char*>(event),
+                         (message_len <= UINT16_MAX) ? (uint16_t)message_len : UINT16_MAX);
         if (rc >= 0) {
             notify |= 1 << LOG_ID_EVENTS;
         }
@@ -313,9 +295,7 @@
         pid = tid;
         comm = "auditd";
     } else {
-        logbuf->wrlock();
-        comm = commfree = logbuf->pidToName(pid);
-        logbuf->unlock();
+        comm = commfree = stats_->PidToName(pid);
         if (!comm) {
             comm = "unknown";
         }
@@ -347,9 +327,8 @@
         strncpy(newstr + 1 + str_len + prefix_len + suffix_len,
                 denial_metadata.c_str(), denial_metadata.length());
 
-        rc = logbuf->log(
-            LOG_ID_MAIN, now, uid, pid, tid, newstr,
-            (message_len <= UINT16_MAX) ? (uint16_t)message_len : UINT16_MAX);
+        rc = logbuf->Log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
+                         (message_len <= UINT16_MAX) ? (uint16_t)message_len : UINT16_MAX);
 
         if (rc >= 0) {
             notify |= 1 << LOG_ID_MAIN;
@@ -361,7 +340,6 @@
     free(str);
 
     if (notify) {
-        reader->notifyNewLog(notify);
         if (rc < 0) {
             rc = message_len;
         }
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index c3d7a3e..181920e 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -14,36 +14,30 @@
  * limitations under the License.
  */
 
-#ifndef _LOGD_LOG_AUDIT_H__
-#define _LOGD_LOG_AUDIT_H__
+#pragma once
 
 #include <map>
 
 #include <sysutils/SocketListener.h>
 
 #include "LogBuffer.h"
-
-class LogReader;
+#include "LogStatistics.h"
 
 class LogAudit : public SocketListener {
     LogBuffer* logbuf;
-    LogReader* reader;
     int fdDmesg;  // fdDmesg >= 0 is functionally bool dmesg
     bool main;
     bool events;
     bool initialized;
 
-   public:
-    LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg);
+  public:
+    LogAudit(LogBuffer* buf, int fdDmesg, LogStatistics* stats);
     int log(char* buf, size_t len);
-    bool isMonotonic() {
-        return logbuf->isMonotonic();
-    }
 
-   protected:
+  protected:
     virtual bool onDataAvailable(SocketClient* cli);
 
-   private:
+  private:
     static int getLogSocket();
     std::map<std::string, std::string> populateDenialMap();
     std::string denialParse(const std::string& denial, char terminator,
@@ -51,6 +45,6 @@
     void auditParse(const std::string& string, uid_t uid, std::string* bug_num);
     int logPrint(const char* fmt, ...)
         __attribute__((__format__(__printf__, 2, 3)));
-};
 
-#endif
+    LogStatistics* stats_;
+};
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
deleted file mode 100644
index 1f8ad05..0000000
--- a/logd/LogBuffer.cpp
+++ /dev/null
@@ -1,1134 +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.
- */
-// for manual checking of stale entries during LogBuffer::erase()
-//#define DEBUG_CHECK_FOR_STALE_ENTRIES
-
-#include <ctype.h>
-#include <endian.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/cdefs.h>
-#include <sys/user.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <unordered_map>
-#include <utility>
-
-#include <cutils/properties.h>
-#include <private/android_logger.h>
-
-#include "LogBuffer.h"
-#include "LogKlog.h"
-#include "LogReader.h"
-#include "LogUtils.h"
-
-#ifndef __predict_false
-#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
-#endif
-
-// Default
-#define log_buffer_size(id) mMaxSize[id]
-
-void LogBuffer::init() {
-    log_id_for_each(i) {
-        mLastSet[i] = false;
-        mLast[i] = mLogElements.begin();
-
-        if (setSize(i, __android_logger_get_buffer_size(i))) {
-            setSize(i, LOG_BUFFER_MIN_SIZE);
-        }
-    }
-    bool lastMonotonic = monotonic;
-    monotonic = android_log_clockid() == CLOCK_MONOTONIC;
-    if (lastMonotonic != monotonic) {
-        //
-        // Fixup all timestamps, may not be 100% accurate, but better than
-        // throwing what we have away when we get 'surprised' by a change.
-        // In-place element fixup so no need to check reader-lock. Entries
-        // should already be in timestamp order, but we could end up with a
-        // few out-of-order entries if new monotonics come in before we
-        // are notified of the reinit change in status. A Typical example would
-        // be:
-        //  --------- beginning of system
-        //      10.494082   184   201 D Cryptfs : Just triggered post_fs_data
-        //  --------- beginning of kernel
-        //       0.000000     0     0 I         : Initializing cgroup subsys
-        // as the act of mounting /data would trigger persist.logd.timestamp to
-        // be corrected. 1/30 corner case YMMV.
-        //
-        rdlock();
-        LogBufferElementCollection::iterator it = mLogElements.begin();
-        while ((it != mLogElements.end())) {
-            LogBufferElement* e = *it;
-            if (monotonic) {
-                if (!android::isMonotonic(e->mRealTime)) {
-                    LogKlog::convertRealToMonotonic(e->mRealTime);
-                    if ((e->mRealTime.tv_nsec % 1000) == 0) {
-                        e->mRealTime.tv_nsec++;
-                    }
-                }
-            } else {
-                if (android::isMonotonic(e->mRealTime)) {
-                    LogKlog::convertMonotonicToReal(e->mRealTime);
-                    if ((e->mRealTime.tv_nsec % 1000) == 0) {
-                        e->mRealTime.tv_nsec++;
-                    }
-                }
-            }
-            ++it;
-        }
-        unlock();
-    }
-
-    // We may have been triggered by a SIGHUP. Release any sleeping reader
-    // threads to dump their current content.
-    //
-    // NB: this is _not_ performed in the context of a SIGHUP, it is
-    // performed during startup, and in context of reinit administrative thread
-    LogTimeEntry::wrlock();
-
-    LastLogTimes::iterator times = mTimes.begin();
-    while (times != mTimes.end()) {
-        LogTimeEntry* entry = times->get();
-        entry->triggerReader_Locked();
-        times++;
-    }
-
-    LogTimeEntry::unlock();
-}
-
-LogBuffer::LogBuffer(LastLogTimes* times)
-    : monotonic(android_log_clockid() == CLOCK_MONOTONIC), mTimes(*times) {
-    pthread_rwlock_init(&mLogElementsLock, nullptr);
-
-    log_id_for_each(i) {
-        lastLoggedElements[i] = nullptr;
-        droppedElements[i] = nullptr;
-    }
-
-    init();
-}
-
-LogBuffer::~LogBuffer() {
-    log_id_for_each(i) {
-        delete lastLoggedElements[i];
-        delete droppedElements[i];
-    }
-}
-
-enum match_type { DIFFERENT, SAME, SAME_LIBLOG };
-
-static enum match_type identical(LogBufferElement* elem,
-                                 LogBufferElement* last) {
-    // is it mostly identical?
-    //  if (!elem) return DIFFERENT;
-    ssize_t lenl = elem->getMsgLen();
-    if (lenl <= 0) return DIFFERENT;  // value if this represents a chatty elem
-    //  if (!last) return DIFFERENT;
-    ssize_t lenr = last->getMsgLen();
-    if (lenr <= 0) return DIFFERENT;  // value if this represents a chatty elem
-    //  if (elem->getLogId() != last->getLogId()) return DIFFERENT;
-    if (elem->getUid() != last->getUid()) return DIFFERENT;
-    if (elem->getPid() != last->getPid()) return DIFFERENT;
-    if (elem->getTid() != last->getTid()) return DIFFERENT;
-
-    // last is more than a minute old, stop squashing identical messages
-    if (elem->getRealTime().nsec() >
-        (last->getRealTime().nsec() + 60 * NS_PER_SEC))
-        return DIFFERENT;
-
-    // Identical message
-    const char* msgl = elem->getMsg();
-    const char* msgr = last->getMsg();
-    if (lenl == lenr) {
-        if (!fastcmp<memcmp>(msgl, msgr, lenl)) return SAME;
-        // liblog tagged messages (content gets summed)
-        if ((elem->getLogId() == LOG_ID_EVENTS) &&
-            (lenl == sizeof(android_log_event_int_t)) &&
-            !fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_int_t) -
-                                             sizeof(int32_t)) &&
-            (elem->getTag() == LIBLOG_LOG_TAG)) {
-            return SAME_LIBLOG;
-        }
-    }
-
-    // audit message (except sequence number) identical?
-    if (last->isBinary() &&
-        (lenl > static_cast<ssize_t>(sizeof(android_log_event_string_t))) &&
-        (lenr > static_cast<ssize_t>(sizeof(android_log_event_string_t)))) {
-        if (fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_string_t) -
-                                            sizeof(int32_t))) {
-            return DIFFERENT;
-        }
-        msgl += sizeof(android_log_event_string_t);
-        lenl -= sizeof(android_log_event_string_t);
-        msgr += sizeof(android_log_event_string_t);
-        lenr -= sizeof(android_log_event_string_t);
-    }
-    static const char avc[] = "): avc: ";
-    const char* avcl = android::strnstr(msgl, lenl, avc);
-    if (!avcl) return DIFFERENT;
-    lenl -= avcl - msgl;
-    const char* avcr = android::strnstr(msgr, lenr, avc);
-    if (!avcr) return DIFFERENT;
-    lenr -= avcr - msgr;
-    if (lenl != lenr) return DIFFERENT;
-    if (fastcmp<memcmp>(avcl + strlen(avc), avcr + strlen(avc),
-                        lenl - strlen(avc))) {
-        return DIFFERENT;
-    }
-    return SAME;
-}
-
-int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
-                   pid_t tid, const char* msg, uint16_t len) {
-    if (log_id >= LOG_ID_MAX) {
-        return -EINVAL;
-    }
-
-    // Slip the time by 1 nsec if the incoming lands on xxxxxx000 ns.
-    // This prevents any chance that an outside source can request an
-    // exact entry with time specified in ms or us precision.
-    if ((realtime.tv_nsec % 1000) == 0) ++realtime.tv_nsec;
-
-    LogBufferElement* elem = new LogBufferElement(log_id, realtime, uid, pid, tid, msg, len);
-
-    // b/137093665: don't coalesce security messages.
-    if (log_id == LOG_ID_SECURITY) {
-        wrlock();
-        log(elem);
-        unlock();
-
-        return len;
-    }
-
-    int prio = ANDROID_LOG_INFO;
-    const char* tag = nullptr;
-    size_t tag_len = 0;
-    if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
-        tag = tagToName(elem->getTag());
-        if (tag) {
-            tag_len = strlen(tag);
-        }
-    } else {
-        prio = *msg;
-        tag = msg + 1;
-        tag_len = strnlen(tag, len - 1);
-    }
-    if (!__android_log_is_loggable_len(prio, tag, tag_len, ANDROID_LOG_VERBOSE)) {
-        // Log traffic received to total
-        wrlock();
-        stats.addTotal(elem);
-        unlock();
-        delete elem;
-        return -EACCES;
-    }
-
-    wrlock();
-    LogBufferElement* currentLast = lastLoggedElements[log_id];
-    if (currentLast) {
-        LogBufferElement* dropped = droppedElements[log_id];
-        uint16_t count = dropped ? dropped->getDropped() : 0;
-        //
-        // State Init
-        //     incoming:
-        //         dropped = nullptr
-        //         currentLast = nullptr;
-        //         elem = incoming message
-        //     outgoing:
-        //         dropped = nullptr -> State 0
-        //         currentLast = copy of elem
-        //         log elem
-        // State 0
-        //     incoming:
-        //         count = 0
-        //         dropped = nullptr
-        //         currentLast = copy of last message
-        //         elem = incoming message
-        //     outgoing: if match != DIFFERENT
-        //         dropped = copy of first identical message -> State 1
-        //         currentLast = reference to elem
-        //     break: if match == DIFFERENT
-        //         dropped = nullptr -> State 0
-        //         delete copy of last message (incoming currentLast)
-        //         currentLast = copy of elem
-        //         log elem
-        // State 1
-        //     incoming:
-        //         count = 0
-        //         dropped = copy of first identical message
-        //         currentLast = reference to last held-back incoming
-        //                       message
-        //         elem = incoming message
-        //     outgoing: if match == SAME
-        //         delete copy of first identical message (dropped)
-        //         dropped = reference to last held-back incoming
-        //                   message set to chatty count of 1 -> State 2
-        //         currentLast = reference to elem
-        //     outgoing: if match == SAME_LIBLOG
-        //         dropped = copy of first identical message -> State 1
-        //         take sum of currentLast and elem
-        //         if sum overflows:
-        //             log currentLast
-        //             currentLast = reference to elem
-        //         else
-        //             delete currentLast
-        //             currentLast = reference to elem, sum liblog.
-        //     break: if match == DIFFERENT
-        //         delete dropped
-        //         dropped = nullptr -> State 0
-        //         log reference to last held-back (currentLast)
-        //         currentLast = copy of elem
-        //         log elem
-        // State 2
-        //     incoming:
-        //         count = chatty count
-        //         dropped = chatty message holding count
-        //         currentLast = reference to last held-back incoming
-        //                       message.
-        //         dropped = chatty message holding count
-        //         elem = incoming message
-        //     outgoing: if match != DIFFERENT
-        //         delete chatty message holding count
-        //         dropped = reference to last held-back incoming
-        //                   message, set to chatty count + 1
-        //         currentLast = reference to elem
-        //     break: if match == DIFFERENT
-        //         log dropped (chatty message)
-        //         dropped = nullptr -> State 0
-        //         log reference to last held-back (currentLast)
-        //         currentLast = copy of elem
-        //         log elem
-        //
-        enum match_type match = identical(elem, currentLast);
-        if (match != DIFFERENT) {
-            if (dropped) {
-                // Sum up liblog tag messages?
-                if ((count == 0) /* at Pass 1 */ && (match == SAME_LIBLOG)) {
-                    android_log_event_int_t* event =
-                        reinterpret_cast<android_log_event_int_t*>(
-                            const_cast<char*>(currentLast->getMsg()));
-                    //
-                    // To unit test, differentiate with something like:
-                    //    event->header.tag = htole32(CHATTY_LOG_TAG);
-                    // here, then instead of delete currentLast below,
-                    // log(currentLast) to see the incremental sums form.
-                    //
-                    uint32_t swab = event->payload.data;
-                    unsigned long long total = htole32(swab);
-                    event = reinterpret_cast<android_log_event_int_t*>(
-                        const_cast<char*>(elem->getMsg()));
-                    swab = event->payload.data;
-
-                    lastLoggedElements[LOG_ID_EVENTS] = elem;
-                    total += htole32(swab);
-                    // check for overflow
-                    if (total >= UINT32_MAX) {
-                        log(currentLast);
-                        unlock();
-                        return len;
-                    }
-                    stats.addTotal(currentLast);
-                    delete currentLast;
-                    swab = total;
-                    event->payload.data = htole32(swab);
-                    unlock();
-                    return len;
-                }
-                if (count == USHRT_MAX) {
-                    log(dropped);
-                    count = 1;
-                } else {
-                    delete dropped;
-                    ++count;
-                }
-            }
-            if (count) {
-                stats.addTotal(currentLast);
-                currentLast->setDropped(count);
-            }
-            droppedElements[log_id] = currentLast;
-            lastLoggedElements[log_id] = elem;
-            unlock();
-            return len;
-        }
-        if (dropped) {         // State 1 or 2
-            if (count) {       // State 2
-                log(dropped);  // report chatty
-            } else {           // State 1
-                delete dropped;
-            }
-            droppedElements[log_id] = nullptr;
-            log(currentLast);  // report last message in the series
-        } else {               // State 0
-            delete currentLast;
-        }
-    }
-    lastLoggedElements[log_id] = new LogBufferElement(*elem);
-
-    log(elem);
-    unlock();
-
-    return len;
-}
-
-// assumes LogBuffer::wrlock() held, owns elem, look after garbage collection
-void LogBuffer::log(LogBufferElement* elem) {
-    mLogElements.push_back(elem);
-    stats.add(elem);
-    maybePrune(elem->getLogId());
-}
-
-// Prune at most 10% of the log entries or maxPrune, whichever is less.
-//
-// LogBuffer::wrlock() must be held when this function is called.
-void LogBuffer::maybePrune(log_id_t id) {
-    size_t sizes = stats.sizes(id);
-    unsigned long maxSize = log_buffer_size(id);
-    if (sizes > maxSize) {
-        size_t sizeOver = sizes - ((maxSize * 9) / 10);
-        size_t elements = stats.realElements(id);
-        size_t minElements = elements / 100;
-        if (minElements < minPrune) {
-            minElements = minPrune;
-        }
-        unsigned long pruneRows = elements * sizeOver / sizes;
-        if (pruneRows < minElements) {
-            pruneRows = minElements;
-        }
-        if (pruneRows > maxPrune) {
-            pruneRows = maxPrune;
-        }
-        prune(id, pruneRows);
-    }
-}
-
-LogBufferElementCollection::iterator LogBuffer::erase(
-    LogBufferElementCollection::iterator it, bool coalesce) {
-    LogBufferElement* element = *it;
-    log_id_t id = element->getLogId();
-
-    // Remove iterator references in the various lists that will become stale
-    // after the element is erased from the main logging list.
-
-    {  // start of scope for found iterator
-        int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY))
-                      ? element->getTag()
-                      : element->getUid();
-        LogBufferIteratorMap::iterator found = mLastWorst[id].find(key);
-        if ((found != mLastWorst[id].end()) && (it == found->second)) {
-            mLastWorst[id].erase(found);
-        }
-    }
-
-    {  // start of scope for pid found iterator
-        // element->getUid() may not be AID_SYSTEM for next-best-watermark.
-        // will not assume id != LOG_ID_EVENTS or LOG_ID_SECURITY for KISS and
-        // long term code stability, find() check should be fast for those ids.
-        LogBufferPidIteratorMap::iterator found =
-            mLastWorstPidOfSystem[id].find(element->getPid());
-        if ((found != mLastWorstPidOfSystem[id].end()) &&
-            (it == found->second)) {
-            mLastWorstPidOfSystem[id].erase(found);
-        }
-    }
-
-    bool setLast[LOG_ID_MAX];
-    bool doSetLast = false;
-    log_id_for_each(i) {
-        doSetLast |= setLast[i] = mLastSet[i] && (it == mLast[i]);
-    }
-#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
-    LogBufferElementCollection::iterator bad = it;
-    int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY))
-                  ? element->getTag()
-                  : element->getUid();
-#endif
-    it = mLogElements.erase(it);
-    if (doSetLast) {
-        log_id_for_each(i) {
-            if (setLast[i]) {
-                if (__predict_false(it == mLogElements.end())) {  // impossible
-                    mLastSet[i] = false;
-                    mLast[i] = mLogElements.begin();
-                } else {
-                    mLast[i] = it;  // push down the road as next-best-watermark
-                }
-            }
-        }
-    }
-#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
-    log_id_for_each(i) {
-        for (auto b : mLastWorst[i]) {
-            if (bad == b.second) {
-                android::prdebug("stale mLastWorst[%d] key=%d mykey=%d\n", i,
-                                 b.first, key);
-            }
-        }
-        for (auto b : mLastWorstPidOfSystem[i]) {
-            if (bad == b.second) {
-                android::prdebug("stale mLastWorstPidOfSystem[%d] pid=%d\n", i,
-                                 b.first);
-            }
-        }
-        if (mLastSet[i] && (bad == mLast[i])) {
-            android::prdebug("stale mLast[%d]\n", i);
-            mLastSet[i] = false;
-            mLast[i] = mLogElements.begin();
-        }
-    }
-#endif
-    if (coalesce) {
-        stats.erase(element);
-    } else {
-        stats.subtract(element);
-    }
-    delete element;
-
-    return it;
-}
-
-// Define a temporary mechanism to report the last LogBufferElement pointer
-// for the specified uid, pid and tid. Used below to help merge-sort when
-// pruning for worst UID.
-class LogBufferElementKey {
-    const union {
-        struct {
-            uint32_t uid;
-            uint16_t pid;
-            uint16_t tid;
-        } __packed;
-        uint64_t value;
-    } __packed;
-
-   public:
-    LogBufferElementKey(uid_t uid, pid_t pid, pid_t tid)
-        : uid(uid), pid(pid), tid(tid) {
-    }
-    explicit LogBufferElementKey(uint64_t key) : value(key) {
-    }
-
-    uint64_t getKey() {
-        return value;
-    }
-};
-
-class LogBufferElementLast {
-    typedef std::unordered_map<uint64_t, LogBufferElement*> LogBufferElementMap;
-    LogBufferElementMap map;
-
-   public:
-    bool coalesce(LogBufferElement* element, uint16_t dropped) {
-        LogBufferElementKey key(element->getUid(), element->getPid(),
-                                element->getTid());
-        LogBufferElementMap::iterator it = map.find(key.getKey());
-        if (it != map.end()) {
-            LogBufferElement* found = it->second;
-            uint16_t moreDropped = found->getDropped();
-            if ((dropped + moreDropped) > USHRT_MAX) {
-                map.erase(it);
-            } else {
-                found->setDropped(dropped + moreDropped);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    void add(LogBufferElement* element) {
-        LogBufferElementKey key(element->getUid(), element->getPid(),
-                                element->getTid());
-        map[key.getKey()] = element;
-    }
-
-    inline void clear() {
-        map.clear();
-    }
-
-    void clear(LogBufferElement* element) {
-        uint64_t current = element->getRealTime().nsec() - (EXPIRE_RATELIMIT * NS_PER_SEC);
-        for (LogBufferElementMap::iterator it = map.begin(); it != map.end();) {
-            LogBufferElement* mapElement = it->second;
-            if (mapElement->getDropped() >= EXPIRE_THRESHOLD &&
-                current > mapElement->getRealTime().nsec()) {
-                it = map.erase(it);
-            } else {
-                ++it;
-            }
-        }
-    }
-};
-
-// If the selected reader is blocking our pruning progress, decide on
-// what kind of mitigation is necessary to unblock the situation.
-void LogBuffer::kickMe(LogTimeEntry* me, log_id_t id, unsigned long pruneRows) {
-    if (stats.sizes(id) > (2 * log_buffer_size(id))) {  // +100%
-        // A misbehaving or slow reader has its connection
-        // dropped if we hit too much memory pressure.
-        android::prdebug("Kicking blocked reader, pid %d, from LogBuffer::kickMe()\n",
-                         me->mClient->getPid());
-        me->release_Locked();
-    } else if (me->mTimeout.tv_sec || me->mTimeout.tv_nsec) {
-        // Allow a blocked WRAP timeout reader to
-        // trigger and start reporting the log data.
-        me->triggerReader_Locked();
-    } else {
-        // tell slow reader to skip entries to catch up
-        android::prdebug(
-                "Skipping %lu entries from slow reader, pid %d, from LogBuffer::kickMe()\n",
-                pruneRows, me->mClient->getPid());
-        me->triggerSkip_Locked(id, pruneRows);
-    }
-}
-
-// prune "pruneRows" of type "id" from the buffer.
-//
-// This garbage collection task is used to expire log entries. It is called to
-// remove all logs (clear), all UID logs (unprivileged clear), or every
-// 256 or 10% of the total logs (whichever is less) to prune the logs.
-//
-// First there is a prep phase where we discover the reader region lock that
-// acts as a backstop to any pruning activity to stop there and go no further.
-//
-// There are three major pruning loops that follow. All expire from the oldest
-// entries. Since there are multiple log buffers, the Android logging facility
-// will appear to drop entries 'in the middle' when looking at multiple log
-// sources and buffers. This effect is slightly more prominent when we prune
-// the worst offender by logging source. Thus the logs slowly loose content
-// and value as you move back in time. This is preferred since chatty sources
-// invariably move the logs value down faster as less chatty sources would be
-// expired in the noise.
-//
-// The first loop performs blacklisting and worst offender pruning. Falling
-// through when there are no notable worst offenders and have not hit the
-// region lock preventing further worst offender pruning. This loop also looks
-// after managing the chatty log entries and merging to help provide
-// statistical basis for blame. The chatty entries are not a notification of
-// how much logs you may have, but instead represent how much logs you would
-// have had in a virtual log buffer that is extended to cover all the in-memory
-// logs without loss. They last much longer than the represented pruned logs
-// since they get multiplied by the gains in the non-chatty log sources.
-//
-// The second loop get complicated because an algorithm of watermarks and
-// history is maintained to reduce the order and keep processing time
-// down to a minimum at scale. These algorithms can be costly in the face
-// of larger log buffers, or severly limited processing time granted to a
-// background task at lowest priority.
-//
-// This second loop does straight-up expiration from the end of the logs
-// (again, remember for the specified log buffer id) but does some whitelist
-// preservation. Thus whitelist is a Hail Mary low priority, blacklists and
-// spam filtration all take priority. This second loop also checks if a region
-// lock is causing us to buffer too much in the logs to help the reader(s),
-// and will tell the slowest reader thread to skip log entries, and if
-// persistent and hits a further threshold, kill the reader thread.
-//
-// The third thread is optional, and only gets hit if there was a whitelist
-// and more needs to be pruned against the backstop of the region lock.
-//
-// LogBuffer::wrlock() must be held when this function is called.
-//
-bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
-    LogTimeEntry* oldest = nullptr;
-    bool busy = false;
-    bool clearAll = pruneRows == ULONG_MAX;
-
-    LogTimeEntry::rdlock();
-
-    // Region locked?
-    LastLogTimes::iterator times = mTimes.begin();
-    while (times != mTimes.end()) {
-        LogTimeEntry* entry = times->get();
-        if (entry->isWatching(id) &&
-            (!oldest || (oldest->mStart > entry->mStart) ||
-             ((oldest->mStart == entry->mStart) &&
-              (entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec)))) {
-            oldest = entry;
-        }
-        times++;
-    }
-
-    LogBufferElementCollection::iterator it;
-
-    if (__predict_false(caller_uid != AID_ROOT)) {  // unlikely
-        // Only here if clear all request from non system source, so chatty
-        // filter logistics is not required.
-        it = mLastSet[id] ? mLast[id] : mLogElements.begin();
-        while (it != mLogElements.end()) {
-            LogBufferElement* element = *it;
-
-            if ((element->getLogId() != id) ||
-                (element->getUid() != caller_uid)) {
-                ++it;
-                continue;
-            }
-
-            if (!mLastSet[id] || ((*mLast[id])->getLogId() != id)) {
-                mLast[id] = it;
-                mLastSet[id] = true;
-            }
-
-            if (oldest && oldest->mStart <= element->getSequence()) {
-                busy = true;
-                kickMe(oldest, id, pruneRows);
-                break;
-            }
-
-            it = erase(it);
-            if (--pruneRows == 0) {
-                break;
-            }
-        }
-        LogTimeEntry::unlock();
-        return busy;
-    }
-
-    // prune by worst offenders; by blacklist, UID, and by PID of system UID
-    bool hasBlacklist = (id != LOG_ID_SECURITY) && mPrune.naughty();
-    while (!clearAll && (pruneRows > 0)) {
-        // recalculate the worst offender on every batched pass
-        int worst = -1;  // not valid for getUid() or getKey()
-        size_t worst_sizes = 0;
-        size_t second_worst_sizes = 0;
-        pid_t worstPid = 0;  // POSIX guarantees PID != 0
-
-        if (worstUidEnabledForLogid(id) && mPrune.worstUidEnabled()) {
-            // Calculate threshold as 12.5% of available storage
-            size_t threshold = log_buffer_size(id) / 8;
-
-            if ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) {
-                stats.sortTags(AID_ROOT, (pid_t)0, 2, id)
-                    .findWorst(worst, worst_sizes, second_worst_sizes,
-                               threshold);
-                // per-pid filter for AID_SYSTEM sources is too complex
-            } else {
-                stats.sort(AID_ROOT, (pid_t)0, 2, id)
-                    .findWorst(worst, worst_sizes, second_worst_sizes,
-                               threshold);
-
-                if ((worst == AID_SYSTEM) && mPrune.worstPidOfSystemEnabled()) {
-                    stats.sortPids(worst, (pid_t)0, 2, id)
-                        .findWorst(worstPid, worst_sizes, second_worst_sizes);
-                }
-            }
-        }
-
-        // skip if we have neither worst nor naughty filters
-        if ((worst == -1) && !hasBlacklist) {
-            break;
-        }
-
-        bool kick = false;
-        bool leading = true;
-        it = mLastSet[id] ? mLast[id] : mLogElements.begin();
-        // Perform at least one mandatory garbage collection cycle in following
-        // - clear leading chatty tags
-        // - coalesce chatty tags
-        // - check age-out of preserved logs
-        bool gc = pruneRows <= 1;
-        if (!gc && (worst != -1)) {
-            {  // begin scope for worst found iterator
-                LogBufferIteratorMap::iterator found =
-                    mLastWorst[id].find(worst);
-                if ((found != mLastWorst[id].end()) &&
-                    (found->second != mLogElements.end())) {
-                    leading = false;
-                    it = found->second;
-                }
-            }
-            if (worstPid) {  // begin scope for pid worst found iterator
-                // FYI: worstPid only set if !LOG_ID_EVENTS and
-                //      !LOG_ID_SECURITY, not going to make that assumption ...
-                LogBufferPidIteratorMap::iterator found =
-                    mLastWorstPidOfSystem[id].find(worstPid);
-                if ((found != mLastWorstPidOfSystem[id].end()) &&
-                    (found->second != mLogElements.end())) {
-                    leading = false;
-                    it = found->second;
-                }
-            }
-        }
-        static const timespec too_old = { EXPIRE_HOUR_THRESHOLD * 60 * 60, 0 };
-        LogBufferElementCollection::iterator lastt;
-        lastt = mLogElements.end();
-        --lastt;
-        LogBufferElementLast last;
-        while (it != mLogElements.end()) {
-            LogBufferElement* element = *it;
-
-            if (oldest && oldest->mStart <= element->getSequence()) {
-                busy = true;
-                // Do not let chatty eliding trigger any reader mitigation
-                break;
-            }
-
-            if (element->getLogId() != id) {
-                ++it;
-                continue;
-            }
-            // below this point element->getLogId() == id
-
-            if (leading && (!mLastSet[id] || ((*mLast[id])->getLogId() != id))) {
-                mLast[id] = it;
-                mLastSet[id] = true;
-            }
-
-            uint16_t dropped = element->getDropped();
-
-            // remove any leading drops
-            if (leading && dropped) {
-                it = erase(it);
-                continue;
-            }
-
-            if (dropped && last.coalesce(element, dropped)) {
-                it = erase(it, true);
-                continue;
-            }
-
-            int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY))
-                          ? element->getTag()
-                          : element->getUid();
-
-            if (hasBlacklist && mPrune.naughty(element)) {
-                last.clear(element);
-                it = erase(it);
-                if (dropped) {
-                    continue;
-                }
-
-                pruneRows--;
-                if (pruneRows == 0) {
-                    break;
-                }
-
-                if (key == worst) {
-                    kick = true;
-                    if (worst_sizes < second_worst_sizes) {
-                        break;
-                    }
-                    worst_sizes -= element->getMsgLen();
-                }
-                continue;
-            }
-
-            if ((element->getRealTime() < ((*lastt)->getRealTime() - too_old)) ||
-                (element->getRealTime() > (*lastt)->getRealTime())) {
-                break;
-            }
-
-            if (dropped) {
-                last.add(element);
-                if (worstPid &&
-                    ((!gc && (element->getPid() == worstPid)) ||
-                     (mLastWorstPidOfSystem[id].find(element->getPid()) ==
-                      mLastWorstPidOfSystem[id].end()))) {
-                    // element->getUid() may not be AID_SYSTEM, next best
-                    // watermark if current one empty. id is not LOG_ID_EVENTS
-                    // or LOG_ID_SECURITY because of worstPid check.
-                    mLastWorstPidOfSystem[id][element->getPid()] = it;
-                }
-                if ((!gc && !worstPid && (key == worst)) ||
-                    (mLastWorst[id].find(key) == mLastWorst[id].end())) {
-                    mLastWorst[id][key] = it;
-                }
-                ++it;
-                continue;
-            }
-
-            if ((key != worst) ||
-                (worstPid && (element->getPid() != worstPid))) {
-                leading = false;
-                last.clear(element);
-                ++it;
-                continue;
-            }
-            // key == worst below here
-            // If worstPid set, then element->getPid() == worstPid below here
-
-            pruneRows--;
-            if (pruneRows == 0) {
-                break;
-            }
-
-            kick = true;
-
-            uint16_t len = element->getMsgLen();
-
-            // do not create any leading drops
-            if (leading) {
-                it = erase(it);
-            } else {
-                stats.drop(element);
-                element->setDropped(1);
-                if (last.coalesce(element, 1)) {
-                    it = erase(it, true);
-                } else {
-                    last.add(element);
-                    if (worstPid &&
-                        (!gc || (mLastWorstPidOfSystem[id].find(worstPid) ==
-                                 mLastWorstPidOfSystem[id].end()))) {
-                        // element->getUid() may not be AID_SYSTEM, next best
-                        // watermark if current one empty. id is not
-                        // LOG_ID_EVENTS or LOG_ID_SECURITY because of worstPid.
-                        mLastWorstPidOfSystem[id][worstPid] = it;
-                    }
-                    if ((!gc && !worstPid) ||
-                        (mLastWorst[id].find(worst) == mLastWorst[id].end())) {
-                        mLastWorst[id][worst] = it;
-                    }
-                    ++it;
-                }
-            }
-            if (worst_sizes < second_worst_sizes) {
-                break;
-            }
-            worst_sizes -= len;
-        }
-        last.clear();
-
-        if (!kick || !mPrune.worstUidEnabled()) {
-            break;  // the following loop will ask bad clients to skip/drop
-        }
-    }
-
-    bool whitelist = false;
-    bool hasWhitelist = (id != LOG_ID_SECURITY) && mPrune.nice() && !clearAll;
-    it = mLastSet[id] ? mLast[id] : mLogElements.begin();
-    while ((pruneRows > 0) && (it != mLogElements.end())) {
-        LogBufferElement* element = *it;
-
-        if (element->getLogId() != id) {
-            it++;
-            continue;
-        }
-
-        if (!mLastSet[id] || ((*mLast[id])->getLogId() != id)) {
-            mLast[id] = it;
-            mLastSet[id] = true;
-        }
-
-        if (oldest && oldest->mStart <= element->getSequence()) {
-            busy = true;
-            if (!whitelist) kickMe(oldest, id, pruneRows);
-            break;
-        }
-
-        if (hasWhitelist && !element->getDropped() && mPrune.nice(element)) {
-            // WhiteListed
-            whitelist = true;
-            it++;
-            continue;
-        }
-
-        it = erase(it);
-        pruneRows--;
-    }
-
-    // Do not save the whitelist if we are reader range limited
-    if (whitelist && (pruneRows > 0)) {
-        it = mLastSet[id] ? mLast[id] : mLogElements.begin();
-        while ((it != mLogElements.end()) && (pruneRows > 0)) {
-            LogBufferElement* element = *it;
-
-            if (element->getLogId() != id) {
-                ++it;
-                continue;
-            }
-
-            if (!mLastSet[id] || ((*mLast[id])->getLogId() != id)) {
-                mLast[id] = it;
-                mLastSet[id] = true;
-            }
-
-            if (oldest && oldest->mStart <= element->getSequence()) {
-                busy = true;
-                kickMe(oldest, id, pruneRows);
-                break;
-            }
-
-            it = erase(it);
-            pruneRows--;
-        }
-    }
-
-    LogTimeEntry::unlock();
-
-    return (pruneRows > 0) && busy;
-}
-
-// clear all rows of type "id" from the buffer.
-bool LogBuffer::clear(log_id_t id, uid_t uid) {
-    bool busy = true;
-    // If it takes more than 4 tries (seconds) to clear, then kill reader(s)
-    for (int retry = 4;;) {
-        if (retry == 1) {  // last pass
-            // Check if it is still busy after the sleep, we say prune
-            // one entry, not another clear run, so we are looking for
-            // the quick side effect of the return value to tell us if
-            // we have a _blocked_ reader.
-            wrlock();
-            busy = prune(id, 1, uid);
-            unlock();
-            // It is still busy, blocked reader(s), lets kill them all!
-            // otherwise, lets be a good citizen and preserve the slow
-            // readers and let the clear run (below) deal with determining
-            // if we are still blocked and return an error code to caller.
-            if (busy) {
-                LogTimeEntry::wrlock();
-                LastLogTimes::iterator times = mTimes.begin();
-                while (times != mTimes.end()) {
-                    LogTimeEntry* entry = times->get();
-                    // Killer punch
-                    if (entry->isWatching(id)) {
-                        android::prdebug(
-                                "Kicking blocked reader, pid %d, from LogBuffer::clear()\n",
-                                entry->mClient->getPid());
-                        entry->release_Locked();
-                    }
-                    times++;
-                }
-                LogTimeEntry::unlock();
-            }
-        }
-        wrlock();
-        busy = prune(id, ULONG_MAX, uid);
-        unlock();
-        if (!busy || !--retry) {
-            break;
-        }
-        sleep(1);  // Let reader(s) catch up after notification
-    }
-    return busy;
-}
-
-// get the used space associated with "id".
-unsigned long LogBuffer::getSizeUsed(log_id_t id) {
-    rdlock();
-    size_t retval = stats.sizes(id);
-    unlock();
-    return retval;
-}
-
-// set the total space allocated to "id"
-int LogBuffer::setSize(log_id_t id, unsigned long size) {
-    // Reasonable limits ...
-    if (!__android_logger_valid_buffer_size(size)) {
-        return -1;
-    }
-    wrlock();
-    log_buffer_size(id) = size;
-    unlock();
-    return 0;
-}
-
-// get the total space allocated to "id"
-unsigned long LogBuffer::getSize(log_id_t id) {
-    rdlock();
-    size_t retval = log_buffer_size(id);
-    unlock();
-    return retval;
-}
-
-uint64_t LogBuffer::flushTo(SocketClient* reader, uint64_t start, pid_t* lastTid, bool privileged,
-                            bool security,
-                            int (*filter)(const LogBufferElement* element, void* arg), void* arg) {
-    LogBufferElementCollection::iterator it;
-    uid_t uid = reader->getUid();
-
-    rdlock();
-
-    if (start <= 1) {
-        // client wants to start from the beginning
-        it = mLogElements.begin();
-    } else {
-        // Client wants to start from some specified time. Chances are
-        // we are better off starting from the end of the time sorted list.
-        for (it = mLogElements.end(); it != mLogElements.begin();
-             /* do nothing */) {
-            --it;
-            LogBufferElement* element = *it;
-            if (element->getSequence() <= start) {
-                it++;
-                break;
-            }
-        }
-    }
-
-    uint64_t curr = start;
-
-    for (; it != mLogElements.end(); ++it) {
-        LogBufferElement* element = *it;
-
-        if (!privileged && (element->getUid() != uid)) {
-            continue;
-        }
-
-        if (!security && (element->getLogId() == LOG_ID_SECURITY)) {
-            continue;
-        }
-
-        // NB: calling out to another object with wrlock() held (safe)
-        if (filter) {
-            int ret = (*filter)(element, arg);
-            if (ret == false) {
-                continue;
-            }
-            if (ret != true) {
-                break;
-            }
-        }
-
-        bool sameTid = false;
-        if (lastTid) {
-            sameTid = lastTid[element->getLogId()] == element->getTid();
-            // Dropped (chatty) immediately following a valid log from the
-            // same source in the same log buffer indicates we have a
-            // multiple identical squash.  chatty that differs source
-            // is due to spam filter.  chatty to chatty of different
-            // source is also due to spam filter.
-            lastTid[element->getLogId()] =
-                (element->getDropped() && !sameTid) ? 0 : element->getTid();
-        }
-
-        unlock();
-
-        // range locking in LastLogTimes looks after us
-        curr = element->flushTo(reader, this, sameTid);
-
-        if (curr == element->FLUSH_ERROR) {
-            return curr;
-        }
-
-        rdlock();
-    }
-    unlock();
-
-    return curr;
-}
-
-std::string LogBuffer::formatStatistics(uid_t uid, pid_t pid,
-                                        unsigned int logMask) {
-    wrlock();
-
-    std::string ret = stats.format(uid, pid, logMask);
-
-    unlock();
-
-    return ret;
-}
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 16225a5..7f1e128 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2014 The Android Open Source Project
+ * Copyright (C) 2020 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,173 +14,45 @@
  * limitations under the License.
  */
 
-#ifndef _LOGD_LOG_BUFFER_H__
-#define _LOGD_LOG_BUFFER_H__
+#pragma once
 
 #include <sys/types.h>
 
-#include <list>
-#include <string>
+#include <functional>
 
-#include <android/log.h>
-#include <private/android_filesystem_config.h>
+#include <log/log.h>
 #include <sysutils/SocketClient.h>
 
 #include "LogBufferElement.h"
-#include "LogStatistics.h"
-#include "LogTags.h"
-#include "LogTimes.h"
-#include "LogWhiteBlackList.h"
 
-//
-// We are either in 1970ish (MONOTONIC) or 2016+ish (REALTIME) so to
-// differentiate without prejudice, we use 1972 to delineate, earlier
-// is likely monotonic, later is real. Otherwise we start using a
-// dividing line between monotonic and realtime if more than a minute
-// difference between them.
-//
-namespace android {
+class LogWriter;
 
-static bool isMonotonic(const log_time& mono) {
-    static const uint32_t EPOCH_PLUS_2_YEARS = 2 * 24 * 60 * 60 * 1461 / 4;
-    static const uint32_t EPOCH_PLUS_MINUTE = 60;
-
-    if (mono.tv_sec >= EPOCH_PLUS_2_YEARS) {
-        return false;
-    }
-
-    log_time now(CLOCK_REALTIME);
-
-    /* Timezone and ntp time setup? */
-    if (now.tv_sec >= EPOCH_PLUS_2_YEARS) {
-        return true;
-    }
-
-    /* no way to differentiate realtime from monotonic time */
-    if (now.tv_sec < EPOCH_PLUS_MINUTE) {
-        return false;
-    }
-
-    log_time cpu(CLOCK_MONOTONIC);
-    /* too close to call to differentiate monotonic times from realtime */
-    if ((cpu.tv_sec + EPOCH_PLUS_MINUTE) >= now.tv_sec) {
-        return false;
-    }
-
-    /* dividing line half way between monotonic and realtime */
-    return mono.tv_sec < ((cpu.tv_sec + now.tv_sec) / 2);
-}
-}
-
-typedef std::list<LogBufferElement*> LogBufferElementCollection;
+enum class FlushToResult {
+    kSkip,
+    kStop,
+    kWrite,
+};
 
 class LogBuffer {
-    LogBufferElementCollection mLogElements;
-    pthread_rwlock_t mLogElementsLock;
+  public:
+    virtual ~LogBuffer() {}
 
-    LogStatistics stats;
+    virtual void Init() = 0;
 
-    PruneList mPrune;
-    // watermark for last per log id
-    LogBufferElementCollection::iterator mLast[LOG_ID_MAX];
-    bool mLastSet[LOG_ID_MAX];
-    // watermark of any worst/chatty uid processing
-    typedef std::unordered_map<uid_t, LogBufferElementCollection::iterator>
-        LogBufferIteratorMap;
-    LogBufferIteratorMap mLastWorst[LOG_ID_MAX];
-    // watermark of any worst/chatty pid of system processing
-    typedef std::unordered_map<pid_t, LogBufferElementCollection::iterator>
-        LogBufferPidIteratorMap;
-    LogBufferPidIteratorMap mLastWorstPidOfSystem[LOG_ID_MAX];
-
-    unsigned long mMaxSize[LOG_ID_MAX];
-
-    bool monotonic;
-
-    LogTags tags;
-
-    LogBufferElement* lastLoggedElements[LOG_ID_MAX];
-    LogBufferElement* droppedElements[LOG_ID_MAX];
-    void log(LogBufferElement* elem);
-
-   public:
-    LastLogTimes& mTimes;
-
-    explicit LogBuffer(LastLogTimes* times);
-    ~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);
+    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;
     // 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)
-    uint64_t flushTo(SocketClient* writer, uint64_t start,
-                     pid_t* lastTid,  // &lastTid[LOG_ID_MAX] or nullptr
-                     bool privileged, bool security,
-                     int (*filter)(const LogBufferElement* element, void* arg) = nullptr,
-                     void* arg = nullptr);
+    static const uint64_t FLUSH_ERROR = 0;
+    virtual uint64_t FlushTo(
+            LogWriter* writer, uint64_t start,
+            pid_t* last_tid,  // nullable
+            const std::function<FlushToResult(const LogBufferElement* element)>& filter) = 0;
 
-    bool clear(log_id_t id, uid_t uid = AID_ROOT);
-    unsigned long getSize(log_id_t id);
-    int setSize(log_id_t id, unsigned long size);
-    unsigned long getSizeUsed(log_id_t id);
+    virtual bool Clear(log_id_t id, uid_t uid) = 0;
+    virtual unsigned long GetSize(log_id_t id) = 0;
+    virtual int SetSize(log_id_t id, unsigned long size) = 0;
 
-    std::string formatStatistics(uid_t uid, pid_t pid, unsigned int logMask);
-
-    void enableStatistics() {
-        stats.enableStatistics();
-    }
-
-    int initPrune(const char* cp) {
-        return mPrune.init(cp);
-    }
-    std::string formatPrune() {
-        return mPrune.format();
-    }
-
-    std::string formatGetEventTag(uid_t uid, const char* name,
-                                  const char* format) {
-        return tags.formatGetEventTag(uid, name, format);
-    }
-    std::string formatEntry(uint32_t tag, uid_t uid) {
-        return tags.formatEntry(tag, uid);
-    }
-    const char* tagToName(uint32_t tag) {
-        return tags.tagToName(tag);
-    }
-
-    // helper must be protected directly or implicitly by wrlock()/unlock()
-    const char* pidToName(pid_t pid) {
-        return stats.pidToName(pid);
-    }
-    uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); }
-    const char* uidToName(uid_t uid) {
-        return stats.uidToName(uid);
-    }
-    void wrlock() {
-        pthread_rwlock_wrlock(&mLogElementsLock);
-    }
-    void rdlock() {
-        pthread_rwlock_rdlock(&mLogElementsLock);
-    }
-    void unlock() {
-        pthread_rwlock_unlock(&mLogElementsLock);
-    }
-
-   private:
-    static constexpr size_t minPrune = 4;
-    static constexpr size_t maxPrune = 256;
-
-    void maybePrune(log_id_t id);
-    void kickMe(LogTimeEntry* me, log_id_t id, unsigned long pruneRows);
-
-    bool prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT);
-    LogBufferElementCollection::iterator erase(
-        LogBufferElementCollection::iterator it, bool coalesce = false);
-};
-
-#endif  // _LOGD_LOG_BUFFER_H__
+    virtual uint64_t sequence() const = 0;
+};
\ No newline at end of file
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 916ed42..c6dbda8 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "LogBufferElement.h"
+
 #include <ctype.h>
 #include <endian.h>
 #include <fcntl.h>
@@ -25,21 +27,15 @@
 #include <log/log_read.h>
 #include <private/android_logger.h>
 
-#include "LogBuffer.h"
-#include "LogBufferElement.h"
-#include "LogCommand.h"
-#include "LogReader.h"
+#include "LogStatistics.h"
 #include "LogUtils.h"
 
-const uint64_t LogBufferElement::FLUSH_ERROR(0);
-atomic_int_fast64_t LogBufferElement::sequence(1);
-
 LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
-                                   pid_t tid, const char* msg, uint16_t len)
+                                   pid_t tid, uint64_t sequence, const char* msg, uint16_t len)
     : mUid(uid),
       mPid(pid),
       mTid(tid),
-      mSequence(sequence.fetch_add(1, memory_order_relaxed)),
+      mSequence(sequence),
       mRealTime(realtime),
       mMsgLen(len),
       mLogId(log_id),
@@ -65,6 +61,23 @@
     }
 }
 
+LogBufferElement::LogBufferElement(LogBufferElement&& elem)
+    : mUid(elem.mUid),
+      mPid(elem.mPid),
+      mTid(elem.mTid),
+      mSequence(elem.mSequence),
+      mRealTime(elem.mRealTime),
+      mMsgLen(elem.mMsgLen),
+      mLogId(elem.mLogId),
+      mDropped(elem.mDropped) {
+    if (mDropped) {
+        mTag = elem.getTag();
+    } else {
+        mMsg = elem.mMsg;
+        elem.mMsg = nullptr;
+    }
+}
+
 LogBufferElement::~LogBufferElement() {
     if (!mDropped) {
         delete[] mMsg;
@@ -153,7 +166,7 @@
 }
 
 // assumption: mMsg == NULL
-size_t LogBufferElement::populateDroppedMessage(char*& buffer, LogBuffer* parent,
+size_t LogBufferElement::populateDroppedMessage(char*& buffer, LogStatistics* stats,
                                                 bool lastSame) {
     static const char tag[] = "chatty";
 
@@ -163,17 +176,13 @@
     }
 
     static const char format_uid[] = "uid=%u%s%s %s %u line%s";
-    parent->wrlock();
-    const char* name = parent->uidToName(mUid);
-    parent->unlock();
+    const char* name = stats->UidToName(mUid);
     const char* commName = android::tidToName(mTid);
     if (!commName && (mTid != mPid)) {
         commName = android::tidToName(mPid);
     }
     if (!commName) {
-        parent->wrlock();
-        commName = parent->pidToName(mPid);
-        parent->unlock();
+        commName = stats->PidToName(mPid);
     }
     if (name && name[0] && commName && (name[0] == commName[0])) {
         size_t len = strlen(name + 1);
@@ -189,16 +198,16 @@
     }
     if (name) {
         char* buf = nullptr;
-        asprintf(&buf, "(%s)", name);
-        if (buf) {
+        int result = asprintf(&buf, "(%s)", name);
+        if (result != -1) {
             free(const_cast<char*>(name));
             name = buf;
         }
     }
     if (commName) {
         char* buf = nullptr;
-        asprintf(&buf, " %s", commName);
-        if (buf) {
+        int result = asprintf(&buf, " %s", commName);
+        if (result != -1) {
             free(const_cast<char*>(commName));
             commName = buf;
         }
@@ -246,7 +255,7 @@
     return retval;
 }
 
-uint64_t LogBufferElement::flushTo(SocketClient* reader, LogBuffer* parent, bool lastSame) {
+bool LogBufferElement::FlushTo(LogWriter* writer, LogStatistics* stats, bool lastSame) {
     struct logger_entry entry = {};
 
     entry.hdr_size = sizeof(struct logger_entry);
@@ -257,23 +266,18 @@
     entry.sec = mRealTime.tv_sec;
     entry.nsec = mRealTime.tv_nsec;
 
-    struct iovec iovec[2];
-    iovec[0].iov_base = &entry;
-    iovec[0].iov_len = entry.hdr_size;
-
     char* buffer = nullptr;
-
+    const char* msg;
     if (mDropped) {
-        entry.len = populateDroppedMessage(buffer, parent, lastSame);
-        if (!entry.len) return mSequence;
-        iovec[1].iov_base = buffer;
+        entry.len = populateDroppedMessage(buffer, stats, lastSame);
+        if (!entry.len) return true;
+        msg = buffer;
     } else {
+        msg = mMsg;
         entry.len = mMsgLen;
-        iovec[1].iov_base = mMsg;
     }
-    iovec[1].iov_len = entry.len;
 
-    uint64_t retval = reader->sendDatav(iovec, 1 + (entry.len != 0)) ? FLUSH_ERROR : mSequence;
+    bool retval = writer->Write(entry, msg);
 
     if (buffer) free(buffer);
 
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 434b7db..35252f9 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -16,15 +16,15 @@
 
 #pragma once
 
-#include <stdatomic.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <sys/types.h>
 
 #include <log/log.h>
-#include <sysutils/SocketClient.h>
 
-class LogBuffer;
+#include "LogWriter.h"
+
+class LogStatistics;
 
 #define EXPIRE_HOUR_THRESHOLD 24  // Only expire chatty UID logs to preserve
                                   // non-chatty UIDs less than this age in hours
@@ -33,8 +33,6 @@
 #define EXPIRE_RATELIMIT 10  // maximum rate in seconds to report expiration
 
 class __attribute__((packed)) LogBufferElement {
-    friend LogBuffer;
-
     // sized to match reality of incoming log packets
     const uint32_t mUid;
     const uint32_t mPid;
@@ -52,16 +50,14 @@
     const uint8_t mLogId;
     bool mDropped;
 
-    static atomic_int_fast64_t sequence;
-
     // assumption: mDropped == true
-    size_t populateDroppedMessage(char*& buffer, LogBuffer* parent,
-                                  bool lastSame);
+    size_t populateDroppedMessage(char*& buffer, LogStatistics* parent, bool lastSame);
 
-   public:
-    LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
-                     pid_t tid, const char* msg, uint16_t len);
+  public:
+    LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
+                     uint64_t sequence, const char* msg, uint16_t len);
     LogBufferElement(const LogBufferElement& elem);
+    LogBufferElement(LogBufferElement&& elem);
     ~LogBufferElement();
 
     bool isBinary(void) const {
@@ -92,11 +88,9 @@
         return mDropped ? nullptr : mMsg;
     }
     uint64_t getSequence() const { return mSequence; }
-    static uint64_t getCurrentSequence() { return sequence.load(memory_order_relaxed); }
     log_time getRealTime(void) const {
         return mRealTime;
     }
 
-    static const uint64_t FLUSH_ERROR;
-    uint64_t flushTo(SocketClient* writer, LogBuffer* parent, bool lastSame);
+    bool FlushTo(LogWriter* writer, LogStatistics* parent, bool lastSame);
 };
diff --git a/logd/LogBufferTest.cpp b/logd/LogBufferTest.cpp
new file mode 100644
index 0000000..334d57b
--- /dev/null
+++ b/logd/LogBufferTest.cpp
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2020 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 "LogBufferTest.h"
+
+#include <unistd.h>
+
+#include <limits>
+#include <memory>
+#include <regex>
+#include <vector>
+
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+#include "LogReaderThread.h"
+#include "LogWriter.h"
+
+using android::base::Join;
+using android::base::Split;
+using android::base::StringPrintf;
+
+#ifndef __ANDROID__
+unsigned long __android_logger_get_buffer_size(log_id_t) {
+    return 1024 * 1024;
+}
+
+bool __android_logger_valid_buffer_size(unsigned long) {
+    return true;
+}
+#endif
+
+void android::prdebug(const char* fmt, ...) {
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
+    va_end(ap);
+}
+
+char* android::uidToName(uid_t) {
+    return nullptr;
+}
+
+static std::vector<std::string> CompareLoggerEntries(const logger_entry& expected,
+                                                     const logger_entry& result, bool ignore_len) {
+    std::vector<std::string> errors;
+    if (!ignore_len && expected.len != result.len) {
+        errors.emplace_back(
+                StringPrintf("len: expected %" PRIu16 " vs %" PRIu16, expected.len, result.len));
+    }
+    if (expected.hdr_size != result.hdr_size) {
+        errors.emplace_back(StringPrintf("hdr_size: %" PRIu16 " vs %" PRIu16, expected.hdr_size,
+                                         result.hdr_size));
+    }
+    if (expected.pid != result.pid) {
+        errors.emplace_back(
+                StringPrintf("pid: expected %" PRIi32 " vs %" PRIi32, expected.pid, result.pid));
+    }
+    if (expected.tid != result.tid) {
+        errors.emplace_back(
+                StringPrintf("tid: expected %" PRIu32 " vs %" PRIu32, expected.tid, result.tid));
+    }
+    if (expected.sec != result.sec) {
+        errors.emplace_back(
+                StringPrintf("sec: expected %" PRIu32 " vs %" PRIu32, expected.sec, result.sec));
+    }
+    if (expected.nsec != result.nsec) {
+        errors.emplace_back(
+                StringPrintf("nsec: expected %" PRIu32 " vs %" PRIu32, expected.nsec, result.nsec));
+    }
+    if (expected.lid != result.lid) {
+        errors.emplace_back(
+                StringPrintf("lid: expected %" PRIu32 " vs %" PRIu32, expected.lid, result.lid));
+    }
+    if (expected.uid != result.uid) {
+        errors.emplace_back(
+                StringPrintf("uid: expected %" PRIu32 " vs %" PRIu32, expected.uid, result.uid));
+    }
+    return errors;
+}
+
+static std::string MakePrintable(std::string in) {
+    if (in.size() > 80) {
+        in = in.substr(0, 80) + "...";
+    }
+    std::string result;
+    for (const char c : in) {
+        if (isprint(c)) {
+            result.push_back(c);
+        } else {
+            result.append(StringPrintf("\\%02x", static_cast<int>(c) & 0xFF));
+        }
+    }
+    return result;
+}
+
+static std::string CompareMessages(const std::string& expected, const std::string& result) {
+    if (expected == result) {
+        return {};
+    }
+    size_t diff_index = 0;
+    for (; diff_index < std::min(expected.size(), result.size()); ++diff_index) {
+        if (expected[diff_index] != result[diff_index]) {
+            break;
+        }
+    }
+
+    if (diff_index < 10) {
+        auto expected_short = MakePrintable(expected);
+        auto result_short = MakePrintable(result);
+        return StringPrintf("msg: expected '%s' vs '%s'", expected_short.c_str(),
+                            result_short.c_str());
+    }
+
+    auto expected_short = MakePrintable(expected.substr(diff_index));
+    auto result_short = MakePrintable(result.substr(diff_index));
+    return StringPrintf("msg: index %zu: expected '%s' vs '%s'", diff_index, expected_short.c_str(),
+                        result_short.c_str());
+}
+
+static std::string CompareRegexMessages(const std::string& expected, const std::string& result) {
+    auto expected_pieces = Split(expected, std::string("\0", 1));
+    auto result_pieces = Split(result, std::string("\0", 1));
+
+    if (expected_pieces.size() != 3 || result_pieces.size() != 3) {
+        return StringPrintf(
+                "msg: should have 3 null delimited strings found %d in expected, %d in result: "
+                "'%s' vs '%s'",
+                static_cast<int>(expected_pieces.size()), static_cast<int>(result_pieces.size()),
+                MakePrintable(expected).c_str(), MakePrintable(result).c_str());
+    }
+    if (expected_pieces[0] != result_pieces[0]) {
+        return StringPrintf("msg: tag/priority mismatch expected '%s' vs '%s'",
+                            MakePrintable(expected_pieces[0]).c_str(),
+                            MakePrintable(result_pieces[0]).c_str());
+    }
+    std::regex expected_tag_regex(expected_pieces[1]);
+    if (!std::regex_search(result_pieces[1], expected_tag_regex)) {
+        return StringPrintf("msg: message regex mismatch expected '%s' vs '%s'",
+                            MakePrintable(expected_pieces[1]).c_str(),
+                            MakePrintable(result_pieces[1]).c_str());
+    }
+    if (expected_pieces[2] != result_pieces[2]) {
+        return StringPrintf("msg: nothing expected after final null character '%s' vs '%s'",
+                            MakePrintable(expected_pieces[2]).c_str(),
+                            MakePrintable(result_pieces[2]).c_str());
+    }
+    return {};
+}
+
+void CompareLogMessages(const std::vector<LogMessage>& expected,
+                        const std::vector<LogMessage>& result) {
+    EXPECT_EQ(expected.size(), result.size());
+    size_t end = std::min(expected.size(), result.size());
+    size_t num_errors = 0;
+    for (size_t i = 0; i < end; ++i) {
+        auto errors =
+                CompareLoggerEntries(expected[i].entry, result[i].entry, expected[i].regex_compare);
+        auto msg_error = expected[i].regex_compare
+                                 ? CompareRegexMessages(expected[i].message, result[i].message)
+                                 : CompareMessages(expected[i].message, result[i].message);
+        if (!msg_error.empty()) {
+            errors.emplace_back(msg_error);
+        }
+        if (!errors.empty()) {
+            GTEST_LOG_(ERROR) << "Mismatch log message " << i << "\n" << Join(errors, "\n");
+            ++num_errors;
+        }
+    }
+    EXPECT_EQ(0U, num_errors);
+}
+
+void FixupMessages(std::vector<LogMessage>* messages) {
+    for (auto& [entry, message, _] : *messages) {
+        entry.hdr_size = sizeof(logger_entry);
+        entry.len = message.size();
+    }
+}
+
+TEST_P(LogBufferTest, smoke) {
+    std::vector<LogMessage> log_messages = {
+            {{
+                     .pid = 1,
+                     .tid = 1,
+                     .sec = 1234,
+                     .nsec = 323001,
+                     .lid = LOG_ID_MAIN,
+                     .uid = 0,
+             },
+             "smoke test"},
+    };
+    FixupMessages(&log_messages);
+    LogMessages(log_messages);
+
+    std::vector<LogMessage> read_log_messages;
+    std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, nullptr));
+    uint64_t flush_result = log_buffer_->FlushTo(test_writer.get(), 1, nullptr, nullptr);
+    EXPECT_EQ(1ULL, flush_result);
+    CompareLogMessages(log_messages, read_log_messages);
+}
+
+TEST_P(LogBufferTest, smoke_with_reader_thread) {
+    std::vector<LogMessage> log_messages = {
+            {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
+             "first"},
+            {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
+             "second"},
+            {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_KERNEL, .uid = 0},
+             "third"},
+            {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20004, .lid = LOG_ID_MAIN, .uid = 0},
+             "fourth"},
+            {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20005, .lid = LOG_ID_RADIO, .uid = 0},
+             "fifth"},
+            {{.pid = 2, .tid = 2, .sec = 10000, .nsec = 20006, .lid = LOG_ID_RADIO, .uid = 0},
+             "sixth"},
+            {{.pid = 3, .tid = 2, .sec = 10000, .nsec = 20007, .lid = LOG_ID_RADIO, .uid = 0},
+             "seventh"},
+            {{.pid = 4, .tid = 2, .sec = 10000, .nsec = 20008, .lid = LOG_ID_MAIN, .uid = 0},
+             "eighth"},
+            {{.pid = 5, .tid = 2, .sec = 10000, .nsec = 20009, .lid = LOG_ID_CRASH, .uid = 0},
+             "nineth"},
+            {{.pid = 6, .tid = 2, .sec = 10000, .nsec = 20011, .lid = LOG_ID_MAIN, .uid = 0},
+             "tenth"},
+    };
+    FixupMessages(&log_messages);
+    LogMessages(log_messages);
+
+    std::vector<LogMessage> read_log_messages;
+    bool released = false;
+
+    {
+        auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
+        std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
+        std::unique_ptr<LogReaderThread> log_reader(
+                new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
+                                    0, ~0, 0, {}, 1, {}));
+        reader_list_.reader_threads().emplace_back(std::move(log_reader));
+    }
+
+    while (!released) {
+        usleep(5000);
+    }
+    {
+        auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
+        EXPECT_EQ(0U, reader_list_.reader_threads().size());
+    }
+    CompareLogMessages(log_messages, read_log_messages);
+}
+
+// Generate random messages, set the 'sec' parameter explicit though, to be able to track the
+// expected order of messages.
+LogMessage GenerateRandomLogMessage(uint32_t sec) {
+    auto rand_uint32 = [](int max) -> uint32_t { return rand() % max; };
+    logger_entry entry = {
+            .hdr_size = sizeof(logger_entry),
+            .pid = rand() % 5000,
+            .tid = rand_uint32(5000),
+            .sec = sec,
+            .nsec = rand_uint32(NS_PER_SEC),
+            .lid = rand_uint32(LOG_ID_STATS),
+            .uid = rand_uint32(100000),
+    };
+
+    // See comment in ChattyLogBuffer::Log() for why this is disallowed.
+    if (entry.nsec % 1000 == 0) {
+        ++entry.nsec;
+    }
+
+    if (entry.lid == LOG_ID_EVENTS) {
+        entry.lid = LOG_ID_KERNEL;
+    }
+
+    std::string message;
+    char priority = ANDROID_LOG_INFO + rand() % 2;
+    message.push_back(priority);
+
+    int tag_length = 2 + rand() % 10;
+    for (int i = 0; i < tag_length; ++i) {
+        message.push_back('a' + rand() % 26);
+    }
+    message.push_back('\0');
+
+    int msg_length = 2 + rand() % 1000;
+    for (int i = 0; i < msg_length; ++i) {
+        message.push_back('a' + rand() % 26);
+    }
+    message.push_back('\0');
+
+    entry.len = message.size();
+
+    return {entry, message};
+}
+
+TEST_P(LogBufferTest, random_messages) {
+    srand(1);
+    std::vector<LogMessage> log_messages;
+    for (size_t i = 0; i < 1000; ++i) {
+        log_messages.emplace_back(GenerateRandomLogMessage(i));
+    }
+    LogMessages(log_messages);
+
+    std::vector<LogMessage> read_log_messages;
+    bool released = false;
+
+    {
+        auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
+        std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
+        std::unique_ptr<LogReaderThread> log_reader(
+                new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
+                                    0, ~0, 0, {}, 1, {}));
+        reader_list_.reader_threads().emplace_back(std::move(log_reader));
+    }
+
+    while (!released) {
+        usleep(5000);
+    }
+    {
+        auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
+        EXPECT_EQ(0U, reader_list_.reader_threads().size());
+    }
+    CompareLogMessages(log_messages, read_log_messages);
+}
+
+INSTANTIATE_TEST_CASE_P(LogBufferTests, LogBufferTest, testing::Values("chatty", "simple"));
diff --git a/logd/LogBufferTest.h b/logd/LogBufferTest.h
new file mode 100644
index 0000000..1659f12
--- /dev/null
+++ b/logd/LogBufferTest.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "ChattyLogBuffer.h"
+#include "LogReaderList.h"
+#include "LogStatistics.h"
+#include "LogTags.h"
+#include "LogWhiteBlackList.h"
+#include "SimpleLogBuffer.h"
+
+struct LogMessage {
+    logger_entry entry;
+    std::string message;
+    bool regex_compare = false;  // Only set for expected messages, when true 'message' should be
+                                 // interpretted as a regex.
+};
+
+// Compares the ordered list of expected and result, causing a test failure with appropriate
+// information on failure.
+void CompareLogMessages(const std::vector<LogMessage>& expected,
+                        const std::vector<LogMessage>& result);
+// Sets hdr_size and len parameters appropriately.
+void FixupMessages(std::vector<LogMessage>* messages);
+
+class TestWriter : public LogWriter {
+  public:
+    TestWriter(std::vector<LogMessage>* msgs, bool* released)
+        : LogWriter(0, true, true), msgs_(msgs), released_(released) {}
+    bool Write(const logger_entry& entry, const char* message) override {
+        msgs_->emplace_back(LogMessage{entry, std::string(message, entry.len), false});
+        return true;
+    }
+
+    void Release() {
+        if (released_) *released_ = true;
+    }
+
+    std::string name() const override { return "test_writer"; }
+
+  private:
+    std::vector<LogMessage>* msgs_;
+    bool* released_;
+};
+
+class LogBufferTest : public testing::TestWithParam<std::string> {
+  protected:
+    void SetUp() override {
+        if (GetParam() == "chatty") {
+            log_buffer_.reset(new ChattyLogBuffer(&reader_list_, &tags_, &prune_, &stats_));
+        } else if (GetParam() == "simple") {
+            log_buffer_.reset(new SimpleLogBuffer(&reader_list_, &tags_, &stats_));
+        } else {
+            FAIL() << "Unknown buffer type selected for test";
+        }
+    }
+
+    void LogMessages(const std::vector<LogMessage>& messages) {
+        for (auto& [entry, message, _] : messages) {
+            log_buffer_->Log(static_cast<log_id_t>(entry.lid), log_time(entry.sec, entry.nsec),
+                             entry.uid, entry.pid, entry.tid, message.c_str(), message.size());
+        }
+    }
+
+    LogReaderList reader_list_;
+    LogTags tags_;
+    PruneList prune_;
+    LogStatistics stats_{false};
+    std::unique_ptr<LogBuffer> log_buffer_;
+};
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index edd326a..1ea87a9 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "LogKlog.h"
+
 #include <ctype.h>
 #include <errno.h>
 #include <inttypes.h>
@@ -29,8 +31,6 @@
 #include <private/android_logger.h>
 
 #include "LogBuffer.h"
-#include "LogKlog.h"
-#include "LogReader.h"
 
 #define KMSG_PRIORITY(PRI) \
     '<', '0' + (LOG_SYSLOG | (PRI)) / 10, '0' + (LOG_SYSLOG | (PRI)) % 10, '>'
@@ -201,15 +201,14 @@
                                        ? log_time(log_time::EPOCH)
                                        : (log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC));
 
-LogKlog::LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead,
-                 bool auditd)
+LogKlog::LogKlog(LogBuffer* buf, int fdWrite, int fdRead, bool auditd, LogStatistics* stats)
     : SocketListener(fdRead, false),
       logbuf(buf),
-      reader(reader),
       signature(CLOCK_MONOTONIC),
       initialized(false),
       enableLogging(true),
-      auditd(auditd) {
+      auditd(auditd),
+      stats_(stats) {
     static const char klogd_message[] = "%s%s%" PRIu64 "\n";
     char buffer[strlen(priority_message) + strlen(klogdStr) +
                 strlen(klogd_message) + 20];
@@ -309,8 +308,6 @@
         }
         buf = cp;
 
-        if (isMonotonic()) return now;
-
         const char* b;
         if (((b = android::strnstr(cp, len, suspendStr))) &&
             (((b += strlen(suspendStr)) - cp) < len)) {
@@ -356,11 +353,7 @@
 
         convertMonotonicToReal(now);
     } else {
-        if (isMonotonic()) {
-            now = log_time(CLOCK_MONOTONIC);
-        } else {
-            now = log_time(CLOCK_REALTIME);
-        }
+        now = log_time(CLOCK_REALTIME);
     }
     return now;
 }
@@ -431,45 +424,6 @@
     return pri;
 }
 
-// Passed the entire SYSLOG_ACTION_READ_ALL buffer and interpret a
-// compensated start time.
-void LogKlog::synchronize(const char* buf, ssize_t len) {
-    const char* cp = android::strnstr(buf, len, suspendStr);
-    if (!cp) {
-        cp = android::strnstr(buf, len, resumeStr);
-        if (!cp) return;
-    } else {
-        const char* rp = android::strnstr(buf, len, resumeStr);
-        if (rp && (rp < cp)) cp = rp;
-    }
-
-    do {
-        --cp;
-    } while ((cp > buf) && (*cp != '\n'));
-    if (*cp == '\n') {
-        ++cp;
-    }
-    parseKernelPrio(cp, len - (cp - buf));
-
-    log_time now = sniffTime(cp, len - (cp - buf), true);
-
-    const char* suspended = android::strnstr(buf, len, suspendedStr);
-    if (!suspended || (suspended > cp)) {
-        return;
-    }
-    cp = suspended;
-
-    do {
-        --cp;
-    } while ((cp > buf) && (*cp != '\n'));
-    if (*cp == '\n') {
-        ++cp;
-    }
-    parseKernelPrio(cp, len - (cp - buf));
-
-    sniffTime(cp, len - (cp - buf), true);
-}
-
 // Convert kernel log priority number into an Android Logger priority number
 static int convertKernelPrioToAndroidPrio(int pri) {
     switch (pri & LOG_PRIMASK) {
@@ -573,9 +527,7 @@
     const pid_t tid = pid;
     uid_t uid = AID_ROOT;
     if (pid) {
-        logbuf->wrlock();
-        uid = logbuf->pidToUid(pid);
-        logbuf->unlock();
+        uid = stats_->PidToUid(pid);
     }
 
     // Parse (rules at top) to pull out a tag from the incoming kernel message.
@@ -789,7 +741,7 @@
     memcpy(np, p, b);
     np[b] = '\0';
 
-    if (!isMonotonic()) {
+    {
         // Watch out for singular race conditions with timezone causing near
         // integer quarter-hour jumps in the time and compensate accordingly.
         // Entries will be temporal within near_seconds * 2. b/21868540
@@ -815,12 +767,7 @@
     }
 
     // Log message
-    int rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr, (uint16_t)n);
-
-    // notify readers
-    if (rc > 0) {
-        reader->notifyNewLog(static_cast<log_mask_t>(1 << LOG_ID_KERNEL));
-    }
+    int rc = logbuf->Log(LOG_ID_KERNEL, now, uid, pid, tid, newstr, (uint16_t)n);
 
     return rc;
 }
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index 6bfd6a8..56e0452 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -14,18 +14,16 @@
  * limitations under the License.
  */
 
-#ifndef _LOGD_LOG_KLOG_H__
-#define _LOGD_LOG_KLOG_H__
+#pragma once
 
 #include <private/android_logger.h>
 #include <sysutils/SocketListener.h>
 
-class LogBuffer;
-class LogReader;
+#include "LogBuffer.h"
+#include "LogStatistics.h"
 
 class LogKlog : public SocketListener {
     LogBuffer* logbuf;
-    LogReader* reader;
     const log_time signature;
     // Set once thread is started, separates KLOG_ACTION_READ_ALL
     // and KLOG_ACTION_READ phases.
@@ -38,27 +36,18 @@
 
     static log_time correction;
 
-   public:
-    LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead,
-            bool auditd);
+  public:
+    LogKlog(LogBuffer* buf, int fdWrite, int fdRead, bool auditd, LogStatistics* stats);
     int log(const char* buf, ssize_t len);
-    void synchronize(const char* buf, ssize_t len);
 
-    bool isMonotonic() {
-        return logbuf->isMonotonic();
-    }
-    static void convertMonotonicToReal(log_time& real) {
-        real += correction;
-    }
-    static void convertRealToMonotonic(log_time& real) {
-        real -= correction;
-    }
+    static void convertMonotonicToReal(log_time& real) { real += correction; }
 
-   protected:
-     log_time sniffTime(const char*& buf, ssize_t len, bool reverse);
-     pid_t sniffPid(const char*& buf, ssize_t len);
-     void calculateCorrection(const log_time& monotonic, const char* real_string, ssize_t len);
-     virtual bool onDataAvailable(SocketClient* cli);
+  protected:
+    log_time sniffTime(const char*& buf, ssize_t len, bool reverse);
+    pid_t sniffPid(const char*& buf, ssize_t len);
+    void calculateCorrection(const log_time& monotonic, const char* real_string, ssize_t len);
+    virtual bool onDataAvailable(SocketClient* cli);
+
+  private:
+    LogStatistics* stats_;
 };
-
-#endif
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index ba61042..a6ab50b 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -22,42 +22,53 @@
 #include <sys/un.h>
 #include <unistd.h>
 
+#include <thread>
+
 #include <cutils/sockets.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
 #include "LogBuffer.h"
 #include "LogListener.h"
-#include "LogUtils.h"
+#include "LogPermissions.h"
 
-LogListener::LogListener(LogBuffer* buf, LogReader* reader)
-    : SocketListener(getLogSocket(), false), logbuf(buf), reader(reader) {}
+LogListener::LogListener(LogBuffer* buf) : socket_(GetLogSocket()), logbuf_(buf) {}
 
-bool LogListener::onDataAvailable(SocketClient* cli) {
-    static bool name_set;
-    if (!name_set) {
-        prctl(PR_SET_NAME, "logd.writer");
-        name_set = true;
+bool LogListener::StartListener() {
+    if (socket_ <= 0) {
+        return false;
     }
+    auto thread = std::thread(&LogListener::ThreadFunction, this);
+    thread.detach();
+    return true;
+}
 
+void LogListener::ThreadFunction() {
+    prctl(PR_SET_NAME, "logd.writer");
+
+    while (true) {
+        HandleData();
+    }
+}
+
+void LogListener::HandleData() {
     // + 1 to ensure null terminator if MAX_PAYLOAD buffer is received
-    char buffer[sizeof(android_log_header_t) + LOGGER_ENTRY_MAX_PAYLOAD + 1];
-    struct iovec iov = { buffer, sizeof(buffer) - 1 };
+    __attribute__((uninitialized)) char
+            buffer[sizeof(android_log_header_t) + LOGGER_ENTRY_MAX_PAYLOAD + 1];
+    struct iovec iov = {buffer, sizeof(buffer) - 1};
 
     alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
     struct msghdr hdr = {
         nullptr, 0, &iov, 1, control, sizeof(control), 0,
     };
 
-    int socket = cli->getSocket();
-
     // To clear the entire buffer is secure/safe, but this contributes to 1.68%
     // overhead under logging load. We are safe because we check counts, but
     // still need to clear null terminator
     // memset(buffer, 0, sizeof(buffer));
-    ssize_t n = recvmsg(socket, &hdr, 0);
+    ssize_t n = recvmsg(socket_, &hdr, 0);
     if (n <= (ssize_t)(sizeof(android_log_header_t))) {
-        return false;
+        return;
     }
 
     buffer[n] = 0;
@@ -75,14 +86,14 @@
     }
 
     if (cred == nullptr) {
-        return false;
+        return;
     }
 
     if (cred->uid == AID_LOGD) {
         // ignore log messages we send to ourself.
         // Such log messages are often generated by libraries we depend on
         // which use standard Android logging.
-        return false;
+        return;
     }
 
     android_log_header_t* header =
@@ -90,13 +101,13 @@
     log_id_t logId = static_cast<log_id_t>(header->id);
     if (/* logId < LOG_ID_MIN || */ logId >= LOG_ID_MAX ||
         logId == LOG_ID_KERNEL) {
-        return false;
+        return;
     }
 
     if ((logId == LOG_ID_SECURITY) &&
         (!__android_log_security() ||
          !clientHasLogCredentials(cred->uid, cred->gid, cred->pid))) {
-        return false;
+        return;
     }
 
     char* msg = ((char*)buffer) + sizeof(android_log_header_t);
@@ -105,16 +116,11 @@
     // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
     // truncated message to the logs.
 
-    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;
+    logbuf_->Log(logId, header->realtime, cred->uid, cred->pid, header->tid, msg,
+                 ((size_t)n <= UINT16_MAX) ? (uint16_t)n : UINT16_MAX);
 }
 
-int LogListener::getLogSocket() {
+int LogListener::GetLogSocket() {
     static const char socketName[] = "logdw";
     int sock = android_get_control_socket(socketName);
 
diff --git a/logd/LogListener.h b/logd/LogListener.h
index 8fe3da4..c114e38 100644
--- a/logd/LogListener.h
+++ b/logd/LogListener.h
@@ -14,24 +14,20 @@
  * limitations under the License.
  */
 
-#ifndef _LOGD_LOG_LISTENER_H__
-#define _LOGD_LOG_LISTENER_H__
+#pragma once
 
-#include <sysutils/SocketListener.h>
-#include "LogReader.h"
+#include "LogBuffer.h"
 
-class LogListener : public SocketListener {
-    LogBuffer* logbuf;
-    LogReader* reader;
+class LogListener {
+  public:
+    LogListener(LogBuffer* buf);
+    bool StartListener();
 
-   public:
-     LogListener(LogBuffer* buf, LogReader* reader);
+  private:
+    void ThreadFunction();
+    void HandleData();
+    static int GetLogSocket();
 
-   protected:
-    virtual bool onDataAvailable(SocketClient* cli);
-
-   private:
-    static int getLogSocket();
+    int socket_;
+    LogBuffer* logbuf_;
 };
-
-#endif
diff --git a/logd/LogCommand.cpp b/logd/LogPermissions.cpp
similarity index 97%
rename from logd/LogCommand.cpp
rename to logd/LogPermissions.cpp
index 8bff9da..8f02d5a 100644
--- a/logd/LogCommand.cpp
+++ b/logd/LogPermissions.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "LogPermissions.h"
+
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -21,12 +23,6 @@
 
 #include <private/android_filesystem_config.h>
 
-#include "LogCommand.h"
-#include "LogUtils.h"
-
-LogCommand::LogCommand(const char* cmd) : FrameworkCommand(cmd) {
-}
-
 // gets a list of supplementary group IDs associated with
 // the socket peer.  This is implemented by opening
 // /proc/PID/status and look for the "Group:" line.
diff --git a/logd/LogCommand.h b/logd/LogPermissions.h
similarity index 74%
rename from logd/LogCommand.h
rename to logd/LogPermissions.h
index e10ffa0..3130db5 100644
--- a/logd/LogCommand.h
+++ b/logd/LogPermissions.h
@@ -14,17 +14,11 @@
  * limitations under the License.
  */
 
-#ifndef _LOGD_COMMAND_H
-#define _LOGD_COMMAND_H
+#pragma once
 
-#include <sysutils/FrameworkCommand.h>
+#include <sys/types.h>
+
 #include <sysutils/SocketClient.h>
 
-class LogCommand : public FrameworkCommand {
-   public:
-    explicit LogCommand(const char* cmd);
-    virtual ~LogCommand() {
-    }
-};
-
-#endif
+bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid);
+bool clientHasLogCredentials(SocketClient* cli);
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index f79d39c..234ddc7 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -21,26 +21,63 @@
 #include <sys/socket.h>
 #include <sys/types.h>
 
+#include <chrono>
+
+#include <android-base/stringprintf.h>
 #include <cutils/sockets.h>
+#include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
-#include "FlushCommand.h"
 #include "LogBuffer.h"
 #include "LogBufferElement.h"
+#include "LogPermissions.h"
 #include "LogReader.h"
 #include "LogUtils.h"
+#include "LogWriter.h"
 
-LogReader::LogReader(LogBuffer* logbuf)
-    : SocketListener(getLogSocket(), true), mLogbuf(*logbuf) {
+static bool CanReadSecurityLogs(SocketClient* client) {
+    return client->getUid() == AID_SYSTEM || client->getGid() == AID_SYSTEM;
 }
 
-// When we are notified a new log entry is available, inform
-// listening sockets who are watching this entry's log id.
-void LogReader::notifyNewLog(log_mask_t logMask) {
-    FlushCommand command(*this, logMask);
-    runOnEachSocket(&command);
+static std::string SocketClientToName(SocketClient* client) {
+    return android::base::StringPrintf("pid %d, fd %d", client->getPid(), client->getSocket());
 }
 
+class SocketLogWriter : public LogWriter {
+  public:
+    SocketLogWriter(LogReader* reader, SocketClient* client, bool privileged,
+                    bool can_read_security_logs)
+        : LogWriter(client->getUid(), privileged, can_read_security_logs),
+          reader_(reader),
+          client_(client) {}
+
+    bool Write(const logger_entry& entry, const char* msg) override {
+        struct iovec iovec[2];
+        iovec[0].iov_base = const_cast<logger_entry*>(&entry);
+        iovec[0].iov_len = entry.hdr_size;
+        iovec[1].iov_base = const_cast<char*>(msg);
+        iovec[1].iov_len = entry.len;
+
+        return client_->sendDatav(iovec, 1 + (entry.len != 0)) == 0;
+    }
+
+    void Release() override {
+        reader_->release(client_);
+        client_->decRef();
+    }
+
+    void Shutdown() override { shutdown(client_->getSocket(), SHUT_RDWR); }
+
+    std::string name() const override { return SocketClientToName(client_); }
+
+  private:
+    LogReader* reader_;
+    SocketClient* client_;
+};
+
+LogReader::LogReader(LogBuffer* logbuf, LogReaderList* reader_list)
+    : SocketListener(getLogSocket(), true), log_buffer_(logbuf), reader_list_(reader_list) {}
+
 // Note returning false will release the SocketClient instance.
 bool LogReader::onDataAvailable(SocketClient* cli) {
     static bool name_set;
@@ -53,22 +90,15 @@
 
     int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1);
     if (len <= 0) {
-        doSocketDelete(cli);
+        DoSocketDelete(cli);
         return false;
     }
     buffer[len] = '\0';
 
-    // Clients are only allowed to send one command, disconnect them if they
-    // send another.
-    LogTimeEntry::wrlock();
-    for (const auto& entry : mLogbuf.mTimes) {
-        if (entry->mClient == cli) {
-            entry->release_Locked();
-            LogTimeEntry::unlock();
-            return false;
-        }
+    // Clients are only allowed to send one command, disconnect them if they send another.
+    if (DoSocketDelete(cli)) {
+        return false;
     }
-    LogTimeEntry::unlock();
 
     unsigned long tail = 0;
     static const char _tail[] = " tail=";
@@ -85,11 +115,12 @@
         start.strptime(cp + sizeof(_start) - 1, "%s.%q");
     }
 
-    uint64_t timeout = 0;
+    std::chrono::steady_clock::time_point deadline = {};
     static const char _timeout[] = " timeout=";
     cp = strstr(buffer, _timeout);
     if (cp) {
-        timeout = atol(cp + sizeof(_timeout) - 1) * NS_PER_SEC + log_time(CLOCK_MONOTONIC).nsec();
+        long timeout_seconds = atol(cp + sizeof(_timeout) - 1);
+        deadline = std::chrono::steady_clock::now() + std::chrono::seconds(timeout_seconds);
     }
 
     unsigned int logMask = -1;
@@ -123,119 +154,92 @@
     if (!fastcmp<strncmp>(buffer, "dumpAndClose", 12)) {
         // Allow writer to get some cycles, and wait for pending notifications
         sched_yield();
-        LogTimeEntry::wrlock();
-        LogTimeEntry::unlock();
+        reader_list_->reader_threads_lock().lock();
+        reader_list_->reader_threads_lock().unlock();
         sched_yield();
         nonBlock = true;
     }
 
+    bool privileged = clientHasLogCredentials(cli);
+    bool can_read_security = CanReadSecurityLogs(cli);
+
+    std::unique_ptr<LogWriter> socket_log_writer(
+            new SocketLogWriter(this, cli, privileged, can_read_security));
+
     uint64_t sequence = 1;
     // Convert realtime to sequence number
     if (start != log_time::EPOCH) {
-        class LogFindStart {
-            const pid_t mPid;
-            const unsigned mLogMask;
-            bool startTimeSet;
-            const log_time start;
-            uint64_t& sequence;
-            uint64_t last;
-            bool isMonotonic;
-
-          public:
-            LogFindStart(unsigned logMask, pid_t pid, log_time start, uint64_t& sequence,
-                         bool isMonotonic)
-                : mPid(pid),
-                  mLogMask(logMask),
-                  startTimeSet(false),
-                  start(start),
-                  sequence(sequence),
-                  last(sequence),
-                  isMonotonic(isMonotonic) {}
-
-            static int callback(const LogBufferElement* element, void* obj) {
-                LogFindStart* me = reinterpret_cast<LogFindStart*>(obj);
-                if ((!me->mPid || (me->mPid == element->getPid())) &&
-                    (me->mLogMask & (1 << element->getLogId()))) {
-                    if (me->start == element->getRealTime()) {
-                        me->sequence = element->getSequence();
-                        me->startTimeSet = true;
-                        return -1;
-                    } else if (!me->isMonotonic || android::isMonotonic(element->getRealTime())) {
-                        if (me->start < element->getRealTime()) {
-                            me->sequence = me->last;
-                            me->startTimeSet = true;
-                            return -1;
-                        }
-                        me->last = element->getSequence();
-                    } else {
-                        me->last = element->getSequence();
-                    }
+        bool start_time_set = false;
+        uint64_t last = sequence;
+        auto log_find_start = [pid, logMask, start, &sequence, &start_time_set,
+                               &last](const LogBufferElement* element) -> FlushToResult {
+            if (pid && pid != element->getPid()) {
+                return FlushToResult::kSkip;
+            }
+            if ((logMask & (1 << element->getLogId())) == 0) {
+                return FlushToResult::kSkip;
+            }
+            if (start == element->getRealTime()) {
+                sequence = element->getSequence();
+                start_time_set = true;
+                return FlushToResult::kStop;
+            } else {
+                if (start < element->getRealTime()) {
+                    sequence = last;
+                    start_time_set = true;
+                    return FlushToResult::kStop;
                 }
-                return false;
+                last = element->getSequence();
             }
+            return FlushToResult::kSkip;
+        };
 
-            bool found() { return startTimeSet; }
-        } logFindStart(logMask, pid, start, sequence,
-                       logbuf().isMonotonic() && android::isMonotonic(start));
+        log_buffer_->FlushTo(socket_log_writer.get(), sequence, nullptr, log_find_start);
 
-        logbuf().flushTo(cli, sequence, nullptr, FlushCommand::hasReadLogs(cli),
-                         FlushCommand::hasSecurityLogs(cli),
-                         logFindStart.callback, &logFindStart);
-
-        if (!logFindStart.found()) {
+        if (!start_time_set) {
             if (nonBlock) {
-                doSocketDelete(cli);
                 return false;
             }
-            sequence = LogBufferElement::getCurrentSequence();
+            sequence = log_buffer_->sequence();
         }
     }
 
     android::prdebug(
             "logdr: UID=%d GID=%d PID=%d %c tail=%lu logMask=%x pid=%d "
-            "start=%" PRIu64 "ns timeout=%" PRIu64 "ns\n",
+            "start=%" PRIu64 "ns deadline=%" PRIi64 "ns\n",
             cli->getUid(), cli->getGid(), cli->getPid(), nonBlock ? 'n' : 'b', tail, logMask,
-            (int)pid, start.nsec(), timeout);
+            (int)pid, start.nsec(), static_cast<int64_t>(deadline.time_since_epoch().count()));
 
     if (start == log_time::EPOCH) {
-        timeout = 0;
+        deadline = {};
     }
 
-    LogTimeEntry::wrlock();
-    auto entry = std::make_unique<LogTimeEntry>(*this, cli, nonBlock, tail, logMask, pid, start,
-                                                sequence, timeout);
-    if (!entry->startReader_Locked()) {
-        LogTimeEntry::unlock();
-        return false;
-    }
-
+    auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
+    auto entry = std::make_unique<LogReaderThread>(log_buffer_, reader_list_,
+                                                   std::move(socket_log_writer), nonBlock, tail,
+                                                   logMask, pid, start, sequence, deadline);
     // release client and entry reference counts once done
     cli->incRef();
-    mLogbuf.mTimes.emplace_front(std::move(entry));
+    reader_list_->reader_threads().emplace_front(std::move(entry));
 
     // Set acceptable upper limit to wait for slow reader processing b/27242723
     struct timeval t = { LOGD_SNDTIMEO, 0 };
     setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t,
                sizeof(t));
 
-    LogTimeEntry::unlock();
-
     return true;
 }
 
-void LogReader::doSocketDelete(SocketClient* cli) {
-    LastLogTimes& times = mLogbuf.mTimes;
-    LogTimeEntry::wrlock();
-    LastLogTimes::iterator it = times.begin();
-    while (it != times.end()) {
-        LogTimeEntry* entry = it->get();
-        if (entry->mClient == cli) {
-            entry->release_Locked();
-            break;
+bool LogReader::DoSocketDelete(SocketClient* cli) {
+    auto cli_name = SocketClientToName(cli);
+    auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
+    for (const auto& reader : reader_list_->reader_threads()) {
+        if (reader->name() == cli_name) {
+            reader->release_Locked();
+            return true;
         }
-        it++;
     }
-    LogTimeEntry::unlock();
+    return false;
 }
 
 int LogReader::getLogSocket() {
diff --git a/logd/LogReader.h b/logd/LogReader.h
index b5312b6..b85a584 100644
--- a/logd/LogReader.h
+++ b/logd/LogReader.h
@@ -14,35 +14,28 @@
  * limitations under the License.
  */
 
-#ifndef _LOGD_LOG_WRITER_H__
-#define _LOGD_LOG_WRITER_H__
+#pragma once
 
 #include <sysutils/SocketListener.h>
 
-#include "LogTimes.h"
+#include "LogBuffer.h"
+#include "LogReaderList.h"
+#include "LogReaderThread.h"
 
 #define LOGD_SNDTIMEO 32
 
-class LogBuffer;
-
 class LogReader : public SocketListener {
-    LogBuffer& mLogbuf;
+  public:
+    explicit LogReader(LogBuffer* logbuf, LogReaderList* reader_list);
 
-   public:
-    explicit LogReader(LogBuffer* logbuf);
-    void notifyNewLog(log_mask_t logMask);
-
-    LogBuffer& logbuf(void) const {
-        return mLogbuf;
-    }
-
-   protected:
+  protected:
     virtual bool onDataAvailable(SocketClient* cli);
 
-   private:
+  private:
     static int getLogSocket();
 
-    void doSocketDelete(SocketClient* cli);
-};
+    bool DoSocketDelete(SocketClient* cli);
 
-#endif
+    LogBuffer* log_buffer_;
+    LogReaderList* reader_list_;
+};
diff --git a/logd/LogReaderList.cpp b/logd/LogReaderList.cpp
new file mode 100644
index 0000000..220027b
--- /dev/null
+++ b/logd/LogReaderList.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 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 "LogReaderList.h"
+
+// When we are notified a new log entry is available, inform
+// listening sockets who are watching this entry's log id.
+void LogReaderList::NotifyNewLog(unsigned int log_mask) const {
+    auto lock = std::lock_guard{reader_threads_lock_};
+
+    for (const auto& entry : reader_threads_) {
+        if (!entry->IsWatchingMultiple(log_mask)) {
+            continue;
+        }
+        if (entry->deadline().time_since_epoch().count() != 0) {
+            continue;
+        }
+        entry->triggerReader_Locked();
+    }
+}
diff --git a/logd/LogReaderList.h b/logd/LogReaderList.h
new file mode 100644
index 0000000..0d84aba
--- /dev/null
+++ b/logd/LogReaderList.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 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 <list>
+#include <memory>
+#include <mutex>
+
+#include "LogReaderThread.h"
+
+class LogReaderList {
+  public:
+    void NotifyNewLog(unsigned int log_mask) const;
+
+    std::list<std::unique_ptr<LogReaderThread>>& reader_threads() { return reader_threads_; }
+    std::mutex& reader_threads_lock() { return reader_threads_lock_; }
+
+  private:
+    std::list<std::unique_ptr<LogReaderThread>> reader_threads_;
+    mutable std::mutex reader_threads_lock_;
+};
\ No newline at end of file
diff --git a/logd/LogReaderThread.cpp b/logd/LogReaderThread.cpp
new file mode 100644
index 0000000..b2001b5
--- /dev/null
+++ b/logd/LogReaderThread.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "LogReaderThread.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/prctl.h>
+
+#include <thread>
+
+#include "LogBuffer.h"
+#include "LogReaderList.h"
+
+using namespace std::placeholders;
+
+LogReaderThread::LogReaderThread(LogBuffer* log_buffer, LogReaderList* reader_list,
+                                 std::unique_ptr<LogWriter> writer, bool non_block,
+                                 unsigned long tail, unsigned int log_mask, pid_t pid,
+                                 log_time start_time, uint64_t start,
+                                 std::chrono::steady_clock::time_point deadline)
+    : log_buffer_(log_buffer),
+      reader_list_(reader_list),
+      writer_(std::move(writer)),
+      leading_dropped_(false),
+      log_mask_(log_mask),
+      pid_(pid),
+      tail_(tail),
+      count_(0),
+      index_(0),
+      start_time_(start_time),
+      start_(start),
+      deadline_(deadline),
+      non_block_(non_block) {
+    memset(last_tid_, 0, sizeof(last_tid_));
+    cleanSkip_Locked();
+    auto thread = std::thread{&LogReaderThread::ThreadFunction, this};
+    thread.detach();
+}
+
+void LogReaderThread::ThreadFunction() {
+    prctl(PR_SET_NAME, "logd.reader.per");
+
+    leading_dropped_ = true;
+
+    auto lock = std::unique_lock{reader_list_->reader_threads_lock()};
+
+    uint64_t start = start_;
+
+    while (!release_) {
+        if (deadline_.time_since_epoch().count() != 0) {
+            if (thread_triggered_condition_.wait_until(lock, deadline_) ==
+                std::cv_status::timeout) {
+                deadline_ = {};
+            }
+            if (release_) {
+                break;
+            }
+        }
+
+        lock.unlock();
+
+        if (tail_) {
+            log_buffer_->FlushTo(writer_.get(), start, nullptr,
+                                 std::bind(&LogReaderThread::FilterFirstPass, this, _1));
+            leading_dropped_ =
+                    true;  // TODO: Likely a bug, if leading_dropped_ was not true before calling
+                           // flushTo(), then it should not be reset to true after.
+        }
+        start = log_buffer_->FlushTo(writer_.get(), start, last_tid_,
+                                     std::bind(&LogReaderThread::FilterSecondPass, this, _1));
+
+        // We only ignore entries before the original start time for the first flushTo(), if we
+        // get entries after this first flush before the original start time, then the client
+        // wouldn't have seen them.
+        // Note: this is still racy and may skip out of order events that came in since the last
+        // time the client disconnected and then reconnected with the new start time.  The long term
+        // solution here is that clients must request events since a specific sequence number.
+        start_time_.tv_sec = 0;
+        start_time_.tv_nsec = 0;
+
+        lock.lock();
+
+        if (start == LogBuffer::FLUSH_ERROR) {
+            break;
+        }
+
+        start_ = start + 1;
+
+        if (non_block_ || release_) {
+            break;
+        }
+
+        cleanSkip_Locked();
+
+        if (deadline_.time_since_epoch().count() == 0) {
+            thread_triggered_condition_.wait(lock);
+        }
+    }
+
+    writer_->Release();
+
+    auto& log_reader_threads = reader_list_->reader_threads();
+    auto it = std::find_if(log_reader_threads.begin(), log_reader_threads.end(),
+                           [this](const auto& other) { return other.get() == this; });
+
+    if (it != log_reader_threads.end()) {
+        log_reader_threads.erase(it);
+    }
+}
+
+// A first pass to count the number of elements
+FlushToResult LogReaderThread::FilterFirstPass(const LogBufferElement* element) {
+    auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
+
+    if (leading_dropped_) {
+        if (element->getDropped()) {
+            return FlushToResult::kSkip;
+        }
+        leading_dropped_ = false;
+    }
+
+    if (count_ == 0) {
+        start_ = element->getSequence();
+    }
+
+    if ((!pid_ || pid_ == element->getPid()) && IsWatching(element->getLogId()) &&
+        (start_time_ == log_time::EPOCH || start_time_ <= element->getRealTime())) {
+        ++count_;
+    }
+
+    return FlushToResult::kSkip;
+}
+
+// A second pass to send the selected elements
+FlushToResult LogReaderThread::FilterSecondPass(const LogBufferElement* element) {
+    auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
+
+    start_ = element->getSequence();
+
+    if (skip_ahead_[element->getLogId()]) {
+        skip_ahead_[element->getLogId()]--;
+        return FlushToResult::kSkip;
+    }
+
+    if (leading_dropped_) {
+        if (element->getDropped()) {
+            return FlushToResult::kSkip;
+        }
+        leading_dropped_ = false;
+    }
+
+    // Truncate to close race between first and second pass
+    if (non_block_ && tail_ && index_ >= count_) {
+        return FlushToResult::kStop;
+    }
+
+    if (!IsWatching(element->getLogId())) {
+        return FlushToResult::kSkip;
+    }
+
+    if (pid_ && pid_ != element->getPid()) {
+        return FlushToResult::kSkip;
+    }
+
+    if (start_time_ != log_time::EPOCH && element->getRealTime() <= start_time_) {
+        return FlushToResult::kSkip;
+    }
+
+    if (release_) {
+        return FlushToResult::kStop;
+    }
+
+    if (!tail_) {
+        goto ok;
+    }
+
+    ++index_;
+
+    if (count_ > tail_ && index_ <= (count_ - tail_)) {
+        return FlushToResult::kSkip;
+    }
+
+    if (!non_block_) {
+        tail_ = 0;
+    }
+
+ok:
+    if (!skip_ahead_[element->getLogId()]) {
+        return FlushToResult::kWrite;
+    }
+    return FlushToResult::kSkip;
+}
+
+void LogReaderThread::cleanSkip_Locked(void) {
+    memset(skip_ahead_, 0, sizeof(skip_ahead_));
+}
diff --git a/logd/LogReaderThread.h b/logd/LogReaderThread.h
new file mode 100644
index 0000000..e48a3ca
--- /dev/null
+++ b/logd/LogReaderThread.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2012-2013 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 <pthread.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <list>
+#include <memory>
+
+#include <log/log.h>
+#include <sysutils/SocketClient.h>
+
+#include "LogBuffer.h"
+#include "LogBufferElement.h"
+#include "LogWriter.h"
+
+class LogReaderList;
+
+class LogReaderThread {
+  public:
+    LogReaderThread(LogBuffer* log_buffer, LogReaderList* reader_list,
+                    std::unique_ptr<LogWriter> writer, bool non_block, unsigned long tail,
+                    unsigned int log_mask, pid_t pid, log_time start_time, uint64_t sequence,
+                    std::chrono::steady_clock::time_point deadline);
+    void triggerReader_Locked() { thread_triggered_condition_.notify_all(); }
+
+    void triggerSkip_Locked(log_id_t id, unsigned int skip) { skip_ahead_[id] = skip; }
+    void cleanSkip_Locked();
+
+    void release_Locked() {
+        // gracefully shut down the socket.
+        writer_->Shutdown();
+        release_ = true;
+        thread_triggered_condition_.notify_all();
+    }
+
+    bool IsWatching(log_id_t id) const { return log_mask_ & (1 << id); }
+    bool IsWatchingMultiple(unsigned int log_mask) const { return log_mask_ & log_mask; }
+
+    std::string name() const { return writer_->name(); }
+    uint64_t start() const { return start_; }
+    std::chrono::steady_clock::time_point deadline() const { return deadline_; }
+
+  private:
+    void ThreadFunction();
+    // flushTo filter callbacks
+    FlushToResult FilterFirstPass(const LogBufferElement* element);
+    FlushToResult FilterSecondPass(const LogBufferElement* element);
+
+    std::condition_variable thread_triggered_condition_;
+    LogBuffer* log_buffer_;
+    LogReaderList* reader_list_;
+    std::unique_ptr<LogWriter> writer_;
+
+    // Set to true to cause the thread to end and the LogReaderThread to delete itself.
+    bool release_ = false;
+    // Indicates whether or not 'leading' (first logs seen starting from start_) 'dropped' (chatty)
+    // messages should be ignored.
+    bool leading_dropped_;
+
+    // A mask of the logs buffers that are read by this reader.
+    const unsigned int log_mask_;
+    // If set to non-zero, only pids equal to this are read by the reader.
+    const pid_t pid_;
+    // When a reader is referencing (via start_) old elements in the log buffer, and the log
+    // buffer's size grows past its memory limit, the log buffer may request the reader to skip
+    // ahead a specified number of logs.
+    unsigned int skip_ahead_[LOG_ID_MAX];
+    // Used for distinguishing 'dropped' messages for duplicate logs vs chatty drops
+    pid_t last_tid_[LOG_ID_MAX];
+
+    // These next three variables are used for reading only the most recent lines aka `adb logcat
+    // -t` / `adb logcat -T`.
+    // tail_ is the number of most recent lines to print.
+    unsigned long tail_;
+    // count_ is the result of a first pass through the log buffer to determine how many total
+    // messages there are.
+    unsigned long count_;
+    // index_ is used along with count_ to only start sending lines once index_ > (count_ - tail_)
+    // and to disconnect the reader (if it is dumpAndClose, `adb logcat -t`), when index_ >= count_.
+    unsigned long index_;
+
+    // When a reader requests logs starting from a given timestamp, its stored here for the first
+    // pass, such that logs before this time stamp that are accumulated in the buffer are ignored.
+    log_time start_time_;
+    // The point from which the reader will read logs once awoken.
+    uint64_t start_;
+    // CLOCK_MONOTONIC based deadline used for log wrapping.  If this deadline expires before logs
+    // wrap, then wake up and send the logs to the reader anyway.
+    std::chrono::steady_clock::time_point deadline_;
+    // If this reader is 'dumpAndClose' and will disconnect once it has read its intended logs.
+    const bool non_block_;
+};
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 431b778..bb7621d 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "LogStatistics.h"
+
 #include <ctype.h>
 #include <fcntl.h>
 #include <inttypes.h>
@@ -27,14 +29,12 @@
 
 #include <private/android_logger.h>
 
-#include "LogStatistics.h"
-
 static const uint64_t hourSec = 60 * 60;
 static const uint64_t monthSec = 31 * 24 * hourSec;
 
-size_t LogStatistics::SizesTotal;
+std::atomic<size_t> LogStatistics::SizesTotal;
 
-LogStatistics::LogStatistics() : enable(false) {
+LogStatistics::LogStatistics(bool enable_statistics) : enable(enable_statistics) {
     log_time now(CLOCK_REALTIME);
     log_id_for_each(id) {
         mSizes[id] = 0;
@@ -79,17 +79,16 @@
 }
 }
 
-void LogStatistics::addTotal(LogBufferElement* element) {
-    if (element->getDropped()) return;
+void LogStatistics::AddTotal(log_id_t log_id, uint16_t size) {
+    auto lock = std::lock_guard{lock_};
 
-    log_id_t log_id = element->getLogId();
-    uint16_t size = element->getMsgLen();
     mSizesTotal[log_id] += size;
     SizesTotal += size;
     ++mElementsTotal[log_id];
 }
 
-void LogStatistics::add(LogBufferElement* element) {
+void LogStatistics::Add(LogBufferElement* element) {
+    auto lock = std::lock_guard{lock_};
     log_id_t log_id = element->getLogId();
     uint16_t size = element->getMsgLen();
     mSizes[log_id] += size;
@@ -159,7 +158,8 @@
     }
 }
 
-void LogStatistics::subtract(LogBufferElement* element) {
+void LogStatistics::Subtract(LogBufferElement* element) {
+    auto lock = std::lock_guard{lock_};
     log_id_t log_id = element->getLogId();
     uint16_t size = element->getMsgLen();
     mSizes[log_id] -= size;
@@ -204,7 +204,8 @@
 
 // Atomically set an entry to drop
 // entry->setDropped(1) must follow this call, caller should do this explicitly.
-void LogStatistics::drop(LogBufferElement* element) {
+void LogStatistics::Drop(LogBufferElement* element) {
+    auto lock = std::lock_guard{lock_};
     log_id_t log_id = element->getLogId();
     uint16_t size = element->getMsgLen();
     mSizes[log_id] -= size;
@@ -238,9 +239,13 @@
     tagNameTable.subtract(TagNameKey(element), element);
 }
 
+const char* LogStatistics::UidToName(uid_t uid) const {
+    auto lock = std::lock_guard{lock_};
+    return UidToNameLocked(uid);
+}
+
 // caller must own and free character string
-// Requires parent LogBuffer::wrlock() to be held
-const char* LogStatistics::uidToName(uid_t uid) const {
+const char* LogStatistics::UidToNameLocked(uid_t uid) const {
     // Local hard coded favourites
     if (uid == AID_LOGD) {
         return strdup("auditd");
@@ -297,6 +302,80 @@
     return name;
 }
 
+template <typename TKey, typename TEntry>
+void LogStatistics::WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
+                                          int* worst, size_t* worst_sizes,
+                                          size_t* second_worst_sizes) const {
+    std::array<const TEntry*, 2> max_entries;
+    table.MaxEntries(AID_ROOT, 0, &max_entries);
+    if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
+        return;
+    }
+    *worst_sizes = max_entries[0]->getSizes();
+    // b/24782000: Allow time horizon to extend roughly tenfold, assume average entry length is
+    // 100 characters.
+    if (*worst_sizes > threshold && *worst_sizes > (10 * max_entries[0]->getDropped())) {
+        *worst = max_entries[0]->getKey();
+        *second_worst_sizes = max_entries[1]->getSizes();
+        if (*second_worst_sizes < threshold) {
+            *second_worst_sizes = threshold;
+        }
+    }
+}
+
+void LogStatistics::WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
+                                 size_t* second_worst_sizes) const {
+    auto lock = std::lock_guard{lock_};
+    WorstTwoWithThreshold(uidTable[id], threshold, worst, worst_sizes, second_worst_sizes);
+}
+
+void LogStatistics::WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
+                                 size_t* second_worst_sizes) const {
+    auto lock = std::lock_guard{lock_};
+    WorstTwoWithThreshold(tagTable, threshold, worst, worst_sizes, second_worst_sizes);
+}
+
+void LogStatistics::WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
+                                       size_t* second_worst_sizes) const {
+    auto lock = std::lock_guard{lock_};
+    std::array<const PidEntry*, 2> max_entries;
+    pidSystemTable[id].MaxEntries(AID_SYSTEM, 0, &max_entries);
+    if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
+        return;
+    }
+
+    *worst = max_entries[0]->getKey();
+    *second_worst_sizes = worst_uid_sizes - max_entries[0]->getSizes() + max_entries[1]->getSizes();
+}
+
+// Prune at most 10% of the log entries or maxPrune, whichever is less.
+bool LogStatistics::ShouldPrune(log_id id, unsigned long max_size,
+                                unsigned long* prune_rows) const {
+    static constexpr size_t kMinPrune = 4;
+    static constexpr size_t kMaxPrune = 256;
+
+    auto lock = std::lock_guard{lock_};
+    size_t sizes = mSizes[id];
+    if (sizes <= max_size) {
+        return false;
+    }
+    size_t size_over = sizes - ((max_size * 9) / 10);
+    size_t elements = mElements[id] - mDroppedElements[id];
+    size_t min_elements = elements / 100;
+    if (min_elements < kMinPrune) {
+        min_elements = kMinPrune;
+    }
+    *prune_rows = elements * size_over / sizes;
+    if (*prune_rows < min_elements) {
+        *prune_rows = min_elements;
+    }
+    if (*prune_rows > kMaxPrune) {
+        *prune_rows = kMaxPrune;
+    }
+
+    return true;
+}
+
 std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
     bool isprune = worstUidEnabledForLogid(id);
     return formatLine(android::base::StringPrintf(name.c_str(),
@@ -308,10 +387,10 @@
 }
 
 // Helper to truncate name, if too long, and add name dressings
-static void formatTmp(const LogStatistics& stat, const char* nameTmp, uid_t uid,
-                      std::string& name, std::string& size, size_t nameLen) {
+void LogStatistics::FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
+                              size_t nameLen) const {
     const char* allocNameTmp = nullptr;
-    if (!nameTmp) nameTmp = allocNameTmp = stat.uidToName(uid);
+    if (!nameTmp) nameTmp = allocNameTmp = UidToNameLocked(uid);
     if (nameTmp) {
         size_t lenSpace = std::max(nameLen - name.length(), (size_t)1);
         size_t len = EntryBaseConstants::total_len -
@@ -332,12 +411,12 @@
     }
 }
 
-std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
+std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const REQUIRES(stat.lock_) {
     uid_t uid = getUid();
     std::string name = android::base::StringPrintf("%u", uid);
     std::string size = android::base::StringPrintf("%zu", getSizes());
 
-    formatTmp(stat, nullptr, uid, name, size, 6);
+    stat.FormatTmp(nullptr, uid, name, size, 6);
 
     std::string pruned = "";
     if (worstUidEnabledForLogid(id)) {
@@ -347,9 +426,9 @@
              it != stat.uidTable[id].end(); ++it) {
             totalDropped += it->second.getDropped();
         }
-        size_t sizes = stat.sizes(id);
-        size_t totalSize = stat.sizesTotal(id);
-        size_t totalElements = stat.elementsTotal(id);
+        size_t sizes = stat.mSizes[id];
+        size_t totalSize = stat.mSizesTotal[id];
+        size_t totalElements = stat.mElementsTotal[id];
         float totalVirtualSize =
             (float)sizes + (float)totalDropped * totalSize / totalElements;
         size_t entrySize = getSizes();
@@ -401,12 +480,9 @@
     }
 
     static const size_t maximum_sorted_entries = 32;
-    std::unique_ptr<const PidEntry* []> sorted =
-        stat.pidSystemTable[id].sort(uid, (pid_t)0, maximum_sorted_entries);
+    std::array<const PidEntry*, maximum_sorted_entries> sorted;
+    stat.pidSystemTable[id].MaxEntries(uid, 0, &sorted);
 
-    if (!sorted.get()) {
-        return output;
-    }
     std::string byPid;
     size_t index;
     bool hasDropped = false;
@@ -440,14 +516,14 @@
                       std::string("BYTES"), std::string("NUM"));
 }
 
-std::string PidEntry::format(const LogStatistics& stat,
-                             log_id_t /* id */) const {
+std::string PidEntry::format(const LogStatistics& stat, log_id_t /* id */) const
+        REQUIRES(stat.lock_) {
     uid_t uid = getUid();
     pid_t pid = getPid();
     std::string name = android::base::StringPrintf("%5u/%u", pid, uid);
     std::string size = android::base::StringPrintf("%zu", getSizes());
 
-    formatTmp(stat, getName(), uid, name, size, 12);
+    stat.FormatTmp(getName(), uid, name, size, 12);
 
     std::string pruned = "";
     size_t dropped = getDropped();
@@ -465,13 +541,13 @@
                       std::string("NUM"));
 }
 
-std::string TidEntry::format(const LogStatistics& stat,
-                             log_id_t /* id */) const {
+std::string TidEntry::format(const LogStatistics& stat, log_id_t /* id */) const
+        REQUIRES(stat.lock_) {
     uid_t uid = getUid();
     std::string name = android::base::StringPrintf("%5u/%u", getTid(), uid);
     std::string size = android::base::StringPrintf("%zu", getSizes());
 
-    formatTmp(stat, getName(), uid, name, size, 12);
+    stat.FormatTmp(getName(), uid, name, size, 12);
 
     std::string pruned = "";
     size_t dropped = getDropped();
@@ -611,8 +687,36 @@
     return output;
 }
 
-std::string LogStatistics::format(uid_t uid, pid_t pid,
-                                  unsigned int logMask) const {
+template <typename TKey, typename TEntry>
+std::string LogStatistics::FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid,
+                                       pid_t pid, const std::string& name, log_id_t id) const
+        REQUIRES(lock_) {
+    static const size_t maximum_sorted_entries = 32;
+    std::string output;
+    std::array<const TEntry*, maximum_sorted_entries> sorted;
+    table.MaxEntries(uid, pid, &sorted);
+    bool header_printed = false;
+    for (size_t index = 0; index < maximum_sorted_entries; ++index) {
+        const TEntry* entry = sorted[index];
+        if (!entry) {
+            break;
+        }
+        if (entry->getSizes() <= (sorted[0]->getSizes() / 100)) {
+            break;
+        }
+        if (!header_printed) {
+            output += "\n\n";
+            output += entry->formatHeader(name, id);
+            header_printed = true;
+        }
+        output += entry->format(*this, id);
+    }
+    return output;
+}
+
+std::string LogStatistics::Format(uid_t uid, pid_t pid, unsigned int logMask) const {
+    auto lock = std::lock_guard{lock_};
+
     static const uint16_t spaces_total = 19;
 
     // Report on total logging, current and for all time
@@ -642,9 +746,9 @@
         if (!(logMask & (1 << id))) continue;
         oldLength = output.length();
         if (spaces < 0) spaces = 0;
-        size_t szs = sizesTotal(id);
+        size_t szs = mSizesTotal[id];
         totalSize += szs;
-        size_t els = elementsTotal(id);
+        size_t els = mElementsTotal[id];
         totalEls += els;
         output +=
             android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
@@ -663,11 +767,11 @@
     log_id_for_each(id) {
         if (!(logMask & (1 << id))) continue;
 
-        size_t els = elements(id);
+        size_t els = mElements[id];
         if (els) {
             oldLength = output.length();
             if (spaces < 0) spaces = 0;
-            size_t szs = sizes(id);
+            size_t szs = mSizes[id];
             totalSize += szs;
             totalEls += els;
             output +=
@@ -749,7 +853,7 @@
     log_id_for_each(id) {
         if (!(logMask & (1 << id))) continue;
 
-        size_t els = elements(id);
+        size_t els = mElements[id];
         if (els) {
             oldLength = output.length();
             if (spaces < 0) spaces = 0;
@@ -758,7 +862,7 @@
                 ((sizeof(LogBufferElement) + sizeof(uint64_t) - 1) &
                  -sizeof(uint64_t)) +
                 sizeof(std::list<LogBufferElement*>);
-            size_t szs = sizes(id) + els * overhead;
+            size_t szs = mSizes[id] + els * overhead;
             totalSize += szs;
             output += android::base::StringPrintf("%*s%zu", spaces, "", szs);
             spaces -= output.length() - oldLength;
@@ -779,39 +883,38 @@
 
         name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:"
                                  : "Logging for your UID in %s log buffer:";
-        output += uidTable[id].format(*this, uid, pid, name, id);
+        output += FormatTable(uidTable[id], uid, pid, name, id);
     }
 
     if (enable) {
         name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:"
                                            : "Logging for this PID:";
-        output += pidTable.format(*this, uid, pid, name);
+        output += FormatTable(pidTable, uid, pid, name);
         name = "Chattiest TIDs";
         if (pid) name += android::base::StringPrintf(" for PID %d", pid);
         name += ":";
-        output += tidTable.format(*this, uid, pid, name);
+        output += FormatTable(tidTable, uid, pid, name);
     }
 
     if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
         name = "Chattiest events log buffer TAGs";
         if (pid) name += android::base::StringPrintf(" for PID %d", pid);
         name += ":";
-        output += tagTable.format(*this, uid, pid, name, LOG_ID_EVENTS);
+        output += FormatTable(tagTable, uid, pid, name, LOG_ID_EVENTS);
     }
 
     if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
         name = "Chattiest security log buffer TAGs";
         if (pid) name += android::base::StringPrintf(" for PID %d", pid);
         name += ":";
-        output +=
-            securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
+        output += FormatTable(securityTagTable, uid, pid, name, LOG_ID_SECURITY);
     }
 
     if (enable) {
         name = "Chattiest TAGs";
         if (pid) name += android::base::StringPrintf(" for PID %d", pid);
         name += ":";
-        output += tagNameTable.format(*this, uid, pid, name);
+        output += FormatTable(tagNameTable, uid, pid, name);
     }
 
     return output;
@@ -839,12 +942,14 @@
 }
 }
 
-uid_t LogStatistics::pidToUid(pid_t pid) {
+uid_t LogStatistics::PidToUid(pid_t pid) {
+    auto lock = std::lock_guard{lock_};
     return pidTable.add(pid)->second.getUid();
 }
 
 // caller must free character string
-const char* LogStatistics::pidToName(pid_t pid) const {
+const char* LogStatistics::PidToName(pid_t pid) const {
+    auto lock = std::lock_guard{lock_};
     // An inconvenient truth ... getName() can alter the object
     pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
     const char* name = writablePidTable.add(pid)->second.getName();
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 0782de3..7d13ff7 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef _LOGD_LOG_STATISTICS_H__
-#define _LOGD_LOG_STATISTICS_H__
+#pragma once
 
 #include <ctype.h>
 #include <inttypes.h>
@@ -25,12 +24,15 @@
 #include <sys/types.h>
 
 #include <algorithm>  // std::max
+#include <array>
 #include <memory>
+#include <mutex>
 #include <string>
 #include <string_view>
 #include <unordered_map>
 
 #include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
 #include <android/log.h>
 #include <log/log_time.h>
 #include <private/android_filesystem_config.h>
@@ -79,16 +81,12 @@
     typedef
         typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
 
-    std::unique_ptr<const TEntry* []> sort(uid_t uid, pid_t pid,
-                                           size_t len) const {
-        if (!len) {
-            std::unique_ptr<const TEntry* []> sorted(nullptr);
-            return sorted;
-        }
-
-        const TEntry** retval = new const TEntry*[len];
-        memset(retval, 0, sizeof(*retval) * len);
-
+    // Returns a sorted array of up to len highest entries sorted by size.  If fewer than len
+    // entries are found, their positions are set to nullptr.
+    template <size_t len>
+    void MaxEntries(uid_t uid, pid_t pid, std::array<const TEntry*, len>* out) const {
+        auto& retval = *out;
+        retval.fill(nullptr);
         for (const_iterator it = map.begin(); it != map.end(); ++it) {
             const TEntry& entry = it->second;
 
@@ -113,8 +111,6 @@
                 retval[index] = &entry;
             }
         }
-        std::unique_ptr<const TEntry* []> sorted(retval);
-        return sorted;
     }
 
     inline iterator add(const TKey& key, const LogBufferElement* element) {
@@ -170,35 +166,6 @@
     inline const_iterator end() const {
         return map.end();
     }
-
-    std::string format(const LogStatistics& stat, uid_t uid, pid_t pid,
-                       const std::string& name = std::string(""),
-                       log_id_t id = LOG_ID_MAX) const {
-        static const size_t maximum_sorted_entries = 32;
-        std::string output;
-        std::unique_ptr<const TEntry* []> sorted =
-            sort(uid, pid, maximum_sorted_entries);
-        if (!sorted.get()) {
-            return output;
-        }
-        bool headerPrinted = false;
-        for (size_t index = 0; index < maximum_sorted_entries; ++index) {
-            const TEntry* entry = sorted[index];
-            if (!entry) {
-                break;
-            }
-            if (entry->getSizes() <= (sorted[0]->getSizes() / 100)) {
-                break;
-            }
-            if (!headerPrinted) {
-                output += "\n\n";
-                output += entry->formatHeader(name, id);
-                headerPrinted = true;
-            }
-            output += entry->format(stat, id);
-        }
-        return output;
-    }
 };
 
 namespace EntryBaseConstants {
@@ -627,84 +594,51 @@
     std::string format(const LogStatistics& stat, log_id_t id) const;
 };
 
-template <typename TEntry>
-class LogFindWorst {
-    std::unique_ptr<const TEntry* []> sorted;
-
-   public:
-    explicit LogFindWorst(std::unique_ptr<const TEntry* []>&& sorted)
-        : sorted(std::move(sorted)) {
-    }
-
-    void findWorst(int& worst, size_t& worst_sizes, size_t& second_worst_sizes,
-                   size_t threshold) {
-        if (sorted.get() && sorted[0] && sorted[1]) {
-            worst_sizes = sorted[0]->getSizes();
-            if ((worst_sizes > threshold)
-                // Allow time horizon to extend roughly tenfold, assume
-                // average entry length is 100 characters.
-                && (worst_sizes > (10 * sorted[0]->getDropped()))) {
-                worst = sorted[0]->getKey();
-                second_worst_sizes = sorted[1]->getSizes();
-                if (second_worst_sizes < threshold) {
-                    second_worst_sizes = threshold;
-                }
-            }
-        }
-    }
-
-    void findWorst(int& worst, size_t worst_sizes, size_t& second_worst_sizes) {
-        if (sorted.get() && sorted[0] && sorted[1]) {
-            worst = sorted[0]->getKey();
-            second_worst_sizes =
-                worst_sizes - sorted[0]->getSizes() + sorted[1]->getSizes();
-        }
-    }
-};
-
 // Log Statistics
 class LogStatistics {
     friend UidEntry;
+    friend PidEntry;
+    friend TidEntry;
 
-    size_t mSizes[LOG_ID_MAX];
-    size_t mElements[LOG_ID_MAX];
-    size_t mDroppedElements[LOG_ID_MAX];
-    size_t mSizesTotal[LOG_ID_MAX];
-    size_t mElementsTotal[LOG_ID_MAX];
-    log_time mOldest[LOG_ID_MAX];
-    log_time mNewest[LOG_ID_MAX];
-    log_time mNewestDropped[LOG_ID_MAX];
-    static size_t SizesTotal;
+    size_t mSizes[LOG_ID_MAX] GUARDED_BY(lock_);
+    size_t mElements[LOG_ID_MAX] GUARDED_BY(lock_);
+    size_t mDroppedElements[LOG_ID_MAX] GUARDED_BY(lock_);
+    size_t mSizesTotal[LOG_ID_MAX] GUARDED_BY(lock_);
+    size_t mElementsTotal[LOG_ID_MAX] GUARDED_BY(lock_);
+    log_time mOldest[LOG_ID_MAX] GUARDED_BY(lock_);
+    log_time mNewest[LOG_ID_MAX] GUARDED_BY(lock_);
+    log_time mNewestDropped[LOG_ID_MAX] GUARDED_BY(lock_);
+    static std::atomic<size_t> SizesTotal;
     bool enable;
 
     // uid to size list
     typedef LogHashtable<uid_t, UidEntry> uidTable_t;
-    uidTable_t uidTable[LOG_ID_MAX];
+    uidTable_t uidTable[LOG_ID_MAX] GUARDED_BY(lock_);
 
     // pid of system to size list
     typedef LogHashtable<pid_t, PidEntry> pidSystemTable_t;
-    pidSystemTable_t pidSystemTable[LOG_ID_MAX];
+    pidSystemTable_t pidSystemTable[LOG_ID_MAX] GUARDED_BY(lock_);
 
     // pid to uid list
     typedef LogHashtable<pid_t, PidEntry> pidTable_t;
-    pidTable_t pidTable;
+    pidTable_t pidTable GUARDED_BY(lock_);
 
     // tid to uid list
     typedef LogHashtable<pid_t, TidEntry> tidTable_t;
-    tidTable_t tidTable;
+    tidTable_t tidTable GUARDED_BY(lock_);
 
     // tag list
     typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
-    tagTable_t tagTable;
+    tagTable_t tagTable GUARDED_BY(lock_);
 
     // security tag list
-    tagTable_t securityTagTable;
+    tagTable_t securityTagTable GUARDED_BY(lock_);
 
     // global tag list
     typedef LogHashtable<TagNameKey, TagNameEntry> tagNameTable_t;
     tagNameTable_t tagNameTable;
 
-    size_t sizeOf() const {
+    size_t sizeOf() const REQUIRES(lock_) {
         size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() +
                       tagTable.sizeOf() + securityTagTable.sizeOf() +
                       tagNameTable.sizeOf() +
@@ -729,62 +663,59 @@
         return size;
     }
 
-   public:
-    LogStatistics();
+  public:
+    LogStatistics(bool enable_statistics);
 
-    void enableStatistics() {
-        enable = true;
-    }
-
-    void addTotal(LogBufferElement* entry);
-    void add(LogBufferElement* entry);
-    void subtract(LogBufferElement* entry);
+    void AddTotal(log_id_t log_id, uint16_t size) EXCLUDES(lock_);
+    void Add(LogBufferElement* entry) EXCLUDES(lock_);
+    void Subtract(LogBufferElement* entry) EXCLUDES(lock_);
     // entry->setDropped(1) must follow this call
-    void drop(LogBufferElement* entry);
+    void Drop(LogBufferElement* entry) EXCLUDES(lock_);
     // Correct for coalescing two entries referencing dropped content
-    void erase(LogBufferElement* element) {
+    void Erase(LogBufferElement* element) EXCLUDES(lock_) {
+        auto lock = std::lock_guard{lock_};
         log_id_t log_id = element->getLogId();
         --mElements[log_id];
         --mDroppedElements[log_id];
     }
 
-    LogFindWorst<UidEntry> sort(uid_t uid, pid_t pid, size_t len, log_id id) {
-        return LogFindWorst<UidEntry>(uidTable[id].sort(uid, pid, len));
-    }
-    LogFindWorst<PidEntry> sortPids(uid_t uid, pid_t pid, size_t len,
-                                    log_id id) {
-        return LogFindWorst<PidEntry>(pidSystemTable[id].sort(uid, pid, len));
-    }
-    LogFindWorst<TagEntry> sortTags(uid_t uid, pid_t pid, size_t len, log_id) {
-        return LogFindWorst<TagEntry>(tagTable.sort(uid, pid, len));
-    }
+    void WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
+                      size_t* second_worst_sizes) const EXCLUDES(lock_);
+    void WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
+                      size_t* second_worst_sizes) const EXCLUDES(lock_);
+    void WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
+                            size_t* second_worst_sizes) const EXCLUDES(lock_);
 
-    // fast track current value by id only
-    size_t sizes(log_id_t id) const {
+    bool ShouldPrune(log_id id, unsigned long max_size, unsigned long* prune_rows) const
+            EXCLUDES(lock_);
+
+    // Snapshot of the sizes for a given log buffer.
+    size_t Sizes(log_id_t id) const EXCLUDES(lock_) {
+        auto lock = std::lock_guard{lock_};
         return mSizes[id];
     }
-    size_t elements(log_id_t id) const {
-        return mElements[id];
-    }
-    size_t realElements(log_id_t id) const {
-        return mElements[id] - mDroppedElements[id];
-    }
-    size_t sizesTotal(log_id_t id) const {
-        return mSizesTotal[id];
-    }
-    size_t elementsTotal(log_id_t id) const {
-        return mElementsTotal[id];
-    }
+    // TODO: Get rid of this entirely.
     static size_t sizesTotal() {
         return SizesTotal;
     }
 
-    std::string format(uid_t uid, pid_t pid, unsigned int logMask) const;
+    std::string Format(uid_t uid, pid_t pid, unsigned int logMask) const EXCLUDES(lock_);
 
-    // helper (must be locked directly or implicitly by mLogElementsLock)
-    const char* pidToName(pid_t pid) const;
-    uid_t pidToUid(pid_t pid);
-    const char* uidToName(uid_t uid) const;
+    const char* PidToName(pid_t pid) const EXCLUDES(lock_);
+    uid_t PidToUid(pid_t pid) EXCLUDES(lock_);
+    const char* UidToName(uid_t uid) const EXCLUDES(lock_);
+
+  private:
+    template <typename TKey, typename TEntry>
+    void WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
+                               int* worst, size_t* worst_sizes, size_t* second_worst_sizes) const;
+    template <typename TKey, typename TEntry>
+    std::string FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid, pid_t pid,
+                            const std::string& name = std::string(""),
+                            log_id_t id = LOG_ID_MAX) const REQUIRES(lock_);
+    void FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
+                   size_t nameLen) const REQUIRES(lock_);
+    const char* UidToNameLocked(uid_t uid) const REQUIRES(lock_);
+
+    mutable std::mutex lock_;
 };
-
-#endif  // _LOGD_LOG_STATISTICS_H__
diff --git a/logd/LogTags.cpp b/logd/LogTags.cpp
index e45cc8a..3afe3ee 100644
--- a/logd/LogTags.cpp
+++ b/logd/LogTags.cpp
@@ -32,11 +32,13 @@
 #include <android-base/macros.h>
 #include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
+#include <android-base/threads.h>
 #include <log/log_event_list.h>
 #include <log/log_properties.h>
 #include <log/log_read.h>
 #include <private/android_filesystem_config.h>
 
+#include "LogStatistics.h"
 #include "LogTags.h"
 #include "LogUtils.h"
 
@@ -99,8 +101,7 @@
             struct tm tm;
             localtime_r(&now, &tm);
             char timebuf[20];
-            size_t len =
-                strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", &tm);
+            strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", &tm);
             android::base::WriteStringToFd(
                 android::base::StringPrintf(
                     "# Rebuilt %.20s, content owned by logd\n", timebuf),
@@ -189,7 +190,6 @@
 // Read the event log tags file, and build up our internal database
 void LogTags::ReadFileEventLogTags(const char* filename, bool warn) {
     bool etc = !strcmp(filename, system_event_log_tags);
-    bool debug = !etc && !strcmp(filename, debug_event_log_tags);
 
     if (!etc) {
         RebuildFileEventLogTags(filename, warn);
@@ -391,23 +391,6 @@
     return me->tagToName(tag);
 }
 
-// Prototype in LogUtils.h allowing external access to our database.
-//
-// This only works on userdebug and eng devices to re-read the
-// /data/misc/logd/event-log-tags file right after /data is mounted.
-// The operation is near to boot and should only happen once.  There
-// are races associated with its use since it can trigger a Rebuild
-// of the file, but that is a can-not-happen since the file was not
-// read yet.  More dangerous if called later, but if all is well it
-// should just skip over everything and not write any new entries.
-void android::ReReadEventLogTags() {
-    LogTags* me = logtags;
-
-    if (me && __android_log_is_debuggable()) {
-        me->ReadFileEventLogTags(me->debug_event_log_tags);
-    }
-}
-
 // converts an event tag into a format
 const char* LogTags::tagToFormat(uint32_t tag) const {
     tag2format_const_iterator iform;
@@ -512,7 +495,7 @@
 
     // Every 16K (half the smallest configurable pmsg buffer size) record
     static const size_t rate_to_pmsg = 16 * 1024;
-    if (lastTotal && ((android::sizesTotal() - lastTotal) < rate_to_pmsg)) {
+    if (lastTotal && (LogStatistics::sizesTotal() - lastTotal) < rate_to_pmsg) {
         return;
     }
 
@@ -565,13 +548,13 @@
      */
 
     struct timespec ts;
-    clock_gettime(android_log_clockid(), &ts);
+    clock_gettime(CLOCK_REALTIME, &ts);
 
     android_log_header_t header = {
-        .id = LOG_ID_EVENTS,
-        .tid = (uint16_t)gettid(),
-        .realtime.tv_sec = (uint32_t)ts.tv_sec,
-        .realtime.tv_nsec = (uint32_t)ts.tv_nsec,
+            .id = LOG_ID_EVENTS,
+            .tid = static_cast<uint16_t>(android::base::GetThreadId()),
+            .realtime.tv_sec = static_cast<uint32_t>(ts.tv_sec),
+            .realtime.tv_nsec = static_cast<uint32_t>(ts.tv_nsec),
     };
 
     uint32_t outTag = TAG_DEF_LOG_TAG;
@@ -682,7 +665,7 @@
         }
     }
 
-    lastTotal = android::sizesTotal();
+    lastTotal = LogStatistics::sizesTotal();
     if (!lastTotal) ++lastTotal;
 
     // record totals for next watermark.
diff --git a/logd/LogTags.h b/logd/LogTags.h
index e4d165a..cce700c 100644
--- a/logd/LogTags.h
+++ b/logd/LogTags.h
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef _LOGD_LOG_TAGS_H__
-#define _LOGD_LOG_TAGS_H__
+#pragma once
 
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
 
+#include <private/android_filesystem_config.h>
 #include <utils/RWLock.h>
 
 class LogTags {
@@ -120,5 +120,3 @@
     std::string formatGetEventTag(uid_t uid, const char* name,
                                   const char* format);
 };
-
-#endif  // _LOGD_LOG_TAGS_H__
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
deleted file mode 100644
index ed8d2f5..0000000
--- a/logd/LogTimes.cpp
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#include <errno.h>
-#include <string.h>
-#include <sys/prctl.h>
-
-#include "FlushCommand.h"
-#include "LogBuffer.h"
-#include "LogReader.h"
-#include "LogTimes.h"
-
-pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER;
-
-LogTimeEntry::LogTimeEntry(LogReader& reader, SocketClient* client, bool nonBlock,
-                           unsigned long tail, log_mask_t logMask, pid_t pid, log_time start_time,
-                           uint64_t start, uint64_t timeout)
-    : leadingDropped(false),
-      mReader(reader),
-      mLogMask(logMask),
-      mPid(pid),
-      mCount(0),
-      mTail(tail),
-      mIndex(0),
-      mClient(client),
-      mStartTime(start_time),
-      mStart(start),
-      mNonBlock(nonBlock) {
-    mTimeout.tv_sec = timeout / NS_PER_SEC;
-    mTimeout.tv_nsec = timeout % NS_PER_SEC;
-    memset(mLastTid, 0, sizeof(mLastTid));
-    pthread_cond_init(&threadTriggeredCondition, nullptr);
-    cleanSkip_Locked();
-}
-
-bool LogTimeEntry::startReader_Locked() {
-    pthread_attr_t attr;
-
-    if (!pthread_attr_init(&attr)) {
-        if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
-            if (!pthread_create(&mThread, &attr, LogTimeEntry::threadStart,
-                                this)) {
-                pthread_attr_destroy(&attr);
-                return true;
-            }
-        }
-        pthread_attr_destroy(&attr);
-    }
-
-    return false;
-}
-
-void* LogTimeEntry::threadStart(void* obj) {
-    prctl(PR_SET_NAME, "logd.reader.per");
-
-    LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
-
-    SocketClient* client = me->mClient;
-
-    LogBuffer& logbuf = me->mReader.logbuf();
-
-    bool privileged = FlushCommand::hasReadLogs(client);
-    bool security = FlushCommand::hasSecurityLogs(client);
-
-    me->leadingDropped = true;
-
-    wrlock();
-
-    uint64_t start = me->mStart;
-
-    while (!me->mRelease) {
-        if (me->mTimeout.tv_sec || me->mTimeout.tv_nsec) {
-            if (pthread_cond_clockwait(&me->threadTriggeredCondition, &timesLock, CLOCK_MONOTONIC,
-                                       &me->mTimeout) == ETIMEDOUT) {
-                me->mTimeout.tv_sec = 0;
-                me->mTimeout.tv_nsec = 0;
-            }
-            if (me->mRelease) {
-                break;
-            }
-        }
-
-        unlock();
-
-        if (me->mTail) {
-            logbuf.flushTo(client, start, nullptr, privileged, security,
-                           FilterFirstPass, me);
-            me->leadingDropped = true;
-        }
-        start = logbuf.flushTo(client, start, me->mLastTid, privileged,
-                               security, FilterSecondPass, me);
-
-        // We only ignore entries before the original start time for the first flushTo(), if we
-        // get entries after this first flush before the original start time, then the client
-        // wouldn't have seen them.
-        // Note: this is still racy and may skip out of order events that came in since the last
-        // time the client disconnected and then reconnected with the new start time.  The long term
-        // solution here is that clients must request events since a specific sequence number.
-        me->mStartTime.tv_sec = 0;
-        me->mStartTime.tv_nsec = 0;
-
-        wrlock();
-
-        if (start == LogBufferElement::FLUSH_ERROR) {
-            break;
-        }
-
-        me->mStart = start + 1;
-
-        if (me->mNonBlock || me->mRelease) {
-            break;
-        }
-
-        me->cleanSkip_Locked();
-
-        if (!me->mTimeout.tv_sec && !me->mTimeout.tv_nsec) {
-            pthread_cond_wait(&me->threadTriggeredCondition, &timesLock);
-        }
-    }
-
-    LogReader& reader = me->mReader;
-    reader.release(client);
-
-    client->decRef();
-
-    LastLogTimes& times = reader.logbuf().mTimes;
-    auto it =
-        std::find_if(times.begin(), times.end(),
-                     [&me](const auto& other) { return other.get() == me; });
-
-    if (it != times.end()) {
-        times.erase(it);
-    }
-
-    unlock();
-
-    return nullptr;
-}
-
-// A first pass to count the number of elements
-int LogTimeEntry::FilterFirstPass(const LogBufferElement* element, void* obj) {
-    LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
-
-    LogTimeEntry::wrlock();
-
-    if (me->leadingDropped) {
-        if (element->getDropped()) {
-            LogTimeEntry::unlock();
-            return false;
-        }
-        me->leadingDropped = false;
-    }
-
-    if (me->mCount == 0) {
-        me->mStart = element->getSequence();
-    }
-
-    if ((!me->mPid || me->mPid == element->getPid()) && me->isWatching(element->getLogId()) &&
-        (me->mStartTime == log_time::EPOCH || me->mStartTime <= element->getRealTime())) {
-        ++me->mCount;
-    }
-
-    LogTimeEntry::unlock();
-
-    return false;
-}
-
-// A second pass to send the selected elements
-int LogTimeEntry::FilterSecondPass(const LogBufferElement* element, void* obj) {
-    LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
-
-    LogTimeEntry::wrlock();
-
-    me->mStart = element->getSequence();
-
-    if (me->skipAhead[element->getLogId()]) {
-        me->skipAhead[element->getLogId()]--;
-        goto skip;
-    }
-
-    if (me->leadingDropped) {
-        if (element->getDropped()) {
-            goto skip;
-        }
-        me->leadingDropped = false;
-    }
-
-    // Truncate to close race between first and second pass
-    if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) {
-        goto stop;
-    }
-
-    if (!me->isWatching(element->getLogId())) {
-        goto skip;
-    }
-
-    if (me->mPid && (me->mPid != element->getPid())) {
-        goto skip;
-    }
-
-    if (me->mStartTime != log_time::EPOCH && element->getRealTime() <= me->mStartTime) {
-        goto skip;
-    }
-
-    if (me->mRelease) {
-        goto stop;
-    }
-
-    if (!me->mTail) {
-        goto ok;
-    }
-
-    ++me->mIndex;
-
-    if ((me->mCount > me->mTail) && (me->mIndex <= (me->mCount - me->mTail))) {
-        goto skip;
-    }
-
-    if (!me->mNonBlock) {
-        me->mTail = 0;
-    }
-
-ok:
-    if (!me->skipAhead[element->getLogId()]) {
-        LogTimeEntry::unlock();
-        return true;
-    }
-// FALLTHRU
-
-skip:
-    LogTimeEntry::unlock();
-    return false;
-
-stop:
-    LogTimeEntry::unlock();
-    return -1;
-}
-
-void LogTimeEntry::cleanSkip_Locked(void) {
-    memset(skipAhead, 0, sizeof(skipAhead));
-}
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
deleted file mode 100644
index a99c73b..0000000
--- a/logd/LogTimes.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2012-2013 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_TIMES_H__
-#define _LOGD_LOG_TIMES_H__
-
-#include <pthread.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <time.h>
-
-#include <list>
-#include <memory>
-
-#include <log/log.h>
-#include <sysutils/SocketClient.h>
-
-typedef unsigned int log_mask_t;
-
-class LogReader;
-class LogBufferElement;
-
-class LogTimeEntry {
-    static pthread_mutex_t timesLock;
-    bool mRelease = false;
-    bool leadingDropped;
-    pthread_cond_t threadTriggeredCondition;
-    pthread_t mThread;
-    LogReader& mReader;
-    static void* threadStart(void* me);
-    const log_mask_t mLogMask;
-    const pid_t mPid;
-    unsigned int skipAhead[LOG_ID_MAX];
-    pid_t mLastTid[LOG_ID_MAX];
-    unsigned long mCount;
-    unsigned long mTail;
-    unsigned long mIndex;
-
-  public:
-    LogTimeEntry(LogReader& reader, SocketClient* client, bool nonBlock, unsigned long tail,
-                 log_mask_t logMask, pid_t pid, log_time start_time, uint64_t sequence,
-                 uint64_t timeout);
-
-    SocketClient* mClient;
-    log_time mStartTime;
-    uint64_t mStart;
-    struct timespec mTimeout;  // CLOCK_MONOTONIC based timeout used for log wrapping.
-    const bool mNonBlock;
-
-    // Protect List manipulations
-    static void wrlock(void) {
-        pthread_mutex_lock(&timesLock);
-    }
-    static void rdlock(void) {
-        pthread_mutex_lock(&timesLock);
-    }
-    static void unlock(void) {
-        pthread_mutex_unlock(&timesLock);
-    }
-
-    bool startReader_Locked();
-
-    void triggerReader_Locked(void) {
-        pthread_cond_signal(&threadTriggeredCondition);
-    }
-
-    void triggerSkip_Locked(log_id_t id, unsigned int skip) {
-        skipAhead[id] = skip;
-    }
-    void cleanSkip_Locked(void);
-
-    void release_Locked(void) {
-        // gracefully shut down the socket.
-        shutdown(mClient->getSocket(), SHUT_RDWR);
-        mRelease = true;
-        pthread_cond_signal(&threadTriggeredCondition);
-    }
-
-    bool isWatching(log_id_t id) const {
-        return mLogMask & (1 << id);
-    }
-    bool isWatchingMultiple(log_mask_t logMask) const {
-        return mLogMask & logMask;
-    }
-    // flushTo filter callbacks
-    static int FilterFirstPass(const LogBufferElement* element, void* me);
-    static int FilterSecondPass(const LogBufferElement* element, void* me);
-};
-
-typedef std::list<std::unique_ptr<LogTimeEntry>> LastLogTimes;
-
-#endif  // _LOGD_LOG_TIMES_H__
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index fa9f398..c472167 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef _LOGD_LOG_UTILS_H__
-#define _LOGD_LOG_UTILS_H__
+#pragma once
 
 #include <sys/cdefs.h>
 #include <sys/types.h>
@@ -31,17 +30,14 @@
 
 // Furnished in main.cpp. Caller must own and free returned value
 char* uidToName(uid_t uid);
-void prdebug(const char* fmt, ...) __printflike(1, 2);
+void prdebug(const char* fmt, ...) __attribute__((__format__(printf, 1, 2)));
 
-// Furnished in LogStatistics.cpp.
-size_t sizesTotal();
 // Caller must own and free returned value
 char* pidToName(pid_t pid);
 char* tidToName(pid_t tid);
 
 // Furnished in LogTags.cpp. Thread safe.
 const char* tagToName(uint32_t tag);
-void ReReadEventLogTags();
 
 // Furnished by LogKlog.cpp
 char* log_strntok_r(char* s, ssize_t& len, char*& saveptr, ssize_t& sublen);
@@ -64,13 +60,7 @@
 }
 }
 
-// Furnished in LogCommand.cpp
-bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid);
-bool clientHasLogCredentials(SocketClient* cli);
-
 static inline bool worstUidEnabledForLogid(log_id_t id) {
     return (id == LOG_ID_MAIN) || (id == LOG_ID_SYSTEM) ||
            (id == LOG_ID_RADIO) || (id == LOG_ID_EVENTS);
 }
-
-#endif  // _LOGD_LOG_UTILS_H__
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index 9d762dc..88a3bdc 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -16,13 +16,11 @@
 
 #include <ctype.h>
 
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
-#include <cutils/properties.h>
 
 #include "LogWhiteBlackList.h"
 
-// White and Black list
-
 Prune::Prune(uid_t uid, pid_t pid) : mUid(uid), mPid(pid) {
 }
 
@@ -75,14 +73,12 @@
         it = mNaughty.erase(it);
     }
 
-    static const char _default[] = "default";
     // default here means take ro.logd.filter, persist.logd.filter then
     // internal default in that order.
-    if (str && !strcmp(str, _default)) {
+    if (str && !strcmp(str, "default")) {
         str = nullptr;
     }
-    static const char _disable[] = "disable";
-    if (str && !strcmp(str, _disable)) {
+    if (str && !strcmp(str, "disable")) {
         str = "";
     }
 
@@ -91,22 +87,20 @@
     if (str) {
         filter = str;
     } else {
-        char property[PROPERTY_VALUE_MAX];
-        property_get("ro.logd.filter", property, _default);
-        filter = property;
-        property_get("persist.logd.filter", property, filter.c_str());
+        filter = android::base::GetProperty("ro.logd.filter", "default");
+        auto persist_filter = android::base::GetProperty("persist.logd.filter", "default");
         // default here means take ro.logd.filter
-        if (strcmp(property, _default)) {
-            filter = property;
+        if (persist_filter != "default") {
+            filter = persist_filter;
         }
     }
 
     // default here means take internal default.
-    if (filter == _default) {
+    if (filter == "default") {
         // See README.property for description of filter format
         filter = "~! ~1000/!";
     }
-    if (filter == _disable) {
+    if (filter == "disable") {
         filter = "";
     }
 
diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h
index 6e9893b..0e4e837 100644
--- a/logd/LogWhiteBlackList.h
+++ b/logd/LogWhiteBlackList.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef _LOGD_LOG_WHITE_BLACK_LIST_H__
-#define _LOGD_LOG_WHITE_BLACK_LIST_H__
+#pragma once
 
 #include <sys/types.h>
 
@@ -24,8 +23,6 @@
 
 #include "LogBufferElement.h"
 
-// White and Blacklist
-
 class Prune {
     friend class PruneList;
 
@@ -84,5 +81,3 @@
 
     std::string format();
 };
-
-#endif  // _LOGD_LOG_WHITE_BLACK_LIST_H__
diff --git a/logd/LogWriter.h b/logd/LogWriter.h
new file mode 100644
index 0000000..b6c5b67
--- /dev/null
+++ b/logd/LogWriter.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <log/log_read.h>
+
+// An interface for writing logs to a reader.
+class LogWriter {
+  public:
+    LogWriter(uid_t uid, bool privileged, bool can_read_security_logs)
+        : uid_(uid), privileged_(privileged), can_read_security_logs_(can_read_security_logs) {}
+    virtual ~LogWriter() {}
+
+    virtual bool Write(const logger_entry& entry, const char* msg) = 0;
+    virtual void Shutdown() {}
+    virtual void Release() {}
+
+    virtual std::string name() const = 0;
+    uid_t uid() const { return uid_; }
+
+    bool privileged() const { return privileged_; }
+    bool can_read_security_logs() const { return can_read_security_logs_; }
+
+  private:
+    uid_t uid_;
+
+    // If this writer sees logs from all UIDs or only its own UID.  See clientHasLogCredentials().
+    bool privileged_;
+    bool can_read_security_logs_;  // If this writer sees security logs.  See CanReadSecurityLogs().
+};
\ No newline at end of file
diff --git a/logd/README.property b/logd/README.property
index 1b7e165..6a9369a 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -44,10 +44,6 @@
                                          oldest entries of chattiest UID, and
                                          the chattiest PID of system
                                          (1000, or AID_SYSTEM).
-persist.logd.timestamp     string  ro    The recording timestamp source.
-                                         "m[onotonic]" is the only supported
-                                         key character, otherwise realtime.
-ro.logd.timestamp        string realtime default for persist.logd.timestamp
 log.tag                   string persist The global logging level, VERBOSE,
                                          DEBUG, INFO, WARN, ERROR, ASSERT or
                                          SILENT. Only the first character is
diff --git a/logd/SimpleLogBuffer.cpp b/logd/SimpleLogBuffer.cpp
new file mode 100644
index 0000000..1c83428
--- /dev/null
+++ b/logd/SimpleLogBuffer.cpp
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2020 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 "SimpleLogBuffer.h"
+
+#include "LogBufferElement.h"
+
+SimpleLogBuffer::SimpleLogBuffer(LogReaderList* reader_list, LogTags* tags, LogStatistics* stats)
+    : reader_list_(reader_list), tags_(tags), stats_(stats) {
+    Init();
+}
+
+SimpleLogBuffer::~SimpleLogBuffer() {}
+
+void SimpleLogBuffer::Init() {
+    log_id_for_each(i) {
+        if (SetSize(i, __android_logger_get_buffer_size(i))) {
+            SetSize(i, LOG_BUFFER_MIN_SIZE);
+        }
+    }
+
+    // Release any sleeping reader threads to dump their current content.
+    auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
+    for (const auto& reader_thread : reader_list_->reader_threads()) {
+        reader_thread->triggerReader_Locked();
+    }
+}
+
+std::list<LogBufferElement>::iterator SimpleLogBuffer::GetOldest(log_id_t log_id) {
+    auto it = logs().begin();
+    if (oldest_[log_id]) {
+        it = *oldest_[log_id];
+    }
+    while (it != logs().end() && it->getLogId() != log_id) {
+        it++;
+    }
+    if (it != logs().end()) {
+        oldest_[log_id] = it;
+    }
+    return it;
+}
+
+bool SimpleLogBuffer::ShouldLog(log_id_t log_id, const char* msg, uint16_t len) {
+    if (log_id == LOG_ID_SECURITY) {
+        return true;
+    }
+
+    int prio = ANDROID_LOG_INFO;
+    const char* tag = nullptr;
+    size_t tag_len = 0;
+    if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
+        if (len < sizeof(android_event_header_t)) {
+            return false;
+        }
+        int32_t numeric_tag = reinterpret_cast<const android_event_header_t*>(msg)->tag;
+        tag = tags_->tagToName(numeric_tag);
+        if (tag) {
+            tag_len = strlen(tag);
+        }
+    } else {
+        prio = *msg;
+        tag = msg + 1;
+        tag_len = strnlen(tag, len - 1);
+    }
+    return __android_log_is_loggable_len(prio, tag, tag_len, ANDROID_LOG_VERBOSE);
+}
+
+int SimpleLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
+                         const char* msg, uint16_t len) {
+    if (log_id >= LOG_ID_MAX) {
+        return -EINVAL;
+    }
+
+    if (!ShouldLog(log_id, msg, len)) {
+        // Log traffic received to total
+        stats_->AddTotal(log_id, len);
+        return -EACCES;
+    }
+
+    // Slip the time by 1 nsec if the incoming lands on xxxxxx000 ns.
+    // This prevents any chance that an outside source can request an
+    // exact entry with time specified in ms or us precision.
+    if ((realtime.tv_nsec % 1000) == 0) ++realtime.tv_nsec;
+
+    auto lock = std::lock_guard{lock_};
+    auto sequence = sequence_.fetch_add(1, std::memory_order_relaxed);
+    LogInternal(LogBufferElement(log_id, realtime, uid, pid, tid, sequence, msg, len));
+    return len;
+}
+
+void SimpleLogBuffer::LogInternal(LogBufferElement&& elem) {
+    log_id_t log_id = elem.getLogId();
+
+    logs_.emplace_back(std::move(elem));
+    stats_->Add(&logs_.back());
+    MaybePrune(log_id);
+    reader_list_->NotifyNewLog(1 << log_id);
+}
+
+uint64_t SimpleLogBuffer::FlushTo(
+        LogWriter* writer, uint64_t start, pid_t* last_tid,
+        const std::function<FlushToResult(const LogBufferElement* element)>& filter) {
+    auto shared_lock = SharedLock{lock_};
+
+    std::list<LogBufferElement>::iterator it;
+    if (start <= 1) {
+        // client wants to start from the beginning
+        it = logs_.begin();
+    } else {
+        // Client wants to start from some specified time. Chances are
+        // we are better off starting from the end of the time sorted list.
+        for (it = logs_.end(); it != logs_.begin();
+             /* do nothing */) {
+            --it;
+            if (it->getSequence() <= start) {
+                it++;
+                break;
+            }
+        }
+    }
+
+    uint64_t curr = start;
+
+    for (; it != logs_.end(); ++it) {
+        LogBufferElement& element = *it;
+
+        if (!writer->privileged() && element.getUid() != writer->uid()) {
+            continue;
+        }
+
+        if (!writer->can_read_security_logs() && element.getLogId() == LOG_ID_SECURITY) {
+            continue;
+        }
+
+        if (filter) {
+            FlushToResult ret = filter(&element);
+            if (ret == FlushToResult::kSkip) {
+                continue;
+            }
+            if (ret == FlushToResult::kStop) {
+                break;
+            }
+        }
+
+        bool same_tid = false;
+        if (last_tid) {
+            same_tid = last_tid[element.getLogId()] == element.getTid();
+            // Dropped (chatty) immediately following a valid log from the
+            // same source in the same log buffer indicates we have a
+            // multiple identical squash.  chatty that differs source
+            // is due to spam filter.  chatty to chatty of different
+            // source is also due to spam filter.
+            last_tid[element.getLogId()] =
+                    (element.getDropped() && !same_tid) ? 0 : element.getTid();
+        }
+
+        shared_lock.unlock();
+
+        // We never prune logs equal to or newer than any LogReaderThreads' `start` value, so the
+        // `element` pointer is safe here without the lock
+        curr = element.getSequence();
+        if (!element.FlushTo(writer, stats_, same_tid)) {
+            return FLUSH_ERROR;
+        }
+
+        shared_lock.lock_shared();
+    }
+
+    return curr;
+}
+
+// clear all rows of type "id" from the buffer.
+bool SimpleLogBuffer::Clear(log_id_t id, uid_t uid) {
+    bool busy = true;
+    // If it takes more than 4 tries (seconds) to clear, then kill reader(s)
+    for (int retry = 4;;) {
+        if (retry == 1) {  // last pass
+            // Check if it is still busy after the sleep, we say prune
+            // one entry, not another clear run, so we are looking for
+            // the quick side effect of the return value to tell us if
+            // we have a _blocked_ reader.
+            {
+                auto lock = std::lock_guard{lock_};
+                busy = Prune(id, 1, uid);
+            }
+            // It is still busy, blocked reader(s), lets kill them all!
+            // otherwise, lets be a good citizen and preserve the slow
+            // readers and let the clear run (below) deal with determining
+            // if we are still blocked and return an error code to caller.
+            if (busy) {
+                auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
+                for (const auto& reader_thread : reader_list_->reader_threads()) {
+                    if (reader_thread->IsWatching(id)) {
+                        android::prdebug("Kicking blocked reader, %s, from LogBuffer::clear()\n",
+                                         reader_thread->name().c_str());
+                        reader_thread->release_Locked();
+                    }
+                }
+            }
+        }
+        {
+            auto lock = std::lock_guard{lock_};
+            busy = Prune(id, ULONG_MAX, uid);
+        }
+
+        if (!busy || !--retry) {
+            break;
+        }
+        sleep(1);  // Let reader(s) catch up after notification
+    }
+    return busy;
+}
+
+// get the total space allocated to "id"
+unsigned long SimpleLogBuffer::GetSize(log_id_t id) {
+    auto lock = SharedLock{lock_};
+    size_t retval = max_size_[id];
+    return retval;
+}
+
+// set the total space allocated to "id"
+int SimpleLogBuffer::SetSize(log_id_t id, unsigned long size) {
+    // Reasonable limits ...
+    if (!__android_logger_valid_buffer_size(size)) {
+        return -1;
+    }
+
+    auto lock = std::lock_guard{lock_};
+    max_size_[id] = size;
+    return 0;
+}
+
+void SimpleLogBuffer::MaybePrune(log_id_t id) {
+    unsigned long prune_rows;
+    if (stats_->ShouldPrune(id, max_size_[id], &prune_rows)) {
+        Prune(id, prune_rows, 0);
+    }
+}
+
+bool SimpleLogBuffer::Prune(log_id_t id, unsigned long prune_rows, uid_t caller_uid) {
+    auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
+
+    // Don't prune logs that are newer than the point at which any reader threads are reading from.
+    LogReaderThread* oldest = nullptr;
+    for (const auto& reader_thread : reader_list_->reader_threads()) {
+        if (!reader_thread->IsWatching(id)) {
+            continue;
+        }
+        if (!oldest || oldest->start() > reader_thread->start() ||
+            (oldest->start() == reader_thread->start() &&
+             reader_thread->deadline().time_since_epoch().count() != 0)) {
+            oldest = reader_thread.get();
+        }
+    }
+
+    auto it = GetOldest(id);
+
+    while (it != logs_.end()) {
+        LogBufferElement& element = *it;
+
+        if (element.getLogId() != id) {
+            ++it;
+            continue;
+        }
+
+        if (caller_uid != 0 && element.getUid() != caller_uid) {
+            ++it;
+            continue;
+        }
+
+        if (oldest && oldest->start() <= element.getSequence()) {
+            KickReader(oldest, id, prune_rows);
+            return true;
+        }
+
+        stats_->Subtract(&element);
+        it = Erase(it);
+        if (--prune_rows == 0) {
+            return false;
+        }
+    }
+    return false;
+}
+
+std::list<LogBufferElement>::iterator SimpleLogBuffer::Erase(
+        std::list<LogBufferElement>::iterator it) {
+    bool oldest_is_it[LOG_ID_MAX];
+    log_id_for_each(i) { oldest_is_it[i] = oldest_[i] && it == *oldest_[i]; }
+
+    it = logs_.erase(it);
+
+    log_id_for_each(i) {
+        if (oldest_is_it[i]) {
+            if (__predict_false(it == logs().end())) {
+                oldest_[i] = std::nullopt;
+            } else {
+                oldest_[i] = it;  // Store the next iterator even if it does not correspond to
+                                  // the same log_id, as a starting point for GetOldest().
+            }
+        }
+    }
+
+    return it;
+}
+
+// If the selected reader is blocking our pruning progress, decide on
+// what kind of mitigation is necessary to unblock the situation.
+void SimpleLogBuffer::KickReader(LogReaderThread* reader, log_id_t id, unsigned long prune_rows) {
+    if (stats_->Sizes(id) > (2 * max_size_[id])) {  // +100%
+        // A misbehaving or slow reader has its connection
+        // dropped if we hit too much memory pressure.
+        android::prdebug("Kicking blocked reader, %s, from LogBuffer::kickMe()\n",
+                         reader->name().c_str());
+        reader->release_Locked();
+    } else if (reader->deadline().time_since_epoch().count() != 0) {
+        // Allow a blocked WRAP deadline reader to trigger and start reporting the log data.
+        reader->triggerReader_Locked();
+    } else {
+        // tell slow reader to skip entries to catch up
+        android::prdebug("Skipping %lu entries from slow reader, %s, from LogBuffer::kickMe()\n",
+                         prune_rows, reader->name().c_str());
+        reader->triggerSkip_Locked(id, prune_rows);
+    }
+}
diff --git a/logd/SimpleLogBuffer.h b/logd/SimpleLogBuffer.h
new file mode 100644
index 0000000..9a2d01a
--- /dev/null
+++ b/logd/SimpleLogBuffer.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 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 <atomic>
+#include <list>
+#include <mutex>
+
+#include "LogBuffer.h"
+#include "LogBufferElement.h"
+#include "LogReaderList.h"
+#include "LogStatistics.h"
+#include "LogTags.h"
+#include "rwlock.h"
+
+class SimpleLogBuffer : public LogBuffer {
+  public:
+    SimpleLogBuffer(LogReaderList* reader_list, LogTags* tags, LogStatistics* stats);
+    ~SimpleLogBuffer();
+    void Init() 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) override;
+    uint64_t FlushTo(
+            LogWriter* writer, uint64_t start, pid_t* lastTid,
+            const std::function<FlushToResult(const LogBufferElement* element)>& filter) override;
+
+    bool Clear(log_id_t id, uid_t uid) override;
+    unsigned long GetSize(log_id_t id) override;
+    int SetSize(log_id_t id, unsigned long size) override;
+
+    uint64_t sequence() const override { return sequence_.load(std::memory_order_relaxed); }
+
+  protected:
+    virtual bool Prune(log_id_t id, unsigned long prune_rows, uid_t uid) REQUIRES(lock_);
+    virtual void LogInternal(LogBufferElement&& elem) REQUIRES(lock_);
+
+    // Returns an iterator to the oldest element for a given log type, or logs_.end() if
+    // there are no logs for the given log type. Requires logs_lock_ to be held.
+    std::list<LogBufferElement>::iterator GetOldest(log_id_t log_id) REQUIRES(lock_);
+    std::list<LogBufferElement>::iterator Erase(std::list<LogBufferElement>::iterator it)
+            REQUIRES(lock_);
+    void KickReader(LogReaderThread* reader, log_id_t id, unsigned long prune_rows)
+            REQUIRES_SHARED(lock_);
+
+    LogStatistics* stats() { return stats_; }
+    LogReaderList* reader_list() { return reader_list_; }
+    unsigned long max_size(log_id_t id) REQUIRES_SHARED(lock_) { return max_size_[id]; }
+    std::list<LogBufferElement>& logs() { return logs_; }
+
+    RwLock lock_;
+
+  private:
+    bool ShouldLog(log_id_t log_id, const char* msg, uint16_t len);
+    void MaybePrune(log_id_t id) REQUIRES(lock_);
+
+    LogReaderList* reader_list_;
+    LogTags* tags_;
+    LogStatistics* stats_;
+
+    std::atomic<uint64_t> sequence_ = 1;
+
+    unsigned long max_size_[LOG_ID_MAX] GUARDED_BY(lock_);
+    std::list<LogBufferElement> logs_ GUARDED_BY(lock_);
+    // Keeps track of the iterator to the oldest log message of a given log type, as an
+    // optimization when pruning logs.  Use GetOldest() to retrieve.
+    std::optional<std::list<LogBufferElement>::iterator> oldest_[LOG_ID_MAX] GUARDED_BY(lock_);
+};
diff --git a/logd/fuzz/Android.bp b/logd/fuzz/Android.bp
index 299242d..f65fbdf 100644
--- a/logd/fuzz/Android.bp
+++ b/logd/fuzz/Android.bp
@@ -25,6 +25,7 @@
         "liblog",
         "liblogd",
         "libcutils",
+        "libsysutils",
     ],
     cflags: ["-Werror"],
 }
diff --git a/logd/fuzz/log_buffer_log_fuzzer.cpp b/logd/fuzz/log_buffer_log_fuzzer.cpp
index 4d1589b..8f90f50 100644
--- a/logd/fuzz/log_buffer_log_fuzzer.cpp
+++ b/logd/fuzz/log_buffer_log_fuzzer.cpp
@@ -15,8 +15,10 @@
  */
 #include <string>
 
-#include "../LogBuffer.h"
-#include "../LogTimes.h"
+#include "../ChattyLogBuffer.h"
+#include "../LogReaderList.h"
+#include "../LogReaderThread.h"
+#include "../LogStatistics.h"
 
 // We don't want to waste a lot of entropy on messages
 #define MAX_MSG_LENGTH 5
@@ -36,7 +38,8 @@
     unsigned int log_mask;
 };
 
-int write_log_messages(const uint8_t** pdata, size_t* data_left, LogBuffer* log_buffer) {
+int write_log_messages(const uint8_t** pdata, size_t* data_left, LogBuffer* log_buffer,
+                       LogStatistics* stats) {
     const uint8_t* data = *pdata;
     const LogInput* logInput = reinterpret_cast<const LogInput*>(data);
     data += sizeof(LogInput);
@@ -69,9 +72,9 @@
 
     // Other elements not in enum.
     log_id_t log_id = static_cast<log_id_t>(unsigned(logInput->log_id) % (LOG_ID_MAX + 1));
-    log_buffer->log(log_id, logInput->realtime, logInput->uid, logInput->pid, logInput->tid, msg,
+    log_buffer->Log(log_id, logInput->realtime, logInput->uid, logInput->pid, logInput->tid, msg,
                     sizeof(uint32_t) + msg_length + 1);
-    log_buffer->formatStatistics(logInput->uid, logInput->pid, logInput->log_mask);
+    stats->Format(logInput->uid, logInput->pid, logInput->log_mask);
     *pdata = data;
     return 1;
 }
@@ -93,23 +96,25 @@
         return 0;
     }
 
-    LastLogTimes times;
-    LogBuffer log_buffer(&times);
+    LogReaderList reader_list;
+    LogTags tags;
+    PruneList prune_list;
+    LogStatistics stats(true);
+    LogBuffer* log_buffer = new ChattyLogBuffer(&reader_list, &tags, &prune_list, &stats);
     size_t data_left = size;
     const uint8_t** pdata = &data;
 
-    log_buffer.enableStatistics();
-    log_buffer.initPrune(nullptr);
+    prune_list.init(nullptr);
     // We want to get pruning code to get called.
-    log_id_for_each(i) { log_buffer.setSize(i, 10000); }
+    log_id_for_each(i) { log_buffer->SetSize(i, 10000); }
 
     while (data_left >= sizeof(LogInput) + 2 * sizeof(uint8_t)) {
-        if (!write_log_messages(pdata, &data_left, &log_buffer)) {
+        if (!write_log_messages(pdata, &data_left, log_buffer, &stats)) {
             return 0;
         }
     }
 
-    log_id_for_each(i) { log_buffer.clear(i); }
+    log_id_for_each(i) { log_buffer->Clear(i, 0); }
     return 0;
 }
 }  // namespace android
diff --git a/logd/libaudit.c b/logd/libaudit.cpp
similarity index 67%
rename from logd/libaudit.c
rename to logd/libaudit.cpp
index f452c71..ccea0a2 100644
--- a/logd/libaudit.c
+++ b/logd/libaudit.cpp
@@ -18,11 +18,13 @@
  *
  */
 
+#include "libaudit.h"
+
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
 
-#include "libaudit.h"
+#include <limits>
 
 /**
  * Waits for an ack from the kernel
@@ -32,22 +34,15 @@
  *  This function returns 0 on success, else -errno.
  */
 static int get_ack(int fd) {
-    int rc;
-    struct audit_message rep;
-
-    /* Sanity check, this is an internal interface this shouldn't happen */
-    if (fd < 0) {
-        return -EINVAL;
-    }
-
-    rc = audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, MSG_PEEK);
+    struct audit_message rep = {};
+    int rc = audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, MSG_PEEK);
     if (rc < 0) {
         return rc;
     }
 
     if (rep.nlh.nlmsg_type == NLMSG_ERROR) {
         audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, 0);
-        rc = ((struct nlmsgerr*)rep.data)->error;
+        rc = reinterpret_cast<struct nlmsgerr*>(rep.data)->error;
         if (rc) {
             return -rc;
         }
@@ -70,19 +65,11 @@
  *  This function returns a positive sequence number on success, else -errno.
  */
 static int audit_send(int fd, int type, const void* data, size_t size) {
-    int rc;
-    static int16_t sequence = 0;
-    struct audit_message req;
-    struct sockaddr_nl addr;
-
-    memset(&req, 0, sizeof(req));
-    memset(&addr, 0, sizeof(addr));
-
-    /* We always send netlink messaged */
-    addr.nl_family = AF_NETLINK;
+    struct sockaddr_nl addr = {.nl_family = AF_NETLINK};
 
     /* Set up the netlink headers */
-    req.nlh.nlmsg_type = type;
+    struct audit_message req = {};
+    req.nlh.nlmsg_type = static_cast<uint16_t>(type);
     req.nlh.nlmsg_len = NLMSG_SPACE(size);
     req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
 
@@ -107,29 +94,23 @@
     /*
      * Only increment the sequence number on a guarantee
      * you will send it to the kernel.
-     *
-     * Also, the sequence is defined as a u32 in the kernel
-     * struct. Using an int here might not work on 32/64 bit splits. A
-     * signed 64 bit value can overflow a u32..but a u32
-     * might not fit in the response, so we need to use s32.
-     * Which is still kind of hackish since int could be 16 bits
-     * in size. The only safe type to use here is a signed 16
-     * bit value.
      */
-    req.nlh.nlmsg_seq = ++sequence;
+    static uint32_t sequence = 0;
+    if (sequence == std::numeric_limits<uint32_t>::max()) {
+        sequence = 1;
+    } else {
+        sequence++;
+    }
+    req.nlh.nlmsg_seq = sequence;
 
-    /* While failing and its due to interrupts */
-
-    rc = TEMP_FAILURE_RETRY(sendto(fd, &req, req.nlh.nlmsg_len, 0,
-                                   (struct sockaddr*)&addr, sizeof(addr)));
+    ssize_t rc = TEMP_FAILURE_RETRY(
+            sendto(fd, &req, req.nlh.nlmsg_len, 0, (struct sockaddr*)&addr, sizeof(addr)));
 
     /* Not all the bytes were sent */
     if (rc < 0) {
-        rc = -errno;
-        goto out;
+        return -errno;
     } else if ((uint32_t)rc != req.nlh.nlmsg_len) {
-        rc = -EPROTO;
-        goto out;
+        return -EPROTO;
     }
 
     /* We sent all the bytes, get the ack */
@@ -138,32 +119,22 @@
     /* If the ack failed, return the error, else return the sequence number */
     rc = (rc == 0) ? (int)sequence : rc;
 
-out:
-    /* Don't let sequence roll to negative */
-    if (sequence < 0) {
-        sequence = 0;
-    }
-
     return rc;
 }
 
 int audit_setup(int fd, pid_t pid) {
-    int rc;
-    struct audit_message rep;
-    struct audit_status status;
-
-    memset(&status, 0, sizeof(status));
-
     /*
      * In order to set the auditd PID we send an audit message over the netlink
      * socket with the pid field of the status struct set to our current pid,
      * and the the mask set to AUDIT_STATUS_PID
      */
-    status.pid = pid;
-    status.mask = AUDIT_STATUS_PID;
+    struct audit_status status = {
+            .mask = AUDIT_STATUS_PID,
+            .pid = static_cast<uint32_t>(pid),
+    };
 
     /* Let the kernel know this pid will be registering for audit events */
-    rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
+    int rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
     if (rc < 0) {
         return rc;
     }
@@ -178,6 +149,7 @@
      * so I went to non-blocking and it seemed to fix the bug.
      * Need to investigate further.
      */
+    struct audit_message rep = {};
     audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
 
     return 0;
@@ -188,27 +160,18 @@
 }
 
 int audit_rate_limit(int fd, uint32_t limit) {
-    struct audit_status status;
-    memset(&status, 0, sizeof(status));
-    status.mask = AUDIT_STATUS_RATE_LIMIT;
-    status.rate_limit = limit; /* audit entries per second */
+    struct audit_status status = {
+            .mask = AUDIT_STATUS_RATE_LIMIT, .rate_limit = limit, /* audit entries per second */
+    };
     return audit_send(fd, AUDIT_SET, &status, sizeof(status));
 }
 
 int audit_get_reply(int fd, struct audit_message* rep, reply_t block, int peek) {
-    ssize_t len;
-    int flags;
-    int rc = 0;
-
-    struct sockaddr_nl nladdr;
-    socklen_t nladdrlen = sizeof(nladdr);
-
     if (fd < 0) {
         return -EBADF;
     }
 
-    /* Set up the flags for recv from */
-    flags = (block == GET_REPLY_NONBLOCKING) ? MSG_DONTWAIT : 0;
+    int flags = (block == GET_REPLY_NONBLOCKING) ? MSG_DONTWAIT : 0;
     flags |= peek;
 
     /*
@@ -216,19 +179,20 @@
      * the interface shows that EINTR can never be returned, other errors,
      * however, can be returned.
      */
-    len = TEMP_FAILURE_RETRY(recvfrom(fd, rep, sizeof(*rep), flags,
-                                      (struct sockaddr*)&nladdr, &nladdrlen));
+    struct sockaddr_nl nladdr;
+    socklen_t nladdrlen = sizeof(nladdr);
+    ssize_t len = TEMP_FAILURE_RETRY(
+            recvfrom(fd, rep, sizeof(*rep), flags, (struct sockaddr*)&nladdr, &nladdrlen));
 
     /*
      * EAGAIN should be re-tried until success or another error manifests.
      */
     if (len < 0) {
-        rc = -errno;
-        if (block == GET_REPLY_NONBLOCKING && rc == -EAGAIN) {
+        if (block == GET_REPLY_NONBLOCKING && errno == EAGAIN) {
             /* If request is non blocking and errno is EAGAIN, just return 0 */
             return 0;
         }
-        return rc;
+        return -errno;
     }
 
     if (nladdrlen != sizeof(nladdr)) {
@@ -242,10 +206,10 @@
 
     /* Check if the reply from the kernel was ok */
     if (!NLMSG_OK(&rep->nlh, (size_t)len)) {
-        rc = (len == sizeof(*rep)) ? -EFBIG : -EBADE;
+        return len == sizeof(*rep) ? -EFBIG : -EBADE;
     }
 
-    return rc;
+    return 0;
 }
 
 void audit_close(int fd) {
diff --git a/logd/libaudit.h b/logd/libaudit.h
index b4a92a8..27b0866 100644
--- a/logd/libaudit.h
+++ b/logd/libaudit.h
@@ -17,8 +17,7 @@
  * Written by William Roberts <w.roberts@sta.samsung.com>
  */
 
-#ifndef _LIBAUDIT_H_
-#define _LIBAUDIT_H_
+#pragma once
 
 #include <stdint.h>
 #include <sys/cdefs.h>
@@ -102,5 +101,3 @@
 extern int audit_rate_limit(int fd, uint32_t limit);
 
 __END_DECLS
-
-#endif
diff --git a/logd/tests/logd_test.cpp b/logd/logd_test.cpp
similarity index 98%
rename from logd/tests/logd_test.cpp
rename to logd/logd_test.cpp
index b092489..ed34ea4 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/logd_test.cpp
@@ -39,7 +39,7 @@
 #include <selinux/selinux.h>
 #endif
 
-#include "../LogReader.h"  // pickup LOGD_SNDTIMEO
+#include "LogReader.h"  // pickup LOGD_SNDTIMEO
 
 #ifdef __ANDROID__
 static void send_to_control(char* buf, size_t len) {
@@ -583,6 +583,7 @@
         "dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=0.000000000");
 }
 
+#ifdef ENABLE_FLAKY_TESTS
 // b/26447386 refined behavior
 TEST(logd, timeout) {
 #ifdef __ANDROID__
@@ -605,7 +606,7 @@
     // A few tries to get it right just in case wrap kicks in due to
     // content providers being active during the test.
     int i = 5;
-    log_time start(android_log_clockid());
+    log_time start(CLOCK_REALTIME);
     start.tv_sec -= 30;  // reach back a moderate period of time
 
     while (--i) {
@@ -681,7 +682,7 @@
             if (msg > start) {
                 start = msg;
                 start.tv_sec += 30;
-                log_time now = log_time(android_log_clockid());
+                log_time now = log_time(CLOCK_REALTIME);
                 if (start > now) {
                     start = now;
                     --start.tv_sec;
@@ -717,6 +718,7 @@
     GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
+#endif
 
 // b/27242723 confirmed fixed
 TEST(logd, SNDTIMEO) {
@@ -902,10 +904,10 @@
             (log_msg.entry.len == (4 + 1 + 8))) {
             if (tag != 0) continue;
 
-            log_time tx(eventData + 4 + 1);
-            if (ts == tx) {
+            log_time* tx = reinterpret_cast<log_time*>(eventData + 4 + 1);
+            if (ts == *tx) {
                 ++count;
-            } else if (ts1 == tx) {
+            } else if (ts1 == *tx) {
                 ++second_count;
             }
         } else if (eventData[4] == EVENT_TYPE_STRING) {
diff --git a/logd/main.cpp b/logd/main.cpp
index 23bbf86..c2b5a1d 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -38,7 +38,6 @@
 
 #include <android-base/macros.h>
 #include <cutils/android_get_control_file.h>
-#include <cutils/properties.h>
 #include <cutils/sockets.h>
 #include <log/event_tag_map.h>
 #include <packagelistparser/packagelistparser.h>
@@ -47,12 +46,17 @@
 #include <processgroup/sched_policy.h>
 #include <utils/threads.h>
 
+#include "ChattyLogBuffer.h"
 #include "CommandListener.h"
 #include "LogAudit.h"
 #include "LogBuffer.h"
 #include "LogKlog.h"
 #include "LogListener.h"
+#include "LogReader.h"
+#include "LogStatistics.h"
+#include "LogTags.h"
 #include "LogUtils.h"
+#include "SimpleLogBuffer.h"
 
 #define KMSG_PRIORITY(PRI)                                 \
     '<', '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \
@@ -108,21 +112,6 @@
     return 0;
 }
 
-// Property helper
-static bool check_flag(const char* prop, const char* flag) {
-    const char* cp = strcasestr(prop, flag);
-    if (!cp) {
-        return false;
-    }
-    // We only will document comma (,)
-    static const char sep[] = ",:;|+ \t\f";
-    if ((cp != prop) && !strchr(sep, cp[-1])) {
-        return false;
-    }
-    cp += strlen(flag);
-    return !*cp || !!strchr(sep, *cp);
-}
-
 static int fdDmesg = -1;
 void android::prdebug(const char* fmt, ...) {
     if (fdDmesg < 0) {
@@ -150,50 +139,6 @@
     }
 }
 
-static sem_t reinit;
-static bool reinit_running = false;
-static LogBuffer* logBuf = nullptr;
-
-static void* reinit_thread_start(void* /*obj*/) {
-    prctl(PR_SET_NAME, "logd.daemon");
-
-    while (reinit_running && !sem_wait(&reinit) && reinit_running) {
-        if (fdDmesg >= 0) {
-            static const char reinit_message[] = { KMSG_PRIORITY(LOG_INFO),
-                                                   'l',
-                                                   'o',
-                                                   'g',
-                                                   'd',
-                                                   '.',
-                                                   'd',
-                                                   'a',
-                                                   'e',
-                                                   'm',
-                                                   'o',
-                                                   'n',
-                                                   ':',
-                                                   ' ',
-                                                   'r',
-                                                   'e',
-                                                   'i',
-                                                   'n',
-                                                   'i',
-                                                   't',
-                                                   '\n' };
-            write(fdDmesg, reinit_message, sizeof(reinit_message));
-        }
-
-        // Anything that reads persist.<property>
-        if (logBuf) {
-            logBuf->init();
-            logBuf->initPrune(nullptr);
-        }
-        android::ReReadEventLogTags();
-    }
-
-    return nullptr;
-}
-
 char* android::uidToName(uid_t u) {
     struct Userdata {
         uid_t uid;
@@ -220,12 +165,6 @@
     return userdata.name;
 }
 
-// Serves as a global method to trigger reinitialization
-// and as a function that can be provided to signal().
-void reinit_signal_handler(int /*signal*/) {
-    sem_post(&reinit);
-}
-
 static void readDmesg(LogAudit* al, LogKlog* kl) {
     if (!al && !kl) {
         return;
@@ -250,10 +189,6 @@
     }
     buf[--len] = '\0';
 
-    if (kl && kl->isMonotonic()) {
-        kl->synchronize(buf.get(), len);
-    }
-
     ssize_t sublen;
     for (char *ptr = nullptr, *tok = buf.get();
          (rc >= 0) && !!(tok = android::log_strntok_r(tok, len, ptr, sublen));
@@ -336,49 +271,34 @@
         return EXIT_FAILURE;
     }
 
-    // Reinit Thread
-    sem_init(&reinit, 0, 0);
-    pthread_attr_t attr;
-    if (!pthread_attr_init(&attr)) {
-        struct sched_param param;
+    // A cache of event log tags
+    LogTags log_tags;
 
-        memset(&param, 0, sizeof(param));
-        pthread_attr_setschedparam(&attr, &param);
-        pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
-        if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
-            pthread_t thread;
-            reinit_running = true;
-            if (pthread_create(&thread, &attr, reinit_thread_start, nullptr)) {
-                reinit_running = false;
-            }
-        }
-        pthread_attr_destroy(&attr);
-    }
+    // Pruning configuration.
+    PruneList prune_list;
+
+    // Partial (required for chatty) or full logging statistics.
+    bool enable_full_log_statistics = __android_logger_property_get_bool(
+            "logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |
+                                       BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE);
+    LogStatistics log_statistics(enable_full_log_statistics);
 
     // Serves the purpose of managing the last logs times read on a
     // socket connection, and as a reader lock on a range of log
     // entries.
+    LogReaderList reader_list;
 
-    LastLogTimes* times = new LastLogTimes();
-
-    // LogBuffer is the object which is responsible for holding all
-    // log entries.
-
-    logBuf = new LogBuffer(times);
-
-    signal(SIGHUP, reinit_signal_handler);
-
-    if (__android_logger_property_get_bool(
-            "logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |
-                                   BOOL_DEFAULT_FLAG_ENG |
-                                   BOOL_DEFAULT_FLAG_SVELTE)) {
-        logBuf->enableStatistics();
+    // LogBuffer is the object which is responsible for holding all log entries.
+    LogBuffer* logBuf;
+    if (true) {
+        logBuf = new ChattyLogBuffer(&reader_list, &log_tags, &prune_list, &log_statistics);
+    } else {
+        logBuf = new SimpleLogBuffer(&reader_list, &log_tags, &log_statistics);
     }
 
     // LogReader listens on /dev/socket/logdr. When a client
     // connects, log entries in the LogBuffer are written to the client.
-
-    LogReader* reader = new LogReader(logBuf);
+    LogReader* reader = new LogReader(logBuf, &reader_list);
     if (reader->startListener()) {
         return EXIT_FAILURE;
     }
@@ -386,17 +306,14 @@
     // LogListener listens on /dev/socket/logdw for client
     // initiated log messages. New log entries are added to LogBuffer
     // and LogReader is notified to send updates to connected clients.
-
-    LogListener* swl = new LogListener(logBuf, reader);
-    // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
-    if (swl->startListener(600)) {
+    LogListener* swl = new LogListener(logBuf);
+    if (!swl->StartListener()) {
         return EXIT_FAILURE;
     }
 
     // Command listener listens on /dev/socket/logd for incoming logd
     // administrative commands.
-
-    CommandListener* cl = new CommandListener(logBuf, reader, swl);
+    CommandListener* cl = new CommandListener(logBuf, &log_tags, &prune_list, &log_statistics);
     if (cl->startListener()) {
         return EXIT_FAILURE;
     }
@@ -404,25 +321,22 @@
     // LogAudit listens on NETLINK_AUDIT socket for selinux
     // initiated log messages. New log entries are added to LogBuffer
     // and LogReader is notified to send updates to connected clients.
-
     LogAudit* al = nullptr;
     if (auditd) {
-        al = new LogAudit(logBuf, reader,
-                          __android_logger_property_get_bool(
-                              "ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE)
-                              ? fdDmesg
-                              : -1);
+        int dmesg_fd = __android_logger_property_get_bool("ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE)
+                               ? fdDmesg
+                               : -1;
+        al = new LogAudit(logBuf, dmesg_fd, &log_statistics);
     }
 
     LogKlog* kl = nullptr;
     if (klogd) {
-        kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != nullptr);
+        kl = new LogKlog(logBuf, fdDmesg, fdPmesg, al != nullptr, &log_statistics);
     }
 
     readDmesg(al, kl);
 
     // failure is an option ... messages are in dmesg (required by standard)
-
     if (kl && kl->startListener()) {
         delete kl;
     }
diff --git a/logd/rwlock.h b/logd/rwlock.h
new file mode 100644
index 0000000..2b27ff1
--- /dev/null
+++ b/logd/rwlock.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 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/LICENSE2.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 <pthread.h>
+
+#include <android-base/macros.h>
+#include <android-base/thread_annotations.h>
+
+// As of the end of May 2020, std::shared_mutex is *not* simply a pthread_rwlock, but rather a
+// combination of std::mutex and std::condition variable, which is obviously less efficient.  This
+// immitates what std::shared_mutex should be doing and is compatible with RAII thread wrappers.
+
+class SHARED_CAPABILITY("mutex") RwLock {
+  public:
+    RwLock() {}
+    ~RwLock() {}
+
+    void lock() ACQUIRE() { pthread_rwlock_wrlock(&rwlock_); }
+    void lock_shared() ACQUIRE_SHARED() { pthread_rwlock_rdlock(&rwlock_); }
+
+    void unlock() RELEASE() { pthread_rwlock_unlock(&rwlock_); }
+
+  private:
+    pthread_rwlock_t rwlock_ = PTHREAD_RWLOCK_INITIALIZER;
+};
+
+// std::shared_lock does not have thread annotations, so we need our own.
+
+class SCOPED_CAPABILITY SharedLock {
+  public:
+    SharedLock(RwLock& lock) ACQUIRE_SHARED(lock) : lock_(lock) { lock_.lock_shared(); }
+    ~SharedLock() RELEASE() { lock_.unlock(); }
+
+    void lock_shared() ACQUIRE_SHARED() { lock_.lock_shared(); }
+    void unlock() RELEASE() { lock_.unlock(); }
+
+    DISALLOW_IMPLICIT_CONSTRUCTORS(SharedLock);
+
+  private:
+    RwLock& lock_;
+};
diff --git a/logd/tests/Android.bp b/logd/tests/Android.bp
deleted file mode 100644
index 9a5defa..0000000
--- a/logd/tests/Android.bp
+++ /dev/null
@@ -1,68 +0,0 @@
-//
-// Copyright (C) 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.
-//
-
-// -----------------------------------------------------------------------------
-// Unit tests.
-// -----------------------------------------------------------------------------
-
-cc_defaults {
-    name: "logd-unit-test-defaults",
-
-    cflags: [
-        "-fstack-protector-all",
-        "-g",
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-        "-fno-builtin",
-
-        "-DAUDITD_LOG_TAG=1003",
-        "-DCHATTY_LOG_TAG=1004",
-    ],
-
-    srcs: ["logd_test.cpp"],
-
-    static_libs: [
-        "libbase",
-        "libcutils",
-        "libselinux",
-        "liblog",
-    ],
-}
-
-// Build tests for the logger. Run with:
-//   adb shell /data/nativetest/logd-unit-tests/logd-unit-tests
-cc_test {
-    name: "logd-unit-tests",
-    defaults: ["logd-unit-test-defaults"],
-}
-
-cc_test {
-    name: "CtsLogdTestCases",
-    defaults: ["logd-unit-test-defaults"],
-    multilib: {
-        lib32: {
-            suffix: "32",
-        },
-        lib64: {
-            suffix: "64",
-        },
-    },
-    test_suites: [
-        "cts",
-        "vts10",
-    ],
-}
diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt
index 405f5a9..5de422f 100644
--- a/rootdir/etc/public.libraries.android.txt
+++ b/rootdir/etc/public.libraries.android.txt
@@ -16,6 +16,7 @@
 liblog.so
 libmediandk.so
 libm.so
+libnativehelper.so
 libnativewindow.so
 libneuralnetworks.so nopreload
 libOpenMAXAL.so
diff --git a/rootdir/etc/public.libraries.iot.txt b/rootdir/etc/public.libraries.iot.txt
index b565340..77f8bb8 100644
--- a/rootdir/etc/public.libraries.iot.txt
+++ b/rootdir/etc/public.libraries.iot.txt
@@ -17,6 +17,7 @@
 liblog.so
 libmediandk.so
 libm.so
+libnativehelper.so
 libnativewindow.so
 libneuralnetworks.so
 libOpenMAXAL.so
diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt
index 7cbda08..82196e4 100644
--- a/rootdir/etc/public.libraries.wear.txt
+++ b/rootdir/etc/public.libraries.wear.txt
@@ -16,6 +16,7 @@
 liblog.so
 libmediandk.so
 libm.so
+libnativehelper.so
 libnativewindow.so
 libneuralnetworks.so
 libOpenMAXAL.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 6564e8f..00a58bf 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -78,6 +78,9 @@
     mkdir /dev/boringssl 0755 root root
     mkdir /dev/boringssl/selftest 0755 root root
 
+    # Mount tracefs
+    mount tracefs tracefs /sys/kernel/tracing
+
 # Run boringssl self test for each ABI so that later processes can skip it. http://b/139348610
 on early-init && property:ro.product.cpu.abilist32=*
     exec_start boringssl_self_test32
@@ -544,8 +547,8 @@
     enter_default_mount_ns
 
     # /data/apex is now available. Start apexd to scan and activate APEXes.
-    mkdir /data/apex 0750 root system encryption=None
-    mkdir /data/apex/active 0750 root system
+    mkdir /data/apex 0755 root system encryption=None
+    mkdir /data/apex/active 0755 root system
     mkdir /data/apex/backup 0700 root system
     mkdir /data/apex/hashtree 0700 root system
     mkdir /data/apex/sessions 0700 root system